Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0c62284
Add transcript
recmo May 20, 2025
eb2306e
Remove TypeId
recmo May 21, 2025
2a84c58
Every interaction is hierarchical
recmo May 21, 2025
f02da32
Example ZeroCopy
recmo May 21, 2025
d6de11b
Transcript to domain separator
recmo May 23, 2025
b85385d
Domain separators and labels
recmo May 23, 2025
1600f55
ProverState and prover random
recmo May 23, 2025
349ac7b
Implement ProverState traits
recmo May 27, 2025
1b9fa68
New approach to traits
recmo May 27, 2025
b190f70
Fix build
recmo May 28, 2025
4393621
Fix tests
recmo May 28, 2025
7432a5a
Add back prover tests
recmo May 28, 2025
21f04ab
Bytes traits
recmo May 29, 2025
f813524
Add zerocopy
recmo May 29, 2025
b25ad1f
Add ark_serialize hints
recmo May 29, 2025
c2b8192
Add field_bytes
recmo May 29, 2025
c8792f9
Add field_bytes
recmo May 29, 2025
827f6f0
Challenge byte extraction
recmo May 29, 2025
c7a43b8
Test ark_serialize
recmo May 29, 2025
e1ccac2
Add Ark Field challenges
recmo May 30, 2025
b0c1ef3
Remove module name from zerocopy
recmo Jun 2, 2025
16dea90
Remove module name from bytes
recmo Jun 2, 2025
a55e6fd
Remove module name from unit
recmo Jun 2, 2025
5cccc14
Move unit to codecs
recmo Jun 2, 2025
f666944
Unit is associated type
recmo Jun 2, 2025
02ce966
Explicit error types
recmo Jun 2, 2025
1f8699c
Update zeropcopy traits
recmo Jun 2, 2025
0d83306
Update arkworks::serialize traits
recmo Jun 2, 2025
14d88e3
Update arkworks::field traits
recmo Jun 2, 2025
abd05ac
Update arkworks::field trait names
recmo Jun 2, 2025
43abb51
Simplify VerifierError
recmo Jun 3, 2025
3a5fd32
Pattern creation is infallible
recmo Jun 4, 2025
f9582c8
Interaction errors are bugs and therefore panic
recmo Jun 4, 2025
70b8037
Remove interaction errors
recmo Jun 4, 2025
9e97ff6
Simplify traits
recmo Jun 10, 2025
39ea768
Static lables
recmo Jun 11, 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
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ group = "0.13.0"
hex = "0.4.3"
keccak = "0.1.5"
spongefish = { path = "spongefish" }
pallas = "0.32"
pasta_curves = "0.5.1"
rand = "0.8.5"
rand = "0.9"
rayon = "1.10.0"
sha2 = "0.10.7"
sha3 = "0.10.8"
Expand Down
18 changes: 15 additions & 3 deletions spongefish/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,34 @@ workspace = true

[dependencies]
zeroize = { workspace = true, features = ["zeroize_derive"] }
rand = { workspace = true, features = ["getrandom"] }
rand = { workspace = true, features = ["std_rng", "os_rng"] }
digest = { workspace = true }
# used as default hasher for the prover
keccak = { workspace = true }
# optional dependencies
ark-ff = { workspace = true, optional = true }
ark-ec = { workspace = true, optional = true }
ark-serialize = { workspace = true, features = ["std"], optional = true }
ark-std = { workspace = true, optional = true }
group = { workspace = true, optional = true }
hex = { workspace = true }
zerocopy = { version = "0.8", features = ["std"], optional = true }
postcard = { version = "1.1.1", optional = true }
thiserror = "2.0.12"
sha3.workspace = true
hex-literal = "1.0.0"

[features]
default = []
default = ["arkworks-algebra", "arkworks-rand", "zerocopy"]
arkworks-rand = [
# Workaround to also implement arkworks version of rand as exported by ark_std
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one should solve this no? arkworks-rs/std#60

"dep:ark-std",
]
arkworks-algebra = ["dep:ark-ff", "dep:ark-ec", "dep:ark-serialize"]
zkcrypto-group = ["dep:group"]
zerocopy = ["dep:zerocopy"]
ark-serialize = ["dep:ark-serialize"]
serde-postcard = ["dep:postcard"]
asm = ["keccak/asm", "keccak/simd"]

