diff --git a/Cargo.toml b/Cargo.toml index 9a4c4be..eabb522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bn" -version = "0.4.0" +version = "0.4.1" authors = ["Sean Bowe "] description = "Pairing cryptography with the Barreto-Naehrig curve" keywords = ["pairing","crypto","cryptography"] diff --git a/README.md b/README.md index be9312e..fecb172 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Add the `bn` crate to your dependencies in `Cargo.toml`... ```toml [dependencies] -bn = "0.4.0" +bn = "0.4.1" ``` ...and add an `extern crate` declaration to your crate root: diff --git a/benches/api.rs b/benches/api.rs index 20e63da..8340eaa 100644 --- a/benches/api.rs +++ b/benches/api.rs @@ -8,272 +8,153 @@ use bn::*; use bincode::SizeLimit::Infinite; use bincode::rustc_serialize::{encode, decode}; -#[bench] -fn g1_deserialization(b: &mut test::Bencher) { - const SAMPLES: usize = 1000; +const SAMPLES: usize = 30; - let rng = &mut rand::thread_rng(); +macro_rules! benchmark( + ($name:ident, $input:ident($rng:ident) = $pre:expr; $post:expr) => ( + #[bench] + fn $name(b: &mut test::Bencher) { + let $rng = &mut rand::thread_rng(); + let $input: Vec<_> = (0..SAMPLES).map(|_| $pre).collect(); - let serialized: Vec<_> = (0..SAMPLES).map(|_| encode(&G1::random(rng), Infinite).unwrap()).collect(); + b.bench_n(SAMPLES as u64, |b| { + let mut c = 0; - let mut ctr = 0; + b.iter(|| { + c += 1; - b.iter(|| { - ctr += 1; + let $input = &$input[c % SAMPLES]; - decode::(&serialized[ctr % SAMPLES]).unwrap() - }); -} + $post + }) + }) + } + ) +); -#[bench] -fn g2_deserialization(b: &mut test::Bencher) { - const SAMPLES: usize = 1000; +benchmark!(g1_serialization, + input(rng) = G1::random(rng); - let rng = &mut rand::thread_rng(); + encode(input, Infinite).unwrap() +); - let serialized: Vec<_> = (0..SAMPLES).map(|_| encode(&G2::random(rng), Infinite).unwrap()).collect(); +benchmark!(g1_serialization_normalized, + input(rng) = {let mut tmp = G1::random(rng); tmp.normalize(); tmp}; - let mut ctr = 0; + encode(input, Infinite).unwrap() +); - b.iter(|| { - ctr += 1; +benchmark!(g2_serialization, + input(rng) = G2::random(rng); - decode::(&serialized[ctr % SAMPLES]).unwrap() - }); -} + encode(input, Infinite).unwrap() +); -#[bench] -fn fr_addition(b: &mut test::Bencher) { - const SAMPLES: usize = 1000; +benchmark!(g2_serialization_normalized, + input(rng) = {let mut tmp = G2::random(rng); tmp.normalize(); tmp}; - let rng = &mut rand::thread_rng(); + encode(input, Infinite).unwrap() +); - let v1: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); +benchmark!(g1_deserialization, + input(rng) = {encode(&G1::random(rng), Infinite).unwrap()}; - let mut ctr = 0; + decode::(input).unwrap() +); - b.iter(|| { - ctr += 1; +benchmark!(g2_deserialization, + input(rng) = {encode(&G2::random(rng), Infinite).unwrap()}; - v1[ctr % SAMPLES] + v2[ctr % SAMPLES] - }); -} + decode::(input).unwrap() +); -#[bench] -fn fr_subtraction(b: &mut test::Bencher) { - const SAMPLES: usize = 1000; +benchmark!(fr_addition, + input(rng) = (Fr::random(rng), Fr::random(rng)); - let rng = &mut rand::thread_rng(); + input.0 + input.1 +); - let v1: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); +benchmark!(fr_subtraction, + input(rng) = (Fr::random(rng), Fr::random(rng)); - let mut ctr = 0; + input.0 - input.1 +); - b.iter(|| { - ctr += 1; +benchmark!(fr_multiplication, + input(rng) = (Fr::random(rng), Fr::random(rng)); - v1[ctr % SAMPLES] - v2[ctr % SAMPLES] - }); -} + input.0 * input.1 +); -#[bench] -fn fr_multiplication(b: &mut test::Bencher) { - const SAMPLES: usize = 1000; +benchmark!(fr_inverses, + input(rng) = Fr::random(rng); - let rng = &mut rand::thread_rng(); + input.inverse() +); - let v1: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); +benchmark!(g1_addition, + input(rng) = (G1::random(rng), G1::random(rng)); - let mut ctr = 0; + input.0 + input.1 +); - b.iter(|| { - ctr += 1; +benchmark!(g1_subtraction, + input(rng) = (G1::random(rng), G1::random(rng)); - v1[ctr % SAMPLES] * v2[ctr % SAMPLES] - }); -} + input.0 - input.1 +); -#[bench] -fn fr_inverses(b: &mut test::Bencher) { - const SAMPLES: usize = 1000; +benchmark!(g1_scalar_multiplication, + input(rng) = (G1::random(rng), Fr::random(rng)); - let rng = &mut rand::thread_rng(); + input.0 * input.1 +); - let v1: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); +benchmark!(g2_addition, + input(rng) = (G2::random(rng), G2::random(rng)); - let mut ctr = 0; + input.0 + input.1 +); - b.iter(|| { - ctr += 1; +benchmark!(g2_subtraction, + input(rng) = (G2::random(rng), G2::random(rng)); - v1[ctr % SAMPLES].inverse() - }); -} + input.0 - input.1 +); -#[bench] -fn g1_addition(b: &mut test::Bencher) { - const SAMPLES: usize = 100; +benchmark!(g2_scalar_multiplication, + input(rng) = (G2::random(rng), Fr::random(rng)); - let rng = &mut rand::thread_rng(); + input.0 * input.1 +); - let v1: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); +benchmark!(fq12_scalar_multiplication, + input(rng) = { + let g1_1 = G1::random(rng); + let g2_1 = G2::random(rng); - let mut ctr = 0; + let g1_2 = G1::random(rng); + let g2_2 = G2::random(rng); - b.iter(|| { - ctr += 1; + (pairing(g1_1, g2_1), pairing(g1_2, g2_2)) + }; - v1[ctr % SAMPLES] + v2[ctr % SAMPLES] - }); -} + input.0 * input.1 +); -#[bench] -fn g1_subtraction(b: &mut test::Bencher) { - const SAMPLES: usize = 100; +benchmark!(fq12_exponentiation, + input(rng) = ({ + let g1 = G1::random(rng); + let g2 = G2::random(rng); - let rng = &mut rand::thread_rng(); + pairing(g1, g2) + }, Fr::random(rng)); - let v1: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); + input.0.pow(input.1) +); - let mut ctr = 0; +benchmark!(perform_pairing, + input(rng) = (G1::random(rng), G2::random(rng)); - b.iter(|| { - ctr += 1; - - v1[ctr % SAMPLES] - v2[ctr % SAMPLES] - }); -} - -#[bench] -fn g1_scalar_multiplication(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - v1[ctr % SAMPLES] * v2[ctr % SAMPLES] - }); -} - -#[bench] -fn g2_addition(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - v1[ctr % SAMPLES] + v2[ctr % SAMPLES] - }); -} - -#[bench] -fn g2_subtraction(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - v1[ctr % SAMPLES] - v2[ctr % SAMPLES] - }); -} - -#[bench] -fn g2_scalar_multiplication(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - v1[ctr % SAMPLES] * v2[ctr % SAMPLES] - }); -} - -#[bench] -fn fq12_scalar_multiplication(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - let v3: Vec<_> = (0..SAMPLES).map(|i| pairing(v1[i], v2[i])).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - v3[(ctr + SAMPLES/50) % SAMPLES] * v3[ctr % SAMPLES] - }); -} - -#[bench] -fn fq12_exponentiation(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - let v3: Vec<_> = (0..SAMPLES).map(|i| pairing(v1[i], v2[i])).collect(); - let v4: Vec<_> = (0..SAMPLES).map(|_| Fr::random(rng)).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - v3[ctr % SAMPLES].pow(v4[ctr % SAMPLES]) - }); -} - -#[bench] -fn perform_pairing(b: &mut test::Bencher) { - const SAMPLES: usize = 100; - - let rng = &mut rand::thread_rng(); - - let v1: Vec<_> = (0..SAMPLES).map(|_| G1::random(rng)).collect(); - let v2: Vec<_> = (0..SAMPLES).map(|_| G2::random(rng)).collect(); - - let mut ctr = 0; - - b.iter(|| { - ctr += 1; - - pairing(v1[ctr % SAMPLES], v2[ctr % SAMPLES]) - }); -} + pairing(input.0, input.1) +); diff --git a/src/groups/mod.rs b/src/groups/mod.rs index 8ff08ba..60338c0 100644 --- a/src/groups/mod.rs +++ b/src/groups/mod.rs @@ -112,6 +112,11 @@ impl G

