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