Skip to main content

oasis_runtime_sdk/crypto/signature/
secp384r1.rs

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