{ pub fn to_affine(&self) -> Option> { if self.z.is_zero() { None + } else if self.z == P::Base::one() { + Some(AffineG { + x: self.x, + y: self.y + }) } else { let zinv = self.z.inverse().unwrap(); let zinv_squared = zinv.squared(); @@ -125,7 +130,7 @@ impl G

{ } impl AffineG

{ - fn to_jacobian(&self) -> G

{ + pub fn to_jacobian(&self) -> G

{ G { x: self.x, y: self.y, diff --git a/src/lib.rs b/src/lib.rs index 420a6fd..2212da7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,6 +73,7 @@ pub trait Group: fn one() -> Self; fn random(rng: &mut R) -> Self; fn is_zero(&self) -> bool; + fn normalize(&mut self); } #[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable)] @@ -84,6 +85,14 @@ impl Group for G1 { fn one() -> Self { G1(groups::G1::one()) } fn random(rng: &mut R) -> Self { G1(groups::G1::random(rng)) } fn is_zero(&self) -> bool { self.0.is_zero() } + fn normalize(&mut self) { + let new = match self.0.to_affine() { + Some(a) => a, + None => return + }; + + self.0 = new.to_jacobian(); + } } impl Add for G1 { @@ -119,6 +128,14 @@ impl Group for G2 { fn one() -> Self { G2(groups::G2::one()) } fn random(rng: &mut R) -> Self { G2(groups::G2::random(rng)) } fn is_zero(&self) -> bool { self.0.is_zero() } + fn normalize(&mut self) { + let new = match self.0.to_affine() { + Some(a) => a, + None => return + }; + + self.0 = new.to_jacobian(); + } } impl Add for G2 { diff --git a/tests/serialization.rs b/tests/serialization.rs index 9125df5..88c928e 100644 --- a/tests/serialization.rs +++ b/tests/serialization.rs @@ -35,6 +35,11 @@ fn group_serialization_and_deserialization() { a = a * b; assert!(reserialize(a) == a); + assert!(reserialize(reserialize(a)) == a); + let mut c = a; + c.normalize(); + + assert!(a == c); } let mut a = G2::one(); @@ -42,6 +47,12 @@ fn group_serialization_and_deserialization() { a = a * b; assert!(reserialize(a) == a); + assert!(reserialize(reserialize(a)) == a); + let mut c = a; + c.normalize(); + + assert!(a == c); + } }