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
32 changes: 16 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,34 @@ description = "A pure-Rust implementation of Bulletproofs using Ristretto"
edition = "2018"

[dependencies]
curve25519-dalek = { version = "4.1.1", features = ["digest", "group", "rand_core", "serde"] }
curve25519-dalek = { version = "5.0.0-pre.1", features = ["digest", "group", "rand_core", "serde"] }
group = { version = "0.13", default-features = false }
subtle = { version = "2.5", default-features = false }
sha3 = { version = "0.10", default-features = false }
digest = { version = "0.10", default-features = false }
rand_core = { version = "0.6", default-features = false, features = ["alloc"] }
rand = { version = "0.8", default-features = false, optional = true }
subtle = { version = "2.6", default-features = false }
sha3 = { version = "0.11.0-rc.3", default-features = false }
digest = { version = "0.11.0-rc.3", default-features = false }
rand_core = { version = "0.9", default-features = false }
rand = { version = "0.9", default-features = false, optional = true }
byteorder = { version = "1", default-features = false }
serde = { version = "1", default-features = false, features = ["alloc"] }
serde_derive = { version = "1", default-features = false }
thiserror = { version = "1", optional = true }
thiserror = { version = "2", optional = true }
merlin = { version = "3", default-features = false }
clear_on_drop = { version = "0.2", default-features = false }
clear_on_drop = { version = "0.2", default-features = false, features = ["no_cc"], optional = true }

[dev-dependencies]
hex = "0.3"
criterion = "0.3"
bincode = "1"
rand_chacha = "0.3"
curve25519-dalek = { version = "4.1.1", features = ["digest", "group", "legacy_compatibility", "rand_core", "serde"] }
hex = "0.4"
criterion = "0.6"
bincode = {version = "2", features = ["serde"] }
rand_chacha = "0.9"
curve25519-dalek = { version = "5.0.0-pre.1", features = ["digest", "group", "legacy_compatibility", "rand_core", "serde"] }

[features]
default = ["std"]
yoloproofs = []
std = ["rand", "rand/std", "rand/std_rng", "thiserror"]
nightly = ["subtle/nightly", "clear_on_drop/nightly"]
std = ["rand", "rand/std", "rand/std_rng", "rand/thread_rng", "thiserror", "dep:clear_on_drop"]
nightly = ["curve25519-dalek/alloc", "subtle/nightly", "clear_on_drop/nightly"]
docs = ["nightly"]

cloneable = []

[[test]]
name = "range_proof"
Expand Down
11 changes: 2 additions & 9 deletions benches/range_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,9 @@ fn create_aggregated_rangeproof_helper(n: usize, c: &mut Criterion) {

b.iter(|| {
// Each proof creation requires a clean transcript.
let mut transcript = Transcript::new(b"AggregateRangeProofBenchmark");
let transcript = Transcript::new(b"AggregateRangeProofBenchmark");

RangeProof::prove_multiple(
&bp_gens,
&pc_gens,
&mut transcript,
&values,
&blindings,
n,
)
RangeProof::prove_multiple(bp_gens, pc_gens, transcript, &values, &blindings, n)
})
},
&AGGREGATION_SIZES,
Expand Down
10 changes: 5 additions & 5 deletions src/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ pub struct BulletproofGens {
/// Number of values or parties
pub party_capacity: usize,
/// Precomputed \\(\mathbf G\\) generators for each party.
G_vec: Vec<Vec<RistrettoPoint>>,
pub G_vec: Vec<Vec<RistrettoPoint>>,
/// Precomputed \\(\mathbf H\\) generators for each party.
H_vec: Vec<Vec<RistrettoPoint>>,
pub H_vec: Vec<Vec<RistrettoPoint>>,
}

