oasis_runtime_sdk/crypto/signature/
secp256k1.rs

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