pairing: Remove BLS12-381 implementation

It is replaced by the bls12_381 crate.
This commit is contained in:
Jack Grigg 2020-07-02 16:22:14 +12:00
parent b9a8e1e415
commit f735e8b83b
36 changed files with 120 additions and 8664 deletions

View File

@ -24,6 +24,7 @@ byteorder = "1"
subtle = "2.2.1"
[dev-dependencies]
bls12_381 = { version = "0.1", path = "../bls12_381" }
hex-literal = "0.2"
rand = "0.7"
rand_xorshift = "0.2"

View File

@ -375,7 +375,7 @@ fn parallel_fft<S: PrimeField, T: Group<S>>(
#[cfg(feature = "pairing")]
#[test]
fn polynomial_arith() {
use pairing::bls12_381::Fr;
use bls12_381::Scalar as Fr;
use rand_core::RngCore;
fn test_mul<S: PrimeField, R: RngCore>(rng: &mut R) {
@ -422,7 +422,7 @@ fn polynomial_arith() {
#[cfg(feature = "pairing")]
#[test]
fn fft_composition() {
use pairing::bls12_381::Fr;
use bls12_381::Scalar as Fr;
use rand_core::RngCore;
fn test_comp<S: PrimeField, R: RngCore>(rng: &mut R) {
@ -460,7 +460,7 @@ fn fft_composition() {
#[cfg(feature = "pairing")]
#[test]
fn parallel_fft_consistency() {
use pairing::bls12_381::Fr;
use bls12_381::Scalar as Fr;
use rand_core::RngCore;
use std::cmp::min;

View File

@ -408,8 +408,8 @@ pub fn blake2s<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
#[cfg(test)]
mod test {
use blake2s_simd::Params as Blake2sParams;
use bls12_381::Scalar;
use hex_literal::hex;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -420,7 +420,7 @@ mod test {
#[test]
fn test_blank_hash() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let input_bits = vec![];
let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
@ -443,7 +443,7 @@ mod test {
#[test]
fn test_blake2s_constraints() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let input_bits: Vec<_> = (0..512)
.map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
@ -461,7 +461,7 @@ mod test {
// Test that 512 fixed leading bits (constants)
// doesn't result in more constraints.
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
@ -481,7 +481,7 @@ mod test {
#[test]
fn test_blake2s_constant_constraints() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
@ -512,7 +512,7 @@ mod test {
let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut input_bits = vec![];
@ -559,7 +559,7 @@ mod test {
let data: Vec<u8> = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec();
assert_eq!(data.len(), 256);
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut input_bits = vec![];
@ -596,7 +596,7 @@ mod test {
let data: Vec<u8> = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec();
assert_eq!(data.len(), 700);
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut input_bits = vec![];
@ -651,7 +651,7 @@ mod test {
let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut input_bits = vec![];

View File

@ -749,19 +749,19 @@ mod test {
use super::{field_into_allocated_bits_le, u64_into_boolean_vec_le, AllocatedBit, Boolean};
use crate::gadgets::test::*;
use crate::ConstraintSystem;
use bls12_381::Scalar;
use ff::{Field, PrimeField};
use pairing::bls12_381::Fr;
#[test]
fn test_allocated_bit() {
let mut cs = TestConstraintSystem::new();
AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
assert!(cs.get("boolean") == Fr::one());
assert!(cs.get("boolean") == Scalar::one());
assert!(cs.is_satisfied());
cs.set("boolean", Fr::zero());
cs.set("boolean", Scalar::zero());
assert!(cs.is_satisfied());
cs.set("boolean", Fr::from_str("2").unwrap());
cs.set("boolean", Scalar::from_str("2").unwrap());
assert!(!cs.is_satisfied());
assert!(cs.which_is_unsatisfied() == Some("boolean constraint"));
}
@ -770,7 +770,7 @@ mod test {
fn test_xor() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::xor(&mut cs, &a, &b).unwrap();
@ -806,7 +806,7 @@ mod test {
fn test_and() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::and(&mut cs, &a, &b).unwrap();
@ -842,7 +842,7 @@ mod test {
fn test_and_not() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::and_not(&mut cs, &a, &b).unwrap();
@ -878,7 +878,7 @@ mod test {
fn test_nor() {
for a_val in [false, true].iter() {
for b_val in [false, true].iter() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
let c = AllocatedBit::nor(&mut cs, &a, &b).unwrap();
@ -917,7 +917,7 @@ mod test {
for a_neg in [false, true].iter().cloned() {
for b_neg in [false, true].iter().cloned() {
{
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(),
@ -938,7 +938,7 @@ mod test {
assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
}
{
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut a = Boolean::Constant(a_bool);
let mut b = Boolean::from(
@ -957,7 +957,7 @@ mod test {
assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
}
{
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(),
@ -976,7 +976,7 @@ mod test {
assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
}
{
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut a = Boolean::Constant(a_bool);
let mut b = Boolean::Constant(b_bool);
@ -1005,7 +1005,7 @@ mod test {
#[test]
fn test_boolean_negation() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap());
@ -1097,7 +1097,7 @@ mod test {
for first_operand in variants.iter().cloned() {
for second_operand in variants.iter().cloned() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a;
let b;
@ -1306,7 +1306,7 @@ mod test {
for first_operand in variants.iter().cloned() {
for second_operand in variants.iter().cloned() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a;
let b;
@ -1527,7 +1527,7 @@ mod test {
#[test]
fn test_u64_into_boolean_vec_le() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let bits = u64_into_boolean_vec_le(&mut cs, Some(17234652694787248421)).unwrap();
@ -1548,9 +1548,9 @@ mod test {
#[test]
fn test_field_into_allocated_bits_le() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let r = Fr::from_str(
let r = Scalar::from_str(
"9147677615426976802526883532204139322118074541891858454835346926874644257775",
)
.unwrap();
@ -1643,16 +1643,16 @@ mod test {
} else {
assert_eq!(cs.get("ch"), {
if expected {
Fr::one()
Scalar::one()
} else {
Fr::zero()
Scalar::zero()
}
});
cs.set("ch", {
if expected {
Fr::zero()
Scalar::zero()
} else {
Fr::one()
Scalar::one()
}
});
assert_eq!(cs.which_is_unsatisfied().unwrap(), "ch computation");
@ -1735,16 +1735,16 @@ mod test {
} else {
assert_eq!(cs.get("maj"), {
if expected {
Fr::one()
Scalar::one()
} else {
Fr::zero()
Scalar::zero()
}
});
cs.set("maj", {
if expected {
Fr::zero()
Scalar::zero()
} else {
Fr::one()
Scalar::one()
}
});
assert_eq!(cs.which_is_unsatisfied().unwrap(), "maj computation");
@ -1757,7 +1757,7 @@ mod test {
#[test]
fn test_alloc_conditionally() {
{
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
let value = None;
@ -1773,7 +1773,7 @@ mod test {
{
// since value is true, b must be false, so it should succeed
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let value = Some(true);
let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
@ -1790,7 +1790,7 @@ mod test {
{
// since value is true, b must be false, so it should fail
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let value = Some(true);
let b = AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
@ -1805,7 +1805,7 @@ mod test {
let value = Some(false);
//check with false bit
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let b1 = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b1)
.unwrap();
@ -1813,7 +1813,7 @@ mod test {
assert!(cs.is_satisfied());
//check with true bit
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b2)
.unwrap();

View File

@ -191,8 +191,8 @@ mod test {
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
use bls12_381::Scalar;
use ff::Field;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, Neg};
@ -218,8 +218,8 @@ mod test {
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..8)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
let points: Vec<(Scalar, Scalar)> = (0..8)
.map(|_| (Scalar::random(&mut rng), Scalar::random(&mut rng)))
.collect();
let res = lookup3_xy(&mut cs, &bits, &points).unwrap();
@ -263,8 +263,8 @@ mod test {
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..4)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
let points: Vec<(Scalar, Scalar)> = (0..4)
.map(|_| (Scalar::random(&mut rng), Scalar::random(&mut rng)))
.collect();
let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap();
@ -297,15 +297,15 @@ mod test {
let window_size = 4;
let mut assignment = vec![Fr::zero(); 1 << window_size];
let mut assignment = vec![Scalar::zero(); 1 << window_size];
let constants: Vec<_> = (0..(1 << window_size))
.map(|_| Fr::random(&mut rng))
.map(|_| Scalar::random(&mut rng))
.collect();
synth(window_size, &constants, &mut assignment);
for b in 0..(1 << window_size) {
let mut acc = Fr::zero();
let mut acc = Scalar::zero();
for j in 0..(1 << window_size) {
if j & b == j {

View File

@ -74,7 +74,7 @@ pub fn compute_multipacking<Scalar: PrimeField>(bits: &[bool]) -> Vec<Scalar> {
#[test]
fn test_multipacking() {
use crate::ConstraintSystem;
use pairing::bls12_381::Fr;
use bls12_381::Scalar;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -87,7 +87,7 @@ fn test_multipacking() {
]);
for num_bits in 0..1500 {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();

View File

@ -410,8 +410,8 @@ impl<Scalar: PrimeField> Num<Scalar> {
#[cfg(test)]
mod test {
use crate::ConstraintSystem;
use bls12_381::Scalar;
use ff::{BitIterator, Field, PrimeField};
use pairing::bls12_381::Fr;
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{Neg, SubAssign};
@ -423,22 +423,22 @@ mod test {
fn test_allocated_num() {
let mut cs = TestConstraintSystem::new();
AllocatedNum::alloc(&mut cs, || Ok(Fr::one())).unwrap();
AllocatedNum::alloc(&mut cs, || Ok(Scalar::one())).unwrap();
assert!(cs.get("num") == Fr::one());
assert!(cs.get("num") == Scalar::one());
}
#[test]
fn test_num_squaring() {
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap();
let n = AllocatedNum::alloc(&mut cs, || Ok(Scalar::from_str("3").unwrap())).unwrap();
let n2 = n.square(&mut cs).unwrap();
assert!(cs.is_satisfied());
assert!(cs.get("squared num") == Fr::from_str("9").unwrap());
assert!(n2.value.unwrap() == Fr::from_str("9").unwrap());
cs.set("squared num", Fr::from_str("10").unwrap());
assert!(cs.get("squared num") == Scalar::from_str("9").unwrap());
assert!(n2.value.unwrap() == Scalar::from_str("9").unwrap());
cs.set("squared num", Scalar::from_str("10").unwrap());
assert!(!cs.is_satisfied());
}
@ -446,16 +446,16 @@ mod test {
fn test_num_multiplication() {
let mut cs = TestConstraintSystem::new();
let n =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
let n2 =
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Scalar::from_str("12").unwrap()))
.unwrap();
let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Scalar::from_str("10").unwrap()))
.unwrap();
let n3 = n.mul(&mut cs, &n2).unwrap();
assert!(cs.is_satisfied());
assert!(cs.get("product num") == Fr::from_str("120").unwrap());
assert!(n3.value.unwrap() == Fr::from_str("120").unwrap());
cs.set("product num", Fr::from_str("121").unwrap());
assert!(cs.get("product num") == Scalar::from_str("120").unwrap());
assert!(n3.value.unwrap() == Scalar::from_str("120").unwrap());
cs.set("product num", Scalar::from_str("121").unwrap());
assert!(!cs.is_satisfied());
}
@ -468,8 +468,10 @@ mod test {
{
let mut cs = TestConstraintSystem::new();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
let a =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Scalar::random(&mut rng))).unwrap();
let b =
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Scalar::random(&mut rng))).unwrap();
let condition = Boolean::constant(false);
let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap();
@ -482,8 +484,10 @@ mod test {
{
let mut cs = TestConstraintSystem::new();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
let a =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Scalar::random(&mut rng))).unwrap();
let b =
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Scalar::random(&mut rng))).unwrap();
let condition = Boolean::constant(true);
let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap();
@ -499,24 +503,24 @@ mod test {
{
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap();
let n = AllocatedNum::alloc(&mut cs, || Ok(Scalar::from_str("3").unwrap())).unwrap();
n.assert_nonzero(&mut cs).unwrap();
assert!(cs.is_satisfied());
cs.set("ephemeral inverse", Fr::from_str("3").unwrap());
cs.set("ephemeral inverse", Scalar::from_str("3").unwrap());
assert!(cs.which_is_unsatisfied() == Some("nonzero assertion constraint"));
}
{
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::zero())).unwrap();
let n = AllocatedNum::alloc(&mut cs, || Ok(Scalar::zero())).unwrap();
assert!(n.assert_nonzero(&mut cs).is_err());
}
}
#[test]
fn test_into_bits_strict() {
let negone = Fr::one().neg();
let negone = Scalar::one().neg();
let mut cs = TestConstraintSystem::new();
@ -526,7 +530,7 @@ mod test {
assert!(cs.is_satisfied());
// make the bit representation the characteristic
cs.set("bit 254/boolean", Fr::one());
cs.set("bit 254/boolean", Scalar::one());
// this makes the conditional boolean constraint fail
assert_eq!(
@ -543,7 +547,7 @@ mod test {
]);
for i in 0..200 {
let r = Fr::random(&mut rng);
let r = Scalar::random(&mut rng);
let mut cs = TestConstraintSystem::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap();
@ -567,15 +571,15 @@ mod test {
}
}
cs.set("num", Fr::random(&mut rng));
cs.set("num", Scalar::random(&mut rng));
assert!(!cs.is_satisfied());
cs.set("num", r);
assert!(cs.is_satisfied());
for i in 0..Fr::NUM_BITS {
for i in 0..Scalar::NUM_BITS {
let name = format!("bit {}/boolean", i);
let cur = cs.get(&name);
let mut tmp = Fr::one();
let mut tmp = Scalar::one();
tmp.sub_assign(&cur);
cs.set(&name, tmp);
assert!(!cs.is_satisfied());

View File

@ -273,8 +273,8 @@ mod test {
use super::*;
use crate::gadgets::boolean::AllocatedBit;
use crate::gadgets::test::TestConstraintSystem;
use bls12_381::Scalar;
use hex_literal::hex;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -282,7 +282,7 @@ mod test {
fn test_blank_hash() {
let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
input_bits[0] = Boolean::Constant(true);
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
@ -312,7 +312,7 @@ mod test {
let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let input_bits: Vec<_> = (0..512)
.map(|i| {
Boolean::from(
@ -346,7 +346,7 @@ mod test {
h.update(&data);
let hash_result = h.finalize();
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let mut input_bits = vec![];
for (byte_i, input_byte) in data.into_iter().enumerate() {

View File

@ -418,46 +418,46 @@ impl<Scalar: PrimeField> ConstraintSystem<Scalar> for TestConstraintSystem<Scala
#[test]
fn test_cs() {
use ff::{Field, PrimeField};
use pairing::bls12_381::Fr;
use bls12_381::Scalar;
use ff::PrimeField;
let mut cs = TestConstraintSystem::new();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 0);
let a = cs
.namespace(|| "a")
.alloc(|| "var", || Ok(Fr::from_str("10").unwrap()))
.alloc(|| "var", || Ok(Scalar::from_str("10").unwrap()))
.unwrap();
let b = cs
.namespace(|| "b")
.alloc(|| "var", || Ok(Fr::from_str("4").unwrap()))
.alloc(|| "var", || Ok(Scalar::from_str("4").unwrap()))
.unwrap();
let c = cs
.alloc(|| "product", || Ok(Fr::from_str("40").unwrap()))
.alloc(|| "product", || Ok(Scalar::from_str("40").unwrap()))
.unwrap();
cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c);
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1);
cs.set("a/var", Fr::from_str("4").unwrap());
cs.set("a/var", Scalar::from_str("4").unwrap());
let one = TestConstraintSystem::<Fr>::one();
let one = TestConstraintSystem::<Scalar>::one();
cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b);
assert!(!cs.is_satisfied());
assert!(cs.which_is_unsatisfied() == Some("mult"));
assert!(cs.get("product") == Fr::from_str("40").unwrap());
assert!(cs.get("product") == Scalar::from_str("40").unwrap());
cs.set("product", Fr::from_str("16").unwrap());
cs.set("product", Scalar::from_str("16").unwrap());
assert!(cs.is_satisfied());
{
let mut cs = cs.namespace(|| "test1");
let mut cs = cs.namespace(|| "test2");
cs.alloc(|| "hehe", || Ok(Fr::one())).unwrap();
cs.alloc(|| "hehe", || Ok(Scalar::one())).unwrap();
}
assert!(cs.get("test1/test2/hehe") == Fr::one());
assert!(cs.get("test1/test2/hehe") == Scalar::one());
}

View File

@ -401,8 +401,8 @@ mod test {
use crate::gadgets::multieq::MultiEq;
use crate::gadgets::test::*;
use crate::ConstraintSystem;
use bls12_381::Scalar;
use ff::Field;
use pairing::bls12_381::Fr;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -484,7 +484,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -529,7 +529,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -572,7 +572,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -685,7 +685,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = rng.next_u32();
let b = rng.next_u32();
@ -729,7 +729,7 @@ mod test {
]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut cs = TestConstraintSystem::<Scalar>::new();
let a = rng.next_u32();
let b = rng.next_u32();

View File

@ -479,8 +479,8 @@ mod test_with_bls12_381 {
use super::*;
use crate::{Circuit, ConstraintSystem, SynthesisError};
use bls12_381::{Bls12, Scalar};
use ff::{Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr};
use rand::thread_rng;
use std::ops::MulAssign;
@ -537,8 +537,8 @@ mod test_with_bls12_381 {
let pvk = prepare_verifying_key::<Bls12>(&params.vk);
for _ in 0..100 {
let a = Fr::random(rng);
let b = Fr::random(rng);
let a = Scalar::random(rng);
let b = Scalar::random(rng);
let mut c = a;
c.mul_assign(&b);

View File

@ -311,17 +311,19 @@ fn test_with_bls12() {
acc
}
use bls12_381::{Bls12, Scalar};
use group::{Curve, Group};
use pairing::{
bls12_381::{Bls12, Fr},
Engine,
};
use pairing::Engine;
use rand;
const SAMPLES: usize = 1 << 14;
let rng = &mut rand::thread_rng();
let v = Arc::new((0..SAMPLES).map(|_| Fr::random(rng)).collect::<Vec<_>>());
let v = Arc::new(
(0..SAMPLES)
.map(|_| Scalar::random(rng))
.collect::<Vec<_>>(),
);
let g = Arc::new(
(0..SAMPLES)
.map(|_| <Bls12 as Engine>::G1::random(rng).to_affine())

View File

@ -8,7 +8,7 @@ use std::time::{Duration, Instant};
use ff::{Field, PrimeField};
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
use pairing::bls12_381::{Bls12, Fr};
use bls12_381::{Bls12, Scalar};
// We'll use these interfaces to construct our circuit.
use bellman::{Circuit, ConstraintSystem, SynthesisError};
@ -151,7 +151,7 @@ fn test_mimc() {
// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS)
.map(|_| Fr::random(rng))
.map(|_| Scalar::random(rng))
.collect::<Vec<_>>();
println!("Creating parameters...");
@ -183,8 +183,8 @@ fn test_mimc() {
for _ in 0..SAMPLES {
// Generate a random preimage and compute the image
let xl = Fr::random(rng);
let xr = Fr::random(rng);
let xl = Scalar::random(rng);
let xr = Scalar::random(rng);
let image = mimc(xl, xr, &constants);
proof_vec.truncate(0);

View File

@ -32,9 +32,5 @@ unstable-features = ["expose-arith"]
expose-arith = []
default = []
[[bench]]
name = "pairing_benches"
harness = false
[badges]
maintenance = { status = "actively-developed" }

View File

@ -1,173 +0,0 @@
pub(crate) mod g1 {
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::AddAssign;
use ff::Field;
use group::Group;
use pairing::bls12_381::*;
fn bench_g1_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let v: Vec<(G1, Fr)> = (0..SAMPLES)
.map(|_| (G1::random(&mut rng), Fr::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("G1::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp *= v[count].1;
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_g1_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let v: Vec<(G1, G1)> = (0..SAMPLES)
.map(|_| (G1::random(&mut rng), G1::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("G1::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_g1_add_assign_mixed(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let v: Vec<(G1, G1Affine)> = (0..SAMPLES)
.map(|_| (G1::random(&mut rng), G1::random(&mut rng).into()))
.collect();
let mut count = 0;
c.bench_function("G1::add_assign_mixed", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_g1_add_assign,
bench_g1_add_assign_mixed,
bench_g1_mul_assign,
);
}
pub(crate) mod g2 {
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::AddAssign;
use ff::Field;
use group::Group;
use pairing::bls12_381::*;
fn bench_g2_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let v: Vec<(G2, Fr)> = (0..SAMPLES)
.map(|_| (G2::random(&mut rng), Fr::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("G2::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp *= v[count].1;
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_g2_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let v: Vec<(G2, G2)> = (0..SAMPLES)
.map(|_| (G2::random(&mut rng), G2::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("G2::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_g2_add_assign_mixed(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let v: Vec<(G2, G2Affine)> = (0..SAMPLES)
.map(|_| (G2::random(&mut rng), G2::random(&mut rng).into()))
.collect();
let mut count = 0;
c.bench_function("G2::add_assign_mixed", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_g2_add_assign,
bench_g2_add_assign_mixed,
bench_g2_mul_assign,
);
}

View File

@ -1,209 +0,0 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField};
use pairing::bls12_381::*;
fn bench_fq_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
.map(|_| (Fq::random(&mut rng), Fq::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
.map(|_| (Fq::random(&mut rng), Fq::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
.map(|_| (Fq::random(&mut rng), Fq::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq_square(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq::invert", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].invert()
})
});
}
fn bench_fq_neg(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq::neg", |b| {
b.iter(|| {
let tmp = v[count].neg();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq_sqrt(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq> = (0..SAMPLES)
.map(|_| Fq::random(&mut rng).square())
.collect();
let mut count = 0;
c.bench_function("Fq::sqrt", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
})
});
}
fn bench_fq_to_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq::to_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].to_repr()
})
});
}
fn bench_fq_from_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<FqRepr> = (0..SAMPLES)
.map(|_| Fq::random(&mut rng).to_repr())
.collect();
let mut count = 0;
c.bench_function("Fq::from_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
Fq::from_repr(v[count])
})
});
}
criterion_group!(
benches,
bench_fq_add_assign,
bench_fq_sub_assign,
bench_fq_mul_assign,
bench_fq_square,
bench_fq_invert,
bench_fq_neg,
bench_fq_sqrt,
bench_fq_to_repr,
bench_fq_from_repr,
);

View File

@ -1,125 +0,0 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, SubAssign};
use ff::Field;
use pairing::bls12_381::*;
fn bench_fq12_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
.map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq12::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq12_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
.map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq12::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq12_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
.map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq12::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq12_squaring(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq12::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq12_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq12::invert", |b| {
b.iter(|| {
let tmp = v[count].invert();
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_fq12_add_assign,
bench_fq12_sub_assign,
bench_fq12_mul_assign,
bench_fq12_squaring,
bench_fq12_invert,
);

View File

@ -1,146 +0,0 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, SubAssign};
use ff::Field;
use pairing::bls12_381::*;
fn bench_fq2_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
.map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq2::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq2_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
.map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq2::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq2_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
.map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fq2::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq2_squaring(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq2::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq2_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq2::invert", |b| {
b.iter(|| {
let tmp = v[count].invert();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fq2_sqrt(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fq2::sqrt", |b| {
b.iter(|| {
let tmp = v[count].sqrt();
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_fq2_add_assign,
bench_fq2_sub_assign,
bench_fq2_mul_assign,
bench_fq2_squaring,
bench_fq2_invert,
bench_fq2_sqrt,
);

View File

@ -1,209 +0,0 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField};
use pairing::bls12_381::*;
fn bench_fr_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fr::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fr_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fr::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fr_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let mut count = 0;
c.bench_function("Fr::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fr_square(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fr::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fr_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fr::invert", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].invert()
})
});
}
fn bench_fr_neg(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fr::neg", |b| {
b.iter(|| {
let tmp = v[count].neg();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_fr_sqrt(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fr> = (0..SAMPLES)
.map(|_| Fr::random(&mut rng).square())
.collect();
let mut count = 0;
c.bench_function("Fr::sqrt", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
})
});
}
fn bench_fr_to_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("Fr::to_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].to_repr()
})
});
}
fn bench_fr_from_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<FrRepr> = (0..SAMPLES)
.map(|_| Fr::random(&mut rng).to_repr())
.collect();
let mut count = 0;
c.bench_function("Fr::from_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
Fr::from_repr(v[count])
})
});
}
criterion_group!(
benches,
bench_fr_add_assign,
bench_fr_sub_assign,
bench_fr_mul_assign,
bench_fr_square,
bench_fr_invert,
bench_fr_neg,
bench_fr_sqrt,
bench_fr_to_repr,
bench_fr_from_repr,
);

View File

@ -1,118 +0,0 @@
pub(crate) mod ec;
pub(crate) mod fq;
pub(crate) mod fq12;
pub(crate) mod fq2;
pub(crate) mod fr;
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use group::Group;
use pairing::bls12_381::*;
use pairing::{Engine, MillerLoopResult, MultiMillerLoop};
fn bench_pairing_g2_preparation(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<G2> = (0..SAMPLES).map(|_| G2::random(&mut rng)).collect();
let mut count = 0;
c.bench_function("G2 preparation", |b| {
b.iter(|| {
let tmp = G2Prepared::from(G2Affine::from(v[count]));
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_pairing_miller_loop(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(G1Affine, G2Prepared)> = (0..SAMPLES)
.map(|_| {
(
G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).into(),
)
})
.collect();
let mut count = 0;
c.bench_function("Miller loop", |b| {
b.iter(|| {
let tmp = Bls12::multi_miller_loop(&[(&v[count].0, &v[count].1)]);
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_pairing_final_exponentiation(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<Fq12> = (0..SAMPLES)
.map(|_| {
(
G1Affine::from(G1::random(&mut rng)),
G2Affine::from(G2::random(&mut rng)).into(),
)
})
.map(|(ref p, ref q)| Bls12::multi_miller_loop(&[(p, q)]))
.collect();
let mut count = 0;
c.bench_function("Final exponentiation", |b| {
b.iter(|| {
let tmp = v[count].final_exponentiation();
count = (count + 1) % SAMPLES;
tmp
})
});
}
fn bench_pairing_full(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let v: Vec<(G1Affine, G2Affine)> = (0..SAMPLES)
.map(|_| (G1::random(&mut rng).into(), G2::random(&mut rng).into()))
.collect();
let mut count = 0;
c.bench_function("Full pairing", |b| {
b.iter(|| {
let tmp = Bls12::pairing(&v[count].0, &v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_pairing_g2_preparation,
bench_pairing_miller_loop,
bench_pairing_final_exponentiation,
bench_pairing_full,
);

View File

@ -1,12 +0,0 @@
use criterion::criterion_main;
mod bls12_381;
criterion_main!(
bls12_381::benches,
bls12_381::ec::g1::benches,
bls12_381::ec::g2::benches,
bls12_381::fq::benches,
bls12_381::fq12::benches,
bls12_381::fq2::benches,
bls12_381::fr::benches,
);

View File

@ -1,71 +0,0 @@
# BLS12-381
This is an implementation of the BLS12-381 pairing-friendly elliptic curve construction.
## BLS12 Parameterization
BLS12 curves are parameterized by a value *x* such that the base field modulus *q* and subgroup *r* can be computed by:
* q = (x - 1)<sup>2</sup> ((x<sup>4</sup> - x<sup>2</sup> + 1) / 3) + x
* r = (x<sup>4</sup> - x<sup>2</sup> + 1)
Given primes *q* and *r* parameterized as above, we can easily construct an elliptic curve over the prime field F<sub>*q*</sub> which contains a subgroup of order *r* such that *r* | (*q*<sup>12</sup> - 1), giving it an embedding degree of 12. Instantiating its sextic twist over an extension field F<sub>q<sup>2</sup></sub> gives rise to an efficient bilinear pairing function between elements of the order *r* subgroups of either curves, into an order *r* multiplicative subgroup of F<sub>q<sup>12</sup></sub>.
In zk-SNARK schemes, we require F<sub>r</sub> with large 2<sup>n</sup> roots of unity for performing efficient fast-fourier transforms. As such, guaranteeing that large 2<sup>n</sup> | (r - 1), or equivalently that *x* has a large 2<sup>n</sup> factor, gives rise to BLS12 curves suitable for zk-SNARKs.
Due to recent research, it is estimated by many that *q* should be approximately 384 bits to target 128-bit security. Conveniently, *r* is approximately 256 bits when *q* is approximately 384 bits, making BLS12 curves ideal for 128-bit security. It also makes them ideal for many zk-SNARK applications, as the scalar field can be used for keying material such as embedded curve constructions.
Many curves match our descriptions, but we require some extra properties for efficiency purposes:
* *q* should be smaller than 2<sup>383</sup>, and *r* should be smaller than 2<sup>255</sup>, so that the most significant bit is unset when using 64-bit or 32-bit limbs. This allows for cheap reductions.
* F<sub>q<sup>12</sup></sub> is typically constructed using towers of extension fields. As a byproduct of [research](https://eprint.iacr.org/2011/465.pdf) for BLS curves of embedding degree 24, we can identify subfamilies of BLS12 curves (for our purposes, where x mod 72 = {16, 64}) that produce efficient extension field towers and twisting isomorphisms.
* We desire *x* of small Hamming weight, to increase the performance of the pairing function.
## BLS12-381 Instantiation
The BLS12-381 construction is instantiated by `x = -0xd201000000010000`, which produces the largest `q` and smallest Hamming weight of `x` that meets the above requirements. This produces:
* q = `0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab` (381 bits)
* r = `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` (255 bits)
Our extension field tower is constructed as follows:
1. F<sub>q<sup>2</sup></sub> is constructed as F<sub>q</sub>(u) / (u<sup>2</sup> - β) where β = -1.
2. F<sub>q<sup>6</sup></sub> is constructed as F<sub>q<sup>2</sup></sub>(v) / (v<sup>3</sup> - ξ) where ξ = u + 1
3. F<sub>q<sup>12</sup></sub> is constructed as F<sub>q<sup>6</sup></sub>(w) / (w<sup>2</sup> - γ) where γ = v
Now, we instantiate the elliptic curve E(F<sub>q</sub>) : y<sup>2</sup> = x<sup>3</sup> + 4, and the elliptic curve E'(F<sub>q<sup>2</sup></sub>) : y<sup>2</sup> = x<sup>3</sup> + 4(u + 1).
The group G<sub>1</sub> is the *r* order subgroup of E, which has cofactor (x - 1)<sup>2</sup> / 3. The group G<sub>2</sub> is the *r* order subgroup of E', which has cofactor (x<sup>8</sup> - 4x<sup>7</sup> + 5x<sup>6</sup> - 4x<sup>4</sup> + 6x<sup>3</sup> - 4x<sup>2</sup> - 4x + 13) / 9.
### Generators
The generators of G<sub>1</sub> and G<sub>2</sub> are computed by finding the lexicographically smallest valid `x`-coordinate, and its lexicographically smallest `y`-coordinate and scaling it by the cofactor such that the result is not the point at infinity.
#### G1
```
x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
```
#### G2
```
x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
```
### Serialization
* Fq elements are encoded in big-endian form. They occupy 48 bytes in this form.
* Fq2 elements are encoded in big-endian form, meaning that the Fq element c0 + c1 * u is represented by the Fq element c1 followed by the Fq element c0. This means Fq2 elements occupy 96 bytes in this form.
* The group G1 uses Fq elements for coordinates. The group G2 uses Fq2 elements for coordinates.
* G1 and G2 elements can be encoded in uncompressed form (the x-coordinate followed by the y-coordinate) or in compressed form (just the x-coordinate). G1 elements occupy 96 bytes in uncompressed form, and 48 bytes in compressed form. G2 elements occupy 192 bytes in uncompressed form, and 96 bytes in compressed form.
The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element:
* The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form.
* The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero.
* The third-most significant bit is set if (and only if) this point is in compressed form _and_ it is not the point at infinity _and_ its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,286 +0,0 @@
use super::fq::FROBENIUS_COEFF_FQ12_C1;
use super::fq2::Fq2;
use super::fq6::Fq6;
use ff::Field;
use rand_core::RngCore;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq12, represented by c0 + c1 * w.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq12 {
pub c0: Fq6,
pub c1: Fq6,
}
impl ::std::fmt::Display for Fq12 {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "Fq12({} + {} * w)", self.c0, self.c1)
}
}
impl Fq12 {
pub fn conjugate(&mut self) {
self.c1 = self.c1.neg();
}
pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) {
let mut aa = self.c0;
aa.mul_by_01(c0, c1);
let mut bb = self.c1;
bb.mul_by_1(c4);
let mut o = *c1;
o.add_assign(c4);
self.c1.add_assign(&self.c0);
self.c1.mul_by_01(c0, &o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = bb;
self.c0.mul_by_nonresidue();
self.c0.add_assign(&aa);
}
pub fn frobenius_map(&mut self, power: usize) {
self.c0.frobenius_map(power);
self.c1.frobenius_map(power);
self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
}
}
impl ConditionallySelectable for Fq12 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq12 {
c0: Fq6::conditional_select(&a.c0, &b.c0, choice),
c1: Fq6::conditional_select(&a.c1, &b.c1, choice),
}
}
}
impl Neg for Fq12 {
type Output = Self;
fn neg(self) -> Self {
Fq12 {
c0: self.c0.neg(),
c1: self.c1.neg(),
}
}
}
impl<'r> Add<&'r Fq12> for Fq12 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq12 {
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
}
}
}
impl Add for Fq12 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<'r> AddAssign<&'r Fq12> for Fq12 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
}
impl AddAssign for Fq12 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq12> for Fq12 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq12 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
}
}
}
impl Sub for Fq12 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq12> for Fq12 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
}
impl SubAssign for Fq12 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> Mul<&'r Fq12> for Fq12 {
type Output = Self;
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq12 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq12> for Fq12 {
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = bb;
self.c0.mul_by_nonresidue();
self.c0.add_assign(&aa);
}
}
impl MulAssign for Fq12 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq12 {
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
Fq12 {
c0: Fq6::random(rng),
c1: Fq6::random(rng),
}
}
fn zero() -> Self {
Fq12 {
c0: Fq6::zero(),
c1: Fq6::zero(),
}
}
fn one() -> Self {
Fq12 {
c0: Fq6::one(),
c1: Fq6::zero(),
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero()
}
fn double(&self) -> Self {
Fq12 {
c0: self.c0.double(),
c1: self.c1.double(),
}
}
fn square(&self) -> Self {
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut c0c1 = self.c0;
c0c1.add_assign(&self.c1);
let mut c0 = self.c1;
c0.mul_by_nonresidue();
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
let mut c1 = ab;
c1.add_assign(&ab);
ab.mul_by_nonresidue();
c0.sub_assign(&ab);
Fq12 { c0, c1 }
}
fn invert(&self) -> CtOption<Self> {
let mut c0s = self.c0.square();
let mut c1s = self.c1.square();
c1s.mul_by_nonresidue();
c0s.sub_assign(&c1s);
c0s.invert().map(|t| Fq12 {
c0: t.mul(&self.c0),
c1: t.mul(&self.c1).neg(),
})
}
fn sqrt(&self) -> CtOption<Self> {
unimplemented!()
}
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
#[test]
fn test_fq12_mul_by_014() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let c0 = Fq2::random(&mut rng);
let c1 = Fq2::random(&mut rng);
let c5 = Fq2::random(&mut rng);
let mut a = Fq12::random(&mut rng);
let mut b = a;
a.mul_by_014(&c0, &c1, &c5);
b.mul_assign(&Fq12 {
c0: Fq6 {
c0,
c1,
c2: Fq2::zero(),
},
c1: Fq6 {
c0: Fq2::zero(),
c1: c5,
c2: Fq2::zero(),
},
});
assert_eq!(a, b);
}
}
#[test]
fn fq12_field_tests() {
crate::tests::field::random_field_tests::<Fq12>();
}

View File

@ -1,925 +0,0 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::Field;
use rand_core::RngCore;
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq2, represented by c0 + c1 * u.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq2 {
pub c0: Fq,
pub c1: Fq,
}
impl ::std::fmt::Display for Fq2 {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "Fq2({} + {} * u)", self.c0, self.c1)
}
}
/// `Fq2` elements are ordered lexicographically.
impl Ord for Fq2 {
#[inline(always)]
fn cmp(&self, other: &Fq2) -> Ordering {
match self.c1.cmp(&other.c1) {
Ordering::Greater => Ordering::Greater,
Ordering::Less => Ordering::Less,
Ordering::Equal => self.c0.cmp(&other.c0),
}
}
}
impl PartialOrd for Fq2 {
#[inline(always)]
fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Fq2 {
/// Multiply this element by the cubic and quadratic nonresidue 1 + u.
pub fn mul_by_nonresidue(&mut self) {
let t0 = self.c0;
self.c0.sub_assign(&self.c1);
self.c1.add_assign(&t0);
}
/// Norm of Fq2 as extension field in i over Fq
pub fn norm(&self) -> Fq {
let t0 = self.c0.square();
let mut t1 = self.c1.square();
t1.add_assign(&t0);
t1
}
pub fn frobenius_map(&mut self, power: usize) {
self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]);
}
}
impl ConditionallySelectable for Fq2 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq2 {
c0: Fq::conditional_select(&a.c0, &b.c0, choice),
c1: Fq::conditional_select(&a.c1, &b.c1, choice),
}
}
}
impl Neg for Fq2 {
type Output = Self;
fn neg(self) -> Self {
Fq2 {
c0: self.c0.neg(),
c1: self.c1.neg(),
}
}
}
impl<'r> Add<&'r Fq2> for Fq2 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq2 {
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
}
}
}
impl Add for Fq2 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<'r> AddAssign<&'r Fq2> for Fq2 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
}
impl AddAssign for Fq2 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq2> for Fq2 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq2 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
}
}
}
impl Sub for Fq2 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq2> for Fq2 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
}
impl SubAssign for Fq2 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> Mul<&'r Fq2> for Fq2 {
type Output = Self;
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq2 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq2> for Fq2 {
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = aa;
self.c0.sub_assign(&bb);
}
}
impl MulAssign for Fq2 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq2 {
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
Fq2 {
c0: Fq::random(rng),
c1: Fq::random(rng),
}
}
fn zero() -> Self {
Fq2 {
c0: Fq::zero(),
c1: Fq::zero(),
}
}
fn one() -> Self {
Fq2 {
c0: Fq::one(),
c1: Fq::zero(),
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero()
}
fn square(&self) -> Self {
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut c0c1 = self.c0;
c0c1.add_assign(&self.c1);
let mut c0 = self.c1.neg();
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
let mut c1 = ab;
c1.add_assign(&ab);
c0.add_assign(&ab);
Fq2 { c0, c1 }
}
fn double(&self) -> Self {
Fq2 {
c0: self.c0.double(),
c1: self.c1.double(),
}
}
fn invert(&self) -> CtOption<Self> {
let t1 = self.c1.square();
let mut t0 = self.c0.square();
t0.add_assign(&t1);
t0.invert().map(|t| Fq2 {
c0: self.c0.mul(&t),
c1: self.c1.mul(&t).neg(),
})
}
/// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET!
/// THIS WILL BE REPLACED BY THE bls12_381 CRATE, WHICH IS CONSTANT TIME!
fn sqrt(&self) -> CtOption<Self> {
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
if self.is_zero() {
CtOption::new(Self::zero(), Choice::from(1))
} else {
// a1 = self^((q - 3) / 4)
let mut a1 = self.pow_vartime([
0xee7fbfffffffeaaau64,
0x7aaffffac54ffff,
0xd9cc34a83dac3d89,
0xd91dd2e13ce144af,
0x92c6e9ed90d2eb35,
0x680447a8e5ff9a6,
]);
let mut alpha = a1.square();
alpha.mul_assign(self);
let mut a0 = alpha;
a0.frobenius_map(1);
a0.mul_assign(&alpha);
let neg1 = Fq2 {
c0: NEGATIVE_ONE,
c1: Fq::zero(),
};
if a0 == neg1 {
CtOption::new(Self::zero(), Choice::from(0))
} else {
a1.mul_assign(self);
if alpha == neg1 {
a1.mul_assign(&Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
});
} else {
alpha.add_assign(&Fq2::one());
// alpha = alpha^((q - 1) / 2)
alpha = alpha.pow_vartime([
0xdcff7fffffffd555u64,
0xf55ffff58a9ffff,
0xb39869507b587b12,
0xb23ba5c279c2895f,
0x258dd3db21a5d66b,
0xd0088f51cbff34d,
]);
a1.mul_assign(&alpha);
}
CtOption::new(a1, Choice::from(1))
}
}
}
}
#[cfg(test)]
use super::fq::FqRepr;
#[cfg(test)]
use ff::PrimeField;
#[test]
fn test_fq2_ordering() {
let mut a = Fq2 {
c0: Fq::zero(),
c1: Fq::zero(),
};
let mut b = a;
assert!(a.cmp(&b) == Ordering::Equal);
b.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Less);
a.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Equal);
b.c1.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Less);
a.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Less);
a.c1.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Greater);
b.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Equal);
}
#[test]
fn test_fq2_basics() {
assert_eq!(
Fq2 {
c0: Fq::zero(),
c1: Fq::zero(),
},
Fq2::zero()
);
assert_eq!(
Fq2 {
c0: Fq::one(),
c1: Fq::zero(),
},
Fq2::one()
);
assert!(Fq2::zero().is_zero());
assert!(!Fq2::one().is_zero());
assert!(!Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}
.is_zero());
}
#[test]
fn test_fq2_squaring() {
let a = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
}; // u + 1
assert_eq!(
a.square(),
Fq2 {
c0: Fq::zero(),
c1: Fq::from(2),
}
); // 2u
let a = Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}; // u
assert_eq!(a.square(), {
Fq2 {
c0: Fq::one().neg(),
c1: Fq::zero(),
}
}); // -1
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x07, 0x08, 0x0c, 0x5f, 0xa1, 0xd8, 0xe0, 0x42, 0x41, 0xb7, 0x6d, 0xcc, 0x1c, 0x3f,
0xbe, 0x5e, 0xf7, 0xf2, 0x95, 0xa9, 0x4e, 0x58, 0xae, 0x7c, 0x90, 0xe3, 0x4a, 0xab,
0x6f, 0xb6, 0xa6, 0xbd, 0x4e, 0xef, 0x5c, 0x94, 0x65, 0x36, 0xf6, 0x02, 0x9c, 0x2c,
0x63, 0x09, 0xbb, 0xf8, 0xb5, 0x98,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x10, 0xd1, 0x61, 0x5e, 0x75, 0x25, 0x0a, 0x21, 0xfc, 0x58, 0xa7, 0xb7, 0xbe, 0x81,
0x54, 0x07, 0xbf, 0xb9, 0x90, 0x20, 0x60, 0x41, 0x37, 0xa0, 0xda, 0xc5, 0xa4, 0xc9,
0x11, 0xa4, 0x35, 0x3e, 0x6a, 0xd3, 0x29, 0x11, 0x77, 0xc8, 0xc7, 0xe5, 0x38, 0xf4,
0x73, 0xb3, 0xc8, 0x70, 0xa4, 0xab,
]))
.unwrap(),
};
assert_eq!(
a.square(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0x07, 0xea, 0xc8, 0x13, 0x69, 0xc4, 0x33, 0x61, 0x4c, 0xf1, 0x7b, 0x58, 0x93, 0xc3,
0xd3, 0x27, 0xcb, 0x67, 0x41, 0x57, 0x61, 0x8d, 0xa1, 0x76, 0x0d, 0xc4, 0x6a, 0xb8,
0xfa, 0xd6, 0x7a, 0xe0, 0xb9, 0xf2, 0xa6, 0x6e, 0xae, 0x10, 0x73, 0xba, 0xf2, 0x62,
0xc2, 0x8c, 0x53, 0x8b, 0xcf, 0x68,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x15, 0x42, 0xa6, 0x1c, 0x8a, 0x8d, 0xb9, 0x94, 0x73, 0x9c, 0x98, 0x30, 0x42, 0x77,
0x9a, 0x65, 0x38, 0xd0, 0xd7, 0x27, 0x5a, 0x96, 0x89, 0xe1, 0xe7, 0x51, 0x38, 0xbc,
0xe4, 0xce, 0xc7, 0xaa, 0xa2, 0x3e, 0xb7, 0xe1, 0x2d, 0xd5, 0x4d, 0x98, 0xc1, 0x57,
0x9c, 0xf5, 0x8e, 0x98, 0x0c, 0xf8,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_mul() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a,
0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15,
0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9,
0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d,
0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81,
0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34,
0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf,
]))
.unwrap(),
};
a.mul_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([
0x02, 0xc9, 0x3a, 0x72, 0xeb, 0x8a, 0xf8, 0x3e, 0x06, 0xc9, 0x11, 0x02, 0x92, 0xbf,
0xa4, 0x09, 0xcd, 0x46, 0x0f, 0x9f, 0x0c, 0x23, 0xe4, 0x30, 0x27, 0xec, 0xe1, 0x75,
0xbe, 0x07, 0xa5, 0x31, 0xfc, 0x87, 0xe6, 0x2e, 0x17, 0x9c, 0x28, 0x5d, 0xe2, 0x1f,
0x91, 0x69, 0x80, 0x5f, 0x53, 0x7e,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x19, 0xe1, 0x73, 0x34, 0xd4, 0xe9, 0x35, 0x58, 0x63, 0x4c, 0xd3, 0xc6, 0xc5, 0x65,
0x09, 0x6d, 0x57, 0xa0, 0x6d, 0x31, 0x35, 0xa7, 0x52, 0xae, 0x88, 0x71, 0xc5, 0x08,
0x65, 0x8d, 0x1e, 0x5f, 0x1d, 0x2a, 0x72, 0x91, 0x6d, 0xba, 0x4c, 0x8a, 0x4b, 0x1c,
0x3f, 0x93, 0x6d, 0x89, 0x92, 0xd4,
]))
.unwrap(),
});
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x17, 0x51, 0xaf, 0xbe, 0x16, 0x6e, 0x53, 0x99, 0x53, 0x10, 0xa2, 0x02, 0xd9, 0x2f,
0x99, 0x63, 0x55, 0x11, 0xfe, 0x4d, 0x84, 0xee, 0x5f, 0x78, 0xf6, 0x1a, 0x96, 0xda,
0xcf, 0x5a, 0x39, 0xbc, 0xde, 0x29, 0xc3, 0x1a, 0x19, 0xa6, 0x93, 0x7e, 0x95, 0xb5,
0x12, 0x7e, 0x63, 0x60, 0xc7, 0xe4,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0xef, 0x1a, 0x36, 0xc2, 0x01, 0x58, 0x9d, 0x33, 0xa9, 0xac, 0x82, 0xce, 0x4c,
0x50, 0x83, 0xc9, 0x75, 0x10, 0x65, 0x79, 0xc2, 0x75, 0xee, 0x5b, 0xa6, 0xe5, 0x43,
0x0e, 0x88, 0x3d, 0x40, 0x06, 0xc6, 0x3c, 0xd4, 0xda, 0x2c, 0x2a, 0xa7, 0x84, 0xaf,
0x0e, 0x1b, 0xd6, 0x30, 0x11, 0x7a,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_invert() {
use super::fq::FqRepr;
use ff::PrimeField;
assert!(bool::from(Fq2::zero().invert().is_none()));
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a,
0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15,
0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9,
0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d,
0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81,
0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34,
0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf,
]))
.unwrap(),
};
let a = a.invert().unwrap();
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x13, 0x51, 0xef, 0x01, 0x94, 0x1b, 0x70, 0xc4, 0xa6, 0xc3, 0xd8, 0xf9, 0x58, 0x6f,
0x26, 0x36, 0xdf, 0xba, 0x70, 0x32, 0x93, 0x94, 0x1c, 0x30, 0x64, 0xbe, 0xf6, 0x17,
0xd2, 0x91, 0x5a, 0x8f, 0xe5, 0xec, 0xda, 0x5f, 0xda, 0xfd, 0xdb, 0xb2, 0x07, 0x03,
0x00, 0xf9, 0xbc, 0xb9, 0xe5, 0x94,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x10, 0x3b, 0xdf, 0x24, 0x1a, 0xfb, 0x00, 0x19, 0xdf, 0x4e, 0x54, 0xf0, 0xd3, 0xef,
0x15, 0xa6, 0xcb, 0xf6, 0x51, 0xa0, 0xf3, 0x67, 0xaf, 0xb2, 0x94, 0x71, 0x43, 0xf8,
0x9f, 0xae, 0xde, 0xe9, 0x15, 0xd7, 0xb6, 0xb9, 0x5d, 0xef, 0xbf, 0xf0, 0x8c, 0x39,
0xfd, 0x76, 0xa8, 0x31, 0x2c, 0xb4,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_addition() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
};
a.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([
0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82,
0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a,
0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a,
0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10,
0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f,
0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32,
0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9,
]))
.unwrap(),
});
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x14, 0xc7, 0x15, 0xd5, 0x55, 0x3f, 0x01, 0xd2, 0x65, 0x30, 0x94, 0x27, 0xb3, 0xd5,
0xd0, 0x90, 0xf4, 0xef, 0x57, 0xd6, 0x04, 0xb6, 0xbc, 0xa2, 0xd7, 0x0b, 0x0c, 0x7b,
0x48, 0x1d, 0x23, 0xff, 0xcb, 0x20, 0x7e, 0x6b, 0x33, 0x41, 0xea, 0xba, 0x8e, 0x9a,
0x7a, 0xda, 0xf6, 0xeb, 0x0e, 0xb9,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x13, 0x03, 0xf3, 0x46, 0x51, 0x12, 0xc8, 0xbc, 0x9a, 0xd2, 0x65, 0xeb, 0x46, 0xe0,
0x19, 0x84, 0xd6, 0x2f, 0xa5, 0x13, 0x34, 0xf5, 0x60, 0xfa, 0xfe, 0x4b, 0x23, 0x31,
0x7e, 0x07, 0x96, 0xd5, 0x35, 0xa2, 0x80, 0x9d, 0x15, 0x46, 0x8d, 0x83, 0xfd, 0xb0,
0x32, 0xe7, 0xd9, 0x07, 0x9a, 0x94,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_subtraction() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
};
a.sub_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([
0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82,
0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a,
0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a,
0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10,
0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f,
0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32,
0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9,
]))
.unwrap(),
});
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x07, 0x2b, 0xa1, 0x40, 0x49, 0xfe, 0x98, 0x81, 0x7f, 0x77, 0xa7, 0x18, 0x02, 0x1c,
0x34, 0x2d, 0xe2, 0x55, 0x90, 0x26, 0x72, 0xef, 0x6c, 0x43, 0xa6, 0x5a, 0x6b, 0xe7,
0x00, 0xb2, 0x85, 0xfe, 0x77, 0x56, 0xbe, 0xd7, 0xc1, 0x59, 0x82, 0xe9, 0x85, 0x65,
0x75, 0x2b, 0xdb, 0x5c, 0x9b, 0x80,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x09, 0x57, 0x41, 0x13, 0x59, 0xba, 0x6e, 0x4c, 0x4c, 0xd5, 0xdd, 0x9f, 0xb4, 0x0b,
0x3b, 0x8f, 0xf6, 0x39, 0x05, 0xf3, 0x9a, 0xd8, 0xcb, 0x1f, 0xe5, 0x26, 0x17, 0x93,
0x05, 0x88, 0xc6, 0x9a, 0x11, 0xdf, 0x49, 0xbc, 0x6c, 0xac, 0xc2, 0x56, 0xeb, 0x4a,
0xba, 0xf7, 0xc2, 0x55, 0xd1, 0xcd,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_negation() {
use super::fq::FqRepr;
use ff::PrimeField;
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
}
.neg();
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x19, 0x08, 0x3f, 0x54, 0x86, 0xa1, 0x0c, 0xbd, 0x7e, 0x55, 0x5d, 0xf1, 0x89, 0xf8,
0x80, 0xe3, 0xab, 0x10, 0x7d, 0x49, 0x31, 0x74, 0x87, 0xab, 0xdc, 0x16, 0x7f, 0xc0,
0x4d, 0xa1, 0x9c, 0x37, 0x0c, 0xc6, 0x61, 0x5c, 0x8f, 0xb0, 0x49, 0x2d, 0x8c, 0xfe,
0x87, 0xfc, 0x96, 0xdb, 0xaa, 0xe4,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b,
0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f,
0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81,
0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_doubling() {
use super::fq::FqRepr;
use ff::PrimeField;
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
};
assert_eq!(
a.double(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0x01, 0xf1, 0xa5, 0x2b, 0x65, 0xbd, 0xb3, 0xb9, 0x99, 0x8c, 0x93, 0x89, 0x72, 0xa6,
0x57, 0xe7, 0x72, 0xcd, 0x9c, 0x77, 0x84, 0x21, 0x16, 0x27, 0x16, 0x34, 0xa5, 0xc1,
0x52, 0x1e, 0xb3, 0xda, 0x23, 0xcb, 0x3d, 0x44, 0x43, 0x47, 0x6d, 0xa4, 0x5a, 0x00,
0xf0, 0x06, 0xd2, 0x47, 0xff, 0x8e,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x02, 0x5a, 0x22, 0x6f, 0x71, 0x4d, 0x50, 0x6e, 0x9c, 0x8c, 0x9b, 0xd4, 0xb7, 0x9f,
0xa8, 0x3d, 0x67, 0xf1, 0x5f, 0x81, 0xdc, 0x49, 0x19, 0x5b, 0x7c, 0x40, 0x68, 0x23,
0x8c, 0xdf, 0x67, 0x4b, 0x28, 0xd5, 0xca, 0x5a, 0xd0, 0x9f, 0x4f, 0xdb, 0x2e, 0xfb,
0xed, 0xdf, 0x9b, 0x5d, 0xc1, 0xb6,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_frobenius_map() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
};
a.frobenius_map(0);
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
}
);
a.frobenius_map(1);
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b,
0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f,
0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81,
0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0,
]))
.unwrap(),
}
);
a.frobenius_map(1);
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
}
);
a.frobenius_map(2);
assert_eq!(
a,
Fq2 {
c0: Fq::from_repr(FqRepr([
0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
]))
.unwrap(),
}
);
}
#[test]
fn test_fq2_sqrt() {
use super::fq::FqRepr;
use ff::PrimeField;
assert_eq!(
Fq2 {
c0: Fq::from_repr(FqRepr([
0x07, 0xca, 0x7d, 0xa1, 0xf1, 0x36, 0x06, 0xac, 0x1e, 0x58, 0xb2, 0x15, 0x9d, 0xfe,
0x10, 0xe2, 0xdb, 0x4a, 0x11, 0x6b, 0x5b, 0xf7, 0x4a, 0xa1, 0xa5, 0x7e, 0x6f, 0xc1,
0xba, 0xb5, 0x1f, 0xd9, 0x03, 0x4c, 0x2d, 0x04, 0xfa, 0xff, 0xda, 0xb6, 0x47, 0x6b,
0x4c, 0x30, 0x97, 0x20, 0xe2, 0x27,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x0e, 0xc9, 0x23, 0x36, 0x65, 0x0e, 0x49, 0xd5, 0x08, 0xee, 0x53, 0x94, 0xd7, 0x7a,
0xfb, 0x3d, 0x21, 0x26, 0x11, 0xbc, 0xa4, 0xe9, 0x91, 0x21, 0x4c, 0xec, 0x2d, 0xca,
0x57, 0x7a, 0x3e, 0xb6, 0x37, 0x1a, 0x75, 0xed, 0x14, 0xf4, 0x16, 0x29, 0xfa, 0x8d,
0xe8, 0x8b, 0x75, 0x16, 0xd2, 0xc3,
]))
.unwrap(),
}
.sqrt()
.unwrap(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0x10, 0xf6, 0x96, 0x3b, 0xba, 0xd2, 0xeb, 0xc5, 0x88, 0x1b, 0x3e, 0x01, 0xb6, 0x11,
0xc0, 0x70, 0x8d, 0x7f, 0x1f, 0x72, 0x3d, 0x02, 0xc1, 0xd3, 0x6d, 0x2d, 0xdb, 0xe5,
0x52, 0x20, 0x3e, 0x82, 0x6e, 0xf7, 0xde, 0x92, 0xe8, 0xc6, 0x8b, 0x63, 0x40, 0xb2,
0x99, 0xb2, 0x70, 0x42, 0x58, 0xc5,
]))
.unwrap(),
c1: Fq::from_repr(FqRepr([
0x08, 0xd7, 0xcf, 0xff, 0x94, 0x21, 0x63, 0x30, 0xa4, 0xc9, 0x3b, 0x08, 0x10, 0x5d,
0x71, 0xa9, 0x6b, 0x85, 0x2a, 0xea, 0xf2, 0xaf, 0xcb, 0x1b, 0x28, 0xa2, 0x0f, 0xae,
0xd2, 0x11, 0xef, 0xe7, 0x76, 0x70, 0x59, 0x46, 0x65, 0x67, 0x64, 0x47, 0xc0, 0x99,
0x53, 0x4f, 0xc2, 0x09, 0xe7, 0x52,
]))
.unwrap(),
}
);
assert_eq!(
Fq2 {
c0: Fq::from_repr(FqRepr([
0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b,
0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0,
0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xf7,
0x84, 0x29, 0xd1, 0x51, 0x7a, 0x6b,
]))
.unwrap(),
c1: Fq::zero(),
}
.sqrt()
.unwrap(),
Fq2 {
c0: Fq::zero(),
c1: Fq::from_repr(FqRepr([
0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b,
0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0,
0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe,
0xff, 0xff, 0xfd, 0x43, 0x57, 0xa3,
]))
.unwrap(),
}
);
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
#[test]
fn test_fq2_mul_nonresidue() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let nqr = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
};
for _ in 0..1000 {
let mut a = Fq2::random(&mut rng);
let mut b = a;
a.mul_by_nonresidue();
b.mul_assign(&nqr);
assert_eq!(a, b);
}
}
#[test]
fn fq2_field_tests() {
crate::tests::field::random_field_tests::<Fq2>();
crate::tests::field::random_sqrt_tests::<Fq2>();
}

View File

@ -1,478 +0,0 @@
use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
use super::fq2::Fq2;
use ff::Field;
use rand_core::RngCore;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq6 {
pub c0: Fq2,
pub c1: Fq2,
pub c2: Fq2,
}
impl ::std::fmt::Display for Fq6 {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2)
}
}
impl Fq6 {
/// Multiply by quadratic nonresidue v.
pub fn mul_by_nonresidue(&mut self) {
use std::mem::swap;
swap(&mut self.c0, &mut self.c1);
swap(&mut self.c0, &mut self.c2);
self.c0.mul_by_nonresidue();
}
pub fn mul_by_1(&mut self, c1: &Fq2) {
let mut b_b = self.c1;
b_b.mul_assign(c1);
let mut t1 = *c1;
{
let mut tmp = self.c1;
tmp.add_assign(&self.c2);
t1.mul_assign(&tmp);
t1.sub_assign(&b_b);
t1.mul_by_nonresidue();
}
let mut t2 = *c1;
{
let mut tmp = self.c0;
tmp.add_assign(&self.c1);
t2.mul_assign(&tmp);
t2.sub_assign(&b_b);
}
self.c0 = t1;
self.c1 = t2;
self.c2 = b_b;
}
pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) {
let mut a_a = self.c0;
let mut b_b = self.c1;
a_a.mul_assign(c0);
b_b.mul_assign(c1);
let mut t1 = *c1;
{
let mut tmp = self.c1;
tmp.add_assign(&self.c2);
t1.mul_assign(&tmp);
t1.sub_assign(&b_b);
t1.mul_by_nonresidue();
t1.add_assign(&a_a);
}
let mut t3 = *c0;
{
let mut tmp = self.c0;
tmp.add_assign(&self.c2);
t3.mul_assign(&tmp);
t3.sub_assign(&a_a);
t3.add_assign(&b_b);
}
let mut t2 = *c0;
t2.add_assign(c1);
{
let mut tmp = self.c0;
tmp.add_assign(&self.c1);
t2.mul_assign(&tmp);
t2.sub_assign(&a_a);
t2.sub_assign(&b_b);
}
self.c0 = t1;
self.c1 = t2;
self.c2 = t3;
}
pub fn frobenius_map(&mut self, power: usize) {
self.c0.frobenius_map(power);
self.c1.frobenius_map(power);
self.c2.frobenius_map(power);
self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]);
self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]);
}
}
impl ConditionallySelectable for Fq6 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq6 {
c0: Fq2::conditional_select(&a.c0, &b.c0, choice),
c1: Fq2::conditional_select(&a.c1, &b.c1, choice),
c2: Fq2::conditional_select(&a.c2, &b.c2, choice),
}
}
}
impl Neg for Fq6 {
type Output = Self;
fn neg(self) -> Self {
Fq6 {
c0: self.c0.neg(),
c1: self.c1.neg(),
c2: self.c2.neg(),
}
}
}
impl<'r> Add<&'r Fq6> for Fq6 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq6 {
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
c2: self.c2 + other.c2,
}
}
}
impl Add for Fq6 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<'r> AddAssign<&'r Fq6> for Fq6 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
self.c2.add_assign(&other.c2);
}
}
impl AddAssign for Fq6 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq6> for Fq6 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq6 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
c2: self.c2 - other.c2,
}
}
}
impl Sub for Fq6 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq6> for Fq6 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
self.c2.sub_assign(&other.c2);
}
}
impl SubAssign for Fq6 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> Mul<&'r Fq6> for Fq6 {
type Output = Self;
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq6 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq6> for Fq6 {
fn mul_assign(&mut self, other: &Self) {
let mut a_a = self.c0;
let mut b_b = self.c1;
let mut c_c = self.c2;
a_a.mul_assign(&other.c0);
b_b.mul_assign(&other.c1);
c_c.mul_assign(&other.c2);
let mut t1 = other.c1;
t1.add_assign(&other.c2);
{
let mut tmp = self.c1;
tmp.add_assign(&self.c2);
t1.mul_assign(&tmp);
t1.sub_assign(&b_b);
t1.sub_assign(&c_c);
t1.mul_by_nonresidue();
t1.add_assign(&a_a);
}
let mut t3 = other.c0;
t3.add_assign(&other.c2);
{
let mut tmp = self.c0;
tmp.add_assign(&self.c2);
t3.mul_assign(&tmp);
t3.sub_assign(&a_a);
t3.add_assign(&b_b);
t3.sub_assign(&c_c);
}
let mut t2 = other.c0;
t2.add_assign(&other.c1);
{
let mut tmp = self.c0;
tmp.add_assign(&self.c1);
t2.mul_assign(&tmp);
t2.sub_assign(&a_a);
t2.sub_assign(&b_b);
c_c.mul_by_nonresidue();
t2.add_assign(&c_c);
}
self.c0 = t1;
self.c1 = t2;
self.c2 = t3;
}
}
impl MulAssign for Fq6 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq6 {
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
Fq6 {
c0: Fq2::random(rng),
c1: Fq2::random(rng),
c2: Fq2::random(rng),
}
}
fn zero() -> Self {
Fq6 {
c0: Fq2::zero(),
c1: Fq2::zero(),
c2: Fq2::zero(),
}
}
fn one() -> Self {
Fq6 {
c0: Fq2::one(),
c1: Fq2::zero(),
c2: Fq2::zero(),
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
}
fn double(&self) -> Self {
Fq6 {
c0: self.c0.double(),
c1: self.c1.double(),
c2: self.c2.double(),
}
}
fn square(&self) -> Self {
let s0 = self.c0.square();
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let s1 = ab.double();
let mut s2 = self.c0;
s2.sub_assign(&self.c1);
s2.add_assign(&self.c2);
s2 = s2.square();
let mut bc = self.c1;
bc.mul_assign(&self.c2);
let s3 = bc.double();
let s4 = self.c2.square();
let mut c0 = s3;
c0.mul_by_nonresidue();
c0.add_assign(&s0);
let mut c1 = s4;
c1.mul_by_nonresidue();
c1.add_assign(&s1);
let mut c2 = s1;
c2.add_assign(&s2);
c2.add_assign(&s3);
c2.sub_assign(&s0);
c2.sub_assign(&s4);
Fq6 { c0, c1, c2 }
}
fn invert(&self) -> CtOption<Self> {
let mut c0 = self.c2;
c0.mul_by_nonresidue();
c0.mul_assign(&self.c1);
c0 = c0.neg();
{
let c0s = self.c0.square();
c0.add_assign(&c0s);
}
let mut c1 = self.c2.square();
c1.mul_by_nonresidue();
{
let mut c01 = self.c0;
c01.mul_assign(&self.c1);
c1.sub_assign(&c01);
}
let mut c2 = self.c1.square();
{
let mut c02 = self.c0;
c02.mul_assign(&self.c2);
c2.sub_assign(&c02);
}
let mut tmp1 = self.c2;
tmp1.mul_assign(&c1);
let mut tmp2 = self.c1;
tmp2.mul_assign(&c2);
tmp1.add_assign(&tmp2);
tmp1.mul_by_nonresidue();
tmp2 = self.c0;
tmp2.mul_assign(&c0);
tmp1.add_assign(&tmp2);
tmp1.invert().map(|t| {
let mut tmp = Fq6 {
c0: t,
c1: t,
c2: t,
};
tmp.c0.mul_assign(&c0);
tmp.c1.mul_assign(&c1);
tmp.c2.mul_assign(&c2);
tmp
})
}
fn sqrt(&self) -> CtOption<Self> {
unimplemented!()
}
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
#[test]
fn test_fq6_mul_nonresidue() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let nqr = Fq6 {
c0: Fq2::zero(),
c1: Fq2::one(),
c2: Fq2::zero(),
};
for _ in 0..1000 {
let mut a = Fq6::random(&mut rng);
let mut b = a;
a.mul_by_nonresidue();
b.mul_assign(&nqr);
assert_eq!(a, b);
}
}
#[test]
fn test_fq6_mul_by_1() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let c1 = Fq2::random(&mut rng);
let mut a = Fq6::random(&mut rng);
let mut b = a;
a.mul_by_1(&c1);
b.mul_assign(&Fq6 {
c0: Fq2::zero(),
c1,
c2: Fq2::zero(),
});
assert_eq!(a, b);
}
}
#[test]
fn test_fq6_mul_by_01() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let c0 = Fq2::random(&mut rng);
let c1 = Fq2::random(&mut rng);
let mut a = Fq6::random(&mut rng);
let mut b = a;
a.mul_by_01(&c0, &c1);
b.mul_assign(&Fq6 {
c0,
c1,
c2: Fq2::zero(),
});
assert_eq!(a, b);
}
}
#[test]
fn fq6_field_tests() {
crate::tests::field::random_field_tests::<Fq6>();
}

