Skip to content
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ec8f61e
benches and tests set up
z-tech Feb 18, 2025
68b3299
linter
z-tech Feb 18, 2025
fcf7efe
fix non neon impl
z-tech Feb 18, 2025
3b0fcda
fix non neon impl 2
z-tech Feb 18, 2025
51d3e4c
add trait implementations
benbencik May 22, 2025
42a7ac6
add fp config from algebra
benbencik May 29, 2025
fdd3d98
add hot-fixes to make FpConfig appropriate for older ark_ff
benbencik May 29, 2025
0d6676d
the most basic macro...but works
benbencik Jun 5, 2025
b0dcb5c
copy FpConfig and add hot fixes
benbencik Jun 11, 2025
1212a48
add garbage that compiles
benbencik Jun 12, 2025
5561e7c
add From implementaitons
benbencik Jun 26, 2025
b841569
fix display trait
benbencik Jul 2, 2025
c3eaa65
fix bigint 2
benbencik Jul 8, 2025
29af509
add new
benbencik Jul 8, 2025
a6215e1
make bigint limbs constant
benbencik Jul 9, 2025
884467b
correct indexing of bigint
benbencik Jul 9, 2025
906aa00
fix some todos
benbencik Jul 9, 2025
00f76ce
add naive implementation for inverse
benbencik Jul 9, 2025
1b9a77d
add tests
benbencik Jul 9, 2025
f40a159
run checks on any PR
z-tech Jul 11, 2025
f330ac3
bump to arkworks 0.5
z-tech Jul 11, 2025
30f3a97
merge main
z-tech Jul 11, 2025
60c3b1c
add constant for fixed bigint limbs
benbencik Aug 6, 2025
32af43b
split small fp backend into modules
benbencik Aug 6, 2025
c5e4999
add benches for small fields
benbencik Aug 14, 2025
e476cb6
add dummy separate backend for field arithermtic
benbencik Aug 14, 2025
06fce99
BigInteger expects least-significant limb first.
benbencik Aug 21, 2025
b3f8000
extends tests with small field
benbencik Aug 21, 2025
02cb1e8
add tests
benbencik Aug 22, 2025
57171ec
add overflow handling
benbencik Aug 23, 2025
84a91df
merge main
z-tech Aug 27, 2025
048e9c4
add garbage mont backend
benbencik Aug 27, 2025
eef2324
fix later
benbencik Aug 27, 2025
7607868
move contructor to backend implementation
benbencik Sep 8, 2025
5b7449f
add montgomery prototype
benbencik Sep 8, 2025
70d3e33
select R based on modulus
benbencik Sep 8, 2025
e2e820e
fix errors in multiplication for standard backend
benbencik Sep 16, 2025
d790d99
add computation of two adicity for standard backend
benbencik Sep 16, 2025
85fb1bb
add two adicity computation to mont backend
benbencik Sep 16, 2025
3c63985
cleanup
benbencik Sep 16, 2025
4e16d72
add benches
benbencik Sep 16, 2025
ef1c24b
add implementation for random sampling
benbencik Sep 17, 2025
e2b3566
do not use modulus_128
benbencik Sep 17, 2025
6116c05
fix failing test
benbencik Sep 17, 2025
5c9cb75
rewrite add_assign
benbencik Sep 17, 2025
caa547d
simplify from conversion
benbencik Sep 19, 2025
f715dac
exiting mont domain
benbencik Sep 19, 2025
ab33b8e
add tests for mont field
benbencik Sep 19, 2025
b3ca510
refactor to get rid of safe_mul function in the trait
benbencik Sep 24, 2025
1f87172
simplify neg in place
benbencik Sep 24, 2025
be37213
polish the trait definition
benbencik Sep 24, 2025
6ac0790
refactor bigint casts
benbencik Sep 24, 2025
8dfcef2
fix formating
benbencik Sep 24, 2025
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: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
branches-ignore: []

env:
CARGO_TERM_COLOR: always
Expand Down
18 changes: 14 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@ edition = "2021"
[dependencies]
ark-ff = "0.5.0"
ark-poly = "0.5.0"
ark-std = "0.5.0"
ark-serialize = "0.5.0"
ark-std ="0.5.0"
num-bigint = "0.4"
num-traits = "0.2"
zeroize = "1.8.1"
itertools = "0.10.5"
educe = "0.6.0"
memmap2 = "0.9.5"
fields_macro = { path = "fields_macro" }

[dev-dependencies]
criterion = "0.4"

[features]
simd = []


