mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
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.
74 lines
2.2 KiB
Rust
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);
|
|
}
|
|
}
|
|
}
|