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_pq::mldsa65::{MLDSA65PublicKey, MLDSA65Signature};
25use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId, OIDCProvider};
26use fastcrypto_zkp::bn254::zk_login_api::ZkLoginEnv;
27use imbl::hashmap::HashMap as ImHashMap;
28use schemars::JsonSchema;
29use serde::Serialize;
30use shared_crypto::intent::IntentMessage;
31use std::hash::Hash;
32use std::sync::Arc;
33#[derive(Default, Debug, Clone)]
34pub struct VerifyParams {
35 pub oidc_provider_jwks: ImHashMap<JwkId, JWK>,
37 pub supported_providers: Vec<OIDCProvider>,
38 pub zk_login_env: ZkLoginEnv,
39 pub zklogin_circuit_mode: u64,
42 pub verify_legacy_zklogin_address: bool,
43 pub accept_zklogin_in_multisig: bool,
44 pub accept_passkey_in_multisig: bool,
45 pub accept_mldsa65_in_multisig: bool,
46 pub zklogin_max_epoch_upper_bound_delta: Option<u64>,
47 pub additional_multisig_checks: bool,
48 pub validate_zklogin_public_identifier: bool,
49}
50
51impl VerifyParams {
52 pub fn new(
53 oidc_provider_jwks: ImHashMap<JwkId, JWK>,
54 supported_providers: Vec<OIDCProvider>,
55 zk_login_env: ZkLoginEnv,
56 zklogin_circuit_mode: u64,
57 verify_legacy_zklogin_address: bool,
58 accept_zklogin_in_multisig: bool,
59 accept_passkey_in_multisig: bool,
60 zklogin_max_epoch_upper_bound_delta: Option<u64>,
61 additional_multisig_checks: bool,
62 validate_zklogin_public_identifier: bool,
63 ) -> Self {
64 Self {
65 oidc_provider_jwks,
66 supported_providers,
67 zk_login_env,
68 zklogin_circuit_mode,
69 verify_legacy_zklogin_address,
70 accept_zklogin_in_multisig,
71 accept_passkey_in_multisig,
72 accept_mldsa65_in_multisig: false,
73 zklogin_max_epoch_upper_bound_delta,
74 additional_multisig_checks,
75 validate_zklogin_public_identifier,
76 }
77 }
78
79 pub fn with_mldsa65_in_multisig(mut self, accept: bool) -> Self {
84 self.accept_mldsa65_in_multisig = accept;
85 self
86 }
87}
88
89#[enum_dispatch]
91pub trait AuthenticatorTrait {
92 fn verify_user_authenticator_epoch(
93 &self,
94 epoch: EpochId,
95 max_epoch_upper_bound_delta: Option<u64>,
96 ) -> SuiResult;
97
98 fn verify_claims<T>(
99 &self,
100 value: &IntentMessage<T>,
101 author: SuiAddress,
102 aux_verify_data: &VerifyParams,
103 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
104 ) -> SuiResult
105 where
106 T: Serialize;
107}
108
109#[enum_dispatch(AuthenticatorTrait)]
114#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Hash)]
115pub enum GenericSignature {
116 MultiSig,
117 MultiSigLegacy,
118 Signature,
119 ZkLoginAuthenticator,
120 PasskeyAuthenticator,
121}
122
123impl GenericSignature {
124 pub fn is_zklogin(&self) -> bool {
125 matches!(self, GenericSignature::ZkLoginAuthenticator(_))
126 }
127 pub fn is_passkey(&self) -> bool {
128 matches!(self, GenericSignature::PasskeyAuthenticator(_))
129 }
130
131 pub fn is_mldsa65(&self) -> bool {
132 matches!(self, GenericSignature::Signature(s) if s.scheme() == SignatureScheme::MLDSA65)
133 }
134
135 pub fn is_upgraded_multisig(&self) -> bool {
136 matches!(self, GenericSignature::MultiSig(_))
137 }
138
139 pub fn verify_authenticator<T>(
140 &self,
141 value: &IntentMessage<T>,
142 author: SuiAddress,
143 epoch: EpochId,
144 verify_params: &VerifyParams,
145 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
146 ) -> SuiResult
147 where
148 T: Serialize,
149 {
150 self.verify_user_authenticator_epoch(
151 epoch,
152 verify_params.zklogin_max_epoch_upper_bound_delta,
153 )?;
154 self.verify_claims(value, author, verify_params, zklogin_inputs_cache)
155 }
156
157 pub fn to_compressed(&self) -> Result<CompressedSignature, SuiError> {
160 match self {
161 GenericSignature::Signature(s) => {
162 let bytes = s.signature_bytes();
163 match s.scheme() {
164 SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519(
165 (&Ed25519Signature::from_bytes(bytes).map_err(|_| {
166 SuiErrorKind::InvalidSignature {
167 error: "Cannot parse ed25519 sig".to_string(),
168 }
169 })?)
170 .into(),
171 )),
172 SignatureScheme::Secp256k1 => Ok(CompressedSignature::Secp256k1(
173 (&Secp256k1Signature::from_bytes(bytes).map_err(|_| {
174 SuiErrorKind::InvalidSignature {
175 error: "Cannot parse secp256k1 sig".to_string(),
176 }
177 })?)
178 .into(),
179 )),
180 SignatureScheme::MLDSA65 => Ok(CompressedSignature::MLDSA65(Box::new(
181 (&MLDSA65Signature::from_bytes(bytes).map_err(|_| {
182 SuiErrorKind::InvalidSignature {
183 error: "Cannot parse mldsa65 sig".to_string(),
184 }
185 })?)
186 .into(),
187 ))),
188 SignatureScheme::Secp256r1 | SignatureScheme::PasskeyAuthenticator => {
189 Ok(CompressedSignature::Secp256r1(
190 (&Secp256r1Signature::from_bytes(bytes).map_err(|_| {
191 SuiErrorKind::InvalidSignature {
192 error: "Cannot parse secp256r1 sig".to_string(),
193 }
194 })?)
195 .into(),
196 ))
197 }
198
199 _ => Err(SuiErrorKind::UnsupportedFeatureError {
200 error: "Unsupported signature scheme".to_string(),
201 }
202 .into()),
203 }
204 }
205 GenericSignature::ZkLoginAuthenticator(s) => Ok(CompressedSignature::ZkLogin(
206 ZkLoginAuthenticatorAsBytes(s.as_ref().to_vec()),
207 )),
208 GenericSignature::PasskeyAuthenticator(s) => Ok(CompressedSignature::Passkey(
209 PasskeyAuthenticatorAsBytes(s.as_ref().to_vec()),
210 )),
211 _ => Err(SuiErrorKind::UnsupportedFeatureError {
212 error: "Unsupported signature scheme".to_string(),
213 }
214 .into()),
215 }
216 }
217
218 pub fn to_public_key(&self) -> Result<PublicKey, SuiError> {
221 match self {
222 GenericSignature::Signature(s) => {
223 let bytes = s.public_key_bytes();
224 match s.scheme() {
225 SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
226 (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| {
227 SuiErrorKind::KeyConversionError("Cannot parse ed25519 pk".to_string())
228 })?)
229 .into(),
230 )),
231 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
232 (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| {
233 SuiErrorKind::KeyConversionError(
234 "Cannot parse secp256k1 pk".to_string(),
235 )
236 })?)
237 .into(),
238 )),
239 SignatureScheme::MLDSA65 => Ok(PublicKey::MLDSA65(Box::new(
240 (&MLDSA65PublicKey::from_bytes(bytes).map_err(|_| {
241 SuiErrorKind::KeyConversionError("Cannot parse mldsa65 pk".to_string())
242 })?)
243 .into(),
244 ))),
245 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
246 (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| {
247 SuiErrorKind::KeyConversionError(
248 "Cannot parse secp256r1 pk".to_string(),
249 )
250 })?)
251 .into(),
252 )),
253 _ => Err(SuiErrorKind::UnsupportedFeatureError {
254 error: "Unsupported signature scheme in MultiSig".to_string(),
255 }
256 .into()),
257 }
258 }
259 GenericSignature::ZkLoginAuthenticator(s) => s.get_pk(),
260 GenericSignature::PasskeyAuthenticator(s) => s.get_pk(),
261 _ => Err(SuiErrorKind::UnsupportedFeatureError {
262 error: "Unsupported signature scheme".to_string(),
263 }
264 .into()),
265 }
266 }
267}
268
269impl ToFromBytes for GenericSignature {
275 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
276 match SignatureScheme::from_flag_byte(
277 bytes.first().ok_or(FastCryptoError::InputTooShort(0))?,
278 ) {
279 Ok(x) => match x {
280 SignatureScheme::ED25519
281 | SignatureScheme::Secp256k1
282 | SignatureScheme::Secp256r1
283 | SignatureScheme::MLDSA65 => Ok(GenericSignature::Signature(
284 Signature::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
285 )),
286 SignatureScheme::MultiSig => match MultiSig::from_bytes(bytes) {
287 Ok(multisig) => Ok(GenericSignature::MultiSig(multisig)),
288 Err(_) => {
289 let multisig = MultiSigLegacy::from_bytes(bytes)?;
290 Ok(GenericSignature::MultiSigLegacy(multisig))
291 }
292 },
293 SignatureScheme::ZkLoginAuthenticator => {
294 let zk_login = ZkLoginAuthenticator::from_bytes(bytes)?;
295 Ok(GenericSignature::ZkLoginAuthenticator(zk_login))
296 }
297 SignatureScheme::PasskeyAuthenticator => {
298 let passkey = PasskeyAuthenticator::from_bytes(bytes)?;
299 Ok(GenericSignature::PasskeyAuthenticator(passkey))
300 }
301 _ => Err(FastCryptoError::InvalidInput),
302 },
303 Err(_) => Err(FastCryptoError::InvalidInput),
304 }
305 }
306}
307
308impl AsRef<[u8]> for GenericSignature {
310 fn as_ref(&self) -> &[u8] {
311 match self {
312 GenericSignature::MultiSig(s) => s.as_ref(),
313 GenericSignature::MultiSigLegacy(s) => s.as_ref(),
314 GenericSignature::Signature(s) => s.as_ref(),
315 GenericSignature::ZkLoginAuthenticator(s) => s.as_ref(),
316 GenericSignature::PasskeyAuthenticator(s) => s.as_ref(),
317 }
318 }
319}
320
321impl ::serde::Serialize for GenericSignature {
322 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
323 if serializer.is_human_readable() {
324 #[derive(serde::Serialize)]
325 struct GenericSignature(String);
326 GenericSignature(self.encode_base64()).serialize(serializer)
327 } else {
328 #[derive(serde::Serialize)]
329 struct GenericSignature<'a>(&'a [u8]);
330 GenericSignature(self.as_ref()).serialize(serializer)
331 }
332 }
333}
334
335impl<'de> ::serde::Deserialize<'de> for GenericSignature {
336 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
337 use serde::de::Error;
338
339 if deserializer.is_human_readable() {
340 #[derive(serde::Deserialize)]
341 struct GenericSignature(String);
342 let s = GenericSignature::deserialize(deserializer)?;
343 Self::decode_base64(&s.0).map_err(::serde::de::Error::custom)
344 } else {
345 #[derive(serde::Deserialize)]
346 struct GenericSignature(Vec<u8>);
347
348 let data = GenericSignature::deserialize(deserializer)?;
349 Self::from_bytes(&data.0).map_err(|e| Error::custom(e.to_string()))
350 }
351 }
352}
353
354impl AuthenticatorTrait for Signature {
356 fn verify_user_authenticator_epoch(&self, _: EpochId, _: Option<EpochId>) -> SuiResult {
357 Ok(())
358 }
359
360 fn verify_claims<T>(
361 &self,
362 value: &IntentMessage<T>,
363 author: SuiAddress,
364 _aux_verify_data: &VerifyParams,
365 _zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
366 ) -> SuiResult
367 where
368 T: Serialize,
369 {
370 self.verify_secure(value, author, self.scheme())
371 }
372}