af_keys/
crypto.rs

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