Skip to main content

defuse_crypto/curve/
secp256k1.rs

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