#[cfg(test)]
extern crate alloc;
use crate::bls12_381::*;
use ark_ec::AffineRepr;
use sp_std::vec::Vec;
use ark_bls12_381::G2Affine;
pub trait SignatureVerifier {
fn verify(pubkey: Vec<u8>, sig: Vec<u8>, msg: Vec<u8>) -> Result<(), CryptoError>;
}
pub struct QuicknetVerifier;
impl SignatureVerifier for QuicknetVerifier {
fn verify(
beacon_pk_bytes: Vec<u8>,
serialized_sig_bytes: Vec<u8>,
serialized_messages_bytes: Vec<u8>,
) -> Result<(), CryptoError> {
let beacon_pk = decode_g2(&beacon_pk_bytes)?;
let asig = decode_g1(&serialized_sig_bytes)?;
let amsg = decode_g1(&serialized_messages_bytes)?;
let g2 = G2Affine::generator();
if !fast_pairing_opt(asig, g2, amsg, beacon_pk) {
return Err(CryptoError::InvalidSignature);
}
Ok(())
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::test_utils::*;
fn get_beacon_pk() -> Vec<u8> {
let pk_bytes = b"83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a";
hex::decode(pk_bytes).unwrap()
}
#[test]
fn test_verifier_works_with_drand_quicknet_values() {
let beacon_pk_bytes = get_beacon_pk();
let (asig, amsg, _pulses) = get(vec![PULSE1000]);
let res = QuicknetVerifier::verify(
beacon_pk_bytes.try_into().unwrap(),
asig.clone(),
amsg.clone(),
);
assert!(res.is_ok());
}
#[test]
fn test_verifier_returns_errors_if_verification_fails() {
let beacon_pk_bytes = get_beacon_pk();
let (asig, _amsg, _pulses) = get(vec![PULSE1000]);
let (_asig, amsg, _pulses) = get(vec![PULSE1001]);
let res = QuicknetVerifier::verify(
beacon_pk_bytes.try_into().unwrap(),
asig.clone(),
amsg.clone(),
);
assert!(res.is_err());
assert!(matches!(res, Err(CryptoError::InvalidSignature)));
}
#[test]
fn can_verify_invalid_with_bad_message() {
let beacon_pk_bytes = get_beacon_pk();
let (asig, _ignore_amsg, _pulses) = get(vec![PULSE1000]);
let (_ignore_asig, amsg, _ignore_pulses) = get(vec![PULSE1001]);
let res = QuicknetVerifier::verify(beacon_pk_bytes.try_into().unwrap(), asig, amsg);
assert!(res.is_err());
assert!(matches!(res, Err(CryptoError::InvalidSignature)));
}
#[test]
fn test_verifier_handles_invalid_public_key() {
let invalid_pk = vec![0u8; 10]; let (asig, amsg, _) = get(vec![PULSE1000]);
let result = QuicknetVerifier::verify(invalid_pk, asig, amsg);
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::DeserializeG2Failure)));
}
#[test]
fn test_verifier_handles_invalid_signature() {
let beacon_pk_bytes = get_beacon_pk();
let invalid_sig = vec![0u8; 10]; let (_, amsg, _) = get(vec![PULSE1000]);
let result = QuicknetVerifier::verify(beacon_pk_bytes, invalid_sig, amsg);
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::DeserializeG1Failure)));
}
#[test]
fn test_verifier_handles_invalid_message() {
let beacon_pk_bytes = get_beacon_pk();
let (asig, _, _) = get(vec![PULSE1000]);
let invalid_msg = vec![0u8; 10];
let result = QuicknetVerifier::verify(beacon_pk_bytes, asig, invalid_msg);
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::DeserializeG1Failure)));
}
#[test]
fn test_verifier_with_empty_inputs() {
let result = QuicknetVerifier::verify(vec![], vec![], vec![]);
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::DeserializeG2Failure)));
}
#[test]
fn test_verifier_with_corrupted_signature() {
let beacon_pk_bytes = get_beacon_pk();
let (mut asig, amsg, _) = get(vec![PULSE1000]);
if !asig.is_empty() {
asig[0] ^= 0x01;
}
let res = QuicknetVerifier::verify(beacon_pk_bytes, asig, amsg);
assert!(res.is_err());
assert!(matches!(res, Err(CryptoError::DeserializeG1Failure)));
}
}