use super::fp;
use super::fp::FP;
use super::big::BIG;
use super::dbig::DBIG;
use super::rom;
use std::str::SplitWhitespace;
use std::fmt;
#[derive(Copy, Clone)]
pub struct FP2 {
a: FP,
b: FP,
}
impl PartialEq for FP2 {
fn eq(&self, other: &FP2) -> bool {
self.equals(other)
}
}
impl fmt::Display for FP2 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FP2: [ {}, {} ]", self.a, self.b)
}
}
impl fmt::Debug for FP2 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FP2: [ {}, {} ]", self.a, self.b)
}
}
impl FP2 {
pub fn new() -> FP2 {
FP2 {
a: FP::new(),
b: FP::new(),
}
}
pub fn new_int(a: isize) -> FP2 {
let mut f = FP2::new();
f.a.copy(&FP::new_int(a));
f.b.zero();
return f;
}
pub fn new_copy(x: &FP2) -> FP2 {
let mut f = FP2::new();
f.a.copy(&x.a);
f.b.copy(&x.b);
return f;
}
pub fn new_fps(c: &FP, d: &FP) -> FP2 {
let mut f = FP2::new();
f.a.copy(c);
f.b.copy(d);
return f;
}
pub fn new_bigs(c: &BIG, d: &BIG) -> FP2 {
let mut f = FP2::new();
f.a.copy(&FP::new_big(c));
f.b.copy(&FP::new_big(d));
return f;
}
pub fn new_fp(c: &FP) -> FP2 {
let mut f = FP2::new();
f.a.copy(c);
f.b.zero();
return f;
}
pub fn new_big(c: &BIG) -> FP2 {
let mut f = FP2::new();
f.a.copy(&FP::new_big(c));
f.b.zero();
return f;
}
pub fn reduce(&mut self) {
self.a.reduce();
self.b.reduce();
}
pub fn norm(&mut self) {
self.a.norm();
self.b.norm();
}
pub fn iszilch(&self) -> bool {
return self.a.iszilch() && self.b.iszilch();
}
pub fn cmove(&mut self, g: &FP2, d: isize) {
self.a.cmove(&g.a, d);
self.b.cmove(&g.b, d);
}
pub fn isunity(&self) -> bool {
let one = FP::new_int(1);
return self.a.equals(&one) && self.b.iszilch();
}
pub fn equals(&self, x: &FP2) -> bool {
return self.a.equals(&x.a) && self.b.equals(&x.b);
}
pub fn geta(&mut self) -> BIG {
return self.a.redc();
}
pub fn getb(&mut self) -> BIG {
return self.b.redc();
}
pub fn seta(&mut self, a: FP) {
self.a = a
}
pub fn setb(&mut self, b: FP) {
self.b = b
}
pub fn copy(&mut self, x: &FP2) {
self.a.copy(&x.a);
self.b.copy(&x.b);
}
pub fn zero(&mut self) {
self.a.zero();
self.b.zero();
}
pub fn one(&mut self) {
self.a.one();
self.b.zero();
}
pub fn neg(&mut self) {
let mut m = FP::new_copy(&self.a);
let mut t = FP::new();
m.add(&self.b);
m.neg();
t.copy(&m);
t.add(&self.b);
self.b.copy(&m);
self.b.add(&self.a);
self.a.copy(&t);
}
pub fn conj(&mut self) {
self.b.neg();
self.b.norm();
}
pub fn add(&mut self, x: &FP2) {
self.a.add(&x.a);
self.b.add(&x.b);
}
pub fn dbl(&mut self) {
self.a.dbl();
self.b.dbl();
}
pub fn sub(&mut self, x: &FP2) {
let mut m = FP2::new_copy(x);
m.neg();
self.add(&m);
}
pub fn rsub(&mut self, x: &FP2) {
self.neg();
self.add(x);
}
pub fn pmul(&mut self, s: &FP) {
self.a.mul(s);
self.b.mul(s);
}
pub fn imul(&mut self, c: isize) {
self.a.imul(c);
self.b.imul(c);
}
pub fn sqr(&mut self) {
let mut w1 = FP::new_copy(&self.a);
let mut w3 = FP::new_copy(&self.a);
let mut mb = FP::new_copy(&self.b);
w1.add(&self.b);
w3.add(&self.a);
w3.norm();
self.b.mul(&w3);
mb.neg();
self.a.add(&mb);
w1.norm();
self.a.norm();
self.a.mul(&w1);
}
pub fn mul(&mut self, y: &FP2) {
if ((self.a.xes + self.b.xes) as i64) * ((y.a.xes + y.b.xes) as i64) > fp::FEXCESS as i64 {
if self.a.xes > 1 {
self.a.reduce()
}
if self.b.xes > 1 {
self.b.reduce()
}
}
let p = BIG::new_ints(&rom::MODULUS);
let mut pr = DBIG::new();
pr.ucopy(&p);
let mut c = BIG::new_copy(&(self.a.x));
let mut d = BIG::new_copy(&(y.a.x));
let mut a = BIG::mul(&self.a.x, &y.a.x);
let mut b = BIG::mul(&self.b.x, &y.b.x);
c.add(&self.b.x);
c.norm();
d.add(&y.b.x);
d.norm();
let mut e = BIG::mul(&c, &d);
let mut f = DBIG::new_copy(&a);
f.add(&b);
b.rsub(&pr);
a.add(&b);
a.norm();
e.sub(&f);
e.norm();
self.a.x.copy(&FP::modulo(&mut a));
self.a.xes = 3;
self.b.x.copy(&FP::modulo(&mut e));
self.b.xes = 2;
}
pub fn sqrt(&mut self) -> bool {
if self.iszilch() {
return true;
}
let mut w1 = FP::new_copy(&self.b);
let mut w2 = FP::new_copy(&self.a);
w1.sqr();
w2.sqr();
w1.add(&w2);
if w1.jacobi() != 1 {
self.zero();
return false;
}
w2.copy(&w1.sqrt());
w1.copy(&w2);
w2.copy(&self.a);
w2.add(&w1);
w2.norm();
w2.div2();
if w2.jacobi() != 1 {
w2.copy(&self.a);
w2.sub(&w1);
w2.norm();
w2.div2();
if w2.jacobi() != 1 {
self.zero();
return false;
}
}
w1.copy(&w2.sqrt());
self.a.copy(&w1);
w1.dbl();
w1.inverse();
self.b.mul(&w1);
return true;
}
pub fn tostring(&mut self) -> String {
return format!("[{},{}]", self.a.tostring(), self.b.tostring());
}
pub fn to_hex(&self) -> String {
format!("{} {}", self.a.to_hex(), self.b.to_hex())
}
pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP2 {
FP2 {
a: FP::from_hex_iter(iter),
b: FP::from_hex_iter(iter)
}
}
pub fn from_hex(val: String) -> FP2 {
let mut iter = val.split_whitespace();
return FP2::from_hex_iter(&mut iter);
}
pub fn inverse(&mut self) {
self.norm();
let mut w1 = FP::new_copy(&self.a);
let mut w2 = FP::new_copy(&self.b);
w1.sqr();
w2.sqr();
w1.add(&w2);
w1.inverse();
self.a.mul(&w1);
w1.neg();
w1.norm();
self.b.mul(&w1);
}
pub fn div2(&mut self) {
self.a.div2();
self.b.div2();
}
pub fn times_i(&mut self) {
let z = FP::new_copy(&self.a);
self.a.copy(&self.b);
self.a.neg();
self.b.copy(&z);
}
pub fn mul_ip(&mut self) {
let t = FP2::new_copy(self);
let z = FP::new_copy(&self.a);
self.a.copy(&self.b);
self.a.neg();
self.b.copy(&z);
self.add(&t);
}
pub fn div_ip2(&mut self) {
let mut t = FP2::new();
self.norm();
t.a.copy(&self.a);
t.a.add(&self.b);
t.b.copy(&self.b);
t.b.sub(&self.a);
t.norm();
self.copy(&t);
}
pub fn div_ip(&mut self) {
let mut t = FP2::new();
self.norm();
t.a.copy(&self.a);
t.a.add(&self.b);
t.b.copy(&self.b);
t.b.sub(&self.a);
t.norm();
self.copy(&t);
self.div2();
}
}