impl BulletproofGens {
Expand Down Expand Up @@ -269,9 +269,9 @@ impl<'a> Iterator for AggregatedGensIter<'a> {
#[derive(Copy, Clone)]
pub struct BulletproofGensShare<'a> {
/// The parent object that this is a view into
gens: &'a BulletproofGens,
pub gens: &'a BulletproofGens,
/// Which share we are
share: usize,
pub share: usize,
}

impl<'a> BulletproofGensShare<'a> {
Expand All @@ -281,7 +281,7 @@ impl<'a> BulletproofGensShare<'a> {
}

/// Return an iterator over this party's H generators with given size `n`.
pub(crate) fn H(&self, n: usize) -> impl Iterator<Item = &'a RistrettoPoint> {
pub fn H(&self, n: usize) -> impl Iterator<Item = &'a RistrettoPoint> {
self.gens.H_vec[self.share].iter().take(n)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/inner_product_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use merlin::Transcript;
use crate::errors::ProofError;
use crate::transcript::TranscriptProtocol;

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InnerProductProof {
pub(crate) L_vec: Vec<CompressedRistretto>,
pub(crate) R_vec: Vec<CompressedRistretto>,
Expand Down Expand Up @@ -224,7 +224,7 @@ impl InnerProductProof {
// 2. Compute 1/(u_k...u_1) and 1/u_k, ..., 1/u_1

let mut challenges_inv = challenges.clone();
let allinv = Scalar::batch_invert(&mut challenges_inv);
let allinv = Scalar::invert_batch_alloc(challenges_inv.as_mut_slice());

// 3. Compute u_i^2 and (1/u_i)^2

Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub use crate::errors::ProofError;
pub use crate::generators::{BulletproofGens, BulletproofGensShare, PedersenGens};
pub use crate::linear_proof::LinearProof;
pub use crate::range_proof::RangeProof;
pub use util::exp_iter;

#[cfg_attr(feature = "docs", doc(include = "../docs/aggregation-api.md"))]
pub mod range_proof_mpc {
Expand Down
2 changes: 1 addition & 1 deletion src/linear_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ impl LinearProof {

// 3. Compute the challenge inverses: 1/x_k, ..., 1/x_1
let mut challenges_inv = challenges.clone();
Scalar::batch_invert(&mut challenges_inv);
Scalar::invert_batch_alloc(challenges_inv.as_mut_slice());

Ok((challenges, challenges_inv, b[0]))
}
Expand Down
2 changes: 2 additions & 0 deletions src/r1cs/prover.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(non_snake_case)]

#[cfg(feature = "dep:clear_on_drop")]
use clear_on_drop::clear::Clear;
use core::borrow::BorrowMut;
use core::mem;
Expand Down Expand Up @@ -72,6 +73,7 @@ pub struct RandomizingProver<'g, T: BorrowMut<Transcript>> {
}

/// Overwrite secrets with null bytes when they go out of scope.
#[cfg(feature = "dep:clear_on_drop")]
impl Drop for Secrets {
fn drop(&mut self) {
self.v.clear();
Expand Down
91 changes: 51 additions & 40 deletions src/range_proof/dealer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,20 @@ use rand::thread_rng;
use super::messages::*;

/// Used to construct a dealer for the aggregated rangeproof MPC protocol.
#[cfg_attr(feature = "cloneable", derive(Clone))]
pub struct Dealer {}

impl Dealer {
/// Creates a new dealer coordinating `m` parties proving `n`-bit ranges.
pub fn new<'a, 'b>(
bp_gens: &'b BulletproofGens,
pc_gens: &'b PedersenGens,
transcript: &'a mut Transcript,
pub fn new(
bp_gens: BulletproofGens,
pc_gens: PedersenGens,
transcript: Transcript,
n: usize,
m: usize,
) -> Result<DealerAwaitingBitCommitments<'a, 'b>, MPCError> {
) -> Result<DealerAwaitingBitCommitments, MPCError> {
let mut transcript = transcript;

if !(n == 8 || n == 16 || n == 32 || n == 64) {
return Err(MPCError::InvalidBitsize);
}
Expand Down Expand Up @@ -82,48 +85,51 @@ impl Dealer {
}

/// A dealer waiting for the parties to send their [`BitCommitment`]s.
pub struct DealerAwaitingBitCommitments<'a, 'b> {
bp_gens: &'b BulletproofGens,
pc_gens: &'b PedersenGens,
transcript: &'a mut Transcript,
#[cfg_attr(feature = "cloneable", derive(Clone))]
pub struct DealerAwaitingBitCommitments {
bp_gens: BulletproofGens,
pc_gens: PedersenGens,
transcript: Transcript,
/// The dealer keeps a copy of the initial transcript state, so
/// that it can attempt to verify the aggregated proof at the end.
initial_transcript: Transcript,
n: usize,
m: usize,
}

impl<'a, 'b> DealerAwaitingBitCommitments<'a, 'b> {
impl DealerAwaitingBitCommitments {
/// Receive each party's [`BitCommitment`]s and compute the [`BitChallenge`].
pub fn receive_bit_commitments(
self,
bit_commitments: Vec<BitCommitment>,
) -> Result<(DealerAwaitingPolyCommitments<'a, 'b>, BitChallenge), MPCError> {
) -> Result<(DealerAwaitingPolyCommitments, BitChallenge), MPCError> {
let mut transcript = self.transcript;

if self.m != bit_commitments.len() {
return Err(MPCError::WrongNumBitCommitments);
}

// Commit each V_j individually
for vc in bit_commitments.iter() {
self.transcript.append_point(b"V", &vc.V_j);
transcript.append_point(b"V", &vc.V_j);
}

// Commit aggregated A_j, S_j
let A: RistrettoPoint = bit_commitments.iter().map(|vc| vc.A_j).sum();
self.transcript.append_point(b"A", &A.compress());
transcript.append_point(b"A", &A.compress());

let S: RistrettoPoint = bit_commitments.iter().map(|vc| vc.S_j).sum();
self.transcript.append_point(b"S", &S.compress());
transcript.append_point(b"S", &S.compress());

let y = self.transcript.challenge_scalar(b"y");
let z = self.transcript.challenge_scalar(b"z");
let y = transcript.challenge_scalar(b"y");
let z = transcript.challenge_scalar(b"z");
let bit_challenge = BitChallenge { y, z };

Ok((
DealerAwaitingPolyCommitments {
n: self.n,
m: self.m,
transcript: self.transcript,
transcript,
initial_transcript: self.initial_transcript,
bp_gens: self.bp_gens,
pc_gens: self.pc_gens,
Expand All @@ -139,13 +145,14 @@ impl<'a, 'b> DealerAwaitingBitCommitments<'a, 'b> {

/// A dealer which has sent the [`BitChallenge`] to the parties and
/// is waiting for their [`PolyCommitment`]s.
pub struct DealerAwaitingPolyCommitments<'a, 'b> {
#[cfg_attr(feature = "cloneable", derive(Clone))]
pub struct DealerAwaitingPolyCommitments {
n: usize,
m: usize,
transcript: &'a mut Transcript,
transcript: Transcript,
initial_transcript: Transcript,
bp_gens: &'b BulletproofGens,
pc_gens: &'b PedersenGens,
bp_gens: BulletproofGens,
pc_gens: PedersenGens,
bit_challenge: BitChallenge,
bit_commitments: Vec<BitCommitment>,
/// Aggregated commitment to the parties' bits
Expand All @@ -154,13 +161,15 @@ pub struct DealerAwaitingPolyCommitments<'a, 'b> {
S: RistrettoPoint,
}

impl<'a, 'b> DealerAwaitingPolyCommitments<'a, 'b> {
impl DealerAwaitingPolyCommitments {
/// Receive [`PolyCommitment`]s from the parties and compute the
/// [`PolyChallenge`].
pub fn receive_poly_commitments(
self,
poly_commitments: Vec<PolyCommitment>,
) -> Result<(DealerAwaitingProofShares<'a, 'b>, PolyChallenge), MPCError> {
) -> Result<(DealerAwaitingProofShares, PolyChallenge), MPCError> {
let mut transcript = self.transcript;

if self.m != poly_commitments.len() {
return Err(MPCError::WrongNumPolyCommitments);
}
Expand All @@ -169,17 +178,17 @@ impl<'a, 'b> DealerAwaitingPolyCommitments<'a, 'b> {
let T_1: RistrettoPoint = poly_commitments.iter().map(|pc| pc.T_1_j).sum();
let T_2: RistrettoPoint = poly_commitments.iter().map(|pc| pc.T_2_j).sum();

self.transcript.append_point(b"T_1", &T_1.compress());
self.transcript.append_point(b"T_2", &T_2.compress());
transcript.append_point(b"T_1", &T_1.compress());
transcript.append_point(b"T_2", &T_2.compress());

let x = self.transcript.challenge_scalar(b"x");
let x = transcript.challenge_scalar(b"x");
let poly_challenge = PolyChallenge { x };

Ok((
DealerAwaitingProofShares {
n: self.n,
m: self.m,
transcript: self.transcript,
transcript,
initial_transcript: self.initial_transcript,
bp_gens: self.bp_gens,
pc_gens: self.pc_gens,
Expand All @@ -200,15 +209,16 @@ impl<'a, 'b> DealerAwaitingPolyCommitments<'a, 'b> {
/// A dealer which has sent the [`PolyChallenge`] to the parties and
/// is waiting to aggregate their [`ProofShare`]s into a
/// [`RangeProof`].
pub struct DealerAwaitingProofShares<'a, 'b> {
#[cfg_attr(feature = "cloneable", derive(Clone))]
pub struct DealerAwaitingProofShares {
n: usize,
m: usize,
transcript: &'a mut Transcript,
transcript: Transcript,
initial_transcript: Transcript,
bp_gens: &'b BulletproofGens,
pc_gens: &'b PedersenGens,
bp_gens: BulletproofGens,
pc_gens: PedersenGens,
bit_challenge: BitChallenge,
bit_commitments: Vec<BitCommitment>,
pub bit_commitments: Vec<BitCommitment>,
poly_challenge: PolyChallenge,
poly_commitments: Vec<PolyCommitment>,
A: RistrettoPoint,
Expand All @@ -217,13 +227,15 @@ pub struct DealerAwaitingProofShares<'a, 'b> {
T_2: RistrettoPoint,
}

impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
impl DealerAwaitingProofShares {
/// Assembles proof shares into an `RangeProof`.
///
/// Used as a helper function by `receive_trusted_shares` (which
/// just hands back the result) and `receive_shares` (which
/// validates the proof shares.
fn assemble_shares(&mut self, proof_shares: &[ProofShare]) -> Result<RangeProof, MPCError> {
let mut transcript = self.transcript.clone();

if self.m != proof_shares.len() {
return Err(MPCError::WrongNumProofShares);
}
Expand All @@ -246,13 +258,12 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
let t_x_blinding: Scalar = proof_shares.iter().map(|ps| ps.t_x_blinding).sum();
let e_blinding: Scalar = proof_shares.iter().map(|ps| ps.e_blinding).sum();

self.transcript.append_scalar(b"t_x", &t_x);
self.transcript
.append_scalar(b"t_x_blinding", &t_x_blinding);
self.transcript.append_scalar(b"e_blinding", &e_blinding);
transcript.append_scalar(b"t_x", &t_x);
transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
transcript.append_scalar(b"e_blinding", &e_blinding);

// Get a challenge value to combine statements for the IPP
let w = self.transcript.challenge_scalar(b"w");
let w = transcript.challenge_scalar(b"w");
let Q = w * self.pc_gens.B;

let G_factors: Vec<Scalar> = iter::repeat(Scalar::ONE).take(self.n * self.m).collect();
Expand All @@ -270,7 +281,7 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
.collect();

let ipp_proof = inner_product_proof::InnerProductProof::create(
self.transcript,
&mut transcript,
&Q,
&G_factors,
&H_factors,
Expand Down Expand Up @@ -328,7 +339,7 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
// See comment in `Dealer::new` for why we use `initial_transcript`
let transcript = &mut self.initial_transcript;
if proof
.verify_multiple_with_rng(self.bp_gens, self.pc_gens, transcript, &Vs, self.n, rng)
.verify_multiple_with_rng(&self.bp_gens, &self.pc_gens, transcript, &Vs, self.n, rng)
.is_ok()
{
Ok(proof)
Expand Down
Loading