use super::{ExtensibleField, FieldElement, StarkField};
use core::{
convert::{TryFrom, TryInto},
fmt::{Debug, Display, Formatter},
mem,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
slice,
};
use utils::{
collections::Vec, string::ToString, AsBytes, ByteReader, ByteWriter, Deserializable,
DeserializationError, Randomizable, Serializable,
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(test)]
mod tests;
const M: u64 = 0xFFFFFFFF00000001;
const R2: u64 = 0xFFFFFFFE00000001;
const ELEMENT_BYTES: usize = core::mem::size_of::<u64>();
#[derive(Copy, Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(from = "u64", into = "u64"))]
pub struct BaseElement(u64);
impl BaseElement {
pub const fn new(value: u64) -> BaseElement {
Self(mont_red_cst((value as u128) * (R2 as u128)))
}
pub const fn from_mont(value: u64) -> BaseElement {
BaseElement(value)
}
pub const fn inner(&self) -> u64 {
self.0
}
#[inline(always)]
pub fn exp7(self) -> Self {
let x2 = self.square();
let x4 = x2.square();
let x3 = x2 * self;
x3 * x4
}
#[inline(always)]
pub fn mul_small(self, rhs: u32) -> Self {
let s = (self.inner() as u128) * (rhs as u128);
let s_hi = (s >> 64) as u64;
let s_lo = s as u64;
let z = (s_hi << 32) - s_hi;
let (res, over) = s_lo.overflowing_add(z);
BaseElement::from_mont(res.wrapping_add(0u32.wrapping_sub(over as u32) as u64))
}
}
impl FieldElement for BaseElement {
type PositiveInteger = u64;
type BaseField = Self;
const EXTENSION_DEGREE: usize = 1;
const ZERO: Self = Self::new(0);
const ONE: Self = Self::new(1);
const ELEMENT_BYTES: usize = ELEMENT_BYTES;
const IS_CANONICAL: bool = false;
#[inline]
fn double(self) -> Self {
let ret = (self.0 as u128) << 1;
let (result, over) = (ret as u64, (ret >> 64) as u64);
Self(result.wrapping_sub(M * over))
}
#[inline]
fn exp(self, power: Self::PositiveInteger) -> Self {
let mut b: Self;
let mut r = Self::ONE;
for i in (0..64).rev() {
r = r.square();
b = r;
b *= self;
let mask = -(((power >> i) & 1 == 1) as i64) as u64;
r.0 ^= mask & (r.0 ^ b.0);
}
r
}
#[inline]
#[allow(clippy::many_single_char_names)]
fn inv(self) -> Self {
let t2 = self.square() * self;
let t3 = t2.square() * self;
let t6 = exp_acc::<3>(t3, t3);
let t12 = exp_acc::<6>(t6, t6);
let t24 = exp_acc::<12>(t12, t12);
let t30 = exp_acc::<6>(t24, t6);
let t31 = t30.square() * self;
let t63 = exp_acc::<32>(t31, t31);
t63.square() * self
}
fn conjugate(&self) -> Self {
Self(self.0)
}
fn base_element(&self, i: usize) -> Self::BaseField {
match i {
0 => *self,
_ => panic!("element index must be 0, but was {i}"),
}
}
fn slice_as_base_elements(elements: &[Self]) -> &[Self::BaseField] {
elements
}
fn slice_from_base_elements(elements: &[Self::BaseField]) -> &[Self] {
elements
}
fn elements_as_bytes(elements: &[Self]) -> &[u8] {
let p = elements.as_ptr();
let len = elements.len() * Self::ELEMENT_BYTES;
unsafe { slice::from_raw_parts(p as *const u8, len) }
}
unsafe fn bytes_as_elements(bytes: &[u8]) -> Result<&[Self], DeserializationError> {
if bytes.len() % Self::ELEMENT_BYTES != 0 {
return Err(DeserializationError::InvalidValue(format!(
"number of bytes ({}) does not divide into whole number of field elements",
bytes.len(),
)));
}
let p = bytes.as_ptr();
let len = bytes.len() / Self::ELEMENT_BYTES;
if (p as usize) % mem::align_of::<u64>() != 0 {
return Err(DeserializationError::InvalidValue(
"slice memory alignment is not valid for this field element type".to_string(),
));
}
Ok(slice::from_raw_parts(p as *const Self, len))
}
fn zeroed_vector(n: usize) -> Vec<Self> {
let result = vec![0u64; n];
let mut v = core::mem::ManuallyDrop::new(result);
let p = v.as_mut_ptr();
let len = v.len();
let cap = v.capacity();
unsafe { Vec::from_raw_parts(p as *mut Self, len, cap) }
}
}
impl StarkField for BaseElement {
const MODULUS: Self::PositiveInteger = M;
const MODULUS_BITS: u32 = 64;
const GENERATOR: Self = Self::new(7);
const TWO_ADICITY: u32 = 32;
const TWO_ADIC_ROOT_OF_UNITY: Self = Self::new(7277203076849721926);
fn get_modulus_le_bytes() -> Vec<u8> {
M.to_le_bytes().to_vec()
}
#[inline]
fn as_int(&self) -> Self::PositiveInteger {
let x = self.0;
let (a, e) = x.overflowing_add(x << 32);
let b = a.wrapping_sub(a >> 32).wrapping_sub(e as u64);
let (r, c) = 0u64.overflowing_sub(b);
r.wrapping_sub(0u32.wrapping_sub(c as u32) as u64)
}
}
impl Randomizable for BaseElement {
const VALUE_SIZE: usize = Self::ELEMENT_BYTES;
fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
Self::try_from(bytes).ok()
}
}
impl Display for BaseElement {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "{}", self.as_int())
}
}
impl PartialEq for BaseElement {
#[inline]
fn eq(&self, other: &Self) -> bool {
equals(self.0, other.0) == 0xFFFFFFFFFFFFFFFF
}
}
impl Eq for BaseElement {}
impl Add for BaseElement {
type Output = Self;
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn add(self, rhs: Self) -> Self {
let (x1, c1) = self.0.overflowing_sub(M - rhs.0);
let adj = 0u32.wrapping_sub(c1 as u32);
Self(x1.wrapping_sub(adj as u64))
}
}
impl AddAssign for BaseElement {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs
}
}
impl Sub for BaseElement {
type Output = Self;
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn sub(self, rhs: Self) -> Self {
let (x1, c1) = self.0.overflowing_sub(rhs.0);
let adj = 0u32.wrapping_sub(c1 as u32);
Self(x1.wrapping_sub(adj as u64))
}
}
impl SubAssign for BaseElement {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl Mul for BaseElement {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Self(mont_red_cst((self.0 as u128) * (rhs.0 as u128)))
}
}
impl MulAssign for BaseElement {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs
}
}
impl Div for BaseElement {
type Output = Self;
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn div(self, rhs: Self) -> Self {
self * rhs.inv()
}
}
impl DivAssign for BaseElement {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs
}
}
impl Neg for BaseElement {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self::ZERO - self
}
}
impl ExtensibleField<2> for BaseElement {
#[inline(always)]
fn mul(a: [Self; 2], b: [Self; 2]) -> [Self; 2] {
let a0b0 = a[0] * b[0];
[
a0b0 - (a[1] * b[1]).double(),
(a[0] + a[1]) * (b[0] + b[1]) - a0b0,
]
}
#[inline(always)]
fn square(a: [Self; 2]) -> [Self; 2] {
let a0 = a[0];
let a1 = a[1];
let a1_sq = a1.square();
let out0 = a0.square() - a1_sq.double();
let out1 = (a0 * a1).double() + a1_sq;
[out0, out1]
}
#[inline(always)]
fn mul_base(a: [Self; 2], b: Self) -> [Self; 2] {
[a[0] * b, a[1] * b]
}
#[inline(always)]
fn frobenius(x: [Self; 2]) -> [Self; 2] {
[x[0] + x[1], -x[1]]
}
}
impl ExtensibleField<3> for BaseElement {
#[inline(always)]
fn mul(a: [Self; 3], b: [Self; 3]) -> [Self; 3] {
let a0b0 = a[0] * b[0];
let a1b1 = a[1] * b[1];
let a2b2 = a[2] * b[2];
let a0b0_a0b1_a1b0_a1b1 = (a[0] + a[1]) * (b[0] + b[1]);
let a0b0_a0b2_a2b0_a2b2 = (a[0] + a[2]) * (b[0] + b[2]);
let a1b1_a1b2_a2b1_a2b2 = (a[1] + a[2]) * (b[1] + b[2]);
let a0b0_minus_a1b1 = a0b0 - a1b1;
let a0b0_a1b2_a2b1 = a1b1_a1b2_a2b1_a2b2 + a0b0_minus_a1b1 - a2b2;
let a0b1_a1b0_a1b2_a2b1_a2b2 =
a0b0_a0b1_a1b0_a1b1 + a1b1_a1b2_a2b1_a2b2 - a1b1.double() - a0b0;
let a0b2_a1b1_a2b0_a2b2 = a0b0_a0b2_a2b0_a2b2 - a0b0_minus_a1b1;
[
a0b0_a1b2_a2b1,
a0b1_a1b0_a1b2_a2b1_a2b2,
a0b2_a1b1_a2b0_a2b2,
]
}
#[inline(always)]
fn square(a: [Self; 3]) -> [Self; 3] {
let a0 = a[0];
let a1 = a[1];
let a2 = a[2];
let a2_sq = a2.square();
let a1_a2 = a1 * a2;
let out0 = a0.square() + a1_a2.double();
let out1 = (a0 * a1 + a1_a2).double() + a2_sq;
let out2 = (a0 * a2).double() + a1.square() + a2_sq;
[out0, out1, out2]
}
#[inline(always)]
fn mul_base(a: [Self; 3], b: Self) -> [Self; 3] {
[a[0] * b, a[1] * b, a[2] * b]
}
#[inline(always)]
fn frobenius(x: [Self; 3]) -> [Self; 3] {
[
x[0] + Self::new(10615703402128488253) * x[1] + Self::new(6700183068485440220) * x[2],
Self::new(10050274602728160328) * x[1] + Self::new(14531223735771536287) * x[2],
Self::new(11746561000929144102) * x[1] + Self::new(8396469466686423992) * x[2],
]
}
}
impl From<u128> for BaseElement {
fn from(x: u128) -> Self {
Self(mont_red_cst(mont_red_cst(x) as u128)) }
}
impl From<u64> for BaseElement {
fn from(value: u64) -> Self {
Self::new(value)
}
}
impl From<u32> for BaseElement {
fn from(value: u32) -> Self {
Self::new(value as u64)
}
}
impl From<u16> for BaseElement {
fn from(value: u16) -> Self {
Self::new(value as u64)
}
}
impl From<u8> for BaseElement {
fn from(value: u8) -> Self {
Self::new(value as u64)
}
}
impl From<[u8; 8]> for BaseElement {
fn from(bytes: [u8; 8]) -> Self {
let value = u64::from_le_bytes(bytes);
Self::new(value)
}
}
impl<'a> TryFrom<&'a [u8]> for BaseElement {
type Error = DeserializationError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < ELEMENT_BYTES {
return Err(DeserializationError::InvalidValue(format!(
"not enough bytes for a full field element; expected {} bytes, but was {} bytes",
ELEMENT_BYTES,
bytes.len(),
)));
}
if bytes.len() > ELEMENT_BYTES {
return Err(DeserializationError::InvalidValue(format!(
"too many bytes for a field element; expected {} bytes, but was {} bytes",
ELEMENT_BYTES,
bytes.len(),
)));
}
let value = bytes
.try_into()
.map(u64::from_le_bytes)
.map_err(|error| DeserializationError::UnknownError(format!("{error}")))?;
if value >= M {
return Err(DeserializationError::InvalidValue(format!(
"invalid field element: value {value} is greater than or equal to the field modulus"
)));
}
Ok(Self::new(value))
}
}
impl From<BaseElement> for u128 {
fn from(value: BaseElement) -> Self {
value.as_int() as u128
}
}
impl From<BaseElement> for u64 {
fn from(value: BaseElement) -> Self {
value.as_int()
}
}
impl AsBytes for BaseElement {
fn as_bytes(&self) -> &[u8] {
let self_ptr: *const BaseElement = self;
unsafe { slice::from_raw_parts(self_ptr as *const u8, ELEMENT_BYTES) }
}
}
impl Serializable for BaseElement {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_bytes(&self.as_int().to_le_bytes());
}
}
impl Deserializable for BaseElement {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let value = source.read_u64()?;
if value >= M {
return Err(DeserializationError::InvalidValue(format!(
"invalid field element: value {value} is greater than or equal to the field modulus"
)));
}
Ok(Self::new(value))
}
}
#[inline(always)]
fn exp_acc<const N: usize>(base: BaseElement, tail: BaseElement) -> BaseElement {
let mut result = base;
for _ in 0..N {
result = result.square();
}
result * tail
}
#[allow(dead_code)]
#[inline(always)]
const fn mont_red_var(x: u128) -> u64 {
const NPRIME: u64 = 4294967297;
let q = (((x as u64) as u128) * (NPRIME as u128)) as u64;
let m = (q as u128) * (M as u128);
let y = (((x as i128).wrapping_sub(m as i128)) >> 64) as i64;
if x < m {
(y + (M as i64)) as u64
} else {
y as u64
}
}
#[inline(always)]
const fn mont_red_cst(x: u128) -> u64 {
let xl = x as u64;
let xh = (x >> 64) as u64;
let (a, e) = xl.overflowing_add(xl << 32);
let b = a.wrapping_sub(a >> 32).wrapping_sub(e as u64);
let (r, c) = xh.overflowing_sub(b);
r.wrapping_sub(0u32.wrapping_sub(c as u32) as u64)
}
#[inline(always)]
pub fn equals(lhs: u64, rhs: u64) -> u64 {
let t = lhs ^ rhs;
!((((t | t.wrapping_neg()) as i64) >> 63) as u64)
}