sui_types/
authenticator_state.rs1use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId};
5use move_core_types::{account_address::AccountAddress, ident_str, identifier::IdentStr};
6use serde::{Deserialize, Serialize};
7
8use crate::base_types::SequenceNumber;
9use crate::dynamic_field::get_dynamic_field_from_store;
10use crate::error::{SuiErrorKind, SuiResult};
11use crate::object::Owner;
12use crate::storage::ObjectStore;
13use crate::{SUI_AUTHENTICATOR_STATE_OBJECT_ID, SUI_FRAMEWORK_ADDRESS, id::UID};
14
15pub const AUTHENTICATOR_STATE_MODULE_NAME: &IdentStr = ident_str!("authenticator_state");
16pub const AUTHENTICATOR_STATE_STRUCT_NAME: &IdentStr = ident_str!("AuthenticatorState");
17pub const AUTHENTICATOR_STATE_UPDATE_FUNCTION_NAME: &IdentStr =
18 ident_str!("update_authenticator_state");
19pub const AUTHENTICATOR_STATE_CREATE_FUNCTION_NAME: &IdentStr = ident_str!("create");
20pub const AUTHENTICATOR_STATE_EXPIRE_JWKS_FUNCTION_NAME: &IdentStr = ident_str!("expire_jwks");
21pub const RESOLVED_SUI_AUTHENTICATOR_STATE: (&AccountAddress, &IdentStr, &IdentStr) = (
22 &SUI_FRAMEWORK_ADDRESS,
23 AUTHENTICATOR_STATE_MODULE_NAME,
24 AUTHENTICATOR_STATE_STRUCT_NAME,
25);
26
27pub const AUTHENTICATOR_STATE_VERSION: u64 = 1;
29
30#[derive(Debug, Serialize, Deserialize)]
31pub struct AuthenticatorState {
32 pub id: UID,
33 pub version: u64,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37pub struct AuthenticatorStateInner {
38 pub version: u64,
39
40 pub active_jwks: Vec<ActiveJwk>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
45pub struct ActiveJwk {
46 pub jwk_id: JwkId,
47 pub jwk: JWK,
48 pub epoch: u64,
50}
51
52fn string_bytes_ord(a: &str, b: &str) -> std::cmp::Ordering {
53 let a_bytes = a.as_bytes();
54 let b_bytes = b.as_bytes();
55
56 if a_bytes.len() < b_bytes.len() {
57 return std::cmp::Ordering::Less;
58 }
59 if a_bytes.len() > b_bytes.len() {
60 return std::cmp::Ordering::Greater;
61 }
62
63 for (a_byte, b_byte) in a_bytes.iter().zip(b_bytes.iter()) {
64 if a_byte < b_byte {
65 return std::cmp::Ordering::Less;
66 }
67 if a_byte > b_byte {
68 return std::cmp::Ordering::Greater;
69 }
70 }
71
72 std::cmp::Ordering::Equal
73}
74
75fn jwk_ord(a: &ActiveJwk, b: &ActiveJwk) -> std::cmp::Ordering {
77 if a.jwk_id.iss != b.jwk_id.iss {
79 string_bytes_ord(&a.jwk_id.iss, &b.jwk_id.iss)
80 } else if a.jwk_id.kid != b.jwk_id.kid {
81 string_bytes_ord(&a.jwk_id.kid, &b.jwk_id.kid)
82 } else if a.jwk.kty != b.jwk.kty {
83 string_bytes_ord(&a.jwk.kty, &b.jwk.kty)
84 } else if a.jwk.e != b.jwk.e {
85 string_bytes_ord(&a.jwk.e, &b.jwk.e)
86 } else if a.jwk.n != b.jwk.n {
87 string_bytes_ord(&a.jwk.n, &b.jwk.n)
88 } else {
89 string_bytes_ord(&a.jwk.alg, &b.jwk.alg)
90 }
91}
92
93#[allow(clippy::non_canonical_partial_ord_impl)]
94impl std::cmp::PartialOrd for ActiveJwk {
95 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
97 Some(jwk_ord(self, other))
98 }
99}
100
101impl std::cmp::Ord for ActiveJwk {
102 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
104 jwk_ord(self, other)
105 }
106}
107
108pub fn get_authenticator_state(
109 object_store: impl ObjectStore,
110) -> SuiResult<Option<AuthenticatorStateInner>> {
111 let outer = object_store.get_object(&SUI_AUTHENTICATOR_STATE_OBJECT_ID);
112 let Some(outer) = outer else {
113 return Ok(None);
114 };
115 let move_object = outer.data.try_as_move().ok_or_else(|| {
116 SuiErrorKind::SuiSystemStateReadError(
117 "AuthenticatorState object must be a Move object".to_owned(),
118 )
119 })?;
120 let outer = bcs::from_bytes::<AuthenticatorState>(move_object.contents())
121 .map_err(|err| SuiErrorKind::SuiSystemStateReadError(err.to_string()))?;
122
123 assert_eq!(outer.version, AUTHENTICATOR_STATE_VERSION);
125
126 let id = outer.id.id.bytes;
127 let inner: AuthenticatorStateInner =
128 get_dynamic_field_from_store(&object_store, id, &outer.version).map_err(|err| {
129 SuiErrorKind::DynamicFieldReadError(format!(
130 "Failed to load sui system state inner object with ID {:?} and version {:?}: {:?}",
131 id, outer.version, err
132 ))
133 })?;
134
135 Ok(Some(inner))
136}
137
138pub fn get_authenticator_state_obj_initial_shared_version(
139 object_store: &dyn ObjectStore,
140) -> SuiResult<Option<SequenceNumber>> {
141 Ok(object_store
142 .get_object(&SUI_AUTHENTICATOR_STATE_OBJECT_ID)
143 .map(|obj| match obj.owner {
144 Owner::Shared {
145 initial_shared_version,
146 } => initial_shared_version,
147 _ => unreachable!("Authenticator state object must be shared"),
148 }))
149}