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};
10use miden_crypto_derive::{SilentDebug, SilentDisplay};
11use rand::{CryptoRng, RngCore};
12use thiserror::Error;
13
14use crate::{
15 Felt, SequentialCommit, Word,
16 ecdh::k256::{EphemeralPublicKey, SharedSecret},
17 utils::{
18 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
19 bytes_to_elements_with_padding,
20 },
21 zeroize::{Zeroize, ZeroizeOnDrop},
22};
23
24#[cfg(test)]
25mod tests;
26
27const SECRET_KEY_BYTES: usize = 32;
32pub(crate) const PUBLIC_KEY_BYTES: usize = 33;
34const SIGNATURE_BYTES: usize = 66;
36const SIGNATURE_STANDARD_BYTES: usize = 64;
38const SCALARS_SIZE_BYTES: usize = 32;
40
41#[derive(Clone, SilentDebug, SilentDisplay)]
46pub struct SecretKey {
47 inner: SigningKey,
48}
49
50impl SecretKey {
51 #[cfg(feature = "std")]
53 #[allow(clippy::new_without_default)]
54 pub fn new() -> Self {
55 let mut rng = rand::rng();
56
57 Self::with_rng(&mut rng)
58 }
59
60 pub fn with_rng<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
62 use k256::elliptic_curve::rand_core::SeedableRng;
67 let mut seed = [0_u8; 32];
68 rand::RngCore::fill_bytes(rng, &mut seed);
69 let mut rng = rand_hc::Hc128Rng::from_seed(seed);
70
71 let signing_key = SigningKey::random(&mut rng);
72
73 seed.zeroize();
75
76 Self { inner: signing_key }
77 }
78
79 pub fn public_key(&self) -> PublicKey {
81 let verifying_key = self.inner.verifying_key();
82 PublicKey { inner: *verifying_key }
83 }
84
85 pub fn sign(&self, message: Word) -> Signature {
87 let message_digest = hash_message(message);
88 self.sign_prehash(message_digest)
89 }
90
91 pub fn sign_prehash(&self, message_digest: [u8; 32]) -> Signature {
93 let (signature_inner, recovery_id) = self
94 .inner
95 .sign_prehash_recoverable(&message_digest)
96 .expect("failed to generate signature");
97
98 let (r, s) = signature_inner.split_scalars();
99
100 Signature {
101 r: r.to_bytes().into(),
102 s: s.to_bytes().into(),
103 v: recovery_id.into(),
104 }
105 }
106
107 pub fn get_shared_secret(&self, pk_e: EphemeralPublicKey) -> SharedSecret {
110 let shared_secret_inner = diffie_hellman(self.inner.as_nonzero_scalar(), pk_e.as_affine());
111
112 SharedSecret::new(shared_secret_inner)
113 }
114}
115
116impl ZeroizeOnDrop for SecretKey {}
119
120impl PartialEq for SecretKey {
121 fn eq(&self, other: &Self) -> bool {
122 use subtle::ConstantTimeEq;
123 self.to_bytes().ct_eq(&other.to_bytes()).into()
124 }
125}
126
127impl Eq for SecretKey {}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct PublicKey {
135 pub(crate) inner: VerifyingKey,
136}
137
138impl PublicKey {
139 pub fn to_commitment(&self) -> Word {
141 <Self as SequentialCommit>::to_commitment(self)
142 }
143
144 pub fn verify(&self, message: Word, signature: &Signature) -> bool {
146 let message_digest = hash_message(message);
147 self.verify_prehash(message_digest, signature)
148 }
149
150 pub fn verify_prehash(&self, message_digest: [u8; 32], signature: &Signature) -> bool {
152 let signature_inner = k256::ecdsa::Signature::from_scalars(*signature.r(), *signature.s());
153
154 match signature_inner {
155 Ok(signature) => self.inner.verify_prehash(&message_digest, &signature).is_ok(),
156 Err(_) => false,
157 }
158 }
159
160 pub fn recover_from(message: Word, signature: &Signature) -> Result<Self, PublicKeyError> {
163 let message_digest = hash_message(message);
164 let signature_data = k256::ecdsa::Signature::from_scalars(*signature.r(), *signature.s())
165 .map_err(|_| PublicKeyError::RecoveryFailed)?;
166
167 let verifying_key = k256::ecdsa::VerifyingKey::recover_from_prehash(
168 &message_digest,
169 &signature_data,
170 RecoveryId::from_byte(signature.v()).ok_or(PublicKeyError::RecoveryFailed)?,
171 )
172 .map_err(|_| PublicKeyError::RecoveryFailed)?;
173
174 Ok(Self { inner: verifying_key })
175 }
176}
177
178impl SequentialCommit for PublicKey {
179 type Commitment = Word;
180
181 fn to_elements(&self) -> Vec<Felt> {
182 bytes_to_elements_with_padding(&self.to_bytes())
183 }
184}
185
186#[derive(Debug, Error)]
187pub enum PublicKeyError {
188 #[error("Could not recover the public key from the message and signature")]
189 RecoveryFailed,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq)]
211pub struct Signature {
212 r: [u8; SCALARS_SIZE_BYTES],
213 s: [u8; SCALARS_SIZE_BYTES],
214 v: u8,
215}
216
217impl Signature {
218 pub fn r(&self) -> &[u8; SCALARS_SIZE_BYTES] {
220 &self.r
221 }
222
223 pub fn s(&self) -> &[u8; SCALARS_SIZE_BYTES] {
225 &self.s
226 }
227
228 pub fn v(&self) -> u8 {
230 self.v
231 }
232
233 pub fn verify(&self, message: Word, pub_key: &PublicKey) -> bool {
235 pub_key.verify(message, self)
236 }
237
238 pub fn to_sec1_bytes(&self) -> [u8; SIGNATURE_STANDARD_BYTES] {
242 let mut bytes = [0u8; 2 * SCALARS_SIZE_BYTES];
243 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
244 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
245 bytes
246 }
247
248 pub fn from_sec1_bytes_and_recovery_id(
254 bytes: [u8; SIGNATURE_STANDARD_BYTES],
255 v: u8,
256 ) -> Result<Self, DeserializationError> {
257 let mut r = [0u8; SCALARS_SIZE_BYTES];
258 let mut s = [0u8; SCALARS_SIZE_BYTES];
259 r.copy_from_slice(&bytes[0..SCALARS_SIZE_BYTES]);
260 s.copy_from_slice(&bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES]);
261
262 if v > 3 {
263 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
264 }
265
266 Ok(Signature { r, s, v })
267 }
268}
269
270impl Serializable for SecretKey {
274 fn write_into<W: ByteWriter>(&self, target: &mut W) {
275 let mut buffer = Vec::with_capacity(SECRET_KEY_BYTES);
276 let sk_bytes: [u8; SECRET_KEY_BYTES] = self.inner.to_bytes().into();
277 buffer.extend_from_slice(&sk_bytes);
278
279 target.write_bytes(&buffer);
280 }
281}
282
283impl Deserializable for SecretKey {
284 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
285 let mut bytes: [u8; SECRET_KEY_BYTES] = source.read_array()?;
286
287 let signing_key = SigningKey::from_slice(&bytes)
288 .map_err(|_| DeserializationError::InvalidValue("Invalid secret key".to_string()))?;
289 bytes.zeroize();
290
291 Ok(Self { inner: signing_key })
292 }
293}
294
295impl Serializable for PublicKey {
296 fn write_into<W: ByteWriter>(&self, target: &mut W) {
297 let encoded = self.inner.to_encoded_point(true);
299
300 target.write_bytes(encoded.as_bytes());
301 }
302}
303
304impl Deserializable for PublicKey {
305 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
306 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
307
308 let verifying_key = VerifyingKey::from_sec1_bytes(&bytes)
309 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
310
311 Ok(Self { inner: verifying_key })
312 }
313}
314
315impl Serializable for Signature {
316 fn write_into<W: ByteWriter>(&self, target: &mut W) {
317 let mut bytes = [0u8; SIGNATURE_BYTES];
318 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
319 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
320 bytes[2 * SCALARS_SIZE_BYTES] = self.v();
321 target.write_bytes(&bytes);
322 }
323}
324
325impl Deserializable for Signature {
326 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
327 let r: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
328 let s: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
329 let v: u8 = source.read_u8()?;
330
331 Ok(Signature { r, s, v })
332 }
333}
334
335fn hash_message(message: Word) -> [u8; 32] {
340 use sha3::{Digest, Keccak256};
341 let mut hasher = Keccak256::new();
342 let message_bytes: [u8; 32] = message.into();
343 hasher.update(message_bytes);
344 hasher.finalize().into()
345}