miden_crypto/dsa/ecdsa_k256_keccak/
mod.rs1use alloc::{string::ToString, vec::Vec};
5use core::fmt;
6
7use k256::{
8 AffinePoint,
9 ecdh::diffie_hellman,
10 ecdsa,
11 ecdsa::{RecoveryId, VerifyingKey, signature::hazmat::PrehashVerifier},
12 elliptic_curve::{Generate, point::AffineCoordinates, scalar::IsHigh},
13 pkcs8::DecodePublicKey,
14};
15use miden_crypto_derive::{SilentDebug, SilentDisplay};
16use rand::CryptoRng;
17use thiserror::Error;
18
19use crate::{
20 Felt, SequentialCommit, Word,
21 ecdh::k256::{EphemeralPublicKey, SharedSecret},
22 utils::{
23 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
24 read_sensitive_array, zeroize::ZeroizeOnDrop,
25 },
26};
27
28mod tests;
29
30const SECRET_KEY_BYTES: usize = 32;
35pub(crate) const PUBLIC_KEY_BYTES: usize = 33;
37const SIGNATURE_BYTES: usize = 65;
39const SIGNATURE_STANDARD_BYTES: usize = 64;
41const SCALARS_SIZE_BYTES: usize = 32;
43
44#[derive(Clone, SilentDebug, SilentDisplay)]
49struct SecretKey {
50 inner: ecdsa::SigningKey,
51}
52
53impl SecretKey {
54 fn with_rng<R: CryptoRng>(rng: &mut R) -> Self {
56 let signing_key = ecdsa::SigningKey::generate_from_rng(rng);
57
58 Self { inner: signing_key }
59 }
60
61 fn public_key(&self) -> PublicKey {
63 let verifying_key = self.inner.verifying_key();
64 PublicKey { inner: *verifying_key }
65 }
66
67 fn sign(&self, message: Word) -> Signature {
69 let message_digest = hash_message(message);
70 self.sign_prehash(message_digest)
71 }
72
73 fn sign_prehash(&self, message_digest: [u8; 32]) -> Signature {
75 let (signature_inner, recovery_id) = self.inner.sign_prehash_recoverable(&message_digest);
76
77 let (r, s) = signature_inner.split_scalars();
78
79 Signature {
80 r: r.to_bytes().into(),
81 s: s.to_bytes().into(),
82 v: recovery_id.into(),
83 }
84 }
85
86 fn get_shared_secret(&self, pk_e: &EphemeralPublicKey) -> SharedSecret {
89 let shared_secret_inner = diffie_hellman(self.inner.as_nonzero_scalar(), pk_e.as_affine());
90
91 SharedSecret::new(shared_secret_inner)
92 }
93}
94
95impl ZeroizeOnDrop for SecretKey {}
98
99impl PartialEq for SecretKey {
100 fn eq(&self, other: &Self) -> bool {
101 use subtle::ConstantTimeEq;
102 self.to_bytes().ct_eq(&other.to_bytes()).into()
103 }
104}
105
106impl Eq for SecretKey {}
107
108#[derive(Clone, Eq, PartialEq, SilentDebug, SilentDisplay)] pub struct SigningKey(SecretKey);
114
115impl SigningKey {
116 #[cfg(feature = "std")]
120 #[allow(clippy::new_without_default)]
121 pub fn new() -> Self {
122 let mut rng = rand::rng();
123 Self::with_rng(&mut rng)
124 }
125
126 pub fn with_rng<R: CryptoRng>(rng: &mut R) -> Self {
128 Self(SecretKey::with_rng(rng))
129 }
130
131 pub fn public_key(&self) -> PublicKey {
133 self.0.public_key()
134 }
135
136 pub fn sign(&self, message: Word) -> Signature {
138 self.0.sign(message)
139 }
140
141 pub fn sign_prehash(&self, message_digest: [u8; 32]) -> Signature {
143 self.0.sign_prehash(message_digest)
144 }
145}
146
147impl From<SecretKey> for SigningKey {
148 fn from(secret_key: SecretKey) -> Self {
149 Self(secret_key)
150 }
151}
152
153impl ZeroizeOnDrop for SigningKey {}
156
157impl Serializable for SigningKey {
158 fn write_into<W: ByteWriter>(&self, target: &mut W) {
159 self.0.write_into(target);
160 }
161}
162
163impl Deserializable for SigningKey {
164 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
165 Ok(Self(SecretKey::read_from(source)?))
166 }
167}
168
169#[derive(Clone, Eq, PartialEq, SilentDebug, SilentDisplay)] pub struct KeyExchangeKey(SecretKey);
175
176impl KeyExchangeKey {
177 #[cfg(feature = "std")]
181 #[allow(clippy::new_without_default)]
182 pub fn new() -> Self {
183 let mut rng = rand::rng();
184 Self::with_rng(&mut rng)
185 }
186
187 pub fn with_rng<R: CryptoRng>(rng: &mut R) -> Self {
189 Self(SecretKey::with_rng(rng))
190 }
191
192 pub fn public_key(&self) -> PublicKey {
194 self.0.public_key()
195 }
196
197 pub fn get_shared_secret(&self, pk_e: EphemeralPublicKey) -> SharedSecret {
200 self.0.get_shared_secret(&pk_e)
201 }
202}
203
204impl From<SecretKey> for KeyExchangeKey {
205 fn from(value: SecretKey) -> Self {
206 Self(value)
207 }
208}
209
210impl ZeroizeOnDrop for KeyExchangeKey {}
213
214impl Serializable for KeyExchangeKey {
215 fn write_into<W: ByteWriter>(&self, target: &mut W) {
216 self.0.write_into(target);
217 }
218}
219
220impl Deserializable for KeyExchangeKey {
221 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
222 Ok(Self(SecretKey::read_from(source)?))
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq)]
231pub struct PublicKey {
232 pub(crate) inner: VerifyingKey,
233}
234
235impl PublicKey {
236 pub fn to_commitment(&self) -> Word {
242 <Self as SequentialCommit>::to_commitment(self)
243 }
244
245 pub fn as_affine(&self) -> &AffinePoint {
247 self.inner.as_affine()
248 }
249
250 pub fn verify(&self, message: Word, signature: &Signature) -> bool {
252 let message_digest = hash_message(message);
253 self.verify_prehash(message_digest, signature)
254 }
255
256 pub fn verify_prehash(&self, message_digest: [u8; 32], signature: &Signature) -> bool {
258 let signature_inner = ecdsa::Signature::from_scalars(*signature.r(), *signature.s());
259
260 match signature_inner {
261 Ok(signature) => self.inner.verify_prehash(&message_digest, &signature).is_ok(),
262 Err(_) => false,
263 }
264 }
265
266 pub fn recover_from(message: Word, signature: &Signature) -> Result<Self, PublicKeyError> {
269 let message_digest = hash_message(message);
270 Self::recover_from_prehash(message_digest, signature)
271 }
272
273 pub fn recover_from_prehash(
285 message_digest: [u8; 32],
286 signature: &Signature,
287 ) -> Result<Self, PublicKeyError> {
288 let signature_data = ecdsa::Signature::from_scalars(*signature.r(), *signature.s())
289 .map_err(|_| PublicKeyError::RecoveryFailed)?;
290
291 let verifying_key = VerifyingKey::recover_from_prehash(
292 &message_digest,
293 &signature_data,
294 RecoveryId::from_byte(signature.v()).ok_or(PublicKeyError::RecoveryFailed)?,
295 )
296 .map_err(|_| PublicKeyError::RecoveryFailed)?;
297
298 Ok(Self { inner: verifying_key })
299 }
300
301 pub fn from_der(bytes: &[u8]) -> Result<Self, DeserializationError> {
306 let verifying_key = VerifyingKey::from_public_key_der(bytes)
307 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
308 Ok(PublicKey { inner: verifying_key })
309 }
310}
311
312impl SequentialCommit for PublicKey {
313 type Commitment = Word;
314
315 fn to_elements(&self) -> Vec<Felt> {
316 affine_point_to_elements(self.as_affine()).to_vec()
317 }
318}
319
320#[derive(Debug, Error)]
321pub enum PublicKeyError {
322 #[error("Could not recover the public key from the message and signature")]
323 RecoveryFailed,
324}
325
326#[derive(Debug, Clone, PartialEq, Eq)]
372pub struct Signature {
373 r: [u8; SCALARS_SIZE_BYTES],
374 s: [u8; SCALARS_SIZE_BYTES],
375 v: u8,
376}
377
378impl Signature {
379 pub fn r(&self) -> &[u8; SCALARS_SIZE_BYTES] {
381 &self.r
382 }
383
384 pub fn s(&self) -> &[u8; SCALARS_SIZE_BYTES] {
386 &self.s
387 }
388
389 pub fn v(&self) -> u8 {
391 self.v
392 }
393
394 pub fn verify(&self, message: Word, pub_key: &PublicKey) -> bool {
396 pub_key.verify(message, self)
397 }
398
399 pub fn to_sec1_bytes(&self) -> [u8; SIGNATURE_STANDARD_BYTES] {
403 let mut bytes = [0u8; 2 * SCALARS_SIZE_BYTES];
404 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
405 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
406 bytes
407 }
408
409 pub fn from_sec1_bytes_and_recovery_id(
415 bytes: [u8; SIGNATURE_STANDARD_BYTES],
416 recovery_id: u8,
417 ) -> Result<Self, DeserializationError> {
418 let mut r = [0u8; SCALARS_SIZE_BYTES];
419 let mut s = [0u8; SCALARS_SIZE_BYTES];
420 r.copy_from_slice(&bytes[0..SCALARS_SIZE_BYTES]);
421 s.copy_from_slice(&bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES]);
422
423 if recovery_id > 3 {
424 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
425 }
426
427 Ok(Signature { r, s, v: recovery_id })
428 }
429
430 pub fn from_der(bytes: &[u8], mut recovery_id: u8) -> Result<Self, DeserializationError> {
436 if recovery_id > 3 {
437 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
438 }
439
440 let sig = ecdsa::Signature::from_der(bytes)
441 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?;
442
443 let high_s = sig.s().is_high();
446 if bool::from(high_s) {
447 recovery_id ^= 1;
452 }
453 let sig = sig.normalize_s();
454
455 let (r, s) = sig.split_scalars();
456
457 Ok(Signature {
458 r: <[u8; SCALARS_SIZE_BYTES]>::from(r.to_bytes()),
459 s: <[u8; SCALARS_SIZE_BYTES]>::from(s.to_bytes()),
460 v: recovery_id,
461 })
462 }
463}
464
465impl Serializable for SecretKey {
469 fn write_into<W: ByteWriter>(&self, target: &mut W) {
470 let mut buffer = Vec::with_capacity(SECRET_KEY_BYTES);
471 let sk_bytes: [u8; SECRET_KEY_BYTES] = self.inner.to_bytes().into();
472 buffer.extend_from_slice(&sk_bytes);
473
474 target.write_bytes(&buffer);
475 }
476}
477
478impl Deserializable for SecretKey {
479 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
480 let bytes = read_sensitive_array::<SECRET_KEY_BYTES, _>(source)?;
481
482 let signing_key = ecdsa::SigningKey::from_slice(bytes.as_slice())
483 .map_err(|_| DeserializationError::InvalidValue("Invalid secret key".to_string()))?;
484
485 Ok(Self { inner: signing_key })
486 }
487}
488
489impl Serializable for PublicKey {
490 fn write_into<W: ByteWriter>(&self, target: &mut W) {
491 let encoded = self.inner.to_sec1_point(true);
492 target.write_bytes(encoded.as_bytes());
493 }
494}
495
496impl Deserializable for PublicKey {
497 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
498 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
499
500 let verifying_key = VerifyingKey::from_sec1_bytes(&bytes)
501 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
502
503 Ok(Self { inner: verifying_key })
504 }
505}
506
507impl fmt::Display for PublicKey {
508 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509 crate::utils::write_hex(f, &self.to_bytes())
510 }
511}
512
513impl Serializable for Signature {
514 fn write_into<W: ByteWriter>(&self, target: &mut W) {
515 let mut bytes = [0u8; SIGNATURE_BYTES];
516 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
517 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
518 bytes[2 * SCALARS_SIZE_BYTES] = self.v();
519 target.write_bytes(&bytes);
520 }
521}
522
523impl Deserializable for Signature {
524 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
525 let r: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
526 let s: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
527 let v: u8 = source.read_u8()?;
528
529 if v > 3 {
530 Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()))
531 } else {
532 Ok(Signature { r, s, v })
533 }
534 }
535}
536
537impl fmt::Display for Signature {
538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539 crate::utils::write_hex(f, &self.to_bytes())
540 }
541}
542
543fn affine_point_to_elements(point: &AffinePoint) -> [Felt; 16] {
547 let qx = be_bytes_to_le_u32_limbs(point.x().as_ref());
548 let qy = be_bytes_to_le_u32_limbs(point.y().as_ref());
549
550 core::array::from_fn(|idx| {
551 if idx < 8 {
552 Felt::from_u32(qx[idx])
553 } else {
554 Felt::from_u32(qy[idx - 8])
555 }
556 })
557}
558
559fn be_bytes_to_le_u32_limbs(bytes: &[u8]) -> [u32; 8] {
560 debug_assert_eq!(bytes.len(), SCALARS_SIZE_BYTES);
561 core::array::from_fn(|idx| {
562 let start = SCALARS_SIZE_BYTES - 4 * (idx + 1);
563 u32::from_be_bytes(bytes[start..start + 4].try_into().expect("chunk is exactly 4 bytes"))
564 })
565}
566
567fn hash_message(message: Word) -> [u8; 32] {
569 use sha3::{Digest, Keccak256};
570 let mut hasher = Keccak256::new();
571 let message_bytes: [u8; 32] = message.into();
572 hasher.update(message_bytes);
573 hasher.finalize().into()
574}