Pairing cryptography library in Rust

Related tags

Cryptography bn
Overview

bn Crates.io Build status

This is a pairing cryptography library written in pure Rust. It makes use of the Barreto-Naehrig (BN) curve construction from [BCTV2015] to provide two cyclic groups G1 and G2, with an efficient bilinear pairing:

e: G1 × G2 → GT

Security warnings

This library, like other pairing cryptography libraries implementing this construction, is not resistant to side-channel attacks.

Usage

Add the bn crate to your dependencies in Cargo.toml...

[dependencies]
bn = "0.4.3"

...and add an extern crate declaration to your crate root:

extern crate bn;

API

  • Fr is an element of Fr
  • G1 is a point on the BN curve E/Fq : y^2 = x^3 + b
  • G2 is a point on the twisted BN curve E'/Fq2 : y^2 = x^3 + b/xi
  • Gt is a group element (written multiplicatively) obtained with the pairing function over G1 and G2.

Examples

Joux's key agreement protocol

In a typical Diffie-Hellman key exchange, relying on ECDLP, a three-party key exchange requires two rounds. A single round protocol is possible through the use of a bilinear pairing: given Alice's public key aP1 and Bob's public key bP2, Carol can compute the shared secret with her private key c by e(aP1, bP2)c.

(See examples/joux.rs for the full example.)

// Generate private keys
let alice_sk = Fr::random(rng);
let bob_sk = Fr::random(rng);
let carol_sk = Fr::random(rng);

// Generate public keys in G1 and G2
let (alice_pk1, alice_pk2) = (G1::one() * alice_sk, G2::one() * alice_sk);
let (bob_pk1, bob_pk2) = (G1::one() * bob_sk, G2::one() * bob_sk);
let (carol_pk1, carol_pk2) = (G1::one() * carol_sk, G2::one() * carol_sk);

// Each party computes the shared secret
let alice_ss = pairing(bob_pk1, carol_pk2).pow(alice_sk);
let bob_ss = pairing(carol_pk1, alice_pk2).pow(bob_sk);
let carol_ss = pairing(alice_pk1, bob_pk2).pow(carol_sk);

assert!(alice_ss == bob_ss && bob_ss == carol_ss);

License

Licensed under either of

at your option.

Copyright 2016 Zcash Electric Coin Company. The Zcash Company promises to maintain the "bn" crate on crates.io under this MIT/Apache-2.0 dual license.

