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