View File

@ -1,601 +0,0 @@
use ff::{Field, PrimeField};
use std::ops::{AddAssign, MulAssign, SubAssign};
#[derive(PrimeField)]
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
#[PrimeFieldGenerator = "7"]
#[PrimeFieldReprEndianness = "little"]
pub struct Fr([u64; 4]);
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
#[cfg(test)]
use std::ops::Neg;
#[test]
fn test_fr_is_valid() {
let mut a = MODULUS_LIMBS;
assert!(!a.is_valid());
a.sub_noborrow(&Fr([1, 0, 0, 0]));
assert!(a.is_valid());
assert!(Fr::from(0).is_valid());
assert!(Fr([
0xffffffff00000000,
0x53bda402fffe5bfe,
0x3339d80809a1d805,
0x73eda753299d7d48
])
.is_valid());
assert!(!Fr([
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff
])
.is_valid());
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
let a = Fr::random(&mut rng);
assert!(a.is_valid());
}
}
#[test]
fn test_fr_add_assign() {
{
// Random number
let mut tmp = Fr([
0x437ce7616d580765,
0xd42d1ccb29d1235b,
0xed8f753821bd1423,
0x4eede1c9c89528ca,
]);
assert!(tmp.is_valid());
// Test that adding zero has no effect.
tmp.add_assign(&Fr([0, 0, 0, 0]));
assert_eq!(
tmp,
Fr([
0x437ce7616d580765,
0xd42d1ccb29d1235b,
0xed8f753821bd1423,
0x4eede1c9c89528ca
])
);
// Add one and test for the result.
tmp.add_assign(&Fr([1, 0, 0, 0]));
assert_eq!(
tmp,
Fr([
0x437ce7616d580766,
0xd42d1ccb29d1235b,
0xed8f753821bd1423,
0x4eede1c9c89528ca
])
);
// Add another random number that exercises the reduction.
tmp.add_assign(&Fr([
0x946f435944f7dc79,
0xb55e7ee6533a9b9b,
0x1e43b84c2f6194ca,
0x58717ab525463496,
]));
assert_eq!(
tmp,
Fr([
0xd7ec2abbb24fe3de,
0x35cdf7ae7d0d62f7,
0xd899557c477cd0e9,
0x3371b52bc43de018
])
);
// Add one to (r - 1) and test for the result.
tmp = Fr([
0xffffffff00000000,
0x53bda402fffe5bfe,
0x3339d80809a1d805,
0x73eda753299d7d48,
]);
tmp.add_assign(&Fr([1, 0, 0, 0]));
assert!(tmp.is_zero());
// Add a random number to another one such that the result is r - 1
tmp = Fr([
0xade5adacdccb6190,
0xaa21ee0f27db3ccd,
0x2550f4704ae39086,
0x591d1902e7c5ba27,
]);
tmp.add_assign(&Fr([
0x521a525223349e70,
0xa99bb5f3d8231f31,
0xde8e397bebe477e,
0x1ad08e5041d7c321,
]));
assert_eq!(
tmp,
Fr([
0xffffffff00000000,
0x53bda402fffe5bfe,
0x3339d80809a1d805,
0x73eda753299d7d48
])
);
// Add one to the result and test for it.
tmp.add_assign(&Fr([1, 0, 0, 0]));
assert!(tmp.is_zero());
}
// Test associativity
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
// Generate a, b, c and ensure (a + b) + c == a + (b + c).
let a = Fr::random(&mut rng);
let b = Fr::random(&mut rng);
let c = Fr::random(&mut rng);
let mut tmp1 = a;
tmp1.add_assign(&b);
tmp1.add_assign(&c);
let mut tmp2 = b;
tmp2.add_assign(&c);
tmp2.add_assign(&a);
assert!(tmp1.is_valid());
assert!(tmp2.is_valid());
assert_eq!(tmp1, tmp2);
}
}
#[test]
fn test_fr_sub_assign() {
{
// Test arbitrary subtraction that tests reduction.
let mut tmp = Fr([
0x6a68c64b6f735a2b,
0xd5f4d143fe0a1972,
0x37c17f3829267c62,
0xa2f37391f30915c,
]);
tmp.sub_assign(&Fr([
0xade5adacdccb6190,
0xaa21ee0f27db3ccd,
0x2550f4704ae39086,
0x591d1902e7c5ba27,
]));
assert_eq!(
tmp,
Fr([
0xbc83189d92a7f89c,
0x7f908737d62d38a3,
0x45aa62cfe7e4c3e1,
0x24ffc5896108547d
])
);
// Test the opposite subtraction which doesn't test reduction.
tmp = Fr([
0xade5adacdccb6190,
0xaa21ee0f27db3ccd,
0x2550f4704ae39086,
0x591d1902e7c5ba27,
]);
tmp.sub_assign(&Fr([
0x6a68c64b6f735a2b,
0xd5f4d143fe0a1972,
0x37c17f3829267c62,
0xa2f37391f30915c,
]));
assert_eq!(
tmp,
Fr([
0x437ce7616d580765,
0xd42d1ccb29d1235b,
0xed8f753821bd1423,
0x4eede1c9c89528ca
])
);
// Test for sensible results with zero
tmp = Fr::from(0);
tmp.sub_assign(&Fr::from(0));
assert!(tmp.is_zero());
tmp = Fr([
0x437ce7616d580765,
0xd42d1ccb29d1235b,
0xed8f753821bd1423,
0x4eede1c9c89528ca,
]);
tmp.sub_assign(&Fr::from(0));
assert_eq!(
tmp,
Fr([
0x437ce7616d580765,
0xd42d1ccb29d1235b,
0xed8f753821bd1423,
0x4eede1c9c89528ca
])
);
}
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
// Ensure that (a - b) + (b - a) = 0.
let a = Fr::random(&mut rng);
let b = Fr::random(&mut rng);
let mut tmp1 = a;
tmp1.sub_assign(&b);
let mut tmp2 = b;
tmp2.sub_assign(&a);
tmp1.add_assign(&tmp2);
assert!(tmp1.is_zero());
}
}
#[test]
fn test_fr_mul_assign() {
let mut tmp = Fr([
0x6b7e9b8faeefc81a,
0xe30a8463f348ba42,
0xeff3cb67a8279c9c,
0x3d303651bd7c774d,
]);
tmp.mul_assign(&Fr([
0x13ae28e3bc35ebeb,
0xa10f4488075cae2c,
0x8160e95a853c3b5d,
0x5ae3f03b561a841d,
]));
assert!(
tmp == Fr([
0x23717213ce710f71,
0xdbee1fe53a16e1af,
0xf565d3e1c2a48000,
0x4426507ee75df9d7
])
);
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000000 {
// Ensure that (a * b) * c = a * (b * c)
let a = Fr::random(&mut rng);
let b = Fr::random(&mut rng);
let c = Fr::random(&mut rng);
let mut tmp1 = a;
tmp1.mul_assign(&b);
tmp1.mul_assign(&c);
let mut tmp2 = b;
tmp2.mul_assign(&c);
tmp2.mul_assign(&a);
assert_eq!(tmp1, tmp2);
}
for _ in 0..1000000 {
// Ensure that r * (a + b + c) = r*a + r*b + r*c
let r = Fr::random(&mut rng);
let mut a = Fr::random(&mut rng);
let mut b = Fr::random(&mut rng);
let mut c = Fr::random(&mut rng);
let mut tmp1 = a;
tmp1.add_assign(&b);
tmp1.add_assign(&c);
tmp1.mul_assign(&r);
a.mul_assign(&r);
b.mul_assign(&r);
c.mul_assign(&r);
a.add_assign(&b);
a.add_assign(&c);
assert_eq!(tmp1, a);
}
}
#[test]
fn test_fr_squaring() {
let a = Fr([
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0x73eda753299d7d47,
]);
assert!(a.is_valid());
assert_eq!(
a.square(),
Fr::from_repr(FrRepr([
0xb8, 0x77, 0xe0, 0xbd, 0xe7, 0x98, 0xd6, 0xc0, 0xc2, 0x6e, 0xe7, 0x79, 0x05, 0x31,
0x9a, 0xb7, 0x5f, 0x4e, 0xaf, 0xa9, 0xd0, 0xa8, 0x1d, 0xac, 0x97, 0x3e, 0xf2, 0x9b,
0xc4, 0x29, 0xf6, 0x13,
]))
.unwrap()
);
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000000 {
// Ensure that (a * a) = a^2
let a = Fr::random(&mut rng);
assert_eq!(a.square(), a * a);
}
}
#[test]
fn test_fr_invert() {
assert!(bool::from(Fr::zero().invert().is_none()));
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let one = Fr::one();
for _ in 0..1000 {
// Ensure that a * a^-1 = 1
let mut a = Fr::random(&mut rng);
let ainv = a.invert().unwrap();
a.mul_assign(&ainv);
assert_eq!(a, one);
}
}
#[test]
fn test_fr_double() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
// Ensure doubling a is equivalent to adding a to itself.
let a = Fr::random(&mut rng);
assert_eq!(a.double(), a + a);
}
}
#[test]
fn test_fr_neg() {
{
let a = Fr::zero().neg();
assert!(a.is_zero());
}
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
// Ensure (a - (-a)) = 0.
let mut a = Fr::random(&mut rng);
let b = a.neg();
a.add_assign(&b);
assert!(a.is_zero());
}
}
#[test]
fn test_fr_pow() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for i in 0u64..1000 {
// Exponentiate by various small numbers and ensure it consists with repeated
// multiplication.
let a = Fr::random(&mut rng);
let target = a.pow_vartime(&[i]);
let mut c = Fr::one();
for _ in 0..i {
c.mul_assign(&a);
}
assert_eq!(c, target);
}
use byteorder::ByteOrder;
let mut char_limbs = [0; 4];
byteorder::LittleEndian::read_u64_into(Fr::char().as_ref(), &mut char_limbs);
for _ in 0..1000 {
// Exponentiating by the modulus should have no effect in a prime field.
let a = Fr::random(&mut rng);
assert_eq!(a, a.pow_vartime(char_limbs));
}
}
#[test]
fn test_fr_sqrt() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero());
for _ in 0..1000 {
// Ensure sqrt(a^2) = a or -a
let a = Fr::random(&mut rng);
let nega = a.neg();
let b = a.square();
let b = b.sqrt().unwrap();
assert!(a == b || nega == b);
}
for _ in 0..1000 {
// Ensure sqrt(a)^2 = a for random a
let a = Fr::random(&mut rng);
let tmp = a.sqrt();
if tmp.is_some().into() {
assert_eq!(a, tmp.unwrap().square());
}
}
}
#[test]
fn test_fr_from_to_repr() {
// r + 1 should not be in the field
assert!(Fr::from_repr(FrRepr([
0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4, 0xbd,
0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7,
0xed, 0x73,
]))
.is_none());
// r should not be in the field
assert!(Fr::from_repr(Fr::char()).is_none());
// Multiply some arbitrary representations to see if the result is as expected.
let a = FrRepr([
0x6a, 0x0c, 0x3c, 0xad, 0xa3, 0xe3, 0xeb, 0x25, 0x7c, 0x81, 0x2e, 0x09, 0x9d, 0xe3, 0x90,
0x69, 0x8e, 0x65, 0xf5, 0x42, 0x0d, 0x90, 0x1f, 0x94, 0xe0, 0x71, 0x8a, 0xb3, 0x03, 0xa1,
0xf8, 0x44,
]);
let mut a_fr = Fr::from_repr(a).unwrap();
let b = FrRepr([
0x75, 0x24, 0x5e, 0x88, 0x54, 0x94, 0x4e, 0x26, 0x70, 0x83, 0x30, 0xb0, 0x6b, 0x74, 0xf7,
0x46, 0xf9, 0x11, 0x74, 0x34, 0xf5, 0x3e, 0x68, 0x04, 0x92, 0x44, 0x8d, 0x20, 0x7f, 0x8d,
0x83, 0x58,
]);
let b_fr = Fr::from_repr(b).unwrap();
let c = FrRepr([
0x0d, 0x74, 0xfc, 0x3c, 0xb9, 0x9a, 0xa0, 0x48, 0x71, 0xa6, 0xc7, 0xbf, 0x0f, 0x60, 0xa6,
0x03, 0x67, 0xd7, 0x01, 0x75, 0x01, 0x67, 0x85, 0x83, 0x12, 0x55, 0x74, 0x77, 0xda, 0xd6,
0x61, 0x71,
]);
a_fr.mul_assign(&b_fr);
assert_eq!(a_fr.to_repr(), c);
// Zero should be in the field.
assert!(Fr::from_repr(FrRepr([0; 32])).unwrap().is_zero());
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for _ in 0..1000 {
// Try to turn Fr elements into representations and back again, and compare.
let a = Fr::random(&mut rng);
let a_repr = a.to_repr();
let b_repr = FrRepr::from(a);
assert_eq!(a_repr, b_repr);
let a_again = Fr::from_repr(a_repr).unwrap();
assert_eq!(a, a_again);
}
}
#[test]
fn test_fr_display() {
assert_eq!(
format!(
"{}",
Fr::from_repr(FrRepr([
0xc7, 0xec, 0xb5, 0xa3, 0x46, 0xe7, 0xca, 0xc3, 0xee, 0x5a, 0x5b, 0x3f, 0xeb, 0xc8,
0x5e, 0x18, 0x99, 0xdd, 0xb9, 0xe4, 0xff, 0x99, 0x44, 0x68, 0xaa, 0x8f, 0xb6, 0xaf,
0xa7, 0xbb, 0xc9, 0x07,
]))
.unwrap()
),
"Fr(0x07c9bba7afb68faa684499ffe4b9dd99185ec8eb3f5b5aeec3cae746a3b5ecc7)".to_string()
);
assert_eq!(
format!(
"{}",
Fr::from_repr(FrRepr([
0x06, 0x81, 0x19, 0xff, 0x98, 0x12, 0xc7, 0x44, 0x6a, 0x9b, 0xf7, 0x7d, 0x81, 0x10,
0xad, 0xb0, 0x2b, 0x13, 0x74, 0x2b, 0x0a, 0xa8, 0x34, 0xd0, 0x19, 0x07, 0xf5, 0x36,
0x13, 0x9a, 0xcf, 0x41,
]))
.unwrap()
),
"Fr(0x41cf9a1336f50719d034a80a2b74132bb0ad10817df79b6a44c71298ff198106)".to_string()
);
}
#[test]
fn test_fr_is_odd() {
assert!(!Fr::from(0).is_odd());
assert!(Fr::from(0).is_even());
assert!(Fr::from(1).is_odd());
assert!(!Fr::from(1).is_even());
assert!(!Fr::from(324834872).is_odd());
assert!(Fr::from(324834872).is_even());
assert!(Fr::from(324834873).is_odd());
assert!(!Fr::from(324834873).is_even());
}
#[test]
fn test_fr_num_bits() {
assert_eq!(Fr::NUM_BITS, 255);
assert_eq!(Fr::CAPACITY, 254);
}
#[test]
fn test_fr_root_of_unity() {
assert_eq!(Fr::S, 32);
assert_eq!(Fr::multiplicative_generator(), Fr::from(7));
assert_eq!(
Fr::multiplicative_generator().pow_vartime([
0xfffe5bfeffffffffu64,
0x9a1d80553bda402,
0x299d7d483339d808,
0x73eda753
]),
Fr::root_of_unity()
);
assert_eq!(Fr::root_of_unity().pow_vartime([1u64 << Fr::S]), Fr::one());
assert!(bool::from(Fr::multiplicative_generator().sqrt().is_none()));
}
#[test]
fn fr_field_tests() {
crate::tests::field::random_field_tests::<Fr>();
crate::tests::field::random_sqrt_tests::<Fr>();
crate::tests::field::from_str_tests::<Fr>();
}
#[test]
fn fr_repr_tests() {
crate::tests::repr::random_repr_tests::<Fr>();
}

