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 serde::Serialize;
17use tracing::instrument;
18
19use crate::{
20 base_types::IotaAddress,
21 crypto::{
22 CompressedSignature, IotaSignature, PasskeyAuthenticatorAsBytes, PublicKey, Signature,
23 SignatureScheme,
24 },
25 error::{IotaError, IotaResult},
26 move_authenticator::{MoveAuthenticator, MoveAuthenticatorInner, MoveAuthenticatorV1},
27 multisig::MultiSig,
28 passkey_authenticator::PasskeyAuthenticator,
29};
30#[derive(Default, Debug, Clone)]
31pub struct VerifyParams {
32 pub accept_passkey_in_multisig: bool,
33 pub additional_multisig_checks: bool,
34}
35
36impl VerifyParams {
37 pub fn new(accept_passkey_in_multisig: bool, additional_multisig_checks: bool) -> Self {
38 Self {
39 accept_passkey_in_multisig,
40 additional_multisig_checks,
41 }
42 }
43}
44
45#[enum_dispatch]
47pub trait AuthenticatorTrait {
48 fn verify_claims<T>(
49 &self,
50 value: &IntentMessage<T>,
51 author: IotaAddress,
52 aux_verify_data: &VerifyParams,
53 ) -> IotaResult
54 where
55 T: Serialize;
56}
57
58#[iota_proc_macros::allow_deprecated_for_derives]
62#[deprecated(note = "zkLogin is deprecated and was never enabled on IOTA")]
63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
64pub struct ZkLoginAuthenticatorDeprecated;
65
66#[allow(deprecated)]
67impl AuthenticatorTrait for ZkLoginAuthenticatorDeprecated {
68 fn verify_claims<T>(
69 &self,
70 _value: &IntentMessage<T>,
71 _author: IotaAddress,
72 _aux_verify_data: &VerifyParams,
73 ) -> IotaResult
74 where
75 T: Serialize,
76 {
77 Err(IotaError::UnsupportedFeature {
78 error: "zkLogin is not supported".to_string(),
79 })
80 }
81}
82
83#[allow(deprecated)]
84impl AsRef<[u8]> for ZkLoginAuthenticatorDeprecated {
85 fn as_ref(&self) -> &[u8] {
86 &[]
87 }
88}
89
90#[iota_proc_macros::allow_deprecated_for_derives]
96#[enum_dispatch(AuthenticatorTrait)]
97#[derive(Debug, Clone, PartialEq, Eq, Hash)]
98#[allow(clippy::large_enum_variant)]
99pub enum GenericSignature {
100 MultiSig,
101 Signature,
102 #[deprecated(note = "zkLogin is deprecated and was never enabled on IOTA")]
103 ZkLoginAuthenticatorDeprecated,
104 PasskeyAuthenticator,
105 MoveAuthenticator,
106}
107
108impl GenericSignature {
109 pub fn is_passkey(&self) -> bool {
110 matches!(self, GenericSignature::PasskeyAuthenticator(_))
111 }
112
113 pub fn is_upgraded_multisig(&self) -> bool {
114 matches!(self, GenericSignature::MultiSig(_))
115 }
116
117 pub fn is_move_authenticator(&self) -> bool {
118 matches!(self, GenericSignature::MoveAuthenticator(_))
119 }
120
121 pub fn verify_authenticator<T>(
122 &self,
123 value: &IntentMessage<T>,
124 author: IotaAddress,
125 verify_params: &VerifyParams,
126 ) -> IotaResult
127 where
128 T: Serialize,
129 {
130 self.verify_claims(value, author, verify_params)
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 #[allow(deprecated)]
173 GenericSignature::ZkLoginAuthenticatorDeprecated(_) => {
174 Err(IotaError::UnsupportedFeature {
175 error: "zkLogin is not supported".to_string(),
176 })
177 }
178 GenericSignature::PasskeyAuthenticator(s) => Ok(CompressedSignature::Passkey(
179 PasskeyAuthenticatorAsBytes(s.as_ref().to_vec()),
180 )),
181 _ => Err(IotaError::UnsupportedFeature {
182 error: "Unsupported signature scheme".to_string(),
183 }),
184 }
185 }
186
187 pub fn to_public_key(&self) -> Result<PublicKey, IotaError> {
191 match self {
192 GenericSignature::Signature(s) => {
193 let bytes = s.public_key_bytes();
194 match s.scheme() {
195 SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
196 (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| {
197 IotaError::KeyConversion("Cannot parse ed25519 pk".to_string())
198 })?)
199 .into(),
200 )),
201 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
202 (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| {
203 IotaError::KeyConversion("Cannot parse secp256k1 pk".to_string())
204 })?)
205 .into(),
206 )),
207 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
208 (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| {
209 IotaError::KeyConversion("Cannot parse secp256r1 pk".to_string())
210 })?)
211 .into(),
212 )),
213 _ => Err(IotaError::UnsupportedFeature {
214 error: "Unsupported signature scheme in MultiSig".to_string(),
215 }),
216 }
217 }
218 #[allow(deprecated)]
219 GenericSignature::ZkLoginAuthenticatorDeprecated(_) => {
220 Err(IotaError::UnsupportedFeature {
221 error: "zkLogin is not supported".to_string(),
222 })
223 }
224 GenericSignature::PasskeyAuthenticator(s) => s.get_pk(),
225 GenericSignature::MoveAuthenticator(_) => Err(IotaError::UnsupportedFeature {
226 error: "Unsupported in MoveAuthenticator".to_string(),
227 }),
228 _ => Err(IotaError::UnsupportedFeature {
229 error: "Unsupported signature scheme".to_string(),
230 }),
231 }
232 }
233}
234
235impl ToFromBytes for GenericSignature {
240 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
241 match SignatureScheme::from_flag_byte(
242 bytes.first().ok_or(FastCryptoError::InputTooShort(0))?,
243 ) {
244 Ok(x) => match x {
245 SignatureScheme::ED25519
246 | SignatureScheme::Secp256k1
247 | SignatureScheme::Secp256r1 => Ok(GenericSignature::Signature(
248 Signature::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
249 )),
250 SignatureScheme::MultiSig => {
251 Ok(GenericSignature::MultiSig(MultiSig::from_bytes(bytes)?))
252 }
253 #[allow(deprecated)]
254 SignatureScheme::ZkLoginAuthenticatorDeprecated => {
255 Err(FastCryptoError::GeneralError(
258 "zkLogin is not supported".to_string(),
259 ))
260 }
261 SignatureScheme::PasskeyAuthenticator => {
262 let passkey = PasskeyAuthenticator::from_bytes(bytes)?;
263 Ok(GenericSignature::PasskeyAuthenticator(passkey))
264 }
265 SignatureScheme::MoveAuthenticator => {
266 let move_auth = MoveAuthenticator::from_bytes(bytes)?;
267 Ok(GenericSignature::MoveAuthenticator(move_auth))
268 }
269 _ => Err(FastCryptoError::InvalidInput),
270 },
271 Err(_) => Err(FastCryptoError::InvalidInput),
272 }
273 }
274}
275
276impl AsRef<[u8]> for GenericSignature {
278 fn as_ref(&self) -> &[u8] {
279 match self {
280 GenericSignature::MultiSig(s) => s.as_ref(),
281 GenericSignature::Signature(s) => s.as_ref(),
282 #[allow(deprecated)]
283 GenericSignature::ZkLoginAuthenticatorDeprecated(s) => s.as_ref(),
284 GenericSignature::PasskeyAuthenticator(s) => s.as_ref(),
285 GenericSignature::MoveAuthenticator(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 {
326 #[instrument(level = "trace", skip_all)]
327 fn verify_claims<T>(
328 &self,
329 value: &IntentMessage<T>,
330 author: IotaAddress,
331 _aux_verify_data: &VerifyParams,
332 ) -> IotaResult
333 where
334 T: Serialize,
335 {
336 self.verify_secure(value, author, self.scheme())
337 }
338}