schnorr_signatures/
lib.rs1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5use core::ops::Deref;
6#[cfg(not(feature = "std"))]
7#[macro_use]
8extern crate alloc;
9use std_shims::{
10 vec::Vec,
11 io::{self, Read, Write},
12};
13
14use rand_core::{RngCore, CryptoRng};
15
16use zeroize::{Zeroize, Zeroizing};
17
18use ciphersuite::{
19 group::{
20 ff::{Field, PrimeField},
21 Group, GroupEncoding,
22 },
23 Ciphersuite,
24};
25use multiexp::{multiexp_vartime, BatchVerifier};
26
27pub mod aggregate;
29
30#[cfg(test)]
31mod tests;
32
33#[allow(non_snake_case)]
42#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
43pub struct SchnorrSignature<C: Ciphersuite> {
44 pub R: C::G,
45 pub s: C::F,
46}
47
48impl<C: Ciphersuite> SchnorrSignature<C> {
49 pub fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
51 Ok(SchnorrSignature { R: C::read_G(reader)?, s: C::read_F(reader)? })
52 }
53
54 pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
56 writer.write_all(self.R.to_bytes().as_ref())?;
57 writer.write_all(self.s.to_repr().as_ref())
58 }
59
60 pub fn serialize(&self) -> Vec<u8> {
62 let mut buf = vec![];
63 self.write(&mut buf).unwrap();
64 buf
65 }
66
67 pub fn sign(
73 private_key: &Zeroizing<C::F>,
74 nonce: Zeroizing<C::F>,
75 challenge: C::F,
76 ) -> SchnorrSignature<C> {
77 SchnorrSignature {
78 R: C::generator() * nonce.deref(),
80 s: (challenge * private_key.deref()) + nonce.deref(),
81 }
82 }
83
84 pub fn batch_statements(&self, public_key: C::G, challenge: C::F) -> [(C::F, C::G); 3] {
87 [
91 (C::F::ONE, self.R),
93 (challenge, public_key),
95 (-self.s, C::generator()),
97 ]
98 }
99
100 #[must_use]
106 pub fn verify(&self, public_key: C::G, challenge: C::F) -> bool {
107 multiexp_vartime(&self.batch_statements(public_key, challenge)).is_identity().into()
108 }
109
110 pub fn batch_verify<R: RngCore + CryptoRng, I: Copy + Zeroize>(
116 &self,
117 rng: &mut R,
118 batch: &mut BatchVerifier<I, C::G>,
119 id: I,
120 public_key: C::G,
121 challenge: C::F,
122 ) {
123 batch.queue(rng, id, self.batch_statements(public_key, challenge));
124 }
125}