defuse_crypto/curve/
p256.rs

1use core::fmt::{self, Debug, Display};
2use std::str::FromStr;
3
4use generic_array::GenericArray;
5use near_sdk::{
6    CryptoHash, near,
7    serde_with::{DeserializeFromStr, SerializeDisplay},
8};
9use p256::{
10    EncodedPoint,
11    ecdsa::{Signature, VerifyingKey, signature::hazmat::PrehashVerifier},
12    elliptic_curve::scalar::IsHigh,
13};
14
15use crate::{Curve, CurveType, ParseCurveError, TypedCurve};
16
17pub struct P256;
18
19impl Curve for P256 {
20    /// Compressed SEC1 encoded coordinates.
21    type PublicKey = [u8; 33];
22
23    /// Concatenated `r || s` coordinates
24    type Signature = [u8; 64];
25
26    // Output of cryptographic hash function
27    type Message = CryptoHash;
28
29    type VerifyingKey = Self::PublicKey;
30
31    fn verify(
32        signature: &Self::Signature,
33        prehashed: &Self::Message,
34        public_key: &Self::VerifyingKey,
35    ) -> Option<Self::PublicKey> {
36        // convert signature
37        let signature =
38            Signature::from_bytes(GenericArray::from_slice(signature).as_0_14()).ok()?;
39
40        if signature.s().is_high().into() {
41            // guard against signature malleability
42            return None;
43        }
44
45        // convert verifying key
46        let verifying_key = VerifyingKey::from_sec1_bytes(public_key).ok()?;
47
48        // verify signature over prehashed
49        verifying_key
50            .verify_prehash(prehashed, &signature)
51            .is_ok()
52            .then_some(public_key)
53            .copied()
54    }
55}
56
57impl TypedCurve for P256 {
58    const CURVE_TYPE: CurveType = CurveType::P256;
59}
60
61/// Compressed public key, i.e. `x` coordinate with leading SEC1 tag byte
62#[cfg_attr(any(feature = "arbitrary", test), derive(arbitrary::Arbitrary))]
63#[near(serializers = [borsh])]
64#[derive(
65    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr,
66)]
67#[serde_with(crate = "::near_sdk::serde_with")]
68#[repr(transparent)]
69pub struct P256CompressedPublicKey(pub <P256 as Curve>::PublicKey);
70
71impl Debug for P256CompressedPublicKey {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        Display::fmt(self, f)
74    }
75}
76
77impl Display for P256CompressedPublicKey {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        f.write_str(&<P256 as TypedCurve>::to_base58(self.0))
80    }
81}
82
83impl FromStr for P256CompressedPublicKey {
84    type Err = ParseCurveError;
85
86    fn from_str(s: &str) -> Result<Self, Self::Err> {
87        P256::parse_base58(s).map(Self)
88    }
89}
90
91/// Concatenated `x || y` coordinates with no leading SEC1 tag byte
92#[cfg_attr(any(feature = "arbitrary", test), derive(arbitrary::Arbitrary))]
93#[near(serializers = [borsh])]
94#[derive(
95    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr,
96)]
97#[serde_with(crate = "::near_sdk::serde_with")]
98#[repr(transparent)]
99pub struct P256UncompressedPublicKey(pub [u8; 64]);
100
101impl Debug for P256UncompressedPublicKey {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        Display::fmt(self, f)
104    }
105}
106
107impl Display for P256UncompressedPublicKey {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        f.write_str(&<P256 as TypedCurve>::to_base58(self.0))
110    }
111}
112
113impl FromStr for P256UncompressedPublicKey {
114    type Err = ParseCurveError;
115
116    fn from_str(s: &str) -> Result<Self, Self::Err> {
117        P256::parse_base58(s).map(Self)
118    }
119}
120
121#[cfg_attr(any(feature = "arbitrary", test), derive(arbitrary::Arbitrary))]
122#[near(serializers = [borsh])]
123#[derive(
124    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr,
125)]
126#[serde_with(crate = "::near_sdk::serde_with")]
127#[repr(transparent)]
128pub struct P256Signature(pub <P256 as Curve>::Signature);
129
130impl Debug for P256Signature {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        Display::fmt(self, f)
133    }
134}
135
136impl Display for P256Signature {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        f.write_str(&<P256 as TypedCurve>::to_base58(self.0))
139    }
140}
141
142impl FromStr for P256Signature {
143    type Err = ParseCurveError;
144
145    fn from_str(s: &str) -> Result<Self, Self::Err> {
146        P256::parse_base58(s).map(Self)
147    }
148}
149
150/// Converts from untagged uncompressed form (i.e. concatenated `x || y`
151/// coordinates with no leading SEC1 tag byte) into compressed form
152/// (i.e. `x` coordinate with leading SEC1 tag byte)
153pub fn compress_public_key(public_key: P256UncompressedPublicKey) -> P256CompressedPublicKey {
154    EncodedPoint::from_untagged_bytes(GenericArray::from_array(public_key.0).as_0_14())
155        .compress()
156        .as_bytes()
157        .try_into()
158        .map_or_else(|_| unreachable!(), P256CompressedPublicKey)
159}