[dev-dependencies]
Expand All @@ -43,7 +56,6 @@ ark-curve25519 = { workspace = true }
bls12_381 = { workspace = true }
ark-bls12-381 = { workspace = true, features = ["std"] }
ark-pallas = { workspace = true, features = ["std"] }
pallas = { workspace = true }
pasta_curves = { workspace = true }
ark-vesta = { workspace = true, features = ["std"] }
sha3 = { workspace = true }
Expand Down
18 changes: 13 additions & 5 deletions spongefish/examples/bulletproof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@

use ark_ec::{AffineRepr, CurveGroup, PrimeGroup, VariableBaseMSM};
use ark_ff::Field;
use ark_std::log2;
use rand::rngs::OsRng;
use ark_std::{
log2,
rand::{rngs::StdRng, SeedableRng},
};
use rand::Rng;
use spongefish::codecs::arkworks_algebra::{
CommonGroupToUnit, DomainSeparator, FieldDomainSeparator, FieldToUnitDeserialize,
FieldToUnitSerialize, GroupDomainSeparator, GroupToUnitDeserialize, GroupToUnitSerialize,
ProofError, ProofResult, ProverState, UnitToField, VerifierState,
};

fn ark_rng() -> ark_std::rand::rngs::StdRng {
let seed: [u8; 32] = rand::rng().random();
<ark_std::rand::rngs::StdRng as ark_std::rand::SeedableRng>::from_seed(seed)
}

/// The domain separator of a bulleproof.
///
/// Defining this as a trait allows us to "attach" the bulletproof IO to
Expand Down Expand Up @@ -188,12 +196,12 @@ fn main() {
let ab = dot_prod(&a, &b);
// the generators to be used for respectively a, b, ip
let g = (0..a.len())
.map(|_| GAffine::rand(&mut OsRng))
.map(|_| GAffine::rand(&mut ark_rng()))
.collect::<Vec<_>>();
let h = (0..b.len())
.map(|_| GAffine::rand(&mut OsRng))
.map(|_| GAffine::rand(&mut ark_rng()))
.collect::<Vec<_>>();
let u = GAffine::rand(&mut OsRng);
let u = GAffine::rand(&mut ark_rng());

let generators = (&g[..], &h[..], &u);
let statement = G::msm_unchecked(&g, &a) + G::msm_unchecked(&h, &b) + u * ab;
Expand Down
9 changes: 7 additions & 2 deletions spongefish/examples/schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
/// It can be used to verify a proof.
use ark_ec::{CurveGroup, PrimeGroup};
use ark_std::UniformRand;
use rand::rngs::OsRng;
use rand::Rng as _;
use spongefish::codecs::arkworks_algebra::{
CommonGroupToUnit, DomainSeparator, DuplexSpongeInterface, FieldDomainSeparator,
FieldToUnitDeserialize, FieldToUnitSerialize, GroupDomainSeparator, GroupToUnitDeserialize,
Expand Down Expand Up @@ -63,11 +63,16 @@ where
}
}

fn ark_rng() -> ark_std::rand::rngs::StdRng {
let seed: [u8; 32] = rand::rng().random();
<ark_std::rand::rngs::StdRng as ark_std::rand::SeedableRng>::from_seed(seed)
}

/// The key generation algorithm otuputs
/// a secret key `sk` in $\mathbb{Z}_p$
/// and its respective public key `pk` in $\mathbb{G}$.
fn keygen<G: CurveGroup>() -> (G::ScalarField, G) {
let sk = G::ScalarField::rand(&mut OsRng);
let sk = G::ScalarField::rand(&mut ark_rng());
let pk = G::generator() * sk;
(sk, pk)
}
Expand Down
2 changes: 1 addition & 1 deletion spongefish/src/codecs/arkworks_algebra/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ where
}

