use crate::bls48556::big;
use crate::bls48556::big::BIG;
use crate::bls48556::fp::FP;
use crate::bls48556::fp2::FP2;
use crate::bls48556::fp8::FP8;
#[derive(Copy, Clone)]
pub struct FP16 {
a: FP8,
b: FP8,
}
#[cfg(feature = "std")]
impl std::fmt::Debug for FP16 {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "{}", self.tostring())
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for FP16 {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "{}", self.tostring())
}
}
impl FP16 {
pub const fn new() -> FP16 {
FP16 {
a: FP8::new(),
b: FP8::new(),
}
}
pub fn new_int(a: isize) -> FP16 {
let mut f = FP16::new();
f.a.copy(&FP8::new_int(a));
f.b.zero();
f
}
pub fn new_copy(x: &FP16) -> FP16 {
let mut f = FP16::new();
f.a.copy(&x.a);
f.b.copy(&x.b);
f
}
pub fn new_fp8s(c: &FP8, d: &FP8) -> FP16 {
let mut f = FP16::new();
f.a.copy(c);
f.b.copy(d);
f
}
pub fn new_fp8(c: &FP8) -> FP16 {
let mut f = FP16::new();
f.a.copy(c);
f.b.zero();
f
}
pub fn set_fp8s(&mut self, c: &FP8, d: &FP8) {
self.a.copy(&c);
self.b.copy(&d);
}
pub fn set_fp8(&mut self, c: &FP8) {
self.a.copy(&c);
self.b.zero();
}
pub fn set_fp8h(&mut self, c: &FP8) {
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: &FP16, 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 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]) -> FP16 {
const MB:usize = 8*(big::MODBYTES as usize);
let mut t: [u8; MB] = [0; MB];
for i in 0..MB {
t[i]=bf[i];
}
let tb=FP8::frombytes(&t);
for i in 0..MB {
t[i]=bf[i+MB];
}
let ta=FP8::frombytes(&t);
FP16::new_fp8s(&ta,&tb)
}
pub fn isunity(&self) -> bool {
let one = FP8::new_int(1);
self.a.equals(&one) && self.b.iszilch()
}
pub fn isreal(&mut self) -> bool {
self.b.iszilch()
}
pub fn real(&self) -> FP8 {
FP8::new_copy(&self.a)
}
pub fn geta(&self) -> FP8 {
FP8::new_copy(&self.a)
}
pub fn getb(&self) -> FP8 {
FP8::new_copy(&self.b)
}
pub fn equals(&self, x: &FP16) -> bool {
self.a.equals(&x.a) && self.b.equals(&x.b)
}
pub fn copy(&mut self, x: &FP16) {
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) {
self.norm();
let mut m = FP8::new_copy(&self.a);
let mut t = FP8::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: &FP16) {
self.a.add(&x.a);
self.b.add(&x.b);
}
pub fn padd(&mut self, x: &FP8) {
self.a.add(x);
}
pub fn dbl(&mut self) {
self.a.dbl();
self.b.dbl();
}
pub fn sub(&mut self, x: &FP16) {
let mut m = FP16::new_copy(x);
m.neg();
self.add(&m);
}
pub fn rsub(&mut self, x: &FP16) {
self.neg();
self.add(x);
}
pub fn pmul(&mut self, s: &FP8) {
self.a.mul(s);
self.b.mul(s);
}
pub fn qmul(&mut self, s: &FP2) {
self.a.qmul(s);
self.b.qmul(s);
}
pub fn tmul(&mut self, s: &FP) {
self.a.tmul(s);
self.b.tmul(s);
}
pub fn imul(&mut self, c: isize) {
self.a.imul(c);
self.b.imul(c);
}
pub fn sqr(&mut self) {
let mut t1 = FP8::new_copy(&self.a);
let mut t2 = FP8::new_copy(&self.b);
let mut t3 = FP8::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: &FP16) {
let mut t1 = FP8::new_copy(&self.a);
let mut t2 = FP8::new_copy(&self.b);
let mut t3 = FP8::new();
let mut t4 = FP8::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) {
let mut t1 = FP8::new_copy(&self.a);
let mut t2 = FP8::new_copy(&self.b);
t1.sqr();
t2.sqr();
t2.times_i();
t2.norm();
t1.sub(&t2);
t1.norm();
t1.inverse(None);
self.a.mul(&t1);
t1.neg();
t1.norm();
self.b.mul(&t1);
}
pub fn times_i(&mut self) {
let mut s = FP8::new_copy(&self.b);
let t = FP8::new_copy(&self.a);
s.times_i();
self.a.copy(&s);
self.b.copy(&t);
self.norm();
}
pub fn times_i2(&mut self) {
self.a.times_i();
self.b.times_i();
}
pub fn times_i4(&mut self) {
self.a.times_i2();
self.b.times_i2();
}
pub fn frob(&mut self, f: &FP2) {
let mut ff = FP2::new_copy(f);
ff.sqr();
ff.norm();
self.a.frob(&ff);
self.b.frob(&ff);
self.b.qmul(f);
self.b.times_i();
}
pub fn pow(&self, e: &BIG) -> FP16 {
let mut w = FP16::new_copy(self);
w.norm();
let mut z = BIG::new_copy(&e);
let mut r = FP16::new_int(1);
z.norm();
loop {
let bt = z.parity();
z.fshr(1);
if bt == 1 {
r.mul(&mut w)
};
if z.iszilch() {
break;
}
w.sqr();
}
r.reduce();
r
}
}