View File

@ -1,524 +0,0 @@
//! An implementation of the BLS12-381 pairing-friendly elliptic curve
//! construction.
mod ec;
mod fq;
mod fq12;
mod fq2;
mod fq6;
mod fr;
#[cfg(test)]
mod tests;
pub use self::ec::{
G1Affine, G1Compressed, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, G2Uncompressed, G1,
G2,
};
pub use self::fq::{Fq, FqRepr};
pub use self::fq12::Fq12;
pub use self::fq2::Fq2;
pub use self::fq6::Fq6;
pub use self::fr::{Fr, FrRepr};
use super::{Engine, MillerLoopResult, MultiMillerLoop};
use ff::{BitIterator, Field, PrimeField};
use group::{prime::PrimeCurveAffine, Group};
use rand_core::RngCore;
use std::fmt;
use std::iter::Sum;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable};
// The BLS parameter x for BLS12-381 is -0xd201000000010000
const BLS_X: u64 = 0xd201000000010000;
const BLS_X_IS_NEGATIVE: bool = true;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Gt(Fq12);
impl fmt::Display for Gt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl ConditionallySelectable for Gt {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Gt(Fq12::conditional_select(&a.0, &b.0, choice))
}
}
impl Neg for Gt {
type Output = Gt;
fn neg(self) -> Self::Output {
let mut ret = self.0;
ret.conjugate();
Gt(ret)
}
}
impl Sum for Gt {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::identity(), Add::add)
}
}
impl<'r> Sum<&'r Gt> for Gt {
fn sum<I: Iterator<Item = &'r Self>>(iter: I) -> Self {
iter.fold(Self::identity(), Add::add)
}
}
impl Add for Gt {
type Output = Gt;
fn add(self, rhs: Self) -> Self::Output {
Gt(self.0 * rhs.0)
}
}
impl Add<&Gt> for Gt {
type Output = Gt;
fn add(self, rhs: &Gt) -> Self::Output {
Gt(self.0 * rhs.0)
}
}
impl AddAssign for Gt {
fn add_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}
impl AddAssign<&Gt> for Gt {
fn add_assign(&mut self, rhs: &Gt) {
self.0 *= rhs.0;
}
}
impl Sub for Gt {
type Output = Gt;
fn sub(self, rhs: Self) -> Self::Output {
self + (-rhs)
}
}
impl Sub<&Gt> for Gt {
type Output = Gt;
fn sub(self, rhs: &Gt) -> Self::Output {
self + (-*rhs)
}
}
impl SubAssign for Gt {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl SubAssign<&Gt> for Gt {
fn sub_assign(&mut self, rhs: &Gt) {
*self = *self - rhs;
}
}
impl Mul<&Fr> for Gt {
type Output = Gt;
fn mul(self, other: &Fr) -> Self::Output {
let mut acc = Self::identity();
// This is a simple double-and-add implementation of group element
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// We skip the leading bit because it's always unset for Fr
// elements.
for bit in other
.to_repr()
.as_ref()
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = Gt::conditional_select(&acc, &(acc + self), bit);
}
acc
}
}
impl Mul<Fr> for Gt {
type Output = Gt;
fn mul(self, other: Fr) -> Self::Output {
self * &other
}
}
impl<'r> MulAssign<&'r Fr> for Gt {
fn mul_assign(&mut self, other: &'r Fr) {
*self = *self * other
}
}
impl MulAssign<Fr> for Gt {
fn mul_assign(&mut self, other: Fr) {
self.mul_assign(&other);
}
}
impl Group for Gt {
type Scalar = Fr;
fn random<R: RngCore + ?Sized>(_rng: &mut R) -> Self {
unimplemented!()
}
fn identity() -> Self {
Gt(Fq12::one())
}
fn generator() -> Self {
unimplemented!()
}
fn is_identity(&self) -> Choice {
Choice::from(if self.0 == Fq12::one() { 1 } else { 0 })
}
#[must_use]
fn double(&self) -> Self {
Gt(self.0.square())
}
}
#[derive(Clone, Debug)]
pub struct Bls12;
impl Engine for Bls12 {
type Fr = Fr;
type G1 = G1;
type G1Affine = G1Affine;
type G2 = G2;
type G2Affine = G2Affine;
type Gt = Gt;
fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
Self::multi_miller_loop(&[(p, &(*q).into())]).final_exponentiation()
}
}
impl MultiMillerLoop for Bls12 {
type G2Prepared = G2Prepared;
type Result = Fq12;
fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
let mut pairs = vec![];
for &(p, q) in terms {
if !bool::from(p.is_identity()) && !q.is_identity() {
pairs.push((p, q.coeffs.iter()));
}
}
// Twisting isomorphism from E to E'
fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
let mut c0 = coeffs.0;
let mut c1 = coeffs.1;
c0.c0.mul_assign(&p.y);
c0.c1.mul_assign(&p.y);
c1.c0.mul_assign(&p.x);
c1.c1.mul_assign(&p.x);
// Sparse multiplication in Fq12
f.mul_by_014(&coeffs.2, &c1, &c0);
}
let mut f = Fq12::one();
let mut found_one = false;
for i in BitIterator::<u64, _>::new(&[BLS_X >> 1]) {
if !found_one {
found_one = i;
continue;
}
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), p);
}
if i {
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), p);
}
}
f = f.square();
}
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), p);
}
if BLS_X_IS_NEGATIVE {
f.conjugate();
}
f
}
}
impl MillerLoopResult for Fq12 {
type Gt = Gt;
fn final_exponentiation(&self) -> Gt {
let mut f1 = *self;
f1.conjugate();
self.invert()
.map(|mut f2| {
let mut r = f1;
r.mul_assign(&f2);
f2 = r;
r.frobenius_map(2);
r.mul_assign(&f2);
fn exp_by_x(f: &mut Fq12, x: u64) {
*f = f.pow_vartime(&[x]);
if BLS_X_IS_NEGATIVE {
f.conjugate();
}
}
let mut x = BLS_X;
let y0 = r.square();
let mut y1 = y0;
exp_by_x(&mut y1, x);
x >>= 1;
let mut y2 = y1;
exp_by_x(&mut y2, x);
x <<= 1;
let mut y3 = r;
y3.conjugate();
y1.mul_assign(&y3);
y1.conjugate();
y1.mul_assign(&y2);
y2 = y1;
exp_by_x(&mut y2, x);
y3 = y2;
exp_by_x(&mut y3, x);
y1.conjugate();
y3.mul_assign(&y1);
y1.conjugate();
y1.frobenius_map(3);
y2.frobenius_map(2);
y1.mul_assign(&y2);
y2 = y3;
exp_by_x(&mut y2, x);
y2.mul_assign(&y0);
y2.mul_assign(&r);
y1.mul_assign(&y2);
y2 = y3;
y2.frobenius_map(1);
y1.mul_assign(&y2);
Gt(y1)
})
// self must be nonzero.
.unwrap()
}
}
impl G2Prepared {
pub fn is_identity(&self) -> bool {
self.infinity
}
pub fn from_affine(q: G2Affine) -> Self {
if q.is_identity().into() {
return G2Prepared {
coeffs: vec![],
infinity: true,
};
}
fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) {
// Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
let mut tmp0 = r.x.square();
let mut tmp1 = r.y.square();
let mut tmp2 = tmp1.square();
let mut tmp3 = tmp1;
tmp3.add_assign(&r.x);
tmp3 = tmp3.square();
tmp3.sub_assign(&tmp0);
tmp3.sub_assign(&tmp2);
tmp3 = tmp3.double();
let mut tmp4 = tmp0.double();
tmp4.add_assign(&tmp0);
let mut tmp6 = r.x;
tmp6.add_assign(&tmp4);
let tmp5 = tmp4.square();
let zsquared = r.z.square();
r.x = tmp5;
r.x.sub_assign(&tmp3);
r.x.sub_assign(&tmp3);
r.z.add_assign(&r.y);
r.z = r.z.square();
r.z.sub_assign(&tmp1);
r.z.sub_assign(&zsquared);
r.y = tmp3;
r.y.sub_assign(&r.x);
r.y.mul_assign(&tmp4);
tmp2 = tmp2.double().double().double();
r.y.sub_assign(&tmp2);
tmp3 = tmp4;
tmp3.mul_assign(&zsquared);
tmp3 = tmp3.double().neg();
tmp6 = tmp6.square();
tmp6.sub_assign(&tmp0);
tmp6.sub_assign(&tmp5);
tmp1 = tmp1.double().double();
tmp6.sub_assign(&tmp1);
tmp0 = r.z;
tmp0.mul_assign(&zsquared);
tmp0 = tmp0.double();
(tmp0, tmp3, tmp6)
}
fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) {
// Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
let zsquared = r.z.square();
let ysquared = q.y.square();
let mut t0 = zsquared;
t0.mul_assign(&q.x);
let mut t1 = q.y;
t1.add_assign(&r.z);
t1 = t1.square();
t1.sub_assign(&ysquared);
t1.sub_assign(&zsquared);
t1.mul_assign(&zsquared);
let mut t2 = t0;
t2.sub_assign(&r.x);
let t3 = t2.square();
let t4 = t3.double().double();
let mut t5 = t4;
t5.mul_assign(&t2);
let mut t6 = t1;
t6.sub_assign(&r.y);
t6.sub_assign(&r.y);
let mut t9 = t6;
t9.mul_assign(&q.x);
let mut t7 = t4;
t7.mul_assign(&r.x);
r.x = t6.square();
r.x.sub_assign(&t5);
r.x.sub_assign(&t7);
r.x.sub_assign(&t7);
r.z.add_assign(&t2);
r.z = r.z.square();
r.z.sub_assign(&zsquared);
r.z.sub_assign(&t3);
let mut t10 = q.y;
t10.add_assign(&r.z);
let mut t8 = t7;
t8.sub_assign(&r.x);
t8.mul_assign(&t6);
t0 = r.y;
t0.mul_assign(&t5);
t0 = t0.double();
r.y = t8;
r.y.sub_assign(&t0);
t10 = t10.square();
t10.sub_assign(&ysquared);
let ztsquared = r.z.square();
t10.sub_assign(&ztsquared);
t9 = t9.double();
t9.sub_assign(&t10);
t10 = r.z.double();
t6 = t6.neg();
t1 = t6.double();
(t10, t1, t9)
}
let mut coeffs = vec![];
let mut r: G2 = q.into();
let mut found_one = false;
for i in BitIterator::<u64, _>::new([BLS_X >> 1]) {
if !found_one {
found_one = i;
continue;
}
coeffs.push(doubling_step(&mut r));
if i {
coeffs.push(addition_step(&mut r, &q));
}
}
coeffs.push(doubling_step(&mut r));
G2Prepared {
coeffs,
infinity: false,
}
}
}
#[test]
fn bls12_engine_tests() {
crate::tests::engine::engine_tests::<Bls12>();
}

