use crate::SchnorrError;
use mohan::dalek::{
constants::RISTRETTO_BASEPOINT_POINT,
ristretto::RistrettoPoint,
scalar::Scalar,
traits::{IsIdentity, VartimeMultiscalarMul},
};
use rand::{CryptoRng, RngCore};
use std::borrow::Borrow;
use std::iter;
use bacteria::{
Transcript,
TranscriptRng
};
pub trait BatchVerification {
fn append<I, J>(&mut self, basepoint_scalar: I::Item, dynamic_scalars: I, dynamic_points: J)
where
I: IntoIterator<Item = Scalar>,
I::Item: Borrow<Scalar>,
J: IntoIterator<Item = Option<RistrettoPoint>>;
}
pub struct SingleVerifier {
result: Result<(), SchnorrError>,
}
impl SingleVerifier {
pub fn verify<F>(closure: F) -> Result<(), SchnorrError>
where
F: FnOnce(&mut Self),
{
let mut verifier = Self {
result: Err(SchnorrError::InvalidSignature),
};
closure(&mut verifier);
verifier.result
}
}
impl BatchVerification for SingleVerifier {
fn append<I, J>(&mut self, basepoint_scalar: I::Item, dynamic_scalars: I, dynamic_points: J)
where
I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator<Item = Option<RistrettoPoint>>,
{
self.result = RistrettoPoint::optional_multiscalar_mul(
iter::once(basepoint_scalar).chain(dynamic_scalars),
iter::once(Some(RISTRETTO_BASEPOINT_POINT)).chain(dynamic_points),
)
.ok_or(SchnorrError::InvalidSignature)
.and_then(|result| {
if result.is_identity() {
Ok(())
} else {
Err(SchnorrError::InvalidSignature)
}
})
}
}
pub struct BatchVerifier {
rng: TranscriptRng,
basepoint_scalar: Scalar,
dyn_weights: Vec<Scalar>,
dyn_points: Vec<Option<RistrettoPoint>>,
}
impl BatchVerifier {
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
Self::with_capacity(rng, 0)
}
pub fn with_capacity<R: RngCore + CryptoRng>(mut rng: &mut R, capacity: usize) -> Self {
Self {
rng: Transcript::new(b"BatchVerifier").build_rng().finalize(&mut rng),
basepoint_scalar: Scalar::zero(),
dyn_weights: Vec::with_capacity(capacity * 2),
dyn_points: Vec::with_capacity(capacity * 2),
}
}
pub fn verify(self) -> Result<(), SchnorrError> {
let result = RistrettoPoint::optional_multiscalar_mul(
iter::once(self.basepoint_scalar).chain(self.dyn_weights.into_iter()),
iter::once(Some(RISTRETTO_BASEPOINT_POINT)).chain(self.dyn_points.into_iter()),
)
.ok_or(SchnorrError::InvalidBatch)?;
if result.is_identity() {
Ok(())
} else {
Err(SchnorrError::InvalidBatch)
}
}
}
impl BatchVerification for BatchVerifier {
fn append<I, J>(&mut self, basepoint_scalar: I::Item, dynamic_scalars: I, dynamic_points: J)
where
I: IntoIterator,
I::Item: Borrow<Scalar>,
J: IntoIterator<Item = Option<RistrettoPoint>>,
{
let mut r = Scalar::random(&mut self.rng);
self.basepoint_scalar += r * basepoint_scalar.borrow();
self.dyn_weights
.extend(dynamic_scalars.into_iter().map(|f| r * f.borrow()));
self.dyn_points.extend(dynamic_points);
mohan::zeroize_hack(&mut r);
}
}