mirror of
https://github.com/pezkuwichain/bizinikiwi-bn.git
synced 2026-06-17 06:41:06 +00:00
Performing reconstruction of the codebase.
This commit is contained in:
+210
-143
@@ -1,167 +1,234 @@
|
||||
use rand::Rng;
|
||||
use num::{BigUint, Num};
|
||||
use std::ops::{Mul,Add,Sub,Neg};
|
||||
use std::cmp::{PartialEq, Eq};
|
||||
use std::convert::From;
|
||||
use std::ops::{Add, Sub, Mul, Neg};
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use super::Field;
|
||||
use super::FieldElement;
|
||||
|
||||
pub trait PrimeFieldParams {
|
||||
fn modulus() -> BigUint;
|
||||
fn bits() -> usize;
|
||||
use arith::U256;
|
||||
|
||||
pub trait FpParams {
|
||||
fn name() -> &'static str;
|
||||
fn modulus() -> U256;
|
||||
fn inv() -> u32;
|
||||
fn rsquared() -> U256;
|
||||
fn rcubed() -> U256;
|
||||
fn one() -> U256;
|
||||
}
|
||||
|
||||
pub struct Fp<P: PrimeFieldParams> {
|
||||
value: BigUint,
|
||||
_marker: PhantomData<P>
|
||||
pub struct Fp<P: FpParams>(U256, PhantomData<P>);
|
||||
impl<P: FpParams> Copy for Fp<P> { }
|
||||
impl<P: FpParams> Clone for Fp<P> {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> fmt::Debug for Fp<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({})", P::name(), self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Field for Fp<P> {
|
||||
fn zero() -> Self {
|
||||
use num::Zero;
|
||||
|
||||
Fp {
|
||||
value: BigUint::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn one() -> Self {
|
||||
use num::One;
|
||||
|
||||
Fp {
|
||||
value: BigUint::one(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
use num::num_bigint::RandBigInt;
|
||||
use num::Zero;
|
||||
|
||||
Fp {
|
||||
value: rng.gen_biguint_range(&BigUint::zero(), &P::modulus()),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Self {
|
||||
if self.is_zero() {
|
||||
// TODO: this should likely bleed through the abstraction layers
|
||||
panic!("cannot get the multiplicative inverse of zero")
|
||||
} else {
|
||||
let mut res = Self::one();
|
||||
|
||||
let mut found_one = false;
|
||||
|
||||
let exp = Self::zero() - Self::one() - Self::one();
|
||||
|
||||
for i in (0..P::bits()).rev() {
|
||||
if found_one {
|
||||
res = res.squared();
|
||||
}
|
||||
|
||||
if exp.test_bit(i) {
|
||||
found_one = true;
|
||||
res = self * &res;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
fn neg(&self) -> Self {
|
||||
use num::Zero;
|
||||
|
||||
Fp {
|
||||
value: if self.value.is_zero() {
|
||||
self.value.clone()
|
||||
} else {
|
||||
P::modulus() - &self.value
|
||||
},
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn mul(&self, other: &Self) -> Self {
|
||||
Fp {
|
||||
value: (&self.value * &other.value) % &P::modulus(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn sub(&self, other: &Self) -> Self {
|
||||
if other.value > self.value {
|
||||
Fp {
|
||||
value: (&self.value + P::modulus()) - &other.value,
|
||||
_marker: PhantomData
|
||||
}
|
||||
} else {
|
||||
Fp {
|
||||
value: &self.value - &other.value,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&self, other: &Self) -> Self {
|
||||
let tmp = &self.value + &other.value;
|
||||
if tmp >= P::modulus() {
|
||||
Fp {
|
||||
value: tmp - P::modulus(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
} else {
|
||||
Fp {
|
||||
value: tmp,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: FpParams> PartialEq for Fp<P> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.value == other.value
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
impl<P: FpParams> Eq for Fp<P> { }
|
||||
impl<P: FpParams> fmt::Debug for Fp<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({:?})", P::name(), self.0)
|
||||
}
|
||||
}
|
||||
impl<P: FpParams> From<Fp<P>> for U256 {
|
||||
fn from(mut a: Fp<P>) -> Self {
|
||||
a.0.mul(&U256::one(), &P::modulus(), P::inv());
|
||||
|
||||
a.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Fp<P> {
|
||||
pub fn test_bit(&self, bit: usize) -> bool {
|
||||
// TODO: This is a naive approach.
|
||||
use num::{One, Zero};
|
||||
#[inline]
|
||||
pub fn const_fp<P: FpParams, I: Into<U256>>(i: I) -> Fp<P> {
|
||||
Fp(i.into(), PhantomData)
|
||||
}
|
||||
|
||||
let mut b = BigUint::one();
|
||||
let two = &b + &b;
|
||||
for _ in 0..bit {
|
||||
b = &b + &b;
|
||||
impl<P: FpParams> Fp<P> {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
let ints: Vec<_> = {
|
||||
let mut acc = Self::zero();
|
||||
(0..11).map(|_| {let tmp = acc; acc = acc + Self::one(); tmp}).collect()
|
||||
};
|
||||
|
||||
let mut res = Self::zero();
|
||||
for c in s.chars() {
|
||||
match c.to_digit(10) {
|
||||
Some(d) => {
|
||||
res = res * ints[10];
|
||||
res = res + ints[d as usize];
|
||||
},
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(&self.value / b) % two != BigUint::zero()
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, P: PrimeFieldParams> From<&'a str> for Fp<P> {
|
||||
fn from(s: &'a str) -> Self {
|
||||
Fp {
|
||||
value: BigUint::from_str_radix(s, 10).unwrap() % P::modulus(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
impl<P: FpParams> Fp<P> {
|
||||
/// Assumes input is mod p, not exposed publicly
|
||||
fn new_checked(mut a: U256) -> Self {
|
||||
a.mul(&P::rsquared(), &P::modulus(), P::inv());
|
||||
|
||||
Fp(a, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: PrimeFieldParams> Clone for Fp<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Fp {
|
||||
value: self.value.clone(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
impl<P: FpParams> FieldElement for Fp<P> {
|
||||
fn zero() -> Self {
|
||||
const_fp(U256::zero())
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
const_fp(P::one())
|
||||
}
|
||||
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fp::new_checked(U256::rand(rng, &P::modulus()))
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.0.is_zero()
|
||||
}
|
||||
|
||||
fn inverse(mut self) -> Self {
|
||||
assert!(!self.is_zero());
|
||||
|
||||
self.0.invert(&P::modulus());
|
||||
self.0.mul(&P::rcubed(), &P::modulus(), P::inv());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
forward_ops_to_field_ops!(impl(P: PrimeFieldParams) Fp<P>);
|
||||
impl<P: FpParams> Add for Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn add(mut self, other: Fp<P>) -> Fp<P> {
|
||||
self.0.add(&other.0, &P::modulus());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: FpParams> Sub for Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn sub(mut self, other: Fp<P>) -> Fp<P> {
|
||||
self.0.sub(&other.0, &P::modulus());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: FpParams> Mul for Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn mul(mut self, other: Fp<P>) -> Fp<P> {
|
||||
self.0.mul(&other.0, &P::modulus(), P::inv());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: FpParams> Neg for Fp<P> {
|
||||
type Output = Fp<P>;
|
||||
|
||||
fn neg(mut self) -> Fp<P> {
|
||||
self.0.neg(&P::modulus());
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FrParams;
|
||||
pub type Fr = Fp<FrParams>;
|
||||
impl FpParams for FrParams {
|
||||
fn name() -> &'static str { "Fr" }
|
||||
|
||||
#[inline]
|
||||
fn modulus() -> U256 {
|
||||
// 21888242871839275222246405745257275088548364400416034343698204186575808495617
|
||||
[0xf0000001, 0x43e1f593, 0x79b97091, 0x2833e848, 0x8181585d, 0xb85045b6, 0xe131a029, 0x30644e72].into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inv() -> u32 {
|
||||
0xefffffff
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rsquared() -> U256 {
|
||||
// 944936681149208446651664254269745548490766851729442924617792859073125903783
|
||||
[0xae216da7, 0x1bb8e645, 0xe35c59e3, 0x53fe3ab1, 0x53bb8085, 0x8c49833d, 0x7f4e44a5, 0x0216d0b1].into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rcubed() -> U256 {
|
||||
// 5866548545943845227489894872040244720403868105578784105281690076696998248512
|
||||
[0xb4bf0040, 0x5e94d8e1, 0x1cfbb6b8, 0x2a489cbe, 0xa19fcfed, 0x893cc664, 0x7fcc657c, 0x0cf8594b].into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn one() -> U256 {
|
||||
[0x4ffffffb, 0xac96341c, 0x9f60cd29, 0x36fc7695, 0x7879462e, 0x666ea36f, 0x9a07df2f, 0x0e0a77c1].into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FqParams;
|
||||
pub type Fq = Fp<FqParams>;
|
||||
impl FpParams for FqParams {
|
||||
fn name() -> &'static str { "Fq" }
|
||||
|
||||
#[inline]
|
||||
fn modulus() -> U256 {
|
||||
// 21888242871839275222246405745257275088696311157297823662689037894645226208583
|
||||
[0xd87cfd47, 0x3c208c16, 0x6871ca8d, 0x97816a91, 0x8181585d, 0xb85045b6, 0xe131a029, 0x30644e72].into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inv() -> u32 {
|
||||
0xe4866389
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rsquared() -> U256 {
|
||||
// 3096616502983703923843567936837374451735540968419076528771170197431451843209
|
||||
[0x538afa89, 0xf32cfc5b, 0xd44501fb, 0xb5e71911, 0x0a417ff6, 0x47ab1eff, 0xcab8351f, 0x06d89f71].into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rcubed() -> U256 {
|
||||
// 14921786541159648185948152738563080959093619838510245177710943249661917737183
|
||||
[0xda1530df, 0xb1cd6daf, 0xa7283db6, 0x62f210e6, 0x0ada0afb, 0xef7f0b0c, 0x2d592544, 0x20fd6e90].into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn one() -> U256 {
|
||||
[0xc58f0d9d, 0xd35d438d, 0xf5c70b3d, 0x0a78eb28, 0x7879462c, 0x666ea36f, 0x9a07df2f, 0x0e0a77c1].into()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rsquared() {
|
||||
let rng = &mut ::rand::thread_rng();
|
||||
|
||||
for _ in 0..1000 {
|
||||
let a = Fr::random(rng);
|
||||
let b: U256 = a.into();
|
||||
let c = Fr::new_checked(b);
|
||||
|
||||
assert_eq!(a, c);
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
let a = Fq::random(rng);
|
||||
let b: U256 = a.into();
|
||||
let c = Fq::new_checked(b);
|
||||
|
||||
assert_eq!(a, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
use ::Fr;
|
||||
use ::Fq2;
|
||||
use ::Fq6;
|
||||
use ::Fq12;
|
||||
use fields::fp::PrimeFieldParams;
|
||||
use fields::fp6::Fp6Params;
|
||||
use params::{FrParams,Fq6Params};
|
||||
use rand::Rng;
|
||||
use fields::Field;
|
||||
use std::ops::{Mul,Add,Sub,Neg};
|
||||
use std::cmp::{PartialEq, Eq};
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
|
||||
pub trait Fp12Params {
|
||||
fn non_residue() -> Fq2;
|
||||
fn name() -> &'static str;
|
||||
fn frobenius_coeffs_c1(n: usize) -> Fq2;
|
||||
}
|
||||
|
||||
pub struct Fp12<P: Fp12Params> {
|
||||
a: Fq6,
|
||||
b: Fq6,
|
||||
_marker: PhantomData<P>
|
||||
}
|
||||
|
||||
impl<P: Fp12Params> Fp12<P> {
|
||||
pub fn new(a: Fq6, b: Fq6) -> Self {
|
||||
Fp12 {
|
||||
a: a,
|
||||
b: b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frobenius_map(&self, power: usize) -> Self {
|
||||
Fp12 {
|
||||
a: self.a.frobenius_map(power),
|
||||
b: &self.b.frobenius_map(power) * &P::frobenius_coeffs_c1(power % 12),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fq12 {
|
||||
pub fn unitary_inverse(&self) -> Fq12 {
|
||||
Fp12 {
|
||||
a: self.a.clone(),
|
||||
b: -&self.b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cyclotomic_exp(&self, exp: &Fr) -> Self {
|
||||
let mut res = Self::one();
|
||||
|
||||
let mut found_one = false;
|
||||
|
||||
for i in (0..FrParams::bits()).rev() {
|
||||
if found_one {
|
||||
res = res.cyclotomic_squared();
|
||||
}
|
||||
|
||||
if exp.test_bit(i) {
|
||||
found_one = true;
|
||||
res = self * &res;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn cyclotomic_squared(&self) -> Self {
|
||||
let z0 = &self.a.a;
|
||||
let z4 = &self.a.b;
|
||||
let z3 = &self.a.c;
|
||||
let z2 = &self.b.a;
|
||||
let z1 = &self.b.b;
|
||||
let z5 = &self.b.c;
|
||||
|
||||
let tmp = z0 * z1;
|
||||
let t0 = (z0 + z1) * (z1 * Fq6Params::non_residue() + z0) - &tmp - &tmp * Fq6Params::non_residue();
|
||||
let t1 = &tmp + &tmp;
|
||||
|
||||
let tmp = z2 * z3;
|
||||
let t2 = (z2 + z3) * (z3 * Fq6Params::non_residue() + z2) - &tmp - &tmp * Fq6Params::non_residue();
|
||||
let t3 = &tmp + &tmp;
|
||||
|
||||
let tmp = z4 * z5;
|
||||
let t4 = (z4 + z5) * (z5 * Fq6Params::non_residue() + z4) - &tmp - &tmp * Fq6Params::non_residue();
|
||||
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 * Fq6Params::non_residue();
|
||||
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;
|
||||
|
||||
Fp12 {
|
||||
a: Fq6::new(z0, z4, z3),
|
||||
b: Fq6::new(z2, z1, z5),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_by_024(&self,
|
||||
ell_0: &Fq2,
|
||||
ell_vw: Fq2,
|
||||
ell_vv: Fq2) -> Fq12 {
|
||||
let z0 = &self.a.a;
|
||||
let z1 = &self.a.b;
|
||||
let z2 = &self.a.c;
|
||||
let z3 = &self.b.a;
|
||||
let z4 = &self.b.b;
|
||||
let z5 = &self.b.c;
|
||||
|
||||
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 * Fq6Params::non_residue() + &d0;
|
||||
let z0 = t4;
|
||||
|
||||
let t3 = z5 * x4;
|
||||
let s1 = &s1 + &t3;
|
||||
let t3 = &t3 + &d2;
|
||||
let t4 = &t3 * Fq6Params::non_residue();
|
||||
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 * Fq6Params::non_residue();
|
||||
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 * Fq6Params::non_residue();
|
||||
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 {
|
||||
a: Fq6::new(z0, z1, z2),
|
||||
b: Fq6::new(z3, z4, z5),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp12Params> fmt::Debug for Fp12<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({:?}, {:?})", P::name(), self.a, self.b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp12Params> Clone for Fp12<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Fp12 {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp12Params> Field for Fp12<P> {
|
||||
fn zero() -> Self {
|
||||
Fp12 {
|
||||
a: Fq6::zero(),
|
||||
b: Fq6::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn one() -> Self {
|
||||
Fp12 {
|
||||
a: Fq6::one(),
|
||||
b: Fq6::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fp12 {
|
||||
a: Fq6::random(rng),
|
||||
b: Fq6::random(rng),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Self {
|
||||
let t = (self.a.squared() - (self.b.squared().mul_by_nonresidue(&P::non_residue()))).inverse();
|
||||
|
||||
Fp12 {
|
||||
a: &self.a * &t,
|
||||
b: -(&self.b * &t),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn squared(&self) -> Self {
|
||||
let a = &self.a; let b = &self.b;
|
||||
let ab = &(a * b);
|
||||
|
||||
Fp12 {
|
||||
a: (b.mul_by_nonresidue(&P::non_residue()) + a) * (a + b) - ab - ab.mul_by_nonresidue(&P::non_residue()),
|
||||
b: ab + ab,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.a == other.a && self.b == other.b
|
||||
}
|
||||
fn neg(&self) -> Self {
|
||||
Fp12 {
|
||||
a: -(&self.a),
|
||||
b: -(&self.b),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn mul(&self, other: &Self) -> Self {
|
||||
let a_a = &(&self.a * &other.a);
|
||||
let b_b = &(&self.b * &other.b);
|
||||
|
||||
Fp12 {
|
||||
a: b_b.mul_by_nonresidue(&P::non_residue()) + a_a,
|
||||
b: (&self.a + &self.b) * (&other.a + &other.b) - a_a - b_b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn sub(&self, other: &Self) -> Self {
|
||||
Fp12 {
|
||||
a: &self.a - &other.a,
|
||||
b: &self.b - &other.b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn add(&self, other: &Self) -> Self {
|
||||
Fp12 {
|
||||
a: &self.a + &other.a,
|
||||
b: &self.b + &other.b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forward_ops_to_field_ops!(impl(P: Fp12Params) Fp12<P>);
|
||||
@@ -1,146 +0,0 @@
|
||||
use ::Fq;
|
||||
use rand::Rng;
|
||||
use fields::Field;
|
||||
use std::ops::{Mul,Add,Sub,Neg};
|
||||
use std::cmp::{PartialEq, Eq};
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
|
||||
pub trait Fp2Params {
|
||||
fn non_residue() -> Fq;
|
||||
fn name() -> &'static str;
|
||||
fn frobenius_coeffs_c1(usize) -> Fq;
|
||||
}
|
||||
|
||||
pub struct Fp2<P: Fp2Params> {
|
||||
a: Fq,
|
||||
b: Fq,
|
||||
_marker: PhantomData<P>
|
||||
}
|
||||
|
||||
impl<P: Fp2Params> Fp2<P> {
|
||||
pub fn new(a: Fq, b: Fq) -> Self {
|
||||
Fp2 {
|
||||
a: a,
|
||||
b: b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frobenius_map(&self, power: usize) -> Self {
|
||||
Fp2 {
|
||||
a: self.a.clone(),
|
||||
b: &self.b * P::frobenius_coeffs_c1(power % 2),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp2Params> fmt::Debug for Fp2<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({:?}, {:?})", P::name(), self.a, self.b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp2Params> Clone for Fp2<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Fp2 {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp2Params> Field for Fp2<P> {
|
||||
fn zero() -> Self {
|
||||
Fp2 {
|
||||
a: Fq::zero(),
|
||||
b: Fq::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn one() -> Self {
|
||||
Fp2 {
|
||||
a: Fq::one(),
|
||||
b: Fq::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fp2 {
|
||||
a: Fq::random(rng),
|
||||
b: Fq::random(rng),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Self {
|
||||
let t = (self.a.squared() - (self.b.squared() * P::non_residue())).inverse();
|
||||
|
||||
Fp2 {
|
||||
a: &self.a * &t,
|
||||
b: -(&self.b * &t),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn squared(&self) -> Self {
|
||||
let a = &self.a; let b = &self.b;
|
||||
let ab = &(a * b);
|
||||
|
||||
Fp2 {
|
||||
a: (b * P::non_residue() + a) * (a + b) - ab - ab * P::non_residue(),
|
||||
b: ab + ab,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.a == other.a && self.b == other.b
|
||||
}
|
||||
fn neg(&self) -> Self {
|
||||
Fp2 {
|
||||
a: -(&self.a),
|
||||
b: -(&self.b),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn mul(&self, other: &Self) -> Self {
|
||||
let a_a = &(&self.a * &other.a);
|
||||
let b_b = &(&self.b * &other.b);
|
||||
|
||||
Fp2 {
|
||||
a: b_b * P::non_residue() + a_a,
|
||||
b: (&self.a + &self.b) * (&other.a + &other.b) - a_a - b_b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn sub(&self, other: &Self) -> Self {
|
||||
Fp2 {
|
||||
a: &self.a - &other.a,
|
||||
b: &self.b - &other.b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
fn add(&self, other: &Self) -> Self {
|
||||
Fp2 {
|
||||
a: &self.a + &other.a,
|
||||
b: &self.b + &other.b,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, P: Fp2Params> Mul<&'a Fq> for &'b Fp2<P> {
|
||||
type Output = Fp2<P>;
|
||||
|
||||
fn mul(self, other: &Fq) -> Fp2<P> {
|
||||
Fp2 {
|
||||
a: &self.a * other,
|
||||
b: &self.b * other,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forward_ops_to_field_ops!(impl(P: Fp2Params) Fp2<P>);
|
||||
@@ -1,192 +0,0 @@
|
||||
use ::Fq2;
|
||||
use rand::Rng;
|
||||
use fields::Field;
|
||||
use std::ops::{Mul,Add,Sub,Neg};
|
||||
use std::cmp::{PartialEq, Eq};
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
|
||||
pub trait Fp6Params {
|
||||
fn non_residue() -> Fq2;
|
||||
fn name() -> &'static str;
|
||||
fn frobenius_coeffs_c1(usize) -> Fq2;
|
||||
fn frobenius_coeffs_c2(usize) -> Fq2;
|
||||
}
|
||||
|
||||
pub struct Fp6<P: Fp6Params> {
|
||||
pub a: Fq2,
|
||||
pub b: Fq2,
|
||||
pub c: Fq2,
|
||||
_marker: PhantomData<P>
|
||||
}
|
||||
|
||||
impl<P: Fp6Params> Fp6<P> {
|
||||
pub fn new(a: Fq2, b: Fq2, c: Fq2) -> Self {
|
||||
Fp6 {
|
||||
a: a,
|
||||
b: b,
|
||||
c: c,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frobenius_map(&self, power: usize) -> Self {
|
||||
Fp6 {
|
||||
a: self.a.frobenius_map(power),
|
||||
b: self.b.frobenius_map(power) * P::frobenius_coeffs_c1(power % 6),
|
||||
c: self.c.frobenius_map(power) * P::frobenius_coeffs_c2(power % 6),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp6Params> fmt::Debug for Fp6<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.a, self.b, self.c)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp6Params> Clone for Fp6<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Fp6 {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
c: self.c.clone(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp6Params> Field for Fp6<P> {
|
||||
fn zero() -> Self {
|
||||
Fp6 {
|
||||
a: Fq2::zero(),
|
||||
b: Fq2::zero(),
|
||||
c: Fq2::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Fp6 {
|
||||
a: Fq2::one(),
|
||||
b: Fq2::zero(),
|
||||
c: Fq2::zero(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fp6 {
|
||||
a: Fq2::random(rng),
|
||||
b: Fq2::random(rng),
|
||||
c: Fq2::random(rng),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(&self) -> Self {
|
||||
let c0 = self.a.squared() - &self.b * &self.c * P::non_residue();
|
||||
let c1 = self.c.squared() * P::non_residue() - &self.a * &self.b;
|
||||
let c2 = self.b.squared() - &self.a * &self.c;
|
||||
let t = ((&self.c * &c1 + &self.b * &c2) * P::non_residue() + &self.a * &c0).inverse();
|
||||
|
||||
Fp6 {
|
||||
a: &t * &c0,
|
||||
b: &t * &c1,
|
||||
c: &t * &c2,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.a == other.a && self.b == other.b && self.c == other.c
|
||||
}
|
||||
|
||||
fn neg(&self) -> Self {
|
||||
Fp6 {
|
||||
a: -(&self.a),
|
||||
b: -(&self.b),
|
||||
c: -(&self.c),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn mul(&self, other: &Self) -> Self {
|
||||
let a_a = &self.a * &other.a;
|
||||
let b_b = &self.b * &other.b;
|
||||
let c_c = &self.c * &other.c;
|
||||
|
||||
Fp6 {
|
||||
a: ((&self.b + &self.c) * (&other.b + &other.c) - &b_b - &c_c) * P::non_residue() + &a_a,
|
||||
b: (&self.a + &self.b) * (&other.a + &other.b) - &a_a - &b_b + &c_c * P::non_residue(),
|
||||
c: (&self.a + &self.c) * (&other.a + &other.c) - &a_a + &b_b - &c_c,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn squared(&self) -> Self {
|
||||
let a = &self.a;
|
||||
let b = &self.b;
|
||||
let c = &self.c;
|
||||
|
||||
let s0 = a.squared();
|
||||
let ab = a * b;
|
||||
let s1 = &ab + &ab;
|
||||
let s2 = (a - b + c).squared();
|
||||
let bc = b * c;
|
||||
let s3 = &bc + &bc;
|
||||
let s4 = c.squared();
|
||||
|
||||
Fp6 {
|
||||
a: &s0 + &s3 * P::non_residue(),
|
||||
b: &s1 + &s4 * P::non_residue(),
|
||||
c: &s1 + &s2 + &s3 - &s0 - &s4,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn sub(&self, other: &Self) -> Self {
|
||||
Fp6 {
|
||||
a: &self.a - &other.a,
|
||||
b: &self.b - &other.b,
|
||||
c: &self.c - &other.c,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&self, other: &Self) -> Self {
|
||||
Fp6 {
|
||||
a: &self.a + &other.a,
|
||||
b: &self.b + &other.b,
|
||||
c: &self.c + &other.c,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Fp6Params> Fp6<P> {
|
||||
pub fn mul_by_nonresidue(&self, other: &Fq2) -> Fp6<P> {
|
||||
Fp6 {
|
||||
a: &self.c * other,
|
||||
b: self.a.clone(),
|
||||
c: self.b.clone(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, P: Fp6Params> Mul<&'a Fq2> for &'b Fp6<P> {
|
||||
type Output = Fp6<P>;
|
||||
|
||||
fn mul(self, other: &Fq2) -> Fp6<P> {
|
||||
Fp6 {
|
||||
a: &self.a * other,
|
||||
b: &self.b * other,
|
||||
c: &self.c * other,
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forward_ops_to_field_ops!(impl(P: Fp6Params) Fp6<P>);
|
||||
@@ -0,0 +1,128 @@
|
||||
use fields::{FieldElement, const_fp, Fq};
|
||||
use std::ops::{Add, Sub, Mul, Neg};
|
||||
use rand::Rng;
|
||||
|
||||
#[inline]
|
||||
fn non_residue() -> Fq {
|
||||
// (q - 1) is a quadratic nonresidue in Fq
|
||||
// 21888242871839275222246405745257275088696311157297823662689037894645226208582
|
||||
const_fp([317583274, 1757628553, 1923792719, 2366144360, 151523889, 1373741639, 1193918714, 576313009])
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Fq2 {
|
||||
c0: Fq,
|
||||
c1: Fq
|
||||
}
|
||||
|
||||
impl Fq2 {
|
||||
pub fn new(c0: Fq, c1: Fq) -> Self {
|
||||
Fq2 {
|
||||
c0: c0,
|
||||
c1: c1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldElement for Fq2 {
|
||||
fn zero() -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::one(),
|
||||
c1: Fq::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn random<R: Rng>(rng: &mut R) -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::random(rng),
|
||||
c1: Fq::random(rng)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero()
|
||||
}
|
||||
|
||||
fn squared(&self) -> Self {
|
||||
// Devegili OhEig Scott Dahab
|
||||
// Multiplication and Squaring on Pairing-Friendly Fields.pdf
|
||||
// Section 3 (Complex squaring)
|
||||
|
||||
let ab = self.c0 * self.c1;
|
||||
|
||||
Fq2 {
|
||||
c0: (self.c1 * non_residue() + self.c0) * (self.c0 + self.c1) - ab - ab * non_residue(),
|
||||
c1: ab + ab
|
||||
}
|
||||
}
|
||||
|
||||
fn inverse(self) -> Self {
|
||||
// "High-Speed Software Implementation of the Optimal Ate Pairing
|
||||
// over Barreto–Naehrig Curves"; Algorithm 8
|
||||
|
||||
let t = (self.c0.squared() - (self.c1.squared() * non_residue())).inverse();
|
||||
|
||||
Fq2 {
|
||||
c0: self.c0 * t,
|
||||
c1: -(self.c1 * t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Fq2 {
|
||||
type Output = Fq2;
|
||||
|
||||
fn mul(self, other: Fq2) -> Fq2 {
|
||||
// Devegili OhEig Scott Dahab
|
||||
// Multiplication and Squaring on Pairing-Friendly Fields.pdf
|
||||
// Section 3 (Karatsuba)
|
||||
|
||||
let aa = self.c0 * other.c0;
|
||||
let bb = self.c1 * other.c1;
|
||||
|
||||
Fq2 {
|
||||
c0: bb * non_residue() + aa,
|
||||
c1: (self.c0 + self.c1) * (other.c0 + other.c1) - aa - bb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Fq2 {
|
||||
type Output = Fq2;
|
||||
|
||||
fn sub(self, other: Fq2) -> Fq2 {
|
||||
Fq2 {
|
||||
c0: self.c0 - other.c0,
|
||||
c1: self.c1 - other.c1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Fq2 {
|
||||
type Output = Fq2;
|
||||
|
||||
fn add(self, other: Fq2) -> Fq2 {
|
||||
Fq2 {
|
||||
c0: self.c0 + other.c0,
|
||||
c1: self.c1 + other.c1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Fq2 {
|
||||
type Output = Fq2;
|
||||
|
||||
fn neg(self) -> Fq2 {
|
||||
Fq2 {
|
||||
c0: -self.c0,
|
||||
c1: -self.c1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
macro_rules! forward_val_val_binop {
|
||||
(impl($($t:ident: $p:ident),*) $imp:ident for $res:ty, $method:ident) => {
|
||||
impl<$($t: $p),*> $imp<$res> for $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn $method(self, other: $res) -> $res {
|
||||
$imp::$method(&self, &other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_ref_val_binop {
|
||||
(impl($($t:ident: $p:ident),*) $imp:ident for $res:ty, $method:ident) => {
|
||||
impl<'a, $($t: $p),*> $imp<$res> for &'a $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn $method(self, other: $res) -> $res {
|
||||
$imp::$method(self, &other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_val_ref_binop {
|
||||
(impl($($t:ident: $p:ident),*) $imp:ident for $res:ty, $method:ident) => {
|
||||
impl<'a, $($t: $p),*> $imp<&'a $res> for $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn $method(self, other: &$res) -> $res {
|
||||
$imp::$method(&self, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_all_binop_to_ref_ref {
|
||||
(impl($($t:ident: $p:ident),*) $imp:ident for $res:ty, $method:ident) => {
|
||||
forward_val_val_binop!(impl($($t: $p),*) $imp for $res, $method);
|
||||
forward_ref_val_binop!(impl($($t: $p),*) $imp for $res, $method);
|
||||
forward_val_ref_binop!(impl($($t: $p),*) $imp for $res, $method);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_ops_to_field_ops {
|
||||
(impl($($t:ident: $p:ident),*) $res:ty) => {
|
||||
impl<'a, 'b, $($t: $p),*> Add<&'a $res> for &'b $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn add(self, other: &'a $res) -> $res {
|
||||
Field::add(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, $($t: $p),*> Sub<&'a $res> for &'b $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, other: &'a $res) -> $res {
|
||||
Field::sub(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, $($t: $p),*> Mul<&'a $res> for &'b $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, other: &'a $res) -> $res {
|
||||
Field::mul(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t: $p),*> Neg for &'a $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> $res {
|
||||
Field::neg(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($t: $p),*> Neg for $res {
|
||||
type Output = $res;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> $res {
|
||||
Field::neg(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($t: $p),*> PartialEq for $res {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Field::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($t: $p),*> Eq for $res {}
|
||||
|
||||
forward_all_binop_to_ref_ref!(impl($($t: $p),*) Add for $res, add);
|
||||
forward_all_binop_to_ref_ref!(impl($($t: $p),*) Sub for $res, sub);
|
||||
forward_all_binop_to_ref_ref!(impl($($t: $p),*) Mul for $res, mul);
|
||||
}
|
||||
}
|
||||
+79
-38
@@ -1,54 +1,95 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
pub mod fp;
|
||||
pub mod fp2;
|
||||
pub mod fp6;
|
||||
pub mod fp12;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
mod fp;
|
||||
mod fq2;
|
||||
|
||||
use arith::U256;
|
||||
use rand::Rng;
|
||||
use self::fp::{Fp, PrimeFieldParams};
|
||||
use std::ops::{Add, Sub, Mul, Neg};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Field: Sized + Clone + Debug {
|
||||
pub use self::fp::{Fq,Fr,const_fp};
|
||||
pub use self::fq2::Fq2;
|
||||
|
||||
pub trait FieldElement: Sized
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Add<Output=Self>
|
||||
+ Sub<Output=Self>
|
||||
+ Mul<Output=Self>
|
||||
+ Neg<Output=Self>
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ Debug
|
||||
{
|
||||
fn zero() -> Self;
|
||||
fn one() -> Self;
|
||||
fn random<R: Rng>(rng: &mut R) -> Self;
|
||||
fn is_zero(&self) -> bool {
|
||||
self.eq(&Self::zero())
|
||||
}
|
||||
fn inverse(&self) -> Self;
|
||||
fn random<R: Rng>(&mut R) -> Self;
|
||||
fn is_zero(&self) -> bool;
|
||||
fn squared(&self) -> Self {
|
||||
self.mul(self)
|
||||
(*self) * (*self)
|
||||
}
|
||||
fn pow<P: PrimeFieldParams>(&self, exp: &Fp<P>) -> Self {
|
||||
fn inverse(self) -> Self;
|
||||
fn pow<I: Into<U256>>(&self, by: I) -> Self {
|
||||
let mut res = Self::one();
|
||||
|
||||
let mut found_one = false;
|
||||
|
||||
for i in (0..P::bits()).rev() {
|
||||
if found_one {
|
||||
res = res.squared();
|
||||
}
|
||||
|
||||
if exp.test_bit(i) {
|
||||
found_one = true;
|
||||
res = self.mul(&res);
|
||||
for i in by.into().bits() {
|
||||
res = res.squared();
|
||||
if i {
|
||||
res = *self * res;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool;
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
|
||||
fn neg(&self) -> Self;
|
||||
fn mul(&self, other: &Self) -> Self;
|
||||
fn sub(&self, other: &Self) -> Self;
|
||||
fn add(&self, other: &Self) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[test]
|
||||
fn test_fr() {
|
||||
tests::field_trials::<Fr>();
|
||||
|
||||
assert_eq!(
|
||||
const_fp::<self::fp::FrParams, _>([0xf0000000, 0x43e1f593, 0x79b97091, 0x2833e848, 0x8181585d, 0xb85045b6, 0xe131a029, 0x30644e72]).inverse(),
|
||||
const_fp::<self::fp::FrParams, _>([1105105498, 673779534, 2522683054, 3560287638, 767940567, 738640505, 1642290052, 776830401])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq() {
|
||||
tests::field_trials::<Fq>();
|
||||
|
||||
assert_eq!(
|
||||
const_fp::<self::fp::FqParams, _>([0xd87cfd46, 0x3c208c16, 0x6871ca8d, 0x97816a91, 0x8181585d, 0xb85045b6, 0xe131a029, 0x30644e72]).inverse(),
|
||||
const_fp::<self::fp::FqParams, _>([2230452926, 1223921595, 2485962897, 3784987007, 2000672870, 1889871543, 377056010, 697020161])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2() {
|
||||
tests::field_trials::<Fq2>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_str() {
|
||||
assert_eq!(-Fr::one(), Fr::from_str("21888242871839275222246405745257275088548364400416034343698204186575808495616").unwrap());
|
||||
assert_eq!(-Fq::one(), Fq::from_str("21888242871839275222246405745257275088696311157297823662689037894645226208582").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fr_squaring() {
|
||||
// Test vector.
|
||||
assert_eq!(
|
||||
Fr::from_str("21888242871839275222246405745257275088548364400416034343698204186575808495610").unwrap().pow([0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]),
|
||||
const_fp([2572677806, 4136501712, 2816341579, 1079830324, 2386666211, 2796237710, 2115470140, 673230670])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_squaring() {
|
||||
// Test vector
|
||||
assert_eq!(
|
||||
Fq::from_str("21888242871839275222246405745257275088696311157297823662689037894645226208540").unwrap().pow([0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff]),
|
||||
const_fp([1128196772, 3636718463, 2555618142, 559034227, 1481851987, 3987127805, 2583602581, 88292310])
|
||||
);
|
||||
}
|
||||
|
||||
+45
-143
@@ -1,181 +1,81 @@
|
||||
use rand::{Rng,SeedableRng,StdRng};
|
||||
use fields::Field;
|
||||
use super::FieldElement;
|
||||
|
||||
mod large_field {
|
||||
use fields::fp::*;
|
||||
use num::{BigUint, Num};
|
||||
|
||||
struct Large;
|
||||
|
||||
impl PrimeFieldParams for Large {
|
||||
fn modulus() -> BigUint {
|
||||
BigUint::from_str_radix("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10).unwrap()
|
||||
}
|
||||
|
||||
fn bits() -> usize { 254 }
|
||||
fn name() -> &'static str { "Large" }
|
||||
}
|
||||
|
||||
type Ft = Fp<Large>;
|
||||
|
||||
#[test]
|
||||
fn bit_testing() {
|
||||
let a = Ft::from("13");
|
||||
assert!(a.test_bit(0) == true);
|
||||
assert!(a.test_bit(1) == false);
|
||||
assert!(a.test_bit(2) == true);
|
||||
assert!(a.test_bit(3) == true);
|
||||
|
||||
let expected: Vec<bool> = [1,1,0,1,1,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1]
|
||||
.iter().map(|a| *a == 1).rev().collect();
|
||||
|
||||
let a = Ft::from("453624211");
|
||||
|
||||
for (i, b) in expected.into_iter().enumerate() {
|
||||
assert!(a.test_bit(i) == b);
|
||||
}
|
||||
|
||||
let expected: Vec<bool> = [1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,0,0,1,0,1,1,0,0]
|
||||
.iter().map(|a| *a == 1).rev().collect();
|
||||
let a = Ft::from("13888242871869275222244405745257275088696211157297823662689037894645226208556");
|
||||
|
||||
for (i, b) in expected.into_iter().enumerate() {
|
||||
assert!(a.test_bit(i) == b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod small_field {
|
||||
use fields::fp::*;
|
||||
use fields::Field;
|
||||
use num::{BigUint, Num};
|
||||
|
||||
struct Small;
|
||||
|
||||
impl PrimeFieldParams for Small {
|
||||
fn modulus() -> BigUint {
|
||||
BigUint::from_str_radix("13", 10).unwrap()
|
||||
}
|
||||
|
||||
fn bits() -> usize { 6 }
|
||||
fn name() -> &'static str { "Small" }
|
||||
}
|
||||
|
||||
type Ft = Fp<Small>;
|
||||
|
||||
#[test]
|
||||
fn field_ops() {
|
||||
fn test_field_operation<C: Fn(&Ft, &Ft) -> Ft>(a: u64, b: u64, f: C, expected: u64) {
|
||||
let af = Ft::from(format!("{}", a).as_ref());
|
||||
let bf = Ft::from(format!("{}", b).as_ref());
|
||||
let expectedf = Ft::from(format!("{}", expected).as_ref());
|
||||
|
||||
let res = f(&af, &bf);
|
||||
|
||||
if res != expectedf {
|
||||
panic!("res={:?} != expectedf={:?} (a={}, b={}, expected={})", res, expectedf, a, b, expected);
|
||||
}
|
||||
}
|
||||
|
||||
const MODULO: u64 = 13;
|
||||
|
||||
for a in 0..13u64 {
|
||||
for b in 0..13u64 {
|
||||
test_field_operation(a, b, |a,b| {a * b}, (a*b)%MODULO);
|
||||
test_field_operation(a, b, |a,b| {a + b}, (a+b)%MODULO);
|
||||
test_field_operation(a, b, |a,b| {a - b}, {
|
||||
let mut tmp = (a as i64) - (b as i64);
|
||||
if tmp < 0 {
|
||||
tmp += MODULO as i64;
|
||||
}
|
||||
|
||||
tmp as u64
|
||||
});
|
||||
test_field_operation(a, b, |a,b| {a.pow(b)}, (a.pow(b as u32))%MODULO);
|
||||
}
|
||||
test_field_operation(a, 0, |a,_| {-a}, if a == 0 { 0 } else { MODULO - a });
|
||||
if a > 0 {
|
||||
test_field_operation(a, 0, |a,_| {&a.inverse() * a}, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn can_invert<F: Field>() {
|
||||
fn can_invert<F: FieldElement>() {
|
||||
let mut a = F::one();
|
||||
for _ in 0..1000 {
|
||||
assert!(a.ne(&F::zero()));
|
||||
|
||||
let inv = a.inverse();
|
||||
for _ in 0..10000 {
|
||||
assert_eq!(a * a.inverse(), F::one());
|
||||
|
||||
assert!(a.mul(&inv).eq(&F::one()));
|
||||
a = a + F::one();
|
||||
}
|
||||
|
||||
a = a.add(&F::one());
|
||||
a = -F::one();
|
||||
for _ in 0..10000 {
|
||||
assert_eq!(a * a.inverse(), F::one());
|
||||
|
||||
a = a - F::one();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn rand_element_squaring<F: Field, R: Rng>(rng: &mut R) {
|
||||
fn rand_element_squaring<F: FieldElement, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..100 {
|
||||
let a = F::random(rng);
|
||||
|
||||
let mul = a.mul(&a);
|
||||
let sq = a.squared();
|
||||
|
||||
assert!(sq.eq(&mul));
|
||||
assert!(a * a == a.squared());
|
||||
}
|
||||
|
||||
let mut cur = F::zero();
|
||||
for _ in 0..100 {
|
||||
let mul = cur.mul(&cur);
|
||||
let sq = cur.squared();
|
||||
assert_eq!(cur.squared(), cur * cur);
|
||||
|
||||
assert!(sq.eq(&mul));
|
||||
|
||||
cur = cur.add(&F::one());
|
||||
cur = cur + F::one();
|
||||
}
|
||||
}
|
||||
|
||||
fn rand_element_addition_and_negation<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10 {
|
||||
fn rand_element_addition_and_negation<F: FieldElement, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..100 {
|
||||
let mut a = F::random(rng);
|
||||
let r = F::random(rng);
|
||||
let mut b = a.add(&r);
|
||||
let mut b = a + r;
|
||||
|
||||
for _ in 0..10 {
|
||||
let r = F::random(rng);
|
||||
a = a.add(&r);
|
||||
b = b.add(&r);
|
||||
a = a + r;
|
||||
b = b + r;
|
||||
|
||||
let r = F::random(rng);
|
||||
a = a.sub(&r);
|
||||
b = b.sub(&r);
|
||||
a = a - r;
|
||||
b = b - r;
|
||||
|
||||
let r = F::random(rng);
|
||||
a = a.add(&r);
|
||||
b = b.add(&r);
|
||||
a = a + (-(-r));
|
||||
b = b + (-(-r));
|
||||
|
||||
let r = F::random(rng);
|
||||
a = a - r;
|
||||
b = b + (-r);
|
||||
|
||||
let r = F::random(rng);
|
||||
a = a + (-r);
|
||||
b = b - r;
|
||||
}
|
||||
|
||||
b = b.sub(&r);
|
||||
assert!(a.eq(&b));
|
||||
b = b - r;
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn rand_element_inverse<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..100 {
|
||||
let mut n = F::random(rng);
|
||||
n = n.inverse().mul(&n);
|
||||
assert!(n.eq(&F::one()));
|
||||
}
|
||||
for _ in 0..100 {
|
||||
fn rand_element_inverse<F: FieldElement, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::random(rng);
|
||||
assert!(a.inverse() * a == F::one());
|
||||
let b = F::random(rng);
|
||||
assert!(a.mul(&b).mul(&a.inverse()).eq(&b));
|
||||
assert_eq!((a * b) * (a.inverse()), b);
|
||||
}
|
||||
}
|
||||
|
||||
fn rand_element_multiplication<F: Field, R: Rng>(rng: &mut R) {
|
||||
fn rand_element_multiplication<F: FieldElement, R: Rng>(rng: &mut R) {
|
||||
// If field is not associative under multiplication, 1/8 of all triplets a, b, c
|
||||
// will fail the test (a*b)*c = a*(b*c).
|
||||
|
||||
@@ -184,13 +84,17 @@ fn rand_element_multiplication<F: Field, R: Rng>(rng: &mut R) {
|
||||
let b = F::random(rng);
|
||||
let c = F::random(rng);
|
||||
|
||||
assert!(a.mul(&b).mul(&c).eq(&b.mul(&c).mul(&a)));
|
||||
assert_eq!((a * b) * c, a * (b * c));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_trials<F: Field>() {
|
||||
pub fn field_trials<F: FieldElement>() {
|
||||
can_invert::<F>();
|
||||
|
||||
assert_eq!(-F::zero(), F::zero());
|
||||
assert_eq!(-F::one() + F::one(), F::zero());
|
||||
assert_eq!(F::zero() - F::zero(), F::zero());
|
||||
|
||||
let seed: [usize; 4] = [103245, 191922, 1293, 192103];
|
||||
let mut rng = StdRng::from_seed(&seed);
|
||||
|
||||
@@ -199,5 +103,3 @@ pub fn field_trials<F: Field>() {
|
||||
rand_element_multiplication::<F, StdRng>(&mut rng);
|
||||
rand_element_inverse::<F, StdRng>(&mut rng);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user