mirror of
https://github.com/pseXperiments/ff-Goldilocks.git
synced 2026-01-09 04:57:59 -05:00
[feat] impl SerdeObject for ext2/3
This commit is contained in:
@@ -1,15 +1,6 @@
|
||||
macro_rules! impl_extension_field {
|
||||
($base_field:ident, $ext_field:ident, $degree: expr) => {
|
||||
impl $ext_field {
|
||||
pub fn to_canonical_u64_array(&self) -> [u64; $degree] {
|
||||
self.0
|
||||
.iter()
|
||||
.map(|a| a.to_canonical_u64())
|
||||
.collect::<Vec<u64>>()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn new_from_base(base_elems: &[$base_field]) -> Self {
|
||||
Self(base_elems.try_into().unwrap())
|
||||
}
|
||||
@@ -17,8 +8,8 @@ macro_rules! impl_extension_field {
|
||||
|
||||
impl ConstantTimeEq for $ext_field {
|
||||
fn ct_eq(&self, other: &Self) -> Choice {
|
||||
self.to_canonical_u64_array()
|
||||
.ct_eq(&other.to_canonical_u64_array())
|
||||
self.to_canonical_u64_vec()
|
||||
.ct_eq(&other.to_canonical_u64_vec())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
56
src/field.rs
56
src/field.rs
@@ -1,20 +1,74 @@
|
||||
//! This module defines our customized field trait.
|
||||
|
||||
use ff::PrimeField;
|
||||
use halo2curves::serde::SerdeObject;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{fp2::GoldilocksExt2, Goldilocks, GoldilocksExt3};
|
||||
|
||||
pub trait SmallField: PrimeField + Serialize {
|
||||
pub trait SmallField: PrimeField + Serialize + SerdeObject {
|
||||
/// Extension degree of the Field
|
||||
const DEGREE: usize;
|
||||
/// Identifier string
|
||||
const NAME: &'static str;
|
||||
/// Convert a byte string into a list of field elements
|
||||
fn bytes_to_field_elements(bytes: &[u8]) -> Vec<Self>;
|
||||
/// Convert a field elements to a u64 vector
|
||||
fn to_canonical_u64_vec(&self) -> Vec<u64>;
|
||||
}
|
||||
|
||||
impl SmallField for Goldilocks {
|
||||
const DEGREE: usize = 1;
|
||||
const NAME: &'static str = "Goldilocks";
|
||||
|
||||
fn bytes_to_field_elements(bytes: &[u8]) -> Vec<Self> {
|
||||
bytes
|
||||
.chunks(8)
|
||||
.map(|chunk| Self::from_raw_bytes_unchecked(chunk))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn to_canonical_u64_vec(&self) -> Vec<u64> {
|
||||
vec![self.to_canonical_u64()]
|
||||
}
|
||||
}
|
||||
impl SmallField for GoldilocksExt2 {
|
||||
const DEGREE: usize = 2;
|
||||
const NAME: &'static str = "GoldilocksExt2";
|
||||
|
||||
fn bytes_to_field_elements(bytes: &[u8]) -> Vec<Self> {
|
||||
bytes
|
||||
.chunks(16)
|
||||
.map(|chunk| Self::from_raw_bytes_unchecked(chunk))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn to_canonical_u64_vec(&self) -> Vec<u64> {
|
||||
self.0
|
||||
.iter()
|
||||
.map(|a| a.to_canonical_u64())
|
||||
.collect::<Vec<u64>>()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl SmallField for GoldilocksExt3 {
|
||||
const DEGREE: usize = 3;
|
||||
const NAME: &'static str = "GoldilocksExt3";
|
||||
|
||||
fn bytes_to_field_elements(bytes: &[u8]) -> Vec<Self> {
|
||||
bytes
|
||||
.chunks(24)
|
||||
.map(|chunk| Self::from_raw_bytes_unchecked(chunk))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn to_canonical_u64_vec(&self) -> Vec<u64> {
|
||||
self.0
|
||||
.iter()
|
||||
.map(|a| a.to_canonical_u64())
|
||||
.collect::<Vec<u64>>()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
11
src/fp.rs
11
src/fp.rs
@@ -18,15 +18,6 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Serialize, Deserialize)]
|
||||
pub struct Goldilocks(pub(crate) u64);
|
||||
|
||||
impl Goldilocks {
|
||||
pub fn bytes_to_field_elements(bytes: &[u8]) -> Vec<Self> {
|
||||
bytes
|
||||
.chunks(8)
|
||||
.map(|chunk| Self::from_raw_bytes_unchecked(chunk))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl SerdeObject for Goldilocks {
|
||||
/// The purpose of unchecked functions is to read the internal memory representation
|
||||
/// of a type from bytes as quickly as possible. No sanitization checks are performed
|
||||
@@ -50,11 +41,11 @@ impl SerdeObject for Goldilocks {
|
||||
|
||||
Self(tmp)
|
||||
}
|
||||
|
||||
fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
if bytes.len() > 8 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let tmp = u64::from_le_bytes(
|
||||
bytes
|
||||
.iter()
|
||||
|
||||
62
src/fp2.rs
62
src/fp2.rs
@@ -1,13 +1,17 @@
|
||||
//! This module implements Goldilocks quadratic extension field mod x^2 - 7
|
||||
|
||||
use crate::Goldilocks;
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use ff::{Field, PrimeField};
|
||||
use halo2curves::serde::SerdeObject;
|
||||
use rand_core::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::{Read, Write};
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
|
||||
use crate::field::SmallField;
|
||||
use crate::Goldilocks;
|
||||
|
||||
/// Degree 3 Goldilocks extension field mod x^2 - 7
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct GoldilocksExt2(pub [Goldilocks; 2]);
|
||||
@@ -33,11 +37,57 @@ fn mul_internal(a: &GoldilocksExt2, b: &GoldilocksExt2) -> GoldilocksExt2 {
|
||||
|
||||
impl_extension_field!(Goldilocks, GoldilocksExt2, 2);
|
||||
|
||||
// impl GoldilocksExt2 {
|
||||
// fn to_canonical_u64_array(&self) -> [u64; 2] {
|
||||
// [self.0[0].to_canonical_u64(), self.0[1].to_canonical_u64()]
|
||||
// }
|
||||
// }
|
||||
impl SerdeObject for GoldilocksExt2 {
|
||||
/// The purpose of unchecked functions is to read the internal memory representation
|
||||
/// of a type from bytes as quickly as possible. No sanitization checks are performed
|
||||
/// to ensure the bytes represent a valid object. As such this function should only be
|
||||
/// used internally as an extension of machine memory. It should not be used to deserialize
|
||||
/// externally provided data.
|
||||
fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
|
||||
Self([
|
||||
Goldilocks::from_raw_bytes_unchecked(bytes[..8].as_ref()),
|
||||
Goldilocks::from_raw_bytes_unchecked(bytes[8..].as_ref()),
|
||||
])
|
||||
}
|
||||
|
||||
fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
let a1 = match Goldilocks::from_raw_bytes(bytes[..8].as_ref()) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
let a2 = match Goldilocks::from_raw_bytes(bytes[8..].as_ref()) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
Some(Self([a1, a2]))
|
||||
}
|
||||
|
||||
fn to_raw_bytes(&self) -> Vec<u8> {
|
||||
[self.0[0].to_raw_bytes(), self.0[1].to_raw_bytes()].concat()
|
||||
}
|
||||
|
||||
/// The purpose of unchecked functions is to read the internal memory representation
|
||||
/// of a type from disk as quickly as possible. No sanitization checks are performed
|
||||
/// to ensure the bytes represent a valid object. This function should only be used
|
||||
/// internally when some machine state cannot be kept in memory (e.g., between runs)
|
||||
/// and needs to be reloaded as quickly as possible.
|
||||
fn read_raw_unchecked<R: Read>(reader: &mut R) -> Self {
|
||||
let a1 = Goldilocks::read_raw_unchecked(reader);
|
||||
let a2 = Goldilocks::read_raw_unchecked(reader);
|
||||
Self([a1, a2])
|
||||
}
|
||||
fn read_raw<R: Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let a1 = Goldilocks::read_raw(reader)?;
|
||||
let a2 = Goldilocks::read_raw(reader)?;
|
||||
Ok(Self([a1, a2]))
|
||||
}
|
||||
|
||||
fn write_raw<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
self.0[0].write_raw(writer)?;
|
||||
self.0[1].write_raw(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for GoldilocksExt2 {
|
||||
/// The zero element of the field, the additive identity.
|
||||
|
||||
108
src/fp3.rs
108
src/fp3.rs
@@ -1,13 +1,17 @@
|
||||
//! This module implements Goldilocks cubic extension field mod x^3-x-1
|
||||
|
||||
use crate::Goldilocks;
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use ff::{Field, PrimeField};
|
||||
use halo2curves::serde::SerdeObject;
|
||||
use rand_core::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::{Read, Write};
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
|
||||
use crate::field::SmallField;
|
||||
use crate::Goldilocks;
|
||||
|
||||
/// Degree 3 Goldilocks extension field mod x^3-x-1
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct GoldilocksExt3(pub [Goldilocks; 3]);
|
||||
@@ -39,15 +43,70 @@ fn mul_internal(a: &GoldilocksExt3, b: &GoldilocksExt3) -> GoldilocksExt3 {
|
||||
|
||||
impl_extension_field!(Goldilocks, GoldilocksExt3, 3);
|
||||
|
||||
// impl GoldilocksExt3 {
|
||||
// fn to_canonical_u64_array(&self) -> [u64; 3] {
|
||||
// [
|
||||
// self.0[0].to_canonical_u64(),
|
||||
// self.0[1].to_canonical_u64(),
|
||||
// self.0[2].to_canonical_u64(),
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
impl SerdeObject for GoldilocksExt3 {
|
||||
/// The purpose of unchecked functions is to read the internal memory representation
|
||||
/// of a type from bytes as quickly as possible. No sanitization checks are performed
|
||||
/// to ensure the bytes represent a valid object. As such this function should only be
|
||||
/// used internally as an extension of machine memory. It should not be used to deserialize
|
||||
/// externally provided data.
|
||||
fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
|
||||
Self([
|
||||
Goldilocks::from_raw_bytes_unchecked(bytes[..8].as_ref()),
|
||||
Goldilocks::from_raw_bytes_unchecked(bytes[8..16].as_ref()),
|
||||
Goldilocks::from_raw_bytes_unchecked(bytes[16..].as_ref()),
|
||||
])
|
||||
}
|
||||
|
||||
fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
let a1 = match Goldilocks::from_raw_bytes(bytes[..8].as_ref()) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
let a2 = match Goldilocks::from_raw_bytes(bytes[8..16].as_ref()) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
let a3 = match Goldilocks::from_raw_bytes(bytes[16..].as_ref()) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
Some(Self([a1, a2, a3]))
|
||||
}
|
||||
|
||||
fn to_raw_bytes(&self) -> Vec<u8> {
|
||||
[
|
||||
self.0[0].to_raw_bytes(),
|
||||
self.0[1].to_raw_bytes(),
|
||||
self.0[2].to_raw_bytes(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
||||
/// The purpose of unchecked functions is to read the internal memory representation
|
||||
/// of a type from disk as quickly as possible. No sanitization checks are performed
|
||||
/// to ensure the bytes represent a valid object. This function should only be used
|
||||
/// internally when some machine state cannot be kept in memory (e.g., between runs)
|
||||
/// and needs to be reloaded as quickly as possible.
|
||||
fn read_raw_unchecked<R: Read>(reader: &mut R) -> Self {
|
||||
let a1 = Goldilocks::read_raw_unchecked(reader);
|
||||
let a2 = Goldilocks::read_raw_unchecked(reader);
|
||||
let a3 = Goldilocks::read_raw_unchecked(reader);
|
||||
Self([a1, a2, a3])
|
||||
}
|
||||
fn read_raw<R: Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let a1 = Goldilocks::read_raw(reader)?;
|
||||
let a2 = Goldilocks::read_raw(reader)?;
|
||||
let a3 = Goldilocks::read_raw(reader)?;
|
||||
Ok(Self([a1, a2, a3]))
|
||||
}
|
||||
|
||||
fn write_raw<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
self.0[0].write_raw(writer)?;
|
||||
self.0[1].write_raw(writer)?;
|
||||
self.0[2].write_raw(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for GoldilocksExt3 {
|
||||
/// The zero element of the field, the additive identity.
|
||||
@@ -129,12 +188,6 @@ impl ConditionallySelectable for GoldilocksExt3 {
|
||||
}
|
||||
}
|
||||
|
||||
// impl ConstantTimeEq for GoldilocksExt3 {
|
||||
// fn ct_eq(&self, other: &Self) -> Choice {
|
||||
// self.to_canonical_u64_array()
|
||||
// .ct_eq(&other.to_canonical_u64_array())
|
||||
// }
|
||||
// }
|
||||
impl Neg for GoldilocksExt3 {
|
||||
type Output = Self;
|
||||
|
||||
@@ -157,29 +210,6 @@ impl Add for GoldilocksExt3 {
|
||||
}
|
||||
}
|
||||
|
||||
// impl<'a> Add<&'a GoldilocksExt3> for GoldilocksExt3 {
|
||||
// type Output = Self;
|
||||
|
||||
// #[inline]
|
||||
// fn add(self, rhs: &'a GoldilocksExt3) -> Self::Output {
|
||||
// self + *rhs
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl AddAssign for GoldilocksExt3 {
|
||||
// #[inline]
|
||||
// fn add_assign(&mut self, rhs: Self) {
|
||||
// *self = *self + rhs;
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<'a> AddAssign<&'a GoldilocksExt3> for GoldilocksExt3 {
|
||||
// #[inline]
|
||||
// fn add_assign(&mut self, rhs: &'a GoldilocksExt3) {
|
||||
// *self = *self + *rhs;
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Sub for GoldilocksExt3 {
|
||||
type Output = Self;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user