plonky2/src/gadgets/insert.rs

130 lines
4.3 KiB
Rust
Raw Normal View History

use crate::circuit_builder::CircuitBuilder;
use crate::field::extension_field::target::ExtensionTarget;
use crate::field::extension_field::Extendable;
use crate::generator::NonzeroTestGenerator;
2021-06-30 21:59:18 -07:00
use crate::target::Target;
impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Evaluates to 0 if `x` equals zero, 1 otherwise.
2021-07-01 12:00:56 -07:00
/// From section 2 of https://github.com/mir-protocol/r1cs-workshop/blob/master/workshop.pdf,
/// based on an idea from https://eprint.iacr.org/2012/598.pdf.
pub fn is_nonzero(&mut self, x: Target) -> Target {
// Dummy variable.
2021-07-01 10:47:13 -07:00
let m = self.add_virtual_target();
2021-07-01 12:00:56 -07:00
// The prover sets this the dummy variable to 1/x if x != 0, or to an arbitrary value if
// x == 0.
self.add_generator(NonzeroTestGenerator {
to_test: x,
dummy: m,
});
// Evaluates to (0) * (0) = 0 if x == 0 and (x) * (1/x) = 1 otherwise.
2021-07-01 10:47:13 -07:00
let y = self.mul(x, m);
// Enforce that (1 - y) * x == 0.
2021-07-01 17:43:22 -07:00
let prod = self.arithmetic(F::NEG_ONE, x, y, F::ONE, x);
2021-07-01 10:47:13 -07:00
self.assert_zero(prod);
2021-06-30 21:31:17 -07:00
y
}
2021-06-30 07:08:36 -07:00
/// Evaluates to 1 if `x` and `y` are equal, 0 otherwise.
2021-06-30 21:31:17 -07:00
pub fn is_equal(&mut self, x: Target, y: Target) -> Target {
2021-06-30 21:59:10 -07:00
let difference = self.sub(x, y);
let not_equal = self.is_nonzero(difference);
let one = self.one();
self.sub(one, not_equal)
2021-06-30 07:08:36 -07:00
}
2021-07-12 11:56:53 -07:00
/// Inserts a `Target` in a vector at a non-deterministic index.
/// Note: `index` is not range-checked.
pub fn insert(
&mut self,
index: Target,
element: ExtensionTarget<D>,
2021-06-16 11:37:07 +02:00
v: Vec<ExtensionTarget<D>>,
) -> Vec<ExtensionTarget<D>> {
2021-06-30 07:08:36 -07:00
let mut already_inserted = self.zero();
let mut new_list = Vec::new();
let one = self.one();
for i in 0..=v.len() {
2021-06-30 14:23:05 -07:00
let cur_index = self.constant(F::from_canonical_usize(i));
2021-06-30 07:08:36 -07:00
let insert_here = self.is_equal(cur_index, index);
2021-06-30 14:20:47 -07:00
let mut new_item = self.zero_extension();
new_item = self.scalar_mul_add_extension(insert_here, element, new_item);
if i > 0 {
new_item = self.scalar_mul_add_extension(already_inserted, v[i - 1], new_item);
2021-06-30 14:20:47 -07:00
}
2021-06-30 07:08:36 -07:00
already_inserted = self.add(already_inserted, insert_here);
2021-06-30 14:02:20 -07:00
2021-06-30 14:20:47 -07:00
let not_already_inserted = self.sub(one, already_inserted);
if i < v.len() {
new_item = self.scalar_mul_add_extension(not_already_inserted, v[i], new_item);
}
2021-06-30 07:08:36 -07:00
new_list.push(new_item);
}
new_list
2021-06-16 10:43:18 +02:00
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::circuit_data::CircuitConfig;
use crate::field::crandall_field::CrandallField;
use crate::field::extension_field::quartic::QuarticCrandallField;
use crate::field::field::Field;
2021-07-08 15:13:29 +02:00
use crate::verifier::verify;
2021-06-16 10:43:18 +02:00
use crate::witness::PartialWitness;
fn real_insert<const D: usize>(
index: usize,
element: ExtensionTarget<D>,
v: &[ExtensionTarget<D>],
) -> Vec<ExtensionTarget<D>> {
let mut res = v.to_vec();
res.insert(index, element);
res
}
fn test_insert_given_len(len_log: usize) {
type F = CrandallField;
type FF = QuarticCrandallField;
let len = 1 << len_log;
let config = CircuitConfig::large_config();
let mut builder = CircuitBuilder::<F, 4>::new(config);
let v = (0..len - 1)
.map(|_| builder.constant_extension(FF::rand()))
.collect::<Vec<_>>();
for i in 0..len {
let it = builder.constant(F::from_canonical_usize(i));
let elem = builder.constant_extension(FF::rand());
let inserted = real_insert(i, elem, &v);
let purported_inserted = builder.insert(it, elem, v.clone());
assert_eq!(inserted.len(), purported_inserted.len());
2021-06-16 10:43:18 +02:00
for (x, y) in inserted.into_iter().zip(purported_inserted) {
builder.route_extension(x, y);
}
}
let data = builder.build();
let proof = data.prove(PartialWitness::new());
2021-07-08 15:13:29 +02:00
verify(proof, &data.verifier_only, &data.common).unwrap();
2021-06-16 10:43:18 +02:00
}
#[test]
fn test_insert() {
for len_log in 1..3 {
test_insert_given_len(len_log);
}
}
}