use crate::bls48286::big;
use crate::bls48286::fp;
use crate::bls48286::fp::FP;
use crate::bls48286::fp2::FP2;
use crate::bls48286::fp4::FP4;
use crate::rand::RAND;
#[allow(unused_imports)]
use crate::bls48286::big::BIG;
#[allow(unused_imports)]
use crate::bls48286::rom;
#[derive(Copy, Clone)]
pub struct FP8 {
a: FP4,
b: FP4,
}
#[cfg(feature = "std")]
impl std::fmt::Debug for FP8 {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "{}", self.tostring())
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for FP8 {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "{}", self.tostring())
}
}
impl FP8 {
pub const fn new() -> FP8 {
FP8 {
a: FP4::new(),
b: FP4::new(),
}
}
pub fn new_int(a: isize) -> FP8 {
let mut f = FP8::new();
f.a.copy(&FP4::new_int(a));
f.b.zero();
f
}
pub fn new_ints(a: isize,b: isize) -> FP8 {
let mut f = FP8::new();
f.a.copy(&FP4::new_int(a));
f.b.copy(&FP4::new_int(b));
f
}
pub fn new_copy(x: &FP8) -> FP8 {
let mut f = FP8::new();
f.a.copy(&x.a);
f.b.copy(&x.b);
f
}
pub fn new_fp4s(c: &FP4, d: &FP4) -> FP8 {
let mut f = FP8::new();
f.a.copy(c);
f.b.copy(d);
f
}
pub fn new_fp4(c: &FP4) -> FP8 {
let mut f = FP8::new();
f.a.copy(c);
f.b.zero();
f
}
pub fn new_fp(c: &FP) -> FP8 {
let mut f = FP8::new();
f.a.set_fp(c);
f.b.zero();
f
}
pub fn new_rand(rng: &mut impl RAND) -> FP8 {
FP8::new_fp4s(&FP4::new_rand(rng),&FP4::new_rand(rng))
}
pub fn set_fp4s(&mut self, c: &FP4, d: &FP4) {
self.a.copy(&c);
self.b.copy(&d);
}
pub fn set_fp4(&mut self, c: &FP4) {
self.a.copy(&c);
self.b.zero();
}
pub fn set_fp4h(&mut self, c: &FP4) {
self.b.copy(&c);
self.a.zero();
}
pub fn reduce(&mut self) {
self.a.reduce();
self.b.reduce();
}
pub fn norm(&mut self) {
self.a.norm();
self.b.norm();
}
pub fn cmove(&mut self, g: &FP8, d: isize) {
self.a.cmove(&g.a, d);
self.b.cmove(&g.b, d);
}
pub fn iszilch(&self) -> bool {
self.a.iszilch() && self.b.iszilch()
}
pub fn islarger(&self) -> isize {
if self.iszilch() {
return 0;
}
let cmp=self.b.islarger();
if cmp!=0 {
return cmp;
}
self.a.islarger()
}
pub fn tobytes(&self,bf: &mut [u8]) {
const MB:usize = 4*(big::MODBYTES as usize);
let mut t: [u8; MB] = [0; MB];
self.b.tobytes(&mut t);
for i in 0..MB {
bf[i]=t[i];
}
self.a.tobytes(&mut t);
for i in 0..MB {
bf[i+MB]=t[i];
}
}
pub fn frombytes(bf: &[u8]) -> FP8 {
const MB:usize = 4*(big::MODBYTES as usize);
let mut t: [u8; MB] = [0; MB];
for i in 0..MB {
t[i]=bf[i];
}
let tb=FP4::frombytes(&t);
for i in 0..MB {
t[i]=bf[i+MB];
}
let ta=FP4::frombytes(&t);
FP8::new_fp4s(&ta,&tb)
}
pub fn isunity(&self) -> bool {
let one = FP4::new_int(1);
self.a.equals(&one) && self.b.iszilch()
}
pub fn isreal(&mut self) -> bool {
self.b.iszilch()
}
pub fn real(&self) -> FP4 {
FP4::new_copy(&self.a)
}
pub fn geta(&self) -> FP4 {
FP4::new_copy(&self.a)
}
pub fn getb(&self) -> FP4 {
FP4::new_copy(&self.b)
}
pub fn equals(&self, x: &FP8) -> bool {
self.a.equals(&x.a) && self.b.equals(&x.b)
}
pub fn copy(&mut self, x: &FP8) {
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 sign(&self) -> isize {
let mut p1=self.a.sign();
let mut p2=self.b.sign();
if fp::BIG_ENDIAN_SIGN {
let u=self.b.iszilch() as isize;
p2^=(p1^p2)&u;
return p2;
} else {
let u=self.a.iszilch() as isize;
p1^=(p1^p2)&u;
return p1;
}
}
pub fn neg(&mut self) {
self.norm();
let mut m = FP4::new_copy(&self.a);
let mut t = FP4::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);
self.norm();
}
pub fn conj(&mut self) {
self.b.neg();
self.norm();
}
pub fn nconj(&mut self) {
self.a.neg();
self.norm();
}
pub fn add(&mut self, x: &FP8) {
self.a.add(&x.a);
self.b.add(&x.b);
}
pub fn padd(&mut self, x: &FP4) {
self.a.add(x);
}
pub fn dbl(&mut self) {
self.a.dbl();
self.b.dbl();
}
pub fn sub(&mut self, x: &FP8) {
let mut m = FP8::new_copy(x);
m.neg();
self.add(&m);
}
pub fn rsub(&mut self, x: &FP8) {
self.neg();
self.add(x);
}
pub fn pmul(&mut self, s: &FP4) {
self.a.mul(s);
self.b.mul(s);
}
pub fn qmul(&mut self, s: &FP2) {
self.a.pmul(s);
self.b.pmul(s);
}
pub fn tmul(&mut self, s: &FP) {
self.a.qmul(s);
self.b.qmul(s);
}
pub fn imul(&mut self, c: isize) {
self.a.imul(c);
self.b.imul(c);
}
pub fn sqr(&mut self) {
let mut t1 = FP4::new_copy(&self.a);
let mut t2 = FP4::new_copy(&self.b);
let mut t3 = FP4::new_copy(&self.a);
t3.mul(&self.b);
t1.add(&self.b);
t2.times_i();
t2.add(&self.a);
t1.norm();
t2.norm();
self.a.copy(&t1);
self.a.mul(&t2);
t2.copy(&t3);
t2.times_i();
t2.add(&t3);
t2.norm();
t2.neg();
self.a.add(&t2);
t3.dbl();
self.b.copy(&t3);
self.norm();
}
pub fn mul(&mut self, y: &FP8) {
let mut t1 = FP4::new_copy(&self.a);
let mut t2 = FP4::new_copy(&self.b);
let mut t3 = FP4::new();
let mut t4 = FP4::new_copy(&self.b);
t1.mul(&y.a);
t2.mul(&y.b);
t3.copy(&y.b);
t3.add(&y.a);
t4.add(&self.a);
t3.norm();
t4.norm();
t4.mul(&t3);
t3.copy(&t1);
t3.neg();
t4.add(&t3);
t4.norm();
t3.copy(&t2);
t3.neg();
self.b.copy(&t4);
self.b.add(&t3);
t2.times_i();
self.a.copy(&t2);
self.a.add(&t1);
self.norm();
}
#[cfg(feature = "std")]
pub fn tostring(&self) -> String {
format!("[{},{}]", self.a.tostring(), self.b.tostring())
}
pub fn inverse(&mut self,h:Option<&FP>) {
let mut t1 = FP4::new_copy(&self.a);
let mut t2 = FP4::new_copy(&self.b);
t1.sqr();
t2.sqr();
t2.times_i();
t2.norm();
t1.sub(&t2);
t1.norm();
t1.inverse(h);
self.a.mul(&t1);
t1.neg();
t1.norm();
self.b.mul(&t1);
}
pub fn times_i(&mut self) {
let mut s = FP4::new_copy(&self.b);
let t = FP4::new_copy(&self.a);
s.times_i();
self.a.copy(&s);
self.b.copy(&t);
self.norm();
if fp::TOWER == fp::POSITOWER {
self.neg();
self.norm();
}
}
pub fn times_i2(&mut self) {
self.a.times_i();
self.b.times_i();
}
pub fn frob(&mut self, f: &FP2) {
let mut ff = FP2::new_copy(f);
ff.sqr();
ff.mul_ip();
ff.norm();
self.a.frob(&ff);
self.b.frob(&ff);
self.b.pmul(f);
self.b.times_i();
}
pub fn div2(&mut self) {
self.a.div2();
self.b.div2();
}
pub fn div_i(&mut self) {
let mut u = FP4::new_copy(&self.a);
let v = FP4::new_copy(&self.b);
u.div_i();
self.a.copy(&v);
self.b.copy(&u);
if fp::TOWER == fp::POSITOWER {
self.neg();
self.norm();
}
}
pub fn qr(&mut self,h:Option<&mut FP>) -> isize {
let mut c=FP8::new_copy(self);
c.conj();
c.mul(self);
return c.geta().qr(h);
}
pub fn sqrt(&mut self,h:Option<&FP>) {
if self.iszilch() {
return;
}
let mut a = FP4::new_copy(&self.a);
let mut b = FP4::new_copy(&self.a);
let mut s = FP4::new_copy(&self.b);
let mut t = FP4::new_copy(&self.a);
let mut hint = FP::new();
s.sqr();
a.sqr();
s.times_i();
s.norm();
a.sub(&s);
s.copy(&a); s.norm();
s.sqrt(h);
a.copy(&t);
a.add(&s);
a.norm();
a.div2();
b.copy(&self.b); b.div2();
let qr=a.qr(Some(&mut hint));
s.copy(&a);
let mut twk = FP::new_big(&BIG::new_ints(&rom::TWK));
twk.mul(&hint);
s.div_i(); s.norm();
a.cmove(&s,1-qr);
hint.cmove(&twk,1-qr);
self.a.copy(&a); self.a.sqrt(Some(&hint));
s.copy(&a); s.inverse(Some(&hint));
s.mul(&self.a);
self.b.copy(&s); self.b.mul(&b);
t.copy(&self.a);
self.a.cmove(&self.b,1-qr);
self.b.cmove(&t,1-qr);
let sgn=self.sign();
let mut nr=FP8::new_copy(&self);
nr.neg(); nr.norm();
self.cmove(&nr,sgn);
}
}