[feat] impl SerdeObject for ext2/3

This commit is contained in:
zhenfei
2023-12-01 21:07:56 -05:00
parent def46699ed
commit 7fb587f726
5 changed files with 183 additions and 67 deletions

View File

@@ -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())
}
}

View File

@@ -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()
}
}

View File

@@ -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()

View File

@@ -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.

View File

@@ -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;