mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 00:03:10 +00:00
Merge branch 'main' into avoid_rotating
This commit is contained in:
commit
a54a4e5830
@ -50,8 +50,8 @@ fn bench_prove<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
|
|||||||
|
|
||||||
let circuit = builder.build();
|
let circuit = builder.build();
|
||||||
let inputs = PartialWitness::new();
|
let inputs = PartialWitness::new();
|
||||||
let proof = circuit.prove(inputs)?;
|
let proof_with_pis = circuit.prove(inputs)?;
|
||||||
let proof_bytes = serde_cbor::to_vec(&proof).unwrap();
|
let proof_bytes = serde_cbor::to_vec(&proof_with_pis).unwrap();
|
||||||
info!("Proof length: {} bytes", proof_bytes.len());
|
info!("Proof length: {} bytes", proof_bytes.len());
|
||||||
circuit.verify(proof)
|
circuit.verify(proof_with_pis)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ use crate::gates::constant::ConstantGate;
|
|||||||
use crate::gates::gate::{GateInstance, GateRef, PrefixedGate};
|
use crate::gates::gate::{GateInstance, GateRef, PrefixedGate};
|
||||||
use crate::gates::gate_tree::Tree;
|
use crate::gates::gate_tree::Tree;
|
||||||
use crate::gates::noop::NoopGate;
|
use crate::gates::noop::NoopGate;
|
||||||
|
use crate::gates::public_input::PublicInputGate;
|
||||||
use crate::generator::{CopyGenerator, RandomValueGenerator, WitnessGenerator};
|
use crate::generator::{CopyGenerator, RandomValueGenerator, WitnessGenerator};
|
||||||
use crate::hash::hash_n_to_hash;
|
use crate::hash::hash_n_to_hash;
|
||||||
use crate::permutation_argument::TargetPartition;
|
use crate::permutation_argument::TargetPartition;
|
||||||
@ -39,8 +40,8 @@ pub struct CircuitBuilder<F: Extendable<D>, const D: usize> {
|
|||||||
/// The concrete placement of each gate.
|
/// The concrete placement of each gate.
|
||||||
gate_instances: Vec<GateInstance<F, D>>,
|
gate_instances: Vec<GateInstance<F, D>>,
|
||||||
|
|
||||||
/// The next available index for a public input.
|
/// Targets to be made public.
|
||||||
public_input_index: usize,
|
public_inputs: Vec<Target>,
|
||||||
|
|
||||||
/// The next available index for a `VirtualTarget`.
|
/// The next available index for a `VirtualTarget`.
|
||||||
virtual_target_index: usize,
|
virtual_target_index: usize,
|
||||||
@ -66,7 +67,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
config,
|
config,
|
||||||
gates: HashSet::new(),
|
gates: HashSet::new(),
|
||||||
gate_instances: Vec::new(),
|
gate_instances: Vec::new(),
|
||||||
public_input_index: 0,
|
public_inputs: Vec::new(),
|
||||||
virtual_target_index: 0,
|
virtual_target_index: 0,
|
||||||
copy_constraints: Vec::new(),
|
copy_constraints: Vec::new(),
|
||||||
context_log: ContextTree::new(),
|
context_log: ContextTree::new(),
|
||||||
@ -81,14 +82,14 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.gate_instances.len()
|
self.gate_instances.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_public_input(&mut self) -> Target {
|
/// Registers the given target as a public input.
|
||||||
let index = self.public_input_index;
|
pub fn register_public_input(&mut self, target: Target) {
|
||||||
self.public_input_index += 1;
|
self.public_inputs.push(target);
|
||||||
Target::PublicInput { index }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_public_inputs(&mut self, n: usize) -> Vec<Target> {
|
/// Registers the given targets as public inputs.
|
||||||
(0..n).map(|_i| self.add_public_input()).collect()
|
pub fn register_public_inputs(&mut self, targets: &[Target]) {
|
||||||
|
targets.iter().for_each(|&t| self.register_public_input(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new "virtual" target. This is not an actual wire in the witness, but just a target
|
/// Adds a new "virtual" target. This is not an actual wire in the witness, but just a target
|
||||||
@ -462,10 +463,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
let degree_log = log2_strict(degree);
|
let degree_log = log2_strict(degree);
|
||||||
let mut target_partition = TargetPartition::new(|t| match t {
|
let mut target_partition = TargetPartition::new(|t| match t {
|
||||||
Target::Wire(Wire { gate, input }) => gate * self.config.num_routed_wires + input,
|
Target::Wire(Wire { gate, input }) => gate * self.config.num_routed_wires + input,
|
||||||
Target::PublicInput { index } => degree * self.config.num_routed_wires + index,
|
Target::VirtualTarget { index } => degree * self.config.num_routed_wires + index,
|
||||||
Target::VirtualTarget { index } => {
|
|
||||||
degree * self.config.num_routed_wires + self.public_input_index + index
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for gate in 0..degree {
|
for gate in 0..degree {
|
||||||
@ -474,10 +472,6 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for index in 0..self.public_input_index {
|
|
||||||
target_partition.add(Target::PublicInput { index });
|
|
||||||
}
|
|
||||||
|
|
||||||
for index in 0..self.virtual_target_index {
|
for index in 0..self.virtual_target_index {
|
||||||
target_partition.add(Target::VirtualTarget { index });
|
target_partition.add(Target::VirtualTarget { index });
|
||||||
}
|
}
|
||||||
@ -500,6 +494,19 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
pub fn build(mut self) -> CircuitData<F, D> {
|
pub fn build(mut self) -> CircuitData<F, D> {
|
||||||
let quotient_degree_factor = 7; // TODO: add this as a parameter.
|
let quotient_degree_factor = 7; // TODO: add this as a parameter.
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
|
// Hash the public inputs, and route them to a `PublicInputGate` which will enforce that
|
||||||
|
// those hash wires match the claimed public inputs.
|
||||||
|
let public_inputs_hash = self.hash_n_to_hash(self.public_inputs.clone(), true);
|
||||||
|
let pi_gate = self.add_gate_no_constants(PublicInputGate::get());
|
||||||
|
for (&hash_part, wire) in public_inputs_hash
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.zip(PublicInputGate::wires_public_inputs_hash())
|
||||||
|
{
|
||||||
|
self.route(hash_part, Target::wire(pi_gate, wire))
|
||||||
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Degree before blinding & padding: {}",
|
"Degree before blinding & padding: {}",
|
||||||
self.gate_instances.len()
|
self.gate_instances.len()
|
||||||
@ -552,6 +559,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
subgroup,
|
subgroup,
|
||||||
copy_constraints: self.copy_constraints,
|
copy_constraints: self.copy_constraints,
|
||||||
gate_instances: self.gate_instances,
|
gate_instances: self.gate_instances,
|
||||||
|
public_inputs: self.public_inputs,
|
||||||
marked_targets: self.marked_targets,
|
marked_targets: self.marked_targets,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,9 @@ use crate::fri::FriConfig;
|
|||||||
use crate::gates::gate::{GateInstance, PrefixedGate};
|
use crate::gates::gate::{GateInstance, PrefixedGate};
|
||||||
use crate::generator::WitnessGenerator;
|
use crate::generator::WitnessGenerator;
|
||||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||||
use crate::proof::{Hash, HashTarget, Proof};
|
use crate::proof::{Hash, HashTarget, ProofWithPublicInputs};
|
||||||
use crate::prover::prove;
|
use crate::prover::prove;
|
||||||
|
use crate::target::Target;
|
||||||
use crate::util::marking::MarkedTargets;
|
use crate::util::marking::MarkedTargets;
|
||||||
use crate::verifier::verify;
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
@ -78,12 +79,12 @@ pub struct CircuitData<F: Extendable<D>, const D: usize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Extendable<D>, const D: usize> CircuitData<F, D> {
|
impl<F: Extendable<D>, const D: usize> CircuitData<F, D> {
|
||||||
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<Proof<F, D>> {
|
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, D>> {
|
||||||
prove(&self.prover_only, &self.common, inputs)
|
prove(&self.prover_only, &self.common, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self, proof: Proof<F, D>) -> Result<()> {
|
pub fn verify(&self, proof_with_pis: ProofWithPublicInputs<F, D>) -> Result<()> {
|
||||||
verify(proof, &self.verifier_only, &self.common)
|
verify(proof_with_pis, &self.verifier_only, &self.common)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ pub struct ProverCircuitData<F: Extendable<D>, const D: usize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Extendable<D>, const D: usize> ProverCircuitData<F, D> {
|
impl<F: Extendable<D>, const D: usize> ProverCircuitData<F, D> {
|
||||||
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<Proof<F, D>> {
|
pub fn prove(&self, inputs: PartialWitness<F>) -> Result<ProofWithPublicInputs<F, D>> {
|
||||||
prove(&self.prover_only, &self.common, inputs)
|
prove(&self.prover_only, &self.common, inputs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,8 +113,8 @@ pub struct VerifierCircuitData<F: Extendable<D>, const D: usize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Extendable<D>, const D: usize> VerifierCircuitData<F, D> {
|
impl<F: Extendable<D>, const D: usize> VerifierCircuitData<F, D> {
|
||||||
pub fn verify(&self, proof: Proof<F, D>) -> Result<()> {
|
pub fn verify(&self, proof_with_pis: ProofWithPublicInputs<F, D>) -> Result<()> {
|
||||||
verify(proof, &self.verifier_only, &self.common)
|
verify(proof_with_pis, &self.verifier_only, &self.common)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +131,8 @@ pub(crate) struct ProverOnlyCircuitData<F: Extendable<D>, const D: usize> {
|
|||||||
pub copy_constraints: Vec<CopyConstraint>,
|
pub copy_constraints: Vec<CopyConstraint>,
|
||||||
/// The concrete placement of each gate in the circuit.
|
/// The concrete placement of each gate in the circuit.
|
||||||
pub gate_instances: Vec<GateInstance<F, D>>,
|
pub gate_instances: Vec<GateInstance<F, D>>,
|
||||||
|
/// Targets to be made public.
|
||||||
|
pub public_inputs: Vec<Target>,
|
||||||
/// A vector of marked targets. The values assigned to these targets will be displayed by the prover.
|
/// A vector of marked targets. The values assigned to these targets will be displayed by the prover.
|
||||||
pub marked_targets: Vec<MarkedTargets<D>>,
|
pub marked_targets: Vec<MarkedTargets<D>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,7 +67,7 @@ fn fft_unrolled_root_table<F: Field>(n: usize) -> FftRootTable<F> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fft_dispatch<F: Field>(
|
fn fft_dispatch<F: Field>(
|
||||||
input: Vec<F>,
|
input: &[F],
|
||||||
zero_factor: Option<usize>,
|
zero_factor: Option<usize>,
|
||||||
root_table: Option<FftRootTable<F>>,
|
root_table: Option<FftRootTable<F>>,
|
||||||
) -> Vec<F> {
|
) -> Vec<F> {
|
||||||
@ -87,13 +87,13 @@ fn fft_dispatch<F: Field>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fft<F: Field>(poly: PolynomialCoeffs<F>) -> PolynomialValues<F> {
|
pub fn fft<F: Field>(poly: &PolynomialCoeffs<F>) -> PolynomialValues<F> {
|
||||||
fft_with_options(poly, None, None)
|
fft_with_options(poly, None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fft_with_options<F: Field>(
|
pub fn fft_with_options<F: Field>(
|
||||||
poly: PolynomialCoeffs<F>,
|
poly: &PolynomialCoeffs<F>,
|
||||||
zero_factor: Option<usize>,
|
zero_factor: Option<usize>,
|
||||||
root_table: Option<FftRootTable<F>>,
|
root_table: Option<FftRootTable<F>>,
|
||||||
) -> PolynomialValues<F> {
|
) -> PolynomialValues<F> {
|
||||||
@ -104,12 +104,12 @@ pub fn fft_with_options<F: Field>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ifft<F: Field>(poly: PolynomialValues<F>) -> PolynomialCoeffs<F> {
|
pub fn ifft<F: Field>(poly: &PolynomialValues<F>) -> PolynomialCoeffs<F> {
|
||||||
ifft_with_options(poly, None, None)
|
ifft_with_options(poly, None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ifft_with_options<F: Field>(
|
pub fn ifft_with_options<F: Field>(
|
||||||
poly: PolynomialValues<F>,
|
poly: &PolynomialValues<F>,
|
||||||
zero_factor: Option<usize>,
|
zero_factor: Option<usize>,
|
||||||
root_table: Option<FftRootTable<F>>,
|
root_table: Option<FftRootTable<F>>,
|
||||||
) -> PolynomialCoeffs<F> {
|
) -> PolynomialCoeffs<F> {
|
||||||
@ -139,11 +139,7 @@ pub fn ifft_with_options<F: Field>(
|
|||||||
/// The parameter r signifies that the first 1/2^r of the entries of
|
/// The parameter r signifies that the first 1/2^r of the entries of
|
||||||
/// input may be non-zero, but the last 1 - 1/2^r entries are
|
/// input may be non-zero, but the last 1 - 1/2^r entries are
|
||||||
/// definitely zero.
|
/// definitely zero.
|
||||||
pub(crate) fn fft_classic<F: Field>(
|
pub(crate) fn fft_classic<F: Field>(input: &[F], r: usize, root_table: FftRootTable<F>) -> Vec<F> {
|
||||||
input: Vec<F>,
|
|
||||||
r: usize,
|
|
||||||
root_table: FftRootTable<F>,
|
|
||||||
) -> Vec<F> {
|
|
||||||
let mut values = reverse_index_bits(input);
|
let mut values = reverse_index_bits(input);
|
||||||
|
|
||||||
let n = values.len();
|
let n = values.len();
|
||||||
@ -196,7 +192,7 @@ pub(crate) fn fft_classic<F: Field>(
|
|||||||
/// The parameter r signifies that the first 1/2^r of the entries of
|
/// The parameter r signifies that the first 1/2^r of the entries of
|
||||||
/// input may be non-zero, but the last 1 - 1/2^r entries are
|
/// input may be non-zero, but the last 1 - 1/2^r entries are
|
||||||
/// definitely zero.
|
/// definitely zero.
|
||||||
fn fft_unrolled<F: Field>(input: Vec<F>, r_orig: usize, root_table: FftRootTable<F>) -> Vec<F> {
|
fn fft_unrolled<F: Field>(input: &[F], r_orig: usize, root_table: FftRootTable<F>) -> Vec<F> {
|
||||||
let n = input.len();
|
let n = input.len();
|
||||||
let lg_n = log2_strict(input.len());
|
let lg_n = log2_strict(input.len());
|
||||||
|
|
||||||
@ -325,10 +321,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let coefficients = PolynomialCoeffs::new_padded(coefficients);
|
let coefficients = PolynomialCoeffs::new_padded(coefficients);
|
||||||
|
|
||||||
let points = fft(coefficients.clone());
|
let points = fft(&coefficients);
|
||||||
assert_eq!(points, evaluate_naive(&coefficients));
|
assert_eq!(points, evaluate_naive(&coefficients));
|
||||||
|
|
||||||
let interpolated_coefficients = ifft(points);
|
let interpolated_coefficients = ifft(&points);
|
||||||
for i in 0..degree {
|
for i in 0..degree {
|
||||||
assert_eq!(interpolated_coefficients.coeffs[i], coefficients.coeffs[i]);
|
assert_eq!(interpolated_coefficients.coeffs[i], coefficients.coeffs[i]);
|
||||||
}
|
}
|
||||||
@ -337,12 +333,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for r in 0..4 {
|
for r in 0..4 {
|
||||||
// expand ceofficients by factor 2^r by filling with zeros
|
// expand coefficients by factor 2^r by filling with zeros
|
||||||
let zero_tail = coefficients.clone().lde(r);
|
let zero_tail = coefficients.lde(r);
|
||||||
assert_eq!(
|
assert_eq!(fft(&zero_tail), fft_with_options(&zero_tail, Some(r), None));
|
||||||
fft(zero_tail.clone()),
|
|
||||||
fft_with_options(zero_tail, Some(r), None)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,10 +343,7 @@ mod tests {
|
|||||||
let degree = coefficients.len();
|
let degree = coefficients.len();
|
||||||
let degree_padded = 1 << log2_ceil(degree);
|
let degree_padded = 1 << log2_ceil(degree);
|
||||||
|
|
||||||
let mut coefficients_padded = coefficients.clone();
|
let coefficients_padded = coefficients.padded(degree_padded);
|
||||||
for _i in degree..degree_padded {
|
|
||||||
coefficients_padded.coeffs.push(F::ZERO);
|
|
||||||
}
|
|
||||||
evaluate_naive_power_of_2(&coefficients_padded)
|
evaluate_naive_power_of_2(&coefficients_padded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ pub(crate) fn interpolant<F: Field>(points: &[(F, F)]) -> PolynomialCoeffs<F> {
|
|||||||
.map(|x| interpolate(points, x, &barycentric_weights))
|
.map(|x| interpolate(points, x, &barycentric_weights))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut coeffs = ifft(PolynomialValues {
|
let mut coeffs = ifft(&PolynomialValues {
|
||||||
values: subgroup_evals,
|
values: subgroup_evals,
|
||||||
});
|
});
|
||||||
coeffs.trim();
|
coeffs.trim();
|
||||||
|
|||||||
@ -16,9 +16,9 @@ use crate::util::reverse_index_bits_in_place;
|
|||||||
pub fn fri_proof<F: Field + Extendable<D>, const D: usize>(
|
pub fn fri_proof<F: Field + Extendable<D>, const D: usize>(
|
||||||
initial_merkle_trees: &[&MerkleTree<F>],
|
initial_merkle_trees: &[&MerkleTree<F>],
|
||||||
// Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero.
|
// Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero.
|
||||||
lde_polynomial_coeffs: &PolynomialCoeffs<F::Extension>,
|
lde_polynomial_coeffs: PolynomialCoeffs<F::Extension>,
|
||||||
// Evaluation of the polynomial on the large domain.
|
// Evaluation of the polynomial on the large domain.
|
||||||
lde_polynomial_values: &PolynomialValues<F::Extension>,
|
lde_polynomial_values: PolynomialValues<F::Extension>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
config: &FriConfig,
|
config: &FriConfig,
|
||||||
) -> FriProof<F, D> {
|
) -> FriProof<F, D> {
|
||||||
@ -53,14 +53,11 @@ pub fn fri_proof<F: Field + Extendable<D>, const D: usize>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fri_committed_trees<F: Field + Extendable<D>, const D: usize>(
|
fn fri_committed_trees<F: Field + Extendable<D>, const D: usize>(
|
||||||
polynomial_coeffs: &PolynomialCoeffs<F::Extension>,
|
mut coeffs: PolynomialCoeffs<F::Extension>,
|
||||||
polynomial_values: &PolynomialValues<F::Extension>,
|
mut values: PolynomialValues<F::Extension>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
config: &FriConfig,
|
config: &FriConfig,
|
||||||
) -> (Vec<MerkleTree<F>>, PolynomialCoeffs<F::Extension>) {
|
) -> (Vec<MerkleTree<F>>, PolynomialCoeffs<F::Extension>) {
|
||||||
let mut values = polynomial_values.clone();
|
|
||||||
let mut coeffs = polynomial_coeffs.clone();
|
|
||||||
|
|
||||||
let mut trees = Vec::new();
|
let mut trees = Vec::new();
|
||||||
|
|
||||||
let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR;
|
let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR;
|
||||||
@ -91,8 +88,7 @@ fn fri_committed_trees<F: Field + Extendable<D>, const D: usize>(
|
|||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
shift = shift.exp_u32(arity as u32);
|
shift = shift.exp_u32(arity as u32);
|
||||||
// TODO: Is it faster to interpolate?
|
values = coeffs.coset_fft(shift.into())
|
||||||
values = coeffs.clone().coset_fft(shift.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
coeffs.trim();
|
coeffs.trim();
|
||||||
|
|||||||
@ -125,14 +125,16 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
"Number of reductions should be non-zero."
|
"Number of reductions should be non-zero."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let precomputed_reduced_evals =
|
||||||
|
PrecomputedReducedEvalsTarget::from_os_and_alpha(os, alpha, self);
|
||||||
for (i, round_proof) in proof.query_round_proofs.iter().enumerate() {
|
for (i, round_proof) in proof.query_round_proofs.iter().enumerate() {
|
||||||
context!(
|
context!(
|
||||||
self,
|
self,
|
||||||
&format!("verify {}'th FRI query", i),
|
&format!("verify {}'th FRI query", i),
|
||||||
self.fri_verifier_query_round(
|
self.fri_verifier_query_round(
|
||||||
os,
|
|
||||||
zeta,
|
zeta,
|
||||||
alpha,
|
alpha,
|
||||||
|
precomputed_reduced_evals,
|
||||||
initial_merkle_roots,
|
initial_merkle_roots,
|
||||||
proof,
|
proof,
|
||||||
challenger,
|
challenger,
|
||||||
@ -169,9 +171,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
proof: &FriInitialTreeProofTarget,
|
proof: &FriInitialTreeProofTarget,
|
||||||
alpha: ExtensionTarget<D>,
|
alpha: ExtensionTarget<D>,
|
||||||
os: &OpeningSetTarget<D>,
|
|
||||||
zeta: ExtensionTarget<D>,
|
zeta: ExtensionTarget<D>,
|
||||||
subgroup_x: Target,
|
subgroup_x: Target,
|
||||||
|
precomputed_reduced_evals: PrecomputedReducedEvalsTarget<D>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> ExtensionTarget<D> {
|
) -> ExtensionTarget<D> {
|
||||||
assert!(D > 1, "Not implemented for D=1.");
|
assert!(D > 1, "Not implemented for D=1.");
|
||||||
@ -199,19 +201,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
)
|
)
|
||||||
.map(|&e| self.convert_to_ext(e))
|
.map(|&e| self.convert_to_ext(e))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let single_openings = os
|
let single_composition_eval = alpha.reduce(&single_evals, self);
|
||||||
.constants
|
let single_numerator =
|
||||||
.iter()
|
self.sub_extension(single_composition_eval, precomputed_reduced_evals.single);
|
||||||
.chain(&os.plonk_sigmas)
|
|
||||||
.chain(&os.wires)
|
|
||||||
.chain(&os.quotient_polys)
|
|
||||||
.chain(&os.partial_products)
|
|
||||||
.copied()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let mut single_numerator = alpha.reduce(&single_evals, self);
|
|
||||||
// TODO: Precompute the rhs as it is the same in all FRI rounds.
|
|
||||||
let rhs = alpha.reduce(&single_openings, self);
|
|
||||||
single_numerator = self.sub_extension(single_numerator, rhs);
|
|
||||||
let single_denominator = self.sub_extension(subgroup_x, zeta);
|
let single_denominator = self.sub_extension(subgroup_x, zeta);
|
||||||
let quotient = self.div_unsafe_extension(single_numerator, single_denominator);
|
let quotient = self.div_unsafe_extension(single_numerator, single_denominator);
|
||||||
sum = self.add_extension(sum, quotient);
|
sum = self.add_extension(sum, quotient);
|
||||||
@ -224,14 +216,15 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
.take(common_data.zs_range().end)
|
.take(common_data.zs_range().end)
|
||||||
.map(|&e| self.convert_to_ext(e))
|
.map(|&e| self.convert_to_ext(e))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let zs_composition_eval = alpha.clone().reduce(&zs_evals, self);
|
let zs_composition_eval = alpha.reduce(&zs_evals, self);
|
||||||
|
|
||||||
let g = self.constant_extension(F::Extension::primitive_root_of_unity(degree_log));
|
let g = self.constant_extension(F::Extension::primitive_root_of_unity(degree_log));
|
||||||
let zeta_right = self.mul_extension(g, zeta);
|
let zeta_right = self.mul_extension(g, zeta);
|
||||||
let zs_ev_zeta = alpha.clone().reduce(&os.plonk_zs, self);
|
|
||||||
let zs_ev_zeta_right = alpha.reduce(&os.plonk_zs_right, self);
|
|
||||||
let interpol_val = self.interpolate2(
|
let interpol_val = self.interpolate2(
|
||||||
[(zeta, zs_ev_zeta), (zeta_right, zs_ev_zeta_right)],
|
[
|
||||||
|
(zeta, precomputed_reduced_evals.zs),
|
||||||
|
(zeta_right, precomputed_reduced_evals.zs_right),
|
||||||
|
],
|
||||||
subgroup_x,
|
subgroup_x,
|
||||||
);
|
);
|
||||||
let zs_numerator = self.sub_extension(zs_composition_eval, interpol_val);
|
let zs_numerator = self.sub_extension(zs_composition_eval, interpol_val);
|
||||||
@ -247,9 +240,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
fn fri_verifier_query_round(
|
fn fri_verifier_query_round(
|
||||||
&mut self,
|
&mut self,
|
||||||
os: &OpeningSetTarget<D>,
|
|
||||||
zeta: ExtensionTarget<D>,
|
zeta: ExtensionTarget<D>,
|
||||||
alpha: ExtensionTarget<D>,
|
alpha: ExtensionTarget<D>,
|
||||||
|
precomputed_reduced_evals: PrecomputedReducedEvalsTarget<D>,
|
||||||
initial_merkle_roots: &[HashTarget],
|
initial_merkle_roots: &[HashTarget],
|
||||||
proof: &FriProofTarget<D>,
|
proof: &FriProofTarget<D>,
|
||||||
challenger: &mut RecursiveChallenger,
|
challenger: &mut RecursiveChallenger,
|
||||||
@ -260,7 +253,6 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
) {
|
) {
|
||||||
let config = &common_data.config.fri_config;
|
let config = &common_data.config.fri_config;
|
||||||
let n_log = log2_strict(n);
|
let n_log = log2_strict(n);
|
||||||
let mut evaluations: Vec<Vec<ExtensionTarget<D>>> = Vec::new();
|
|
||||||
// TODO: Do we need to range check `x_index` to a target smaller than `p`?
|
// TODO: Do we need to range check `x_index` to a target smaller than `p`?
|
||||||
let mut x_index = challenger.get_challenge(self);
|
let mut x_index = challenger.get_challenge(self);
|
||||||
x_index = self.split_low_high(x_index, n_log, 64).0;
|
x_index = self.split_low_high(x_index, n_log, 64).0;
|
||||||
@ -287,6 +279,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.mul(g, phi)
|
self.mul(g, phi)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut evaluations: Vec<Vec<ExtensionTarget<D>>> = Vec::new();
|
||||||
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
|
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
|
||||||
let next_domain_size = domain_size >> arity_bits;
|
let next_domain_size = domain_size >> arity_bits;
|
||||||
let e_x = if i == 0 {
|
let e_x = if i == 0 {
|
||||||
@ -296,9 +289,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.fri_combine_initial(
|
self.fri_combine_initial(
|
||||||
&round_proof.initial_trees_proof,
|
&round_proof.initial_trees_proof,
|
||||||
alpha,
|
alpha,
|
||||||
os,
|
|
||||||
zeta,
|
zeta,
|
||||||
subgroup_x,
|
subgroup_x,
|
||||||
|
precomputed_reduced_evals,
|
||||||
common_data,
|
common_data,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -322,23 +315,21 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
let (low_x_index, high_x_index) =
|
let (low_x_index, high_x_index) =
|
||||||
self.split_low_high(x_index, arity_bits, x_index_num_bits);
|
self.split_low_high(x_index, arity_bits, x_index_num_bits);
|
||||||
evals = self.insert(low_x_index, e_x, evals);
|
evals = self.insert(low_x_index, e_x, evals);
|
||||||
evaluations.push(evals);
|
|
||||||
context!(
|
context!(
|
||||||
self,
|
self,
|
||||||
"verify FRI round Merkle proof.",
|
"verify FRI round Merkle proof.",
|
||||||
self.verify_merkle_proof(
|
self.verify_merkle_proof(
|
||||||
flatten_target(&evaluations[i]),
|
flatten_target(&evals),
|
||||||
high_x_index,
|
high_x_index,
|
||||||
proof.commit_phase_merkle_roots[i],
|
proof.commit_phase_merkle_roots[i],
|
||||||
&round_proof.steps[i].merkle_proof,
|
&round_proof.steps[i].merkle_proof,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
evaluations.push(evals);
|
||||||
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
// Update the point x to x^arity.
|
// Update the point x to x^arity.
|
||||||
for _ in 0..config.reduction_arity_bits[i - 1] {
|
subgroup_x = self.exp_power_of_2(subgroup_x, config.reduction_arity_bits[i - 1]);
|
||||||
subgroup_x = self.square(subgroup_x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
domain_size = next_domain_size;
|
domain_size = next_domain_size;
|
||||||
old_x_index = low_x_index;
|
old_x_index = low_x_index;
|
||||||
@ -359,9 +350,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
*betas.last().unwrap(),
|
*betas.last().unwrap(),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
for _ in 0..final_arity_bits {
|
subgroup_x = self.exp_power_of_2(subgroup_x, final_arity_bits);
|
||||||
subgroup_x = self.square(subgroup_x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final check of FRI. After all the reductions, we check that the final polynomial is equal
|
// Final check of FRI. After all the reductions, we check that the final polynomial is equal
|
||||||
// to the one sent by the prover.
|
// to the one sent by the prover.
|
||||||
@ -373,3 +362,39 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.assert_equal_extension(eval, purported_eval);
|
self.assert_equal_extension(eval, purported_eval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct PrecomputedReducedEvalsTarget<const D: usize> {
|
||||||
|
pub single: ExtensionTarget<D>,
|
||||||
|
pub zs: ExtensionTarget<D>,
|
||||||
|
pub zs_right: ExtensionTarget<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const D: usize> PrecomputedReducedEvalsTarget<D> {
|
||||||
|
fn from_os_and_alpha<F: Extendable<D>>(
|
||||||
|
os: &OpeningSetTarget<D>,
|
||||||
|
alpha: ExtensionTarget<D>,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
) -> Self {
|
||||||
|
let mut alpha = ReducingFactorTarget::new(alpha);
|
||||||
|
let single = alpha.reduce(
|
||||||
|
&os.constants
|
||||||
|
.iter()
|
||||||
|
.chain(&os.plonk_sigmas)
|
||||||
|
.chain(&os.wires)
|
||||||
|
.chain(&os.quotient_polys)
|
||||||
|
.chain(&os.partial_products)
|
||||||
|
.copied()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
builder,
|
||||||
|
);
|
||||||
|
let zs = alpha.reduce(&os.plonk_zs, builder);
|
||||||
|
let zs_right = alpha.reduce(&os.plonk_zs_right, builder);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
single,
|
||||||
|
zs,
|
||||||
|
zs_right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -113,11 +113,12 @@ pub fn verify_fri_proof<F: Field + Extendable<D>, const D: usize>(
|
|||||||
"Number of reductions should be non-zero."
|
"Number of reductions should be non-zero."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let precomputed_reduced_evals = PrecomputedReducedEvals::from_os_and_alpha(os, alpha);
|
||||||
for round_proof in &proof.query_round_proofs {
|
for round_proof in &proof.query_round_proofs {
|
||||||
fri_verifier_query_round(
|
fri_verifier_query_round(
|
||||||
os,
|
|
||||||
zeta,
|
zeta,
|
||||||
alpha,
|
alpha,
|
||||||
|
precomputed_reduced_evals,
|
||||||
initial_merkle_roots,
|
initial_merkle_roots,
|
||||||
&proof,
|
&proof,
|
||||||
challenger,
|
challenger,
|
||||||
@ -143,12 +144,43 @@ fn fri_verify_initial_proof<F: Field>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds the reduced (by `alpha`) evaluations at `zeta` for the polynomial opened just at
|
||||||
|
/// zeta, for `Z` at zeta and for `Z` at `g*zeta`.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct PrecomputedReducedEvals<F: Extendable<D>, const D: usize> {
|
||||||
|
pub single: F::Extension,
|
||||||
|
pub zs: F::Extension,
|
||||||
|
pub zs_right: F::Extension,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D> {
|
||||||
|
fn from_os_and_alpha(os: &OpeningSet<F, D>, alpha: F::Extension) -> Self {
|
||||||
|
let mut alpha = ReducingFactor::new(alpha);
|
||||||
|
let single = alpha.reduce(
|
||||||
|
os.constants
|
||||||
|
.iter()
|
||||||
|
.chain(&os.plonk_sigmas)
|
||||||
|
.chain(&os.wires)
|
||||||
|
.chain(&os.quotient_polys)
|
||||||
|
.chain(&os.partial_products),
|
||||||
|
);
|
||||||
|
let zs = alpha.reduce(os.plonk_zs.iter());
|
||||||
|
let zs_right = alpha.reduce(os.plonk_zs_right.iter());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
single,
|
||||||
|
zs,
|
||||||
|
zs_right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
||||||
proof: &FriInitialTreeProof<F>,
|
proof: &FriInitialTreeProof<F>,
|
||||||
alpha: F::Extension,
|
alpha: F::Extension,
|
||||||
os: &OpeningSet<F, D>,
|
|
||||||
zeta: F::Extension,
|
zeta: F::Extension,
|
||||||
subgroup_x: F,
|
subgroup_x: F,
|
||||||
|
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> F::Extension {
|
) -> F::Extension {
|
||||||
let config = &common_data.config;
|
let config = &common_data.config;
|
||||||
@ -175,19 +207,8 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
|||||||
[common_data.partial_products_range()],
|
[common_data.partial_products_range()],
|
||||||
)
|
)
|
||||||
.map(|&e| F::Extension::from_basefield(e));
|
.map(|&e| F::Extension::from_basefield(e));
|
||||||
let single_openings = os
|
let single_composition_eval = alpha.reduce(single_evals);
|
||||||
.constants
|
let single_numerator = single_composition_eval - precomputed_reduced_evals.single;
|
||||||
.iter()
|
|
||||||
.chain(&os.plonk_sigmas)
|
|
||||||
.chain(&os.wires)
|
|
||||||
.chain(&os.quotient_polys)
|
|
||||||
.chain(&os.partial_products);
|
|
||||||
let single_diffs = single_evals
|
|
||||||
.into_iter()
|
|
||||||
.zip(single_openings)
|
|
||||||
.map(|(e, &o)| e - o)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let single_numerator = alpha.reduce(single_diffs.iter());
|
|
||||||
let single_denominator = subgroup_x - zeta;
|
let single_denominator = subgroup_x - zeta;
|
||||||
sum += single_numerator / single_denominator;
|
sum += single_numerator / single_denominator;
|
||||||
alpha.reset();
|
alpha.reset();
|
||||||
@ -198,12 +219,12 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|&e| F::Extension::from_basefield(e))
|
.map(|&e| F::Extension::from_basefield(e))
|
||||||
.take(common_data.zs_range().end);
|
.take(common_data.zs_range().end);
|
||||||
let zs_composition_eval = alpha.clone().reduce(zs_evals);
|
let zs_composition_eval = alpha.reduce(zs_evals);
|
||||||
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
|
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
|
||||||
let zs_interpol = interpolate2(
|
let zs_interpol = interpolate2(
|
||||||
[
|
[
|
||||||
(zeta, alpha.clone().reduce(os.plonk_zs.iter())),
|
(zeta, precomputed_reduced_evals.zs),
|
||||||
(zeta_right, alpha.reduce(os.plonk_zs_right.iter())),
|
(zeta_right, precomputed_reduced_evals.zs_right),
|
||||||
],
|
],
|
||||||
subgroup_x,
|
subgroup_x,
|
||||||
);
|
);
|
||||||
@ -216,9 +237,9 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
||||||
os: &OpeningSet<F, D>,
|
|
||||||
zeta: F::Extension,
|
zeta: F::Extension,
|
||||||
alpha: F::Extension,
|
alpha: F::Extension,
|
||||||
|
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
|
||||||
initial_merkle_roots: &[Hash<F>],
|
initial_merkle_roots: &[Hash<F>],
|
||||||
proof: &FriProof<F, D>,
|
proof: &FriProof<F, D>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
@ -228,7 +249,6 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = &common_data.config.fri_config;
|
let config = &common_data.config.fri_config;
|
||||||
let mut evaluations: Vec<Vec<F::Extension>> = Vec::new();
|
|
||||||
let x = challenger.get_challenge();
|
let x = challenger.get_challenge();
|
||||||
let mut domain_size = n;
|
let mut domain_size = n;
|
||||||
let mut x_index = x.to_canonical_u64() as usize % n;
|
let mut x_index = x.to_canonical_u64() as usize % n;
|
||||||
@ -242,6 +262,8 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
let log_n = log2_strict(n);
|
let log_n = log2_strict(n);
|
||||||
let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR
|
let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR
|
||||||
* F::primitive_root_of_unity(log_n).exp(reverse_bits(x_index, log_n) as u64);
|
* F::primitive_root_of_unity(log_n).exp(reverse_bits(x_index, log_n) as u64);
|
||||||
|
|
||||||
|
let mut evaluations: Vec<Vec<F::Extension>> = Vec::new();
|
||||||
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
|
for (i, &arity_bits) in config.reduction_arity_bits.iter().enumerate() {
|
||||||
let arity = 1 << arity_bits;
|
let arity = 1 << arity_bits;
|
||||||
let next_domain_size = domain_size >> arity_bits;
|
let next_domain_size = domain_size >> arity_bits;
|
||||||
@ -249,9 +271,9 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
fri_combine_initial(
|
fri_combine_initial(
|
||||||
&round_proof.initial_trees_proof,
|
&round_proof.initial_trees_proof,
|
||||||
alpha,
|
alpha,
|
||||||
os,
|
|
||||||
zeta,
|
zeta,
|
||||||
subgroup_x,
|
subgroup_x,
|
||||||
|
precomputed_reduced_evals,
|
||||||
common_data,
|
common_data,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -268,20 +290,18 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
let mut evals = round_proof.steps[i].evals.clone();
|
let mut evals = round_proof.steps[i].evals.clone();
|
||||||
// Insert P(y) into the evaluation vector, since it wasn't included by the prover.
|
// Insert P(y) into the evaluation vector, since it wasn't included by the prover.
|
||||||
evals.insert(x_index & (arity - 1), e_x);
|
evals.insert(x_index & (arity - 1), e_x);
|
||||||
evaluations.push(evals);
|
|
||||||
verify_merkle_proof(
|
verify_merkle_proof(
|
||||||
flatten(&evaluations[i]),
|
flatten(&evals),
|
||||||
x_index >> arity_bits,
|
x_index >> arity_bits,
|
||||||
proof.commit_phase_merkle_roots[i],
|
proof.commit_phase_merkle_roots[i],
|
||||||
&round_proof.steps[i].merkle_proof,
|
&round_proof.steps[i].merkle_proof,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
evaluations.push(evals);
|
||||||
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
// Update the point x to x^arity.
|
// Update the point x to x^arity.
|
||||||
for _ in 0..config.reduction_arity_bits[i - 1] {
|
subgroup_x = subgroup_x.exp_power_of_2(config.reduction_arity_bits[i - 1]);
|
||||||
subgroup_x = subgroup_x.square();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
domain_size = next_domain_size;
|
domain_size = next_domain_size;
|
||||||
old_x_index = x_index & (arity - 1);
|
old_x_index = x_index & (arity - 1);
|
||||||
@ -297,9 +317,7 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
last_evals,
|
last_evals,
|
||||||
*betas.last().unwrap(),
|
*betas.last().unwrap(),
|
||||||
);
|
);
|
||||||
for _ in 0..final_arity_bits {
|
subgroup_x = subgroup_x.exp_power_of_2(final_arity_bits);
|
||||||
subgroup_x = subgroup_x.square();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final check of FRI. After all the reductions, we check that the final polynomial is equal
|
// Final check of FRI. After all the reductions, we check that the final polynomial is equal
|
||||||
// to the one sent by the prover.
|
// to the one sent by the prover.
|
||||||
|
|||||||
@ -16,7 +16,8 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
/// Computes `x^3`.
|
/// Computes `x^3`.
|
||||||
pub fn cube(&mut self, x: Target) -> Target {
|
pub fn cube(&mut self, x: Target) -> Target {
|
||||||
self.mul_many(&[x, x, x])
|
let xe = self.convert_to_ext(x);
|
||||||
|
self.mul_three_extension(xe, xe, xe).to_target_array()[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `const_0 * multiplicand_0 * multiplicand_1 + const_1 * addend`.
|
/// Computes `const_0 * multiplicand_0 * multiplicand_1 + const_1 * addend`.
|
||||||
@ -123,13 +124,14 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.arithmetic(F::ONE, x, one, F::ONE, y)
|
self.arithmetic(F::ONE, x, one, F::ONE, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add `n` `Target`s with `ceil(n/2) + 1` `ArithmeticExtensionGate`s.
|
||||||
// TODO: Can be made `2*D` times more efficient by using all wires of an `ArithmeticExtensionGate`.
|
// TODO: Can be made `2*D` times more efficient by using all wires of an `ArithmeticExtensionGate`.
|
||||||
pub fn add_many(&mut self, terms: &[Target]) -> Target {
|
pub fn add_many(&mut self, terms: &[Target]) -> Target {
|
||||||
let mut sum = self.zero();
|
let terms_ext = terms
|
||||||
for term in terms {
|
.iter()
|
||||||
sum = self.add(sum, *term);
|
.map(|&t| self.convert_to_ext(t))
|
||||||
}
|
.collect::<Vec<_>>();
|
||||||
sum
|
self.add_many_extension(&terms_ext).to_target_array()[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `x - y`.
|
/// Computes `x - y`.
|
||||||
@ -145,12 +147,22 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.arithmetic(F::ONE, x, y, F::ZERO, x)
|
self.arithmetic(F::ONE, x, y, F::ZERO, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Multiply `n` `Target`s with `ceil(n/2) + 1` `ArithmeticExtensionGate`s.
|
||||||
pub fn mul_many(&mut self, terms: &[Target]) -> Target {
|
pub fn mul_many(&mut self, terms: &[Target]) -> Target {
|
||||||
let mut product = self.one();
|
let terms_ext = terms
|
||||||
for term in terms {
|
.iter()
|
||||||
product = self.mul(product, *term);
|
.map(|&t| self.convert_to_ext(t))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.mul_many_extension(&terms_ext).to_target_array()[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exponentiate `base` to the power of `2^power_log`.
|
||||||
|
// TODO: Test
|
||||||
|
pub fn exp_power_of_2(&mut self, mut base: Target, power_log: usize) -> Target {
|
||||||
|
for _ in 0..power_log {
|
||||||
|
base = self.square(base);
|
||||||
}
|
}
|
||||||
product
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Optimize this, maybe with a new gate.
|
// TODO: Optimize this, maybe with a new gate.
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use crate::circuit_builder::CircuitBuilder;
|
|||||||
use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget};
|
use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget};
|
||||||
use crate::field::extension_field::{Extendable, OEF};
|
use crate::field::extension_field::{Extendable, OEF};
|
||||||
use crate::gates::arithmetic::ArithmeticExtensionGate;
|
use crate::gates::arithmetic::ArithmeticExtensionGate;
|
||||||
use crate::generator::SimpleGenerator;
|
use crate::generator::{GeneratedValues, SimpleGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::util::bits_u64;
|
use crate::util::bits_u64;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
@ -17,37 +17,47 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
const_0: F,
|
const_0: F,
|
||||||
const_1: F,
|
const_1: F,
|
||||||
fixed_multiplicand: ExtensionTarget<D>,
|
first_multiplicand_0: ExtensionTarget<D>,
|
||||||
multiplicand_0: ExtensionTarget<D>,
|
first_multiplicand_1: ExtensionTarget<D>,
|
||||||
addend_0: ExtensionTarget<D>,
|
first_addend: ExtensionTarget<D>,
|
||||||
multiplicand_1: ExtensionTarget<D>,
|
second_multiplicand_0: ExtensionTarget<D>,
|
||||||
addend_1: ExtensionTarget<D>,
|
second_multiplicand_1: ExtensionTarget<D>,
|
||||||
|
second_addend: ExtensionTarget<D>,
|
||||||
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
||||||
let gate = self.add_gate(ArithmeticExtensionGate::new(), vec![const_0, const_1]);
|
let gate = self.add_gate(ArithmeticExtensionGate::new(), vec![const_0, const_1]);
|
||||||
|
|
||||||
let wire_fixed_multiplicand = ExtensionTarget::from_range(
|
let wire_first_multiplicand_0 = ExtensionTarget::from_range(
|
||||||
gate,
|
gate,
|
||||||
ArithmeticExtensionGate::<D>::wires_fixed_multiplicand(),
|
ArithmeticExtensionGate::<D>::wires_first_multiplicand_0(),
|
||||||
);
|
);
|
||||||
let wire_multiplicand_0 =
|
let wire_first_multiplicand_1 = ExtensionTarget::from_range(
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_multiplicand_0());
|
gate,
|
||||||
let wire_addend_0 =
|
ArithmeticExtensionGate::<D>::wires_first_multiplicand_1(),
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_addend_0());
|
);
|
||||||
let wire_multiplicand_1 =
|
let wire_first_addend =
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_multiplicand_1());
|
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_first_addend());
|
||||||
let wire_addend_1 =
|
let wire_second_multiplicand_0 = ExtensionTarget::from_range(
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_addend_1());
|
gate,
|
||||||
let wire_output_0 =
|
ArithmeticExtensionGate::<D>::wires_second_multiplicand_0(),
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_output_0());
|
);
|
||||||
let wire_output_1 =
|
let wire_second_multiplicand_1 = ExtensionTarget::from_range(
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_output_1());
|
gate,
|
||||||
|
ArithmeticExtensionGate::<D>::wires_second_multiplicand_1(),
|
||||||
|
);
|
||||||
|
let wire_second_addend =
|
||||||
|
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_second_addend());
|
||||||
|
let wire_first_output =
|
||||||
|
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_first_output());
|
||||||
|
let wire_second_output =
|
||||||
|
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_second_output());
|
||||||
|
|
||||||
self.route_extension(fixed_multiplicand, wire_fixed_multiplicand);
|
self.route_extension(first_multiplicand_0, wire_first_multiplicand_0);
|
||||||
self.route_extension(multiplicand_0, wire_multiplicand_0);
|
self.route_extension(first_multiplicand_1, wire_first_multiplicand_1);
|
||||||
self.route_extension(addend_0, wire_addend_0);
|
self.route_extension(first_addend, wire_first_addend);
|
||||||
self.route_extension(multiplicand_1, wire_multiplicand_1);
|
self.route_extension(second_multiplicand_0, wire_second_multiplicand_0);
|
||||||
self.route_extension(addend_1, wire_addend_1);
|
self.route_extension(second_multiplicand_1, wire_second_multiplicand_1);
|
||||||
(wire_output_0, wire_output_1)
|
self.route_extension(second_addend, wire_second_addend);
|
||||||
|
(wire_first_output, wire_second_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arithmetic_extension(
|
pub fn arithmetic_extension(
|
||||||
@ -67,6 +77,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
addend,
|
addend,
|
||||||
zero,
|
zero,
|
||||||
zero,
|
zero,
|
||||||
|
zero,
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
@ -80,6 +91,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.arithmetic_extension(F::ONE, F::ONE, one, a, b)
|
self.arithmetic_extension(F::ONE, F::ONE, one, a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `(a0+b0, a1+b1)`.
|
||||||
pub fn add_two_extension(
|
pub fn add_two_extension(
|
||||||
&mut self,
|
&mut self,
|
||||||
a0: ExtensionTarget<D>,
|
a0: ExtensionTarget<D>,
|
||||||
@ -88,7 +100,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
b1: ExtensionTarget<D>,
|
b1: ExtensionTarget<D>,
|
||||||
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
||||||
let one = self.one_extension();
|
let one = self.one_extension();
|
||||||
self.double_arithmetic_extension(F::ONE, F::ONE, one, a0, b0, a1, b1)
|
self.double_arithmetic_extension(F::ONE, F::ONE, one, a0, b0, one, a1, b1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_ext_algebra(
|
pub fn add_ext_algebra(
|
||||||
@ -113,20 +125,39 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
ExtensionAlgebraTarget(res.try_into().unwrap())
|
ExtensionAlgebraTarget(res.try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add 3 `ExtensionTarget`s with 1 `ArithmeticExtensionGate`s.
|
||||||
|
pub fn add_three_extension(
|
||||||
|
&mut self,
|
||||||
|
a: ExtensionTarget<D>,
|
||||||
|
b: ExtensionTarget<D>,
|
||||||
|
c: ExtensionTarget<D>,
|
||||||
|
) -> ExtensionTarget<D> {
|
||||||
|
let one = self.one_extension();
|
||||||
|
let gate = self.num_gates();
|
||||||
|
let first_out =
|
||||||
|
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_first_output());
|
||||||
|
self.double_arithmetic_extension(F::ONE, F::ONE, one, a, b, one, c, first_out)
|
||||||
|
.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add `n` `ExtensionTarget`s with `n/2` `ArithmeticExtensionGate`s.
|
||||||
pub fn add_many_extension(&mut self, terms: &[ExtensionTarget<D>]) -> ExtensionTarget<D> {
|
pub fn add_many_extension(&mut self, terms: &[ExtensionTarget<D>]) -> ExtensionTarget<D> {
|
||||||
let zero = self.zero_extension();
|
let zero = self.zero_extension();
|
||||||
let mut terms = terms.to_vec();
|
let mut terms = terms.to_vec();
|
||||||
if terms.len().is_odd() {
|
if terms.is_empty() {
|
||||||
|
return zero;
|
||||||
|
} else if terms.len() < 3 {
|
||||||
|
terms.resize(3, zero);
|
||||||
|
} else if terms.len().is_even() {
|
||||||
terms.push(zero);
|
terms.push(zero);
|
||||||
}
|
}
|
||||||
// We maintain two accumulators, one for the sum of even elements, and one for odd elements.
|
|
||||||
let mut acc0 = zero;
|
let mut acc = self.add_three_extension(terms[0], terms[1], terms[2]);
|
||||||
let mut acc1 = zero;
|
terms.drain(0..3);
|
||||||
for chunk in terms.chunks_exact(2) {
|
for chunk in terms.chunks_exact(2) {
|
||||||
(acc0, acc1) = self.add_two_extension(acc0, chunk[0], acc1, chunk[1]);
|
acc = self.add_three_extension(acc, chunk[0], chunk[1]);
|
||||||
}
|
}
|
||||||
// We sum both accumulators to get the final result.
|
acc
|
||||||
self.add_extension(acc0, acc1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_extension(
|
pub fn sub_extension(
|
||||||
@ -146,7 +177,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
b1: ExtensionTarget<D>,
|
b1: ExtensionTarget<D>,
|
||||||
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
||||||
let one = self.one_extension();
|
let one = self.one_extension();
|
||||||
self.double_arithmetic_extension(F::ONE, F::NEG_ONE, one, a0, b0, a1, b1)
|
self.double_arithmetic_extension(F::ONE, F::NEG_ONE, one, a0, b0, one, a1, b1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_ext_algebra(
|
pub fn sub_ext_algebra(
|
||||||
@ -184,6 +215,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
zero,
|
zero,
|
||||||
zero,
|
zero,
|
||||||
zero,
|
zero,
|
||||||
|
zero,
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
@ -196,6 +228,18 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
self.mul_extension_with_const(F::ONE, multiplicand_0, multiplicand_1)
|
self.mul_extension_with_const(F::ONE, multiplicand_0, multiplicand_1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `(a0*b0, a1*b1)`.
|
||||||
|
pub fn mul_two_extension(
|
||||||
|
&mut self,
|
||||||
|
a0: ExtensionTarget<D>,
|
||||||
|
b0: ExtensionTarget<D>,
|
||||||
|
a1: ExtensionTarget<D>,
|
||||||
|
b1: ExtensionTarget<D>,
|
||||||
|
) -> (ExtensionTarget<D>, ExtensionTarget<D>) {
|
||||||
|
let zero = self.zero_extension();
|
||||||
|
self.double_arithmetic_extension(F::ONE, F::ZERO, a0, b0, zero, a1, b1, zero)
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes `x^2`.
|
/// Computes `x^2`.
|
||||||
pub fn square_extension(&mut self, x: ExtensionTarget<D>) -> ExtensionTarget<D> {
|
pub fn square_extension(&mut self, x: ExtensionTarget<D>) -> ExtensionTarget<D> {
|
||||||
self.mul_extension(x, x)
|
self.mul_extension(x, x)
|
||||||
@ -221,12 +265,38 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
ExtensionAlgebraTarget(res)
|
ExtensionAlgebraTarget(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Multiply 3 `ExtensionTarget`s with 1 `ArithmeticExtensionGate`s.
|
||||||
|
pub fn mul_three_extension(
|
||||||
|
&mut self,
|
||||||
|
a: ExtensionTarget<D>,
|
||||||
|
b: ExtensionTarget<D>,
|
||||||
|
c: ExtensionTarget<D>,
|
||||||
|
) -> ExtensionTarget<D> {
|
||||||
|
let zero = self.zero_extension();
|
||||||
|
let gate = self.num_gates();
|
||||||
|
let first_out =
|
||||||
|
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_first_output());
|
||||||
|
self.double_arithmetic_extension(F::ONE, F::ZERO, a, b, zero, c, first_out, zero)
|
||||||
|
.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiply `n` `ExtensionTarget`s with `n/2` `ArithmeticExtensionGate`s.
|
||||||
pub fn mul_many_extension(&mut self, terms: &[ExtensionTarget<D>]) -> ExtensionTarget<D> {
|
pub fn mul_many_extension(&mut self, terms: &[ExtensionTarget<D>]) -> ExtensionTarget<D> {
|
||||||
let mut product = self.one_extension();
|
let one = self.one_extension();
|
||||||
for term in terms {
|
let mut terms = terms.to_vec();
|
||||||
product = self.mul_extension(product, *term);
|
if terms.is_empty() {
|
||||||
|
return one;
|
||||||
|
} else if terms.len() < 3 {
|
||||||
|
terms.resize(3, one);
|
||||||
|
} else if terms.len().is_even() {
|
||||||
|
terms.push(one);
|
||||||
}
|
}
|
||||||
product
|
let mut acc = self.mul_three_extension(terms[0], terms[1], terms[2]);
|
||||||
|
terms.drain(0..3);
|
||||||
|
for chunk in terms.chunks_exact(2) {
|
||||||
|
acc = self.mul_three_extension(acc, chunk[0], chunk[1]);
|
||||||
|
}
|
||||||
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `mul_add`, but for `ExtensionTarget`s.
|
/// Like `mul_add`, but for `ExtensionTarget`s.
|
||||||
@ -292,7 +362,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
/// Exponentiate `base` to the power of `2^power_log`.
|
/// Exponentiate `base` to the power of `2^power_log`.
|
||||||
// TODO: Test
|
// TODO: Test
|
||||||
pub fn exp_power_of_2(
|
pub fn exp_power_of_2_extension(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut base: ExtensionTarget<D>,
|
mut base: ExtensionTarget<D>,
|
||||||
power_log: usize,
|
power_log: usize,
|
||||||
@ -384,11 +454,11 @@ impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for QuotientGeneratorE
|
|||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let num = witness.get_extension_target(self.numerator);
|
let num = witness.get_extension_target(self.numerator);
|
||||||
let dem = witness.get_extension_target(self.denominator);
|
let dem = witness.get_extension_target(self.denominator);
|
||||||
let quotient = num / dem;
|
let quotient = num / dem;
|
||||||
PartialWitness::singleton_extension_target(self.quotient, quotient)
|
GeneratedValues::singleton_extension_target(self.quotient, quotient)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,6 +513,43 @@ mod tests {
|
|||||||
use crate::verifier::verify;
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mul_many() -> Result<()> {
|
||||||
|
type F = CrandallField;
|
||||||
|
type FF = QuarticCrandallField;
|
||||||
|
const D: usize = 4;
|
||||||
|
|
||||||
|
let config = CircuitConfig::large_config();
|
||||||
|
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
let mut pw = PartialWitness::new();
|
||||||
|
|
||||||
|
let vs = FF::rand_vec(3);
|
||||||
|
let ts = builder.add_virtual_extension_targets(3);
|
||||||
|
for (&v, &t) in vs.iter().zip(&ts) {
|
||||||
|
pw.set_extension_target(t, v);
|
||||||
|
}
|
||||||
|
let mul0 = builder.mul_many_extension(&ts);
|
||||||
|
let mul1 = {
|
||||||
|
let mut acc = builder.one_extension();
|
||||||
|
for &t in &ts {
|
||||||
|
acc = builder.mul_extension(acc, t);
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
};
|
||||||
|
let mul2 = builder.mul_three_extension(ts[0], ts[1], ts[2]);
|
||||||
|
let mul3 = builder.constant_extension(vs.into_iter().product());
|
||||||
|
|
||||||
|
builder.assert_equal_extension(mul0, mul1);
|
||||||
|
builder.assert_equal_extension(mul1, mul2);
|
||||||
|
builder.assert_equal_extension(mul2, mul3);
|
||||||
|
|
||||||
|
let data = builder.build();
|
||||||
|
let proof = data.prove(pw)?;
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_div_extension() -> Result<()> {
|
fn test_div_extension() -> Result<()> {
|
||||||
type F = CrandallField;
|
type F = CrandallField;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::circuit_builder::CircuitBuilder;
|
|||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::base_sum::BaseSumGate;
|
use crate::gates::base_sum::BaseSumGate;
|
||||||
use crate::generator::SimpleGenerator;
|
use crate::generator::{GeneratedValues, SimpleGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
@ -49,12 +49,12 @@ impl<F: Field> SimpleGenerator<F> for LowHighGenerator {
|
|||||||
vec![self.integer]
|
vec![self.integer]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let integer_value = witness.get_target(self.integer).to_canonical_u64();
|
let integer_value = witness.get_target(self.integer).to_canonical_u64();
|
||||||
let low = integer_value & ((1 << self.n_log) - 1);
|
let low = integer_value & ((1 << self.n_log) - 1);
|
||||||
let high = integer_value >> self.n_log;
|
let high = integer_value >> self.n_log;
|
||||||
|
|
||||||
let mut result = PartialWitness::new();
|
let mut result = GeneratedValues::with_capacity(2);
|
||||||
result.set_target(self.low, F::from_canonical_u64(low));
|
result.set_target(self.low, F::from_canonical_u64(low));
|
||||||
result.set_target(self.high, F::from_canonical_u64(high));
|
result.set_target(self.high, F::from_canonical_u64(high));
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::circuit_builder::CircuitBuilder;
|
|||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::base_sum::BaseSumGate;
|
use crate::gates::base_sum::BaseSumGate;
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::util::ceil_div_usize;
|
use crate::util::ceil_div_usize;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
@ -110,10 +110,10 @@ impl<F: Field> SimpleGenerator<F> for SplitGenerator {
|
|||||||
vec![self.integer]
|
vec![self.integer]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
|
let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
|
||||||
|
|
||||||
let mut result = PartialWitness::new();
|
let mut result = GeneratedValues::with_capacity(self.bits.len());
|
||||||
for &b in &self.bits {
|
for &b in &self.bits {
|
||||||
let b_value = integer_value & 1;
|
let b_value = integer_value & 1;
|
||||||
result.set_target(b, F::from_canonical_u64(b_value));
|
result.set_target(b, F::from_canonical_u64(b_value));
|
||||||
@ -141,10 +141,10 @@ impl<F: Field> SimpleGenerator<F> for WireSplitGenerator {
|
|||||||
vec![self.integer]
|
vec![self.integer]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
|
let mut integer_value = witness.get_target(self.integer).to_canonical_u64();
|
||||||
|
|
||||||
let mut result = PartialWitness::new();
|
let mut result = GeneratedValues::with_capacity(self.gates.len());
|
||||||
for &gate in &self.gates {
|
for &gate in &self.gates {
|
||||||
let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM);
|
let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM);
|
||||||
result.set_target(
|
result.set_target(
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use crate::circuit_builder::CircuitBuilder;
|
|||||||
use crate::field::extension_field::target::ExtensionTarget;
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
@ -18,27 +18,30 @@ impl<const D: usize> ArithmeticExtensionGate<D> {
|
|||||||
GateRef::new(ArithmeticExtensionGate)
|
GateRef::new(ArithmeticExtensionGate)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wires_fixed_multiplicand() -> Range<usize> {
|
pub fn wires_first_multiplicand_0() -> Range<usize> {
|
||||||
0..D
|
0..D
|
||||||
}
|
}
|
||||||
pub fn wires_multiplicand_0() -> Range<usize> {
|
pub fn wires_first_multiplicand_1() -> Range<usize> {
|
||||||
D..2 * D
|
D..2 * D
|
||||||
}
|
}
|
||||||
pub fn wires_addend_0() -> Range<usize> {
|
pub fn wires_first_addend() -> Range<usize> {
|
||||||
2 * D..3 * D
|
2 * D..3 * D
|
||||||
}
|
}
|
||||||
pub fn wires_multiplicand_1() -> Range<usize> {
|
pub fn wires_second_multiplicand_0() -> Range<usize> {
|
||||||
3 * D..4 * D
|
3 * D..4 * D
|
||||||
}
|
}
|
||||||
pub fn wires_addend_1() -> Range<usize> {
|
pub fn wires_second_multiplicand_1() -> Range<usize> {
|
||||||
4 * D..5 * D
|
4 * D..5 * D
|
||||||
}
|
}
|
||||||
pub fn wires_output_0() -> Range<usize> {
|
pub fn wires_second_addend() -> Range<usize> {
|
||||||
5 * D..6 * D
|
5 * D..6 * D
|
||||||
}
|
}
|
||||||
pub fn wires_output_1() -> Range<usize> {
|
pub fn wires_first_output() -> Range<usize> {
|
||||||
6 * D..7 * D
|
6 * D..7 * D
|
||||||
}
|
}
|
||||||
|
pub fn wires_second_output() -> Range<usize> {
|
||||||
|
7 * D..8 * D
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Extendable<D>, const D: usize> Gate<F, D> for ArithmeticExtensionGate<D> {
|
impl<F: Extendable<D>, const D: usize> Gate<F, D> for ArithmeticExtensionGate<D> {
|
||||||
@ -50,21 +53,24 @@ impl<F: Extendable<D>, const D: usize> Gate<F, D> for ArithmeticExtensionGate<D>
|
|||||||
let const_0 = vars.local_constants[0];
|
let const_0 = vars.local_constants[0];
|
||||||
let const_1 = vars.local_constants[1];
|
let const_1 = vars.local_constants[1];
|
||||||
|
|
||||||
let fixed_multiplicand = vars.get_local_ext_algebra(Self::wires_fixed_multiplicand());
|
let first_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_0());
|
||||||
let multiplicand_0 = vars.get_local_ext_algebra(Self::wires_multiplicand_0());
|
let first_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_1());
|
||||||
let addend_0 = vars.get_local_ext_algebra(Self::wires_addend_0());
|
let first_addend = vars.get_local_ext_algebra(Self::wires_first_addend());
|
||||||
let multiplicand_1 = vars.get_local_ext_algebra(Self::wires_multiplicand_1());
|
let second_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_0());
|
||||||
let addend_1 = vars.get_local_ext_algebra(Self::wires_addend_1());
|
let second_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_1());
|
||||||
let output_0 = vars.get_local_ext_algebra(Self::wires_output_0());
|
let second_addend = vars.get_local_ext_algebra(Self::wires_second_addend());
|
||||||
let output_1 = vars.get_local_ext_algebra(Self::wires_output_1());
|
let first_output = vars.get_local_ext_algebra(Self::wires_first_output());
|
||||||
|
let second_output = vars.get_local_ext_algebra(Self::wires_second_output());
|
||||||
|
|
||||||
let computed_output_0 =
|
let first_computed_output = first_multiplicand_0 * first_multiplicand_1 * const_0.into()
|
||||||
fixed_multiplicand * multiplicand_0 * const_0.into() + addend_0 * const_1.into();
|
+ first_addend * const_1.into();
|
||||||
let computed_output_1 =
|
let second_computed_output = second_multiplicand_0 * second_multiplicand_1 * const_0.into()
|
||||||
fixed_multiplicand * multiplicand_1 * const_0.into() + addend_1 * const_1.into();
|
+ second_addend * const_1.into();
|
||||||
|
|
||||||
let mut constraints = (output_0 - computed_output_0).to_basefield_array().to_vec();
|
let mut constraints = (first_output - first_computed_output)
|
||||||
constraints.extend((output_1 - computed_output_1).to_basefield_array());
|
.to_basefield_array()
|
||||||
|
.to_vec();
|
||||||
|
constraints.extend((second_output - second_computed_output).to_basefield_array());
|
||||||
constraints
|
constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,26 +82,32 @@ impl<F: Extendable<D>, const D: usize> Gate<F, D> for ArithmeticExtensionGate<D>
|
|||||||
let const_0 = vars.local_constants[0];
|
let const_0 = vars.local_constants[0];
|
||||||
let const_1 = vars.local_constants[1];
|
let const_1 = vars.local_constants[1];
|
||||||
|
|
||||||
let fixed_multiplicand = vars.get_local_ext_algebra(Self::wires_fixed_multiplicand());
|
let first_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_0());
|
||||||
let multiplicand_0 = vars.get_local_ext_algebra(Self::wires_multiplicand_0());
|
let first_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_first_multiplicand_1());
|
||||||
let addend_0 = vars.get_local_ext_algebra(Self::wires_addend_0());
|
let first_addend = vars.get_local_ext_algebra(Self::wires_first_addend());
|
||||||
let multiplicand_1 = vars.get_local_ext_algebra(Self::wires_multiplicand_1());
|
let second_multiplicand_0 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_0());
|
||||||
let addend_1 = vars.get_local_ext_algebra(Self::wires_addend_1());
|
let second_multiplicand_1 = vars.get_local_ext_algebra(Self::wires_second_multiplicand_1());
|
||||||
let output_0 = vars.get_local_ext_algebra(Self::wires_output_0());
|
let second_addend = vars.get_local_ext_algebra(Self::wires_second_addend());
|
||||||
let output_1 = vars.get_local_ext_algebra(Self::wires_output_1());
|
let first_output = vars.get_local_ext_algebra(Self::wires_first_output());
|
||||||
|
let second_output = vars.get_local_ext_algebra(Self::wires_second_output());
|
||||||
|
|
||||||
let computed_output_0 = builder.mul_ext_algebra(fixed_multiplicand, multiplicand_0);
|
let first_computed_output =
|
||||||
let computed_output_0 = builder.scalar_mul_ext_algebra(const_0, computed_output_0);
|
builder.mul_ext_algebra(first_multiplicand_0, first_multiplicand_1);
|
||||||
let scaled_addend_0 = builder.scalar_mul_ext_algebra(const_1, addend_0);
|
let first_computed_output = builder.scalar_mul_ext_algebra(const_0, first_computed_output);
|
||||||
let computed_output_0 = builder.add_ext_algebra(computed_output_0, scaled_addend_0);
|
let first_scaled_addend = builder.scalar_mul_ext_algebra(const_1, first_addend);
|
||||||
|
let first_computed_output =
|
||||||
|
builder.add_ext_algebra(first_computed_output, first_scaled_addend);
|
||||||
|
|
||||||
let computed_output_1 = builder.mul_ext_algebra(fixed_multiplicand, multiplicand_1);
|
let second_computed_output =
|
||||||
let computed_output_1 = builder.scalar_mul_ext_algebra(const_0, computed_output_1);
|
builder.mul_ext_algebra(second_multiplicand_0, second_multiplicand_1);
|
||||||
let scaled_addend_1 = builder.scalar_mul_ext_algebra(const_1, addend_1);
|
let second_computed_output =
|
||||||
let computed_output_1 = builder.add_ext_algebra(computed_output_1, scaled_addend_1);
|
builder.scalar_mul_ext_algebra(const_0, second_computed_output);
|
||||||
|
let second_scaled_addend = builder.scalar_mul_ext_algebra(const_1, second_addend);
|
||||||
|
let second_computed_output =
|
||||||
|
builder.add_ext_algebra(second_computed_output, second_scaled_addend);
|
||||||
|
|
||||||
let diff_0 = builder.sub_ext_algebra(output_0, computed_output_0);
|
let diff_0 = builder.sub_ext_algebra(first_output, first_computed_output);
|
||||||
let diff_1 = builder.sub_ext_algebra(output_1, computed_output_1);
|
let diff_1 = builder.sub_ext_algebra(second_output, second_computed_output);
|
||||||
let mut constraints = diff_0.to_ext_target_array().to_vec();
|
let mut constraints = diff_0.to_ext_target_array().to_vec();
|
||||||
constraints.extend(diff_1.to_ext_target_array());
|
constraints.extend(diff_1.to_ext_target_array());
|
||||||
constraints
|
constraints
|
||||||
@ -120,7 +132,7 @@ impl<F: Extendable<D>, const D: usize> Gate<F, D> for ArithmeticExtensionGate<D>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn num_wires(&self) -> usize {
|
fn num_wires(&self) -> usize {
|
||||||
7 * D
|
8 * D
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_constants(&self) -> usize {
|
fn num_constants(&self) -> usize {
|
||||||
@ -150,67 +162,67 @@ struct ArithmeticExtensionGenerator1<F: Extendable<D>, const D: usize> {
|
|||||||
|
|
||||||
impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for ArithmeticExtensionGenerator0<F, D> {
|
impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for ArithmeticExtensionGenerator0<F, D> {
|
||||||
fn dependencies(&self) -> Vec<Target> {
|
fn dependencies(&self) -> Vec<Target> {
|
||||||
ArithmeticExtensionGate::<D>::wires_fixed_multiplicand()
|
ArithmeticExtensionGate::<D>::wires_first_multiplicand_0()
|
||||||
.chain(ArithmeticExtensionGate::<D>::wires_multiplicand_0())
|
.chain(ArithmeticExtensionGate::<D>::wires_first_multiplicand_1())
|
||||||
.chain(ArithmeticExtensionGate::<D>::wires_addend_0())
|
.chain(ArithmeticExtensionGate::<D>::wires_first_addend())
|
||||||
.map(|i| Target::wire(self.gate_index, i))
|
.map(|i| Target::wire(self.gate_index, i))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let extract_extension = |range: Range<usize>| -> F::Extension {
|
let extract_extension = |range: Range<usize>| -> F::Extension {
|
||||||
let t = ExtensionTarget::from_range(self.gate_index, range);
|
let t = ExtensionTarget::from_range(self.gate_index, range);
|
||||||
witness.get_extension_target(t)
|
witness.get_extension_target(t)
|
||||||
};
|
};
|
||||||
|
|
||||||
let fixed_multiplicand =
|
|
||||||
extract_extension(ArithmeticExtensionGate::<D>::wires_fixed_multiplicand());
|
|
||||||
let multiplicand_0 =
|
let multiplicand_0 =
|
||||||
extract_extension(ArithmeticExtensionGate::<D>::wires_multiplicand_0());
|
extract_extension(ArithmeticExtensionGate::<D>::wires_first_multiplicand_0());
|
||||||
let addend_0 = extract_extension(ArithmeticExtensionGate::<D>::wires_addend_0());
|
let multiplicand_1 =
|
||||||
|
extract_extension(ArithmeticExtensionGate::<D>::wires_first_multiplicand_1());
|
||||||
|
let addend = extract_extension(ArithmeticExtensionGate::<D>::wires_first_addend());
|
||||||
|
|
||||||
let output_target_0 = ExtensionTarget::from_range(
|
let output_target = ExtensionTarget::from_range(
|
||||||
self.gate_index,
|
self.gate_index,
|
||||||
ArithmeticExtensionGate::<D>::wires_output_0(),
|
ArithmeticExtensionGate::<D>::wires_first_output(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let computed_output_0 = fixed_multiplicand * multiplicand_0 * self.const_0.into()
|
let computed_output =
|
||||||
+ addend_0 * self.const_1.into();
|
multiplicand_0 * multiplicand_1 * self.const_0.into() + addend * self.const_1.into();
|
||||||
|
|
||||||
PartialWitness::singleton_extension_target(output_target_0, computed_output_0)
|
GeneratedValues::singleton_extension_target(output_target, computed_output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for ArithmeticExtensionGenerator1<F, D> {
|
impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for ArithmeticExtensionGenerator1<F, D> {
|
||||||
fn dependencies(&self) -> Vec<Target> {
|
fn dependencies(&self) -> Vec<Target> {
|
||||||
ArithmeticExtensionGate::<D>::wires_fixed_multiplicand()
|
ArithmeticExtensionGate::<D>::wires_second_multiplicand_0()
|
||||||
.chain(ArithmeticExtensionGate::<D>::wires_multiplicand_1())
|
.chain(ArithmeticExtensionGate::<D>::wires_second_multiplicand_1())
|
||||||
.chain(ArithmeticExtensionGate::<D>::wires_addend_1())
|
.chain(ArithmeticExtensionGate::<D>::wires_second_addend())
|
||||||
.map(|i| Target::wire(self.gate_index, i))
|
.map(|i| Target::wire(self.gate_index, i))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let extract_extension = |range: Range<usize>| -> F::Extension {
|
let extract_extension = |range: Range<usize>| -> F::Extension {
|
||||||
let t = ExtensionTarget::from_range(self.gate_index, range);
|
let t = ExtensionTarget::from_range(self.gate_index, range);
|
||||||
witness.get_extension_target(t)
|
witness.get_extension_target(t)
|
||||||
};
|
};
|
||||||
|
|
||||||
let fixed_multiplicand =
|
let multiplicand_0 =
|
||||||
extract_extension(ArithmeticExtensionGate::<D>::wires_fixed_multiplicand());
|
extract_extension(ArithmeticExtensionGate::<D>::wires_second_multiplicand_0());
|
||||||
let multiplicand_1 =
|
let multiplicand_1 =
|
||||||
extract_extension(ArithmeticExtensionGate::<D>::wires_multiplicand_1());
|
extract_extension(ArithmeticExtensionGate::<D>::wires_second_multiplicand_1());
|
||||||
let addend_1 = extract_extension(ArithmeticExtensionGate::<D>::wires_addend_1());
|
let addend = extract_extension(ArithmeticExtensionGate::<D>::wires_second_addend());
|
||||||
|
|
||||||
let output_target_1 = ExtensionTarget::from_range(
|
let output_target = ExtensionTarget::from_range(
|
||||||
self.gate_index,
|
self.gate_index,
|
||||||
ArithmeticExtensionGate::<D>::wires_output_1(),
|
ArithmeticExtensionGate::<D>::wires_second_output(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let computed_output_1 = fixed_multiplicand * multiplicand_1 * self.const_0.into()
|
let computed_output =
|
||||||
+ addend_1 * self.const_1.into();
|
multiplicand_0 * multiplicand_1 * self.const_0.into() + addend * self.const_1.into();
|
||||||
|
|
||||||
PartialWitness::singleton_extension_target(output_target_1, computed_output_1)
|
GeneratedValues::singleton_extension_target(output_target, computed_output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget;
|
|||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::plonk_common::{reduce_with_powers, reduce_with_powers_recursive};
|
use crate::plonk_common::{reduce_with_powers, reduce_with_powers_recursive};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
@ -130,7 +130,7 @@ impl<F: Field, const B: usize> SimpleGenerator<F> for BaseSplitGenerator<B> {
|
|||||||
vec![Target::wire(self.gate_index, BaseSumGate::<B>::WIRE_SUM)]
|
vec![Target::wire(self.gate_index, BaseSumGate::<B>::WIRE_SUM)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let sum_value = witness
|
let sum_value = witness
|
||||||
.get_target(Target::wire(self.gate_index, BaseSumGate::<B>::WIRE_SUM))
|
.get_target(Target::wire(self.gate_index, BaseSumGate::<B>::WIRE_SUM))
|
||||||
.to_canonical_u64() as usize;
|
.to_canonical_u64() as usize;
|
||||||
@ -155,7 +155,7 @@ impl<F: Field, const B: usize> SimpleGenerator<F> for BaseSplitGenerator<B> {
|
|||||||
.iter()
|
.iter()
|
||||||
.fold(F::ZERO, |acc, &x| acc * b_field + x);
|
.fold(F::ZERO, |acc, &x| acc * b_field + x);
|
||||||
|
|
||||||
let mut result = PartialWitness::new();
|
let mut result = GeneratedValues::with_capacity(self.num_limbs + 1);
|
||||||
result.set_target(
|
result.set_target(
|
||||||
Target::wire(self.gate_index, BaseSumGate::<B>::WIRE_REVERSED_SUM),
|
Target::wire(self.gate_index, BaseSumGate::<B>::WIRE_REVERSED_SUM),
|
||||||
reversed_sum,
|
reversed_sum,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::field::extension_field::target::ExtensionTarget;
|
|||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
@ -83,12 +83,12 @@ impl<F: Field> SimpleGenerator<F> for ConstantGenerator<F> {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, _witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, _witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let wire = Wire {
|
let wire = Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input: ConstantGate::WIRE_OUTPUT,
|
input: ConstantGate::WIRE_OUTPUT,
|
||||||
};
|
};
|
||||||
PartialWitness::singleton_target(Target::Wire(wire), self.constant)
|
GeneratedValues::singleton_target(Target::Wire(wire), self.constant)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,11 @@ pub trait Gate<F: Extendable<D>, const D: usize>: 'static + Send + Sync {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|w| F::Extension::from_basefield(*w))
|
.map(|w| F::Extension::from_basefield(*w))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
let public_inputs_hash = &vars_base.public_inputs_hash;
|
||||||
let vars = EvaluationVars {
|
let vars = EvaluationVars {
|
||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
|
public_inputs_hash,
|
||||||
};
|
};
|
||||||
let values = self.eval_unfiltered(vars);
|
let values = self.eval_unfiltered(vars);
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::field::extension_field::Extendable;
|
|||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::GateRef;
|
use crate::gates::gate::GateRef;
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
|
use crate::proof::Hash;
|
||||||
use crate::util::{log2_ceil, transpose};
|
use crate::util::{log2_ceil, transpose};
|
||||||
use crate::vars::EvaluationVars;
|
use crate::vars::EvaluationVars;
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ pub(crate) fn test_low_degree<F: Extendable<D>, const D: usize>(gate: GateRef<F,
|
|||||||
let wire_ldes = random_low_degree_matrix::<F::Extension>(gate.num_wires(), rate_bits);
|
let wire_ldes = random_low_degree_matrix::<F::Extension>(gate.num_wires(), rate_bits);
|
||||||
let constant_ldes = random_low_degree_matrix::<F::Extension>(gate.num_constants(), rate_bits);
|
let constant_ldes = random_low_degree_matrix::<F::Extension>(gate.num_constants(), rate_bits);
|
||||||
assert_eq!(wire_ldes.len(), constant_ldes.len());
|
assert_eq!(wire_ldes.len(), constant_ldes.len());
|
||||||
|
let public_inputs_hash = &Hash::rand();
|
||||||
|
|
||||||
let constraint_evals = wire_ldes
|
let constraint_evals = wire_ldes
|
||||||
.iter()
|
.iter()
|
||||||
@ -24,6 +26,7 @@ pub(crate) fn test_low_degree<F: Extendable<D>, const D: usize>(gate: GateRef<F,
|
|||||||
.map(|(local_wires, local_constants)| EvaluationVars {
|
.map(|(local_wires, local_constants)| EvaluationVars {
|
||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
|
public_inputs_hash,
|
||||||
})
|
})
|
||||||
.map(|vars| gate.eval_unfiltered(vars))
|
.map(|vars| gate.eval_unfiltered(vars))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget;
|
|||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::gmimc::gmimc_automatic_constants;
|
use crate::gmimc::gmimc_automatic_constants;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
@ -239,8 +239,8 @@ impl<F: Extendable<D>, const D: usize, const R: usize> SimpleGenerator<F>
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let mut result = PartialWitness::new();
|
let mut result = GeneratedValues::with_capacity(R + W + 1);
|
||||||
|
|
||||||
let mut state = (0..W)
|
let mut state = (0..W)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
@ -326,6 +326,7 @@ mod tests {
|
|||||||
use crate::gates::gmimc::{GMiMCGate, W};
|
use crate::gates::gmimc::{GMiMCGate, W};
|
||||||
use crate::generator::generate_partial_witness;
|
use crate::generator::generate_partial_witness;
|
||||||
use crate::gmimc::gmimc_permute_naive;
|
use crate::gmimc::gmimc_permute_naive;
|
||||||
|
use crate::proof::Hash;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
use crate::verifier::verify;
|
use crate::verifier::verify;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
@ -416,9 +417,11 @@ mod tests {
|
|||||||
let gate = Gate::with_constants(constants);
|
let gate = Gate::with_constants(constants);
|
||||||
|
|
||||||
let wires = FF::rand_vec(Gate::end());
|
let wires = FF::rand_vec(Gate::end());
|
||||||
|
let public_inputs_hash = &Hash::rand();
|
||||||
let vars = EvaluationVars {
|
let vars = EvaluationVars {
|
||||||
local_constants: &[],
|
local_constants: &[],
|
||||||
local_wires: &wires,
|
local_wires: &wires,
|
||||||
|
public_inputs_hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ev = gate.0.eval_unfiltered(vars);
|
let ev = gate.0.eval_unfiltered(vars);
|
||||||
@ -427,9 +430,14 @@ mod tests {
|
|||||||
for i in 0..Gate::end() {
|
for i in 0..Gate::end() {
|
||||||
pw.set_extension_target(wires_t[i], wires[i]);
|
pw.set_extension_target(wires_t[i], wires[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let public_inputs_hash_t = builder.add_virtual_hash();
|
||||||
|
pw.set_hash_target(public_inputs_hash_t, *public_inputs_hash);
|
||||||
|
|
||||||
let vars_t = EvaluationTargets {
|
let vars_t = EvaluationTargets {
|
||||||
local_constants: &[],
|
local_constants: &[],
|
||||||
local_wires: &wires_t,
|
local_wires: &wires_t,
|
||||||
|
public_inputs_hash: &public_inputs_hash_t,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ev_t = gate.0.eval_unfiltered_recursively(&mut builder, vars_t);
|
let ev_t = gate.0.eval_unfiltered_recursively(&mut builder, vars_t);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use crate::field::extension_field::target::ExtensionTarget;
|
|||||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
@ -218,7 +218,7 @@ impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for InsertionGenerator
|
|||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let local_wire = |input| Wire {
|
let local_wire = |input| Wire {
|
||||||
gate: self.gate_index,
|
gate: self.gate_index,
|
||||||
input,
|
input,
|
||||||
@ -264,7 +264,7 @@ impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for InsertionGenerator
|
|||||||
let mut insert_here_vals = vec![F::ZERO; vec_size];
|
let mut insert_here_vals = vec![F::ZERO; vec_size];
|
||||||
insert_here_vals.insert(insertion_index, F::ONE);
|
insert_here_vals.insert(insertion_index, F::ONE);
|
||||||
|
|
||||||
let mut result = PartialWitness::<F>::new();
|
let mut result = GeneratedValues::<F>::with_capacity((vec_size + 1) * (D + 2));
|
||||||
for i in 0..=vec_size {
|
for i in 0..=vec_size {
|
||||||
let output_wires = self.gate.wires_output_list_item(i).map(local_wire);
|
let output_wires = self.gate.wires_output_list_item(i).map(local_wire);
|
||||||
result.set_ext_wires(output_wires, new_vec[i]);
|
result.set_ext_wires(output_wires, new_vec[i]);
|
||||||
@ -288,6 +288,7 @@ mod tests {
|
|||||||
use crate::gates::gate::Gate;
|
use crate::gates::gate::Gate;
|
||||||
use crate::gates::gate_testing::test_low_degree;
|
use crate::gates::gate_testing::test_low_degree;
|
||||||
use crate::gates::insertion::InsertionGate;
|
use crate::gates::insertion::InsertionGate;
|
||||||
|
use crate::proof::Hash;
|
||||||
use crate::vars::EvaluationVars;
|
use crate::vars::EvaluationVars;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -366,6 +367,7 @@ mod tests {
|
|||||||
let vars = EvaluationVars {
|
let vars = EvaluationVars {
|
||||||
local_constants: &[],
|
local_constants: &[],
|
||||||
local_wires: &get_wires(orig_vec, insertion_index, element_to_insert),
|
local_wires: &get_wires(orig_vec, insertion_index, element_to_insert),
|
||||||
|
public_inputs_hash: &Hash::rand(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use crate::field::extension_field::{Extendable, FieldExtension};
|
|||||||
use crate::field::interpolation::interpolant;
|
use crate::field::interpolation::interpolant;
|
||||||
use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget;
|
use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget;
|
||||||
use crate::gates::gate::{Gate, GateRef};
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
use crate::generator::{SimpleGenerator, WitnessGenerator};
|
use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars};
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
@ -216,7 +216,7 @@ impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for InterpolationGener
|
|||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let n = self.gate.num_points;
|
let n = self.gate.num_points;
|
||||||
|
|
||||||
let local_wire = |input| Wire {
|
let local_wire = |input| Wire {
|
||||||
@ -244,7 +244,7 @@ impl<F: Extendable<D>, const D: usize> SimpleGenerator<F> for InterpolationGener
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let interpolant = interpolant(&points);
|
let interpolant = interpolant(&points);
|
||||||
|
|
||||||
let mut result = PartialWitness::<F>::new();
|
let mut result = GeneratedValues::<F>::with_capacity(D * (self.gate.num_points + 1));
|
||||||
for (i, &coeff) in interpolant.coeffs.iter().enumerate() {
|
for (i, &coeff) in interpolant.coeffs.iter().enumerate() {
|
||||||
let wires = self.gate.wires_coeff(i).map(local_wire);
|
let wires = self.gate.wires_coeff(i).map(local_wire);
|
||||||
result.set_ext_wires(wires, coeff);
|
result.set_ext_wires(wires, coeff);
|
||||||
@ -271,6 +271,7 @@ mod tests {
|
|||||||
use crate::gates::gate_testing::test_low_degree;
|
use crate::gates::gate_testing::test_low_degree;
|
||||||
use crate::gates::interpolation::InterpolationGate;
|
use crate::gates::interpolation::InterpolationGate;
|
||||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||||
|
use crate::proof::Hash;
|
||||||
use crate::vars::EvaluationVars;
|
use crate::vars::EvaluationVars;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -352,6 +353,7 @@ mod tests {
|
|||||||
let vars = EvaluationVars {
|
let vars = EvaluationVars {
|
||||||
local_constants: &[],
|
local_constants: &[],
|
||||||
local_wires: &get_wires(2, coeffs, points, eval_point),
|
local_wires: &get_wires(2, coeffs, points, eval_point),
|
||||||
|
public_inputs_hash: &Hash::rand(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub mod gmimc;
|
|||||||
pub mod insertion;
|
pub mod insertion;
|
||||||
pub mod interpolation;
|
pub mod interpolation;
|
||||||
pub(crate) mod noop;
|
pub(crate) mod noop;
|
||||||
|
pub(crate) mod public_input;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod gate_testing;
|
mod gate_testing;
|
||||||
|
|||||||
84
src/gates/public_input.rs
Normal file
84
src/gates/public_input.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use crate::circuit_builder::CircuitBuilder;
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::Extendable;
|
||||||
|
use crate::gates::gate::{Gate, GateRef};
|
||||||
|
use crate::generator::WitnessGenerator;
|
||||||
|
use crate::vars::{EvaluationTargets, EvaluationVars};
|
||||||
|
|
||||||
|
/// A gate whose first four wires will be equal to a hash of public inputs.
|
||||||
|
pub struct PublicInputGate;
|
||||||
|
|
||||||
|
impl PublicInputGate {
|
||||||
|
pub fn get<F: Extendable<D>, const D: usize>() -> GateRef<F, D> {
|
||||||
|
GateRef::new(PublicInputGate)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wires_public_inputs_hash() -> Range<usize> {
|
||||||
|
0..4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Extendable<D>, const D: usize> Gate<F, D> for PublicInputGate {
|
||||||
|
fn id(&self) -> String {
|
||||||
|
"PublicInputGate".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
||||||
|
Self::wires_public_inputs_hash()
|
||||||
|
.zip(vars.public_inputs_hash.elements)
|
||||||
|
.map(|(wire, hash_part)| vars.local_wires[wire] - hash_part.into())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_unfiltered_recursively(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
|
vars: EvaluationTargets<D>,
|
||||||
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
|
Self::wires_public_inputs_hash()
|
||||||
|
.zip(vars.public_inputs_hash.elements)
|
||||||
|
.map(|(wire, hash_part)| {
|
||||||
|
let hash_part_ext = builder.convert_to_ext(hash_part);
|
||||||
|
builder.sub_extension(vars.local_wires[wire], hash_part_ext)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generators(
|
||||||
|
&self,
|
||||||
|
_gate_index: usize,
|
||||||
|
_local_constants: &[F],
|
||||||
|
) -> Vec<Box<dyn WitnessGenerator<F>>> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_wires(&self) -> usize {
|
||||||
|
4
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_constants(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn degree(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_constraints(&self) -> usize {
|
||||||
|
4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::field::crandall_field::CrandallField;
|
||||||
|
use crate::gates::gate_testing::test_low_degree;
|
||||||
|
use crate::gates::public_input::PublicInputGate;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn low_degree() {
|
||||||
|
test_low_degree(PublicInputGate::get::<CrandallField, 4>())
|
||||||
|
}
|
||||||
|
}
|
||||||
130
src/generator.rs
130
src/generator.rs
@ -1,8 +1,13 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::convert::identity;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use crate::field::extension_field::target::ExtensionTarget;
|
||||||
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
|
use crate::proof::{Hash, HashTarget};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
|
use crate::wire::Wire;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
/// Given a `PartialWitness` that has only inputs set, populates the rest of the witness using the
|
/// Given a `PartialWitness` that has only inputs set, populates the rest of the witness using the
|
||||||
@ -27,7 +32,7 @@ pub(crate) fn generate_partial_witness<F: Field>(
|
|||||||
let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect();
|
let mut pending_generator_indices: HashSet<_> = (0..generators.len()).collect();
|
||||||
|
|
||||||
// We also track a list of "expired" generators which have already returned false.
|
// We also track a list of "expired" generators which have already returned false.
|
||||||
let mut expired_generator_indices = HashSet::new();
|
let mut generator_is_expired = vec![false; generators.len()];
|
||||||
|
|
||||||
// Keep running generators until no generators are queued.
|
// Keep running generators until no generators are queued.
|
||||||
while !pending_generator_indices.is_empty() {
|
while !pending_generator_indices.is_empty() {
|
||||||
@ -36,15 +41,15 @@ pub(crate) fn generate_partial_witness<F: Field>(
|
|||||||
for &generator_idx in &pending_generator_indices {
|
for &generator_idx in &pending_generator_indices {
|
||||||
let (result, finished) = generators[generator_idx].run(&witness);
|
let (result, finished) = generators[generator_idx].run(&witness);
|
||||||
if finished {
|
if finished {
|
||||||
expired_generator_indices.insert(generator_idx);
|
generator_is_expired[generator_idx] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue unfinished generators that were watching one of the newly populated targets.
|
// Enqueue unfinished generators that were watching one of the newly populated targets.
|
||||||
for watch in result.target_values.keys() {
|
for (watch, _) in &result.target_values {
|
||||||
if let Some(watching_generator_indices) = generator_indices_by_watches.get(watch) {
|
if let Some(watching_generator_indices) = generator_indices_by_watches.get(watch) {
|
||||||
for watching_generator_idx in watching_generator_indices {
|
for &watching_generator_idx in watching_generator_indices {
|
||||||
if !expired_generator_indices.contains(watching_generator_idx) {
|
if !generator_is_expired[watching_generator_idx] {
|
||||||
next_pending_generator_indices.insert(*watching_generator_idx);
|
next_pending_generator_indices.insert(watching_generator_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,9 +60,9 @@ pub(crate) fn generate_partial_witness<F: Field>(
|
|||||||
|
|
||||||
pending_generator_indices = next_pending_generator_indices;
|
pending_generator_indices = next_pending_generator_indices;
|
||||||
}
|
}
|
||||||
assert_eq!(
|
|
||||||
expired_generator_indices.len(),
|
assert!(
|
||||||
generators.len(),
|
generator_is_expired.into_iter().all(identity),
|
||||||
"Some generators weren't run."
|
"Some generators weren't run."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -72,14 +77,101 @@ pub trait WitnessGenerator<F: Field>: 'static + Send + Sync {
|
|||||||
/// flag indicating whether the generator is finished. If the flag is true, the generator will
|
/// 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
|
/// never be run again, otherwise it will be queued for another run next time a target in its
|
||||||
/// watch list is populated.
|
/// watch list is populated.
|
||||||
fn run(&self, witness: &PartialWitness<F>) -> (PartialWitness<F>, bool);
|
fn run(&self, witness: &PartialWitness<F>) -> (GeneratedValues<F>, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Values generated by a generator invocation.
|
||||||
|
pub struct GeneratedValues<F: Field> {
|
||||||
|
pub(crate) target_values: Vec<(Target, F)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field> From<Vec<(Target, F)>> for GeneratedValues<F> {
|
||||||
|
fn from(target_values: Vec<(Target, F)>) -> Self {
|
||||||
|
Self { target_values }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field> GeneratedValues<F> {
|
||||||
|
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 singleton_extension_target<const D: usize>(
|
||||||
|
et: ExtensionTarget<D>,
|
||||||
|
value: F::Extension,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
F: Extendable<D>,
|
||||||
|
{
|
||||||
|
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: HashTarget, value: Hash<F>) {
|
||||||
|
ht.elements
|
||||||
|
.iter()
|
||||||
|
.zip(value.elements)
|
||||||
|
.for_each(|(&t, x)| self.set_target(t, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_extension_target<const D: usize>(
|
||||||
|
&mut self,
|
||||||
|
et: ExtensionTarget<D>,
|
||||||
|
value: F::Extension,
|
||||||
|
) where
|
||||||
|
F: Extendable<D>,
|
||||||
|
{
|
||||||
|
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<W>(&mut self, wires: W, values: &[F])
|
||||||
|
where
|
||||||
|
W: IntoIterator<Item = Wire>,
|
||||||
|
{
|
||||||
|
// 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<W, const D: usize>(&mut self, wires: W, value: F::Extension)
|
||||||
|
where
|
||||||
|
F: Extendable<D>,
|
||||||
|
W: IntoIterator<Item = Wire>,
|
||||||
|
{
|
||||||
|
self.set_wires(wires, &value.to_basefield_array());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generator which runs once after a list of dependencies is present in the witness.
|
/// A generator which runs once after a list of dependencies is present in the witness.
|
||||||
pub trait SimpleGenerator<F: Field>: 'static + Send + Sync {
|
pub trait SimpleGenerator<F: Field>: 'static + Send + Sync {
|
||||||
fn dependencies(&self) -> Vec<Target>;
|
fn dependencies(&self) -> Vec<Target>;
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F>;
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field, SG: SimpleGenerator<F>> WitnessGenerator<F> for SG {
|
impl<F: Field, SG: SimpleGenerator<F>> WitnessGenerator<F> for SG {
|
||||||
@ -87,11 +179,11 @@ impl<F: Field, SG: SimpleGenerator<F>> WitnessGenerator<F> for SG {
|
|||||||
self.dependencies()
|
self.dependencies()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, witness: &PartialWitness<F>) -> (PartialWitness<F>, bool) {
|
fn run(&self, witness: &PartialWitness<F>) -> (GeneratedValues<F>, bool) {
|
||||||
if witness.contains_all(&self.dependencies()) {
|
if witness.contains_all(&self.dependencies()) {
|
||||||
(self.run_once(witness), true)
|
(self.run_once(witness), true)
|
||||||
} else {
|
} else {
|
||||||
(PartialWitness::new(), false)
|
(GeneratedValues::empty(), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,9 +200,9 @@ impl<F: Field> SimpleGenerator<F> for CopyGenerator {
|
|||||||
vec![self.src]
|
vec![self.src]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let value = witness.get_target(self.src);
|
let value = witness.get_target(self.src);
|
||||||
PartialWitness::singleton_target(self.dst, value)
|
GeneratedValues::singleton_target(self.dst, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,10 +216,10 @@ impl<F: Field> SimpleGenerator<F> for RandomValueGenerator {
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, _witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, _witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let random_value = F::rand();
|
let random_value = F::rand();
|
||||||
|
|
||||||
PartialWitness::singleton_target(self.target, random_value)
|
GeneratedValues::singleton_target(self.target, random_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +234,7 @@ impl<F: Field> SimpleGenerator<F> for NonzeroTestGenerator {
|
|||||||
vec![self.to_test]
|
vec![self.to_test]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, witness: &PartialWitness<F>) -> PartialWitness<F> {
|
fn run_once(&self, witness: &PartialWitness<F>) -> GeneratedValues<F> {
|
||||||
let to_test_value = witness.get_target(self.to_test);
|
let to_test_value = witness.get_target(self.to_test);
|
||||||
|
|
||||||
let dummy_value = if to_test_value == F::ZERO {
|
let dummy_value = if to_test_value == F::ZERO {
|
||||||
@ -151,6 +243,6 @@ impl<F: Field> SimpleGenerator<F> for NonzeroTestGenerator {
|
|||||||
to_test_value.inverse()
|
to_test_value.inverse()
|
||||||
};
|
};
|
||||||
|
|
||||||
PartialWitness::singleton_target(self.dummy, dummy_value)
|
GeneratedValues::singleton_target(self.dummy, dummy_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,7 +90,7 @@ impl<F: Fn(Target) -> usize> TargetPartition<Target, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut indices = HashMap::new();
|
let mut indices = HashMap::new();
|
||||||
// // Here we keep just the Wire targets, filtering out everything else.
|
// Here we keep just the Wire targets, filtering out everything else.
|
||||||
let partition = partition
|
let partition = partition
|
||||||
.into_values()
|
.into_values()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
|
|||||||
@ -34,10 +34,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
/// Creates a list polynomial commitment for the polynomials interpolating the values in `values`.
|
/// Creates a list polynomial commitment for the polynomials interpolating the values in `values`.
|
||||||
pub fn new(values: Vec<PolynomialValues<F>>, rate_bits: usize, blinding: bool) -> Self {
|
pub fn new(values: Vec<PolynomialValues<F>>, rate_bits: usize, blinding: bool) -> Self {
|
||||||
let degree = values[0].len();
|
let degree = values[0].len();
|
||||||
let polynomials = values
|
let polynomials = values.par_iter().map(|v| v.ifft()).collect::<Vec<_>>();
|
||||||
.par_iter()
|
|
||||||
.map(|v| v.clone().ifft())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let lde_values = timed!(
|
let lde_values = timed!(
|
||||||
Self::lde_values(&polynomials, rate_bits, blinding),
|
Self::lde_values(&polynomials, rate_bits, blinding),
|
||||||
"to compute LDE"
|
"to compute LDE"
|
||||||
@ -92,7 +89,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
assert_eq!(p.len(), degree, "Polynomial degree invalid.");
|
assert_eq!(p.len(), degree, "Polynomial degree invalid.");
|
||||||
p.clone().lde(rate_bits).coset_fft(F::coset_shift()).values
|
p.lde(rate_bits).coset_fft(F::coset_shift()).values
|
||||||
})
|
})
|
||||||
.chain(if blinding {
|
.chain(if blinding {
|
||||||
// If blinding, salt with two random elements to each leaf vector.
|
// If blinding, salt with two random elements to each leaf vector.
|
||||||
@ -182,15 +179,15 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
final_poly += zs_quotient;
|
final_poly += zs_quotient;
|
||||||
|
|
||||||
let lde_final_poly = final_poly.lde(config.rate_bits);
|
let lde_final_poly = final_poly.lde(config.rate_bits);
|
||||||
let lde_final_values = lde_final_poly.clone().coset_fft(F::coset_shift().into());
|
let lde_final_values = lde_final_poly.coset_fft(F::coset_shift().into());
|
||||||
|
|
||||||
let fri_proof = fri_proof(
|
let fri_proof = fri_proof(
|
||||||
&commitments
|
&commitments
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|c| &c.merkle_tree)
|
.map(|c| &c.merkle_tree)
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&lde_final_poly,
|
lde_final_poly,
|
||||||
&lde_final_values,
|
lde_final_values,
|
||||||
challenger,
|
challenger,
|
||||||
&config.fri_config,
|
&config.fri_config,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -88,7 +88,7 @@ impl<F: Field> PolynomialCoeffs<F> {
|
|||||||
|
|
||||||
let root = F::primitive_root_of_unity(log2_strict(a.len()));
|
let root = F::primitive_root_of_unity(log2_strict(a.len()));
|
||||||
// Equals to the evaluation of `a` on `{g.w^i}`.
|
// Equals to the evaluation of `a` on `{g.w^i}`.
|
||||||
let mut a_eval = fft(a);
|
let mut a_eval = fft(&a);
|
||||||
// Compute the denominators `1/(g^n.w^(n*i) - 1)` using batch inversion.
|
// Compute the denominators `1/(g^n.w^(n*i) - 1)` using batch inversion.
|
||||||
let denominator_g = g.exp(n as u64);
|
let denominator_g = g.exp(n as u64);
|
||||||
let root_n = root.exp(n as u64);
|
let root_n = root.exp(n as u64);
|
||||||
@ -112,7 +112,7 @@ impl<F: Field> PolynomialCoeffs<F> {
|
|||||||
*x *= d;
|
*x *= d;
|
||||||
});
|
});
|
||||||
// `p` is the interpolating polynomial of `a_eval` on `{w^i}`.
|
// `p` is the interpolating polynomial of `a_eval` on `{w^i}`.
|
||||||
let mut p = ifft(a_eval);
|
let mut p = ifft(&a_eval);
|
||||||
// We need to scale it by `g^(-i)` to get the interpolating polynomial of `a_eval` on `{g.w^i}`,
|
// We need to scale it by `g^(-i)` to get the interpolating polynomial of `a_eval` on `{g.w^i}`,
|
||||||
// a.k.a `a/Z_H`.
|
// a.k.a `a/Z_H`.
|
||||||
let g_inv = g.inverse();
|
let g_inv = g.inverse();
|
||||||
|
|||||||
@ -33,12 +33,12 @@ impl<F: Field> PolynomialValues<F> {
|
|||||||
self.values.len()
|
self.values.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ifft(self) -> PolynomialCoeffs<F> {
|
pub fn ifft(&self) -> PolynomialCoeffs<F> {
|
||||||
ifft(self)
|
ifft(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the polynomial whose evaluation on the coset `shift*H` is `self`.
|
/// Returns the polynomial whose evaluation on the coset `shift*H` is `self`.
|
||||||
pub fn coset_ifft(self, shift: F) -> PolynomialCoeffs<F> {
|
pub fn coset_ifft(&self, shift: F) -> PolynomialCoeffs<F> {
|
||||||
let mut shifted_coeffs = self.ifft();
|
let mut shifted_coeffs = self.ifft();
|
||||||
shifted_coeffs
|
shifted_coeffs
|
||||||
.coeffs
|
.coeffs
|
||||||
@ -54,9 +54,9 @@ impl<F: Field> PolynomialValues<F> {
|
|||||||
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
|
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lde(self, rate_bits: usize) -> Self {
|
pub fn lde(&self, rate_bits: usize) -> Self {
|
||||||
let coeffs = ifft(self).lde(rate_bits);
|
let coeffs = ifft(self).lde(rate_bits);
|
||||||
fft_with_options(coeffs, Some(rate_bits), None)
|
fft_with_options(&coeffs, Some(rate_bits), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn degree(&self) -> usize {
|
pub fn degree(&self) -> usize {
|
||||||
@ -66,7 +66,7 @@ impl<F: Field> PolynomialValues<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn degree_plus_one(&self) -> usize {
|
pub fn degree_plus_one(&self) -> usize {
|
||||||
self.clone().ifft().degree_plus_one()
|
self.ifft().degree_plus_one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ impl<F: Field> PolynomialCoeffs<F> {
|
|||||||
.fold(F::ZERO, |acc, &c| acc * x + c)
|
.fold(F::ZERO, |acc, &c| acc * x + c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lde_multiple(polys: Vec<Self>, rate_bits: usize) -> Vec<Self> {
|
pub fn lde_multiple(polys: Vec<&Self>, rate_bits: usize) -> Vec<Self> {
|
||||||
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
|
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,16 +194,16 @@ impl<F: Field> PolynomialCoeffs<F> {
|
|||||||
Self::new(self.trimmed().coeffs.into_iter().rev().collect())
|
Self::new(self.trimmed().coeffs.into_iter().rev().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fft(self) -> PolynomialValues<F> {
|
pub fn fft(&self) -> PolynomialValues<F> {
|
||||||
fft(self)
|
fft(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the evaluation of the polynomial on the coset `shift*H`.
|
/// Returns the evaluation of the polynomial on the coset `shift*H`.
|
||||||
pub fn coset_fft(self, shift: F) -> PolynomialValues<F> {
|
pub fn coset_fft(&self, shift: F) -> PolynomialValues<F> {
|
||||||
let modified_poly: Self = shift
|
let modified_poly: Self = shift
|
||||||
.powers()
|
.powers()
|
||||||
.zip(self.coeffs)
|
.zip(&self.coeffs)
|
||||||
.map(|(r, c)| r * c)
|
.map(|(r, &c)| r * c)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into();
|
.into();
|
||||||
modified_poly.fft()
|
modified_poly.fft()
|
||||||
@ -262,8 +262,7 @@ impl<F: Field> Sub for &PolynomialCoeffs<F> {
|
|||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
let len = max(self.len(), rhs.len());
|
let len = max(self.len(), rhs.len());
|
||||||
let mut coeffs = self.coeffs.clone();
|
let mut coeffs = self.padded(len).coeffs;
|
||||||
coeffs.resize(len, F::ZERO);
|
|
||||||
for (i, &c) in rhs.coeffs.iter().enumerate() {
|
for (i, &c) in rhs.coeffs.iter().enumerate() {
|
||||||
coeffs[i] -= c;
|
coeffs[i] -= c;
|
||||||
}
|
}
|
||||||
@ -343,7 +342,7 @@ impl<F: Field> Mul for &PolynomialCoeffs<F> {
|
|||||||
.zip(b_evals.values)
|
.zip(b_evals.values)
|
||||||
.map(|(pa, pb)| pa * pb)
|
.map(|(pa, pb)| pa * pb)
|
||||||
.collect();
|
.collect();
|
||||||
ifft(mul_evals.into())
|
ifft(&mul_evals.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +389,7 @@ mod tests {
|
|||||||
let n = 1 << k;
|
let n = 1 << k;
|
||||||
let poly = PolynomialCoeffs::new(F::rand_vec(n));
|
let poly = PolynomialCoeffs::new(F::rand_vec(n));
|
||||||
let shift = F::rand();
|
let shift = F::rand();
|
||||||
let coset_evals = poly.clone().coset_fft(shift).values;
|
let coset_evals = poly.coset_fft(shift).values;
|
||||||
|
|
||||||
let generator = F::primitive_root_of_unity(k);
|
let generator = F::primitive_root_of_unity(k);
|
||||||
let naive_coset_evals = F::cyclic_subgroup_coset_known_order(generator, shift, n)
|
let naive_coset_evals = F::cyclic_subgroup_coset_known_order(generator, shift, n)
|
||||||
@ -411,7 +410,7 @@ mod tests {
|
|||||||
let n = 1 << k;
|
let n = 1 << k;
|
||||||
let evals = PolynomialValues::new(F::rand_vec(n));
|
let evals = PolynomialValues::new(F::rand_vec(n));
|
||||||
let shift = F::rand();
|
let shift = F::rand();
|
||||||
let coeffs = evals.clone().coset_ifft(shift);
|
let coeffs = evals.coset_ifft(shift);
|
||||||
|
|
||||||
let generator = F::primitive_root_of_unity(k);
|
let generator = F::primitive_root_of_unity(k);
|
||||||
let naive_coset_evals = F::cyclic_subgroup_coset_known_order(generator, shift, n)
|
let naive_coset_evals = F::cyclic_subgroup_coset_known_order(generator, shift, n)
|
||||||
|
|||||||
18
src/proof.rs
18
src/proof.rs
@ -37,6 +37,12 @@ impl<F: Field> Hash<F> {
|
|||||||
elements: [elements[0], elements[1], elements[2], elements[3]],
|
elements: [elements[0], elements[1], elements[2], elements[3]],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rand() -> Self {
|
||||||
|
Self {
|
||||||
|
elements: [F::rand(), F::rand(), F::rand(), F::rand()],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a ~256 bit hash output.
|
/// Represents a ~256 bit hash output.
|
||||||
@ -79,6 +85,13 @@ pub struct Proof<F: Extendable<D>, const D: usize> {
|
|||||||
pub opening_proof: OpeningProof<F, D>,
|
pub opening_proof: OpeningProof<F, D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(bound = "")]
|
||||||
|
pub struct ProofWithPublicInputs<F: Extendable<D>, const D: usize> {
|
||||||
|
pub proof: Proof<F, D>,
|
||||||
|
pub public_inputs: Vec<F>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ProofTarget<const D: usize> {
|
pub struct ProofTarget<const D: usize> {
|
||||||
pub wires_root: HashTarget,
|
pub wires_root: HashTarget,
|
||||||
pub plonk_zs_partial_products_root: HashTarget,
|
pub plonk_zs_partial_products_root: HashTarget,
|
||||||
@ -87,6 +100,11 @@ pub struct ProofTarget<const D: usize> {
|
|||||||
pub opening_proof: OpeningProofTarget<D>,
|
pub opening_proof: OpeningProofTarget<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ProofWithPublicInputsTarget<const D: usize> {
|
||||||
|
pub proof: ProofTarget<D>,
|
||||||
|
pub public_inputs: Vec<Target>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluations and Merkle proof produced by the prover in a FRI query step.
|
/// Evaluations and Merkle proof produced by the prover in a FRI query step.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "")]
|
#[serde(bound = "")]
|
||||||
|
|||||||
@ -7,11 +7,12 @@ use rayon::prelude::*;
|
|||||||
use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
|
use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::generator::generate_partial_witness;
|
use crate::generator::generate_partial_witness;
|
||||||
|
use crate::hash::hash_n_to_hash;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::plonk_common::{PlonkPolynomials, ZeroPolyOnCoset};
|
use crate::plonk_common::{PlonkPolynomials, ZeroPolyOnCoset};
|
||||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
use crate::proof::Proof;
|
use crate::proof::{Hash, Proof, ProofWithPublicInputs};
|
||||||
use crate::timed;
|
use crate::timed;
|
||||||
use crate::util::partial_products::partial_products;
|
use crate::util::partial_products::partial_products;
|
||||||
use crate::util::{log2_ceil, transpose};
|
use crate::util::{log2_ceil, transpose};
|
||||||
@ -23,7 +24,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
prover_data: &ProverOnlyCircuitData<F, D>,
|
prover_data: &ProverOnlyCircuitData<F, D>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
inputs: PartialWitness<F>,
|
inputs: PartialWitness<F>,
|
||||||
) -> Result<Proof<F, D>> {
|
) -> Result<ProofWithPublicInputs<F, D>> {
|
||||||
let config = &common_data.config;
|
let config = &common_data.config;
|
||||||
let num_wires = config.num_wires;
|
let num_wires = config.num_wires;
|
||||||
let num_challenges = config.num_challenges;
|
let num_challenges = config.num_challenges;
|
||||||
@ -39,6 +40,9 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
"to generate witness"
|
"to generate witness"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let public_inputs = partial_witness.get_targets(&prover_data.public_inputs);
|
||||||
|
let public_inputs_hash = hash_n_to_hash(public_inputs.clone(), true);
|
||||||
|
|
||||||
// Display the marked targets for debugging purposes.
|
// Display the marked targets for debugging purposes.
|
||||||
for m in &prover_data.marked_targets {
|
for m in &prover_data.marked_targets {
|
||||||
m.display(&partial_witness);
|
m.display(&partial_witness);
|
||||||
@ -58,7 +62,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
let wires_values: Vec<PolynomialValues<F>> = timed!(
|
let wires_values: Vec<PolynomialValues<F>> = timed!(
|
||||||
witness
|
witness
|
||||||
.wire_values
|
.wire_values
|
||||||
.iter()
|
.par_iter()
|
||||||
.map(|column| PolynomialValues::new(column.clone()))
|
.map(|column| PolynomialValues::new(column.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
"to compute wire polynomials"
|
"to compute wire polynomials"
|
||||||
@ -119,6 +123,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
compute_quotient_polys(
|
compute_quotient_polys(
|
||||||
common_data,
|
common_data,
|
||||||
prover_data,
|
prover_data,
|
||||||
|
&public_inputs_hash,
|
||||||
&wires_commitment,
|
&wires_commitment,
|
||||||
&zs_partial_products_commitment,
|
&zs_partial_products_commitment,
|
||||||
&betas,
|
&betas,
|
||||||
@ -178,12 +183,16 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
start_proof_gen.elapsed().as_secs_f32()
|
start_proof_gen.elapsed().as_secs_f32()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Proof {
|
let proof = Proof {
|
||||||
wires_root: wires_commitment.merkle_tree.root,
|
wires_root: wires_commitment.merkle_tree.root,
|
||||||
plonk_zs_partial_products_root: zs_partial_products_commitment.merkle_tree.root,
|
plonk_zs_partial_products_root: zs_partial_products_commitment.merkle_tree.root,
|
||||||
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
|
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
|
||||||
openings,
|
openings,
|
||||||
opening_proof,
|
opening_proof,
|
||||||
|
};
|
||||||
|
Ok(ProofWithPublicInputs {
|
||||||
|
proof,
|
||||||
|
public_inputs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,6 +293,7 @@ fn compute_z<F: Extendable<D>, const D: usize>(
|
|||||||
fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
prover_data: &'a ProverOnlyCircuitData<F, D>,
|
prover_data: &'a ProverOnlyCircuitData<F, D>,
|
||||||
|
public_inputs_hash: &Hash<F>,
|
||||||
wires_commitment: &'a ListPolynomialCommitment<F>,
|
wires_commitment: &'a ListPolynomialCommitment<F>,
|
||||||
zs_partial_products_commitment: &'a ListPolynomialCommitment<F>,
|
zs_partial_products_commitment: &'a ListPolynomialCommitment<F>,
|
||||||
betas: &[F],
|
betas: &[F],
|
||||||
@ -337,6 +347,7 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
|||||||
let vars = EvaluationVarsBase {
|
let vars = EvaluationVarsBase {
|
||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
|
public_inputs_hash,
|
||||||
};
|
};
|
||||||
let mut quotient_values = eval_vanishing_poly_base(
|
let mut quotient_values = eval_vanishing_poly_base(
|
||||||
common_data,
|
common_data,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarge
|
|||||||
use crate::context;
|
use crate::context;
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::plonk_challenger::RecursiveChallenger;
|
use crate::plonk_challenger::RecursiveChallenger;
|
||||||
use crate::proof::{HashTarget, ProofTarget};
|
use crate::proof::{HashTarget, ProofWithPublicInputsTarget};
|
||||||
use crate::util::scaling::ReducingFactorTarget;
|
use crate::util::scaling::ReducingFactorTarget;
|
||||||
use crate::vanishing_poly::eval_vanishing_poly_recursively;
|
use crate::vanishing_poly::eval_vanishing_poly_recursively;
|
||||||
use crate::vars::EvaluationTargets;
|
use crate::vars::EvaluationTargets;
|
||||||
@ -15,15 +15,21 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
/// Recursively verifies an inner proof.
|
/// Recursively verifies an inner proof.
|
||||||
pub fn add_recursive_verifier(
|
pub fn add_recursive_verifier(
|
||||||
&mut self,
|
&mut self,
|
||||||
proof: ProofTarget<D>,
|
proof_with_pis: ProofWithPublicInputsTarget<D>,
|
||||||
inner_config: &CircuitConfig,
|
inner_config: &CircuitConfig,
|
||||||
inner_verifier_data: &VerifierCircuitTarget,
|
inner_verifier_data: &VerifierCircuitTarget,
|
||||||
inner_common_data: &CommonCircuitData<F, D>,
|
inner_common_data: &CommonCircuitData<F, D>,
|
||||||
) {
|
) {
|
||||||
assert!(self.config.num_wires >= MIN_WIRES);
|
assert!(self.config.num_wires >= MIN_WIRES);
|
||||||
assert!(self.config.num_wires >= MIN_ROUTED_WIRES);
|
assert!(self.config.num_wires >= MIN_ROUTED_WIRES);
|
||||||
|
let ProofWithPublicInputsTarget {
|
||||||
|
proof,
|
||||||
|
public_inputs,
|
||||||
|
} = proof_with_pis;
|
||||||
let one = self.one_extension();
|
let one = self.one_extension();
|
||||||
|
|
||||||
|
let public_inputs_hash = &self.hash_n_to_hash(public_inputs, true);
|
||||||
|
|
||||||
let num_challenges = inner_config.num_challenges;
|
let num_challenges = inner_config.num_challenges;
|
||||||
|
|
||||||
let mut challenger = RecursiveChallenger::new(self);
|
let mut challenger = RecursiveChallenger::new(self);
|
||||||
@ -53,13 +59,14 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
let vars = EvaluationTargets {
|
let vars = EvaluationTargets {
|
||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
|
public_inputs_hash,
|
||||||
};
|
};
|
||||||
let local_zs = &proof.openings.plonk_zs;
|
let local_zs = &proof.openings.plonk_zs;
|
||||||
let next_zs = &proof.openings.plonk_zs_right;
|
let next_zs = &proof.openings.plonk_zs_right;
|
||||||
let s_sigmas = &proof.openings.plonk_sigmas;
|
let s_sigmas = &proof.openings.plonk_sigmas;
|
||||||
let partial_products = &proof.openings.partial_products;
|
let partial_products = &proof.openings.partial_products;
|
||||||
|
|
||||||
let zeta_pow_deg = self.exp_power_of_2(zeta, inner_common_data.degree_bits);
|
let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits);
|
||||||
let vanishing_polys_zeta = context!(
|
let vanishing_polys_zeta = context!(
|
||||||
self,
|
self,
|
||||||
"evaluate the vanishing polynomial at our challenge point, zeta.",
|
"evaluate the vanishing polynomial at our challenge point, zeta.",
|
||||||
@ -89,7 +96,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
{
|
{
|
||||||
let recombined_quotient = scale.reduce(chunk, self);
|
let recombined_quotient = scale.reduce(chunk, self);
|
||||||
let computed_vanishing_poly = self.mul_extension(z_h_zeta, recombined_quotient);
|
let computed_vanishing_poly = self.mul_extension(z_h_zeta, recombined_quotient);
|
||||||
self.named_route_extension(
|
self.named_assert_equal_extension(
|
||||||
vanishing_polys_zeta[i],
|
vanishing_polys_zeta[i],
|
||||||
computed_vanishing_poly,
|
computed_vanishing_poly,
|
||||||
format!("Vanishing polynomial == Z_H * quotient, challenge {}", i),
|
format!("Vanishing polynomial == Z_H * quotient, challenge {}", i),
|
||||||
@ -127,7 +134,7 @@ mod tests {
|
|||||||
use crate::polynomial::commitment::OpeningProofTarget;
|
use crate::polynomial::commitment::OpeningProofTarget;
|
||||||
use crate::proof::{
|
use crate::proof::{
|
||||||
FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget,
|
FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget,
|
||||||
OpeningSetTarget, Proof,
|
OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs,
|
||||||
};
|
};
|
||||||
use crate::verifier::verify;
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
@ -167,9 +174,14 @@ mod tests {
|
|||||||
|
|
||||||
// Construct a `ProofTarget` with the same dimensions as `proof`.
|
// Construct a `ProofTarget` with the same dimensions as `proof`.
|
||||||
fn proof_to_proof_target<F: Extendable<D>, const D: usize>(
|
fn proof_to_proof_target<F: Extendable<D>, const D: usize>(
|
||||||
proof: &Proof<F, D>,
|
proof_with_pis: &ProofWithPublicInputs<F, D>,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
) -> ProofTarget<D> {
|
) -> ProofWithPublicInputsTarget<D> {
|
||||||
|
let ProofWithPublicInputs {
|
||||||
|
proof,
|
||||||
|
public_inputs,
|
||||||
|
} = proof_with_pis;
|
||||||
|
|
||||||
let wires_root = builder.add_virtual_hash();
|
let wires_root = builder.add_virtual_hash();
|
||||||
let plonk_zs_root = builder.add_virtual_hash();
|
let plonk_zs_root = builder.add_virtual_hash();
|
||||||
let quotient_polys_root = builder.add_virtual_hash();
|
let quotient_polys_root = builder.add_virtual_hash();
|
||||||
@ -208,21 +220,41 @@ mod tests {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
ProofTarget {
|
let proof = ProofTarget {
|
||||||
wires_root,
|
wires_root,
|
||||||
plonk_zs_partial_products_root: plonk_zs_root,
|
plonk_zs_partial_products_root: plonk_zs_root,
|
||||||
quotient_polys_root,
|
quotient_polys_root,
|
||||||
openings,
|
openings,
|
||||||
opening_proof,
|
opening_proof,
|
||||||
|
};
|
||||||
|
|
||||||
|
let public_inputs = builder.add_virtual_targets(public_inputs.len());
|
||||||
|
ProofWithPublicInputsTarget {
|
||||||
|
proof,
|
||||||
|
public_inputs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`.
|
// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`.
|
||||||
fn set_proof_target<F: Extendable<D>, const D: usize>(
|
fn set_proof_target<F: Extendable<D>, const D: usize>(
|
||||||
proof: &Proof<F, D>,
|
proof: &ProofWithPublicInputs<F, D>,
|
||||||
pt: &ProofTarget<D>,
|
pt: &ProofWithPublicInputsTarget<D>,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
) {
|
) {
|
||||||
|
let ProofWithPublicInputs {
|
||||||
|
proof,
|
||||||
|
public_inputs,
|
||||||
|
} = proof;
|
||||||
|
let ProofWithPublicInputsTarget {
|
||||||
|
proof: pt,
|
||||||
|
public_inputs: pi_targets,
|
||||||
|
} = pt;
|
||||||
|
|
||||||
|
// Set public inputs.
|
||||||
|
for (&pi_t, &pi) in pi_targets.iter().zip(public_inputs) {
|
||||||
|
pw.set_target(pi_t, pi);
|
||||||
|
}
|
||||||
|
|
||||||
pw.set_hash_target(pt.wires_root, proof.wires_root);
|
pw.set_hash_target(pt.wires_root, proof.wires_root);
|
||||||
pw.set_hash_target(
|
pw.set_hash_target(
|
||||||
pt.plonk_zs_partial_products_root,
|
pt.plonk_zs_partial_products_root,
|
||||||
@ -343,7 +375,7 @@ mod tests {
|
|||||||
num_query_rounds: 40,
|
num_query_rounds: 40,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let (proof, vd, cd) = {
|
let (proof_with_pis, vd, cd) = {
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||||
let _two = builder.two();
|
let _two = builder.two();
|
||||||
let _two = builder.hash_n_to_hash(vec![_two], true).elements[0];
|
let _two = builder.hash_n_to_hash(vec![_two], true).elements[0];
|
||||||
@ -357,12 +389,12 @@ mod tests {
|
|||||||
data.common,
|
data.common,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
verify(proof.clone(), &vd, &cd)?;
|
verify(proof_with_pis.clone(), &vd, &cd)?;
|
||||||
|
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||||
let mut pw = PartialWitness::new();
|
let mut pw = PartialWitness::new();
|
||||||
let pt = proof_to_proof_target(&proof, &mut builder);
|
let pt = proof_to_proof_target(&proof_with_pis, &mut builder);
|
||||||
set_proof_target(&proof, &pt, &mut pw);
|
set_proof_target(&proof_with_pis, &pt, &mut pw);
|
||||||
|
|
||||||
let inner_data = VerifierCircuitTarget {
|
let inner_data = VerifierCircuitTarget {
|
||||||
constants_sigmas_root: builder.add_virtual_hash(),
|
constants_sigmas_root: builder.add_virtual_hash(),
|
||||||
|
|||||||
@ -7,9 +7,6 @@ use crate::wire::Wire;
|
|||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
Wire(Wire),
|
Wire(Wire),
|
||||||
PublicInput {
|
|
||||||
index: usize,
|
|
||||||
},
|
|
||||||
/// A target that doesn't have any inherent location in the witness (but it can be copied to
|
/// A target that doesn't have any inherent location in the witness (but it can be copied to
|
||||||
/// another target that does). This is useful for representing intermediate values in witness
|
/// another target that does). This is useful for representing intermediate values in witness
|
||||||
/// generation.
|
/// generation.
|
||||||
@ -26,7 +23,6 @@ impl Target {
|
|||||||
pub fn is_routable(&self, config: &CircuitConfig) -> bool {
|
pub fn is_routable(&self, config: &CircuitConfig) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Target::Wire(wire) => wire.is_routable(config),
|
Target::Wire(wire) => wire.is_routable(config),
|
||||||
Target::PublicInput { .. } => true,
|
|
||||||
Target::VirtualTarget { .. } => true,
|
Target::VirtualTarget { .. } => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,7 @@ pub(crate) fn transpose<T: Clone>(matrix: &[Vec<T>]) -> Vec<Vec<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Permutes `arr` such that each index is mapped to its reverse in binary.
|
/// Permutes `arr` such that each index is mapped to its reverse in binary.
|
||||||
pub(crate) fn reverse_index_bits<T: Copy>(arr: Vec<T>) -> Vec<T> {
|
pub(crate) fn reverse_index_bits<T: Copy>(arr: &[T]) -> Vec<T> {
|
||||||
let n = arr.len();
|
let n = arr.len();
|
||||||
let n_power = log2_strict(n);
|
let n_power = log2_strict(n);
|
||||||
|
|
||||||
@ -99,12 +99,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_reverse_index_bits() {
|
fn test_reverse_index_bits() {
|
||||||
|
assert_eq!(reverse_index_bits(&[10, 20, 30, 40]), vec![10, 30, 20, 40]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
reverse_index_bits(vec![10, 20, 30, 40]),
|
reverse_index_bits(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
|
||||||
vec![10, 30, 20, 40]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
reverse_index_bits(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
|
|
||||||
vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
|
vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use crate::polynomial::polynomial::PolynomialCoeffs;
|
|||||||
/// This struct abstract away these operations by implementing Horner's method and keeping track
|
/// This struct abstract away these operations by implementing Horner's method and keeping track
|
||||||
/// of the number of multiplications by `a` to compute the scaling factor.
|
/// of the number of multiplications by `a` to compute the scaling factor.
|
||||||
/// See https://github.com/mir-protocol/plonky2/pull/69 for more details and discussions.
|
/// See https://github.com/mir-protocol/plonky2/pull/69 for more details and discussions.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReducingFactor<F: Field> {
|
pub struct ReducingFactor<F: Field> {
|
||||||
base: F,
|
base: F,
|
||||||
count: u64,
|
count: u64,
|
||||||
@ -79,7 +79,7 @@ impl<F: Field> ReducingFactor<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ReducingFactorTarget<const D: usize> {
|
pub struct ReducingFactorTarget<const D: usize> {
|
||||||
base: ExtensionTarget<D>,
|
base: ExtensionTarget<D>,
|
||||||
count: u64,
|
count: u64,
|
||||||
@ -122,8 +122,10 @@ impl<const D: usize> ReducingFactorTarget<D> {
|
|||||||
// out_0 = alpha acc + pair[0]
|
// out_0 = alpha acc + pair[0]
|
||||||
// acc' = out_1 = alpha out_0 + pair[1]
|
// acc' = out_1 = alpha out_0 + pair[1]
|
||||||
let gate = builder.num_gates();
|
let gate = builder.num_gates();
|
||||||
let out_0 =
|
let out_0 = ExtensionTarget::from_range(
|
||||||
ExtensionTarget::from_range(gate, ArithmeticExtensionGate::<D>::wires_output_0());
|
gate,
|
||||||
|
ArithmeticExtensionGate::<D>::wires_first_output(),
|
||||||
|
);
|
||||||
acc = builder
|
acc = builder
|
||||||
.double_arithmetic_extension(
|
.double_arithmetic_extension(
|
||||||
F::ONE,
|
F::ONE,
|
||||||
@ -131,6 +133,7 @@ impl<const D: usize> ReducingFactorTarget<D> {
|
|||||||
self.base,
|
self.base,
|
||||||
acc,
|
acc,
|
||||||
pair[0],
|
pair[0],
|
||||||
|
self.base,
|
||||||
out_0,
|
out_0,
|
||||||
pair[1],
|
pair[1],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -236,10 +236,13 @@ pub fn evaluate_gate_constraints_recursively<F: Extendable<D>, const D: usize>(
|
|||||||
) -> Vec<ExtensionTarget<D>> {
|
) -> Vec<ExtensionTarget<D>> {
|
||||||
let mut constraints = vec![builder.zero_extension(); num_gate_constraints];
|
let mut constraints = vec![builder.zero_extension(); num_gate_constraints];
|
||||||
for gate in gates {
|
for gate in gates {
|
||||||
let gate_constraints = gate
|
let gate_constraints = context!(
|
||||||
.gate
|
builder,
|
||||||
.0
|
&format!("evaluate {} constraints", gate.gate.0.id()),
|
||||||
.eval_filtered_recursively(builder, vars, &gate.prefix);
|
gate.gate
|
||||||
|
.0
|
||||||
|
.eval_filtered_recursively(builder, vars, &gate.prefix)
|
||||||
|
);
|
||||||
for (i, c) in gate_constraints.into_iter().enumerate() {
|
for (i, c) in gate_constraints.into_iter().enumerate() {
|
||||||
constraints[i] = builder.add_extension(constraints[i], c);
|
constraints[i] = builder.add_extension(constraints[i], c);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,17 +5,20 @@ use crate::field::extension_field::algebra::ExtensionAlgebra;
|
|||||||
use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget};
|
use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget};
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
|
use crate::proof::{Hash, HashTarget};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct EvaluationVars<'a, F: Extendable<D>, const D: usize> {
|
pub struct EvaluationVars<'a, F: Extendable<D>, const D: usize> {
|
||||||
pub(crate) local_constants: &'a [F::Extension],
|
pub(crate) local_constants: &'a [F::Extension],
|
||||||
pub(crate) local_wires: &'a [F::Extension],
|
pub(crate) local_wires: &'a [F::Extension],
|
||||||
|
pub(crate) public_inputs_hash: &'a Hash<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct EvaluationVarsBase<'a, F: Field> {
|
pub struct EvaluationVarsBase<'a, F: Field> {
|
||||||
pub(crate) local_constants: &'a [F],
|
pub(crate) local_constants: &'a [F],
|
||||||
pub(crate) local_wires: &'a [F],
|
pub(crate) local_wires: &'a [F],
|
||||||
|
pub(crate) public_inputs_hash: &'a Hash<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, F: Extendable<D>, const D: usize> EvaluationVars<'a, F, D> {
|
impl<'a, F: Extendable<D>, const D: usize> EvaluationVars<'a, F, D> {
|
||||||
@ -49,6 +52,7 @@ impl<'a, const D: usize> EvaluationTargets<'a, D> {
|
|||||||
pub struct EvaluationTargets<'a, const D: usize> {
|
pub struct EvaluationTargets<'a, const D: usize> {
|
||||||
pub(crate) local_constants: &'a [ExtensionTarget<D>],
|
pub(crate) local_constants: &'a [ExtensionTarget<D>],
|
||||||
pub(crate) local_wires: &'a [ExtensionTarget<D>],
|
pub(crate) local_wires: &'a [ExtensionTarget<D>],
|
||||||
|
pub(crate) public_inputs_hash: &'a HashTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, const D: usize> EvaluationTargets<'a, D> {
|
impl<'a, const D: usize> EvaluationTargets<'a, D> {
|
||||||
|
|||||||
@ -3,20 +3,27 @@ use anyhow::{ensure, Result};
|
|||||||
use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
|
use crate::hash::hash_n_to_hash;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::plonk_common::reduce_with_powers;
|
use crate::plonk_common::reduce_with_powers;
|
||||||
use crate::proof::Proof;
|
use crate::proof::ProofWithPublicInputs;
|
||||||
use crate::vanishing_poly::eval_vanishing_poly;
|
use crate::vanishing_poly::eval_vanishing_poly;
|
||||||
use crate::vars::EvaluationVars;
|
use crate::vars::EvaluationVars;
|
||||||
|
|
||||||
pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
||||||
proof: Proof<F, D>,
|
proof_with_pis: ProofWithPublicInputs<F, D>,
|
||||||
verifier_data: &VerifierOnlyCircuitData<F>,
|
verifier_data: &VerifierOnlyCircuitData<F>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let ProofWithPublicInputs {
|
||||||
|
proof,
|
||||||
|
public_inputs,
|
||||||
|
} = proof_with_pis;
|
||||||
let config = &common_data.config;
|
let config = &common_data.config;
|
||||||
let num_challenges = config.num_challenges;
|
let num_challenges = config.num_challenges;
|
||||||
|
|
||||||
|
let public_inputs_hash = &hash_n_to_hash(public_inputs, true);
|
||||||
|
|
||||||
let mut challenger = Challenger::new();
|
let mut challenger = Challenger::new();
|
||||||
// Observe the instance.
|
// Observe the instance.
|
||||||
// TODO: Need to include public inputs as well.
|
// TODO: Need to include public inputs as well.
|
||||||
@ -37,6 +44,7 @@ pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
|||||||
let vars = EvaluationVars {
|
let vars = EvaluationVars {
|
||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
|
public_inputs_hash,
|
||||||
};
|
};
|
||||||
let local_zs = &proof.openings.plonk_zs;
|
let local_zs = &proof.openings.plonk_zs;
|
||||||
let next_zs = &proof.openings.plonk_zs_right;
|
let next_zs = &proof.openings.plonk_zs_right;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use crate::field::extension_field::target::ExtensionTarget;
|
|||||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::gates::gate::GateInstance;
|
use crate::gates::gate::GateInstance;
|
||||||
|
use crate::generator::GeneratedValues;
|
||||||
use crate::proof::{Hash, HashTarget};
|
use crate::proof::{Hash, HashTarget};
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
@ -35,28 +36,6 @@ impl<F: Field> PartialWitness<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|
||||||
let mut witness = PartialWitness::new();
|
|
||||||
witness.set_target(target, value);
|
|
||||||
witness
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn singleton_extension_target<const D: usize>(
|
|
||||||
et: ExtensionTarget<D>,
|
|
||||||
value: F::Extension,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
F: Extendable<D>,
|
|
||||||
{
|
|
||||||
let mut witness = PartialWitness::new();
|
|
||||||
witness.set_extension_target(et, value);
|
|
||||||
witness
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.target_values.is_empty()
|
self.target_values.is_empty()
|
||||||
}
|
}
|
||||||
@ -157,7 +136,7 @@ impl<F: Field> PartialWitness<F> {
|
|||||||
self.set_wires(wires, &value.to_basefield_array());
|
self.set_wires(wires, &value.to_basefield_array());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend(&mut self, other: PartialWitness<F>) {
|
pub fn extend(&mut self, other: GeneratedValues<F>) {
|
||||||
for (target, value) in other.target_values {
|
for (target, value) in other.target_values {
|
||||||
self.set_target(target, value);
|
self.set_target(target, value);
|
||||||
}
|
}
|
||||||
@ -193,7 +172,6 @@ impl<F: Field> PartialWitness<F> {
|
|||||||
gate,
|
gate,
|
||||||
gate_instances[*gate].gate_type.0.id()
|
gate_instances[*gate].gate_type.0.id()
|
||||||
),
|
),
|
||||||
Target::PublicInput { index } => format!("{}-th public input", index),
|
|
||||||
Target::VirtualTarget { index } => format!("{}-th virtual target", index),
|
Target::VirtualTarget { index } => format!("{}-th virtual target", index),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user