Authors

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Why does a pairing take so long?

    Why does a pairing take so long?

    https://crypto.stanford.edu/pbc/

    I was under impression pairings would take roughly 30 milliseconds according to the link above.

    But my test shows otherwise:

    $ time cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
         Running `target/debug/hello_world`
    PT0.321907197S seconds for whatever you did.
    
    real	0m0.840s
    user	0m0.792s
    sys	0m0.012s
    

    My test code:

    extern crate bn;
    extern crate rand;
    extern crate time;
    use bn::{Group, Fr, G1, G2, pairing};
    use time::PreciseTime;
    
    fn main() {
    	let rng = &mut rand::thread_rng();
    
    	// Generate private keys
    	let bob_sk = Fr::random(rng);
    	let carol_sk = Fr::random(rng);
    
    	// Generate public keys in G1 and G2
    	let (bob_pk1, bob_pk2) = (G1::one() * bob_sk, G2::one() * bob_sk);
    	let (carol_pk1, carol_pk2) = (G1::one() * carol_sk, G2::one() * carol_sk);
    
    	// Time the pairing
    	let start = PreciseTime::now();
    	let alice_ss = pairing(bob_pk1, carol_pk2);
    	let end = PreciseTime::now();
    	
    	println!("{} seconds for whatever you did.", start.to(end));
    }
    

    @chronusz

    opened by ghost 6
  • Don't negate y if point at infinity

    Don't negate y if point at infinity

    The y coordinate shouldn't be negated if it's zero. Since z = 0, this doesn't break any library invariants.

    I pushed 4e2096bedd67d77370985b5ee92f4ab241c25430 to master on accident, so please review that as well. [Edit by @daira: link to commit.]

    See also https://github.com/scipr-lab/libsnark/issues/60.

    This also bumps the crate version.

    opened by ebfull 1
  • Fq2 serialization

    Fq2 serialization

    Currently, Fq2 elements (c1*q + c0) are serializing c1 || c0, this changes the serialization to match the IEEE 1363 standard format, which we use in Zcash.

    Since we're adding divrem anyway for the standard, I changed Fp randomness to sample a random U512 and modulo the field char for a uniform distribution. (This was recommended by @daira.) This also allows me to add Fr interpretation to the API, which is useful for signature schemes.

    opened by ebfull 1
  • Should we perform subgroup checks for G2?

    Should we perform subgroup checks for G2?

    https://github.com/paritytech/bn/blob/master/src/groups/mod.rs#L108 The check is here. I have seen no the same checks in bellman_ce, go-ethereum, and ethereumj. But parity-ethereum (openethereum) is still using this costly check.

    Obviously, we should not check the subgroup for G1 at the prime order curve. What about checking G2 subgroup before pairing?

    opened by snjax 0
  • Add

    Add "normalize" method to Group and improve performance of serialization

    This adds a new normalize method to Group that can be used to speed up serialization in parallel. The jacobian-to-affine conversion will handle the trivial case of z=1, speeding up serialization significantly in some cases. In the future, I would rather elevate this stuff to the type system, but this works for now.

    Also, cleaned up the benchmarks.

    test fq12_exponentiation         ... bench:   5,969,704 ns/iter (+/- 410,626)
    test fq12_scalar_multiplication  ... bench:      19,286 ns/iter (+/- 756)
    test fr_addition                 ... bench:          22 ns/iter (+/- 5)
    test fr_inverses                 ... bench:      10,260 ns/iter (+/- 206)
    test fr_multiplication           ... bench:         146 ns/iter (+/- 47)
    test fr_subtraction              ... bench:          22 ns/iter (+/- 6)
    test g1_addition                 ... bench:       2,597 ns/iter (+/- 200)
    test g1_deserialization          ... bench:       1,229 ns/iter (+/- 118)
    test g1_scalar_multiplication    ... bench:     633,965 ns/iter (+/- 12,880)
    test g1_serialization            ... bench:      11,888 ns/iter (+/- 261)
    test g1_serialization_normalized ... bench:         687 ns/iter (+/- 169)
    test g1_subtraction              ... bench:       2,606 ns/iter (+/- 152)
    test g2_addition                 ... bench:      11,340 ns/iter (+/- 475)
    test g2_deserialization          ... bench:       9,407 ns/iter (+/- 273)
    test g2_scalar_multiplication    ... bench:   2,728,459 ns/iter (+/- 336,310)
    test g2_serialization            ... bench:      15,467 ns/iter (+/- 257)
    test g2_serialization_normalized ... bench:       1,353 ns/iter (+/- 146)
    test g2_subtraction              ... bench:      11,382 ns/iter (+/- 238)
    test perform_pairing             ... bench:   6,992,153 ns/iter (+/- 788,769)
    
    opened by ebfull 0
  • Add G1/G2 serialization benchmarks.

    Add G1/G2 serialization benchmarks.

    on my system:

    test g1_deserialization ... bench: 1,264 ns/iter (+/- 35) test g2_deserialization ... bench: 3,650 ns/iter (+/- 143)

    opened by ebfull 0
  • Performing reconstruction of the codebase.

    Performing reconstruction of the codebase.

    • [x] New Fp/Fp2 implementations
    • [x] New G1/G2 implementations
    • [x] New Fp6/Fp12 implementations
    • [x] New pairing implementations
    • [x] Test vectors, benchmarks, travis tests
    opened by ebfull 0
  • few PRs

    few PRs

    seems like a lot of people fork and add bits but don't PR back to the main lib?

    wondering if there's some way that maybe co-ordination could be improved? I wonder why they don't contribute back...

    opened by gilescope 1
  • Make Gt serializable

    Make Gt serializable

    Hi,

    We needed Gt to be serializabe. This approach might not be the cleanest solution as I am still a rust newbie, but it does the job for us currently.

    OTOH, you might want to replace serialisation with serde soon anyway...

    BR Martin

    opened by schanzen 1
  • New core implementation

    New core implementation

    I'm designing a new "core" for the cryptography in this library, mostly in the interest of performance and flexibility.

    Features include:

    • The library will support multiple BN curve implementations all behind this abstract API. In particular, I plan to integrate a stronger curve construction which should be more secure and more useful for zk-SNARKs.
    • The user can perform miller loops (with any number of point tuples) manually if they want to avoid unnecessary final exponentiations or redundant ate loops. The Ethereum folks will need to expose all of this functionality in their precompiles if they want to give users maximum performance and flexibility, especially if you need to use newer zk-SNARK schemes or do batch/probablistic verification of proofs.
    • The user can perform G2 precomputation for the miller loop manually.
    • Support for mixed addition.
    • Support for curve point compression (the same way that Zcash compresses proofs).

    API preview:

    pub trait Field<E: Engine>: Sized +
                                Eq +
                                PartialEq +
                                Copy +
                                Clone +
                                Send +
                                Sync +
                                Debug +
                                'static
    {
        fn zero() -> Self;
        fn one(&E) -> Self;
        fn random<R: rand::Rng>(&E, &mut R) -> Self;
    
        fn is_zero(&self) -> bool;
        
        fn square(&mut self, &E);
        fn double(&mut self, &E);
        fn negate(&mut self, &E);
        fn add_assign(&mut self, &E, other: &Self);
        fn sub_assign(&mut self, &E, other: &Self);
        fn mul_assign(&mut self, &E, other: &Self);
        fn inverse(&self, &E) -> Option<Self>;
        fn sqrt(&self, &E) -> Option<Self>;
        fn powi<I: IntoIterator<Item=u64>>(&self, engine: &E, exp: I) -> Self;
        fn powb<I: IntoIterator<Item=bool>>(&self, engine: &E, exp: I) -> Self;
    }
    
    pub trait PrimeField<E: Engine>: Field<E>
    {
        type Repr: AsRef<[u64]>;
    
        fn from_str(&E, s: &str) -> Result<Self, ()>;
        fn from_repr(&E, Self::Repr) -> Result<Self, ()>;
        fn into_repr(&self, &E) -> Self::Repr;
    }
    
    /// A representation of a group element that can be serialized and deserialized,
    /// but is not guaranteed to be a point on the curve.
    pub trait GroupRepresentation<E: Engine, F: Field<E>, G: Group<E, F>>: Copy +
                                                                           Clone +
                                                                           Sized +
                                                                           Send +
                                                                           Sync +
                                                                           Debug +
                                                                           'static
    {
        /// Attempt to parse the representation as an element on
        /// the curve in the affine.
        fn to_affine(&self, &E) -> Option<G::Affine>;
    
        /// This is like `to_affine` except the caller is
        /// responsible for ensuring the point is on the curve.
        /// If it isn't, this function is allowed to panic,
        /// but not guaranteed to.
        fn to_affine_unchecked(&self, &E) -> G::Affine;
    }
    
    pub trait GroupAffine<E: Engine, F: Field<E>, G: Group<E, F>>: Copy +
                                                                   Clone +
                                                                   Sized +
                                                                   Send +
                                                                   Sync +
                                                                   Debug +
                                                                   PartialEq +
                                                                   Eq +
                                                                   'static
    {
        fn to_jacobian(&self, &E) -> G;
        fn to_compressed(&self, &E) -> G::Compressed;
        fn to_uncompressed(&self, &E) -> G::Uncompressed;
    }
    
    pub trait Group<E: Engine, F: Field<E>>: Sized +
                                             Eq +
                                             PartialEq +
                                             Copy +
                                             Clone +
                                             Send +
                                             Sync +
                                             Debug +
                                             'static
    {
        type Affine: GroupAffine<E, F, Self>;
        type Compressed: GroupRepresentation<E, F, Self>;
        type Uncompressed: GroupRepresentation<E, F, Self>;
        type Prepared: Clone + 'static;
    
        fn zero(&E) -> Self;
        fn one(&E) -> Self;
        fn random<R: rand::Rng>(&E, &mut R) -> Self;
    
        fn is_zero(&E) -> Self;
    
        fn to_affine(&self, &E) -> Self::Affine;
        fn prepare(&self, &E) -> Self::Prepared;
    
        fn double(&mut self, &E);
        fn negate(&mut self, engine: &E);
        fn add_assign(&mut self, &E, other: &Self);
        fn add_assign_mixed(&mut self, &E, other: &Self::Affine);
        fn mul_assign(&mut self, &E, other: &E::Fr);
    }
    
    pub trait Engine: Sized {
        type Fq: PrimeField<Self>;
        type Fr: PrimeField<Self>;
        type Fqe: Field<Self>;
        type Fqk: Field<Self>;
        type G1: Group<Self, Self::Fq>;
        type G2: Group<Self, Self::Fqe>;
    
        fn new() -> Self;
    
        fn miller_loop<'a, I>(&self, I) -> Self::Fqk
            where I: IntoIterator<Item=&'a (
                                        &'a <Self::G1 as Group<Self, Self::Fq>>::Prepared,
                                        &'a <Self::G2 as Group<Self, Self::Fqe>>::Prepared
                                   )>;
    
        fn final_exponentiation(&self, &Self::Fqk) -> Self::Fqk;
    
        fn pairing(&self, p: &Self::G1, q: &Self::G2) -> Self::Fqk
        {
            self.final_exponentiation(&self.miller_loop(
                [(&p.prepare(self), &q.prepare(self))].into_iter()
            ))
        }
    }
    
    opened by ebfull 1
  • Testing Boneh Franklin IBE on BN curve

    Testing Boneh Franklin IBE on BN curve

    This PR implements the Boneh Franklin "BasicIdent" IBE scheme with BN curves. I'll update the PR with the FullIdent scheme once I write it.

    From what I've read, the original scheme works on bilinear pairings, but with G1 x G2 -> Gt, it only requires that CDH holds in G1 and G2, and DDH holds in Gt, so it should work on BN curves (could anyone confirm this?).

    This PR uses the two previous ones, the first to fix compilation, the second to reuse the sighash module. I'll rebase when those are merged.

    What I currently need to move this forward, is a way to serialize a point in compressed form, to generate a hash from it. The way I do it for this test is very ugly: using format! and the Debug implementation for g_idto generate a string, and hashing it with sha256.

    A way to serialize and deserialize arbitrary points from G1, G2 and Gt would be useful as well, to transport ciphertexts or signatures.

    The hash derived from the shared g_id point is used to generate a Chacha20 key instead of XOR-ing it directly with the plaintext. I think it is ok, assuming that Chacha20 is a PRF, but I have not verified it yet. It keeps the malleability from the original scheme, but it would not be hard to derive more data, to do a Chacha20+Poly1305 authenticated encryption (or any other algorithm combination).

    opened by Geal 1
