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_packed_u32_elements,
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 {
144 <Self as SequentialCommit>::to_commitment(self)
145 }
146
147 pub fn verify(&self, message: Word, signature: &Signature) -> bool {
149 let message_digest = hash_message(message);
150 self.verify_prehash(message_digest, signature)
151 }
152
153 pub fn verify_prehash(&self, message_digest: [u8; 32], signature: &Signature) -> bool {
155 let signature_inner = k256::ecdsa::Signature::from_scalars(*signature.r(), *signature.s());
156
157 match signature_inner {
158 Ok(signature) => self.inner.verify_prehash(&message_digest, &signature).is_ok(),
159 Err(_) => false,
160 }
161 }
162
163 pub fn recover_from(message: Word, signature: &Signature) -> Result<Self, PublicKeyError> {
166 let message_digest = hash_message(message);
167 let signature_data = k256::ecdsa::Signature::from_scalars(*signature.r(), *signature.s())
168 .map_err(|_| PublicKeyError::RecoveryFailed)?;
169
170 let verifying_key = k256::ecdsa::VerifyingKey::recover_from_prehash(
171 &message_digest,
172 &signature_data,
173 RecoveryId::from_byte(signature.v()).ok_or(PublicKeyError::RecoveryFailed)?,
174 )
175 .map_err(|_| PublicKeyError::RecoveryFailed)?;
176
177 Ok(Self { inner: verifying_key })
178 }
179}
180
181impl SequentialCommit for PublicKey {
182 type Commitment = Word;
183
184 fn to_elements(&self) -> Vec<Felt> {
185 bytes_to_packed_u32_elements(&self.to_bytes())
186 }
187}
188
189#[derive(Debug, Error)]
190pub enum PublicKeyError {
191 #[error("Could not recover the public key from the message and signature")]
192 RecoveryFailed,
193}
194
195#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct Signature {
215 r: [u8; SCALARS_SIZE_BYTES],
216 s: [u8; SCALARS_SIZE_BYTES],
217 v: u8,
218}
219
220impl Signature {
221 pub fn r(&self) -> &[u8; SCALARS_SIZE_BYTES] {
223 &self.r
224 }
225
226 pub fn s(&self) -> &[u8; SCALARS_SIZE_BYTES] {
228 &self.s
229 }
230
231 pub fn v(&self) -> u8 {
233 self.v
234 }
235
236 pub fn verify(&self, message: Word, pub_key: &PublicKey) -> bool {
238 pub_key.verify(message, self)
239 }
240
241 pub fn to_sec1_bytes(&self) -> [u8; SIGNATURE_STANDARD_BYTES] {
245 let mut bytes = [0u8; 2 * SCALARS_SIZE_BYTES];
246 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
247 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
248 bytes
249 }
250
251 pub fn from_sec1_bytes_and_recovery_id(
257 bytes: [u8; SIGNATURE_STANDARD_BYTES],
258 v: u8,
259 ) -> Result<Self, DeserializationError> {
260 let mut r = [0u8; SCALARS_SIZE_BYTES];
261 let mut s = [0u8; SCALARS_SIZE_BYTES];
262 r.copy_from_slice(&bytes[0..SCALARS_SIZE_BYTES]);
263 s.copy_from_slice(&bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES]);
264
265 if v > 3 {
266 return Err(DeserializationError::InvalidValue(r#"Invalid recovery ID"#.to_string()));
267 }
268
269 Ok(Signature { r, s, v })
270 }
271}
272
273impl Serializable for SecretKey {
277 fn write_into<W: ByteWriter>(&self, target: &mut W) {
278 let mut buffer = Vec::with_capacity(SECRET_KEY_BYTES);
279 let sk_bytes: [u8; SECRET_KEY_BYTES] = self.inner.to_bytes().into();
280 buffer.extend_from_slice(&sk_bytes);
281
282 target.write_bytes(&buffer);
283 }
284}
285
286impl Deserializable for SecretKey {
287 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
288 let mut bytes: [u8; SECRET_KEY_BYTES] = source.read_array()?;
289
290 let signing_key = SigningKey::from_slice(&bytes)
291 .map_err(|_| DeserializationError::InvalidValue("Invalid secret key".to_string()))?;
292 bytes.zeroize();
293
294 Ok(Self { inner: signing_key })
295 }
296}
297
298impl Serializable for PublicKey {
299 fn write_into<W: ByteWriter>(&self, target: &mut W) {
300 let encoded = self.inner.to_encoded_point(true);
302
303 target.write_bytes(encoded.as_bytes());
304 }
305}
306
307impl Deserializable for PublicKey {
308 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
309 let bytes: [u8; PUBLIC_KEY_BYTES] = source.read_array()?;
310
311 let verifying_key = VerifyingKey::from_sec1_bytes(&bytes)
312 .map_err(|_| DeserializationError::InvalidValue("Invalid public key".to_string()))?;
313
314 Ok(Self { inner: verifying_key })
315 }
316}
317
318impl Serializable for Signature {
319 fn write_into<W: ByteWriter>(&self, target: &mut W) {
320 let mut bytes = [0u8; SIGNATURE_BYTES];
321 bytes[0..SCALARS_SIZE_BYTES].copy_from_slice(self.r());
322 bytes[SCALARS_SIZE_BYTES..2 * SCALARS_SIZE_BYTES].copy_from_slice(self.s());
323 bytes[2 * SCALARS_SIZE_BYTES] = self.v();
324 target.write_bytes(&bytes);
325 }
326}
327
328impl Deserializable for Signature {
329 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
330 let r: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
331 let s: [u8; SCALARS_SIZE_BYTES] = source.read_array()?;
332 let v: u8 = source.read_u8()?;
333
334 Ok(Signature { r, s, v })
335 }
336}
337
338fn hash_message(message: Word) -> [u8; 32] {
343 use sha3::{Digest, Keccak256};
344 let mut hasher = Keccak256::new();
345 let message_bytes: [u8; 32] = message.into();
346 hasher.update(message_bytes);
347 hasher.finalize().into()
348}