[[bench]]
name = "explanation"
harness = false
4 changes: 3 additions & 1 deletion benches/explanation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
fn main() {
eprintln!("Error: This project uses a custom benchmarking workflow.");
eprintln!("Please navigate to the appropriate bench directory and call the shell './run_bench.sh' directly.");
eprintln!("Please choose a bench:");
eprintln!(" Full Protocol Benches: 'cd ./benches/sumcheck-benches/ && cargo build --release && ./run_benches.sh'");
eprintln!(" Lagrange Polynomial Benches: 'cd ./benches/lag-poly-benches/ && cargo build --release && ./run_benches.sh'");
std::process::exit(1);
}
4 changes: 4 additions & 0 deletions benches/lag-poly-benches/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 115 additions & 0 deletions examples/fpconfig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use ark_ff::{BigInt, SqrtPrecomputation};
use fields_macro::SmallFpConfig;
use space_efficient_sumcheck::fields::small_fp_backend::SmallFp;
use space_efficient_sumcheck::fields::small_fp_backend::SmallFpConfig;

#[derive(SmallFpConfig)]
#[modulus = "2147483647"]
#[generator = "7"]
struct SomeField;

fn main() {
println!(
"MOD: {} GENERATOR: {}",
SomeField::MODULUS,
SomeField::GENERATOR
);
let mut a = SomeField::ONE;
let b = SomeField::ONE;
let c = SomeField::new(4);
a += b;
a += c;
println!("{}", a);
}

#[cfg(test)]
mod tests {
use super::*;
use ark_ff::{One, Zero};

#[test]
fn add_assign_test() {
let mut a = SomeField::new(10);
let b = SomeField::new(20);
a += b;
assert_eq!(a.value, 30);

let mut a = SomeField::new(SomeField::MODULUS - 1);
let b = SomeField::new(2);
a += b;
assert_eq!(a.value, 1);
}

#[test]
fn sub_assign_test() {
let mut a = SomeField::new(30);
let b = SomeField::new(10);
a -= b;
assert_eq!(a.value, 20);

let mut a = SomeField::new(5);
let b = SomeField::new(10);
a -= b;
assert_eq!(a.value, SomeField::MODULUS - 5);
}

#[test]
fn mul_assign_test() {
let mut a = SomeField::new(5);
let b = SomeField::new(10);
a *= b;
assert_eq!(a.value, 50);

let mut a = SomeField::new(SomeField::MODULUS / 2);
let b = SomeField::new(3);
a *= b;
assert_eq!(a.value, (SomeField::MODULUS / 2) * 3 % SomeField::MODULUS);
}

#[test]
fn neg_in_place_test() {
let mut a = SomeField::new(10);
SomeField::neg_in_place(&mut a);
assert_eq!(a.value, SomeField::MODULUS - 10);

let mut a = SomeField::ZERO;
SomeField::neg_in_place(&mut a);
assert_eq!(a.value, 0);
}

#[test]
fn double_in_place_test() {
let mut a = SomeField::new(10);
SomeField::double_in_place(&mut a);
assert_eq!(a.value, 20);

let mut a = SomeField::new(SomeField::MODULUS - 1);
SomeField::double_in_place(&mut a);
assert_eq!(a.value, SomeField::MODULUS - 2);
}

#[test]
fn square_in_place_test() {
let mut a = SomeField::new(5);
SomeField::square_in_place(&mut a);
assert_eq!(a.value, 25);

let mut a = SomeField::new(SomeField::MODULUS - 1);
SomeField::square_in_place(&mut a);
assert_eq!(a.value, 1);
}

#[test]
fn zero_inverse() {
let zero = SomeField::ZERO;
assert!(SomeField::inverse(&zero).is_none())
}

#[test]
fn test_specific_inverse() {
let mut val = SomeField::new(17);
let val_inv = SomeField::inverse(&val);
SomeField::mul_assign(&mut val, &val_inv.unwrap());
assert_eq!(val, SomeField::ONE);
}
}
15 changes: 15 additions & 0 deletions fields_macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "fields_macro"
version = "0.1.0"
edition = "2021"

[dependencies]
syn = "2.0.0"
quote = "1.0.0"
ark-ff = "0.4.0"
num-bigint = "0.4"
num-traits = "0.2"
proc-macro2 = "1.0.36"

[lib]
proc-macro = true
195 changes: 195 additions & 0 deletions fields_macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
use core::convert::Into;
use proc_macro::TokenStream;
use quote::quote;
// use space_efficeint_sumcheck::fields::small_fp_backend::SmallFp;

use syn::{Expr, ExprLit, Lit, Meta};

extern crate proc_macro;
pub(crate) mod utils;

/// Fetch an attribute string from the derived struct.
fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option<String> {
// Go over each attribute
for attr in attrs {
match attr.meta {
// If the attribute's path matches `name`, and if the attribute is of
// the form `#[name = "value"]`, return `value`
Meta::NameValue(ref nv) if nv.path.is_ident(name) => {
// Extract and return the string value.
// If `value` is not a string, return an error
if let Expr::Lit(ExprLit {
lit: Lit::Str(ref s),
..
}) = nv.value
{
return Some(s.value());
}
panic!("attribute {name} should be a string")
}
_ => {}
}
}
None
}

