mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-12 09:01:28 +01:00
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:
2
src/constants.rs
Normal file
2
src/constants.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub(crate) const NUM_CHALLENGE_BITS: usize = 128;
|
||||||
|
pub(crate) const NUM_HASH_BITS: usize = 250;
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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[..NUM_CHALLENGE_BITS].into())
|
||||||
Ok(bits[..128].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[..NUM_HASH_BITS].into())
|
||||||
Ok(bits[..250].into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
src/r1cs.rs
31
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<G: Group> AppendToTranscriptTrait for R1CSShape<G> {
|
|||||||
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user