use core::ops::Deref; use std::io::{self, Read, Write}; use rand_core::{RngCore, CryptoRng}; use zeroize::{Zeroize, Zeroizing}; use group::{ ff::{Field, PrimeField}, GroupEncoding, }; use multiexp::BatchVerifier; use ciphersuite::Ciphersuite; pub mod aggregate; #[cfg(test)] mod tests; /// A Schnorr signature of the form (R, s) where s = r + cx. #[allow(non_snake_case)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct SchnorrSignature { pub R: C::G, pub s: C::F, } impl SchnorrSignature { /// Read a SchnorrSignature from something implementing Read. pub fn read(reader: &mut R) -> io::Result { Ok(SchnorrSignature { R: C::read_G(reader)?, s: C::read_F(reader)? }) } /// Write a SchnorrSignature to something implementing Read. pub fn write(&self, writer: &mut W) -> io::Result<()> { writer.write_all(self.R.to_bytes().as_ref())?; writer.write_all(self.s.to_repr().as_ref()) } /// Serialize a SchnorrSignature, returning a Vec. pub fn serialize(&self) -> Vec { let mut buf = vec![]; self.write(&mut buf).unwrap(); buf } /// Sign a Schnorr signature with the given nonce for the specified challenge. pub fn sign( private_key: &Zeroizing, nonce: Zeroizing, challenge: C::F, ) -> SchnorrSignature { SchnorrSignature { // Uses deref instead of * as * returns C::F yet deref returns &C::F, preventing a copy R: C::generator() * nonce.deref(), s: (challenge * private_key.deref()) + nonce.deref(), } } /// Verify a Schnorr signature for the given key with the specified challenge. #[must_use] pub fn verify(&self, public_key: C::G, challenge: C::F) -> bool { (C::generator() * self.s) == (self.R + (public_key * challenge)) } /// Queue a signature for batch verification. pub fn batch_verify( &self, rng: &mut R, batch: &mut BatchVerifier, id: I, public_key: C::G, challenge: C::F, ) { // s = r + ca // sG == R + cA // R + cA - sG == 0 batch.queue( rng, id, [ // R (C::F::one(), self.R), // cA (challenge, public_key), // -sG (-self.s, C::generator()), ], ); } }