bls_like/lib.rs
1//! # Aggregate BLS signature library with extensive tuning options.
2//!
3//! In short, anyone using BLS signatures should normally choose both
4//! an orientation as well as some aggregation and batching strategies
5//! These two decissions impact performance dramaticaly, but making
6//! the optimal choises requires some attentiom. This crate employs
7//! convenient abstraction boundaries between curver arithmatic,
8//! verifier routines, and aggregated and/or batched BLS signatures.
9//!
10//! ### Pairings
11//!
12//! If we have two elliptic curve with a pairing `e`, then
13//! a BLS signature `sigma = s*H(msg)` by a public key `S = s g1`
14//! can be verified with the one equation `e(g1,sigma) = e(S,H(msg))`.
15//! These simple BLS signatures are very slow to verify however
16//! because the pairing map `e` is far slower than many cryptographic
17//! primitives.
18//!
19//! Our pairing `e` maps from a small curve over `F(q)` and a larger
20//! curve over `F(q^2)` into some multipliccative group if a field,
21//! normally over `F(q^12)`. In principle, this map `e` into `F(q^12)`
22//! makes pairing based cryptography like BLS less secure than
23//! other elliptic curve based cryptography, which further slows down
24//! BLS signatures by requiring larger `q`.
25//!
26//! ### Arithmatic
27//!
28//! An almost universally applicable otimization is to seperate the
29//! "Miller loop" that computes in `F(q)` and `F(q^2)` from the slow
30//! final exponentiation that happens in `F(q^12)`. So our actual
31//! verification equation more resembles `e(-g1,sigma) e(S,H(msg)) = 1`.
32//!
33//! As one curve is smaller and hence faster, the user should choose
34//! which orientation of curves they prefer, meaning to which curve
35//! they hash, and which curves hold the signatues and public keys.
36//! In other words, your desired aggregation techniques and usage
37//! characteristics should determine if youp refer the verification
38//! equation `e(g1,sigma) = e(S,H(msg))` or the fliped form
39//! `e(sigma,g2) = e(H(msg),S)`. See `UsualBLS` and `TinyBLS`.
40//!
41//! ### Aggregation
42//!
43//! We consder BLS signatures interesting because they support
44//! dramatic optimizations when handling multiple signatures together.
45//! In fact, BLS signatures support aggregation by a third party
46//! that makes signatures smaller, not merely batch verification.
47//! All this stems from the bilinearity of `e`, meaning we reduce
48//! the number of pairings, or size of the miller loop, by appling
49//! rules like `e(x,z)e(y,z) = e(x+y,z)`, `e(x,y)e(x,z) = e(x,y+z)`,
50//! etc.
51//!
52//! In essence, our aggregation tricks fall into two categories,
53//! linear aggregation, in which only addition is used, and
54//! delinearized optimiztions, in which we multiply curve points
55//! by values unforseeable to the signers.
56//! In general, linear techniques provide much better performance,
57//! but require stronger invariants be maintained by the caller,
58//! like messages being distinct, or limited signer sets with
59//! proofs-of-possession. Also, the delinearized techniques remain
60//! secure without tricky assumptions, but require more computation.
61//!
62//! ### Verification
63//!
64//! We can often further reduce the pairings required in the
65//! verification equation, beyond the naieve information tracked
66//! by the aggregated signature itself. Aggregated signature must
67//! state all the individual messages and/or public keys, but
68//! verifiers may collapse anything permitted.
69//! We thus encounter aggregation-like decissions that impact
70//! verifier performance.
71//!
72//! We therefore provide an abstract interface that permits
73//! doing further aggregation and/or passing any aggregate signature
74//! to any verification routine.
75//!
76//! As a rule, we also attempt to batch normalize different arithmatic
77//! outputs, but concievably small signer set sizes might make this
78//! a pessimization.
79//!
80//!
81//!
82
83
84// #![feature(generic_associated_types)]
85#![feature(associated_type_defaults)]
86
87#[macro_use]
88extern crate arrayref;
89
90// #[macro_use]
91extern crate ff;
92
93extern crate paired as pairing;
94extern crate rand;
95extern crate sha3;
96
97use std::borrow::Borrow;
98
99use ff::{Field, PrimeField, ScalarEngine, SqrtField}; // PrimeFieldDecodingError, PrimeFieldRepr
100use pairing::{CurveAffine, CurveProjective, Engine};
101use rand::{Rand, Rng};
102
103pub mod single;
104pub mod distinct;
105pub mod pop;
106pub mod delinear;
107pub mod verifiers;
108// pub mod delinear;
109
110
111pub use single::{PublicKey,KeypairVT,Keypair,SecretKeyVT,SecretKey,Signature};
112
113
114/// Internal message hash size.
115///
116/// We choose 256 bits here so that birthday bound attacks cannot
117/// find messages with the same hash.
118const MESSAGE_SIZE: usize = 32;
119
120/// Internal message hash type. Short for frequent rehashing
121/// by `HashMap`, etc.
122#[derive(Debug,Copy,Clone,Hash,PartialEq,Eq,PartialOrd,Ord)]
123pub struct Message(pub [u8; MESSAGE_SIZE]);
124
125impl Message {
126 pub fn new(context: &'static [u8], message: &[u8]) -> Message {
127 use sha3::{Shake128, digest::{Input,ExtendableOutput,XofReader}};
128 let mut h = Shake128::default();
129 h.input(context);
130 let l = message.len() as u64;
131 h.input(l.to_le_bytes());
132 h.input(message);
133 // let mut t = ::merlin::Transcript::new(context);
134 // t.append_message(b"", message);
135 let mut msg = [0u8; MESSAGE_SIZE];
136 h.xof_result().read(&mut msg[..]);
137 // t.challenge_bytes(b"", &mut msg);
138 Message(msg)
139 }
140
141 pub fn hash_to_signature_curve<E: EngineBLS>(&self) -> E::SignatureGroup {
142 E::hash_to_signature_curve(&self.0[..])
143 }
144}
145
146impl<'a> From<&'a [u8]> for Message {
147 fn from(x: &[u8]) -> Message { Message::new(b"",x) }
148}
149
150
151/// A weakening of `pairing::Engine` to permit transposing the groups.
152///
153/// You cannot transpose the two groups in a `pairing::Engine` without
154/// first providing panicing implementations of `pairing::PrimeField`
155/// for `Engine::Fqe`, which is not a prime field, and second,
156/// providing wrapper types for the projective and affine group
157/// representations, which makes interacting with the original
158/// `pairing::Engine` annoying. This trait merely replicates
159/// transposable functionality from `pairing::Engine` by removing
160/// the fields of definition, but leaves the actual BLS signature
161/// scheme to wrapper types.
162///
163/// We also extract two functions users may with to override:
164/// random scalar generation and hashing to the singature curve.
165pub trait EngineBLS {
166 type Engine: Engine + ScalarEngine<Fr = Self::Scalar>;
167 type Scalar: PrimeField + SqrtField; // = <Self::Engine as ScalarEngine>::Fr;
168
169 /// Group where BLS public keys live
170 ///
171 /// You should take this to be the `Engine::G1` curve usually
172 /// becuase all verifiers perform additions on this curve, or
173 /// even scalar multiplicaitons with delinearization.
174 type PublicKeyGroup:
175 CurveProjective<Engine = Self::Engine, Scalar = Self::Scalar>
176 + Into<<Self::PublicKeyGroup as CurveProjective>::Affine>;
177
178 /// Group where BLS signatures live
179 ///
180 /// You should take this to be the `Engine::G2` curve usually
181 /// becuase only aggregators perform additions on this curve, or
182 /// scalar multiplicaitons with delinearization.
183 type SignatureGroup:
184 CurveProjective<Engine = Self::Engine, Scalar = Self::Scalar>
185 + Into<<Self::SignatureGroup as CurveProjective>::Affine>;
186
187 /// Generate a random scalar for use as a secret key.
188 fn generate<R: Rng>(rng: &mut R) -> Self::Scalar {
189 Self::Scalar::rand(rng)
190 }
191
192 /// Hash one message to the signature curve.
193 fn hash_to_signature_curve<M: Borrow<[u8]>>(message: M) -> Self::SignatureGroup {
194 <Self::SignatureGroup as CurveProjective>::hash(message.borrow())
195 }
196
197 /// Run the Miller loop from `Engine` but orients its arguments
198 /// to be a `SignatureGroup` and `PublicKeyGroup`.
199 fn miller_loop<'a,I>(i: I) -> <Self::Engine as Engine>::Fqk
200 where
201 I: IntoIterator<Item = (
202 &'a <<Self::PublicKeyGroup as CurveProjective>::Affine as CurveAffine>::Prepared,
203 &'a <<Self::SignatureGroup as CurveProjective>::Affine as CurveAffine>::Prepared,
204 )>;
205
206 /// Perform final exponentiation on the result of a Miller loop.
207 fn final_exponentiation(e: &<Self::Engine as Engine>::Fqk) -> Option<<Self::Engine as Engine>::Fqk> {
208 Self::Engine::final_exponentiation(e)
209 }
210
211 /// Performs a pairing operation `e(p, q)` by calling `Engine::pairing`
212 /// but orients its arguments to be a `PublicKeyGroup` and `SignatureGroup`.
213 fn pairing<G1,G2>(p: G1, q: G2) -> <Self::Engine as Engine>::Fqk
214 where
215 G1: Into<<Self::PublicKeyGroup as CurveProjective>::Affine>,
216 G2: Into<<Self::SignatureGroup as CurveProjective>::Affine>;
217 /*
218 {
219 Self::final_exponentiation(&Self::miller_loop(
220 [(&(p.into().prepare()), &(q.into().prepare()))].into_iter(),
221 )).unwrap()
222 }
223 */
224
225 /// Implement verification equation for aggregate BLS signatures
226 /// provided as prepared points
227 ///
228 /// This low-level routine does no verification of critical security
229 /// properties like message distinctness. It exists purely to
230 /// simplify replacing mid-level routines with optimized variants,
231 /// like versions that cache public key preperation or use fewer pairings.
232 fn verify_prepared<'a,I>(
233 signature: &'a <<Self::SignatureGroup as CurveProjective>::Affine as CurveAffine>::Prepared,
234 inputs: I
235 ) -> bool
236 where
237 I: IntoIterator<Item = (
238 &'a <<Self::PublicKeyGroup as CurveProjective>::Affine as CurveAffine>::Prepared,
239 &'a <<Self::SignatureGroup as CurveProjective>::Affine as CurveAffine>::Prepared,
240 )>
241 {
242 // Use a polymorphic static or const if we ever get either.
243 let mut g1_minus_generator = <Self::PublicKeyGroup as CurveProjective>::Affine::one();
244 g1_minus_generator.negate();
245 Self::final_exponentiation( & Self::miller_loop(
246 inputs.into_iter().map(|t| t) // reborrow hack
247 .chain(::std::iter::once( (& g1_minus_generator.prepare(), signature) ))
248 ) ).unwrap() == <Self::Engine as Engine>::Fqk::one()
249 }
250}
251
252
253pub type PublicKeyProjective<E> = <E as EngineBLS>::PublicKeyGroup;
254pub type PublicKeyAffine<E> = <<E as EngineBLS>::PublicKeyGroup as CurveProjective>::Affine;
255
256pub type SignatureProjective<E> = <E as EngineBLS>::SignatureGroup;
257pub type SignatureAffine<E> = <<E as EngineBLS>::SignatureGroup as CurveProjective>::Affine;
258
259
260
261
262/// Usual aggregate BLS signature scheme on ZCash's BLS12-381 curve.
263pub type ZBLS = UsualBLS<::pairing::bls12_381::Bls12>;
264
265/// Usual aggregate BLS signature scheme on ZCash's BLS12-381 curve.
266pub const Z_BLS : ZBLS = UsualBLS(::pairing::bls12_381::Bls12);
267
268
269/// Usual BLS variant with tiny 48 byte public keys and 96 byte signatures.
270///
271/// We favor this variant because verifiers always perform
272/// `O(signers)` additions on the `PublicKeyGroup`, or worse 128 bit
273/// scalar multiplications with delinearization.
274/// We also orient this variant to match zcash's traits.
275#[derive(Default)]
276pub struct UsualBLS<E: Engine>(pub E);
277
278impl<E: Engine> EngineBLS for UsualBLS<E> {
279 type Engine = E;
280 type Scalar = <Self::Engine as ScalarEngine>::Fr;
281 type PublicKeyGroup = E::G1;
282 type SignatureGroup = E::G2;
283
284 fn miller_loop<'a,I>(i: I) -> E::Fqk
285 where
286 I: IntoIterator<Item = (
287 &'a <E::G1Affine as CurveAffine>::Prepared,
288 &'a <E::G2Affine as CurveAffine>::Prepared,
289 )>,
290 {
291 // We require an ugly unecessary allocation here because
292 // zcash's pairing library cnsumes an iterator of references
293 // to tuples of references, which always requires
294 let i = i.into_iter().map(|t| t)
295 .collect::<Vec<(&<E::G1Affine as CurveAffine>::Prepared,&<E::G2Affine as CurveAffine>::Prepared)>>();
296 E::miller_loop(&i)
297 }
298
299 fn pairing<G1,G2>(p: G1, q: G2) -> E::Fqk
300 where
301 G1: Into<E::G1Affine>,
302 G2: Into<E::G2Affine>,
303 {
304 E::pairing(p,q)
305 }
306}
307
308
309/// Infrequently used BLS variant with tiny 48 byte signatures and 96 byte public keys,
310///
311/// We recommend gainst this variant by default because verifiers
312/// always perform `O(signers)` additions on the `PublicKeyGroup`,
313/// or worse 128 bit scalar multiplications with delinearization.
314/// Yet, there are specific use cases where this variant performs
315/// better. We swapy two group roles relative to zcash here.
316#[derive(Default)]
317pub struct TinyBLS<E: Engine>(pub E);
318
319impl<E: Engine> EngineBLS for TinyBLS<E> {
320 type Engine = E;
321 type Scalar = <Self::Engine as ScalarEngine>::Fr;
322 type PublicKeyGroup = E::G2;
323 type SignatureGroup = E::G1;
324
325 fn miller_loop<'a,I>(i: I) -> E::Fqk
326 where
327 I: IntoIterator<Item = (
328 &'a <E::G2Affine as CurveAffine>::Prepared,
329 &'a <E::G1Affine as CurveAffine>::Prepared,
330 )>,
331 {
332 // We require an ugly unecessary allocation here because
333 // zcash's pairing library cnsumes an iterator of references
334 // to tuples of references, which always requires
335 let i = i.into_iter().map(|(x,y)| (y,x))
336 .collect::<Vec<(&<E::G1Affine as CurveAffine>::Prepared,&<E::G2Affine as CurveAffine>::Prepared)>>();
337 E::miller_loop(&i)
338 }
339
340 fn pairing<G2,G1>(p: G2, q: G1) -> E::Fqk
341 where
342 G1: Into<E::G1Affine>,
343 G2: Into<E::G2Affine>,
344 {
345 E::pairing(q,p)
346 }
347}
348
349
350/// Representation of an aggregated BLS signature.
351///
352/// We implement this trait only for borrows of appropriate structs
353/// because otherwise we'd need extensive lifetime plumbing here,
354/// due to the absence of assocaited type constructers (ATCs).
355/// We shall make `messages_and_publickeys` take `&sefl` and
356/// remove these limitations in the future once ATCs stabalize,
357/// thus removing `PKG`. See [Rust RFC 1598](https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md)
358/// We shall eventually remove MnPK entirely whenever `-> impl Trait`
359/// in traits gets stabalized. See [Rust RFCs 1522, 1951, and 2071](https://github.com/rust-lang/rust/issues/34511
360pub trait Signed: Sized {
361 type E: EngineBLS;
362
363 /// Return the aggregated signature
364 fn signature(&self) -> Signature<Self::E>;
365
366 type M: Borrow<Message> = Message;
367 type PKG: Borrow<PublicKey<Self::E>> = PublicKey<Self::E>;
368
369 /// Iterator over messages and public key reference pairs.
370 type PKnM: Iterator<Item = (Self::M,Self::PKG)> + ExactSizeIterator;
371 // type PKnM<'a>: Iterator<Item = (
372 // &'a <<Self as Signed<'a>>::E as EngineBLS>::PublicKeyGroup,
373 // &'a Self::M,
374 // )> + DoubleEndedIterator + ExactSizeIterator + 'a;
375
376 /// Returns an iterator over messages and public key reference for
377 /// pairings, often only partially aggregated.
378 fn messages_and_publickeys(self) -> Self::PKnM;
379 // fn messages_and_publickeys<'a>(&'s self) -> PKnM<'a>
380 // -> impl Iterator<Item = (&'a Self::M, &'a Self::E::PublicKeyGroup)> + 'a;
381
382 /// Appropriate BLS signature verification for the `Self` type.
383 ///
384 /// We use `verify_simple` as a default implementation because
385 /// it supports unstable `self.messages_and_publickeys()` securely
386 /// by calling it only once, and does not expect pulic key points
387 /// to be normalized, but this should usually be replaced by more
388 /// optimized variants.
389 fn verify(self) -> bool {
390 verifiers::verify_simple(self)
391 }
392}
393
394
395
396#[cfg(test)]
397mod tests {
398 // use super::*;
399
400 // use rand::{SeedableRng, XorShiftRng};
401
402 // #[test]
403 // fn foo() { }
404}
405