miden_crypto/dsa/ecdsa_k256_keccak/
mod.rs1use alloc::{string::ToString, vec::Vec};
5
6use k256::{
7 ecdh::diffie_hellman,
8 ecdsa::{RecoveryId, SigningKey, VerifyingKey, signature::hazmat::PrehashVerifier},
9 pkcs8::DecodePublicKey,
10};
11use miden_crypto_derive::{SilentDebug, SilentDisplay};
12use rand::{CryptoRng, RngCore};
13use thiserror::Error;
14
15use crate::{
16 Felt, SequentialCommit, Word,
17 ecdh::k256::{EphemeralPublicKey, SharedSecret},
18 utils::{
19 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
20 bytes_to_packed_u32_elements,
21 zeroize::{Zeroize, ZeroizeOnDrop},
22 },
23};
24
25#[cfg(test)]
26mod tests;
27
28const SECRET_KEY_BYTES: usize = 32;
33pub(crate) const PUBLIC_KEY_BYTES: usize = 33;
35const SIGNATURE_BYTES: usize = 65;
37const SIGNATURE_STANDARD_BYTES: usize = 64;
39const SCALARS_SIZE_BYTES: usize = 32;
41
42#[derive(Clone, SilentDebug, SilentDisplay)]
47pub struct SecretKey {
48 inner: SigningKey,
49}
50
51impl SecretKey {
52 #[cfg(feature = "std")]
54 #[allow(clippy::new_without_default)]
55 pub fn new() -> Self {
56 let mut rng = rand::rng();
57
58 Self::with_rng(&mut rng)
59 }
60
61 pub fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
63 use k256::elliptic_curve::rand_core::SeedableRng;
68 let mut seed = [0_u8; 32];
69 rand::RngCore::fill_bytes(rng, &mut seed);
70 let mut rng = rand_hc::Hc128Rng::from_seed(seed);
71
72 let signing_key = SigningKey::random(&mut rng);
73
74 seed.zeroize();
76
77 Self { inner: signing_key }
78 }
79
80 pub fn public_key(&self) -> PublicKey {
82 let verifying_key = self.inner.verifying_key();
83 PublicKey { inner: *verifying_key }
84 }
85
86 pub fn sign(&self, message: Word) -> Signature {
88 let message_digest = hash_message(message);
89 self.sign_prehash(message_digest)
90 }
91
92 pub fn sign_prehash(&self, message_digest: [u8; 32]) -> Signature {
94 let (signature_inner, recovery_id) = self
95 .inner
96 .sign_prehash_recoverable(&message_digest)
97 .expect("failed to generate signature");
98
99 let (r, s) = signature_inner.split_scalars();
100
101 Signature {
102 r: r.to_bytes().into(),
103 s: s.to_bytes().into(),
104 v: recovery_id.into(),
105 }
106 }
107
108 pub fn get_shared_secret(&self, pk_e: EphemeralPublicKey) -> SharedSecret {
111 let shared_secret_inner = diffie_hellman(self.inner.as_nonzero_scalar(), pk_e.as_affine());
112
113 SharedSecret::new(shared_secret_inner)
114 }
115}
116
117impl ZeroizeOnDrop for SecretKey {}
120
121impl PartialEq for SecretKey {
122 fn eq(&self, other: &Self) -> bool {
123 use subtle::ConstantTimeEq;
124 self.to_bytes().ct_eq(&other.to_bytes()).into()
125 }
126}
127
128impl Eq for SecretKey {}
129
130#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct PublicKey {
136 pub(crate) inner: VerifyingKey,
137}
138
139impl PublicKey {
140 pub fn to_commitment(&self) -> Word {
145 <Self as SequentialCommit>::to_commitment(self)
146 }
147
148 pub fn verify(&self, message: Word, signature: &Signature) -> bool {
150 let message_digest = hash_message(message);
151 self.verify_prehash(message_digest, signature)
152 }
153
154 pub fn verify_prehash(&self, message_digest: [u8; 32], signature: &Signature) -> bool {
156 let signature_inner = k256::ecdsa::Signature::from_scalars(*signature.r(), *signature.s());
157
158 match signature_inner {
159 Ok(signature) => self.inner.verify_prehash(&message_digest, &signature).is_ok(),
160 Err(_) => false,
161 }
162 }
163
164 pub fn recover_from(message: Word, signature: &Signature) -> Result<Self, PublicKeyError> {
167 let message_digest = hash_message(message);
168 let signature_data = k256::ecdsa::Signature::from_scalars(*signature.r(), *signature.s())
169 .map_err(|_| PublicKeyError::RecoveryFailed)?;
170
171 let verifying_key = k256::ecdsa::VerifyingKey::recover_from_prehash(
172 &message_digest,
173 &signature_data,
174 RecoveryId::from_byte(signature.v()).ok_or(PublicKeyError::RecoveryFailed)?,
175 )
176 .map_err(|_| PublicKeyError::RecoveryFailed)?;
177
178 Ok(Self { inner: verifying_key })
179 }
180
181 pub fn from_der(bytes: &[u8]) -> Result<Self, DeserializationError> {
186 let verifying_key = VerifyingKey::from_public_key_der(bytes)
187 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
188 Ok(PublicKey { inner: verifying_key })
189 }
190}
191
192impl SequentialCommit for PublicKey {
193 type Commitment = Word;
194
195 fn to_elements(&self) -> Vec<Felt> {
196 bytes_to_packed_u32_elements(&self.to_bytes())
197 }
198}
199
200#[derive(Debug, Error)]
201pub enum PublicKeyError {
202 #[error("Could not recover the public key from the message and signature")]
203 RecoveryFailed,
204}
205
206#[derive(Debug, Clone, PartialEq, Eq)]
225pub struct Signature {
226 r: [u8; SCALARS_SIZE_BYTES],
227 s: [u8; SCALARS_SIZE_BYTES],
228 v: u8,
229}
230
231impl Signature {
232 pub fn r(&self) -> &[u8; SCALARS_SIZE_BYTES] {
234 &self.r
235 }
236
237 pub fn s(&self) -> &[u8; SCALARS_SIZE_BYTES] {
239 &self.s
240 }
241
242 pub fn v(&self) -> u8 {
244 self.v
245 }
246
247 pub fn verify(&self, message: Word, pub_key: &PublicKey) -> bool {
249 pub_key.verify(message, self)
250 }
251
252 pub fn to_sec1_bytes(&self) -> [u8; SIGNATURE_STANDARD_BYTES] {
256 let mut bytes = [0u8; 2 * SCALARS_SIZE_BYTES];
257 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
258 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
259 bytes
260 }
261
262 pub fn from_sec1_bytes_and_recovery_id(
268 bytes: [u8; SIGNATURE_STANDARD_BYTES],
269 recovery_id: u8,
270 ) -> Result<Self, DeserializationError> {
271 let mut r = [0u8; SCALARS_SIZE_BYTES];
272 let mut s = [0u8; SCALARS_SIZE_BYTES];
273 r.copy_from_slice(&bytes[0..SCALARS_SIZE_BYTES]);
274 s.copy_from_slice(&bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES]);
275
276 if recovery_id > 3 {
277 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
278 }
279
280 Ok(Signature { r, s, v: recovery_id })
281 }
282
283 pub fn from_der(bytes: &[u8], mut recovery_id: u8) -> Result<Self, DeserializationError> {
289 if recovery_id > 3 {
290 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
291 }
292
293 let sig = k256::ecdsa::Signature::from_der(bytes)
294 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
295
296 let sig = if let Some(norm) = sig.normalize_s() {
299 recovery_id ^= 1;
304 norm
305 } else {
306 sig
307 };
308
309 let (r, s) = sig.split_scalars();
310
311 Ok(Signature {
312 r: r.to_bytes().into(),
313 s: s.to_bytes().into(),
314 v: recovery_id,
315 })
316 }
317}
318
319impl Serializable for SecretKey {
323 fn write_into<W: ByteWriter>(&self, target: &mut W) {
324 let mut buffer = Vec::with_capacity(SECRET_KEY_BYTES);
325 let sk_bytes: [u8; SECRET_KEY_BYTES] = self.inner.to_bytes().into();
326 buffer.extend_from_slice(&sk_bytes);
327
328 target.write_bytes(&buffer);
329 }
330}
331
332impl Deserializable for SecretKey {
333 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
334 let mut bytes: [u8; SECRET_KEY_BYTES] = source.read_array()?;
335
336 let signing_key = SigningKey::from_slice(&bytes)
337 .map_err(|_| DeserializationError::InvalidValue("Invalid secret key".to_string()))?;
338 bytes.zeroize();
339
340 Ok(Self { inner: signing_key })
341 }
342}
343
344impl Serializable for PublicKey {
345 fn write_into<W: ByteWriter>(&self, target: &mut W) {
346 let encoded = self.inner.to_encoded_point(true);
348
349 target.write_bytes(encoded.as_bytes());
350 }
351}
352
353impl Deserializable for PublicKey {
354 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
355 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
356
357 let verifying_key = VerifyingKey::from_sec1_bytes(&bytes)
358 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
359
360 Ok(Self { inner: verifying_key })
361 }
362}
363
364impl Serializable for Signature {
365 fn write_into<W: ByteWriter>(&self, target: &mut W) {
366 let mut bytes = [0u8; SIGNATURE_BYTES];
367 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
368 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
369 bytes[2 * SCALARS_SIZE_BYTES] = self.v();
370 target.write_bytes(&bytes);
371 }
372}
373
374impl Deserializable for Signature {
375 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
376 let r: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
377 let s: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
378 let v: u8 = source.read_u8()?;
379
380 if v > 3 {
381 Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()))
382 } else {
383 Ok(Signature { r, s, v })
384 }
385 }
386}
387
388fn hash_message(message: Word) -> [u8; 32] {
393 use sha3::{Digest, Keccak256};
394 let mut hasher = Keccak256::new();
395 let message_bytes: [u8; 32] = message.into();
396 hasher.update(message_bytes);
397 hasher.finalize().into()
398}