From 3ebd5271673e8671fc7a8f26075fdb9647571b58 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 14 Sep 2016 21:30:38 -0600 Subject: [PATCH] Use macros to instantiate finite fields. --- src/arith.rs | 16 +-- src/fields/fp.rs | 350 ++++++++++++++++++--------------------------- src/fields/fq12.rs | 14 +- src/fields/fq2.rs | 8 +- src/fields/fq6.rs | 22 +-- src/fields/mod.rs | 2 +- src/groups/mod.rs | 30 ++-- 7 files changed, 186 insertions(+), 256 deletions(-) diff --git a/src/arith.rs b/src/arith.rs index ac08c5e..8dadfc2 100644 --- a/src/arith.rs +++ b/src/arith.rs @@ -7,7 +7,8 @@ use byteorder::{ByteOrder, BigEndian}; /// 256-bit, stack allocated biginteger for use in prime field /// arithmetic. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct U256([u64; 4]); +#[repr(C)] +pub struct U256(pub [u64; 4]); impl Encodable for U256 { fn encode(&self, s: &mut S) -> Result<(), S::Error> { @@ -40,7 +41,7 @@ impl Decodable for U256 { n[1] = BigEndian::read_u64(&buf[16..]); n[0] = BigEndian::read_u64(&buf[24..]); - Ok(n.into()) + Ok(U256(n)) } } @@ -66,22 +67,15 @@ impl PartialOrd for U256 { } } -impl From<[u64; 4]> for U256 { - #[inline] - fn from(a: [u64; 4]) -> U256 { - U256(a) - } -} - impl U256 { #[inline] pub fn zero() -> U256 { - [0, 0, 0, 0].into() + U256([0, 0, 0, 0]) } #[inline] pub fn one() -> U256 { - [1, 0, 0, 0].into() + U256([1, 0, 0, 0]) } /// Produce a random number (mod `modulo`) diff --git a/src/fields/fp.rs b/src/fields/fp.rs index b881f52..0e621be 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -1,238 +1,174 @@ use rand::Rng; use std::ops::{Add, Sub, Mul, Neg}; -use std::fmt; -use std::marker::PhantomData; use super::FieldElement; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use arith::U256; -pub trait FpParams { - fn name() -> &'static str; - fn modulus() -> U256; - fn inv() -> u64; - fn rsquared() -> U256; - fn rcubed() -> U256; - fn one() -> U256; -} +macro_rules! field_impl { + ($name:ident, $modulus:expr, $rsquared:expr, $rcubed:expr, $one:expr, $inv:expr) => { + #[derive(Copy, Clone, PartialEq, Eq, Debug)] + #[repr(C)] + pub struct $name(U256); -#[repr(C)] -pub struct Fp(U256, PhantomData

); -impl Copy for Fp

{ } -impl Clone for Fp

{ - fn clone(&self) -> Self { *self } -} -impl PartialEq for Fp

{ - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} -impl Eq for Fp

{ } -impl fmt::Debug for Fp

{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}({:?})", P::name(), self.0) - } -} -impl From> for U256 { - fn from(mut a: Fp

) -> Self { - a.0.mul(&U256::one(), &P::modulus(), P::inv()); + impl From<$name> for U256 { + #[inline] + fn from(mut a: $name) -> Self { + a.0.mul(&U256::one(), &U256($modulus), $inv); + + a.0 + } + } - a.0 - } -} + impl Encodable for $name { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + let normalized = U256::from(*self); -#[inline] -pub fn const_fp>(i: I) -> Fp

{ - Fp(i.into(), PhantomData) -} + normalized.encode(s) + } + } -impl Encodable for Fp

{ - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - let normalized = U256::from(*self); + impl Decodable for $name { + fn decode(s: &mut S) -> Result<$name, S::Error> { + $name::new(try!(U256::decode(s))).ok_or_else(|| s.error("integer is not less than modulus")) + } + } - normalized.encode(s) - } -} + impl $name { + pub fn from_str(s: &str) -> Option { + let ints: Vec<_> = { + let mut acc = Self::zero(); + (0..11).map(|_| {let tmp = acc; acc = acc + Self::one(); tmp}).collect() + }; -impl Decodable for Fp

{ - fn decode(s: &mut S) -> Result, S::Error> { - Fp::new(try!(U256::decode(s))).ok_or_else(|| s.error("integer is not less than modulus")) - } -} + 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; + } + } + } -impl Fp

