Skip to content
Merged
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
16 changes: 10 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,23 @@ spongefish-derive = { path = "derive" }
spongefish-poseidon2 = { path = "poseidon2" }
spongefish-circuit = { path = "circuit" }
# p256 = "^0.13"
p3-baby-bear = "^0.3"
p3-field = "^0.3"
p3-koala-bear = "^0.3"
p3-mersenne-31 = "^0.3"
p3-poseidon2 = "^0.3"
p3-symmetric = "^0.3"
p3-baby-bear = "^0.4"
p3-field = "^0.4"
p3-koala-bear = "^0.4"
p3-mersenne-31 = "^0.4"
p3-poseidon2 = "^0.4"
p3-symmetric = "^0.4"
pallas = "^0.32"
rand = "^0.8.5"
rayon = "^1.10.0"
sha2 = "^0.10.7"
sha3 = "^0.10.8"
zeroize = "^1.8.1"
risc0-zkp = "3.0.3"
libtest-mimic = "0.8.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
spin = { version = "0.9", default-features = false, features = ["rwlock"] }


# Un-comment below for pulling zkp libraries from git.
Expand Down
1 change: 1 addition & 0 deletions circuit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ workspace = true
[dependencies]
p3-field = { workspace = true }
spongefish = { workspace = true, features = ["derive"] }
spin = { workspace = true }

# Optional Plonky3/BabyBear support
p3-baby-bear = { workspace = true, optional = true }
Expand Down
60 changes: 30 additions & 30 deletions circuit/src/allocator.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! Defines the allocator and wires to be used for computing the key-derivation steps.

use alloc::{rc::Rc, vec::Vec};
use core::{cell::RefCell, usize};
use alloc::{sync::Arc, vec::Vec};

use spin::RwLock;
use spongefish::Unit;

/// A symbolic wire over which we perform out computation.
/// Wraps over a [`usize`]
#[derive(Clone, Copy, Default, PartialEq, Eq, Unit)]
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, Unit)]
pub struct FieldVar(pub usize);

impl core::fmt::Debug for FieldVar {
Expand All @@ -16,52 +16,56 @@ impl core::fmt::Debug for FieldVar {
}
}

// /// A witness-instance pair that builds at the same time the instance and the relation.
// ///
// /// # Semantics
// ///
// /// When we deref this object, we are talking about its value.
// /// When we get the ref of this object, we are talking about its symbolic value.
// #[derive(Clone, Debug, Unit)]
// pub struct WitnessInstancePair<T: Unit>(FieldVar, T);

/// Allocator for field variables.
///
/// Creates a new wire identifier when requested,
/// and keeps tracks of the wires that have been declared as public.
#[derive(Clone)]
pub struct VarAllocator<T> {
state: Rc<RefCell<AllocatorState<T>>>,
state: Arc<RwLock<AllocatorState<T>>>,
}

struct AllocatorState<T> {
vars_count: usize,
public_values: Vec<(FieldVar, T)>,
}