fn test_arkworks_end_to_end<F: Field, H: DuplexSpongeInterface>() -> ProofResult<()> {
use rand::Rng;
use ark_std::rand::Rng;

use crate::codecs::arkworks_algebra::{
FieldToUnitDeserialize, FieldToUnitSerialize, UnitToField,
Expand Down
12 changes: 12 additions & 0 deletions spongefish/src/codecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ pub mod arkworks_algebra;
/// This plugin is experimental and has not yet been thoroughly tested.
pub mod zkcrypto_group;

#[cfg(feature = "zerocopy")]
/// Use [`zerocopy`] to convert types to/from bytes.
pub mod zerocopy;

#[cfg(feature = "ark-serialize")]
/// Use [`ark_serialize`] to convert types to/from bytes.
pub mod zerocopy;

// #[cfg(feature = "serde-postcard")]
// /// Use [`zerocopy`] to convert types to/from bytes.
// pub mod zerocopy;

Comment on lines +25 to +28
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be removed?

/// Bytes needed in order to obtain a uniformly distributed random element of `modulus_bits`
pub(super) const fn bytes_uniform_modp(modulus_bits: u32) -> usize {
(modulus_bits as usize + 128) / 8
Expand Down
132 changes: 132 additions & 0 deletions spongefish/src/codecs/zerocopy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! [`zerocopy`] allows safe and efficient conversion to/from bytes for types that have
//! simple in-memory representations.

use zerocopy::{FromBytes, Immutable, IntoBytes};

use crate::{
traits::{
BytesChallenge, BytesHintProver, BytesHintVerifier, BytesMessageProver,
BytesMessageVerifier, BytesPattern,
},
transcript::{Label, Length, Transcript},
};

pub trait ZeroCopyPattern<T>: Transcript {
fn message(&mut self, label: Label) -> Result<(), Self::Error>;
fn hint(&mut self, label: Label) -> Result<(), Self::Error>;
fn challenge(&mut self, label: Label) -> Result<(), Self::Error>;
}

pub trait ZeroCopyMessageProver<T: Immutable + IntoBytes>: Transcript {
fn message(&mut self, label: Label, value: &T) -> Result<(), Self::Error>;
}

pub trait ZeroCopyMessageVerifier<T: IntoBytes + FromBytes>: Transcript {
fn message(&mut self, label: Label) -> Result<T, Self::Error>;
}

pub trait ZeroCopyHintProver<T: Immutable + IntoBytes>: Transcript {
fn hint(&mut self, label: Label, value: &T) -> Result<(), Self::Error>;
}

pub trait ZeroCopyHintVerifier<T: IntoBytes + FromBytes>: Transcript {
fn hint(&mut self, label: Label) -> Result<T, Self::Error>;
}

pub trait ZeroCopyChallenge<T: IntoBytes + FromBytes>: Transcript {
fn challenge(&mut self, label: Label) -> Result<T, Self::Error>;
}

impl<State, T> ZeroCopyPattern<T> for State
where
State: Transcript + BytesPattern,
{
fn message(&mut self, label: Label) -> Result<(), Self::Error> {
self.begin_message::<(Self, T)>(label.clone(), Length::Scalar)?;
self.add_bytes(size_of::<T>(), &label);
self.end_message::<(Self, T)>(label, Length::Scalar)
}

fn hint(&mut self, label: Label) -> Result<(), Self::Error> {
self.begin_hint::<(Self, T)>(label.clone(), Length::Scalar)?;
self.hint(&label);
self.end_hint::<(Self, T)>(label, Length::Scalar)
}

fn challenge(&mut self, label: Label) -> Result<(), Self::Error> {
self.begin_challenge::<(Self, T)>(label.clone(), Length::Scalar)?;
self.challenge_bytes(size_of::<T>(), &label);
self.end_challenge::<(Self, T)>(label, Length::Scalar)
}
}

impl<State, T> ZeroCopyMessageProver<T> for State
where
State: Transcript + BytesMessageProver,
T: Immutable + IntoBytes,
{
fn message(&mut self, label: Label, value: &T) -> Result<(), Self::Error> {
self.begin_message::<(Self, T)>(label.clone(), Length::Scalar)?;
self.message(value.as_bytes()).unwrap();
self.end_message::<(Self, T)>(label, Length::Scalar)
}
}

impl<State, T> ZeroCopyMessageVerifier<T> for State
where
State: Transcript + BytesMessageVerifier,
T: IntoBytes + FromBytes,
{
fn message(&mut self, label: Label) -> Result<T, Self::Error> {
self.begin_message::<(Self, T)>(label.clone(), Length::Scalar)?;
let mut result = T::new_zeroed();
self.message(result.as_mut_bytes()).unwrap();
self.end_message::<(Self, T)>(label, Length::Scalar)?;
Ok(result)
}
}

impl<State, T> ZeroCopyHintProver<T> for State
where
State: Transcript + BytesHintProver,
T: Immutable + IntoBytes,
{
fn hint(&mut self, label: Label, value: &T) -> Result<(), Self::Error> {
self.begin_hint::<(Self, T)>(label.clone(), Length::Scalar)?;
self.hint(value.as_bytes()).unwrap();
self.end_hint::<(Self, T)>(label, Length::Scalar)
}
}

impl<State, T> ZeroCopyHintVerifier<T> for State
where
State: Transcript + BytesHintVerifier,
T: FromBytes + IntoBytes,
{
fn hint(&mut self, label: Label) -> Result<T, Self::Error> {
self.begin_message::<(Self, T)>(label.clone(), Length::Scalar)?;
let mut result = T::new_zeroed();
self.hint(result.as_mut_bytes()).unwrap();
self.end_message::<(Self, T)>(label, Length::Scalar)?;
Ok(result)
}
}

impl<State, T> ZeroCopyChallenge<T> for State
where
State: Transcript + BytesChallenge,
T: FromBytes + IntoBytes,
{
fn challenge(&mut self, label: Label) -> Result<T, Self::Error> {
self.begin_challenge::<(Self, T)>(label.clone(), Length::Scalar)?;
let mut result = T::new_zeroed();
self.challenge(result.as_mut_bytes()).unwrap();
self.end_challenge::<(Self, T)>(label.clone(), Length::Scalar)?;
Ok(result)
}
}

#[cfg(test)]
mod tests {
use super::*;
}
2 changes: 1 addition & 1 deletion spongefish/src/domain_separator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl<H: DuplexSpongeInterface<U>, U: Unit> DomainSeparator<H, U> {
/// Create an [`crate::ProverState`] instance from the domain separator.
#[must_use]
pub fn to_prover_state(&self) -> crate::ProverState<H, U, crate::DefaultRng> {
self.into()
unimplemented!()
}

/// Create a [`crate::VerifierState`] instance from the domain separator and the protocol transcript (bytes).
Expand Down
23 changes: 3 additions & 20 deletions spongefish/src/duplex_sponge/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ where
fn new(iv: [u8; 32]) -> Self;

/// Absorbs new elements in the sponge.
fn absorb_unchecked(&mut self, input: &[U]) -> &mut Self;
fn absorb(&mut self, input: &[U]) -> &mut Self;

/// Squeezes out new elements.
fn squeeze_unchecked(&mut self, output: &mut [U]) -> &mut Self;
fn squeeze(&mut self, output: &mut [U]) -> &mut Self;

/// Ratcheting.
///
Expand All @@ -29,22 +29,5 @@ where
/// - zero rate elements.
/// This has the effect that state holds no information about the elements absorbed so far.
/// The resulting state is compressed.
fn ratchet_unchecked(&mut self) -> &mut Self;

// /// Exports the hash state, allowing for preprocessing.
// ///
// /// This function can be used for duplicating the state of the sponge,
// /// but is limited to exporting the state in a way that is compatible
// /// with the `load` function.
// fn tag(self) -> &'static [Self::U];
}

impl Unit for u8 {
fn write(bunch: &[Self], w: &mut impl std::io::Write) -> Result<(), std::io::Error> {
w.write_all(bunch)
}

fn read(r: &mut impl std::io::Read, bunch: &mut [Self]) -> Result<(), std::io::Error> {
r.read_exact(bunch)
}
fn ratchet(&mut self) -> &mut Self;
}
Loading