Skip to content

Commit

Permalink
Better validation of proof shares in Range Proof MPC (#296)
Browse files Browse the repository at this point in the history
Addressing issues raised by the quarkslab audit (to be released soon):

* additional size validation for individual proof shares,
* correct `size_hint` for `AggregatedGensIter`,
* reused computation of powers-of-z in the proof aggregation to save a bit of CPU.
  • Loading branch information
oleganza authored Aug 12, 2019
1 parent 4bc89d2 commit f7c6df9
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ keywords = ["cryptography", "crypto", "ristretto", "zero-knowledge", "bulletproo
description = "A pure-Rust implementation of Bulletproofs using Ristretto"

[dependencies]
curve25519-dalek = { version = "1.0.3", features = ["serde"] }
curve25519-dalek = { version = "^1.2.3", features = ["serde"] }
subtle = "2"
sha3 = "0.8"
digest = "0.8"
Expand Down
2 changes: 1 addition & 1 deletion src/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl<'a> Iterator for AggregatedGensIter<'a> {
}

fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.n * self.m;
let size = self.n * (self.m - self.party_idx) - self.gen_idx;
(size, Some(size))
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/range_proof/dealer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,20 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
return Err(MPCError::WrongNumProofShares);
}

// Validate lengths for each share
let mut bad_shares = Vec::<usize>::new(); // no allocations until we append
for (j, share) in proof_shares.iter().enumerate() {
share
.check_size(self.n, &self.bp_gens, j)
.unwrap_or_else(|_| {
bad_shares.push(j);
});
}

if bad_shares.len() > 0 {
return Err(MPCError::MalformedProofShares { bad_shares });
}

let t_x: Scalar = proof_shares.iter().map(|ps| ps.t_x).sum();
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();
Expand Down
29 changes: 29 additions & 0 deletions src/range_proof/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ pub struct ProofShare {
}

impl ProofShare {
/// Checks consistency of all sizes in the proof share and returns the size of the l/r vector.
pub(super) fn check_size(
&self,
expected_n: usize,
bp_gens: &BulletproofGens,
j: usize,
) -> Result<(), ()> {
if self.l_vec.len() != expected_n {
return Err(());
}

if self.r_vec.len() != expected_n {
return Err(());
}

if expected_n > bp_gens.gens_capacity {
return Err(());
}

if j >= bp_gens.party_capacity {
return Err(());
}

Ok(())
}

/// Audit an individual proof share to determine whether it is
/// malformed.
pub(super) fn audit_share(
Expand All @@ -69,6 +95,9 @@ impl ProofShare {
use util;

let n = self.l_vec.len();

self.check_size(n, bp_gens, j)?;

let (y, z) = (&bit_challenge.y, &bit_challenge.z);
let x = &poly_challenge.x;

Expand Down
12 changes: 5 additions & 7 deletions src/range_proof/party.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl<'a> PartyAwaitingBitChallenge<'a> {
let mut l_poly = util::VecPoly1::zero(n);
let mut r_poly = util::VecPoly1::zero(n);

let zz = vc.z * vc.z;
let offset_zz = vc.z * vc.z * offset_z;
let mut exp_y = offset_y; // start at y^j
let mut exp_2 = Scalar::one(); // start at 2^0 = 1
for i in 0..n {
Expand All @@ -178,7 +178,7 @@ impl<'a> PartyAwaitingBitChallenge<'a> {

l_poly.0[i] = a_L_i - vc.z;
l_poly.1[i] = self.s_L[i];
r_poly.0[i] = exp_y * (a_R_i + vc.z) + zz * offset_z * exp_2;
r_poly.0[i] = exp_y * (a_R_i + vc.z) + offset_zz * exp_2;
r_poly.1[i] = exp_y * self.s_R[i];

exp_y *= vc.y; // y^i -> y^(i+1)
Expand All @@ -202,8 +202,7 @@ impl<'a> PartyAwaitingBitChallenge<'a> {
v_blinding: self.v_blinding,
a_blinding: self.a_blinding,
s_blinding: self.s_blinding,
z: vc.z,
offset_z,
offset_zz,
l_poly,
r_poly,
t_poly,
Expand Down Expand Up @@ -240,8 +239,7 @@ impl<'a> Drop for PartyAwaitingBitChallenge<'a> {
/// A party which has committed to their polynomial coefficents
/// and is waiting for the polynomial challenge from the dealer.
pub struct PartyAwaitingPolyChallenge {
z: Scalar,
offset_z: Scalar,
offset_zz: Scalar,
l_poly: util::VecPoly1,
r_poly: util::VecPoly1,
t_poly: util::Poly2,
Expand All @@ -263,7 +261,7 @@ impl PartyAwaitingPolyChallenge {
}

let t_blinding_poly = util::Poly2(
self.z * self.z * self.offset_z * self.v_blinding,
self.offset_zz * self.v_blinding,
self.t_1_blinding,
self.t_2_blinding,
);
Expand Down

0 comments on commit f7c6df9

Please sign in to comment.