Skip to main content

oasis_runtime_sdk/crypto/signature/
secp256r1.rs

1//! Secp256r1 signatures.
2use base64::prelude::*;
3use digest::{common::BlockSizeUser, consts::U32, Digest, FixedOutput, FixedOutputReset};
4use k256::sha2::Sha512_256;
5use p256::{
6    self,
7    ecdsa::{
8        self,
9        signature::{
10            hazmat::{PrehashSigner, PrehashVerifier},
11            Signer as _, Verifier as _,
12        },
13    },
14};
15use rand::TryCryptoRng;
16
17use crate::crypto::signature::{Error, Signature};
18
19/// A Secp256r1 public key (in compressed form).
20#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct PublicKey(p256::Sec1Point);
22
23impl PublicKey {
24    /// Return a byte representation of this public key.
25    pub fn as_bytes(&self) -> &[u8] {
26        self.0.as_bytes()
27    }
28
29    /// Construct a public key from a slice of bytes.
30    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
31        p256::Sec1Point::from_bytes(bytes)
32            .map_err(|_| Error::MalformedPublicKey)
33            .map(PublicKey)
34    }
35
36    /// Verify a signature.
37    pub fn verify(
38        &self,
39        context: &[u8],
40        message: &[u8],
41        signature: &Signature,
42    ) -> Result<(), Error> {
43        let digest = Sha512_256::new()
44            .chain_update(context)
45            .chain_update(message);
46        self.verify_digest(digest, signature)
47    }
48
49    /// Verify signature without using any domain separation scheme.
50    pub fn verify_raw(&self, message: &[u8], signature: &Signature) -> Result<(), Error> {
51        let sig = ecdsa::Signature::from_der(signature.0.as_ref())
52            .map_err(|_| Error::MalformedSignature)?;
53        let verify_key =
54            ecdsa::VerifyingKey::from_sec1_point(&self.0).map_err(|_| Error::MalformedPublicKey)?;
55        verify_key
56            .verify(message, &sig)
57            .map_err(|_| Error::VerificationFailed)
58    }
59
60    /// Verify signature of a pre-hashed message.
61    pub fn verify_digest<D>(&self, digest: D, signature: &Signature) -> Result<(), Error>
62    where
63        D: Digest + FixedOutput<OutputSize = U32>,
64    {
65        let sig = ecdsa::Signature::from_der(signature.as_ref())
66            .map_err(|_| Error::MalformedSignature)?;
67        let verify_key =
68            ecdsa::VerifyingKey::from_sec1_point(&self.0).map_err(|_| Error::MalformedPublicKey)?;
69        let prehash = digest.finalize_fixed();
70        verify_key
71            .verify_prehash(&prehash, &sig)
72            .map_err(|_| Error::VerificationFailed)
73    }
74}
75
76impl From<&'static str> for PublicKey {
77    fn from(s: &'static str) -> PublicKey {
78        PublicKey::from_bytes(&BASE64_STANDARD.decode(s).unwrap()).unwrap()
79    }
80}
81
82impl cbor::Encode for PublicKey {
83    fn into_cbor_value(self) -> cbor::Value {
84        cbor::Value::ByteString(self.as_bytes().to_vec())
85    }
86}
87
88impl cbor::Decode for PublicKey {
89    fn try_from_cbor_value(value: cbor::Value) -> Result<Self, cbor::DecodeError> {
90        match value {
91            cbor::Value::ByteString(data) => {
92                Self::from_bytes(&data).map_err(|_| cbor::DecodeError::UnexpectedType)
93            }
94            _ => Err(cbor::DecodeError::UnexpectedType),
95        }
96    }
97}
98
99/// A memory-backed signer for Secp256r1.
100pub struct MemorySigner {
101    sk: ecdsa::SigningKey,
102}
103
104impl MemorySigner {
105    pub fn sign_digest<D>(&self, digest: D) -> Result<Signature, Error>
106    where
107        D: Digest + FixedOutput<OutputSize = U32> + BlockSizeUser + FixedOutputReset,
108    {
109        let prehash = digest.finalize_fixed();
110        let signature: ecdsa::Signature = self
111            .sk
112            .sign_prehash(&prehash)
113            .map_err(|_| Error::SigningError)?;
114        Ok(signature.to_der().as_bytes().to_vec().into())
115    }
116}
117
118impl super::Signer for MemorySigner {
119    fn random(rng: &mut impl TryCryptoRng) -> Result<Self, Error> {
120        let mut seed = [0u8; 32];
121        rng.try_fill_bytes(&mut seed).map_err(|_| Error::RngError)?;
122        Self::new_from_seed(&seed)
123    }
124
125    fn new_from_seed(seed: &[u8]) -> Result<Self, Error> {
126        let sk = ecdsa::SigningKey::from_slice(seed).map_err(|_| Error::InvalidArgument)?;
127        Ok(Self { sk })
128    }
129
130    fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
131        Ok(Self {
132            sk: ecdsa::SigningKey::from_slice(bytes).map_err(|_| Error::MalformedPrivateKey)?,
133        })
134    }
135
136    fn to_bytes(&self) -> Vec<u8> {
137        self.sk.to_bytes().to_vec()
138    }
139
140    fn public_key(&self) -> super::PublicKey {
141        super::PublicKey::Secp256r1(PublicKey(self.sk.verifying_key().to_sec1_point(true)))
142    }
143
144    fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
145        let digest = sha2::Sha256::new()
146            .chain_update(context)
147            .chain_update(message);
148        let prehash = digest.finalize_fixed();
149        let signature: ecdsa::Signature = self
150            .sk
151            .sign_prehash(&prehash)
152            .map_err(|_| Error::SigningError)?;
153        Ok(signature.to_der().as_bytes().to_vec().into())
154    }
155
156    fn sign_raw(&self, message: &[u8]) -> Result<Signature, Error> {
157        let signature: ecdsa::Signature = self.sk.sign(message);
158        Ok(signature.to_der().as_bytes().to_vec().into())
159    }
160}