impl<T: Clone> VarAllocator<T> {
impl<T: Clone + Unit> Default for VarAllocator<T> {
fn default() -> Self {
Self::new()
}
}

impl<T: Clone + Unit> VarAllocator<T> {
#[must_use]
pub fn new() -> Self {
let zero_var = FieldVar::ZERO;
Self {
state: Rc::new(RefCell::new(AllocatorState {
vars_count: 0,
public_values: Vec::new(),
state: Arc::new(RwLock::new(AllocatorState {
vars_count: 1,
public_values: Vec::from([(zero_var, T::ZERO)]),
})),
}
}

#[must_use]
pub fn new_field_var(&self) -> FieldVar {
let mut state = self.state.borrow_mut();
let mut state = self.state.write();
let var = FieldVar(state.vars_count);
state.vars_count += 1;
var
}

#[must_use]
pub fn allocate_vars<const N: usize>(&self) -> [FieldVar; N] {
let mut buf = [FieldVar::default(); N];
buf.iter_mut().for_each(|x| *x = self.new_field_var());
for x in &mut buf {
*x = self.new_field_var();
}
buf
}

#[must_use]
pub fn allocate_vars_vec(&self, count: usize) -> Vec<FieldVar> {
(0..count).map(|_| self.new_field_var()).collect()
}
Expand All @@ -78,12 +82,13 @@ impl<T: Clone> VarAllocator<T> {
vars
}

#[must_use]
pub fn vars_count(&self) -> usize {
self.state.borrow().vars_count
self.state.read().vars_count
}

pub fn set_public_var(&self, val: FieldVar, var: T) {
self.state.borrow_mut().public_values.push((val, var));
self.state.write().public_values.push((val, var));
}

pub fn set_public_vars<Val, Var>(
Expand All @@ -94,20 +99,15 @@ impl<T: Clone> VarAllocator<T> {
Var: core::borrow::Borrow<FieldVar>,
Val: core::borrow::Borrow<T>,
{
self.state.borrow_mut().public_values.extend(
self.state.write().public_values.extend(
vars.into_iter()
.zip(vals)
.map(|(var, val)| (*var.borrow(), val.borrow().clone())),
)
);
}

#[must_use]
pub fn public_vars(&self) -> Vec<(FieldVar, T)> {
self.state
.borrow()
.public_values
.iter()
.cloned()
.map(|(var, val)| (var, val.clone()))
.collect()
self.state.read().public_values.clone()
}
}
76 changes: 66 additions & 10 deletions circuit/src/permutation.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Builders for permutation evaluation relations.
use alloc::{rc::Rc, vec::Vec};
use core::cell::RefCell;
use alloc::{sync::Arc, vec::Vec};

use spin::RwLock;
use spongefish::{Permutation, Unit};

use crate::allocator::{FieldVar, VarAllocator};
Expand All @@ -11,7 +11,15 @@ use crate::allocator::{FieldVar, VarAllocator};
#[derive(Clone)]
pub struct PermutationInstanceBuilder<T, const WIDTH: usize> {
allocator: VarAllocator<T>,
constraints: Rc<RefCell<PermutationInstance<WIDTH>>>,
constraints: Arc<RwLock<PermutationInstance<WIDTH>>>,
}

type QueryAnswerPair<U, const WIDTH: usize> = ([U; WIDTH], [U; WIDTH]);

#[derive(Clone)]
pub struct PermutationWitnessBuilder<P: Permutation<WIDTH>, const WIDTH: usize> {
trace: Arc<RwLock<Vec<QueryAnswerPair<P::U, WIDTH>>>>,
permutation: P,
}

/// The internal state of the instance,
Expand All @@ -29,43 +37,91 @@ impl<T: Unit, const WIDTH: usize> Permutation<WIDTH> for PermutationInstanceBuil
}
}

impl<T: Clone, const WIDTH: usize> Default for PermutationInstanceBuilder<T, WIDTH> {
impl<P: Permutation<WIDTH>, const WIDTH: usize> Permutation<WIDTH>
for PermutationWitnessBuilder<P, WIDTH>
{
type U = P::U;

fn permute(&self, state: &[Self::U; WIDTH]) -> [Self::U; WIDTH] {
self.allocate_permutation(state)
}
}

impl<T: Clone + Unit, const WIDTH: usize> Default for PermutationInstanceBuilder<T, WIDTH> {
fn default() -> Self {
Self::new()
}
}

impl<T: Clone, const WIDTH: usize> PermutationInstanceBuilder<T, WIDTH> {
impl<T: Clone + Unit, const WIDTH: usize> PermutationInstanceBuilder<T, WIDTH> {
#[must_use]
pub fn with_allocator(allocator: VarAllocator<T>) -> Self {
Self {
allocator: allocator.clone(),
allocator,
constraints: Default::default(),
}
}

#[must_use]
pub fn new() -> Self {
Self::with_allocator(VarAllocator::new())
}

pub fn allocator(&self) -> &VarAllocator<T> {
#[must_use]
pub const fn allocator(&self) -> &VarAllocator<T> {
&self.allocator
}

#[must_use]
pub fn allocate_permutation(&self, &input: &[FieldVar; WIDTH]) -> [FieldVar; WIDTH] {
let output = self.allocator.allocate_vars();
self.constraints.borrow_mut().state.push((input, output));
self.constraints.write().state.push((input, output));
output
}

pub fn add_permutation(&self, input: [FieldVar; WIDTH], output: [FieldVar; WIDTH]) {
self.constraints.borrow_mut().state.push((input, output));
self.constraints.write().state.push((input, output));
}

#[must_use]
pub fn constraints(&self) -> impl AsRef<[([FieldVar; WIDTH], [FieldVar; WIDTH])]> {
self.constraints.borrow_mut().state.clone()
self.constraints.read().state.clone()
}

#[must_use]
pub fn public_vars(&self) -> Vec<(FieldVar, T)> {
self.allocator.public_vars()
}
}

impl<P: Permutation<WIDTH>, const WIDTH: usize> From<P> for PermutationWitnessBuilder<P, WIDTH> {
fn from(value: P) -> Self {
Self::new(value)
}
}

impl<P: Permutation<WIDTH>, const WIDTH: usize> PermutationWitnessBuilder<P, WIDTH> {
#[must_use]
pub fn new(permutation: P) -> Self {
Self {
trace: Default::default(),
permutation,
}
}

#[must_use]
pub fn allocate_permutation(&self, input: &[P::U; WIDTH]) -> [P::U; WIDTH] {
let output = self.permutation.permute(input);
self.add_permutation(input, &output);
output
}

pub fn add_permutation(&self, input: &[P::U; WIDTH], output: &[P::U; WIDTH]) {
self.trace.write().push((input.clone(), output.clone()));
}

#[must_use]
pub fn trace(&self) -> impl AsRef<[QueryAnswerPair<P::U, WIDTH>]> {
self.trace.read().clone()
}
}
6 changes: 4 additions & 2 deletions circuit/tests/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use p3_baby_bear::BabyBear;
use spongefish::{DuplexSponge, DuplexSpongeInterface};

use spongefish_circuit::permutation::PermutationInstanceBuilder;

#[test]
Expand Down Expand Up @@ -43,6 +42,9 @@ pub fn test_xof() {
assert_eq!(inst_builder.constraints().as_ref().len(), 2);

// the instance is a set of:
println!("input/otutput vars: {:?}", inst_builder.constraints().as_ref());
println!(
"input/otutput vars: {:?}",
inst_builder.constraints().as_ref()
);
println!("public vars: {:?}", inst_builder.allocator().public_vars());
}
9 changes: 6 additions & 3 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ fn generate_encoding_impl(input: &DeriveInput) -> TokenStream2 {
};

let bound = quote!(::spongefish::Encoding<[u8]>);
let generics = add_trait_bounds_for_fields(input.generics.clone(), &encoding_bounds, &bound);
let generics =
add_trait_bounds_for_fields(input.generics.clone(), &encoding_bounds, &bound);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

quote! {
Expand Down Expand Up @@ -177,7 +178,8 @@ fn generate_decoding_impl(input: &DeriveInput) -> TokenStream2 {
};

let bound = quote!(::spongefish::Decoding<[u8]>);
let generics = add_trait_bounds_for_fields(input.generics.clone(), &decoding_bounds, &bound);
let generics =
add_trait_bounds_for_fields(input.generics.clone(), &decoding_bounds, &bound);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

quote! {
Expand Down Expand Up @@ -252,7 +254,8 @@ fn generate_narg_deserialize_impl(input: &DeriveInput) -> TokenStream2 {
};

let bound = quote!(::spongefish::NargDeserialize);
let generics = add_trait_bounds_for_fields(input.generics.clone(), &deserialize_bounds, &bound);
let generics =
add_trait_bounds_for_fields(input.generics.clone(), &deserialize_bounds, &bound);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

quote! {
Expand Down
3 changes: 3 additions & 0 deletions spongefish/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ pallas = { workspace = true }
ark-vesta = { workspace = true }
sha3 = { workspace = true }
ark-secp256k1 = { workspace = true }
libtest-mimic = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }

[package.metadata.docs.rs]
all-features = true
Expand Down
6 changes: 3 additions & 3 deletions spongefish/src/drivers/p3_baby_bear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Decoding<[u8]> for BabyBear {

fn decode(buf: Self::Repr) -> Self {
let n = u64::from_le_bytes(buf);
return BabyBear::new((n % (BabyBear::ORDER_U32 as u64)) as u32);
Self::new((n % u64::from(Self::ORDER_U32)) as u32)
}
}

Expand All @@ -53,11 +53,11 @@ impl NargDeserialize for BabyBear {
let value = u32::from_le_bytes(repr);

// Check that the value is in the valid range
if value >= BabyBear::ORDER_U32 {
if value >= Self::ORDER_U32 {
return Err(VerificationError);
}

Ok(BabyBear::new(value))
Ok(Self::new(value))
}
}

Expand Down
3 changes: 2 additions & 1 deletion spongefish/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloc::string::String;

use rand::RngCore;

#[test]
Expand Down Expand Up @@ -77,7 +78,7 @@ fn domain_separator_accepts_variable_sessions() {
assert_eq!(literal_session, from_str);

let session_owned = String::from("shared session");
let from_owned = crate::domain_separator!("variable sessions"; session_owned.clone())
let from_owned = crate::domain_separator!("variable sessions"; session_owned)
.instance(&instance)
.session
.expect("owned session missing");
Expand Down
1 change: 1 addition & 0 deletions spongefish/tests/derive_generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fn codec_derive_handles_generic_types() {
assert_eq!(roundtrip.value, tagged.value);
assert!(buf.is_empty());

#[allow(clippy::items_after_statements)]
fn assert_codec<T: Codec>(_: &T) {}
assert_codec(&tagged);
}
Loading
Loading