Skip to content

Commit 477cca8

Browse files
Patch outline, revert which_is_unsatisfied and more (#392)
* r1cs replaced with gr1cs * addressed the PR comments * instance assignment getter created * instance assignment fixed outer * nax_arity added * predicate num constraints added * bump version to 0.5.0 and update dependencies * refactor: changed the constraint storage method in the predicates * Fix: predicate weakly references to a constraint system * polish * feat: expose R1CS_PREDICATE_LABEL from gr1cs module * refactor: move make_row method to ConstraintSystem and ConstraintSystemRef for matrix row creation * refactor: update make_row method to improve error handling and clarity * refactor: Replaced the weak reference with downstreaming constraint system reference * tracing checked * work * works * ready to review * finalized * Update * Fix * Fix * Remove patches * Bug Fix: Outline instances handling 'One' * bug fix: Handling one in instance outline * outline instance optimized * path instance_outline * Bug Fix: Outline instances handling 'One' * bug fix: Handling one in instance outline * outline instance optimized * path instance_outline * Fmt * Fix * Fix * work * fix * which_is_unsatisfied reverted * fmt * Work * Fix CI * fmt * Clean up * Improve * Tweak --------- Co-authored-by: Pratyush Mishra <[email protected]>
1 parent f632770 commit 477cca8

File tree

14 files changed

+647
-133
lines changed

14 files changed

+647
-133
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
toolchain: ${{ matrix.rust }}
5151
override: true
5252

53-
- uses: actions/cache@v2
53+
- uses: actions/cache@v4
5454
with:
5555
path: |
5656
~/.cargo/registry
@@ -92,7 +92,7 @@ jobs:
9292
- name: Checkout
9393
uses: actions/checkout@v2
9494

95-
- name: Install Rust (${{ matrix.rust }})
95+
- name: Install Rust
9696
uses: actions-rs/toolchain@v1
9797
with:
9898
toolchain: stable

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ark-serialize = { version = "0.5.0", default-features = false }
2222
tracing = { version = "0.1", default-features = false }
2323
tracing-subscriber = { version = "0.3", default-features = false }
2424
ark-test-curves = { version = "0.5.0", default-features = false }
25+
rayon = { version = "1" }
2526

2627
[profile.release]
2728
opt-level = 3

relations/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ ark-poly.workspace = true
1919
ark-serialize.workspace = true
2020
tracing = { workspace = true, features = ["attributes"] }
2121
tracing-subscriber = { workspace = true, default-features = true, optional = true }
22+
rayon = { workspace = true, optional = true }
2223

2324
[dev-dependencies]
2425
ark-test-curves = { workspace = true, default-features = false, features = [ "bls12_381_scalar_field" ] }
2526

2627
[features]
2728
default = []
2829
std = [ "ark-std/std", "ark-ff/std", "tracing-subscriber", "tracing/std" ]
30+
parallel = [ "std", "ark-std/parallel", "ark-ff/parallel", "rayon" ]
2931

3032

3133
[[example]]

relations/src/gr1cs/constraint_system.rs

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! This module contains the implementation of the `ConstraintSystem` struct.
22
//! a constraint system contains multiple predicate constraint systems,
3-
//! each of which enforce have seperate predicates and constraints. For more infomation about the terminology and the structure of the constraint system, refer to section 3.3 of https://eprint.iacr.org/2024/1245
3+
//! each of which enforce have separate predicates and constraints. For more information about the terminology and the structure of the constraint system, refer to section 3.3 of https://eprint.iacr.org/2024/1245
44
55
use super::{
6+
instance_outliner::InstanceOutliner,
67
predicate::{
78
polynomial_constraint::R1CS_PREDICATE_LABEL, PredicateConstraintSystem, PredicateType,
89
},
@@ -22,6 +23,7 @@ use ark_std::{
2223
string::{String, ToString},
2324
vec::Vec,
2425
};
26+
// TODO: Prayush's PR, Hashbrown, HAshmap for nostd
2527
///////////////////////////////////////////////////////////////////////////////////////
2628

2729
/// A GR1CS `ConstraintSystem`. Enforces constraints of the form
@@ -55,7 +57,7 @@ pub struct ConstraintSystem<F: Field> {
5557
/// It assigns a witness variable to each instance variable and enforces the
5658
/// equality of the instance and witness variables. Then only uses the
5759
/// witness variables in the constraints.
58-
outline_instances: bool,
60+
instance_outliner: Option<InstanceOutliner<F>>,
5961

6062
/// Assignments to the public input variables. This is empty if `self.mode
6163
/// == SynthesisMode::Setup`.
@@ -99,7 +101,7 @@ impl<F: Field> ConstraintSystem<F> {
99101
num_instance_variables: 1,
100102
num_witness_variables: 0,
101103
num_linear_combinations: 0,
102-
outline_instances: false,
104+
instance_outliner: None,
103105
predicate_constraint_systems: BTreeMap::new(),
104106
instance_assignment: vec![F::one()],
105107
witness_assignment: Vec::new(),
@@ -109,7 +111,7 @@ impl<F: Field> ConstraintSystem<F> {
109111
mode: SynthesisMode::Prove {
110112
construct_matrices: true,
111113
},
112-
optimization_goal: OptimizationGoal::Constraints,
114+
optimization_goal: OptimizationGoal::None,
113115
#[cfg(feature = "std")]
114116
predicate_traces: BTreeMap::new(),
115117
};
@@ -361,6 +363,11 @@ impl<F: Field> ConstraintSystem<F> {
361363
Ok(())
362364
}
363365

366+
/// Remove the predicate with the given label from the constraint system.
367+
pub fn remove_predicate(&mut self, predicate_label: &str) {
368+
self.predicate_constraint_systems.remove(predicate_label);
369+
}
370+
364371
/// check if there is a predicate with the given label
365372
pub fn has_predicate(&self, predicate_label: &str) -> bool {
366373
self.predicate_constraint_systems
@@ -402,15 +409,15 @@ impl<F: Field> ConstraintSystem<F> {
402409
/// If `self` is unsatisfied, outputs `Ok(false)`.
403410
/// If `self.is_in_setup_mode()` or if `self == None`, outputs `Err(())`.
404411
pub fn is_satisfied(&self) -> crate::utils::Result<bool> {
405-
self.which_predicate_is_unsatisfied().map(|s| s.is_none())
412+
self.which_is_unsatisfied().map(|s| s.is_none())
406413
}
407414

408415
/// If `self` is satisfied, outputs `Ok(None)`.
409416
/// If `self` is unsatisfied, outputs `Some(s,i)`, where `s` is the label of
410417
/// the unsatisfied prediacate and `i` is the index of
411418
/// the first unsatisfied constraint in that predicate.
412419
/// If `self.is_in_setup_mode()` or `self == None`, outputs `Err(())`.
413-
pub fn which_predicate_is_unsatisfied(&self) -> crate::utils::Result<Option<String>> {
420+
pub fn which_is_unsatisfied(&self) -> crate::utils::Result<Option<String>> {
414421
if self.is_in_setup_mode() {
415422
Err(SynthesisError::AssignmentMissing)
416423
} else {
@@ -448,24 +455,35 @@ impl<F: Field> ConstraintSystem<F> {
448455
/// Finalize the constraint system (either by outlining or inlining,
449456
/// if an optimization goal is set).
450457
pub fn finalize(&mut self) {
458+
let timer_finalize = start_timer!(|| "Finalize GR1CS");
459+
let timer_inline_ouline_lcs = start_timer!(|| "Inline/Outline LCs");
451460
match self.optimization_goal {
452-
OptimizationGoal::None => self.inline_all_lcs(),
453461
OptimizationGoal::Constraints => self.inline_all_lcs(),
454462
OptimizationGoal::Weight => self.outline_lcs(),
463+
_ => self.inline_all_lcs(),
455464
};
456-
if self.outline_instances {
457-
let _ = self.do_outline_instances();
465+
end_timer!(timer_inline_ouline_lcs);
466+
// check if should outline instance or not
467+
let timer_instance_outlining = start_timer!(|| "Instance Outlining");
468+
if let Some(instance_outliner) = self.instance_outliner.take() {
469+
// Check if the predicate to be outlined is in the constraint system
470+
if self.has_predicate(&instance_outliner.pred_label) {
471+
// Outline the instances
472+
let _ = self.perform_instance_outlining(instance_outliner);
473+
}
458474
}
475+
end_timer!(timer_instance_outlining);
476+
end_timer!(timer_finalize);
459477
}
460478

461479
/// Naively inlines symbolic linear combinations into the linear
462480
/// combinations that use them.
463481
///
464-
/// Useful for standard pairing-based SNARKs where addition gates are cheap.
465-
/// For example, in the SNARKs such as [\[Groth16\]](https://eprint.iacr.org/2016/260) and
482+
/// Useful for standard pairing-based SNARKs where addition gates are
483+
/// cheap. For example, in the SNARKs such as [\[Groth16\]](https://eprint.iacr.org/2016/260) and
466484
/// [\[Groth-Maller17\]](https://eprint.iacr.org/2017/540), addition gates
467-
/// do not contribute to the size of the multi-scalar multiplication, which
468-
/// is the dominating cost.
485+
/// do not contribute to the size of the multi-scalar multiplication,
486+
/// which is the dominating cost.
469487
pub fn inline_all_lcs(&mut self) {
470488
// Only inline when a matrix representing R1CS is needed.
471489
if !self.should_construct_matrices() {
@@ -478,11 +496,11 @@ impl<F: Field> ConstraintSystem<F> {
478496
self.transform_lc_map(&mut |_, _, _| (0, None));
479497
}
480498

481-
/// If a `SymbolicLc` is used in more than one location and has sufficient
482-
/// length, this method makes a new variable for that `SymbolicLc`, adds
483-
/// a constraint ensuring the equality of the variable and the linear
484-
/// combination, and then uses that variable in every location the
485-
/// `SymbolicLc` is used.
499+
/// If a `SymbolicLc` is used in more than one location and has
500+
/// sufficient length, this method makes a new variable for that
501+
/// `SymbolicLc`, adds a constraint ensuring the equality of the
502+
/// variable and the linear combination, and then uses that
503+
/// variable in every location the `SymbolicLc` is used.
486504
///
487505
/// Useful for SNARKs like [\[Marlin\]](https://eprint.iacr.org/2019/1047) or
488506
/// [\[Fractal\]](https://eprint.iacr.org/2019/1076), where addition gates
@@ -583,10 +601,10 @@ impl<F: Field> ConstraintSystem<F> {
583601
/// This method is used as a subroutine of `inline_all_lcs` and
584602
/// `outline_lcs`.
585603
///
586-
/// The transformer function is given a references of this constraint system
587-
/// (&self), number of times used, and a mutable reference of the linear
588-
/// combination to be transformed. (&ConstraintSystem<F>, usize,
589-
/// &mut LinearCombination<F>)
604+
/// The transformer function is given a references of this constraint
605+
/// system (&self), number of times used, and a mutable
606+
/// reference of the linear combination to be transformed.
607+
/// (&ConstraintSystem<F>, usize, &mut LinearCombination<F>)
590608
///
591609
/// The transformer function returns the number of new witness variables
592610
/// needed and a vector of new witness assignments (if not in the setup
@@ -600,7 +618,8 @@ impl<F: Field> ConstraintSystem<F> {
600618
) -> (usize, Option<Vec<F>>),
601619
) {
602620
// `transformed_lc_map` stores the transformed linear combinations.
603-
let mut transformed_lc_map = BTreeMap::<_, LinearCombination<F>>::new();
621+
let mut transformed_lc_map: BTreeMap<LcIndex, LinearCombination<F>> =
622+
BTreeMap::<_, LinearCombination<F>>::new();
604623
let mut num_times_used = self.lc_num_times_used(false);
605624

606625
// This loop goes through all the LCs in the map, starting from
@@ -707,8 +726,8 @@ impl<F: Field> ConstraintSystem<F> {
707726
}
708727

709728
/// Get the linear combination corresponding to the given `lc_index`.
710-
/// TODO: This function should return a reference to the linear combination
711-
/// and not clone it.
729+
/// TODO: This function should return a reference to the linear
730+
/// combination and not clone it.
712731
pub fn get_lc(&self, lc_index: LcIndex) -> crate::gr1cs::Result<LinearCombination<F>> {
713732
self.lc_map
714733
.get(&lc_index)
@@ -735,24 +754,27 @@ impl<F: Field> ConstraintSystem<F> {
735754
}
736755

737756
/// Sets the flag for outlining the instances
738-
pub(crate) fn outline_instances(&mut self) {
739-
self.outline_instances = true;
757+
pub(crate) fn set_instance_outliner(&mut self, instance_outliner: InstanceOutliner<F>) {
758+
self.instance_outliner = Some(instance_outliner);
740759
}
741760

742-
/// Returns the flag for outlining the instances, This is by default set to
743-
/// false
761+
/// Returns the flag for outlining the instances, This is by default set
762+
/// to false
744763
pub(crate) fn should_outline_instances(&self) -> bool {
745-
self.outline_instances
764+
self.instance_outliner.is_some()
746765
}
747766

748767
/// Outlines the instances in the constraint system
749-
/// This function creates a new witness variable for each instance variable
750-
/// and uses these witness variables in the constraints instead of instance
751-
/// variables. This technique is useful for verifier succinctness in some
752-
/// SNARKs like Garuda, Pari and PolyMath
753-
/// After the function call, The instances are only used in the `c` matrix
754-
/// of r1cs
755-
pub(crate) fn do_outline_instances(&mut self) -> crate::gr1cs::Result<()> {
768+
/// This function creates a new witness variable for each instance
769+
/// variable and uses these witness variables in the constraints
770+
/// instead of instance variables. This technique is useful for
771+
/// verifier succinctness in some SNARKs like Garuda, Pari and
772+
/// PolyMath After the function call, The instances are only
773+
/// used in the `c` matrix of r1cs
774+
pub fn perform_instance_outlining(
775+
&mut self,
776+
outliner: InstanceOutliner<F>,
777+
) -> crate::gr1cs::Result<()> {
756778
// First build a map from instance variables to witness variables
757779
let mut instance_to_witness_map = BTreeMap::<Variable, Variable>::new();
758780
// Initialize the map with the one variable, this is done manually because we
@@ -797,30 +819,7 @@ impl<F: Field> ConstraintSystem<F> {
797819
self.witness_assignment[witness_index] = instance_value;
798820
}
799821
}
800-
801-
// Now, enforce the equality between the instance and the corresponding witness
802-
// variable This is done by iterating over the instance-witness map
803-
// which contains the unique instance-witness pairs The equality
804-
// constraints are enforced with r1cs constraints, it is assumed that a
805-
// constraint system has a default r1cs predicate registered
806-
for (instance, witness) in instance_to_witness_map.iter() {
807-
let r1cs_constraint = if instance.is_one() {
808-
vec![
809-
LinearCombination::from(*witness),
810-
LinearCombination::from(*witness),
811-
LinearCombination::from(*instance),
812-
]
813-
} else {
814-
vec![
815-
LinearCombination::from(one_witt),
816-
LinearCombination::from(*witness),
817-
LinearCombination::from(*instance),
818-
]
819-
};
820-
821-
self.enforce_constraint(R1CS_PREDICATE_LABEL, r1cs_constraint)?;
822-
}
823-
822+
(outliner.func)(self, instance_to_witness_map)?;
824823
Ok(())
825824
}
826825
}

0 commit comments

Comments
 (0)