w3f_bls/
engine.rs

1//! ## Adaptation of `ark_ec::PairingEngine` to BLS-like signatures.
2//!
3//! We provide an `EngineBLS` trait that adapts `pairing::Engine`
4//! to BLS-like signatures by permitting the group roles to be
5//! transposed, which involves removing the field of definition,
6//! while retaining the correct associations.  
7//!
8//! We support same-message aggregation strategies using wrappers
9//! that satisfy `EngineBLS` as well, primarily because these
10//! strategies must ocntroll access to the public key type.
11//!
12//! In future, we should support [Pixel](https://github.com/w3f/bls/issues/4)
13//! by adding wrapper that replace `SignatureGroup` with a product
14//! of both groups.  I think this requires abstracting `CruveAffine`
15//! and `CruveProjective` without their base fields and wNAF windows,
16//! but still with their affine, projective, and compressed forms,
17//! and batch normalization.
18
19use core::borrow::Borrow;
20use core::ops::MulAssign;
21
22use alloc::{vec, vec::Vec};
23
24use ark_ec::hashing::curve_maps::wb::{WBConfig, WBMap};
25use ark_ec::hashing::{
26    map_to_curve_hasher::{MapToCurve, MapToCurveBasedHasher},
27    HashToCurve,
28};
29use ark_ec::{
30    pairing::{MillerLoopOutput, Pairing, PairingOutput},
31    AffineRepr, CurveGroup,
32};
33use ark_ff::field_hashers::{DefaultFieldHasher, HashToField};
34use ark_ff::{Field, PrimeField, UniformRand, Zero};
35use ark_serialize::CanonicalSerialize;
36use rand::Rng;
37use rand_core::RngCore;
38
39use core::fmt::Debug;
40
41use sha2::Sha256; //IETF standard asks for SHA256
42
43use ark_ec::bls12::Bls12Config;
44use core::marker::PhantomData;
45
46// Expand SHA256 from 256 bits to 1024 bits.
47// let output_bits = 1024;
48// let output_bytes = 1024 / 8;
49// let mut hasher = FullDomainHash::<Sha256>::new(output_bytes).unwrap();
50// hasher.update(b"ATTACK AT DAWN");
51// let result = hasher.finalize_boxed().into_vec();
52
53/// A weakening of `pairing::Engine` to permit transposing the groups.
54///
55/// You cannot transpose the two groups in a `pairing::Engine` without
56/// first providing panicing implementations of `pairing::PrimeField`
57/// for `Engine::Fqe`, which is not a prime field, and second,
58/// providing wrapper types for the projective and affine group
59/// representations, which makes interacting with the original
60/// `pairing::Engine` annoying.  This trait merely replicates
61/// transposable functionality from `pairing::Engine` by removing
62/// the fields of definition, but leaves the actual BLS signature
63/// scheme to wrapper types.
64///
65/// We also extract two functions users may with to override:
66/// random scalar generation and hashing to the singature curve.
67pub trait EngineBLS {
68    type Engine: Pairing; //<Fr = Self::Scalar>;
69    type Scalar: PrimeField; // = <Self::Engine as ScalarEngine>::Fr;
70    /// Group where BLS public keys live
71    ///
72    /// You should take this to be the `Engine::G1` curve usually
73    /// becuase all verifiers perform additions on this curve, or
74    /// even scalar multiplicaitons with delinearization.
75    type PublicKeyGroupBaseField: Field;
76    type PublicKeyGroupAffine: AffineRepr<ScalarField = Self::Scalar, Group = Self::PublicKeyGroup>
77        + From<Self::PublicKeyGroup>
78        + Into<Self::PublicKeyGroup>
79        + Into<Self::PublicKeyPrepared>;
80    //+ Into<<Self::PublicKeyGroup as CurveGroup>::Affine>;
81
82    type PublicKeyGroup: CurveGroup<
83            Affine = Self::PublicKeyGroupAffine,
84            ScalarField = Self::Scalar,
85            BaseField = Self::PublicKeyGroupBaseField,
86        > + From<Self::PublicKeyGroupAffine>
87        + Into<Self::PublicKeyGroupAffine>
88        + MulAssign<Self::Scalar>;
89
90    type PublicKeyPrepared: Default + Clone + Send + Sync + Debug + From<Self::PublicKeyGroupAffine>;
91
92    const PUBLICKEY_SERIALIZED_SIZE: usize;
93    const SECRET_KEY_SIZE: usize;
94
95    // See https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html#name-ciphersuites
96    const CURVE_NAME: &'static [u8];
97    const SIG_GROUP_NAME: &'static [u8];
98    const CIPHER_SUIT_DOMAIN_SEPARATION: &'static [u8];
99
100    /// Group where BLS signatures live
101    ///
102    /// You should take this to be the `Engine::G2` curve usually
103    /// becuase only aggregators perform additions on this curve, or
104    /// scalar multiplicaitons with delinearization.
105    type SignatureGroupBaseField: Field;
106
107    type SignatureGroupAffine: AffineRepr<ScalarField = Self::Scalar, Group = Self::SignatureGroup>
108        + From<Self::SignatureGroup>
109        + Into<Self::SignatureGroup>
110        + Into<Self::SignaturePrepared>;
111
112    type SignatureGroup: CurveGroup<
113            Affine = Self::SignatureGroupAffine,
114            ScalarField = Self::Scalar,
115            BaseField = Self::SignatureGroupBaseField,
116        > + Into<Self::SignatureGroupAffine>
117        + From<Self::SignatureGroupAffine>
118        + MulAssign<Self::Scalar>;
119
120    type SignaturePrepared: Default + Clone + Send + Sync + Debug + From<Self::SignatureGroupAffine>;
121
122    const SIGNATURE_SERIALIZED_SIZE: usize;
123
124    type HashToSignatureField: HashToField<Self::SignatureGroupBaseField>;
125    type MapToSignatureCurve: MapToCurve<Self::SignatureGroup>;
126
127    /// Generate a random scalar for use as a secret key.
128    fn generate<R: Rng + RngCore>(rng: &mut R) -> Self::Scalar {
129        Self::Scalar::rand(rng)
130    }
131
132    /// getter function for the hash to curve map
133    fn hash_to_curve_map() -> MapToCurveBasedHasher<
134        Self::SignatureGroup,
135        Self::HashToSignatureField,
136        Self::MapToSignatureCurve,
137    >;
138
139    /// Hash one message to the signature curve.
140    fn hash_to_signature_curve<M: Borrow<[u8]>>(message: M) -> Self::SignatureGroup {
141        Self::hash_to_curve_map()
142            .hash(message.borrow())
143            .unwrap()
144            .into_group()
145    }
146
147    /// Run the Miller loop from `Engine` but orients its arguments
148    /// to be a `SignatureGroup` and `PublicKeyGroup`.
149    fn miller_loop<'a, I>(i: I) -> MillerLoopOutput<Self::Engine>
150    where
151        Self::PublicKeyPrepared: 'a,
152        Self::SignaturePrepared: 'a,
153        I: IntoIterator<
154            Item = &'a (
155                <Self as EngineBLS>::PublicKeyPrepared,
156                Self::SignaturePrepared,
157            ),
158        >;
159
160    /// Perform final exponentiation on the result of a Miller loop.
161    fn final_exponentiation(
162        e: MillerLoopOutput<Self::Engine>,
163    ) -> Option<PairingOutput<Self::Engine>> {
164        Self::Engine::final_exponentiation(e)
165    }
166
167    /// Performs a pairing operation `e(p, q)` by calling `Engine::pairing`
168    /// but orients its arguments to be a `PublicKeyGroup` and `SignatureGroup`.
169    fn pairing<G1, G2>(p: G1, q: G2) -> <Self::Engine as Pairing>::TargetField
170    where
171        G1: Into<<Self::PublicKeyGroup as CurveGroup>::Affine>,
172        G2: Into<<Self::SignatureGroup as CurveGroup>::Affine>;
173    /*
174    {
175        Self::final_exponentiation(&Self::miller_loop(
176            [(&(p.into().prepare()), &(q.into().prepare()))].into_iter(),
177        )).unwrap()
178    }
179    */
180
181    /// Implement verification equation for aggregate BLS signatures
182    /// provided as prepared points
183    ///
184    /// This low-level routine does no verification of critical security
185    /// properties like message distinctness.  It exists purely to
186    /// simplify replacing mid-level routines with optimized variants,
187    /// like versions that cache public key preperation or use fewer pairings.
188    fn verify_prepared<'a, I>(signature: Self::SignaturePrepared, inputs: I) -> bool
189    where
190        Self::PublicKeyPrepared: 'a,
191        Self::SignaturePrepared: 'a,
192        I: IntoIterator<Item = &'a (Self::PublicKeyPrepared, Self::SignaturePrepared)>,
193    {
194        let lhs: [_; 1] = [(
195            Self::minus_generator_of_public_key_group_prepared(),
196            signature,
197        )];
198        Self::final_exponentiation(Self::miller_loop(inputs.into_iter().map(|t| t).chain(&lhs)))
199            .unwrap()
200            == (PairingOutput::<Self::Engine>::zero()) //zero is the target_field::one !!
201    }
202
203    /// Prepared negative of the generator of the public key curve.
204    fn minus_generator_of_public_key_group_prepared() -> Self::PublicKeyPrepared;
205
206    /// return the generator of signature group
207    fn generator_of_signature_group() -> Self::SignatureGroup {
208        <Self::SignatureGroup as CurveGroup>::Affine::generator().into()
209    }
210
211    /// Process the public key to be use in pairing. This has to be
212    /// implemented by the type of BLS system implementing the engine
213    /// by calling either prepare_g1 or prepare_g2 based on which group
214    /// is used by the signature system to host the public key
215    fn prepare_public_key(g: impl Into<Self::PublicKeyGroupAffine>) -> Self::PublicKeyPrepared {
216        let g_affine: Self::PublicKeyGroupAffine = g.into();
217        Self::PublicKeyPrepared::from(g_affine)
218    }
219
220    /// Process the signature to be use in pairing. This has to be
221    /// implemented by the type of BLS system implementing the engine
222    /// by calling either prepare_g1 or prepare_g2 based on which group
223    /// is used by the signature system to host the public key
224    fn prepare_signature(g: impl Into<Self::SignatureGroupAffine>) -> Self::SignaturePrepared {
225        let g_affine: Self::SignatureGroupAffine = g.into();
226        Self::SignaturePrepared::from(g_affine)
227    }
228
229    /// Serialization helper for various sigma protocols
230    fn signature_point_to_byte(point: &Self::SignatureGroup) -> Vec<u8> {
231        let mut point_as_bytes = vec![0; Self::SIGNATURE_SERIALIZED_SIZE];
232        let point_affine = point.into_affine();
233        point_affine
234            .serialize_compressed(&mut point_as_bytes[..])
235            .unwrap();
236        point_as_bytes
237    }
238
239    fn public_key_point_to_byte(point: &Self::PublicKeyGroup) -> Vec<u8> {
240        let mut point_as_bytes = vec![0; Self::PUBLICKEY_SERIALIZED_SIZE];
241        let point_affine = point.into_affine();
242        point_affine
243            .serialize_compressed(&mut point_as_bytes[..])
244            .unwrap();
245        point_as_bytes
246    }
247}
248
249/// Usual aggregate BLS signature scheme on ZCash's BLS12-381 curve.
250pub type ZBLS = UsualBLS<ark_bls12_381::Bls12_381, ark_bls12_381::Config>;
251pub type BLS377 = UsualBLS<ark_bls12_377::Bls12_377, ark_bls12_377::Config>;
252
253/// Usual aggregate BLS signature scheme on ZCash's BLS12-381 curve.
254// pub const Z_BLS : ZBLS = UsualBLS(::zexe_algebra::bls12_381::Bls12_381{});
255
256/// Usual BLS variant with tiny 48 byte public keys and 96 byte signatures.
257///
258/// We favor this variant because verifiers always perform
259/// `O(signers)` additions on the `PublicKeyGroup`, or worse 128 bit
260/// scalar multiplications with delinearization.
261/// We also orient this variant to match zcash's traits.
262#[derive(Default)]
263pub struct UsualBLS<E: Pairing, P: Bls12Config + CurveExtraConfig>(pub E, PhantomData<fn() -> P>)
264where
265    <P as Bls12Config>::G2Config: WBConfig,
266    WBMap<<P as Bls12Config>::G2Config>: MapToCurve<<E as Pairing>::G2>;
267
268impl<E: Pairing, P: Bls12Config + CurveExtraConfig> EngineBLS for UsualBLS<E, P>
269where
270    <P as Bls12Config>::G2Config: WBConfig,
271    WBMap<<P as Bls12Config>::G2Config>: MapToCurve<<E as Pairing>::G2>,
272{
273    type Engine = E;
274    type Scalar = <Self::Engine as Pairing>::ScalarField;
275
276    type PublicKeyGroup = E::G1;
277    type PublicKeyGroupAffine = E::G1Affine;
278    type PublicKeyPrepared = E::G1Prepared;
279    type PublicKeyGroupBaseField = <<E as Pairing>::G1 as CurveGroup>::BaseField;
280
281    const PUBLICKEY_SERIALIZED_SIZE: usize = 48;
282    const SECRET_KEY_SIZE: usize = 32;
283
284    const CURVE_NAME: &'static [u8] = P::CURVE_NAME;
285    const SIG_GROUP_NAME: &'static [u8] = b"G2";
286    const CIPHER_SUIT_DOMAIN_SEPARATION: &'static [u8] = b"_XMD:SHA-256_SSWU_RO_";
287
288    type SignatureGroup = E::G2;
289    type SignatureGroupAffine = E::G2Affine;
290    type SignaturePrepared = E::G2Prepared;
291    type SignatureGroupBaseField = <<E as Pairing>::G2 as CurveGroup>::BaseField;
292
293    const SIGNATURE_SERIALIZED_SIZE: usize = 96;
294
295    type HashToSignatureField = DefaultFieldHasher<Sha256, 128>;
296    type MapToSignatureCurve = WBMap<P::G2Config>;
297
298    fn miller_loop<'a, I>(i: I) -> MillerLoopOutput<E>
299    where
300        // Self::PublicKeyPrepared: 'a,
301        // Self::SignaturePrepared: 'a,
302        I: IntoIterator<Item = &'a (Self::PublicKeyPrepared, Self::SignaturePrepared)>,
303    {
304        let (i_a, i_b): (Vec<Self::PublicKeyPrepared>, Vec<Self::SignaturePrepared>) =
305            i.into_iter().cloned().unzip();
306
307        E::multi_miller_loop(i_a, i_b)
308    }
309
310    fn pairing<G1, G2>(p: G1, q: G2) -> E::TargetField
311    where
312        G1: Into<E::G1Affine>,
313        G2: Into<E::G2Affine>,
314    {
315        E::pairing(p.into(), q.into()).0
316    }
317
318    /// Prepared negative of the generator of the public key curve.
319    fn minus_generator_of_public_key_group_prepared() -> Self::PublicKeyPrepared {
320        let g1_minus_generator = <Self::PublicKeyGroup as CurveGroup>::Affine::generator();
321        <Self::PublicKeyGroup as Into<Self::PublicKeyPrepared>>::into(
322            -g1_minus_generator.into_group(),
323        )
324    }
325
326    fn hash_to_curve_map() -> MapToCurveBasedHasher<
327        Self::SignatureGroup,
328        Self::HashToSignatureField,
329        Self::MapToSignatureCurve,
330    > {
331        MapToCurveBasedHasher::<
332            Self::SignatureGroup,
333            DefaultFieldHasher<Sha256, 128>,
334            WBMap<P::G2Config>,
335        >::new(&[1])
336        .unwrap()
337    }
338}
339
340/// Infrequently used BLS variant with tiny 48 byte signatures and 96 byte public keys,
341///
342/// We recommend gainst this variant by default because verifiers
343/// always perform `O(signers)` additions on the `PublicKeyGroup`,
344/// or worse 128 bit scalar multiplications with delinearization.
345/// Yet, there are specific use cases where this variant performs
346/// better.  We swapy two group roles relative to zcash here.
347#[derive(Default)]
348pub struct TinyBLS<E: Pairing, P: Bls12Config + CurveExtraConfig>(pub E, PhantomData<fn() -> P>)
349where
350    <P as Bls12Config>::G1Config: WBConfig,
351    WBMap<<P as Bls12Config>::G1Config>: MapToCurve<<E as Pairing>::G1>;
352
353/// Trait to add extra config for a curve which is not in ArkWorks library
354pub trait CurveExtraConfig {
355    const CURVE_NAME: &'static [u8];
356}
357
358impl<E: Pairing, P: Bls12Config + CurveExtraConfig> EngineBLS for TinyBLS<E, P>
359where
360    <P as Bls12Config>::G1Config: WBConfig,
361    WBMap<<P as Bls12Config>::G1Config>: MapToCurve<<E as Pairing>::G1>,
362{
363    type Engine = E;
364    type Scalar = <Self::Engine as Pairing>::ScalarField;
365
366    type SignatureGroup = E::G1;
367    type SignatureGroupAffine = E::G1Affine;
368    type SignaturePrepared = E::G1Prepared;
369    type SignatureGroupBaseField = <<E as Pairing>::G1 as CurveGroup>::BaseField;
370
371    const SIGNATURE_SERIALIZED_SIZE: usize = 48;
372
373    type PublicKeyGroup = E::G2;
374    type PublicKeyGroupAffine = E::G2Affine;
375    type PublicKeyPrepared = E::G2Prepared;
376    type PublicKeyGroupBaseField = <<E as Pairing>::G2 as CurveGroup>::BaseField;
377
378    const PUBLICKEY_SERIALIZED_SIZE: usize = 96;
379    const SECRET_KEY_SIZE: usize = 32;
380
381    const CURVE_NAME: &'static [u8] = P::CURVE_NAME;
382    const SIG_GROUP_NAME: &'static [u8] = b"G1";
383    const CIPHER_SUIT_DOMAIN_SEPARATION: &'static [u8] = b"_XMD:SHA-256_SSWU_RO_";
384
385    type HashToSignatureField = DefaultFieldHasher<Sha256, 128>;
386    type MapToSignatureCurve = WBMap<P::G1Config>;
387
388    fn miller_loop<'a, I>(i: I) -> MillerLoopOutput<E>
389    where
390        I: IntoIterator<Item = &'a (Self::PublicKeyPrepared, Self::SignaturePrepared)>,
391    {
392        // We require an ugly unecessary allocation here because
393        // zcash's pairing library cnsumes an iterator of references
394        // to tuples of references, which always requires
395        let (i_a, i_b): (Vec<Self::PublicKeyPrepared>, Vec<Self::SignaturePrepared>) =
396            i.into_iter().cloned().unzip();
397
398        E::multi_miller_loop(i_b, i_a) //in Tiny BLS signature is in G1
399    }
400
401    fn pairing<G2, G1>(p: G2, q: G1) -> E::TargetField
402    where
403        G1: Into<E::G1Affine>,
404        G2: Into<E::G2Affine>,
405    {
406        E::pairing(q.into(), p.into()).0
407    }
408
409    /// Prepared negative of the generator of the public key curve.
410    fn minus_generator_of_public_key_group_prepared() -> Self::PublicKeyPrepared {
411        let g2_minus_generator = <Self::PublicKeyGroup as CurveGroup>::Affine::generator();
412        <Self::PublicKeyGroup as Into<Self::PublicKeyPrepared>>::into(
413            -g2_minus_generator.into_group(),
414        )
415    }
416
417    fn hash_to_curve_map() -> MapToCurveBasedHasher<
418        Self::SignatureGroup,
419        Self::HashToSignatureField,
420        Self::MapToSignatureCurve,
421    > {
422        MapToCurveBasedHasher::<
423            Self::SignatureGroup,
424            DefaultFieldHasher<Sha256, 128>,
425            WBMap<P::G1Config>,
426        >::new(&[1])
427        .unwrap()
428    }
429}
430
431/// Aggregate BLS signature scheme with Signature in G1 for BLS12-377 curve.
432impl CurveExtraConfig for ark_bls12_377::Config {
433    const CURVE_NAME: &'static [u8] = b"BLS12377";
434}
435pub type TinyBLS377 = TinyBLS<ark_bls12_377::Bls12_377, ark_bls12_377::Config>;
436/// Aggregate BLS signature scheme with Signature in G1 for BLS12-381 curve.
437impl CurveExtraConfig for ark_bls12_381::Config {
438    const CURVE_NAME: &'static [u8] = b"BLS12381";
439}
440pub type TinyBLS381 = TinyBLS<ark_bls12_381::Bls12_381, ark_bls12_381::Config>;