Owner
Electric Coin Company Prototypes and Experiments
Prototypes, experiments, demos, works in progress by Electric Coin Company
Electric Coin Company Prototypes and Experiments
Implementation of the BLS12-381 pairing-friendly elliptic curve group

bls12_381 This crate provides an implementation of the BLS12-381 pairing-friendly elliptic curve construction. This implementation has not been review

Zero-knowledge Cryptography in Rust 183 Dec 27, 2022
A pairing-based threshold cryptosystem for collaborative decryption and signatures used in HoneybadgerBFT implementation

threshold_crypto A pairing-based threshold cryptosystem for collaborative decryption and signatures. The threshold_crypto crate provides cryptographic

null 166 Dec 29, 2022
Mundane is a Rust cryptography library backed by BoringSSL that is difficult to misuse, ergonomic, and performant (in that order).

Mundane Mundane is a Rust cryptography library backed by BoringSSL that is difficult to misuse, ergonomic, and performant (in that order). Issues and

Google 1.1k Jan 3, 2023
Cryptography-oriented big integer library with constant-time, stack-allocated (no_std-friendly) implementations of modern formulas

RustCrypto: Cryptographic Big Integers Pure Rust implementation of a big integer library which has been designed from the ground-up for use in cryptog

Rust Crypto 88 Dec 31, 2022
Ursa - Hyperledger Ursa is a shared cryptography library

