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
This commit is contained in:
Srinath Setty
2022-05-13 10:38:43 +05:30
committed by GitHub
parent 0d53db18e3
commit ccc6dc3a04
4 changed files with 45 additions and 14 deletions

2
src/constants.rs Normal file
View File

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

View File

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

View File

@@ -1,5 +1,8 @@
//! 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::{
gadgets::{
boolean::{AllocatedBit, Boolean},
@@ -102,11 +105,11 @@ where
#[allow(dead_code)]
fn get_challenge(&self) -> Scalar {
let hash = self.hash_inner();
// Only keep 128 bits
// Only keep NUM_CHALLENGE_BITS bits
let bits = hash.to_le_bits();
let mut res = Scalar::zero();
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 {
res += coeff;
}
@@ -118,11 +121,11 @@ where
#[allow(dead_code)]
fn get_hash(&self) -> Scalar {
let hash = self.hash_inner();
// Only keep 250 bits
// Only keep NUM_HASH_BITS bits
let bits = hash.to_le_bits();
let mut res = Scalar::zero();
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 {
res += coeff;
}
@@ -204,8 +207,7 @@ where
CS: ConstraintSystem<Scalar>,
{
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)]
@@ -214,8 +216,7 @@ where
CS: ConstraintSystem<Scalar>,
{
let bits = self.hash_inner(cs.namespace(|| "hash"))?;
// Only keep 250 bits
Ok(bits[..250].into())
Ok(bits[..NUM_HASH_BITS].into())
}
}

View File

@@ -2,6 +2,7 @@
#![allow(clippy::type_complexity)]
use super::{
commitments::{CommitGens, CommitTrait, Commitment, CompressedCommitment},
constants::NUM_HASH_BITS,
errors::NovaError,
traits::{AppendToTranscriptTrait, Group},
};
@@ -11,6 +12,7 @@ use itertools::concat;
use merlin::Transcript;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use sha3::{Digest, Sha3_256};
/// Public parameters for a given R1CS
pub struct R1CSGens<G: Group> {
@@ -328,10 +330,37 @@ impl<G: Group> AppendToTranscriptTrait for R1CSShape<G> {
.collect(),
};
// obtain a vector of bytes representing the R1CS shape
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
bincode::serialize_into(&mut encoder, &shape_serialized).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);
}
}