use alloc::borrow::ToOwned;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::str::FromStr;
use rand::{CryptoRng, Rng};
use crate::crypto::dsa::{ecdsa_k256_keccak, falcon512_poseidon2};
use crate::errors::AuthSchemeError;
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
use crate::{Felt, Word};
const FALCON512_POSEIDON2: u8 = 2;
const ECDSA_K256_KECCAK: u8 = 1;
const FALCON512_POSEIDON2_STR: &str = "Falcon512Poseidon2";
const ECDSA_K256_KECCAK_STR: &str = "EcdsaK256Keccak";
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[repr(u8)]
pub enum AuthScheme {
Falcon512Poseidon2 = FALCON512_POSEIDON2,
EcdsaK256Keccak = ECDSA_K256_KECCAK,
}
impl AuthScheme {
pub fn as_u8(&self) -> u8 {
*self as u8
}
}
impl core::fmt::Display for AuthScheme {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Falcon512Poseidon2 => f.write_str(FALCON512_POSEIDON2_STR),
Self::EcdsaK256Keccak => f.write_str(ECDSA_K256_KECCAK_STR),
}
}
}
impl TryFrom<u8> for AuthScheme {
type Error = AuthSchemeError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
FALCON512_POSEIDON2 => Ok(Self::Falcon512Poseidon2),
ECDSA_K256_KECCAK => Ok(Self::EcdsaK256Keccak),
value => Err(AuthSchemeError::InvalidAuthSchemeIdentifier(value.to_string())),
}
}
}
impl FromStr for AuthScheme {
type Err = AuthSchemeError;
fn from_str(input: &str) -> Result<Self, Self::Err> {
match input {
FALCON512_POSEIDON2_STR => Ok(AuthScheme::Falcon512Poseidon2),
ECDSA_K256_KECCAK_STR => Ok(AuthScheme::EcdsaK256Keccak),
other => Err(AuthSchemeError::InvalidAuthSchemeIdentifier(other.to_owned())),
}
}
}
impl Serializable for AuthScheme {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_u8(*self as u8);
}
fn get_size_hint(&self) -> usize {
size_of::<u8>()
}
}
impl Deserializable for AuthScheme {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read_u8()? {
FALCON512_POSEIDON2 => Ok(Self::Falcon512Poseidon2),
ECDSA_K256_KECCAK => Ok(Self::EcdsaK256Keccak),
value => Err(DeserializationError::InvalidValue(format!(
"auth scheme identifier `{value}` is not valid"
))),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[repr(u8)]
pub enum AuthSecretKey {
Falcon512Poseidon2(falcon512_poseidon2::SecretKey) = FALCON512_POSEIDON2,
EcdsaK256Keccak(ecdsa_k256_keccak::SecretKey) = ECDSA_K256_KECCAK,
}
impl AuthSecretKey {
#[cfg(feature = "std")]
pub fn new_falcon512_poseidon2() -> Self {
Self::Falcon512Poseidon2(falcon512_poseidon2::SecretKey::new())
}
pub fn new_falcon512_poseidon2_with_rng<R: Rng>(rng: &mut R) -> Self {
Self::Falcon512Poseidon2(falcon512_poseidon2::SecretKey::with_rng(rng))
}
#[cfg(feature = "std")]
pub fn new_ecdsa_k256_keccak() -> Self {
Self::EcdsaK256Keccak(ecdsa_k256_keccak::SecretKey::new())
}
pub fn new_ecdsa_k256_keccak_with_rng<R: Rng + CryptoRng>(rng: &mut R) -> Self {
Self::EcdsaK256Keccak(ecdsa_k256_keccak::SecretKey::with_rng(rng))
}
pub fn with_scheme_and_rng<R: Rng + CryptoRng>(
scheme: AuthScheme,
rng: &mut R,
) -> Result<Self, AuthSchemeError> {
match scheme {
AuthScheme::Falcon512Poseidon2 => Ok(Self::new_falcon512_poseidon2_with_rng(rng)),
AuthScheme::EcdsaK256Keccak => Ok(Self::new_ecdsa_k256_keccak_with_rng(rng)),
}
}
#[cfg(feature = "std")]
pub fn with_scheme(scheme: AuthScheme) -> Result<Self, AuthSchemeError> {
match scheme {
AuthScheme::Falcon512Poseidon2 => Ok(Self::new_falcon512_poseidon2()),
AuthScheme::EcdsaK256Keccak => Ok(Self::new_ecdsa_k256_keccak()),
}
}
pub fn auth_scheme(&self) -> AuthScheme {
match self {
AuthSecretKey::Falcon512Poseidon2(_) => AuthScheme::Falcon512Poseidon2,
AuthSecretKey::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
}
}
pub fn public_key(&self) -> PublicKey {
match self {
AuthSecretKey::Falcon512Poseidon2(key) => {
PublicKey::Falcon512Poseidon2(key.public_key())
},
AuthSecretKey::EcdsaK256Keccak(key) => PublicKey::EcdsaK256Keccak(key.public_key()),
}
}
pub fn sign(&self, message: Word) -> Signature {
match self {
AuthSecretKey::Falcon512Poseidon2(key) => {
Signature::Falcon512Poseidon2(key.sign(message))
},
AuthSecretKey::EcdsaK256Keccak(key) => Signature::EcdsaK256Keccak(key.sign(message)),
}
}
}
impl Serializable for AuthSecretKey {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.auth_scheme().write_into(target);
match self {
AuthSecretKey::Falcon512Poseidon2(key) => key.write_into(target),
AuthSecretKey::EcdsaK256Keccak(key) => key.write_into(target),
}
}
}
impl Deserializable for AuthSecretKey {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read::<AuthScheme>()? {
AuthScheme::Falcon512Poseidon2 => {
let secret_key = falcon512_poseidon2::SecretKey::read_from(source)?;
Ok(AuthSecretKey::Falcon512Poseidon2(secret_key))
},
AuthScheme::EcdsaK256Keccak => {
let secret_key = ecdsa_k256_keccak::SecretKey::read_from(source)?;
Ok(AuthSecretKey::EcdsaK256Keccak(secret_key))
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PublicKeyCommitment(Word);
impl core::fmt::Display for PublicKeyCommitment {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<falcon512_poseidon2::PublicKey> for PublicKeyCommitment {
fn from(value: falcon512_poseidon2::PublicKey) -> Self {
Self(value.to_commitment())
}
}
impl From<PublicKeyCommitment> for Word {
fn from(value: PublicKeyCommitment) -> Self {
value.0
}
}
impl From<Word> for PublicKeyCommitment {
fn from(value: Word) -> Self {
Self(value)
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum PublicKey {
Falcon512Poseidon2(falcon512_poseidon2::PublicKey),
EcdsaK256Keccak(ecdsa_k256_keccak::PublicKey),
}
impl PublicKey {
pub fn auth_scheme(&self) -> AuthScheme {
match self {
PublicKey::Falcon512Poseidon2(_) => AuthScheme::Falcon512Poseidon2,
PublicKey::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
}
}
pub fn to_commitment(&self) -> PublicKeyCommitment {
match self {
PublicKey::Falcon512Poseidon2(key) => key.to_commitment().into(),
PublicKey::EcdsaK256Keccak(key) => key.to_commitment().into(),
}
}
pub fn verify(&self, message: Word, signature: Signature) -> bool {
match (self, signature) {
(PublicKey::Falcon512Poseidon2(key), Signature::Falcon512Poseidon2(sig)) => {
key.verify(message, &sig)
},
(PublicKey::EcdsaK256Keccak(key), Signature::EcdsaK256Keccak(sig)) => {
key.verify(message, &sig)
},
_ => false,
}
}
}
impl Serializable for PublicKey {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.auth_scheme().write_into(target);
match self {
PublicKey::Falcon512Poseidon2(pub_key) => pub_key.write_into(target),
PublicKey::EcdsaK256Keccak(pub_key) => pub_key.write_into(target),
}
}
}
impl Deserializable for PublicKey {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read::<AuthScheme>()? {
AuthScheme::Falcon512Poseidon2 => {
let pub_key = falcon512_poseidon2::PublicKey::read_from(source)?;
Ok(PublicKey::Falcon512Poseidon2(pub_key))
},
AuthScheme::EcdsaK256Keccak => {
let pub_key = ecdsa_k256_keccak::PublicKey::read_from(source)?;
Ok(PublicKey::EcdsaK256Keccak(pub_key))
},
}
}
}
#[derive(Clone, Debug)]
#[repr(u8)]
pub enum Signature {
Falcon512Poseidon2(falcon512_poseidon2::Signature) = FALCON512_POSEIDON2,
EcdsaK256Keccak(ecdsa_k256_keccak::Signature) = ECDSA_K256_KECCAK,
}
impl Signature {
pub fn auth_scheme(&self) -> AuthScheme {
match self {
Signature::Falcon512Poseidon2(_) => AuthScheme::Falcon512Poseidon2,
Signature::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
}
}
pub fn to_prepared_signature(&self, msg: Word) -> Vec<Felt> {
match self {
Signature::Falcon512Poseidon2(sig) => {
miden_core_lib::dsa::falcon512_poseidon2::encode_signature(sig.public_key(), sig)
},
Signature::EcdsaK256Keccak(sig) => {
let pk = ecdsa_k256_keccak::PublicKey::recover_from(msg, sig)
.expect("inferring public key from signature and message should succeed");
miden_core_lib::dsa::ecdsa_k256_keccak::encode_signature(&pk, sig)
},
}
}
}
impl From<falcon512_poseidon2::Signature> for Signature {
fn from(signature: falcon512_poseidon2::Signature) -> Self {
Signature::Falcon512Poseidon2(signature)
}
}
impl Serializable for Signature {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.auth_scheme().write_into(target);
match self {
Signature::Falcon512Poseidon2(signature) => signature.write_into(target),
Signature::EcdsaK256Keccak(signature) => signature.write_into(target),
}
}
}
impl Deserializable for Signature {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
match source.read::<AuthScheme>()? {
AuthScheme::Falcon512Poseidon2 => {
let signature = falcon512_poseidon2::Signature::read_from(source)?;
Ok(Signature::Falcon512Poseidon2(signature))
},
AuthScheme::EcdsaK256Keccak => {
let signature = ecdsa_k256_keccak::Signature::read_from(source)?;
Ok(Signature::EcdsaK256Keccak(signature))
},
}
}
}