1use std::hash::Hash;
6
7pub use enum_dispatch::enum_dispatch;
8use fastcrypto::{
9 ed25519::{Ed25519PublicKey, Ed25519Signature},
10 encoding::{Base64, Encoding},
11 error::{FastCryptoError, FastCryptoResult},
12 secp256k1::{Secp256k1PublicKey, Secp256k1Signature},
13 secp256r1::{Secp256r1PublicKey, Secp256r1Signature},
14 traits::{EncodeDecodeBase64, ToFromBytes},
15};
16use iota_sdk_types::{Address, crypto::IntentMessage};
17use serde::Serialize;
18use tracing::instrument;
19
20use crate::{
21 crypto::{
22 CompressedSignature, IotaSignature, PasskeyAuthenticatorAsBytes, PublicKey, Signature,
23 SignatureScheme,
24 },
25 error::{IotaError, IotaResult},
26 move_authenticator::MoveAuthenticator,
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: Address,
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: Address,
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: Address,
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.to_bytes()),
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(passkey) => {
225 let pk = Secp256r1PublicKey::from_bytes(passkey.public_key().inner().as_ref())
226 .map_err(|e| {
227 IotaError::KeyConversion(format!("Cannot parse secp256r1 pk: {e}"))
228 })?;
229 Ok(PublicKey::Passkey((&pk).into()))
230 }
231 GenericSignature::MoveAuthenticator(_) => Err(IotaError::UnsupportedFeature {
232 error: "Unsupported in MoveAuthenticator".to_string(),
233 }),
234 _ => Err(IotaError::UnsupportedFeature {
235 error: "Unsupported signature scheme".to_string(),
236 }),
237 }
238 }
239
240 pub fn to_bytes(&self) -> Vec<u8> {
241 match self {
242 GenericSignature::MultiSig(s) => s.to_bytes(),
243 GenericSignature::Signature(s) => s.as_ref().to_vec(),
244 #[allow(deprecated)]
245 GenericSignature::ZkLoginAuthenticatorDeprecated(s) => s.as_ref().to_vec(),
246 GenericSignature::PasskeyAuthenticator(s) => s.to_bytes(),
247 GenericSignature::MoveAuthenticator(s) => s.to_bytes(),
248 }
249 }
250
251 pub fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
252 match SignatureScheme::from_flag_byte(
253 bytes.first().ok_or(FastCryptoError::InputTooShort(0))?,
254 ) {
255 Ok(x) => match x {
256 SignatureScheme::ED25519
257 | SignatureScheme::Secp256k1
258 | SignatureScheme::Secp256r1 => Ok(GenericSignature::Signature(
259 Signature::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
260 )),
261 SignatureScheme::MultiSig => Ok(GenericSignature::MultiSig(
262 MultiSig::from_bytes(bytes).map_err(|_| FastCryptoError::InvalidSignature)?,
263 )),
264 #[allow(deprecated)]
265 SignatureScheme::ZkLoginAuthenticatorDeprecated => {
266 Err(FastCryptoError::GeneralError(
269 "zkLogin is not supported".to_string(),
270 ))
271 }
272 SignatureScheme::PasskeyAuthenticator => {
273 let passkey = PasskeyAuthenticator::from_bytes(bytes)
274 .map_err(|e| FastCryptoError::GeneralError(e.to_string()))?;
275 Ok(GenericSignature::PasskeyAuthenticator(passkey))
276 }
277 SignatureScheme::MoveAuthenticator => {
278 let move_auth = MoveAuthenticator::from_bytes(bytes)
279 .map_err(|e| FastCryptoError::GeneralError(e.to_string()))?;
280 Ok(GenericSignature::MoveAuthenticator(move_auth))
281 }
282 _ => Err(FastCryptoError::InvalidInput),
283 },
284 Err(_) => Err(FastCryptoError::InvalidInput),
285 }
286 }
287}
288
289impl EncodeDecodeBase64 for GenericSignature {
290 fn encode_base64(&self) -> String {
291 Base64::encode(self.to_bytes())
292 }
293
294 fn decode_base64(value: &str) -> FastCryptoResult<Self> {
295 let bytes = Base64::decode(value)?;
296 Self::from_bytes(&bytes)
297 }
298}
299
300impl ::serde::Serialize for GenericSignature {
301 fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
302 if serializer.is_human_readable() {
303 #[derive(serde::Serialize)]
304 struct GenericSignature(String);
305 GenericSignature(self.encode_base64()).serialize(serializer)
306 } else {
307 #[derive(serde::Serialize)]
308 struct GenericSignature<'a>(&'a [u8]);
309 GenericSignature(self.to_bytes().as_ref()).serialize(serializer)
310 }
311 }
312}
313
314impl<'de> ::serde::Deserialize<'de> for GenericSignature {
315 fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
316 use serde::de::Error;
317
318 if deserializer.is_human_readable() {
319 #[derive(serde::Deserialize)]
320 struct GenericSignature(String);
321 let s = GenericSignature::deserialize(deserializer)?;
322 Self::decode_base64(&s.0).map_err(::serde::de::Error::custom)
323 } else {
324 #[derive(serde::Deserialize)]
325 struct GenericSignature(Vec<u8>);
326
327 let data = GenericSignature::deserialize(deserializer)?;
328 Self::from_bytes(&data.0).map_err(|e| Error::custom(e.to_string()))
329 }
330 }
331}
332
333impl AuthenticatorTrait for Signature {
336 #[instrument(level = "trace", skip_all)]
337 fn verify_claims<T>(
338 &self,
339 value: &IntentMessage<T>,
340 author: Address,
341 _aux_verify_data: &VerifyParams,
342 ) -> IotaResult
343 where
344 T: Serialize,
345 {
346 self.verify_secure(value, author, self.scheme())
347 }
348}