HYPERLEDGER URSA Introduction Features Libursa Libzmix Dependencies Building from source Contributing Introduction Ursa was created because people in

Hyperledger 307 Dec 20, 2022
Implementation of the Web Cryptography specification in Rust.

[wip] webcrypto Implementation of the Web Cryptography specification in Rust. This crate hopes to ease interoperability between WASM and native target

Divy Srivastava 5 Mar 7, 2022
Collect libraries and packages about cryptography in Rust.

Awesome Cryptography Rust Collect libraries and packages about cryptography in Rust. Collection Library Symmetric Public-key / Asymmetric One-way Hash

Rust Cryptography Community 282 Dec 25, 2022
A general solution for commonly used crypt in rust, collection of cryptography-related traits and algorithms.

Crypto-rs A general solution for commonly used crypt in rust, collection of cryptography-related traits and algorithms. This is a Rust implementation

houseme 4 Nov 28, 2022
Example implementation for Biscuit tokens cryptography

example implementation for Biscuit token cryptography To aid in the implementation of Biscuit tokens in various languages, this repository contains an

Clever Cloud 6 May 25, 2021
Manage secret values in-repo via public key cryptography

amber Manage secret values in-repo via public key cryptography. See the announcement blog post for more motivation. Amber provides the ability to secu

