use alloc::vec::Vec;
use rand::{CryptoRng, Rng};
use crate::crypto::dsa::{ecdsa_k256_keccak, rpo_falcon512};
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
use crate::{AuthSchemeError, Felt, Hasher, Word};
const RPO_FALCON_512: u8 = 0;
const ECDSA_K256_KECCAK: u8 = 1;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[repr(u8)]
pub enum AuthScheme {
RpoFalcon512 = RPO_FALCON_512,
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::RpoFalcon512 => f.write_str("RpoFalcon512"),
Self::EcdsaK256Keccak => f.write_str("EcdsaK256Keccak"),
}
}
}
impl TryFrom<u8> for AuthScheme {
type Error = AuthSchemeError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
RPO_FALCON_512 => Ok(Self::RpoFalcon512),
ECDSA_K256_KECCAK => Ok(Self::EcdsaK256Keccak),
value => Err(AuthSchemeError::InvalidAuthSchemeIdentifier(value)),
}
}
}
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()? {
RPO_FALCON_512 => Ok(Self::RpoFalcon512),
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 {
RpoFalcon512(rpo_falcon512::SecretKey) = RPO_FALCON_512,
EcdsaK256Keccak(ecdsa_k256_keccak::SecretKey) = ECDSA_K256_KECCAK,
}
impl AuthSecretKey {
#[cfg(feature = "std")]
pub fn new_rpo_falcon512() -> Self {
Self::RpoFalcon512(rpo_falcon512::SecretKey::new())
}
pub fn new_rpo_falcon512_with_rng<R: Rng>(rng: &mut R) -> Self {
Self::RpoFalcon512(rpo_falcon512::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 auth_scheme(&self) -> AuthScheme {
match self {
AuthSecretKey::RpoFalcon512(_) => AuthScheme::RpoFalcon512,
AuthSecretKey::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
}
}
pub fn public_key(&self) -> PublicKey {
match self {
AuthSecretKey::RpoFalcon512(key) => PublicKey::RpoFalcon512(key.public_key()),
AuthSecretKey::EcdsaK256Keccak(key) => PublicKey::EcdsaK256Keccak(key.public_key()),
}
}
pub fn sign(&self, message: Word) -> Signature {
match self {
AuthSecretKey::RpoFalcon512(key) => Signature::RpoFalcon512(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::RpoFalcon512(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::RpoFalcon512 => {
let secret_key = rpo_falcon512::SecretKey::read_from(source)?;
Ok(AuthSecretKey::RpoFalcon512(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<rpo_falcon512::PublicKey> for PublicKeyCommitment {
fn from(value: rpo_falcon512::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 {
RpoFalcon512(rpo_falcon512::PublicKey),
EcdsaK256Keccak(ecdsa_k256_keccak::PublicKey),
}
impl PublicKey {
pub fn auth_scheme(&self) -> AuthScheme {
match self {
PublicKey::RpoFalcon512(_) => AuthScheme::RpoFalcon512,
PublicKey::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
}
}
pub fn to_commitment(&self) -> PublicKeyCommitment {
match self {
PublicKey::RpoFalcon512(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::RpoFalcon512(key), Signature::RpoFalcon512(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::RpoFalcon512(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::RpoFalcon512 => {
let pub_key = rpo_falcon512::PublicKey::read_from(source)?;
Ok(PublicKey::RpoFalcon512(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 {
RpoFalcon512(rpo_falcon512::Signature) = RPO_FALCON_512,
EcdsaK256Keccak(ecdsa_k256_keccak::Signature) = ECDSA_K256_KECCAK,
}
impl Signature {
pub fn auth_scheme(&self) -> AuthScheme {
match self {
Signature::RpoFalcon512(_) => AuthScheme::RpoFalcon512,
Signature::EcdsaK256Keccak(_) => AuthScheme::EcdsaK256Keccak,
}
}
pub fn to_prepared_signature(&self, msg: Word) -> Vec<Felt> {
let mut result = match self {
Signature::RpoFalcon512(sig) => prepare_rpo_falcon512_signature(sig),
Signature::EcdsaK256Keccak(sig) => miden_stdlib::prepare_ecdsa_signature(msg, sig)
.expect("inferring public key from signature and message should succeed"),
};
result.reverse();
result
}
}
impl From<rpo_falcon512::Signature> for Signature {
fn from(signature: rpo_falcon512::Signature) -> Self {
Signature::RpoFalcon512(signature)
}
}
impl Serializable for Signature {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.auth_scheme().write_into(target);
match self {
Signature::RpoFalcon512(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::RpoFalcon512 => {
let signature = rpo_falcon512::Signature::read_from(source)?;
Ok(Signature::RpoFalcon512(signature))
},
AuthScheme::EcdsaK256Keccak => {
let signature = ecdsa_k256_keccak::Signature::read_from(source)?;
Ok(Signature::EcdsaK256Keccak(signature))
},
}
}
}
fn prepare_rpo_falcon512_signature(sig: &rpo_falcon512::Signature) -> Vec<Felt> {
use rpo_falcon512::Polynomial;
let nonce = sig.nonce();
let s2 = sig.sig_poly();
let h = sig.public_key();
let pi = Polynomial::mul_modulo_p(h, s2);
let mut polynomials: Vec<Felt> =
h.coefficients.iter().map(|a| Felt::from(a.value() as u32)).collect();
polynomials.extend(s2.coefficients.iter().map(|a| Felt::from(a.value() as u32)));
polynomials.extend(pi.iter().map(|a| Felt::new(*a)));
let digest_polynomials = Hasher::hash_elements(&polynomials);
let challenge = (digest_polynomials[0], digest_polynomials[1]);
let mut result: Vec<Felt> = vec![challenge.0, challenge.1];
result.extend_from_slice(&polynomials);
result.extend_from_slice(&nonce.to_elements());
result
}