use crate::{
arith::{U256, U512},
fields::{FieldElement, Fq, const_fq},
};
use core::ops::{Add, Mul, Neg, Sub};
use rand::Rng;
#[cfg(feature = "rustc-serialize")]
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
#[inline]
fn fq_non_residue() -> Fq {
const_fq([
0x68c3488912edefaa,
0x8d087f6872aabf4f,
0x51e1a24709081231,
0x2259d6b14729c0fa,
])
}
#[inline]
pub fn fq2_nonresidue() -> Fq2 {
Fq2::new(
const_fq([
0xf60647ce410d7ff7,
0x2f3d6f4dd31bd011,
0x2943337e3940c6d1,
0x1d9598e8a7e39857,
]),
const_fq([
0xd35d438dc58f0d9d,
0x0a78eb28f5c70b3d,
0x666ea36f7879462c,
0x0e0a77c19a07df2f,
]),
)
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Fq2 {
c0: Fq,
c1: Fq,
}
#[cfg(feature = "rustc-serialize")]
impl Encodable for Fq2 {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
let c0: U256 = self.c0.into();
let c1: U256 = self.c1.into();
U512::new(&c1, &c0, &Fq::modulus()).encode(s)
}
}
#[cfg(feature = "rustc-serialize")]
impl Decodable for Fq2 {
fn decode<S: Decoder>(s: &mut S) -> Result<Fq2, S::Error> {
let combined = U512::decode(s)?;
match combined.divrem(&Fq::modulus()) {
(Some(c1), c0) => Ok(Fq2::new(Fq::new(c0).unwrap(), Fq::new(c1).unwrap())),
_ => Err(s.error("integer not less than modulus squared")),
}
}
}
impl Fq2 {
pub fn new(c0: Fq, c1: Fq) -> Self {
Fq2 { c0, c1 }
}
pub fn scale(&self, by: Fq) -> Self {
Fq2 {
c0: self.c0 * by,
c1: self.c1 * by,
}
}
pub fn mul_by_nonresidue(&self) -> Self {
*self * fq2_nonresidue()
}
pub fn frobenius_map(&self, power: usize) -> Self {
if power % 2 == 0 {
*self
} else {
Fq2 {
c0: self.c0,
c1: self.c1 * fq_non_residue(),
}
}
}
pub fn real(&self) -> &Fq {
&self.c0
}
pub fn imaginary(&self) -> &Fq {
&self.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 {
let ab = self.c0 * self.c1;
Fq2 {
c0: (self.c1 * fq_non_residue() + self.c0) * (self.c0 + self.c1)
- ab
- ab * fq_non_residue(),
c1: ab + ab,
}
}
fn inverse(self) -> Option<Self> {
(self.c0.squared() - (self.c1.squared() * fq_non_residue()))
.inverse()
.map(|t| Fq2 {
c0: self.c0 * t,
c1: -(self.c1 * t),
})
}
}
impl Mul for Fq2 {
type Output = Fq2;
fn mul(self, other: Fq2) -> Fq2 {
let aa = self.c0 * other.c0;
let bb = self.c1 * other.c1;
Fq2 {
c0: bb * fq_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,
}
}
}
lazy_static! {
static ref FQ: U256 = U256::from([
0x3c208c16d87cfd47,
0x97816a916871ca8d,
0xb85045b68181585d,
0x30644e72e131a029
]);
static ref FQ_MINUS3_DIV4: Fq = Fq::new(3.into())
.expect("3 is a valid field element and static; qed")
.neg()
* Fq::new(4.into())
.expect("4 is a valid field element and static; qed")
.inverse()
.expect("4 has inverse in Fq and is static; qed");
static ref FQ_MINUS1_DIV2: Fq = Fq::new(1.into())
.expect("1 is a valid field element and static; qed")
.neg()
* Fq::new(2.into())
.expect("2 is a valid field element and static; qed")
.inverse()
.expect("2 has inverse in Fq and is static; qed");
}
impl Fq2 {
pub fn i() -> Fq2 {
Fq2::new(Fq::zero(), Fq::one())
}
pub fn sqrt(&self) -> Option<Self> {
let a1 = self.pow::<U256>((*FQ_MINUS3_DIV4).into());
let a1a = a1 * *self;
let alpha = a1 * a1a;
let a0 = alpha.pow(*FQ) * alpha;
if a0 == Fq2::one().neg() {
return None;
}
if alpha == Fq2::one().neg() {
Some(Self::i() * a1a)
} else {
let b = (alpha + Fq2::one()).pow::<U256>((*FQ_MINUS1_DIV2).into());
Some(b * a1a)
}
}
pub fn to_u512(self) -> U512 {
let c0: U256 = (*self.real()).into();
let c1: U256 = (*self.imaginary()).into();
U512::new(&c1, &c0, &FQ)
}
}
#[test]
fn sqrt_fq2() {
let x1 = Fq2::new(
Fq::from_str(
"12844195307879678418043983815760255909500142247603239203345049921980497041944",
)
.unwrap(),
Fq::from_str(
"7476417578426924565731404322659619974551724117137577781074613937423560117731",
)
.unwrap(),
);
let x2 = Fq2::new(
Fq::from_str(
"3345897230485723946872934576923485762803457692345760237495682347502347589474",
)
.unwrap(),
Fq::from_str(
"1234912378405347958234756902345768290345762348957605678245967234857634857676",
)
.unwrap(),
);
assert_eq!(x2.sqrt().unwrap(), x1);
assert_eq!(Fq2::one().neg().sqrt().unwrap(), Fq2::i(),);
assert!(
Fq2::new(Fq::from_str("1").unwrap(), Fq::from_str("2").unwrap())
.sqrt()
.is_none()
);
}