You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.7 KiB

//! Support for generating R1CS witness using bellperson.
use crate::traits::Group;
use ff::{Field, PrimeField};
use bellperson::{
multiexp::DensityTracker, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable,
};
/// A `ConstraintSystem` which calculates witness values for a concrete instance of an R1CS circuit.
pub struct SatisfyingAssignment<G: Group>
where
G::Scalar: PrimeField,
{
// Density of queries
a_aux_density: DensityTracker,
b_input_density: DensityTracker,
b_aux_density: DensityTracker,
// Evaluations of A, B, C polynomials
a: Vec<G::Scalar>,
b: Vec<G::Scalar>,
c: Vec<G::Scalar>,
// Assignments of variables
pub(crate) input_assignment: Vec<G::Scalar>,
pub(crate) aux_assignment: Vec<G::Scalar>,
}
use std::fmt;
impl<G: Group> fmt::Debug for SatisfyingAssignment<G>
where
G::Scalar: PrimeField,
{
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt
.debug_struct("SatisfyingAssignment")
.field("a_aux_density", &self.a_aux_density)
.field("b_input_density", &self.b_input_density)
.field("b_aux_density", &self.b_aux_density)
.field(
"a",
&self
.a
.iter()
.map(|v| format!("Fr({v:?})"))
.collect::<Vec<_>>(),
)
.field(
"b",
&self
.b
.iter()
.map(|v| format!("Fr({v:?})"))
.collect::<Vec<_>>(),
)
.field(
"c",
&self
.c
.iter()
.map(|v| format!("Fr({v:?})"))
.collect::<Vec<_>>(),
)
.field("input_assignment", &self.input_assignment)
.field("aux_assignment", &self.aux_assignment)
.finish()
}
}
impl<G: Group> PartialEq for SatisfyingAssignment<G>
where
G::Scalar: PrimeField,
{
fn eq(&self, other: &SatisfyingAssignment<G>) -> bool {
self.a_aux_density == other.a_aux_density
&& self.b_input_density == other.b_input_density
&& self.b_aux_density == other.b_aux_density
&& self.a == other.a
&& self.b == other.b
&& self.c == other.c
&& self.input_assignment == other.input_assignment
&& self.aux_assignment == other.aux_assignment
}
}
impl<G: Group> ConstraintSystem<G::Scalar> for SatisfyingAssignment<G>
where
G::Scalar: PrimeField,
{
type Root = Self;
fn new() -> Self {
let input_assignment = vec![G::Scalar::ONE];
let mut d = DensityTracker::new();
d.add_element();
Self {
a_aux_density: DensityTracker::new(),
b_input_density: d,
b_aux_density: DensityTracker::new(),
a: vec![],
b: vec![],
c: vec![],
input_assignment,
aux_assignment: vec![],
}
}
fn alloc<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<G::Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.aux_assignment.push(f()?);
self.a_aux_density.add_element();
self.b_aux_density.add_element();
Ok(Variable(Index::Aux(self.aux_assignment.len() - 1)))
}
fn alloc_input<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<G::Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.input_assignment.push(f()?);
self.b_input_density.add_element();
Ok(Variable(Index::Input(self.input_assignment.len() - 1)))
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, _a: LA, _b: LB, _c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<G::Scalar>) -> LinearCombination<G::Scalar>,
LB: FnOnce(LinearCombination<G::Scalar>) -> LinearCombination<G::Scalar>,
LC: FnOnce(LinearCombination<G::Scalar>) -> LinearCombination<G::Scalar>,
{
// Do nothing: we don't care about linear-combination evaluations in this context.
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
// Do nothing; we don't care about namespaces in this context.
}
fn pop_namespace(&mut self) {
// Do nothing; we don't care about namespaces in this context.
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
fn is_extensible() -> bool {
true
}
fn extend(&mut self, other: Self) {
self.a_aux_density.extend(other.a_aux_density, false);
self.b_input_density.extend(other.b_input_density, true);
self.b_aux_density.extend(other.b_aux_density, false);
self.a.extend(other.a);
self.b.extend(other.b);
self.c.extend(other.c);
self.input_assignment
// Skip first input, which must have been a temporarily allocated one variable.
.extend(&other.input_assignment[1..]);
self.aux_assignment.extend(other.aux_assignment);
}
}