defuse_crypto/curve/
secp256k1.rs

1use core::fmt::{self, Debug, Display};
2use std::str::FromStr;
3
4use near_sdk::{
5    CryptoHash, env, near,
6    serde_with::{DeserializeFromStr, SerializeDisplay},
7};
8
9use crate::{Curve, CurveType, ParseCurveError, TypedCurve};
10
11pub struct Secp256k1;
12
13impl Curve for Secp256k1 {
14    type PublicKey = [u8; 64];
15
16    /// Concatenated `r`, `s` and `v` (recovery byte).
17    ///
18    /// Note: Ethereum clients shift the recovery byte and this
19    /// logic might depend on chain id, so clients must rollback
20    /// these changes to v ∈ {0, 1}.
21    /// References:
22    /// * <https://github.com/ethereumjs/ethereumjs-monorepo/blob/dc7169c16df6d36adeb6e234fcc66eb6cfc5ea3f/packages/util/src/signature.ts#L31-L62>
23    /// * <https://github.com/ethereum/go-ethereum/issues/19751#issuecomment-504900739>
24    type Signature = [u8; 65];
25
26    // Output of cryptographic hash function
27    type Message = CryptoHash;
28
29    /// ECDSA signatures are recoverable, so you don't need a verifying key
30    type VerifyingKey = ();
31
32    #[inline]
33    fn verify(
34        [signature @ .., v]: &Self::Signature,
35        hash: &Self::Message,
36        _verifying_key: &(),
37    ) -> Option<Self::PublicKey> {
38        env::ecrecover(
39            hash, signature, *v,
40            // Do not accept malleable signatures:
41            // https://github.com/near/nearcore/blob/d73041cc1d1a70af4456fceefaceb1bf7f684fde/core/crypto/src/signature.rs#L448-L455
42            true,
43        )
44    }
45}
46
47impl TypedCurve for Secp256k1 {
48    const CURVE_TYPE: CurveType = CurveType::Secp256k1;
49}
50
51#[cfg_attr(any(feature = "arbitrary", test), derive(arbitrary::Arbitrary))]
52#[near(serializers = [borsh])]
53#[derive(
54    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr,
55)]
56#[serde_with(crate = "::near_sdk::serde_with")]
57#[repr(transparent)]
58pub struct Secp256k1PublicKey(pub <Secp256k1 as Curve>::PublicKey);
59
60impl Debug for Secp256k1PublicKey {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        Display::fmt(self, f)
63    }
64}
65
66impl Display for Secp256k1PublicKey {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.write_str(&<Secp256k1 as TypedCurve>::to_base58(self.0))
69    }
70}
71
72impl FromStr for Secp256k1PublicKey {
73    type Err = ParseCurveError;
74
75    fn from_str(s: &str) -> Result<Self, Self::Err> {
76        Secp256k1::parse_base58(s).map(Self)
77    }
78}
79
80#[cfg_attr(any(feature = "arbitrary", test), derive(arbitrary::Arbitrary))]
81#[near(serializers = [borsh])]
82#[derive(
83    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr,
84)]
85#[serde_with(crate = "::near_sdk::serde_with")]
86#[repr(transparent)]
87pub struct Secp256k1Signature(pub <Secp256k1 as Curve>::Signature);
88
89impl Debug for Secp256k1Signature {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        Display::fmt(self, f)
92    }
93}
94
95impl Display for Secp256k1Signature {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        f.write_str(&<Secp256k1 as TypedCurve>::to_base58(self.0))
98    }
99}
100
101impl FromStr for Secp256k1Signature {
102    type Err = ParseCurveError;
103
104    fn from_str(s: &str) -> Result<Self, Self::Err> {
105        Secp256k1::parse_base58(s).map(Self)
106    }
107}