Pass bits around

This commit is contained in:
wborgeaud 2021-07-22 15:10:55 +02:00
parent 15a64017dc
commit 22fcc3bc06
3 changed files with 26 additions and 23 deletions

View File

@ -20,7 +20,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn compute_evaluation(
&mut self,
x: Target,
old_x_index: Target,
old_x_index_bits: &[Target],
arity_bits: usize,
last_evals: &[ExtensionTarget<D>],
beta: ExtensionTarget<D>,
@ -33,7 +33,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// The evaluation vector needs to be reordered first.
let mut evals = last_evals.to_vec();
reverse_index_bits_in_place(&mut evals);
let mut old_x_index_bits = self.split_le(old_x_index, arity_bits);
let mut old_x_index_bits = old_x_index_bits.to_vec();
old_x_index_bits.reverse();
// Want `g^(arity - rev_old_x_index)` as in the out-of-circuit version.
// Compute it as `g^(arity-1-rev_old_x_index) * g`, where the first term is gotten using two's complement.
@ -148,7 +148,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn fri_verify_initial_proof(
&mut self,
x_index: Target,
x_index_bits: &[Target],
proof: &FriInitialTreeProofTarget,
initial_merkle_roots: &[HashTarget],
) {
@ -161,7 +161,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
context!(
self,
&format!("verify {}'th initial Merkle proof", i),
self.verify_merkle_proof(evals.clone(), x_index, root, merkle_proof)
self.verify_merkle_proof(evals.clone(), x_index_bits, root, merkle_proof)
);
}
}
@ -255,18 +255,19 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// TODO: Do we need to range check `x_index` to a target smaller than `p`?
let mut x_index = challenger.get_challenge(self);
x_index = self.split_low_high(x_index, n_log, 64).0;
let mut x_index_bits = self.low_bits(x_index, n_log, 64);
let mut x_index_num_bits = n_log;
let mut domain_size = n;
context!(
self,
"check FRI initial proof",
self.fri_verify_initial_proof(
x_index,
&x_index_bits,
&round_proof.initial_trees_proof,
initial_merkle_roots,
)
);
let mut old_x_index = self.zero();
let mut old_x_index_bits = Vec::new();
// `subgroup_x` is `subgroup[x_index]`, i.e., the actual field element in the domain.
let mut subgroup_x = context!(self, "compute x from its index", {
@ -302,7 +303,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
"infer evaluation using interpolation",
self.compute_evaluation(
subgroup_x,
old_x_index,
&old_x_index_bits,
config.reduction_arity_bits[i - 1],
last_evals,
betas[i - 1],
@ -313,13 +314,15 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// Insert P(y) into the evaluation vector, since it wasn't included by the prover.
let (low_x_index, high_x_index) =
self.split_low_high(x_index, arity_bits, x_index_num_bits);
let high_x_index_bits = x_index_bits.split_off(arity_bits);
old_x_index_bits = x_index_bits;
evals = self.insert(low_x_index, e_x, evals);
context!(
self,
"verify FRI round Merkle proof.",
self.verify_merkle_proof(
flatten_target(&evals),
high_x_index,
&high_x_index_bits,
proof.commit_phase_merkle_roots[i],
&round_proof.steps[i].merkle_proof,
)
@ -331,9 +334,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
subgroup_x = self.exp_power_of_2(subgroup_x, config.reduction_arity_bits[i - 1]);
}
domain_size = next_domain_size;
old_x_index = low_x_index;
x_index = high_x_index;
x_index_num_bits -= arity_bits;
x_index_bits = high_x_index_bits;
}
let last_evals = evaluations.last().unwrap();
@ -343,7 +346,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
"infer final evaluation using interpolation",
self.compute_evaluation(
subgroup_x,
old_x_index,
&old_x_index_bits,
final_arity_bits,
last_evals,
*betas.last().unwrap(),

View File

@ -14,6 +14,14 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.route(x, sum);
}
/// Returns the first `n_log` little-endian bits of `x`.
/// Note: `x` is assumed to be range-checked for having `num_bits` bits.
pub fn low_bits(&mut self, x: Target, n_log: usize, num_bits: usize) -> Vec<Target> {
let mut res = self.split_le(x, num_bits);
res.truncate(n_log);
res
}
/// Returns `(a,b)` such that `x = a + 2^n_log * b` with `a < 2^n_log`.
/// `x` is assumed to be range-checked for having `num_bits` bits.
pub fn split_low_high(&mut self, x: Target, n_log: usize, num_bits: usize) -> (Target, Target) {

View File

@ -59,23 +59,20 @@ pub(crate) fn verify_merkle_proof<F: Field>(
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Verifies that the given leaf data is present at the given index in the Merkle tree with the
/// given root.
/// given root. The index is given by it's little-endian bits.
pub(crate) fn verify_merkle_proof(
&mut self,
leaf_data: Vec<Target>,
leaf_index: Target,
leaf_index_bits: &[Target],
merkle_root: HashTarget,
proof: &MerkleProofTarget,
) {
let zero = self.zero();
let two = self.two();
let height = proof.siblings.len();
let purported_index_bits = self.split_le_virtual(leaf_index, height);
let mut state: HashTarget = self.hash_or_noop(leaf_data);
let mut acc_leaf_index = zero;
for (bit, &sibling) in purported_index_bits.into_iter().zip(&proof.siblings) {
for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) {
let gate = self
.add_gate_no_constants(GMiMCGate::<F, D, GMIMC_ROUNDS>::with_automatic_constants());
@ -86,8 +83,6 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
});
self.generate_copy(bit, swap_wire);
acc_leaf_index = self.mul_add(two, acc_leaf_index, bit);
let input_wires = (0..12)
.map(|i| {
Target::Wire(Wire {
@ -115,10 +110,6 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
)
}
// TODO: this is far from optimal.
let leaf_index_rev = self.reverse_limbs::<2>(leaf_index, height);
self.assert_equal(acc_leaf_index, leaf_index_rev);
self.named_assert_hashes_equal(state, merkle_root, "check Merkle root".into())
}
@ -180,13 +171,14 @@ mod tests {
pw.set_hash_target(root_t, tree.root);
let i_c = builder.constant(F::from_canonical_usize(i));
let i_bits = builder.split_le(i_c, log_n);
let data = builder.add_virtual_targets(tree.leaves[i].len());
for j in 0..data.len() {
pw.set_target(data[j], tree.leaves[i][j]);
}
builder.verify_merkle_proof(data, i_c, root_t, &proof_t);
builder.verify_merkle_proof(data, &i_bits, root_t, &proof_t);
let data = builder.build();
let proof = data.prove(pw)?;