{ - pub fn from_str(s: &str) -> Option { - let ints: Vec<_> = { - let mut acc = Self::zero(); - (0..11).map(|_| {let tmp = acc; acc = acc + Self::one(); tmp}).collect() - }; + Some(res) + } - 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; + /// Converts a U256 to an Fp so long as it's below the modulus. + pub fn new(mut a: U256) -> Option { + if a < U256($modulus) { + a.mul(&U256($rsquared), &U256($modulus), $inv); + + Some($name(a)) + } else { + None } } } - Some(res) - } -} + impl FieldElement for $name { + #[inline] + fn zero() -> Self { + $name(U256([0, 0, 0, 0])) + } -impl Fp

{ - /// Converts a U256 to an Fp so long as it's below the modulus. - pub fn new(mut a: U256) -> Option { - if a < P::modulus() { - a.mul(&P::rsquared(), &P::modulus(), P::inv()); + #[inline] + fn one() -> Self { + $name(U256($one)) + } + + fn random(rng: &mut R) -> Self { + $name(U256::random(rng, &U256($modulus))) + } - Some(Fp(a, PhantomData)) - } else { - None + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } + + fn inverse(mut self) -> Option { + if self.is_zero() { + None + } else { + self.0.invert(&U256($modulus)); + self.0.mul(&U256($rcubed), &U256($modulus), $inv); + + Some(self) + } + } + } + + impl Add for $name { + type Output = $name; + + #[inline] + fn add(mut self, other: $name) -> $name { + self.0.add(&other.0, &U256($modulus)); + + self + } + } + + impl Sub for $name { + type Output = $name; + + #[inline] + fn sub(mut self, other: $name) -> $name { + self.0.sub(&other.0, &U256($modulus)); + + self + } + } + + impl Mul for $name { + type Output = $name; + + #[inline] + fn mul(mut self, other: $name) -> $name { + self.0.mul(&other.0, &U256($modulus), $inv); + + self + } + } + + impl Neg for $name { + type Output = $name; + + #[inline] + fn neg(mut self) -> $name { + self.0.neg(&U256($modulus)); + + self + } } } } -impl FieldElement for Fp

{ - fn zero() -> Self { - const_fp(U256::zero()) - } +field_impl!( + Fr, + [0x43e1f593f0000001, 0x2833e84879b97091, 0xb85045b68181585d, 0x30644e72e131a029], + [0x1bb8e645ae216da7, 0x53fe3ab1e35c59e3, 0x8c49833d53bb8085, 0x0216d0b17f4e44a5], + [0x5e94d8e1b4bf0040, 0x2a489cbe1cfbb6b8, 0x893cc664a19fcfed, 0x0cf8594b7fcc657c], + [0xac96341c4ffffffb, 0x36fc76959f60cd29, 0x666ea36f7879462e, 0xe0a77c19a07df2f], + 0xc2e1f593efffffff +); - fn one() -> Self { - const_fp(P::one()) - } - - fn random(rng: &mut R) -> Self { - const_fp(U256::random(rng, &P::modulus())) - } +field_impl!( + Fq, + [0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029], + [0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f], + [0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544], + [0xd35d438dc58f0d9d, 0xa78eb28f5c70b3d, 0x666ea36f7879462c, 0xe0a77c19a07df2f], + 0x87d20782e4866389 +); - fn is_zero(&self) -> bool { - self.0.is_zero() - } - - fn inverse(mut self) -> Option { - if self.is_zero() { - None - } else { - self.0.invert(&P::modulus()); - self.0.mul(&P::rcubed(), &P::modulus(), P::inv()); - - Some(self) - } - } -} - -impl Add for Fp

{ - type Output = Fp

; - - fn add(mut self, other: Fp

) -> Fp

{ - self.0.add(&other.0, &P::modulus()); - - self - } -} - -impl Sub for Fp

{ - type Output = Fp

; - - fn sub(mut self, other: Fp

) -> Fp

{ - self.0.sub(&other.0, &P::modulus()); - - self - } -} - -impl Mul for Fp

{ - type Output = Fp

; - - fn mul(mut self, other: Fp

) -> Fp

{ - self.0.mul(&other.0, &P::modulus(), P::inv()); - - self - } -} - -impl Neg for Fp

{ - type Output = Fp

; - - fn neg(mut self) -> Fp

{ - self.0.neg(&P::modulus()); - - self - } -} - -pub struct FrParams; -pub type Fr = Fp; -impl FpParams for FrParams { - fn name() -> &'static str { "Fr" } - - #[inline] - fn modulus() -> U256 { - // 21888242871839275222246405745257275088548364400416034343698204186575808495617 - [0x43e1f593f0000001, 0x2833e84879b97091, 0xb85045b68181585d, 0x30644e72e131a029].into() - } - - #[inline] - fn inv() -> u64 { - 0xc2e1f593efffffff - } - - #[inline] - fn rsquared() -> U256 { - // 944936681149208446651664254269745548490766851729442924617792859073125903783 - [0x1bb8e645ae216da7, 0x53fe3ab1e35c59e3, 0x8c49833d53bb8085, 0x0216d0b17f4e44a5].into() - } - - #[inline] - fn rcubed() -> U256 { - // 5866548545943845227489894872040244720403868105578784105281690076696998248512 - [0x5e94d8e1b4bf0040, 0x2a489cbe1cfbb6b8, 0x893cc664a19fcfed, 0x0cf8594b7fcc657c].into() - } - - #[inline] - fn one() -> U256 { - [0xac96341c4ffffffb, 0x36fc76959f60cd29, 0x666ea36f7879462e, 0xe0a77c19a07df2f].into() - } -} - -pub struct FqParams; -pub type Fq = Fp; -impl FpParams for FqParams { - fn name() -> &'static str { "Fq" } - - #[inline] - fn modulus() -> U256 { - // 21888242871839275222246405745257275088696311157297823662689037894645226208583 - [0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029].into() - } - - #[inline] - fn inv() -> u64 { - 0x87d20782e4866389 - } - - #[inline] - fn rsquared() -> U256 { - // 3096616502983703923843567936837374451735540968419076528771170197431451843209 - [0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f].into() - } - - #[inline] - fn rcubed() -> U256 { - // 14921786541159648185948152738563080959093619838510245177710943249661917737183 - [0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544].into() - } - - #[inline] - fn one() -> U256 { - [0xd35d438dc58f0d9d, 0xa78eb28f5c70b3d, 0x666ea36f7879462c, 0xe0a77c19a07df2f].into() - } +#[inline] +pub fn const_fq(i: [u64; 4]) -> Fq { + Fq(U256(i)) } #[test] diff --git a/src/fields/fq12.rs b/src/fields/fq12.rs index d8d0dbc..ab2d16f 100644 --- a/src/fields/fq12.rs +++ b/src/fields/fq12.rs @@ -1,4 +1,4 @@ -use fields::{FieldElement, Fq2, Fq, Fq6, const_fp}; +use fields::{FieldElement, Fq2, Fq, Fq6, const_fq}; use std::ops::{Add, Sub, Mul, Neg}; use rand::Rng; @@ -8,16 +8,16 @@ 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]) + const_fq([12653890742059813127, 14585784200204367754, 1278438861261381767, 212598772761311868]), + const_fq([11683091849979440498, 14992204589386555739, 15866167890766973222, 1200023580730561873]) ), 2 => Fq2::new( - const_fp([14595462726357228530, 17349508522658994025, 1017833795229664280, 299787779797702374]), + const_fq([14595462726357228530, 17349508522658994025, 1017833795229664280, 299787779797702374]), Fq::zero() ), 3 => Fq2::new( - const_fp([3914496794763385213, 790120733010914719, 7322192392869644725, 581366264293887267]), - const_fp([12817045492518885689, 4440270538777280383, 11178533038884588256, 2767537931541304486]) + const_fq([3914496794763385213, 790120733010914719, 7322192392869644725, 581366264293887267]), + const_fq([12817045492518885689, 4440270538777280383, 11178533038884588256, 2767537931541304486]) ), _ => unimplemented!() } @@ -96,7 +96,7 @@ impl Fq12 { pub fn exp_by_neg_z(&self) -> Fq12 { self.cyclotomic_pow( - U256::from([4965661367192848881, 0, 0, 0]) + U256([4965661367192848881, 0, 0, 0]) ).unitary_inverse() } diff --git a/src/fields/fq2.rs b/src/fields/fq2.rs index 551842e..1ed6762 100644 --- a/src/fields/fq2.rs +++ b/src/fields/fq2.rs @@ -1,4 +1,4 @@ -use fields::{FieldElement, const_fp, Fq}; +use fields::{FieldElement, const_fq, Fq}; use std::ops::{Add, Sub, Mul, Neg}; use rand::Rng; @@ -8,14 +8,14 @@ use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; fn fq_non_residue() -> Fq { // (q - 1) is a quadratic nonresidue in Fq // 21888242871839275222246405745257275088696311157297823662689037894645226208582 - const_fp([0x68c3488912edefaa, 0x8d087f6872aabf4f, 0x51e1a24709081231, 0x2259d6b14729c0fa]) + const_fq([0x68c3488912edefaa, 0x8d087f6872aabf4f, 0x51e1a24709081231, 0x2259d6b14729c0fa]) } #[inline] pub fn fq2_nonresidue() -> Fq2 { Fq2::new( - const_fp([0xf60647ce410d7ff7, 0x2f3d6f4dd31bd011, 0x2943337e3940c6d1, 0x1d9598e8a7e39857]), - const_fp([0xd35d438dc58f0d9d, 0x0a78eb28f5c70b3d, 0x666ea36f7879462c, 0x0e0a77c19a07df2f]) + const_fq([0xf60647ce410d7ff7, 0x2f3d6f4dd31bd011, 0x2943337e3940c6d1, 0x1d9598e8a7e39857]), + const_fq([0xd35d438dc58f0d9d, 0x0a78eb28f5c70b3d, 0x666ea36f7879462c, 0x0e0a77c19a07df2f]) ) } diff --git a/src/fields/fq6.rs b/src/fields/fq6.rs index 39b91ed..ec5258f 100644 --- a/src/fields/fq6.rs +++ b/src/fields/fq6.rs @@ -1,4 +1,4 @@ -use fields::{FieldElement, Fq, Fq2, const_fp}; +use fields::{FieldElement, Fq, Fq2, const_fq}; use std::ops::{Add, Sub, Mul, Neg}; use rand::Rng; @@ -6,16 +6,16 @@ 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]) + const_fq([13075984984163199792, 3782902503040509012, 8791150885551868305, 1825854335138010348]), + const_fq([7963664994991228759, 12257807996192067905, 13179524609921305146, 2767831111890561987]) ), 2 => Fq2::new( - const_fp([3697675806616062876, 9065277094688085689, 6918009208039626314, 2775033306905974752]), + const_fq([3697675806616062876, 9065277094688085689, 6918009208039626314, 2775033306905974752]), Fq::zero() ), 3 => Fq2::new( - const_fp([14532872967180610477, 12903226530429559474, 1868623743233345524, 2316889217940299650]), - const_fp([12447993766991532972, 4121872836076202828, 7630813605053367399, 740282956577754197]) + const_fq([14532872967180610477, 12903226530429559474, 1868623743233345524, 2316889217940299650]), + const_fq([12447993766991532972, 4121872836076202828, 7630813605053367399, 740282956577754197]) ), _ => unimplemented!() } @@ -24,16 +24,16 @@ 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]) + const_fq([8314163329781907090, 11942187022798819835, 11282677263046157209, 1576150870752482284]), + const_fq([6763840483288992073, 7118829427391486816, 4016233444936635065, 2630958277570195709]) ), 2 => Fq2::new( - const_fp([8183898218631979349, 12014359695528440611, 12263358156045030468, 3187210487005268291]), + const_fq([8183898218631979349, 12014359695528440611, 12263358156045030468, 3187210487005268291]), Fq::zero() ), 3 => Fq2::new( - const_fp([4938922280314430175, 13823286637238282975, 15589480384090068090, 481952561930628184]), - const_fp([3105754162722846417, 11647802298615474591, 13057042392041828081, 1660844386505564338]) + const_fq([4938922280314430175, 13823286637238282975, 15589480384090068090, 481952561930628184]), + const_fq([3105754162722846417, 11647802298615474591, 13057042392041828081, 1660844386505564338]) ), _ => unimplemented!() } diff --git a/src/fields/mod.rs b/src/fields/mod.rs index 5b54a51..4fa51da 100644 --- a/src/fields/mod.rs +++ b/src/fields/mod.rs @@ -8,7 +8,7 @@ use rand::Rng; use std::ops::{Add, Sub, Mul, Neg}; use std::fmt::Debug; -pub use self::fp::{Fq,Fr,const_fp}; +pub use self::fp::{Fq,Fr,const_fq}; pub use self::fq2::{Fq2, fq2_nonresidue}; pub use self::fq6::Fq6; pub use self::fq12::Fq12; diff --git a/src/groups/mod.rs b/src/groups/mod.rs index 6fef217..8ff08ba 100644 --- a/src/groups/mod.rs +++ b/src/groups/mod.rs @@ -1,5 +1,5 @@ use std::ops::{Add,Sub,Neg,Mul}; -use fields::{FieldElement, Fq, Fq2, Fq12, Fr, const_fp, fq2_nonresidue}; +use fields::{FieldElement, Fq, Fq2, Fq12, Fr, const_fq, fq2_nonresidue}; use arith::U256; use std::fmt; use rand::Rng; @@ -334,13 +334,13 @@ impl GroupParams for G1Params { fn one() -> G { G { x: Fq::one(), - y: const_fp([0xa6ba871b8b1e1b3a, 0x14f1d651eb8e167b, 0xccdd46def0f28c58, 0x1c14ef83340fbe5e]), + y: const_fq([0xa6ba871b8b1e1b3a, 0x14f1d651eb8e167b, 0xccdd46def0f28c58, 0x1c14ef83340fbe5e]), z: Fq::one() } } fn coeff_b() -> Fq { - const_fp([0x7a17caa950ad28d7, 0x1f6ac17ae15521b9, 0x334bea4e696bd284, 0x2a1f6744ce179d8e]) + const_fq([0x7a17caa950ad28d7, 0x1f6ac17ae15521b9, 0x334bea4e696bd284, 0x2a1f6744ce179d8e]) } } @@ -356,12 +356,12 @@ impl GroupParams for G2Params { fn one() -> G { G { x: Fq2::new( - const_fp([0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b]), - const_fp([0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b]) + const_fq([0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b]), + const_fq([0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b]) ), y: Fq2::new( - const_fp([0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206]), - const_fp([0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482]) + const_fq([0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206]), + const_fq([0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482]) ), z: Fq2::one() } @@ -369,8 +369,8 @@ impl GroupParams for G2Params { fn coeff_b() -> Fq2 { Fq2::new( - const_fp([0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d]), - const_fp([0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d]) + const_fq([0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d]), + const_fq([0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d]) ) } } @@ -421,27 +421,27 @@ fn twist() -> Fq2 { #[inline] fn two_inv() -> Fq { - const_fp([9781510331150239090, 15059239858463337189, 10331104244869713732, 2249375503248834476]) + const_fq([9781510331150239090, 15059239858463337189, 10331104244869713732, 2249375503248834476]) } #[inline] fn ate_loop_count() -> U256 { - [0x9d797039be763ba8, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000].into() + U256([0x9d797039be763ba8, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000]) } #[inline] fn twist_mul_by_q_x() -> Fq2 { Fq2::new( - const_fp([13075984984163199792, 3782902503040509012, 8791150885551868305, 1825854335138010348]), - const_fp([7963664994991228759, 12257807996192067905, 13179524609921305146, 2767831111890561987]) + const_fq([13075984984163199792, 3782902503040509012, 8791150885551868305, 1825854335138010348]), + const_fq([7963664994991228759, 12257807996192067905, 13179524609921305146, 2767831111890561987]) ) } #[inline] fn twist_mul_by_q_y() -> Fq2 { Fq2::new( - const_fp([16482010305593259561, 13488546290961988299, 3578621962720924518, 2681173117283399901]), - const_fp([11661927080404088775, 553939530661941723, 7860678177968807019, 3208568454732775116]) + const_fq([16482010305593259561, 13488546290961988299, 3578621962720924518, 2681173117283399901]), + const_fq([11661927080404088775, 553939530661941723, 7860678177968807019, 3208568454732775116]) ) }