use std::collections::{HashMap, HashSet}; use std::convert::identity; use std::fmt::Debug; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field_types::Field; use crate::hash::hash_types::{HashOut, HashOutTarget}; use crate::iop::target::Target; use crate::iop::wire::Wire; use crate::iop::witness::PartialWitness; /// Given a `PartialWitness` that has only inputs set, populates the rest of the witness using the /// given set of generators. pub(crate) fn generate_partial_witness( witness: &mut PartialWitness, generators: &[Box>], ) { // Index generator indices by their watched targets. let mut generator_indices_by_watches = HashMap::new(); for (i, generator) in generators.iter().enumerate() { for watch in generator.watch_list() { generator_indices_by_watches .entry(watch) .or_insert_with(Vec::new) .push(i); } } // Build a list of "pending" generators which are queued to be run. Initially, all generators // are queued. let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect(); // We also track a list of "expired" generators which have already returned false. let mut generator_is_expired = vec![false; generators.len()]; let mut buffer = GeneratedValues::empty(); // Keep running generators until no generators are queued. while !pending_generator_indices.is_empty() { let mut next_pending_generator_indices = HashSet::new(); for &generator_idx in &pending_generator_indices { let finished = generators[generator_idx].run(&witness, &mut buffer); if finished { generator_is_expired[generator_idx] = true; } // Enqueue unfinished generators that were watching one of the newly populated targets. for (watch, _) in &buffer.target_values { if let Some(watching_generator_indices) = generator_indices_by_watches.get(watch) { for &watching_generator_idx in watching_generator_indices { if !generator_is_expired[watching_generator_idx] { next_pending_generator_indices.insert(watching_generator_idx); } } } } witness.extend(buffer.target_values.drain(..)); } pending_generator_indices = next_pending_generator_indices; } assert!( generator_is_expired.into_iter().all(identity), "Some generators weren't run." ); } /// A generator participates in the generation of the witness. pub trait WitnessGenerator: 'static + Send + Sync { /// Targets to be "watched" by this generator. Whenever a target in the watch list is populated, /// the generator will be queued to run. fn watch_list(&self) -> Vec; /// Run this generator, returning a flag indicating whether the generator is finished. If the /// flag is true, the generator will never be run again, otherwise it will be queued for another /// run next time a target in its watch list is populated. fn run(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues) -> bool; } /// Values generated by a generator invocation. pub struct GeneratedValues { pub(crate) target_values: Vec<(Target, F)>, } impl From> for GeneratedValues { fn from(target_values: Vec<(Target, F)>) -> Self { Self { target_values } } } impl GeneratedValues { pub fn with_capacity(capacity: usize) -> Self { Vec::with_capacity(capacity).into() } pub fn empty() -> Self { Vec::new().into() } pub fn singleton_wire(wire: Wire, value: F) -> Self { Self::singleton_target(Target::Wire(wire), value) } pub fn singleton_target(target: Target, value: F) -> Self { vec![(target, value)].into() } pub fn clear(&mut self) { self.target_values.clear(); } pub fn singleton_extension_target( et: ExtensionTarget, value: F::Extension, ) -> Self where F: Extendable, { let mut witness = Self::with_capacity(D); witness.set_extension_target(et, value); witness } pub fn set_target(&mut self, target: Target, value: F) { self.target_values.push((target, value)) } pub fn set_hash_target(&mut self, ht: HashOutTarget, value: HashOut) { ht.elements .iter() .zip(value.elements) .for_each(|(&t, x)| self.set_target(t, x)); } pub fn set_extension_target( &mut self, et: ExtensionTarget, value: F::Extension, ) where F: Extendable, { let limbs = value.to_basefield_array(); (0..D).for_each(|i| { self.set_target(et.0[i], limbs[i]); }); } pub fn set_wire(&mut self, wire: Wire, value: F) { self.set_target(Target::Wire(wire), value) } pub fn set_wires(&mut self, wires: W, values: &[F]) where W: IntoIterator, { // If we used itertools, we could use zip_eq for extra safety. for (wire, &value) in wires.into_iter().zip(values) { self.set_wire(wire, value); } } pub fn set_ext_wires(&mut self, wires: W, value: F::Extension) where F: Extendable, W: IntoIterator, { self.set_wires(wires, &value.to_basefield_array()); } } /// A generator which runs once after a list of dependencies is present in the witness. pub trait SimpleGenerator: 'static + Send + Sync { fn dependencies(&self) -> Vec; fn run_once(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues); } impl> WitnessGenerator for SG { fn watch_list(&self) -> Vec { self.dependencies() } fn run(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues) -> bool { if witness.contains_all(&self.dependencies()) { self.run_once(witness, out_buffer); true } else { false } } } /// A generator which copies one wire to another. #[derive(Debug)] pub(crate) struct CopyGenerator { pub(crate) src: Target, pub(crate) dst: Target, } impl SimpleGenerator for CopyGenerator { fn dependencies(&self) -> Vec { vec![self.src] } fn run_once(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues) { let value = witness.get_target(self.src); out_buffer.set_target(self.dst, value); } } /// A generator for including a random value pub(crate) struct RandomValueGenerator { pub(crate) target: Target, } impl SimpleGenerator for RandomValueGenerator { fn dependencies(&self) -> Vec { Vec::new() } fn run_once(&self, _witness: &PartialWitness, out_buffer: &mut GeneratedValues) { let random_value = F::rand(); out_buffer.set_target(self.target, random_value); } } /// A generator for testing if a value equals zero pub(crate) struct NonzeroTestGenerator { pub(crate) to_test: Target, pub(crate) dummy: Target, } impl SimpleGenerator for NonzeroTestGenerator { fn dependencies(&self) -> Vec { vec![self.to_test] } fn run_once(&self, witness: &PartialWitness, out_buffer: &mut GeneratedValues) { let to_test_value = witness.get_target(self.to_test); let dummy_value = if to_test_value == F::ZERO { F::ONE } else { to_test_value.inverse() }; out_buffer.set_target(self.dummy, dummy_value); } }