use crate::fields::fp::{fp_from_hex, fp_from_mont, Fp};
use crate::fields::FieldElement;
#[derive(Debug, Copy, Clone)]
pub struct Fp2 {
pub(crate) c0: Fp,
pub(crate) c1: Fp,
}
impl Fp2 {
pub(crate) fn fp_mul_fp(&self, k: &Fp) -> Fp2 {
Fp2 {
c0: self.c0.fp_mul(k),
c1: self.c1.fp_mul(k),
}
}
}
impl PartialEq for Fp2 {
fn eq(&self, other: &Self) -> bool {
self.c0.eq(&other.c0) && self.c1.eq(&other.c1)
}
}
impl Eq for Fp2 {}
impl FieldElement for Fp2 {
fn zero() -> Self {
Fp2 {
c0: Fp::zero(),
c1: Fp::zero(),
}
}
fn one() -> Self {
Fp2 {
c0: Fp::one(),
c1: Fp::zero(),
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero()
}
fn fp_sqr(&self) -> Self {
let mut r0 = Fp::zero();
let mut r1 = Fp::zero();
let mut t0 = Fp::zero();
let mut t1 = Fp::zero();
r1 = self.c0.fp_mul(&self.c1);
t0 = self.c0.fp_add(&self.c1);
t1 = self.c1.fp_double();
t1 = self.c0.fp_sub(&t1);
r0 = t0.fp_mul(&t1);
r0 = r0.fp_add(&r1);
r1 = r1.fp_double();
Self { c0: r0, c1: r1 }
}
fn fp_double(&self) -> Self {
Fp2 {
c0: self.c0.fp_double(),
c1: self.c1.fp_double(),
}
}
fn fp_triple(&self) -> Self {
Fp2 {
c0: self.c0.fp_triple(),
c1: self.c1.fp_triple(),
}
}
fn fp_add(&self, rhs: &Self) -> Self {
Fp2 {
c0: self.c0.fp_add(&rhs.c0),
c1: self.c1.fp_add(&rhs.c1),
}
}
fn fp_sub(&self, rhs: &Self) -> Self {
Fp2 {
c0: self.c0.fp_sub(&rhs.c0),
c1: self.c1.fp_sub(&rhs.c1),
}
}
fn fp_mul(&self, rhs: &Self) -> Self {
let mut r0 = Fp::zero();
let mut r1 = Fp::zero();
let mut t = Fp::zero();
r0 = self.c0.fp_add(&self.c1);
t = rhs.c0.fp_add(&rhs.c1);
r1 = t.fp_mul(&r0);
r0 = self.c0.fp_mul(&rhs.c0);
t = self.c1.fp_mul(&rhs.c1);
r1 = r1.fp_sub(&r0);
r1 = r1.fp_sub(&t);
t = t.fp_double();
r0 = r0.fp_sub(&t);
Self { c0: r0, c1: r1 }
}
fn fp_neg(&self) -> Self {
Fp2 {
c0: self.c0.fp_neg(),
c1: self.c1.fp_neg(),
}
}
fn fp_div2(&self) -> Self {
Fp2 {
c0: self.c0.fp_div2(),
c1: self.c1.fp_div2(),
}
}
fn fp_inv(&self) -> Self {
let mut r: Fp2 = Fp2::zero();
let mut k = Fp::zero();
let mut t = Fp::zero();
let mut r0 = Fp::zero();
let mut r1 = Fp::zero();
if self.c0.is_zero() {
r1 = self.c1.fp_double();
r1 = self.c1.fp_inv();
r1 = r1.fp_neg();
} else if self.c1.is_zero() {
r0 = self.c0.fp_inv();
} else {
k = self.c0.fp_sqr();
t = self.c1.fp_sqr();
t = t.fp_double();
k = k.fp_add(&t);
k = k.fp_inv();
r0 = self.c0.fp_mul(&k);
r1 = self.c1.fp_mul(&k);
r1 = r1.fp_neg();
}
r.c0 = r0;
r.c1 = r1;
r
}
fn to_bytes_be(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(&self.c1.to_bytes_be().as_slice());
bytes.extend_from_slice(&self.c0.to_bytes_be().as_slice());
bytes
}
}
impl Fp2 {
pub(crate) fn div(&self, rhs: &Self) -> Self {
let t = rhs.fp_inv();
self.fp_mul(&t)
}
pub(crate) fn conjugate(&self) -> Self {
let r0 = self.c0;
let r1 = self.c1.fp_neg();
Self { c0: r0, c1: r1 }
}
pub(crate) fn a_mul_u(&self) -> Self {
let mut r0 = Fp::zero();
let mut a0 = Fp::zero();
let mut a1 = Fp::zero();
a0 = self.c0;
a1 = self.c1;
r0 = a1.fp_double();
r0 = r0.fp_neg();
Self { c0: r0, c1: a0 }
}
pub(crate) fn fp_mul_u(&self, rhs: &Self) -> Self {
let mut t0 = Fp::zero();
let mut t1 = Fp::zero();
let mut t2 = Fp::zero();
t0 = self.c0.fp_add(&self.c1);
t1 = rhs.c0.fp_add(&rhs.c1);
t2 = t0.fp_mul(&t1);
t0 = self.c0.fp_mul(&rhs.c0);
t1 = self.c1.fp_mul(&rhs.c1);
t2 = t2.fp_sub(&t0);
t2 = t2.fp_sub(&t1);
t2 = t2.fp_double();
t2 = t2.fp_neg();
t0 = t0.fp_sub(&t1.fp_double());
Self { c0: t2, c1: t0 }
}
pub(crate) fn sqr_u(&self) -> Self {
let mut r: Fp2 = Fp2::zero();
let mut r0 = Fp::zero();
let mut r1 = Fp::zero();
let mut t = Fp::zero();
r0 = self.c0.fp_mul(&self.c1);
r0 = r0.fp_double();
r0 = r0.fp_double();
r0 = r0.fp_neg();
r1 = self.c0.fp_sqr();
t = self.c1.fp_sqr();
t = t.fp_double();
r1 = r1.fp_sub(&t);
r.c0 = r0;
r.c1 = r1;
r
}
pub fn from_hex(hex: [&str; 2]) -> Fp2 {
Fp2 {
c0: fp_from_hex(hex[0]),
c1: fp_from_hex(hex[1]),
}
}
}
#[cfg(test)]
mod test_mod_operation {
use crate::fields::fp::{fp_from_mont, fp_to_mont};
use crate::fields::fp2::Fp2;
use crate::fields::FieldElement;
#[test]
fn test_mod_op() {
let mut a: Fp2 = Fp2 {
c0: [
0x6215BBA5C999A7C7,
0x47EFBA98A71A0811,
0x5F3170153D278FF2,
0xA7CF28D519BE3DA6,
],
c1: [
0x856DC76B84EBEB96,
0x0736A96FA347C8BD,
0x66BA0D262CBEE6ED,
0x17509B092E845C12,
],
};
let mut b: Fp2 = Fp2 {
c0: [
0x8F14D65696EA5E32,
0x414D2177386A92DD,
0x6CE843ED24A3B573,
0x29DBA116152D1F78,
],
c1: [
0x0AB1B6791B94C408,
0x1CE0711C5E392CFB,
0xE48AFF4B41B56501,
0x9F64080B3084F733,
],
};
a.c0 = fp_to_mont(&a.c0);
a.c1 = fp_to_mont(&a.c1);
b.c0 = fp_to_mont(&b.c0);
b.c1 = fp_to_mont(&b.c1);
let mut r = a.fp_add(&b);
r.c0 = fp_from_mont(&r.c0);
r.c1 = fp_from_mont(&r.c1);
r.c0.reverse();
r.c1.reverse();
println!("fp_add ={:x?}", r); }
}