1use crate::committee::EpochId;
5use crate::crypto::{
6 CompressedSignature, PasskeyAuthenticatorAsBytes, PublicKey, SignatureScheme, SuiSignature,
7 ZkLoginAuthenticatorAsBytes,
8};
9use crate::digests::ZKLoginInputsDigest;
10use crate::error::{SuiError, SuiErrorKind};
11use crate::multisig_legacy::MultiSigLegacy;
12use crate::passkey_authenticator::PasskeyAuthenticator;
13use crate::signature_verification::VerifiedDigestCache;
14use crate::zk_login_authenticator::ZkLoginAuthenticator;
15use crate::{base_types::SuiAddress, crypto::Signature, error::SuiResult, multisig::MultiSig};
16pub use enum_dispatch::enum_dispatch;
17use fastcrypto::ed25519::{Ed25519PublicKey, Ed25519Signature};
18use fastcrypto::secp256k1::{Secp256k1PublicKey, Secp256k1Signature};
19use fastcrypto::secp256r1::{Secp256r1PublicKey, Secp256r1Signature};
20use fastcrypto::{
21 error::FastCryptoError,
22 traits::{EncodeDecodeBase64, ToFromBytes},
23};
24use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId, OIDCProvider};
25use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;
26use im::hashmap::HashMap as ImHashMap;
27use schemars::JsonSchema;
28use serde::Serialize;
29use shared_crypto::intent::IntentMessage;
30use std::hash::Hash;
31use std::sync::Arc;
32#[derive(Default, Debug, Clone)]
33pub struct VerifyParams {
34 pub oidc_provider_jwks: ImHashMap<JwkId, JWK>,
36 pub supported_providers: Vec<OIDCProvider>,
37 pub zk_login_env: ZkLoginEnv,
38 pub verify_legacy_zklogin_address: bool,
39 pub accept_zklogin_in_multisig: bool,
40 pub accept_passkey_in_multisig: bool,
41 pub zklogin_max_epoch_upper_bound_delta: Option<u64>,
42 pub additional_multisig_checks: bool,
43 pub validate_zklogin_public_identifier: bool,
44}
45
46impl VerifyParams {
47 pub fn new(
48 oidc_provider_jwks: ImHashMap<JwkId, JWK>,
49 supported_providers: Vec<OIDCProvider>,
50 zk_login_env: ZkLoginEnv,
51 verify_legacy_zklogin_address: bool,
52 accept_zklogin_in_multisig: bool,
53 accept_passkey_in_multisig: bool,
54 zklogin_max_epoch_upper_bound_delta: Option<u64>,
55 additional_multisig_checks: bool,
56 validate_zklogin_public_identifier: bool,
57 ) -> Self {
58 Self {
59 oidc_provider_jwks,
60 supported_providers,
61 zk_login_env,
62 verify_legacy_zklogin_address,
63 accept_zklogin_in_multisig,
64 accept_passkey_in_multisig,
65 zklogin_max_epoch_upper_bound_delta,
66 additional_multisig_checks,
67 validate_zklogin_public_identifier,
68 }
69 }
70}
71
72#[enum_dispatch]
74pub trait AuthenticatorTrait {
75 fn verify_user_authenticator_epoch(
76 &self,
77 epoch: EpochId,
78 max_epoch_upper_bound_delta: Option<u64>,
79 ) -> SuiResult;
80
81 fn verify_claims<T>(
82 &self,
83 value: &IntentMessage<T>,
84 author: SuiAddress,
85 aux_verify_data: &VerifyParams,
86 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
87 ) -> SuiResult
88 where
89 T: Serialize;
90}
91
92#[enum_dispatch(AuthenticatorTrait)]
97#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Hash)]
98pub enum GenericSignature {
99 MultiSig,
100 MultiSigLegacy,
101 Signature,
102 ZkLoginAuthenticator,
103 PasskeyAuthenticator,
104}
105
106impl GenericSignature {
107 pub fn is_zklogin(&self) -> bool {
108 matches!(self, GenericSignature::ZkLoginAuthenticator(_))
109 }
110 pub fn is_passkey(&self) -> bool {
111 matches!(self, GenericSignature::PasskeyAuthenticator(_))
112 }
113
114 pub fn is_upgraded_multisig(&self) -> bool {
115 matches!(self, GenericSignature::MultiSig(_))
116 }
117
118 pub fn verify_authenticator<T>(
119 &self,
120 value: &IntentMessage<T>,
121 author: SuiAddress,
122 epoch: EpochId,
123 verify_params: &VerifyParams,
124 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
125 ) -> SuiResult
126 where
127 T: Serialize,
128 {
129 self.verify_user_authenticator_epoch(
130 epoch,
131 verify_params.zklogin_max_epoch_upper_bound_delta,
132 )?;
133 self.verify_claims(value, author, verify_params, zklogin_inputs_cache)
134 }
135
136 pub fn to_compressed(&self) -> Result<CompressedSignature, SuiError> {
139 match self {
140 GenericSignature::Signature(s) => {
141 let bytes = s.signature_bytes();
142 match s.scheme() {
143 SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519(
144 (&Ed25519Signature::from_bytes(bytes).map_err(|_| {
145 SuiErrorKind::InvalidSignature {
146 error: "Cannot parse ed25519 sig".to_string(),
147 }
148 })?)
149 .into(),
150 )),
151 SignatureScheme::Secp256k1 => Ok(CompressedSignature::Secp256k1(
152 (&Secp256k1Signature::from_bytes(bytes).map_err(|_| {
153 SuiErrorKind::InvalidSignature {
154 error: "Cannot parse secp256k1 sig".to_string(),
155 }
156 })?)
157 .into(),
158 )),
159 SignatureScheme::Secp256r1 | SignatureScheme::PasskeyAuthenticator => {
160 Ok(CompressedSignature::Secp256r1(
161 (&Secp256r1Signature::from_bytes(bytes).map_err(|_| {
162 SuiErrorKind::InvalidSignature {
163 error: "Cannot parse secp256r1 sig".to_string(),
164 }
165 })?)
166 .into(),
167 ))
168 }
169
170 _ => Err(SuiErrorKind::UnsupportedFeatureError {
171 error: "Unsupported signature scheme".to_string(),
172 }
173 .into()),
174 }
175 }
176 GenericSignature::ZkLoginAuthenticator(s) => Ok(CompressedSignature::ZkLogin(
177 ZkLoginAuthenticatorAsBytes(s.as_ref().to_vec()),
178 )),
179 GenericSignature::PasskeyAuthenticator(s) => Ok(CompressedSignature::Passkey(
180 PasskeyAuthenticatorAsBytes(s.as_ref().to_vec()),
181 )),
182 _ => Err(SuiErrorKind::UnsupportedFeatureError {
183 error: "Unsupported signature scheme".to_string(),
184 }
185 .into()),
186 }
187 }
188
189 pub fn to_public_key(&self) -> Result<PublicKey, SuiError> {
192 match self {
193 GenericSignature::Signature(s) => {
194 let bytes = s.public_key_bytes();
195 match s.scheme() {
196 SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
197 (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| {
198 SuiErrorKind::KeyConversionError("Cannot parse ed25519 pk".to_string())
199 })?)
200 .into(),
201 )),
202 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
203 (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| {
204 SuiErrorKind::KeyConversionError(
205 "Cannot parse secp256k1 pk".to_string(),
206 )
207 })?)
208 .into(),
209 )),
210 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
211 (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| {
212 SuiErrorKind::KeyConversionError(
213 "Cannot parse secp256r1 pk".to_string(),
214 )
215 })?)
216 .into(),
217 )),
218 _ => Err(SuiErrorKind::UnsupportedFeatureError {
219 error: "Unsupported signature scheme in MultiSig".to_string(),
220 }
221 .into()),
222 }
223 }
224 GenericSignature::ZkLoginAuthenticator(s) => s.get_pk(),
225 GenericSignature::PasskeyAuthenticator(s) => s.get_pk(),
226 _ => Err(SuiErrorKind::UnsupportedFeatureError {
227 error: "Unsupported signature scheme".to_string(),
228 }
229 .into()),
230 }
231 }
232}
233
234impl ToFromBytes for GenericSignature {
240 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
241 match SignatureScheme::from_flag_byte(
242 bytes.first().ok_or(FastCryptoError::InputTooShort(0))?,
243 ) {
244 Ok(x) => match x {
245 SignatureScheme::ED25519
246 | SignatureScheme::Secp256k1
247 | SignatureScheme::Secp256r1 => Ok(GenericSignature::Signature(
248 Signature::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
249 )),
250 SignatureScheme::MultiSig => match MultiSig::from_bytes(bytes) {
251 Ok(multisig) => Ok(GenericSignature::MultiSig(multisig)),
252 Err(_) => {
253 let multisig = MultiSigLegacy::from_bytes(bytes)?;
254 Ok(GenericSignature::MultiSigLegacy(multisig))
255 }
256 },
257 SignatureScheme::ZkLoginAuthenticator => {
258 let zk_login = ZkLoginAuthenticator::from_bytes(bytes)?;
259 Ok(GenericSignature::ZkLoginAuthenticator(zk_login))
260 }
261 SignatureScheme::PasskeyAuthenticator => {
262 let passkey = PasskeyAuthenticator::from_bytes(bytes)?;
263 Ok(GenericSignature::PasskeyAuthenticator(passkey))
264 }
265 _ => Err(FastCryptoError::InvalidInput),
266 },
267 Err(_) => Err(FastCryptoError::InvalidInput),
268 }
269 }
270}
271
272impl AsRef<[u8]> for GenericSignature {
274 fn as_ref(&self) -> &[u8] {
275 match self {
276 GenericSignature::MultiSig(s) => s.as_ref(),
277 GenericSignature::MultiSigLegacy(s) => s.as_ref(),
278 GenericSignature::Signature(s) => s.as_ref(),
279 GenericSignature::ZkLoginAuthenticator(s) => s.as_ref(),
280 GenericSignature::PasskeyAuthenticator(s) => s.as_ref(),
281 }
282 }
283}
284
285impl ::serde::Serialize for GenericSignature {
286 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
287 if serializer.is_human_readable() {
288 #[derive(serde::Serialize)]
289 struct GenericSignature(String);
290 GenericSignature(self.encode_base64()).serialize(serializer)
291 } else {
292 #[derive(serde::Serialize)]
293 struct GenericSignature<'a>(&'a [u8]);
294 GenericSignature(self.as_ref()).serialize(serializer)
295 }
296 }
297}
298
299impl<'de> ::serde::Deserialize<'de> for GenericSignature {
300 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
301 use serde::de::Error;
302
303 if deserializer.is_human_readable() {
304 #[derive(serde::Deserialize)]
305 struct GenericSignature(String);
306 let s = GenericSignature::deserialize(deserializer)?;
307 Self::decode_base64(&s.0).map_err(::serde::de::Error::custom)
308 } else {
309 #[derive(serde::Deserialize)]
310 struct GenericSignature(Vec<u8>);
311
312 let data = GenericSignature::deserialize(deserializer)?;
313 Self::from_bytes(&data.0).map_err(|e| Error::custom(e.to_string()))
314 }
315 }
316}
317
318impl AuthenticatorTrait for Signature {
320 fn verify_user_authenticator_epoch(&self, _: EpochId, _: Option<EpochId>) -> SuiResult {
321 Ok(())
322 }
323
324 fn verify_claims<T>(
325 &self,
326 value: &IntentMessage<T>,
327 author: SuiAddress,
328 _aux_verify_data: &VerifyParams,
329 _zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
330 ) -> SuiResult
331 where
332 T: Serialize,
333 {
334 self.verify_secure(value, author, self.scheme())
335 }
336}