From eb47322d25d31fd15dca4c2597c3ddd23d0db3aa Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Wed, 1 Jun 2022 00:23:37 +0200 Subject: [PATCH 01/10] added .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2c94578..8da52f0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ parser/target/ program_structure/target/ type_analysis/target/ .idea/ +.vscode .DS_Store Cargo.lock From 5db87fefdd12b0bd15fbc098db7db88d08dae59f Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Wed, 1 Jun 2022 00:24:33 +0200 Subject: [PATCH 02/10] extended grammar to use custom gates --- parser/src/lang.lalrpop | 42 +++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index b679483..396f601 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -27,6 +27,10 @@ ParsePragma : Version = { // maybe change to usize instead of BigInt => version, }; +// Pragma to indicate that we are using PLONK with custom gates. +ParseCustomGates : () = { + "pragma" "ultraPlonk" ";" => () +} // Includes are added at the start of the file. // Their structure is the following: #include "path to the file" @@ -36,22 +40,14 @@ ParseInclude : String = { }; // Parsing a program requires: -// Parsing the "pragma" instruction, if there is one -// Parsing "includes" instructions, if there is anyone, -// Parsing function and template definitions, +// Parsing the version pragma, if there is one +// Parsing the custom gates pragma, if there is one +// Parsing "includes" instructions, if there is anyone +// Parsing function and template definitions // Parsing the declaration of the main component pub ParseAst : AST = { - - => AST::new(Meta::new(s,e), Option::Some(pragma), includes,definitions,Option::Some(main)), - - - => AST::new(Meta::new(s,e),Option::None, includes,definitions,Option::Some(main)), - - - => AST::new(Meta::new(s,e), Option::Some(pragma), includes,definitions,Option::None), - - - => AST::new(Meta::new(s,e), Option::None,includes,definitions,Option::None), + + => AST::new(Meta::new(s,e), version, custom_gates.is_some(), includes, definitions, main), }; // ==================================================================== @@ -84,9 +80,16 @@ pub ParseDefinition : Definition = { "template" "(" ")" => match arg_names { None - => build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some()), + => build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some(), false), Some(a) - => build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some()), + => build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), false), + }, + "custom_gate" "(" ")" + => match arg_names { + None + => build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some(), true), + Some(a) + => build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), true), }, }; @@ -193,6 +196,13 @@ ParseDeclaration : Statement = { symbols.push(symbol); ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignVar) }, + "custom_component" ",")*> => { + let mut symbols = symbols; + let meta = Meta::new(s,e); + let xtype = VariableType::Component; + symbols.push(symbol); + ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignVar) + }, ",")*> => { let mut symbols = symbols; From 87a5152b64210ef33f3f43c2a9c7eb8e13bec910 Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Wed, 1 Jun 2022 12:24:43 +0200 Subject: [PATCH 03/10] first version --- circom/src/input_user.rs | 8 +- circom/src/main.rs | 8 +- .../component_representation.rs | 11 +- constraint_generation/src/execute.rs | 117 +++++++++-- .../src/execution_data/executed_template.rs | 71 ++++++- .../src/execution_data/type_definitions.rs | 3 +- .../src/constraint_simplification.rs | 18 +- constraint_writers/src/r1cs_writer.rs | 198 ++++++++++++++++-- dag/src/lib.rs | 117 +++++++++-- dag/src/r1cs_porting.rs | 59 +++++- parser/src/lib.rs | 3 +- .../src/abstract_syntax_tree/ast.rs | 7 +- .../src/program_library/program_merger.rs | 3 +- .../src/program_library/template_data.rs | 6 + 14 files changed, 542 insertions(+), 87 deletions(-) diff --git a/circom/src/input_user.rs b/circom/src/input_user.rs index 205729e..64782db 100644 --- a/circom/src/input_user.rs +++ b/circom/src/input_user.rs @@ -58,10 +58,10 @@ impl Input { out_r1cs: Input::build_output(&output_path, &file_name, R1CS), out_wat_code: Input::build_output(&output_js_path, &file_name, WAT), out_wasm_code: Input::build_output(&output_js_path, &file_name, WASM), - out_js_folder: output_js_path.clone(), - out_wasm_name: file_name.clone(), - out_c_folder: output_c_path.clone(), - out_c_run_name: file_name.clone(), + out_js_folder: output_js_path.clone(), + out_wasm_name: file_name.clone(), + out_c_folder: output_c_path.clone(), + out_c_run_name: file_name.clone(), out_c_code: Input::build_output(&output_c_path, &file_name, CPP), out_c_dat: Input::build_output(&output_c_path, &file_name, DAT), out_sym: Input::build_output(&output_path, &file_name, SYM), diff --git a/circom/src/main.rs b/circom/src/main.rs index 115c6a5..acb1a85 100644 --- a/circom/src/main.rs +++ b/circom/src/main.rs @@ -47,10 +47,10 @@ fn start() -> Result<(), ()> { c_flag: user_input.c_flag(), wasm_flag: user_input.wasm_flag(), wat_flag: user_input.wat_flag(), - js_folder: user_input.js_folder().to_string(), - wasm_name: user_input.wasm_name().to_string(), - c_folder: user_input.c_folder().to_string(), - c_run_name: user_input.c_run_name().to_string(), + js_folder: user_input.js_folder().to_string(), + wasm_name: user_input.wasm_name().to_string(), + c_folder: user_input.c_folder().to_string(), + c_run_name: user_input.c_run_name().to_string(), c_file: user_input.c_file().to_string(), dat_file: user_input.dat_file().to_string(), wat_file: user_input.wat_file().to_string(), diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index a769f99..733cbd3 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -8,6 +8,7 @@ pub struct ComponentRepresentation { unassigned_inputs: HashMap, inputs: HashMap, outputs: HashMap, + pub is_custom_gate: bool, } impl Default for ComponentRepresentation { @@ -17,6 +18,7 @@ impl Default for ComponentRepresentation { unassigned_inputs: HashMap::new(), inputs: HashMap::new(), outputs: HashMap::new(), + is_custom_gate: false, } } } @@ -27,6 +29,7 @@ impl Clone for ComponentRepresentation { unassigned_inputs: self.unassigned_inputs.clone(), inputs: self.inputs.clone(), outputs: self.outputs.clone(), + is_custom_gate: self.is_custom_gate, } } } @@ -49,9 +52,8 @@ impl ComponentRepresentation { for (symbol, route) in node.inputs() { let signal_slice = SignalSlice::new_with_route(route, &false); let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); - if signal_slice_size > 0{ - unassigned_inputs - .insert(symbol.clone(), signal_slice_size); + if signal_slice_size > 0 { + unassigned_inputs.insert(symbol.clone(), signal_slice_size); } inputs.insert(symbol.clone(), signal_slice); } @@ -65,9 +67,11 @@ impl ComponentRepresentation { unassigned_inputs, inputs, outputs, + is_custom_gate: node.is_custom_gate, }; Result::Ok(()) } + pub fn signal_has_value( component: &ComponentRepresentation, signal_name: &str, @@ -88,6 +92,7 @@ impl ComponentRepresentation { let enabled = *SignalSlice::get_reference_to_single_value(slice, access)?; Result::Ok(enabled) } + pub fn get_signal(&self, signal_name: &str) -> Result<&SignalSlice, MemoryError> { if self.node_pointer.is_none() { return Result::Err(MemoryError::InvalidAccess); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 82d4475..0e74611 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -16,7 +16,6 @@ use super::{ UsefulConstants, }; use circom_algebra::num_bigint::BigInt; -use std::collections::HashMap; type AExpr = ArithmeticExpressionGen; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] @@ -55,6 +54,7 @@ impl RuntimeInformation { struct FoldedValue { pub arithmetic_slice: Option, pub node_pointer: Option, + pub custom_gate_name: Option, } impl FoldedValue { pub fn valid_arithmetic_slice(f_value: &FoldedValue) -> bool { @@ -67,7 +67,11 @@ impl FoldedValue { impl Default for FoldedValue { fn default() -> Self { - FoldedValue { arithmetic_slice: Option::None, node_pointer: Option::None } + FoldedValue { + arithmetic_slice: Option::None, + node_pointer: Option::None, + custom_gate_name: Option::None + } } } @@ -187,10 +191,22 @@ fn execute_statement( Option::None } Substitution { meta, var, access, op, rhe, .. } => { - let access_information = treat_accessing(meta, access, program_archive, runtime, flag_verbose)?; + let access_information = treat_accessing( + meta, + access, + program_archive, + runtime, + flag_verbose + )?; let r_folded = execute_expression(rhe, program_archive, runtime, flag_verbose)?; - let possible_constraint = - perform_assign(meta, var, &access_information, r_folded, actual_node, runtime)?; + let possible_constraint = perform_assign( + meta, + var, + &access_information, + r_folded, + actual_node, + runtime + )?; if let (Option::Some(node), AssignOp::AssignConstraintSignal) = (actual_node, op) { debug_assert!(possible_constraint.is_some()); let constrained = possible_constraint.unwrap(); @@ -207,7 +223,40 @@ fn execute_statement( let symbol = AExpr::Signal { symbol: constrained.left }; let expr = AExpr::sub(&symbol, &constrained.right, &p); let ctr = AExpr::transform_expression_to_constraint_form(expr, &p).unwrap(); - node.add_constraint(ctr); + if constrained.custom_gate_name.is_none() { + node.add_constraint(ctr); + } else { + // From a previous semantic analysis we know that in this case we must + // have that constrained.right is an AExpr::Signal, so we can safely unwrap + // the name of the signal in the right hand side of the expression. + debug_assert!(matches!(symbol, AExpr::Signal {..})); + debug_assert!(matches!(constrained.right, AExpr::Signal {..})); + if let AExpr::Signal { symbol: left } = symbol { + if let AExpr::Signal { symbol: right } = constrained.right { + let custom_gate_name = constrained.custom_gate_name.unwrap(); + fn reorder( + left: String, + right: String, + custom_gate_name: &String + ) -> (String, String) { + if left.starts_with(custom_gate_name) { + (left, right) + } else { + debug_assert!(right.starts_with(custom_gate_name)); + (right, left) + } + } + + // Assignment of the form left <== right + let (inner, outer) = reorder(left, right, &custom_gate_name); + node.treat_custom_gate_constraint(custom_gate_name, inner, outer); + } else { + unreachable!(); + } + } else { + unreachable!(); + } + } } } Option::None @@ -484,6 +533,7 @@ fn execute_signal_declaration( ) { use SignalType::*; if let Option::Some(node) = actual_node { + node.add_ordered_signal(signal_name, dimensions); match signal_type { Input => { environment_shortcut_add_input(environment, signal_name, dimensions); @@ -510,6 +560,7 @@ fn execute_signal_declaration( struct Constrained { left: String, right: AExpr, + custom_gate_name: Option, } fn perform_assign( meta: &Meta, @@ -522,9 +573,8 @@ fn perform_assign( use super::execution_data::type_definitions::SubComponentData; let environment = &mut runtime.environment; let full_symbol = create_symbol(symbol, &accessing_information); - - let possible_arithmetic_expression = if ExecutionEnvironment::has_variable(environment, symbol) - { + let possible_custom_gate_name = r_folded.custom_gate_name.clone(); + let possible_arithmetic_expression = if ExecutionEnvironment::has_variable(environment, symbol) { // review! debug_assert!(accessing_information.signal_access.is_none()); debug_assert!(accessing_information.after_signal.is_empty()); let environment_result = ExecutionEnvironment::get_mut_variable_mut(environment, symbol); @@ -601,7 +651,7 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - Option::Some(safe_unwrap_to_single_arithmetic_expression(r_folded, line!())) + Option::Some((safe_unwrap_to_single_arithmetic_expression(r_folded, line!()), None)) } else if ExecutionEnvironment::has_component(environment, symbol) { let environment_response = ExecutionEnvironment::get_mut_component_res(environment, symbol); let component_slice = treat_result_with_environment_error( @@ -661,14 +711,28 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - Option::Some(AExpressionSlice::unwrap_to_single(arithmetic_slice)) + let custom_gate = if component.is_custom_gate { Some(symbol.to_string()) } else { None }; + Option::Some((AExpressionSlice::unwrap_to_single(arithmetic_slice), custom_gate)) } } else { unreachable!(); }; - if let Option::Some(arithmetic_expression) = possible_arithmetic_expression { - let ret = Constrained { left: full_symbol, right: arithmetic_expression }; - Result::Ok(Some(ret)) + if let Option::Some((arithmetic_expression, custom_gate_name)) = possible_arithmetic_expression { + if custom_gate_name.is_none() { + let ret = Constrained { + left: full_symbol, + right: arithmetic_expression, + custom_gate_name: possible_custom_gate_name, + }; + Result::Ok(Some(ret)) + } else { + let ret = Constrained { + left: full_symbol, + right: arithmetic_expression, + custom_gate_name + }; + Result::Ok(Some(ret)) + } } else { Result::Ok(None) } @@ -905,6 +969,11 @@ fn execute_component( &mut runtime.runtime_errors, &runtime.call_trace, )?; + let custom_gate_name = if checked_component.is_custom_gate { + Some(symbol.to_string()) + } else { + None + }; if let Option::Some(signal_name) = &access_information.signal_access { let access_after_signal = &access_information.after_signal; let signal = treat_result_with_memory_error( @@ -921,8 +990,13 @@ fn execute_component( &runtime.call_trace, )?; let symbol = create_symbol(symbol, &access_information); - let result = signal_to_arith(symbol, slice) - .map(|s| FoldedValue { arithmetic_slice: Option::Some(s), ..FoldedValue::default() }); + let result = signal_to_arith(symbol, slice).map(|s| + FoldedValue { + arithmetic_slice: Option::Some(s), + custom_gate_name, + ..FoldedValue::default() + } + ); treat_result_with_memory_error( result, meta, @@ -932,6 +1006,7 @@ fn execute_component( } else { Result::Ok(FoldedValue { node_pointer: checked_component.node_pointer, + custom_gate_name, ..FoldedValue::default() }) } @@ -984,14 +1059,15 @@ fn execute_template_call( debug_assert!(runtime.block_type == BlockType::Known); let is_main = std::mem::replace(&mut runtime.public_inputs, vec![]); let is_parallel = program_archive.get_template_data(id).is_parallel(); + let is_custom_gate = program_archive.get_template_data(id).is_custom_gate(); let args_names = program_archive.get_template_data(id).get_name_of_params(); - let template_body = program_archive.get_template_data(id).get_body_as_vec(); - let mut args_to_values = HashMap::new(); debug_assert_eq!(args_names.len(), parameter_values.len()); + let template_body = program_archive.get_template_data(id).get_body_as_vec(); + let mut args_to_values = vec![]; let mut instantiation_name = format!("{}(", id); for (name, value) in args_names.iter().zip(parameter_values) { instantiation_name.push_str(&format!("{},", value.to_string())); - args_to_values.insert(name.clone(), value.clone()); + args_to_values.push((name.clone(), value.clone())); } if !parameter_values.is_empty() { instantiation_name.pop(); @@ -1010,7 +1086,8 @@ fn execute_template_call( instantiation_name, args_to_values, code, - is_parallel + is_parallel, + is_custom_gate, )); let ret = execute_sequence_of_statements( template_body, diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 8299093..3cd36d0 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -21,7 +21,9 @@ pub struct ExecutedTemplate { pub report_name: String, pub inputs: SignalCollector, pub outputs: SignalCollector, + pub ordered_signals: Vec, pub constraints: Vec, + pub custom_gate_constraints: HashMap>, pub intermediates: SignalCollector, pub components: ComponentCollector, pub number_of_components: usize, @@ -29,6 +31,7 @@ pub struct ExecutedTemplate { pub parameter_instances: ParameterContext, pub is_parallel: bool, pub has_parallel_sub_cmp: bool, + pub is_custom_gate: bool, connexions: Vec, } @@ -40,6 +43,7 @@ impl ExecutedTemplate { instance: ParameterContext, code: Statement, is_parallel: bool, + is_custom_gate: bool, ) -> ExecutedTemplate { let public_inputs: HashSet<_> = public.iter().cloned().collect(); ExecutedTemplate { @@ -47,15 +51,18 @@ impl ExecutedTemplate { public_inputs, is_parallel, has_parallel_sub_cmp: false, + is_custom_gate, code: code.clone(), template_name: name, parameter_instances: instance, inputs: SignalCollector::new(), outputs: SignalCollector::new(), intermediates: SignalCollector::new(), + ordered_signals: Vec::new(), components: ComponentCollector::new(), number_of_components: 0, constraints: Vec::new(), + custom_gate_constraints: HashMap::new(), connexions: Vec::new(), } } @@ -82,6 +89,27 @@ impl ExecutedTemplate { self.intermediates.push((intermediate_name.to_string(), dimensions.to_vec())); } + pub fn add_ordered_signal(&mut self, signal_name: &str, dimensions: &[usize]) { + fn generate_symbols(name: String, current: usize, dimensions: &[usize]) -> Vec { + let symbol_name = name.clone(); + if current == dimensions.len() { + vec![name] + } else { + let mut generated_symbols = vec![]; + let mut index = 0; + while index < dimensions[current] { + let new_name = format!("{}[{}]", symbol_name, index); + generated_symbols.append(&mut generate_symbols(new_name, current + 1, dimensions)); + index += 1; + } + generated_symbols + } + } + for signal in generate_symbols(signal_name.to_string(), 0, dimensions) { + self.ordered_signals.push(signal); + } + } + pub fn add_component(&mut self, component_name: &str, dimensions: &[usize]) { self.components.push((component_name.to_string(), dimensions.to_vec())); self.number_of_components += dimensions.iter().fold(1, |p, c| p * (*c)); @@ -91,6 +119,10 @@ impl ExecutedTemplate { self.constraints.push(constraint); } + pub fn treat_custom_gate_constraint(&mut self, custom_gate: String, left: String, right: String) { + self.custom_gate_constraints.entry(custom_gate).or_insert(HashMap::new()).insert(left, right); + } + pub fn template_name(&self) -> &String { &self.template_name } @@ -112,10 +144,27 @@ impl ExecutedTemplate { } pub fn insert_in_dag(&mut self, dag: &mut DAG) { - dag.add_node(self.report_name.clone(), self.is_parallel); + let parameter_instances = { + let mut parameters = vec![]; + for (_, data) in self.parameter_instances.clone() { + let (_, values) = data.destruct(); + for value in as_big_int(values) { + parameters.push(value); + } + } + parameters + }; + dag.add_node( + self.report_name.clone(), + parameter_instances, + self.ordered_signals.clone(), + self.is_parallel, + self.is_custom_gate + ); self.build_signals(dag); self.build_connexions(dag); self.build_constraints(dag); + self.build_custom_gates_constraints(dag); } fn build_signals(&self, dag: &mut DAG) { @@ -144,6 +193,7 @@ impl ExecutedTemplate { generate_symbols(dag, state, &config); } } + fn build_connexions(&mut self, dag: &mut DAG) { self.connexions.sort_by(|l, r| { use std::cmp::Ordering; @@ -168,6 +218,7 @@ impl ExecutedTemplate { self.has_parallel_sub_cmp = dag.nodes[dag.main_id()].has_parallel_sub_cmp(); dag.set_number_of_subcomponents_indexes(self.number_of_components); } + fn build_constraints(&self, dag: &mut DAG) { for c in &self.constraints { let correspondence = dag.get_main().unwrap().correspondence(); @@ -175,6 +226,24 @@ impl ExecutedTemplate { dag.add_constraint(cc); } } + + fn build_custom_gates_constraints(&self, dag: &mut DAG) { + for cnn in &self.connexions { + let constraint = if let Some(custom_gate_constraints) = self.custom_gate_constraints.get(&cnn.full_name) { + let mut signal_correspondence = vec![]; + for signal in dag.nodes[cnn.inspect.goes_to].ordered_signals() { + let signal_name = format!("{}.{}", cnn.full_name, signal); + let correspondence = custom_gate_constraints.get(&signal_name).unwrap(); + signal_correspondence.push(*dag.nodes[dag.main_id()].correspondence().get(correspondence).unwrap()); + } + Some(signal_correspondence) + } else { + None + }; + dag.add_custom_gate_constraint(constraint); + } + } + pub fn export_to_circuit(self, instances: &[TemplateInstance]) -> TemplateInstance { use SignalType::*; fn build_triggers( diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index e337206..04b4e87 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -1,10 +1,9 @@ use super::AExpressionSlice; use super::Constraint as ConstraintGen; -use std::collections::HashMap; pub type NodePointer = usize; pub type Constraint = ConstraintGen; -pub type ParameterContext = HashMap; +pub type ParameterContext = Vec<(String, AExpressionSlice)>; pub type SignalCollector = Vec<(String, Vec)>; pub type ComponentCollector = Vec<(String, Vec)>; pub struct SubComponentData { diff --git a/constraint_list/src/constraint_simplification.rs b/constraint_list/src/constraint_simplification.rs index 3b4c5c6..2e0b4e5 100644 --- a/constraint_list/src/constraint_simplification.rs +++ b/constraint_list/src/constraint_simplification.rs @@ -517,7 +517,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { relevant }; - let linear_substitutions = if apply_linear { + let linear_substitutions = if remove_unused { let now = SystemTime::now(); let (subs, mut cons) = linear_simplification( &mut substitution_log, @@ -563,7 +563,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { crate::state_utils::empty_encoding_constraints(&mut smp.dag_encoding); let _dur = now.elapsed().unwrap().as_millis(); // println!("Storages built in {} ms", dur); - no_rounds -= 1; + if remove_unused { no_rounds -= 1; } (with_linear, storage) }; @@ -571,7 +571,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { let _ = round_id; let mut linear = with_linear; let mut apply_round = apply_linear && no_rounds > 0 && !linear.is_empty(); - let mut non_linear_map = if apply_round || remove_unused{ + let mut non_linear_map = if apply_round || remove_unused { // println!("Building non-linear map"); let now = SystemTime::now(); let non_linear_map = build_non_linear_signal_map(&constraint_storage); @@ -615,7 +615,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { } for constraint in linear { - if remove_unused{ + if remove_unused { let signals = C::take_cloned_signals(&constraint); let c_id = constraint_storage.add_constraint(constraint); for signal in signals { @@ -627,14 +627,13 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { non_linear_map.insert(signal, new); } } - } - else{ + } else { constraint_storage.add_constraint(constraint); } } for constraint in lconst { - if remove_unused{ - let signals = C::take_cloned_signals(&constraint); + if remove_unused { + let signals = C::take_cloned_signals(&constraint); let c_id = constraint_storage.add_constraint(constraint); for signal in signals { if let Some(list) = non_linear_map.get_mut(&signal) { @@ -645,8 +644,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { non_linear_map.insert(signal, new); } } - } - else{ + } else { constraint_storage.add_constraint(constraint); } } diff --git a/constraint_writers/src/r1cs_writer.rs b/constraint_writers/src/r1cs_writer.rs index c3c2c5e..54a7026 100644 --- a/constraint_writers/src/r1cs_writer.rs +++ b/constraint_writers/src/r1cs_writer.rs @@ -3,12 +3,15 @@ use std::collections::HashMap; use std::fs::File; use std::io::{BufWriter, Seek, SeekFrom, Write}; +const SECTIONS: u8 = 5; const MAGIC: &[u8] = b"r1cs"; const VERSION: &[u8] = &[1, 0, 0, 0]; -const NUMBER_OF_SECTIONS: &[u8] = &[3, 0, 0, 0]; +const NUMBER_OF_SECTIONS: &[u8] = &[SECTIONS, 0, 0, 0]; const HEADER_TYPE: &[u8] = &[1, 0, 0, 0]; const CONSTRAINT_TYPE: &[u8] = &[2, 0, 0, 0]; const WIRE2LABEL_TYPE: &[u8] = &[3, 0, 0, 0]; +const CUSTOM_GATES_USED_TYPE: &[u8] = &[4, 0, 0, 0]; +const CUSTOM_GATES_APPLIED_TYPE: &[u8] = &[5, 0, 0, 0]; const PLACE_HOLDER: &[u8] = &[3, 3, 3, 3, 3, 3, 3, 3]; fn into_format(number: &[u8], with_bytes: usize) -> (Vec, usize) { @@ -33,6 +36,7 @@ fn initialize_section(writer: &mut BufWriter, header: &[u8]) -> Result, go_back: u64, size: usize) -> Result<(), ()> { let go_back_1 = writer.seek(SeekFrom::Current(0)).map_err(|_err| {})?; writer.seek(SeekFrom::Start(go_back)).map_err(|_err| {})?; @@ -45,10 +49,7 @@ fn end_section(writer: &mut BufWriter, go_back: u64, size: usize) -> Resul fn obtain_linear_combination_block( linear_combination: &HashMap, field_size: usize, -) -> (Vec, usize) -where - T: AsRef<[u8]> + std::cmp::Ord + std::hash::Hash, -{ +) -> (Vec, usize) where T: AsRef<[u8]> + std::cmp::Ord + std::hash::Hash { let mut block = Vec::new(); let non_zero_factors = BigInt::from(linear_combination.len()); let mut size = 0; @@ -76,10 +77,7 @@ fn write_constraint( b: &HashMap, c: &HashMap, field_size: usize, -) -> Result -where - T: AsRef<[u8]> + std::cmp::Ord + std::hash::Hash, -{ +) -> Result where T: AsRef<[u8]> + std::cmp::Ord + std::hash::Hash { let (block_a, size_a) = obtain_linear_combination_block(a, field_size); let (block_b, size_b) = obtain_linear_combination_block(b, field_size); let (block_c, size_c) = obtain_linear_combination_block(c, field_size); @@ -105,16 +103,18 @@ fn initialize_file(writer: &mut BufWriter) -> Result<(), ()> { pub struct R1CSWriter { field_size: usize, writer: BufWriter, - sections: [bool; 3], + sections: [bool; SECTIONS as usize] } + pub struct HeaderSection { writer: BufWriter, go_back: u64, size: usize, index: usize, field_size: usize, - sections: [bool; 3], + sections: [bool; SECTIONS as usize] } + pub struct ConstraintSection { writer: BufWriter, number_of_constraints: usize, @@ -122,25 +122,45 @@ pub struct ConstraintSection { size: usize, index: usize, field_size: usize, - sections: [bool; 3], + sections: [bool; SECTIONS as usize] } + pub struct SignalSection { writer: BufWriter, go_back: u64, size: usize, index: usize, field_size: usize, - sections: [bool; 3], + sections: [bool; SECTIONS as usize] +} + +pub struct CustomGatesUsedSection { + writer: BufWriter, + go_back: u64, + size: usize, + index: usize, + field_size: usize, + sections: [bool; SECTIONS as usize] +} + +pub struct CustomGatesAppliedSection { + writer: BufWriter, + go_back: u64, + size: usize, + index: usize, + field_size: usize, + sections: [bool; SECTIONS as usize] } impl R1CSWriter { pub fn new(output_file: String, field_size: usize) -> Result { - let sections = [false; 3]; + let sections = [false; SECTIONS as usize]; let mut writer = File::create(&output_file).map_err(|_err| {}).map(|f| BufWriter::new(f))?; initialize_file(&mut writer)?; Result::Ok(R1CSWriter { writer, sections, field_size }) } + pub fn start_header_section(mut r1cs: R1CSWriter) -> Result { let start = initialize_section(&mut r1cs.writer, HEADER_TYPE)?; Result::Ok(HeaderSection { @@ -152,6 +172,7 @@ impl R1CSWriter { sections: r1cs.sections, }) } + pub fn start_constraints_section(mut r1cs: R1CSWriter) -> Result { let start = initialize_section(&mut r1cs.writer, CONSTRAINT_TYPE)?; Result::Ok(ConstraintSection { @@ -164,6 +185,7 @@ impl R1CSWriter { sections: r1cs.sections, }) } + pub fn start_signal_section(mut r1cs: R1CSWriter) -> Result { let start = initialize_section(&mut r1cs.writer, WIRE2LABEL_TYPE)?; Result::Ok(SignalSection { @@ -175,6 +197,30 @@ impl R1CSWriter { sections: r1cs.sections, }) } + + pub fn start_custom_gates_used_section(mut r1cs: R1CSWriter) -> Result { + let start = initialize_section(&mut r1cs.writer, CUSTOM_GATES_USED_TYPE)?; + Result::Ok(CustomGatesUsedSection { + writer: r1cs.writer, + go_back: start, + size: 0, + index: 3, + field_size: r1cs.field_size, + sections: r1cs.sections + }) + } + + pub fn start_custom_gates_applied_section(mut r1cs: R1CSWriter) -> Result { + let start = initialize_section(&mut r1cs.writer, CUSTOM_GATES_APPLIED_TYPE)?; + Result::Ok(CustomGatesAppliedSection { + writer: r1cs.writer, + go_back: start, + size: 0, + index: 4, + field_size: r1cs.field_size, + sections: r1cs.sections + }) + } } pub struct HeaderData { @@ -186,6 +232,7 @@ pub struct HeaderData { pub number_of_labels: usize, pub number_of_constraints: usize, } + impl HeaderSection { pub fn write_section(&mut self, data: HeaderData) -> Result<(), ()> { let (field_stream, bytes_field) = bigint_as_bytes(&data.field, self.field_size); @@ -250,12 +297,17 @@ impl ConstraintSection { self.number_of_constraints += 1; Result::Ok(()) } + pub fn end_section(mut self) -> Result { end_section(&mut self.writer, self.go_back, self.size)?; let mut sections = self.sections; let index = self.index; sections[index] = true; - Result::Ok(R1CSWriter { writer: self.writer, field_size: self.field_size, sections }) + Result::Ok(R1CSWriter { + writer: self.writer, + field_size: self.field_size, + sections + }) } pub fn constraints_written(&self) -> usize { @@ -264,24 +316,130 @@ impl ConstraintSection { } impl SignalSection { - pub fn write_signal(&mut self, bytes: &T) -> Result<(), ()> - where - T: AsRef<[u8]>, - { + pub fn write_signal( + &mut self, + bytes: &T + ) -> Result<(), ()> where T: AsRef<[u8]> { let (bytes, size) = into_format(bytes.as_ref(), 8); self.size += size; self.writer.write_all(&bytes).map_err(|_err| {})?; self.writer.flush().map_err(|_err| {}) } + pub fn write_signal_usize(&mut self, signal: usize) -> Result<(), ()> { let (_, as_bytes) = BigInt::from(signal).to_bytes_le(); SignalSection::write_signal(self, &as_bytes) } + pub fn end_section(mut self) -> Result { end_section(&mut self.writer, self.go_back, self.size)?; let mut sections = self.sections; let index = self.index; sections[index] = true; - Result::Ok(R1CSWriter { writer: self.writer, field_size: self.field_size, sections }) + Result::Ok(R1CSWriter { + writer: self.writer, + field_size: self.field_size, + sections + }) } } + +pub type CustomGatesUsedData = Vec<(String, Vec)>; +impl CustomGatesUsedSection { + pub fn write_custom_gates_usages(&mut self, data: CustomGatesUsedData) -> Result<(), ()> { + let no_custom_gates = data.len(); + let (no_custom_gates_stream, no_custom_gates_size) = + bigint_as_bytes(&BigInt::from(no_custom_gates), 4); + self.size += no_custom_gates_size; + self.writer.write_all(&no_custom_gates_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + + for custom_gate in data { + let custom_gate_name = custom_gate.0; + let custom_gate_name_stream = custom_gate_name.as_bytes(); + self.size += custom_gate_name_stream.len() + 1; + self.writer.write_all(custom_gate_name_stream).map_err(|_err| {})?; + self.writer.write_all(&[0]).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + + let custom_gate_parameters = custom_gate.1; + let no_custom_gate_parameters = custom_gate_parameters.len(); + let (no_custom_gate_parameters_stream, no_custom_gate_parameters_size) = + bigint_as_bytes(&BigInt::from(no_custom_gate_parameters), 4); + self.size += no_custom_gate_parameters_size; + self.writer.write_all(&no_custom_gate_parameters_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + + for parameter in custom_gate_parameters { + let (parameter_stream, parameter_size) = bigint_as_bytes(¶meter, 32); + self.size += parameter_size; + self.writer.write(¶meter_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + } + } + + Result::Ok(()) + } + + pub fn end_section(mut self) -> Result { + end_section(&mut self.writer, self.go_back, self.size)?; + let mut sections = self.sections; + let index = self.index; + sections[index] = true; + Result::Ok(R1CSWriter { + writer: self.writer, + field_size: self.field_size, + sections + }) + } +} + +pub type CustomGatesAppliedData = Vec<(usize, Vec)>; +impl CustomGatesAppliedSection { + pub fn write_custom_gates_applications(&mut self, data: CustomGatesAppliedData) -> Result<(), ()> { + let no_custom_gate_applications = data.len(); + let (no_custom_gate_applications_stream, no_custom_gate_applications_size) = + bigint_as_bytes(&BigInt::from(no_custom_gate_applications), 4); + self.size += no_custom_gate_applications_size; + self.writer.write_all(&no_custom_gate_applications_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + + for custom_gate_application in data { + let custom_gate_index = custom_gate_application.0; + let (custom_gate_index_stream, custom_gate_index_size) = + bigint_as_bytes(&BigInt::from(custom_gate_index), 4); + self.size += custom_gate_index_size; + self.writer.write_all(&custom_gate_index_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + + let custom_gate_signals = custom_gate_application.1; + let no_custom_gate_signals = custom_gate_signals.len(); + let (no_custom_gate_signals_stream, no_custom_gate_signals_size) = + bigint_as_bytes(&BigInt::from(no_custom_gate_signals), 4); + self.size += no_custom_gate_signals_size; + self.writer.write_all(&no_custom_gate_signals_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + + for signal in custom_gate_signals { + let (signal_stream, signal_size) = bigint_as_bytes(&BigInt::from(signal), 4); + self.size += signal_size; + self.writer.write(&signal_stream).map_err(|_err| {})?; + self.writer.flush().map_err(|_err| {})?; + } + } + + Result::Ok(()) + } + + pub fn end_section(mut self) -> Result { + end_section(&mut self.writer, self.go_back, self.size)?; + let mut sections = self.sections; + let index = self.index; + sections[index] = true; + Result::Ok(R1CSWriter { + writer: self.writer, + field_size: self.field_size, + sections + }) + } +} \ No newline at end of file diff --git a/dag/src/lib.rs b/dag/src/lib.rs index a04becd..e2451b5 100644 --- a/dag/src/lib.rs +++ b/dag/src/lib.rs @@ -29,6 +29,7 @@ pub struct Tree<'a> { pub forbidden: HashSet, pub id_to_name: HashMap, pub constraints: Vec, + pub custom_gates_constraints: Vec>>, } impl<'a> Tree<'a> { @@ -40,6 +41,7 @@ impl<'a> Tree<'a> { let offset = dag.get_entry().unwrap().in_number; let path = dag.get_entry().unwrap().label.clone(); let constraints = root.constraints.clone(); + let custom_gates_constraints = root.custom_gates_constraints.clone(); let mut id_to_name = HashMap::new(); let mut signals: Vec<_> = Vec::new(); let forbidden: HashSet<_> = @@ -51,7 +53,18 @@ impl<'a> Tree<'a> { } } signals.sort(); - Tree { field, dag, path, offset, node_id, signals, forbidden, id_to_name, constraints } + Tree { + field, + dag, + path, + offset, + node_id, + signals, + forbidden, + id_to_name, + constraints, + custom_gates_constraints, + } } pub fn go_to_subtree(current: &'a Tree, edge: &Edge) -> Tree<'a> { @@ -72,13 +85,29 @@ impl<'a> Tree<'a> { } } signals.sort(); - let constraints: Vec<_> = node - .constraints - .iter() - .filter(|c| !c.is_empty()) - .map(|c| Constraint::apply_offset(c, offset)) - .collect(); - Tree { field, dag, path, offset, node_id, signals, forbidden, id_to_name, constraints } + let constraints = node.constraints.iter().filter(|c| !c.is_empty()).map(|c| + Constraint::apply_offset(c, offset) + ).collect(); + let custom_gates_constraints = node.custom_gates_constraints.iter().map(|component| { + if let Some(custom_gate) = component { + Some(custom_gate.iter().map(|s| *s + offset).collect()) + } else { + None + } + }).collect::>>>(); + + Tree { + field, + dag, + path, + offset, + node_id, + signals, + forbidden, + id_to_name, + constraints, + custom_gates_constraints, + } } pub fn get_edges(tree: &'a Tree) -> &'a Vec { @@ -137,6 +166,7 @@ impl Edge { pub struct Node { entry: Edge, template_name: String, + parameter_instances: Vec, number_of_signals: usize, number_of_components: usize, intermediates_length: usize, @@ -144,24 +174,39 @@ pub struct Node { inputs_length: usize, outputs_length: usize, signal_correspondence: HashMap, + ordered_signals: Vec, locals: HashSet, forbidden_if_main: HashSet, io_signals: Vec, constraints: Vec, + custom_gates_constraints: Vec>>, is_parallel: bool, has_parallel_sub_cmp: bool, + is_custom_gate: bool, number_of_subcomponents_indexes: usize, } impl Node { - fn new(id: usize, template_name: String, is_parallel:bool) -> Node { - Node { - template_name, entry: Edge::new_entry(id), - number_of_components: 1, - is_parallel, - has_parallel_sub_cmp: false, + fn new( + id: usize, + template_name: String, + parameter_instances: Vec, + ordered_signals: Vec, + is_parallel: bool, + is_custom_gate: bool, + ) -> Node { + Node { + entry: Edge::new_entry(id), + template_name, + parameter_instances, + number_of_components: 1, + ordered_signals, + is_parallel, + has_parallel_sub_cmp: false, + is_custom_gate, forbidden_if_main: vec![0].into_iter().collect(), - ..Node::default() } + ..Node::default() + } } fn add_input(&mut self, name: String, is_public: bool) { @@ -202,6 +247,10 @@ impl Node { self.constraints.push(constraint) } + fn add_custom_gate_constraint(&mut self, custom_gate_constraint: Option>) { + self.custom_gates_constraints.push(custom_gate_constraint) + } + fn set_number_of_subcomponents_indexes(&mut self, number_scmp: usize) { self.number_of_subcomponents_indexes = number_scmp } @@ -210,6 +259,10 @@ impl Node { self.locals.contains(&s) } + pub fn parameter_instances(&self) -> &Vec { + &self.parameter_instances + } + pub fn number_of_signals(&self) -> usize { self.number_of_signals } @@ -218,6 +271,10 @@ impl Node { &self.signal_correspondence } + pub fn ordered_signals(&self) -> &Vec { + &self.ordered_signals + } + pub fn constraints(&self) -> &[Constraint] { &self.constraints } @@ -254,6 +311,10 @@ impl Node { self.has_parallel_sub_cmp } + pub fn is_custom_gate(&self) -> bool { + self.is_custom_gate + } + pub fn number_of_subcomponents_indexes(&self) -> usize { self.number_of_subcomponents_indexes } @@ -324,9 +385,25 @@ impl DAG { } } - pub fn add_node(&mut self, template_name: String, is_parallel:bool) -> usize { + pub fn add_node( + &mut self, + template_name: String, + parameter_instances: Vec, + ordered_signals: Vec, + is_parallel: bool, + is_custom_gate: bool, + ) -> usize { let id = self.nodes.len(); - self.nodes.push(Node::new(id, template_name, is_parallel)); + self.nodes.push( + Node::new( + id, + template_name, + parameter_instances, + ordered_signals, + is_parallel, + is_custom_gate + ) + ); self.adjacency.push(vec![]); id } @@ -355,6 +432,12 @@ impl DAG { } } + pub fn add_custom_gate_constraint(&mut self, custom_gate_constraint: Option>) { + if let Option::Some(node) = self.get_mut_main() { + node.add_custom_gate_constraint(custom_gate_constraint); + } + } + pub fn set_number_of_subcomponents_indexes(&mut self, number_scmp: usize){ if let Option::Some(node) = self.get_mut_main() { node.set_number_of_subcomponents_indexes(number_scmp); diff --git a/dag/src/r1cs_porting.rs b/dag/src/r1cs_porting.rs index 18fc4c9..36055dc 100644 --- a/dag/src/r1cs_porting.rs +++ b/dag/src/r1cs_porting.rs @@ -1,6 +1,6 @@ use super::{Constraint, Tree, DAG}; use constraint_writers::log_writer::Log; -use constraint_writers::r1cs_writer::{ConstraintSection, HeaderData, R1CSWriter}; +use constraint_writers::r1cs_writer::{ConstraintSection, CustomGatesAppliedData, HeaderData, R1CSWriter}; pub fn write(dag: &DAG, output: &str) -> Result<(), ()> { let tree = Tree::new(dag); @@ -33,11 +33,66 @@ pub fn write(dag: &DAG, output: &str) -> Result<(), ()> { let mut header_section = R1CSWriter::start_header_section(r1cs)?; header_section.write_section(header_data)?; let r1cs = header_section.end_section()?; + let mut signal_section = R1CSWriter::start_signal_section(r1cs)?; for signal in 0..labels { signal_section.write_signal_usize(signal)?; } - let _r1cs = signal_section.end_section()?; + let r1cs = signal_section.end_section()?; + + let mut custom_gates_used_section = R1CSWriter::start_custom_gates_used_section(r1cs)?; + let usage_data = { + let mut usage_data_mut = vec![]; + for node in &dag.nodes { + if node.is_custom_gate() { + let mut name = node.template_name.clone(); + while name.pop() != Some('(') {}; + usage_data_mut.push((name, node.parameter_instances().clone())); + } + } + usage_data_mut + }; + custom_gates_used_section.write_custom_gates_usages(usage_data)?; + let r1cs = custom_gates_used_section.end_section()?; + + let mut custom_gates_applied_section = R1CSWriter::start_custom_gates_applied_section(r1cs)?; + let application_data = { + fn find_indexes(dag: &DAG, application_data: Vec<(String, Vec)>) -> CustomGatesAppliedData { + let mut application_data_mut = vec![]; + for (custom_gate_name, constraints) in application_data { + let mut index = 0; + while dag.nodes[index].template_name != custom_gate_name { + index += 1; + } + application_data_mut.push((index, constraints)); + } + application_data_mut + } + + fn traverse_tree(dag: &DAG, tree: &Tree, application_data: &mut Vec<(String, Vec)>) { + let mut index = 0; + for edge in Tree::get_edges(tree) { + let node = &dag.nodes[edge.get_goes_to()]; + let possible_custom_gate_constraints = tree.custom_gates_constraints[index].clone(); + if node.is_custom_gate() { + if let Some(constraints) = possible_custom_gate_constraints { + application_data.push((node.template_name.clone(), constraints)); + } else { + unreachable!(); + } + } else { + traverse_tree(dag, &Tree::go_to_subtree(tree, edge), application_data); + } + index += 1; + } + } + let mut application_data_mut = vec![]; + traverse_tree(dag, &tree, &mut application_data_mut); + find_indexes(dag, application_data_mut) + }; + custom_gates_applied_section.write_custom_gates_applications(application_data)?; + let _r1cs = custom_gates_applied_section.end_section(); + Log::print(&log); Result::Ok(()) } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 7671e51..ebb807c 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -52,8 +52,7 @@ pub fn run_parser(file: String, version: &str) -> Result<(ProgramArchive, Report } else if main_components.len() > 1 { let report = errors::MultipleMainError::produce_report(); Err((file_library, vec![report])) - } - else{ + } else { let (main_id, main_component) = main_components.pop().unwrap(); let result_program_archive = ProgramArchive::new(file_library, main_id, main_component, definitions); diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 3b95907..8dc67c4 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -80,6 +80,7 @@ impl Meta { pub struct AST { pub meta: Meta, pub compiler_version: Option, + pub custom_gates: bool, pub includes: Vec, pub definitions: Vec, pub main_component: Option, @@ -88,11 +89,12 @@ impl AST { pub fn new( meta: Meta, compiler_version: Option, + custom_gates: bool, includes: Vec, definitions: Vec, main_component: Option, ) -> AST { - AST { meta, compiler_version, includes, definitions, main_component } + AST { meta, compiler_version, custom_gates, includes, definitions, main_component } } } @@ -105,6 +107,7 @@ pub enum Definition { arg_location: FileLocation, body: Statement, parallel: bool, + is_custom_gate: bool, }, Function { meta: Meta, @@ -121,6 +124,7 @@ pub fn build_template( arg_location: FileLocation, body: Statement, parallel: bool, + is_custom_gate: bool, ) -> Definition { Definition::Template { meta, @@ -129,6 +133,7 @@ pub fn build_template( arg_location, body, parallel, + is_custom_gate, } } diff --git a/program_structure/src/program_library/program_merger.rs b/program_structure/src/program_library/program_merger.rs index dfa3810..7e44cac 100644 --- a/program_structure/src/program_library/program_merger.rs +++ b/program_structure/src/program_library/program_merger.rs @@ -29,7 +29,7 @@ impl Merger { let mut reports = vec![]; for definition in definitions { let (name, meta) = match definition { - Definition::Template { name, args, arg_location, body, meta, parallel } => { + Definition::Template { name, args, arg_location, body, meta, parallel, is_custom_gate } => { if self.contains_function(&name) || self.contains_template(&name) { (Option::Some(name), meta) } else { @@ -42,6 +42,7 @@ impl Merger { arg_location, &mut self.fresh_id, parallel, + is_custom_gate, ); self.get_mut_template_info().insert(name.clone(), new_data); (Option::None, meta) diff --git a/program_structure/src/program_library/template_data.rs b/program_structure/src/program_library/template_data.rs index bac3057..5ffd52c 100644 --- a/program_structure/src/program_library/template_data.rs +++ b/program_structure/src/program_library/template_data.rs @@ -18,6 +18,7 @@ pub struct TemplateData { input_signals: SignalInfo, output_signals: SignalInfo, is_parallel: bool, + is_custom_gate: bool, } impl TemplateData { @@ -30,6 +31,7 @@ impl TemplateData { param_location: FileLocation, elem_id: &mut usize, is_parallel: bool, + is_custom_gate: bool, ) -> TemplateData { body.fill(file_id, elem_id); let mut input_signals = SignalInfo::new(); @@ -45,6 +47,7 @@ impl TemplateData { input_signals, output_signals, is_parallel, + is_custom_gate, } } pub fn get_file_id(&self) -> FileID { @@ -95,6 +98,9 @@ impl TemplateData { pub fn is_parallel(&self) -> bool { self.is_parallel } + pub fn is_custom_gate(&self) -> bool { + self.is_custom_gate + } } fn fill_inputs_and_outputs( From 0413e9c88225759b03ce636f974782068f197a57 Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 07:20:03 +0200 Subject: [PATCH 04/10] solved bug regarding the application information of custom gates --- dag/src/r1cs_porting.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dag/src/r1cs_porting.rs b/dag/src/r1cs_porting.rs index 36055dc..6c15f5f 100644 --- a/dag/src/r1cs_porting.rs +++ b/dag/src/r1cs_porting.rs @@ -41,27 +41,29 @@ pub fn write(dag: &DAG, output: &str) -> Result<(), ()> { let r1cs = signal_section.end_section()?; let mut custom_gates_used_section = R1CSWriter::start_custom_gates_used_section(r1cs)?; - let usage_data = { - let mut usage_data_mut = vec![]; + let (usage_data, occurring_order) = { + let mut usage_data = vec![]; + let mut occurring_order = vec![]; for node in &dag.nodes { if node.is_custom_gate() { let mut name = node.template_name.clone(); + occurring_order.push(name.clone()); while name.pop() != Some('(') {}; - usage_data_mut.push((name, node.parameter_instances().clone())); + usage_data.push((name, node.parameter_instances().clone())); } } - usage_data_mut + (usage_data, occurring_order) }; custom_gates_used_section.write_custom_gates_usages(usage_data)?; let r1cs = custom_gates_used_section.end_section()?; let mut custom_gates_applied_section = R1CSWriter::start_custom_gates_applied_section(r1cs)?; let application_data = { - fn find_indexes(dag: &DAG, application_data: Vec<(String, Vec)>) -> CustomGatesAppliedData { + fn find_indexes(occurring_order: Vec, application_data: Vec<(String, Vec)>) -> CustomGatesAppliedData { let mut application_data_mut = vec![]; for (custom_gate_name, constraints) in application_data { let mut index = 0; - while dag.nodes[index].template_name != custom_gate_name { + while occurring_order[index] != custom_gate_name { index += 1; } application_data_mut.push((index, constraints)); @@ -86,9 +88,9 @@ pub fn write(dag: &DAG, output: &str) -> Result<(), ()> { index += 1; } } - let mut application_data_mut = vec![]; - traverse_tree(dag, &tree, &mut application_data_mut); - find_indexes(dag, application_data_mut) + let mut application_data = vec![]; + traverse_tree(dag, &tree, &mut application_data); + find_indexes(occurring_order, application_data) }; custom_gates_applied_section.write_custom_gates_applications(application_data)?; let _r1cs = custom_gates_applied_section.end_section(); From b5414a0c54a55950cb1c34141b568ec7f8e140bd Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 07:23:50 +0200 Subject: [PATCH 05/10] format --- dag/src/r1cs_porting.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dag/src/r1cs_porting.rs b/dag/src/r1cs_porting.rs index 6c15f5f..05cb969 100644 --- a/dag/src/r1cs_porting.rs +++ b/dag/src/r1cs_porting.rs @@ -59,7 +59,10 @@ pub fn write(dag: &DAG, output: &str) -> Result<(), ()> { let mut custom_gates_applied_section = R1CSWriter::start_custom_gates_applied_section(r1cs)?; let application_data = { - fn find_indexes(occurring_order: Vec, application_data: Vec<(String, Vec)>) -> CustomGatesAppliedData { + fn find_indexes( + occurring_order: Vec, + application_data: Vec<(String, Vec)> + ) -> CustomGatesAppliedData { let mut application_data_mut = vec![]; for (custom_gate_name, constraints) in application_data { let mut index = 0; @@ -71,13 +74,17 @@ pub fn write(dag: &DAG, output: &str) -> Result<(), ()> { application_data_mut } - fn traverse_tree(dag: &DAG, tree: &Tree, application_data: &mut Vec<(String, Vec)>) { + fn traverse_tree( + dag: &DAG, + tree: &Tree, + application_data: &mut Vec<(String, Vec)> + ) { let mut index = 0; for edge in Tree::get_edges(tree) { let node = &dag.nodes[edge.get_goes_to()]; - let possible_custom_gate_constraints = tree.custom_gates_constraints[index].clone(); + let custom_gate_constraints = tree.custom_gates_constraints[index].clone(); if node.is_custom_gate() { - if let Some(constraints) = possible_custom_gate_constraints { + if let Some(constraints) = custom_gate_constraints { application_data.push((node.template_name.clone(), constraints)); } else { unreachable!(); From 20b5c2159da93c67f05e006a1fd900ecb2bb8667 Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 07:24:27 +0200 Subject: [PATCH 06/10] custom gate's signals are not included in the witness (--O0) --- dag/src/witness_producer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dag/src/witness_producer.rs b/dag/src/witness_producer.rs index b369706..769d2e0 100644 --- a/dag/src/witness_producer.rs +++ b/dag/src/witness_producer.rs @@ -14,6 +14,8 @@ fn produce_tree_witness(tree: &Tree, witness: &mut Vec) { } for edge in Tree::get_edges(tree) { let subtree = Tree::go_to_subtree(tree, edge); - produce_tree_witness(&subtree, witness); + if !subtree.dag.nodes[edge.get_goes_to()].is_custom_gate { + produce_tree_witness(&subtree, witness); + } } } From 1b344550daef3bf4fd6ecb8f53d29684d70e17fd Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 07:30:21 +0200 Subject: [PATCH 07/10] we may not compute the subtree for every edge --- dag/src/witness_producer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dag/src/witness_producer.rs b/dag/src/witness_producer.rs index 769d2e0..97bdfd6 100644 --- a/dag/src/witness_producer.rs +++ b/dag/src/witness_producer.rs @@ -13,8 +13,8 @@ fn produce_tree_witness(tree: &Tree, witness: &mut Vec) { Vec::push(witness, *signal); } for edge in Tree::get_edges(tree) { - let subtree = Tree::go_to_subtree(tree, edge); - if !subtree.dag.nodes[edge.get_goes_to()].is_custom_gate { + if !tree.dag.nodes[edge.get_goes_to()].is_custom_gate { + let subtree = Tree::go_to_subtree(tree, edge); produce_tree_witness(&subtree, witness); } } From e4ad173dd36b8f1bfbc708aa3b9d2ad8076dc3a8 Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 11:50:38 +0200 Subject: [PATCH 08/10] writing a value from the field requires field_size bytes (it's the same as before for the field we are working with) --- constraint_writers/src/r1cs_writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constraint_writers/src/r1cs_writer.rs b/constraint_writers/src/r1cs_writer.rs index 54a7026..5ba73fb 100644 --- a/constraint_writers/src/r1cs_writer.rs +++ b/constraint_writers/src/r1cs_writer.rs @@ -371,7 +371,7 @@ impl CustomGatesUsedSection { self.writer.flush().map_err(|_err| {})?; for parameter in custom_gate_parameters { - let (parameter_stream, parameter_size) = bigint_as_bytes(¶meter, 32); + let (parameter_stream, parameter_size) = bigint_as_bytes(¶meter, self.field_size); self.size += parameter_size; self.writer.write(¶meter_stream).map_err(|_err| {})?; self.writer.flush().map_err(|_err| {})?; From da7888e8bc11555530d46a03563668a9fca15c69 Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 11:51:31 +0200 Subject: [PATCH 09/10] signal identifiers are written with 64 bits (8 bytes) --- constraint_writers/src/r1cs_writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constraint_writers/src/r1cs_writer.rs b/constraint_writers/src/r1cs_writer.rs index 5ba73fb..dd780ec 100644 --- a/constraint_writers/src/r1cs_writer.rs +++ b/constraint_writers/src/r1cs_writer.rs @@ -421,7 +421,7 @@ impl CustomGatesAppliedSection { self.writer.flush().map_err(|_err| {})?; for signal in custom_gate_signals { - let (signal_stream, signal_size) = bigint_as_bytes(&BigInt::from(signal), 4); + let (signal_stream, signal_size) = bigint_as_bytes(&BigInt::from(signal), 8); self.size += signal_size; self.writer.write(&signal_stream).map_err(|_err| {})?; self.writer.flush().map_err(|_err| {})?; From bcb6b8c6354dfeca60c38fb4649d948dc884828b Mon Sep 17 00:00:00 2001 From: Victor Carrillo Redondo Date: Thu, 2 Jun 2022 19:10:19 +0200 Subject: [PATCH 10/10] undo removal of custom gates signals in witness --- dag/src/witness_producer.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dag/src/witness_producer.rs b/dag/src/witness_producer.rs index 97bdfd6..b369706 100644 --- a/dag/src/witness_producer.rs +++ b/dag/src/witness_producer.rs @@ -13,9 +13,7 @@ fn produce_tree_witness(tree: &Tree, witness: &mut Vec) { Vec::push(witness, *signal); } for edge in Tree::get_edges(tree) { - if !tree.dag.nodes[edge.get_goes_to()].is_custom_gate { - let subtree = Tree::go_to_subtree(tree, edge); - produce_tree_witness(&subtree, witness); - } + let subtree = Tree::go_to_subtree(tree, edge); + produce_tree_witness(&subtree, witness); } }