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 pub additional_multisig_checks: bool,
47}
48
49impl VerifyParams {
50 pub fn new(
51 oidc_provider_jwks: ImHashMap<JwkId, JWK>,
52 zk_login_env: ZkLoginEnv,
53 accept_zklogin_in_multisig: bool,
54 accept_passkey_in_multisig: bool,
55 zklogin_max_epoch_upper_bound_delta: Option<u64>,
56 additional_multisig_checks: bool,
57 ) -> Self {
58 Self {
59 oidc_provider_jwks,
60 zk_login_env,
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 ) -> IotaResult;
77
78 fn verify_claims<T>(
79 &self,
80 value: &IntentMessage<T>,
81 author: IotaAddress,
82 aux_verify_data: &VerifyParams,
83 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
84 ) -> IotaResult
85 where
86 T: Serialize;
87}
88
89#[enum_dispatch(AuthenticatorTrait)]
95#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Hash)]
96pub enum GenericSignature {
97 MultiSig,
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: IotaAddress,
119 epoch: EpochId,
120 verify_params: &VerifyParams,
121 zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
122 ) -> IotaResult
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, IotaError> {
137 match self {
138 GenericSignature::Signature(s) => {
139 let bytes = s.signature_bytes();
140 match s.scheme() {
141 SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519(
142 (&Ed25519Signature::from_bytes(bytes).map_err(|_| {
143 IotaError::InvalidSignature {
144 error: "Cannot parse ed25519 sig".to_string(),
145 }
146 })?)
147 .into(),
148 )),
149 SignatureScheme::Secp256k1 => Ok(CompressedSignature::Secp256k1(
150 (&Secp256k1Signature::from_bytes(bytes).map_err(|_| {
151 IotaError::InvalidSignature {
152 error: "Cannot parse secp256k1 sig".to_string(),
153 }
154 })?)
155 .into(),
156 )),
157 SignatureScheme::Secp256r1 | SignatureScheme::PasskeyAuthenticator => {
158 Ok(CompressedSignature::Secp256r1(
159 (&Secp256r1Signature::from_bytes(bytes).map_err(|_| {
160 IotaError::InvalidSignature {
161 error: "Cannot parse secp256r1 sig".to_string(),
162 }
163 })?)
164 .into(),
165 ))
166 }
167 _ => Err(IotaError::UnsupportedFeature {
168 error: "Unsupported signature scheme".to_string(),
169 }),
170 }
171 }
172 GenericSignature::ZkLoginAuthenticator(s) => Ok(CompressedSignature::ZkLogin(
173 ZkLoginAuthenticatorAsBytes(s.as_ref().to_vec()),
174 )),
175 GenericSignature::PasskeyAuthenticator(s) => Ok(CompressedSignature::Passkey(
176 PasskeyAuthenticatorAsBytes(s.as_ref().to_vec()),
177 )),
178 _ => Err(IotaError::UnsupportedFeature {
179 error: "Unsupported signature scheme".to_string(),
180 }),
181 }
182 }
183
184 pub fn to_public_key(&self) -> Result<PublicKey, IotaError> {
188 match self {
189 GenericSignature::Signature(s) => {
190 let bytes = s.public_key_bytes();
191 match s.scheme() {
192 SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
193 (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| {
194 IotaError::KeyConversion("Cannot parse ed25519 pk".to_string())
195 })?)
196 .into(),
197 )),
198 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
199 (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| {
200 IotaError::KeyConversion("Cannot parse secp256k1 pk".to_string())
201 })?)
202 .into(),
203 )),
204 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
205 (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| {
206 IotaError::KeyConversion("Cannot parse secp256r1 pk".to_string())
207 })?)
208 .into(),
209 )),
210 _ => Err(IotaError::UnsupportedFeature {
211 error: "Unsupported signature scheme in MultiSig".to_string(),
212 }),
213 }
214 }
215 GenericSignature::ZkLoginAuthenticator(s) => s.get_pk(),
216 GenericSignature::PasskeyAuthenticator(s) => s.get_pk(),
217 _ => Err(IotaError::UnsupportedFeature {
218 error: "Unsupported signature scheme".to_string(),
219 }),
220 }
221 }
222}
223
224impl ToFromBytes for GenericSignature {
229 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
230 match SignatureScheme::from_flag_byte(
231 bytes.first().ok_or(FastCryptoError::InputTooShort(0))?,
232 ) {
233 Ok(x) => match x {
234 SignatureScheme::ED25519
235 | SignatureScheme::Secp256k1
236 | SignatureScheme::Secp256r1 => Ok(GenericSignature::Signature(
237 Signature::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
238 )),
239 SignatureScheme::MultiSig => {
240 Ok(GenericSignature::MultiSig(MultiSig::from_bytes(bytes)?))
241 }
242 SignatureScheme::ZkLoginAuthenticator => {
243 let zk_login = ZkLoginAuthenticator::from_bytes(bytes)?;
244 Ok(GenericSignature::ZkLoginAuthenticator(zk_login))
245 }
246 SignatureScheme::PasskeyAuthenticator => {
247 let passkey = PasskeyAuthenticator::from_bytes(bytes)?;
248 Ok(GenericSignature::PasskeyAuthenticator(passkey))
249 }
250 _ => Err(FastCryptoError::InvalidInput),
251 },
252 Err(_) => Err(FastCryptoError::InvalidInput),
253 }
254 }
255}
256
257impl AsRef<[u8]> for GenericSignature {
259 fn as_ref(&self) -> &[u8] {
260 match self {
261 GenericSignature::MultiSig(s) => s.as_ref(),
262 GenericSignature::Signature(s) => s.as_ref(),
263 GenericSignature::ZkLoginAuthenticator(s) => s.as_ref(),
264 GenericSignature::PasskeyAuthenticator(s) => s.as_ref(),
265 }
266 }
267}
268
269impl ::serde::Serialize for GenericSignature {
270 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
271 if serializer.is_human_readable() {
272 #[derive(serde::Serialize)]
273 struct GenericSignature(String);
274 GenericSignature(self.encode_base64()).serialize(serializer)
275 } else {
276 #[derive(serde::Serialize)]
277 struct GenericSignature<'a>(&'a [u8]);
278 GenericSignature(self.as_ref()).serialize(serializer)
279 }
280 }
281}
282
283impl<'de> ::serde::Deserialize<'de> for GenericSignature {
284 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
285 use serde::de::Error;
286
287 if deserializer.is_human_readable() {
288 #[derive(serde::Deserialize)]
289 struct GenericSignature(String);
290 let s = GenericSignature::deserialize(deserializer)?;
291 Self::decode_base64(&s.0).map_err(::serde::de::Error::custom)
292 } else {
293 #[derive(serde::Deserialize)]
294 struct GenericSignature(Vec<u8>);
295
296 let data = GenericSignature::deserialize(deserializer)?;
297 Self::from_bytes(&data.0).map_err(|e| Error::custom(e.to_string()))
298 }
299 }
300}
301
302impl AuthenticatorTrait for Signature {
305 fn verify_user_authenticator_epoch(&self, _: EpochId, _: Option<EpochId>) -> IotaResult {
306 Ok(())
307 }
308
309 fn verify_claims<T>(
310 &self,
311 value: &IntentMessage<T>,
312 author: IotaAddress,
313 _aux_verify_data: &VerifyParams,
314 _zklogin_inputs_cache: Arc<VerifiedDigestCache<ZKLoginInputsDigest>>,
315 ) -> IotaResult
316 where
317 T: Serialize,
318 {
319 self.verify_secure(value, author, self.scheme())
320 }
321}