Skip to content

Commit

Permalink
[zk-token-sdk] Restrict range proof generator length and prevent 0-bi…
Browse files Browse the repository at this point in the history
…t range proof (#34166)

* limit range proof generator length

* forbid 0-bit range proof verification
  • Loading branch information
samkim-crypto authored Nov 20, 2023
1 parent e251b86 commit 0e6dd54
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 13 deletions.
13 changes: 12 additions & 1 deletion zk-token-sdk/src/range_proof/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
use {crate::errors::TranscriptError, thiserror::Error};

#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum RangeProofGenerationError {}
pub enum RangeProofGenerationError {
#[error("maximum generator length exceeded")]
MaximumGeneratorLengthExceeded,
}

#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum RangeProofVerificationError {
Expand All @@ -20,4 +23,12 @@ pub enum RangeProofVerificationError {
InvalidBitSize,
#[error("insufficient generators for the proof")]
InvalidGeneratorsLength,
#[error("maximum generator length exceeded")]
MaximumGeneratorLengthExceeded,
}

#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum RangeProofGeneratorError {
#[error("maximum generator length exceeded")]
MaximumGeneratorLengthExceeded,
}
27 changes: 19 additions & 8 deletions zk-token-sdk/src/range_proof/generators.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use {
crate::range_proof::errors::RangeProofGeneratorError,
curve25519_dalek::{
digest::{ExtendableOutput, Update, XofReader},
ristretto::RistrettoPoint,
},
sha3::{Sha3XofReader, Shake256},
};

#[cfg(not(target_os = "solana"))]
const MAX_GENERATOR_LENGTH: usize = u32::MAX as usize;

/// Generators for Pedersen vector commitments that are used for inner-product proofs.
struct GeneratorsChain {
reader: Sha3XofReader,
Expand Down Expand Up @@ -67,37 +71,44 @@ pub struct BulletproofGens {
}

impl BulletproofGens {
pub fn new(gens_capacity: usize) -> Self {
pub fn new(gens_capacity: usize) -> Result<Self, RangeProofGeneratorError> {
let mut gens = BulletproofGens {
gens_capacity: 0,
G_vec: Vec::new(),
H_vec: Vec::new(),
};
gens.increase_capacity(gens_capacity);
gens
gens.increase_capacity(gens_capacity)?;
Ok(gens)
}

/// Increases the generators' capacity to the amount specified.
/// If less than or equal to the current capacity, does nothing.
pub fn increase_capacity(&mut self, new_capacity: usize) {
pub fn increase_capacity(
&mut self,
new_capacity: usize,
) -> Result<(), RangeProofGeneratorError> {
if self.gens_capacity >= new_capacity {
return;
return Ok(());
}

if new_capacity > MAX_GENERATOR_LENGTH {
return Err(RangeProofGeneratorError::MaximumGeneratorLengthExceeded);
}

let label = [b'G'];
self.G_vec.extend(
&mut GeneratorsChain::new(&[label, [b'G']].concat())
&mut GeneratorsChain::new(&[b'G'])
.fast_forward(self.gens_capacity)
.take(new_capacity - self.gens_capacity),
);

self.H_vec.extend(
&mut GeneratorsChain::new(&[label, [b'H']].concat())
&mut GeneratorsChain::new(&[b'H'])
.fast_forward(self.gens_capacity)
.take(new_capacity - self.gens_capacity),
);

self.gens_capacity = new_capacity;
Ok(())
}

#[allow(non_snake_case)]
Expand Down
4 changes: 2 additions & 2 deletions zk-token-sdk/src/range_proof/inner_product.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl InnerProductProof {
transcript: &mut Transcript,
) -> Result<(Vec<Scalar>, Vec<Scalar>, Vec<Scalar>), RangeProofVerificationError> {
let lg_n = self.L_vec.len();
if lg_n >= 32 {
if lg_n == 0 || lg_n >= 32 {
// 4 billion multiplications should be enough for anyone
// and this check prevents overflow in 1<<lg_n below.
return Err(RangeProofVerificationError::InvalidBitSize);
Expand Down Expand Up @@ -410,7 +410,7 @@ mod tests {
fn test_basic_correctness() {
let n = 32;

let bp_gens = BulletproofGens::new(n);
let bp_gens = BulletproofGens::new(n).unwrap();
let G: Vec<RistrettoPoint> = bp_gens.G(n).cloned().collect();
let H: Vec<RistrettoPoint> = bp_gens.H(n).cloned().collect();

Expand Down
6 changes: 4 additions & 2 deletions zk-token-sdk/src/range_proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ impl RangeProof {
let nm: usize = bit_lengths.iter().sum();
assert!(nm.is_power_of_two());

let bp_gens = BulletproofGens::new(nm);
let bp_gens = BulletproofGens::new(nm)
.map_err(|_| RangeProofGenerationError::MaximumGeneratorLengthExceeded)?;

// bit-decompose values and generate their Pedersen vector commitment
let a_blinding = Scalar::random(&mut OsRng);
Expand Down Expand Up @@ -241,7 +242,8 @@ impl RangeProof {

let m = bit_lengths.len();
let nm: usize = bit_lengths.iter().sum();
let bp_gens = BulletproofGens::new(nm);
let bp_gens = BulletproofGens::new(nm)
.map_err(|_| RangeProofVerificationError::MaximumGeneratorLengthExceeded)?;

if !nm.is_power_of_two() {
return Err(RangeProofVerificationError::InvalidBitSize);
Expand Down

0 comments on commit 0e6dd54

Please sign in to comment.