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