miden_crypto/dsa/ecdsa_k256_keccak/
mod.rs1use alloc::{string::ToString, vec::Vec};
5
6use k256::{
7 ecdh::diffie_hellman,
8 ecdsa,
9 ecdsa::{RecoveryId, VerifyingKey, signature::hazmat::PrehashVerifier},
10 pkcs8::DecodePublicKey,
11};
12use miden_crypto_derive::{SilentDebug, SilentDisplay};
13use rand::{CryptoRng, RngCore};
14use thiserror::Error;
15
16use crate::{
17 Felt, SequentialCommit, Word,
18 ecdh::k256::{EphemeralPublicKey, SharedSecret},
19 utils::{
20 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
21 bytes_to_packed_u32_elements,
22 zeroize::{Zeroize, ZeroizeOnDrop},
23 },
24};
25
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)]
47struct SecretKey {
48 inner: ecdsa::SigningKey,
49}
50
51impl SecretKey {
52 fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
54 use k256::elliptic_curve::rand_core::SeedableRng;
59 let mut seed = [0_u8; 32];
60 RngCore::fill_bytes(rng, &mut seed);
61 let mut rng = rand_hc::Hc128Rng::from_seed(seed);
62
63 let signing_key = ecdsa::SigningKey::random(&mut rng);
64
65 seed.zeroize();
67
68 Self { inner: signing_key }
69 }
70
71 fn public_key(&self) -> PublicKey {
73 let verifying_key = self.inner.verifying_key();
74 PublicKey { inner: *verifying_key }
75 }
76
77 fn sign(&self, message: Word) -> Signature {
79 let message_digest = hash_message(message);
80 self.sign_prehash(message_digest)
81 }
82
83 fn sign_prehash(&self, message_digest: [u8; 32]) -> Signature {
85 let (signature_inner, recovery_id) = self
86 .inner
87 .sign_prehash_recoverable(&message_digest)
88 .expect("failed to generate signature");
89
90 let (r, s) = signature_inner.split_scalars();
91
92 Signature {
93 r: r.to_bytes().into(),
94 s: s.to_bytes().into(),
95 v: recovery_id.into(),
96 }
97 }
98
99 fn get_shared_secret(&self, pk_e: EphemeralPublicKey) -> SharedSecret {
102 let shared_secret_inner = diffie_hellman(self.inner.as_nonzero_scalar(), pk_e.as_affine());
103
104 SharedSecret::new(shared_secret_inner)
105 }
106}
107
108impl ZeroizeOnDrop for SecretKey {}
111
112impl PartialEq for SecretKey {
113 fn eq(&self, other: &Self) -> bool {
114 use subtle::ConstantTimeEq;
115 self.to_bytes().ct_eq(&other.to_bytes()).into()
116 }
117}
118
119impl Eq for SecretKey {}
120
121#[derive(Clone, Eq, PartialEq, SilentDebug, SilentDisplay)] pub struct SigningKey(SecretKey);
127
128impl SigningKey {
129 #[cfg(feature = "std")]
133 #[allow(clippy::new_without_default)]
134 pub fn new() -> Self {
135 let mut rng = rand::rng();
136 Self::with_rng(&mut rng)
137 }
138
139 pub fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
141 Self(SecretKey::with_rng(rng))
142 }
143
144 pub fn public_key(&self) -> PublicKey {
146 self.0.public_key()
147 }
148
149 pub fn sign(&self, message: Word) -> Signature {
151 self.0.sign(message)
152 }
153
154 pub fn sign_prehash(&self, message_digest: [u8; 32]) -> Signature {
156 self.0.sign_prehash(message_digest)
157 }
158}
159
160impl From<SecretKey> for SigningKey {
161 fn from(secret_key: SecretKey) -> Self {
162 Self(secret_key)
163 }
164}
165
166impl ZeroizeOnDrop for SigningKey {}
169
170impl Serializable for SigningKey {
171 fn write_into<W: ByteWriter>(&self, target: &mut W) {
172 self.0.write_into(target);
173 }
174}
175
176impl Deserializable for SigningKey {
177 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
178 Ok(Self(SecretKey::read_from(source)?))
179 }
180}
181
182#[derive(Clone, Eq, PartialEq, SilentDebug, SilentDisplay)] pub struct KeyExchangeKey(SecretKey);
188
189impl KeyExchangeKey {
190 #[cfg(feature = "std")]
194 #[allow(clippy::new_without_default)]
195 pub fn new() -> Self {
196 let mut rng = rand::rng();
197 Self::with_rng(&mut rng)
198 }
199
200 pub fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
202 Self(SecretKey::with_rng(rng))
203 }
204
205 pub fn public_key(&self) -> PublicKey {
207 self.0.public_key()
208 }
209
210 pub fn get_shared_secret(&self, pk_e: EphemeralPublicKey) -> SharedSecret {
213 self.0.get_shared_secret(pk_e)
214 }
215}
216
217impl From<SecretKey> for KeyExchangeKey {
218 fn from(value: SecretKey) -> Self {
219 Self(value)
220 }
221}
222
223impl ZeroizeOnDrop for KeyExchangeKey {}
226
227impl Serializable for KeyExchangeKey {
228 fn write_into<W: ByteWriter>(&self, target: &mut W) {
229 self.0.write_into(target);
230 }
231}
232
233impl Deserializable for KeyExchangeKey {
234 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
235 Ok(Self(SecretKey::read_from(source)?))
236 }
237}
238
239#[derive(Debug, Clone, PartialEq, Eq)]
244pub struct PublicKey {
245 pub(crate) inner: VerifyingKey,
246}
247
248impl PublicKey {
249 pub fn to_commitment(&self) -> Word {
254 <Self as SequentialCommit>::to_commitment(self)
255 }
256
257 pub fn verify(&self, message: Word, signature: &Signature) -> bool {
259 let message_digest = hash_message(message);
260 self.verify_prehash(message_digest, signature)
261 }
262
263 pub fn verify_prehash(&self, message_digest: [u8; 32], signature: &Signature) -> bool {
265 let signature_inner = ecdsa::Signature::from_scalars(*signature.r(), *signature.s());
266
267 match signature_inner {
268 Ok(signature) => self.inner.verify_prehash(&message_digest, &signature).is_ok(),
269 Err(_) => false,
270 }
271 }
272
273 pub fn recover_from(message: Word, signature: &Signature) -> Result<Self, PublicKeyError> {
276 let message_digest = hash_message(message);
277 let signature_data = ecdsa::Signature::from_scalars(*signature.r(), *signature.s())
278 .map_err(|_| PublicKeyError::RecoveryFailed)?;
279
280 let verifying_key = VerifyingKey::recover_from_prehash(
281 &message_digest,
282 &signature_data,
283 RecoveryId::from_byte(signature.v()).ok_or(PublicKeyError::RecoveryFailed)?,
284 )
285 .map_err(|_| PublicKeyError::RecoveryFailed)?;
286
287 Ok(Self { inner: verifying_key })
288 }
289
290 pub fn from_der(bytes: &[u8]) -> Result<Self, DeserializationError> {
295 let verifying_key = VerifyingKey::from_public_key_der(bytes)
296 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
297 Ok(PublicKey { inner: verifying_key })
298 }
299}
300
301impl SequentialCommit for PublicKey {
302 type Commitment = Word;
303
304 fn to_elements(&self) -> Vec<Felt> {
305 bytes_to_packed_u32_elements(&self.to_bytes())
306 }
307}
308
309#[derive(Debug, Error)]
310pub enum PublicKeyError {
311 #[error("Could not recover the public key from the message and signature")]
312 RecoveryFailed,
313}
314
315#[derive(Debug, Clone, PartialEq, Eq)]
334pub struct Signature {
335 r: [u8; SCALARS_SIZE_BYTES],
336 s: [u8; SCALARS_SIZE_BYTES],
337 v: u8,
338}
339
340impl Signature {
341 pub fn r(&self) -> &[u8; SCALARS_SIZE_BYTES] {
343 &self.r
344 }
345
346 pub fn s(&self) -> &[u8; SCALARS_SIZE_BYTES] {
348 &self.s
349 }
350
351 pub fn v(&self) -> u8 {
353 self.v
354 }
355
356 pub fn verify(&self, message: Word, pub_key: &PublicKey) -> bool {
358 pub_key.verify(message, self)
359 }
360
361 pub fn to_sec1_bytes(&self) -> [u8; SIGNATURE_STANDARD_BYTES] {
365 let mut bytes = [0u8; 2 * SCALARS_SIZE_BYTES];
366 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
367 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
368 bytes
369 }
370
371 pub fn from_sec1_bytes_and_recovery_id(
377 bytes: [u8; SIGNATURE_STANDARD_BYTES],
378 recovery_id: u8,
379 ) -> Result<Self, DeserializationError> {
380 let mut r = [0u8; SCALARS_SIZE_BYTES];
381 let mut s = [0u8; SCALARS_SIZE_BYTES];
382 r.copy_from_slice(&bytes[0..SCALARS_SIZE_BYTES]);
383 s.copy_from_slice(&bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES]);
384
385 if recovery_id > 3 {
386 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
387 }
388
389 Ok(Signature { r, s, v: recovery_id })
390 }
391
392 pub fn from_der(bytes: &[u8], mut recovery_id: u8) -> Result<Self, DeserializationError> {
398 if recovery_id > 3 {
399 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
400 }
401
402 let sig = ecdsa::Signature::from_der(bytes)
403 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
404
405 let sig = if let Some(norm) = sig.normalize_s() {
408 recovery_id ^= 1;
413 norm
414 } else {
415 sig
416 };
417
418 let (r, s) = sig.split_scalars();
419
420 Ok(Signature {
421 r: r.to_bytes().into(),
422 s: s.to_bytes().into(),
423 v: recovery_id,
424 })
425 }
426}
427
428impl Serializable for SecretKey {
432 fn write_into<W: ByteWriter>(&self, target: &mut W) {
433 let mut buffer = Vec::with_capacity(SECRET_KEY_BYTES);
434 let sk_bytes: [u8; SECRET_KEY_BYTES] = self.inner.to_bytes().into();
435 buffer.extend_from_slice(&sk_bytes);
436
437 target.write_bytes(&buffer);
438 }
439}
440
441impl Deserializable for SecretKey {
442 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
443 let mut bytes: [u8; SECRET_KEY_BYTES] = source.read_array()?;
444
445 let signing_key = ecdsa::SigningKey::from_slice(&bytes)
446 .map_err(|_| DeserializationError::InvalidValue("Invalid secret key".to_string()))?;
447 bytes.zeroize();
448
449 Ok(Self { inner: signing_key })
450 }
451}
452
453impl Serializable for PublicKey {
454 fn write_into<W: ByteWriter>(&self, target: &mut W) {
455 let encoded = self.inner.to_encoded_point(true);
457
458 target.write_bytes(encoded.as_bytes());
459 }
460}
461
462impl Deserializable for PublicKey {
463 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
464 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
465
466 let verifying_key = VerifyingKey::from_sec1_bytes(&bytes)
467 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
468
469 Ok(Self { inner: verifying_key })
470 }
471}
472
473impl Serializable for Signature {
474 fn write_into<W: ByteWriter>(&self, target: &mut W) {
475 let mut bytes = [0u8; SIGNATURE_BYTES];
476 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
477 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
478 bytes[2 * SCALARS_SIZE_BYTES] = self.v();
479 target.write_bytes(&bytes);
480 }
481}
482
483impl Deserializable for Signature {
484 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
485 let r: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
486 let s: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
487 let v: u8 = source.read_u8()?;
488
489 if v > 3 {
490 Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()))
491 } else {
492 Ok(Signature { r, s, v })
493 }
494 }
495}
496
497fn hash_message(message: Word) -> [u8; 32] {
502 use sha3::{Digest, Keccak256};
503 let mut hasher = Keccak256::new();
504 let message_bytes: [u8; 32] = message.into();
505 hasher.update(message_bytes);
506 hasher.finalize().into()
507}