#[proc_macro_derive(SmallFpConfig, attributes(modulus, generator))]
pub fn fp_config(input: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(input).unwrap();

let modulus: u128 = fetch_attr("modulus", &ast.attrs)
.expect("Please supply a modulus attribute")
.parse()
.expect("Modulus should be a number");

let generator: u128 = fetch_attr("generator", &ast.attrs)
.expect("Please supply a generator attribute")
.parse()
.expect("Generator should be a number");

let (ty, suffix) = {
let u8_max = u128::from(u8::MAX);
let u16_max = u128::from(u16::MAX);
let u32_max = u128::from(u32::MAX);
let u64_max = u128::from(u64::MAX);

if modulus <= u8_max {
(quote! { u8 }, "u8")
} else if modulus <= u16_max {
(quote! { u16 }, "u16")
} else if modulus <= u32_max {
(quote! { u32 }, "u32")
} else if modulus <= u64_max {
(quote! { u64 }, "u64")
} else {
(quote! { u128 }, "u128")
}
};

// Type u128 has two limbs all other have only one
let (from_bigint_impl, into_bigint_impl) = if suffix == "u128" {
(
quote! {
fn from_bigint(a: BigInt<2>) -> Option<SmallFp<Self>> {
let val = (a.0[0] as u128) + ((a.0[0] as u128) << 64);
Some(SmallFp::new(val as Self::T))
}
},
quote! {
fn into_bigint(a: SmallFp<Self>) -> BigInt<2> {
ark_ff::BigInt([(a.value as u64), (a.value >> 64) as u64])
}
},
)
} else {
(
quote! {
fn from_bigint(a: BigInt<2>) -> Option<SmallFp<Self>> {
if a.0[0] >= (Self::MODULUS as u64) {
None
} else {
Some(SmallFp::new(a.0[0] as Self::T))
}
}
},
quote! {
fn into_bigint(a: SmallFp<Self>) -> BigInt<2> {
ark_ff::BigInt([0, a.value as u64])
}
},
)
};

let name = &ast.ident;
let gen = quote! {
impl SmallFpConfig for #name {
type T = #ty;

const MODULUS: Self::T = #modulus as Self::T;
const MODULUS_128: u128 = #modulus;


const GENERATOR: SmallFp<Self> = SmallFp::new(#generator as Self::T);
const ZERO: SmallFp<Self> = SmallFp::new(0 as Self::T);
const ONE: SmallFp<Self> = SmallFp::new(1 as Self::T);
const TWO_ADIC_ROOT_OF_UNITY: SmallFp<Self> = SmallFp::new(1 as Self::T);

const TWO_ADICITY: u32 = 0;
const SQRT_PRECOMP: Option<SqrtPrecomputation<SmallFp<Self>>> = None;

fn add_assign(a: &mut SmallFp<Self>, b: &SmallFp<Self>) {
a.value = (a.value + b.value) % Self::MODULUS;
}

fn sub_assign(a: &mut SmallFp<Self>, b: &SmallFp<Self>) {
if a.value >= b.value {
a.value -= b.value;
} else {
a.value = Self::MODULUS - (b.value - a.value);
}
}

fn double_in_place(a: &mut SmallFp<Self>) {
a.value = (a.value + a.value) % Self::MODULUS;
}

fn neg_in_place(a: &mut SmallFp<Self>) {
if a.value == (0 as Self::T) {
a.value = 0 as Self::T;
} else {
a.value = Self::MODULUS - a.value;
}
}

fn mul_assign(a: &mut SmallFp<Self>, b: &SmallFp<Self>) {
let product = (a.value as u128) * (b.value as u128);
a.value = (product % (Self::MODULUS as u128)) as Self::T;
}

fn sum_of_products<const T: usize>(
a: &[SmallFp<Self>; T],
b: &[SmallFp<Self>; T],) -> SmallFp<Self> {
a.iter().zip(b.iter()).map(|(x, y)| *x * *y).sum()
}

fn square_in_place(a: &mut SmallFp<Self>) {
let product = (a.value as u128) * (a.value as u128);
a.value = (product % (Self::MODULUS as u128)) as Self::T;
}

// TODO: Do the EE algorithm in #ty
fn inverse(a: &SmallFp<Self>) -> Option<SmallFp<Self>> {
if a.value == 0 {
return None;
}

let mut base: #ty = a.value;
let mut exp: u128 = (Self::MODULUS_128 - 2);
let mut acc: u128 = 1;
let m: u128 = Self::MODULUS_128;

while exp > 0 {
if (exp & 1) == 1 {
acc = (acc * (base as u128)) % m;
}
base = (((base as u128) * (base as u128)) % m) as #ty;
exp >>= 1;
}
Some(SmallFp::new(acc as Self::T))
}

#from_bigint_impl

#into_bigint_impl
}

impl #name {
pub fn new(value: <Self as SmallFpConfig>::T) -> SmallFp<Self> {
SmallFp::new(value % <Self as SmallFpConfig>::MODULUS)
}
}


};
gen.into()
}
Loading