2021-08-04 10:58:07 -07:00
|
|
|
use crate::field::extension_field::target::ExtensionTarget;
|
|
|
|
|
use crate::field::extension_field::Extendable;
|
2021-09-07 18:28:28 -07:00
|
|
|
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;
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
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.
|
|
|
|
|
pub fn random_access(&mut self, access_index: Target, claimed_element: Target, v: Vec<Target>) {
|
|
|
|
|
debug_assert!(!v.is_empty());
|
|
|
|
|
if v.len() == 1 {
|
|
|
|
|
return self.connect(claimed_element, v[0]);
|
|
|
|
|
}
|
|
|
|
|
let gate = RandomAccessGate::new(1, v.len());
|
|
|
|
|
let gate_index = self.add_gate(gate.clone(), vec![]);
|
|
|
|
|
|
|
|
|
|
let copy = 0;
|
|
|
|
|
v.iter().enumerate().for_each(|(i, &val)| {
|
|
|
|
|
self.connect(val, Target::wire(gate_index, gate.wire_list_item(i, copy)));
|
|
|
|
|
});
|
|
|
|
|
self.connect(
|
|
|
|
|
access_index,
|
|
|
|
|
Target::wire(gate_index, gate.wire_access_index(copy)),
|
|
|
|
|
);
|
|
|
|
|
self.connect(
|
|
|
|
|
claimed_element,
|
|
|
|
|
Target::wire(gate_index, gate.wire_claimed_element(copy)),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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-06 16:36:30 +02:00
|
|
|
debug_assert!(!v.is_empty());
|
|
|
|
|
if v.len() == 1 {
|
|
|
|
|
return self.connect_extension(claimed_element, v[0]);
|
|
|
|
|
}
|
2021-10-18 15:19:09 +02:00
|
|
|
let gate = RandomAccessGate::new(D, v.len());
|
2021-08-04 10:58:07 -07:00
|
|
|
let gate_index = self.add_gate(gate.clone(), vec![]);
|
|
|
|
|
|
2021-10-18 15:19:09 +02:00
|
|
|
for copy in 0..D {
|
|
|
|
|
v.iter().enumerate().for_each(|(i, &val)| {
|
|
|
|
|
self.connect(
|
|
|
|
|
val.0[copy],
|
|
|
|
|
Target::wire(gate_index, gate.wire_list_item(i, copy)),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
self.connect(
|
|
|
|
|
access_index,
|
|
|
|
|
Target::wire(gate_index, gate.wire_access_index(copy)),
|
2021-08-04 10:58:07 -07:00
|
|
|
);
|
2021-10-18 15:19:09 +02:00
|
|
|
self.connect(
|
|
|
|
|
claimed_element.0[copy],
|
|
|
|
|
Target::wire(gate_index, gate.wire_claimed_element(copy)),
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-08-04 10:58:07 -07:00
|
|
|
}
|
2021-08-12 13:32:49 -07:00
|
|
|
|
|
|
|
|
/// Like `random_access`, but first pads `v` to a given minimum length. This can help to avoid
|
|
|
|
|
/// having multiple `RandomAccessGate`s with different sizes.
|
|
|
|
|
pub fn random_access_padded(
|
|
|
|
|
&mut self,
|
|
|
|
|
access_index: Target,
|
|
|
|
|
claimed_element: ExtensionTarget<D>,
|
|
|
|
|
mut v: Vec<ExtensionTarget<D>>,
|
|
|
|
|
min_length: usize,
|
|
|
|
|
) {
|
2021-10-06 16:36:30 +02:00
|
|
|
debug_assert!(!v.is_empty());
|
|
|
|
|
if v.len() == 1 {
|
|
|
|
|
return self.connect_extension(claimed_element, v[0]);
|
|
|
|
|
}
|
2021-08-12 13:32:49 -07:00
|
|
|
let zero = self.zero_extension();
|
|
|
|
|
if v.len() < min_length {
|
|
|
|
|
v.resize(8, zero);
|
|
|
|
|
}
|
2021-10-18 15:19:09 +02:00
|
|
|
self.random_access_extension(access_index, claimed_element, v);
|
2021-08-12 13:32:49 -07:00
|
|
|
}
|
2021-08-04 10:58:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
use crate::field::crandall_field::CrandallField;
|
2021-09-13 11:45:17 -07:00
|
|
|
use crate::field::extension_field::quartic::QuarticExtension;
|
2021-08-04 10:58:07 -07:00
|
|
|
use crate::field::field_types::Field;
|
|
|
|
|
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<()> {
|
|
|
|
|
type F = CrandallField;
|
2021-09-13 11:45:17 -07:00
|
|
|
type FF = QuarticExtension<CrandallField>;
|
2021-08-04 10:58:07 -07:00
|
|
|
let len = 1 << len_log;
|
|
|
|
|
let config = CircuitConfig::large_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(())
|
|
|
|
|
}
|
|
|
|
|
}
|