#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use falcon_rust::falcon512::{self as fr, PublicKey as FrPublicKey, Signature as FrSignature};
use crate::{
error::Error,
keypair::domain_hash,
PUBLIC_KEY_BYTES, SIGNATURE_MAX_BYTES, SIGNATURE_MIN_BYTES,
};
pub fn verify_raw(
message: &[u8],
signature: &[u8],
public_key: &[u8],
signer_index: usize,
) -> Result<bool, Error> {
if public_key.len() != PUBLIC_KEY_BYTES {
return Err(Error::InvalidPublicKeyLength {
expected: PUBLIC_KEY_BYTES,
actual: public_key.len(),
});
}
if signature.len() < SIGNATURE_MIN_BYTES || signature.len() > SIGNATURE_MAX_BYTES {
return Err(Error::InvalidSignatureLength {
actual: signature.len(),
min: SIGNATURE_MIN_BYTES,
max: SIGNATURE_MAX_BYTES,
});
}
let pk = FrPublicKey::from_bytes(public_key).map_err(|_| Error::PublicKeyParseError {
index: signer_index,
})?;
let sig = FrSignature::from_bytes(signature).map_err(|_| Error::SignatureParseError {
index: signer_index,
})?;
let digest = domain_hash(message);
Ok(fr::verify(&digest, &sig, &pk))
}
pub fn verify_partial(
message: &[u8],
signature: &[u8],
public_key: &[u8],
signer_index: usize,
) -> Result<bool, Error> {
verify_raw(message, signature, public_key, signer_index)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::keypair::KeyPair;
fn make_signed(message: &[u8]) -> (KeyPair, Vec<u8>) {
let kp = KeyPair::generate();
let sig = kp.sign(message);
(kp, sig)
}
#[test]
fn valid_signature_verifies() {
let msg = b"chain-agnostic test message";
let (kp, sig) = make_signed(msg);
let result = verify_raw(msg, &sig, kp.public_key().as_bytes(), 0).unwrap();
assert!(result);
}
#[test]
fn tampered_message_fails() {
let (kp, sig) = make_signed(b"original");
let result = verify_raw(b"tampered", &sig, kp.public_key().as_bytes(), 0).unwrap();
assert!(!result);
}
#[test]
fn wrong_public_key_fails() {
let msg = b"some payload";
let (kp1, sig) = make_signed(msg);
let kp2 = KeyPair::generate();
let result = verify_raw(msg, &sig, kp2.public_key().as_bytes(), 0).unwrap();
assert!(!result);
}
#[test]
fn bad_pubkey_length_returns_error() {
let msg = b"payload";
let (_, sig) = make_signed(msg);
let bad_pk = vec![0u8; 32];
let err = verify_raw(msg, &sig, &bad_pk, 0).unwrap_err();
assert!(matches!(err, Error::InvalidPublicKeyLength { .. }));
}
#[test]
fn bad_sig_length_returns_error() {
let msg = b"payload";
let kp = KeyPair::generate();
let short_sig = vec![0u8; 1];
let err = verify_raw(msg, &short_sig, kp.public_key().as_bytes(), 2).unwrap_err();
assert!(matches!(err, Error::InvalidSignatureLength { .. }));
}
#[test]
fn signer_index_appears_in_parse_error() {
let msg = b"x";
let kp = KeyPair::generate();
let garbage_sig = vec![0u8; SIGNATURE_MAX_BYTES];
let err = verify_raw(msg, &garbage_sig, kp.public_key().as_bytes(), 7).unwrap_err();
let err_str = format!("{err}");
assert!(err_str.contains('7'), "signer index must appear in error: {err_str}");
}
}