Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ extern crate alloc;
// ─── Generic field trait ─────────────────────────────────────────────────────

pub mod field;
#[macro_use]
mod macros;
pub mod proof;

// ─── New canonical API (Thaler §4.1) ────────────────────────────────────────
Expand Down
132 changes: 132 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! Exported convenience macros.

/// Define a thin newtype wrapper around a field type and implement
/// [`SumcheckField`](crate::field::SumcheckField) for it.
///
/// This is useful when integrating a field type from another ecosystem whose
/// trait impls cannot be implemented directly because of Rust's orphan rules.
///
/// ```ignore
/// effsc::sumcheck_field_newtype! {
/// pub struct MyField(OtherCrateField);
/// const ZERO = OtherCrateField::ZERO;
/// const ONE = OtherCrateField::ONE;
/// fn from_u64(val) { OtherCrateField::from_canonical_u64(val) }
/// fn inverse(self) { self.0.try_inverse() }
/// }
/// ```
#[macro_export]
macro_rules! sumcheck_field_newtype {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident($inner:ty);
const ZERO = $zero:expr;
const ONE = $one:expr;
fn from_u64($from_arg:ident) $from_u64:block
fn inverse($self_arg:ident) $inverse:block
) => {
$(#[$meta])*
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq)]
$vis struct $name($inner);

impl $name {
#[inline]
pub fn new(val: u64) -> Self {
<Self as $crate::field::SumcheckField>::from_u64(val)
}

#[inline]
pub const fn from_inner(inner: $inner) -> Self {
Self(inner)
}

#[inline]
pub fn into_inner(self) -> $inner {
self.0
}
}

impl core::fmt::Display for $name {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.0)
}
}

impl core::ops::Add for $name {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}

impl core::ops::Sub for $name {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}

impl core::ops::Mul for $name {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Self(self.0 * rhs.0)
}
}

impl core::ops::Neg for $name {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self(-self.0)
}
}

impl core::ops::AddAssign for $name {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}

impl core::ops::SubAssign for $name {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}

impl core::ops::MulAssign for $name {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}

impl core::iter::Sum for $name {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(<Self as $crate::field::SumcheckField>::ZERO, |acc, x| acc + x)
}
}

impl $crate::field::SumcheckField for $name {
const ZERO: Self = Self($zero);
const ONE: Self = Self($one);

#[inline]
fn from_u64($from_arg: u64) -> Self {
Self($from_u64)
}

#[inline]
fn inverse(&$self_arg) -> Option<Self> {
$inverse.map(Self)
}
}
};
}
92 changes: 8 additions & 84 deletions tests/plonky3_roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,102 +3,26 @@
//! Shows that any ecosystem's field type works with the sumcheck library
//! via a thin `SumcheckField` impl — no arkworks dependency required.

use effsc::field::SumcheckField;
use effsc::noop_hook;
use effsc::provers::multilinear_lsb::MultilinearProverLSB;
use effsc::runner::sumcheck;
use effsc::sumcheck_field_newtype;
use effsc::transcript::{ProverTranscript, VerifierTranscript};
use effsc::verifier::sumcheck_verify;

use p3_field::integers::QuotientMap;
use p3_field::Field;
use p3_goldilocks::Goldilocks;

use core::fmt;
use core::iter::Sum;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};

// ─── Newtype wrapper ───────────────────────────────────────────────────────

/// Thin wrapper around Plonky3's Goldilocks to implement `SumcheckField`.
#[derive(Copy, Clone, Debug, PartialEq)]
struct P3Goldilocks(Goldilocks);

impl P3Goldilocks {
fn new(val: u64) -> Self {
Self(Goldilocks::from_int(val))
}
}

impl fmt::Display for P3Goldilocks {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}

impl Add for P3Goldilocks {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}

impl Sub for P3Goldilocks {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}

impl Mul for P3Goldilocks {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self(self.0 * rhs.0)
}
}

impl Neg for P3Goldilocks {
type Output = Self;
fn neg(self) -> Self {
Self(-self.0)
}
}

impl AddAssign for P3Goldilocks {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}

impl SubAssign for P3Goldilocks {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}

impl MulAssign for P3Goldilocks {
fn mul_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}

impl Sum for P3Goldilocks {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ZERO, |acc, x| acc + x)
}
}

impl SumcheckField for P3Goldilocks {
const ZERO: Self = Self(Goldilocks::new(0));
const ONE: Self = Self(Goldilocks::new(1));

fn from_u64(val: u64) -> Self {
Self(Goldilocks::from_int(val))
}

fn inverse(&self) -> Option<Self> {
self.0.try_inverse().map(Self)
}
sumcheck_field_newtype! {
/// Thin wrapper around Plonky3's Goldilocks to implement `SumcheckField`.
struct P3Goldilocks(Goldilocks);
const ZERO = Goldilocks::new(0);
const ONE = Goldilocks::new(1);
fn from_u64(val) { Goldilocks::from_int(val) }
fn inverse(self) { self.0.try_inverse() }
}

// ─── Minimal transcript ────────────────────────────────────────────────────
Expand Down
Loading