View File

@ -1,645 +0,0 @@
use ff::PrimeField;
use group::{GroupEncoding, UncompressedEncoding};
use super::*;
use crate::*;
#[test]
fn test_pairing_result_against_relic() {
/*
Sent to me from Diego Aranha (author of RELIC library):
1250EBD871FC0A92 A7B2D83168D0D727 272D441BEFA15C50 3DD8E90CE98DB3E7 B6D194F60839C508 A84305AACA1789B6
089A1C5B46E5110B 86750EC6A5323488 68A84045483C92B7 AF5AF689452EAFAB F1A8943E50439F1D 59882A98EAA0170F
1368BB445C7C2D20 9703F239689CE34C 0378A68E72A6B3B2 16DA0E22A5031B54 DDFF57309396B38C 881C4C849EC23E87
193502B86EDB8857 C273FA075A505129 37E0794E1E65A761 7C90D8BD66065B1F FFE51D7A579973B1 315021EC3C19934F
01B2F522473D1713 91125BA84DC4007C FBF2F8DA752F7C74 185203FCCA589AC7 19C34DFFBBAAD843 1DAD1C1FB597AAA5
018107154F25A764 BD3C79937A45B845 46DA634B8F6BE14A 8061E55CCEBA478B 23F7DACAA35C8CA7 8BEAE9624045B4B6
19F26337D205FB46 9CD6BD15C3D5A04D C88784FBB3D0B2DB DEA54D43B2B73F2C BB12D58386A8703E 0F948226E47EE89D
06FBA23EB7C5AF0D 9F80940CA771B6FF D5857BAAF222EB95 A7D2809D61BFE02E 1BFD1B68FF02F0B8 102AE1C2D5D5AB1A
11B8B424CD48BF38 FCEF68083B0B0EC5 C81A93B330EE1A67 7D0D15FF7B984E89 78EF48881E32FAC9 1B93B47333E2BA57
03350F55A7AEFCD3 C31B4FCB6CE5771C C6A0E9786AB59733 20C806AD36082910 7BA810C5A09FFDD9 BE2291A0C25A99A2
04C581234D086A99 02249B64728FFD21 A189E87935A95405 1C7CDBA7B3872629 A4FAFC05066245CB 9108F0242D0FE3EF
0F41E58663BF08CF 068672CBD01A7EC7 3BACA4D72CA93544 DEFF686BFD6DF543 D48EAA24AFE47E1E FDE449383B676631
*/
assert_eq!(Bls12::pairing(&G1Affine::generator(), &G2Affine::generator()), Gt(Fq12 {
c0: Fq6 {
c0: Fq2 {
c0: Fq::from_str("2819105605953691245277803056322684086884703000473961065716485506033588504203831029066448642358042597501014294104502").unwrap(),
c1: Fq::from_str("1323968232986996742571315206151405965104242542339680722164220900812303524334628370163366153839984196298685227734799").unwrap()
},
c1: Fq2 {
c0: Fq::from_str("2987335049721312504428602988447616328830341722376962214011674875969052835043875658579425548512925634040144704192135").unwrap(),
c1: Fq::from_str("3879723582452552452538684314479081967502111497413076598816163759028842927668327542875108457755966417881797966271311").unwrap()
},
c2: Fq2 {
c0: Fq::from_str("261508182517997003171385743374653339186059518494239543139839025878870012614975302676296704930880982238308326681253").unwrap(),
c1: Fq::from_str("231488992246460459663813598342448669854473942105054381511346786719005883340876032043606739070883099647773793170614").unwrap()
}
},
c1: Fq6 {
c0: Fq2 {
c0: Fq::from_str("3993582095516422658773669068931361134188738159766715576187490305611759126554796569868053818105850661142222948198557").unwrap(),
c1: Fq::from_str("1074773511698422344502264006159859710502164045911412750831641680783012525555872467108249271286757399121183508900634").unwrap()
},
c1: Fq2 {
c0: Fq::from_str("2727588299083545686739024317998512740561167011046940249988557419323068809019137624943703910267790601287073339193943").unwrap(),
c1: Fq::from_str("493643299814437640914745677854369670041080344349607504656543355799077485536288866009245028091988146107059514546594").unwrap()
},
c2: Fq2 {
c0: Fq::from_str("734401332196641441839439105942623141234148957972407782257355060229193854324927417865401895596108124443575283868655").unwrap(),
c1: Fq::from_str("2348330098288556420918672502923664952620152483128593484301759394583320358354186482723629999370241674973832318248497").unwrap()
}
}
}));
}
fn uncompressed_test_vectors<G: PrimeCurve>(expected: &[u8])
where
G::Affine: UncompressedEncoding,
{
let mut e = G::identity();
let encoded_len = <G::Affine as UncompressedEncoding>::Uncompressed::default()
.as_ref()
.len();
let mut v = vec![];
{
let mut expected = expected;
for _ in 0..1000 {
let e_affine = e.to_affine();
let encoded = e_affine.to_uncompressed();
v.extend_from_slice(encoded.as_ref());
let mut decoded = <G::Affine as UncompressedEncoding>::Uncompressed::default();
decoded.as_mut().copy_from_slice(&expected[0..encoded_len]);
expected = &expected[encoded_len..];
let decoded = G::Affine::from_uncompressed(&decoded).unwrap();
assert_eq!(e_affine, decoded);
e.add_assign(&G::generator());
}
}
assert_eq!(&v[..], expected);
}
fn compressed_test_vectors<G: PrimeCurve>(expected: &[u8]) {
let mut e = G::identity();
let encoded_len = <G::Affine as GroupEncoding>::Repr::default().as_ref().len();
let mut v = vec![];
{
let mut expected = expected;
for _ in 0..1000 {
let e_affine = e.to_affine();
let encoded = e_affine.to_bytes();
v.extend_from_slice(encoded.as_ref());
let mut decoded = <G::Affine as GroupEncoding>::Repr::default();
decoded.as_mut().copy_from_slice(&expected[0..encoded_len]);
expected = &expected[encoded_len..];
let decoded = G::Affine::from_bytes(&decoded).unwrap();
assert_eq!(e_affine, decoded);
e.add_assign(&G::generator());
}
}
assert_eq!(&v[..], expected);
}
#[test]
fn test_g1_uncompressed_valid_vectors() {
uncompressed_test_vectors::<G1>(include_bytes!("g1_uncompressed_valid_test_vectors.dat"));
}
#[test]
fn test_g1_compressed_valid_vectors() {
compressed_test_vectors::<G1>(include_bytes!("g1_compressed_valid_test_vectors.dat"));
}
#[test]
fn test_g2_uncompressed_valid_vectors() {
uncompressed_test_vectors::<G2>(include_bytes!("g2_uncompressed_valid_test_vectors.dat"));
}
#[test]
fn test_g2_compressed_valid_vectors() {
compressed_test_vectors::<G2>(include_bytes!("g2_compressed_valid_test_vectors.dat"));
}
#[test]
fn test_g1_uncompressed_invalid_vectors() {
{
let z = G1Affine::identity().to_uncompressed();
{
let mut z = z;
z.as_mut()[0] |= 0b1000_0000;
if G1Affine::from_uncompressed(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected an uncompressed point");
}
}
{
let mut z = z;
z.as_mut()[0] |= 0b0010_0000;
if G1Affine::from_uncompressed(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
}
}
for i in 0..G1Uncompressed::size() {
let mut z = z;
z.as_mut()[i] |= 0b0000_0001;
if G1Affine::from_uncompressed(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
}
}
}
let o = G1Affine::generator().to_uncompressed();
{
let mut o = o;
o.as_mut()[0] |= 0b1000_0000;
if G1Affine::from_uncompressed(&o).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected an uncompressed point");
}
}
let m = Fq::char();
{
let mut o = o;
o.as_mut()[..48].copy_from_slice(m.as_ref());
if G1Affine::from_uncompressed(&o).is_none().into() {
// x coordinate
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
o.as_mut()[48..].copy_from_slice(m.as_ref());
if G1Affine::from_uncompressed(&o).is_none().into() {
// y coordinate
} else {
panic!("should have rejected the point")
}
}
{
let m = Fq::zero().to_repr();
let mut o = o;
o.as_mut()[..48].copy_from_slice(m.as_ref());
if G1Affine::from_uncompressed(&o).is_none().into() {
// :)
} else {
panic!("should have rejected the point because it isn't on the curve")
}
}
{
let mut o = o;
let mut x = Fq::one();
loop {
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq::from(4)); // TODO: perhaps expose coeff_b through API?
let y = x3b.sqrt();
if y.is_some().into() {
let y = y.unwrap();
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
o.as_mut()[..48].copy_from_slice(x.to_repr().as_ref());
o.as_mut()[48..].copy_from_slice(y.to_repr().as_ref());
if G1Affine::from_uncompressed(&o).is_none().into() {
break;
} else {
panic!(
"should have rejected the point because it isn't in the correct subgroup"
)
}
} else {
x.add_assign(&Fq::one());
}
}
}
}
#[test]
fn test_g2_uncompressed_invalid_vectors() {
{
let z = G2Affine::identity().to_uncompressed();
{
let mut z = z;
z.as_mut()[0] |= 0b1000_0000;
if G2Affine::from_uncompressed(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected an uncompressed point");
}
}
{
let mut z = z;
z.as_mut()[0] |= 0b0010_0000;
if G2Affine::from_uncompressed(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
}
}
for i in 0..G2Uncompressed::size() {
let mut z = z;
z.as_mut()[i] |= 0b0000_0001;
if G2Affine::from_uncompressed(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
}
}
}
let o = G2Affine::generator().to_uncompressed();
{
let mut o = o;
o.as_mut()[0] |= 0b1000_0000;
if G2Affine::from_uncompressed(&o).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected an uncompressed point");
}
}
let m = Fq::char();
{
let mut o = o;
o.as_mut()[..48].copy_from_slice(m.as_ref());
if G2Affine::from_uncompressed(&o).is_none().into() {
// x coordinate (c1)
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
o.as_mut()[48..96].copy_from_slice(m.as_ref());
if G2Affine::from_uncompressed(&o).is_none().into() {
// x coordinate (c0)
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
o.as_mut()[96..144].copy_from_slice(m.as_ref());
if G2Affine::from_uncompressed(&o).is_none().into() {
// y coordinate (c1)
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
o.as_mut()[144..].copy_from_slice(m.as_ref());
if G2Affine::from_uncompressed(&o).is_none().into() {
// y coordinate (c0)
} else {
panic!("should have rejected the point")
}
}
{
let m = Fq::zero().to_repr();
let mut o = o;
o.as_mut()[..48].copy_from_slice(m.as_ref());
o.as_mut()[48..96].copy_from_slice(m.as_ref());
if G2Affine::from_uncompressed(&o).is_none().into() {
// :)
} else {
panic!("should have rejected the point because it isn't on the curve")
}
}
{
let mut o = o;
let mut x = Fq2::one();
loop {
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq2 {
c0: Fq::from(4),
c1: Fq::from(4),
}); // TODO: perhaps expose coeff_b through API?
let y = x3b.sqrt();
if y.is_some().into() {
let y = y.unwrap();
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
o.as_mut()[..48].copy_from_slice(x.c1.to_repr().as_ref());
o.as_mut()[48..96].copy_from_slice(x.c0.to_repr().as_ref());
o.as_mut()[96..144].copy_from_slice(y.c1.to_repr().as_ref());
o.as_mut()[144..].copy_from_slice(y.c0.to_repr().as_ref());
if G2Affine::from_uncompressed(&o).is_none().into() {
break;
} else {
panic!(
"should have rejected the point because it isn't in the correct subgroup"
)
}
} else {
x.add_assign(&Fq2::one());
}
}
}
}
#[test]
fn test_g1_compressed_invalid_vectors() {
{
let z = G1Affine::identity().to_bytes();
{
let mut z = z;
z.as_mut()[0] &= 0b0111_1111;
if G1Affine::from_bytes(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected a compressed point");
}
}
{
let mut z = z;
z.as_mut()[0] |= 0b0010_0000;
if G1Affine::from_bytes(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
}
}
for i in 0..G1Compressed::size() {
let mut z = z;
z.as_mut()[i] |= 0b0000_0001;
if G1Affine::from_bytes(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
}
}
}
let o = G1Affine::generator().to_bytes();
{
let mut o = o;
o.as_mut()[0] &= 0b0111_1111;
if G1Affine::from_bytes(&o).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected a compressed point");
}
}
let m = Fq::char();
{
let mut o = o;
o.as_mut()[..48].copy_from_slice(m.as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G1Affine::from_bytes(&o).is_none().into() {
// x coordinate
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
let mut x = Fq::one();
loop {
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq::from(4)); // TODO: perhaps expose coeff_b through API?
if x3b.sqrt().is_some().into() {
x.add_assign(&Fq::one());
} else {
o.as_mut().copy_from_slice(x.to_repr().as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G1Affine::from_bytes(&o).is_none().into() {
break;
} else {
panic!("should have rejected the point because it isn't on the curve")
}
}
}
}
{
let mut o = o;
let mut x = Fq::one();
loop {
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq::from(4)); // TODO: perhaps expose coeff_b through API?
if x3b.sqrt().is_some().into() {
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
o.as_mut().copy_from_slice(x.to_repr().as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G1Affine::from_bytes(&o).is_none().into() {
break;
} else {
panic!(
"should have rejected the point because it isn't in the correct subgroup"
)
}
} else {
x.add_assign(&Fq::one());
}
}
}
}
#[test]
fn test_g2_compressed_invalid_vectors() {
{
let z = G2Affine::identity().to_bytes();
{
let mut z = z;
z.as_mut()[0] &= 0b0111_1111;
if G2Affine::from_bytes(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected a compressed point");
}
}
{
let mut z = z;
z.as_mut()[0] |= 0b0010_0000;
if G2Affine::from_bytes(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the parity bit should not be set if the point is at infinity");
}
}
for i in 0..G2Compressed::size() {
let mut z = z;
z.as_mut()[i] |= 0b0000_0001;
if G2Affine::from_bytes(&z).is_none().into() {
// :)
} else {
panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity");
}
}
}
let o = G2Affine::generator().to_bytes();
{
let mut o = o;
o.as_mut()[0] &= 0b0111_1111;
if G2Affine::from_bytes(&o).is_none().into() {
// :)
} else {
panic!("should have rejected the point because we expected a compressed point");
}
}
let m = Fq::char();
{
let mut o = o;
o.as_mut()[..48].copy_from_slice(m.as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G2Affine::from_bytes(&o).is_none().into() {
// x coordinate (c1)
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
o.as_mut()[48..96].copy_from_slice(m.as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G2Affine::from_bytes(&o).is_none().into() {
// x coordinate (c0)
} else {
panic!("should have rejected the point")
}
}
{
let mut o = o;
let mut x = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
};
loop {
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq2 {
c0: Fq::from(4),
c1: Fq::from(4),
}); // TODO: perhaps expose coeff_b through API?
if x3b.sqrt().is_some().into() {
x.add_assign(&Fq2::one());
} else {
o.as_mut()[..48].copy_from_slice(x.c1.to_repr().as_ref());
o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G2Affine::from_bytes(&o).is_none().into() {
break;
} else {
panic!("should have rejected the point because it isn't on the curve")
}
}
}
}
{
let mut o = o;
let mut x = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
};
loop {
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq2 {
c0: Fq::from(4),
c1: Fq::from(4),
}); // TODO: perhaps expose coeff_b through API?
if x3b.sqrt().is_some().into() {
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
o.as_mut()[..48].copy_from_slice(x.c1.to_repr().as_ref());
o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref());
o.as_mut()[0] |= 0b1000_0000;
if G2Affine::from_bytes(&o).is_none().into() {
break;
} else {
panic!(
"should have rejected the point because it isn't in the correct subgroup"
)
}
} else {
x.add_assign(&Fq2::one());
}
}
}
}

View File

@ -18,8 +18,6 @@
#[cfg(test)]
pub mod tests;
pub mod bls12_381;
use core::ops::Mul;
use ff::PrimeField;
use group::{