use std::fmt::Debug;
pub mod ff_p434;
pub mod ff_p503;
pub mod ff_p610;
pub mod ff_p751;
pub use crate::ff::{
ff_p434::PrimeFieldP434, ff_p503::PrimeFieldP503, ff_p610::PrimeFieldP610,
ff_p751::PrimeFieldP751,
};
pub trait FiniteField: Sized {
fn is_zero(&self) -> bool;
fn dimension() -> usize;
fn zero() -> Self;
fn one() -> Self;
fn neg(&self) -> Self;
fn inv(&self) -> Result<Self, String>;
fn add(&self, other: &Self) -> Self;
fn sub(&self, other: &Self) -> Self;
fn mul(&self, other: &Self) -> Self;
fn div(&self, other: &Self) -> Result<Self, String>;
fn equals(&self, other: &Self) -> bool;
fn into_bytes(self) -> Vec<u8>;
fn from_bytes(bytes: &[u8]) -> Result<Self, String>;
}
#[derive(Clone, Copy, PartialEq)]
pub struct QuadraticExtension<F: FiniteField> {
a: F,
b: F,
}
impl<F: FiniteField + Debug> Debug for QuadraticExtension<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} + i {:?}", self.a, self.b)
}
}
impl<F: FiniteField> QuadraticExtension<F> {
pub fn from(a: F, b: F) -> Self {
Self { a, b }
}
}
impl<F: FiniteField + Debug> FiniteField for QuadraticExtension<F> {
fn is_zero(&self) -> bool {
self.a.is_zero() && self.b.is_zero()
}
fn dimension() -> usize {
2 * F::dimension()
}
fn zero() -> Self {
Self {
a: F::zero(),
b: F::zero(),
}
}
fn one() -> Self {
Self {
a: F::one(),
b: F::zero(),
}
}
fn neg(&self) -> Self {
Self {
a: self.a.neg(),
b: self.b.neg(),
}
}
fn add(&self, other: &Self) -> Self {
Self {
a: self.a.add(&other.a),
b: self.b.add(&other.b),
}
}
fn sub(&self, other: &Self) -> Self {
self.add(&other.neg())
}
fn div(&self, other: &Self) -> Result<Self, String> {
Ok(self.mul(&other.inv()?))
}
fn mul(&self, other: &Self) -> Self {
let m1 = self.a.mul(&other.a);
let m2 = self.b.mul(&other.b);
let m3 = self.a.mul(&other.b);
let m4 = other.a.mul(&self.b);
Self {
a: m1.sub(&m2),
b: m3.add(&m4),
}
}
fn inv(&self) -> Result<Self, String> {
let asq = self.a.mul(&self.a);
let bsq = self.b.mul(&self.b);
let inv_norm = asq.add(&bsq).inv()?;
Ok(Self {
a: inv_norm.mul(&self.a),
b: inv_norm.mul(&self.b.neg()),
})
}
fn equals(&self, other: &Self) -> bool {
self.a.equals(&other.a) && self.b.equals(&other.b)
}
fn into_bytes(self) -> Vec<u8> {
use crate::utils::conversion::concatenate;
let part1 = self.a.into_bytes();
let part2 = self.b.into_bytes();
let p21 = part1.len().next_power_of_two();
let p22 = part2.len().next_power_of_two();
let len = std::cmp::max(p21, p22);
let pad1 = vec![0; len - part1.len()];
let pad2 = vec![0; len - part2.len()];
concatenate(&[&pad1, &part1, &pad2, &part2])
}
fn from_bytes(bytes: &[u8]) -> Result<Self, String> {
let n = bytes.len() / 2;
let a = F::from_bytes(&bytes[..n])?;
let b = F::from_bytes(&bytes[n..])?;
Ok(Self::from(a, b))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::cs_p434::{SIKE_P434_XP20, SIKE_P434_XP21};
#[test]
fn test_conversion_ff434_bytes() {
let num = PrimeFieldP434::from_string(SIKE_P434_XP20).unwrap();
let b = num.clone().into_bytes();
let num_recovered = PrimeFieldP434::from_bytes(&b).unwrap();
println!("{:?}", num);
println!("{:?}", num_recovered);
assert!(num.equals(&num_recovered));
}
#[test]
fn test_conversion_quadratic_bytes() {
let num1 = PrimeFieldP434::from_string(SIKE_P434_XP20).unwrap();
let num2 = PrimeFieldP434::from_string(SIKE_P434_XP21).unwrap();
let q = QuadraticExtension::from(num1, num2);
let b = q.clone().into_bytes();
let q_recovered = QuadraticExtension::from_bytes(&b).unwrap();
println!("{:?}", q);
println!("{:?}", q_recovered);
assert!(q.equals(&q_recovered));
}
#[test]
fn test_ff() {
let one = PrimeFieldP434::one();
let two = one.add(&one);
let three = two.add(&one);
let four1 = two.add(&two);
let four2 = two.mul(&two);
let zero = one.sub(&one);
println!("zero = {:?}", zero);
println!("one = {:?}", one);
println!("two = {:?}", two);
println!("three = {:?}", three);
println!("four1 = {:?}", four1);
println!("four2 = {:?}", four2);
}
#[test]
fn test_qff() {
let one = PrimeFieldP434::one();
let two = one.add(&one);
let x = QuadraticExtension::from(two.clone(), two.clone());
let eight_i = x.mul(&x);
println!("eight_i = {:?}", eight_i);
let two_plus_two_i = eight_i.div(&x).unwrap();
println!("two_plus_two_i = {:?}", two_plus_two_i);
assert_eq!(two_plus_two_i, x)
}
}