Browse Source

Truncate digest bits (#50)

* apply a hash function before adding to transcript

* truncate shape_digest into 250 bits

* add missing file

* fix clippy

* cargo fmt
main
Srinath Setty 2 years ago
committed by GitHub
parent
commit
ccc6dc3a04
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 14 deletions
  1. +2
    -0
      src/constants.rs
  2. +3
    -4
      src/lib.rs
  3. +10
    -9
      src/poseidon.rs
  4. +30
    -1
      src/r1cs.rs

+ 2
- 0
src/constants.rs

@ -0,0 +1,2 @@
pub(crate) const NUM_CHALLENGE_BITS: usize = 128;
pub(crate) const NUM_HASH_BITS: usize = 250;

+ 3
- 4
src/lib.rs

@ -3,10 +3,10 @@
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
#![deny(missing_docs)] #![deny(missing_docs)]
mod commitments;
pub mod bellperson; pub mod bellperson;
mod circuit; mod circuit;
mod commitments;
mod constants;
pub mod errors; pub mod errors;
pub mod gadgets; pub mod gadgets;
pub mod pasta; pub mod pasta;
@ -14,14 +14,13 @@ mod poseidon;
pub mod r1cs; pub mod r1cs;
pub mod traits; pub mod traits;
use std::marker::PhantomData;
use commitments::CompressedCommitment; use commitments::CompressedCommitment;
use errors::NovaError; use errors::NovaError;
use merlin::Transcript; use merlin::Transcript;
use r1cs::{ use r1cs::{
R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness,
}; };
use std::marker::PhantomData;
use traits::{AppendToTranscriptTrait, ChallengeTrait, Group}; use traits::{AppendToTranscriptTrait, ChallengeTrait, Group};
/// A SNARK that holds the proof of a step of an incremental computation /// A SNARK that holds the proof of a step of an incremental computation

+ 10
- 9
src/poseidon.rs

@ -1,5 +1,8 @@
//! Poseidon Constants and Poseidon-based RO used in Nova //! Poseidon Constants and Poseidon-based RO used in Nova
use crate::traits::{HashFuncConstantsTrait, HashFuncTrait};
use super::{
constants::{NUM_CHALLENGE_BITS, NUM_HASH_BITS},
traits::{HashFuncConstantsTrait, HashFuncTrait},
};
use bellperson::{ use bellperson::{
gadgets::{ gadgets::{
boolean::{AllocatedBit, Boolean}, boolean::{AllocatedBit, Boolean},
@ -102,11 +105,11 @@ where
#[allow(dead_code)] #[allow(dead_code)]
fn get_challenge(&self) -> Scalar { fn get_challenge(&self) -> Scalar {
let hash = self.hash_inner(); let hash = self.hash_inner();
// Only keep 128 bits
// Only keep NUM_CHALLENGE_BITS bits
let bits = hash.to_le_bits(); let bits = hash.to_le_bits();
let mut res = Scalar::zero(); let mut res = Scalar::zero();
let mut coeff = Scalar::one(); let mut coeff = Scalar::one();
for bit in bits[0..128].into_iter() {
for bit in bits[0..NUM_CHALLENGE_BITS].into_iter() {
if *bit { if *bit {
res += coeff; res += coeff;
} }
@ -118,11 +121,11 @@ where
#[allow(dead_code)] #[allow(dead_code)]
fn get_hash(&self) -> Scalar { fn get_hash(&self) -> Scalar {
let hash = self.hash_inner(); let hash = self.hash_inner();
// Only keep 250 bits
// Only keep NUM_HASH_BITS bits
let bits = hash.to_le_bits(); let bits = hash.to_le_bits();
let mut res = Scalar::zero(); let mut res = Scalar::zero();
let mut coeff = Scalar::one(); let mut coeff = Scalar::one();
for bit in bits[0..250].into_iter() {
for bit in bits[0..NUM_HASH_BITS].into_iter() {
if *bit { if *bit {
res += coeff; res += coeff;
} }
@ -204,8 +207,7 @@ where
CS: ConstraintSystem<Scalar>, CS: ConstraintSystem<Scalar>,
{ {
let bits = self.hash_inner(cs.namespace(|| "hash"))?; let bits = self.hash_inner(cs.namespace(|| "hash"))?;
// Only keep 128 bits
Ok(bits[..128].into())
Ok(bits[..NUM_CHALLENGE_BITS].into())
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -214,8 +216,7 @@ where
CS: ConstraintSystem<Scalar>, CS: ConstraintSystem<Scalar>,
{ {
let bits = self.hash_inner(cs.namespace(|| "hash"))?; let bits = self.hash_inner(cs.namespace(|| "hash"))?;
// Only keep 250 bits
Ok(bits[..250].into())
Ok(bits[..NUM_HASH_BITS].into())
} }
} }

+ 30
- 1
src/r1cs.rs

@ -2,6 +2,7 @@
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
use super::{ use super::{
commitments::{CommitGens, CommitTrait, Commitment, CompressedCommitment}, commitments::{CommitGens, CommitTrait, Commitment, CompressedCommitment},
constants::NUM_HASH_BITS,
errors::NovaError, errors::NovaError,
traits::{AppendToTranscriptTrait, Group}, traits::{AppendToTranscriptTrait, Group},
}; };
@ -11,6 +12,7 @@ use itertools::concat;
use merlin::Transcript; use merlin::Transcript;
use rayon::prelude::*; use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha3::{Digest, Sha3_256};
/// Public parameters for a given R1CS /// Public parameters for a given R1CS
pub struct R1CSGens<G: Group> { pub struct R1CSGens<G: Group> {
@ -328,10 +330,37 @@ impl AppendToTranscriptTrait for R1CSShape {
.collect(), .collect(),
}; };
// obtain a vector of bytes representing the R1CS shape
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
bincode::serialize_into(&mut encoder, &shape_serialized).unwrap(); bincode::serialize_into(&mut encoder, &shape_serialized).unwrap();
let shape_bytes = encoder.finish().unwrap(); let shape_bytes = encoder.finish().unwrap();
transcript.append_message(b"R1CSShape", &shape_bytes);
// convert shape_bytes into a short digest
let mut hasher = Sha3_256::new();
hasher.input(&shape_bytes);
let shape_digest = hasher.result();
let shape_digest_trun = {
// truncate the digest to 250 bits
let bv = (0..NUM_HASH_BITS).map(|i| {
let (byte_pos, bit_pos) = (i / 8, i % 8);
let bit = (shape_digest[byte_pos] >> bit_pos) & 1;
bit == 1
});
// turn the bit vector into a scalar
let mut res = G::Scalar::zero();
let mut coeff = G::Scalar::one();
for bit in bv {
if bit {
res += coeff;
}
coeff += coeff;
}
res
};
shape_digest_trun.append_to_transcript(b"R1CSShape", transcript);
} }
} }

Loading…
Cancel
Save