1use std::hash::Hash;
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 iota_sdk_types::crypto::IntentMessage;
16use schemars::JsonSchema;
17use serde::Serialize;
18use tracing::instrument;
19
20use crate::{
21 base_types::IotaAddress,
22 crypto::{
23 CompressedSignature, IotaSignature, PasskeyAuthenticatorAsBytes, PublicKey, Signature,
24 SignatureScheme,
25 },
26 error::{IotaError, IotaResult},
27 move_authenticator::{MoveAuthenticator, MoveAuthenticatorInner, MoveAuthenticatorV1},
28 multisig::MultiSig,
29 passkey_authenticator::PasskeyAuthenticator,
30};
31#[derive(Default, Debug, Clone)]
32pub struct VerifyParams {
33 pub accept_passkey_in_multisig: bool,
34 pub additional_multisig_checks: bool,
35}
36
37impl VerifyParams {
38 pub fn new(accept_passkey_in_multisig: bool, additional_multisig_checks: bool) -> Self {
39 Self {
40 accept_passkey_in_multisig,
41 additional_multisig_checks,
42 }
43 }
44}
45
46#[enum_dispatch]
48pub trait AuthenticatorTrait {
49 fn verify_claims<T>(
50 &self,
51 value: &IntentMessage<T>,
52 author: IotaAddress,
53 aux_verify_data: &VerifyParams,
54 ) -> IotaResult
55 where
56 T: Serialize;
57}
58
59#[iota_proc_macros::allow_deprecated_for_derives]
63#[deprecated(note = "zkLogin is deprecated and was never enabled on IOTA")]
64#[derive(Debug, Clone, PartialEq, Eq, Hash, JsonSchema)]
65pub struct ZkLoginAuthenticatorDeprecated;
66
67#[allow(deprecated)]
68impl AuthenticatorTrait for ZkLoginAuthenticatorDeprecated {
69 fn verify_claims<T>(
70 &self,
71 _value: &IntentMessage<T>,
72 _author: IotaAddress,
73 _aux_verify_data: &VerifyParams,
74 ) -> IotaResult
75 where
76 T: Serialize,
77 {
78 Err(IotaError::UnsupportedFeature {
79 error: "zkLogin is not supported".to_string(),
80 })
81 }
82}
83
84#[allow(deprecated)]
85impl AsRef<[u8]> for ZkLoginAuthenticatorDeprecated {
86 fn as_ref(&self) -> &[u8] {
87 &[]
88 }
89}
90
91#[iota_proc_macros::allow_deprecated_for_derives]
97#[enum_dispatch(AuthenticatorTrait)]
98#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Hash)]
99#[allow(clippy::large_enum_variant)]
100pub enum GenericSignature {
101 MultiSig,
102 Signature,
103 #[deprecated(note = "zkLogin is deprecated and was never enabled on IOTA")]
104 ZkLoginAuthenticatorDeprecated,
105 PasskeyAuthenticator,
106 MoveAuthenticator,
107}
108
109impl GenericSignature {
110 pub fn is_passkey(&self) -> bool {
111 matches!(self, GenericSignature::PasskeyAuthenticator(_))
112 }
113
114 pub fn is_upgraded_multisig(&self) -> bool {
115 matches!(self, GenericSignature::MultiSig(_))
116 }
117
118 pub fn is_move_authenticator(&self) -> bool {
119 matches!(self, GenericSignature::MoveAuthenticator(_))
120 }
121
122 pub fn verify_authenticator<T>(
123 &self,
124 value: &IntentMessage<T>,
125 author: IotaAddress,
126 verify_params: &VerifyParams,
127 ) -> IotaResult
128 where
129 T: Serialize,
130 {
131 self.verify_claims(value, author, verify_params)
132 }
133
134 pub fn to_compressed(&self) -> Result<CompressedSignature, IotaError> {
138 match self {
139 GenericSignature::Signature(s) => {
140 let bytes = s.signature_bytes();
141 match s.scheme() {
142 SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519(
143 (&Ed25519Signature::from_bytes(bytes).map_err(|_| {
144 IotaError::InvalidSignature {
145 error: "Cannot parse ed25519 sig".to_string(),
146 }
147 })?)
148 .into(),
149 )),
150 SignatureScheme::Secp256k1 => Ok(CompressedSignature::Secp256k1(
151 (&Secp256k1Signature::from_bytes(bytes).map_err(|_| {
152 IotaError::InvalidSignature {
153 error: "Cannot parse secp256k1 sig".to_string(),
154 }
155 })?)
156 .into(),
157 )),
158 SignatureScheme::Secp256r1 | SignatureScheme::PasskeyAuthenticator => {
159 Ok(CompressedSignature::Secp256r1(
160 (&Secp256r1Signature::from_bytes(bytes).map_err(|_| {
161 IotaError::InvalidSignature {
162 error: "Cannot parse secp256r1 sig".to_string(),
163 }
164 })?)
165 .into(),
166 ))
167 }
168 _ => Err(IotaError::UnsupportedFeature {
169 error: "Unsupported signature scheme".to_string(),
170 }),
171 }
172 }
173 #[allow(deprecated)]
174 GenericSignature::ZkLoginAuthenticatorDeprecated(_) => {
175 Err(IotaError::UnsupportedFeature {
176 error: "zkLogin is not supported".to_string(),
177 })
178 }
179 GenericSignature::PasskeyAuthenticator(s) => Ok(CompressedSignature::Passkey(
180 PasskeyAuthenticatorAsBytes(s.as_ref().to_vec()),
181 )),
182 _ => Err(IotaError::UnsupportedFeature {
183 error: "Unsupported signature scheme".to_string(),
184 }),
185 }
186 }
187
188 pub fn to_public_key(&self) -> Result<PublicKey, IotaError> {
192 match self {
193 GenericSignature::Signature(s) => {
194 let bytes = s.public_key_bytes();
195 match s.scheme() {
196 SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
197 (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| {
198 IotaError::KeyConversion("Cannot parse ed25519 pk".to_string())
199 })?)
200 .into(),
201 )),
202 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
203 (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| {
204 IotaError::KeyConversion("Cannot parse secp256k1 pk".to_string())
205 })?)
206 .into(),
207 )),
208 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
209 (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| {
210 IotaError::KeyConversion("Cannot parse secp256r1 pk".to_string())
211 })?)
212 .into(),
213 )),
214 _ => Err(IotaError::UnsupportedFeature {
215 error: "Unsupported signature scheme in MultiSig".to_string(),
216 }),
217 }
218 }
219 #[allow(deprecated)]
220 GenericSignature::ZkLoginAuthenticatorDeprecated(_) => {
221 Err(IotaError::UnsupportedFeature {
222 error: "zkLogin is not supported".to_string(),
223 })
224 }
225 GenericSignature::PasskeyAuthenticator(s) => s.get_pk(),
226 GenericSignature::MoveAuthenticator(_) => Err(IotaError::UnsupportedFeature {
227 error: "Unsupported in MoveAuthenticator".to_string(),
228 }),
229 _ => Err(IotaError::UnsupportedFeature {
230 error: "Unsupported signature scheme".to_string(),
231 }),
232 }
233 }
234}
235
236impl ToFromBytes for GenericSignature {
241 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
242 match SignatureScheme::from_flag_byte(
243 bytes.first().ok_or(FastCryptoError::InputTooShort(0))?,
244 ) {
245 Ok(x) => match x {
246 SignatureScheme::ED25519
247 | SignatureScheme::Secp256k1
248 | SignatureScheme::Secp256r1 => Ok(GenericSignature::Signature(
249 Signature::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
250 )),
251 SignatureScheme::MultiSig => {
252 Ok(GenericSignature::MultiSig(MultiSig::from_bytes(bytes)?))
253 }
254 #[allow(deprecated)]
255 SignatureScheme::ZkLoginAuthenticatorDeprecated => {
256 Err(FastCryptoError::GeneralError(
259 "zkLogin is not supported".to_string(),
260 ))
261 }
262 SignatureScheme::PasskeyAuthenticator => {
263 let passkey = PasskeyAuthenticator::from_bytes(bytes)?;
264 Ok(GenericSignature::PasskeyAuthenticator(passkey))
265 }
266 SignatureScheme::MoveAuthenticator => {
267 let move_auth = MoveAuthenticator::from_bytes(bytes)?;
268 Ok(GenericSignature::MoveAuthenticator(move_auth))
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::Signature(s) => s.as_ref(),
283 #[allow(deprecated)]
284 GenericSignature::ZkLoginAuthenticatorDeprecated(s) => s.as_ref(),
285 GenericSignature::PasskeyAuthenticator(s) => s.as_ref(),
286 GenericSignature::MoveAuthenticator(s) => s.as_ref(),
287 }
288 }
289}
290
291impl ::serde::Serialize for GenericSignature {
292 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
293 if serializer.is_human_readable() {
294 #[derive(serde::Serialize)]
295 struct GenericSignature(String);
296 GenericSignature(self.encode_base64()).serialize(serializer)
297 } else {
298 #[derive(serde::Serialize)]
299 struct GenericSignature<'a>(&'a [u8]);
300 GenericSignature(self.as_ref()).serialize(serializer)
301 }
302 }
303}
304
305impl<'de> ::serde::Deserialize<'de> for GenericSignature {
306 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
307 use serde::de::Error;
308
309 if deserializer.is_human_readable() {
310 #[derive(serde::Deserialize)]
311 struct GenericSignature(String);
312 let s = GenericSignature::deserialize(deserializer)?;
313 Self::decode_base64(&s.0).map_err(::serde::de::Error::custom)
314 } else {
315 #[derive(serde::Deserialize)]
316 struct GenericSignature(Vec<u8>);
317
318 let data = GenericSignature::deserialize(deserializer)?;
319 Self::from_bytes(&data.0).map_err(|e| Error::custom(e.to_string()))
320 }
321 }
322}
323
324impl AuthenticatorTrait for Signature {
327 #[instrument(level = "trace", skip_all)]
328 fn verify_claims<T>(
329 &self,
330 value: &IntentMessage<T>,
331 author: IotaAddress,
332 _aux_verify_data: &VerifyParams,
333 ) -> IotaResult
334 where
335 T: Serialize,
336 {
337 self.verify_secure(value, author, self.scheme())
338 }
339}