Skip to main content

jwt_compact_preview/alg/
es256k.rs

1use rand_core::{CryptoRng, RngCore};
2use secp256k1::{All, Message, PublicKey, Secp256k1, SecretKey, Signature};
3use sha2::{
4    digest::{generic_array::typenum::U32, Digest},
5    Sha256,
6};
7use std::{borrow::Cow, marker::PhantomData};
8
9use crate::{Algorithm, AlgorithmSignature};
10
11impl AlgorithmSignature for Signature {
12    fn try_from_slice(slice: &[u8]) -> anyhow::Result<Self> {
13        Signature::from_compact(slice).map_err(Into::into)
14    }
15
16    fn as_bytes(&self) -> Cow<[u8]> {
17        Cow::Owned(self.serialize_compact()[..].to_vec())
18    }
19}
20
21/// A verification key.
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23pub struct Es256kVerifyingKey(PublicKey);
24
25impl AsRef<PublicKey> for Es256kVerifyingKey {
26    fn as_ref(&self) -> &PublicKey {
27        &self.0
28    }
29}
30
31impl Es256kVerifyingKey {
32    /// Create a verification key from a slice.
33    pub fn from_slice(raw: &[u8]) -> anyhow::Result<Es256kVerifyingKey> {
34        Ok(Es256kVerifyingKey(PublicKey::from_slice(raw)?))
35    }
36
37    /// Return the key as raw bytes.
38    pub fn as_bytes(&self) -> Cow<[u8]> {
39        Cow::Owned(self.as_ref().serialize().to_vec())
40    }
41}
42
43/// A signing key.
44#[derive(Debug)]
45pub struct Es256kSigningKey(SecretKey);
46
47impl AsRef<SecretKey> for Es256kSigningKey {
48    fn as_ref(&self) -> &SecretKey {
49        &self.0
50    }
51}
52
53impl Es256kSigningKey {
54    /// Create a signing key from a slice.
55    pub fn from_slice(raw: &[u8]) -> anyhow::Result<Es256kSigningKey> {
56        Ok(Es256kSigningKey(SecretKey::from_slice(raw)?))
57    }
58
59    /// Convert a signing key to a verification key.
60    pub fn to_verifying_key(&self) -> PublicKey {
61        PublicKey::from_secret_key(&Secp256k1::new(), &self.0)
62    }
63}
64
65/// Algorithm implementing elliptic curve digital signatures (ECDSA) on the secp256k1 curve.
66///
67/// The algorithm does not fix the choice of the message digest algorithm; instead,
68/// it is provided as a type parameter. SHA-256 is the default parameter value,
69/// but it can be set to any cryptographically secure hash function with 32-byte output
70/// (e.g., SHA3-256).
71///
72/// *This type is available if the crate is built with the `secp256k1` feature.*
73#[derive(Debug)]
74pub struct Es256k<D = Sha256> {
75    context: Secp256k1<All>,
76    _digest: PhantomData<D>,
77}
78
79impl<D> Default for Es256k<D>
80where
81    D: Digest<OutputSize = U32> + Default,
82{
83    fn default() -> Self {
84        Es256k {
85            context: Secp256k1::new(),
86            _digest: PhantomData,
87        }
88    }
89}
90
91impl<D> Es256k<D>
92where
93    D: Digest<OutputSize = U32> + Default,
94{
95    /// Creates a new algorithm instance.
96    /// This is a (moderately) expensive operation, so if necessary, the algorithm should
97    /// be `clone()`d rather than created anew.
98    pub fn new(context: Secp256k1<All>) -> Self {
99        Es256k {
100            context,
101            _digest: PhantomData,
102        }
103    }
104}
105
106impl<D> Algorithm for Es256k<D>
107where
108    D: Digest<OutputSize = U32> + Default,
109{
110    type SigningKey = Es256kSigningKey;
111    type VerifyingKey = Es256kVerifyingKey;
112    type Signature = Signature;
113
114    fn name(&self) -> Cow<'static, str> {
115        Cow::Borrowed("ES256K")
116    }
117
118    fn sign(&self, signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
119        let mut digest = D::default();
120        digest.update(message);
121        let message = Message::from_slice(&digest.finalize())
122            .expect("failed to convert message to the correct form");
123
124        self.context.sign(&message, signing_key.as_ref())
125    }
126
127    fn verify_signature(
128        &self,
129        signature: &Self::Signature,
130        verifying_key: &Self::VerifyingKey,
131        message: &[u8],
132    ) -> bool {
133        let mut digest = D::default();
134        digest.update(message);
135        let message = Message::from_slice(&digest.finalize())
136            .expect("failed to convert message to the correct form");
137
138        self.context
139            .verify(&message, signature, verifying_key.as_ref())
140            .is_ok()
141    }
142}
143
144impl Es256k {
145    /// Generate a new key pair.
146    pub fn generate<R: CryptoRng + RngCore>(
147        &self,
148        rng: &mut R,
149    ) -> (Es256kSigningKey, Es256kVerifyingKey) {
150        let signing_key = loop {
151            let mut bytes: [u8; secp256k1::constants::SECRET_KEY_SIZE];
152            rng.fill_bytes(&mut bytes);
153            if let Ok(key) = SecretKey::from_slice(&bytes) {
154                break Es256kSigningKey(key);
155            }
156        };
157        let verifying_key = Es256kVerifyingKey(signing_key.to_verifying_key());
158        (signing_key, verifying_key)
159    }
160}