mirror of
https://github.com/pezkuwichain/bizinikiwi-bn.git
synced 2026-07-23 21:45:39 +00:00
Implementation of pairing.
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
use fields::{FieldElement, Fq2, Fq, Fq6, const_fp};
|
||||
use std::ops::{Add, Sub, Mul, Neg};
|
||||
use rand::Rng;
|
||||
|
||||
use arith::U256;
|
||||
|
||||
fn frobenius_coeffs_c1(power: usize) -> Fq2 {
|
||||
match power % 12 {
|
||||
0 => Fq2::one(),
|
||||
1 => Fq2::new(
|
||||
const_fp([12653890742059813127, 14585784200204367754, 1278438861261381767, 212598772761311868]),
|
||||
const_fp([11683091849979440498, 14992204589386555739, 15866167890766973222, 1200023580730561873])
|
||||
),
|
||||
2 => Fq2::new(
|
||||
const_fp([14595462726357228530, 17349508522658994025, 1017833795229664280, 299787779797702374]),
|
||||
Fq::zero()
|
||||
),
|
||||
3 => Fq2::new(
|
||||
const_fp([3914496794763385213, 790120733010914719, 7322192392869644725, 581366264293887267]),
|
||||
const_fp([12817045492518885689, 4440270538777280383, 11178533038884588256, 2767537931541304486])
|
||||
),
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Fq12 {
|
||||
c0: Fq6,
|
||||
c1: Fq6
|
||||
}
|
||||
|
||||
impl Fq12 {
|
||||
pub fn new(c0: Fq6, c1: Fq6) -> Self {
|
||||
Fq12 {
|
||||
c0: c0,
|
||||
c1: c1
|
||||
}
|
||||
}
|
||||
|
||||
fn final_exponentiation_first_chunk(&self) -> Option<Fq12> {
|
||||
match self.inverse() {
|
||||
Some(b) => {
|
||||
let a = self.unitary_inverse();
|
||||
let c = a * b;
|
||||
let d = c.frobenius_map(2);
|
||||
|
||||
Some(d * c)
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
fn final_exponentiation_last_chunk(&self) -> Fq12 {
|
||||
let a = self.exp_by_neg_z();
|
||||
let b = a.cyclotomic_squared();
|
||||
let c = b.cyclotomic_squared();
|
||||
let d = c * b;
|
||||
|
||||
let e = d.exp_by_neg_z();
|
||||
let f = e.cyclotomic_squared();
|
||||
let g = f.exp_by_neg_z();
|
||||
let h = d.unitary_inverse();
|
||||
let i = g.unitary_inverse();
|
||||
|
||||
let j = i * e;
|
||||
let k = j * h;
|
||||
let l = k * b;
|
||||
let m = k * e;
|
||||
let n = *self * m;
|
||||
|
||||
let o = l.frobenius_map(1);
|
||||
let p = o * n;
|
||||
|
||||
let q = k.frobenius_map(2);
|
||||
let r = q * p;
|
||||
|
||||
let s = self.unitary_inverse();
|
||||
let t = s * l;
|
||||
let u = t.frobenius_map(3);
|
||||
let v = u * r;
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
pub fn final_exponentiation(&self) -> Option<Fq12> {
|
||||
self.final_exponentiation_first_chunk().map(|a| a.final_exponentiation_last_chunk())
|
||||
}
|
||||
|
||||
pub fn frobenius_map(&self, power: usize) -> Self {
|
||||
Fq12 {
|
||||
c0: self.c0.frobenius_map(power),
|
||||
c1: self.c1.frobenius_map(power).scale(frobenius_coeffs_c1(power))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exp_by_neg_z(&self) -> Fq12 {
|
||||
self.cyclotomic_pow(
|
||||
U256::from([4965661367192848881, 0, 0, 0])
|
||||
).unitary_inverse()
|
||||
}
|
||||
|
||||
pub fn unitary_inverse(&self) -> Fq12 {
|
||||
Fq12 {
|
||||
c0: self.c0,
|
||||
c1: -self.c1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_by_024(&self,
|
||||
ell_0: Fq2,
|
||||
ell_vw: Fq2,
|
||||
ell_vv: Fq2) -> Fq12 {
|
||||
let z0 = self.c0.c0;
|
||||
let z1 = self.c0.c1;
|
||||
let z2 = self.c0.c2;
|
||||
let z3 = self.c1.c0;
|
||||
let z4 = self.c1.c1;
|
||||
let z5 = self.c1.c2;
|
||||
|
||||
let x0 = ell_0;
|
||||
let x2 = ell_vv;
|
||||
let x4 = ell_vw;
|
||||
|
||||
let d0 = z0 * x0;
|
||||
let d2 = z2 * x2;
|
||||
let d4 = z4 * x4;
|
||||
let t2 = z0 + z4;
|
||||
let t1 = z0 + z2;
|
||||
let s0 = z1 + z3 + z5;
|
||||
|
||||
let s1 = z1 * x2;
|
||||
let t3 = s1 + d4;
|
||||
let t4 = t3.mul_by_nonresidue() + d0;
|
||||
let z0 = t4;
|
||||
|
||||
let t3 = z5 * x4;
|
||||
let s1 = s1 + t3;
|
||||
let t3 = t3 + d2;
|
||||
let t4 = t3.mul_by_nonresidue();
|
||||
let t3 = z1 * x0;
|
||||
let s1 = s1 + t3;
|
||||
let t4 = t4 + t3;
|
||||
let z1 = t4;
|
||||
|
||||
let t0 = x0 + x2;
|
||||
let t3 = t1 * t0 - d0 - d2;
|
||||
let t4 = z3 * x4;
|
||||
let s1 = s1 + t4;
|
||||
let t3 = t3 + t4;
|
||||
|
||||
let t0 = z2 + z4;
|
||||
let z2 = t3;
|
||||
|
||||
let t1 = x2 + x4;
|
||||
let t3 = t0 * t1 - d2 - d4;
|
||||
let t4 = t3.mul_by_nonresidue();
|
||||
let t3 = z3 * x0;
|
||||
let s1 = s1 + t3;
|
||||
let t4 = t4 + t3;
|
||||
let z3 = t4;
|
||||
|
||||
let t3 = z5 * x2;
|
||||
let s1 = s1 + t3;
|
||||
let t4 = t3.mul_by_nonresidue();
|
||||
let t0 = x0 + x4;
|
||||
let t3 = t2 * t0 - d0 - d4;
|
||||
let t4 = t4 + t3;
|
||||
let z4 = t4;
|
||||
|
||||
let t0 = x0 + x2 + x4;
|
||||
let t3 = s0 * t0 - s1;
|
||||
let z5 = t3;
|
||||
|
||||
Fq12 {
|
||||
c0: Fq6::new(z0, z1, z2),
|
||||
c1: Fq6::new(z3, z4, z5)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cyclotomic_squared(&self) -> Self {
|
||||
let z0 = self.c0.c0;
|
||||
let z4 = self.c0.c1;
|
||||
let z3 = self.c0.c2;
|
||||
let z2 = self.c1.c0;
|
||||
let z1 = self.c1.c1;
|
||||
let z5 = self.c1.c2;
|
||||
|
||||
let tmp = z0 * z1;
|
||||
let t0 = (z0 + z1) * (z1.mul_by_nonresidue() + z0) - tmp - tmp.mul_by_nonresidue();
|
||||
let t1 = tmp + tmp;
|
||||
|
||||
let tmp = z2 * z3;
|
||||
let t2 = (z2 + z3) * (z3.mul_by_nonresidue() + z2) - tmp - tmp.mul_by_nonresidue();
|
||||
let t3 = tmp + tmp;
|
||||
|
||||
let tmp = z4 * z5;
|
||||
let t4 = (z4 + z5) * (z5.mul_by_nonresidue() + z4) - tmp - tmp.mul_by_nonresidue();
|
||||
let t5 = tmp + tmp;
|
||||
|
||||
let z0 = t0 - z0;
|
||||
let z0 = z0 + z0;
|
||||
let z0 = z0 + t0;
|
||||
|
||||
let z1 = t1 + z1;
|
||||
let z1 = z1 + z1;
|
||||
let z1 = z1 + t1;
|
||||
|
||||
let tmp = t5.mul_by_nonresidue();
|
||||
let z2 = tmp + z2;
|
||||
let z2 = z2 + z2;
|
||||
let z2 = z2 + tmp;
|
||||
|
||||
let z3 = t4 - z3;
|
||||
let z3 = z3 + z3;
|
||||
let z3 = z3 + t4;
|
||||
|
||||
let z4 = t2 - z4;
|
||||
let z4 = z4 + z4;
|
||||
let z4 = z4 + t2;
|
||||
|
||||
let z5 = t3 + z5;
|
||||
let z5 = z5 + z5;
|
||||
let z5 = z5 + t3;
|
||||
|
||||
Fq12 {
|
||||
c0: Fq6::new(z0, z4, z3),
|
||||
c1: Fq6::new(z2, z1, z5)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cyclotomic_pow<I: Into<U256>>(&self, by: I) -> Self {
|
||||
let mut res = Self::one();
|
||||
|
||||
let mut found_one = false;
|
||||
|
||||
for i in by.into().bits() {
|
||||
if found_one {
|
||||
res = res.cyclotomic_squared();
|
||||
}
|
||||
|
||||
if i {
|
||||
found_one = true;
|
||||
res = *self * res;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldElement for Fq12 {
|
||||
fn zero() -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::zero(),
|
||||
c1: Fq6::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::one(),
|
||||
c1: Fq6::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::random(rng),
|
||||
c1: Fq6::random(rng)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero()
|
||||
}
|
||||
|
||||
fn squared(&self) -> Self {
|
||||
let ab = self.c0 * self.c1;
|
||||
|
||||
Fq12 {
|
||||
c0: (self.c1.mul_by_nonresidue() + self.c0) * (self.c0 + self.c1) - ab - ab.mul_by_nonresidue(),
|
||||
c1: ab + ab
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(self) -> Option<Self> {
|
||||
match (self.c0.squared() - (self.c1.squared().mul_by_nonresidue())).inverse() {
|
||||
Some(t) => Some(Fq12 {
|
||||
c0: self.c0 * t,
|
||||
c1: -(self.c1 * t)
|
||||
}),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Fq12 {
|
||||
type Output = Fq12;
|
||||
|
||||
fn mul(self, other: Fq12) -> Fq12 {
|
||||
let aa = self.c0 * other.c0;
|
||||
let bb = self.c1 * other.c1;
|
||||
|
||||
Fq12 {
|
||||
c0: bb.mul_by_nonresidue() + aa,
|
||||
c1: (self.c0 + self.c1) * (other.c0 + other.c1) - aa - bb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Fq12 {
|
||||
type Output = Fq12;
|
||||
|
||||
fn sub(self, other: Fq12) -> Fq12 {
|
||||
Fq12 {
|
||||
c0: self.c0 - other.c0,
|
||||
c1: self.c1 - other.c1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Fq12 {
|
||||
type Output = Fq12;
|
||||
|
||||
fn add(self, other: Fq12) -> Fq12 {
|
||||
Fq12 {
|
||||
c0: self.c0 + other.c0,
|
||||
c1: self.c1 + other.c1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Fq12 {
|
||||
type Output = Fq12;
|
||||
|
||||
fn neg(self) -> Fq12 {
|
||||
Fq12 {
|
||||
c0: -self.c0,
|
||||
c1: -self.c1
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-4
@@ -5,12 +5,20 @@ use rand::Rng;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
#[inline]
|
||||
fn non_residue() -> Fq {
|
||||
fn fq_non_residue() -> Fq {
|
||||
// (q - 1) is a quadratic nonresidue in Fq
|
||||
// 21888242871839275222246405745257275088696311157297823662689037894645226208582
|
||||
const_fp([0x68c3488912edefaa, 0x8d087f6872aabf4f, 0x51e1a24709081231, 0x2259d6b14729c0fa])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fq2_nonresidue() -> Fq2 {
|
||||
Fq2::new(
|
||||
const_fp([0xf60647ce410d7ff7, 0x2f3d6f4dd31bd011, 0x2943337e3940c6d1, 0x1d9598e8a7e39857]),
|
||||
const_fp([0xd35d438dc58f0d9d, 0x0a78eb28f5c70b3d, 0x666ea36f7879462c, 0x0e0a77c19a07df2f])
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Fq2 {
|
||||
c0: Fq,
|
||||
@@ -51,6 +59,21 @@ impl Fq2 {
|
||||
c1: self.c1 * by
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_by_nonresidue(&self) -> Self {
|
||||
*self * fq2_nonresidue()
|
||||
}
|
||||
|
||||
pub fn frobenius_map(&self, power: usize) -> Self {
|
||||
if power % 2 == 0 {
|
||||
*self
|
||||
} else {
|
||||
Fq2 {
|
||||
c0: self.c0,
|
||||
c1: self.c1 * fq_non_residue()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldElement for Fq2 {
|
||||
@@ -87,7 +110,7 @@ impl FieldElement for Fq2 {
|
||||
let ab = self.c0 * self.c1;
|
||||
|
||||
Fq2 {
|
||||
c0: (self.c1 * non_residue() + self.c0) * (self.c0 + self.c1) - ab - ab * non_residue(),
|
||||
c0: (self.c1 * fq_non_residue() + self.c0) * (self.c0 + self.c1) - ab - ab * fq_non_residue(),
|
||||
c1: ab + ab
|
||||
}
|
||||
}
|
||||
@@ -96,7 +119,7 @@ impl FieldElement for Fq2 {
|
||||
// "High-Speed Software Implementation of the Optimal Ate Pairing
|
||||
// over Barreto–Naehrig Curves"; Algorithm 8
|
||||
|
||||
match (self.c0.squared() - (self.c1.squared() * non_residue())).inverse() {
|
||||
match (self.c0.squared() - (self.c1.squared() * fq_non_residue())).inverse() {
|
||||
Some(t) => Some(Fq2 {
|
||||
c0: self.c0 * t,
|
||||
c1: -(self.c1 * t)
|
||||
@@ -118,7 +141,7 @@ impl Mul for Fq2 {
|
||||
let bb = self.c1 * other.c1;
|
||||
|
||||
Fq2 {
|
||||
c0: bb * non_residue() + aa,
|
||||
c0: bb * fq_non_residue() + aa,
|
||||
c1: (self.c0 + self.c1) * (other.c0 + other.c1) - aa - bb
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
use fields::{FieldElement, Fq, Fq2, const_fp};
|
||||
use std::ops::{Add, Sub, Mul, Neg};
|
||||
use rand::Rng;
|
||||
|
||||
fn frobenius_coeffs_c1(n: usize) -> Fq2 {
|
||||
match n % 6 {
|
||||
0 => Fq2::one(),
|
||||
1 => Fq2::new(
|
||||
const_fp([13075984984163199792, 3782902503040509012, 8791150885551868305, 1825854335138010348]),
|
||||
const_fp([7963664994991228759, 12257807996192067905, 13179524609921305146, 2767831111890561987])
|
||||
),
|
||||
2 => Fq2::new(
|
||||
const_fp([3697675806616062876, 9065277094688085689, 6918009208039626314, 2775033306905974752]),
|
||||
Fq::zero()
|
||||
),
|
||||
3 => Fq2::new(
|
||||
const_fp([14532872967180610477, 12903226530429559474, 1868623743233345524, 2316889217940299650]),
|
||||
const_fp([12447993766991532972, 4121872836076202828, 7630813605053367399, 740282956577754197])
|
||||
),
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
fn frobenius_coeffs_c2(n: usize) -> Fq2 {
|
||||
match n % 6 {
|
||||
0 => Fq2::one(),
|
||||
1 => Fq2::new(
|
||||
const_fp([8314163329781907090, 11942187022798819835, 11282677263046157209, 1576150870752482284]),
|
||||
const_fp([6763840483288992073, 7118829427391486816, 4016233444936635065, 2630958277570195709])
|
||||
),
|
||||
2 => Fq2::new(
|
||||
const_fp([8183898218631979349, 12014359695528440611, 12263358156045030468, 3187210487005268291]),
|
||||
Fq::zero()
|
||||
),
|
||||
3 => Fq2::new(
|
||||
const_fp([4938922280314430175, 13823286637238282975, 15589480384090068090, 481952561930628184]),
|
||||
const_fp([3105754162722846417, 11647802298615474591, 13057042392041828081, 1660844386505564338])
|
||||
),
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Fq6 {
|
||||
pub c0: Fq2,
|
||||
pub c1: Fq2,
|
||||
pub c2: Fq2
|
||||
}
|
||||
|
||||
impl Fq6 {
|
||||
pub fn new(c0: Fq2, c1: Fq2, c2: Fq2) -> Self {
|
||||
Fq6 {
|
||||
c0: c0,
|
||||
c1: c1,
|
||||
c2: c2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_by_nonresidue(&self) -> Self {
|
||||
Fq6 {
|
||||
c0: self.c2.mul_by_nonresidue(),
|
||||
c1: self.c0,
|
||||
c2: self.c1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(&self, by: Fq2) -> Self {
|
||||
Fq6 {
|
||||
c0: self.c0 * by,
|
||||
c1: self.c1 * by,
|
||||
c2: self.c2 * by
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frobenius_map(&self, power: usize) -> Self {
|
||||
Fq6 {
|
||||
c0: self.c0.frobenius_map(power),
|
||||
c1: self.c1.frobenius_map(power) * frobenius_coeffs_c1(power),
|
||||
c2: self.c2.frobenius_map(power) * frobenius_coeffs_c2(power)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldElement for Fq6 {
|
||||
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 random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fq6 {
|
||||
c0: Fq2::random(rng),
|
||||
c1: Fq2::random(rng),
|
||||
c2: Fq2::random(rng)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
|
||||
}
|
||||
|
||||
fn squared(&self) -> Self {
|
||||
let s0 = self.c0.squared();
|
||||
let ab = self.c0 * self.c1;
|
||||
let s1 = ab + ab;
|
||||
let s2 = (self.c0 - self.c1 + self.c2).squared();
|
||||
let bc = self.c1 * self.c2;
|
||||
let s3 = bc + bc;
|
||||
let s4 = self.c2.squared();
|
||||
|
||||
Fq6 {
|
||||
c0: s0 + s3.mul_by_nonresidue(),
|
||||
c1: s1 + s4.mul_by_nonresidue(),
|
||||
c2: s1 + s2 + s3 - s0 - s4
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(self) -> Option<Self> {
|
||||
let c0 = self.c0.squared() - self.c1 * self.c2.mul_by_nonresidue();
|
||||
let c1 = self.c2.squared().mul_by_nonresidue() - self.c0 * self.c1;
|
||||
let c2 = self.c1.squared() - self.c0 * self.c2;
|
||||
match ((self.c2 * c1 + self.c1 * c2).mul_by_nonresidue() + self.c0 * c0).inverse() {
|
||||
Some(t) => Some(Fq6 {
|
||||
c0: t * c0,
|
||||
c1: t * c1,
|
||||
c2: t * c2
|
||||
}),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Fq6 {
|
||||
type Output = Fq6;
|
||||
|
||||
fn mul(self, other: Fq6) -> Fq6 {
|
||||
let a_a = self.c0 * other.c0;
|
||||
let b_b = self.c1 * other.c1;
|
||||
let c_c = self.c2 * other.c2;
|
||||
|
||||
Fq6 {
|
||||
c0: ((self.c1 + self.c2) * (other.c1 + other.c2) - b_b - c_c).mul_by_nonresidue() + a_a,
|
||||
c1: (self.c0 + self.c1) * (other.c0 + other.c1) - a_a - b_b + c_c.mul_by_nonresidue(),
|
||||
c2: (self.c0 + self.c2) * (other.c0 + other.c2) - a_a + b_b - c_c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Fq6 {
|
||||
type Output = Fq6;
|
||||
|
||||
fn sub(self, other: Fq6) -> Fq6 {
|
||||
Fq6 {
|
||||
c0: self.c0 - other.c0,
|
||||
c1: self.c1 - other.c1,
|
||||
c2: self.c2 - other.c2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Fq6 {
|
||||
type Output = Fq6;
|
||||
|
||||
fn add(self, other: Fq6) -> Fq6 {
|
||||
Fq6 {
|
||||
c0: self.c0 + other.c0,
|
||||
c1: self.c1 + other.c1,
|
||||
c2: self.c2 + other.c2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Fq6 {
|
||||
type Output = Fq6;
|
||||
|
||||
fn neg(self) -> Fq6 {
|
||||
Fq6 {
|
||||
c0: -self.c0,
|
||||
c1: -self.c1,
|
||||
c2: -self.c2
|
||||
}
|
||||
}
|
||||
}
|
||||
+135
-1
@@ -1,5 +1,7 @@
|
||||
mod fp;
|
||||
mod fq2;
|
||||
mod fq6;
|
||||
mod fq12;
|
||||
|
||||
use arith::U256;
|
||||
use rand::Rng;
|
||||
@@ -7,7 +9,9 @@ use std::ops::{Add, Sub, Mul, Neg};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use self::fp::{Fq,Fr,const_fp};
|
||||
pub use self::fq2::Fq2;
|
||||
pub use self::fq2::{Fq2, fq2_nonresidue};
|
||||
pub use self::fq6::Fq6;
|
||||
pub use self::fq12::Fq12;
|
||||
|
||||
pub trait FieldElement: Sized
|
||||
+ Copy
|
||||
@@ -65,3 +69,133 @@ fn test_str() {
|
||||
assert_eq!(-Fr::one(), Fr::from_str("21888242871839275222246405745257275088548364400416034343698204186575808495616").unwrap());
|
||||
assert_eq!(-Fq::one(), Fq::from_str("21888242871839275222246405745257275088696311157297823662689037894645226208582").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq6() {
|
||||
tests::field_trials::<Fq6>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq12() {
|
||||
tests::field_trials::<Fq12>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fq12_test_vector() {
|
||||
let start = Fq12::new(
|
||||
Fq6::new(
|
||||
Fq2::new(
|
||||
Fq::from_str("19797905000333868150253315089095386158892526856493194078073564469188852136946").unwrap(),
|
||||
Fq::from_str("10509658143212501778222314067134547632307419253211327938344904628569123178733").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("208316612133170645758860571704540129781090973693601051684061348604461399206").unwrap(),
|
||||
Fq::from_str("12617661120538088237397060591907161689901553895660355849494983891299803248390").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("2897490589776053688661991433341220818937967872052418196321943489809183508515").unwrap(),
|
||||
Fq::from_str("2730506433347642574983433139433778984782882168213690554721050571242082865799").unwrap()
|
||||
)
|
||||
),
|
||||
Fq6::new(
|
||||
Fq2::new(
|
||||
Fq::from_str("17870056122431653936196746815433147921488990391314067765563891966783088591110").unwrap(),
|
||||
Fq::from_str("14314041658607615069703576372547568077123863812415914883625850585470406221594").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("10123533891707846623287020000407963680629966110211808794181173248765209982878").unwrap(),
|
||||
Fq::from_str("5062091880848845693514855272640141851746424235009114332841857306926659567101").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("9839781502639936537333620974973645053542086898304697594692219798017709586567").unwrap(),
|
||||
Fq::from_str("1583892292110602864638265389721494775152090720173641072176370350017825640703").unwrap()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Do a bunch of arbitrary stuff to the element
|
||||
|
||||
let mut next = start.clone();
|
||||
for _ in 0..100 {
|
||||
next = next * start;
|
||||
}
|
||||
|
||||
let cpy = next.clone();
|
||||
|
||||
for _ in 0..10 {
|
||||
next = next.squared();
|
||||
}
|
||||
|
||||
for _ in 0..10 {
|
||||
next = next + start;
|
||||
next = next - cpy;
|
||||
next = -next;
|
||||
}
|
||||
|
||||
next = next.squared();
|
||||
|
||||
let finally = Fq12::new(
|
||||
Fq6::new(
|
||||
Fq2::new(
|
||||
Fq::from_str("18388750939593263065521177085001223024106699964957029146547831509155008229833").unwrap(),
|
||||
Fq::from_str("18370529854582635460997127698388761779167953912610241447912705473964014492243").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("3691824277096717481466579496401243638295254271265821828017111951446539785268").unwrap(),
|
||||
Fq::from_str("20513494218085713799072115076991457239411567892860153903443302793553884247235").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("12214155472433286415803224222551966441740960297013786627326456052558698216399").unwrap(),
|
||||
Fq::from_str("10987494248070743195602580056085773610850106455323751205990078881956262496575").unwrap()
|
||||
)
|
||||
),
|
||||
Fq6::new(
|
||||
Fq2::new(
|
||||
Fq::from_str("5134522153456102954632718911439874984161223687865160221119284322136466794876").unwrap(),
|
||||
Fq::from_str("20119236909927036376726859192821071338930785378711977469360149362002019539920").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("8839766648621210419302228913265679710586991805716981851373026244791934012854").unwrap(),
|
||||
Fq::from_str("9103032146464138788288547957401673544458789595252696070370942789051858719203").unwrap()
|
||||
),
|
||||
Fq2::new(
|
||||
Fq::from_str("10378379548636866240502412547812481928323945124508039853766409196375806029865").unwrap(),
|
||||
Fq::from_str("9021627154807648093720460686924074684389554332435186899318369174351765754041").unwrap()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(finally, next);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cyclotomic_exp() {
|
||||
let orig = Fq12::new(
|
||||
Fq6::new(
|
||||
Fq2::new(Fq::from_str("2259924035228092997691937637688451143058635253053054071159756458902878894295").unwrap(), Fq::from_str("13145690032701362144460254305183927872683620413225364127064863863535255135244").unwrap()),
|
||||
Fq2::new(Fq::from_str("9910063591662383599552477067956819406417086889312288278252482503717089428441").unwrap(), Fq::from_str("537414042055419261990282459138081732565514913399498746664966841152381183961").unwrap()),
|
||||
Fq2::new(Fq::from_str("15311812409497308894370893420777496684951030254049554818293571309705780605004").unwrap(), Fq::from_str("13657107176064455789881282546557276003626320193974643644160350907227082365810").unwrap())
|
||||
),
|
||||
Fq6::new(Fq2::new(Fq::from_str("4913017949003742946864670837361832856526234260447029873580022776602534856819").unwrap(), Fq::from_str("7834351480852267338070670220119081676575418514182895774094743209915633114041").unwrap()),
|
||||
Fq2::new(Fq::from_str("12837298223308203788092748646758194441270207338661891973231184407371206766993").unwrap(), Fq::from_str("12756474445699147370503225379431475413909971718057034061593007812727141391799").unwrap()),
|
||||
Fq2::new(Fq::from_str("9473802207170192255373153510655867502408045964296373712891954747252332944018").unwrap(), Fq::from_str("4583089109360519374075173304035813179013579459429335467869926761027310749713").unwrap())
|
||||
)
|
||||
);
|
||||
|
||||
let expected = Fq12::new(
|
||||
Fq6::new(
|
||||
Fq2::new(Fq::from_str("14722956046055152398903846391223329501345567382234608299399030576415080188350").unwrap(), Fq::from_str("14280703280777926697010730619606819467080027543707671882210769811674790473417").unwrap()),
|
||||
Fq2::new(Fq::from_str("19969875076083990244184003223190771301761436396530543002586073549972410735411").unwrap(), Fq::from_str("10717335566913889643303549252432531178405520196706173198634734518494041323243").unwrap()),
|
||||
Fq2::new(Fq::from_str("6063612626166484870786832843320782567259894784043383626084549455432890717937").unwrap(), Fq::from_str("17089783040131779205038789608891431427943860868115199598200376195935079808729").unwrap())
|
||||
),
|
||||
Fq6::new(
|
||||
Fq2::new(Fq::from_str("10029863438921507421569931792104023129735006154272482043027653425575205672906").unwrap(), Fq::from_str("6406252222753462799887280578845937185621081001436094637606245493619821542775").unwrap()),
|
||||
Fq2::new(Fq::from_str("1048245462913506652602966692378792381004227332967846949234978073448561848050").unwrap(), Fq::from_str("1444281375189053827455518242624554285012408033699861764136810522738182087554").unwrap()),
|
||||
Fq2::new(Fq::from_str("8839610992666735109106629514135300820412539620261852250193684883379364789120").unwrap(), Fq::from_str("11347360242067273846784836674906058940820632082713814508736182487171407730718").unwrap())
|
||||
)
|
||||
);
|
||||
|
||||
let e = orig.exp_by_neg_z();
|
||||
|
||||
assert_eq!(e, expected);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user