mirror of
https://github.com/arnaucube/ark-curves-cherry-picked.git
synced 2026-01-11 08:21:33 +01:00
Initial commit
This commit is contained in:
96
bn254/src/fields/fq.rs
Normal file
96
bn254/src/fields/fq.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use ark_ff::{biginteger::BigInteger256 as BigInteger, field_new, fields::*};
|
||||
|
||||
pub type Fq = Fp256<FqParameters>;
|
||||
|
||||
pub struct FqParameters;
|
||||
|
||||
impl Fp256Parameters for FqParameters {}
|
||||
impl FftParameters for FqParameters {
|
||||
type BigInt = BigInteger;
|
||||
|
||||
const TWO_ADICITY: u32 = 1;
|
||||
|
||||
#[rustfmt::skip]
|
||||
const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([
|
||||
0x68c3488912edefaa,
|
||||
0x8d087f6872aabf4f,
|
||||
0x51e1a24709081231,
|
||||
0x2259d6b14729c0fa,
|
||||
]);
|
||||
}
|
||||
impl FpParameters for FqParameters {
|
||||
/// MODULUS = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177
|
||||
#[rustfmt::skip]
|
||||
const MODULUS: BigInteger = BigInteger([
|
||||
0x3c208c16d87cfd47,
|
||||
0x97816a916871ca8d,
|
||||
0xb85045b68181585d,
|
||||
0x30644e72e131a029,
|
||||
]);
|
||||
|
||||
const MODULUS_BITS: u32 = 254;
|
||||
|
||||
const CAPACITY: u32 = Self::MODULUS_BITS - 1;
|
||||
|
||||
const REPR_SHAVE_BITS: u32 = 2;
|
||||
|
||||
#[rustfmt::skip]
|
||||
const R: BigInteger = BigInteger([
|
||||
0xd35d438dc58f0d9d,
|
||||
0x0a78eb28f5c70b3d,
|
||||
0x666ea36f7879462c,
|
||||
0xe0a77c19a07df2f,
|
||||
]);
|
||||
|
||||
#[rustfmt::skip]
|
||||
const R2: BigInteger = BigInteger([
|
||||
0xf32cfc5b538afa89,
|
||||
0xb5e71911d44501fb,
|
||||
0x47ab1eff0a417ff6,
|
||||
0x6d89f71cab8351f,
|
||||
]);
|
||||
|
||||
const INV: u64 = 9786893198990664585u64;
|
||||
|
||||
// GENERATOR = 3
|
||||
#[rustfmt::skip]
|
||||
const GENERATOR: BigInteger = BigInteger([
|
||||
0x7a17caa950ad28d7,
|
||||
0x1f6ac17ae15521b9,
|
||||
0x334bea4e696bd284,
|
||||
0x2a1f6744ce179d8e,
|
||||
]);
|
||||
|
||||
#[rustfmt::skip]
|
||||
const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([
|
||||
0x9e10460b6c3e7ea3,
|
||||
0xcbc0b548b438e546,
|
||||
0xdc2822db40c0ac2e,
|
||||
0x183227397098d014,
|
||||
]);
|
||||
|
||||
// T and T_MINUS_ONE_DIV_TWO, where MODULUS - 1 = 2^S * T
|
||||
|
||||
// T = (MODULUS - 1) // 2^S =
|
||||
// 10944121435919637611123202872628637544348155578648911831344518947322613104291
|
||||
#[rustfmt::skip]
|
||||
const T: BigInteger = BigInteger([
|
||||
0x9e10460b6c3e7ea3,
|
||||
0xcbc0b548b438e546,
|
||||
0xdc2822db40c0ac2e,
|
||||
0x183227397098d014,
|
||||
]);
|
||||
|
||||
// (T - 1) // 2 =
|
||||
// 1837921289030710838195067919506396475074392872918698035817074744121558668640693829665401097909504529
|
||||
#[rustfmt::skip]
|
||||
const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([
|
||||
0x4f082305b61f3f51,
|
||||
0x65e05aa45a1c72a3,
|
||||
0x6e14116da0605617,
|
||||
0xc19139cb84c680a,
|
||||
]);
|
||||
}
|
||||
|
||||
pub const FQ_ONE: Fq = field_new!(Fq, FqParameters::R);
|
||||
pub const FQ_ZERO: Fq = field_new!(Fq, BigInteger([0, 0, 0, 0]));
|
||||
159
bn254/src/fields/fq12.rs
Normal file
159
bn254/src/fields/fq12.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use super::*;
|
||||
use ark_ff::{biginteger::BigInteger256, field_new, fields::*};
|
||||
|
||||
pub type Fq12 = Fp12<Fq12Parameters>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Fq12Parameters;
|
||||
|
||||
impl Fp12Parameters for Fq12Parameters {
|
||||
type Fp6Params = Fq6Parameters;
|
||||
|
||||
const NONRESIDUE: Fq6 = field_new!(Fq6, FQ2_ZERO, FQ2_ONE, FQ2_ZERO);
|
||||
|
||||
#[rustfmt::skip]
|
||||
const FROBENIUS_COEFF_FP12_C1: &'static [Fq2] = &[
|
||||
// Fp2::NONRESIDUE^(((q^0) - 1) / 6)
|
||||
FQ2_ONE,
|
||||
// Fp2::NONRESIDUE^(((q^1) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xaf9ba69633144907,
|
||||
0xca6b1d7387afb78a,
|
||||
0x11bded5ef08a2087,
|
||||
0x02f34d751a1f3a7c,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xa222ae234c492d72,
|
||||
0xd00f02a4565de15b,
|
||||
0xdc2ff3a253dfc926,
|
||||
0x10a75716b3899551,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^2) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xca8d800500fa1bf2,
|
||||
0xf0c5d61468b39769,
|
||||
0x0e201271ad0d4418,
|
||||
0x04290f65bad856e6,
|
||||
])),
|
||||
FQ_ZERO,
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^3) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x365316184e46d97d,
|
||||
0x0af7129ed4c96d9f,
|
||||
0x659da72fca1009b5,
|
||||
0x08116d8983a20d23,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xb1df4af7c39c1939,
|
||||
0x3d9f02878a73bf7f,
|
||||
0x9b2220928caf0ae0,
|
||||
0x26684515eff054a6,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^4) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x3350c88e13e80b9c,
|
||||
0x7dce557cdb5e56b9,
|
||||
0x6001b4b8b615564a,
|
||||
0x2682e617020217e0,
|
||||
])),
|
||||
FQ_ZERO,
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^5) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x86b76f821b329076,
|
||||
0x408bf52b4d19b614,
|
||||
0x53dfb9d0d985e92d,
|
||||
0x051e20146982d2a7,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x0fbc9cd47752ebc7,
|
||||
0x6d8fffe33415de24,
|
||||
0xbef22cf038cf41b9,
|
||||
0x15c0edff3c66bf54,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^6) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x68c3488912edefaa,
|
||||
0x8d087f6872aabf4f,
|
||||
0x51e1a24709081231,
|
||||
0x2259d6b14729c0fa,
|
||||
])),
|
||||
FQ_ZERO,
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^7) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x8c84e580a568b440,
|
||||
0xcd164d1de0c21302,
|
||||
0xa692585790f737d5,
|
||||
0x2d7100fdc71265ad,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x99fdddf38c33cfd5,
|
||||
0xc77267ed1213e931,
|
||||
0xdc2052142da18f36,
|
||||
0x1fbcf75c2da80ad7,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^8) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x71930c11d782e155,
|
||||
0xa6bb947cffbe3323,
|
||||
0xaa303344d4741444,
|
||||
0x2c3b3f0d26594943,
|
||||
])),
|
||||
FQ_ZERO,
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^9) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x05cd75fe8a3623ca,
|
||||
0x8c8a57f293a85cee,
|
||||
0x52b29e86b7714ea8,
|
||||
0x2852e0e95d8f9306,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x8a41411f14e0e40e,
|
||||
0x59e26809ddfe0b0d,
|
||||
0x1d2e2523f4d24d7d,
|
||||
0x09fc095cf1414b83,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^10) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x08cfc388c494f1ab,
|
||||
0x19b315148d1373d4,
|
||||
0x584e90fdcb6c0213,
|
||||
0x09e1685bdf2f8849,
|
||||
])),
|
||||
FQ_ZERO,
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^11) - 1) / 6)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xb5691c94bd4a6cd1,
|
||||
0x56f575661b581478,
|
||||
0x64708be5a7fb6f30,
|
||||
0x2b462e5e77aecd82,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x2c63ef42612a1180,
|
||||
0x29f16aae345bec69,
|
||||
0xf95e18c648b216a4,
|
||||
0x1aa36073a4cae0d4,
|
||||
])),
|
||||
),
|
||||
];
|
||||
}
|
||||
63
bn254/src/fields/fq2.rs
Normal file
63
bn254/src/fields/fq2.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use super::*;
|
||||
use ark_ff::{biginteger::BigInteger256 as BigInteger, field_new, fields::*};
|
||||
|
||||
pub type Fq2 = Fp2<Fq2Parameters>;
|
||||
|
||||
pub struct Fq2Parameters;
|
||||
|
||||
impl Fp2Parameters for Fq2Parameters {
|
||||
type Fp = Fq;
|
||||
|
||||
/// NONRESIDUE = -1
|
||||
#[rustfmt::skip]
|
||||
const NONRESIDUE: Fq = field_new!(Fq, BigInteger([
|
||||
0x68c3488912edefaa,
|
||||
0x8d087f6872aabf4f,
|
||||
0x51e1a24709081231,
|
||||
0x2259d6b14729c0fa,
|
||||
]));
|
||||
|
||||
/// QUADRATIC_NONRESIDUE = U+2
|
||||
#[rustfmt::skip]
|
||||
const QUADRATIC_NONRESIDUE: (Fq, Fq) = (
|
||||
field_new!(Fq, BigInteger([
|
||||
12014063508332092218u64,
|
||||
1509222997478479483u64,
|
||||
14762033076929465432u64,
|
||||
2023505479389396574u64,
|
||||
])),
|
||||
field_new!(Fq, BigInteger([
|
||||
202099033278250856u64,
|
||||
8885205928937022213u64,
|
||||
5545221690922665192u64,
|
||||
39800542322357402u64,
|
||||
])),
|
||||
);
|
||||
|
||||
/// Coefficients for the Frobenius automorphism.
|
||||
#[rustfmt::skip]
|
||||
const FROBENIUS_COEFF_FP2_C1: &'static [Fq] = &[
|
||||
// NONRESIDUE**(((q^0) - 1) / 2)
|
||||
field_new!(Fq, BigInteger([
|
||||
0xd35d438dc58f0d9d,
|
||||
0x0a78eb28f5c70b3d,
|
||||
0x666ea36f7879462c,
|
||||
0xe0a77c19a07df2f,
|
||||
])),
|
||||
// NONRESIDUE**(((q^1) - 1) / 2)
|
||||
field_new!(Fq, BigInteger([
|
||||
0x68c3488912edefaa,
|
||||
0x8d087f6872aabf4f,
|
||||
0x51e1a24709081231,
|
||||
0x2259d6b14729c0fa,
|
||||
])),
|
||||
];
|
||||
|
||||
#[inline(always)]
|
||||
fn mul_fp_by_nonresidue(fe: &Self::Fp) -> Self::Fp {
|
||||
-(*fe)
|
||||
}
|
||||
}
|
||||
|
||||
pub const FQ2_ZERO: Fq2 = field_new!(Fq2, FQ_ZERO, FQ_ZERO);
|
||||
pub const FQ2_ONE: Fq2 = field_new!(Fq2, FQ_ONE, FQ_ZERO);
|
||||
195
bn254/src/fields/fq6.rs
Normal file
195
bn254/src/fields/fq6.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use super::*;
|
||||
use ark_ff::{biginteger::BigInteger256, field_new, fields::*};
|
||||
|
||||
pub type Fq6 = Fp6<Fq6Parameters>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Fq6Parameters;
|
||||
|
||||
impl Fp6Parameters for Fq6Parameters {
|
||||
type Fp2Params = Fq2Parameters;
|
||||
|
||||
/// NONRESIDUE = U+9
|
||||
#[rustfmt::skip]
|
||||
const NONRESIDUE: Fq2 = field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xf60647ce410d7ff7,
|
||||
0x2f3d6f4dd31bd011,
|
||||
0x2943337e3940c6d1,
|
||||
0x1d9598e8a7e39857,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
202099033278250856u64,
|
||||
8885205928937022213u64,
|
||||
5545221690922665192u64,
|
||||
39800542322357402u64,
|
||||
])),
|
||||
);
|
||||
|
||||
#[rustfmt::skip]
|
||||
const FROBENIUS_COEFF_FP6_C1: &'static [Fq2] = &[
|
||||
// Fp2::NONRESIDUE^(((q^0) - 1) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xd35d438dc58f0d9d,
|
||||
0x0a78eb28f5c70b3d,
|
||||
0x666ea36f7879462c,
|
||||
0xe0a77c19a07df2f,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^1) - 1) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xb5773b104563ab30,
|
||||
0x347f91c8a9aa6454,
|
||||
0x7a007127242e0991,
|
||||
0x1956bcd8118214ec,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x6e849f1ea0aa4757,
|
||||
0xaa1c7b6d89f89141,
|
||||
0xb6e713cdfae0ca3a,
|
||||
0x26694fbb4e82ebc3,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^2) - 1) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x3350c88e13e80b9c,
|
||||
0x7dce557cdb5e56b9,
|
||||
0x6001b4b8b615564a,
|
||||
0x2682e617020217e0,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^3) - 1) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xc9af22f716ad6bad,
|
||||
0xb311782a4aa662b2,
|
||||
0x19eeaf64e248c7f4,
|
||||
0x20273e77e3439f82,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xacc02860f7ce93ac,
|
||||
0x3933d5817ba76b4c,
|
||||
0x69e6188b446c8467,
|
||||
0xa46036d4417cc55,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^4) - 1) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x71930c11d782e155,
|
||||
0xa6bb947cffbe3323,
|
||||
0xaa303344d4741444,
|
||||
0x2c3b3f0d26594943,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^(((q^5) - 1) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xf91aba2654e8e3b1,
|
||||
0x4771cb2fdc92ce12,
|
||||
0xdcb16ae0fc8bdf35,
|
||||
0x274aa195cd9d8be4,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x5cfc50ae18811f8b,
|
||||
0x4bb28433cb43988c,
|
||||
0x4fd35f13c3b56219,
|
||||
0x301949bd2fc8883a,
|
||||
])),
|
||||
),
|
||||
];
|
||||
#[rustfmt::skip]
|
||||
const FROBENIUS_COEFF_FP6_C2: &'static [Fq2] = &[
|
||||
// Fp2::NONRESIDUE^((2*(q^0) - 2) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xd35d438dc58f0d9d,
|
||||
0x0a78eb28f5c70b3d,
|
||||
0x666ea36f7879462c,
|
||||
0xe0a77c19a07df2f,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^((2*(q^1) - 2) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x7361d77f843abe92,
|
||||
0xa5bb2bd3273411fb,
|
||||
0x9c941f314b3e2399,
|
||||
0x15df9cddbb9fd3ec,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x5dddfd154bd8c949,
|
||||
0x62cb29a5a4445b60,
|
||||
0x37bc870a0c7dd2b9,
|
||||
0x24830a9d3171f0fd,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^((2*(q^2) - 2) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x71930c11d782e155,
|
||||
0xa6bb947cffbe3323,
|
||||
0xaa303344d4741444,
|
||||
0x2c3b3f0d26594943,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^((2*(q^3) - 2) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x448a93a57b6762df,
|
||||
0xbfd62df528fdeadf,
|
||||
0xd858f5d00e9bd47a,
|
||||
0x6b03d4d3476ec58,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x2b19daf4bcc936d1,
|
||||
0xa1a54e7a56f4299f,
|
||||
0xb533eee05adeaef1,
|
||||
0x170c812b84dda0b2,
|
||||
])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^((2*(q^4) - 2) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x3350c88e13e80b9c,
|
||||
0x7dce557cdb5e56b9,
|
||||
0x6001b4b8b615564a,
|
||||
0x2682e617020217e0,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([0x0, 0x0, 0x0, 0x0])),
|
||||
),
|
||||
// Fp2::NONRESIDUE^((2*(q^5) - 2) / 3)
|
||||
field_new!(Fq2,
|
||||
field_new!(Fq, BigInteger256([
|
||||
0x843420f1d8dadbd6,
|
||||
0x31f010c9183fcdb2,
|
||||
0x436330b527a76049,
|
||||
0x13d47447f11adfe4,
|
||||
])),
|
||||
field_new!(Fq, BigInteger256([
|
||||
0xef494023a857fa74,
|
||||
0x2a925d02d5ab101a,
|
||||
0x83b015829ba62f10,
|
||||
0x2539111d0c13aea3,
|
||||
])),
|
||||
),
|
||||
];
|
||||
|
||||
#[inline(always)]
|
||||
fn mul_fp2_by_nonresidue(fe: &Fq2) -> Fq2 {
|
||||
// (c0+u*c1)*(9+u) = (9*c0-c1)+u*(9*c1+c0)
|
||||
let mut f = *fe;
|
||||
f.double_in_place().double_in_place().double_in_place();
|
||||
let c0 = f.c0 + fe.c0 + Fq2Parameters::mul_fp_by_nonresidue(&fe.c1);
|
||||
let c1 = f.c1 + fe.c1 + fe.c0;
|
||||
field_new!(Fq2, c0, c1)
|
||||
}
|
||||
}
|
||||
95
bn254/src/fields/fr.rs
Normal file
95
bn254/src/fields/fr.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use ark_ff::{biginteger::BigInteger256 as BigInteger, fields::*};
|
||||
|
||||
pub type Fr = Fp256<FrParameters>;
|
||||
|
||||
pub struct FrParameters;
|
||||
|
||||
impl Fp256Parameters for FrParameters {}
|
||||
impl FftParameters for FrParameters {
|
||||
type BigInt = BigInteger;
|
||||
|
||||
const TWO_ADICITY: u32 = 28;
|
||||
|
||||
#[rustfmt::skip]
|
||||
const TWO_ADIC_ROOT_OF_UNITY: BigInteger = BigInteger([
|
||||
7164790868263648668u64,
|
||||
11685701338293206998u64,
|
||||
6216421865291908056u64,
|
||||
1756667274303109607u64,
|
||||
]);
|
||||
}
|
||||
impl FpParameters for FrParameters {
|
||||
/// MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617
|
||||
#[rustfmt::skip]
|
||||
const MODULUS: BigInteger = BigInteger([
|
||||
4891460686036598785u64,
|
||||
2896914383306846353u64,
|
||||
13281191951274694749u64,
|
||||
3486998266802970665u64,
|
||||
]);
|
||||
|
||||
const MODULUS_BITS: u32 = 254;
|
||||
|
||||
const CAPACITY: u32 = Self::MODULUS_BITS - 1;
|
||||
|
||||
const REPR_SHAVE_BITS: u32 = 2;
|
||||
|
||||
#[rustfmt::skip]
|
||||
const R: BigInteger = BigInteger([
|
||||
12436184717236109307u64,
|
||||
3962172157175319849u64,
|
||||
7381016538464732718u64,
|
||||
1011752739694698287u64,
|
||||
]);
|
||||
|
||||
#[rustfmt::skip]
|
||||
const R2: BigInteger = BigInteger([
|
||||
1997599621687373223u64,
|
||||
6052339484930628067u64,
|
||||
10108755138030829701u64,
|
||||
150537098327114917u64,
|
||||
]);
|
||||
|
||||
const INV: u64 = 14042775128853446655u64;
|
||||
|
||||
// GENERATOR = 5
|
||||
#[rustfmt::skip]
|
||||
const GENERATOR: BigInteger = BigInteger([
|
||||
1949230679015292902u64,
|
||||
16913946402569752895u64,
|
||||
5177146667339417225u64,
|
||||
1571765431670520771u64,
|
||||
]);
|
||||
|
||||
/// (r - 1)/2 =
|
||||
/// 10944121435919637611123202872628637544274182200208017171849102093287904247808
|
||||
#[rustfmt::skip]
|
||||
const MODULUS_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([
|
||||
0xa1f0fac9f8000000,
|
||||
0x9419f4243cdcb848,
|
||||
0xdc2822db40c0ac2e,
|
||||
0x183227397098d014,
|
||||
]);
|
||||
|
||||
// T and T_MINUS_ONE_DIV_TWO, where r - 1 = 2^s * t
|
||||
|
||||
/// t = (r - 1) / 2^s =
|
||||
/// 81540058820840996586704275553141814055101440848469862132140264610111
|
||||
#[rustfmt::skip]
|
||||
const T: BigInteger = BigInteger([
|
||||
0x9b9709143e1f593f,
|
||||
0x181585d2833e8487,
|
||||
0x131a029b85045b68,
|
||||
0x30644e72e,
|
||||
]);
|
||||
|
||||
/// (t - 1) / 2 =
|
||||
/// 40770029410420498293352137776570907027550720424234931066070132305055
|
||||
#[rustfmt::skip]
|
||||
const T_MINUS_ONE_DIV_TWO: BigInteger = BigInteger([
|
||||
0xcdcb848a1f0fac9f,
|
||||
0x0c0ac2e9419f4243,
|
||||
0x098d014dc2822db4,
|
||||
0x183227397,
|
||||
]);
|
||||
}
|
||||
27
bn254/src/fields/mod.rs
Normal file
27
bn254/src/fields/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
#[cfg(feature = "scalar_field")]
|
||||
pub mod fr;
|
||||
#[cfg(feature = "scalar_field")]
|
||||
pub use self::fr::*;
|
||||
|
||||
#[cfg(feature = "curve")]
|
||||
pub mod fq;
|
||||
#[cfg(feature = "curve")]
|
||||
pub use self::fq::*;
|
||||
|
||||
#[cfg(feature = "curve")]
|
||||
pub mod fq2;
|
||||
#[cfg(feature = "curve")]
|
||||
pub use self::fq2::*;
|
||||
|
||||
#[cfg(feature = "curve")]
|
||||
pub mod fq6;
|
||||
#[cfg(feature = "curve")]
|
||||
pub use self::fq6::*;
|
||||
|
||||
#[cfg(feature = "curve")]
|
||||
pub mod fq12;
|
||||
#[cfg(feature = "curve")]
|
||||
pub use self::fq12::*;
|
||||
|
||||
#[cfg(all(feature = "curve", test))]
|
||||
mod tests;
|
||||
504
bn254/src/fields/tests.rs
Normal file
504
bn254/src/fields/tests.rs
Normal file
@@ -0,0 +1,504 @@
|
||||
use ark_ff::{
|
||||
biginteger::{BigInteger, BigInteger256},
|
||||
fields::{
|
||||
fp6_3over2::Fp6Parameters, FftField, FftParameters, Field, FpParameters, PrimeField,
|
||||
SquareRootField,
|
||||
},
|
||||
test_rng, One, UniformRand, Zero,
|
||||
};
|
||||
use ark_serialize::{buffer_bit_byte_size, CanonicalSerialize};
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
ops::{AddAssign, MulAssign, SubAssign},
|
||||
};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
use crate::{Fq, Fq12, Fq2, Fq6, Fq6Parameters, FqParameters, Fr};
|
||||
use ark_curve_tests::fields::*;
|
||||
|
||||
pub(crate) const ITERATIONS: usize = 5;
|
||||
|
||||
#[test]
|
||||
fn test_fr() {
|
||||
let mut rng = test_rng();
|
||||
for _ in 0..ITERATIONS {
|
||||
let a: Fr = rng.gen();
|
||||
let b: Fr = rng.gen();
|
||||
field_test(a, b);
|
||||
primefield_test::<Fr>();
|
||||
sqrt_field_test(b);
|
||||
let byte_size = a.serialized_size();
|
||||
field_serialization_test::<Fr>(byte_size);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq() {
|
||||
let mut rng = test_rng();
|
||||
for _ in 0..ITERATIONS {
|
||||
let a: Fq = rng.gen();
|
||||
let b: Fq = rng.gen();
|
||||
field_test(a, b);
|
||||
primefield_test::<Fq>();
|
||||
sqrt_field_test(a);
|
||||
let byte_size = a.serialized_size();
|
||||
let (_, buffer_size) = buffer_bit_byte_size(Fq::size_in_bits());
|
||||
assert_eq!(byte_size, buffer_size);
|
||||
field_serialization_test::<Fq>(byte_size);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2() {
|
||||
let mut rng = test_rng();
|
||||
for _ in 0..ITERATIONS {
|
||||
let a: Fq2 = rng.gen();
|
||||
let b: Fq2 = rng.gen();
|
||||
field_test(a, b);
|
||||
sqrt_field_test(a);
|
||||
}
|
||||
frobenius_test::<Fq2, _>(Fq::characteristic(), 13);
|
||||
let byte_size = Fq2::zero().serialized_size();
|
||||
field_serialization_test::<Fq2>(byte_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq6() {
|
||||
let mut rng = test_rng();
|
||||
for _ in 0..ITERATIONS {
|
||||
let g: Fq6 = rng.gen();
|
||||
let h: Fq6 = rng.gen();
|
||||
field_test(g, h);
|
||||
}
|
||||
frobenius_test::<Fq6, _>(Fq::characteristic(), 13);
|
||||
let byte_size = Fq6::zero().serialized_size();
|
||||
field_serialization_test::<Fq6>(byte_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq12() {
|
||||
let mut rng = test_rng();
|
||||
for _ in 0..ITERATIONS {
|
||||
let g: Fq12 = rng.gen();
|
||||
let h: Fq12 = rng.gen();
|
||||
field_test(g, h);
|
||||
}
|
||||
frobenius_test::<Fq12, _>(Fq::characteristic(), 13);
|
||||
let byte_size = Fq12::zero().serialized_size();
|
||||
field_serialization_test::<Fq12>(byte_size);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_repr_from() {
|
||||
assert_eq!(BigInteger256::from(100), BigInteger256([100, 0, 0, 0]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_repr_is_odd() {
|
||||
assert!(!BigInteger256::from(0).is_odd());
|
||||
assert!(BigInteger256::from(0).is_even());
|
||||
assert!(BigInteger256::from(1).is_odd());
|
||||
assert!(!BigInteger256::from(1).is_even());
|
||||
assert!(!BigInteger256::from(324834872).is_odd());
|
||||
assert!(BigInteger256::from(324834872).is_even());
|
||||
assert!(BigInteger256::from(324834873).is_odd());
|
||||
assert!(!BigInteger256::from(324834873).is_even());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_repr_is_zero() {
|
||||
assert!(BigInteger256::from(0).is_zero());
|
||||
assert!(!BigInteger256::from(1).is_zero());
|
||||
assert!(!BigInteger256([0, 0, 1, 0]).is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_repr_num_bits() {
|
||||
let mut a = BigInteger256::from(0);
|
||||
assert_eq!(0, a.num_bits());
|
||||
a = BigInteger256::from(1);
|
||||
for i in 1..257 {
|
||||
assert_eq!(i, a.num_bits());
|
||||
a.mul2();
|
||||
}
|
||||
assert_eq!(0, a.num_bits());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_add_assign() {
|
||||
// Test associativity
|
||||
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Generate a, b, c and ensure (a + b) + c == a + (b + c).
|
||||
let a = Fq::rand(&mut rng);
|
||||
let b = Fq::rand(&mut rng);
|
||||
let c = Fq::rand(&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_eq!(tmp1, tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_sub_assign() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure that (a - b) + (b - a) = 0.
|
||||
let a = Fq::rand(&mut rng);
|
||||
let b = Fq::rand(&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_fq_mul_assign() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000000 {
|
||||
// Ensure that (a * b) * c = a * (b * c)
|
||||
let a = Fq::rand(&mut rng);
|
||||
let b = Fq::rand(&mut rng);
|
||||
let c = Fq::rand(&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 = Fq::rand(&mut rng);
|
||||
let mut a = Fq::rand(&mut rng);
|
||||
let mut b = Fq::rand(&mut rng);
|
||||
let mut c = Fq::rand(&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_fq_squaring() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000000 {
|
||||
// Ensure that (a * a) = a^2
|
||||
let a = Fq::rand(&mut rng);
|
||||
|
||||
let mut tmp = a;
|
||||
tmp.square_in_place();
|
||||
|
||||
let mut tmp2 = a;
|
||||
tmp2.mul_assign(&a);
|
||||
|
||||
assert_eq!(tmp, tmp2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_inverse() {
|
||||
assert!(Fq::zero().inverse().is_none());
|
||||
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
let one = Fq::one();
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure that a * a^-1 = 1
|
||||
let mut a = Fq::rand(&mut rng);
|
||||
let ainv = a.inverse().unwrap();
|
||||
a.mul_assign(&ainv);
|
||||
assert_eq!(a, one);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_double_in_place() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure doubling a is equivalent to adding a to itself.
|
||||
let mut a = Fq::rand(&mut rng);
|
||||
let mut b = a;
|
||||
b.add_assign(&a);
|
||||
a.double_in_place();
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_negate() {
|
||||
{
|
||||
let a = -Fq::zero();
|
||||
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure (a - (-a)) = 0.
|
||||
let mut a = Fq::rand(&mut rng);
|
||||
let b = -a;
|
||||
a.add_assign(&b);
|
||||
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_pow() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for i in 0..1000 {
|
||||
// Exponentiate by various small numbers and ensure it consists with repeated
|
||||
// multiplication.
|
||||
let a = Fq::rand(&mut rng);
|
||||
let target = a.pow(&[i]);
|
||||
let mut c = Fq::one();
|
||||
for _ in 0..i {
|
||||
c.mul_assign(&a);
|
||||
}
|
||||
assert_eq!(c, target);
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Exponentiating by the modulus should have no effect in a prime field.
|
||||
let a = Fq::rand(&mut rng);
|
||||
|
||||
assert_eq!(a, a.pow(Fq::characteristic()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_sqrt() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero());
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure sqrt(a^2) = a or -a
|
||||
let a = Fq::rand(&mut rng);
|
||||
let nega = -a;
|
||||
let mut b = a;
|
||||
b.square_in_place();
|
||||
|
||||
let b = b.sqrt().unwrap();
|
||||
|
||||
assert!(a == b || nega == b);
|
||||
}
|
||||
|
||||
for _ in 0..1000 {
|
||||
// Ensure sqrt(a)^2 = a for random a
|
||||
let a = Fq::rand(&mut rng);
|
||||
|
||||
if let Some(mut tmp) = a.sqrt() {
|
||||
tmp.square_in_place();
|
||||
|
||||
assert_eq!(a, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_num_bits() {
|
||||
assert_eq!(FqParameters::MODULUS_BITS, 254);
|
||||
assert_eq!(FqParameters::CAPACITY, 253);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_root_of_unity() {
|
||||
assert_eq!(FqParameters::TWO_ADICITY, 1);
|
||||
assert_eq!(
|
||||
Fq::multiplicative_generator().pow([
|
||||
0x9e10460b6c3e7ea3,
|
||||
0xcbc0b548b438e546,
|
||||
0xdc2822db40c0ac2e,
|
||||
0x183227397098d014,
|
||||
]),
|
||||
Fq::two_adic_root_of_unity()
|
||||
);
|
||||
assert_eq!(
|
||||
Fq::two_adic_root_of_unity().pow([1 << FqParameters::TWO_ADICITY]),
|
||||
Fq::one()
|
||||
);
|
||||
assert!(Fq::multiplicative_generator().sqrt().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_ordering() {
|
||||
// BigInteger256's ordering is well-tested, but we still need to make sure the
|
||||
// Fq elements aren't being compared in Montgomery form.
|
||||
for i in 0..100 {
|
||||
assert!(Fq::from(BigInteger256::from(i + 1)) > Fq::from(BigInteger256::from(i)));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq_legendre() {
|
||||
use ark_ff::fields::LegendreSymbol::*;
|
||||
|
||||
assert_eq!(QuadraticResidue, Fq::one().legendre());
|
||||
assert_eq!(Zero, Fq::zero().legendre());
|
||||
assert_eq!(
|
||||
QuadraticResidue,
|
||||
Fq::from(BigInteger256::from(4)).legendre()
|
||||
);
|
||||
assert_eq!(
|
||||
QuadraticNonResidue,
|
||||
Fq::from(BigInteger256::from(5)).legendre()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_ordering() {
|
||||
let mut a = Fq2::new(Fq::zero(), Fq::zero());
|
||||
let mut b = a.clone();
|
||||
|
||||
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::new(Fq::zero(), Fq::zero(),), Fq2::zero());
|
||||
assert_eq!(Fq2::new(Fq::one(), Fq::zero(),), Fq2::one());
|
||||
assert!(Fq2::zero().is_zero());
|
||||
assert!(!Fq2::one().is_zero());
|
||||
assert!(!Fq2::new(Fq::zero(), Fq::one(),).is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_legendre() {
|
||||
use ark_ff::fields::LegendreSymbol::*;
|
||||
|
||||
assert_eq!(Zero, Fq2::zero().legendre());
|
||||
// i^2 = -1
|
||||
let mut m1 = -Fq2::one();
|
||||
assert_eq!(QuadraticResidue, m1.legendre());
|
||||
m1 = Fq6Parameters::mul_fp2_by_nonresidue(&m1);
|
||||
assert_eq!(QuadraticNonResidue, m1.legendre());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq6_mul_by_1() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c1 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq6::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_1(&c1);
|
||||
b.mul_assign(&Fq6::new(Fq2::zero(), c1, Fq2::zero()));
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq6_mul_by_01() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c0 = Fq2::rand(&mut rng);
|
||||
let c1 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq6::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_01(&c0, &c1);
|
||||
b.mul_assign(&Fq6::new(c0, c1, Fq2::zero()));
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq12_mul_by_014() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c0 = Fq2::rand(&mut rng);
|
||||
let c1 = Fq2::rand(&mut rng);
|
||||
let c5 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq12::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_014(&c0, &c1, &c5);
|
||||
b.mul_assign(&Fq12::new(
|
||||
Fq6::new(c0, c1, Fq2::zero()),
|
||||
Fq6::new(Fq2::zero(), c5, Fq2::zero()),
|
||||
));
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq12_mul_by_034() {
|
||||
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let c0 = Fq2::rand(&mut rng);
|
||||
let c3 = Fq2::rand(&mut rng);
|
||||
let c4 = Fq2::rand(&mut rng);
|
||||
let mut a = Fq12::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
a.mul_by_034(&c0, &c3, &c4);
|
||||
b.mul_assign(&Fq12::new(
|
||||
Fq6::new(c0, Fq2::zero(), Fq2::zero()),
|
||||
Fq6::new(c3, c4, Fq2::zero()),
|
||||
));
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user