af_keys/
crypto.rs

1use std::hash::Hash;
2
3use af_sui_types::Address as SuiAddress;
4use derive_more::{AsMut, AsRef};
5use enum_dispatch::enum_dispatch;
6use eyre::eyre;
7use fastcrypto::ed25519::{
8    Ed25519KeyPair,
9    Ed25519PublicKey,
10    Ed25519PublicKeyAsBytes,
11    Ed25519Signature,
12    Ed25519SignatureAsBytes,
13};
14use fastcrypto::encoding::{Base64 as Base64Wrapper, Bech32, Encoding as _};
15use fastcrypto::error::FastCryptoError;
16use fastcrypto::hash::{Blake2b256, HashFunction as _};
17use fastcrypto::secp256k1::{
18    Secp256k1KeyPair,
19    Secp256k1PublicKey,
20    Secp256k1PublicKeyAsBytes,
21    Secp256k1Signature,
22    Secp256k1SignatureAsBytes,
23};
24use fastcrypto::secp256r1::{
25    Secp256r1KeyPair,
26    Secp256r1PublicKey,
27    Secp256r1PublicKeyAsBytes,
28    Secp256r1Signature,
29    Secp256r1SignatureAsBytes,
30};
31use fastcrypto::traits::{
32    Authenticator,
33    EncodeDecodeBase64,
34    KeyPair as KeypairTraits,
35    Signer,
36    ToFromBytes,
37    VerifyingKey,
38};
39use serde::{Deserialize, Deserializer, Serialize, Serializer};
40use serde_with::base64::Base64;
41use serde_with::{Bytes, IfIsHumanReadable, serde_as};
42use strum::EnumString;
43
44use crate::intent::IntentMessage;
45
46pub type DefaultHash = Blake2b256;
47
48pub const SUI_PRIV_KEY_PREFIX: &str = "suiprivkey";
49
50/// Custom cryptography errors.
51#[derive(
52    Eq,
53    PartialEq,
54    Clone,
55    Debug,
56    Serialize,
57    Deserialize,
58    thiserror::Error,
59    Hash,
60    strum::AsRefStr,
61    strum::IntoStaticStr,
62)]
63pub enum Error {
64    #[error("Signature key generation error: {0}")]
65    SignatureKeyGenError(String),
66    #[error("Key Conversion Error: {0}")]
67    KeyConversionError(String),
68    #[error("Invalid Private Key provided")]
69    InvalidPrivateKey,
70    #[error("Signature is not valid: {}", error)]
71    InvalidSignature { error: String },
72    #[error("Value was not signed by the correct sender: {}", error)]
73    IncorrectSigner { error: String },
74    #[error("Use of disabled feature: {:?}", error)]
75    UnsupportedFeatureError { error: String },
76}
77
78// =============================================================================
79//  CompressedSignature
80// =============================================================================
81
82/// Unlike [enum Signature], [enum CompressedSignature] does not contain public key.
83#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
84pub enum CompressedSignature {
85    Ed25519(Ed25519SignatureAsBytes),
86    Secp256k1(Secp256k1SignatureAsBytes),
87    Secp256r1(Secp256r1SignatureAsBytes),
88    ZkLogin(ZkLoginAuthenticatorAsBytes),
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
92pub struct ZkLoginAuthenticatorAsBytes(pub Vec<u8>);
93
94impl AsRef<[u8]> for CompressedSignature {
95    fn as_ref(&self) -> &[u8] {
96        match self {
97            Self::Ed25519(sig) => &sig.0,
98            Self::Secp256k1(sig) => &sig.0,
99            Self::Secp256r1(sig) => &sig.0,
100            Self::ZkLogin(sig) => &sig.0,
101        }
102    }
103}
104
105// =============================================================================
106//  PublicKey
107// =============================================================================
108
109#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
110pub enum PublicKey {
111    Ed25519(Ed25519PublicKeyAsBytes),
112    Secp256k1(Secp256k1PublicKeyAsBytes),
113    Secp256r1(Secp256r1PublicKeyAsBytes),
114    ZkLogin(ZkLoginPublicIdentifier),
115}
116
117impl AsRef<[u8]> for PublicKey {
118    fn as_ref(&self) -> &[u8] {
119        match self {
120            Self::Ed25519(pk) => &pk.0,
121            Self::Secp256k1(pk) => &pk.0,
122            Self::Secp256r1(pk) => &pk.0,
123            Self::ZkLogin(z) => &z.0,
124        }
125    }
126}
127
128impl EncodeDecodeBase64 for PublicKey {
129    fn encode_base64(&self) -> String {
130        let mut bytes: Vec<u8> = Vec::new();
131        bytes.extend_from_slice(&[self.flag()]);
132        bytes.extend_from_slice(self.as_ref());
133        Base64Wrapper::encode(&bytes[..])
134    }
135
136    fn decode_base64(value: &str) -> Result<Self, FastCryptoError> {
137        let bytes = Base64Wrapper::decode(value)?;
138        match bytes.first() {
139            Some(x) => {
140                if x == &SignatureScheme::ED25519.flag() {
141                    let pk: Ed25519PublicKey = Ed25519PublicKey::from_bytes(
142                        bytes
143                            .get(1..)
144                            .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
145                    )?;
146                    Ok(Self::Ed25519((&pk).into()))
147                } else if x == &SignatureScheme::Secp256k1.flag() {
148                    let pk = Secp256k1PublicKey::from_bytes(
149                        bytes
150                            .get(1..)
151                            .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
152                    )?;
153                    Ok(Self::Secp256k1((&pk).into()))
154                } else if x == &SignatureScheme::Secp256r1.flag() {
155                    let pk = Secp256r1PublicKey::from_bytes(
156                        bytes
157                            .get(1..)
158                            .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
159                    )?;
160                    Ok(Self::Secp256r1((&pk).into()))
161                } else {
162                    Err(FastCryptoError::GeneralError(
163                        "Invalid flag byte".to_string(),
164                    ))
165                }
166            }
167            _ => Err(FastCryptoError::InvalidInput),
168        }
169    }
170}
171
172impl PublicKey {
173    /// Derive a [SuiAddress].
174    ///
175    /// Extension to the original trait since a generic [From] cannot be implemented here for
176    /// [SuiAddress].
177    pub fn to_sui_address(&self) -> SuiAddress {
178        let mut hasher = DefaultHash::default();
179        hasher.update([self.flag()]);
180        hasher.update(self);
181        let g_arr = hasher.finalize();
182        SuiAddress::new(g_arr.digest)
183    }
184
185    pub const fn flag(&self) -> u8 {
186        self.scheme().flag()
187    }
188
189    pub fn try_from_bytes(curve: SignatureScheme, key_bytes: &[u8]) -> Result<Self, eyre::Report> {
190        match curve {
191            SignatureScheme::ED25519 => Ok(Self::Ed25519(
192                (&Ed25519PublicKey::from_bytes(key_bytes)?).into(),
193            )),
194            SignatureScheme::Secp256k1 => Ok(Self::Secp256k1(
195                (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(),
196            )),
197            SignatureScheme::Secp256r1 => Ok(Self::Secp256r1(
198                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
199            )),
200            _ => Err(eyre!("Unsupported curve")),
201        }
202    }
203
204    pub const fn scheme(&self) -> SignatureScheme {
205        match self {
206            Self::Ed25519(_) => Ed25519SuiSignature::SCHEME,
207            Self::Secp256k1(_) => Secp256k1SuiSignature::SCHEME,
208            Self::Secp256r1(_) => Secp256r1SuiSignature::SCHEME,
209            Self::ZkLogin(_) => SignatureScheme::ZkLoginAuthenticator,
210        }
211    }
212}
213/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin.
214/// Useful to construct [struct MultiSigPublicKey].
215#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
216pub struct ZkLoginPublicIdentifier(pub Vec<u8>);
217
218// =============================================================================
219//  Signature
220// =============================================================================
221
222// Enums for signature scheme signatures
223#[enum_dispatch]
224#[derive(Clone, Debug, PartialEq, Eq, Hash)]
225pub enum Signature {
226    Ed25519SuiSignature,
227    Secp256k1SuiSignature,
228    Secp256r1SuiSignature,
229}
230
231impl Signature {
232    /// The messaged passed in is already hashed form.
233    pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer<Self>) -> Self {
234        Signer::sign(secret, hashed_msg)
235    }
236
237    pub fn new_secure<T>(value: &IntentMessage<T>, secret: &dyn Signer<Self>) -> Self
238    where
239        T: Serialize,
240    {
241        let mut hasher = DefaultHash::default();
242        hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
243        Signer::sign(secret, &hasher.finalize().digest)
244    }
245
246    pub fn to_compressed(&self) -> Result<CompressedSignature, Error> {
247        let bytes = self.signature_bytes();
248        match self.scheme() {
249            SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519(
250                (&Ed25519Signature::from_bytes(bytes).map_err(|_| Error::InvalidSignature {
251                    error: "Cannot parse ed25519 sig".to_string(),
252                })?)
253                    .into(),
254            )),
255            SignatureScheme::Secp256k1 => Ok(CompressedSignature::Secp256k1(
256                (&Secp256k1Signature::from_bytes(bytes).map_err(|_| Error::InvalidSignature {
257                    error: "Cannot parse secp256k1 sig".to_string(),
258                })?)
259                    .into(),
260            )),
261            SignatureScheme::Secp256r1 => Ok(CompressedSignature::Secp256r1(
262                (&Secp256r1Signature::from_bytes(bytes).map_err(|_| Error::InvalidSignature {
263                    error: "Cannot parse secp256r1 sig".to_string(),
264                })?)
265                    .into(),
266            )),
267            _ => Err(Error::UnsupportedFeatureError {
268                error: "Unsupported signature scheme".to_string(),
269            }),
270        }
271    }
272
273    pub fn to_public_key(&self) -> Result<PublicKey, Error> {
274        let bytes = self.public_key_bytes();
275        match self.scheme() {
276            SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
277                (&Ed25519PublicKey::from_bytes(bytes).map_err(|_| {
278                    Error::KeyConversionError("Cannot parse ed25519 pk".to_string())
279                })?)
280                    .into(),
281            )),
282            SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
283                (&Secp256k1PublicKey::from_bytes(bytes).map_err(|_| {
284                    Error::KeyConversionError("Cannot parse secp256k1 pk".to_string())
285                })?)
286                    .into(),
287            )),
288            SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
289                (&Secp256r1PublicKey::from_bytes(bytes).map_err(|_| {
290                    Error::KeyConversionError("Cannot parse secp256r1 pk".to_string())
291                })?)
292                    .into(),
293            )),
294            _ => Err(Error::UnsupportedFeatureError {
295                error: "Unsupported signature scheme in Signature".to_string(),
296            }),
297        }
298    }
299}
300
301impl Serialize for Signature {
302    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
303    where
304        S: Serializer,
305    {
306        let bytes = self.as_ref();
307
308        if serializer.is_human_readable() {
309            let s = Base64Wrapper::encode(bytes);
310            serializer.serialize_str(&s)
311        } else {
312            serializer.serialize_bytes(bytes)
313        }
314    }
315}
316
317impl<'de> Deserialize<'de> for Signature {
318    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
319    where
320        D: Deserializer<'de>,
321    {
322        use serde::de::Error;
323
324        let bytes = if deserializer.is_human_readable() {
325            let s = String::deserialize(deserializer)?;
326            Base64Wrapper::decode(&s).map_err(|e| Error::custom(e.to_string()))?
327        } else {
328            let data: Vec<u8> = Vec::deserialize(deserializer)?;
329            data
330        };
331
332        Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))
333    }
334}
335
336impl AsRef<[u8]> for Signature {
337    fn as_ref(&self) -> &[u8] {
338        match self {
339            Self::Ed25519SuiSignature(sig) => sig.as_ref(),
340            Self::Secp256k1SuiSignature(sig) => sig.as_ref(),
341            Self::Secp256r1SuiSignature(sig) => sig.as_ref(),
342        }
343    }
344}
345impl AsMut<[u8]> for Signature {
346    fn as_mut(&mut self) -> &mut [u8] {
347        match self {
348            Self::Ed25519SuiSignature(sig) => sig.as_mut(),
349            Self::Secp256k1SuiSignature(sig) => sig.as_mut(),
350            Self::Secp256r1SuiSignature(sig) => sig.as_mut(),
351        }
352    }
353}
354
355impl ToFromBytes for Signature {
356    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
357        match bytes.first() {
358            Some(x) => {
359                if x == &Ed25519SuiSignature::SCHEME.flag() {
360                    Ok(<Ed25519SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
361                } else if x == &Secp256k1SuiSignature::SCHEME.flag() {
362                    Ok(<Secp256k1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
363                } else if x == &Secp256r1SuiSignature::SCHEME.flag() {
364                    Ok(<Secp256r1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
365                } else {
366                    Err(FastCryptoError::InvalidInput)
367                }
368            }
369            _ => Err(FastCryptoError::InvalidInput),
370        }
371    }
372}
373
374impl From<Signature> for af_sui_types::UserSignature {
375    fn from(value: Signature) -> Self {
376        Self::from_bytes(value.as_bytes()).expect("Compatible")
377    }
378}
379
380// =============================================================================
381//  SignatureScheme
382// =============================================================================
383
384#[derive(Clone, Copy, Deserialize, Serialize, Debug, EnumString, strum::Display)]
385#[strum(serialize_all = "lowercase")]
386pub enum SignatureScheme {
387    ED25519,
388    Secp256k1,
389    Secp256r1,
390    BLS12381, // This is currently not supported for user Sui Address.
391    MultiSig,
392    ZkLoginAuthenticator,
393}
394
395impl SignatureScheme {
396    pub const fn flag(&self) -> u8 {
397        match self {
398            Self::ED25519 => 0x00,
399            Self::Secp256k1 => 0x01,
400            Self::Secp256r1 => 0x02,
401            Self::MultiSig => 0x03,
402            Self::BLS12381 => 0x04, // This is currently not supported for user Sui Address.
403            Self::ZkLoginAuthenticator => 0x05,
404        }
405    }
406
407    pub fn from_flag(flag: &str) -> Result<Self, Error> {
408        let byte_int = flag
409            .parse::<u8>()
410            .map_err(|_| Error::KeyConversionError("Invalid key scheme".to_string()))?;
411        Self::from_flag_byte(&byte_int)
412    }
413
414    pub fn from_flag_byte(byte_int: &u8) -> Result<Self, Error> {
415        match byte_int {
416            0x00 => Ok(Self::ED25519),
417            0x01 => Ok(Self::Secp256k1),
418            0x02 => Ok(Self::Secp256r1),
419            0x03 => Ok(Self::MultiSig),
420            0x04 => Ok(Self::BLS12381),
421            0x05 => Ok(Self::ZkLoginAuthenticator),
422            _ => Err(Error::KeyConversionError("Invalid key scheme".to_string())),
423        }
424    }
425}
426
427// =============================================================================
428//  SuiKeyPair
429// =============================================================================
430
431#[allow(clippy::large_enum_variant)]
432#[derive(Debug, derive_more::From, PartialEq, Eq)]
433pub enum SuiKeyPair {
434    Ed25519(Ed25519KeyPair),
435    Secp256k1(Secp256k1KeyPair),
436    Secp256r1(Secp256r1KeyPair),
437}
438
439impl SuiKeyPair {
440    pub fn public(&self) -> PublicKey {
441        match self {
442            Self::Ed25519(kp) => PublicKey::Ed25519(kp.public().into()),
443            Self::Secp256k1(kp) => PublicKey::Secp256k1(kp.public().into()),
444            Self::Secp256r1(kp) => PublicKey::Secp256r1(kp.public().into()),
445        }
446    }
447}
448
449impl Signer<Signature> for SuiKeyPair {
450    fn sign(&self, msg: &[u8]) -> Signature {
451        match self {
452            Self::Ed25519(kp) => kp.sign(msg),
453            Self::Secp256k1(kp) => kp.sign(msg),
454            Self::Secp256r1(kp) => kp.sign(msg),
455        }
456    }
457}
458
459impl EncodeDecodeBase64 for SuiKeyPair {
460    fn encode_base64(&self) -> String {
461        Base64Wrapper::encode(self.to_bytes())
462    }
463
464    fn decode_base64(value: &str) -> Result<Self, FastCryptoError> {
465        let bytes = Base64Wrapper::decode(value)?;
466        Self::from_bytes(&bytes)
467    }
468}
469impl SuiKeyPair {
470    pub fn to_bytes(&self) -> Vec<u8> {
471        let mut bytes: Vec<u8> = Vec::new();
472        bytes.push(self.public().flag());
473
474        match self {
475            Self::Ed25519(kp) => {
476                bytes.extend_from_slice(kp.as_bytes());
477            }
478            Self::Secp256k1(kp) => {
479                bytes.extend_from_slice(kp.as_bytes());
480            }
481            Self::Secp256r1(kp) => {
482                bytes.extend_from_slice(kp.as_bytes());
483            }
484        }
485        bytes
486    }
487
488    pub fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
489        match SignatureScheme::from_flag_byte(
490            bytes
491                .first()
492                .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
493        ) {
494            Ok(x) => match x {
495                SignatureScheme::ED25519 => Ok(Self::Ed25519(Ed25519KeyPair::from_bytes(
496                    bytes
497                        .get(1..)
498                        .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
499                )?)),
500                SignatureScheme::Secp256k1 => Ok(Self::Secp256k1(Secp256k1KeyPair::from_bytes(
501                    bytes
502                        .get(1..)
503                        .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
504                )?)),
505                SignatureScheme::Secp256r1 => Ok(Self::Secp256r1(Secp256r1KeyPair::from_bytes(
506                    bytes
507                        .get(1..)
508                        .ok_or(FastCryptoError::InputLengthWrong(bytes.len()))?,
509                )?)),
510                _ => Err(FastCryptoError::GeneralError(
511                    "Invalid flag byte".to_string(),
512                )),
513            },
514            _ => Err(FastCryptoError::InvalidInput),
515        }
516    }
517    /// Encode a SuiKeyPair as `flag || privkey` in Bech32 starting with "suiprivkey" to a string. Note that the pubkey is not encoded.
518    pub fn encode(&self) -> Result<String, FastCryptoError> {
519        Bech32::encode(self.to_bytes(), SUI_PRIV_KEY_PREFIX)
520    }
521
522    /// Decode a SuiKeyPair from `flag || privkey` in Bech32 starting with "suiprivkey" to SuiKeyPair. The public key is computed directly from the private key bytes.
523    pub fn decode(value: &str) -> Result<Self, FastCryptoError> {
524        let bytes = Bech32::decode(value, SUI_PRIV_KEY_PREFIX)?;
525        Self::from_bytes(&bytes)
526    }
527}
528
529impl Serialize for SuiKeyPair {
530    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
531    where
532        S: Serializer,
533    {
534        let s = self.encode_base64();
535        serializer.serialize_str(&s)
536    }
537}
538
539impl<'de> Deserialize<'de> for SuiKeyPair {
540    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
541    where
542        D: Deserializer<'de>,
543    {
544        use serde::de::Error;
545        let s = String::deserialize(deserializer)?;
546        Self::decode_base64(&s).map_err(|e| Error::custom(e.to_string()))
547    }
548}
549
550// =============================================================================
551//  Ed25519 Sui Signature port
552// =============================================================================
553
554#[serde_as]
555#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, AsRef, AsMut)]
556#[as_ref(forward)]
557#[as_mut(forward)]
558pub struct Ed25519SuiSignature(
559    #[serde_as(as = "IfIsHumanReadable<Base64, Bytes>")]
560    [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1],
561);
562
563// Implementation useful for simplify testing when mock signature is needed
564impl Default for Ed25519SuiSignature {
565    fn default() -> Self {
566        Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1])
567    }
568}
569
570impl SuiSignatureInner for Ed25519SuiSignature {
571    type Sig = Ed25519Signature;
572    type PubKey = Ed25519PublicKey;
573    type KeyPair = Ed25519KeyPair;
574    const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1;
575}
576
577impl SuiPublicKey for Ed25519PublicKey {
578    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519;
579}
580
581impl ToFromBytes for Ed25519SuiSignature {
582    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
583        if bytes.len() != Self::LENGTH {
584            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
585        }
586        let mut sig_bytes = [0; Self::LENGTH];
587        sig_bytes.copy_from_slice(bytes);
588        Ok(Self(sig_bytes))
589    }
590}
591
592impl Signer<Signature> for Ed25519KeyPair {
593    fn sign(&self, msg: &[u8]) -> Signature {
594        Ed25519SuiSignature::new(self, msg).into()
595    }
596}
597
598// =============================================================================
599//  Secp256k1 Sui Signature port
600// =============================================================================
601
602#[serde_as]
603#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, AsRef, AsMut)]
604#[as_ref(forward)]
605#[as_mut(forward)]
606pub struct Secp256k1SuiSignature(
607    #[serde_as(as = "IfIsHumanReadable<Base64, Bytes>")]
608    [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1],
609);
610
611impl SuiSignatureInner for Secp256k1SuiSignature {
612    type Sig = Secp256k1Signature;
613    type PubKey = Secp256k1PublicKey;
614    type KeyPair = Secp256k1KeyPair;
615    const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1;
616}
617
618impl SuiPublicKey for Secp256k1PublicKey {
619    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
620}
621
622impl ToFromBytes for Secp256k1SuiSignature {
623    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
624        if bytes.len() != Self::LENGTH {
625            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
626        }
627        let mut sig_bytes = [0; Self::LENGTH];
628        sig_bytes.copy_from_slice(bytes);
629        Ok(Self(sig_bytes))
630    }
631}
632
633impl Signer<Signature> for Secp256k1KeyPair {
634    fn sign(&self, msg: &[u8]) -> Signature {
635        Secp256k1SuiSignature::new(self, msg).into()
636    }
637}
638
639// =============================================================================
640// Secp256r1 Sui Signature port
641// =============================================================================
642
643#[serde_as]
644#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, AsRef, AsMut)]
645#[as_ref(forward)]
646#[as_mut(forward)]
647pub struct Secp256r1SuiSignature(
648    #[serde_as(as = "IfIsHumanReadable<Base64, Bytes>")]
649    [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1],
650);
651
652impl SuiSignatureInner for Secp256r1SuiSignature {
653    type Sig = Secp256r1Signature;
654    type PubKey = Secp256r1PublicKey;
655    type KeyPair = Secp256r1KeyPair;
656    const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1;
657}
658
659impl SuiPublicKey for Secp256r1PublicKey {
660    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
661}
662
663impl ToFromBytes for Secp256r1SuiSignature {
664    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
665        if bytes.len() != Self::LENGTH {
666            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
667        }
668        let mut sig_bytes = [0; Self::LENGTH];
669        sig_bytes.copy_from_slice(bytes);
670        Ok(Self(sig_bytes))
671    }
672}
673
674impl Signer<Signature> for Secp256r1KeyPair {
675    fn sign(&self, msg: &[u8]) -> Signature {
676        Secp256r1SuiSignature::new(self, msg).into()
677    }
678}
679
680// =============================================================================
681//  This struct exists due to the limitations of the `enum_dispatch` library.
682// =============================================================================
683
684pub trait SuiSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash {
685    type Sig: Authenticator<PubKey = Self::PubKey>;
686    type PubKey: VerifyingKey<Sig = Self::Sig> + SuiPublicKey;
687    type KeyPair: KeypairTraits<PubKey = Self::PubKey, Sig = Self::Sig>;
688
689    const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1;
690    const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME;
691
692    /// Returns the deserialized signature and deserialized pubkey.
693    fn get_verification_inputs(&self) -> Result<(Self::Sig, Self::PubKey), Error> {
694        let pk = Self::PubKey::from_bytes(self.public_key_bytes())
695            .map_err(|_| Error::KeyConversionError("Invalid public key".to_string()))?;
696
697        // deserialize the signature
698        let signature =
699            Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| Error::InvalidSignature {
700                error: "Fail to get pubkey and sig".to_string(),
701            })?;
702
703        Ok((signature, pk))
704    }
705
706    fn new(kp: &Self::KeyPair, message: &[u8]) -> Self {
707        let sig = Signer::sign(kp, message);
708
709        let mut signature_bytes: Vec<u8> = Vec::new();
710        signature_bytes
711            .extend_from_slice(&[<Self::PubKey as SuiPublicKey>::SIGNATURE_SCHEME.flag()]);
712        signature_bytes.extend_from_slice(sig.as_ref());
713        signature_bytes.extend_from_slice(kp.public().as_ref());
714        Self::from_bytes(&signature_bytes[..])
715            .expect("Serialized signature did not have expected size")
716    }
717}
718
719#[enum_dispatch(Signature)]
720pub trait SuiSignature: Sized + ToFromBytes {
721    fn signature_bytes(&self) -> &[u8];
722    fn public_key_bytes(&self) -> &[u8];
723    fn scheme(&self) -> SignatureScheme;
724
725    fn verify_secure<T>(
726        &self,
727        value: &IntentMessage<T>,
728        author: SuiAddress,
729        scheme: SignatureScheme,
730    ) -> Result<(), Error>
731    where
732        T: Serialize;
733}
734
735impl<S: SuiSignatureInner + Sized> SuiSignature for S {
736    fn signature_bytes(&self) -> &[u8] {
737        // Access array slice is safe because the array bytes is initialized as
738        // flag || signature || pubkey with its defined length.
739        &self.as_ref()[1..1 + S::Sig::LENGTH]
740    }
741
742    fn public_key_bytes(&self) -> &[u8] {
743        // Access array slice is safe because the array bytes is initialized as
744        // flag || signature || pubkey with its defined length.
745        &self.as_ref()[S::Sig::LENGTH + 1..]
746    }
747
748    fn scheme(&self) -> SignatureScheme {
749        S::PubKey::SIGNATURE_SCHEME
750    }
751
752    fn verify_secure<T>(
753        &self,
754        value: &IntentMessage<T>,
755        author: SuiAddress,
756        scheme: SignatureScheme,
757    ) -> Result<(), Error>
758    where
759        T: Serialize,
760    {
761        let mut hasher = DefaultHash::default();
762        hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
763        let digest = hasher.finalize().digest;
764
765        let (sig, pk) = &self.get_verification_inputs()?;
766        match scheme {
767            SignatureScheme::ZkLoginAuthenticator => {} // Pass this check because zk login does not derive address from pubkey.
768            _ => {
769                let address = pk.to_sui_address();
770                if author != address {
771                    return Err(Error::IncorrectSigner {
772                        error: format!(
773                            "Incorrect signer, expected {:?}, got {:?}",
774                            author, address
775                        ),
776                    });
777                }
778            }
779        }
780
781        pk.verify(&digest, sig)
782            .map_err(|e| Error::InvalidSignature {
783                error: format!("Fail to verify user sig {}", e),
784            })
785    }
786}
787
788// =============================================================================
789//  SuiPublicKey
790// =============================================================================
791
792pub trait SuiPublicKey: VerifyingKey {
793    const SIGNATURE_SCHEME: SignatureScheme;
794
795    /// Convert to a [SuiAddress].
796    ///
797    /// Extension to the original trait since a generic [From] cannot be implemented here for
798    /// [SuiAddress].
799    fn to_sui_address(&self) -> SuiAddress {
800        let mut hasher = DefaultHash::default();
801        hasher.update([Self::SIGNATURE_SCHEME.flag()]);
802        hasher.update(self);
803        let g_arr = hasher.finalize();
804        SuiAddress::new(g_arr.digest)
805    }
806}