Files
serai/crypto/frost/src/tests/schnorr.rs
Luke Parker 469ce9106b Implement a binary search for BatchVerifier blame
Adds helper functions to verify and, on failure, blame, which move an 
unwrap from callers into multiexp where it's guaranteed to be safe and 
easily verified to be proper.

Closes https://github.com/serai-dex/serai/issues/10.
2022-05-27 02:01:01 -04:00

74 lines
2.2 KiB
Rust

use rand_core::{RngCore, CryptoRng};
use ff::Field;
use crate::{Curve, schnorr, algorithm::SchnorrSignature};
pub(crate) fn sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
let private_key = C::F::random(&mut *rng);
let nonce = C::F::random(&mut *rng);
let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM
assert!(
schnorr::verify::<C>(
C::generator_table() * private_key,
challenge,
&schnorr::sign(private_key, nonce, challenge)
)
);
}
// The above sign function verifies signing works
// This verifies invalid signatures don't pass, using zero signatures, which should effectively be
// random
pub(crate) fn verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
assert!(
!schnorr::verify::<C>(
C::generator_table() * C::F::random(&mut *rng),
C::F::random(rng),
&SchnorrSignature { R: C::generator_table() * C::F::zero(), s: C::F::zero() }
)
);
}
pub(crate) fn batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
// Create 5 signatures
let mut keys = vec![];
let mut challenges = vec![];
let mut sigs = vec![];
for i in 0 .. 5 {
keys.push(C::F::random(&mut *rng));
challenges.push(C::F::random(&mut *rng));
sigs.push(schnorr::sign::<C>(keys[i], C::F::random(&mut *rng), challenges[i]));
}
// Batch verify
let triplets = (0 .. 5).map(
|i| (u16::try_from(i + 1).unwrap(), C::generator_table() * keys[i], challenges[i], sigs[i])
).collect::<Vec<_>>();
schnorr::batch_verify(rng, &triplets).unwrap();
// Shift 1 from s from one to another and verify it fails
// This test will fail if unique factors aren't used per-signature, hence its inclusion
{
let mut triplets = triplets.clone();
triplets[1].3.s += C::F::one();
triplets[2].3.s -= C::F::one();
if let Err(blame) = schnorr::batch_verify(rng, &triplets) {
assert_eq!(blame, 2);
} else {
assert!(false);
}
}
// Make sure a completely invalid signature fails when included
for i in 0 .. 5 {
let mut triplets = triplets.clone();
triplets[i].3.s = C::F::random(&mut *rng);
if let Err(blame) = schnorr::batch_verify(rng, &triplets) {
assert_eq!(blame, u16::try_from(i + 1).unwrap());
} else {
assert!(false);
}
}
}