use core::ops::{Add, Mul, Sub};
use miden_core::field::PrimeCharacteristicRing;
use miden_crypto::stark::air::AirBuilder;
const W: u16 = 7;
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct QuadFeltExpr<E>(pub E, pub E);
impl<E> QuadFeltExpr<E> {
pub fn new(c0: impl Into<E>, c1: impl Into<E>) -> Self {
Self(c0.into(), c1.into())
}
pub fn into_parts(self) -> [E; 2] {
[self.0, self.1]
}
pub fn into_expr<O>(self) -> QuadFeltExpr<O>
where
E: Into<O>,
{
QuadFeltExpr(self.0.into(), self.1.into())
}
}
impl<E: PrimeCharacteristicRing> QuadFeltExpr<E> {
pub fn double(self) -> Self {
Self(self.0.double(), self.1.double())
}
pub fn square(self) -> Self {
let w = E::from_u16(W);
let a0_sq = self.0.clone() * self.0.clone();
let a1_sq = self.1.clone() * self.1.clone();
let a0_a1 = self.0 * self.1;
let c0 = a0_sq + w * a1_sq;
let c1 = a0_a1.double();
Self(c0, c1)
}
fn ext_mul(self, rhs: Self) -> Self {
let w = E::from_u16(W);
let c0 = self.0.clone() * rhs.0.clone() + w * (self.1.clone() * rhs.1.clone());
let c1 = self.0 * rhs.1 + self.1 * rhs.0;
Self(c0, c1)
}
}
impl<E> Add for QuadFeltExpr<E>
where
E: PrimeCharacteristicRing,
{
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0, self.1 + rhs.1)
}
}
impl<E> Sub for QuadFeltExpr<E>
where
E: PrimeCharacteristicRing,
{
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0, self.1 - rhs.1)
}
}
impl<E> Mul for QuadFeltExpr<E>
where
E: PrimeCharacteristicRing,
{
type Output = Self;
fn mul(self, rhs: Self) -> Self {
self.ext_mul(rhs)
}
}
impl<E> Add<E> for QuadFeltExpr<E>
where
E: PrimeCharacteristicRing,
{
type Output = Self;
fn add(self, rhs: E) -> Self {
Self(self.0 + rhs, self.1)
}
}
impl<E> Sub<E> for QuadFeltExpr<E>
where
E: PrimeCharacteristicRing,
{
type Output = Self;
fn sub(self, rhs: E) -> Self {
Self(self.0 - rhs, self.1)
}
}
impl<E> Mul<E> for QuadFeltExpr<E>
where
E: PrimeCharacteristicRing,
{
type Output = Self;
fn mul(self, rhs: E) -> Self {
Self(self.0 * rhs.clone(), self.1 * rhs)
}
}
pub trait QuadFeltAirBuilder: AirBuilder {
fn assert_eq_quad(&mut self, lhs: QuadFeltExpr<Self::Expr>, rhs: QuadFeltExpr<Self::Expr>) {
self.assert_eq(lhs.0, rhs.0);
self.assert_eq(lhs.1, rhs.1);
}
}
impl<AB: AirBuilder> QuadFeltAirBuilder for AB {}