FP Complete 82 Nov 10, 2022
Cryptography-related format encoders/decoders: PKCS, PKIX

RustCrypto: Formats Cryptography-related format encoders/decoders: PKCS, PKIX. Crates Name crates.io Docs Description base64ct Constant-time encoder a

Rust Crypto 112 Dec 20, 2022
BLS12-381 cryptography using Apache Milagro

BLS12-381 Aggregate Signatures in Rust using Apache Milagro WARNING: This library is a work in progress and has not been audited. Do NOT consider the

Sigma Prime 21 Apr 4, 2022
Traits - Collection of cryptography-related traits

RustCrypto: Traits Collection of traits which describe functionality of cryptographic primitives. Crates Name Algorithm Crates.io Docs MSRV aead Authe

Rust Crypto 401 Dec 27, 2022
A down-to-the-metal ongoing cryptography challenge designed by Radical Semiconductor.

woodpecker ?? [NOTE: scoreboard will now be updated weekends, starting the weekend of 12/10/2022--sorry for delays! I'll also be merging in pull reque

Radical Semiconductor 16 Dec 15, 2022
Elliptic curve cryptography on Soroban.

Elliptic Curve Cryptography on Soroban Contract examples and reusable primitives. Groth 16 verifier. This crate provides a SorobanGroth16Verifier obje

Xycloo Labs 5 Feb 10, 2023
High-level networking library that extends the bevy_replicon library to allow snapshot interpolation and client-side prediction

bevy_replicon_snap A Snapshot Interpolation plugin for the networking solution bevy_replicon in the Bevy game engine. This library is a very rough pro

Ben 3 Oct 15, 2023
A Rust library for working with Bitcoin SV

Rust-SV A library to build Bitcoin SV applications in Rust. Documentation Features P2P protocol messages (construction and serialization) Address enco

Brenton Gunning 51 Oct 13, 2022
A Rust library for generating cryptocurrency wallets

Table of Contents 1. Overview 2. Build Guide 2.1 Install Rust 2.2a Build from Homebrew 2.2b Build from Crates.io 2.2c Build from Source Code 3. Usage

Aleo 552 Dec 29, 2022
A modern TLS library in Rust

Rustls is a modern TLS library written in Rust. It's pronounced 'rustles'. It uses ring for cryptography and libwebpki for certificate verification. S

ctz 4k Jan 9, 2023