use miden_core::Felt;
use super::spec::{Limbs, UintSpec};
use crate::math::{k1_base::K1Base, k1_scalar::K1Scalar, u256::U256};
pub const U256_BOUND_PTR: u32 = 1;
pub const K1_BASE_BOUND_PTR: u32 = 2;
pub const K1_SCALAR_BOUND_PTR: u32 = 3;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UintDomain {
U256,
K1Base,
K1Scalar,
}
impl UintDomain {
pub const ALL: [Self; 3] = [Self::U256, Self::K1Base, Self::K1Scalar];
pub fn from_id(id: Felt) -> Option<Self> {
match id {
id if id == <U256 as UintSpec>::ID => Some(Self::U256),
id if id == <K1Base as UintSpec>::ID => Some(Self::K1Base),
id if id == <K1Scalar as UintSpec>::ID => Some(Self::K1Scalar),
_ => None,
}
}
pub fn id(self) -> Felt {
match self {
Self::U256 => <U256 as UintSpec>::ID,
Self::K1Base => <K1Base as UintSpec>::ID,
Self::K1Scalar => <K1Scalar as UintSpec>::ID,
}
}
pub const fn bound_ptr(self) -> u32 {
match self {
Self::U256 => U256_BOUND_PTR,
Self::K1Base => K1_BASE_BOUND_PTR,
Self::K1Scalar => K1_SCALAR_BOUND_PTR,
}
}
pub const fn from_bound_ptr(ptr: u32) -> Option<Self> {
match ptr {
U256_BOUND_PTR => Some(Self::U256),
K1_BASE_BOUND_PTR => Some(Self::K1Base),
K1_SCALAR_BOUND_PTR => Some(Self::K1Scalar),
_ => None,
}
}
pub fn encoded_modulus(self) -> Limbs {
match self {
Self::U256 => <U256 as UintSpec>::ENCODED_MODULUS,
Self::K1Base => <K1Base as UintSpec>::ENCODED_MODULUS,
Self::K1Scalar => <K1Scalar as UintSpec>::ENCODED_MODULUS,
}
}
pub fn is_prime_field(self) -> bool {
match self {
Self::U256 => <U256 as UintSpec>::IS_PRIME_FIELD,
Self::K1Base => <K1Base as UintSpec>::IS_PRIME_FIELD,
Self::K1Scalar => <K1Scalar as UintSpec>::IS_PRIME_FIELD,
}
}
pub fn is_canonical(self, value: &Limbs) -> bool {
match self {
Self::U256 => U256::is_canonical(value),
Self::K1Base => K1Base::is_canonical(value),
Self::K1Scalar => K1Scalar::is_canonical(value),
}
}
pub fn add(self, lhs: Limbs, rhs: Limbs) -> Limbs {
match self {
Self::U256 => U256::add(lhs, rhs),
Self::K1Base => K1Base::add(lhs, rhs),
Self::K1Scalar => K1Scalar::add(lhs, rhs),
}
}
pub fn sub(self, lhs: Limbs, rhs: Limbs) -> Limbs {
match self {
Self::U256 => U256::sub(lhs, rhs),
Self::K1Base => K1Base::sub(lhs, rhs),
Self::K1Scalar => K1Scalar::sub(lhs, rhs),
}
}
pub fn mul(self, lhs: Limbs, rhs: Limbs) -> Limbs {
match self {
Self::U256 => U256::mul(lhs, rhs),
Self::K1Base => K1Base::mul(lhs, rhs),
Self::K1Scalar => K1Scalar::mul(lhs, rhs),
}
}
pub fn inv(self, value: Limbs) -> Option<Limbs> {
match self {
Self::U256 => U256::inv(value),
Self::K1Base => K1Base::inv(value),
Self::K1Scalar => K1Scalar::inv(value),
}
}
pub fn max(self) -> Option<Limbs> {
match self {
Self::U256 => Some(U256::MAX),
_ => None,
}
}
pub fn minus_one(self) -> Limbs {
match self {
Self::U256 => U256::minus_one(),
Self::K1Base => K1Base::minus_one(),
Self::K1Scalar => K1Scalar::minus_one(),
}
}
pub fn half(self) -> Option<Limbs> {
match self {
Self::U256 => U256::half(),
Self::K1Base => K1Base::half(),
Self::K1Scalar => K1Scalar::half(),
}
}
pub fn pow2_mod(self, exponent: usize) -> Option<Limbs> {
match self {
Self::U256 => U256::pow2_mod(exponent),
Self::K1Base => K1Base::pow2_mod(exponent),
Self::K1Scalar => K1Scalar::pow2_mod(exponent),
}
}
pub fn field_constants(self) -> Option<[Limbs; 5]> {
if self.is_prime_field() {
Some([
self.minus_one(),
self.half()?,
self.pow2_mod(128)?,
self.pow2_mod(256)?,
self.pow2_mod(384)?,
])
} else {
None
}
}
}