plonky2/src/gadgets/random_access.rs

127 lines
4.3 KiB
Rust
Raw Normal View History

2021-08-04 10:58:07 -07:00
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::Extendable;
use crate::field::field_types::RichField;
2021-08-04 10:58:07 -07:00
use crate::gates::random_access::RandomAccessGate;
use crate::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder;
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
2021-10-18 16:48:21 +02:00
/// Finds the last available random access gate with the given `vec_size` or add one if there aren't any.
/// Returns `(g,i)` such that there is a random access gate with the given `vec_size` at index
/// `g` and the gate's `i`-th random access is available.
fn find_random_access_gate(&mut self, vec_size: usize) -> (usize, usize) {
2021-10-18 16:48:21 +02:00
let (gate, i) = self
.free_random_access
.get(&vec_size)
.copied()
.unwrap_or_else(|| {
let gate = self.add_gate(
RandomAccessGate::new_from_config(&self.config, vec_size),
vec![],
);
(gate, 0)
});
// Update `free_random_access` with new values.
if i < RandomAccessGate::<F, D>::max_num_copies(
self.config.num_routed_wires,
self.config.num_wires,
vec_size,
) - 1
{
self.free_random_access.insert(vec_size, (gate, i + 1));
} else {
self.free_random_access.remove(&vec_size);
}
(gate, i)
}
2021-10-18 17:23:39 +02:00
/// Checks that a `Target` matches a vector at a non-deterministic index.
2021-10-18 15:45:52 +02:00
/// Note: `access_index` is not range-checked.
pub fn random_access(&mut self, access_index: Target, claimed_element: Target, v: Vec<Target>) {
2021-10-18 16:48:21 +02:00
let vec_size = v.len();
debug_assert!(vec_size > 0);
if vec_size == 1 {
2021-10-18 15:45:52 +02:00
return self.connect(claimed_element, v[0]);
}
let (gate_index, copy) = self.find_random_access_gate(vec_size);
2021-10-18 16:48:21 +02:00
let dummy_gate = RandomAccessGate::<F, D>::new_from_config(&self.config, vec_size);
2021-10-18 15:45:52 +02:00
v.iter().enumerate().for_each(|(i, &val)| {
2021-10-18 16:48:21 +02:00
self.connect(
val,
Target::wire(gate_index, dummy_gate.wire_list_item(i, copy)),
);
2021-10-18 15:45:52 +02:00
});
self.connect(
access_index,
2021-10-18 16:48:21 +02:00
Target::wire(gate_index, dummy_gate.wire_access_index(copy)),
2021-10-18 15:45:52 +02:00
);
self.connect(
claimed_element,
2021-10-18 16:48:21 +02:00
Target::wire(gate_index, dummy_gate.wire_claimed_element(copy)),
2021-10-18 15:45:52 +02:00
);
}
/// Checks that an `ExtensionTarget` matches a vector at a non-deterministic index.
/// Note: `access_index` is not range-checked.
2021-10-18 15:19:09 +02:00
pub fn random_access_extension(
2021-08-04 10:58:07 -07:00
&mut self,
access_index: Target,
claimed_element: ExtensionTarget<D>,
2021-08-12 13:56:45 -07:00
v: Vec<ExtensionTarget<D>>,
2021-08-04 10:58:07 -07:00
) {
2021-10-18 16:48:21 +02:00
for i in 0..D {
self.random_access(
2021-10-18 15:19:09 +02:00
access_index,
2021-10-18 16:48:21 +02:00
claimed_element.0[i],
v.iter().map(|et| et.0[i]).collect(),
2021-10-18 15:19:09 +02:00
);
}
2021-08-04 10:58:07 -07:00
}
}
#[cfg(test)]
mod tests {
use anyhow::Result;
use super::*;
use crate::field::extension_field::quartic::QuarticExtension;
2021-08-04 10:58:07 -07:00
use crate::field::field_types::Field;
2021-11-02 12:04:42 -07:00
use crate::field::goldilocks_field::GoldilocksField;
2021-08-04 10:58:07 -07:00
use crate::iop::witness::PartialWitness;
use crate::plonk::circuit_data::CircuitConfig;
use crate::plonk::verifier::verify;
fn test_random_access_given_len(len_log: usize) -> Result<()> {
2021-11-02 12:04:42 -07:00
type F = GoldilocksField;
type FF = QuarticExtension<GoldilocksField>;
2021-08-04 10:58:07 -07:00
let len = 1 << len_log;
let config = CircuitConfig::standard_recursion_config();
2021-08-20 11:56:57 +02:00
let pw = PartialWitness::new();
2021-08-04 10:58:07 -07:00
let mut builder = CircuitBuilder::<F, 4>::new(config);
2021-08-04 14:19:06 -07:00
let vec = FF::rand_vec(len);
let v: Vec<_> = vec.iter().map(|x| builder.constant_extension(*x)).collect();
2021-08-04 10:58:07 -07:00
for i in 0..len {
let it = builder.constant(F::from_canonical_usize(i));
let elem = builder.constant_extension(vec[i]);
2021-10-18 15:19:09 +02:00
builder.random_access_extension(it, elem, v.clone());
2021-08-04 10:58:07 -07:00
}
let data = builder.build();
2021-08-06 15:14:38 +02:00
let proof = data.prove(pw)?;
2021-08-04 10:58:07 -07:00
verify(proof, &data.verifier_only, &data.common)
}
#[test]
fn test_random_access() -> Result<()> {
for len_log in 1..3 {
test_random_access_given_len(len_log)?;
}
Ok(())
}
}