1use alloc::borrow::ToOwned;
2use alloc::string::ToString;
3use alloc::vec::Vec;
4use core::str::FromStr;
5
6use rand::{CryptoRng, Rng};
7
8use crate::crypto::dsa::{ecdsa_k256_keccak, falcon512_poseidon2};
9use crate::errors::AuthSchemeError;
10use crate::utils::serde::{
11 ByteReader,
12 ByteWriter,
13 Deserializable,
14 DeserializationError,
15 Serializable,
16};
17use crate::{Felt, Word};
18
19const FALCON512_POSEIDON2: u8 = 2;
24const ECDSA_K256_KECCAK: u8 = 1;
25
26const FALCON512_POSEIDON2_STR: &str = "Falcon512Poseidon2";
27const ECDSA_K256_KECCAK_STR: &str = "EcdsaK256Keccak";
28
29#[derive(Copy, Clone, Debug, PartialEq, Eq)]
32#[non_exhaustive]
33#[repr(u8)]
34pub enum AuthScheme {
35 Falcon512Poseidon2 = FALCON512_POSEIDON2,
41
42 EcdsaK256Keccak = ECDSA_K256_KECCAK,
60}
61
62impl AuthScheme {
63 pub fn as_u8(&self) -> u8 {
65 *self as u8
66 }
67}
68
69impl core::fmt::Display for AuthScheme {
70 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71 match self {
72 Self::Falcon512Poseidon2 => f.write_str(FALCON512_POSEIDON2_STR),
73 Self::EcdsaK256Keccak => f.write_str(ECDSA_K256_KECCAK_STR),
74 }
75 }
76}
77
78impl TryFrom<u8> for AuthScheme {
79 type Error = AuthSchemeError;
80
81 fn try_from(value: u8) -> Result<Self, Self::Error> {
82 match value {
83 FALCON512_POSEIDON2 => Ok(Self::Falcon512Poseidon2),
84 ECDSA_K256_KECCAK => Ok(Self::EcdsaK256Keccak),
85 value => Err(AuthSchemeError::InvalidAuthSchemeIdentifier(value.to_string())),
86 }
87 }
88}
89
90impl FromStr for AuthScheme {
91 type Err = AuthSchemeError;
92
93 fn from_str(input: &str) -> Result<Self, Self::Err> {
94 match input {
95 FALCON512_POSEIDON2_STR => Ok(AuthScheme::Falcon512Poseidon2),
96 ECDSA_K256_KECCAK_STR => Ok(AuthScheme::EcdsaK256Keccak),
97 other => Err(AuthSchemeError::InvalidAuthSchemeIdentifier(other.to_owned())),
98 }
99 }
100}
101
102impl Serializable for AuthScheme {
103 fn write_into<W: ByteWriter>(&self, target: &mut W) {
104 target.write_u8(*self as u8);
105 }
106
107 fn get_size_hint(&self) -> usize {
108 size_of::<u8>()
110 }
111}
112
113impl Deserializable for AuthScheme {
114 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
115 match source.read_u8()? {
116 FALCON512_POSEIDON2 => Ok(Self::Falcon512Poseidon2),
117 ECDSA_K256_KECCAK => Ok(Self::EcdsaK256Keccak),
118 value => Err(DeserializationError::InvalidValue(format!(
119 "auth scheme identifier `{value}` is not valid"
120 ))),
121 }
122 }
123}
124
125#[derive(Clone, Debug, PartialEq, Eq)]
130#[non_exhaustive]
131#[repr(u8)]
132pub enum AuthSecretKey {
133 Falcon512Poseidon2(falcon512_poseidon2::SecretKey) = FALCON512_POSEIDON2,
134 EcdsaK256Keccak(ecdsa_k256_keccak::SigningKey) = ECDSA_K256_KECCAK,
135}
136
137impl AuthSecretKey {
138 #[cfg(feature = "std")]
140 pub fn new_falcon512_poseidon2() -> Self {
141 Self::Falcon512Poseidon2(falcon512_poseidon2::SecretKey::new())
142 }
143
144 pub fn new_falcon512_poseidon2_with_rng<R: Rng + CryptoRng>(rng: &mut R) -> Self {
147 Self::Falcon512Poseidon2(falcon512_poseidon2::SecretKey::with_rng::<R>(rng))
148 }
149
150 #[cfg(feature = "std")]
156 pub fn new_ecdsa_k256_keccak() -> Self {
157 Self::EcdsaK256Keccak(ecdsa_k256_keccak::SigningKey::new())
158 }
159
160 pub fn new_ecdsa_k256_keccak_with_rng<R: Rng + CryptoRng>(rng: &mut R) -> Self {
166 Self::EcdsaK256Keccak(ecdsa_k256_keccak::SigningKey::with_rng::<R>(rng))
167 }
168
169 pub fn with_scheme_and_rng<R: Rng + CryptoRng>(
174 scheme: AuthScheme,
175 rng: &mut R,
176 ) -> Result<Self, AuthSchemeError> {
177 match scheme {
178 AuthScheme::Falcon512Poseidon2 => Ok(Self::new_falcon512_poseidon2_with_rng(rng)),
179 AuthScheme::EcdsaK256Keccak => Ok(Self::new_ecdsa_k256_keccak_with_rng(rng)),
180 }
181 }
182
183 #[cfg(feature = "std")]
188 pub fn with_scheme(scheme: AuthScheme) -> Result<Self, AuthSchemeError> {
189 match scheme {
190 AuthScheme::Falcon512Poseidon2 => Ok(Self::new_falcon512_poseidon2()),
191 AuthScheme::EcdsaK256Keccak => Ok(Self::new_ecdsa_k256_keccak()),
192 }
193 }
194
195 pub fn auth_scheme(&self) -> AuthScheme {
197 match self {
198 AuthSecretKey::Falcon512Poseidon2(_) => AuthScheme::Falcon512Poseidon2,
199 AuthSecretKey::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
200 }
201 }
202
203 pub fn public_key(&self) -> PublicKey {
205 match self {
206 AuthSecretKey::Falcon512Poseidon2(key) => {
207 PublicKey::Falcon512Poseidon2(key.public_key())
208 },
209 AuthSecretKey::EcdsaK256Keccak(key) => PublicKey::EcdsaK256Keccak(key.public_key()),
210 }
211 }
212
213 pub fn sign(&self, message: Word) -> Signature {
215 match self {
216 AuthSecretKey::Falcon512Poseidon2(key) => {
217 Signature::Falcon512Poseidon2(key.sign(message))
218 },
219 AuthSecretKey::EcdsaK256Keccak(key) => Signature::EcdsaK256Keccak(key.sign(message)),
220 }
221 }
222}
223
224impl Serializable for AuthSecretKey {
225 fn write_into<W: ByteWriter>(&self, target: &mut W) {
226 self.auth_scheme().write_into(target);
227 match self {
228 AuthSecretKey::Falcon512Poseidon2(key) => key.write_into(target),
229 AuthSecretKey::EcdsaK256Keccak(key) => key.write_into(target),
230 }
231 }
232}
233
234impl Deserializable for AuthSecretKey {
235 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
236 match source.read::<AuthScheme>()? {
237 AuthScheme::Falcon512Poseidon2 => {
238 let secret_key = falcon512_poseidon2::SecretKey::read_from(source)?;
239 Ok(AuthSecretKey::Falcon512Poseidon2(secret_key))
240 },
241 AuthScheme::EcdsaK256Keccak => {
242 let secret_key = ecdsa_k256_keccak::SigningKey::read_from(source)?;
243 Ok(AuthSecretKey::EcdsaK256Keccak(secret_key))
244 },
245 }
246 }
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
254pub struct PublicKeyCommitment(Word);
255
256impl core::fmt::Display for PublicKeyCommitment {
257 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258 write!(f, "{}", self.0)
259 }
260}
261
262impl From<falcon512_poseidon2::PublicKey> for PublicKeyCommitment {
263 fn from(value: falcon512_poseidon2::PublicKey) -> Self {
264 Self(value.to_commitment())
265 }
266}
267
268impl From<ecdsa_k256_keccak::PublicKey> for PublicKeyCommitment {
269 fn from(value: ecdsa_k256_keccak::PublicKey) -> Self {
270 Self(value.to_commitment())
271 }
272}
273
274impl From<PublicKeyCommitment> for Word {
275 fn from(value: PublicKeyCommitment) -> Self {
276 value.0
277 }
278}
279
280impl From<Word> for PublicKeyCommitment {
281 fn from(value: Word) -> Self {
282 Self(value)
283 }
284}
285
286#[derive(Clone, Debug)]
288#[non_exhaustive]
289pub enum PublicKey {
290 Falcon512Poseidon2(falcon512_poseidon2::PublicKey),
291 EcdsaK256Keccak(ecdsa_k256_keccak::PublicKey),
292}
293
294impl PublicKey {
295 pub fn auth_scheme(&self) -> AuthScheme {
297 match self {
298 PublicKey::Falcon512Poseidon2(_) => AuthScheme::Falcon512Poseidon2,
299 PublicKey::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
300 }
301 }
302
303 pub fn to_commitment(&self) -> PublicKeyCommitment {
305 match self {
306 PublicKey::Falcon512Poseidon2(key) => key.to_commitment().into(),
307 PublicKey::EcdsaK256Keccak(key) => key.to_commitment().into(),
308 }
309 }
310
311 pub fn verify(&self, message: Word, signature: Signature) -> bool {
313 match (self, signature) {
314 (PublicKey::Falcon512Poseidon2(key), Signature::Falcon512Poseidon2(sig)) => {
315 key.verify(message, &sig)
316 },
317 (PublicKey::EcdsaK256Keccak(key), Signature::EcdsaK256Keccak(sig)) => {
318 key.verify(message, &sig)
319 },
320 _ => false,
321 }
322 }
323}
324
325impl Serializable for PublicKey {
326 fn write_into<W: ByteWriter>(&self, target: &mut W) {
327 self.auth_scheme().write_into(target);
328 match self {
329 PublicKey::Falcon512Poseidon2(pub_key) => pub_key.write_into(target),
330 PublicKey::EcdsaK256Keccak(pub_key) => pub_key.write_into(target),
331 }
332 }
333}
334
335impl Deserializable for PublicKey {
336 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
337 match source.read::<AuthScheme>()? {
338 AuthScheme::Falcon512Poseidon2 => {
339 let pub_key = falcon512_poseidon2::PublicKey::read_from(source)?;
340 Ok(PublicKey::Falcon512Poseidon2(pub_key))
341 },
342 AuthScheme::EcdsaK256Keccak => {
343 let pub_key = ecdsa_k256_keccak::PublicKey::read_from(source)?;
344 Ok(PublicKey::EcdsaK256Keccak(pub_key))
345 },
346 }
347 }
348}
349
350#[derive(Clone, Debug)]
369#[repr(u8)]
370pub enum Signature {
371 Falcon512Poseidon2(falcon512_poseidon2::Signature) = FALCON512_POSEIDON2,
372 EcdsaK256Keccak(ecdsa_k256_keccak::Signature) = ECDSA_K256_KECCAK,
373}
374
375impl Signature {
376 pub const MAX_NUM_ENCODED_SIGNATURE_FELTS: usize = 2058;
382
383 pub fn auth_scheme(&self) -> AuthScheme {
385 match self {
386 Signature::Falcon512Poseidon2(_) => AuthScheme::Falcon512Poseidon2,
387 Signature::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
388 }
389 }
390
391 pub fn to_encoded_signature(&self, msg: Word) -> Vec<Felt> {
400 match self {
403 Signature::Falcon512Poseidon2(sig) => {
404 miden_core_lib::dsa::falcon512_poseidon2::encode_signature(sig.public_key(), sig)
405 },
406 Signature::EcdsaK256Keccak(sig) => {
407 let pk = ecdsa_k256_keccak::PublicKey::recover_from(msg, sig)
408 .expect("inferring public key from signature and message should succeed");
409 miden_core_lib::dsa::ecdsa_k256_keccak::encode_signature(&pk, sig)
410 },
411 }
412 }
413}
414
415impl From<falcon512_poseidon2::Signature> for Signature {
416 fn from(signature: falcon512_poseidon2::Signature) -> Self {
417 Signature::Falcon512Poseidon2(signature)
418 }
419}
420
421impl Serializable for Signature {
422 fn write_into<W: ByteWriter>(&self, target: &mut W) {
423 self.auth_scheme().write_into(target);
424 match self {
425 Signature::Falcon512Poseidon2(signature) => signature.write_into(target),
426 Signature::EcdsaK256Keccak(signature) => signature.write_into(target),
427 }
428 }
429}
430
431impl Deserializable for Signature {
432 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
433 match source.read::<AuthScheme>()? {
434 AuthScheme::Falcon512Poseidon2 => {
435 let signature = falcon512_poseidon2::Signature::read_from(source)?;
436 Ok(Signature::Falcon512Poseidon2(signature))
437 },
438 AuthScheme::EcdsaK256Keccak => {
439 let signature = ecdsa_k256_keccak::Signature::read_from(source)?;
440 Ok(Signature::EcdsaK256Keccak(signature))
441 },
442 }
443 }
444}
445
446#[cfg(test)]
450mod tests {
451 use rand::SeedableRng;
452 use rand_chacha::ChaCha20Rng;
453 use rstest::rstest;
454
455 use super::*;
456
457 #[rstest]
461 #[case::falcon512_poseidon2(AuthScheme::Falcon512Poseidon2, 2058)]
462 #[case::ecdsa_k256_keccak(AuthScheme::EcdsaK256Keccak, 32)]
463 fn encoded_signature_does_not_exceed_max_num_felts(
464 #[case] auth_scheme: AuthScheme,
465 #[case] expected_num_felts: usize,
466 ) -> anyhow::Result<()> {
467 let mut rng = ChaCha20Rng::from_seed([0; 32]);
468 let secret_key = AuthSecretKey::with_scheme_and_rng(auth_scheme, &mut rng)?;
469 let message = Word::from([1u32, 2, 3, 4]);
470 let signature = secret_key.sign(message);
471
472 let encoded_signature = signature.to_encoded_signature(message);
473 assert_eq!(encoded_signature.len(), expected_num_felts);
474 assert!(encoded_signature.len() <= Signature::MAX_NUM_ENCODED_SIGNATURE_FELTS);
475
476 match signature {
479 Signature::Falcon512Poseidon2(_) | Signature::EcdsaK256Keccak(_) => {},
480 }
481
482 Ok(())
483 }
484}