use super::{FalconScheme, FalconSignature, FalconSigningKey, FalconVerificationKey, InnerFalcon};
use crate::error::*;
pub type EthFalconVerifyingKey = [u8; fn_dsa_comm::eth_falcon::PUBKEY_NTT_PACKED_LENGTH];
pub type EthFalconSignature = [u8; fn_dsa_comm::eth_falcon::SIGNATURE_ABI_PACKED_LENGTH];
impl TryFrom<FalconVerificationKey> for EthFalconVerifyingKey {
type Error = Error;
fn try_from(public_key: FalconVerificationKey) -> Result<Self> {
Self::try_from(&public_key)
}
}
impl TryFrom<&FalconVerificationKey> for EthFalconVerifyingKey {
type Error = Error;
fn try_from(public_key: &FalconVerificationKey) -> Result<Self> {
if public_key.0.scheme == FalconScheme::Ethereum {
fn_dsa_comm::eth_falcon::decode_pubkey_to_ntt_packed(public_key.0.value.as_ref())
.map_err(|e| Error::FnDsaError(e.to_string()))
} else {
Err(Error::InvalidSchemeStr(
"Only ETHFALCON public key is supported".to_string(),
))
}
}
}
impl TryFrom<FalconSignature> for EthFalconSignature {
type Error = Error;
fn try_from(signature: FalconSignature) -> Result<Self> {
Self::try_from(&signature)
}
}
impl TryFrom<&FalconSignature> for EthFalconSignature {
type Error = Error;
fn try_from(signature: &FalconSignature) -> Result<Self> {
if signature.0.scheme == FalconScheme::Ethereum {
fn_dsa_comm::eth_falcon::decode_signature_to_packed(signature.0.value.as_ref())
.map_err(|e| Error::FnDsaError(e.to_string()))
} else {
Err(Error::InvalidSchemeStr(
"Only ETHFALCON signature is supported".to_string(),
))
}
}
}
impl FalconScheme {
#[cfg(feature = "sign")]
pub fn sign(&self, message: &[u8], signing_key: &FalconSigningKey) -> Result<FalconSignature> {
match self {
Self::Ethereum => {
use fn_dsa_sign::{
eth_falcon::{generate_salt, EthFalconSigningKey},
signature_size, SigningKey, SigningKeyStandard, FN_DSA_LOGN_512,
};
let mut sk = SigningKeyStandard::decode(signing_key.0.value.as_ref())
.ok_or_else(|| Error::FnDsaError("Invalid signing key".to_string()))?;
let salt = generate_salt();
let mut sig = [0u8; signature_size(FN_DSA_LOGN_512)];
sk.sign_eth(message, &salt, &mut sig);
Ok(InnerFalcon {
scheme: *self,
value: sig.to_vec(),
}
.into())
}
_ => self.sign_inner(message, signing_key),
}
}
#[cfg(feature = "vrfy")]
pub fn verify(
&self,
message: &[u8],
signature: &FalconSignature,
verification_key: &FalconVerificationKey,
) -> Result<()> {
match self {
Self::Ethereum => {
use fn_dsa_comm::eth_falcon::{decode_signature_to_packed, SALT_LEN};
use fn_dsa_vrfy::eth_falcon::EthFalconVerifyingKey as Efvk;
let pk = EthFalconVerifyingKey::try_from(verification_key)?;
let pk = Efvk::decode(&pk);
let mut salt = [0u8; SALT_LEN];
salt.copy_from_slice(&signature.0.value[1..SALT_LEN + 1]);
let sig = decode_signature_to_packed(&signature.0.value)
.map_err(|e| Error::FnDsaError(e.to_string()))?;
if pk.verify(message, &salt, &sig) {
Ok(())
} else {
Err(Error::FnDsaError("Invalid signature".to_string()))
}
}
_ => self.verify_inner(message, signature, verification_key),
}
}
}
impl FalconSigningKey {
pub fn into_ethereum(self) -> Result<Self> {
self.convert(FalconScheme::Dsa512, FalconScheme::Ethereum)
}
pub fn into_dsa512(self) -> Result<Self> {
self.convert(FalconScheme::Ethereum, FalconScheme::Dsa512)
}
fn convert(self, from: FalconScheme, to: FalconScheme) -> Result<Self> {
if self.0.scheme == from {
Ok(InnerFalcon {
scheme: to,
value: self.0.value,
}
.into())
} else {
Err(Error::InvalidSchemeStr(format!(
"Unsupported scheme change from {} to {}",
self.0.scheme, to,
)))
}
}
}