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