mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-10 16:11:29 +01:00
make step_circuit mandatory; add support for longer hashes (#30)
This commit is contained in:
@@ -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
|
||||
@@ -289,7 +289,7 @@ where
|
||||
// U2' = default if i == 0, otherwise NIFS.V(pp, u_new, U, T)
|
||||
/***********************************************************************/
|
||||
|
||||
//Allocate 0 and 1
|
||||
// Allocate 0 and 1
|
||||
let zero = alloc_zero(cs.namespace(|| "zero"))?;
|
||||
// Hack: We just do this because the number of inputs must be even!!
|
||||
zero.inputize(cs.namespace(|| "allocate zero as input"))?;
|
||||
@@ -477,15 +477,14 @@ where
|
||||
|lc| lc + next_i.get_variable() - CS::one() - i.get_variable(),
|
||||
);
|
||||
|
||||
if self.step_circuit.is_some() {
|
||||
/***********************************************************************/
|
||||
//Allocate z0
|
||||
// Allocate z0
|
||||
/***********************************************************************/
|
||||
|
||||
let z_0 = AllocatedNum::alloc(cs.namespace(|| "z0"), || Ok(self.inputs.get()?.z0))?;
|
||||
|
||||
/***********************************************************************/
|
||||
//Allocate zi
|
||||
// Allocate zi
|
||||
/***********************************************************************/
|
||||
|
||||
let z_i = AllocatedNum::alloc(cs.namespace(|| "zi"), || Ok(self.inputs.get()?.zi))?;
|
||||
@@ -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);
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user