make step_circuit mandatory; add support for longer hashes (#30)

This commit is contained in:
Srinath Setty
2022-04-15 16:06:26 -07:00
committed by GitHub
parent 866717a8f2
commit 9a0f5604d6
2 changed files with 168 additions and 188 deletions

View File

@@ -104,7 +104,7 @@ where
{
params: NIFSVerifierCircuitParams,
inputs: Option<NIFSVerifierCircuitInputs<G>>,
step_circuit: Option<SC>, // The function that is applied for each step. may be None.
step_circuit: SC, // The function that is applied for each step
poseidon_constants: NovaPoseidonConstants<G::Base>,
}
@@ -119,7 +119,7 @@ where
pub fn new(
params: NIFSVerifierCircuitParams,
inputs: Option<NIFSVerifierCircuitInputs<G>>,
step_circuit: Option<SC>,
step_circuit: SC,
poseidon_constants: NovaPoseidonConstants<G::Base>,
) -> Self
where
@@ -477,7 +477,6 @@ where
|lc| lc + next_i.get_variable() - CS::one() - i.get_variable(),
);
if self.step_circuit.is_some() {
/***********************************************************************/
// Allocate z0
/***********************************************************************/
@@ -537,7 +536,7 @@ where
h1_hash.absorb(z_0.clone());
h1_hash.absorb(z_i.clone());
let hash_bits = h1_hash.get_challenge(cs.namespace(|| "Input hash"))?;
let hash_bits = h1_hash.get_challenge(cs.namespace(|| "Input hash"))?; // TODO: use get_hash method
let hash = le_bits_to_num(cs.namespace(|| "bits to hash"), hash_bits)?;
cs.enforce(
@@ -553,7 +552,6 @@ where
let z_next = self
.step_circuit
.unwrap()
.synthesize(&mut cs.namespace(|| "F"), z_i)?;
/***********************************************************************/
@@ -583,75 +581,9 @@ where
h1_hash.absorb(next_i.clone());
h1_hash.absorb(z_0);
h1_hash.absorb(z_next);
let h1_new_bits = h1_hash.get_challenge(cs.namespace(|| "h1_new bits"))?;
let h1_new_bits = h1_hash.get_challenge(cs.namespace(|| "h1_new bits"))?; // TODO: use get_hash method
let h1_new = le_bits_to_num(cs.namespace(|| "h1_new"), h1_new_bits)?;
let _ = h1_new.inputize(cs.namespace(|| "output h1_new"))?;
} else {
/***********************************************************************/
// Check that h1 = Hash(params, u2, i)
/***********************************************************************/
let mut h1_hash: PoseidonROGadget<G::Base> = PoseidonROGadget::new(self.poseidon_constants);
h1_hash.absorb(params.clone());
h1_hash.absorb(W_r.x);
h1_hash.absorb(W_r.y);
h1_hash.absorb(W_r.is_infinity);
h1_hash.absorb(E_r.x);
h1_hash.absorb(E_r.y);
h1_hash.absorb(E_r.is_infinity);
h1_hash.absorb(u_r);
h1_hash.absorb(i.clone());
// absorb each of the limbs of X_r[0]
for limb in Xr0_bn.into_iter() {
h1_hash.absorb(limb);
}
// absorb each of the limbs of X_r[1]
for limb in Xr1_bn.into_iter() {
h1_hash.absorb(limb);
}
let hash_bits = h1_hash.get_challenge(cs.namespace(|| "Input hash"))?;
let hash = le_bits_to_num(cs.namespace(|| "bits to hash"), hash_bits)?;
cs.enforce(
|| "check h1",
|lc| lc,
|lc| lc,
|lc| lc + h1.get_variable() - hash.get_variable(),
);
/***********************************************************************/
// Compute the new hash H(params, u2')
/***********************************************************************/
h1_hash.flush_state();
h1_hash.absorb(params);
h1_hash.absorb(W_new.x.clone());
h1_hash.absorb(W_new.y.clone());
h1_hash.absorb(W_new.is_infinity);
h1_hash.absorb(E_new.x.clone());
h1_hash.absorb(E_new.y.clone());
h1_hash.absorb(E_new.is_infinity);
h1_hash.absorb(u_new);
h1_hash.absorb(next_i.clone());
// absorb each of the limbs of X_r_new[0]
for limb in Xr0_new_bn.into_iter() {
h1_hash.absorb(limb);
}
// absorb each of the limbs of X_r_new[1]
for limb in Xr1_new_bn.into_iter() {
h1_hash.absorb(limb);
}
let h1_new_bits = h1_hash.get_challenge(cs.namespace(|| "h1_new bits"))?;
let h1_new = le_bits_to_num(cs.namespace(|| "h1_new"), h1_new_bits)?;
let _ = h1_new.inputize(cs.namespace(|| "output h1_new"))?;
}
Ok(())
}
@@ -700,9 +632,9 @@ mod tests {
NIFSVerifierCircuit::new(
params.clone(),
None,
Some(TestCircuit {
TestCircuit {
_p: Default::default(),
}),
},
poseidon_constants1.clone(),
);
// First create the shape
@@ -718,7 +650,14 @@ mod tests {
let poseidon_constants2: NovaPoseidonConstants<<G1 as Group>::Base> =
NovaPoseidonConstants::new();
let circuit2: NIFSVerifierCircuit<G1, TestCircuit<<G1 as Group>::Base>> =
NIFSVerifierCircuit::new(params.clone(), None, None, poseidon_constants2);
NIFSVerifierCircuit::new(
params.clone(),
None,
TestCircuit {
_p: Default::default(),
},
poseidon_constants2,
);
// First create the shape
let mut cs: ShapeCS<G2> = ShapeCS::new();
let _ = circuit2.synthesize(&mut cs);
@@ -755,9 +694,9 @@ mod tests {
NIFSVerifierCircuit::new(
params,
Some(inputs),
Some(TestCircuit {
TestCircuit {
_p: Default::default(),
}),
},
poseidon_constants1,
);
let _ = circuit.synthesize(&mut cs);

View File

@@ -80,10 +80,8 @@ where
self.state.push(e);
}
/// Compute a challenge by hashing the current state
#[allow(dead_code)]
pub fn get_challenge(&mut self) -> Scalar {
let hash = match self.state.len() {
fn hash_inner(&mut self) -> Scalar {
match self.state.len() {
25 => {
Poseidon::<Scalar, U25>::new_with_preimage(&self.state, &self.constants.constants25).hash()
}
@@ -96,7 +94,13 @@ where
_ => {
panic!("Number of elements in the RO state does not match any of the arities used in Nova")
}
};
}
}
/// Compute a challenge by hashing the current state
#[allow(dead_code)]
pub fn get_challenge(&mut self) -> Scalar {
let hash = self.hash_inner();
// Only keep 128 bits
let bits = hash.to_le_bits();
let mut res = Scalar::zero();
@@ -109,6 +113,22 @@ where
}
res
}
#[allow(dead_code)]
pub fn get_hash(&mut self) -> Scalar {
let hash = self.hash_inner();
// Only keep 250 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() {
if *bit {
res += coeff;
}
coeff += coeff;
}
res
}
}
/// A Poseidon-based RO gadget to use inside the verifier circuit.
@@ -145,9 +165,7 @@ where
self.state.push(e);
}
/// Compute a challenge by hashing the current state
#[allow(dead_code)]
pub fn get_challenge<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
fn hash_inner<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where
CS: ConstraintSystem<Scalar>,
{
@@ -171,17 +189,40 @@ where
panic!("Number of elements in the RO state does not match any of the arities used in Nova")
}
};
// Only keep 128 bits
let bits: Vec<AllocatedBit> = out
// return the hash as a vector of bits
Ok(
out
.to_bits_le_strict(cs.namespace(|| "poseidon hash to boolean"))?
.iter()
.map(|boolean| match boolean {
Boolean::Is(ref x) => x.clone(),
_ => panic!("Wrong type of input. We should have never reached there"),
})
.collect();
.collect(),
)
}
/// Compute a challenge by hashing the current state
#[allow(dead_code)]
pub fn get_challenge<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where
CS: ConstraintSystem<Scalar>,
{
let bits = self.hash_inner(cs.namespace(|| "hash"))?;
// Only keep 128 bits
Ok(bits[..128].into())
}
#[allow(dead_code)]
pub fn get_hash<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
where
CS: ConstraintSystem<Scalar>,
{
let bits = self.hash_inner(cs.namespace(|| "hash"))?;
// Only keep 250 bits
Ok(bits[..250].into())
}
}
#[cfg(test)]