From 0941309d972d9e64e45ba36247dd424764283516 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 20 Feb 2024 18:55:48 +0100 Subject: [PATCH 001/189] Added changes to the parser for recognising bus declarations. --- parser/src/lang.lalrpop | 56 +++++++++++++++++++ .../src/abstract_syntax_tree/ast.rs | 14 +++++ .../src/program_library/program_merger.rs | 10 +++- tests/bus_dec1.circom | 15 +++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/bus_dec1.circom diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index 64b6f6c2a..7c2c8f4e3 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -126,6 +126,16 @@ pub ParseDefinition : Definition = { Some(a) => build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), custom_gate.is_some()), }, + "bus" "(" ")" + => { + println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); + build_bus(Meta::new(s,e), name) + }, + "bus" + => { + println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); + build_bus(Meta::new(s,e), name) + }, }; @@ -283,6 +293,7 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignSignal) }, }; + ParseSubstitution : Statement = { => {if let Expression::Variable {meta, name, access} = variable { @@ -399,6 +410,7 @@ ParseStatement1 : Statement = { => build_conditional_block(Meta::new(s,e),cond,if_case,Option::Some(else_case)), ParseStatement2 }; + ParseStatement2 : Statement = { "for" "(" Semicolon Semicolon ")" => ast_shortcuts::for_into_while(Meta::new(s,e),init,cond,step,body), @@ -766,3 +778,47 @@ Version : Version = { (version, subversion, subsubversion) } }; + + +// ==================================================================== +// Bus syntax +// ==================================================================== + +BusSignalHeader: VariableType = { + "signal" + => { + let t = match tags_list { + None => Vec::new(), + Some(tl) => tl, + }; + VariableType::Signal(SignalType::Intermediate, t) + } +}; + +// The only declarations allowed in a bus are the signal ones without initialization +ParseBusSignalDeclaration: Statement = { + + "(" ",")*> ")" => { + let mut symbols = symbols; + let meta = Meta::new(s,e); + symbols.push(symbol); + ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols,None) + }, + + ",")*> => { + let mut symbols = symbols; + let meta = Meta::new(s,e); + symbols.push(symbol); + ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols,None) + }, +}; + +ParseBusBlock: Statement = { + "{" "}" + => build_block(Meta::new(s,e),stmts), +}; + +ParseBusStatement: Statement = { + Semicolon + => dec +}; \ No newline at end of file diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 7f2dffb8d..fdf790257 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -155,6 +155,10 @@ pub enum Definition { arg_location: FileLocation, body: Statement, }, + Bus { + meta: Meta, + name: String, + }, } pub fn build_template( meta: Meta, @@ -178,6 +182,16 @@ pub fn build_function( Definition::Function { meta, name, args, arg_location, body } } +pub fn build_bus( + meta: Meta, + name: String, + //args: Vec, + //arg_location: FileLocation, + //body: Statement, +) -> Definition { + Definition::Bus { meta, name } +} + #[derive(Clone)] pub enum Statement { IfThenElse { diff --git a/program_structure/src/program_library/program_merger.rs b/program_structure/src/program_library/program_merger.rs index 7e44cac09..7c0eb8dfd 100644 --- a/program_structure/src/program_library/program_merger.rs +++ b/program_structure/src/program_library/program_merger.rs @@ -65,6 +65,14 @@ impl Merger { (Option::None, meta) } } + Definition::Bus { name, meta } => { + if self.contains_function(&name) || self.contains_template(&name) { + (Option::Some(name), meta) + } else { + + (Option::None, meta) + } + } }; if let Option::Some(definition_name) = name { let mut report = Report::error( @@ -105,4 +113,4 @@ impl Merger { pub fn decompose(self) -> (usize, FunctionInfo, TemplateInfo) { (self.fresh_id, self.function_info, self.template_info) } -} +} \ No newline at end of file diff --git a/tests/bus_dec1.circom b/tests/bus_dec1.circom new file mode 100644 index 000000000..742304175 --- /dev/null +++ b/tests/bus_dec1.circom @@ -0,0 +1,15 @@ +pragma circom 2.0.0; + +bus Point (n) { + signal {binary} x[n]; + signal {maxvalue} y; +} + +template Multiplier () { + signal input a,b; + signal output c; + + c <== a * b; +} + +component main = Multiplier(); \ No newline at end of file From c6cec590e1d3db87f0bd86e97397154b20956b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Isabel=20M=C3=A1rquez?= Date: Wed, 21 Feb 2024 03:45:05 +0100 Subject: [PATCH 002/189] Combining both parser rules in only one. Now, we can also avoid the use of parenthesis after template name in the definition --- parser/src/lang.lalrpop | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index 7c2c8f4e3..ea507d3f1 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -110,6 +110,14 @@ pub ParseMainComponent : MainComponent = { }, }; +pub ParseParenthesisArguments : Vec = { + "(" ")" =>{ + match arg_names { + None => Vec::new(), + Some(a) => a + } + }, +}; pub ParseDefinition : Definition = { "function" "(" ")" @@ -119,23 +127,20 @@ pub ParseDefinition : Definition = { Some(a) => build_function(Meta::new(s,e),name,a,args..arge,body), }, - "template" "(" ")" + "template" => match arg_names { None => build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some(), custom_gate.is_some()), Some(a) => build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), custom_gate.is_some()), }, - "bus" "(" ")" - => { - println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); - build_bus(Meta::new(s,e), name) - }, - "bus" + + "bus" => { println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); build_bus(Meta::new(s,e), name) }, + }; From 4c212ecc8e4738cbe2b2703cae9c43074f654fce Mon Sep 17 00:00:00 2001 From: clararod9 Date: Sat, 24 Feb 2024 12:12:27 +0100 Subject: [PATCH 003/189] Changes made to allow the declaration of buses: MyBus a; is transformed into bus a = MyBus() --- parser/src/lang.lalrpop | 24 ++++++++++++++ parser/src/syntax_sugar_remover.rs | 16 ++++++++++ .../src/abstract_syntax_tree/ast.rs | 9 +++++- .../src/abstract_syntax_tree/ast_shortcuts.rs | 32 +++++++++++++++++++ .../expression_builders.rs | 4 +++ .../abstract_syntax_tree/expression_impl.rs | 7 ++-- type_analysis/src/analyzers/type_check.rs | 4 +++ 7 files changed, 93 insertions(+), 3 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index ea507d3f1..f748b4574 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -297,6 +297,16 @@ ParseDeclaration : Statement = { symbols.push(symbol); ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignSignal) }, + + ",")*> => { + let mut symbols = symbols; + let meta = Meta::new(s,e); + symbols.push(symbol); + ast_shortcuts::build_bus_declaration_and_split(meta,type_bus,symbols,AssignOp::AssignSignal) + }, + + + }; ParseSubstitution : Statement = { @@ -789,6 +799,20 @@ Version : Version = { // Bus syntax // ==================================================================== +BusHeader: Expression = { + =>{ + build_bus_call(Meta::new(s,e),id,Vec::new()) + }, + + + "(" ")" + => match args { + None => build_bus_call(Meta::new(s,e),id,Vec::new()), + Some(a) => build_bus_call(Meta::new(s,e),id,a), + }, + +}; + BusSignalHeader: VariableType = { "signal" => { diff --git a/parser/src/syntax_sugar_remover.rs b/parser/src/syntax_sugar_remover.rs index fb9462b80..a79ab78c1 100644 --- a/parser/src/syntax_sugar_remover.rs +++ b/parser/src/syntax_sugar_remover.rs @@ -236,6 +236,14 @@ pub fn check_anonymous_components_expression( } Result::Ok(()) }, + BusCall { meta, args, .. } => { + for value in args{ + if value.contains_anonymous_comp() { + return Result::Err(anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a bus call ".to_string())); + } + } + Result::Ok(()) + }, AnonymousComp {meta, params, signals, .. } => { for value in params{ if value.contains_anonymous_comp() { @@ -756,6 +764,14 @@ pub fn check_tuples_expression(exp: &Expression) -> Result<(), Report>{ } Result::Ok(()) }, + BusCall { meta, args, .. } => { + for value in args{ + if value.contains_tuple() { + return Result::Err(tuple_general_error(meta.clone(),"A tuple cannot be used as a parameter of a bus call".to_string())); + } + } + Result::Ok(()) + }, AnonymousComp { .. } => { unreachable!(); } diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index fdf790257..425362405 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -267,12 +267,14 @@ pub enum SignalType { pub type TagList = Vec; -#[derive(Clone, PartialEq, Ord, PartialOrd, Eq)] + +#[derive(Clone, PartialEq, Eq)] pub enum VariableType { Var, Signal(SignalType, TagList), Component, AnonymousComponent, + Bus, } #[derive(Clone)] @@ -309,6 +311,11 @@ pub enum Expression { id: String, args: Vec, }, + BusCall { + meta: Meta, + id: String, + args: Vec, + }, AnonymousComp{ meta: Meta, id: String, diff --git a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs index 2041797d0..44923c5ef 100644 --- a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs +++ b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs @@ -122,4 +122,36 @@ pub fn split_declaration_into_single_nodes_and_multisubstitution( initializations.push(multi_sub); } build_initialization_block(meta, xtype, initializations) +} + + + +pub fn build_bus_declaration_and_split( + meta: Meta, + type_bus: Expression, + symbols: Vec, + op: AssignOp, +) -> Statement { + use crate::ast_shortcuts::AssignOp::AssignVar; + + let mut initializations = Vec::new(); + + for symbol in symbols { + let with_meta = meta.clone(); + let has_type = VariableType::Bus; + let name = symbol.name.clone(); + let dimensions = symbol.is_array; + let possible_init = symbol.init; + let single_declaration = build_declaration(with_meta, has_type, name, dimensions.clone()); + let bus_declaration = build_substitution(meta.clone(), symbol.name.clone(), vec![], AssignVar, type_bus.clone()); + initializations.push(single_declaration); + initializations.push(bus_declaration); + + if let Option::Some(init) = possible_init { + let substitution = + build_substitution(meta.clone(), symbol.name, vec![], op, init); + initializations.push(substitution); + } + } + build_initialization_block(meta, VariableType::Bus, initializations) } \ No newline at end of file diff --git a/program_structure/src/abstract_syntax_tree/expression_builders.rs b/program_structure/src/abstract_syntax_tree/expression_builders.rs index 0e7d2a0ba..91aef9161 100644 --- a/program_structure/src/abstract_syntax_tree/expression_builders.rs +++ b/program_structure/src/abstract_syntax_tree/expression_builders.rs @@ -51,6 +51,10 @@ pub fn build_call(meta: Meta, id: String, args: Vec) -> Expression { Call { meta, id, args } } +pub fn build_bus_call(meta: Meta, id: String, args: Vec) -> Expression { + BusCall { meta, id, args } +} + pub fn build_anonymous_component(meta: Meta, id: String, params: Vec, signals: Vec, names: Option>, is_parallel: bool) -> Expression { AnonymousComp { meta, id, params, signals, names, is_parallel } } diff --git a/program_structure/src/abstract_syntax_tree/expression_impl.rs b/program_structure/src/abstract_syntax_tree/expression_impl.rs index 900827e6f..cc2101a07 100644 --- a/program_structure/src/abstract_syntax_tree/expression_impl.rs +++ b/program_structure/src/abstract_syntax_tree/expression_impl.rs @@ -17,6 +17,7 @@ impl Expression { | ArrayInLine { meta, .. } => meta, | UniformArray { meta, .. } => meta, | Tuple {meta, ..} => meta, + | BusCall { meta, .. } => meta, } } pub fn get_mut_meta(&mut self) -> &mut Meta { @@ -33,6 +34,7 @@ impl Expression { | ArrayInLine { meta, .. } => meta, | UniformArray { meta, .. } => meta, | Tuple {meta, ..} => meta, + | BusCall {meta, ..} => meta, } } @@ -149,7 +151,7 @@ impl Expression { InlineSwitchOp { cond, if_true, if_false, .. } => { cond.contains_anonymous_comp() || if_true.contains_anonymous_comp() || if_false.contains_anonymous_comp() }, - Call { args, .. } | Tuple {values: args, ..} | ArrayInLine { values : args, .. } => { + BusCall { args, .. } | Call { args, .. } | Tuple {values: args, ..} | ArrayInLine { values : args, .. } => { for arg in args{ if arg.contains_anonymous_comp() { return true;} } @@ -182,7 +184,7 @@ impl Expression { InlineSwitchOp { cond, if_true, if_false, .. } => { cond.contains_tuple() || if_true.contains_tuple() || if_false.contains_tuple() }, - Call { args, .. } | ArrayInLine { values : args, .. } => { + BusCall{ args, .. } | Call { args, .. } | ArrayInLine { values : args, .. } => { for arg in args{ if arg.contains_tuple() { return true;} } @@ -228,6 +230,7 @@ impl FillMeta for Expression { fill_inline_switch_op(meta, cond, if_true, if_false, file_id, element_id) } Call { meta, args, .. } => fill_call(meta, args, file_id, element_id), + BusCall { meta, args, .. } => fill_call(meta, args, file_id, element_id), ArrayInLine { meta, values, .. } => { fill_array_inline(meta, values, file_id, element_id) } diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index c1bd56a3f..464ffd5c3 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -167,6 +167,10 @@ fn type_statement( VariableType::AnonymousComponent => analysis_information .environment .add_component(name, (meta.component_inference.clone(), dimensions.len())), + VariableType::Bus => { + // TODO: + unreachable!("TODO") + } } } Substitution { var, access, op, rhe, meta, .. } => { From ff3a72eaa0403377090b0bf1eaa7c741c66b3c34 Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 12 Mar 2024 01:29:46 +0100 Subject: [PATCH 004/189] Current work --- parser/src/lang.lalrpop | 9 +- parser/src/syntax_sugar_remover.rs | 3 +- .../src/abstract_syntax_tree/ast.rs | 11 +- .../abstract_syntax_tree/expression_impl.rs | 2 +- .../src/program_library/bus_data.rs | 131 ++++++++++++++++++ program_structure/src/program_library/mod.rs | 3 +- .../src/program_library/program_archive.rs | 40 +++++- .../src/program_library/program_merger.rs | 36 ++++- type_analysis/src/analyzers/type_check.rs | 2 +- 9 files changed, 217 insertions(+), 20 deletions(-) create mode 100644 program_structure/src/program_library/bus_data.rs diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index f748b4574..2e91f5556 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -137,8 +137,13 @@ pub ParseDefinition : Definition = { "bus" => { - println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); - build_bus(Meta::new(s,e), name) + //println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); + match arg_names{ + None => + build_bus(Meta::new(s,e), name, Vec::new(), args..arge, body), + Some(a) => + build_bus(Meta::new(s,e), name, a, args..arge, body), + } }, }; diff --git a/parser/src/syntax_sugar_remover.rs b/parser/src/syntax_sugar_remover.rs index a79ab78c1..bfc28b2da 100644 --- a/parser/src/syntax_sugar_remover.rs +++ b/parser/src/syntax_sugar_remover.rs @@ -935,5 +935,4 @@ pub fn remove_tuple_from_expression(exp : Expression) -> Expression{ }, _ => exp, } -} - +} \ No newline at end of file diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 425362405..003bbb491 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -158,6 +158,9 @@ pub enum Definition { Bus { meta: Meta, name: String, + args: Vec, + arg_location: FileLocation, + body: Statement, }, } pub fn build_template( @@ -185,11 +188,11 @@ pub fn build_function( pub fn build_bus( meta: Meta, name: String, - //args: Vec, - //arg_location: FileLocation, - //body: Statement, + args: Vec, + arg_location: FileLocation, + body: Statement, ) -> Definition { - Definition::Bus { meta, name } + Definition::Bus { meta, name, args, arg_location, body } } #[derive(Clone)] diff --git a/program_structure/src/abstract_syntax_tree/expression_impl.rs b/program_structure/src/abstract_syntax_tree/expression_impl.rs index cc2101a07..33e973c7a 100644 --- a/program_structure/src/abstract_syntax_tree/expression_impl.rs +++ b/program_structure/src/abstract_syntax_tree/expression_impl.rs @@ -344,4 +344,4 @@ fn fill_uniform_array( meta.set_file_id(file_id); value.fill(file_id, element_id); dimensions.fill(file_id, element_id); -} +} \ No newline at end of file diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs new file mode 100644 index 000000000..505602a26 --- /dev/null +++ b/program_structure/src/program_library/bus_data.rs @@ -0,0 +1,131 @@ +use super::ast; +use super::ast::{FillMeta, Statement}; +use super::file_definition::FileID; +use crate::file_definition::FileLocation; +use std::collections::{HashMap, BTreeMap, HashSet}; + +pub type BusInfo = HashMap; +pub type TagInfo = HashSet; +type SignalInfo = BTreeMap; +type SignalDeclarationOrder = Vec<(String, usize)>; +#[derive(Clone)] +pub struct BusData { + name: String, + file_id: FileID, + num_of_params: usize, + name_of_params: Vec, + param_location: FileLocation, + signals: SignalInfo, + body: Statement, +} + +impl BusData { + pub fn new( + name: String, + file_id: FileID, + mut body: Statement, + num_of_params: usize, + name_of_params: Vec, + param_location: FileLocation, + elem_id: &mut usize, + ) -> BusData { + body.fill(file_id, elem_id); + let signals = SignalInfo::new(); + + BusData { + name, + file_id, + body, + name_of_params, + param_location, + num_of_params, + signals + } + } + pub fn get_file_id(&self) -> FileID { + self.file_id + } + pub fn get_body(&self) -> &Statement { + &self.body + } + pub fn get_body_as_vec(&self) -> &Vec { + match &self.body { + Statement::Block { stmts, .. } => stmts, + _ => panic!("Function body should be a block"), + } + } + pub fn get_mut_body(&mut self) -> &mut Statement { + &mut self.body + } + pub fn set_body(&mut self, body: Statement){ + self.body = body; + } + pub fn replace_body(&mut self, new: Statement) -> Statement { + std::mem::replace(&mut self.body, new) + } + pub fn get_mut_body_as_vec(&mut self) -> &mut Vec { + match &mut self.body { + Statement::Block { stmts, .. } => stmts, + _ => panic!("Function body should be a block"), + } + } + pub fn get_param_location(&self) -> FileLocation { + self.param_location.clone() + } + pub fn get_num_of_params(&self) -> usize { + self.num_of_params + } + pub fn get_name_of_params(&self) -> &Vec { + &self.name_of_params + } + pub fn get_name(&self) -> &str { + &self.name + } + pub fn get_signal_info(&self, name: &str) -> Option<&(usize, TagInfo)> { + self.signals.get(name) + } + pub fn get_signals(&self) -> &SignalInfo { + &self.signals + } +} + + +fn fill_signals( + template_statement: &Statement, + signals: &mut SignalInfo, +) { + match template_statement { + Statement::IfThenElse { if_case, else_case, .. } => { + fill_signals(if_case, signals); + if let Option::Some(else_value) = else_case { + fill_signals(else_value, signals); + } + } + Statement::Block { stmts, .. } => { + for stmt in stmts.iter() { + fill_signals(stmt, signals); + } + } + Statement::While { stmt, .. } => { + fill_signals(stmt, signals); + } + Statement::InitializationBlock { initializations, .. } => { + for initialization in initializations.iter() { + fill_signals(initialization, signals); + } + } + Statement::Declaration { xtype, name, dimensions, .. } => { + if let ast::VariableType::Signal(stype, tag_list) = xtype { + let signal_name = name.clone(); + let dim = dimensions.len(); + let mut tag_info = HashSet::new(); + for tag in tag_list{ + tag_info.insert(tag.clone()); + } + + signals.insert(signal_name.clone(), (dim, tag_info)); + } + } + _ => {} + } +} \ No newline at end of file diff --git a/program_structure/src/program_library/mod.rs b/program_structure/src/program_library/mod.rs index 7b0e436bf..230c0b2a2 100644 --- a/program_structure/src/program_library/mod.rs +++ b/program_structure/src/program_library/mod.rs @@ -1,8 +1,9 @@ use super::ast; +pub mod bus_data; pub mod error_code; pub mod error_definition; pub mod file_definition; pub mod function_data; pub mod program_archive; pub mod program_merger; -pub mod template_data; +pub mod template_data; \ No newline at end of file diff --git a/program_structure/src/program_library/program_archive.rs b/program_structure/src/program_library/program_archive.rs index 69f6d18a4..3a55d95bf 100644 --- a/program_structure/src/program_library/program_archive.rs +++ b/program_structure/src/program_library/program_archive.rs @@ -3,6 +3,7 @@ use super::file_definition::{FileID, FileLibrary}; use super::function_data::{FunctionData, FunctionInfo}; use super::program_merger::Merger; use super::template_data::{TemplateData, TemplateInfo}; +use super::bus_data::{BusData, BusInfo}; use crate::abstract_syntax_tree::ast::FillMeta; use std::collections::HashSet; use crate::error_definition::Report; @@ -16,8 +17,10 @@ pub struct ProgramArchive { pub file_library: FileLibrary, pub functions: FunctionInfo, pub templates: TemplateInfo, + pub buses: BusInfo, pub function_keys: HashSet, pub template_keys: HashSet, + pub bus_keys: HashSet, pub public_inputs: Vec, pub initial_template_call: Expression, pub custom_gates: bool, @@ -37,15 +40,20 @@ impl ProgramArchive { reports.append(&mut errs); } } - let (mut fresh_id, functions, templates) = merger.decompose(); + let (mut fresh_id, functions, templates, buses) = merger.decompose(); let mut function_keys = HashSet::new(); let mut template_keys = HashSet::new(); + let mut bus_keys = HashSet::new(); + for key in functions.keys() { function_keys.insert(key.clone()); } for key in templates.keys() { template_keys.insert(key.clone()); } + for key in buses.keys() { + bus_keys.insert(key.clone()); + } let (public_inputs, mut initial_template_call) = main_component; initial_template_call.fill(file_id_main, &mut fresh_id); if reports.is_empty() { @@ -55,10 +63,12 @@ impl ProgramArchive { file_library, functions, templates, + buses, public_inputs, initial_template_call, function_keys, template_keys, + bus_keys, custom_gates, }) } else { @@ -123,6 +133,32 @@ impl ProgramArchive { self.functions.remove(id); } + // bus functions + pub fn contains_bus(&self, bus_name: &str) -> bool { + self.get_buses().contains_key(bus_name) + } + pub fn get_bus_data(&self, bus_name: &str) -> &BusData { + assert!(self.contains_bus(bus_name)); + self.get_buses().get(bus_name).unwrap() + } + pub fn get_mut_bus_data(&mut self, bus_name: &str) -> &mut BusData { + assert!(self.contains_bus(bus_name)); + self.buses.get_mut(bus_name).unwrap() + } + pub fn get_bus_names(&self) -> &HashSet { + &self.bus_keys + } + pub fn get_buses(&self) -> &BusInfo { + &self.buses + } + pub fn get_mut_buses(&mut self) -> &mut BusInfo { + &mut self.buses + } + pub fn remove_bus(&mut self, id: &str) { + self.bus_keys.remove(id); + self.buses.remove(id); + } + //main_component functions pub fn get_public_inputs_main_component(&self) -> &Vec { &self.public_inputs @@ -134,4 +170,4 @@ impl ProgramArchive { pub fn get_file_library(&self) -> &FileLibrary { &self.file_library } -} +} \ No newline at end of file diff --git a/program_structure/src/program_library/program_merger.rs b/program_structure/src/program_library/program_merger.rs index 7c0eb8dfd..a0eb81ad9 100644 --- a/program_structure/src/program_library/program_merger.rs +++ b/program_structure/src/program_library/program_merger.rs @@ -4,11 +4,13 @@ use super::error_definition::Report; use super::file_definition::FileID; use super::function_data::{FunctionData, FunctionInfo}; use super::template_data::{TemplateData, TemplateInfo}; +use super::bus_data::{BusData, BusInfo}; pub struct Merger { fresh_id: usize, function_info: FunctionInfo, template_info: TemplateInfo, + bus_info: BusInfo, } impl Default for Merger { fn default() -> Self { @@ -16,6 +18,7 @@ impl Default for Merger { fresh_id: 0, function_info: FunctionInfo::new(), template_info: TemplateInfo::new(), + bus_info: BusInfo::new() } } } @@ -30,7 +33,7 @@ impl Merger { for definition in definitions { let (name, meta) = match definition { Definition::Template { name, args, arg_location, body, meta, parallel, is_custom_gate } => { - if self.contains_function(&name) || self.contains_template(&name) { + if self.contains_function(&name) || self.contains_template(&name) || self.contains_bus(&name) { (Option::Some(name), meta) } else { let new_data = TemplateData::new( @@ -49,7 +52,7 @@ impl Merger { } } Definition::Function { name, body, args, arg_location, meta } => { - if self.contains_function(&name) || self.contains_template(&name) { + if self.contains_function(&name) || self.contains_template(&name) || self.contains_bus(&name) { (Option::Some(name), meta) } else { let new_data = FunctionData::new( @@ -65,11 +68,20 @@ impl Merger { (Option::None, meta) } } - Definition::Bus { name, meta } => { - if self.contains_function(&name) || self.contains_template(&name) { + Definition::Bus { name, body, args, arg_location, meta } => { + if self.contains_function(&name) || self.contains_template(&name) || self.contains_bus(&name) { (Option::Some(name), meta) } else { - + let new_data = BusData::new( + name.clone(), + file_id, + body, + args.len(), + args, + arg_location, + &mut self.fresh_id, + ); + self.get_mut_bus_info().insert(name.clone(), new_data); (Option::None, meta) } } @@ -109,8 +121,18 @@ impl Merger { &mut self.template_info } + pub fn contains_bus(&self, bus_name: &str) -> bool { + self.get_bus_info().contains_key(bus_name) + } + fn get_bus_info(&self) -> &BusInfo { + &self.bus_info + } + fn get_mut_bus_info(&mut self) -> &mut BusInfo { + &mut self.bus_info + } + - pub fn decompose(self) -> (usize, FunctionInfo, TemplateInfo) { - (self.fresh_id, self.function_info, self.template_info) + pub fn decompose(self) -> (usize, FunctionInfo, TemplateInfo, BusInfo) { + (self.fresh_id, self.function_info, self.template_info, self.bus_info) } } \ No newline at end of file diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 464ffd5c3..cf5e5e177 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1077,4 +1077,4 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio }; report.add_primary(location, file_id, message); reports.push(report); -} +} \ No newline at end of file From e5456b482fd76e6023b34efb5e23024ef35bca68 Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 12 Mar 2024 02:13:06 +0100 Subject: [PATCH 005/189] Updating with only bus' stuffs --- parser/src/lang.lalrpop | 109 +++++++----------- .../src/abstract_syntax_tree/ast.rs | 2 +- .../src/abstract_syntax_tree/ast_shortcuts.rs | 44 ++++++- .../src/program_library/bus_data.rs | 83 +++++++++---- tests/bus_dec1.circom | 11 ++ .../functions_free_of_template_elements.rs | 10 ++ .../src/analyzers/symbol_analysis.rs | 13 +++ type_analysis/src/analyzers/type_check.rs | 2 +- .../src/decorators/constants_handler.rs | 11 ++ .../src/decorators/type_reduction.rs | 3 + 10 files changed, 194 insertions(+), 94 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index 2e91f5556..8b7c97fea 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -135,9 +135,8 @@ pub ParseDefinition : Definition = { => build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), custom_gate.is_some()), }, - "bus" + "bus" => { - //println!("Bus {} with declaration starting at {} and finishing at {} parsed", name, s, e); match arg_names{ None => build_bus(Meta::new(s,e), name, Vec::new(), args..arge, body), @@ -165,8 +164,8 @@ ParseSignalType: SignalType = { "output" => SignalType::Output }; -SignalHeader : VariableType = { - "signal" +ParseHeader: (SignalType, Vec) = { + => { let s = match signal_type { None => SignalType::Intermediate, @@ -176,10 +175,37 @@ SignalHeader : VariableType = { None => Vec::new(), Some(tl) => tl, }; + (s,t) + } +} + +SignalHeader : VariableType = { + "signal" + => { + let (s,t) = header; VariableType::Signal(s, t) } }; +BusHeader : (Expression, VariableType) = { + + => { + let bus_builder = build_bus_call(Meta::new(s,e),id,Vec::new()); + let (s,t) = header; + (bus_builder,VariableType::Bus(s, t)) + }, + + "(" ")" + => { + let bus_builder = match args { + None => build_bus_call(Meta::new(s,e),id,Vec::new()), + Some(a) => build_bus_call(Meta::new(s,e),id,a), + }; + let (s,t) = header; + (bus_builder,VariableType::Bus(s, t)) + } +}; + // ==================================================================== // Statements // ==================================================================== @@ -263,6 +289,7 @@ ParseDeclaration : Statement = { symbols.push(symbol); ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols, init) }, + "component" "(" ",")*> ")" => { let mut symbols = symbols; let meta = Meta::new(s,e); @@ -271,6 +298,13 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols, init) }, +// "(" ",")*> ")" => { +// let (bus_type,xtype) = bus_header; +// let mut symbols = symbols; +// let meta = Meta::new(s,e); +// symbols.push(symbol); +// ast_shortcuts::split_bus_declaration_into_single_nodes_and_multisubstitution(meta,bus_type,xtype,symbols, init) +// }, "var" ",")*> => { let mut symbols = symbols; @@ -288,14 +322,14 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignVar) }, - ",")*> + ",")*> => { let mut symbols = symbols; let meta = Meta::new(s,e); symbols.push(symbol); ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignConstraintSignal) }, - ",")*> + ",")*> => { let mut symbols = symbols; let meta = Meta::new(s,e); @@ -303,11 +337,12 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignSignal) }, - ",")*> => { + ",")*> => { + let (bus_type,xtype) = bus_header; let mut symbols = symbols; let meta = Meta::new(s,e); symbols.push(symbol); - ast_shortcuts::build_bus_declaration_and_split(meta,type_bus,symbols,AssignOp::AssignSignal) + ast_shortcuts::split_bus_declaration_into_single_nodes(meta,bus_type,xtype,symbols,AssignOp::AssignSignal) }, @@ -797,62 +832,4 @@ Version : Version = { "." "." => { (version, subversion, subsubversion) } -}; - - -// ==================================================================== -// Bus syntax -// ==================================================================== - -BusHeader: Expression = { - =>{ - build_bus_call(Meta::new(s,e),id,Vec::new()) - }, - - - "(" ")" - => match args { - None => build_bus_call(Meta::new(s,e),id,Vec::new()), - Some(a) => build_bus_call(Meta::new(s,e),id,a), - }, - -}; - -BusSignalHeader: VariableType = { - "signal" - => { - let t = match tags_list { - None => Vec::new(), - Some(tl) => tl, - }; - VariableType::Signal(SignalType::Intermediate, t) - } -}; - -// The only declarations allowed in a bus are the signal ones without initialization -ParseBusSignalDeclaration: Statement = { - - "(" ",")*> ")" => { - let mut symbols = symbols; - let meta = Meta::new(s,e); - symbols.push(symbol); - ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols,None) - }, - - ",")*> => { - let mut symbols = symbols; - let meta = Meta::new(s,e); - symbols.push(symbol); - ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols,None) - }, -}; - -ParseBusBlock: Statement = { - "{" "}" - => build_block(Meta::new(s,e),stmts), -}; - -ParseBusStatement: Statement = { - Semicolon - => dec }; \ No newline at end of file diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 003bbb491..bb47892b5 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -277,7 +277,7 @@ pub enum VariableType { Signal(SignalType, TagList), Component, AnonymousComponent, - Bus, + Bus(SignalType, TagList), } #[derive(Clone)] diff --git a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs index 44923c5ef..7d693e980 100644 --- a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs +++ b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs @@ -73,7 +73,7 @@ pub fn split_declaration_into_single_nodes( initializations.push(substitution); } else if xtype == Var { - let mut value = Expression:: Number(meta.clone(), BigInt::from(0)); + let mut value = Expression::Number(meta.clone(), BigInt::from(0)); for dim_expr in dimensions.iter().rev(){ value = build_uniform_array(meta.clone(), value, dim_expr.clone()); } @@ -126,9 +126,10 @@ pub fn split_declaration_into_single_nodes_and_multisubstitution( -pub fn build_bus_declaration_and_split( +pub fn split_bus_declaration_into_single_nodes( meta: Meta, - type_bus: Expression, + bustype: Expression, + xtype: VariableType, symbols: Vec, op: AssignOp, ) -> Statement { @@ -138,12 +139,12 @@ pub fn build_bus_declaration_and_split( for symbol in symbols { let with_meta = meta.clone(); - let has_type = VariableType::Bus; + let has_type = xtype.clone(); let name = symbol.name.clone(); let dimensions = symbol.is_array; let possible_init = symbol.init; let single_declaration = build_declaration(with_meta, has_type, name, dimensions.clone()); - let bus_declaration = build_substitution(meta.clone(), symbol.name.clone(), vec![], AssignVar, type_bus.clone()); + let bus_declaration = build_substitution(meta.clone(), symbol.name.clone(), vec![], AssignVar, bustype.clone()); initializations.push(single_declaration); initializations.push(bus_declaration); @@ -153,5 +154,36 @@ pub fn build_bus_declaration_and_split( initializations.push(substitution); } } - build_initialization_block(meta, VariableType::Bus, initializations) + build_initialization_block(meta, xtype, initializations) +} + +pub fn split_bus_declaration_into_single_nodes_and_multisubstitution( + meta: Meta, + bustype: Expression, + xtype: VariableType, + symbols: Vec, + init: Option, +) -> Statement { + use crate::ast_shortcuts::AssignOp::AssignVar; + + let mut initializations = Vec::new(); + let mut values = Vec::new(); + for symbol in symbols { + let with_meta = meta.clone(); + let has_type = xtype.clone(); + let name = symbol.name.clone(); + let dimensions = symbol.is_array; + debug_assert!(symbol.init.is_none()); + let single_declaration = build_declaration(with_meta.clone(), has_type, name.clone(), dimensions.clone()); + let bus_declaration = build_substitution(meta.clone(), symbol.name.clone(), vec![], AssignVar, bustype.clone()); + initializations.push(single_declaration); + initializations.push(bus_declaration); + values.push(Expression::Variable { meta: with_meta.clone(), name: name, access: Vec::new() }) + } + if let Some(tuple) = init { + let (op,expression) = tuple.tuple_init; + let multi_sub = build_mult_substitution(meta.clone(), build_tuple(meta.clone(), values), op, expression); + initializations.push(multi_sub); + } + build_initialization_block(meta, xtype, initializations) } \ No newline at end of file diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs index 505602a26..0665e4c47 100644 --- a/program_structure/src/program_library/bus_data.rs +++ b/program_structure/src/program_library/bus_data.rs @@ -6,8 +6,42 @@ use std::collections::{HashMap, BTreeMap, HashSet}; pub type BusInfo = HashMap; pub type TagInfo = HashSet; -type SignalInfo = BTreeMap; -type SignalDeclarationOrder = Vec<(String, usize)>; +type FieldInfo = BTreeMap; +type FieldDeclarationOrder = Vec<(String, usize)>; + +#[derive(Clone)] +pub struct FieldType { + is_signal: bool, + dimension: usize, + tag_info: TagInfo, +} + +impl FieldType { + pub fn new( + is_signal: bool, + dimension: usize, + tag_info: TagInfo, + ) -> FieldType { + FieldType { + is_signal, + dimension, + tag_info + } + } + pub fn is_signal(&self) -> bool { + self.is_signal + } + pub fn get_dimension(&self) -> usize { + self.dimension + } + pub fn contains_tag(&self, name: &str) -> bool { + self.tag_info.contains(name) + } + pub fn get_tags(&self) -> &TagInfo { + &self.tag_info + } +} + #[derive(Clone)] pub struct BusData { name: String, @@ -15,7 +49,7 @@ pub struct BusData { num_of_params: usize, name_of_params: Vec, param_location: FileLocation, - signals: SignalInfo, + fields: FieldInfo, body: Statement, } @@ -30,7 +64,7 @@ impl BusData { elem_id: &mut usize, ) -> BusData { body.fill(file_id, elem_id); - let signals = SignalInfo::new(); + let fields = FieldInfo::new(); BusData { name, @@ -39,7 +73,7 @@ impl BusData { name_of_params, param_location, num_of_params, - signals + fields } } pub fn get_file_id(&self) -> FileID { @@ -81,37 +115,37 @@ impl BusData { pub fn get_name(&self) -> &str { &self.name } - pub fn get_signal_info(&self, name: &str) -> Option<&(usize, TagInfo)> { - self.signals.get(name) + pub fn get_field_info(&self, name: &str) -> Option<&FieldType> { + self.fields.get(name) } - pub fn get_signals(&self) -> &SignalInfo { - &self.signals + pub fn get_fields(&self) -> &FieldInfo { + &self.fields } } -fn fill_signals( - template_statement: &Statement, - signals: &mut SignalInfo, +fn fill_fields( + bus_statement: &Statement, + fields: &mut FieldInfo, ) { - match template_statement { + match bus_statement { Statement::IfThenElse { if_case, else_case, .. } => { - fill_signals(if_case, signals); + fill_fields(if_case, fields); if let Option::Some(else_value) = else_case { - fill_signals(else_value, signals); + fill_fields(else_value, fields); } } Statement::Block { stmts, .. } => { for stmt in stmts.iter() { - fill_signals(stmt, signals); + fill_fields(stmt, fields); } } Statement::While { stmt, .. } => { - fill_signals(stmt, signals); + fill_fields(stmt, fields); } Statement::InitializationBlock { initializations, .. } => { for initialization in initializations.iter() { - fill_signals(initialization, signals); + fill_fields(initialization, fields); } } Statement::Declaration { xtype, name, dimensions, .. } => { @@ -122,9 +156,18 @@ fn fill_signals( for tag in tag_list{ tag_info.insert(tag.clone()); } - - signals.insert(signal_name.clone(), (dim, tag_info)); + let field_type = FieldType::new(true,dim,tag_info); + fields.insert(signal_name.clone(), field_type.clone()); } + else if let ast::VariableType::Bus(stype, tag_list) = xtype { + let bus_name = name.clone(); + let dim = dimensions.len(); + let mut tag_info = HashSet::new(); + for tag in tag_list{ + tag_info.insert(tag.clone()); + } + let field_type = FieldType::new(false,dim,tag_info); + fields.insert(bus_name.clone(), field_type); } } _ => {} } diff --git a/tests/bus_dec1.circom b/tests/bus_dec1.circom index 742304175..13c0301e2 100644 --- a/tests/bus_dec1.circom +++ b/tests/bus_dec1.circom @@ -5,11 +5,22 @@ bus Point (n) { signal {maxvalue} y; } +bus New (m,n) { + Point(m) {babyedwards} a; + signal {binary} select; + Point(n) {babymontgomery} b; +} + template Multiplier () { signal input a,b; signal output c; + Point(3) input {tag1} p1; + New(2,4) output {tag2} n1; + Point(3) {tag1} p2 <== p1, p3; + p3.x[0] <-- p1.y; c <== a * b; + } component main = Multiplier(); \ No newline at end of file diff --git a/type_analysis/src/analyzers/functions_free_of_template_elements.rs b/type_analysis/src/analyzers/functions_free_of_template_elements.rs index b5330864c..d8371d214 100644 --- a/type_analysis/src/analyzers/functions_free_of_template_elements.rs +++ b/type_analysis/src/analyzers/functions_free_of_template_elements.rs @@ -205,6 +205,16 @@ fn analyse_expression( } + BusCall { meta, .. } => { + let mut report = Report::error( + "Template elements declared inside the function".to_string(), + ReportCode::UndefinedFunction, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Declaring template element".to_string()); + reports.push(report); + }, _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } } diff --git a/type_analysis/src/analyzers/symbol_analysis.rs b/type_analysis/src/analyzers/symbol_analysis.rs index 1d92ce25e..fe723dbc5 100644 --- a/type_analysis/src/analyzers/symbol_analysis.rs +++ b/type_analysis/src/analyzers/symbol_analysis.rs @@ -414,6 +414,19 @@ fn analyze_expression( environment, ); }, + Expression::BusCall { args, .. } => + { + for arg in args.iter() { + analyze_expression( + arg, + file_id, + function_info, + template_info, + reports, + environment, + ); + } + }, _ => {} } } diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index cf5e5e177..931288a4b 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -167,7 +167,7 @@ fn type_statement( VariableType::AnonymousComponent => analysis_information .environment .add_component(name, (meta.component_inference.clone(), dimensions.len())), - VariableType::Bus => { + VariableType::Bus(s_type, tags) => { // TODO: unreachable!("TODO") } diff --git a/type_analysis/src/decorators/constants_handler.rs b/type_analysis/src/decorators/constants_handler.rs index bbffe78d7..da8d70ce7 100644 --- a/type_analysis/src/decorators/constants_handler.rs +++ b/type_analysis/src/decorators/constants_handler.rs @@ -224,6 +224,7 @@ fn has_constant_value(expr: &Expression, environment: &Constants) -> bool { Variable { name, .. } => variable(name, environment), ArrayInLine { .. } => array_inline(), UniformArray { .. } => uniform_array(), + BusCall { args, .. } => call(args, environment), _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } } @@ -415,10 +416,20 @@ fn expand_expression(expr: Expression, environment: &ExpressionHolder) -> Expres expand_inline_switch_op(meta, *cond, *if_true, *if_false, environment) } Variable { meta, name, access } => expand_variable(meta, name, access, environment), + BusCall { meta, id, args } => expand_bus_call(meta,id,args,environment), _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } } +fn expand_bus_call(meta: Meta, id: String, old_args: Vec, environment: &ExpressionHolder,) -> Expression { + let mut args = Vec::new(); + for expr in old_args { + let new_expression = expand_expression(expr, environment); + args.push(new_expression); + } + build_bus_call(meta, id, args) +} + fn expand_number(meta: Meta, value: BigInt) -> Expression { build_number(meta, value) } diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 3e42a1027..6a9efe8b1 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -82,6 +82,9 @@ fn reduce_types_in_expression(expression: &mut Expression, environment: &Environ reduce_types_in_expression(dimension, environment); } Number(..) => {} + BusCall { args, .. } => { + reduce_types_in_vec_of_expressions(args, environment); + }, _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } } From 72864b622123dd6a8008b19f17b76416844876a3 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Fri, 15 Mar 2024 19:16:23 +0100 Subject: [PATCH 006/189] Finished bus_data and added file wire_data to store all information about signals and buses. --- constraint_generation/src/execute.rs | 4 +- .../src/program_library/bus_data.rs | 72 +++--------- program_structure/src/program_library/mod.rs | 3 +- .../src/program_library/template_data.rs | 109 ++++++++++-------- .../src/program_library/wire_data.rs | 47 ++++++++ type_analysis/src/analyzers/type_check.rs | 9 +- 6 files changed, 140 insertions(+), 104 deletions(-) create mode 100644 program_structure/src/program_library/wire_data.rs diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index a4d085fff..613f39da7 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1897,11 +1897,11 @@ fn preexecute_template_call( for (name, info_input) in inputs { - inputs_to_tags.insert(name.clone(), info_input.1.clone()); + inputs_to_tags.insert(name.clone(), info_input.get_tags().clone()); } for (name, info_output) in outputs { - outputs_to_tags.insert(name.clone(), info_output.1.clone()); + outputs_to_tags.insert(name.clone(), info_output.get_tags().clone()); } let node_wrap = Option::Some(PreExecutedTemplate::new( diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs index 0665e4c47..7f55b1d67 100644 --- a/program_structure/src/program_library/bus_data.rs +++ b/program_structure/src/program_library/bus_data.rs @@ -1,46 +1,10 @@ use super::ast; use super::ast::{FillMeta, Statement}; -use super::file_definition::FileID; -use crate::file_definition::FileLocation; -use std::collections::{HashMap, BTreeMap, HashSet}; +use super::file_definition::{FileID, FileLocation}; +use super::wire_data::{TagInfo, WireInfo, WireData, WireType, WireDeclarationOrder}; +use std::collections::{HashMap}; pub type BusInfo = HashMap; -pub type TagInfo = HashSet; -type FieldInfo = BTreeMap; -type FieldDeclarationOrder = Vec<(String, usize)>; - -#[derive(Clone)] -pub struct FieldType { - is_signal: bool, - dimension: usize, - tag_info: TagInfo, -} - -impl FieldType { - pub fn new( - is_signal: bool, - dimension: usize, - tag_info: TagInfo, - ) -> FieldType { - FieldType { - is_signal, - dimension, - tag_info - } - } - pub fn is_signal(&self) -> bool { - self.is_signal - } - pub fn get_dimension(&self) -> usize { - self.dimension - } - pub fn contains_tag(&self, name: &str) -> bool { - self.tag_info.contains(name) - } - pub fn get_tags(&self) -> &TagInfo { - &self.tag_info - } -} #[derive(Clone)] pub struct BusData { @@ -49,7 +13,7 @@ pub struct BusData { num_of_params: usize, name_of_params: Vec, param_location: FileLocation, - fields: FieldInfo, + fields: WireInfo, body: Statement, } @@ -64,7 +28,7 @@ impl BusData { elem_id: &mut usize, ) -> BusData { body.fill(file_id, elem_id); - let fields = FieldInfo::new(); + let fields = WireInfo::new(); BusData { name, @@ -115,10 +79,10 @@ impl BusData { pub fn get_name(&self) -> &str { &self.name } - pub fn get_field_info(&self, name: &str) -> Option<&FieldType> { + pub fn get_field_info(&self, name: &str) -> Option<&WireData> { self.fields.get(name) } - pub fn get_fields(&self) -> &FieldInfo { + pub fn get_fields(&self) -> &WireInfo { &self.fields } } @@ -126,7 +90,7 @@ impl BusData { fn fill_fields( bus_statement: &Statement, - fields: &mut FieldInfo, + fields: &mut WireInfo, ) { match bus_statement { Statement::IfThenElse { if_case, else_case, .. } => { @@ -149,25 +113,25 @@ fn fill_fields( } } Statement::Declaration { xtype, name, dimensions, .. } => { - if let ast::VariableType::Signal(stype, tag_list) = xtype { + if let ast::VariableType::Signal(_, tag_list) = xtype { let signal_name = name.clone(); let dim = dimensions.len(); - let mut tag_info = HashSet::new(); - for tag in tag_list{ + let mut tag_info = TagInfo::new(); + for tag in tag_list { tag_info.insert(tag.clone()); } - let field_type = FieldType::new(true,dim,tag_info); - fields.insert(signal_name.clone(), field_type.clone()); + let field_data = WireData::new(WireType::Signal,dim,tag_info); + fields.insert(signal_name, field_data); } - else if let ast::VariableType::Bus(stype, tag_list) = xtype { + else if let ast::VariableType::Bus(_, tag_list) = xtype { let bus_name = name.clone(); let dim = dimensions.len(); - let mut tag_info = HashSet::new(); - for tag in tag_list{ + let mut tag_info = TagInfo::new(); + for tag in tag_list { tag_info.insert(tag.clone()); } - let field_type = FieldType::new(false,dim,tag_info); - fields.insert(bus_name.clone(), field_type); } + let field_data = WireData::new(WireType::Bus,dim,tag_info); + fields.insert(bus_name, field_data); } } _ => {} } diff --git a/program_structure/src/program_library/mod.rs b/program_structure/src/program_library/mod.rs index 230c0b2a2..d19497041 100644 --- a/program_structure/src/program_library/mod.rs +++ b/program_structure/src/program_library/mod.rs @@ -6,4 +6,5 @@ pub mod file_definition; pub mod function_data; pub mod program_archive; pub mod program_merger; -pub mod template_data; \ No newline at end of file +pub mod template_data; +pub mod wire_data; \ No newline at end of file diff --git a/program_structure/src/program_library/template_data.rs b/program_structure/src/program_library/template_data.rs index 125bf7ab8..c35b04ba6 100644 --- a/program_structure/src/program_library/template_data.rs +++ b/program_structure/src/program_library/template_data.rs @@ -1,13 +1,10 @@ use super::ast; use super::ast::{FillMeta, Statement}; -use super::file_definition::FileID; -use crate::file_definition::FileLocation; -use std::collections::{HashMap, HashSet, BTreeMap}; +use super::file_definition::{FileID, FileLocation}; +use super::wire_data::{TagInfo, WireInfo, WireData, WireType, WireDeclarationOrder}; +use std::collections::{HashMap}; pub type TemplateInfo = HashMap; -pub type TagInfo = HashSet; -type SignalInfo = BTreeMap; -type SignalDeclarationOrder = Vec<(String, usize)>; #[derive(Clone)] pub struct TemplateData { @@ -17,13 +14,13 @@ pub struct TemplateData { num_of_params: usize, name_of_params: Vec, param_location: FileLocation, - input_signals: SignalInfo, - output_signals: SignalInfo, + input_wires: WireInfo, + output_wires: WireInfo, is_parallel: bool, is_custom_gate: bool, /* Only used to know the order in which signals are declared.*/ - input_declarations: SignalDeclarationOrder, - output_declarations: SignalDeclarationOrder, + input_declarations: WireDeclarationOrder, + output_declarations: WireDeclarationOrder, } impl TemplateData { @@ -39,11 +36,11 @@ impl TemplateData { is_custom_gate: bool, ) -> TemplateData { body.fill(file_id, elem_id); - let mut input_signals = SignalInfo::new(); - let mut output_signals = SignalInfo::new(); - let mut input_declarations = SignalDeclarationOrder::new(); - let mut output_declarations = SignalDeclarationOrder::new(); - fill_inputs_and_outputs(&body, &mut input_signals, &mut output_signals, &mut input_declarations, &mut output_declarations); + let mut input_wires = WireInfo::new(); + let mut output_wires = WireInfo::new(); + let mut input_declarations = WireDeclarationOrder::new(); + let mut output_declarations = WireDeclarationOrder::new(); + fill_inputs_and_outputs(&body, &mut input_wires, &mut output_wires, &mut input_declarations, &mut output_declarations); TemplateData { name, file_id, @@ -51,8 +48,8 @@ impl TemplateData { num_of_params, name_of_params, param_location, - input_signals, - output_signals, + input_wires, + output_wires, is_parallel, is_custom_gate, input_declarations, @@ -67,12 +64,12 @@ impl TemplateData { num_of_params: usize, name_of_params: Vec, param_location: FileLocation, - input_signals: SignalInfo, - output_signals: SignalInfo, + input_wires: WireInfo, + output_wires: WireInfo, is_parallel: bool, is_custom_gate: bool, - input_declarations :SignalDeclarationOrder, - output_declarations : SignalDeclarationOrder + input_declarations: WireDeclarationOrder, + output_declarations: WireDeclarationOrder ) -> TemplateData { TemplateData { name, @@ -81,8 +78,8 @@ impl TemplateData { num_of_params, name_of_params, param_location, - input_signals, - output_signals, + input_wires, + output_wires, is_parallel, is_custom_gate, input_declarations, @@ -123,22 +120,22 @@ impl TemplateData { pub fn get_name_of_params(&self) -> &Vec { &self.name_of_params } - pub fn get_input_info(&self, name: &str) -> Option<&(usize, TagInfo)> { - self.input_signals.get(name) + pub fn get_input_info(&self, name: &str) -> Option<&WireData> { + self.input_wires.get(name) } - pub fn get_output_info(&self, name: &str) -> Option<&(usize, TagInfo)> { - self.output_signals.get(name) + pub fn get_output_info(&self, name: &str) -> Option<&WireData> { + self.output_wires.get(name) } - pub fn get_inputs(&self) -> &SignalInfo { - &self.input_signals + pub fn get_inputs(&self) -> &WireInfo { + &self.input_wires } - pub fn get_outputs(&self) -> &SignalInfo { - &self.output_signals + pub fn get_outputs(&self) -> &WireInfo { + &self.output_wires } - pub fn get_declaration_inputs(&self) -> &SignalDeclarationOrder { + pub fn get_declaration_inputs(&self) -> &WireDeclarationOrder { &&self.input_declarations } - pub fn get_declaration_outputs(&self) -> &SignalDeclarationOrder { + pub fn get_declaration_outputs(&self) -> &WireDeclarationOrder { &self.output_declarations } pub fn get_name(&self) -> &str { @@ -154,52 +151,74 @@ impl TemplateData { fn fill_inputs_and_outputs( template_statement: &Statement, - input_signals: &mut SignalInfo, - output_signals: &mut SignalInfo, - input_declarations : &mut SignalDeclarationOrder, - output_declarations : &mut SignalDeclarationOrder + input_wires: &mut WireInfo, + output_wires: &mut WireInfo, + input_declarations: &mut WireDeclarationOrder, + output_declarations: &mut WireDeclarationOrder ) { match template_statement { Statement::IfThenElse { if_case, else_case, .. } => { - fill_inputs_and_outputs(if_case, input_signals, output_signals, input_declarations, output_declarations); + fill_inputs_and_outputs(if_case, input_wires, output_wires, input_declarations, output_declarations); if let Option::Some(else_value) = else_case { - fill_inputs_and_outputs(else_value, input_signals, output_signals, input_declarations, output_declarations); + fill_inputs_and_outputs(else_value, input_wires, output_wires, input_declarations, output_declarations); } } Statement::Block { stmts, .. } => { for stmt in stmts.iter() { - fill_inputs_and_outputs(stmt, input_signals, output_signals, input_declarations, output_declarations); + fill_inputs_and_outputs(stmt, input_wires, output_wires, input_declarations, output_declarations); } } Statement::While { stmt, .. } => { - fill_inputs_and_outputs(stmt, input_signals, output_signals, input_declarations, output_declarations); + fill_inputs_and_outputs(stmt, input_wires, output_wires, input_declarations, output_declarations); } Statement::InitializationBlock { initializations, .. } => { for initialization in initializations.iter() { - fill_inputs_and_outputs(initialization, input_signals, output_signals, input_declarations, output_declarations); + fill_inputs_and_outputs(initialization, input_wires, output_wires, input_declarations, output_declarations); } } Statement::Declaration { xtype, name, dimensions, .. } => { if let ast::VariableType::Signal(stype, tag_list) = xtype { let signal_name = name.clone(); let dim = dimensions.len(); - let mut tag_info = HashSet::new(); + let mut tag_info = TagInfo::new(); for tag in tag_list{ tag_info.insert(tag.clone()); } + let wire_data = WireData::new(WireType::Signal,dim,tag_info); match stype { ast::SignalType::Input => { - input_signals.insert(signal_name.clone(), (dim, tag_info)); + input_wires.insert(signal_name.clone(), wire_data); input_declarations.push((signal_name,dim)); } ast::SignalType::Output => { - output_signals.insert(signal_name.clone(), (dim, tag_info)); + output_wires.insert(signal_name.clone(), wire_data); output_declarations.push((signal_name,dim)); } _ => {} //no need to deal with intermediate signals } } + else if let ast::VariableType::Bus(stype, tag_list) = xtype { + let bus_name = name.clone(); + let dim = dimensions.len(); + let mut tag_info = TagInfo::new(); + for tag in tag_list{ + tag_info.insert(tag.clone()); + } + let wire_data = WireData::new(WireType::Bus,dim,tag_info); + + match stype { + ast::SignalType::Input => { + input_wires.insert(bus_name.clone(), wire_data); + input_declarations.push((bus_name,dim)); + } + ast::SignalType::Output => { + output_wires.insert(bus_name.clone(), wire_data); + output_declarations.push((bus_name,dim)); + } + _ => {} //no need to deal with intermediate signals + } + } } _ => {} } diff --git a/program_structure/src/program_library/wire_data.rs b/program_structure/src/program_library/wire_data.rs new file mode 100644 index 000000000..a4d81ab29 --- /dev/null +++ b/program_structure/src/program_library/wire_data.rs @@ -0,0 +1,47 @@ +use std::collections::{HashSet, HashMap}; + + +pub type TagInfo = HashSet; +pub type WireInfo = HashMap; +pub type WireDeclarationOrder = Vec<(String, usize)>; + + +#[derive(Clone, PartialEq, Eq)] +pub enum WireType { + Signal, + Bus, +} + + +#[derive(Clone)] +pub struct WireData { + wire_type: WireType, + dimension: usize, + tag_info: TagInfo, +} + +impl WireData { + pub fn new( + wire_type: WireType, + dimension: usize, + tag_info: TagInfo, + ) -> WireData { + WireData { + wire_type, + dimension, + tag_info + } + } + pub fn get_type(&self) -> WireType { + self.wire_type.clone() + } + pub fn get_dimension(&self) -> usize { + self.dimension + } + pub fn contains_tag(&self, name: &str) -> bool { + self.tag_info.contains(name) + } + pub fn get_tags(&self) -> &TagInfo { + &self.tag_info + } +} \ No newline at end of file diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 931288a4b..ddbfe0bd4 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -108,7 +108,7 @@ fn check_main_has_tags(initial_expression: &Expression, program_archive: &Progra let inputs = program_archive.get_template_data(id).get_inputs(); let mut tag_in_inputs = false; for input in inputs { - if !input.1.1.is_empty(){ + if !input.1.get_tags().is_empty(){ tag_in_inputs = true; break; } @@ -844,7 +844,12 @@ fn apply_access_to_symbol( let output = program_archive.get_template_data(&template_name).get_output_info(&signal_name); let tags; (current_dim, tags) = match (input, output) { - (Option::Some((d, tags)), _) | (_, Option::Some((d, tags))) => (*d, tags), + //(Option::Some((d, tags)), _) | (_, Option::Some((d, tags))) => (*d, tags), + //_ => { + // return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); + //} + (Option::Some(wire_data), _) | (_, Option::Some(wire_data)) => + (wire_data.get_dimension(), wire_data.get_tags()), _ => { return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); } From 820c979ac2da23209b8fa9350c3b737d63fa1e7a Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sun, 17 Mar 2024 17:40:24 +0100 Subject: [PATCH 007/189] Added block analysis for buses. --- .../src/program_library/bus_data.rs | 58 ++--- .../src/program_library/error_code.rs | 2 + .../src/program_library/template_data.rs | 73 +++--- .../buses_free_of_invalid_statements.rs | 223 ++++++++++++++++++ type_analysis/src/analyzers/type_check.rs | 4 - 5 files changed, 277 insertions(+), 83 deletions(-) create mode 100644 type_analysis/src/analyzers/buses_free_of_invalid_statements.rs diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs index 7f55b1d67..57bc6c223 100644 --- a/program_structure/src/program_library/bus_data.rs +++ b/program_structure/src/program_library/bus_data.rs @@ -1,7 +1,6 @@ -use super::ast; -use super::ast::{FillMeta, Statement}; +use super::ast::{FillMeta, Statement, VariableType, SignalType}; use super::file_definition::{FileID, FileLocation}; -use super::wire_data::{TagInfo, WireInfo, WireData, WireType, WireDeclarationOrder}; +use super::wire_data::*; use std::collections::{HashMap}; pub type BusInfo = HashMap; @@ -92,46 +91,33 @@ fn fill_fields( bus_statement: &Statement, fields: &mut WireInfo, ) { + use Statement::*; match bus_statement { - Statement::IfThenElse { if_case, else_case, .. } => { - fill_fields(if_case, fields); - if let Option::Some(else_value) = else_case { - fill_fields(else_value, fields); - } - } - Statement::Block { stmts, .. } => { + Block { stmts, .. } => { for stmt in stmts.iter() { fill_fields(stmt, fields); } } - Statement::While { stmt, .. } => { - fill_fields(stmt, fields); - } - Statement::InitializationBlock { initializations, .. } => { - for initialization in initializations.iter() { - fill_fields(initialization, fields); - } - } - Statement::Declaration { xtype, name, dimensions, .. } => { - if let ast::VariableType::Signal(_, tag_list) = xtype { - let signal_name = name.clone(); - let dim = dimensions.len(); - let mut tag_info = TagInfo::new(); - for tag in tag_list { - tag_info.insert(tag.clone()); + Declaration { xtype, name, dimensions, .. } => { + match xtype { + VariableType::Signal(stype, tag_list) | VariableType::Bus(stype, tag_list) => { + if *stype == SignalType::Intermediate { + let wire_name = name.clone(); + let dim = dimensions.len(); + let mut tag_info = TagInfo::new(); + for tag in tag_list { + tag_info.insert(tag.clone()); + } + let field_data = if let VariableType::Signal(_,_) = xtype { + WireData::new(WireType::Signal,dim,tag_info) + } else { + WireData::new(WireType::Bus,dim,tag_info) + }; + fields.insert(wire_name, field_data); + } } - let field_data = WireData::new(WireType::Signal,dim,tag_info); - fields.insert(signal_name, field_data); + _ => {} } - else if let ast::VariableType::Bus(_, tag_list) = xtype { - let bus_name = name.clone(); - let dim = dimensions.len(); - let mut tag_info = TagInfo::new(); - for tag in tag_list { - tag_info.insert(tag.clone()); - } - let field_data = WireData::new(WireType::Bus,dim,tag_info); - fields.insert(bus_name, field_data); } } _ => {} } diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index ba1ca693a..96cc2c11b 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -27,6 +27,7 @@ pub enum ReportCode { WrongNumberOfArguments(usize, usize), UndefinedFunction, UndefinedTemplate, + UndefinedBus, UninitializedSymbolInExpression, UnableToTypeFunction, UnreachableConstraints, @@ -190,6 +191,7 @@ impl fmt::Display for ReportCode { UnreachableTags => "T2049", UnreachableSignals => "T2050", MainComponentWithTags => "T2051", + UndefinedBus => "T2052", RuntimeError => "T3001", RuntimeWarning => "T3002", UnknownDimension => "T20460", diff --git a/program_structure/src/program_library/template_data.rs b/program_structure/src/program_library/template_data.rs index c35b04ba6..c8592410a 100644 --- a/program_structure/src/program_library/template_data.rs +++ b/program_structure/src/program_library/template_data.rs @@ -1,7 +1,7 @@ use super::ast; use super::ast::{FillMeta, Statement}; use super::file_definition::{FileID, FileLocation}; -use super::wire_data::{TagInfo, WireInfo, WireData, WireType, WireDeclarationOrder}; +use super::wire_data::*; use std::collections::{HashMap}; pub type TemplateInfo = HashMap; @@ -156,68 +156,55 @@ fn fill_inputs_and_outputs( input_declarations: &mut WireDeclarationOrder, output_declarations: &mut WireDeclarationOrder ) { + use Statement::*; match template_statement { - Statement::IfThenElse { if_case, else_case, .. } => { + IfThenElse { if_case, else_case, .. } => { fill_inputs_and_outputs(if_case, input_wires, output_wires, input_declarations, output_declarations); if let Option::Some(else_value) = else_case { fill_inputs_and_outputs(else_value, input_wires, output_wires, input_declarations, output_declarations); } } - Statement::Block { stmts, .. } => { + Block { stmts, .. } => { for stmt in stmts.iter() { fill_inputs_and_outputs(stmt, input_wires, output_wires, input_declarations, output_declarations); } } - Statement::While { stmt, .. } => { + While { stmt, .. } => { fill_inputs_and_outputs(stmt, input_wires, output_wires, input_declarations, output_declarations); } - Statement::InitializationBlock { initializations, .. } => { + InitializationBlock { initializations, .. } => { for initialization in initializations.iter() { fill_inputs_and_outputs(initialization, input_wires, output_wires, input_declarations, output_declarations); } } - Statement::Declaration { xtype, name, dimensions, .. } => { - if let ast::VariableType::Signal(stype, tag_list) = xtype { - let signal_name = name.clone(); - let dim = dimensions.len(); - let mut tag_info = TagInfo::new(); - for tag in tag_list{ - tag_info.insert(tag.clone()); - } - let wire_data = WireData::new(WireType::Signal,dim,tag_info); - - match stype { - ast::SignalType::Input => { - input_wires.insert(signal_name.clone(), wire_data); - input_declarations.push((signal_name,dim)); + Declaration { xtype, name, dimensions, .. } => { + match xtype { + ast::VariableType::Signal(stype, tag_list) | ast::VariableType::Bus(stype, tag_list) => { + let wire_name = name.clone(); + let dim = dimensions.len(); + let mut tag_info = TagInfo::new(); + for tag in tag_list{ + tag_info.insert(tag.clone()); } - ast::SignalType::Output => { - output_wires.insert(signal_name.clone(), wire_data); - output_declarations.push((signal_name,dim)); - } - _ => {} //no need to deal with intermediate signals - } - } - else if let ast::VariableType::Bus(stype, tag_list) = xtype { - let bus_name = name.clone(); - let dim = dimensions.len(); - let mut tag_info = TagInfo::new(); - for tag in tag_list{ - tag_info.insert(tag.clone()); - } - let wire_data = WireData::new(WireType::Bus,dim,tag_info); + let wire_data = if let ast::VariableType::Signal(_,_) = xtype { + WireData::new(WireType::Signal,dim,tag_info) + } else { + WireData::new(WireType::Bus,dim,tag_info) + }; - match stype { - ast::SignalType::Input => { - input_wires.insert(bus_name.clone(), wire_data); - input_declarations.push((bus_name,dim)); - } - ast::SignalType::Output => { - output_wires.insert(bus_name.clone(), wire_data); - output_declarations.push((bus_name,dim)); + match stype { + ast::SignalType::Input => { + input_wires.insert(wire_name.clone(), wire_data); + input_declarations.push((wire_name,dim)); + } + ast::SignalType::Output => { + output_wires.insert(wire_name.clone(), wire_data); + output_declarations.push((wire_name,dim)); + } + _ => {} //no need to deal with intermediate signals } - _ => {} //no need to deal with intermediate signals } + _ => {} } } _ => {} diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs new file mode 100644 index 000000000..6d11ae313 --- /dev/null +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -0,0 +1,223 @@ +use program_structure::ast::*; +use program_structure::error_code::ReportCode; +use program_structure::error_definition::{Report, ReportCollection}; +use program_structure::file_definition; +use program_structure::bus_data::BusData; +use std::collections::HashSet; + +pub fn free_of_invalid_statements( + bus_data: &BusData, + bus_names: &HashSet, +) -> Result<(), ReportCollection> { + let body = bus_data.get_body(); + let mut reports = Vec::new(); + analyse_statement(body, bus_names, &mut reports); + if reports.is_empty() { + Result::Ok(()) + } else { + Result::Err(reports) + } +} + +fn analyse_statement( + stmt: &Statement, + bus_names: &HashSet, + reports: &mut ReportCollection, +) { + use Statement::*; + let file_id = stmt.get_meta().get_file_id(); + match stmt { + MultSubstitution { .. } => unreachable!(), + IfThenElse { .. } => { + let mut report = Report::error( + "Conditional statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + While { .. } => { + let mut report = Report::error( + "Loop statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + Block { stmts, .. } => { + for stmt in stmts.iter() { + analyse_statement(stmt, bus_names, reports); + } + }, + InitializationBlock { meta, xtype, initializations } => { + let mut report = Report::error( + "Initialization statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + Declaration { meta, xtype, dimensions, .. } => { + match xtype { + VariableType::Signal(stype, tag_list) if stype == ast::SignalType::Intermediate | + VariableType::Bus(stype, tag_list) if stype == ast::SignalType::Intermediate => { + for dimension in dimensions.iter() { + analyse_expression(dimension, bus_names, reports); + } + }, + _ => { + let mut report = Report::error( + "Template elements declared inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Declaring template element".to_string()); + reports.push(report); + } + } + }, + Substitution { .. } | UnderscoreSubstitution { .. } => { + let mut report = Report::error( + "Substitution statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + ConstraintEquality { .. } => { + let mut report = Report::error( + "Constraint statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + LogCall { .. } => { + let mut report = Report::error( + "I/O statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + Assert { .. } => { + let mut report = Report::error( + "Assert statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + Return { .. } => { + let mut report = Report::error( + "Return statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + }, + } +} + +fn analyse_expression( + expr: &Expression, + bus_names: &HashSet, + reports: &mut ReportCollection, +) { + use Expression::*; + let file_id = expr.get_meta().get_file_id(); + match expr { + InfixOp { lhe, rhe, .. } => { + analyse_expression(lhe, bus_names, reports); + analyse_expression(rhe, bus_names, reports); + } + PrefixOp { rhe, .. } => { + analyse_expression(rhe, bus_names, reports); + } + ParallelOp{ rhe, ..} =>{ + analyse_expression(rhe, bus_names, reports); + } + InlineSwitchOp { cond, if_true, if_false, .. } => { + analyse_expression(cond, bus_names, reports); + analyse_expression(if_true, bus_names, reports); + analyse_expression(if_false, bus_names, reports); + } + Variable { meta, access, .. } => analyse_access(access, meta, bus_names, reports), + Number(..) => {} + Call { meta, id, args, .. } => { + if !bus_names.contains(id) { + let mut report = Report::error( + format!("Unknown call in bus"), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id.clone(), format!("Is not a function call")); + reports.push(report); + } + for arg in args.iter() { + analyse_expression(arg, bus_names, reports); + } + } + ArrayInLine { values, .. } => { + for value in values.iter() { + analyse_expression(value, bus_names, reports); + } + } + UniformArray {value, dimension, .. } => { + analyse_expression(value, bus_names, reports); + analyse_expression(dimension, bus_names, reports); + } + BusCall { meta, .. } => { + let mut report = Report::error( + "Template elements declared inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Declaring template element".to_string()); + reports.push(report); + }, + _ => {unreachable!("Anonymous calls should not be reachable at this point."); } + } +} + +fn analyse_access( + access: &Vec, + meta: &Meta, + bus_names: &HashSet, + reports: &mut ReportCollection, +) { + let file_id = meta.get_file_id(); + for acc in access.iter() { + if let Access::ArrayAccess(index) = acc { + analyse_expression(index, bus_names, reports); + } else { + let mut report = Report::error( + format!("Bus uses component operators"), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id.clone(), format!("Template operator found")); + reports.push(report); + } + } +} \ No newline at end of file diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index ddbfe0bd4..1fd86b298 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -844,10 +844,6 @@ fn apply_access_to_symbol( let output = program_archive.get_template_data(&template_name).get_output_info(&signal_name); let tags; (current_dim, tags) = match (input, output) { - //(Option::Some((d, tags)), _) | (_, Option::Some((d, tags))) => (*d, tags), - //_ => { - // return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); - //} (Option::Some(wire_data), _) | (_, Option::Some(wire_data)) => (wire_data.get_dimension(), wire_data.get_tags()), _ => { From ea6c6b460f9c0ed0c84ec02deb35a76a55d4b218 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Fri, 22 Mar 2024 12:55:28 +0100 Subject: [PATCH 008/189] Added string representing the name of the type to VariableType::Bus and WireType::Bus. --- parser/src/lang.lalrpop | 10 +-- .../src/abstract_syntax_tree/ast.rs | 2 +- .../src/program_library/bus_data.rs | 82 ++++++++++++++----- .../src/program_library/program_merger.rs | 2 +- .../src/program_library/template_data.rs | 36 ++++++-- .../src/program_library/wire_data.rs | 2 +- type_analysis/src/analyzers/type_check.rs | 2 +- 7 files changed, 97 insertions(+), 39 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index 8b7c97fea..a5462a73d 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -190,19 +190,19 @@ SignalHeader : VariableType = { BusHeader : (Expression, VariableType) = { => { - let bus_builder = build_bus_call(Meta::new(s,e),id,Vec::new()); + let bus_builder = build_bus_call(Meta::new(s,e),id.clone(),Vec::new()); let (s,t) = header; - (bus_builder,VariableType::Bus(s, t)) + (bus_builder,VariableType::Bus(id, s, t)) }, "(" ")" => { let bus_builder = match args { - None => build_bus_call(Meta::new(s,e),id,Vec::new()), - Some(a) => build_bus_call(Meta::new(s,e),id,a), + None => build_bus_call(Meta::new(s,e),id.clone(),Vec::new()), + Some(a) => build_bus_call(Meta::new(s,e),id.clone(),a), }; let (s,t) = header; - (bus_builder,VariableType::Bus(s, t)) + (bus_builder,VariableType::Bus(id, s, t)) } }; diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index bb47892b5..c60e3cda0 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -277,7 +277,7 @@ pub enum VariableType { Signal(SignalType, TagList), Component, AnonymousComponent, - Bus(SignalType, TagList), + Bus(String, SignalType, TagList), } #[derive(Clone)] diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs index 57bc6c223..77835cf06 100644 --- a/program_structure/src/program_library/bus_data.rs +++ b/program_structure/src/program_library/bus_data.rs @@ -7,19 +7,21 @@ pub type BusInfo = HashMap; #[derive(Clone)] pub struct BusData { - name: String, file_id: FileID, + name: String, + body: Statement, num_of_params: usize, name_of_params: Vec, param_location: FileLocation, fields: WireInfo, - body: Statement, + /* Only used to know the order in which fields are declared.*/ + field_declarations: WireDeclarationOrder, } impl BusData { pub fn new( - name: String, file_id: FileID, + name: String, mut body: Statement, num_of_params: usize, name_of_params: Vec, @@ -27,16 +29,39 @@ impl BusData { elem_id: &mut usize, ) -> BusData { body.fill(file_id, elem_id); - let fields = WireInfo::new(); - + let mut fields = WireInfo::new(); + let mut field_declarations = WireDeclarationOrder::new(); + fill_fields(&body, &mut fields, &mut field_declarations); BusData { - name, - file_id, - body, - name_of_params, - param_location, + file_id, + name, + body, num_of_params, - fields + name_of_params, + param_location, + fields, + field_declarations + } + } + pub fn copy( + file_id: FileID, + name: String, + body: Statement, + num_of_params: usize, + name_of_params: Vec, + param_location: FileLocation, + fields: WireInfo, + field_declarations: WireDeclarationOrder + ) -> BusData { + BusData { + file_id, + name, + body, + num_of_params, + name_of_params, + param_location, + fields, + field_declarations } } pub fn get_file_id(&self) -> FileID { @@ -84,39 +109,54 @@ impl BusData { pub fn get_fields(&self) -> &WireInfo { &self.fields } + pub fn get_declaration_fields(&self) -> &WireDeclarationOrder { + &self.field_declarations + } } fn fill_fields( bus_statement: &Statement, fields: &mut WireInfo, + field_declarations: &mut WireDeclarationOrder ) { use Statement::*; match bus_statement { Block { stmts, .. } => { for stmt in stmts.iter() { - fill_fields(stmt, fields); + fill_fields(stmt, fields, field_declarations); } } Declaration { xtype, name, dimensions, .. } => { match xtype { - VariableType::Signal(stype, tag_list) | VariableType::Bus(stype, tag_list) => { + VariableType::Signal(stype, tag_list) => { + if *stype == SignalType::Intermediate { + let wire_name = name.clone(); + let dim = dimensions.len(); + let mut tag_info = TagInfo::new(); + for tag in tag_list { + tag_info.insert(tag.clone()); + } + let field_data = WireData::new(WireType::Signal,dim,tag_info); + fields.insert(wire_name.clone(), field_data); + field_declarations.push((wire_name,dim)); + } + }, + VariableType::Bus(tname, stype, tag_list) => { if *stype == SignalType::Intermediate { let wire_name = name.clone(); let dim = dimensions.len(); + let type_name = tname.clone(); let mut tag_info = TagInfo::new(); for tag in tag_list { tag_info.insert(tag.clone()); } - let field_data = if let VariableType::Signal(_,_) = xtype { - WireData::new(WireType::Signal,dim,tag_info) - } else { - WireData::new(WireType::Bus,dim,tag_info) - }; - fields.insert(wire_name, field_data); + let field_data = WireData::new(WireType::Bus(type_name),dim,tag_info); + fields.insert(wire_name.clone(), field_data); + field_declarations.push((wire_name,dim)); } - } - _ => {} + }, + _ => {}, } } _ => {} diff --git a/program_structure/src/program_library/program_merger.rs b/program_structure/src/program_library/program_merger.rs index a0eb81ad9..5d2d808e8 100644 --- a/program_structure/src/program_library/program_merger.rs +++ b/program_structure/src/program_library/program_merger.rs @@ -73,8 +73,8 @@ impl Merger { (Option::Some(name), meta) } else { let new_data = BusData::new( - name.clone(), file_id, + name.clone(), body, args.len(), args, diff --git a/program_structure/src/program_library/template_data.rs b/program_structure/src/program_library/template_data.rs index c8592410a..c4b343d90 100644 --- a/program_structure/src/program_library/template_data.rs +++ b/program_structure/src/program_library/template_data.rs @@ -133,7 +133,7 @@ impl TemplateData { &self.output_wires } pub fn get_declaration_inputs(&self) -> &WireDeclarationOrder { - &&self.input_declarations + &self.input_declarations } pub fn get_declaration_outputs(&self) -> &WireDeclarationOrder { &self.output_declarations @@ -179,18 +179,14 @@ fn fill_inputs_and_outputs( } Declaration { xtype, name, dimensions, .. } => { match xtype { - ast::VariableType::Signal(stype, tag_list) | ast::VariableType::Bus(stype, tag_list) => { + ast::VariableType::Signal(stype, tag_list) => { let wire_name = name.clone(); let dim = dimensions.len(); let mut tag_info = TagInfo::new(); for tag in tag_list{ tag_info.insert(tag.clone()); } - let wire_data = if let ast::VariableType::Signal(_,_) = xtype { - WireData::new(WireType::Signal,dim,tag_info) - } else { - WireData::new(WireType::Bus,dim,tag_info) - }; + let wire_data = WireData::new(WireType::Signal,dim,tag_info); match stype { ast::SignalType::Input => { @@ -203,8 +199,30 @@ fn fill_inputs_and_outputs( } _ => {} //no need to deal with intermediate signals } - } - _ => {} + }, + ast::VariableType::Bus(tname, stype, tag_list) => { + let wire_name = name.clone(); + let dim = dimensions.len(); + let type_name = tname.clone(); + let mut tag_info = TagInfo::new(); + for tag in tag_list{ + tag_info.insert(tag.clone()); + } + let wire_data = WireData::new(WireType::Bus(type_name),dim,tag_info); + + match stype { + ast::SignalType::Input => { + input_wires.insert(wire_name.clone(), wire_data); + input_declarations.push((wire_name,dim)); + } + ast::SignalType::Output => { + output_wires.insert(wire_name.clone(), wire_data); + output_declarations.push((wire_name,dim)); + } + _ => {} //no need to deal with intermediate signals + } + }, + _ => {}, } } _ => {} diff --git a/program_structure/src/program_library/wire_data.rs b/program_structure/src/program_library/wire_data.rs index a4d81ab29..8e539a89f 100644 --- a/program_structure/src/program_library/wire_data.rs +++ b/program_structure/src/program_library/wire_data.rs @@ -9,7 +9,7 @@ pub type WireDeclarationOrder = Vec<(String, usize)>; #[derive(Clone, PartialEq, Eq)] pub enum WireType { Signal, - Bus, + Bus(String), } diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 1fd86b298..9a7224e3e 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -167,7 +167,7 @@ fn type_statement( VariableType::AnonymousComponent => analysis_information .environment .add_component(name, (meta.component_inference.clone(), dimensions.len())), - VariableType::Bus(s_type, tags) => { + VariableType::Bus(tname, stype, tags) => { // TODO: unreachable!("TODO") } From 1abd9ef1694811927c1064c6f5b4c9368ff842ab Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 23 Mar 2024 19:57:01 +0100 Subject: [PATCH 009/189] Included bus treatment in symbol_analysis. --- parser/src/lang.lalrpop | 2 +- .../abstract_syntax_tree/expression_impl.rs | 12 +-- .../abstract_syntax_tree/statement_impl.rs | 8 +- .../analyzers/signal_declaration_analysis.rs | 6 +- .../src/analyzers/symbol_analysis.rs | 73 ++++++++++++++----- 5 files changed, 69 insertions(+), 32 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index a5462a73d..ae8387450 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -523,7 +523,7 @@ ParseVarAccess : Access = { => build_component_access(component_acc), }; ParseArrayAcc: Expression = { - "[""]" => dim + "[" "]" => dim }; ParseComponentAcc: String = { "." => id, diff --git a/program_structure/src/abstract_syntax_tree/expression_impl.rs b/program_structure/src/abstract_syntax_tree/expression_impl.rs index 33e973c7a..63a157b25 100644 --- a/program_structure/src/abstract_syntax_tree/expression_impl.rs +++ b/program_structure/src/abstract_syntax_tree/expression_impl.rs @@ -14,9 +14,9 @@ impl Expression { | Number(meta, ..) | Call { meta, .. } | AnonymousComp { meta, ..} - | ArrayInLine { meta, .. } => meta, - | UniformArray { meta, .. } => meta, - | Tuple {meta, ..} => meta, + | ArrayInLine { meta, .. } + | UniformArray { meta, .. } + | Tuple {meta, ..} | BusCall { meta, .. } => meta, } } @@ -31,9 +31,9 @@ impl Expression { | Number(meta, ..) | Call { meta, .. } | AnonymousComp {meta, ..} - | ArrayInLine { meta, .. } => meta, - | UniformArray { meta, .. } => meta, - | Tuple {meta, ..} => meta, + | ArrayInLine { meta, .. } + | UniformArray { meta, .. } + | Tuple {meta, ..} | BusCall {meta, ..} => meta, } } diff --git a/program_structure/src/abstract_syntax_tree/statement_impl.rs b/program_structure/src/abstract_syntax_tree/statement_impl.rs index 7b8463e72..9fd59ccf7 100644 --- a/program_structure/src/abstract_syntax_tree/statement_impl.rs +++ b/program_structure/src/abstract_syntax_tree/statement_impl.rs @@ -13,8 +13,8 @@ impl Statement { | Block { meta, .. } | Assert { meta, .. } | ConstraintEquality { meta, .. } - | InitializationBlock { meta, .. } => meta, - | MultSubstitution { meta, ..} => meta, + | InitializationBlock { meta, .. } + | MultSubstitution { meta, ..} | UnderscoreSubstitution { meta, .. } => meta, } } @@ -30,8 +30,8 @@ impl Statement { | Block { meta, .. } | Assert { meta, .. } | ConstraintEquality { meta, .. } - | InitializationBlock { meta, .. } => meta, - | MultSubstitution { meta, ..} => meta, + | InitializationBlock { meta, .. } + | MultSubstitution { meta, ..} | UnderscoreSubstitution { meta, .. } => meta, } } diff --git a/type_analysis/src/analyzers/signal_declaration_analysis.rs b/type_analysis/src/analyzers/signal_declaration_analysis.rs index aa63f7a60..bfba85b00 100644 --- a/type_analysis/src/analyzers/signal_declaration_analysis.rs +++ b/type_analysis/src/analyzers/signal_declaration_analysis.rs @@ -41,10 +41,12 @@ fn treat_statement( } } InitializationBlock { meta, xtype, .. } => match xtype { - VariableType::Signal(_, _) | VariableType::Component => { + VariableType::Signal(_, _) + | VariableType::Bus(_, _, _) + | VariableType::Component => { if !signal_declaration_allowed { let mut report = Report::error( - "Signal or component declaration inside While scope. Signal and component can only be defined in the initial scope or in If scopes with known condition".to_string(), + "Signal, bus or component declaration inside While scope. Signals, buses and components can only be defined in the initial scope or in If scopes with known condition".to_string(), ReportCode::SignalOutsideOriginalScope, ); let location = diff --git a/type_analysis/src/analyzers/symbol_analysis.rs b/type_analysis/src/analyzers/symbol_analysis.rs index fe723dbc5..3590e9821 100644 --- a/type_analysis/src/analyzers/symbol_analysis.rs +++ b/type_analysis/src/analyzers/symbol_analysis.rs @@ -2,9 +2,10 @@ use program_structure::ast::{Access, Expression, Meta, Statement, LogArgument}; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; use program_structure::file_definition::{self, FileID, FileLocation}; -use program_structure::function_data::FunctionInfo; use program_structure::program_archive::ProgramArchive; +use program_structure::function_data::FunctionInfo; use program_structure::template_data::TemplateInfo; +use program_structure::bus_data::BusInfo; use std::collections::HashSet; type Block = HashSet; type Environment = Vec; @@ -12,6 +13,7 @@ type Environment = Vec; pub fn check_naming_correctness(program_archive: &ProgramArchive) -> Result<(), ReportCollection> { let template_info = program_archive.get_templates(); let function_info = program_archive.get_functions(); + let bus_info = program_archive.get_buses(); let mut reports = ReportCollection::new(); let mut instances = Vec::new(); for (_, data) in template_info { @@ -32,6 +34,15 @@ pub fn check_naming_correctness(program_archive: &ProgramArchive) -> Result<(), ); instances.push(instance); } + for (_, data) in bus_info { + let instance = ( + data.get_file_id(), + data.get_param_location(), + data.get_name_of_params(), + data.get_body_as_vec(), + ); + instances.push(instance); + } if let Err(mut r) = analyze_main(program_archive) { reports.append(&mut r); } @@ -43,6 +54,7 @@ pub fn check_naming_correctness(program_archive: &ProgramArchive) -> Result<(), body, function_info, template_info, + bus_info, ); if let Result::Err(mut r) = res { reports.append(&mut r); @@ -60,6 +72,7 @@ fn analyze_main(program: &ProgramArchive) -> Result<(), Vec> { let signals = program.get_public_inputs_main_component(); let template_info = program.get_templates(); let function_info = program.get_functions(); + let bus_info = program.get_buses(); let mut reports = vec![]; if let Expression::Call { id, .. } = call { @@ -87,6 +100,7 @@ fn analyze_main(program: &ProgramArchive) -> Result<(), Vec> { call.get_meta().get_file_id(), function_info, template_info, + bus_info, &mut reports, &environment, ); @@ -101,6 +115,7 @@ pub fn analyze_symbols( body: &[Statement], function_info: &FunctionInfo, template_info: &TemplateInfo, + bus_info: &BusInfo, ) -> Result<(), ReportCollection> { let mut param_name_collision = false; let mut reports = ReportCollection::new(); @@ -126,6 +141,7 @@ pub fn analyze_symbols( file_id, function_info, template_info, + bus_info, &mut reports, &mut environment, ); @@ -160,19 +176,20 @@ fn analyze_statement( file_id: FileID, function_info: &FunctionInfo, template_info: &TemplateInfo, + bus_info: &BusInfo, reports: &mut ReportCollection, environment: &mut Environment, ) { match stmt { Statement::MultSubstitution { .. } => unreachable!(), Statement::Return { value, .. } => { - analyze_expression(value, file_id, function_info, template_info, reports, environment) + analyze_expression(value, file_id, function_info, template_info, bus_info, reports, environment) } Statement::UnderscoreSubstitution { rhe, .. } => { - analyze_expression(rhe, file_id, function_info, template_info, reports, environment); + analyze_expression(rhe, file_id, function_info, template_info, bus_info, reports, environment); } Statement::Substitution { meta, var, access, rhe, .. } => { - analyze_expression(rhe, file_id, function_info, template_info, reports, environment); + analyze_expression(rhe, file_id, function_info, template_info, bus_info, reports, environment); treat_variable( meta, var, @@ -180,13 +197,14 @@ fn analyze_statement( file_id, function_info, template_info, + bus_info, reports, environment, ); } Statement::ConstraintEquality { lhe, rhe, .. } => { - analyze_expression(lhe, file_id, function_info, template_info, reports, environment); - analyze_expression(rhe, file_id, function_info, template_info, reports, environment); + analyze_expression(lhe, file_id, function_info, template_info, bus_info, reports, environment); + analyze_expression(rhe, file_id, function_info, template_info, bus_info, reports, environment); } Statement::InitializationBlock { initializations, .. } => { for initialization in initializations.iter() { @@ -195,6 +213,7 @@ fn analyze_statement( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -207,6 +226,7 @@ fn analyze_statement( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -227,12 +247,12 @@ fn analyze_statement( Statement::LogCall { args, .. } => { for logarg in args { if let LogArgument::LogExp(arg) = logarg { - analyze_expression(arg, file_id, function_info, template_info, reports, environment); + analyze_expression(arg, file_id, function_info, template_info, bus_info, reports, environment); } } } Statement::Assert { arg, .. } => { - analyze_expression(arg, file_id, function_info, template_info, reports, environment) + analyze_expression(arg, file_id, function_info, template_info, bus_info, reports, environment) } Statement::Block { stmts, .. } => { environment.push(Block::new()); @@ -242,6 +262,7 @@ fn analyze_statement( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -249,18 +270,19 @@ fn analyze_statement( environment.pop(); } Statement::While { stmt, cond, .. } => { - analyze_expression(cond, file_id, function_info, template_info, reports, environment); - analyze_statement(stmt, file_id, function_info, template_info, reports, environment); + analyze_expression(cond, file_id, function_info, template_info, bus_info, reports, environment); + analyze_statement(stmt, file_id, function_info, template_info, bus_info, reports, environment); } Statement::IfThenElse { cond, if_case, else_case, .. } => { - analyze_expression(cond, file_id, function_info, template_info, reports, environment); - analyze_statement(if_case, file_id, function_info, template_info, reports, environment); + analyze_expression(cond, file_id, function_info, template_info, bus_info, reports, environment); + analyze_statement(if_case, file_id, function_info, template_info, bus_info, reports, environment); if let Option::Some(else_stmt) = else_case { analyze_statement( else_stmt, file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -276,6 +298,7 @@ fn treat_variable( file_id: FileID, function_info: &FunctionInfo, template_info: &TemplateInfo, + bus_info: &BusInfo, reports: &mut ReportCollection, environment: &Environment, ) { @@ -289,8 +312,11 @@ fn treat_variable( reports.push(report); } for acc in access.iter() { - if let Access::ArrayAccess(index) = acc { - analyze_expression(index, file_id, function_info, template_info, reports, environment); + match acc { + Access::ArrayAccess(index) => { + analyze_expression(index, file_id, function_info, template_info, bus_info, reports, environment); + } + Access::ComponentAccess(_) => {} } } } @@ -300,27 +326,29 @@ fn analyze_expression( file_id: FileID, function_info: &FunctionInfo, template_info: &TemplateInfo, + bus_info: &BusInfo, reports: &mut ReportCollection, environment: &Environment, ) { match expression { Expression::InfixOp { lhe, rhe, .. } => { - analyze_expression(lhe, file_id, function_info, template_info, reports, environment); - analyze_expression(rhe, file_id, function_info, template_info, reports, environment); + analyze_expression(lhe, file_id, function_info, template_info, bus_info, reports, environment); + analyze_expression(rhe, file_id, function_info, template_info, bus_info, reports, environment); } Expression::PrefixOp { rhe, .. } => { - analyze_expression(rhe, file_id, function_info, template_info, reports, environment) + analyze_expression(rhe, file_id, function_info, template_info, bus_info, reports, environment) } Expression::ParallelOp { rhe, .. } => { - analyze_expression(rhe, file_id, function_info, template_info, reports, environment) + analyze_expression(rhe, file_id, function_info, template_info, bus_info, reports, environment) } Expression::InlineSwitchOp { cond, if_true, if_false, .. } => { - analyze_expression(cond, file_id, function_info, template_info, reports, environment); + analyze_expression(cond, file_id, function_info, template_info, bus_info, reports, environment); analyze_expression( if_true, file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -329,6 +357,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -340,6 +369,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ), @@ -379,6 +409,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -391,6 +422,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -402,6 +434,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -410,6 +443,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ); @@ -422,6 +456,7 @@ fn analyze_expression( file_id, function_info, template_info, + bus_info, reports, environment, ); From e0873062274bd88ab3ed9e8cdd70c9141c2825ed Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 23 Mar 2024 20:53:10 +0100 Subject: [PATCH 010/189] Corrected some errors from buses_free_of_invalid_statements. --- .../buses_free_of_invalid_statements.rs | 73 +++++++++++-------- type_analysis/src/analyzers/mod.rs | 2 + type_analysis/src/check_types.rs | 28 ++++++- 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 6d11ae313..96917244b 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -7,11 +7,11 @@ use std::collections::HashSet; pub fn free_of_invalid_statements( bus_data: &BusData, - bus_names: &HashSet, + function_names: &HashSet, ) -> Result<(), ReportCollection> { let body = bus_data.get_body(); let mut reports = Vec::new(); - analyse_statement(body, bus_names, &mut reports); + analyse_statement(body, function_names, &mut reports); if reports.is_empty() { Result::Ok(()) } else { @@ -21,14 +21,14 @@ pub fn free_of_invalid_statements( fn analyse_statement( stmt: &Statement, - bus_names: &HashSet, + function_names: &HashSet, reports: &mut ReportCollection, ) { use Statement::*; let file_id = stmt.get_meta().get_file_id(); match stmt { MultSubstitution { .. } => unreachable!(), - IfThenElse { .. } => { + IfThenElse { meta, .. } => { let mut report = Report::error( "Conditional statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -38,7 +38,7 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); }, - While { .. } => { + While { meta, .. } => { let mut report = Report::error( "Loop statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -50,7 +50,7 @@ fn analyse_statement( }, Block { stmts, .. } => { for stmt in stmts.iter() { - analyse_statement(stmt, bus_names, reports); + analyse_statement(stmt, function_names, reports); } }, InitializationBlock { meta, xtype, initializations } => { @@ -65,10 +65,21 @@ fn analyse_statement( }, Declaration { meta, xtype, dimensions, .. } => { match xtype { - VariableType::Signal(stype, tag_list) if stype == ast::SignalType::Intermediate | - VariableType::Bus(stype, tag_list) if stype == ast::SignalType::Intermediate => { - for dimension in dimensions.iter() { - analyse_expression(dimension, bus_names, reports); + VariableType::Signal(stype, _) + | VariableType::Bus(_, stype, _) => { + if *stype == SignalType::Intermediate { + for dimension in dimensions.iter() { + analyse_expression(dimension, function_names, reports); + } + } else { + let mut report = Report::error( + "Template elements declared inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Declaring template element".to_string()); + reports.push(report); } }, _ => { @@ -83,7 +94,7 @@ fn analyse_statement( } } }, - Substitution { .. } | UnderscoreSubstitution { .. } => { + Substitution { meta, .. } | UnderscoreSubstitution { meta, .. } => { let mut report = Report::error( "Substitution statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -93,7 +104,7 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); }, - ConstraintEquality { .. } => { + ConstraintEquality { meta, .. } => { let mut report = Report::error( "Constraint statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -103,7 +114,7 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); }, - LogCall { .. } => { + LogCall { meta, .. } => { let mut report = Report::error( "I/O statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -113,7 +124,7 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); }, - Assert { .. } => { + Assert { meta, .. } => { let mut report = Report::error( "Assert statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -123,7 +134,7 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); }, - Return { .. } => { + Return { meta, .. } => { let mut report = Report::error( "Return statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -138,31 +149,31 @@ fn analyse_statement( fn analyse_expression( expr: &Expression, - bus_names: &HashSet, + function_names: &HashSet, reports: &mut ReportCollection, ) { use Expression::*; let file_id = expr.get_meta().get_file_id(); match expr { InfixOp { lhe, rhe, .. } => { - analyse_expression(lhe, bus_names, reports); - analyse_expression(rhe, bus_names, reports); + analyse_expression(lhe, function_names, reports); + analyse_expression(rhe, function_names, reports); } PrefixOp { rhe, .. } => { - analyse_expression(rhe, bus_names, reports); + analyse_expression(rhe, function_names, reports); } ParallelOp{ rhe, ..} =>{ - analyse_expression(rhe, bus_names, reports); + analyse_expression(rhe, function_names, reports); } InlineSwitchOp { cond, if_true, if_false, .. } => { - analyse_expression(cond, bus_names, reports); - analyse_expression(if_true, bus_names, reports); - analyse_expression(if_false, bus_names, reports); + analyse_expression(cond, function_names, reports); + analyse_expression(if_true, function_names, reports); + analyse_expression(if_false, function_names, reports); } - Variable { meta, access, .. } => analyse_access(access, meta, bus_names, reports), + Variable { meta, access, .. } => analyse_access(access, meta, function_names, reports), Number(..) => {} Call { meta, id, args, .. } => { - if !bus_names.contains(id) { + if !function_names.contains(id) { let mut report = Report::error( format!("Unknown call in bus"), ReportCode::UndefinedBus, @@ -173,17 +184,17 @@ fn analyse_expression( reports.push(report); } for arg in args.iter() { - analyse_expression(arg, bus_names, reports); + analyse_expression(arg, function_names, reports); } } ArrayInLine { values, .. } => { for value in values.iter() { - analyse_expression(value, bus_names, reports); + analyse_expression(value, function_names, reports); } } UniformArray {value, dimension, .. } => { - analyse_expression(value, bus_names, reports); - analyse_expression(dimension, bus_names, reports); + analyse_expression(value, function_names, reports); + analyse_expression(dimension, function_names, reports); } BusCall { meta, .. } => { let mut report = Report::error( @@ -202,13 +213,13 @@ fn analyse_expression( fn analyse_access( access: &Vec, meta: &Meta, - bus_names: &HashSet, + function_names: &HashSet, reports: &mut ReportCollection, ) { let file_id = meta.get_file_id(); for acc in access.iter() { if let Access::ArrayAccess(index) = acc { - analyse_expression(index, bus_names, reports); + analyse_expression(index, function_names, reports); } else { let mut report = Report::error( format!("Bus uses component operators"), diff --git a/type_analysis/src/analyzers/mod.rs b/type_analysis/src/analyzers/mod.rs index bcfc47dee..ea4dc9f8f 100644 --- a/type_analysis/src/analyzers/mod.rs +++ b/type_analysis/src/analyzers/mod.rs @@ -1,3 +1,4 @@ +pub use buses_free_of_invalid_statements::free_of_invalid_statements; pub use custom_gate_analysis::custom_gate_analysis; pub use functions_all_paths_with_return_statement::all_paths_with_return_check; pub use functions_free_of_template_elements::free_of_template_elements; @@ -7,6 +8,7 @@ pub use symbol_analysis::check_naming_correctness; pub use type_check::type_check; pub use unknown_known_analysis::unknown_known_analysis; +pub mod buses_free_of_invalid_statements; pub mod custom_gate_analysis; pub mod functions_all_paths_with_return_statement; pub mod functions_free_of_template_elements; diff --git a/type_analysis/src/check_types.rs b/type_analysis/src/check_types.rs index 5cc3c5682..67d51ad7c 100644 --- a/type_analysis/src/check_types.rs +++ b/type_analysis/src/check_types.rs @@ -25,6 +25,11 @@ pub fn check_types( return Result::Err(errors); } + bus_level_analyses(program_archive, &mut errors); + if !errors.is_empty() { + return Result::Err(errors); + } + // Decorators template_level_decorators(program_archive, &mut errors); if !errors.is_empty() { @@ -54,6 +59,11 @@ pub fn check_types( program_archive.remove_template(&name) } } + for name in program_archive.get_bus_names().clone() { + if !info.reached.contains(&name) { + program_archive.remove_bus(&name) + } + } } } @@ -102,12 +112,12 @@ fn template_level_decorators( fn function_level_analyses(program_archive: &ProgramArchive, reports: &mut ReportCollection) { let function_names = program_archive.get_function_names(); for function_data in program_archive.get_functions().values() { - let result_0 = free_of_template_elements(function_data, function_names); - let result_1 = all_paths_with_return_check(function_data); - if let Result::Err(mut functions_free_of_template_elements_reports) = result_0 { + let free_of_template_elements_result = free_of_template_elements(function_data, function_names); + let return_check_result = all_paths_with_return_check(function_data); + if let Result::Err(mut functions_free_of_template_elements_reports) = free_of_template_elements_result { reports.append(&mut functions_free_of_template_elements_reports); } - if let Result::Err(functions_all_paths_with_return_statement_report) = result_1 { + if let Result::Err(functions_all_paths_with_return_statement_report) = return_check_result { reports.push(functions_all_paths_with_return_statement_report); } } @@ -122,6 +132,16 @@ fn function_level_decorators(program_archive: &mut ProgramArchive, reports: &mut } } +fn bus_level_analyses(program_archive: &ProgramArchive, reports: &mut ReportCollection) { + let function_names = program_archive.get_function_names(); + for bus_data in program_archive.get_buses().values() { + let free_of_invalid_statements_result = free_of_invalid_statements(bus_data, function_names); + if let Result::Err(mut free_of_invalid_statements_reports) = free_of_invalid_statements_result { + reports.append(&mut free_of_invalid_statements_reports); + } + } +} + fn semantic_analyses( program_archive: &ProgramArchive, errors: &mut ReportCollection, From 6579e7bb9eb97865a737ff28235e2028450c3575 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sun, 24 Mar 2024 11:01:35 +0100 Subject: [PATCH 011/189] Added constants_handler to bus decorators. --- type_analysis/src/check_types.rs | 14 ++++++++++++++ .../src/decorators/constants_handler.rs | 19 ++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/type_analysis/src/check_types.rs b/type_analysis/src/check_types.rs index 67d51ad7c..7f9007978 100644 --- a/type_analysis/src/check_types.rs +++ b/type_analysis/src/check_types.rs @@ -41,6 +41,11 @@ pub fn check_types( return Result::Err(errors); } + bus_level_decorators(program_archive, &mut errors); + if !errors.is_empty() { + return Result::Err(errors); + } + // Type analysis let typing_result = type_check(program_archive); match typing_result { @@ -142,6 +147,15 @@ fn bus_level_analyses(program_archive: &ProgramArchive, reports: &mut ReportColl } } +fn bus_level_decorators(program_archive: &mut ProgramArchive, reports: &mut ReportCollection) { + for bus_data in program_archive.get_mut_buses().values_mut() { + let mut constant_handler_reports = + constants_handler::handle_bus_constants(bus_data); + //type_reduction::reduce_bus(bus_data); + reports.append(&mut constant_handler_reports); + } +} + fn semantic_analyses( program_archive: &ProgramArchive, errors: &mut ReportCollection, diff --git a/type_analysis/src/decorators/constants_handler.rs b/type_analysis/src/decorators/constants_handler.rs index da8d70ce7..90edda577 100644 --- a/type_analysis/src/decorators/constants_handler.rs +++ b/type_analysis/src/decorators/constants_handler.rs @@ -4,7 +4,9 @@ use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; use program_structure::expression_builders::*; use program_structure::utils::environment::VarEnvironment; -use program_structure::{function_data::FunctionData, template_data::TemplateData}; +use program_structure::function_data::FunctionData; +use program_structure::template_data::TemplateData; +use program_structure::bus_data::BusData; use std::collections::HashSet; type Constants = VarEnvironment; @@ -37,6 +39,17 @@ pub fn _handle_template_constants(template: &mut TemplateData) -> ReportCollecti expand_statement(template.get_mut_body(), &mut expression_holder); reports } +pub fn handle_bus_constants(bus: &mut BusData) -> ReportCollection { + let mut environment = Constants::new(); + let mut expression_holder = ExpressionHolder::new(); + for p in bus.get_name_of_params() { + environment.add_variable(p, false); + } + statement_constant_inference(bus.get_mut_body(), &mut environment); + let reports = statement_invariant_check(bus.get_body(), &mut environment); + expand_statement(bus.get_mut_body(), &mut expression_holder); + reports +} // Set of functions used to infer the constant tag in variable declarations fn statement_constant_inference(stmt: &mut Statement, environment: &mut Constants) { @@ -49,7 +62,7 @@ fn statement_constant_inference(stmt: &mut Statement, environment: &mut Constant InitializationBlock { initializations, .. } => { initialization_block_constant_inference(initializations, environment) } - While { stmt, .. } => while_stmt_constant_inference(stmt, environment), + While { stmt, .. } => while_constant_inference(stmt, environment), Block { stmts, .. } => block_constant_inference(stmts, environment), _ => {} } @@ -84,7 +97,7 @@ fn initialization_block_constant_inference( } } -fn while_stmt_constant_inference(stmt: &mut Statement, environment: &mut Constants) { +fn while_constant_inference(stmt: &mut Statement, environment: &mut Constants) { statement_constant_inference(stmt, environment) } From 8f2ba5e8a57dfeb9d00563f4555a41aff848e2da Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 9 Apr 2024 18:31:28 +0200 Subject: [PATCH 012/189] working on execute --- .../environment_utils/bus_representation.rs | 94 +++++++++++++++++++ .../src/environment_utils/environment.rs | 2 + .../src/environment_utils/mod.rs | 1 + .../src/environment_utils/slice_types.rs | 4 + .../src/execution_data/executed_bus.rs | 77 +++++++++++++++ .../src/execution_data/executed_program.rs | 12 +++ .../src/execution_data/executed_template.rs | 22 +++++ .../src/execution_data/mod.rs | 1 + .../src/execution_data/type_definitions.rs | 8 ++ 9 files changed, 221 insertions(+) create mode 100644 constraint_generation/src/environment_utils/bus_representation.rs create mode 100644 constraint_generation/src/execution_data/executed_bus.rs diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs new file mode 100644 index 000000000..32dcdc6e3 --- /dev/null +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -0,0 +1,94 @@ +use super::slice_types::{MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo}; +use crate::execution_data::type_definitions::NodePointer; +use crate::execution_data::ExecutedProgram; +use std::collections::{BTreeMap,HashMap, HashSet}; +use crate::ast::Meta; + +#[derive(Clone)] +struct FieldTypes { // For each field, we store the info depending on if it is a signal o a bus + // Depending on the case we store a different slice + pub signal: Option, + pub bus: Option, +} + +pub struct BusRepresentation { + pub node_pointer: Option, + pub meta: Option, + pub fields: BTreeMap, + pub field_tags: BTreeMap, +} + +impl Default for BusRepresentation { + fn default() -> Self { + BusRepresentation { + node_pointer: Option::None, + fields: BTreeMap::new(), + field_tags: BTreeMap::new(), + meta: Option::None, + } + } +} +impl Clone for BusRepresentation { + fn clone(&self) -> Self { + BusRepresentation { + node_pointer: self.node_pointer, + fields: self.fields.clone(), + field_tags: self.field_tags.clone(), + meta : self.meta.clone(), + } + } +} + +impl BusRepresentation { + + pub fn initialize_bus( + component: &mut BusRepresentation, + node_pointer: NodePointer, + scheme: &ExecutedProgram, + ) -> Result<(), MemoryError> { + let possible_node = ExecutedProgram::get_bus_node(scheme, node_pointer); + assert!(possible_node.is_some()); + let node = possible_node.unwrap(); + + // Distinguir si es bus o señal y crear la Slice correspondiente + // En caso de los buses, crear e inicializar componentRepresentation de todos + + for (symbol, route) in node.signal_fields() { + + } + for (symbol, route) in node.bus_fields() { + + } + + component.node_pointer = Option::Some(node_pointer); + + + Result::Ok(()) + } + + pub fn get_field(&self, field_name: &str) -> Result<(&TagInfo, &SignalSlice), MemoryError> { + + // Devuelve las tags y la SignalSlice con los valores + // Si es un bus, llamar a que cada uno devuelva todo (get_all_fields) + unreachable!() + } + + fn get_all_fields(&self) -> Result<&SignalSlice, MemoryError>{ + // TODO + unreachable!() + } + + pub fn assign_value_to_field( + component: &mut BusRepresentation, + field_name: &str, + access: &[SliceCapacity], + slice_route: &[SliceCapacity], + tags: TagInfo, + ) -> Result<(), MemoryError> { + // TODO + unreachable!() + } + + + +} diff --git a/constraint_generation/src/environment_utils/environment.rs b/constraint_generation/src/environment_utils/environment.rs index 3dca8c5a8..6a06cc387 100644 --- a/constraint_generation/src/environment_utils/environment.rs +++ b/constraint_generation/src/environment_utils/environment.rs @@ -15,6 +15,8 @@ use crate::ast::Meta; pub type ExecutionEnvironmentError = CircomEnvironmentError; pub type ExecutionEnvironment = CircomEnvironment; +// TODO: ADD environment buses -> BusSlice + pub fn environment_shortcut_add_component( environment: &mut ExecutionEnvironment, component_name: &str, diff --git a/constraint_generation/src/environment_utils/mod.rs b/constraint_generation/src/environment_utils/mod.rs index 4cb388acd..0e9f36cad 100644 --- a/constraint_generation/src/environment_utils/mod.rs +++ b/constraint_generation/src/environment_utils/mod.rs @@ -2,6 +2,7 @@ use super::ArithmeticExpression; use program_structure::environment::{CircomEnvironment, CircomEnvironmentError}; use program_structure::utils::memory_slice; +mod bus_representation; mod component_representation; pub mod environment; pub mod slice_types; diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index 83e99fc4b..685fabcb1 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -1,4 +1,5 @@ pub use super::component_representation::ComponentRepresentation; +pub use super::bus_representation::BusRepresentation; pub use super::memory_slice::MemorySlice; pub use super::memory_slice::{MemoryError, TypeInvalidAccess, TypeAssignmentError, SliceCapacity}; pub use circom_algebra::algebra::ArithmeticExpression; @@ -17,3 +18,6 @@ pub type AExpressionSlice = MemorySlice>; // The boolean is true if the signal contains a value pub type SignalSlice = MemorySlice; pub type ComponentSlice = MemorySlice; + +// To store the buses, similar to the components +pub type BusSlice = MemorySlice; diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs new file mode 100644 index 000000000..8f9d83498 --- /dev/null +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -0,0 +1,77 @@ +use super::type_definitions::*; +use circom_algebra::algebra::ArithmeticExpression; +use compiler::hir::very_concrete_program::*; +use dag::DAG; +use num_bigint::BigInt; +use program_structure::ast::{SignalType, Statement}; +use std::collections::{HashMap, HashSet}; +use crate::execution_data::AExpressionSlice; +use crate::execution_data::TagInfo; + + +struct BusConnexion{ + full_name: String, + inspect: BusData, + dag_offset: usize, + dag_jump: usize, +} + + +pub struct ExecutedBus { + pub bus_name: String, + pub report_name: String, + pub signal_fields: SignalCollector, + pub bus_fields: BusCollector, + pub parameter_instances: ParameterContext, + bus_connexions: HashMap, +} + +impl ExecutedBus { + pub fn new( + name: String, + report_name: String, + instance: ParameterContext, + ) -> ExecutedBus { + ExecutedBus { + report_name, + bus_name: name, + parameter_instances: instance, + signal_fields: Vec::new(), + bus_fields: Vec::new(), + bus_connexions: HashMap::new(), + } + } + + pub fn is_equal(&self, name: &str, context: &ParameterContext, tag_context: &TagContext) -> bool { + self.bus_name == name + && self.parameter_instances == *context + } + + pub fn add_bus_arrow(&mut self, component_name: String, data: BusData) { + let cnn = + BusConnexion { full_name: component_name.clone(), inspect: data, dag_offset: 0, dag_jump: 0}; + self.bus_connexions.insert(component_name, cnn); + } + + pub fn add_signal(&mut self, signal_name: &str, dimensions: &[usize]) { + self.signal_fields.push((signal_name.to_string(), dimensions.to_vec())); + } + + pub fn add_bus(&mut self, bus_name: &str, dimensions: &[usize]) { + self.bus_fields.push((bus_name.to_string(), dimensions.to_vec())); + } + + + + fn build_signals(&self, dag: &mut DAG) { + + } + + pub fn signal_fields(&self) -> &SignalCollector { + &self.signal_fields + } + pub fn bus_fields(&self) -> &BusCollector { + &self.bus_fields + } + +} \ No newline at end of file diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index dcb1ce2da..c203031e8 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -1,6 +1,8 @@ use super::analysis::Analysis; use crate::FlagsExecution; use super::executed_template::{ExecutedTemplate, PreExecutedTemplate}; +use super::executed_bus::ExecutedBus; + use super::type_definitions::*; use compiler::hir::very_concrete_program::{Stats, VCPConfig, VCP}; use dag::DAG; @@ -14,7 +16,9 @@ pub type ExportResult = Result<(DAG, VCP, ReportCollection), ReportCollection>; pub struct ExecutedProgram { pub model: Vec, pub model_pretemplates: Vec, + pub model_buses: Vec, pub template_to_nodes: HashMap>, + pub bus_to_nodes: HashMap>, pub prime: String, } @@ -25,6 +29,8 @@ impl ExecutedProgram { template_to_nodes: HashMap::new(), prime: prime.clone(), model_pretemplates: Vec::new(), + model_buses: Vec::new(), + bus_to_nodes: HashMap::new(), } } @@ -64,6 +70,12 @@ impl ExecutedProgram { } Option::Some(self.model_pretemplates[node_pointer].clone()) } + pub fn get_bus_node(&self, node_pointer: NodePointer) -> Option<&ExecutedBus> { + if node_pointer >= self.model_buses.len() { + return Option::None; + } + Option::Some(&self.model_buses[node_pointer]) + } pub fn add_prenode_to_scheme( &mut self, diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index a56fc328a..ac1333997 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -18,6 +18,14 @@ struct Connexion { dag_component_jump: usize, } +struct BusConnexion{ + full_name: String, + inspect: BusData, + dag_offset: usize, + dag_jump: usize, +} + + #[derive(Clone)] pub struct PreExecutedTemplate { pub template_name: String, @@ -65,8 +73,11 @@ pub struct ExecutedTemplate { pub template_name: String, pub report_name: String, pub inputs: SignalCollector, + pub bus_inputs: BusCollector, pub outputs: SignalCollector, + pub bus_outputs: BusCollector, pub intermediates: SignalCollector, + pub bus_intermediates: BusCollector, pub ordered_signals: Vec, pub constraints: Vec, pub components: ComponentCollector, @@ -80,6 +91,7 @@ pub struct ExecutedTemplate { pub is_custom_gate: bool, pub underscored_signals: Vec, connexions: Vec, + bus_connexions: HashMap, } impl ExecutedTemplate { @@ -108,11 +120,15 @@ impl ExecutedTemplate { inputs: SignalCollector::new(), outputs: SignalCollector::new(), intermediates: SignalCollector::new(), + bus_inputs: BusCollector::new(), + bus_outputs: BusCollector::new(), + bus_intermediates: BusCollector::new(), ordered_signals: Vec::new(), constraints: Vec::new(), components: ComponentCollector::new(), number_of_components: 0, connexions: Vec::new(), + bus_connexions: HashMap::new(), underscored_signals: Vec::new(), } } @@ -123,12 +139,15 @@ impl ExecutedTemplate { && self.tag_instances == *tag_context } + // pub add_bus_arrow pub fn add_arrow(&mut self, component_name: String, data: SubComponentData) { let cnn = Connexion { full_name: component_name, inspect: data, dag_offset: 0, dag_component_offset: 0, dag_jump: 0, dag_component_jump: 0}; self.connexions.push(cnn); } + // Same with buses + pub fn add_input(&mut self, input_name: &str, dimensions: &[usize]) { self.inputs.push((input_name.to_string(), dimensions.to_vec())); } @@ -259,6 +278,7 @@ impl ExecutedTemplate { let config = SignalConfig { signal_type: 2, dimensions: dim, is_public: false }; generate_symbols(dag, state, &config); } + // We also need to build the signals inside the buses -> similar to build_connexions } fn build_connexions(&mut self, dag: &mut DAG) { self.connexions.sort_by(|l, r| { @@ -401,6 +421,8 @@ impl ExecutedTemplate { instance.add_signal(signal); } + // Here we need to add the buses + instance } } diff --git a/constraint_generation/src/execution_data/mod.rs b/constraint_generation/src/execution_data/mod.rs index 6dcc6c012..536ba439a 100644 --- a/constraint_generation/src/execution_data/mod.rs +++ b/constraint_generation/src/execution_data/mod.rs @@ -7,5 +7,6 @@ pub use type_definitions::NodePointer; pub mod analysis; pub mod executed_program; pub mod executed_template; +pub mod executed_bus; mod filters; pub mod type_definitions; diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index 03ef731c3..639496f71 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -11,6 +11,7 @@ pub type TagContext = BTreeMap; pub type TagInfo = BTreeMap>; // From name to dimensions pub type SignalCollector = Vec<(String, Vec)>; +pub type BusCollector = Vec<(String, Vec)>; pub type ComponentCollector = Vec<(String, Vec)>; pub struct SubComponentData { pub name: String, @@ -18,3 +19,10 @@ pub struct SubComponentData { pub indexed_with: Vec, pub goes_to: NodePointer, } + +pub struct BusData { + pub name: String, + pub indexed_with: Vec, + pub goes_to: NodePointer, +} + From a276e1910a08c99017ec071ce5a158007b151ebd Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Wed, 10 Apr 2024 16:23:43 +0200 Subject: [PATCH 013/189] Updated enviroments with buses. --- program_structure/src/utils/environment.rs | 312 +++++++++++++++++---- 1 file changed, 250 insertions(+), 62 deletions(-) diff --git a/program_structure/src/utils/environment.rs b/program_structure/src/utils/environment.rs index 0215dce61..2d7aefcbc 100644 --- a/program_structure/src/utils/environment.rs +++ b/program_structure/src/utils/environment.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; pub trait VarInfo {} pub trait SignalInfo {} +pub trait BusInfo {} pub trait ComponentInfo {} #[derive(Clone)] @@ -13,67 +14,84 @@ impl VarInfo for OnlyVars {} pub struct OnlySignals; impl SignalInfo for OnlySignals {} #[derive(Clone)] +pub struct OnlyBuses; +impl BusInfo for OnlyBuses {} +#[derive(Clone)] pub struct OnlyComponents; impl ComponentInfo for OnlyComponents {} #[derive(Clone)] pub struct FullEnvironment; impl VarInfo for FullEnvironment {} impl SignalInfo for FullEnvironment {} +impl BusInfo for FullEnvironment {} impl ComponentInfo for FullEnvironment {} -pub type VarEnvironment = RawEnvironment; -pub type SignalEnvironment = RawEnvironment; -pub type ComponentEnvironment = RawEnvironment; -pub type CircomEnvironment = RawEnvironment; +pub type VarEnvironment = RawEnvironment; +pub type SignalEnvironment = RawEnvironment; +pub type BusEnvironment = RawEnvironment; +pub type ComponentEnvironment = RawEnvironment; +pub type CircomEnvironment = RawEnvironment; pub enum CircomEnvironmentError { NonExistentSymbol, } #[derive(Clone)] -pub struct RawEnvironment { - components: HashMap, - inputs: HashMap, - outputs: HashMap, - intermediates: HashMap, +pub struct RawEnvironment { variables: Vec>, + signal_inputs: HashMap, + signal_outputs: HashMap, + signal_intermediates: HashMap, + bus_inputs: HashMap, + bus_outputs: HashMap, + bus_intermediates: HashMap, + components: HashMap, behaviour: PhantomData, } -impl Default for RawEnvironment { +impl Default for RawEnvironment { fn default() -> Self { let variables = vec![VariableBlock::new()]; RawEnvironment { - components: HashMap::new(), - inputs: HashMap::new(), - outputs: HashMap::new(), - intermediates: HashMap::new(), variables, + signal_inputs: HashMap::new(), + signal_outputs: HashMap::new(), + signal_intermediates: HashMap::new(), + bus_inputs: HashMap::new(), + bus_outputs: HashMap::new(), + bus_intermediates: HashMap::new(), + components: HashMap::new(), behaviour: PhantomData, } } } -impl RawEnvironment +impl RawEnvironment where - T: VarInfo + SignalInfo + ComponentInfo, + T: VarInfo + SignalInfo + BusInfo + ComponentInfo, { pub fn has_symbol(&self, symbol: &str) -> bool { - self.has_signal(symbol) || self.has_component(symbol) || self.has_variable(symbol) + self.has_signal(symbol) || self.has_bus(symbol) || self.has_component(symbol) || self.has_variable(symbol) } } -impl RawEnvironment { +impl RawEnvironment { pub fn merge( - left: RawEnvironment, - right: RawEnvironment, + left: RawEnvironment, + right: RawEnvironment, using: fn(VC, VC) -> VC, - ) -> RawEnvironment { + ) -> RawEnvironment { + let mut signal_inputs = left.signal_inputs; + let mut signal_outputs = left.signal_outputs; + let mut signal_intermediates = left.signal_intermediates; + let mut bus_inputs = left.bus_inputs; + let mut bus_outputs = left.bus_outputs; + let mut bus_intermediates = left.bus_intermediates; let mut components = left.components; - let mut inputs = left.inputs; - let mut outputs = left.outputs; - let mut intermediates = left.intermediates; + signal_inputs.extend(right.signal_inputs); + signal_outputs.extend(right.signal_outputs); + signal_intermediates.extend(right.signal_intermediates); + bus_inputs.extend(right.bus_inputs); + bus_outputs.extend(right.bus_outputs); + bus_intermediates.extend(right.bus_intermediates); components.extend(right.components); - inputs.extend(right.inputs); - outputs.extend(right.outputs); - intermediates.extend(right.intermediates); let mut variables_left = left.variables; let mut variables_right = right.variables; let mut variables = Vec::new(); @@ -85,16 +103,19 @@ impl RawEnvironment { } variables.reverse(); RawEnvironment { - components, - inputs, - intermediates, - outputs, variables, + signal_inputs, + signal_outputs, + signal_intermediates, + bus_inputs, + bus_outputs, + bus_intermediates, + components, behaviour: PhantomData, } } } -impl RawEnvironment +impl RawEnvironment where T: VarInfo, { @@ -120,7 +141,7 @@ where } Option::None } - pub fn new() -> RawEnvironment { + pub fn new() -> RawEnvironment { RawEnvironment::default() } pub fn add_variable_block(&mut self) { @@ -198,7 +219,7 @@ where } } -impl RawEnvironment +impl RawEnvironment where T: ComponentInfo, { @@ -239,100 +260,100 @@ where } } -impl RawEnvironment +impl RawEnvironment where T: SignalInfo, { pub fn add_input(&mut self, input_name: &str, content: SC) { - self.inputs.insert(input_name.to_string(), content); + self.signal_inputs.insert(input_name.to_string(), content); } pub fn remove_input(&mut self, input_name: &str) { - self.inputs.remove(input_name); + self.signal_inputs.remove(input_name); } pub fn add_output(&mut self, output_name: &str, content: SC) { - self.outputs.insert(output_name.to_string(), content); + self.signal_outputs.insert(output_name.to_string(), content); } pub fn remove_output(&mut self, output_name: &str) { - self.outputs.remove(output_name); + self.signal_outputs.remove(output_name); } pub fn add_intermediate(&mut self, intermediate_name: &str, content: SC) { - self.intermediates.insert(intermediate_name.to_string(), content); + self.signal_intermediates.insert(intermediate_name.to_string(), content); } pub fn remove_intermediate(&mut self, intermediate_name: &str) { - self.intermediates.remove(intermediate_name); + self.signal_intermediates.remove(intermediate_name); } pub fn has_input(&self, symbol: &str) -> bool { - self.inputs.contains_key(symbol) + self.signal_inputs.contains_key(symbol) } pub fn has_output(&self, symbol: &str) -> bool { - self.outputs.contains_key(symbol) + self.signal_outputs.contains_key(symbol) } pub fn has_intermediate(&self, symbol: &str) -> bool { - self.intermediates.contains_key(symbol) + self.signal_intermediates.contains_key(symbol) } pub fn has_signal(&self, symbol: &str) -> bool { self.has_input(symbol) || self.has_output(symbol) || self.has_intermediate(symbol) } pub fn get_input(&self, symbol: &str) -> Option<&SC> { - self.inputs.get(symbol) + self.signal_inputs.get(symbol) } pub fn get_mut_input(&mut self, symbol: &str) -> Option<&mut SC> { - self.inputs.get_mut(symbol) + self.signal_inputs.get_mut(symbol) } pub fn get_input_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { - self.inputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + self.signal_inputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_input_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { assert!(self.has_input(symbol), "Method call in file {} line {}", file, line); - self.inputs.get(symbol).unwrap() + self.signal_inputs.get(symbol).unwrap() } pub fn get_mut_input_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { - self.inputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + self.signal_inputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_mut_input_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { assert!(self.has_input(symbol), "Method call in file {} line {}", file, line); - self.inputs.get_mut(symbol).unwrap() + self.signal_inputs.get_mut(symbol).unwrap() } pub fn get_output(&self, symbol: &str) -> Option<&SC> { - self.outputs.get(symbol) + self.signal_outputs.get(symbol) } pub fn get_mut_output(&mut self, symbol: &str) -> Option<&mut SC> { - self.outputs.get_mut(symbol) + self.signal_outputs.get_mut(symbol) } pub fn get_output_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { - self.outputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + self.signal_outputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_output_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { assert!(self.has_output(symbol), "Method call in file {} line {}", file, line); - self.outputs.get(symbol).unwrap() + self.signal_outputs.get(symbol).unwrap() } pub fn get_mut_output_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { - self.outputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + self.signal_outputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_mut_output_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { assert!(self.has_output(symbol), "Method call in file {} line {}", file, line); - self.outputs.get_mut(symbol).unwrap() + self.signal_outputs.get_mut(symbol).unwrap() } pub fn get_intermediate(&self, symbol: &str) -> Option<&SC> { - self.intermediates.get(symbol) + self.signal_intermediates.get(symbol) } pub fn get_mut_intermediate(&mut self, symbol: &str) -> Option<&mut SC> { - self.intermediates.get_mut(symbol) + self.signal_intermediates.get_mut(symbol) } pub fn get_intermediate_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { - self.intermediates.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + self.signal_intermediates.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_intermediate_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { assert!(self.has_intermediate(symbol), "Method call in file {} line {}", file, line); - self.intermediates.get(symbol).unwrap() + self.signal_intermediates.get(symbol).unwrap() } pub fn get_mut_intermediate_res( &mut self, symbol: &str, ) -> Result<&mut SC, CircomEnvironmentError> { - self.intermediates.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + self.signal_intermediates.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_mut_intermediate_or_break( &mut self, @@ -341,7 +362,7 @@ where line: u32, ) -> &mut SC { assert!(self.has_intermediate(symbol), "Method call in file {} line {}", file, line); - self.intermediates.get_mut(symbol).unwrap() + self.signal_intermediates.get_mut(symbol).unwrap() } pub fn get_signal(&self, symbol: &str) -> Option<&SC> { @@ -406,6 +427,173 @@ where } } +impl RawEnvironment +where + T: BusInfo, +{ + pub fn add_input_bus(&mut self, input_name: &str, content: SC) { + self.bus_inputs.insert(input_name.to_string(), content); + } + pub fn remove_input_bus(&mut self, input_name: &str) { + self.bus_inputs.remove(input_name); + } + pub fn add_output_bus(&mut self, output_name: &str, content: SC) { + self.bus_outputs.insert(output_name.to_string(), content); + } + pub fn remove_output_bus(&mut self, output_name: &str) { + self.bus_outputs.remove(output_name); + } + pub fn add_intermediate_bus(&mut self, intermediate_name: &str, content: SC) { + self.bus_intermediates.insert(intermediate_name.to_string(), content); + } + pub fn remove_intermediate_bus(&mut self, intermediate_name: &str) { + self.bus_intermediates.remove(intermediate_name); + } + pub fn has_input_bus(&self, symbol: &str) -> bool { + self.bus_inputs.contains_key(symbol) + } + pub fn has_output_bus(&self, symbol: &str) -> bool { + self.bus_outputs.contains_key(symbol) + } + pub fn has_intermediate_bus(&self, symbol: &str) -> bool { + self.bus_intermediates.contains_key(symbol) + } + pub fn has_bus(&self, symbol: &str) -> bool { + self.has_input_bus(symbol) || self.has_output_bus(symbol) || self.has_intermediate_bus(symbol) + } + pub fn get_input_bus(&self, symbol: &str) -> Option<&SC> { + self.bus_inputs.get(symbol) + } + pub fn get_mut_input_bus(&mut self, symbol: &str) -> Option<&mut SC> { + self.bus_inputs.get_mut(symbol) + } + pub fn get_input_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + self.bus_inputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + } + pub fn get_input_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + assert!(self.has_input_bus(symbol), "Method call in file {} line {}", file, line); + self.bus_inputs.get(symbol).unwrap() + } + pub fn get_mut_input_bus_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { + self.bus_inputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + } + pub fn get_mut_input_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { + assert!(self.has_input_bus(symbol), "Method call in file {} line {}", file, line); + self.bus_inputs.get_mut(symbol).unwrap() + } + + pub fn get_output_bus(&self, symbol: &str) -> Option<&SC> { + self.bus_outputs.get(symbol) + } + pub fn get_mut_output_bus(&mut self, symbol: &str) -> Option<&mut SC> { + self.bus_outputs.get_mut(symbol) + } + pub fn get_output_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + self.bus_outputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + } + pub fn get_output_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + assert!(self.has_output_bus(symbol), "Method call in file {} line {}", file, line); + self.bus_outputs.get(symbol).unwrap() + } + pub fn get_mut_output_bus_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { + self.bus_outputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + } + pub fn get_mut_output_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { + assert!(self.has_output(symbol), "Method call in file {} line {}", file, line); + self.bus_outputs.get_mut_bus(symbol).unwrap() + } + + pub fn get_intermediate_bus(&self, symbol: &str) -> Option<&SC> { + self.bus_intermediates.get(symbol) + } + pub fn get_mut_intermediate_bus(&mut self, symbol: &str) -> Option<&mut SC> { + self.bus_intermediates.get_mut(symbol) + } + pub fn get_intermediate_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + self.bus_intermediates.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + } + pub fn get_intermediate_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + assert!(self.has_intermediate_bus(symbol), "Method call in file {} line {}", file, line); + self.bus_intermediates.get(symbol).unwrap() + } + pub fn get_mut_intermediate_bus_res( + &mut self, + symbol: &str, + ) -> Result<&mut SC, CircomEnvironmentError> { + self.bus_intermediates.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) + } + pub fn get_mut_intermediate_bus_or_break( + &mut self, + symbol: &str, + file: &str, + line: u32, + ) -> &mut SC { + assert!(self.has_intermediate_bus(symbol), "Method call in file {} line {}", file, line); + self.bus_intermediates.get_mut(symbol).unwrap() + } + + pub fn get_bus(&self, symbol: &str) -> Option<&SC> { + if self.has_input_bus(symbol) { + self.get_input_bus(symbol) + } else if self.has_output_bus(symbol) { + self.get_output_bus(symbol) + } else if self.has_intermediate_bus(symbol) { + self.get_intermediate_bus(symbol) + } else { + Option::None + } + } + pub fn get_mut_bus(&mut self, symbol: &str) -> Option<&mut SC> { + if self.has_input_bus(symbol) { + self.get_mut_input_bus(symbol) + } else if self.has_output_bus(symbol) { + self.get_mut_output_bus(symbol) + } else if self.has_intermediate_bus(symbol) { + self.get_mut_intermediate_bus(symbol) + } else { + Option::None + } + } + pub fn get_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + if self.has_input_bus(symbol) { + self.get_input_bus_res(symbol) + } else if self.has_output_bus(symbol) { + self.get_output_bus_res(symbol) + } else if self.has_intermediate_bus(symbol) { + self.get_intermediate_bus_res(symbol) + } else { + Result::Err(CircomEnvironmentError::NonExistentSymbol) + } + } + pub fn get_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + assert!(self.has_bus(symbol), "Method call in file {} line {}", file, line); + if let Result::Ok(v) = self.get_bus_res(symbol) { + v + } else { + unreachable!(); + } + } + pub fn get_mut_bus_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { + if self.has_input_bus(symbol) { + self.get_mut_input_bus_res(symbol) + } else if self.has_output_bus(symbol) { + self.get_mut_output_bus_res(symbol) + } else if self.has_intermediate_bus(symbol) { + self.get_mut_intermediate_bus_res(symbol) + } else { + Result::Err(CircomEnvironmentError::NonExistentSymbol) + } + } + pub fn get_mut_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { + assert!(self.has_bus(symbol), "Method call in file {} line {}", file, line); + if let Result::Ok(v) = self.get_mut_bus_res(symbol) { + v + } else { + unreachable!(); + } + } +} + #[derive(Clone)] struct VariableBlock { variables: HashMap, From 10347c0bc0e4ab8e0bb3c45934e251c205eb9f4c Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 10 Apr 2024 18:29:36 +0200 Subject: [PATCH 014/189] working on environment and changes execute --- .../src/environment_utils/environment.rs | 50 ++++++++++- constraint_generation/src/execute.rs | 53 +++++++++++ .../src/execution_data/executed_template.rs | 12 +++ program_structure/src/utils/environment.rs | 90 +++++++++---------- type_analysis/src/analyzers/type_check.rs | 3 +- .../src/analyzers/unknown_known_analysis.rs | 2 +- .../src/decorators/type_reduction.rs | 2 +- 7 files changed, 161 insertions(+), 51 deletions(-) diff --git a/constraint_generation/src/environment_utils/environment.rs b/constraint_generation/src/environment_utils/environment.rs index 6a06cc387..86fbf0cd3 100644 --- a/constraint_generation/src/environment_utils/environment.rs +++ b/constraint_generation/src/environment_utils/environment.rs @@ -1,21 +1,23 @@ use super::slice_types::{ AExpressionSlice, ComponentRepresentation, + BusRepresentation, ComponentSlice, SignalSlice, SliceCapacity, TagInfo, TagDefinitions, - TagState + TagState, + BusSlice }; use super::{ArithmeticExpression, CircomEnvironment, CircomEnvironmentError}; use program_structure::memory_slice::MemoryError; use crate::ast::Meta; pub type ExecutionEnvironmentError = CircomEnvironmentError; -pub type ExecutionEnvironment = CircomEnvironment; +pub type ExecutionEnvironment = CircomEnvironment; -// TODO: ADD environment buses -> BusSlice +// TODO: ADD environment buses -> BusSlice pub fn environment_shortcut_add_component( environment: &mut ExecutionEnvironment, @@ -25,6 +27,7 @@ pub fn environment_shortcut_add_component( let slice = ComponentSlice::new_with_route(dimensions, &ComponentRepresentation::default()); environment.add_component(component_name, slice); } + pub fn environment_shortcut_add_input( environment: &mut ExecutionEnvironment, input_name: &str, @@ -65,6 +68,47 @@ pub fn environment_shortcut_add_intermediate( } environment.add_intermediate(intermediate_name, (tags.clone(), tags_defined, slice)); } +pub fn environment_shortcut_add_bus_input( + environment: &mut ExecutionEnvironment, + input_name: &str, + dimensions: &[SliceCapacity], + tags: &TagInfo, +) { + // In this case we need to set all the signals of the bus to known -> in the default method + let slice = BusSlice::new_with_route(dimensions, &BusRepresentation::default()); + let mut tags_defined = TagDefinitions::new(); + for (t, value) in tags{ + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: true}); + } + + environment.add_input_bus(input_name, (tags.clone(), tags_defined, slice)); +} +pub fn environment_shortcut_add_bus_output( + environment: &mut ExecutionEnvironment, + output_name: &str, + dimensions: &[SliceCapacity], + tags: &TagInfo, +) { + let slice = BusSlice::new_with_route(dimensions, &BusRepresentation::default()); + let mut tags_defined = TagDefinitions::new(); + for (t, value) in tags{ + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); + } + environment.add_output_bus(output_name, (tags.clone(), tags_defined, slice)); +} +pub fn environment_shortcut_add_bus_intermediate( + environment: &mut ExecutionEnvironment, + intermediate_name: &str, + dimensions: &[SliceCapacity], + tags: &TagInfo, +) { + let slice = BusSlice::new_with_route(dimensions, &BusRepresentation::default()); + let mut tags_defined = TagDefinitions::new(); + for (t, value) in tags{ + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); + } + environment.add_intermediate_bus(intermediate_name, (tags.clone(), tags_defined, slice)); +} pub fn environment_shortcut_add_variable( environment: &mut ExecutionEnvironment, variable_name: &str, diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 613f39da7..3b2902259 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2,6 +2,8 @@ use super::environment_utils::{ environment::{ environment_shortcut_add_component, environment_shortcut_add_input, environment_shortcut_add_intermediate, environment_shortcut_add_output, + environment_shortcut_add_bus_input, environment_shortcut_add_bus_intermediate, + environment_shortcut_add_bus_output, environment_shortcut_add_variable, ExecutionEnvironment, ExecutionEnvironmentError, environment_check_all_components_assigned }, @@ -250,6 +252,16 @@ fn execute_statement( &mut runtime.environment, actual_node, ), + VariableType::Bus(id, signal_type, tag_list) => { + execute_bus_declaration( + name, + &usable_dimensions, + tag_list, + *signal_type, + &mut runtime.environment, + actual_node, + ) + } _ =>{ unreachable!() } @@ -819,6 +831,44 @@ fn execute_signal_declaration( } } +fn execute_bus_declaration( + bus_name: &str, + dimensions: &[SliceCapacity], + list_tags: &Vec, + signal_type: SignalType, + environment: &mut ExecutionEnvironment, + actual_node: &mut Option, +) { + use SignalType::*; + let mut tags = TagInfo::new(); + for t in list_tags{ + tags.insert(t.clone(), None); + } + if let Option::Some(node) = actual_node { + //node.add_ordered_signal(signal_name, dimensions); + match signal_type { + Input => { + if let Some(tags_input) = node.tag_instances().get(bus_name){ + environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tags_input); + } else{ + environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tags); + } + node.add_bus_input(bus_name, dimensions); + } + Output => { + environment_shortcut_add_bus_output(environment, bus_name, dimensions, &tags); + node.add_bus_output(bus_name, dimensions); + } + Intermediate => { + environment_shortcut_add_bus_intermediate(environment, bus_name, dimensions, &tags); + node.add_bus_intermediate(bus_name, dimensions); + } + } + } else { + unreachable!(); + } +} + /* In case the assigment could be a constraint generator the returned value is the constraint that will be created @@ -1343,6 +1393,9 @@ fn perform_assign( } Option::Some(arithmetic_slice) } + } else if ExecutionEnvironment::has_variable(&runtime.environment, symbol){ + // Case buses -> case assigning bus type or assigning values + unreachable!(); } else { unreachable!(); }; diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index ac1333997..6785d8267 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -160,6 +160,18 @@ impl ExecutedTemplate { self.intermediates.push((intermediate_name.to_string(), dimensions.to_vec())); } + pub fn add_bus_input(&mut self, input_name: &str, dimensions: &[usize]) { + self.bus_inputs.push((input_name.to_string(), dimensions.to_vec())); + } + + pub fn add_bus_output(&mut self, output_name: &str, dimensions: &[usize]) { + self.bus_outputs.push((output_name.to_string(), dimensions.to_vec())); + } + + pub fn add_bus_intermediate(&mut self, intermediate_name: &str, dimensions: &[usize]) { + self.bus_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(); diff --git a/program_structure/src/utils/environment.rs b/program_structure/src/utils/environment.rs index 2d7aefcbc..cd181ed48 100644 --- a/program_structure/src/utils/environment.rs +++ b/program_structure/src/utils/environment.rs @@ -26,18 +26,18 @@ impl SignalInfo for FullEnvironment {} impl BusInfo for FullEnvironment {} impl ComponentInfo for FullEnvironment {} -pub type VarEnvironment = RawEnvironment; +pub type VarEnvironment = RawEnvironment; pub type SignalEnvironment = RawEnvironment; -pub type BusEnvironment = RawEnvironment; -pub type ComponentEnvironment = RawEnvironment; -pub type CircomEnvironment = RawEnvironment; +pub type BusEnvironment = RawEnvironment; +pub type ComponentEnvironment = RawEnvironment; +pub type CircomEnvironment = RawEnvironment; pub enum CircomEnvironmentError { NonExistentSymbol, } #[derive(Clone)] -pub struct RawEnvironment { +pub struct RawEnvironment { variables: Vec>, signal_inputs: HashMap, signal_outputs: HashMap, @@ -48,7 +48,7 @@ pub struct RawEnvironment { components: HashMap, behaviour: PhantomData, } -impl Default for RawEnvironment { +impl Default for RawEnvironment { fn default() -> Self { let variables = vec![VariableBlock::new()]; RawEnvironment { @@ -64,7 +64,7 @@ impl Default for RawEnvironment { } } } -impl RawEnvironment +impl RawEnvironment where T: VarInfo + SignalInfo + BusInfo + ComponentInfo, { @@ -72,12 +72,12 @@ where self.has_signal(symbol) || self.has_bus(symbol) || self.has_component(symbol) || self.has_variable(symbol) } } -impl RawEnvironment { +impl RawEnvironment { pub fn merge( - left: RawEnvironment, - right: RawEnvironment, + left: RawEnvironment, + right: RawEnvironment, using: fn(VC, VC) -> VC, - ) -> RawEnvironment { + ) -> RawEnvironment { let mut signal_inputs = left.signal_inputs; let mut signal_outputs = left.signal_outputs; let mut signal_intermediates = left.signal_intermediates; @@ -115,7 +115,7 @@ impl RawEnvironment { } } } -impl RawEnvironment +impl RawEnvironment where T: VarInfo, { @@ -141,7 +141,7 @@ where } Option::None } - pub fn new() -> RawEnvironment { + pub fn new() -> RawEnvironment { RawEnvironment::default() } pub fn add_variable_block(&mut self) { @@ -219,7 +219,7 @@ where } } -impl RawEnvironment +impl RawEnvironment where T: ComponentInfo, { @@ -260,7 +260,7 @@ where } } -impl RawEnvironment +impl RawEnvironment where T: SignalInfo, { @@ -427,23 +427,23 @@ where } } -impl RawEnvironment +impl RawEnvironment where T: BusInfo, { - pub fn add_input_bus(&mut self, input_name: &str, content: SC) { + pub fn add_input_bus(&mut self, input_name: &str, content: BC) { self.bus_inputs.insert(input_name.to_string(), content); } pub fn remove_input_bus(&mut self, input_name: &str) { self.bus_inputs.remove(input_name); } - pub fn add_output_bus(&mut self, output_name: &str, content: SC) { + pub fn add_output_bus(&mut self, output_name: &str, content: BC) { self.bus_outputs.insert(output_name.to_string(), content); } pub fn remove_output_bus(&mut self, output_name: &str) { self.bus_outputs.remove(output_name); } - pub fn add_intermediate_bus(&mut self, intermediate_name: &str, content: SC) { + pub fn add_intermediate_bus(&mut self, intermediate_name: &str, content: BC) { self.bus_intermediates.insert(intermediate_name.to_string(), content); } pub fn remove_intermediate_bus(&mut self, intermediate_name: &str) { @@ -461,65 +461,65 @@ where pub fn has_bus(&self, symbol: &str) -> bool { self.has_input_bus(symbol) || self.has_output_bus(symbol) || self.has_intermediate_bus(symbol) } - pub fn get_input_bus(&self, symbol: &str) -> Option<&SC> { + pub fn get_input_bus(&self, symbol: &str) -> Option<&BC> { self.bus_inputs.get(symbol) } - pub fn get_mut_input_bus(&mut self, symbol: &str) -> Option<&mut SC> { + pub fn get_mut_input_bus(&mut self, symbol: &str) -> Option<&mut BC> { self.bus_inputs.get_mut(symbol) } - pub fn get_input_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + pub fn get_input_bus_res(&self, symbol: &str) -> Result<&BC, CircomEnvironmentError> { self.bus_inputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } - pub fn get_input_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + pub fn get_input_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &BC { assert!(self.has_input_bus(symbol), "Method call in file {} line {}", file, line); self.bus_inputs.get(symbol).unwrap() } - pub fn get_mut_input_bus_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { + pub fn get_mut_input_bus_res(&mut self, symbol: &str) -> Result<&mut BC, CircomEnvironmentError> { self.bus_inputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } - pub fn get_mut_input_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { + pub fn get_mut_input_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut BC { assert!(self.has_input_bus(symbol), "Method call in file {} line {}", file, line); self.bus_inputs.get_mut(symbol).unwrap() } - pub fn get_output_bus(&self, symbol: &str) -> Option<&SC> { + pub fn get_output_bus(&self, symbol: &str) -> Option<&BC> { self.bus_outputs.get(symbol) } - pub fn get_mut_output_bus(&mut self, symbol: &str) -> Option<&mut SC> { + pub fn get_mut_output_bus(&mut self, symbol: &str) -> Option<&mut BC> { self.bus_outputs.get_mut(symbol) } - pub fn get_output_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + pub fn get_output_bus_res(&self, symbol: &str) -> Result<&BC, CircomEnvironmentError> { self.bus_outputs.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } - pub fn get_output_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + pub fn get_output_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &BC { assert!(self.has_output_bus(symbol), "Method call in file {} line {}", file, line); self.bus_outputs.get(symbol).unwrap() } - pub fn get_mut_output_bus_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { + pub fn get_mut_output_bus_res(&mut self, symbol: &str) -> Result<&mut BC, CircomEnvironmentError> { self.bus_outputs.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } - pub fn get_mut_output_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { - assert!(self.has_output(symbol), "Method call in file {} line {}", file, line); - self.bus_outputs.get_mut_bus(symbol).unwrap() + pub fn get_mut_output_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut BC { + assert!(self.has_output_bus(symbol), "Method call in file {} line {}", file, line); + self.bus_outputs.get_mut(symbol).unwrap() } - pub fn get_intermediate_bus(&self, symbol: &str) -> Option<&SC> { + pub fn get_intermediate_bus(&self, symbol: &str) -> Option<&BC> { self.bus_intermediates.get(symbol) } - pub fn get_mut_intermediate_bus(&mut self, symbol: &str) -> Option<&mut SC> { + pub fn get_mut_intermediate_bus(&mut self, symbol: &str) -> Option<&mut BC> { self.bus_intermediates.get_mut(symbol) } - pub fn get_intermediate_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + pub fn get_intermediate_bus_res(&self, symbol: &str) -> Result<&BC, CircomEnvironmentError> { self.bus_intermediates.get(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } - pub fn get_intermediate_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + pub fn get_intermediate_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &BC { assert!(self.has_intermediate_bus(symbol), "Method call in file {} line {}", file, line); self.bus_intermediates.get(symbol).unwrap() } pub fn get_mut_intermediate_bus_res( &mut self, symbol: &str, - ) -> Result<&mut SC, CircomEnvironmentError> { + ) -> Result<&mut BC, CircomEnvironmentError> { self.bus_intermediates.get_mut(symbol).ok_or_else(|| CircomEnvironmentError::NonExistentSymbol) } pub fn get_mut_intermediate_bus_or_break( @@ -527,12 +527,12 @@ where symbol: &str, file: &str, line: u32, - ) -> &mut SC { + ) -> &mut BC { assert!(self.has_intermediate_bus(symbol), "Method call in file {} line {}", file, line); self.bus_intermediates.get_mut(symbol).unwrap() } - pub fn get_bus(&self, symbol: &str) -> Option<&SC> { + pub fn get_bus(&self, symbol: &str) -> Option<&BC> { if self.has_input_bus(symbol) { self.get_input_bus(symbol) } else if self.has_output_bus(symbol) { @@ -543,7 +543,7 @@ where Option::None } } - pub fn get_mut_bus(&mut self, symbol: &str) -> Option<&mut SC> { + pub fn get_mut_bus(&mut self, symbol: &str) -> Option<&mut BC> { if self.has_input_bus(symbol) { self.get_mut_input_bus(symbol) } else if self.has_output_bus(symbol) { @@ -554,7 +554,7 @@ where Option::None } } - pub fn get_bus_res(&self, symbol: &str) -> Result<&SC, CircomEnvironmentError> { + pub fn get_bus_res(&self, symbol: &str) -> Result<&BC, CircomEnvironmentError> { if self.has_input_bus(symbol) { self.get_input_bus_res(symbol) } else if self.has_output_bus(symbol) { @@ -565,7 +565,7 @@ where Result::Err(CircomEnvironmentError::NonExistentSymbol) } } - pub fn get_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &SC { + pub fn get_bus_or_break(&self, symbol: &str, file: &str, line: u32) -> &BC { assert!(self.has_bus(symbol), "Method call in file {} line {}", file, line); if let Result::Ok(v) = self.get_bus_res(symbol) { v @@ -573,7 +573,7 @@ where unreachable!(); } } - pub fn get_mut_bus_res(&mut self, symbol: &str) -> Result<&mut SC, CircomEnvironmentError> { + pub fn get_mut_bus_res(&mut self, symbol: &str) -> Result<&mut BC, CircomEnvironmentError> { if self.has_input_bus(symbol) { self.get_mut_input_bus_res(symbol) } else if self.has_output_bus(symbol) { @@ -584,7 +584,7 @@ where Result::Err(CircomEnvironmentError::NonExistentSymbol) } } - pub fn get_mut_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut SC { + pub fn get_mut_bus_or_break(&mut self, symbol: &str, file: &str, line: u32) -> &mut BC { assert!(self.has_bus(symbol), "Method call in file {} line {}", file, line); if let Result::Ok(v) = self.get_mut_bus_res(symbol) { v diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 9a7224e3e..9d5537c31 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -11,7 +11,8 @@ use std::collections::HashSet; type ArithmeticType = usize; type ComponentInfo = (Option, ArithmeticType); -type TypingEnvironment = CircomEnvironment), ArithmeticType>; +type BusInfo = (Option, ArithmeticType); +type TypingEnvironment = CircomEnvironment), ArithmeticType, BusInfo>; type CallRegister = TypeRegister; struct AnalysisInformation { diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 5cb5541f2..1595663ce 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -26,7 +26,7 @@ enum Tag { Known, Unknown, } -type Environment = CircomEnvironment; +type Environment = CircomEnvironment; pub fn unknown_known_analysis( template_name: &str, diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 6a9efe8b1..f350524ab 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -3,7 +3,7 @@ use program_structure::environment::CircomEnvironment; use program_structure::function_data::FunctionData; use program_structure::template_data::TemplateData; -type Environment = CircomEnvironment<(), (), ()>; +type Environment = CircomEnvironment<(), (), (), ()>; pub fn reduce_function(function_data: &mut FunctionData) { let mut environment = CircomEnvironment::new(); From de1f290bff66b7ca248d2d12663e3d7fe45d7f67 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Fri, 12 Apr 2024 18:08:13 +0200 Subject: [PATCH 015/189] Solved errors involving unknown_known_analysis. --- .../buses_free_of_invalid_statements.rs | 2 +- .../src/analyzers/unknown_known_analysis.rs | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 96917244b..970567985 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -53,7 +53,7 @@ fn analyse_statement( analyse_statement(stmt, function_names, reports); } }, - InitializationBlock { meta, xtype, initializations } => { + InitializationBlock { meta, .. } => { let mut report = Report::error( "Initialization statement used inside the bus".to_string(), ReportCode::UndefinedBus, diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index f36c9bf0b..d1d162b7f 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -52,7 +52,6 @@ pub fn unknown_known_analysis( fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInformation { use Statement::*; - use TypeReduction::*; use Tag::*; fn iterate_statements( @@ -101,7 +100,7 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma environment.add_intermediate_bus(name, Unknown); signals_declared = true; } - VariableType::Comment + VariableType::Component | VariableType::AnonymousComponent => { environment.add_component(name, Unknown); signals_declared = true; @@ -125,7 +124,7 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma } } Substitution { meta, var, access, op, rhe, .. } => { - let reduced_type = meta.get_type_knowledge().unwrap(); + let reduced_type = meta.get_type_knowledge().get_reduces_to(); let expression_tag = tag(rhe, &environment); let mut access_tag = Known; for acc in access { @@ -135,17 +134,17 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma } _ => {} } - if access_tag == Unkown { + if access_tag == Unknown { break; } } match reduced_type { - Variable => { + TypeReduction::Variable => { let value = environment.get_mut_variable_or_break(var, file!(), line!()); *value = max(expression_tag, access_tag); modified_variables.insert(var.clone()); } - Component => { + TypeReduction::Component => { constraints_declared = true; if expression_tag == Unknown { add_report(ReportCode::UnknownTemplate, rhe.get_meta(), file_id, &mut reports); @@ -154,7 +153,7 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma add_report(ReportCode::UnknownTemplate, meta, file_id, &mut reports); } } - Bus => { + TypeReduction::Bus => { constraints_declared = true; if expression_tag == Unknown { add_report(ReportCode::UnknownBus, rhe.get_meta(), file_id, &mut reports); @@ -163,7 +162,7 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma add_report(ReportCode::UnknownBus, meta, file_id, &mut reports); } } - SignalTag => { + TypeReduction::Tag => { tags_modified = true; if expression_tag == Unknown { add_report(ReportCode::UnknownTemplate, rhe.get_meta(), file_id, &mut reports); @@ -356,18 +355,17 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma fn tag(expression: &Expression, environment: &Environment) -> Tag { use Expression::*; - use TypeReduction::*; use Tag::*; match expression { Number(_, _) => Known, - Variable { meta, name, access } => { - let reduced_type = meta.get_type_knowledge().unwrap(); + Variable { meta, name, .. } => { + let reduced_type = meta.get_type_knowledge().get_reduces_to(); match reduced_type { - Variable => *environment.get_variable_or_break(name, file!(), line!()), - Signal => *environment.get_intermediate_or_break(name, file!(), line!()), - Bus => *environment.get_intermediate_bus_or_break(name, file!(), line!()), - Component => *environment.get_component_or_break(name, file!(), line!()), - Tag => Known, + TypeReduction::Variable => *environment.get_variable_or_break(name, file!(), line!()), + TypeReduction::Signal => *environment.get_intermediate_or_break(name, file!(), line!()), + TypeReduction::Bus => *environment.get_intermediate_bus_or_break(name, file!(), line!()), + TypeReduction::Component => *environment.get_component_or_break(name, file!(), line!()), + TypeReduction::Tag => Known, } } ArrayInLine { values, .. } | Call { args: values, .. } => { @@ -457,16 +455,18 @@ fn unknown_index(exp: &Expression, environment: &Environment) -> bool { has_unknown_index } InfixOp { lhe, rhe, .. } => { - unknown_index(lhe.as_ref()) || unknown_index(rhe.as_ref()) + unknown_index(lhe.as_ref(), environment) || unknown_index(rhe.as_ref(), environment) } PrefixOp { rhe, .. } => { - unknown_index(rhe.as_ref()) + unknown_index(rhe.as_ref(), environment) } ParallelOp { rhe, .. } => { - unknown_index(rhe.as_ref()) + unknown_index(rhe.as_ref(), environment) } InlineSwitchOp { cond, if_true, if_false, .. } => { - unknown_index(cond.as_ref()) || unknown_index(if_true.as_ref()) || unknown_index(if_false.as_ref()) + unknown_index(cond.as_ref(), environment) + || unknown_index(if_true.as_ref(), environment) + || unknown_index(if_false.as_ref(), environment) } Call { args: exprs, .. } | BusCall { args: exprs, .. } @@ -474,7 +474,7 @@ fn unknown_index(exp: &Expression, environment: &Environment) -> bool { | Tuple { values: exprs, .. } => { let mut has_unknown_index = false; for exp in exprs { - has_unknown_index = has_unknown_index || unknown_index(exp); + has_unknown_index = has_unknown_index || unknown_index(exp, environment); if has_unknown_index { break; } @@ -482,7 +482,7 @@ fn unknown_index(exp: &Expression, environment: &Environment) -> bool { has_unknown_index } UniformArray{ value, dimension, .. } => { - unknown_index(value.as_ref()) || unknown_index(dimension.as_ref()) + unknown_index(value.as_ref(), environment) || unknown_index(dimension.as_ref(), environment) } _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } From 624ab86d489923cc3c39699c0864486db149218d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 16 Apr 2024 10:49:16 +0200 Subject: [PATCH 016/189] working on execute --- .../environment_utils/bus_representation.rs | 34 +- constraint_generation/src/execute.rs | 358 ++++++++++++++++-- .../src/execution_data/executed_bus.rs | 23 +- .../src/execution_data/executed_template.rs | 7 +- .../src/execution_data/mod.rs | 1 + .../src/execution_data/type_definitions.rs | 1 - parser/src/lang.lalrpop | 2 +- .../src/abstract_syntax_tree/ast_shortcuts.rs | 8 +- 8 files changed, 385 insertions(+), 49 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 32dcdc6e3..06d9c36a9 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -14,8 +14,9 @@ struct FieldTypes { // For each field, we store the info depending on if it is a pub struct BusRepresentation { pub node_pointer: Option, pub meta: Option, - pub fields: BTreeMap, + fields: BTreeMap, pub field_tags: BTreeMap, + unassigned_fields: HashMap, } impl Default for BusRepresentation { @@ -25,6 +26,7 @@ impl Default for BusRepresentation { fields: BTreeMap::new(), field_tags: BTreeMap::new(), meta: Option::None, + unassigned_fields: HashMap::new(), } } } @@ -35,6 +37,7 @@ impl Clone for BusRepresentation { fields: self.fields.clone(), field_tags: self.field_tags.clone(), meta : self.meta.clone(), + unassigned_fields: self.unassigned_fields.clone(), } } } @@ -54,10 +57,35 @@ impl BusRepresentation { // En caso de los buses, crear e inicializar componentRepresentation de todos for (symbol, route) in node.signal_fields() { - + 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{ + component.unassigned_fields + .insert(symbol.clone(), signal_slice_size); + } + let field_signal = FieldTypes{signal: Some(signal_slice), bus:None}; + component.fields.insert(symbol.clone(), field_signal); } - for (symbol, route) in node.bus_fields() { + let bus_connexions = node.bus_connexions(); + + for (symbol, route) in node.bus_fields() { + + let bus_node = bus_connexions.get(symbol).unwrap().inspect.goes_to; + let mut bus_field = BusRepresentation::default(); + BusRepresentation::initialize_bus( + &mut bus_field, + bus_node, + scheme, + )?; + let bus_slice = BusSlice::new_with_route(route, &bus_field); + let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); + if bus_slice_size > 0{ + component.unassigned_fields + .insert(symbol.clone(), bus_slice_size); + } + let field_bus = FieldTypes{bus: Some(bus_slice), signal:None}; + component.fields.insert(symbol.clone(), field_bus); } component.node_pointer = Option::Some(node_pointer); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 3b2902259..eca4fa775 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -10,14 +10,15 @@ use super::environment_utils::{ slice_types::{ AExpressionSlice, ArithmeticExpression as ArithmeticExpressionGen, ComponentRepresentation, ComponentSlice, MemoryError, TypeInvalidAccess, TypeAssignmentError, MemorySlice, - SignalSlice, SliceCapacity, TagInfo, TagState + SignalSlice, SliceCapacity, TagInfo, TagState, BusSlice, BusRepresentation }, }; use program_structure::constants::UsefulConstants; use super::execution_data::analysis::Analysis; -use super::execution_data::{ExecutedProgram, ExecutedTemplate, PreExecutedTemplate, NodePointer}; +use super::execution_data::{ExecutedBus, ExecutedProgram, ExecutedTemplate, PreExecutedTemplate, NodePointer}; + use super::{ ast::*, ArithmeticError, FileID, ProgramArchive, Report, ReportCode, ReportCollection }; @@ -66,15 +67,22 @@ impl RuntimeInformation { struct FoldedValue { pub arithmetic_slice: Option, pub node_pointer: Option, + pub bus_node_pointer: Option, pub is_parallel: Option, pub tags: Option, } impl FoldedValue { pub fn valid_arithmetic_slice(f_value: &FoldedValue) -> bool { - f_value.arithmetic_slice.is_some() && f_value.node_pointer.is_none() && f_value.is_parallel.is_none() + f_value.arithmetic_slice.is_some() && f_value.node_pointer.is_none() && + f_value.is_parallel.is_none() && f_value.bus_node_pointer.is_none() } pub fn valid_node_pointer(f_value: &FoldedValue) -> bool { - f_value.node_pointer.is_some() && f_value.is_parallel.is_some() && f_value.arithmetic_slice.is_none() + f_value.node_pointer.is_some() && f_value.is_parallel.is_some() && + f_value.arithmetic_slice.is_none() && f_value.bus_node_pointer.is_none() + } + pub fn valid_bus_node_pointer(f_value: &FoldedValue) -> bool{ + f_value.bus_node_pointer.is_some() && f_value.node_pointer.is_none() && + f_value.is_parallel.is_none() && f_value.arithmetic_slice.is_none() } } @@ -83,6 +91,7 @@ impl Default for FoldedValue { FoldedValue { arithmetic_slice: Option::None, node_pointer: Option::None, + bus_node_pointer: Option::None, is_parallel: Option::None, tags: Option::None, } @@ -274,8 +283,25 @@ fn execute_statement( Substitution { meta, var, access, op, rhe, .. } => { let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; let r_folded = execute_expression(rhe, program_archive, runtime, flags)?; + + let mut struct_node = if actual_node.is_some(){ + ExecutedStructure::Template(actual_node.as_mut().unwrap()) + } else{ + ExecutedStructure::None + }; + let possible_constraint = - perform_assign(meta, var, *op, &access_information, r_folded, actual_node, runtime, program_archive, flags)?; + perform_assign( + meta, + var, + *op, + &access_information, + r_folded, + &mut struct_node, + runtime, + program_archive, + flags + )?; if let Option::Some(node) = actual_node { if *op == AssignOp::AssignConstraintSignal || (*op == AssignOp::AssignSignal && flags.inspect){ debug_assert!(possible_constraint.is_some()); @@ -548,6 +574,90 @@ fn execute_statement( Result::Ok((res, can_be_simplified)) } +fn execute_bus_statement( + stmt: &Statement, + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + actual_node: &mut ExecutedBus, + flags: FlagsExecution +)-> Result<(), ()>{ + use Statement::*; + let id = stmt.get_meta().elem_id; + Analysis::reached(&mut runtime.analysis, id); + let res = match stmt { + InitializationBlock { initializations, .. } => { + execute_sequence_of_bus_statements( + initializations, + program_archive, + runtime, + actual_node, + flags, + )? + } + Declaration { meta, xtype, name, dimensions, .. } => { + + let mut arithmetic_values = Vec::new(); + for dimension in dimensions.iter() { + let f_dimensions = + execute_expression(dimension, program_archive, runtime, flags)?; + arithmetic_values + .push(safe_unwrap_to_single_arithmetic_expression(f_dimensions, line!())); + } + treat_result_with_memory_error_void( + valid_array_declaration(&arithmetic_values), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let usable_dimensions = + if let Option::Some(dimensions) = cast_indexing(&arithmetic_values) { + dimensions + } else { + let err = Result::Err(ExecutionError::ArraySizeTooBig); + treat_result_with_execution_error( + err, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + }; + match xtype { + + VariableType::Signal(_signal_type, tag_list) => + execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, false), + + VariableType::Bus(_id, _signal_type, tag_list) => + execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, false), + + _ =>{ + unreachable!() + } + } + } + Substitution { meta, var, access, op, rhe, .. } => { + let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; + let r_folded = execute_expression(rhe, program_archive, runtime, flags)?; + let _possible_constraint = + perform_assign( + meta, + var, + *op, + &access_information, + r_folded, + &mut ExecutedStructure::Bus(actual_node), + runtime, + program_archive, + flags + )?; + } + Block { stmts, .. } => { + execute_sequence_of_bus_statements(stmts, program_archive, runtime, actual_node, flags)?; + } + _ => unreachable!(), + }; + Result::Ok(()) +} + fn execute_expression( expr: &Expression, program_archive: &ProgramArchive, @@ -679,6 +789,12 @@ fn execute_expression( can_be_simplified = can_simplify; value } + BusCall{id, args, ..} =>{ + let (value, can_simplify) = execute_bus_call(id, args, program_archive, runtime, flags)?; + can_be_simplified = can_simplify; + value + + } ParallelOp{rhe, ..} => { let folded_value = execute_expression(rhe, program_archive, runtime, flags)?; let (node_pointer, _) = @@ -793,6 +909,43 @@ fn execute_anonymous_component_declaration( anonymous_components.insert(component_name.to_string(), (meta, dimensions.clone())); } +fn execute_bus_call( + id: &String, + args: &Vec, + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + flags: FlagsExecution, +) -> Result<(FoldedValue, bool), ()> { + let mut arg_values = Vec::new(); + + for arg_expression in args.iter() { + let f_arg = execute_expression(arg_expression, program_archive, runtime, flags)?; + arg_values.push(safe_unwrap_to_arithmetic_slice(f_arg, line!())); + } + + if program_archive.contains_bus(id){ // in this case we execute + let new_environment = prepare_environment_for_call(id, &arg_values, program_archive); + let previous_environment = std::mem::replace(&mut runtime.environment, new_environment); + let previous_block_type = std::mem::replace(&mut runtime.block_type, BlockType::Known); + let previous_anonymous_components = std::mem::replace(&mut runtime.anonymous_components, AnonymousComponentsInfo::new()); + + let new_file_id = program_archive.get_function_data(id).get_file_id(); + let previous_id = std::mem::replace(&mut runtime.current_file, new_file_id); + + runtime.call_trace.push(id.clone()); + let folded_result = execute_function_call(id, program_archive, runtime, flags)?; + + runtime.environment = previous_environment; + runtime.current_file = previous_id; + runtime.block_type = previous_block_type; + runtime.anonymous_components = previous_anonymous_components; + runtime.call_trace.pop(); + Ok(folded_result) + } else{ + unreachable!() + } +} + fn execute_signal_declaration( signal_name: &str, dimensions: &[SliceCapacity], @@ -831,6 +984,23 @@ fn execute_signal_declaration( } } +fn execute_declaration_bus( + signal_name: &str, + dimensions: &[SliceCapacity], + list_tags: &Vec, + actual_node: &mut ExecutedBus, + is_bus: bool, +) { + if is_bus{ + actual_node.add_bus(signal_name, dimensions); + } else{ + actual_node.add_signal(signal_name, dimensions); + } + for t in list_tags{ + actual_node.add_tag_signal(signal_name, t, None); + } +} + fn execute_bus_declaration( bus_name: &str, dimensions: &[SliceCapacity], @@ -873,6 +1043,12 @@ fn execute_bus_declaration( In case the assigment could be a constraint generator the returned value is the constraint that will be created */ +enum ExecutedStructure<'a>{ + Template(&'a mut ExecutedTemplate), + Bus(&'a mut ExecutedBus), + None +} + struct Constrained { left: String, right: AExpressionSlice, @@ -883,12 +1059,12 @@ fn perform_assign( op: AssignOp, accessing_information: &AccessingInformation, r_folded: FoldedValue, - actual_node: &mut Option, + actual_node: &mut ExecutedStructure, runtime: &mut RuntimeInformation, program_archive: &ProgramArchive, flags: FlagsExecution ) -> Result, ()> { - use super::execution_data::type_definitions::SubComponentData; + use super::execution_data::type_definitions::{SubComponentData, BusData}; let full_symbol = create_symbol(symbol, &accessing_information); let possible_arithmetic_slice = if ExecutionEnvironment::has_variable(&runtime.environment, symbol) @@ -990,10 +1166,16 @@ fn perform_assign( reference_to_tags.insert(tag.clone(), Option::Some(value.clone())); let tag_state = reference_to_tags_defined.get_mut(&tag).unwrap(); tag_state.value_defined = true; - if let Option::Some(node) = actual_node{ - node.add_tag_signal(symbol, &tag, Some(value)); - } else{ - unreachable!(); + match actual_node{ + ExecutedStructure::Template(node) =>{ + node.add_tag_signal(symbol, &tag, Some(value)); + }, + ExecutedStructure::Bus(node) =>{ + node.add_tag_signal(symbol, &tag, Some(value)); + }, + ExecutedStructure::None => { + unreachable!(); + } } } @@ -1172,12 +1354,18 @@ fn perform_assign( for (tag, value) in reference_to_tags{ let tag_state = reference_to_tags_defined.get_mut(tag).unwrap(); tag_state.complete = true; - if let Option::Some(node) = actual_node{ - if !tag_state.value_defined{ - node.add_tag_signal(symbol, &tag, value.clone()); + match actual_node{ + ExecutedStructure::Template(node) =>{ + if !tag_state.value_defined{ + node.add_tag_signal(symbol, &tag, value.clone()); + } + }, + ExecutedStructure::Bus(node) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); } - } else{ - unreachable!(); } } } @@ -1288,17 +1476,24 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - if let Option::Some(actual_node) = actual_node { - let data = SubComponentData { - name: symbol.to_string(), - is_parallel: component.is_parallel, - goes_to: node_pointer, - indexed_with: accessing_information.before_signal.clone(), - }; - actual_node.add_arrow(full_symbol.clone(), data); - } else { - unreachable!(); - } + + match actual_node{ + ExecutedStructure::Template(node) =>{ + let data = SubComponentData { + name: symbol.to_string(), + is_parallel: component.is_parallel, + goes_to: node_pointer, + indexed_with: accessing_information.before_signal.clone(), + }; + node.add_arrow(full_symbol.clone(), data); + }, + ExecutedStructure::Bus(node) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); + } + } } Option::None } else { @@ -1378,24 +1573,98 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - if let Option::Some(actual_node) = actual_node { - let data = SubComponentData { + match actual_node{ + ExecutedStructure::Template(node) =>{ + let data = SubComponentData { + name: symbol.to_string(), + goes_to: node_pointer, + is_parallel: component.is_parallel, + indexed_with: accessing_information.before_signal.clone(), + }; + let component_symbol = create_component_symbol(symbol, &accessing_information); + node.add_arrow(component_symbol, data); + }, + ExecutedStructure::Bus(node) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); + } + } + } + Option::Some(arithmetic_slice) + } + } else if ExecutionEnvironment::has_bus(&runtime.environment, symbol){ + + let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); + + let bus_slice = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + if FoldedValue::valid_bus_node_pointer(&r_folded){ + // in this case we are performing an assigment of the type in the node_pointer + // to the bus in the left + + let bus_pointer = r_folded.bus_node_pointer.unwrap(); + debug_assert!(accessing_information.before_signal.len() == 0); + debug_assert!(accessing_information.signal_access.is_none()); + + + + for i in 0..BusSlice::get_number_of_cells(&bus_slice.2){ + let mut value_left = treat_result_with_memory_error( + BusSlice::access_value_by_index(&bus_slice.2, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let memory_result = BusRepresentation::initialize_bus( + &mut value_left, + bus_pointer, + &runtime.exec_program, + ); + treat_result_with_memory_error_void( + memory_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + } + match actual_node{ + ExecutedStructure::Template(node) =>{ + let data = BusData { name: symbol.to_string(), - goes_to: node_pointer, - is_parallel: component.is_parallel, - indexed_with: accessing_information.before_signal.clone(), + goes_to: bus_pointer, }; let component_symbol = create_component_symbol(symbol, &accessing_information); - actual_node.add_arrow(component_symbol, data); - } else { + node.add_bus_arrow(component_symbol, data);; + }, + ExecutedStructure::Bus(node) =>{ + let data = BusData { + name: symbol.to_string(), + goes_to: bus_pointer, + }; + let component_symbol = create_component_symbol(symbol, &accessing_information); + node.add_bus_arrow(component_symbol, data); + }, + ExecutedStructure::None => { unreachable!(); } } - Option::Some(arithmetic_slice) + + None + } else{ + // case assigning a signal of the bus or a tag + None } - } else if ExecutionEnvironment::has_variable(&runtime.environment, symbol){ - // Case buses -> case assigning bus type or assigning values - unreachable!(); + + } else { unreachable!(); }; @@ -1469,6 +1738,19 @@ fn execute_sequence_of_statements( Result::Ok((Option::None, can_be_simplified)) } +fn execute_sequence_of_bus_statements( + stmts: &[Statement], + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + actual_node: &mut ExecutedBus, + flags: FlagsExecution, +) -> Result<(), ()> { + for stmt in stmts.iter() { + execute_bus_statement(stmt, program_archive, runtime, actual_node, flags)?; + } + Result::Ok(()) +} + fn execute_delayed_declarations( program_archive: &ProgramArchive, runtime: &mut RuntimeInformation, diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index 8f9d83498..ce2c75754 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -9,9 +9,9 @@ use crate::execution_data::AExpressionSlice; use crate::execution_data::TagInfo; -struct BusConnexion{ +pub struct BusConnexion{ full_name: String, - inspect: BusData, + pub inspect: BusData, dag_offset: usize, dag_jump: usize, } @@ -23,7 +23,8 @@ pub struct ExecutedBus { pub signal_fields: SignalCollector, pub bus_fields: BusCollector, pub parameter_instances: ParameterContext, - bus_connexions: HashMap, + pub signal_to_tags: TagContext, + pub bus_connexions: HashMap, } impl ExecutedBus { @@ -38,6 +39,7 @@ impl ExecutedBus { parameter_instances: instance, signal_fields: Vec::new(), bus_fields: Vec::new(), + signal_to_tags: TagContext::new(), bus_connexions: HashMap::new(), } } @@ -61,7 +63,16 @@ impl ExecutedBus { self.bus_fields.push((bus_name.to_string(), dimensions.to_vec())); } - + pub fn add_tag_signal(&mut self, signal_name: &str, tag_name: &str, value: Option){ + let tags_signal = self.signal_to_tags.get_mut(signal_name); + if tags_signal.is_none(){ + let mut new_tags_signal = TagInfo::new(); + new_tags_signal.insert(tag_name.to_string(), value); + self.signal_to_tags.insert(signal_name.to_string(), new_tags_signal); + } else { + tags_signal.unwrap().insert(tag_name.to_string(), value); + } + } fn build_signals(&self, dag: &mut DAG) { @@ -73,5 +84,9 @@ impl ExecutedBus { pub fn bus_fields(&self) -> &BusCollector { &self.bus_fields } + + pub fn bus_connexions(&self) -> &HashMap{ + &self.bus_connexions + } } \ No newline at end of file diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 6785d8267..cc79ab745 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -139,13 +139,18 @@ impl ExecutedTemplate { && self.tag_instances == *tag_context } - // pub add_bus_arrow pub fn add_arrow(&mut self, component_name: String, data: SubComponentData) { let cnn = Connexion { full_name: component_name, inspect: data, dag_offset: 0, dag_component_offset: 0, dag_jump: 0, dag_component_jump: 0}; self.connexions.push(cnn); } + pub fn add_bus_arrow(&mut self, bus_name: String, data: BusData){ + let cnn = + BusConnexion { full_name:bus_name.clone(), inspect: data, dag_offset: 0, dag_jump: 0}; + self.bus_connexions.insert(bus_name, cnn); + } + // Same with buses pub fn add_input(&mut self, input_name: &str, dimensions: &[usize]) { diff --git a/constraint_generation/src/execution_data/mod.rs b/constraint_generation/src/execution_data/mod.rs index 536ba439a..b471a0035 100644 --- a/constraint_generation/src/execution_data/mod.rs +++ b/constraint_generation/src/execution_data/mod.rs @@ -2,6 +2,7 @@ use super::environment_utils::slice_types::{AExpressionSlice, TagInfo}; use circom_algebra::algebra::Constraint; pub use executed_program::ExecutedProgram; pub use executed_template::{PreExecutedTemplate, ExecutedTemplate}; +pub use executed_bus::ExecutedBus; pub use type_definitions::NodePointer; pub mod analysis; diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index 639496f71..b76dbb9d3 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -22,7 +22,6 @@ pub struct SubComponentData { pub struct BusData { pub name: String, - pub indexed_with: Vec, pub goes_to: NodePointer, } diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index ae8387450..b837d0c79 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -192,7 +192,7 @@ BusHeader : (Expression, VariableType) = { => { let bus_builder = build_bus_call(Meta::new(s,e),id.clone(),Vec::new()); let (s,t) = header; - (bus_builder,VariableType::Bus(id, s, t)) + (bus_builder, VariableType::Bus(id, s, t)) }, "(" ")" diff --git a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs index 7d693e980..6f4527074 100644 --- a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs +++ b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs @@ -144,7 +144,13 @@ pub fn split_bus_declaration_into_single_nodes( let dimensions = symbol.is_array; let possible_init = symbol.init; let single_declaration = build_declaration(with_meta, has_type, name, dimensions.clone()); - let bus_declaration = build_substitution(meta.clone(), symbol.name.clone(), vec![], AssignVar, bustype.clone()); + + let mut value = bustype.clone(); + for dim_expr in dimensions.iter().rev(){ + value = build_uniform_array(meta.clone(), value, dim_expr.clone()); + } + + let bus_declaration = build_substitution(meta.clone(), symbol.name.clone(), vec![], AssignVar, value); initializations.push(single_declaration); initializations.push(bus_declaration); From 499923f63971eac4410aa4028d2f1d4202da21b4 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 16 Apr 2024 17:58:07 +0200 Subject: [PATCH 017/189] working on execute --- .../environment_utils/bus_representation.rs | 5 +- constraint_generation/src/execute.rs | 283 +++++++++++++++++- .../src/execution_data/executed_bus.rs | 10 +- .../src/execution_data/executed_program.rs | 40 +++ program_structure/src/utils/memory_slice.rs | 1 + 5 files changed, 328 insertions(+), 11 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 06d9c36a9..c9f08d875 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -101,9 +101,8 @@ impl BusRepresentation { unreachable!() } - fn get_all_fields(&self) -> Result<&SignalSlice, MemoryError>{ - // TODO - unreachable!() + pub fn has_unassigned_fields(&self) -> bool{ + self.node_pointer.is_none() || !self.unassigned_fields.is_empty() } pub fn assign_value_to_field( diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index eca4fa775..cfd045766 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -66,6 +66,7 @@ impl RuntimeInformation { struct FoldedValue { pub arithmetic_slice: Option, + pub bus_slice: Option, pub node_pointer: Option, pub bus_node_pointer: Option, pub is_parallel: Option, @@ -75,14 +76,22 @@ impl FoldedValue { pub fn valid_arithmetic_slice(f_value: &FoldedValue) -> bool { f_value.arithmetic_slice.is_some() && f_value.node_pointer.is_none() && f_value.is_parallel.is_none() && f_value.bus_node_pointer.is_none() + && f_value.bus_slice.is_none() + } + pub fn valid_bus_slice(f_value: &FoldedValue) -> bool { + f_value.bus_slice.is_some() && f_value.node_pointer.is_none() && + f_value.is_parallel.is_none() && f_value.bus_node_pointer.is_none() + && f_value.arithmetic_slice.is_none() } pub fn valid_node_pointer(f_value: &FoldedValue) -> bool { f_value.node_pointer.is_some() && f_value.is_parallel.is_some() && f_value.arithmetic_slice.is_none() && f_value.bus_node_pointer.is_none() + && f_value.bus_slice.is_none() } pub fn valid_bus_node_pointer(f_value: &FoldedValue) -> bool{ f_value.bus_node_pointer.is_some() && f_value.node_pointer.is_none() && f_value.is_parallel.is_none() && f_value.arithmetic_slice.is_none() + && f_value.bus_slice.is_none() } } @@ -90,6 +99,7 @@ impl Default for FoldedValue { fn default() -> Self { FoldedValue { arithmetic_slice: Option::None, + bus_slice: Option::None, node_pointer: Option::None, bus_node_pointer: Option::None, is_parallel: Option::None, @@ -679,7 +689,10 @@ fn execute_expression( execute_component(meta, name, access, program_archive, runtime, flags)? } else if ExecutionEnvironment::has_variable(&runtime.environment, name) { execute_variable(meta, name, access, program_archive, runtime, flags)? - } else { + } else if ExecutionEnvironment::has_bus(&runtime.environment, name){ + execute_bus(meta, name, access, program_archive, runtime, flags)? + } + else { unreachable!(); } } @@ -790,8 +803,7 @@ fn execute_expression( value } BusCall{id, args, ..} =>{ - let (value, can_simplify) = execute_bus_call(id, args, program_archive, runtime, flags)?; - can_be_simplified = can_simplify; + let value = execute_bus_call_complete(id, args, program_archive, runtime, flags)?; value } @@ -909,13 +921,13 @@ fn execute_anonymous_component_declaration( anonymous_components.insert(component_name.to_string(), (meta, dimensions.clone())); } -fn execute_bus_call( +fn execute_bus_call_complete( id: &String, args: &Vec, program_archive: &ProgramArchive, runtime: &mut RuntimeInformation, flags: FlagsExecution, -) -> Result<(FoldedValue, bool), ()> { +) -> Result { let mut arg_values = Vec::new(); for arg_expression in args.iter() { @@ -929,11 +941,11 @@ fn execute_bus_call( let previous_block_type = std::mem::replace(&mut runtime.block_type, BlockType::Known); let previous_anonymous_components = std::mem::replace(&mut runtime.anonymous_components, AnonymousComponentsInfo::new()); - let new_file_id = program_archive.get_function_data(id).get_file_id(); + let new_file_id = program_archive.get_bus_data(id).get_file_id(); let previous_id = std::mem::replace(&mut runtime.current_file, new_file_id); runtime.call_trace.push(id.clone()); - let folded_result = execute_function_call(id, program_archive, runtime, flags)?; + let folded_result = execute_bus_call(id, arg_values, program_archive, runtime, flags)?; runtime.environment = previous_environment; runtime.current_file = previous_id; @@ -1979,6 +1991,116 @@ fn unfold_signals(current: String, dim: usize, lengths: &[usize], result: &mut V } } +fn execute_bus( + meta: &Meta, + symbol: &str, + access: &[Access], + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + flags: FlagsExecution +) -> Result { + let access_information = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; + if access_information.undefined { + let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); + return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); + } + let environment_response = + ExecutionEnvironment::get_bus_res(&runtime.environment, symbol); + let (tags, tags_definitions, bus_slice) = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let memory_response = BusSlice::access_values(&bus_slice, &access_information.array_access); + let bus_slice = treat_result_with_memory_error( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + if access_information.field_access.is_none() { + + // Case we are accessing the complete bus or array of buses + + let mut tags_propagated = TagInfo::new(); + for (tag, value) in tags{ + let state = tags_definitions.get(tag).unwrap(); + if state.value_defined || state.complete{ + tags_propagated.insert(tag.clone(), value.clone()); + } else if state.defined{ + tags_propagated.insert(tag.clone(), None); + } + } + // Check that all the buses are completely assigned + + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + let value_left = treat_result_with_memory_error( + BusSlice::access_value_by_index(&bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + if value_left.has_unassigned_fields(){ + treat_result_with_memory_error( + Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } + } + + Result::Ok(FoldedValue{bus_slice: Some(bus_slice), tags: Some(tags_propagated), ..FoldedValue::default()}) + } else{ + if meta.get_type_knowledge().is_tag(){ + // Case we are accessing a tag of the bus + let acc = access_information.field_access.unwrap(); + if tags.contains_key(&acc) { + let value_tag = tags.get(&acc).unwrap(); + let state = tags_definitions.get(&acc).unwrap(); + if let Some(value_tag) = value_tag { // tag has value + // access only allowed when (1) it is value defined by user or (2) it is completely assigned + if state.value_defined || state.complete{ + let a_value = AExpr::Number { value: value_tag.clone() }; + let ae_slice = AExpressionSlice::new(&a_value); + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) + } else{ + let error = MemoryError::TagValueNotInitializedAccess; + treat_result_with_memory_error( + Result::Err(error), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + + } + else { + let error = MemoryError::TagValueNotInitializedAccess; + treat_result_with_memory_error( + Result::Err(error), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + } + else { + unreachable!() + } + + } else{ + // Case we are accessing a field of the component + Ok(FoldedValue{..FoldedValue::default()}) + + } + } + +} + fn execute_component( meta: &Meta, symbol: &str, @@ -2129,6 +2251,8 @@ fn execute_function_call( Result::Ok((return_value, can_be_simplified)) } + + fn execute_template_call( id: &str, parameter_values: Vec, @@ -2251,6 +2375,61 @@ fn preexecute_template_call( Result::Ok(FoldedValue { node_pointer: Option::Some(node_pointer), is_parallel: Option::Some(false), ..FoldedValue::default() }) } +fn execute_bus_call( + id: &str, + parameter_values: Vec, + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + flags: FlagsExecution, +) -> Result { + debug_assert!(runtime.block_type == BlockType::Known); + + let args_names = program_archive.get_bus_data(id).get_name_of_params(); + let template_body = program_archive.get_bus_data(id).get_body_as_vec(); + let mut args_to_values = BTreeMap::new(); + debug_assert_eq!(args_names.len(), parameter_values.len()); + let mut instantiation_name = format!("{}(", id); + let mut not_empty_name = false; + + for (name, value) in args_names.iter().zip(parameter_values) { + instantiation_name.push_str(&format!("{},", value.to_string())); + not_empty_name = true; + args_to_values.insert(name.clone(), value.clone()); + } + + if not_empty_name { + instantiation_name.pop(); + } + instantiation_name.push(')'); + + let existent_node = runtime.exec_program.identify_bus_node(id, &args_to_values); + let node_pointer = if let Option::Some(pointer) = existent_node { + pointer + } else { + let analysis = + std::mem::replace(&mut runtime.analysis, Analysis::new(program_archive.id_max)); + let code = program_archive.get_bus_data(id).get_body().clone(); + let mut node = ExecutedBus::new( + id.to_string(), + instantiation_name, + args_to_values, + ); + execute_sequence_of_bus_statements( + template_body, + program_archive, + runtime, + &mut node, + flags, + )?; + + + let analysis = std::mem::replace(&mut runtime.analysis, analysis); + let node_pointer = runtime.exec_program.add_bus_node_to_scheme(node, analysis); + node_pointer + }; + Result::Ok(FoldedValue { bus_node_pointer: Option::Some(node_pointer), ..FoldedValue::default() }) +} + fn execute_infix_op( meta: &Meta, infix: ExpressionInfixOpcode, @@ -2451,6 +2630,88 @@ fn treat_accessing( Result::Ok(AccessingInformation { undefined, before_signal, after_signal, signal_access, tag_access}) } + +/* + Usable representation of a series of accesses performed over a symbol representing a bus. + AccessingInformationBus { + pub undefined: bool ===> true if one of the index values could not be transformed into a SliceCapacity during the process, + pub array_access: Vec + pub field_access: Option // may not appear + pub remaining_access: Option, // may not appear + } +*/ +struct AccessingInformationBus { + pub undefined: bool, + pub array_access: Vec, + pub field_access: Option, + pub remaining_access: Option>, +} +fn treat_accessing_bus( + meta: &Meta, + access: &[Access], + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + flags: FlagsExecution +) -> Result { + + fn treat_accessing_bus_index( + index: usize, + meta: &Meta, + access: &[Access], + program_archive: &ProgramArchive, + runtime: &mut RuntimeInformation, + flags: FlagsExecution + ) -> Result{ + + let (ae_before_signal, field_access, signal_index) = + treat_indexing(index, access, program_archive, runtime, flags)?; + + treat_result_with_memory_error( + valid_indexing(&ae_before_signal), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let mut remaining_access = if signal_index < access.len(){ + Some(Box::new( + treat_accessing_bus_index(signal_index + 1, meta, access, program_archive, runtime, flags)?) + ) + } else{ + None + }; + + let possible_before_indexing = cast_indexing(&ae_before_signal); + + let remaining_access_undefined = remaining_access.is_some() && remaining_access.as_ref().unwrap().undefined; + + let undefined = possible_before_indexing.is_none() || remaining_access_undefined; + + let array_access = if undefined { + Vec::new() + } else { + possible_before_indexing.unwrap() + }; + if undefined{ + remaining_access = None + }; + + Result::Ok(AccessingInformationBus { undefined, array_access, remaining_access, field_access}) + + } + + treat_accessing_bus_index( + 0, + meta, + access, + program_archive, + runtime, + flags + ) + +} + + //************************************************* Safe transformations ************************************************* fn safe_unwrap_to_single_arithmetic_expression(folded_value: FoldedValue, line: u32) -> AExpr { @@ -2536,6 +2797,10 @@ fn treat_result_with_memory_error_void( TypeInvalidAccess::NoInitializedSignal =>{ Report::error("Exception caused by invalid access: trying to access to a signal that is not initialized" .to_string(), RuntimeError) + }, + TypeInvalidAccess::NoInitializedBus =>{ + Report::error("Exception caused by invalid access: trying to access to a bus whose fields have not been completely initialized" .to_string(), + RuntimeError) } } } @@ -2640,6 +2905,10 @@ fn treat_result_with_memory_error( Report::error("Exception caused by invalid access: trying to access to a signal that is not initialized" .to_string(), RuntimeError) } + TypeInvalidAccess::NoInitializedBus =>{ + Report::error("Exception caused by invalid access: trying to access to a bus whose fields have not been completely initialized" .to_string(), + RuntimeError) + } } }, MemoryError::AssignmentError(type_asig_error) => { diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index ce2c75754..20587eea4 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -44,7 +44,7 @@ impl ExecutedBus { } } - pub fn is_equal(&self, name: &str, context: &ParameterContext, tag_context: &TagContext) -> bool { + pub fn is_equal(&self, name: &str, context: &ParameterContext) -> bool { self.bus_name == name && self.parameter_instances == *context } @@ -78,6 +78,14 @@ impl ExecutedBus { } + pub fn bus_name(&self) -> &String { + &self.bus_name + } + + pub fn parameter_instances(&self) -> &ParameterContext { + &self.parameter_instances + } + pub fn signal_fields(&self) -> &SignalCollector { &self.signal_fields } diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index c203031e8..f965ac252 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -47,6 +47,20 @@ impl ExecutedProgram { } Option::None } + pub fn identify_bus_node(&self, name: &str, context: &ParameterContext) -> Option { + if !self.bus_to_nodes.contains_key(name) { + return Option::None; + } + let related_nodes = self.bus_to_nodes.get(name).unwrap(); + for index in related_nodes { + let existing_node = &self.model_buses[*index]; + if ExecutedBus::is_equal(existing_node, name, context) { + return Option::Some(*index); + } + } + Option::None + } + pub fn number_of_nodes(&self) -> usize { self.model.len() } @@ -113,6 +127,32 @@ impl ExecutedProgram { node_index } + + pub fn add_bus_node_to_scheme( + &mut self, + mut node: ExecutedBus, + analysis: Analysis, // not needed? + ) -> NodePointer { + //use super::filters::*; + // Clean code??? + //apply_unused(&mut node.code, &analysis, &self.prime); + //apply_computed(&mut node.code, &analysis); + // Insert template + let possible_index = self.identify_bus_node( + node.bus_name(), + node.parameter_instances(), + ); + if let Option::Some(index) = possible_index { + return index; + } + self.bus_to_nodes.entry(node.bus_name().clone()).or_insert_with(|| vec![]); + let nodes_for_bus = self.bus_to_nodes.get_mut(node.bus_name()).unwrap(); + let node_index = self.model_buses.len(); + self.model_buses.push(node); + nodes_for_bus.push(node_index); + node_index + } + pub fn export(mut self, mut program: ProgramArchive, flags: FlagsExecution) -> ExportResult { use super::executed_template::templates_in_mixed_arrays; fn merge_mixed(org: Vec, new: Vec) -> Vec { diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 3b9d6fc74..29ee8a749 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -6,6 +6,7 @@ pub enum TypeInvalidAccess { MissingInputTags(String), NoInitializedComponent, NoInitializedSignal, + NoInitializedBus, } pub enum TypeAssignmentError { From 6349570508d3a5e7d7d55dc875165bae1dc0ce31 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 20 Apr 2024 16:53:55 +0200 Subject: [PATCH 018/189] Added new errors for bus typing and new test files. --- .../src/program_library/error_code.rs | 6 ++ tests/bus_dec1.circom | 26 ------ tests/bus_test_correct_1.circom | 17 ++++ tests/bus_test_correct_2.circom | 82 +++++++++++++++++++ tests/bus_test_correct_3.circom | 23 ++++++ 5 files changed, 128 insertions(+), 26 deletions(-) delete mode 100644 tests/bus_dec1.circom create mode 100644 tests/bus_test_correct_1.circom create mode 100644 tests/bus_test_correct_2.circom create mode 100644 tests/bus_test_correct_3.circom diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index d3fa0303b..418ced740 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -21,8 +21,10 @@ pub enum ReportCode { WrongTypesInAssignOperationOperatorSignal, WrongTypesInAssignOperationOperatorNoSignal, WrongTypesInAssignOperationTemplate, + WrongTypesInAssignOperationBus, WrongTypesInAssignOperationExpression, WrongTypesInAssignOperationArrayTemplates, + WrongTypesInAssignOperationArrayBuses, WrongTypesInAssignOperationDims(usize, usize), WrongNumberOfArguments(usize, usize), UndefinedFunction, @@ -69,6 +71,7 @@ pub enum ReportCode { InvalidTagAccessAfterArray, InvalidArraySize(usize), InvalidArraySizeT, + InvalidArraySizeB, InvalidArrayType, ForStatementIllConstructed, BadArrayAccess, @@ -122,6 +125,8 @@ impl fmt::Display for ReportCode { WrongTypesInAssignOperationOperatorNoSignal => "T2000", WrongTypesInAssignOperationArrayTemplates => "T2000", WrongTypesInAssignOperationTemplate => "T2000", + WrongTypesInAssignOperationArrayBuses => "T2000", + WrongTypesInAssignOperationBus => "T2000", WrongTypesInAssignOperationExpression => "T2000", WrongTypesInAssignOperationDims(..) => "T2000", UnclosedComment => "P1005", @@ -193,6 +198,7 @@ impl fmt::Display for ReportCode { UnreachableSignals => "T2050", MainComponentWithTags => "T2051", UndefinedBus => "T2052", + InvalidArraySizeB => "T2053", RuntimeError => "T3001", RuntimeWarning => "T3002", UnknownDimension => "T20460", diff --git a/tests/bus_dec1.circom b/tests/bus_dec1.circom deleted file mode 100644 index 13c0301e2..000000000 --- a/tests/bus_dec1.circom +++ /dev/null @@ -1,26 +0,0 @@ -pragma circom 2.0.0; - -bus Point (n) { - signal {binary} x[n]; - signal {maxvalue} y; -} - -bus New (m,n) { - Point(m) {babyedwards} a; - signal {binary} select; - Point(n) {babymontgomery} b; -} - -template Multiplier () { - signal input a,b; - signal output c; - Point(3) input {tag1} p1; - New(2,4) output {tag2} n1; - Point(3) {tag1} p2 <== p1, p3; - - p3.x[0] <-- p1.y; - c <== a * b; - -} - -component main = Multiplier(); \ No newline at end of file diff --git a/tests/bus_test_correct_1.circom b/tests/bus_test_correct_1.circom new file mode 100644 index 000000000..59ebf204a --- /dev/null +++ b/tests/bus_test_correct_1.circom @@ -0,0 +1,17 @@ +pragma circom 2.0.0; + +bus Point (n) { + signal {binary} x[n], y[n]; +} + +template Pipe (n) { + Point(n) input {babyedwards} pin; + Point(n) output {babyedwards} pout; + + for (var i=0; i pout; +} + + +template BabyCheck() { + Point input p; + + Point q; + + var a = 168700; + var d = 168696; + + q.x <== p.x*p.x; + q.y <== p.y*p.y; + + a*q.x + q.y === 1 + d*q.x*q.y; +} + +// Extracts the public key from private key +template BabyPbk() { + signal input in; + Point output A; + + var BASE8[2] = [ + 5299619240641551281634865583518297030282874472190772894086521144482721001553, + 16950150798460657717958625567821834550301663161624707787222815936182638968203 + ]; + + component pvkBits = Num2Bits(253); + pvkBits.in <== in; + + component mulFix = EscalarMulFix(253, BASE8); + + var i; + for (i=0; i<253; i++) { + mulFix.e[i] <== pvkBits.out[i]; + } + A.x <== mulFix.out[0]; + A.y <== mulFix.out[1]; +} \ No newline at end of file diff --git a/tests/bus_test_correct_3.circom b/tests/bus_test_correct_3.circom new file mode 100644 index 000000000..e7acc2778 --- /dev/null +++ b/tests/bus_test_correct_3.circom @@ -0,0 +1,23 @@ +pragma circom 2.0.0; + +bus Correct { + signal {binary} correct; +} + +bus RecursiveArray (N) { + Correct array[N]; + RecursiveArray(N-1) rec; +} + +template Create (N) { + RecursiveArray(N) output out; + + component create_rec = Create(N-1); + + for (var i=0; i Date: Wed, 24 Apr 2024 09:28:59 +0200 Subject: [PATCH 019/189] Incomplete modifications on type analysis for typing buses. --- type_analysis/src/analyzers/type_check.rs | 209 ++++++++++++++-------- 1 file changed, 137 insertions(+), 72 deletions(-) diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 9d5537c31..62724ec86 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1,7 +1,7 @@ -use program_structure::ast::Expression::Call; use super::type_given_function::type_given_function; use super::type_register::TypeRegister; use program_structure::ast::*; +use program_structure::ast::Expression::Call; use program_structure::environment::CircomEnvironment; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; @@ -11,8 +11,10 @@ use std::collections::HashSet; type ArithmeticType = usize; type ComponentInfo = (Option, ArithmeticType); -type BusInfo = (Option, ArithmeticType); -type TypingEnvironment = CircomEnvironment), ArithmeticType, BusInfo>; +type BusInfo = (Option, ArithmeticType, std::vec::Vec); +type SignalInfo = (ArithmeticType, std::vec::Vec); +type VarInfo = ArithmeticType; +type TypingEnvironment = CircomEnvironment; type CallRegister = TypeRegister; struct AnalysisInformation { @@ -25,19 +27,29 @@ struct AnalysisInformation { } struct FoldedType { + // var dimension arithmetic: Option, + // template name template: Option, + // bus type name + bus: Option, } impl FoldedType { pub fn arithmetic_type(dimensions: ArithmeticType) -> FoldedType { - FoldedType { arithmetic: Option::Some(dimensions), template: Option::None } + FoldedType { arithmetic: Option::Some(dimensions), template: Option::None, bus: Option::None } } pub fn template(name: &str) -> FoldedType { - FoldedType { template: Option::Some(name.to_string()), arithmetic: Option::None } + FoldedType { template: Option::Some(name.to_string()), arithmetic: Option::None, bus: Option::None } } pub fn is_template(&self) -> bool { self.template.is_some() && self.arithmetic.is_none() } + pub fn bus(name: &str, dimensions: ArithmeticType) -> FoldedType { + FoldedType { bus: Option::Some(name.to_string()), arithmetic: Option::Some(dimensions), template: Option::None } + } + pub fn is_bus(&self) -> bool { + self.bus.is_some() + } pub fn dim(&self) -> usize { if let Option::Some(dim) = &self.arithmetic { *dim @@ -47,11 +59,12 @@ impl FoldedType { } pub fn same_type(left: &FoldedType, right: &FoldedType) -> bool { let mut equal = false; - if let (Option::Some(l_template), Option::Some(r_template)) = - (&left.template, &right.template) - { + if let (Option::Some(l_template), Option::Some(r_template)) = (&left.template, &right.template) { equal = l_template.eq(r_template); } + if let (Option::Some(l_bus), Option::Some(r_bus)) = (&left.bus, &right.bus) { + equal = l_bus.eq(r_bus); + } if let (Option::Some(l_dim), Option::Some(r_dim)) = (&left.arithmetic, &right.arithmetic) { equal = *l_dim == *r_dim; } @@ -105,7 +118,7 @@ pub fn type_check(program_archive: &ProgramArchive) -> Result bool { - if let Call { id, .. } = initial_expression{ + if let Call { id, .. } = initial_expression { let inputs = program_archive.get_template_data(id).get_inputs(); let mut tag_in_inputs = false; for input in inputs { @@ -141,6 +154,13 @@ fn type_statement( &mut analysis_information.reports, ); } + else if dim_type.is_bus() { + add_report( + ReportCode::InvalidArraySizeB, + dim_expression.get_meta(), + &mut analysis_information.reports, + ); + } else if dim_type.dim() > 0 { add_report( ReportCode::InvalidArraySize(dim_type.dim()), @@ -151,17 +171,21 @@ fn type_statement( } match xtype { VariableType::Signal(s_type, tags) => { - if let SignalType::Input = s_type { - analysis_information.environment.add_input(name, (dimensions.len(),tags.clone())); - } else if let SignalType::Output = s_type { - analysis_information.environment.add_output(name, (dimensions.len(),tags.clone())); - } else { - analysis_information.environment.add_intermediate(name, (dimensions.len(),tags.clone())); + match s_type { + SignalType::Input => analysis_information + .environment + .add_input(name, (dimensions.len(),tags.clone())), + SignalType::Output => analysis_information + .environment + .add_output(name, (dimensions.len(),tags.clone())), + SignalType::Intermediate => analysis_information + .environment + .add_intermediate(name, (dimensions.len(),tags.clone())), } } - VariableType::Var => { - analysis_information.environment.add_variable(name, dimensions.len()) - } + VariableType::Var => analysis_information + .environment + .add_variable(name, dimensions.len()), VariableType::Component => analysis_information .environment .add_component(name, (meta.component_inference.clone(), dimensions.len())), @@ -169,8 +193,17 @@ fn type_statement( .environment .add_component(name, (meta.component_inference.clone(), dimensions.len())), VariableType::Bus(tname, stype, tags) => { - // TODO: - unreachable!("TODO") + match s_type { + SignalType::Input => analysis_information + .environment + .add_input_bus(name, (Option::Some(tname), dimensions.len(), tags.clone())), + SignalType::Output => analysis_information + .environment + .add_output_bus(name, (Option::Some(tname), dimensions.len(), tags.clone())), + SignalType::Intermediate => analysis_information + .environment + .add_intermediate_bus(name, (Option::Some(tname), dimensions.len(), tags.clone())), + } } } } @@ -216,10 +249,13 @@ fn type_statement( match (&symbol_information, op) { (SymbolInformation::Signal(_), AssignOp::AssignConstraintSignal) | (SymbolInformation::Signal(_), AssignOp::AssignSignal) + | (SymbolInformation::Bus(_), AssignOp::AssignConstraintSignal) + | (SymbolInformation::Bus(_), AssignOp::AssignSignal) + | (SymbolInformation::Bus(_), AssignOp::AssignVar) | (SymbolInformation::Var(_), AssignOp::AssignVar) - | (SymbolInformation::Component(_), AssignOp::AssignVar) => {} + | (SymbolInformation::Component(_), AssignOp::AssignVar) | (SymbolInformation::Tag, AssignOp::AssignVar) => {} - (SymbolInformation::Signal(_), AssignOp::AssignVar)=>{ + (SymbolInformation::Signal(_), AssignOp::AssignVar) => { return add_report( ReportCode::WrongTypesInAssignOperationOperatorSignal, meta, @@ -235,14 +271,14 @@ fn type_statement( } } match symbol_information { - SymbolInformation::Component(possible_template) =>{ - if rhe_type.is_template(){ - if possible_template.is_none(){ + SymbolInformation::Component(possible_template) => { + if rhe_type.is_template() { + if possible_template.is_none() { let (current_template, _) = analysis_information .environment .get_mut_component_or_break(var, file!(), line!()); *current_template = rhe_type.template; - } else{ + } else { let template = possible_template.unwrap(); let r_template = rhe_type.template.unwrap(); if template != r_template { @@ -253,7 +289,7 @@ fn type_statement( ) } } - } else{ + } else { add_report( ReportCode::WrongTypesInAssignOperationTemplate, meta, @@ -261,53 +297,69 @@ fn type_statement( ) } } - SymbolInformation::Signal(dim) =>{ - if rhe_type.is_template(){ - add_report( - ReportCode::WrongTypesInAssignOperationExpression, - meta, - &mut analysis_information.reports, - ) - } else if dim != rhe_type.dim(){ + SymbolInformation::Bus(possible_bus, dim) => { + if rhe_type.is_bus() { + if dim != rhe_type.dim() { + add_report( + ReportCode::WrongTypesInAssignOperationDims(dim, rhe_type.dim()), + meta, + &mut analysis_information.reports, + ) + } + else if possible_bus.is_none() { + let (current_bus, _) = analysis_information + .environment + .get_mut_bus_or_break(var, file!(), line!()); + *current_bus = rhe_type.bus; + } else { + let bus = possible_bus.unwrap(); + let r_bus = rhe_type.bus.unwrap(); + if bus != r_bus { + add_report( + ReportCode::WrongTypesInAssignOperationArrayBuses, + meta, + &mut analysis_information.reports, + ) + } + } + } else { add_report( - ReportCode::WrongTypesInAssignOperationDims(dim, rhe_type.dim()), + ReportCode::WrongTypesInAssignOperationBus, meta, &mut analysis_information.reports, ) } - } - SymbolInformation::Var(dim) =>{ - if rhe_type.is_template(){ + SymbolInformation::Signal(dim) + | SymbolInformation::Var(dim) => { + if rhe_type.is_template() || rhe_type.is_bus() { add_report( ReportCode::WrongTypesInAssignOperationExpression, meta, &mut analysis_information.reports, ) - } else if dim != rhe_type.dim(){ + } else if dim != rhe_type.dim() { add_report( - ReportCode::WrongTypesInAssignOperationDims(dim, rhe_type.dim()), + ReportCode::WrongTypesInAssignOperationDims(dim, rhe_type.dim()), meta, &mut analysis_information.reports, ) } - } - SymbolInformation::Tag =>{ - if rhe_type.is_template(){ + SymbolInformation::Tag => { + if rhe_type.is_template() || rhe_type.is_bus() { add_report( ReportCode::WrongTypesInAssignOperationExpression, meta, &mut analysis_information.reports, ) - } else if 0 != rhe_type.dim(){ + } else if 0 != rhe_type.dim() { add_report( ReportCode::WrongTypesInAssignOperationDims(0, rhe_type.dim()), meta, &mut analysis_information.reports, ) } - } } } @@ -355,7 +407,7 @@ fn type_statement( } else { return; }; - if arg_type.is_template() { + if arg_type.is_template() || arg_type.is_bus() { add_report( ReportCode::MustBeSingleArithmeticT, meta, @@ -378,7 +430,7 @@ fn type_statement( } else { return; }; - if arg_type.is_template() { + if arg_type.is_template() || arg_type.is_bus() { add_report( ReportCode::MustBeSingleArithmeticT, meta, @@ -421,13 +473,13 @@ fn type_statement( } else { return; }; - if cond_type.is_template(){ + if cond_type.is_template() || cond_type.is_bus() { add_report( ReportCode::MustBeSingleArithmeticT, cond.get_meta(), &mut analysis_information.reports, ) - }else if cond_type.dim() > 0 { + } else if cond_type.dim() > 0 { add_report( ReportCode::MustBeSingleArithmetic(cond_type.dim()), cond.get_meta(), @@ -443,7 +495,7 @@ fn type_statement( } else { return; }; - if cond_type.is_template(){ + if cond_type.is_template() || cond_type.is_bus() { add_report( ReportCode::MustBeSingleArithmeticT, cond.get_meta(), @@ -472,7 +524,7 @@ fn type_statement( } else { return; }; - if rhe_type.is_template() { + if rhe_type.is_template() || rhe_type.is_bus() { add_report( ReportCode::MustBeArithmetic, rhe.get_meta(), @@ -482,6 +534,7 @@ fn type_statement( }, } } + fn type_expression( expression: &Expression, program_archive: &ProgramArchive, @@ -502,7 +555,7 @@ fn type_expression( } let inferred_dim = values_types[0].dim(); for (expression, value_type) in values.iter().zip(values_types.iter()) { - if value_type.is_template() { + if value_type.is_template() || value_type.is_bus() { add_report( ReportCode::InvalidArrayType, expression.get_meta(), @@ -528,7 +581,7 @@ fn type_expression( ); }; let dim_type = type_expression(dimension, program_archive, analysis_information)?; - if dim_type.is_template() { + if dim_type.is_template() || dim_type.is_bus() { add_report( ReportCode::InvalidArrayType, expression.get_meta(), @@ -541,8 +594,11 @@ fn type_expression( &mut analysis_information.reports, ); } - - Result::Ok(FoldedType::arithmetic_type(value_type.dim() + 1)) + if let Some(iden) = &value_type.bus { + Result::Ok(FoldedType::bus(iden.clone(), value_type.dim() + 1)) + } else { + Result::Ok(FoldedType::arithmetic_type(value_type.dim() + 1)) + } } InfixOp { lhe, rhe, .. } => { let lhe_response = type_expression(lhe, program_archive, analysis_information); @@ -550,14 +606,14 @@ fn type_expression( let lhe_type = lhe_response?; let rhe_type = rhe_response?; let mut successful = Result::Ok(()); - if lhe_type.is_template() || lhe_type.dim() > 0 { + if lhe_type.is_template() || lhe_type.is_bus() || lhe_type.dim() > 0 { successful = add_report_and_end( ReportCode::InfixOperatorWithWrongTypes, lhe.get_meta(), &mut analysis_information.reports, ); } - if rhe_type.is_template() || rhe_type.dim() > 0 { + if rhe_type.is_template() || rhe_type.is_bus() || rhe_type.dim() > 0 { successful = add_report_and_end( ReportCode::InfixOperatorWithWrongTypes, rhe.get_meta(), @@ -569,7 +625,7 @@ fn type_expression( } PrefixOp { rhe, .. } => { let rhe_type = type_expression(rhe, program_archive, analysis_information)?; - if rhe_type.is_template() || rhe_type.dim() > 0 { + if rhe_type.is_template() || rhe_type.is_bus() || rhe_type.dim() > 0 { add_report_and_end( ReportCode::PrefixOperatorWithWrongTypes, rhe.get_meta(), @@ -579,9 +635,9 @@ fn type_expression( Result::Ok(FoldedType::arithmetic_type(0)) } } - ParallelOp {rhe, .. } =>{ + ParallelOp {rhe, .. } => { let rhe_type = type_expression(rhe, program_archive, analysis_information)?; - if rhe_type.is_template() { + if rhe_type.is_template() { Result::Ok(rhe_type) } else { add_report_and_end( @@ -594,8 +650,7 @@ fn type_expression( InlineSwitchOp { cond, if_true, if_false, .. } => { let cond_response = type_expression(cond, program_archive, analysis_information); let if_true_response = type_expression(if_true, program_archive, analysis_information); - let if_false_response = - type_expression(if_false, program_archive, analysis_information); + let if_false_response = type_expression(if_false, program_archive, analysis_information); let if_true_type = if_true_response?; let cond_type = if let Result::Ok(f) = cond_response { @@ -603,7 +658,7 @@ fn type_expression( } else { return Result::Ok(if_true_type); }; - if cond_type.is_template(){ + if cond_type.is_template() || cond_type.is_bus() { add_report( ReportCode::MustBeSingleArithmeticT, cond.get_meta(), @@ -650,15 +705,21 @@ fn type_expression( SymbolInformation::Component(possible_template) if possible_template.is_some() => { Result::Ok(FoldedType::template(&possible_template.unwrap())) } + SymbolInformation::Component(possible_template) if possible_template.is_none() => { + add_report_and_end(ReportCode::UninitializedSymbolInExpression, meta, reports) + } + SymbolInformation::Bus(possible_bus, dim) if possible_bus.is_some() => { + Result::Ok(FoldedType::bus(&possible_bus.unwrap(), dim)) + } + SymbolInformation::Bus(possible_bus, _) if possible_bus.is_none() => { + add_report_and_end(ReportCode::UninitializedSymbolInExpression, meta, reports) + } SymbolInformation::Var(dim) | SymbolInformation::Signal(dim) => { Result::Ok(FoldedType::arithmetic_type(dim)) } SymbolInformation::Tag => { Result::Ok(FoldedType::arithmetic_type(0)) } - SymbolInformation::Component(possible_template) if possible_template.is_none() => { - add_report_and_end(ReportCode::UninitializedSymbolInExpression, meta, reports) - } _ => unreachable!(), } } @@ -673,7 +734,7 @@ fn type_expression( let mut concrete_types = Vec::new(); let mut success = Result::Ok(()); for (arg_expr, arg_type) in args.iter().zip(arg_types.iter()) { - if arg_type.is_template() { + if arg_type.is_template() || arg_type.is_bus() { success = add_report_and_end( ReportCode::InvalidArgumentInCall, arg_expr.get_meta(), @@ -750,13 +811,13 @@ fn treat_access( ArrayAccess(index) => { let index_response = type_expression(&index, program_archive, analysis_information); - if access_info.2.is_some(){ + if access_info.2.is_some() { add_report( ReportCode::InvalidArrayAccess(0, 1), index.get_meta(), &mut analysis_information.reports, ); - } else{ + } else { if let Option::Some(signal_info) = &mut access_info.1 { signal_info.1 += 1; } else { @@ -782,7 +843,7 @@ fn treat_access( } ComponentAccess(name) => { if let Option::Some(_signal_info) = & access_info.1 { - if access_info.2.is_none(){ + if access_info.2.is_none() { access_info.2 = Some(name.clone()) } else{ add_report( @@ -800,13 +861,14 @@ fn treat_access( Result::Ok(access_info) } - enum SymbolInformation { Component(Option), Var(ArithmeticType), Signal(ArithmeticType), + Bus(Option, ArithmeticType), Tag, } + fn apply_access_to_symbol( symbol: &str, meta: &Meta, @@ -1022,6 +1084,9 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio InvalidArraySizeT =>{ "Array indexes and lengths must be single arithmetic expressions.\n Found component instead of expression.".to_string() } + InvalidArraySizeB =>{ + "Array indexes and lengths must be single arithmetic expressions.\n Found bus instead of expression.".to_string() + } InvalidArrayAccess(expected, given) => { format!("Array access does not match the dimensions of the expression. \n Expected {} dimensions, given {}.", expected, given From a66dd0f6f7b3d288d860e9d21fcfc3d906a353a9 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sun, 28 Apr 2024 13:24:58 +0200 Subject: [PATCH 020/189] Corrected two of the tests. --- tests/bus_test_correct_2.circom | 95 ++++-------------- tests/bus_test_correct_3.circom | 164 +++++++++++++++++++++++++++++--- 2 files changed, 171 insertions(+), 88 deletions(-) diff --git a/tests/bus_test_correct_2.circom b/tests/bus_test_correct_2.circom index e4b63cf4e..a5db57c90 100644 --- a/tests/bus_test_correct_2.circom +++ b/tests/bus_test_correct_2.circom @@ -1,82 +1,29 @@ pragma circom 2.0.0; -include "bitify.circom"; -include "escalarmulfix.circom"; - -bus Point () { - signal x, y; -} - -bus Parameters () { - signal beta, gamma, delta, tau; -} - -template BabyAdd() { - Point input p1, p2; - Point output pout; - - Parameters params; - - var a = 168700; - var d = 168696; - - params.beta <== p1.x*p2.y; - params.gamma <== p1.y*p2.x; - params.delta <== (-a*p1.x+p1.y)*(p2.x + p2.y); - params.tau <== params.beta * params.gamma; - - pout.x <-- (params.beta + params.gamma) / (1+ d*params.tau); - (1 + d*params.tau) * pout.x === (params.beta + params.gamma); - - pout.y <-- (params.delta + a*params.beta - params.gamma) / (1-d*params.tau); - (1-d*params.tau)*pout.y === (params.delta + a*params.beta - params.gamma); +bus Point (dim) { + signal {maxbit} x[dim]; } -template BabyDbl() { - Point() input pin; - Point output pout; - - component adder = BabyAdd(); - adder.p1 <== pin; - adder.p2 <== pin; - - adder.pout ==> pout; +bus Figure (N,dim) { + Point(dim) list[N]; } - -template BabyCheck() { - Point input p; - - Point q; - - var a = 168700; - var d = 168696; - - q.x <== p.x*p.x; - q.y <== p.y*p.y; - - a*q.x + q.y === 1 + d*q.x*q.y; +template Create (N,bitmax) { + Figure(N) output fig(N,3); + + var c0 = 0; + var c1 = 0; + var c2 = 0; + for (var i=0; i. +*/ +pragma circom 2.1.5; + +include "bitify.circom"; +include "escalarmul/escalarmulfix.circom"; + +// The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) + + +/* +*** BabyAdd(): template that receives two points of the Baby Jubjub curve in Edwards form and returns the addition of the points. + - Inputs: p1 = (p1.x, p1.y) -> two field values representing a point of the curve in Edwards form + p2 = (p2.x, p2.y) -> two field values representing a point of the curve in Edwards form + - Outputs: pout = (pout.x, pout.y) -> two field values representing a point of the curve in Edwards form, pout = p1 + p2 + + Example: + + tau = d * p1.x * p2.x * p1.y * p2.y + + + p1.x * p2.y + p1.y * p2.x p1.y * p2.y - p1.x * p2.x + [pout.x, pout.y] = [ --------------------------- , --------------------------- ] + 1 + d * tau 1 - d * tau + +*/ + +bus Point { + signal {bn128} x,y; } -bus RecursiveArray (N) { - Correct array[N]; - RecursiveArray(N-1) rec; +template BabyAdd() { + Point input {babyedwards} p1,p2; + Point output {babyedwards} pout; + + signal beta; + signal gamma; + signal delta; + signal tau; + + var a = 168700; + var d = 168696; + + beta <== p1.x*p2.y; + gamma <== p1.y*p2.x; + delta <== (-a*p1.x + p1.y)*(p2.x + p2.y); + tau <== beta * gamma; + + pout.x <-- (beta + gamma) / (1 + d*tau); + (1 + d*tau) * pout.x === (beta + gamma); + + pout.y <-- (delta + a*beta - gamma) / (1 - d*tau); + (1 - d*tau)*pout.y === (delta + a*beta - gamma); } -template Create (N) { - RecursiveArray(N) output out; - component create_rec = Create(N-1); - for (var i=0; i two field values representing a point of the curve in Edwards form + - Outputs: pout = (pout.x, pout.y) -> two field values representing a point of the curve in Edwards form, 2 * pin = pout + + Example: BabyDouble()(p) = BabyAdd()(p, p) + +*/ + +template BabyDbl() { + Point input {babyedwards} pin; + Point output {babyedwards} pout; + + component adder = BabyAdd(); + adder.p1 <== pin; + adder.p2 <== pin; + + adder.pout ==> pout; } -component main = Create(2); \ No newline at end of file + +/* +*** BabyCheck(): template that receives an input point pin = (pin.x, pin.y) and checks if it belongs to the Baby Jubjub curve. + - Inputs: pin = (pin.x, pin.y) -> two field values representing the point that we want to check + - Outputs: pout = (pout.x, pout.y) -> two field values representing the same point as the input but with the babyedwards tag + to point out it is a point of the Baby Jubjub curve in Edwards form + + Example: The set of solutions of BabyCheck()(p) are the points of the Baby Jubjub curve in Edwards form + +*/ + + +template BabyCheck() { + Point input pin; + Point output {babyedwards} pout; + + // Point p2; + signal x2; + signal y2; + + var a = 168700; + var d = 168696; + + x2 <== pin.x*pin.x; //x2 = pin.x^2 + y2 <== pin.y*pin.y; //y2 = pin.y^2 + + a*x2 + y2 === 1 + d*x2*y2; + + pout <== pin; +} + + +/* +*** BabyPbk(): template that receives an input in representing a value in the prime subgroup with order r = 2736030358979909402780800718157159386076813972158567259200215660948447373041, + and returns the point of the BabyJubjub curve in * P with P being the point P = (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203) + +This template is used to extract the public key from the private key. + - Inputs: in -> field value in [1,r-1] + - Outputs: A = (A.x, A.y) -> two field values representing a point of the curve in Edwards form, in * P = A + +*/ + +template BabyPbk() { + signal input {minvalue,maxvalue} in; + Point output {babyedwards} A; + + + var r = 2736030358979909402780800718157159386076813972158567259200215660948447373041; + assert(in.minvalue > 0 && in.maxvalue < r); + var BASE8[2] = [ + 5299619240641551281634865583518297030282874472190772894086521144482721001553, + 16950150798460657717958625567821834550301663161624707787222815936182638968203 + ]; + + component pvkBits = Num2Bits(253); + pvkBits.in <== in; + + component mulFix = EscalarMulFix(253, BASE8); + + var i; + for (i=0; i<253; i++) { + mulFix.e[i] <== pvkBits.out[i]; + } + + A <== mulFix.out; +} \ No newline at end of file From b341c51580fdda3782e9593264cd13165b5e8058 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sun, 28 Apr 2024 17:32:44 +0200 Subject: [PATCH 021/189] Updated tests. --- tests/bus_test_correct_3.circom | 33 ++-- tests/bus_test_correct_4.circom | 291 ++++++++++++++++++++++++++++++++ tests/bus_test_correct_5.circom | 165 ++++++++++++++++++ 3 files changed, 472 insertions(+), 17 deletions(-) create mode 100644 tests/bus_test_correct_4.circom create mode 100644 tests/bus_test_correct_5.circom diff --git a/tests/bus_test_correct_3.circom b/tests/bus_test_correct_3.circom index 52ea39fb1..66c750f65 100644 --- a/tests/bus_test_correct_3.circom +++ b/tests/bus_test_correct_3.circom @@ -23,28 +23,27 @@ include "escalarmul/escalarmulfix.circom"; // The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) +bus Point { + signal {bn128} x,y; +} /* *** BabyAdd(): template that receives two points of the Baby Jubjub curve in Edwards form and returns the addition of the points. - - Inputs: p1 = (p1.x, p1.y) -> two field values representing a point of the curve in Edwards form - p2 = (p2.x, p2.y) -> two field values representing a point of the curve in Edwards form - - Outputs: pout = (pout.x, pout.y) -> two field values representing a point of the curve in Edwards form, pout = p1 + p2 + - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in Edwards form + p2 = (x2, y2) -> bus representing a point of the curve in Edwards form + - Outputs: pout = (xout, yout) -> bus representing a point of the curve in Edwards form, pout = p1 + p2 Example: - tau = d * p1.x * p2.x * p1.y * p2.y + tau = d * x1 * x2 * y1 * y2 - p1.x * p2.y + p1.y * p2.x p1.y * p2.y - p1.x * p2.x - [pout.x, pout.y] = [ --------------------------- , --------------------------- ] - 1 + d * tau 1 - d * tau + x1 * y2 + y1 * x2 y1 * y2 - x1 * x2 + [xout, yout] = [ ----------------------- , ----------------------- ] + 1 + d * tau 1 - d * tau */ -bus Point { - signal {bn128} x,y; -} - template BabyAdd() { Point input {babyedwards} p1,p2; Point output {babyedwards} pout; @@ -73,8 +72,8 @@ template BabyAdd() { /* *** BabyDouble(): template that receives a point pin of the Baby Jubjub curve in Edwards form and returns the point 2 * pin. - - Inputs: pin = (pin.x, pin.y) -> two field values representing a point of the curve in Edwards form - - Outputs: pout = (pout.x, pout.y) -> two field values representing a point of the curve in Edwards form, 2 * pin = pout + - Inputs: pin = (x1, y1) -> bus representing a point of the curve in Edwards form + - Outputs: pout = (x2, y2) -> bus representing a point of the curve in Edwards form, 2 * pin = pout Example: BabyDouble()(p) = BabyAdd()(p, p) @@ -93,9 +92,9 @@ template BabyDbl() { /* -*** BabyCheck(): template that receives an input point pin = (pin.x, pin.y) and checks if it belongs to the Baby Jubjub curve. - - Inputs: pin = (pin.x, pin.y) -> two field values representing the point that we want to check - - Outputs: pout = (pout.x, pout.y) -> two field values representing the same point as the input but with the babyedwards tag +*** BabyCheck(): template that receives an input point pin and checks if it belongs to the Baby Jubjub curve. + - Inputs: pin = (x1, y1) -> bus representing the point that we want to check + - Outputs: pout = (x2, y2) -> two field values representing the same point as the input but with the babyedwards tag to point out it is a point of the Baby Jubjub curve in Edwards form Example: The set of solutions of BabyCheck()(p) are the points of the Baby Jubjub curve in Edwards form @@ -129,7 +128,7 @@ template BabyCheck() { This template is used to extract the public key from the private key. - Inputs: in -> field value in [1,r-1] - - Outputs: A = (A.x, A.y) -> two field values representing a point of the curve in Edwards form, in * P = A + - Outputs: A = (x, y) -> two field values representing a point of the curve in Edwards form, in * P = A */ diff --git a/tests/bus_test_correct_4.circom b/tests/bus_test_correct_4.circom new file mode 100644 index 000000000..cb32f1bd0 --- /dev/null +++ b/tests/bus_test_correct_4.circom @@ -0,0 +1,291 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.1.5; + +include "../mux3.circom"; +include "../montgomery.circom"; +include "../babyjub.circom"; + +/* + + The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243 + First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B + + Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B + + And Finaly we compute the result: RES = SQ - Q + + As you can see the input of the adders cannot be equal nor zero, except for the last + substraction that it's done in montgomery. + + A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input + is the output of the windows that it's going to be <= 2^246*B +*/ + +bus Point { + signal {bn128} x,y; +} + +/* + +*** WindowMulFix(): template that given a point in Montgomery representation base and a binary input in, calculates: + out = base + base*in[0] + 2*base*in[1] + 4*base*in[2] + out8 = 8*base + + This circuit is used in order to multiply a fixed point of the BabyJub curve by a escalar (k * p with p a fixed point of the curve). + - Inputs: in[3] -> binary value + requires tag binary + base -> input curve point in Montgomery representation + - Outputs: out -> output curve point in Montgomery representation + out8 -> output curve point in Montgomery representation + + */ + +template WindowMulFix() { + signal input {binary} in[3]; + Point input {babymontgomery} base; + Point output {babymontgomery} out; + Point output {babymontgomery} out8; // Returns 8*Base (To be linked) + + component mux = MultiMux3(2); + + mux.s[0] <== in[0]; + mux.s[1] <== in[1]; + mux.s[2] <== in[2]; + + component dbl2 = MontgomeryDouble(); + component adr3 = MontgomeryAdd(); + component adr4 = MontgomeryAdd(); + component adr5 = MontgomeryAdd(); + component adr6 = MontgomeryAdd(); + component adr7 = MontgomeryAdd(); + component adr8 = MontgomeryAdd(); + +// in[0] -> 1*BASE + + mux.c[0][0] <== base.x; + mux.c[1][0] <== base.y; + +// in[1] -> 2*BASE + + dbl2.pin <== base; + mux.c[0][1] <== dbl2.pout.x; + mux.c[1][1] <== dbl2.pout.y; + +// in[2] -> 3*BASE + + adr3.pin1 <== base; + adr3.pin2 <== dbl2.pout; + mux.c[0][2] <== adr3.pout.x; + mux.c[1][2] <== adr3.pout.y; + +// in[3] -> 4*BASE + + adr4.pin1 <== base; + adr4.pin2 <== adr3.pout; + mux.c[0][3] <== adr4.pout.x; + mux.c[1][3] <== adr4.pout.y; + +// in[4] -> 5*BASE + + adr5.pin1 <== base; + adr5.pin2 <== adr4.pout; + mux.c[0][4] <== adr5.pout.x; + mux.c[1][4] <== adr5.pout.y; + +// in[5] -> 6*BASE + + adr6.pin1 <== base; + adr6.pin2 <== adr5.pout; + mux.c[0][5] <== adr6.pout.x; + mux.c[1][5] <== adr6.pout.y; + +// in[6] -> 7*BASE + + adr7.pin1 <== base; + adr7.pin2 <== adr6.pout; + mux.c[0][6] <== adr7.pout.x; + mux.c[1][6] <== adr7.pout.y; + +// in[7] -> 8*BASE + + adr8.pin1 <== base; + adr8.pin2 <== adr7.pout; + mux.c[0][7] <== adr8.pout.x; + mux.c[1][7] <== adr8.pout.y; + + out8 <== adr8.pout; + + out.x <== mux.out[0]; + out.y <== mux.out[1]; +} + + +/* + +*** SegmentMulFix(nWindows): template used to perform a segment of the multiplications needed to perform a multiplication of a scalar times a fix base (k * BASE). + - Inputs: e[3 * nWindows] -> binary representation of the scalar + requires tag binary + base -> input curve point in Edwards representation + - Outputs: out -> output curve point in Edwards representation + dbl -> output curve point in Montgomery representation (to be linked to the next segment) + + */ + +template SegmentMulFix(nWindows) { + signal input {binary} e[nWindows*3]; + Point input {babyedwards} base; + Point output {babyedwards} out; + Point output {babymontgomery} dbl; + + var i; + var j; + + // Convert the base to montgomery + + component e2m = Edwards2Montgomery(); + e2m.pin <== base; + + component windows[nWindows]; + component adders[nWindows]; + component cadders[nWindows]; + + // In the last step we add an extra doubler so that numbers do not match. + component dblLast = MontgomeryDouble(); + + for (i=0; i out; + + windows[nWindows-1].out8 ==> dbl; +} + + +/* + +*** EscalarMulFix(n, BASE): template that does a multiplication of a scalar times a fixed point BASE. + It receives a point in Edwards representation BASE and a binary input e representing a value k using n bits, + and calculates the point k * p. + - Inputs: e[n] -> binary representation of the scalar k + requires tag binary + - Outputs: out -> output curve point in Edwards representation, out = k * BASE + + */ + + +template EscalarMulFix(n, BASE) { + signal input {binary} e[n]; // Input in binary format + Point output {babyedwards} out; // Point (Twisted format) + + var nsegments = (n-1)\246 + 1; // 249 probably would work. But I'm not sure and for security I keep 246 + var nlastsegment = n - (nsegments-1)*249; + + component segments[nsegments]; + + component m2e[nsegments-1]; + component adders[nsegments-1]; + + var s; + var i; + var nseg; + var nWindows; + + signal {binary} aux_0 <== 0; + + for (s=0; s m2e[s-1].pin; + + m2e[s-1].pout ==> segments[s].base; + + if (s==1) { + segments[s-1].out ==> adders[s-1].p1; + } else { + adders[s-2].pout ==> adders[s-1].p1; + } + segments[s].out ==> adders[s-1].p2; + } + } + + if (nsegments == 1) { + segments[0].out ==> out; + } else { + adders[nsegments-2].pout ==> out; + } +} \ No newline at end of file diff --git a/tests/bus_test_correct_5.circom b/tests/bus_test_correct_5.circom new file mode 100644 index 000000000..45d6fe0a2 --- /dev/null +++ b/tests/bus_test_correct_5.circom @@ -0,0 +1,165 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ + + pragma circom 2.1.5; + + // The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) + + +/* + Source: https://en.wikipedia.org/wiki/Montgomery_curve + +*/ + +bus Point { + signal {bn128} x,y; +} + +/* +*** Edwards2Montgomery(): template that receives an input pin representing a point of an elliptic curve in Edwards form + and returns the equivalent point in Montgomery form. + - Inputs: pin -> bus representing a point of the curve in Edwards form + - Outputs: pout -> bus representing a point of the curve in Montgomery form + + Example: if we consider the input pin = (x, y), then the circuit produces the following output pout = (u, v). + + 1 + y 1 + y + (u, v) = [ ------- , ---------- ] + 1 - y (1 - y)x + +*/ + +template Edwards2Montgomery() { + Point input {babyedwards} pin; + Point output {babymontgomery} pout; + + pout.x <-- (1 + pin.y) / (1 - pin.y); + pout.y <-- pout.x / pin.x; + + pout.x * (1 - pin.y) === (1 + pin.y); + pout.y * pin.x === pout.x; +} + +/* +*** Montgomery2Edwards(): template that receives an input pin representing a point of an elliptic curve in Montgomery form + and returns the equivalent point in Edwards form. + - Inputs: pin -> bus representing a point of the curve in Montgomery form + - Outputs: pout -> bus representing a point of the curve in Edwards form + + Example: if we consider the input pin = (u, v), then the circuit produces the following output pout = (x, y) + + u u - 1 + (x, y) = [ ---, ------- ] + v u + 1 + + */ + +template Montgomery2Edwards() { + Point input {babymontgomery} pin; + Point output {babyedwards} pout; + + pout.x <-- pin.x / pin.y; + pout.y <-- (pin.x - 1) / (pin.x + 1); + + pout.x * pin.y === pin.x; + pout.y * (pin.x + 1) === pin.x - 1; +} + + +/* +*** MontgomeryAdd(): template that receives two inputs pin1, pin2 representing points of the Baby Jubjub curve in Montgomery form + and returns the addition of the points. + - Inputs: pin1 -> bus representing a point of the curve in Montgomery form + pin2 -> bus representing a point of the curve in Montgomery form + - Outputs: pout -> bus representing the point pin1 + pin2 in Montgomery form + + Example: if we consider the inputs pin1 = (x1, y1) and pin2 = (x2, y2), then the circuit produces the following output pout = (x3, y3): + + y2 - y1 + lamda = --------- + x2 - x1 + + x3 = B * lamda^2 - A - x1 -x2 + + y3 = lamda * ( x1 - x3 ) - y1 + + where A and B are two constants defined below. + */ + +template MontgomeryAdd() { + Point input {babymontgomery} pin1, pin2; + Point output {babymontgomery} pout; + + var a = 168700; + var d = 168696; + + var A = (2 * (a + d)) / (a - d); + var B = 4 / (a - d); + + signal lamda; + + lamda <-- (pin2.y - pin1.y) / (pin2.x - pin1.x); + lamda * (pin2.x - pin1.x) === pin2.y - pin1.y; + + pout.x <== B*lamda*lamda - A - pin1.x - pin2.x; + pout.y <== lamda * (pin1.x - pout.x) - pin1.y; +} + +/* +*** MontgomeryDouble(): template that receives an input pin representing a point of the Baby Jubjub curve in Montgomery form + and returns the point 2 * pin. + - Inputs: pin -> bus representing a point of the curve in Montgomery form + - Outputs: pout -> bus representing the point 2*pin in Montgomery form + + + Example: if we consider the input pin = (x1, y1), then the circuit produces the following output pout = (x2, y2): + + x1_2 = x1*x1 + + 3*x1_2 + 2*A*x1 + 1 + lamda = --------------------- + 2*B*y1 + + x2 = B * lamda^2 - A - x1 -x1 + + y2 = lamda * ( x1 - x2 ) - y1 + + */ + +template MontgomeryDouble() { + Point input {babymontgomery} pin; + Point output {babymontgomery} pout; + + var a = 168700; + var d = 168696; + + var A = (2 * (a + d)) / (a - d); + var B = 4 / (a - d); + + signal lamda; + signal x1_2; + + x1_2 <== pin.x * pin.x; + + lamda <-- (3*x1_2 + 2*A*pin.x + 1) / (2*B*pin.y); + lamda * (2*B*pin.y) === (3*x1_2 + 2*A*pin.x + 1); + + pout.x <== B*lamda*lamda - A - 2*pin.x; + pout.y <== lamda * (pin.x - pout.x) - pin.y; +} \ No newline at end of file From c5851c778f48bb54c86698c987831de8ac2dc817 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sun, 28 Apr 2024 19:06:33 +0200 Subject: [PATCH 022/189] Added more tests. --- tests/bus_test_correct_1.circom | 4 +- tests/bus_test_correct_6.circom | 229 ++++++++++++++++++++++++++++++++ tests/bus_test_error_1.circom | 22 +++ tests/bus_test_error_2.circom | 30 +++++ 4 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 tests/bus_test_correct_6.circom create mode 100644 tests/bus_test_error_1.circom create mode 100644 tests/bus_test_error_2.circom diff --git a/tests/bus_test_correct_1.circom b/tests/bus_test_correct_1.circom index 59ebf204a..11c9aeace 100644 --- a/tests/bus_test_correct_1.circom +++ b/tests/bus_test_correct_1.circom @@ -12,6 +12,4 @@ template Pipe (n) { pout.x[i] <== pin.x[i]; pout.y[i] <== pin.y[i]; } -} - -component main = Pipe(3); \ No newline at end of file +} \ No newline at end of file diff --git a/tests/bus_test_correct_6.circom b/tests/bus_test_correct_6.circom new file mode 100644 index 000000000..23aee509f --- /dev/null +++ b/tests/bus_test_correct_6.circom @@ -0,0 +1,229 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "montgomery.circom"; +include "mux3.circom"; +include "babyjub.circom"; + +bus Point { + signal {bn128} x,y; +} + +template Window4() { + signal input {binary} in[4]; + Point input {babymontgomery} base; + Point output {babymontgomery} out; + Point output {babymontgomery} out8; // Returns 8*Base (To be linked) + + component mux = MultiMux3(2); + + mux.s[0] <== in[0]; + mux.s[1] <== in[1]; + mux.s[2] <== in[2]; + + component dbl2 = MontgomeryDouble(); + component adr3 = MontgomeryAdd(); + component adr4 = MontgomeryAdd(); + component adr5 = MontgomeryAdd(); + component adr6 = MontgomeryAdd(); + component adr7 = MontgomeryAdd(); + component adr8 = MontgomeryAdd(); + +// in[0] -> 1*BASE + + mux.c[0][0] <== base.x; + mux.c[1][0] <== base.y; + +// in[1] -> 2*BASE + dbl2.in <== base; + mux.c[0][1] <== dbl2.pout.x; + mux.c[1][1] <== dbl2.pout.y; + +// in[2] -> 3*BASE + adr3.pin1 <== base; + adr3.pin2 <== dbl2.pout; + mux.c[0][2] <== adr3.pout.x; + mux.c[1][2] <== adr3.pout.y; + +// in[3] -> 4*BASE + adr4.pin1 <== base; + adr4.pin2 <== adr3.pout; + mux.c[0][3] <== adr4.pout.x; + mux.c[1][3] <== adr4.pout.y; + +// in[4] -> 5*BASE + adr5.pin1 <== base; + adr5.pin2 <== adr4.pout; + mux.c[0][4] <== adr5.pout.x; + mux.c[1][4] <== adr5.pout.y; + +// in[5] -> 6*BASE + adr6.pin1 <== base; + adr6.pin2 <== adr5.pout; + mux.c[0][5] <== adr6.pout.x; + mux.c[1][5] <== adr6.pout.y; + +// in[6] -> 7*BASE + adr7.pin1 <== base; + adr7.pin2 <== adr6.pout; + mux.c[0][6] <== adr7.pout.x; + mux.c[1][6] <== adr7.pout.y; + +// in[7] -> 8*BASE + adr8.pin1 <== base; + adr8.pin2 <== adr7.pout; + mux.c[0][7] <== adr8.pout.x; + mux.c[1][7] <== adr8.pout.y; + + out8 <== adr8.pout; + + out.x <== mux.out[0]; + out.y <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one +} + + +template Segment(nWindows) { + signal input {binary} in[nWindows*4]; + Point input {babyedwards} base; + Point output {babyedwards} out; + + var i; + var j; + + // Convert the base to montgomery + + component e2m = Edwards2Montgomery(); + e2m.pin <== base; + + component windows[nWindows]; + component doublers1[nWindows-1]; + component doublers2[nWindows-1]; + component adders[nWindows-1]; + for (i=0; i 1) { + m2e.pin <== adders[nWindows-2].pout; + } else { + m2e.pin <== windows[0].out; + } + + out <== m2e.pout; +} + +template Pedersen(n) { + signal input {binary} in[n]; + Point output {babyedwards} pout; + + var BASE[10][2] = [ + [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317], + [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094], + [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896], + [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654], + [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506], + [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003], + [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236], + [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695], + [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506], + [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481] + + ]; + + var nSegments = ((n-1)\200)+1; + + component segments[nSegments]; + + var i; + var j; + var nBits; + var nWindows; + for (i=0; i1) { + packPoint.in[0] <== adders[nSegments-2].xout; + packPoint.in[1] <== adders[nSegments-2].yout; + } else { + packPoint.in[0] <== segments[0].out[0]; + packPoint.in[1] <== segments[0].out[1]; + } + + out[0] <== packPoint.out[0]; + out[1] <== packPoint.out[1]; +*/ + + if (nSegments>1) { + pout <== adders[nSegments-2].pout; + } else { + pout <== segments[0].out; + } +} \ No newline at end of file diff --git a/tests/bus_test_error_1.circom b/tests/bus_test_error_1.circom new file mode 100644 index 000000000..4886dfbc4 --- /dev/null +++ b/tests/bus_test_error_1.circom @@ -0,0 +1,22 @@ +pragma circom 2.0.0; + +/* + + This code should fail because buses cannot be defined with tags. + Tags are asigned to bus signals when declared. + +*/ + +bus {babyedwards} Point (n) { + signal {binary} x[n], y[n]; +} + +template Pipe (n) { + Point(n) input pin; + Point(n) output pout; + + for (var i=0; i Date: Mon, 29 Apr 2024 11:49:18 +0200 Subject: [PATCH 023/189] New tests. --- tests/bus_test_correct_7.circom | 39 +++++++++++++++++++++++++++++++++ tests/bus_test_correct_8.circom | 23 +++++++++++++++++++ tests/bus_test_error_3.circom | 26 ++++++++++++++++++++++ tests/bus_test_error_4.circom | 26 ++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 tests/bus_test_correct_7.circom create mode 100644 tests/bus_test_correct_8.circom create mode 100644 tests/bus_test_error_3.circom create mode 100644 tests/bus_test_error_4.circom diff --git a/tests/bus_test_correct_7.circom b/tests/bus_test_correct_7.circom new file mode 100644 index 000000000..75a931d32 --- /dev/null +++ b/tests/bus_test_correct_7.circom @@ -0,0 +1,39 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "compconstant.circom"; + +bus BinaryNumber { + signal {binary} bits[254]; +} + +template AliasCheck() { + signal input {binary} in[254]; + BinaryNumber output {unique} out; + + component compConstant = CompConstant(-1); + + for (var i=0; i<254; i++) { + in[i] ==> compConstant.in[i]; + in[i] ==> out.bits[i]; + } + + compConstant.out === 0; +} \ No newline at end of file diff --git a/tests/bus_test_correct_8.circom b/tests/bus_test_correct_8.circom new file mode 100644 index 000000000..8d9413ebe --- /dev/null +++ b/tests/bus_test_correct_8.circom @@ -0,0 +1,23 @@ +pragma circom 2.0.0; + +include "compconstant.circom"; + +bus BinaryNumber { + signal {binary} bits[254]; +} + +template AliasCheck() { + signal input {binary} in[254]; + BinaryNumber output {unique, maxvalue} out; + + component compConstant = CompConstant(-1); + + for (var i=0; i<254; i++) { + in[i] ==> compConstant.in[i]; + in[i] ==> out.bits[i]; + } + + out.maxvalue = (1 << 254) - 1; + + compConstant.out === 0; +} \ No newline at end of file diff --git a/tests/bus_test_error_3.circom b/tests/bus_test_error_3.circom new file mode 100644 index 000000000..5e4c5d03b --- /dev/null +++ b/tests/bus_test_error_3.circom @@ -0,0 +1,26 @@ +pragma circom 2.0.0; + +/* + + This code should fail because buses cannot be defined with input or output fields. + Input or output signals can only be defined inside templates. + +*/ + +bus InputPoint (n) { + signal input {binary} x[n], y[n]; +} + +bus OutputPoint (n) { + signal output {binary} x[n], y[n]; +} + +template Pipe (n) { + Point(n) input {babyedwards} pin; + Point(n) output {babyedwards} pout; + + for (var i=0; i Date: Mon, 29 Apr 2024 12:21:20 +0200 Subject: [PATCH 024/189] Corrected bus_test_correct_2. --- tests/bus_test_correct_2.circom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bus_test_correct_2.circom b/tests/bus_test_correct_2.circom index a5db57c90..fb86f1e65 100644 --- a/tests/bus_test_correct_2.circom +++ b/tests/bus_test_correct_2.circom @@ -9,7 +9,7 @@ bus Figure (N,dim) { } template Create (N,bitmax) { - Figure(N) output fig(N,3); + Figure(N,3) output fig; var c0 = 0; var c1 = 0; From f0d32ba8f64a105db6976ad36110aa551cea6aae Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:30:12 +0200 Subject: [PATCH 025/189] code modified using anonymous components and array assignments --- tests/bus_test_correct_7.circom | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/bus_test_correct_7.circom b/tests/bus_test_correct_7.circom index 75a931d32..84d314403 100644 --- a/tests/bus_test_correct_7.circom +++ b/tests/bus_test_correct_7.circom @@ -30,10 +30,15 @@ template AliasCheck() { component compConstant = CompConstant(-1); - for (var i=0; i<254; i++) { +/* for (var i=0; i<254; i++) { in[i] ==> compConstant.in[i]; in[i] ==> out.bits[i]; } compConstant.out === 0; -} \ No newline at end of file +*/ + signal out_aux <== CompConstant(-1)(in); + out_aux === 0; + in ==> out.bits; + +} From 9aea11287b9478e79e30239ea2f333beabfd673c Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:31:08 +0200 Subject: [PATCH 026/189] minor change --- tests/bus_test_correct_7.circom | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/bus_test_correct_7.circom b/tests/bus_test_correct_7.circom index 84d314403..abf75e9a2 100644 --- a/tests/bus_test_correct_7.circom +++ b/tests/bus_test_correct_7.circom @@ -28,9 +28,10 @@ template AliasCheck() { signal input {binary} in[254]; BinaryNumber output {unique} out; +/* component compConstant = CompConstant(-1); -/* for (var i=0; i<254; i++) { + for (var i=0; i<254; i++) { in[i] ==> compConstant.in[i]; in[i] ==> out.bits[i]; } From 457ca3b7c77101e454830864418ebdde4f0f0c32 Mon Sep 17 00:00:00 2001 From: miguelis Date: Fri, 3 May 2024 16:00:19 +0200 Subject: [PATCH 027/189] Improving buses_free_of_invalid_statements and symbol analysis --- program_structure/src/lib.rs | 1 + .../src/program_library/error_code.rs | 2 ++ .../buses_free_of_invalid_statements.rs | 17 +++++------- .../src/analyzers/symbol_analysis.rs | 27 ++++++++++++++++++- type_analysis/src/analyzers/type_check.rs | 20 +++++++------- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/program_structure/src/lib.rs b/program_structure/src/lib.rs index 3b078ccbc..134a2f55b 100644 --- a/program_structure/src/lib.rs +++ b/program_structure/src/lib.rs @@ -9,3 +9,4 @@ pub mod utils; pub use abstract_syntax_tree::*; pub use program_library::*; pub use utils::*; +pub use program_library::bus_data; \ No newline at end of file diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 418ced740..0eb6d2468 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -111,6 +111,7 @@ pub enum ReportCode { TupleError, InvalidSignalTagAccess, UninitializedComponent, + BusWrongNumberOfArguments, } impl fmt::Display for ReportCode { @@ -223,6 +224,7 @@ impl fmt::Display for ReportCode { AnonymousCompError => "TAC01", TupleError => "TAC02", UnderscoreWithNoSignalWarning => "TAC03", + BusWrongNumberOfArguments => "BU01", }; f.write_str(string_format) } diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 970567985..a9f5e2683 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -1,8 +1,8 @@ use program_structure::ast::*; +use program_structure::program_library::bus_data::BusData; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; use program_structure::file_definition; -use program_structure::bus_data::BusData; use std::collections::HashSet; pub fn free_of_invalid_statements( @@ -48,20 +48,15 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); }, - Block { stmts, .. } => { + Block { stmts, .. } => { for stmt in stmts.iter() { analyse_statement(stmt, function_names, reports); } }, - InitializationBlock { meta, .. } => { - let mut report = Report::error( - "Initialization statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + InitializationBlock { initializations, .. } => { + for stmt in initializations.iter() { + analyse_statement(stmt, function_names, reports); + } }, Declaration { meta, xtype, dimensions, .. } => { match xtype { diff --git a/type_analysis/src/analyzers/symbol_analysis.rs b/type_analysis/src/analyzers/symbol_analysis.rs index 3590e9821..265a461a8 100644 --- a/type_analysis/src/analyzers/symbol_analysis.rs +++ b/type_analysis/src/analyzers/symbol_analysis.rs @@ -448,8 +448,33 @@ fn analyze_expression( environment, ); }, - Expression::BusCall { args, .. } => + Expression::BusCall { meta, id, args } => { + if !bus_info.contains_key(id) { + let mut report = + Report::error(format!("Calling symbol"), ReportCode::NonExistentSymbol); + report.add_primary( + file_definition::generate_file_location(meta.get_start(), meta.get_end()), + file_id.clone(), + format!("Calling unknown symbol"), + ); + reports.push(report); + return; + } + let expected_num_of_params = bus_info.get(id).unwrap().get_num_of_params(); + if args.len() != expected_num_of_params { + let mut report = Report::error( + format!("Instantiating bus with wrong number of arguments"), + ReportCode::BusWrongNumberOfArguments, + ); + report.add_primary( + file_definition::generate_file_location(meta.get_start(), meta.get_end()), + file_id.clone(), + format!("Got {} params, {} where expected", args.len(), expected_num_of_params), + ); + reports.push(report); + return; + } for arg in args.iter() { analyze_expression( arg, diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 62724ec86..b46aac191 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -192,17 +192,17 @@ fn type_statement( VariableType::AnonymousComponent => analysis_information .environment .add_component(name, (meta.component_inference.clone(), dimensions.len())), - VariableType::Bus(tname, stype, tags) => { - match s_type { + VariableType::Bus(tname, ss_type, tags) => { + match ss_type { SignalType::Input => analysis_information .environment - .add_input_bus(name, (Option::Some(tname), dimensions.len(), tags.clone())), + .add_input_bus(name, (Option::Some(tname.clone()), dimensions.len(), tags.clone())), SignalType::Output => analysis_information .environment - .add_output_bus(name, (Option::Some(tname), dimensions.len(), tags.clone())), + .add_output_bus(name, (Option::Some(tname.clone()), dimensions.len(), tags.clone())), SignalType::Intermediate => analysis_information .environment - .add_intermediate_bus(name, (Option::Some(tname), dimensions.len(), tags.clone())), + .add_intermediate_bus(name, (Option::Some(tname.clone()), dimensions.len(), tags.clone())), } } } @@ -249,9 +249,9 @@ fn type_statement( match (&symbol_information, op) { (SymbolInformation::Signal(_), AssignOp::AssignConstraintSignal) | (SymbolInformation::Signal(_), AssignOp::AssignSignal) - | (SymbolInformation::Bus(_), AssignOp::AssignConstraintSignal) - | (SymbolInformation::Bus(_), AssignOp::AssignSignal) - | (SymbolInformation::Bus(_), AssignOp::AssignVar) + | (SymbolInformation::Bus(_,_), AssignOp::AssignConstraintSignal) + | (SymbolInformation::Bus(_,_), AssignOp::AssignSignal) + | (SymbolInformation::Bus(_,_), AssignOp::AssignVar) | (SymbolInformation::Var(_), AssignOp::AssignVar) | (SymbolInformation::Component(_), AssignOp::AssignVar) | (SymbolInformation::Tag, AssignOp::AssignVar) => {} @@ -307,7 +307,7 @@ fn type_statement( ) } else if possible_bus.is_none() { - let (current_bus, _) = analysis_information + let (current_bus, _,_) = analysis_information .environment .get_mut_bus_or_break(var, file!(), line!()); *current_bus = rhe_type.bus; @@ -595,7 +595,7 @@ fn type_expression( ); } if let Some(iden) = &value_type.bus { - Result::Ok(FoldedType::bus(iden.clone(), value_type.dim() + 1)) + Result::Ok(FoldedType::bus(iden.clone().as_str(), value_type.dim() + 1)) } else { Result::Ok(FoldedType::arithmetic_type(value_type.dim() + 1)) } From 50d00709a0106a8d97737b62caf6f939d346dbff Mon Sep 17 00:00:00 2001 From: miguelis Date: Fri, 3 May 2024 17:13:33 +0200 Subject: [PATCH 028/189] Custom files should not allow the use of intermediate buses. Parameters for a bus should be considered as constants. --- .../src/analyzers/custom_gate_analysis.rs | 18 +++++++++++++++++- .../src/decorators/constants_handler.rs | 8 +++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/type_analysis/src/analyzers/custom_gate_analysis.rs b/type_analysis/src/analyzers/custom_gate_analysis.rs index d829d6d2f..421f411f9 100644 --- a/type_analysis/src/analyzers/custom_gate_analysis.rs +++ b/type_analysis/src/analyzers/custom_gate_analysis.rs @@ -46,7 +46,23 @@ pub fn custom_gate_analysis( ) ); warnings.push(warning); - } + }, + Bus(_,SignalType::Intermediate, _) => { + let mut warning = Report::warning( + String::from("Intermediate bus inside custom template"), + ReportCode::CustomGateIntermediateSignalWarning + ); + warning.add_primary( + meta.location.clone(), + meta.file_id.unwrap(), + format!( + "Intermediate bus {} declared in custom template {}", + name, + custom_gate_name + ) + ); + warnings.push(warning); + }, Component | AnonymousComponent => { let mut error = Report::error( String::from("Component inside custom template"), diff --git a/type_analysis/src/decorators/constants_handler.rs b/type_analysis/src/decorators/constants_handler.rs index 90edda577..c73519d27 100644 --- a/type_analysis/src/decorators/constants_handler.rs +++ b/type_analysis/src/decorators/constants_handler.rs @@ -39,11 +39,17 @@ pub fn _handle_template_constants(template: &mut TemplateData) -> ReportCollecti expand_statement(template.get_mut_body(), &mut expression_holder); reports } + pub fn handle_bus_constants(bus: &mut BusData) -> ReportCollection { let mut environment = Constants::new(); let mut expression_holder = ExpressionHolder::new(); for p in bus.get_name_of_params() { - environment.add_variable(p, false); + environment.add_variable(p, true); + let meta = bus.get_body().get_meta().clone(); + let name = p.clone(); + let access = vec![]; + let expression = build_variable(meta, name, access); + expression_holder.add_variable(p, expression); } statement_constant_inference(bus.get_mut_body(), &mut environment); let reports = statement_invariant_check(bus.get_body(), &mut environment); From 940917fab803017a24bd55ab13e5d7484bbe5068 Mon Sep 17 00:00:00 2001 From: miguelis Date: Sat, 4 May 2024 01:31:22 +0200 Subject: [PATCH 029/189] Type reduction analysis for buses extension --- .../src/abstract_syntax_tree/ast.rs | 20 +- type_analysis/src/check_types.rs | 9 +- .../src/decorators/type_reduction.rs | 198 ++++++++++++------ 3 files changed, 157 insertions(+), 70 deletions(-) diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 007767908..9437fc3b1 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -394,11 +394,11 @@ pub enum ExpressionPrefixOpcode { // Knowledge buckets -#[derive(Copy, Clone, PartialOrd, PartialEq, Ord, Eq)] +#[derive(Clone, PartialOrd, PartialEq, Ord, Eq)] pub enum TypeReduction { Variable, - Component, - Bus, + Component(Option), + Bus(Option), Signal, Tag, } @@ -429,7 +429,7 @@ impl TypeKnowledge { } pub fn get_reduces_to(&self) -> TypeReduction { if let Option::Some(t) = &self.reduces_to { - *t + t.clone() } else { panic!("reduces_to knowledge is been look at without being initialized"); } @@ -437,8 +437,18 @@ impl TypeKnowledge { pub fn is_var(&self) -> bool { self.get_reduces_to() == TypeReduction::Variable } + + pub fn is_initialized(&self) -> bool { + if let Option::Some(_) = &self.reduces_to { + true + } else { + false + } + } pub fn is_component(&self) -> bool { - self.get_reduces_to() == TypeReduction::Component + if let TypeReduction::Component(_) = self.get_reduces_to() { + true + } else { false } } pub fn is_signal(&self) -> bool { self.get_reduces_to() == TypeReduction::Signal diff --git a/type_analysis/src/check_types.rs b/type_analysis/src/check_types.rs index 7f9007978..8ac955b2d 100644 --- a/type_analysis/src/check_types.rs +++ b/type_analysis/src/check_types.rs @@ -109,8 +109,9 @@ fn template_level_decorators( _reports: &mut ReportCollection, ) { component_type_inference::inference(program_archive); + let program_archive2 = program_archive.clone(); for template_data in program_archive.get_mut_templates().values_mut() { - type_reduction::reduce_template(template_data); + type_reduction::reduce_template(template_data,&program_archive2); } } @@ -129,10 +130,11 @@ fn function_level_analyses(program_archive: &ProgramArchive, reports: &mut Repor } fn function_level_decorators(program_archive: &mut ProgramArchive, reports: &mut ReportCollection) { + let program_archive2 = program_archive.clone(); for function_data in program_archive.get_mut_functions().values_mut() { let mut constant_handler_reports = constants_handler::handle_function_constants(function_data); - type_reduction::reduce_function(function_data); + type_reduction::reduce_function(function_data,&program_archive2); reports.append(&mut constant_handler_reports); } } @@ -148,10 +150,11 @@ fn bus_level_analyses(program_archive: &ProgramArchive, reports: &mut ReportColl } fn bus_level_decorators(program_archive: &mut ProgramArchive, reports: &mut ReportCollection) { + let program_archive2 = program_archive.clone(); for bus_data in program_archive.get_mut_buses().values_mut() { let mut constant_handler_reports = constants_handler::handle_bus_constants(bus_data); - //type_reduction::reduce_bus(bus_data); + type_reduction::reduce_bus(bus_data,&program_archive2); reports.append(&mut constant_handler_reports); } } diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index f350524ab..220386e73 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -1,89 +1,101 @@ -use program_structure::ast::*; +use program_structure::program_archive::{self, ProgramArchive}; +use program_structure::wire_data::WireType; +use program_structure::{ast::*, bus_data}; +use program_structure::bus_data::BusData; use program_structure::environment::CircomEnvironment; use program_structure::function_data::FunctionData; use program_structure::template_data::TemplateData; -type Environment = CircomEnvironment<(), (), (), ()>; +type Environment = CircomEnvironment; -pub fn reduce_function(function_data: &mut FunctionData) { - let mut environment = CircomEnvironment::new(); +pub fn reduce_function(function_data: &mut FunctionData, program_archive : &ProgramArchive) { + let mut environment = Environment::new(); for param in function_data.get_name_of_params() { environment.add_variable(param, ()); } let body = function_data.get_mut_body(); - reduce_types_in_statement(body, &mut environment); + reduce_types_in_statement(body, &mut environment, program_archive); } -pub fn reduce_template(template_data: &mut TemplateData) { - let mut environment = CircomEnvironment::new(); +pub fn reduce_template(template_data: &mut TemplateData, program_archive : &ProgramArchive) { + let mut environment = Environment::new(); for param in template_data.get_name_of_params() { environment.add_variable(param, ()); } let body = template_data.get_mut_body(); - reduce_types_in_statement(body, &mut environment); + reduce_types_in_statement(body, &mut environment, program_archive); } -fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment) { +pub fn reduce_bus(bus_data: &mut BusData, program_archive : &ProgramArchive) { + let mut environment = Environment::new(); + for param in bus_data.get_name_of_params() { + environment.add_variable(param, ()); + } + let body = bus_data.get_mut_body(); + reduce_types_in_statement(body, &mut environment, program_archive); +} + +fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment, program_archive : &ProgramArchive) { use Statement::*; match stmt { Substitution { var, access, rhe, meta, .. } => { - reduce_types_in_substitution(var, access, environment, rhe, meta) + reduce_types_in_substitution(var, access, environment, rhe, meta, program_archive) } Declaration { name, xtype, dimensions, .. } => { - reduce_types_in_declaration(xtype, name, dimensions, environment) + reduce_types_in_declaration(xtype, name, dimensions, environment,program_archive) } - While { cond, stmt, .. } => reduce_types_in_while(cond, stmt, environment), - Block { stmts, .. } => reduce_types_in_vec_of_statements(stmts, environment), + While { cond, stmt, .. } => reduce_types_in_while(cond, stmt, environment,program_archive), + Block { stmts, .. } => reduce_types_in_vec_of_statements(stmts, environment,program_archive), InitializationBlock { initializations, .. } => { - reduce_types_in_vec_of_statements(initializations, environment) + reduce_types_in_vec_of_statements(initializations, environment,program_archive) } IfThenElse { cond, if_case, else_case, .. } => { - reduce_types_in_conditional(cond, if_case, else_case, environment) + reduce_types_in_conditional(cond, if_case, else_case, environment,program_archive) } LogCall { args, .. } => { - reduce_types_in_log_call(args, environment) + reduce_types_in_log_call(args, environment,program_archive) }, - Assert { arg, .. } => reduce_types_in_expression(arg, environment), - Return { value, .. } => reduce_types_in_expression(value, environment), + Assert { arg, .. } => reduce_types_in_expression(arg, environment,program_archive), + Return { value, .. } => reduce_types_in_expression(value, environment,program_archive), ConstraintEquality { lhe, rhe, .. } => { - reduce_types_in_constraint_equality(lhe, rhe, environment) + reduce_types_in_constraint_equality(lhe, rhe, environment,program_archive) } MultSubstitution { .. } => unreachable!(), UnderscoreSubstitution { rhe, .. } => { - reduce_types_in_expression(rhe, environment); + reduce_types_in_expression(rhe, environment,program_archive); }, } } -fn reduce_types_in_log_call(args: &mut Vec, environment: &Environment){ +fn reduce_types_in_log_call(args: &mut Vec, environment: &Environment, program_archive : &ProgramArchive){ for arg in args { if let LogArgument::LogExp(exp) = arg { - reduce_types_in_expression(exp, environment); + reduce_types_in_expression(exp, environment, program_archive); } } } -fn reduce_types_in_expression(expression: &mut Expression, environment: &Environment) { +fn reduce_types_in_expression(expression: &mut Expression, environment: &Environment, program_archive : &ProgramArchive) { use Expression::*; match expression { Variable { name, access, meta, .. } => { - reduce_types_in_variable(name, environment, access, meta) + reduce_types_in_variable(name, environment, access, meta,program_archive) } - InfixOp { lhe, rhe, .. } => reduce_types_in_infix(lhe, rhe, environment), - PrefixOp { rhe, .. } => reduce_types_in_expression(rhe, environment), - ParallelOp { rhe, .. } => reduce_types_in_expression(rhe, environment), + InfixOp { lhe, rhe, .. } => reduce_types_in_infix(lhe, rhe, environment,program_archive), + PrefixOp { rhe, .. } => reduce_types_in_expression(rhe, environment,program_archive), + ParallelOp { rhe, .. } => reduce_types_in_expression(rhe, environment,program_archive), InlineSwitchOp { cond, if_true, if_false, .. } => { - reduce_types_in_inline_switch(cond, if_true, if_false, environment) + reduce_types_in_inline_switch(cond, if_true, if_false, environment,program_archive) } - Call { args, .. } => reduce_types_in_vec_of_expressions(args, environment), - ArrayInLine { values, .. } => reduce_types_in_vec_of_expressions(values, environment), + Call { args, .. } => reduce_types_in_vec_of_expressions(args, environment,program_archive), + ArrayInLine { values, .. } => reduce_types_in_vec_of_expressions(values, environment,program_archive), UniformArray { value, dimension, .. } => { - reduce_types_in_expression(value, environment); - reduce_types_in_expression(dimension, environment); + reduce_types_in_expression(value, environment,program_archive); + reduce_types_in_expression(dimension, environment,program_archive); } Number(..) => {} BusCall { args, .. } => { - reduce_types_in_vec_of_expressions(args, environment); + reduce_types_in_vec_of_expressions(args, environment,program_archive); }, _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } @@ -93,9 +105,10 @@ fn reduce_types_in_constraint_equality( lhe: &mut Expression, rhe: &mut Expression, environment: &mut Environment, + program_archive : &ProgramArchive ) { - reduce_types_in_expression(lhe, environment); - reduce_types_in_expression(rhe, environment); + reduce_types_in_expression(lhe, environment,program_archive); + reduce_types_in_expression(rhe, environment,program_archive); } fn reduce_types_in_declaration( @@ -103,36 +116,65 @@ fn reduce_types_in_declaration( name: &str, dimensions: &mut [Expression], environment: &mut Environment, + program_archive : &ProgramArchive ) { use VariableType::*; if *xtype == Var { environment.add_variable(name, ()); } else if *xtype == Component || *xtype == AnonymousComponent { - environment.add_component(name, ()); + let mut typ = TypeKnowledge::default(); + typ.set_reduces_to(TypeReduction::Component(None)); + environment.add_component(name, typ); + } else if let Bus(_,_,_) = *xtype{ + let mut typ = TypeKnowledge::default(); + typ.set_reduces_to(TypeReduction::Bus(None)); + environment.add_intermediate_bus(name, typ) } else { environment.add_intermediate(name, ()); } - reduce_types_in_vec_of_expressions(dimensions, environment); + reduce_types_in_vec_of_expressions(dimensions, environment,program_archive); } fn reduce_types_in_substitution( name: &str, access: &mut [Access], - environment: &Environment, + environment: &mut Environment, expr: &mut Expression, meta: &mut Meta, + program_archive : &ProgramArchive ) { - reduce_types_in_variable(name, environment, access, meta); - reduce_types_in_expression(expr, environment); + reduce_types_in_variable(name, environment, access, meta,program_archive); + reduce_types_in_expression(expr, environment,program_archive); + let mut is_simple_component_or_bus = true; + for a in access{ + if let Access::ComponentAccess(_) = a { + is_simple_component_or_bus = false; + } + } + if environment.has_intermediate_bus(name) && is_simple_component_or_bus { + if let Some(xtype) = environment.get_mut_bus(name) { + if !xtype.is_initialized(){ + xtype.set_reduces_to(expr.get_meta().get_type_knowledge().get_reduces_to()) + } + } + } + if environment.has_component(name) && is_simple_component_or_bus { + if let Some(xtype) = environment.get_mut_component(name) { + if !xtype.is_initialized(){ + xtype.set_reduces_to(expr.get_meta().get_type_knowledge().get_reduces_to()) + } + } + } } fn reduce_types_in_while( cond: &mut Expression, stmt: &mut Statement, environment: &mut Environment, + program_archive : &ProgramArchive ) { - reduce_types_in_expression(cond, environment); - reduce_types_in_statement(stmt, environment); + reduce_types_in_expression(cond, environment,program_archive); + reduce_types_in_statement(stmt, environment, program_archive); } fn reduce_types_in_conditional( @@ -140,17 +182,18 @@ fn reduce_types_in_conditional( if_branch: &mut Statement, else_branch: &mut Option>, environment: &mut Environment, + program_archive : &ProgramArchive ) { - reduce_types_in_expression(cond, environment); - reduce_types_in_statement(if_branch, environment); + reduce_types_in_expression(cond, environment,program_archive); + reduce_types_in_statement(if_branch, environment,program_archive); if let Option::Some(else_stmt) = else_branch { - reduce_types_in_statement(else_stmt, environment); + reduce_types_in_statement(else_stmt, environment,program_archive); } } -fn reduce_types_in_vec_of_statements(vec: &mut [Statement], environment: &mut Environment) { +fn reduce_types_in_vec_of_statements(vec: &mut [Statement], environment: &mut Environment, program_archive : &ProgramArchive) { for stmt in vec { - reduce_types_in_statement(stmt, environment); + reduce_types_in_statement(stmt, environment,program_archive); } } @@ -159,32 +202,62 @@ fn reduce_types_in_variable( environment: &Environment, access: &mut [Access], meta: &mut Meta, + program_archive : &ProgramArchive ) { use Access::*; use TypeReduction::*; let mut reduction = if environment.has_signal(name) { Signal } else if environment.has_component(name) { - Component + environment.get_component(name).unwrap().get_reduces_to() + } else if environment.has_bus(name){ + environment.get_bus(name).unwrap().get_reduces_to() } else { Variable }; for acc in access { - if let ArrayAccess(exp) = acc { - reduce_types_in_expression(exp, environment) - } else if reduction == Signal{ - reduction = Tag; - } else { - reduction = Signal; + match acc { + ComponentAccess(name) => { + match reduction{ + Variable => unreachable!(), + Component(ref comp) => { + if let Some(comp) = comp { + let template = program_archive.get_template_data(comp.as_str()); + let wire = if let Some(wire) = template.get_inputs().get(name) { wire } + else if let Some(wire) = template.get_outputs().get(name) { wire } + else {unreachable!()}; + match wire.get_type(){ + WireType::Signal => reduction = Signal, + WireType::Bus(new_name) => reduction = Bus(Some(new_name)), + } + } + }, + Bus(ref b) => { + if let Some(b) = b { + let busdata = program_archive.get_bus_data(b.as_str()); + let wire = busdata.get_fields().get(name).unwrap(); + match wire.get_type(){ + WireType::Signal => reduction = Signal, + WireType::Bus(new_name) => reduction = Bus(Some(new_name)), + } + } + }, + Signal => reduction = Tag, + Tag => unreachable!(), + } + }, + ArrayAccess(exp) => { + reduce_types_in_expression(exp, environment,program_archive) + }, } } meta.get_mut_type_knowledge().set_reduces_to(reduction); } -fn reduce_types_in_infix(lhe: &mut Expression, rhe: &mut Expression, environment: &Environment) { - reduce_types_in_expression(lhe, environment); - reduce_types_in_expression(rhe, environment); +fn reduce_types_in_infix(lhe: &mut Expression, rhe: &mut Expression, environment: &Environment, program_archive : &ProgramArchive) { + reduce_types_in_expression(lhe, environment, program_archive); + reduce_types_in_expression(rhe, environment, program_archive); } fn reduce_types_in_inline_switch( @@ -192,14 +265,15 @@ fn reduce_types_in_inline_switch( if_true: &mut Expression, if_false: &mut Expression, environment: &Environment, + program_archive : &ProgramArchive ) { - reduce_types_in_expression(cond, environment); - reduce_types_in_expression(if_true, environment); - reduce_types_in_expression(if_false, environment); + reduce_types_in_expression(cond, environment,program_archive); + reduce_types_in_expression(if_true, environment,program_archive); + reduce_types_in_expression(if_false, environment,program_archive); } -fn reduce_types_in_vec_of_expressions(vec: &mut [Expression], environment: &Environment) { +fn reduce_types_in_vec_of_expressions(vec: &mut [Expression], environment: &Environment, program_archive : &ProgramArchive) { for expr in vec { - reduce_types_in_expression(expr, environment); + reduce_types_in_expression(expr, environment,program_archive); } } From a059e72c87b5880abb8235c07ae44e03c3121e4f Mon Sep 17 00:00:00 2001 From: miguelis Date: Sat, 4 May 2024 03:03:02 +0200 Subject: [PATCH 030/189] Known unknown analysis for buses extension --- .../src/program_library/error_code.rs | 2 ++ .../src/analyzers/unknown_known_analysis.rs | 36 ++++++++++++------- type_analysis/src/check_types.rs | 6 ++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 0eb6d2468..87705af7a 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -63,6 +63,7 @@ pub enum ReportCode { ParallelOperatorWithWrongTypes, InfixOperatorWithWrongTypes, InvalidArgumentInCall, + InvalidArgumentInBusInstantiation, InconsistentReturnTypesInBlock, InconsistentStaticInformation, InvalidArrayAccess(usize, usize), @@ -225,6 +226,7 @@ impl fmt::Display for ReportCode { TupleError => "TAC02", UnderscoreWithNoSignalWarning => "TAC03", BusWrongNumberOfArguments => "BU01", + InvalidArgumentInBusInstantiation => "BU02", }; f.write_str(string_format) } diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index d1d162b7f..275165920 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -29,20 +29,32 @@ enum Tag { type Environment = CircomEnvironment; pub fn unknown_known_analysis( - template_name: &str, + name: &str, program_archive: &ProgramArchive, ) -> Result<(), ReportCollection> { debug_assert!(Tag::Known < Tag::Unknown); - let template_data = program_archive.get_template_data(template_name); - let template_body = template_data.get_body(); - let file_id = template_data.get_file_id(); let mut environment = Environment::new(); - for arg in template_data.get_name_of_params() { - environment.add_variable(arg, Tag::Known); - } + let (body, file_id) = if program_archive.contains_template(name) { + let template_data = program_archive.get_template_data(name); + let template_body = template_data.get_body(); + let file_id = template_data.get_file_id(); + for arg in template_data.get_name_of_params() { + environment.add_variable(arg, Tag::Known); + } + (template_body, file_id) + } else { + debug_assert!(program_archive.contains_bus(name)); + let bus_data = program_archive.get_bus_data(name); + let bus_body = bus_data.get_body(); + let file_id = bus_data.get_file_id(); + for arg in bus_data.get_name_of_params() { + environment.add_variable(arg, Tag::Known); + } + (bus_body, file_id) + }; let entry = EntryInformation { file_id, environment }; - let result = analyze(template_body, entry); + let result = analyze(body, entry); if result.reports.is_empty() { Result::Ok(()) } else { @@ -144,7 +156,7 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma *value = max(expression_tag, access_tag); modified_variables.insert(var.clone()); } - TypeReduction::Component => { + TypeReduction::Component(_) => { constraints_declared = true; if expression_tag == Unknown { add_report(ReportCode::UnknownTemplate, rhe.get_meta(), file_id, &mut reports); @@ -153,7 +165,7 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma add_report(ReportCode::UnknownTemplate, meta, file_id, &mut reports); } } - TypeReduction::Bus => { + TypeReduction::Bus(_) => { constraints_declared = true; if expression_tag == Unknown { add_report(ReportCode::UnknownBus, rhe.get_meta(), file_id, &mut reports); @@ -363,8 +375,8 @@ fn tag(expression: &Expression, environment: &Environment) -> Tag { match reduced_type { TypeReduction::Variable => *environment.get_variable_or_break(name, file!(), line!()), TypeReduction::Signal => *environment.get_intermediate_or_break(name, file!(), line!()), - TypeReduction::Bus => *environment.get_intermediate_bus_or_break(name, file!(), line!()), - TypeReduction::Component => *environment.get_component_or_break(name, file!(), line!()), + TypeReduction::Bus(_) => *environment.get_intermediate_bus_or_break(name, file!(), line!()), + TypeReduction::Component(_) => *environment.get_component_or_break(name, file!(), line!()), TypeReduction::Tag => Known, } } diff --git a/type_analysis/src/check_types.rs b/type_analysis/src/check_types.rs index 8ac955b2d..68e965acd 100644 --- a/type_analysis/src/check_types.rs +++ b/type_analysis/src/check_types.rs @@ -164,6 +164,12 @@ fn semantic_analyses( errors: &mut ReportCollection, warnings: &mut ReportCollection, ) { + for bus_name in program_archive.get_bus_names().iter() { + if let Result::Err(mut unknown_known_report) = + unknown_known_analysis(&bus_name, program_archive) { + errors.append(&mut unknown_known_report); + } + } for template_name in program_archive.get_template_names().iter() { if let Result::Err(mut unknown_known_report) = unknown_known_analysis(template_name, program_archive) { From e15f7e6950129935f93045e8a08cd31eaa7edbf7 Mon Sep 17 00:00:00 2001 From: miguelis Date: Sat, 4 May 2024 16:27:03 +0200 Subject: [PATCH 031/189] Type reduction for buses extension --- .../abstract_syntax_tree/expression_impl.rs | 9 +- .../src/program_library/bus_data.rs | 3 +- .../src/program_library/error_code.rs | 2 + .../buses_free_of_invalid_statements.rs | 20 +- type_analysis/src/check_types.rs | 8 +- .../src/decorators/type_reduction.rs | 190 +++++++++++------- 6 files changed, 143 insertions(+), 89 deletions(-) diff --git a/program_structure/src/abstract_syntax_tree/expression_impl.rs b/program_structure/src/abstract_syntax_tree/expression_impl.rs index 63a157b25..16e828720 100644 --- a/program_structure/src/abstract_syntax_tree/expression_impl.rs +++ b/program_structure/src/abstract_syntax_tree/expression_impl.rs @@ -119,7 +119,14 @@ impl Expression { false } } - + pub fn is_bus_call(&self) -> bool { + use Expression::*; + if let BusCall { .. } = self { + true + } else { + false + } + } pub fn is_anonymous_comp(&self) -> bool { use Expression::*; if let AnonymousComp { .. } = self { diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs index 77835cf06..ed9b3d7f0 100644 --- a/program_structure/src/program_library/bus_data.rs +++ b/program_structure/src/program_library/bus_data.rs @@ -2,6 +2,7 @@ use super::ast::{FillMeta, Statement, VariableType, SignalType}; use super::file_definition::{FileID, FileLocation}; use super::wire_data::*; use std::collections::{HashMap}; +use std::num::IntErrorKind; pub type BusInfo = HashMap; @@ -122,7 +123,7 @@ fn fill_fields( ) { use Statement::*; match bus_statement { - Block { stmts, .. } => { + Block { stmts, .. } | InitializationBlock { initializations : stmts, .. } => { for stmt in stmts.iter() { fill_fields(stmt, fields, field_declarations); } diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 87705af7a..4945344db 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -113,6 +113,7 @@ pub enum ReportCode { InvalidSignalTagAccess, UninitializedComponent, BusWrongNumberOfArguments, + InvalidSignalAccessInBus, } impl fmt::Display for ReportCode { @@ -227,6 +228,7 @@ impl fmt::Display for ReportCode { UnderscoreWithNoSignalWarning => "TAC03", BusWrongNumberOfArguments => "BU01", InvalidArgumentInBusInstantiation => "BU02", + InvalidSignalAccessInBus => "BU03", }; f.write_str(string_format) } diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index a9f5e2683..41d858fb6 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -89,15 +89,17 @@ fn analyse_statement( } } }, - Substitution { meta, .. } | UnderscoreSubstitution { meta, .. } => { - let mut report = Report::error( - "Substitution statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + Substitution { meta, rhe, .. } | UnderscoreSubstitution { meta, rhe, .. } => { + if !rhe.is_bus_call(){ + let mut report = Report::error( + "Substitution statement used inside the bus".to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Using invalid statement".to_string()); + reports.push(report); + } }, ConstraintEquality { meta, .. } => { let mut report = Report::error( diff --git a/type_analysis/src/check_types.rs b/type_analysis/src/check_types.rs index 68e965acd..e63c87dee 100644 --- a/type_analysis/src/check_types.rs +++ b/type_analysis/src/check_types.rs @@ -106,12 +106,12 @@ fn template_level_analyses(program_archive: &ProgramArchive, reports: &mut Repor fn template_level_decorators( program_archive: &mut ProgramArchive, - _reports: &mut ReportCollection, + reports: &mut ReportCollection, ) { component_type_inference::inference(program_archive); let program_archive2 = program_archive.clone(); for template_data in program_archive.get_mut_templates().values_mut() { - type_reduction::reduce_template(template_data,&program_archive2); + reports.append(&mut type_reduction::reduce_template(template_data,&program_archive2)); } } @@ -134,7 +134,7 @@ fn function_level_decorators(program_archive: &mut ProgramArchive, reports: &mut for function_data in program_archive.get_mut_functions().values_mut() { let mut constant_handler_reports = constants_handler::handle_function_constants(function_data); - type_reduction::reduce_function(function_data,&program_archive2); + reports.append(&mut type_reduction::reduce_function(function_data,&program_archive2)); reports.append(&mut constant_handler_reports); } } @@ -154,7 +154,7 @@ fn bus_level_decorators(program_archive: &mut ProgramArchive, reports: &mut Repo for bus_data in program_archive.get_mut_buses().values_mut() { let mut constant_handler_reports = constants_handler::handle_bus_constants(bus_data); - type_reduction::reduce_bus(bus_data,&program_archive2); + reports.append(&mut type_reduction::reduce_bus(bus_data,&program_archive2)); reports.append(&mut constant_handler_reports); } } diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 220386e73..5ed55cb0b 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -1,3 +1,5 @@ +use program_structure::error_code::ReportCode; +use program_structure::error_definition::{Report, ReportCollection}; use program_structure::program_archive::{self, ProgramArchive}; use program_structure::wire_data::WireType; use program_structure::{ast::*, bus_data}; @@ -8,33 +10,33 @@ use program_structure::template_data::TemplateData; type Environment = CircomEnvironment; -pub fn reduce_function(function_data: &mut FunctionData, program_archive : &ProgramArchive) { +pub fn reduce_function(function_data: &mut FunctionData, program_archive : &ProgramArchive) -> ReportCollection { let mut environment = Environment::new(); for param in function_data.get_name_of_params() { environment.add_variable(param, ()); } let body = function_data.get_mut_body(); - reduce_types_in_statement(body, &mut environment, program_archive); + reduce_types_in_statement(body, &mut environment, program_archive) } -pub fn reduce_template(template_data: &mut TemplateData, program_archive : &ProgramArchive) { +pub fn reduce_template(template_data: &mut TemplateData, program_archive : &ProgramArchive) -> ReportCollection { let mut environment = Environment::new(); for param in template_data.get_name_of_params() { environment.add_variable(param, ()); } let body = template_data.get_mut_body(); - reduce_types_in_statement(body, &mut environment, program_archive); + reduce_types_in_statement(body, &mut environment, program_archive) } -pub fn reduce_bus(bus_data: &mut BusData, program_archive : &ProgramArchive) { +pub fn reduce_bus(bus_data: &mut BusData, program_archive : &ProgramArchive) -> ReportCollection { let mut environment = Environment::new(); for param in bus_data.get_name_of_params() { environment.add_variable(param, ()); } let body = bus_data.get_mut_body(); - reduce_types_in_statement(body, &mut environment, program_archive); + reduce_types_in_statement(body, &mut environment, program_archive) } -fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment, program_archive : &ProgramArchive) { +fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment, program_archive : &ProgramArchive) -> ReportCollection { use Statement::*; match stmt { Substitution { var, access, rhe, meta, .. } => { @@ -62,20 +64,24 @@ fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment } MultSubstitution { .. } => unreachable!(), UnderscoreSubstitution { rhe, .. } => { - reduce_types_in_expression(rhe, environment,program_archive); + reduce_types_in_expression(rhe, environment,program_archive) }, } } -fn reduce_types_in_log_call(args: &mut Vec, environment: &Environment, program_archive : &ProgramArchive){ +fn reduce_types_in_log_call(args: &mut Vec, environment: &Environment, program_archive : &ProgramArchive) + -> ReportCollection { + let mut reports = Vec::new(); for arg in args { if let LogArgument::LogExp(exp) = arg { - reduce_types_in_expression(exp, environment, program_archive); + reports.append(&mut reduce_types_in_expression(exp, environment, program_archive)); } } + reports } -fn reduce_types_in_expression(expression: &mut Expression, environment: &Environment, program_archive : &ProgramArchive) { +fn reduce_types_in_expression(expression: &mut Expression, environment: &Environment, program_archive : &ProgramArchive) + -> ReportCollection { use Expression::*; match expression { Variable { name, access, meta, .. } => { @@ -90,12 +96,13 @@ fn reduce_types_in_expression(expression: &mut Expression, environment: &Environ Call { args, .. } => reduce_types_in_vec_of_expressions(args, environment,program_archive), ArrayInLine { values, .. } => reduce_types_in_vec_of_expressions(values, environment,program_archive), UniformArray { value, dimension, .. } => { - reduce_types_in_expression(value, environment,program_archive); - reduce_types_in_expression(dimension, environment,program_archive); + let mut reports = reduce_types_in_expression(value, environment,program_archive); + reports.append(&mut reduce_types_in_expression(dimension, environment,program_archive)); + reports } - Number(..) => {} + Number(..) => { Vec::new() } BusCall { args, .. } => { - reduce_types_in_vec_of_expressions(args, environment,program_archive); + reduce_types_in_vec_of_expressions(args, environment,program_archive) }, _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } @@ -106,9 +113,10 @@ fn reduce_types_in_constraint_equality( rhe: &mut Expression, environment: &mut Environment, program_archive : &ProgramArchive -) { - reduce_types_in_expression(lhe, environment,program_archive); - reduce_types_in_expression(rhe, environment,program_archive); +) -> ReportCollection{ + let mut reports = reduce_types_in_expression(lhe, environment,program_archive); + reports.append(&mut reduce_types_in_expression(rhe, environment,program_archive)); + reports } fn reduce_types_in_declaration( @@ -117,7 +125,7 @@ fn reduce_types_in_declaration( dimensions: &mut [Expression], environment: &mut Environment, program_archive : &ProgramArchive -) { +) -> ReportCollection { use VariableType::*; if *xtype == Var { environment.add_variable(name, ()); @@ -125,46 +133,39 @@ fn reduce_types_in_declaration( let mut typ = TypeKnowledge::default(); typ.set_reduces_to(TypeReduction::Component(None)); environment.add_component(name, typ); - } else if let Bus(_,_,_) = *xtype{ + } else if let Bus(bname,_,_) = xtype.clone(){ let mut typ = TypeKnowledge::default(); - typ.set_reduces_to(TypeReduction::Bus(None)); + typ.set_reduces_to(TypeReduction::Bus(Some(bname))); environment.add_intermediate_bus(name, typ) } else { environment.add_intermediate(name, ()); } - reduce_types_in_vec_of_expressions(dimensions, environment,program_archive); + reduce_types_in_vec_of_expressions(dimensions, environment,program_archive) } -fn reduce_types_in_substitution( +fn reduce_types_in_substitution ( name: &str, access: &mut [Access], environment: &mut Environment, expr: &mut Expression, meta: &mut Meta, program_archive : &ProgramArchive -) { - reduce_types_in_variable(name, environment, access, meta,program_archive); - reduce_types_in_expression(expr, environment,program_archive); - let mut is_simple_component_or_bus = true; +) -> ReportCollection { + let mut reports = reduce_types_in_variable(name, environment, access, meta,program_archive); + reports.append(&mut reduce_types_in_expression(expr, environment,program_archive)); + let mut is_simple_component = true; for a in access{ if let Access::ComponentAccess(_) = a { - is_simple_component_or_bus = false; + is_simple_component = false; } } - if environment.has_intermediate_bus(name) && is_simple_component_or_bus { - if let Some(xtype) = environment.get_mut_bus(name) { - if !xtype.is_initialized(){ - xtype.set_reduces_to(expr.get_meta().get_type_knowledge().get_reduces_to()) - } - } - } - if environment.has_component(name) && is_simple_component_or_bus { - if let Some(xtype) = environment.get_mut_component(name) { - if !xtype.is_initialized(){ - xtype.set_reduces_to(expr.get_meta().get_type_knowledge().get_reduces_to()) - } + if is_simple_component { + let xtype = environment.get_mut_component(name); + if xtype.is_some() && xtype.as_ref().unwrap().is_initialized() { + xtype.unwrap().set_reduces_to(expr.get_meta().get_type_knowledge().get_reduces_to()); } } + reports } fn reduce_types_in_while( @@ -172,9 +173,11 @@ fn reduce_types_in_while( stmt: &mut Statement, environment: &mut Environment, program_archive : &ProgramArchive -) { - reduce_types_in_expression(cond, environment,program_archive); - reduce_types_in_statement(stmt, environment, program_archive); +)-> ReportCollection{ + let mut reports = Vec::new(); + reports.append(&mut reduce_types_in_expression(cond, environment,program_archive)); + reports.append(&mut reduce_types_in_statement(stmt, environment, program_archive)); + reports } fn reduce_types_in_conditional( @@ -183,35 +186,41 @@ fn reduce_types_in_conditional( else_branch: &mut Option>, environment: &mut Environment, program_archive : &ProgramArchive -) { - reduce_types_in_expression(cond, environment,program_archive); - reduce_types_in_statement(if_branch, environment,program_archive); +) -> ReportCollection { + let mut reports = Vec::new(); + reports.append(&mut reduce_types_in_expression(cond, environment,program_archive)); + reports.append(&mut reduce_types_in_statement(if_branch, environment,program_archive)); if let Option::Some(else_stmt) = else_branch { - reduce_types_in_statement(else_stmt, environment,program_archive); + reports.append(&mut reduce_types_in_statement(else_stmt, environment,program_archive)); } + reports } -fn reduce_types_in_vec_of_statements(vec: &mut [Statement], environment: &mut Environment, program_archive : &ProgramArchive) { +fn reduce_types_in_vec_of_statements(vec: &mut [Statement], environment: &mut Environment, program_archive : &ProgramArchive) + -> ReportCollection { + let mut reports = Vec::new(); for stmt in vec { - reduce_types_in_statement(stmt, environment,program_archive); + reports.append(&mut reduce_types_in_statement(stmt, environment,program_archive)); } + reports } fn reduce_types_in_variable( - name: &str, + oname: &str, environment: &Environment, access: &mut [Access], meta: &mut Meta, program_archive : &ProgramArchive -) { +) -> ReportCollection { use Access::*; use TypeReduction::*; - let mut reduction = if environment.has_signal(name) { + let mut reports = Vec::new(); + let mut reduction = if environment.has_signal(oname) { Signal - } else if environment.has_component(name) { - environment.get_component(name).unwrap().get_reduces_to() - } else if environment.has_bus(name){ - environment.get_bus(name).unwrap().get_reduces_to() + } else if environment.has_component(oname) { + environment.get_component(oname).unwrap().get_reduces_to() + } else if environment.has_bus(oname){ + environment.get_bus(oname).unwrap().get_reduces_to() } else { Variable }; @@ -220,44 +229,54 @@ fn reduce_types_in_variable( match acc { ComponentAccess(name) => { match reduction{ - Variable => unreachable!(), + Variable => {}, //Check type will return the corresponding error. Component(ref comp) => { if let Some(comp) = comp { let template = program_archive.get_template_data(comp.as_str()); - let wire = if let Some(wire) = template.get_inputs().get(name) { wire } - else if let Some(wire) = template.get_outputs().get(name) { wire } - else {unreachable!()}; - match wire.get_type(){ + let wire = template.get_inputs().get(name).or(template.get_outputs().get(name)); + if wire.is_some() { + match wire.unwrap().get_type(){ WireType::Signal => reduction = Signal, WireType::Bus(new_name) => reduction = Bus(Some(new_name)), - } + }//If it is not a signal or a bus, it is expected to be tag. + } else {//Then, type_check will finally check it. + name_not_found_in_component_error(name.clone(), oname.to_string(), meta,&mut reports); + return reports; + } } }, Bus(ref b) => { if let Some(b) = b { let busdata = program_archive.get_bus_data(b.as_str()); - let wire = busdata.get_fields().get(name).unwrap(); + if let Some(wire) = busdata.get_fields().get(name){ + match wire.get_type(){ WireType::Signal => reduction = Signal, WireType::Bus(new_name) => reduction = Bus(Some(new_name)), } + } else { + reduction = Tag; + } } }, Signal => reduction = Tag, - Tag => unreachable!(), + Tag => {}, } }, ArrayAccess(exp) => { - reduce_types_in_expression(exp, environment,program_archive) + reports.append(&mut reduce_types_in_expression(exp, environment,program_archive)); }, } } meta.get_mut_type_knowledge().set_reduces_to(reduction); + reports } -fn reduce_types_in_infix(lhe: &mut Expression, rhe: &mut Expression, environment: &Environment, program_archive : &ProgramArchive) { - reduce_types_in_expression(lhe, environment, program_archive); - reduce_types_in_expression(rhe, environment, program_archive); +fn reduce_types_in_infix(lhe: &mut Expression, rhe: &mut Expression, environment: &Environment, program_archive : &ProgramArchive) -> ReportCollection{ + let mut reports = Vec::new(); + reports.append(&mut reduce_types_in_expression(lhe, environment, program_archive)); + reports.append(&mut reduce_types_in_expression(rhe, environment, program_archive)); + reports } fn reduce_types_in_inline_switch( @@ -266,14 +285,37 @@ fn reduce_types_in_inline_switch( if_false: &mut Expression, environment: &Environment, program_archive : &ProgramArchive -) { - reduce_types_in_expression(cond, environment,program_archive); - reduce_types_in_expression(if_true, environment,program_archive); - reduce_types_in_expression(if_false, environment,program_archive); +) -> ReportCollection { + let mut reports = Vec::new(); + reports.append(&mut reduce_types_in_expression(cond, environment,program_archive)); + reports.append(&mut reduce_types_in_expression(if_true, environment,program_archive)); + reports.append(&mut reduce_types_in_expression(if_false, environment,program_archive)); + reports } -fn reduce_types_in_vec_of_expressions(vec: &mut [Expression], environment: &Environment, program_archive : &ProgramArchive) { +fn reduce_types_in_vec_of_expressions(vec: &mut [Expression], environment: &Environment, program_archive : &ProgramArchive) -> ReportCollection { + let mut reports = Vec::new(); for expr in vec { - reduce_types_in_expression(expr, environment,program_archive); + reports.append(& mut reduce_types_in_expression(expr, environment,program_archive)); } + reports } + +// Errors +fn name_not_found_in_bus_error(signal: String, what: String, meta: &Meta, reports: &mut ReportCollection) { + let message = "Bus or signal not defined in bus".to_string(); + let error_code = ReportCode::InvalidSignalAccessInBus; + let mut report = Report::error(message, error_code); + let message = signal + &" is not defined in ".to_string() + what.as_str(); + report.add_primary(meta.file_location(), meta.get_file_id(), message); + reports.push(report); +} + +fn name_not_found_in_component_error(signal: String, what: String, meta: &Meta, reports: &mut ReportCollection) { + let message = "Bus or signal not defined in component".to_string(); + let error_code = ReportCode::InvalidSignalAccess; + let mut report = Report::error(message, error_code); + let message = signal + &" is not defined in ".to_string() + what.as_str(); + report.add_primary(meta.file_location(), meta.get_file_id(), message); + reports.push(report); +} \ No newline at end of file From 526d7ebc11378acdca5e0913c90c4d4724de1ed9 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 6 May 2024 01:53:57 +0200 Subject: [PATCH 032/189] Type check for buses extension --- .../src/program_library/error_code.rs | 4 + .../buses_free_of_invalid_statements.rs | 16 +- type_analysis/src/analyzers/type_check.rs | 342 +++++++++++++----- .../src/decorators/type_reduction.rs | 8 +- 4 files changed, 268 insertions(+), 102 deletions(-) diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 4945344db..bb3c2af18 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -114,6 +114,8 @@ pub enum ReportCode { UninitializedComponent, BusWrongNumberOfArguments, InvalidSignalAccessInBus, + MustBeSameBus, + MustBeBus, } impl fmt::Display for ReportCode { @@ -229,6 +231,8 @@ impl fmt::Display for ReportCode { BusWrongNumberOfArguments => "BU01", InvalidArgumentInBusInstantiation => "BU02", InvalidSignalAccessInBus => "BU03", + MustBeSameBus => "BU04", + MustBeBus => "BU04", }; f.write_str(string_format) } diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 41d858fb6..f0f78403e 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -90,7 +90,19 @@ fn analyse_statement( } }, Substitution { meta, rhe, .. } | UnderscoreSubstitution { meta, rhe, .. } => { - if !rhe.is_bus_call(){ + let mut throw_undefined_bus = false; + match rhe { + Expression::BusCall {.. } => {}, + Expression::UniformArray { value, .. } => { + if !value.is_bus_call(){ + throw_undefined_bus = true; + } + }, + _ => { + throw_undefined_bus = true; + } + } + if throw_undefined_bus { let mut report = Report::error( "Substitution statement used inside the bus".to_string(), ReportCode::UndefinedBus, @@ -100,7 +112,7 @@ fn analyse_statement( report.add_primary(location, file_id, "Using invalid statement".to_string()); reports.push(report); } - }, + } ConstraintEquality { meta, .. } => { let mut report = Report::error( "Constraint statement used inside the bus".to_string(), diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index b46aac191..0656751c6 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1,13 +1,17 @@ use super::type_given_function::type_given_function; use super::type_register::TypeRegister; -use program_structure::ast::*; +use num_traits::sign; +use program_structure::{ast::*, template_data}; use program_structure::ast::Expression::Call; use program_structure::environment::CircomEnvironment; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; use program_structure::file_definition::{generate_file_location, FileID}; use program_structure::program_archive::ProgramArchive; +use program_structure::wire_data::WireType; use std::collections::HashSet; +use std::fmt::Error; +use std::thread::current; type ArithmeticType = usize; type ComponentInfo = (Option, ArithmeticType); @@ -99,9 +103,7 @@ pub fn type_check(program_archive: &ProgramArchive) -> Result {} + | (SymbolInformation::Tag, AssignOp::AssignVar) => { + //If the tag comes from an output wire, it cannot be modified. + if analysis_information.environment.has_component(var){ + let (comp,_) = analysis_information.environment.get_component(var).unwrap(); + if comp.is_some() && access_information.1.is_some() && access_information.1.as_ref().unwrap().len() > 0 { + let template_name = comp.clone().unwrap(); + let (first_access,_) = access_information.1.as_ref().unwrap().get(0).unwrap(); + let output = program_archive.get_template_data(&template_name).get_output_info(&first_access); + if output.is_some() { + return add_report( ReportCode::OutputTagCannotBeModifiedOutside,meta, &mut analysis_information.reports); + } + } + } + } (SymbolInformation::Signal(_), AssignOp::AssignVar) => { return add_report( ReportCode::WrongTypesInAssignOperationOperatorSignal, @@ -390,7 +397,26 @@ fn type_statement( &mut analysis_information.reports, ); } - if rhe_type.dim() != lhe_type.dim() { + if lhe_type.is_bus() || rhe_type.is_bus() { + match (lhe_type.bus, rhe_type.bus) { + (Some(b1),Some(b2)) => { + if b1 != b2 { + add_report(ReportCode::MustBeSameBus, lhe.get_meta(), + &mut analysis_information.reports); + } + } + (Some(_),_)=>{ + add_report(ReportCode::MustBeBus, rhe.get_meta(), + &mut analysis_information.reports); + }, + (_,Some(_)) => { + add_report(ReportCode::MustBeBus, lhe.get_meta(), + &mut analysis_information.reports); + }, + (_,_) => {unreachable!("At least one of them is a bus.")} + } + } + else if rhe_type.dim() != lhe_type.dim() { add_report( ReportCode::MustBeSameDimension(rhe_type.dim(), lhe_type.dim()), rhe.get_meta(), @@ -524,7 +550,7 @@ fn type_statement( } else { return; }; - if rhe_type.is_template() || rhe_type.is_bus() { + if rhe_type.is_template() { add_report( ReportCode::MustBeArithmetic, rhe.get_meta(), @@ -734,7 +760,7 @@ fn type_expression( let mut concrete_types = Vec::new(); let mut success = Result::Ok(()); for (arg_expr, arg_type) in args.iter().zip(arg_types.iter()) { - if arg_type.is_template() || arg_type.is_bus() { + if arg_type.is_template() { success = add_report_and_end( ReportCode::InvalidArgumentInCall, arg_expr.get_meta(), @@ -778,10 +804,58 @@ fn type_expression( analysis_information.file_id = previous_file_id; let folded_value = returned_type?; Result::Ok(folded_value) + }, + BusCall { meta, id, args } => { + analysis_information.reached.insert(id.clone()); + let typing_response = + type_array_of_expressions(args, program_archive, analysis_information); + if program_archive.contains_bus(id) && typing_response.is_err() { + return Result::Ok(FoldedType::bus(id,program_archive.get_bus_data(id).get_fields().len())); + } + let arg_types = typing_response?; + let mut concrete_types = Vec::new(); + let mut success = Result::Ok(()); + for (arg_expr, arg_type) in args.iter().zip(arg_types.iter()) { + if arg_type.is_template() || arg_type.is_bus() { + success = add_report_and_end( + ReportCode::InvalidArgumentInBusInstantiation, + arg_expr.get_meta(), + &mut analysis_information.reports, + ); + } + concrete_types.push(arg_type.dim()); + } + if program_archive.contains_bus(id) && success.is_err() { + return Result::Ok(FoldedType::bus(id,program_archive.get_bus_data(id).get_fields().len())); + } + success?; + let previous_file_id = analysis_information.file_id; + analysis_information.file_id = program_archive.get_bus_data(id).get_file_id(); + + let new_environment = prepare_environment_for_call( + meta, + id, + &concrete_types, + program_archive, + &mut analysis_information.reports, + ); + if new_environment.is_err() { + return Result::Ok(FoldedType::bus(id,program_archive.get_bus_data(id).get_fields().len())); + } + let new_environment = new_environment?; + let previous_environment = + std::mem::replace(&mut analysis_information.environment, new_environment); + let returned_type = type_bus(id, &concrete_types, analysis_information, program_archive); + analysis_information.environment = previous_environment; + analysis_information.file_id = previous_file_id; + let folded_value = returned_type?; + Result::Ok(folded_value) + } _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } } + //************************************************* Statement support ************************************************* fn treat_sequence_of_statements( stmts: &[Statement], @@ -795,9 +869,10 @@ fn treat_sequence_of_statements( //************************************************* Expression support ************************************************* // 0: symbol dimensions accessed -// 1: Signal accessed and dimensions accessed in that signal (optional) -// 2: Tag accessed (optional) -type AccessInfo = (ArithmeticType, Option<(String, ArithmeticType)>, Option); +// 1: Vector of (Wire accessed and dimensions accessed in that wire) (optional) +// Size of this vector is equals to the number of buses (+1 if it finishes in a signal)) +// (+1 if it finishes in a tag) +type AccessInfo = (ArithmeticType, Option>); fn treat_access( accesses: &[Access], meta: &Meta, @@ -805,33 +880,29 @@ fn treat_access( analysis_information: &mut AnalysisInformation, ) -> Result { use Access::*; - let mut access_info: AccessInfo = (0, Option::None, Option::None); + let mut access_info: AccessInfo = (0, Option::None); + let mut signal_info : Vec<(String, ArithmeticType)> = Vec::new(); for access in accesses { match access { ArrayAccess(index) => { let index_response = type_expression(&index, program_archive, analysis_information); - - if access_info.2.is_some() { - add_report( - ReportCode::InvalidArrayAccess(0, 1), - index.get_meta(), - &mut analysis_information.reports, - ); + if signal_info.len() > 0 { + let mut info = signal_info.get(signal_info.len()-1).unwrap().clone(); + info.1 = info.1 + 1; + signal_info.remove(signal_info.len()-1); + signal_info.push(info); } else { - if let Option::Some(signal_info) = &mut access_info.1 { - signal_info.1 += 1; - } else { - access_info.0 += 1; - } - if let Result::Ok(index_type) = index_response { - if index_type.is_template() { - add_report( + access_info.0 += 1; + } + if let Result::Ok(index_type) = index_response { + if index_type.is_template() || index_type.is_bus() { + add_report( ReportCode::InvalidArraySizeT, index.get_meta(), &mut analysis_information.reports, ); - } - else if index_type.dim() > 0 { + } + else if index_type.dim() > 0 { add_report( ReportCode::InvalidArraySize(index_type.dim()), index.get_meta(), @@ -839,25 +910,20 @@ fn treat_access( ); } } - } } ComponentAccess(name) => { - if let Option::Some(_signal_info) = & access_info.1 { - if access_info.2.is_none() { - access_info.2 = Some(name.clone()) - } else{ - add_report( - ReportCode::InvalidSignalTagAccess, - meta, - &mut analysis_information.reports, - ); - } + + if signal_info.len() > 0 { + signal_info.push((name.clone(),0)); } else { - access_info.1 = Option::Some((name.clone(), 0)); + signal_info = vec![(name.clone(), 0)]; } } } } + if signal_info.len() > 0{ + access_info.1 = Some(signal_info); + } else { access_info.1 = None; } Result::Ok(access_info) } @@ -877,12 +943,14 @@ fn apply_access_to_symbol( reports: &mut ReportCollection, program_archive: &ProgramArchive, ) -> Result { - let (current_template, mut current_dim, possible_tags) = if environment.has_component(symbol) { + let (current_template_or_bus, mut current_dim, possible_tags) = if environment.has_component(symbol) { let (temp, dim) = environment.get_component_or_break(symbol, file!(), line!()).clone(); - (temp,dim, Vec::new()) + (temp.clone(),dim, Vec::new()) } else if environment.has_signal(symbol) { let(dim, tags) = environment.get_signal_or_break(symbol, file!(), line!()); - (Option::None, *dim, tags.clone()) + (Some(symbol.to_string()), *dim, tags.clone()) + } else if environment.has_bus(symbol){ + environment.get_bus_or_break(symbol, file!(), line!()).clone() } else { let dim = environment.get_variable_or_break(symbol, file!(), line!()); (Option::None, *dim, Vec::new()) @@ -893,70 +961,130 @@ fn apply_access_to_symbol( } else { current_dim -= access_information.0 } + // Case wires or tags + if let Option::Some(buses_and_signals) = access_information.1{ + assert!(buses_and_signals.len() > 0); + let mut pos = 0; + if current_template_or_bus.is_none() && environment.has_bus(symbol){ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } else if current_template_or_bus.is_none() && environment.has_component(symbol){ + return add_report_and_end(ReportCode::UninitializedComponent, meta, reports); + } - // Case signals or tags - if let Option::Some((signal_name, dims_accessed)) = access_information.1{ - if current_template.is_some(){ // we are inside component + let (mut kind, mut tags) = if environment.has_component(symbol){ + // we are inside component if current_dim != 0{ // only allowed complete accesses to component return add_report_and_end(ReportCode::InvalidPartialArray, meta, reports); } - - let template_name = current_template.unwrap(); - let input = program_archive.get_template_data(&template_name).get_input_info(&signal_name); - let output = program_archive.get_template_data(&template_name).get_output_info(&signal_name); - let tags; - (current_dim, tags) = match (input, output) { + //current_dim == 0 => component completely defined + let template_name = current_template_or_bus.unwrap(); + let (accessed_element,accessed_dim) = buses_and_signals.get(pos).unwrap(); + let input = program_archive.get_template_data(&template_name).get_input_info(&accessed_element); + let output = program_archive.get_template_data(&template_name).get_output_info(&accessed_element); + let (dim, kind, atags) = match (input, output) { (Option::Some(wire_data), _) | (_, Option::Some(wire_data)) => - (wire_data.get_dimension(), wire_data.get_tags()), + (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()), _ => { return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); } }; - if access_information.2.is_some(){ // tag of io signal of component - if dims_accessed > 0{ - return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); - } - else if !tags.contains(&access_information.2.unwrap()){ - return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); - } else{ - return Result::Ok(SymbolInformation::Tag); + + if *accessed_dim > dim { + return add_report_and_end(ReportCode::InvalidArrayAccess(*accessed_dim, dim), meta, reports); + } + current_dim = dim - accessed_dim; + if pos == buses_and_signals.len()-1 { + match kind { + WireType::Signal => {return Result::Ok(SymbolInformation::Signal(current_dim));}, + WireType::Bus(_) => {return Result::Ok(SymbolInformation::Bus(Some(accessed_element.clone()),current_dim))}, } - } else{ // io signal of component - if dims_accessed > current_dim { - return add_report_and_end(ReportCode::InvalidArrayAccess(current_dim, dims_accessed), meta, reports); - } else { - return Result::Ok(SymbolInformation::Signal(current_dim - dims_accessed)); - } } - } else{ // we are in template - if environment.has_signal(symbol){ - if access_information.0 != 0{ - add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports) - } else if dims_accessed > 0{ - add_report_and_end( - ReportCode::InvalidArrayAccess(0, dims_accessed), - meta, - reports, - ) - } else if !possible_tags.contains(&signal_name){ - add_report_and_end(ReportCode::InvalidTagAccess, meta, reports) - } else{ - Result::Ok(SymbolInformation::Tag) + pos += 1; + (kind, atags.clone()) + } else if environment.has_bus(symbol){ + let kind = WireType::Bus(current_template_or_bus.unwrap()); + let mut tags = HashSet::new(); + for i in possible_tags.clone() { + tags.insert(i); + } + (kind, tags) + } else { + let kind = WireType::Signal; + let mut tags = HashSet::new(); + for i in possible_tags.clone() { + tags.insert(i); + } + (kind,tags) + }; + while pos < buses_and_signals.len() { + let (accessed_element, accessed_dim) = buses_and_signals.get(pos).unwrap().clone(); + if kind == WireType::Signal { + if tags.contains(&accessed_element) { + if pos == buses_and_signals.len()-1 && current_dim == 0 && accessed_dim == 0{ + return Result::Ok(SymbolInformation::Tag); + } else if current_dim > 0 { + return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); + } else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + } + else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + } else if let WireType::Bus(b_name) = kind { + let field = program_archive.get_bus_data(&b_name).get_field_info(&accessed_element); + match field { + Some(wire) => { + if accessed_dim > wire.get_dimension() { + return add_report_and_end(ReportCode::InvalidArrayAccess(wire.get_dimension(), accessed_dim), meta, reports); + } + current_dim = wire.get_dimension() - accessed_dim; + if pos == buses_and_signals.len()-1 { + match wire.get_type() { + WireType::Signal => {return Result::Ok(SymbolInformation::Signal(current_dim));}, + WireType::Bus(_) => {return Result::Ok(SymbolInformation::Bus(Some(b_name), current_dim))}, + } + } else { + if current_dim > 0 { + return add_report_and_end(ReportCode::InvalidArrayAccess(wire.get_dimension(),accessed_dim), meta, reports); + } + kind = wire.get_type(); + tags = wire.get_tags().clone(); + } + }, + None => { + if tags.contains(&accessed_element) { + if pos == buses_and_signals.len()-1 && current_dim == 0 && accessed_dim == 0{ + return Result::Ok(SymbolInformation::Tag); + } else if current_dim > 0 { + return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); + } else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + } + else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + }, } - - } else if environment.has_component(symbol){ - add_report_and_end(ReportCode::UninitializedComponent, meta, reports) } else{ - add_report_and_end(ReportCode::InvalidSignalTagAccess, meta, reports) + unreachable!() } + pos += 1; } + unreachable!() + + + //add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); } else if environment.has_variable(symbol) { Result::Ok(SymbolInformation::Var(current_dim)) } else if environment.has_signal(symbol) { Result::Ok(SymbolInformation::Signal(current_dim)) - } else if environment.has_component(symbol) && current_dim == 0 { - Result::Ok(SymbolInformation::Component(current_template)) + } else if environment.has_bus(symbol){ + Result::Ok(SymbolInformation::Bus(current_template_or_bus, current_dim)) + }else if environment.has_component(symbol) && current_dim == 0 { + Result::Ok(SymbolInformation::Component(current_template_or_bus)) } else { add_report_and_end(ReportCode::InvalidPartialArray, meta, reports) } @@ -994,8 +1122,10 @@ fn prepare_environment_for_call( ) -> Result { let args_names = if program_archive.contains_function(call_id) { program_archive.get_function_data(call_id).get_name_of_params() - } else { + } else if program_archive.contains_template(call_id) { program_archive.get_template_data(call_id).get_name_of_params() + } else { + program_archive.get_bus_data(call_id).get_name_of_params() }; if args_dims.len() != args_names.len() { let error_code = ReportCode::WrongNumberOfArguments(args_names.len(), args_dims.len()); @@ -1023,6 +1153,17 @@ fn type_template( call_id.to_string() } + +fn type_bus(id: &str, args_dims: &[ArithmeticType], analysis_information: &mut AnalysisInformation, program_archive: &ProgramArchive) -> Result { + debug_assert!(program_archive.contains_bus(id)); + if analysis_information.registered_calls.get_instance(id, args_dims).is_none() { + analysis_information.registered_calls.add_instance(id, args_dims.to_vec(), 0); + let stmts = program_archive.get_bus_data(id).get_body_as_vec(); + treat_sequence_of_statements(stmts, program_archive, analysis_information); + } + Result::Ok(FoldedType::bus(id,0)) +} + fn type_function( call_id: &str, args_dims: &[ArithmeticType], @@ -1119,6 +1260,7 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio expected, found) } InvalidArgumentInCall => "Components can not be passed as arguments".to_string(), + InvalidArgumentInBusInstantiation => "Components or buses can not be passed as arguments".to_string(), UnableToTypeFunction => "Unable to infer the type of this function".to_string(), MustBeSingleArithmetic(dim) => { format!("Must be a single arithmetic expression.\n Found expression of {} dimensions", dim) @@ -1140,6 +1282,10 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio } UninitializedComponent => "Trying to access to a signal of a component that has not been initialized".to_string(), NonCompatibleBranchTypes => "Inline switch operator branches types are non compatible".to_string(), + MustBeSameBus => "Both kind of buses must be equals".to_string(), + MustBeBus => "Expected to be a bus".to_string(), + InvalidSignalAccessInBus => format!("Field not defined in bus"), + WrongTypesInAssignOperationBus=> "Assignee and assigned types do not match.".to_string(), e => panic!("Unimplemented error code: {}", e), }; report.add_primary(location, file_id, message); diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 5ed55cb0b..0e7b7f37e 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -93,7 +93,10 @@ fn reduce_types_in_expression(expression: &mut Expression, environment: &Environ InlineSwitchOp { cond, if_true, if_false, .. } => { reduce_types_in_inline_switch(cond, if_true, if_false, environment,program_archive) } - Call { args, .. } => reduce_types_in_vec_of_expressions(args, environment,program_archive), + Call { args, id, meta, .. } => { + meta.get_mut_type_knowledge().set_reduces_to(TypeReduction::Component(Some(id.clone()))); + reduce_types_in_vec_of_expressions(args, environment,program_archive) + }, ArrayInLine { values, .. } => reduce_types_in_vec_of_expressions(values, environment,program_archive), UniformArray { value, dimension, .. } => { let mut reports = reduce_types_in_expression(value, environment,program_archive); @@ -101,7 +104,8 @@ fn reduce_types_in_expression(expression: &mut Expression, environment: &Environ reports } Number(..) => { Vec::new() } - BusCall { args, .. } => { + BusCall { args, meta, id, .. } => { + meta.get_mut_type_knowledge().set_reduces_to(TypeReduction::Bus(Some(id.clone()))); reduce_types_in_vec_of_expressions(args, environment,program_archive) }, _ => {unreachable!("Anonymous calls should not be reachable at this point."); } From 0b43fa4514d34a0ac48716b54cca96f2048855ac Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 7 May 2024 02:19:02 +0200 Subject: [PATCH 033/189] Fixing a problem with type reduction --- type_analysis/src/analyzers/type_check.rs | 13 +++++++++---- type_analysis/src/decorators/type_reduction.rs | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 0656751c6..92faf7812 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1021,9 +1021,12 @@ fn apply_access_to_symbol( let (accessed_element, accessed_dim) = buses_and_signals.get(pos).unwrap().clone(); if kind == WireType::Signal { if tags.contains(&accessed_element) { - if pos == buses_and_signals.len()-1 && current_dim == 0 && accessed_dim == 0{ + let prev_dim_access = if buses_and_signals.len()>1 {buses_and_signals.get(buses_and_signals.len()-2).unwrap().1} + else {access_information.0}; + //Tags cannot be partially accessed. Then, the previous bus or signal cannot be array accessed. + if pos == buses_and_signals.len()-1 && 0 == prev_dim_access && accessed_dim == 0{ return Result::Ok(SymbolInformation::Tag); - } else if current_dim > 0 { + } else if prev_dim_access > 0 { return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); } else{ return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); @@ -1055,9 +1058,11 @@ fn apply_access_to_symbol( }, None => { if tags.contains(&accessed_element) { - if pos == buses_and_signals.len()-1 && current_dim == 0 && accessed_dim == 0{ + let prev_dim_access = if buses_and_signals.len()>1 {buses_and_signals.get(buses_and_signals.len()-2).unwrap().1} + else {access_information.0}; + if pos == buses_and_signals.len()-1 && prev_dim_access == 0 && accessed_dim == 0{ return Result::Ok(SymbolInformation::Tag); - } else if current_dim > 0 { + } else if prev_dim_access > 0 { return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); } else{ return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 0e7b7f37e..a115260c7 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -166,7 +166,8 @@ fn reduce_types_in_substitution ( if is_simple_component { let xtype = environment.get_mut_component(name); if xtype.is_some() && xtype.as_ref().unwrap().is_initialized() { - xtype.unwrap().set_reduces_to(expr.get_meta().get_type_knowledge().get_reduces_to()); + let reduced_type = expr.get_meta().get_type_knowledge().get_reduces_to(); + xtype.unwrap().set_reduces_to(reduced_type); } } reports From f7bab59e0bc562e22302a9bbcbca286b7d298465 Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 7 May 2024 02:40:43 +0200 Subject: [PATCH 034/189] Fixed problem with known-unknown analysis --- type_analysis/src/analyzers/unknown_known_analysis.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 275165920..38bb89551 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -374,8 +374,8 @@ fn tag(expression: &Expression, environment: &Environment) -> Tag { let reduced_type = meta.get_type_knowledge().get_reduces_to(); match reduced_type { TypeReduction::Variable => *environment.get_variable_or_break(name, file!(), line!()), - TypeReduction::Signal => *environment.get_intermediate_or_break(name, file!(), line!()), - TypeReduction::Bus(_) => *environment.get_intermediate_bus_or_break(name, file!(), line!()), + TypeReduction::Signal => Unknown,//*environment.get_intermediate_or_break(name, file!(), line!()), + TypeReduction::Bus(_) => Unknown,//*environment.get_intermediate_bus_or_break(name, file!(), line!()), TypeReduction::Component(_) => *environment.get_component_or_break(name, file!(), line!()), TypeReduction::Tag => Known, } From a15547119283e6bebf5a6e716512a8806465d658 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 7 May 2024 14:51:40 +0200 Subject: [PATCH 035/189] cambios clara --- .../environment_utils/bus_representation.rs | 38 +++++++++++----- .../src/environment_utils/slice_types.rs | 8 ++++ constraint_generation/src/execute.rs | 45 +++++-------------- .../src/execution_data/type_definitions.rs | 34 ++++++++++++++ .../src/abstract_syntax_tree/ast.rs | 3 ++ 5 files changed, 83 insertions(+), 45 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index c9f08d875..7e8362ba9 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,16 +1,9 @@ -use super::slice_types::{MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo}; -use crate::execution_data::type_definitions::NodePointer; +use super::slice_types::{FieldTypes, MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo}; +use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; use crate::ast::Meta; -#[derive(Clone)] -struct FieldTypes { // For each field, we store the info depending on if it is a signal o a bus - // Depending on the case we store a different slice - pub signal: Option, - pub bus: Option, -} - pub struct BusRepresentation { pub node_pointer: Option, pub meta: Option, @@ -94,11 +87,34 @@ impl BusRepresentation { Result::Ok(()) } - pub fn get_field(&self, field_name: &str) -> Result<(&TagInfo, &SignalSlice), MemoryError> { + pub fn get_signal_field( + &self, + field_name: &str, + access: Option>, + ) -> Result<(&TagInfo, &FieldTypes), MemoryError> { + + let field = self.fields.get(field_name).unwrap(); + let field_tags = self.field_tags.get(field_name).unwrap(); + + match access{ + None => { + Ok((field_tags, field)) + } + Some(access) =>{ + let memory_response = MemorySlice::access_values(&field, &access_information.array_access); + let bus_slice = treat_result_with_memory_error( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + Ok((field_tags, field)) + } + } // Devuelve las tags y la SignalSlice con los valores // Si es un bus, llamar a que cada uno devuelva todo (get_all_fields) - unreachable!() + //unreachable!() } pub fn has_unassigned_fields(&self) -> bool{ diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index 685fabcb1..4595b960e 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -21,3 +21,11 @@ pub type ComponentSlice = MemorySlice; // To store the buses, similar to the components pub type BusSlice = MemorySlice; + +// To store the fields of a bus +#[derive(Clone)] +pub struct FieldTypes { // For each field, we store the info depending on if it is a signal o a bus + // Depending on the case we store a different slice + pub signal: Option, + pub bus: Option, +} \ No newline at end of file diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index cfd045766..1427dc144 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -18,6 +18,7 @@ use program_structure::constants::UsefulConstants; use super::execution_data::analysis::Analysis; use super::execution_data::{ExecutedBus, ExecutedProgram, ExecutedTemplate, PreExecutedTemplate, NodePointer}; +use super::execution_data::type_definitions::{AccessingInformationBus, AccessingInformation}; use super::{ ast::*, ArithmeticError, FileID, ProgramArchive, Report, ReportCode, ReportCollection @@ -2033,7 +2034,7 @@ fn execute_bus( tags_propagated.insert(tag.clone(), None); } } - // Check that all the buses are completely assigned + // Check that all the buses are completely assigned? for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let value_left = treat_result_with_memory_error( @@ -2093,7 +2094,15 @@ fn execute_bus( } } else{ - // Case we are accessing a field of the component + // Case we are accessing a field of the bus + let resulting_component = safe_unwrap_to_single(bus_slice, line!()); + + if meta.get_type_knowledge().is_bus(){ + // Case we return a bus + } else if meta.get_type_knowledge().is_signal(){ + // Case we return a signal + let access_result = resulting_component.get_signal_field(&access_information.field_access.unwrap(), access_information.remaining_access); + } Ok(FoldedValue{..FoldedValue::default()}) } @@ -2575,23 +2584,6 @@ fn cast_index(ae_index: &AExpr) -> Option { } } -/* - Usable representation of a series of accesses performed over a symbol. - AccessingInformation { - pub undefined: bool ===> true if one of the index values could not be transformed into a SliceCapacity during the process, - pub before_signal: Vec, - pub signal_access: Option ==> may not appear, - pub after_signal: Vec - pub tag_access: Option ==> may not appear, - } -*/ -struct AccessingInformation { - pub undefined: bool, - pub before_signal: Vec, - pub signal_access: Option, - pub after_signal: Vec, - pub tag_access: Option -} fn treat_accessing( meta: &Meta, access: &[Access], @@ -2631,21 +2623,6 @@ fn treat_accessing( } -/* - Usable representation of a series of accesses performed over a symbol representing a bus. - AccessingInformationBus { - pub undefined: bool ===> true if one of the index values could not be transformed into a SliceCapacity during the process, - pub array_access: Vec - pub field_access: Option // may not appear - pub remaining_access: Option, // may not appear - } -*/ -struct AccessingInformationBus { - pub undefined: bool, - pub array_access: Vec, - pub field_access: Option, - pub remaining_access: Option>, -} fn treat_accessing_bus( meta: &Meta, access: &[Access], diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index b76dbb9d3..243454e9d 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -25,3 +25,37 @@ pub struct BusData { pub goes_to: NodePointer, } +/* + Usable representation of a series of accesses performed over a symbol representing a bus. + AccessingInformationBus { + pub undefined: bool ===> true if one of the index values could not be transformed into a SliceCapacity during the process, + pub array_access: Vec + pub field_access: Option // may not appear + pub remaining_access: Option, // may not appear + } +*/ +pub struct AccessingInformationBus { + pub undefined: bool, + pub array_access: Vec, + pub field_access: Option, + pub remaining_access: Option>, +} + + +/* + Usable representation of a series of accesses performed over a symbol. + AccessingInformation { + pub undefined: bool ===> true if one of the index values could not be transformed into a SliceCapacity during the process, + pub before_signal: Vec, + pub signal_access: Option ==> may not appear, + pub after_signal: Vec + pub tag_access: Option ==> may not appear, + } +*/ +pub struct AccessingInformation { + pub undefined: bool, + pub before_signal: Vec, + pub signal_access: Option, + pub after_signal: Vec, + pub tag_access: Option +} diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 007767908..f8df101f6 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -446,6 +446,9 @@ impl TypeKnowledge { pub fn is_tag(&self) -> bool { self.get_reduces_to() == TypeReduction::Tag } + pub fn is_bus(&self) -> bool { + self.get_reduces_to() == TypeReduction::Bus + } } #[derive(Default, Clone)] From ac8f5b16a0d41292a50b6188324998a801376b43 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 7 May 2024 15:09:09 +0200 Subject: [PATCH 036/189] Corrected error in ast. --- program_structure/src/abstract_syntax_tree/ast.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 588676243..eaae1a0f3 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -457,7 +457,9 @@ impl TypeKnowledge { self.get_reduces_to() == TypeReduction::Tag } pub fn is_bus(&self) -> bool { - self.get_reduces_to() == TypeReduction::Bus + if let TypeReduction::Bus(_) = self.get_reduces_to() { + true + } else { false } } } From ca385d694cf411e23135e836cfbf52f5dd1a60a6 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 11 May 2024 18:00:02 +0200 Subject: [PATCH 037/189] Corrected error in ast. --- .../abstract_syntax_tree/expression_impl.rs | 15 ++++++ .../src/program_library/error_code.rs | 20 ++++---- tests/bus_test_correct_1.circom | 26 ++++++++-- .../src/analyzers/symbol_analysis.rs | 22 ++++++++- type_analysis/src/analyzers/type_check.rs | 47 +++++++++++++------ .../src/analyzers/unknown_known_analysis.rs | 23 ++++++--- 6 files changed, 116 insertions(+), 37 deletions(-) diff --git a/program_structure/src/abstract_syntax_tree/expression_impl.rs b/program_structure/src/abstract_syntax_tree/expression_impl.rs index 16e828720..c122447e5 100644 --- a/program_structure/src/abstract_syntax_tree/expression_impl.rs +++ b/program_structure/src/abstract_syntax_tree/expression_impl.rs @@ -20,6 +20,7 @@ impl Expression { | BusCall { meta, .. } => meta, } } + pub fn get_mut_meta(&mut self) -> &mut Meta { use Expression::*; match self { @@ -75,6 +76,7 @@ impl Expression { false } } + pub fn is_switch(&self) -> bool { use Expression::*; if let InlineSwitchOp { .. } = self { @@ -119,6 +121,7 @@ impl Expression { false } } + pub fn is_bus_call(&self) -> bool { use Expression::*; if let BusCall { .. } = self { @@ -127,6 +130,18 @@ impl Expression { false } } + + pub fn is_bus_call_array(&self) -> bool { + use Expression::*; + if let BusCall { .. } = self { + true + } else if let UniformArray { value, .. } = self { + value.is_bus_call_array() + } else { + false + } + } + pub fn is_anonymous_comp(&self) -> bool { use Expression::*; if let AnonymousComp { .. } = self { diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index bb3c2af18..8ce2b0e03 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -126,14 +126,6 @@ impl fmt::Display for ReportCode { MultipleMain => "P1002", CompilerVersionError => "P1003", NoCompilerVersionWarning => "P1004", - WrongTypesInAssignOperationOperatorSignal => "T2000", - WrongTypesInAssignOperationOperatorNoSignal => "T2000", - WrongTypesInAssignOperationArrayTemplates => "T2000", - WrongTypesInAssignOperationTemplate => "T2000", - WrongTypesInAssignOperationArrayBuses => "T2000", - WrongTypesInAssignOperationBus => "T2000", - WrongTypesInAssignOperationExpression => "T2000", - WrongTypesInAssignOperationDims(..) => "T2000", UnclosedComment => "P1005", FileOs => "P1006", MissingSemicolon => "P1008", @@ -204,6 +196,14 @@ impl fmt::Display for ReportCode { MainComponentWithTags => "T2051", UndefinedBus => "T2052", InvalidArraySizeB => "T2053", + WrongTypesInAssignOperationOperatorSignal => "T2054", + WrongTypesInAssignOperationOperatorNoSignal => "T2055", + WrongTypesInAssignOperationArrayTemplates => "T2056", + WrongTypesInAssignOperationTemplate => "T2057", + WrongTypesInAssignOperationArrayBuses => "T2058", + WrongTypesInAssignOperationBus => "T2059", + WrongTypesInAssignOperationExpression => "T2060", + WrongTypesInAssignOperationDims(..) => "T2061", RuntimeError => "T3001", RuntimeWarning => "T3002", UnknownDimension => "T20460", @@ -232,8 +232,8 @@ impl fmt::Display for ReportCode { InvalidArgumentInBusInstantiation => "BU02", InvalidSignalAccessInBus => "BU03", MustBeSameBus => "BU04", - MustBeBus => "BU04", + MustBeBus => "BU05", }; f.write_str(string_format) } -} +} \ No newline at end of file diff --git a/tests/bus_test_correct_1.circom b/tests/bus_test_correct_1.circom index 11c9aeace..a7e6822c1 100644 --- a/tests/bus_test_correct_1.circom +++ b/tests/bus_test_correct_1.circom @@ -4,12 +4,32 @@ bus Point (n) { signal {binary} x[n], y[n]; } +template Main(n) { + Point(n) output {babyedwards} pout; + + Point(n) {babyedwards} pin; + for (var i=0; i { + Statement::Declaration { meta, name, dimensions, xtype, .. } => { for index in dimensions { analyze_expression( index, @@ -243,6 +243,24 @@ fn analyze_statement( ); reports.push(report); } + if let program_structure::ast::VariableType::Bus(b_name,_,tags ) = xtype { + if let Some(bus) = bus_info.get(b_name) { + for t in tags { + if bus.get_fields().contains_key(t) { + let mut report = Report::error( + format!("Declaring same symbol twice"), + ReportCode::SameSymbolDeclaredTwice, + ); + report.add_primary( + meta.location.clone(), + file_id.clone(), + format!("This tag name is also a field name in the bus."), + ); + reports.push(report); + } + } + } + } } Statement::LogCall { args, .. } => { for logarg in args { @@ -489,4 +507,4 @@ fn analyze_expression( }, _ => {} } -} +} \ No newline at end of file diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 92faf7812..1348099ba 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -243,11 +243,15 @@ fn type_statement( match (&symbol_information, op) { (SymbolInformation::Signal(_), AssignOp::AssignConstraintSignal) | (SymbolInformation::Signal(_), AssignOp::AssignSignal) - | (SymbolInformation::Bus(_,_), AssignOp::AssignConstraintSignal) - | (SymbolInformation::Bus(_,_), AssignOp::AssignSignal) - | (SymbolInformation::Bus(_,_), AssignOp::AssignVar) | (SymbolInformation::Var(_), AssignOp::AssignVar) | (SymbolInformation::Component(_), AssignOp::AssignVar) + | (SymbolInformation::Bus(_,_), AssignOp::AssignConstraintSignal) + | (SymbolInformation::Bus(_,_), AssignOp::AssignSignal) => {} + | (SymbolInformation::Bus(_,_), AssignOp::AssignVar) => { + if !rhe.is_bus_call() && !rhe.is_bus_call_array(){ + return add_report(ReportCode::WrongTypesInAssignOperationBus, meta, &mut analysis_information.reports); + } + } | (SymbolInformation::Tag, AssignOp::AssignVar) => { //If the tag comes from an output wire, it cannot be modified. if analysis_information.environment.has_component(var){ @@ -322,11 +326,20 @@ fn type_statement( let bus = possible_bus.unwrap(); let r_bus = rhe_type.bus.unwrap(); if bus != r_bus { - add_report( - ReportCode::WrongTypesInAssignOperationArrayBuses, - meta, - &mut analysis_information.reports, - ) + if dim > 0 { + add_report( + ReportCode::WrongTypesInAssignOperationArrayBuses, + meta, + &mut analysis_information.reports, + ) + } + else { + add_report( + ReportCode::WrongTypesInAssignOperationBus, + meta, + &mut analysis_information.reports, + ) + } } } } else { @@ -965,6 +978,9 @@ fn apply_access_to_symbol( if let Option::Some(buses_and_signals) = access_information.1{ assert!(buses_and_signals.len() > 0); let mut pos = 0; + if current_dim > 0 && (pos < buses_and_signals.len()- 1 || !possible_tags.contains(&buses_and_signals.get(0).unwrap().0)){ + return add_report_and_end(ReportCode::InvalidArrayAccess(current_dim+access_information.0,access_information.0), meta, reports); + } if current_template_or_bus.is_none() && environment.has_bus(symbol){ return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); } else if current_template_or_bus.is_none() && environment.has_component(symbol){ @@ -991,13 +1007,13 @@ fn apply_access_to_symbol( }; if *accessed_dim > dim { - return add_report_and_end(ReportCode::InvalidArrayAccess(*accessed_dim, dim), meta, reports); + return add_report_and_end(ReportCode::InvalidArrayAccess(dim, *accessed_dim), meta, reports); } current_dim = dim - accessed_dim; if pos == buses_and_signals.len()-1 { match kind { WireType::Signal => {return Result::Ok(SymbolInformation::Signal(current_dim));}, - WireType::Bus(_) => {return Result::Ok(SymbolInformation::Bus(Some(accessed_element.clone()),current_dim))}, + WireType::Bus(b_name) => {return Result::Ok(SymbolInformation::Bus(Some(b_name.clone()),current_dim))}, } } pos += 1; @@ -1019,6 +1035,9 @@ fn apply_access_to_symbol( }; while pos < buses_and_signals.len() { let (accessed_element, accessed_dim) = buses_and_signals.get(pos).unwrap().clone(); + if current_dim > 0 && (pos < buses_and_signals.len()- 1 || !tags.contains(&accessed_element)){ + return add_report_and_end(ReportCode::InvalidArrayAccess(current_dim,accessed_dim), meta, reports); + } if kind == WireType::Signal { if tags.contains(&accessed_element) { let prev_dim_access = if buses_and_signals.len()>1 {buses_and_signals.get(buses_and_signals.len()-2).unwrap().1} @@ -1049,9 +1068,6 @@ fn apply_access_to_symbol( WireType::Bus(_) => {return Result::Ok(SymbolInformation::Bus(Some(b_name), current_dim))}, } } else { - if current_dim > 0 { - return add_report_and_end(ReportCode::InvalidArrayAccess(wire.get_dimension(),accessed_dim), meta, reports); - } kind = wire.get_type(); tags = wire.get_tags().clone(); } @@ -1258,7 +1274,9 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio format!("The operator does not match the types of the assigned elements.\n Only assignments to signals allow the operators <== and <--, try using = instead") } WrongTypesInAssignOperationArrayTemplates => "Assignee and assigned types do not match.\n All components of an array must be instances of the same template.".to_string(), - WrongTypesInAssignOperationTemplate => "Assignee and assigned types do not match.\n Expected template found expression.".to_string(), + WrongTypesInAssignOperationTemplate => "Assignee and assigned types do not match.\n Expected template but found expression.".to_string(), + WrongTypesInAssignOperationArrayBuses => "Assignee and assigned types do not match.\n All buses of an array must be the same type.".to_string(), + WrongTypesInAssignOperationBus => "Assignee and assigned types do not match.\n Expected bus but found a different expression.".to_string(), WrongTypesInAssignOperationExpression => "Assignee and assigned types do not match.\n Expected expression found template.".to_string(), WrongTypesInAssignOperationDims(expected, found) => { format!("Assignee and assigned types do not match. \n Expected dimensions: {}, found {}", @@ -1290,7 +1308,6 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio MustBeSameBus => "Both kind of buses must be equals".to_string(), MustBeBus => "Expected to be a bus".to_string(), InvalidSignalAccessInBus => format!("Field not defined in bus"), - WrongTypesInAssignOperationBus=> "Assignee and assigned types do not match.".to_string(), e => panic!("Unimplemented error code: {}", e), }; report.add_primary(location, file_id, message); diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 38bb89551..8fdc0f3f3 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -166,13 +166,20 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma } } TypeReduction::Bus(_) => { - constraints_declared = true; - if expression_tag == Unknown { - add_report(ReportCode::UnknownBus, rhe.get_meta(), file_id, &mut reports); + if *op == AssignOp::AssignConstraintSignal { + constraints_declared = true; } - if access_tag == Unknown { + if *op == AssignOp::AssignVar && expression_tag == Unknown { add_report(ReportCode::UnknownBus, meta, file_id, &mut reports); } + if *op == AssignOp::AssignConstraintSignal { + if is_non_quadratic(rhe, &environment) { + add_report(ReportCode::UnknownTemplate, rhe.get_meta(), file_id, &mut reports); + } + if access_tag == Unknown { + add_report(ReportCode::NonQuadratic, meta, file_id, &mut reports); + } + } } TypeReduction::Tag => { tags_modified = true; @@ -380,7 +387,9 @@ fn tag(expression: &Expression, environment: &Environment) -> Tag { TypeReduction::Tag => Known, } } - ArrayInLine { values, .. } | Call { args: values, .. } => { + ArrayInLine { values, .. } + | Call { args: values, .. } + | BusCall { args: values, .. }=> { expression_iterator(values, Known, Unknown, environment) } UniformArray { value, dimension, .. } => { @@ -513,7 +522,7 @@ fn add_report( let message = match error_code { UnknownDimension => "The length of every array must known during the constraint generation phase".to_string(), UnknownTemplate => "Every component instantiation must be resolved during the constraint generation phase".to_string(), - UnknownBus => "Every bus instantiation must be resolved during the constraint generation phase".to_string(), + UnknownBus => "Parameters of a bus must be known during the constraint generation phase".to_string(), NonQuadratic => "Non-quadratic constraint was detected statically, using unknown index will cause the constraint to be non-quadratic".to_string(), UnreachableConstraints => "There are constraints depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), UnreachableTags => "There are tag assignments depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), @@ -522,4 +531,4 @@ fn add_report( }; report.add_primary(location, file_id, message); reports.push(report); -} +} \ No newline at end of file From 58eb7f38a3fa652cbd089d82590e815302252c4e Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 11 May 2024 18:51:20 +0200 Subject: [PATCH 038/189] Changed test files. --- ...est_correct_7.circom => aliascheck.circom} | 0 ...correct_8.circom => aliascheck_old.circom} | 0 tests/babyjub.circom | 158 ++++++++++++++++ tests/bus_test_correct_3.circom | 168 +++--------------- tests/bus_test_error_1.circom | 26 ++- tests/bus_test_error_2.circom | 17 +- tests/bus_test_error_3.circom | 8 +- tests/bus_test_error_4.circom | 17 -- ..._correct_4.circom => escalarmulfix.circom} | 0 ...est_correct_5.circom => montgomery.circom} | 0 ..._test_correct_6.circom => pedersen.circom} | 0 11 files changed, 220 insertions(+), 174 deletions(-) rename tests/{bus_test_correct_7.circom => aliascheck.circom} (100%) rename tests/{bus_test_correct_8.circom => aliascheck_old.circom} (100%) create mode 100644 tests/babyjub.circom rename tests/{bus_test_correct_4.circom => escalarmulfix.circom} (100%) rename tests/{bus_test_correct_5.circom => montgomery.circom} (100%) rename tests/{bus_test_correct_6.circom => pedersen.circom} (100%) diff --git a/tests/bus_test_correct_7.circom b/tests/aliascheck.circom similarity index 100% rename from tests/bus_test_correct_7.circom rename to tests/aliascheck.circom diff --git a/tests/bus_test_correct_8.circom b/tests/aliascheck_old.circom similarity index 100% rename from tests/bus_test_correct_8.circom rename to tests/aliascheck_old.circom diff --git a/tests/babyjub.circom b/tests/babyjub.circom new file mode 100644 index 000000000..66c750f65 --- /dev/null +++ b/tests/babyjub.circom @@ -0,0 +1,158 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.1.5; + +include "bitify.circom"; +include "escalarmul/escalarmulfix.circom"; + +// The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) + +bus Point { + signal {bn128} x,y; +} + +/* +*** BabyAdd(): template that receives two points of the Baby Jubjub curve in Edwards form and returns the addition of the points. + - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in Edwards form + p2 = (x2, y2) -> bus representing a point of the curve in Edwards form + - Outputs: pout = (xout, yout) -> bus representing a point of the curve in Edwards form, pout = p1 + p2 + + Example: + + tau = d * x1 * x2 * y1 * y2 + + + x1 * y2 + y1 * x2 y1 * y2 - x1 * x2 + [xout, yout] = [ ----------------------- , ----------------------- ] + 1 + d * tau 1 - d * tau + +*/ + +template BabyAdd() { + Point input {babyedwards} p1,p2; + Point output {babyedwards} pout; + + signal beta; + signal gamma; + signal delta; + signal tau; + + var a = 168700; + var d = 168696; + + beta <== p1.x*p2.y; + gamma <== p1.y*p2.x; + delta <== (-a*p1.x + p1.y)*(p2.x + p2.y); + tau <== beta * gamma; + + pout.x <-- (beta + gamma) / (1 + d*tau); + (1 + d*tau) * pout.x === (beta + gamma); + + pout.y <-- (delta + a*beta - gamma) / (1 - d*tau); + (1 - d*tau)*pout.y === (delta + a*beta - gamma); +} + + + +/* +*** BabyDouble(): template that receives a point pin of the Baby Jubjub curve in Edwards form and returns the point 2 * pin. + - Inputs: pin = (x1, y1) -> bus representing a point of the curve in Edwards form + - Outputs: pout = (x2, y2) -> bus representing a point of the curve in Edwards form, 2 * pin = pout + + Example: BabyDouble()(p) = BabyAdd()(p, p) + +*/ + +template BabyDbl() { + Point input {babyedwards} pin; + Point output {babyedwards} pout; + + component adder = BabyAdd(); + adder.p1 <== pin; + adder.p2 <== pin; + + adder.pout ==> pout; +} + + +/* +*** BabyCheck(): template that receives an input point pin and checks if it belongs to the Baby Jubjub curve. + - Inputs: pin = (x1, y1) -> bus representing the point that we want to check + - Outputs: pout = (x2, y2) -> two field values representing the same point as the input but with the babyedwards tag + to point out it is a point of the Baby Jubjub curve in Edwards form + + Example: The set of solutions of BabyCheck()(p) are the points of the Baby Jubjub curve in Edwards form + +*/ + + +template BabyCheck() { + Point input pin; + Point output {babyedwards} pout; + + // Point p2; + signal x2; + signal y2; + + var a = 168700; + var d = 168696; + + x2 <== pin.x*pin.x; //x2 = pin.x^2 + y2 <== pin.y*pin.y; //y2 = pin.y^2 + + a*x2 + y2 === 1 + d*x2*y2; + + pout <== pin; +} + + +/* +*** BabyPbk(): template that receives an input in representing a value in the prime subgroup with order r = 2736030358979909402780800718157159386076813972158567259200215660948447373041, + and returns the point of the BabyJubjub curve in * P with P being the point P = (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203) + +This template is used to extract the public key from the private key. + - Inputs: in -> field value in [1,r-1] + - Outputs: A = (x, y) -> two field values representing a point of the curve in Edwards form, in * P = A + +*/ + +template BabyPbk() { + signal input {minvalue,maxvalue} in; + Point output {babyedwards} A; + + + var r = 2736030358979909402780800718157159386076813972158567259200215660948447373041; + assert(in.minvalue > 0 && in.maxvalue < r); + var BASE8[2] = [ + 5299619240641551281634865583518297030282874472190772894086521144482721001553, + 16950150798460657717958625567821834550301663161624707787222815936182638968203 + ]; + + component pvkBits = Num2Bits(253); + pvkBits.in <== in; + + component mulFix = EscalarMulFix(253, BASE8); + + var i; + for (i=0; i<253; i++) { + mulFix.e[i] <== pvkBits.out[i]; + } + + A <== mulFix.out; +} \ No newline at end of file diff --git a/tests/bus_test_correct_3.circom b/tests/bus_test_correct_3.circom index 66c750f65..5a660c3a4 100644 --- a/tests/bus_test_correct_3.circom +++ b/tests/bus_test_correct_3.circom @@ -1,158 +1,40 @@ -/* - Copyright 2018 0KIMS association. +pragma circom 2.0.0; - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.1.5; - -include "bitify.circom"; -include "escalarmul/escalarmulfix.circom"; - -// The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) - -bus Point { - signal {bn128} x,y; +bus A () { + signal {tag1} a; } -/* -*** BabyAdd(): template that receives two points of the Baby Jubjub curve in Edwards form and returns the addition of the points. - - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in Edwards form - p2 = (x2, y2) -> bus representing a point of the curve in Edwards form - - Outputs: pout = (xout, yout) -> bus representing a point of the curve in Edwards form, pout = p1 + p2 - - Example: - - tau = d * x1 * x2 * y1 * y2 - - - x1 * y2 + y1 * x2 y1 * y2 - x1 * x2 - [xout, yout] = [ ----------------------- , ----------------------- ] - 1 + d * tau 1 - d * tau - -*/ - -template BabyAdd() { - Point input {babyedwards} p1,p2; - Point output {babyedwards} pout; - - signal beta; - signal gamma; - signal delta; - signal tau; - - var a = 168700; - var d = 168696; - - beta <== p1.x*p2.y; - gamma <== p1.y*p2.x; - delta <== (-a*p1.x + p1.y)*(p2.x + p2.y); - tau <== beta * gamma; - - pout.x <-- (beta + gamma) / (1 + d*tau); - (1 + d*tau) * pout.x === (beta + gamma); - - pout.y <-- (delta + a*beta - gamma) / (1 - d*tau); - (1 - d*tau)*pout.y === (delta + a*beta - gamma); +bus B { + A b1, b2; } - - -/* -*** BabyDouble(): template that receives a point pin of the Baby Jubjub curve in Edwards form and returns the point 2 * pin. - - Inputs: pin = (x1, y1) -> bus representing a point of the curve in Edwards form - - Outputs: pout = (x2, y2) -> bus representing a point of the curve in Edwards form, 2 * pin = pout - - Example: BabyDouble()(p) = BabyAdd()(p, p) - -*/ - -template BabyDbl() { - Point input {babyedwards} pin; - Point output {babyedwards} pout; - - component adder = BabyAdd(); - adder.p1 <== pin; - adder.p2 <== pin; - - adder.pout ==> pout; +bus C (n) { + A () a; + B () {tag2} b[n]; } - -/* -*** BabyCheck(): template that receives an input point pin and checks if it belongs to the Baby Jubjub curve. - - Inputs: pin = (x1, y1) -> bus representing the point that we want to check - - Outputs: pout = (x2, y2) -> two field values representing the same point as the input but with the babyedwards tag - to point out it is a point of the Baby Jubjub curve in Edwards form - - Example: The set of solutions of BabyCheck()(p) are the points of the Baby Jubjub curve in Edwards form - -*/ - - -template BabyCheck() { - Point input pin; - Point output {babyedwards} pout; - - // Point p2; - signal x2; - signal y2; - - var a = 168700; - var d = 168696; - - x2 <== pin.x*pin.x; //x2 = pin.x^2 - y2 <== pin.y*pin.y; //y2 = pin.y^2 - - a*x2 + y2 === 1 + d*x2*y2; - - pout <== pin; +bus D (array,m,n) { + A a1; + A {tag3} a2; + B b1[array[0]], b2[array[1]]; + C(m) {tag4} c1[n], c2[n]; } +template Main (m,n) { + C(m) input c[n]; + A output {tag1} a; -/* -*** BabyPbk(): template that receives an input in representing a value in the prime subgroup with order r = 2736030358979909402780800718157159386076813972158567259200215660948447373041, - and returns the point of the BabyJubjub curve in * P with P being the point P = (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203) - -This template is used to extract the public key from the private key. - - Inputs: in -> field value in [1,r-1] - - Outputs: A = (x, y) -> two field values representing a point of the curve in Edwards form, in * P = A - -*/ - -template BabyPbk() { - signal input {minvalue,maxvalue} in; - Point output {babyedwards} A; + var array[2] = [2,4]; + var s = 0; + D(array,m,n) {tag5} d; - var r = 2736030358979909402780800718157159386076813972158567259200215660948447373041; - assert(in.minvalue > 0 && in.maxvalue < r); - var BASE8[2] = [ - 5299619240641551281634865583518297030282874472190772894086521144482721001553, - 16950150798460657717958625567821834550301663161624707787222815936182638968203 - ]; + d.c1 <== c; - component pvkBits = Num2Bits(253); - pvkBits.in <== in; - - component mulFix = EscalarMulFix(253, BASE8); - - var i; - for (i=0; i<253; i++) { - mulFix.e[i] <== pvkBits.out[i]; + for (var i=0; i Date: Sat, 11 May 2024 19:33:08 +0200 Subject: [PATCH 039/189] Corrected error in bus_test_correct_3. --- tests/bus_test_correct_3.circom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bus_test_correct_3.circom b/tests/bus_test_correct_3.circom index 5a660c3a4..69aa0b551 100644 --- a/tests/bus_test_correct_3.circom +++ b/tests/bus_test_correct_3.circom @@ -33,7 +33,7 @@ template Main (m,n) { for (var i=0; i Date: Sat, 11 May 2024 19:37:39 +0200 Subject: [PATCH 040/189] fixing a problem reducing type with bus inside bus. --- type_analysis/src/analyzers/type_check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 1348099ba..36a13e76d 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1065,7 +1065,7 @@ fn apply_access_to_symbol( if pos == buses_and_signals.len()-1 { match wire.get_type() { WireType::Signal => {return Result::Ok(SymbolInformation::Signal(current_dim));}, - WireType::Bus(_) => {return Result::Ok(SymbolInformation::Bus(Some(b_name), current_dim))}, + WireType::Bus(b_name2) => {return Result::Ok(SymbolInformation::Bus(Some(b_name2.clone()), current_dim))}, } } else { kind = wire.get_type(); From 55948d422a0ec8400c1d5c6db524822cf14616ad Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 11 May 2024 19:40:53 +0200 Subject: [PATCH 041/189] New error file. --- tests/bus_test_error_4.circom | 42 +++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/tests/bus_test_error_4.circom b/tests/bus_test_error_4.circom index 99f71f437..395e5f43e 100644 --- a/tests/bus_test_error_4.circom +++ b/tests/bus_test_error_4.circom @@ -2,8 +2,46 @@ pragma circom 2.0.0; /* - This code should fail because buses cannot be defined with input or output fields. - Input or output signals can only be defined inside templates. + This code should fail because field accesses and array accesses do not match + with the types and dimensions of the expresions. */ +bus A () { + signal {tag1} a; +} + +bus B { + A b1, b2; +} + +bus C (n) { + A () a; + B () {tag2} b[n]; +} + +bus D (array,m,n) { + A a1; + A {tag3} a2; + B b1[array[0]], b2[array[1]]; + C(m) {tag4} c1[n], c2[n]; +} + +template Main (m,n) { + C(m) input c[n]; + A output {tag1} a; + + var array[2] = [2,4]; + var s = 0; + + D(array,m,n) {tag5} d; + + d.c1[0] <== c; + + for (var i=0; i Date: Sat, 11 May 2024 21:03:43 +0200 Subject: [PATCH 042/189] New error file. --- tests/bus_test_error_5.circom | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/bus_test_error_5.circom diff --git a/tests/bus_test_error_5.circom b/tests/bus_test_error_5.circom new file mode 100644 index 000000000..93f1dec5e --- /dev/null +++ b/tests/bus_test_error_5.circom @@ -0,0 +1,50 @@ +pragma circom 2.0.0; + +/* + + This code should fail because field accesses and array accesses do not match + with the types and dimensions of the expresions. + +*/ + +bus A () { + signal {tag1} a1; + signal {tag2} a2; +} + +bus B { + signal {tag1} b1; + signal {tag2} b2; +} + +bus C { + B b; +} + +template Main () { + signal input in1, in2; + B output busB; + + A busA; + C busC; + + busA.a1 <== in1; + busA.a2 <== busA.a1 + in2 * busA.a1; + + busB <== busA; + + busB.b1 <== busA.a1; + busB.b2 <== busA.a2; + busB.b1 <== busA.a2; + busB.b2 <== busA.a1; + + busC <== busA; + busC.b <== busA; + busB <== busC; + busB <== busC.b; + + busC.b.b1 <== busA.a2 + busC.b.b2; + busB.b2 + busC.b.b2 === busB.b1 + busA.a1; +} + +component main {public [in1, in2]} = Main(); \ No newline at end of file From d51f8902afc3196c0d430839080660dfb3562a9a Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 11 May 2024 21:15:35 +0200 Subject: [PATCH 043/189] Modified bus_test_error_5. --- tests/bus_test_error_5.circom | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/bus_test_error_5.circom b/tests/bus_test_error_5.circom index 93f1dec5e..79c4494b8 100644 --- a/tests/bus_test_error_5.circom +++ b/tests/bus_test_error_5.circom @@ -42,6 +42,8 @@ template Main () { busC.b <== busA; busB <== busC; busB <== busC.b; + busC.b <== busB; + busC.b <-- busC.b; busC.b.b1 <== busA.a2 + busC.b.b2; busB.b2 + busC.b.b2 === busB.b1 + busA.a1; From a5672c9c7b16bfd6e7e8686a8df433f82f312601 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 11 May 2024 21:18:45 +0200 Subject: [PATCH 044/189] Modified bus_test_error_5. --- tests/bus_test_error_5.circom | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/bus_test_error_5.circom b/tests/bus_test_error_5.circom index 79c4494b8..710424cd7 100644 --- a/tests/bus_test_error_5.circom +++ b/tests/bus_test_error_5.circom @@ -2,8 +2,7 @@ pragma circom 2.0.0; /* - This code should fail because field accesses and array accesses do not match - with the types and dimensions of the expresions. + This code should fail because of type mismatches. */ @@ -42,7 +41,7 @@ template Main () { busC.b <== busA; busB <== busC; busB <== busC.b; - busC.b <== busB; + busC.b === busB; busC.b <-- busC.b; busC.b.b1 <== busA.a2 + busC.b.b2; From 862a94a8cdda8ae73aba1c2eb9613f0c721f6600 Mon Sep 17 00:00:00 2001 From: miguelis Date: Sun, 12 May 2024 00:06:31 +0200 Subject: [PATCH 045/189] typos --- program_structure/src/program_library/bus_data.rs | 3 +-- type_analysis/src/analyzers/type_check.rs | 11 ++++------- type_analysis/src/decorators/type_reduction.rs | 4 ++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/program_structure/src/program_library/bus_data.rs b/program_structure/src/program_library/bus_data.rs index ed9b3d7f0..712497854 100644 --- a/program_structure/src/program_library/bus_data.rs +++ b/program_structure/src/program_library/bus_data.rs @@ -1,8 +1,7 @@ +use std::collections::HashMap; use super::ast::{FillMeta, Statement, VariableType, SignalType}; use super::file_definition::{FileID, FileLocation}; use super::wire_data::*; -use std::collections::{HashMap}; -use std::num::IntErrorKind; pub type BusInfo = HashMap; diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 36a13e76d..b27f2afa8 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1,7 +1,6 @@ use super::type_given_function::type_given_function; use super::type_register::TypeRegister; -use num_traits::sign; -use program_structure::{ast::*, template_data}; +use program_structure::ast::*; use program_structure::ast::Expression::Call; use program_structure::environment::CircomEnvironment; use program_structure::error_code::ReportCode; @@ -10,8 +9,7 @@ use program_structure::file_definition::{generate_file_location, FileID}; use program_structure::program_archive::ProgramArchive; use program_structure::wire_data::WireType; use std::collections::HashSet; -use std::fmt::Error; -use std::thread::current; + type ArithmeticType = usize; type ComponentInfo = (Option, ArithmeticType); @@ -218,7 +216,7 @@ fn type_statement( }; let access_information_result = - treat_access(access, meta, program_archive, analysis_information); + treat_access(access, program_archive, analysis_information); let access_information = if let Result::Ok(info) = access_information_result { info @@ -729,7 +727,7 @@ fn type_expression( Variable { name, access, meta, .. } => { debug_assert!(analysis_information.environment.has_symbol(name)); let access_information = - treat_access( access, meta, program_archive, analysis_information)?; + treat_access( access, program_archive, analysis_information)?; let environment = &analysis_information.environment; let reports = &mut analysis_information.reports; let symbol_information = apply_access_to_symbol( @@ -888,7 +886,6 @@ fn treat_sequence_of_statements( type AccessInfo = (ArithmeticType, Option>); fn treat_access( accesses: &[Access], - meta: &Meta, program_archive: &ProgramArchive, analysis_information: &mut AnalysisInformation, ) -> Result { diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index a115260c7..2a5b15d50 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -1,8 +1,8 @@ use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; -use program_structure::program_archive::{self, ProgramArchive}; +use program_structure::program_archive::ProgramArchive; use program_structure::wire_data::WireType; -use program_structure::{ast::*, bus_data}; +use program_structure::ast::*; use program_structure::bus_data::BusData; use program_structure::environment::CircomEnvironment; use program_structure::function_data::FunctionData; From 453f6ef23a56712d1b5c59572ec6a34eb0ad2af5 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 13 May 2024 01:38:25 +0200 Subject: [PATCH 046/189] reducing code --- .../buses_free_of_invalid_statements.rs | 120 ++++-------------- 1 file changed, 24 insertions(+), 96 deletions(-) diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index f0f78403e..436a60d1b 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -29,24 +29,10 @@ fn analyse_statement( match stmt { MultSubstitution { .. } => unreachable!(), IfThenElse { meta, .. } => { - let mut report = Report::error( - "Conditional statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Conditional statement used inside the bus",file_id, None, reports); }, While { meta, .. } => { - let mut report = Report::error( - "Loop statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Loop statement used inside the bus", file_id, None, reports); }, Block { stmts, .. } => { for stmt in stmts.iter() { @@ -67,25 +53,11 @@ fn analyse_statement( analyse_expression(dimension, function_names, reports); } } else { - let mut report = Report::error( - "Template elements declared inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Declaring template element".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Template elements declared inside the bus", file_id, None, reports) } }, _ => { - let mut report = Report::error( - "Template elements declared inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Declaring template element".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Template elements declared inside the bus", file_id, None, reports) } } }, @@ -103,59 +75,36 @@ fn analyse_statement( } } if throw_undefined_bus { - let mut report = Report::error( - "Substitution statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } } ConstraintEquality { meta, .. } => { - let mut report = Report::error( - "Constraint statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Constraint statement used inside the bus", file_id, None, reports); }, LogCall { meta, .. } => { - let mut report = Report::error( - "I/O statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "I/O statement used inside the bus", file_id, None, reports) }, Assert { meta, .. } => { - let mut report = Report::error( - "Assert statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Assert statement used inside the bus", file_id, None, reports) }, Return { meta, .. } => { - let mut report = Report::error( - "Return statement used inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Using invalid statement".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Return statement used inside the bus", file_id, None, reports) }, } } +fn report_undefined_bus_error(meta: &Meta, msg : &str, file_id: usize, primary_msg : Option<&str>, reports: &mut Vec) { + let mut report = Report::error( + msg.to_string(), + ReportCode::UndefinedBus, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + let primary_msg = if let Some(msg) = primary_msg { msg } else {"Using invalid statement"}; + report.add_primary(location, file_id, primary_msg.to_string()); + reports.push(report); +} + fn analyse_expression( expr: &Expression, function_names: &HashSet, @@ -183,14 +132,7 @@ fn analyse_expression( Number(..) => {} Call { meta, id, args, .. } => { if !function_names.contains(id) { - let mut report = Report::error( - format!("Unknown call in bus"), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id.clone(), format!("Is not a function call")); - reports.push(report); + report_undefined_bus_error(meta, "Unknown call in bus", file_id, Some("Is not a function call"), reports) } for arg in args.iter() { analyse_expression(arg, function_names, reports); @@ -206,14 +148,7 @@ fn analyse_expression( analyse_expression(dimension, function_names, reports); } BusCall { meta, .. } => { - let mut report = Report::error( - "Template elements declared inside the bus".to_string(), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id, "Declaring template element".to_string()); - reports.push(report); + report_undefined_bus_error(meta, "Template elements declared inside the bus", file_id, Some("Declaring template element"), reports) }, _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } @@ -230,14 +165,7 @@ fn analyse_access( if let Access::ArrayAccess(index) = acc { analyse_expression(index, function_names, reports); } else { - let mut report = Report::error( - format!("Bus uses component operators"), - ReportCode::UndefinedBus, - ); - let location = - file_definition::generate_file_location(meta.get_start(), meta.get_end()); - report.add_primary(location, file_id.clone(), format!("Template operator found")); - reports.push(report); + report_undefined_bus_error(meta, "Bus uses name-access operators", file_id, Some("Template operator found"), reports) } } } \ No newline at end of file From e935f23b892d2dbe8e33948b7d6a350d37503261 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 13 May 2024 02:15:25 +0200 Subject: [PATCH 047/189] improving some parts and fixing small typos --- .../buses_free_of_invalid_statements.rs | 20 +++++++------------ .../src/analyzers/symbol_analysis.rs | 4 ++-- .../src/analyzers/unknown_known_analysis.rs | 8 +++----- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 436a60d1b..857161dcd 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -61,20 +61,14 @@ fn analyse_statement( } } }, - Substitution { meta, rhe, .. } | UnderscoreSubstitution { meta, rhe, .. } => { - let mut throw_undefined_bus = false; - match rhe { - Expression::BusCall {.. } => {}, - Expression::UniformArray { value, .. } => { - if !value.is_bus_call(){ - throw_undefined_bus = true; - } - }, - _ => { - throw_undefined_bus = true; - } + Substitution { meta, rhe, access, .. } =>{ + if rhe.is_bus_call_array(){ + report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } - if throw_undefined_bus { + analyse_access(access, meta, function_names, reports) + } + UnderscoreSubstitution { meta, rhe, .. } => { + if rhe.is_bus_call_array(){ report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } } diff --git a/type_analysis/src/analyzers/symbol_analysis.rs b/type_analysis/src/analyzers/symbol_analysis.rs index e5da3ccef..94a9ad05e 100644 --- a/type_analysis/src/analyzers/symbol_analysis.rs +++ b/type_analysis/src/analyzers/symbol_analysis.rs @@ -1,4 +1,4 @@ -use program_structure::ast::{Access, Expression, Meta, Statement, LogArgument}; +use program_structure::ast::{Access, Expression, LogArgument, Meta, Statement, VariableType}; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; use program_structure::file_definition::{self, FileID, FileLocation}; @@ -243,7 +243,7 @@ fn analyze_statement( ); reports.push(report); } - if let program_structure::ast::VariableType::Bus(b_name,_,tags ) = xtype { + if let VariableType::Bus(b_name,_,tags ) = xtype { if let Some(bus) = bus_info.get(b_name) { for t in tags { if bus.get_fields().contains_key(t) { diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 8fdc0f3f3..81e825611 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -166,13 +166,11 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma } } TypeReduction::Bus(_) => { - if *op == AssignOp::AssignConstraintSignal { - constraints_declared = true; - } if *op == AssignOp::AssignVar && expression_tag == Unknown { add_report(ReportCode::UnknownBus, meta, file_id, &mut reports); } - if *op == AssignOp::AssignConstraintSignal { + if *op == AssignOp::AssignConstraintSignal { + constraints_declared = true; if is_non_quadratic(rhe, &environment) { add_report(ReportCode::UnknownTemplate, rhe.get_meta(), file_id, &mut reports); } @@ -526,7 +524,7 @@ fn add_report( NonQuadratic => "Non-quadratic constraint was detected statically, using unknown index will cause the constraint to be non-quadratic".to_string(), UnreachableConstraints => "There are constraints depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), UnreachableTags => "There are tag assignments depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), - UnreachableSignals => "There are signal or component declarations depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), + UnreachableSignals => "There are signal, bus or component declarations depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), _ => panic!("Unimplemented error code") }; report.add_primary(location, file_id, message); From 1bc79eba517e0eca0ac983deca86010f6f6dfc7c Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 14 May 2024 10:31:00 +0200 Subject: [PATCH 048/189] Corrected error in buses_free_of_invalid_statements to prevent the definition of constraints inside buses. --- tests/bus_test_error_6.circom | 46 +++++++++++++++++++ .../buses_free_of_invalid_statements.rs | 6 +-- 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/bus_test_error_6.circom diff --git a/tests/bus_test_error_6.circom b/tests/bus_test_error_6.circom new file mode 100644 index 000000000..fc24b11e9 --- /dev/null +++ b/tests/bus_test_error_6.circom @@ -0,0 +1,46 @@ +pragma circom 2.0.0; + +/* + + This code should fail because there are template elements declared inside the bus. + +*/ + +template T () { + signal input in; + signal output out; + + out <== in; +} + +bus A () { + signal a1, a2; + a1 <== 1; + a2 <-- a1; + a2 === a1; + signal array1[2], array2[2]; + array1[0] <== 1; + array1[1] <-- 1; + array1[0] === array1[1]; + array2 <== array1; + array2 <-- array1; + array2 === array1; + component c = T(); + A bus1, bus2; + bus1 <== 1; + bus2 <-- bus1; + bus2 === bus1; + A busArray1[2], busArray2[2]; + busArray1[0] <== 1; + busArray1[0] === busArray1[1]; + busArray2 <== busArray1; + busArray2 <-- busArray1; + busArray2 === busArray1; +} + +template Main () { + signal input in; + A output out; +} + +component main {public [in]} = Main(); \ No newline at end of file diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 857161dcd..4d638deb3 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -61,14 +61,14 @@ fn analyse_statement( } } }, - Substitution { meta, rhe, access, .. } =>{ - if rhe.is_bus_call_array(){ + Substitution { meta, rhe, access, .. } => { + if !rhe.is_bus_call() { report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } analyse_access(access, meta, function_names, reports) } UnderscoreSubstitution { meta, rhe, .. } => { - if rhe.is_bus_call_array(){ + if !rhe.is_bus_call() { report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } } From 63da094092a49823d0689521766ad6243846f519 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 14 May 2024 12:46:42 +0200 Subject: [PATCH 049/189] Added bus syntax to some files of the Circomlib. --- tests/aliascheck_old.circom | 23 --- tests/{ => circomlib}/aliascheck.circom | 26 +-- tests/{ => circomlib}/babyjub.circom | 0 tests/circomlib/binsub.circom | 81 ++++++++++ tests/circomlib/binsum.circom | 103 ++++++++++++ tests/circomlib/bitify.circom | 103 ++++++++++++ tests/circomlib/comparators.circom | 177 +++++++++++++++++++++ tests/circomlib/compconstant.circom | 73 +++++++++ tests/{ => circomlib}/escalarmulfix.circom | 0 tests/{ => circomlib}/montgomery.circom | 0 tests/{ => circomlib}/pedersen.circom | 0 11 files changed, 543 insertions(+), 43 deletions(-) delete mode 100644 tests/aliascheck_old.circom rename tests/{ => circomlib}/aliascheck.circom (67%) rename tests/{ => circomlib}/babyjub.circom (100%) create mode 100644 tests/circomlib/binsub.circom create mode 100644 tests/circomlib/binsum.circom create mode 100644 tests/circomlib/bitify.circom create mode 100644 tests/circomlib/comparators.circom create mode 100644 tests/circomlib/compconstant.circom rename tests/{ => circomlib}/escalarmulfix.circom (100%) rename tests/{ => circomlib}/montgomery.circom (100%) rename tests/{ => circomlib}/pedersen.circom (100%) diff --git a/tests/aliascheck_old.circom b/tests/aliascheck_old.circom deleted file mode 100644 index 8d9413ebe..000000000 --- a/tests/aliascheck_old.circom +++ /dev/null @@ -1,23 +0,0 @@ -pragma circom 2.0.0; - -include "compconstant.circom"; - -bus BinaryNumber { - signal {binary} bits[254]; -} - -template AliasCheck() { - signal input {binary} in[254]; - BinaryNumber output {unique, maxvalue} out; - - component compConstant = CompConstant(-1); - - for (var i=0; i<254; i++) { - in[i] ==> compConstant.in[i]; - in[i] ==> out.bits[i]; - } - - out.maxvalue = (1 << 254) - 1; - - compConstant.out === 0; -} \ No newline at end of file diff --git a/tests/aliascheck.circom b/tests/circomlib/aliascheck.circom similarity index 67% rename from tests/aliascheck.circom rename to tests/circomlib/aliascheck.circom index abf75e9a2..d73f2ba07 100644 --- a/tests/aliascheck.circom +++ b/tests/circomlib/aliascheck.circom @@ -19,27 +19,13 @@ pragma circom 2.0.0; include "compconstant.circom"; - -bus BinaryNumber { - signal {binary} bits[254]; -} +include "bitify.circom"; template AliasCheck() { - signal input {binary} in[254]; - BinaryNumber output {unique} out; - -/* - component compConstant = CompConstant(-1); - - for (var i=0; i<254; i++) { - in[i] ==> compConstant.in[i]; - in[i] ==> out.bits[i]; - } + BinaryNumber(254) input in; + BinaryNumber(254) output {unique} out; - compConstant.out === 0; -*/ - signal out_aux <== CompConstant(-1)(in); - out_aux === 0; - in ==> out.bits; - + signal greater <== CompConstant(-1)(in); + greater === 0; + out <== in; } diff --git a/tests/babyjub.circom b/tests/circomlib/babyjub.circom similarity index 100% rename from tests/babyjub.circom rename to tests/circomlib/babyjub.circom diff --git a/tests/circomlib/binsub.circom b/tests/circomlib/binsub.circom new file mode 100644 index 000000000..42e93831d --- /dev/null +++ b/tests/circomlib/binsub.circom @@ -0,0 +1,81 @@ + /* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ + +/* +This component creates a binary substraction. + + +Main Constraint: + (in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1)) + + + 2^n + - (in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1)) + === + out[0] * 2^0 + out[1] * 2^1 + + out[n-1] *2^(n-1) + aux + + + out[0] * (out[0] - 1) === 0 + out[1] * (out[0] - 1) === 0 + . + . + . + out[n-1] * (out[n-1] - 1) === 0 + aux * (aux-1) == 0 + +*/ +pragma circom 2.0.0; + +include "bitify.circom"; + +template BinSub(n) { + BinaryNumber(n) input in[2]; + BinaryNumber(n) output out; + + signal aux; + + var lin = 2**n; + var lout = 0; + + var i; + var pot = 1; + + for (i=0; i> i) & 1; + + // Ensure out is binary + out.bits[i] * (out.bits[i] - 1) === 0; + + lout = lout + out.bits[i]*pot; + pot *= 2; + } + + aux <-- (lin >> n) & 1; + aux*(aux-1) === 0; + lout = lout + aux*(2**n); + + // Ensure the sum; + lin === lout; +} \ No newline at end of file diff --git a/tests/circomlib/binsum.circom b/tests/circomlib/binsum.circom new file mode 100644 index 000000000..ccf5b03e0 --- /dev/null +++ b/tests/circomlib/binsum.circom @@ -0,0 +1,103 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ + +/* + +Binary Sum +========== + +This component creates a binary sum componet of ops operands and n bits each operand. + +e is Number of carries: Depends on the number of operands in the input. + +Main Constraint: + in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) + + + in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) + + + .. + + in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) + + === + out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1) + +To waranty binary outputs: + + out[0] * (out[0] - 1) === 0 + out[1] * (out[0] - 1) === 0 + . + . + . + out[n+e-1] * (out[n+e-1] - 1) == 0 + + */ + + +/* + This function calculates the number of extra bits in the output to do the full sum. +*/ +pragma circom 2.0.0; + +include "bitify.circom"; + +function nbits(a) { + var n = 1; + var r = 0; + while (n-1> k) & 1; + + // Ensure out is binary + out.bits[k] * (out.bits[k] - 1) === 0; + + lout += out.bits[k] * e2; + + e2 = e2+e2; + } + + // Ensure the sum; + + lin === lout; +} \ No newline at end of file diff --git a/tests/circomlib/bitify.circom b/tests/circomlib/bitify.circom new file mode 100644 index 000000000..018bb746c --- /dev/null +++ b/tests/circomlib/bitify.circom @@ -0,0 +1,103 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "comparators.circom"; +include "aliascheck.circom"; + +bus BinaryNumber(n) { + signal {binary} bits[n]; +} + +template Num2Bits(n) { + signal input in; + BinaryNumber(n) output out; + var lc1=0; + + var e2=1; + for (var i=0; i> i) & 1; + out.bits[i] * (out.bits[i] - 1) === 0; + lc1 += out.bits[i] * e2; + e2 = e2 + e2; + } + + lc1 === in; +} + +template Num2Bits_strict() { + signal input in; + BinaryNumber(254) output {unique} out; + + component aliasCheck = AliasCheck(); + component n2b = Num2Bits(254); + + in ==> n2b.in; + n2b.out ==> aliasCheck.in; + aliasCheck.out ==> out; +} + +template Bits2Num(n) { + BinaryNumber(n) input in; + signal output out; + var lc1=0; + + var e2 = 1; + for (var i=0; i out; +} + +template Bits2Num_strict() { + BinaryNumber(254) input in; + signal output out; + + component aliasCheck = AliasCheck(); + component b2n = Bits2Num(254); + + in ==> aliasCheck.in; + aliasCheck.out ==> b2n.in; + b2n.out ==> out; +} + +template Num2BitsNeg(n) { + signal input in; + BinaryNumber(n) output out; + + component isZero = IsZero(); + + var lc1 = 0; + var pot = 1; + var maxpot = 2**n; + var neg = n == 0 ? 0 : maxpot - in; + + for (var i=0; i> i) & 1; + out.bits[i] * (out.bits[i] - 1) === 0; + lc1 += out.bits[i] * pot; + pot *= 2; + } + + in ==> isZero.in; + + lc1 + isZero.out * maxpot === maxpot - in; +} \ No newline at end of file diff --git a/tests/circomlib/comparators.circom b/tests/circomlib/comparators.circom new file mode 100644 index 000000000..b9cf146c4 --- /dev/null +++ b/tests/circomlib/comparators.circom @@ -0,0 +1,177 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "bitify.circom"; + +bus Pair { + signal s[2]; +} + +template IsZero() { + signal input in; + signal output out; + + signal inv; + + inv <-- in!=0 ? 1/in : 0; + + out <== -in*inv + 1; + in*out === 0; +} + +template ForceZero() { + signal input in; + signal output {zero} out; + + component isz = IsZero(); + + in ==> isz.in; + isz.out === 1; + in ==> out; +} + + +template IsEqual() { + signal input in[2]; + signal output out; + + component isz = IsZero(); + + in[1] - in[0] ==> isz.in; + isz.out ==> out; +} + +template ForceEqual() { + signal input in[2]; + Pair output {equal} out; + + component ise = IsEqual(); + + in ==> ise.in; + ise.out === 1; + in ==> out.s; +} + +template ForceEqualIfEnabled() { + signal input enabled; + signal input in[2]; + + component isz = IsZero(); + + in[1] - in[0] ==> isz.in; + + (1 - isz.out)*enabled === 0; +} + + +// N is the number of bits the input have. +// The MSF is the sign bit. +template LessThan(n) { + assert(n <= 252); + signal input in[2]; + signal output out; + + component n2b = Num2Bits(n+1); + + n2b.in <== in[0] + (1< out; +} + +template ForceLessEqThan(n) { + signal input in[2]; + Pair output {le} out; + + component leq = LessEqThan(n); + leq.in <== in; + leq.out === 1; + out.s <== in; +} + +// N is the number of bits the input have. +// The MSF is the sign bit. +template GreaterThan(n) { + signal input in[2]; + signal output out; + + component lt = LessThan(n); + + lt.in[0] <== in[1]; + lt.in[1] <== in[0]; + lt.out ==> out; +} + +template ForceGreaterThan(n) { + signal input in[2]; + Pair output {gt} out; + + component greaterThan = GreaterThan(n); + greaterThan.in <== in; + greaterThan.out === 1; + out.s <== in; +} + +// N is the number of bits the input have. +// The MSF is the sign bit. +template GreaterEqThan(n) { + signal input in[2]; + signal output out; + + component lt = LessThan(n); + + lt.in[0] <== in[1]; + lt.in[1] <== in[0]+1; + lt.out ==> out; +} + +template ForceGreaterEqThan(n) { + signal input in[2]; + Pair output {ge} out; + + component geq = GreaterEqThan(n); + geq.in <== in; + geq.out === 1; + out.s <== in; +} \ No newline at end of file diff --git a/tests/circomlib/compconstant.circom b/tests/circomlib/compconstant.circom new file mode 100644 index 000000000..1dba37179 --- /dev/null +++ b/tests/circomlib/compconstant.circom @@ -0,0 +1,73 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "bitify.circom"; + +// Returns 1 if in (in binary) > ct + +template CompConstant(ct) { + BinaryNumber(254) input in; + signal output out; + + signal parts[127]; + signal sout; + + var clsb; + var cmsb; + var slsb; + var smsb; + + var sum=0; + + var b = (1 << 128)-1; + var a = 1; + var e = 1; + var i; + + for (i=0; i<127; i++) { + clsb = (ct >> (i*2)) & 1; + cmsb = (ct >> (i*2+1)) & 1; + slsb = in.bits[i*2]; + smsb = in.bits[i*2+1]; + + if ((cmsb==0)&&(clsb==0)) { + parts[i] <== -b*smsb*slsb + b*smsb + b*slsb; + } else if ((cmsb==0)&&(clsb==1)) { + parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a; + } else if ((cmsb==1)&&(clsb==0)) { + parts[i] <== b*smsb*slsb - a*smsb + a; + } else { + parts[i] <== -a*smsb*slsb + a; + } + + sum = sum + parts[i]; + + b = b-e; + a = a+e; + e = e*2; + } + + sout <== sum; + + component num2bits = Num2Bits(135); + + num2bits.in <== sout; + out <== num2bits.out.bits[127]; +} \ No newline at end of file diff --git a/tests/escalarmulfix.circom b/tests/circomlib/escalarmulfix.circom similarity index 100% rename from tests/escalarmulfix.circom rename to tests/circomlib/escalarmulfix.circom diff --git a/tests/montgomery.circom b/tests/circomlib/montgomery.circom similarity index 100% rename from tests/montgomery.circom rename to tests/circomlib/montgomery.circom diff --git a/tests/pedersen.circom b/tests/circomlib/pedersen.circom similarity index 100% rename from tests/pedersen.circom rename to tests/circomlib/pedersen.circom From 65ae38338545304606cde1f57809c3bb49db8c20 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 14 May 2024 13:07:58 +0200 Subject: [PATCH 050/189] Corrected error in buses_free_of_invalid_statements. --- .../src/analyzers/buses_free_of_invalid_statements.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs index 4d638deb3..b5a71dd4f 100644 --- a/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs +++ b/type_analysis/src/analyzers/buses_free_of_invalid_statements.rs @@ -62,13 +62,13 @@ fn analyse_statement( } }, Substitution { meta, rhe, access, .. } => { - if !rhe.is_bus_call() { + if !rhe.is_bus_call_array() { report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } analyse_access(access, meta, function_names, reports) } UnderscoreSubstitution { meta, rhe, .. } => { - if !rhe.is_bus_call() { + if !rhe.is_bus_call_array() { report_undefined_bus_error(meta, "Substitution statement used inside the bus", file_id, None, reports); } } From f1b659b65ff7a0715cb90fd3528684fe8c0434a4 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 14 May 2024 23:40:04 +0200 Subject: [PATCH 051/189] New modified files from the Circomlib. --- tests/circomlib/aliascheck.circom | 2 +- tests/circomlib/babyjub.circom | 17 ++-- tests/circomlib/escalarmulfix.circom | 29 +++---- tests/circomlib/mux1.circom | 48 +++++++++++ tests/circomlib/mux2.circom | 63 ++++++++++++++ tests/circomlib/mux3.circom | 75 +++++++++++++++++ tests/circomlib/mux4.circom | 119 +++++++++++++++++++++++++++ tests/circomlib/pedersen.circom | 27 +++--- 8 files changed, 334 insertions(+), 46 deletions(-) create mode 100644 tests/circomlib/mux1.circom create mode 100644 tests/circomlib/mux2.circom create mode 100644 tests/circomlib/mux3.circom create mode 100644 tests/circomlib/mux4.circom diff --git a/tests/circomlib/aliascheck.circom b/tests/circomlib/aliascheck.circom index d73f2ba07..53a3353e5 100644 --- a/tests/circomlib/aliascheck.circom +++ b/tests/circomlib/aliascheck.circom @@ -28,4 +28,4 @@ template AliasCheck() { signal greater <== CompConstant(-1)(in); greater === 0; out <== in; -} +} \ No newline at end of file diff --git a/tests/circomlib/babyjub.circom b/tests/circomlib/babyjub.circom index 66c750f65..35a79f061 100644 --- a/tests/circomlib/babyjub.circom +++ b/tests/circomlib/babyjub.circom @@ -19,14 +19,11 @@ pragma circom 2.1.5; include "bitify.circom"; -include "escalarmul/escalarmulfix.circom"; +include "montgomery.circom"; +include "escalarmulfix.circom"; // The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) -bus Point { - signal {bn128} x,y; -} - /* *** BabyAdd(): template that receives two points of the Baby Jubjub curve in Edwards form and returns the addition of the points. - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in Edwards form @@ -84,9 +81,9 @@ template BabyDbl() { Point output {babyedwards} pout; component adder = BabyAdd(); + adder.p1 <== pin; adder.p2 <== pin; - adder.pout ==> pout; } @@ -133,7 +130,7 @@ This template is used to extract the public key from the private key. */ template BabyPbk() { - signal input {minvalue,maxvalue} in; + signal input {minvalue, maxvalue} in; Point output {babyedwards} A; @@ -149,10 +146,6 @@ template BabyPbk() { component mulFix = EscalarMulFix(253, BASE8); - var i; - for (i=0; i<253; i++) { - mulFix.e[i] <== pvkBits.out[i]; - } - + mulFix.e <== pvkBits.out; A <== mulFix.out; } \ No newline at end of file diff --git a/tests/circomlib/escalarmulfix.circom b/tests/circomlib/escalarmulfix.circom index cb32f1bd0..7118a2073 100644 --- a/tests/circomlib/escalarmulfix.circom +++ b/tests/circomlib/escalarmulfix.circom @@ -18,9 +18,10 @@ */ pragma circom 2.1.5; -include "../mux3.circom"; -include "../montgomery.circom"; -include "../babyjub.circom"; +include "mux3.circom"; +include "montgomery.circom"; +include "babyjub.circom"; +include "bitify.circom"; /* @@ -37,10 +38,6 @@ include "../babyjub.circom"; A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input is the output of the windows that it's going to be <= 2^246*B */ - -bus Point { - signal {bn128} x,y; -} /* @@ -58,16 +55,14 @@ bus Point { */ template WindowMulFix() { - signal input {binary} in[3]; + BinaryNumber(3) input in; Point input {babymontgomery} base; Point output {babymontgomery} out; Point output {babymontgomery} out8; // Returns 8*Base (To be linked) component mux = MultiMux3(2); - mux.s[0] <== in[0]; - mux.s[1] <== in[1]; - mux.s[2] <== in[2]; + mux.s <== in.bits; component dbl2 = MontgomeryDouble(); component adr3 = MontgomeryAdd(); @@ -149,7 +144,7 @@ template WindowMulFix() { */ template SegmentMulFix(nWindows) { - signal input {binary} e[nWindows*3]; + BinaryNumber(nWindows*3) input e; Point input {babyedwards} base; Point output {babyedwards} out; Point output {babymontgomery} dbl; @@ -180,7 +175,7 @@ template SegmentMulFix(nWindows) { cadders[i].pin1 <== cadders[i-1].pout; } for (j=0; j<3; j++) { - windows[i].in[j] <== e[3*i+j]; + windows[i].in.bits[j] <== e.bits[3*i+j]; } if (i. +*/ +pragma circom 2.0.0; + +template MultiMux1(n) { + signal input c[n][2]; // Constants + signal input s; // Selector + signal output out[n]; + + for (var i=0; i mux.s; + + mux.out[0] ==> out; +} \ No newline at end of file diff --git a/tests/circomlib/mux2.circom b/tests/circomlib/mux2.circom new file mode 100644 index 000000000..31985d7ae --- /dev/null +++ b/tests/circomlib/mux2.circom @@ -0,0 +1,63 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +template MultiMux2(n) { + signal input c[n][4]; // Constants + signal input s[2]; // Selector + signal output out[n]; + + signal a10[n]; + signal a1[n]; + signal a0[n]; + signal a[n]; + + signal s10; + s10 <== s[1] * s[0]; + + for (var i=0; i mux.s[i]; + } + + mux.out[0] ==> out; +} \ No newline at end of file diff --git a/tests/circomlib/mux3.circom b/tests/circomlib/mux3.circom new file mode 100644 index 000000000..6e05d8511 --- /dev/null +++ b/tests/circomlib/mux3.circom @@ -0,0 +1,75 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +template MultiMux3(n) { + signal input c[n][8]; // Constants + signal input s[3]; // Selector + signal output out[n]; + + signal a210[n]; + signal a21[n]; + signal a20[n]; + signal a2[n]; + + signal a10[n]; + signal a1[n]; + signal a0[n]; + signal a[n]; + + // 4 constrains for the intermediary variables + signal s10; + s10 <== s[1] * s[0]; + + for (var i=0; i mux.s[i]; + } + + mux.out[0] ==> out; +} \ No newline at end of file diff --git a/tests/circomlib/mux4.circom b/tests/circomlib/mux4.circom new file mode 100644 index 000000000..29c3285a7 --- /dev/null +++ b/tests/circomlib/mux4.circom @@ -0,0 +1,119 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +template MultiMux4(n) { + signal input c[n][16]; // Constants + signal input s[4]; // Selector + signal output out[n]; + + signal a3210[n]; + signal a321[n]; + signal a320[n]; + signal a310[n]; + signal a32[n]; + signal a31[n]; + signal a30[n]; + signal a3[n]; + + signal a210[n]; + signal a21[n]; + signal a20[n]; + signal a10[n]; + signal a2[n]; + signal a1[n]; + signal a0[n]; + signal a[n]; + + // 4 constrains for the intermediary variables + signal s10; + s10 <== s[1] * s[0]; + signal s20; + s20 <== s[2] * s[0]; + signal s21; + s21 <== s[2] * s[1]; + signal s210; + s210 <== s21 * s[0]; + + + for (var i=0; i mux.s[i]; + } + + mux.out[0] ==> out; +} \ No newline at end of file diff --git a/tests/circomlib/pedersen.circom b/tests/circomlib/pedersen.circom index 23aee509f..2beb6e414 100644 --- a/tests/circomlib/pedersen.circom +++ b/tests/circomlib/pedersen.circom @@ -22,21 +22,15 @@ include "montgomery.circom"; include "mux3.circom"; include "babyjub.circom"; -bus Point { - signal {bn128} x,y; -} - template Window4() { - signal input {binary} in[4]; + BinaryNumber(4) input in; Point input {babymontgomery} base; Point output {babymontgomery} out; Point output {babymontgomery} out8; // Returns 8*Base (To be linked) component mux = MultiMux3(2); - mux.s[0] <== in[0]; - mux.s[1] <== in[1]; - mux.s[2] <== in[2]; + mux.s <== in.bits; component dbl2 = MontgomeryDouble(); component adr3 = MontgomeryAdd(); @@ -52,7 +46,7 @@ template Window4() { mux.c[1][0] <== base.y; // in[1] -> 2*BASE - dbl2.in <== base; + dbl2.pin <== base; mux.c[0][1] <== dbl2.pout.x; mux.c[1][1] <== dbl2.pout.y; @@ -95,12 +89,12 @@ template Window4() { out8 <== adr8.pout; out.x <== mux.out[0]; - out.y <== - mux.out[1]*2*in[3] + mux.out[1]; // Negate y if in[3] is one + out.y <== - mux.out[1]*2*in.bits[3] + mux.out[1]; // Negate y if in[3] is one } template Segment(nWindows) { - signal input {binary} in[nWindows*4]; + BinaryNumber(nWindows*4) input in; Point input {babyedwards} base; Point output {babyedwards} out; @@ -116,10 +110,11 @@ template Segment(nWindows) { component doublers1[nWindows-1]; component doublers2[nWindows-1]; component adders[nWindows-1]; + for (i=0; i Date: Wed, 15 May 2024 17:14:02 +0200 Subject: [PATCH 052/189] Modified new circomlib circuit with buses. Created folders buses and circomlib inside tests. --- tests/{ => buses}/bus_test_correct_1.circom | 0 tests/{ => buses}/bus_test_correct_2.circom | 0 tests/{ => buses}/bus_test_correct_3.circom | 0 tests/{ => buses}/bus_test_error_1.circom | 0 tests/{ => buses}/bus_test_error_2.circom | 0 tests/{ => buses}/bus_test_error_3.circom | 0 tests/{ => buses}/bus_test_error_4.circom | 0 tests/{ => buses}/bus_test_error_5.circom | 0 tests/{ => buses}/bus_test_error_6.circom | 0 tests/circomlib/compconstant.circom | 2 +- tests/circomlib/eddsa.circom | 117 +++++++++++++++ tests/circomlib/pointbits.circom | 151 ++++++++++++++++++++ 12 files changed, 269 insertions(+), 1 deletion(-) rename tests/{ => buses}/bus_test_correct_1.circom (100%) rename tests/{ => buses}/bus_test_correct_2.circom (100%) rename tests/{ => buses}/bus_test_correct_3.circom (100%) rename tests/{ => buses}/bus_test_error_1.circom (100%) rename tests/{ => buses}/bus_test_error_2.circom (100%) rename tests/{ => buses}/bus_test_error_3.circom (100%) rename tests/{ => buses}/bus_test_error_4.circom (100%) rename tests/{ => buses}/bus_test_error_5.circom (100%) rename tests/{ => buses}/bus_test_error_6.circom (100%) create mode 100644 tests/circomlib/eddsa.circom create mode 100644 tests/circomlib/pointbits.circom diff --git a/tests/bus_test_correct_1.circom b/tests/buses/bus_test_correct_1.circom similarity index 100% rename from tests/bus_test_correct_1.circom rename to tests/buses/bus_test_correct_1.circom diff --git a/tests/bus_test_correct_2.circom b/tests/buses/bus_test_correct_2.circom similarity index 100% rename from tests/bus_test_correct_2.circom rename to tests/buses/bus_test_correct_2.circom diff --git a/tests/bus_test_correct_3.circom b/tests/buses/bus_test_correct_3.circom similarity index 100% rename from tests/bus_test_correct_3.circom rename to tests/buses/bus_test_correct_3.circom diff --git a/tests/bus_test_error_1.circom b/tests/buses/bus_test_error_1.circom similarity index 100% rename from tests/bus_test_error_1.circom rename to tests/buses/bus_test_error_1.circom diff --git a/tests/bus_test_error_2.circom b/tests/buses/bus_test_error_2.circom similarity index 100% rename from tests/bus_test_error_2.circom rename to tests/buses/bus_test_error_2.circom diff --git a/tests/bus_test_error_3.circom b/tests/buses/bus_test_error_3.circom similarity index 100% rename from tests/bus_test_error_3.circom rename to tests/buses/bus_test_error_3.circom diff --git a/tests/bus_test_error_4.circom b/tests/buses/bus_test_error_4.circom similarity index 100% rename from tests/bus_test_error_4.circom rename to tests/buses/bus_test_error_4.circom diff --git a/tests/bus_test_error_5.circom b/tests/buses/bus_test_error_5.circom similarity index 100% rename from tests/bus_test_error_5.circom rename to tests/buses/bus_test_error_5.circom diff --git a/tests/bus_test_error_6.circom b/tests/buses/bus_test_error_6.circom similarity index 100% rename from tests/bus_test_error_6.circom rename to tests/buses/bus_test_error_6.circom diff --git a/tests/circomlib/compconstant.circom b/tests/circomlib/compconstant.circom index 1dba37179..3acf3315e 100644 --- a/tests/circomlib/compconstant.circom +++ b/tests/circomlib/compconstant.circom @@ -24,7 +24,7 @@ include "bitify.circom"; template CompConstant(ct) { BinaryNumber(254) input in; - signal output out; + signal output {binary} out; signal parts[127]; signal sout; diff --git a/tests/circomlib/eddsa.circom b/tests/circomlib/eddsa.circom new file mode 100644 index 000000000..ab6ea39ee --- /dev/null +++ b/tests/circomlib/eddsa.circom @@ -0,0 +1,117 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "compconstant.circom"; +include "pointbits.circom"; +include "pedersen.circom"; +include "escalarmulany.circom"; +include "escalarmulfix.circom"; + +template EdDSAVerifier(n) { + BinaryNumber(n) input msg; + BinaryNumber(256) input A; + BinaryNumber(256) input R8; + BinaryNumber(256) input S; + + Point pA; + Point pR8; + + var i; + +// Ensure S compConstant.in.bits[i]; + } + compConstant.out === 0; + S.bits[254] === 0; + S.bits[255] === 0; + +// Convert A to Field elements (And verify A) + + component bits2pointA = Bits2Point_Strict(); + + bits2pointA.in <== A; + pA <== bits2pointA.pout; + +// Convert R8 to Field elements (And verify R8) + + component bits2pointR8 = Bits2Point_Strict(); + + bits2pointR8.in <== R8; + pR8 <== bits2pointR8.pout; + +// Calculate the h = H(R,A, msg) + + component hash = Pedersen(512+n); + + for (i=0; i<256; i++) { + hash.in.bits[i] <== R8.bits[i]; + hash.in.bits[256+i] <== A.bits[i]; + } + for (i=0; i. +*/ +pragma circom 2.0.0; + +include "bitify.circom"; +include "aliascheck.circom"; +include "compconstant.circom"; +include "babyjub.circom"; + + +function sqrt(n) { + + if (n == 0) { + return 0; + } + + // Test that have solution + var res = n ** ((-1) >> 1); +// if (res!=1) assert(false, "SQRT does not exists"); + if (res!=1) return 0; + + var m = 28; + var c = 19103219067921713944291392827692070036145651957329286315305642004821462161904; + var t = n ** 81540058820840996586704275553141814055101440848469862132140264610111; + var r = n ** ((81540058820840996586704275553141814055101440848469862132140264610111+1)>>1); + var sq; + var i; + var b; + var j; + + while ((r != 0)&&(t != 1)) { + sq = t*t; + i = 1; + while (sq!=1) { + i++; + sq = sq*sq; + } + + // b = c ^ m-i-1 + b = c; + for (j=0; j< m-i-1; j ++) b = b*b; + + m = i; + c = b*b; + t = t*c; + r = r*b; + } + + if (r < 0 ) { + r = -r; + } + + return r; +} + + +template Bits2Point() { + BinaryNumber(256) input in; + Point output pout; +} + +template Bits2Point_Strict() { + BinaryNumber(256) input in; + Point output pout; + + var i; + + // Check aliasing + component aliasCheckY = AliasCheck(); + for (i=0; i<254; i++) { + aliasCheckY.in.bits[i] <== in.bits[i]; + } + in.bits[254] === 0; + + component b2nY = Bits2Num(254); + b2nY.in <== aliascheck.out; + pout.y <== b2nY.out; + + var a = 168700; + var d = 168696; + + var y2 = pout.y * pout.y; + + var x = sqrt( (1-y2)/(a - d*y2) ); + + if (in.bits[255] == 1) x = -x; + + pout.x <-- x; + + component babyCheck = BabyCheck(); + babyCheck.pin <== pout; + + component n2bX = Num2Bits(254); + n2bX.in <== pout.x; + + component aliasCheckX = AliasCheck(); + aliasCheckX.in <== n2bX.out; + + component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); + signCalc.in <== n2bX.out; + + signCalc.out === in.bits[255]; +} + + +template Point2Bits() { + Point input pin; + BinaryNumber(256) output out; +} + +template Point2Bits_Strict() { + Point input pin; + BinaryNumber(256) output out; + + var i; + + component n2bX = Num2Bits(254); + n2bX.in <== pin.x; + component n2bY = Num2Bits(254); + n2bY.in <== pin.y; + + component aliasCheckX = AliasCheck(); + component aliasCheckY = AliasCheck(); + aliasCheckX.in <== n2bX.out; + aliasCheckY.in <== n2bY.out; + + component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); + signCalc.in <== aliasCheckX.out; + + for (i=0; i<254; i++) { + out.bits[i] <== n2bY.out.bits[i]; + } + out.bits[254] <== 0; + out.bits[255] <== signCalc.out; +} \ No newline at end of file From 58b45275df620f594d7b7d2718b467f911b0d36c Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Thu, 16 May 2024 13:55:44 +0200 Subject: [PATCH 053/189] Added buses to new circuits of the circomlib library. --- tests/circomlib/escalarmulany.circom | 177 +++++++++++++++++++++++++++ tests/circomlib/pointbits.circom | 2 +- 2 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 tests/circomlib/escalarmulany.circom diff --git a/tests/circomlib/escalarmulany.circom b/tests/circomlib/escalarmulany.circom new file mode 100644 index 000000000..6c2b5bdb2 --- /dev/null +++ b/tests/circomlib/escalarmulany.circom @@ -0,0 +1,177 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "montgomery.circom"; +include "babyjub.circom"; +include "comparators.circom"; + +template Multiplexor2() { + signal input sel; + signal input in[2][2]; + signal output out[2]; + + out[0] <== (in[1][0] - in[0][0])*sel + in[0][0]; + out[1] <== (in[1][1] - in[0][1])*sel + in[0][1]; +} + +template BitElementMulAny() { + signal input sel; + Point input {babymontgomery} dblIn; + Point input {babymontgomery} addIn; + Point output {babymontgomery} dblOut; + Point output {babymontgomery} addOut; + + component doubler = MontgomeryDouble(); + component adder = MontgomeryAdd(); + component selector = Multiplexor2(); + + + sel ==> selector.sel; + + dblIn ==> doubler.pin; + doubler.pout ==> adder.pin1; + addIn ==> adder.pin2; + addIn.x ==> selector.in[0][0]; + addIn.y ==> selector.in[0][1]; + adder.pout.x ==> selector.in[1][0]; + adder.pout.y ==> selector.in[1][1]; + + doubler.pout ==> dblOut; + selector.out[0] ==> addOut.x; + selector.out[1] ==> addOut.y; +} + +// pin is edwards point +// n must be <= 248 +// returns pout in twisted edwards +// dbl is in montgomery to be linked; + +template SegmentMulAny(n) { + BinaryNumber(n) input e; + Point input {babyedwards} pin; + Point output {babyedwards} pout; + Point output {babymontgomery} dbl; + + component bits[n-1]; + + component e2m = Edwards2Montgomery(); + + pin ==> e2m.pin; + + var i; + + bits[0] = BitElementMulAny(); + e2m.pout ==> bits[0].dblIn; + e2m.pout ==> bits[0].addIn; + e.bits[1] ==> bits[0].sel; + + for (i=1; i bits[i].dblIn; + bits[i-1].addOut ==> bits[i].addIn; + e.bits[i+1] ==> bits[i].sel; + } + + bits[n-2].dblOut ==> dbl; + + component m2e = Montgomery2Edwards(); + + bits[n-2].addOut ==> m2e.pin; + + component eadder = BabyAdd(); + + m2e.pout ==> eadder.p1; + -pin.x ==> eadder.p2.x; + pin.y ==> eadder.p2.y; + + component lastSel = Multiplexor2(); + + e.bits[0] ==> lastSel.sel; + eadder.pout.x ==> lastSel.in[0][0]; + eadder.pout.y ==> lastSel.in[0][1]; + m2e.pout.x ==> lastSel.in[1][0]; + m2e.pout.y ==> lastSel.in[1][1]; + + lastSel.out[0] ==> pout.x; + lastSel.out[1] ==> pout.y; +} + +// This function assumes that p is in the subgroup and it is different to 0 + +template EscalarMulAny(n) { + BinaryNumber(n) input e; // Input in binary format + Point input {babyedwards} pin; // Point (Twisted format) + Point output {babyedwards} pout; // Point (Twisted format) + + var nsegments = (n-1)\148 +1; + var nlastsegment = n - (nsegments-1)*148; + + component segments[nsegments]; + component doublers[nsegments-1]; + component m2e[nsegments-1]; + component adders[nsegments-1]; + component zeropoint = IsZero(); + zeropoint.in <== pin.x; + + var s; + var i; + var nseg; + + for (s=0; s segments[s].e.bits[i]; + } + + if (s==0) { + // force G8 point if input point is zero + segments[s].pin.x <== pin.x + (5299619240641551281634865583518297030282874472190772894086521144482721001553 - pin.x)*zeropoint.out; + segments[s].pin.y <== pin.y + (16950150798460657717958625567821834550301663161624707787222815936182638968203 - pin.y)*zeropoint.out; + } else { + doublers[s-1] = MontgomeryDouble(); + m2e[s-1] = Montgomery2Edwards(); + adders[s-1] = BabyAdd(); + + segments[s-1].dbl ==> doublers[s-1].pin; + doublers[s-1].pout ==> m2e[s-1].pin; + m2e[s-1].pout ==> segments[s].pin; + + if (s==1) { + segments[s-1].pout ==> adders[s-1].p1; + } else { + adders[s-2].pout ==> adders[s-1].p1; + } + segments[s].pout ==> adders[s-1].p2; + } + } + + if (nsegments == 1) { + segments[0].pout.x*(1-zeropoint.out) ==> pout.x; + segments[0].pout.y+(1-segments[0].pout.y)*zeropoint.out ==> pout.y; + } else { + adders[nsegments-2].pout.x*(1-zeropoint.out) ==> pout.x; + adders[nsegments-2].pout.y+(1-adders[nsegments-2].pout.y)*zeropoint.out ==> pout.y; + } +} \ No newline at end of file diff --git a/tests/circomlib/pointbits.circom b/tests/circomlib/pointbits.circom index 5c03c62b0..512b49f97 100644 --- a/tests/circomlib/pointbits.circom +++ b/tests/circomlib/pointbits.circom @@ -89,7 +89,7 @@ template Bits2Point_Strict() { in.bits[254] === 0; component b2nY = Bits2Num(254); - b2nY.in <== aliascheck.out; + b2nY.in <== aliasCheckY.out; pout.y <== b2nY.out; var a = 168700; From 8ef16b1159f06639f3ece97d6851fdb820b7a58b Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 16 May 2024 15:38:08 +0200 Subject: [PATCH 054/189] finished execute_bus --- .../environment_utils/bus_representation.rs | 101 ++++++++++++++---- constraint_generation/src/execute.rs | 70 +++++++++++- .../src/abstract_syntax_tree/ast.rs | 6 +- 3 files changed, 152 insertions(+), 25 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 7e8362ba9..85435c0a0 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,4 +1,4 @@ -use super::slice_types::{FieldTypes, MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo}; +use super::slice_types::{AExpressionSlice, FieldTypes, MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo}; use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; @@ -87,34 +87,95 @@ impl BusRepresentation { Result::Ok(()) } - pub fn get_signal_field( + pub fn get_field_signal( &self, field_name: &str, - access: Option>, - ) -> Result<(&TagInfo, &FieldTypes), MemoryError> { + remaining_access: &AccessingInformationBus + ) -> Result<(&TagInfo, &SignalSlice), MemoryError> { + + let field = self.fields.get(field_name).unwrap(); + let field_tags = self.field_tags.get(field_name).unwrap(); + if remaining_access.field_access.is_some(){ + // we are still considering a bus + assert!(field.bus.is_some()); + let bus_slice = field.bus.as_ref().unwrap(); + + let memory_response = BusSlice::access_values( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.get_field_signal( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap()); + } + Result::Err(err)=>{ + return Err(err); + } + } + + unreachable!() + } else{ + if field.signal.is_some(){ + // Case it is just a signal or an array of signals, + // in this case there is no need for recursion + let signals = field.signal.as_ref().unwrap(); + assert!(remaining_access.field_access.is_none()); + Ok((field_tags, signals)) + } else{ + unreachable!("should not enter here") + } + } + + // Returns the tags and a SignalSlice with true/false values + } + + pub fn get_field_bus( + &self, + field_name: &str, + remaining_access: &AccessingInformationBus + ) -> Result<(&TagInfo, &BusSlice), MemoryError> { let field = self.fields.get(field_name).unwrap(); let field_tags = self.field_tags.get(field_name).unwrap(); - match access{ - None => { - Ok((field_tags, field)) + if remaining_access.field_access.is_some(){ + // we are still considering an intermediate bus + assert!(field.bus.is_some()); + let bus_slice = field.bus.as_ref().unwrap(); + + let memory_response = BusSlice::access_values( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.get_field_bus( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap()); + } + Result::Err(err)=>{ + return Err(err); + } } - Some(access) =>{ - let memory_response = MemorySlice::access_values(&field, &access_information.array_access); - let bus_slice = treat_result_with_memory_error( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - Ok((field_tags, field)) + + unreachable!() + } else{ + if field.bus.is_some(){ + // Case it is the final array of buses that we must return + let buses = field.bus.as_ref().unwrap(); + Ok((field_tags, buses)) + } else{ + unreachable!("should not enter here") } } - - // Devuelve las tags y la SignalSlice con los valores - // Si es un bus, llamar a que cada uno devuelva todo (get_all_fields) - //unreachable!() } pub fn has_unassigned_fields(&self) -> bool{ diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 1427dc144..5e404f57a 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1824,6 +1824,22 @@ fn create_symbol(symbol: &str, access_information: &AccessingInformation) -> Str format!("{}{}", symbol, appendix) } +fn create_symbol_bus(symbol: &str, access_information: &AccessingInformationBus) -> String { + let mut appendix = symbol.to_string(); + let bf_field = create_index_appendix(&access_information.array_access); + appendix.push_str(&bf_field); + if let Option::Some(field) = &access_information.field_access { + let field = format!(".{}", field); + appendix.push_str(&field); + } + if let Option::Some(after_field) = &access_information.remaining_access { + create_symbol_bus(&appendix, after_field) + } else{ + appendix + } +} + + fn create_index_appendix(indexing: &[usize]) -> String { let mut appendix = "".to_string(); for index in indexing { @@ -2095,15 +2111,53 @@ fn execute_bus( } else{ // Case we are accessing a field of the bus - let resulting_component = safe_unwrap_to_single(bus_slice, line!()); + let resulting_bus = safe_unwrap_to_single(bus_slice, line!()); + let symbol = create_symbol_bus(symbol, &access_information); + if meta.get_type_knowledge().is_bus(){ // Case we return a bus + + Result::Ok(FoldedValue{..FoldedValue::default()}) + } else if meta.get_type_knowledge().is_signal(){ // Case we return a signal - let access_result = resulting_component.get_signal_field(&access_information.field_access.unwrap(), access_information.remaining_access); + + let (tags_signal, signal) = treat_result_with_memory_error( + resulting_bus.get_field_signal( + access_information.field_access.as_ref().unwrap(), + access_information.remaining_access.as_ref().unwrap() + ), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let final_array_access = get_final_array_access_bus_accessing(&access_information); + + let slice = SignalSlice::access_values(signal, final_array_access); + let slice = treat_result_with_memory_error( + slice, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let result = signal_to_arith(symbol, slice) + .map(|s| FoldedValue { + arithmetic_slice: Option::Some(s), + tags: Option::Some(tags_signal.clone()), + ..FoldedValue::default() + }); + treat_result_with_memory_error( + result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + ) + } + else{ + unreachable!() } - Ok(FoldedValue{..FoldedValue::default()}) } } @@ -2688,6 +2742,14 @@ fn treat_accessing_bus( } +pub fn get_final_array_access_bus_accessing(access: &AccessingInformationBus)->&Vec{ + let mut last_access = access; + while last_access.field_access.is_some(){ + last_access = &last_access.remaining_access.as_ref().unwrap(); + } + &last_access.array_access +} + //************************************************* Safe transformations ************************************************* @@ -2849,7 +2911,7 @@ fn treat_result_with_memory_error_void( } } -fn treat_result_with_memory_error( +pub fn treat_result_with_memory_error( memory_error: Result, meta: &Meta, runtime_errors: &mut ReportCollection, diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 588676243..44b8b8b38 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -457,7 +457,11 @@ impl TypeKnowledge { self.get_reduces_to() == TypeReduction::Tag } pub fn is_bus(&self) -> bool { - self.get_reduces_to() == TypeReduction::Bus + if let TypeReduction::Component(_) = self.get_reduces_to() { + true + } else { + false + } } } From 3787fc9d21383d46e127c8f870ced4a3103d8e79 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Fri, 17 May 2024 17:36:54 +0200 Subject: [PATCH 055/189] New circuits from the circomlib modified. --- tests/circomlib/sign.circom | 33 ++++++++++++++++++++++++++ tests/circomlib/switcher.circom | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/circomlib/sign.circom create mode 100644 tests/circomlib/switcher.circom diff --git a/tests/circomlib/sign.circom b/tests/circomlib/sign.circom new file mode 100644 index 000000000..8f4bdb5c6 --- /dev/null +++ b/tests/circomlib/sign.circom @@ -0,0 +1,33 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ +pragma circom 2.0.0; + +include "compconstant.circom"; + +template Sign() { + BinaryNumber(254) input in; + signal output sign; + + component comp = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); + + var i; + + comp.in <== in; + sign <== comp.out; +} \ No newline at end of file diff --git a/tests/circomlib/switcher.circom b/tests/circomlib/switcher.circom new file mode 100644 index 000000000..cc102be42 --- /dev/null +++ b/tests/circomlib/switcher.circom @@ -0,0 +1,42 @@ +/* + Copyright 2018 0KIMS association. + + This file is part of circom (Zero Knowledge Circuit Compiler). + + circom is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + circom is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with circom. If not, see . +*/ + +/* + Assume sel is binary. + + If sel == 0 then outL = L and outR=R + If sel == 1 then outL = R and outR=L + + */ + +pragma circom 2.0.0; + +template Switcher() { + signal input {binary} sel; + signal input L; + signal input R; + signal output outL; + signal output outR; + + signal aux; + + aux <== (R-L)*sel; // We create aux in order to have only one multiplication + outL <== aux + L; + outR <== -aux + R; +} \ No newline at end of file From b030cfef08a994097d60a44efb31658cad1125da Mon Sep 17 00:00:00 2001 From: clararod9 Date: Sat, 18 May 2024 11:41:15 +0200 Subject: [PATCH 056/189] cambios --- .../environment_utils/bus_representation.rs | 165 ++++++++++++------ .../src/environment_utils/slice_types.rs | 6 +- constraint_generation/src/execute.rs | 84 +++++++-- program_structure/src/utils/memory_slice.rs | 2 + 4 files changed, 186 insertions(+), 71 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 85435c0a0..bb3315278 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -56,7 +56,7 @@ impl BusRepresentation { component.unassigned_fields .insert(symbol.clone(), signal_slice_size); } - let field_signal = FieldTypes{signal: Some(signal_slice), bus:None}; + let field_signal = FieldTypes::Signal(signal_slice); component.fields.insert(symbol.clone(), field_signal); } @@ -77,7 +77,7 @@ impl BusRepresentation { component.unassigned_fields .insert(symbol.clone(), bus_slice_size); } - let field_bus = FieldTypes{bus: Some(bus_slice), signal:None}; + let field_bus = FieldTypes::Bus(bus_slice); component.fields.insert(symbol.clone(), field_bus); } @@ -91,44 +91,48 @@ impl BusRepresentation { &self, field_name: &str, remaining_access: &AccessingInformationBus - ) -> Result<(&TagInfo, &SignalSlice), MemoryError> { + ) -> Result<(TagInfo, SignalSlice), MemoryError> { + // TODO: REMOVE CLONE let field = self.fields.get(field_name).unwrap(); let field_tags = self.field_tags.get(field_name).unwrap(); if remaining_access.field_access.is_some(){ // we are still considering a bus - assert!(field.bus.is_some()); - let bus_slice = field.bus.as_ref().unwrap(); - - let memory_response = BusSlice::access_values( - &bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let resulting_bus = - BusSlice::unwrap_to_single(bus_slice); - resulting_bus.get_field_signal( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap()); - } - Result::Err(err)=>{ - return Err(err); + match field{ + FieldTypes::Bus(bus_slice)=>{ + + let memory_response = BusSlice::access_values( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.get_field_signal( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap() + ) + } + Result::Err(err)=>{ + return Err(err); + } + } } + FieldTypes::Signal(_) => unreachable!(), } - - unreachable!() + } else{ - if field.signal.is_some(){ - // Case it is just a signal or an array of signals, - // in this case there is no need for recursion - let signals = field.signal.as_ref().unwrap(); - assert!(remaining_access.field_access.is_none()); - Ok((field_tags, signals)) - } else{ - unreachable!("should not enter here") - } + match field{ + FieldTypes::Signal(signals) =>{ + // Case it is just a signal or an array of signals, + // in this case there is no need for recursion + assert!(remaining_access.field_access.is_none()); + Ok((field_tags.clone(), signals.clone())) + } + FieldTypes::Bus(_) => unreachable!(), + } } // Returns the tags and a SignalSlice with true/false values @@ -138,42 +142,45 @@ impl BusRepresentation { &self, field_name: &str, remaining_access: &AccessingInformationBus - ) -> Result<(&TagInfo, &BusSlice), MemoryError> { - + ) -> Result<(TagInfo, BusSlice), MemoryError> { + // TODO: REMOVE CLONE let field = self.fields.get(field_name).unwrap(); let field_tags = self.field_tags.get(field_name).unwrap(); if remaining_access.field_access.is_some(){ // we are still considering an intermediate bus - assert!(field.bus.is_some()); - let bus_slice = field.bus.as_ref().unwrap(); + match field{ + FieldTypes::Bus(bus_slice)=>{ - let memory_response = BusSlice::access_values( + let memory_response = BusSlice::access_values( &bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let resulting_bus = - BusSlice::unwrap_to_single(bus_slice); - resulting_bus.get_field_bus( + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.get_field_bus( remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap()); - } - Result::Err(err)=>{ - return Err(err); + &remaining_access.remaining_access.as_ref().unwrap()) + } + Result::Err(err)=>{ + return Err(err); + } } } - - unreachable!() + FieldTypes::Signal(_) => unreachable!(), + } } else{ - if field.bus.is_some(){ - // Case it is the final array of buses that we must return - let buses = field.bus.as_ref().unwrap(); - Ok((field_tags, buses)) - } else{ - unreachable!("should not enter here") + match field{ + FieldTypes::Bus(buses) =>{ + // Case it is the final array of buses that we must return + + assert!(remaining_access.field_access.is_none()); + Ok((field_tags.clone(), buses.clone())) + } + FieldTypes::Signal(_) => unreachable!(), } } } @@ -193,6 +200,50 @@ impl BusRepresentation { unreachable!() } + pub fn get_accesses_bus(&self, name: &String) -> Vec{ + + fn unfold_signals(current: String, dim: usize, lengths: &[usize], result: &mut Vec) { + if dim == lengths.len() { + result.push(current); + } else { + for i in 0..lengths[dim] { + unfold_signals(format!("{}[{}]", current, i), dim + 1, lengths, result) + } + } + } + + let mut result = Vec::new(); + for field in &self.fields{ + match field{ + (field_name, FieldTypes::Bus(bus_slice)) => { + let accessed_name = format!("{}.{}", name, field_name); + let dims = bus_slice.route(); + let mut prefixes = Vec::new(); + unfold_signals(accessed_name, 0, dims, &mut prefixes); + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + let access = BusSlice::access_value_by_index(&bus_slice, i); + + match access{ + Ok(bus) =>{ + let mut result_field = bus.get_accesses_bus(&prefixes[i]); + result.append(&mut result_field); + } + Err(_) =>{ + unreachable!() + } + } + } + } + (field_name, FieldTypes::Signal(signal_slice)) =>{ + let accessed_name = format!("{}.{}", name, field_name); + let dims = signal_slice.route(); + unfold_signals(accessed_name, 0, dims, &mut result); + } + } + } + result + } + } diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index 4595b960e..fe15ae070 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -24,8 +24,8 @@ pub type BusSlice = MemorySlice; // To store the fields of a bus #[derive(Clone)] -pub struct FieldTypes { // For each field, we store the info depending on if it is a signal o a bus +pub enum FieldTypes { // For each field, we store the info depending on if it is a signal o a bus // Depending on the case we store a different slice - pub signal: Option, - pub bus: Option, + Signal(SignalSlice), + Bus(BusSlice), } \ No newline at end of file diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 5e404f57a..481e9ec2d 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -646,6 +646,7 @@ fn execute_bus_statement( } } Substitution { meta, var, access, op, rhe, .. } => { + // different access information depending if bus or other variable let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; let r_folded = execute_expression(rhe, program_archive, runtime, flags)?; let _possible_constraint = @@ -1066,11 +1067,18 @@ struct Constrained { left: String, right: AExpressionSlice, } + +struct TypesAccess{ + bus_access: Option, + other_access: Option, +} + + fn perform_assign( meta: &Meta, symbol: &str, op: AssignOp, - accessing_information: &AccessingInformation, + accessing_information: &TypesAccess, r_folded: FoldedValue, actual_node: &mut ExecutedStructure, runtime: &mut RuntimeInformation, @@ -1078,10 +1086,17 @@ fn perform_assign( flags: FlagsExecution ) -> Result, ()> { use super::execution_data::type_definitions::{SubComponentData, BusData}; - let full_symbol = create_symbol(symbol, &accessing_information); + if accessing_information.bus_access.is_some(){ + let full_symbol = create_symbol_bus(symbol, &accessing_information.bus_access.unwrap()); + + } else{ + let full_symbol = create_symbol(symbol, &accessing_information.other_access.unwrap()); + } + let possible_arithmetic_slice = if ExecutionEnvironment::has_variable(&runtime.environment, symbol) { + let accessing_information = accessing_information.other_access.unwrap(); debug_assert!(accessing_information.signal_access.is_none()); debug_assert!(accessing_information.after_signal.is_empty()); let environment_result = ExecutionEnvironment::get_mut_variable_mut(&mut runtime.environment, symbol); @@ -1135,8 +1150,10 @@ fn perform_assign( } } Option::None - } else if ExecutionEnvironment::has_signal(&runtime.environment, symbol) && - accessing_information.signal_access.is_some() { + } else if ExecutionEnvironment::has_signal(&runtime.environment, symbol){ + let accessing_information = accessing_information.other_access.unwrap(); + if accessing_information.signal_access.is_some() { + // it is a tag if ExecutionEnvironment::has_input(&runtime.environment, symbol) { treat_result_with_memory_error( Result::Err(MemoryError::AssignmentTagInput), @@ -1201,7 +1218,8 @@ fn perform_assign( unreachable!() } Option::None - } else if ExecutionEnvironment::has_signal(&runtime.environment, symbol) { + }else { + // it is just a signal debug_assert!(accessing_information.signal_access.is_none()); debug_assert!(accessing_information.after_signal.is_empty()); @@ -1393,7 +1411,9 @@ fn perform_assign( )?; Option::Some(r_slice) - } else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { + }} + else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { + let accessing_information = accessing_information.other_access.unwrap(); if accessing_information.tag_access.is_some() { unreachable!() } @@ -1618,13 +1638,15 @@ fn perform_assign( &runtime.call_trace, )?; + let accessing_information = accessing_information.bus_access.unwrap(); + if FoldedValue::valid_bus_node_pointer(&r_folded){ // in this case we are performing an assigment of the type in the node_pointer // to the bus in the left let bus_pointer = r_folded.bus_node_pointer.unwrap(); - debug_assert!(accessing_information.before_signal.len() == 0); - debug_assert!(accessing_information.signal_access.is_none()); + debug_assert!(accessing_information.array_access.len() == 0); + debug_assert!(accessing_information.field_access.is_none()); @@ -2050,7 +2072,7 @@ fn execute_bus( tags_propagated.insert(tag.clone(), None); } } - // Check that all the buses are completely assigned? + // Check that all the buses are completely assigned for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let value_left = treat_result_with_memory_error( @@ -2117,9 +2139,49 @@ fn execute_bus( if meta.get_type_knowledge().is_bus(){ // Case we return a bus + + let (tags_bus, bus) = treat_result_with_memory_error( + resulting_bus.get_field_bus( + access_information.field_access.as_ref().unwrap(), + access_information.remaining_access.as_ref().unwrap() + ), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let final_array_access = get_final_array_access_bus_accessing(&access_information); - Result::Ok(FoldedValue{..FoldedValue::default()}) + let slice = BusSlice::access_values(&bus, final_array_access); + let slice = treat_result_with_memory_error( + slice, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + // Check that all the buses are completely assigned + for i in 0..BusSlice::get_number_of_cells(&slice){ + let value_left = treat_result_with_memory_error( + BusSlice::access_value_by_index(&slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + if value_left.has_unassigned_fields(){ + treat_result_with_memory_error( + Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } + } + + Result::Ok(FoldedValue{bus_slice: Some(slice), tags: Some(tags_bus.clone()), ..FoldedValue::default()}) + } else if meta.get_type_knowledge().is_signal(){ // Case we return a signal @@ -2135,7 +2197,7 @@ fn execute_bus( let final_array_access = get_final_array_access_bus_accessing(&access_information); - let slice = SignalSlice::access_values(signal, final_array_access); + let slice = SignalSlice::access_values(&signal, final_array_access); let slice = treat_result_with_memory_error( slice, meta, diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 29ee8a749..f0c74670e 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -350,9 +350,11 @@ impl MemorySlice { let mut memory_slice = memory_slice; memory_slice.values.pop().unwrap() } + pub fn destruct(self) -> (Vec, Vec) { (self.route, self.values) } + } #[cfg(test)] From 914f2b169ab3e9cb08ea662176fb53b40b342aca Mon Sep 17 00:00:00 2001 From: miguelis Date: Sun, 19 May 2024 06:21:24 -0700 Subject: [PATCH 057/189] executed template and more --- .../component_representation.rs | 52 +++++++++- .../src/execution_data/executed_bus.rs | 8 +- .../src/execution_data/executed_program.rs | 2 +- .../src/execution_data/executed_template.rs | 95 +++++++++++++++---- 4 files changed, 131 insertions(+), 26 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 3d6505466..ab16ff4e1 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -9,11 +9,15 @@ pub struct ComponentRepresentation { pub is_parallel: bool, pub meta: Option, unassigned_inputs: HashMap, + unassigned_input_buses: HashMap, unassigned_tags: HashSet, to_assign_inputs: Vec<(String, Vec, Vec)>, + to_assign_input_buses: Vec<(String, Vec, Vec)>, inputs: HashMap, + input_buses: HashMap, pub inputs_tags: BTreeMap, outputs: HashMap, + output_buses: HashMap, pub outputs_tags: BTreeMap, pub is_initialized: bool, } @@ -32,6 +36,10 @@ impl Default for ComponentRepresentation { outputs_tags: BTreeMap::new(), is_initialized: false, meta: Option::None, + unassigned_input_buses: HashMap::new(), + to_assign_input_buses: Vec::new(), + input_buses: HashMap::new(), + output_buses: HashMap::new(), } } } @@ -49,6 +57,10 @@ impl Clone for ComponentRepresentation { outputs_tags: self.outputs_tags.clone(), is_initialized: self.is_initialized, meta : self.meta.clone(), + unassigned_input_buses: self.unassigned_input_buses.clone(), + to_assign_input_buses: self.to_assign_input_buses.clone(), + input_buses: self.input_buses.clone(), + output_buses: self.output_buses.clone(), } } } @@ -103,6 +115,10 @@ impl ComponentRepresentation { is_initialized: false, is_parallel, meta: Some(meta.clone()), + unassigned_input_buses: HashMap::new(), + to_assign_input_buses: Vec::new(), + input_buses: HashMap::new(), + output_buses: HashMap::new(), }; Result::Ok(()) } @@ -127,9 +143,17 @@ impl ComponentRepresentation { component.inputs.insert(symbol.clone(), signal_slice); } - for (symbol, route) in node.outputs() { - component.outputs.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); - + for (symbol, route) in node.bus_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{ + component.unassigned_input_buses + .insert(symbol.clone(), signal_slice_size); + } + component.input_buses.insert(symbol.clone(), signal_slice); + } + + fn insert_tags_output(node: &crate::execution_data::ExecutedTemplate, symbol: &String, component: &mut ComponentRepresentation) { let tags_output = node.signal_to_tags.get(symbol); let component_tags_output = component.outputs_tags.get_mut(symbol); if tags_output.is_some() && component_tags_output.is_some(){ @@ -143,13 +167,31 @@ impl ComponentRepresentation { } } } + + for (symbol, route) in node.outputs() { + component.outputs.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); + insert_tags_output(node, symbol, component); + } + + for (symbol, route) in node.bus_outputs() { + component.output_buses.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); + insert_tags_output(node, symbol, component); + } + component.node_pointer = Option::Some(node_pointer); + let to_assign = component.to_assign_inputs.clone(); + for s in to_assign{ + let tags_input = component.inputs_tags.get(&s.0).unwrap(); + ComponentRepresentation::assign_value_to_signal_init(component, &s.0, &s.1, &s.2, tags_input.clone())?; + } + let to_assign = component.to_assign_input_buses.clone(); for s in to_assign{ let tags_input = component.inputs_tags.get(&s.0).unwrap(); ComponentRepresentation::assign_value_to_signal_init(component, &s.0, &s.1, &s.2, tags_input.clone())?; } + Result::Ok(()) } /* @@ -364,7 +406,9 @@ impl ComponentRepresentation { } pub fn has_unassigned_inputs(&self) -> bool{ - !self.unassigned_inputs.is_empty() + !self.unassigned_inputs.is_empty() || !self.unassigned_input_buses.is_empty() } } + + diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index 20587eea4..e023231d6 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -10,10 +10,10 @@ use crate::execution_data::TagInfo; pub struct BusConnexion{ - full_name: String, + pub full_name: String, pub inspect: BusData, - dag_offset: usize, - dag_jump: usize, + pub dag_offset: usize, + pub dag_jump: usize, } @@ -25,6 +25,7 @@ pub struct ExecutedBus { pub parameter_instances: ParameterContext, pub signal_to_tags: TagContext, pub bus_connexions: HashMap, + pub size: usize, } impl ExecutedBus { @@ -41,6 +42,7 @@ impl ExecutedBus { bus_fields: Vec::new(), signal_to_tags: TagContext::new(), bus_connexions: HashMap::new(), + size: 0, } } diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index f965ac252..80cd4689a 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -176,7 +176,7 @@ impl ExecutedProgram { } for exe in &mut self.model { - exe.insert_in_dag(&mut dag); + exe.insert_in_dag(&mut dag, &self.model_buses); } for exe in self.model { diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index cc79ab745..3e8883715 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -1,4 +1,6 @@ +use super::executed_bus::BusConnexion; use super::type_definitions::*; +use super::ExecutedBus; use circom_algebra::algebra::ArithmeticExpression; use compiler::hir::very_concrete_program::*; use dag::DAG; @@ -18,14 +20,6 @@ struct Connexion { dag_component_jump: usize, } -struct BusConnexion{ - full_name: String, - inspect: BusData, - dag_offset: usize, - dag_jump: usize, -} - - #[derive(Clone)] pub struct PreExecutedTemplate { pub template_name: String, @@ -246,7 +240,19 @@ impl ExecutedTemplate { &self.intermediates } - pub fn insert_in_dag(&mut self, dag: &mut DAG) { + pub fn bus_inputs(&self) -> &BusCollector { + &self.bus_inputs + } + + pub fn bus_outputs(&self) -> &BusCollector { + &self.bus_outputs + } + + pub fn bus_intermediates(&self) -> &BusCollector { + &self.bus_intermediates + } + + pub fn insert_in_dag(&mut self, dag: &mut DAG, buses_info : &Vec) { let parameters = { let mut parameters = vec![]; for (_, data) in self.parameter_instances.clone() { @@ -265,38 +271,62 @@ impl ExecutedTemplate { self.is_parallel, self.is_custom_gate ); - self.build_signals(dag); + self.build_wires(dag, buses_info); self.build_connexions(dag); self.build_constraints(dag); } - fn build_signals(&self, dag: &mut DAG) { + fn build_wires(&self, dag: &mut DAG, buses_info : &Vec) { for (name, dim) in self.outputs() { - let state = State { name: name.clone(), dim: 0 }; + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; let config = SignalConfig { signal_type: 1, dimensions: dim, is_public: false }; generate_symbols(dag, state, &config); } + for (name, dim) in self.bus_outputs() { + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 1, dimensions: dim, is_public: false }; + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } for (name, dim) in self.inputs() { if self.public_inputs.contains(name) { - let state = State { name: name.clone(), dim: 0 }; + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: true }; generate_symbols(dag, state, &config); } } + for (name, dim) in self.bus_inputs() { + if self.public_inputs.contains(name) { + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: true }; + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } + } for (name, dim) in self.inputs() { if !self.public_inputs.contains(name) { - let state = State { name: name.clone(), dim: 0 }; + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: false }; generate_symbols(dag, state, &config); } } + for (name, dim) in self.bus_inputs() { + if !self.public_inputs.contains(name) { + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: false }; + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } + } for (name, dim) in self.intermediates() { - let state = State { name: name.clone(), dim: 0 }; + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; let config = SignalConfig { signal_type: 2, dimensions: dim, is_public: false }; generate_symbols(dag, state, &config); } - // We also need to build the signals inside the buses -> similar to build_connexions + for (name, dim) in self.bus_intermediates() { + let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 2, dimensions: dim, is_public: false }; + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } } + fn build_connexions(&mut self, dag: &mut DAG) { self.connexions.sort_by(|l, r| { use std::cmp::Ordering; @@ -442,6 +472,7 @@ impl ExecutedTemplate { instance } + } struct SignalConfig<'a> { @@ -450,7 +481,8 @@ struct SignalConfig<'a> { dimensions: &'a [usize], } struct State { - name: String, + basic_name: String, //Only name without array accesses []. + name: String, //Full name with array accesses. dim: usize, } fn generate_symbols(dag: &mut DAG, state: State, config: &SignalConfig) { @@ -466,13 +498,40 @@ fn generate_symbols(dag: &mut DAG, state: State, config: &SignalConfig) { let mut index = 0; while index < config.dimensions[state.dim] { let new_state = - State { name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; + State { basic_name: state.basic_name, name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; generate_symbols(dag, new_state, config); index += 1; } } } +fn generate_bus_symbols(dag: &mut DAG, state: State, config: &SignalConfig, bus_connexions: &HashMap, buses: &Vec) { + let bus_connection = bus_connexions.get(&state.basic_name).unwrap(); + let ex_bus2 = buses.get(bus_connection.inspect.goes_to).unwrap(); + if state.dim == config.dimensions.len() { + for (signal, signal_dims) in ex_bus2.signal_fields(){ + let mut signal_name = format!("{}.{}",state.name,signal); + let state = State { basic_name: *signal, name: signal_name, dim: 0 }; + let config = SignalConfig { signal_type: config.signal_type, dimensions: signal_dims, is_public: config.is_public }; + generate_symbols(dag, state, &config); + } + for (bus, bus_dims) in ex_bus2.bus_fields(){ + let mut bus_name = format!("{}.{}",state.name,bus); + let state = State { basic_name: *bus, name: bus_name, dim: 0 }; + let config = SignalConfig { signal_type: config.signal_type, dimensions: &bus_dims, is_public: config.is_public }; + generate_bus_symbols(dag, state, &config, ex_bus2.bus_connexions(), buses); + } + } else { + let mut index = 0; + while index < config.dimensions[state.dim] { + let new_state = + State { basic_name: state.basic_name, name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; + generate_bus_symbols(dag, new_state, config, bus_connexions, buses); + index += 1; + } + } +} + fn as_big_int(exprs: Vec>) -> Vec { let mut numbers = Vec::with_capacity(exprs.len()); for e in exprs { From a608d287fab4cd9b353c2e76b2178657173fcd52 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 03:16:36 +0200 Subject: [PATCH 058/189] cambios clara --- .../environment_utils/bus_representation.rs | 270 ++++++++++++++- .../src/environment_utils/slice_types.rs | 2 +- constraint_generation/src/execute.rs | 326 ++++++++++++++++-- 3 files changed, 558 insertions(+), 40 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index bb3315278..153769990 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,15 +1,20 @@ -use super::slice_types::{AExpressionSlice, FieldTypes, MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo}; +use program_structure::ast::Access; + +use super::slice_types::{AExpressionSlice, FieldTypes, MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo, TagDefinitions, TagState}; use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; use crate::ast::Meta; +use std::mem; +use num_bigint_dig::BigInt; pub struct BusRepresentation { pub node_pointer: Option, pub meta: Option, fields: BTreeMap, - pub field_tags: BTreeMap, + pub field_tags: BTreeMap, unassigned_fields: HashMap, + has_assignment: bool } impl Default for BusRepresentation { @@ -20,6 +25,7 @@ impl Default for BusRepresentation { field_tags: BTreeMap::new(), meta: Option::None, unassigned_fields: HashMap::new(), + has_assignment: false } } } @@ -31,6 +37,7 @@ impl Clone for BusRepresentation { field_tags: self.field_tags.clone(), meta : self.meta.clone(), unassigned_fields: self.unassigned_fields.clone(), + has_assignment: self.has_assignment } } } @@ -91,7 +98,7 @@ impl BusRepresentation { &self, field_name: &str, remaining_access: &AccessingInformationBus - ) -> Result<(TagInfo, SignalSlice), MemoryError> { + ) -> Result<((TagDefinitions, TagInfo), SignalSlice), MemoryError> { // TODO: REMOVE CLONE let field = self.fields.get(field_name).unwrap(); @@ -142,11 +149,12 @@ impl BusRepresentation { &self, field_name: &str, remaining_access: &AccessingInformationBus - ) -> Result<(TagInfo, BusSlice), MemoryError> { + ) -> Result<((TagDefinitions, TagInfo), BusSlice), MemoryError> { // TODO: REMOVE CLONE + let field = self.fields.get(field_name).unwrap(); let field_tags = self.field_tags.get(field_name).unwrap(); - + if remaining_access.field_access.is_some(){ // we are still considering an intermediate bus match field{ @@ -189,15 +197,253 @@ impl BusRepresentation { self.node_pointer.is_none() || !self.unassigned_fields.is_empty() } - pub fn assign_value_to_field( - component: &mut BusRepresentation, + pub fn assign_value_to_field_signal( + &mut self, field_name: &str, - access: &[SliceCapacity], + remaining_access: &AccessingInformationBus, slice_route: &[SliceCapacity], tags: TagInfo, ) -> Result<(), MemoryError> { - // TODO - unreachable!() + + self.has_assignment = true; + + let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); + + // TODO: add quick check if completely assigned + + if remaining_access.field_access.is_some(){ + // we are still considering a bus + match field{ + FieldTypes::Bus(bus_slice)=>{ + + let memory_response = BusSlice::access_values( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let mut resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.assign_value_to_field_signal( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap(), + slice_route, + tags, + ) + } + Result::Err(err)=>{ + return Err(err); + } + } + } + FieldTypes::Signal(_) => unreachable!(), + } + + } else{ + // in this case we are in a signal + match field{ + FieldTypes::Signal(ref mut signal_slice) =>{ + + // First we add the tags --> similar to what we do in execute + let (tags_defs, tags_info) = self.field_tags.get_mut(field_name).unwrap(); + let previous_tags = mem::take(tags_info); + + let signal_is_init = SignalSlice::get_number_of_inserts(&signal_slice) > 0; + + for (tag, value) in previous_tags{ + let tag_state = tags_defs.get(&tag).unwrap(); + if tag_state.defined{// is signal defined by user + if tag_state.value_defined{ + // already with value, store the same value + tags_info.insert(tag, value); + } else{ + if signal_is_init { + // only keep value if same as previous + let to_store_value = if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + if value != *value_new{ + None + } else{ + value + } + } else{ + None + }; + tags_info.insert(tag, to_store_value); + } else{ + // always keep + if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + tags_info.insert(tag, value_new.clone()); + } else{ + tags_info.insert(tag, None); + } + } + } + } else{ + // it is not defined by user + if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + if value == *value_new{ + tags_info.insert(tag, value); + } else{ + tags_info.remove(&tag); + } + } else{ + tags_info.remove(&tag); + } + } + } + if !signal_is_init{ // first init, add new tags + for (tag, value) in tags{ + if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) + tags_info.insert(tag.clone(), value.clone()); + let state = TagState{defined: false, value_defined: false, complete: false}; + tags_defs.insert(tag.clone(), state); + } + } + } + + // Similar to what we do to assign components + + let signal_previous_value = SignalSlice::access_values( + &signal_slice, + &remaining_access.array_access, + )?; + + let new_value_slice = &SignalSlice::new_with_route(slice_route, &true); + + SignalSlice::check_correct_dims( + &signal_previous_value, + &Vec::new(), + &new_value_slice, + true + )?; + + let dim_slice: usize = SignalSlice::get_number_of_cells(new_value_slice); + for i in 0..dim_slice{ + let signal_was_assigned = SignalSlice::access_value_by_index(&signal_previous_value, i)?; + if signal_was_assigned { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + } + } + + SignalSlice::insert_values( + signal_slice, + &remaining_access.array_access, + &new_value_slice, + true + )?; + + // Update the value of unnasigned fields + match self.unassigned_fields.get_mut(field_name){ + Some(left) => { + *left -= dim_slice; + if *left == 0 { + self.unassigned_fields.remove(field_name); + } + } + None => {} + } + + Result::Ok(()) + } + FieldTypes::Bus(_) => unreachable!(), + } + } + } + + + + pub fn assign_value_to_field_tag( + &mut self, + field_name: &str, + remaining_access: &AccessingInformationBus, + value: BigInt, + ) -> Result<(), MemoryError> { + + let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); + + // we need to stop when there is something like bus.field.tag + // distance 2 between the tag and where we add it + + // the access with distance 2 + let next_access = remaining_access.remaining_access.as_ref().unwrap(); + + if next_access.field_access.is_some(){ + // we are still considering a bus + match field{ + FieldTypes::Bus(bus_slice)=>{ + + let memory_response = BusSlice::access_values( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let mut resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.assign_value_to_field_tag( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap(), + value + ) + } + Result::Err(err)=>{ + return Err(err); + } + } + } + FieldTypes::Signal(_) => unreachable!(), + } + + } else{ + // just add the tag to the field + // distance 2 (self.field.tag) + let tag = remaining_access.field_access.as_ref().unwrap(); + + let (tags_status, tags_value) = self.field_tags.get_mut(field_name).unwrap(); + + match field{ + FieldTypes::Signal(s) =>{ + let signal_is_init = SignalSlice::get_number_of_inserts(&s) > 0; + if signal_is_init{ + return Result::Err(MemoryError::AssignmentTagAfterInit) + } + } + FieldTypes::Bus(s) =>{ + // TODO, include info about assignments, no recorrer todo + for i in 0..BusSlice::get_number_of_cells(s){ + let accessed_bus = BusSlice::access_value_by_index(&s, i)?; + if accessed_bus.has_assignment(){ + return Result::Err(MemoryError::AssignmentTagAfterInit) + } + } + } + } + + + let possible_tag = tags_value.get_mut(tag); + if let Some(val) = possible_tag { + if let Some(_) = val { + Result::Err(MemoryError::AssignmentTagTwice) + } else { // we add the info saying that the tag is defined + let tag_state = tags_status.get_mut(tag).unwrap(); + tag_state.value_defined = true; + tags_value.insert(tag.clone(), Option::Some(value)); + Result::Ok(()) + + } + } else{ + unreachable!("Tag does not exist"); + } + } + } + + pub fn completely_assign(&mut self){ + } pub fn get_accesses_bus(&self, name: &String) -> Vec{ @@ -246,4 +492,8 @@ impl BusRepresentation { + pub fn has_assignment(&self)-> bool{ + self.has_assignment + } + } diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index fe15ae070..9c559b241 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -28,4 +28,4 @@ pub enum FieldTypes { // For each field, we store the info depending on if it is // Depending on the case we store a different slice Signal(SignalSlice), Bus(BusSlice), -} \ No newline at end of file +} diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 481e9ec2d..2a40e982c 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -292,7 +292,17 @@ fn execute_statement( Option::None } Substitution { meta, var, access, op, rhe, .. } => { - let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; + let access_information = + if ExecutionEnvironment::has_bus(&runtime.environment, var){ + let access_bus = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; + TypesAccess{bus_access: Some(access_bus), other_access: None} + } else{ + let access_other = treat_accessing(meta, access, program_archive, runtime, flags)?; + TypesAccess{bus_access: None, other_access: Some(access_other)} + }; + + + let r_folded = execute_expression(rhe, program_archive, runtime, flags)?; let mut struct_node = if actual_node.is_some(){ @@ -301,6 +311,7 @@ fn execute_statement( ExecutedStructure::None }; + let possible_constraint = perform_assign( meta, @@ -647,7 +658,14 @@ fn execute_bus_statement( } Substitution { meta, var, access, op, rhe, .. } => { // different access information depending if bus or other variable - let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; + let access_information = + if ExecutionEnvironment::has_bus(&runtime.environment, var){ + let access_bus = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; + TypesAccess{bus_access: Some(access_bus), other_access: None} + } else{ + let access_other = treat_accessing(meta, access, program_archive, runtime, flags)?; + TypesAccess{bus_access: None, other_access: Some(access_other)} + }; let r_folded = execute_expression(rhe, program_archive, runtime, flags)?; let _possible_constraint = perform_assign( @@ -1087,16 +1105,16 @@ fn perform_assign( ) -> Result, ()> { use super::execution_data::type_definitions::{SubComponentData, BusData}; - if accessing_information.bus_access.is_some(){ - let full_symbol = create_symbol_bus(symbol, &accessing_information.bus_access.unwrap()); + let full_symbol = if accessing_information.bus_access.is_some(){ + create_symbol_bus(symbol, &accessing_information.bus_access.as_ref().unwrap()) } else{ - let full_symbol = create_symbol(symbol, &accessing_information.other_access.unwrap()); - } + create_symbol(symbol, &accessing_information.other_access.as_ref().unwrap()) + }; let possible_arithmetic_slice = if ExecutionEnvironment::has_variable(&runtime.environment, symbol) { - let accessing_information = accessing_information.other_access.unwrap(); + let accessing_information = accessing_information.other_access.as_ref().unwrap(); debug_assert!(accessing_information.signal_access.is_none()); debug_assert!(accessing_information.after_signal.is_empty()); let environment_result = ExecutionEnvironment::get_mut_variable_mut(&mut runtime.environment, symbol); @@ -1151,7 +1169,7 @@ fn perform_assign( } Option::None } else if ExecutionEnvironment::has_signal(&runtime.environment, symbol){ - let accessing_information = accessing_information.other_access.unwrap(); + let accessing_information = accessing_information.other_access.as_ref().unwrap(); if accessing_information.signal_access.is_some() { // it is a tag if ExecutionEnvironment::has_input(&runtime.environment, symbol) { @@ -1413,7 +1431,7 @@ fn perform_assign( Option::Some(r_slice) }} else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { - let accessing_information = accessing_information.other_access.unwrap(); + let accessing_information = accessing_information.other_access.as_ref().unwrap(); if accessing_information.tag_access.is_some() { unreachable!() } @@ -1520,7 +1538,7 @@ fn perform_assign( }; node.add_arrow(full_symbol.clone(), data); }, - ExecutedStructure::Bus(node) =>{ + ExecutedStructure::Bus(_) =>{ unreachable!(); }, ExecutedStructure::None => { @@ -1617,7 +1635,7 @@ fn perform_assign( let component_symbol = create_component_symbol(symbol, &accessing_information); node.add_arrow(component_symbol, data); }, - ExecutedStructure::Bus(node) =>{ + ExecutedStructure::Bus(_) =>{ unreachable!(); }, ExecutedStructure::None => { @@ -1631,28 +1649,29 @@ fn perform_assign( let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); - let bus_slice = treat_result_with_environment_error( + let (tags_info, tags_definition, bus_slice) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let accessing_information = accessing_information.bus_access.unwrap(); + let accessing_information = accessing_information.bus_access.as_ref().unwrap(); if FoldedValue::valid_bus_node_pointer(&r_folded){ // in this case we are performing an assigment of the type in the node_pointer // to the bus in the left let bus_pointer = r_folded.bus_node_pointer.unwrap(); + // in this case we cannot assign to a single value of the array debug_assert!(accessing_information.array_access.len() == 0); debug_assert!(accessing_information.field_access.is_none()); - for i in 0..BusSlice::get_number_of_cells(&bus_slice.2){ + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let mut value_left = treat_result_with_memory_error( - BusSlice::access_value_by_index(&bus_slice.2, i), + BusSlice::access_value_by_index(&bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1677,15 +1696,15 @@ fn perform_assign( name: symbol.to_string(), goes_to: bus_pointer, }; - let component_symbol = create_component_symbol(symbol, &accessing_information); - node.add_bus_arrow(component_symbol, data);; + let component_symbol = create_array_accessed_symbol(symbol, &accessing_information.array_access); + node.add_bus_arrow(component_symbol, data); }, ExecutedStructure::Bus(node) =>{ let data = BusData { name: symbol.to_string(), goes_to: bus_pointer, }; - let component_symbol = create_component_symbol(symbol, &accessing_information); + let component_symbol = create_array_accessed_symbol(symbol, &accessing_information.array_access); node.add_bus_arrow(component_symbol, data); }, ExecutedStructure::None => { @@ -1694,9 +1713,234 @@ fn perform_assign( } None - } else{ + } else if FoldedValue::valid_arithmetic_slice(&r_folded){ // case assigning a signal of the bus or a tag + if meta.get_type_knowledge().is_signal(){ + let value_left = treat_result_with_memory_error( + BusSlice::access_values(&bus_slice, &accessing_information.array_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let mut single_bus = safe_unwrap_to_single(value_left, line!()); + + + assert!(accessing_information.field_access.is_some()); + let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); + let tags = if r_folded.tags.is_some() { + r_folded.tags.unwrap() + } else { + TagInfo::new() + }; + + let memory_response = single_bus.assign_value_to_field_signal( + accessing_information.field_access.as_ref().unwrap(), + accessing_information.remaining_access.as_ref().unwrap(), + &arithmetic_slice.route(), + tags, + ); + treat_result_with_memory_error_void( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + Some(arithmetic_slice) + } else if meta.get_type_knowledge().is_tag(){ + // in case we are assigning a tag of the complete bus + assert!(accessing_information.array_access.len() == 0); + assert!(accessing_information.field_access.is_some()); + if accessing_information.remaining_access.as_ref().unwrap().field_access.is_none(){ + let tag = accessing_information.field_access.as_ref().unwrap(); + let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); + let (reference_to_tags, reference_to_tags_defined, bus_content) = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + for i in 0..BusSlice::get_number_of_cells(bus_content){ + let accessed_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(bus_content, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + if accessed_bus.has_assignment(){ + treat_result_with_memory_error( + Result::Err(MemoryError::AssignmentTagAfterInit), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + } + + if let Some(a_slice) = r_folded.arithmetic_slice { + let value = AExpressionSlice::unwrap_to_single(a_slice); + match value { + ArithmeticExpressionGen::Number { value } => { + let possible_tag = reference_to_tags.get(&tag.clone()); + if let Some(val) = possible_tag { + if let Some(_) = val { + treat_result_with_memory_error( + Result::Err(MemoryError::AssignmentTagTwice), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } else { // we add the info saying that the tag is defined + reference_to_tags.insert(tag.clone(), Option::Some(value.clone())); + let tag_state = reference_to_tags_defined.get_mut(tag).unwrap(); + tag_state.value_defined = true; + match actual_node{ + ExecutedStructure::Template(node) =>{ + node.add_tag_signal(symbol, &tag, Some(value)); + }, + ExecutedStructure::Bus(node) =>{ + node.add_tag_signal(symbol, &tag, Some(value)); + }, + ExecutedStructure::None => { + unreachable!(); + } + } + } + } else {unreachable!()} + }, + _ => unreachable!(), + } + } + else { + unreachable!() + } + } else{ + // in case it is a tag of one its fields + let value_left = treat_result_with_memory_error( + BusSlice::access_values(&bus_slice, &accessing_information.array_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let mut single_bus = safe_unwrap_to_single(value_left, line!()); + + + assert!(accessing_information.field_access.is_some()); + let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); + let value_aux = AExpressionSlice::unwrap_to_single(arithmetic_slice); + let value = if let ArithmeticExpressionGen::Number { value } = value_aux { + value + } else { + unreachable!(); + }; + let memory_response = single_bus.assign_value_to_field_tag( + accessing_information.field_access.as_ref().unwrap(), + accessing_information.remaining_access.as_ref().unwrap(), + value, + ); + treat_result_with_memory_error_void( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } + None + } else{ + unreachable!(); + } + } else if FoldedValue::valid_bus_slice(&r_folded){ + // case assigning a bus (complete or field) + if accessing_information.field_access.is_none(){ + // We are assigning the original buses + + // We assign the tags + if r_folded.tags.is_some(){ + let tags = r_folded.tags.unwrap(); + let previous_tags = mem::take(tags_info); + + let mut bus_is_init = false; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + let accessed_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + bus_is_init |= accessed_bus.has_assignment(); + } + + for (tag, value) in previous_tags{ + let tag_state = tags_definition.get(&tag).unwrap(); + if tag_state.defined{// is signal defined by user + if tag_state.value_defined{ + // already with value, store the same value + tags_info.insert(tag, value); + } else{ + if bus_is_init { + // only keep value if same as previous + let to_store_value = if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + if value != *value_new{ + None + } else{ + value + } + } else{ + None + }; + tags_info.insert(tag, to_store_value); + } else{ + // always keep + if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + tags_info.insert(tag, value_new.clone()); + } else{ + tags_info.insert(tag, None); + } + } + } + } else{ + // it is not defined by user + if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + if value == *value_new{ + tags_info.insert(tag, value); + } else{ + tags_info.remove(&tag); + } + } else{ + tags_info.remove(&tag); + } + } + } + if !bus_is_init{ // first init, add new tags + for (tag, value) in tags{ + if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) + tags_info.insert(tag.clone(), value.clone()); + let state = TagState{defined: false, value_defined: false, complete: false}; + tags_definition.insert(tag.clone(), state); + } + } + } + } + + + let signals_values = Vec::new(); + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + // We completely assign each one of them and generate + // an arithmetic slice with the result + + + } + + + } None + } else{ + unreachable!() } @@ -1826,12 +2070,15 @@ fn execute_delayed_declarations( //************************************************* Expression execution support ************************************************* -fn create_component_symbol(symbol: &str, access_information: &AccessingInformation) -> String { +fn create_array_accessed_symbol(symbol: &str, array_access: &Vec) -> String { let mut appendix = "".to_string(); - let bf_signal = create_index_appendix(&access_information.before_signal); - appendix.push_str(&bf_signal); + let access = create_index_appendix(array_access); + appendix.push_str(&access); format!("{}{}", symbol, appendix) } +fn create_component_symbol(symbol: &str, access_information: &AccessingInformation) -> String { + create_array_accessed_symbol(symbol, &access_information.before_signal) +} fn create_symbol(symbol: &str, access_information: &AccessingInformation) -> String { let mut appendix = "".to_string(); @@ -2164,10 +2411,10 @@ fn execute_bus( for i in 0..BusSlice::get_number_of_cells(&slice){ let value_left = treat_result_with_memory_error( - BusSlice::access_value_by_index(&slice, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, + BusSlice::access_value_by_index(&slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, )?; if value_left.has_unassigned_fields(){ @@ -2179,13 +2426,23 @@ fn execute_bus( )?; } } + + let mut tags_propagated = TagInfo::new(); + for (tag, value) in tags{ + let state = tags_definitions.get(tag).unwrap(); + if state.value_defined || state.complete{ + tags_propagated.insert(tag.clone(), value.clone()); + } else if state.defined{ + tags_propagated.insert(tag.clone(), None); + } + } - Result::Ok(FoldedValue{bus_slice: Some(slice), tags: Some(tags_bus.clone()), ..FoldedValue::default()}) + Result::Ok(FoldedValue{bus_slice: Some(slice), tags: Some(tags_propagated), ..FoldedValue::default()}) } else if meta.get_type_knowledge().is_signal(){ // Case we return a signal - let (tags_signal, signal) = treat_result_with_memory_error( + let ((tags_definitions, tags), signal) = treat_result_with_memory_error( resulting_bus.get_field_signal( access_information.field_access.as_ref().unwrap(), access_information.remaining_access.as_ref().unwrap() @@ -2204,10 +2461,21 @@ fn execute_bus( &mut runtime.runtime_errors, &runtime.call_trace, )?; + + let mut tags_propagated = TagInfo::new(); + for (tag, value) in &tags{ + let state = tags_definitions.get(tag).unwrap(); + if state.value_defined || state.complete{ + tags_propagated.insert(tag.clone(), value.clone()); + } else if state.defined{ + tags_propagated.insert(tag.clone(), None); + } + } + let result = signal_to_arith(symbol, slice) .map(|s| FoldedValue { arithmetic_slice: Option::Some(s), - tags: Option::Some(tags_signal.clone()), + tags: Option::Some(tags_propagated), ..FoldedValue::default() }); treat_result_with_memory_error( From 76c3eebaf0a33b8f95c4cf76514c13d840dd01ee Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 04:53:46 +0200 Subject: [PATCH 059/189] cambios clara --- .../environment_utils/bus_representation.rs | 149 +++++++++++++++++- constraint_generation/src/execute.rs | 32 +++- .../src/execution_data/executed_template.rs | 8 +- constraint_generation/src/lib.rs | 1 + 4 files changed, 179 insertions(+), 11 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 153769990..8fab8be7d 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -442,11 +442,156 @@ impl BusRepresentation { } } - pub fn completely_assign(&mut self){ + pub fn completely_assign_bus(&mut self, assigned_bus: &BusRepresentation)-> Result<(), MemoryError>{ + self.has_assignment = true; + for (field_name, value) in &mut self.fields{ + + // update the tags + + let (tags_definition, tags_info) = self.field_tags.get_mut(field_name).unwrap(); + let (tags_assigned_definition, tags_assigned_info) = assigned_bus.field_tags.get(field_name).unwrap(); + + let mut tags_propagated = TagInfo::new(); + for (tag, value) in tags_assigned_info{ + let state = tags_assigned_definition.get(tag).unwrap(); + if state.value_defined || state.complete{ + tags_propagated.insert(tag.clone(), value.clone()); + } else if state.defined{ + tags_propagated.insert(tag.clone(), None); + } + } + + let is_init = match value{ + FieldTypes::Bus(bus_slice) =>{ + let mut bus_is_init = false; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + match BusSlice::access_value_by_index(bus_slice, i){ + Ok(bus) => { + bus_is_init |= bus.has_assignment(); + } + Err(_) => unreachable!() + } + } + bus_is_init + }, + FieldTypes::Signal(signal_slice)=>{ + SignalSlice::get_number_of_inserts(&signal_slice) > 0 + } + }; + + let previous_tags = mem::take(tags_info); + + for (tag, value) in previous_tags{ + let tag_state = tags_definition.get(&tag).unwrap(); + if tag_state.defined{// is signal defined by user + if tag_state.value_defined{ + // already with value, store the same value + tags_info.insert(tag, value); + } else{ + if is_init { + // only keep value if same as previous + let to_store_value = if tags_propagated.contains_key(&tag){ + let value_new = tags_propagated.get(&tag).unwrap(); + if value != *value_new{ + None + } else{ + value + } + } else{ + None + }; + tags_info.insert(tag, to_store_value); + } else{ + // always keep + if tags_propagated.contains_key(&tag){ + let value_new = tags_propagated.get(&tag).unwrap(); + tags_info.insert(tag, value_new.clone()); + } else{ + tags_info.insert(tag, None); + } + } + } + } else{ + // it is not defined by user + if tags_propagated.contains_key(&tag){ + let value_new = tags_propagated.get(&tag).unwrap(); + if value == *value_new{ + tags_info.insert(tag, value); + } else{ + tags_info.remove(&tag); + } + } else{ + tags_info.remove(&tag); + } + } + } + if !is_init{ // first init, add new tags + for (tag, value) in tags_propagated{ + if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) + tags_info.insert(tag.clone(), value.clone()); + let state = TagState{defined: false, value_defined: false, complete: false}; + tags_definition.insert(tag.clone(), state); + } + } + } + + + + match value{ + FieldTypes::Bus(bus_slice) =>{ + let bus_slice_assigned = match assigned_bus.fields.get(field_name).unwrap(){ + FieldTypes::Bus(bs) => bs, + FieldTypes::Signal(_) => unreachable!(), + }; + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + let mut accessed_bus = match BusSlice::access_value_by_index(&bus_slice, i){ + Ok(v) => v, + Err(_) => unreachable!(), + }; + let value_assigned = match BusSlice::access_value_by_index(bus_slice_assigned, i){ + Ok(v) => v, + Err(_) => unreachable!(), + }; + + accessed_bus.completely_assign_bus(&value_assigned); + + } + }, + FieldTypes::Signal(signal_slice)=>{ + // check if not assigned yet + // set to true + // updated unassigned_fields + + let new_value_slice = &SignalSlice::new_with_route(signal_slice.route(), &true); + + let dim_slice: usize = SignalSlice::get_number_of_cells(signal_slice); + for i in 0..dim_slice{ + let signal_was_assigned = match SignalSlice::access_value_by_index(&signal_slice, i){ + Ok(v) => v, + Err(_) => unreachable!() + }; + if signal_was_assigned { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + } + } + + SignalSlice::insert_values( + signal_slice, + &Vec::new(), + &new_value_slice, + true + )?; + } + } + + // Update the value of unnasigned fields + self.unassigned_fields.remove(field_name); + } + Ok(()) } - pub fn get_accesses_bus(&self, name: &String) -> Vec{ + pub fn get_accesses_bus(&self, name: &str) -> Vec{ fn unfold_signals(current: String, dim: usize, lengths: &[usize], result: &mut Vec) { if dim == lengths.len() { diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 2a40e982c..620c9135c 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1928,17 +1928,39 @@ fn perform_assign( } - let signals_values = Vec::new(); + let mut signals_values: Vec = Vec::new(); for i in 0..BusSlice::get_number_of_cells(&bus_slice){ // We completely assign each one of them and generate // an arithmetic slice with the result + let mut accessed_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let assigned_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(r_folded.bus_slice.as_ref().unwrap(), i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + treat_result_with_memory_error( + accessed_bus.completely_assign_bus(&assigned_bus), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + signals_values.append(&mut accessed_bus.get_accesses_bus(symbol)); - } - - + let mut ae_signals = Vec::new(); + for signal_name in signals_values{ + ae_signals.push(AExpr::Signal { symbol: signal_name }); + } + Some(AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals)) + } else{ + None } - None } else{ unreachable!() } diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 3e8883715..92f4f10a6 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -498,7 +498,7 @@ fn generate_symbols(dag: &mut DAG, state: State, config: &SignalConfig) { let mut index = 0; while index < config.dimensions[state.dim] { let new_state = - State { basic_name: state.basic_name, name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; + State { basic_name: state.basic_name.clone(), name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; generate_symbols(dag, new_state, config); index += 1; } @@ -511,13 +511,13 @@ fn generate_bus_symbols(dag: &mut DAG, state: State, config: &SignalConfig, bus_ if state.dim == config.dimensions.len() { for (signal, signal_dims) in ex_bus2.signal_fields(){ let mut signal_name = format!("{}.{}",state.name,signal); - let state = State { basic_name: *signal, name: signal_name, dim: 0 }; + let state = State { basic_name: signal.clone(), name: signal_name, dim: 0 }; let config = SignalConfig { signal_type: config.signal_type, dimensions: signal_dims, is_public: config.is_public }; generate_symbols(dag, state, &config); } for (bus, bus_dims) in ex_bus2.bus_fields(){ let mut bus_name = format!("{}.{}",state.name,bus); - let state = State { basic_name: *bus, name: bus_name, dim: 0 }; + let state = State { basic_name: bus.clone(), name: bus_name, dim: 0 }; let config = SignalConfig { signal_type: config.signal_type, dimensions: &bus_dims, is_public: config.is_public }; generate_bus_symbols(dag, state, &config, ex_bus2.bus_connexions(), buses); } @@ -525,7 +525,7 @@ fn generate_bus_symbols(dag: &mut DAG, state: State, config: &SignalConfig, bus_ let mut index = 0; while index < config.dimensions[state.dim] { let new_state = - State { basic_name: state.basic_name, name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; + State { basic_name: state.basic_name.clone(), name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; generate_bus_symbols(dag, new_state, config, bus_connexions, buses); index += 1; } diff --git a/constraint_generation/src/lib.rs b/constraint_generation/src/lib.rs index a7d26eb2a..90eb2f556 100644 --- a/constraint_generation/src/lib.rs +++ b/constraint_generation/src/lib.rs @@ -5,6 +5,7 @@ mod compute_constants; mod environment_utils; mod execute; mod execution_data; +mod assignment_utils; use ansi_term::Colour; use circom_algebra::algebra::{ArithmeticError, ArithmeticExpression}; From ce15944aef6e2c0d9e07c5adffcc744ca1ad2a06 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 07:18:05 +0200 Subject: [PATCH 060/189] working on execute --- .../environment_utils/bus_representation.rs | 159 +++++++++++++++++- constraint_generation/src/execute.rs | 57 ++++++- 2 files changed, 213 insertions(+), 3 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 8fab8be7d..7ff45b570 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -442,7 +442,164 @@ impl BusRepresentation { } } + + pub fn assign_value_to_field_bus( + &mut self, + field_name: &str, + remaining_access: &AccessingInformationBus, + slice_route: &[SliceCapacity], + assigned_bus: &BusSlice, + tags: TagInfo + ) -> Result<(), MemoryError> { + + self.has_assignment = true; + + + let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); + + // TODO: add quick check if completely assigned + + if remaining_access.field_access.is_some(){ + // we are still considering a bus + match field{ + FieldTypes::Bus(bus_slice)=>{ + + let memory_response = BusSlice::access_values( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.is_single()); + let mut resulting_bus = + BusSlice::unwrap_to_single(bus_slice); + resulting_bus.assign_value_to_field_bus( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap(), + slice_route, + assigned_bus, + tags + ) + } + Result::Err(err)=>{ + return Err(err); + } + } + } + FieldTypes::Signal(_) => unreachable!(), + } + + } else{ + // in this case we are in a signal + match field{ + FieldTypes::Bus(ref mut bus_slice) =>{ + + // First we add the tags --> similar to what we do in execute + let (tags_defs, tags_info) = self.field_tags.get_mut(field_name).unwrap(); + let previous_tags = mem::take(tags_info); + + let mut bus_is_init = false; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + match BusSlice::access_value_by_index(bus_slice, i){ + Ok(bus) => { + bus_is_init |= bus.has_assignment(); + } + Err(_) => unreachable!() + } + } + + for (tag, value) in previous_tags{ + let tag_state = tags_defs.get(&tag).unwrap(); + if tag_state.defined{// is signal defined by user + if tag_state.value_defined{ + // already with value, store the same value + tags_info.insert(tag, value); + } else{ + if bus_is_init { + // only keep value if same as previous + let to_store_value = if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + if value != *value_new{ + None + } else{ + value + } + } else{ + None + }; + tags_info.insert(tag, to_store_value); + } else{ + // always keep + if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + tags_info.insert(tag, value_new.clone()); + } else{ + tags_info.insert(tag, None); + } + } + } + } else{ + // it is not defined by user + if tags.contains_key(&tag){ + let value_new = tags.get(&tag).unwrap(); + if value == *value_new{ + tags_info.insert(tag, value); + } else{ + tags_info.remove(&tag); + } + } else{ + tags_info.remove(&tag); + } + } + } + if !bus_is_init{ // first init, add new tags + for (tag, value) in tags{ + if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) + tags_info.insert(tag.clone(), value.clone()); + let state = TagState{defined: false, value_defined: false, complete: false}; + tags_defs.insert(tag.clone(), state); + } + } + } + + // We completely assign each one of the buses + + let bus_previous_value = BusSlice::access_values( + bus_slice, + &remaining_access.array_access, + )?; + + let dim_slice: usize = BusSlice::get_number_of_cells(&bus_previous_value); + for i in 0..dim_slice{ + let mut bus_assigned = BusSlice::access_value_by_index(&bus_previous_value, i)?; + let value = BusSlice::access_value_by_index(&assigned_bus, i)?; + + bus_assigned.completely_assign_bus(&value)?; + } + + // Update the value of unnasigned fields + match self.unassigned_fields.get_mut(field_name){ + Some(left) => { + *left -= dim_slice; + if *left == 0 { + self.unassigned_fields.remove(field_name); + } + } + None => {} + } + + Result::Ok(()) + } + FieldTypes::Signal(_) => unreachable!(), + } + } + } + + pub fn completely_assign_bus(&mut self, assigned_bus: &BusRepresentation)-> Result<(), MemoryError>{ + if self.has_assignment{ + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + } self.has_assignment = true; for (field_name, value) in &mut self.fields{ @@ -553,7 +710,7 @@ impl BusRepresentation { Err(_) => unreachable!(), }; - accessed_bus.completely_assign_bus(&value_assigned); + accessed_bus.completely_assign_bus(&value_assigned)?; } }, diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 620c9135c..7a8a625a6 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1950,7 +1950,7 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values.append(&mut accessed_bus.get_accesses_bus(symbol)); + signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); } let mut ae_signals = Vec::new(); @@ -1959,9 +1959,62 @@ fn perform_assign( } Some(AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals)) } else{ - None + + let value_left = treat_result_with_memory_error( + BusSlice::access_values(&bus_slice, &accessing_information.array_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let mut single_bus = safe_unwrap_to_single(value_left, line!()); + + + assert!(accessing_information.field_access.is_some()); + let bus_slice = r_folded.bus_slice.unwrap(); + let tags = if r_folded.tags.is_some() { + r_folded.tags.unwrap() + } else { + TagInfo::new() + }; + + let memory_response = single_bus.assign_value_to_field_bus( + accessing_information.field_access.as_ref().unwrap(), + accessing_information.remaining_access.as_ref().unwrap(), + &bus_slice.route(), + &bus_slice, + tags, + ); + treat_result_with_memory_error_void( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + + let mut signals_values: Vec = Vec::new(); + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + // We generate an arithmetic slice with the result + + let assigned_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(&bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); + + } + let mut ae_signals = Vec::new(); + for signal_name in signals_values{ + ae_signals.push(AExpr::Signal { symbol: signal_name }); + } + Some(AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals)) + } } else{ + unreachable!() } From 766384885f9d5a8404fdd42cb45cc8033d0d8b7e Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 08:29:56 -0700 Subject: [PATCH 061/189] re-estructuring code tag assignments --- constraint_generation/src/assignment_utils.rs | 96 ++++++++++ constraint_generation/src/execute.rs | 168 +++--------------- 2 files changed, 120 insertions(+), 144 deletions(-) create mode 100644 constraint_generation/src/assignment_utils.rs diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs new file mode 100644 index 000000000..6d732a5fc --- /dev/null +++ b/constraint_generation/src/assignment_utils.rs @@ -0,0 +1,96 @@ +use super::environment_utils::{ + + slice_types::{ + AExpressionSlice, ArithmeticExpression as ArithmeticExpressionGen, ComponentRepresentation, + ComponentSlice, MemoryError, TypeInvalidAccess, TypeAssignmentError, MemorySlice, + SignalSlice, SliceCapacity, TagInfo, TagState, TagDefinitions, BusSlice, BusRepresentation + }, +}; + +use std::mem; + + +// Utils for assigning tags + +pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut TagDefinitions, assigned_tags: &TagInfo, is_init: bool){ + // Study the tags: add the new ones and copy their content. + /* + Cases: + + Inherance in arrays => We only have a tag in case it inherites the tag in all positions + + - Tag defined by user: + * Already with value defined by user => do not copy new values + * No value defined by user + - Already initialized: + * If same value as previous preserve + * If not set value to None + - No initialized: + * Set value to new one + - Tag not defined by user: + * Already initialized: + - If contains same tag with same value preserve + - No tag or different value => do not save tag or loose it + * No initialized: + - Save tag + + + */ + let previous_tags = mem::take(tags_values); + + for (tag, value) in previous_tags{ + let tag_state = tags_definitions.get(&tag).unwrap(); + if tag_state.defined{// is signal defined by user + if tag_state.value_defined{ + // already with value, store the same value + tags_values.insert(tag, value); + } else{ + if is_init { + // only keep value if same as previous + let to_store_value = if assigned_tags.contains_key(&tag){ + let value_new = assigned_tags.get(&tag).unwrap(); + if value != *value_new{ + None + } else{ + value + } + } else{ + None + }; + tags_values.insert(tag, to_store_value); + } else{ + // always keep + if assigned_tags.contains_key(&tag){ + let value_new = assigned_tags.get(&tag).unwrap(); + tags_values.insert(tag, value_new.clone()); + } else{ + tags_values.insert(tag, None); + } + } + } + } else{ + // it is not defined by user + if assigned_tags.contains_key(&tag){ + let value_new = assigned_tags.get(&tag).unwrap(); + if value == *value_new{ + tags_values.insert(tag, value); + } else{ + tags_values.remove(&tag); + } + } else{ + tags_values.remove(&tag); + } + } + } + + if !is_init{ // first init, add new tags + for (tag, value) in assigned_tags{ + if !tags_values.contains_key(tag){ // in case it is a new tag (not defined by user) + tags_values.insert(tag.clone(), value.clone()); + let state = TagState{defined: false, value_defined: false, complete: false}; + tags_definitions.insert(tag.clone(), state); + } + } + } + +} \ No newline at end of file diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 7a8a625a6..f69a626e4 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -14,6 +14,9 @@ use super::environment_utils::{ }, }; +use crate::assignment_utils::perform_tag_propagation; + + use program_structure::constants::UsefulConstants; use super::execution_data::analysis::Analysis; @@ -1248,42 +1251,9 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - let memory_response_for_signal_previous_value = SignalSlice::access_values( - reference_to_signal_content, - &accessing_information.before_signal, - ); - let signal_previous_value = treat_result_with_memory_error( - memory_response_for_signal_previous_value, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - // Study the tags: add the new ones and copy their content. - /* - Cases: - - Inherance in arrays => We only have a tag in case it inherites the tag in all positions - - - Tag defined by user: - * Already with value defined by user => do not copy new values - * No value defined by user - - Already initialized: - * If same value as previous preserve - * If not set value to None - - No initialized: - * Set value to new one - - Tag not defined by user: - * Already initialized: - - If contains same tag with same value preserve - - No tag or different value => do not save tag or loose it - * No initialized: - - Save tag - - - */ - let previous_tags = mem::take(reference_to_tags); - + // Perform the tag assignment + let new_tags = if r_folded.tags.is_some() && op == AssignOp::AssignConstraintSignal{ r_folded.tags.clone().unwrap() } else{ @@ -1292,62 +1262,21 @@ fn perform_assign( let signal_is_init = SignalSlice::get_number_of_inserts(reference_to_signal_content) > 0; - for (tag, value) in previous_tags{ - let tag_state = reference_to_tags_defined.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - reference_to_tags.insert(tag, value); - } else{ - if signal_is_init { - // only keep value if same as previous - let to_store_value = if new_tags.contains_key(&tag){ - let value_new = new_tags.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - reference_to_tags.insert(tag, to_store_value); - } else{ - // always keep - if new_tags.contains_key(&tag){ - let value_new = new_tags.get(&tag).unwrap(); - reference_to_tags.insert(tag, value_new.clone()); - } else{ - reference_to_tags.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if new_tags.contains_key(&tag){ - let value_new = new_tags.get(&tag).unwrap(); - if value == *value_new{ - reference_to_tags.insert(tag, value); - } else{ - reference_to_tags_defined.remove(&tag); - } - } else{ - reference_to_tags_defined.remove(&tag); - } - } - } - - if !signal_is_init{ // first init, add new tags - for (tag, value) in new_tags{ - if !reference_to_tags.contains_key(&tag){ // in case it is a new tag (not defined by user) - reference_to_tags.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - reference_to_tags_defined.insert(tag.clone(), state); - } - } - } + perform_tag_propagation(reference_to_tags, reference_to_tags_defined, &new_tags, signal_is_init); + + // Perform the signal assignment + let memory_response_for_signal_previous_value = SignalSlice::access_values( + reference_to_signal_content, + &accessing_information.before_signal, + ); + let signal_previous_value = treat_result_with_memory_error( + memory_response_for_signal_previous_value, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; let r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); let new_value_slice = &SignalSlice::new_with_route(r_slice.route(), &true); @@ -1858,8 +1787,10 @@ fn perform_assign( // We assign the tags if r_folded.tags.is_some(){ - let tags = r_folded.tags.unwrap(); - let previous_tags = mem::take(tags_info); + + // Perform the tag assignment + + let new_tags = r_folded.tags.unwrap(); let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ @@ -1871,60 +1802,9 @@ fn perform_assign( )?; bus_is_init |= accessed_bus.has_assignment(); } + perform_tag_propagation(tags_info, tags_definition, &new_tags, bus_is_init); - for (tag, value) in previous_tags{ - let tag_state = tags_definition.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if bus_is_init { - // only keep value if same as previous - let to_store_value = if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !bus_is_init{ // first init, add new tags - for (tag, value) in tags{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_definition.insert(tag.clone(), state); - } - } - } + } From 04db5afb4b9ba59bcf23447fd5e8734ae617ab02 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 08:37:36 -0700 Subject: [PATCH 062/189] re-estructuring code tag assignments --- .../environment_utils/bus_representation.rs | 175 +----------------- 1 file changed, 9 insertions(+), 166 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 7ff45b570..50984bbc6 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -8,6 +8,8 @@ use crate::ast::Meta; use std::mem; use num_bigint_dig::BigInt; +use crate::assignment_utils::perform_tag_propagation; + pub struct BusRepresentation { pub node_pointer: Option, pub meta: Option, @@ -246,64 +248,11 @@ impl BusRepresentation { FieldTypes::Signal(ref mut signal_slice) =>{ // First we add the tags --> similar to what we do in execute - let (tags_defs, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let previous_tags = mem::take(tags_info); + let (tags_definitions, tags_info) = self.field_tags.get_mut(field_name).unwrap(); let signal_is_init = SignalSlice::get_number_of_inserts(&signal_slice) > 0; - for (tag, value) in previous_tags{ - let tag_state = tags_defs.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if signal_is_init { - // only keep value if same as previous - let to_store_value = if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !signal_is_init{ // first init, add new tags - for (tag, value) in tags{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_defs.insert(tag.clone(), state); - } - } - } + perform_tag_propagation(tags_info, tags_definitions, &tags, signal_is_init); // Similar to what we do to assign components @@ -495,8 +444,7 @@ impl BusRepresentation { FieldTypes::Bus(ref mut bus_slice) =>{ // First we add the tags --> similar to what we do in execute - let (tags_defs, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let previous_tags = mem::take(tags_info); + let (tags_definitions, tags_info) = self.field_tags.get_mut(field_name).unwrap(); let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ @@ -508,59 +456,8 @@ impl BusRepresentation { } } - for (tag, value) in previous_tags{ - let tag_state = tags_defs.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if bus_is_init { - // only keep value if same as previous - let to_store_value = if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !bus_is_init{ // first init, add new tags - for (tag, value) in tags{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_defs.insert(tag.clone(), state); - } - } - } + perform_tag_propagation(tags_info, tags_definitions, &tags, bus_is_init); + // We completely assign each one of the buses @@ -636,62 +533,8 @@ impl BusRepresentation { } }; - let previous_tags = mem::take(tags_info); - - for (tag, value) in previous_tags{ - let tag_state = tags_definition.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if is_init { - // only keep value if same as previous - let to_store_value = if tags_propagated.contains_key(&tag){ - let value_new = tags_propagated.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags_propagated.contains_key(&tag){ - let value_new = tags_propagated.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags_propagated.contains_key(&tag){ - let value_new = tags_propagated.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !is_init{ // first init, add new tags - for (tag, value) in tags_propagated{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_definition.insert(tag.clone(), state); - } - } - } - + // perform the tag assignment + perform_tag_propagation(tags_info, tags_definition, &tags_propagated, is_init); match value{ From e5684aa931c656ae8a4465972c85d6a3fd906030 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 20 May 2024 10:08:52 -0700 Subject: [PATCH 063/189] component component_representation --- .../component_representation.rs | 196 ++++++++++++++---- 1 file changed, 157 insertions(+), 39 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index ab16ff4e1..3589a8f34 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -1,5 +1,5 @@ -use super::slice_types::{MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, SliceCapacity,TagInfo}; -use crate::execution_data::type_definitions::NodePointer; +use super::slice_types::{BusSlice, MemoryError, SignalSlice, SliceCapacity, TagInfo, TypeAssignmentError, TypeInvalidAccess}; +use crate::{environment_utils::slice_types::BusRepresentation, execution_data::type_definitions::NodePointer}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; use crate::ast::Meta; @@ -9,15 +9,14 @@ pub struct ComponentRepresentation { pub is_parallel: bool, pub meta: Option, unassigned_inputs: HashMap, - unassigned_input_buses: HashMap, unassigned_tags: HashSet, to_assign_inputs: Vec<(String, Vec, Vec)>, - to_assign_input_buses: Vec<(String, Vec, Vec)>, + to_assign_input_buses: Vec<(String, Vec, Vec, BusSlice)>, inputs: HashMap, - input_buses: HashMap, + input_buses: HashMap, pub inputs_tags: BTreeMap, outputs: HashMap, - output_buses: HashMap, + output_buses: HashMap, pub outputs_tags: BTreeMap, pub is_initialized: bool, } @@ -36,7 +35,6 @@ impl Default for ComponentRepresentation { outputs_tags: BTreeMap::new(), is_initialized: false, meta: Option::None, - unassigned_input_buses: HashMap::new(), to_assign_input_buses: Vec::new(), input_buses: HashMap::new(), output_buses: HashMap::new(), @@ -57,7 +55,6 @@ impl Clone for ComponentRepresentation { outputs_tags: self.outputs_tags.clone(), is_initialized: self.is_initialized, meta : self.meta.clone(), - unassigned_input_buses: self.unassigned_input_buses.clone(), to_assign_input_buses: self.to_assign_input_buses.clone(), input_buses: self.input_buses.clone(), output_buses: self.output_buses.clone(), @@ -115,7 +112,6 @@ impl ComponentRepresentation { is_initialized: false, is_parallel, meta: Some(meta.clone()), - unassigned_input_buses: HashMap::new(), to_assign_input_buses: Vec::new(), input_buses: HashMap::new(), output_buses: HashMap::new(), @@ -144,13 +140,13 @@ impl ComponentRepresentation { } for (symbol, route) in node.bus_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{ - component.unassigned_input_buses - .insert(symbol.clone(), signal_slice_size); + let bus_slice = BusSlice::new_with_route(route, &BusRepresentation::default()); + let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); + if bus_slice_size > 0{ + component.unassigned_inputs + .insert(symbol.clone(), bus_slice_size); } - component.input_buses.insert(symbol.clone(), signal_slice); + component.input_buses.insert(symbol.clone(), bus_slice); } fn insert_tags_output(node: &crate::execution_data::ExecutedTemplate, symbol: &String, component: &mut ComponentRepresentation) { @@ -174,7 +170,7 @@ impl ComponentRepresentation { } for (symbol, route) in node.bus_outputs() { - component.output_buses.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); + component.output_buses.insert(symbol.clone(), BusSlice::new_with_route(route, &BusRepresentation::default())); insert_tags_output(node, symbol, component); } @@ -189,7 +185,7 @@ impl ComponentRepresentation { let to_assign = component.to_assign_input_buses.clone(); for s in to_assign{ let tags_input = component.inputs_tags.get(&s.0).unwrap(); - ComponentRepresentation::assign_value_to_signal_init(component, &s.0, &s.1, &s.2, tags_input.clone())?; + ComponentRepresentation::assign_value_to_bus_init(component, &s.0, &s.1, &s.2, tags_input.clone(), &s.3)?; } Result::Ok(()) @@ -225,6 +221,31 @@ impl ComponentRepresentation { } */ + pub fn get_bus(&self, bus_name: &str) -> Result<(&TagInfo, &BusSlice), MemoryError> { + + if self.node_pointer.is_none() { + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent)); + } + if self.output_buses.contains_key(bus_name) && !self.unassigned_inputs.is_empty() { + // we return the name of an input that has not been assigned + let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal))); + } + + if !self.is_initialized { + // we return the name of an input with tags that has not been assigned + let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal))); + } + + let slice = if self.input_buses.contains_key(bus_name) { + (self.inputs_tags.get(bus_name).unwrap(), self.input_buses.get(bus_name).unwrap()) + } else { + (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) + }; + Result::Ok(slice) + } + pub fn get_signal(&self, signal_name: &str) -> Result<(&TagInfo, &SignalSlice), MemoryError> { if self.node_pointer.is_none() { @@ -283,32 +304,23 @@ impl ComponentRepresentation { */ - pub fn assign_value_to_signal_no_init( - component: &mut ComponentRepresentation, - signal_name: &str, - access: &[SliceCapacity], - slice_route: &[SliceCapacity], - tags: TagInfo, - ) -> Result<(), MemoryError> { - // We copy tags in any case, complete or incomplete assignment - // The values of the tags must be the same than the ones stored before - if !component.is_preinitialized() { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); + fn handle_tag_assignment(component: &mut ComponentRepresentation, signal_name: &str, tags: TagInfo) -> Option> { + if !component.is_preinitialized() { + return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent))); } - if !component.inputs_tags.contains_key(signal_name){ - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); + return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput))); } - let tags_input = component.inputs_tags.get_mut(signal_name).unwrap(); - let is_first_assignment_signal = component.unassigned_tags.contains(signal_name); component.unassigned_tags.remove(signal_name); + // We copy tags in any case, complete or incomplete assignment + // The values of the tags must be the same than the ones stored before for (t, value) in tags_input{ if !tags.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone())); + return Some(Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone()))); } else{ if is_first_assignment_signal{ *value = tags.get(t).unwrap().clone(); @@ -316,15 +328,48 @@ impl ComponentRepresentation { else{ // already given a value, check that it is the same if value != tags.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone())); + return Some(Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone()))); } } } } + None + } + + + + pub fn assign_value_to_signal_no_init( + component: &mut ComponentRepresentation, + signal_name: &str, + access: &[SliceCapacity], + slice_route: &[SliceCapacity], + tags: TagInfo, + ) -> Result<(), MemoryError> { + + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, signal_name, tags) { + //if Some, then an error was detected. + return value; + } component.to_assign_inputs.push((signal_name.to_string(), access.to_vec(), slice_route.to_vec())); Result::Ok(()) } + pub fn assign_value_to_bus_no_init( + component: &mut ComponentRepresentation, + bus_name: &str, + access: &[SliceCapacity], + slice_route: &[SliceCapacity], + tags: TagInfo, + bus_slice: BusSlice + ) -> Result<(), MemoryError> { + + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { + return value; + } + component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(), slice_route.to_vec(),bus_slice)); + Result::Ok(()) + } + pub fn assign_value_to_signal_init( component: &mut ComponentRepresentation, signal_name: &str, @@ -397,6 +442,82 @@ impl ComponentRepresentation { Result::Ok(()) } + + pub fn assign_value_to_bus_init( + component: &mut ComponentRepresentation, + bus_name: &str, + access: &[SliceCapacity], + slice_route: &[SliceCapacity], + tags: TagInfo, + bus_slice : &BusSlice, + ) -> Result<(), MemoryError> { + + if !component.is_preinitialized() { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); + } + + if !component.input_buses.contains_key(bus_name){ + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); + } + + let tags_input = component.inputs_tags.get_mut(bus_name).unwrap(); + for (t, value) in tags_input{ + if !tags.contains_key(t){ + return Result::Err(MemoryError::AssignmentMissingTags(bus_name.to_string(), t.clone())); + } else{ + // We are in the case where the component is initialized, so we + // assume that all tags already have their value and check if it is + // the same as the one we are receiving + if value != tags.get(t).unwrap(){ + return Result::Err(MemoryError::AssignmentTagInputTwice(bus_name.to_string(), t.clone())); + } + } + } + + let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); + let bus_previous_value = BusSlice::access_values( + inputs_response, + &access, + )?; + + let initial_value = BusSlice::get_reference_to_single_value(bus_slice, &access)?; + let new_value_slice = &BusSlice::new_with_route(slice_route, initial_value); + + BusSlice::check_correct_dims( + &bus_previous_value, + &Vec::new(), + &new_value_slice, + true + )?; + + for i in 0..BusSlice::get_number_of_cells(&bus_previous_value){ + let bus = BusSlice::access_value_by_index(&bus_previous_value, i)?; + if bus.has_assignment() { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + } + } + + BusSlice::insert_values( + inputs_response, + &access, + &new_value_slice, + true + )?; + let dim = BusSlice::get_number_of_cells(new_value_slice); + match component.unassigned_inputs.get_mut(bus_name){ + Some(left) => { + *left -= dim; + if *left == 0 { + component.unassigned_inputs.remove(bus_name); + } + } + None => {} + } + + Result::Ok(()) + + } + pub fn is_preinitialized(&self) -> bool { self.node_pointer.is_some() } @@ -406,9 +527,6 @@ impl ComponentRepresentation { } pub fn has_unassigned_inputs(&self) -> bool{ - !self.unassigned_inputs.is_empty() || !self.unassigned_input_buses.is_empty() + !self.unassigned_inputs.is_empty() } - -} - - +} \ No newline at end of file From 9ae4a2d5bc888ca978b69fa7ed233df35ea43f96 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 10:15:13 -0700 Subject: [PATCH 064/189] re-estructuring code signal assignments --- constraint_generation/src/assignment_utils.rs | 51 ++++++++ .../environment_utils/bus_representation.rs | 82 +++++++----- constraint_generation/src/execute.rs | 117 ++++++++---------- 3 files changed, 153 insertions(+), 97 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index 6d732a5fc..b565e3477 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -93,4 +93,55 @@ pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut } } +} + + +pub fn perform_signal_assignment(signal_slice: &mut SignalSlice, array_access: &[SliceCapacity], new_route: &[SliceCapacity])-> Result<(), MemoryError>{ + let memory_response_for_signal_previous_value = SignalSlice::access_values( + signal_slice, + array_access, + ); + let signal_previous_value = match memory_response_for_signal_previous_value{ + Ok(v) => v, + Err(err) => return Err(err) + }; + + let new_value_slice = &SignalSlice::new_with_route(new_route, &true); + + let correct_dims_result = SignalSlice::check_correct_dims( + &signal_previous_value, + &Vec::new(), + &new_value_slice, + true + ); + match correct_dims_result{ + Ok(_) => {}, + Err(err) => return Err(err) + }; + + for i in 0..SignalSlice::get_number_of_cells(&signal_previous_value){ + let memory_response_access = SignalSlice::access_value_by_index(&signal_previous_value, i); + let signal_was_assigned = match memory_response_access{ + Ok(v) => v, + Err(err) => return Err(err) + }; + if signal_was_assigned { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + } + } + + + + let access_response = SignalSlice::insert_values( + signal_slice, + array_access, + &new_value_slice, + true + ); + + match access_response{ + Ok(_) => {}, + Err(err) => return Err(err) + }; + Result::Ok(()) } \ No newline at end of file diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 50984bbc6..0c88199a6 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -8,7 +8,7 @@ use crate::ast::Meta; use std::mem; use num_bigint_dig::BigInt; -use crate::assignment_utils::perform_tag_propagation; +use crate::assignment_utils::*; pub struct BusRepresentation { pub node_pointer: Option, @@ -254,38 +254,15 @@ impl BusRepresentation { perform_tag_propagation(tags_info, tags_definitions, &tags, signal_is_init); - // Similar to what we do to assign components - - let signal_previous_value = SignalSlice::access_values( - &signal_slice, - &remaining_access.array_access, - )?; - - let new_value_slice = &SignalSlice::new_with_route(slice_route, &true); - - SignalSlice::check_correct_dims( - &signal_previous_value, - &Vec::new(), - &new_value_slice, - true - )?; - - let dim_slice: usize = SignalSlice::get_number_of_cells(new_value_slice); - for i in 0..dim_slice{ - let signal_was_assigned = SignalSlice::access_value_by_index(&signal_previous_value, i)?; - if signal_was_assigned { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - } - } - - SignalSlice::insert_values( - signal_slice, - &remaining_access.array_access, - &new_value_slice, - true - )?; + // Perform the signal assignment + perform_signal_assignment(signal_slice, &remaining_access.array_access, slice_route); // Update the value of unnasigned fields + let mut dim_slice = 1; + for i in slice_route { + dim_slice *= *i; + } + match self.unassigned_fields.get_mut(field_name){ Some(left) => { *left -= dim_slice; @@ -296,6 +273,20 @@ impl BusRepresentation { None => {} } + // Update the value of the signal tags it is complete + let signal_is_completely_initialized = + SignalSlice::get_number_of_inserts(signal_slice) == + SignalSlice::get_number_of_cells(signal_slice); + + if signal_is_completely_initialized { + + for (tag, value) in tags_info{ + let tag_state = tags_definitions.get_mut(tag).unwrap(); + tag_state.complete = true; + + } + } + Result::Ok(()) } FieldTypes::Bus(_) => unreachable!(), @@ -485,6 +476,26 @@ impl BusRepresentation { None => {} } + // Update the value of the signal tags it is complete + let mut bus_is_completely_init = true; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + match BusSlice::access_value_by_index(bus_slice, i){ + Ok(bus) => { + bus_is_init &= bus.has_assignment(); + } + Err(_) => unreachable!() + } + } + + if bus_is_completely_init { + + for (tag, value) in tags_info{ + let tag_state = tags_definitions.get_mut(tag).unwrap(); + tag_state.complete = true; + + } + } + Result::Ok(()) } FieldTypes::Signal(_) => unreachable!(), @@ -582,10 +593,17 @@ impl BusRepresentation { true )?; } + } // Update the value of unnasigned fields - self.unassigned_fields.remove(field_name); + self.unassigned_fields.remove(field_name); + // Update the value of the complete tags + for (tag, value) in tags_info{ + let tag_state = tags_definition.get_mut(tag).unwrap(); + tag_state.complete = true; + + } } Ok(()) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index f69a626e4..cb395f84e 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -14,7 +14,7 @@ use super::environment_utils::{ }, }; -use crate::assignment_utils::perform_tag_propagation; +use crate::assignment_utils::*; use program_structure::constants::UsefulConstants; @@ -1266,61 +1266,19 @@ fn perform_assign( // Perform the signal assignment - - let memory_response_for_signal_previous_value = SignalSlice::access_values( - reference_to_signal_content, - &accessing_information.before_signal, - ); - let signal_previous_value = treat_result_with_memory_error( - memory_response_for_signal_previous_value, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); - let new_value_slice = &SignalSlice::new_with_route(r_slice.route(), &true); - - let correct_dims_result = SignalSlice::check_correct_dims( - &signal_previous_value, - &Vec::new(), - &new_value_slice, - true - ); + + let signal_assignment_response = perform_signal_assignment(reference_to_signal_content, &accessing_information.before_signal, &r_slice.route()); + treat_result_with_memory_error_void( - correct_dims_result, + signal_assignment_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - for i in 0..SignalSlice::get_number_of_cells(&signal_previous_value){ - let signal_was_assigned = treat_result_with_memory_error( - SignalSlice::access_value_by_index(&signal_previous_value, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - if signal_was_assigned { - let access_response = Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - treat_result_with_memory_error( - access_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - } - } - - - - let access_response = SignalSlice::insert_values( - reference_to_signal_content, - &accessing_information.before_signal, - &new_value_slice, - true - ); + // Update complete tags if completely init let signal_is_completely_initialized = SignalSlice::get_number_of_inserts(reference_to_signal_content) == SignalSlice::get_number_of_cells(reference_to_signal_content); @@ -1348,15 +1306,6 @@ fn perform_assign( } } - - - treat_result_with_memory_error_void( - access_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - Option::Some(r_slice) }} else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { @@ -1783,15 +1732,10 @@ fn perform_assign( } else if FoldedValue::valid_bus_slice(&r_folded){ // case assigning a bus (complete or field) if accessing_information.field_access.is_none(){ - // We are assigning the original buses // We assign the tags if r_folded.tags.is_some(){ - // Perform the tag assignment - - let new_tags = r_folded.tags.unwrap(); - let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ let accessed_bus = treat_result_with_memory_error( @@ -1802,18 +1746,28 @@ fn perform_assign( )?; bus_is_init |= accessed_bus.has_assignment(); } + + // Perform the tag assignment + let new_tags = r_folded.tags.unwrap(); perform_tag_propagation(tags_info, tags_definition, &new_tags, bus_is_init); - } + // We are assigning the original buses + let value_left = treat_result_with_memory_error( + BusSlice::access_values(&bus_slice, &accessing_information.array_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let mut signals_values: Vec = Vec::new(); - for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + for i in 0..BusSlice::get_number_of_cells(&value_left){ // We completely assign each one of them and generate // an arithmetic slice with the result let mut accessed_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(bus_slice, i), + BusSlice::access_value_by_index(&value_left, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1833,6 +1787,38 @@ fn perform_assign( signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); } + + // Update the final tags + let mut bus_is_completely_init = true; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + let accessed_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + bus_is_completely_init &= accessed_bus.has_assignment(); + } + if bus_is_completely_init{ + for (tag, value) in tags_info{ + let tag_state = tags_definition.get_mut(tag).unwrap(); + tag_state.complete = true; + match actual_node{ + ExecutedStructure::Template(node) =>{ + if !tag_state.value_defined{ + node.add_tag_signal(symbol, &tag, value.clone()); + } + }, + ExecutedStructure::Bus(node) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); + } + } + } + } + let mut ae_signals = Vec::new(); for signal_name in signals_values{ ae_signals.push(AExpr::Signal { symbol: signal_name }); @@ -1886,6 +1872,7 @@ fn perform_assign( signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); } + let mut ae_signals = Vec::new(); for signal_name in signals_values{ ae_signals.push(AExpr::Signal { symbol: signal_name }); From 9c1c943866c23e83cb59c00dde18b9e5893bf0ea Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 20 May 2024 10:41:25 -0700 Subject: [PATCH 065/189] component representation --- .../component_representation.rs | 66 +++++++++++++++---- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 3589a8f34..9f14884ca 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -1,4 +1,5 @@ -use super::slice_types::{BusSlice, MemoryError, SignalSlice, SliceCapacity, TagInfo, TypeAssignmentError, TypeInvalidAccess}; +use super::slice_types::{BusSlice, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TypeAssignmentError, TypeInvalidAccess}; +use crate::execution_data::type_definitions::AccessingInformationBus; use crate::{environment_utils::slice_types::BusRepresentation, execution_data::type_definitions::NodePointer}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; @@ -221,21 +222,62 @@ impl ComponentRepresentation { } */ - pub fn get_bus(&self, bus_name: &str) -> Result<(&TagInfo, &BusSlice), MemoryError> { +fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { + if self.node_pointer.is_none() { + return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent))); + } + if self.output_buses.contains_key(bus_name) && !self.unassigned_inputs.is_empty() { + // we return the name of an input that has not been assigned + let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); + return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal)))); + } - if self.node_pointer.is_none() { - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent)); + if !self.is_initialized { + // we return the name of an input with tags that has not been assigned + let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); + return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal)))); + } + Result::Ok(()) +} + pub fn get_signal_field_bus(&self, bus_name: &str,remaining_access: &AccessingInformationBus) -> Result<((TagDefinitions, TagInfo), SignalSlice), MemoryError> { + if let Result::Err(value) = self.check_initialized_inputs(bus_name) { + return Err(value); } - if self.output_buses.contains_key(bus_name) && !self.unassigned_inputs.is_empty() { - // we return the name of an input that has not been assigned - let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal))); + + let bus_slice = if self.input_buses.contains_key(bus_name) { + (self.inputs_tags.get(bus_name).unwrap(), self.input_buses.get(bus_name).unwrap()) + } else { + (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) + }; + let initial_value = BusSlice::get_reference_to_single_value(bus_slice.1, &[])?; + let (tags,slice) = initial_value.get_field_signal( + bus_name, + remaining_access + )?; + Result::Ok((tags,slice)) + } + + pub fn get_bus_field_bus(&self, bus_name: &str,remaining_access: &AccessingInformationBus) -> Result<((TagDefinitions, TagInfo), BusSlice), MemoryError> { + if let Result::Err(value) = self.check_initialized_inputs(bus_name) { + return Err(value); } - if !self.is_initialized { - // we return the name of an input with tags that has not been assigned - let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal))); + let bus_slice = if self.input_buses.contains_key(bus_name) { + (self.inputs_tags.get(bus_name).unwrap(), self.input_buses.get(bus_name).unwrap()) + } else { + (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) + }; + let initial_value = BusSlice::get_reference_to_single_value(bus_slice.1, &[])?; + let (tags,slice) = initial_value.get_field_bus( + bus_name, + remaining_access + )?; + Result::Ok((tags,slice)) + } + + pub fn get_complete_bus(&self, bus_name: &str) -> Result<(&TagInfo, &BusSlice), MemoryError> { + if let Result::Err(value) = self.check_initialized_inputs(bus_name) { + return Err(value); } let slice = if self.input_buses.contains_key(bus_name) { From d5e1cc3a670f9471c21eab69dd5cb63608764c64 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 10:50:38 -0700 Subject: [PATCH 066/189] re-estructuring code signal assignments --- constraint_generation/src/assignment_utils.rs | 51 ++++ .../environment_utils/bus_representation.rs | 255 ++++-------------- constraint_generation/src/execute.rs | 117 ++++---- 3 files changed, 161 insertions(+), 262 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index 6d732a5fc..b565e3477 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -93,4 +93,55 @@ pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut } } +} + + +pub fn perform_signal_assignment(signal_slice: &mut SignalSlice, array_access: &[SliceCapacity], new_route: &[SliceCapacity])-> Result<(), MemoryError>{ + let memory_response_for_signal_previous_value = SignalSlice::access_values( + signal_slice, + array_access, + ); + let signal_previous_value = match memory_response_for_signal_previous_value{ + Ok(v) => v, + Err(err) => return Err(err) + }; + + let new_value_slice = &SignalSlice::new_with_route(new_route, &true); + + let correct_dims_result = SignalSlice::check_correct_dims( + &signal_previous_value, + &Vec::new(), + &new_value_slice, + true + ); + match correct_dims_result{ + Ok(_) => {}, + Err(err) => return Err(err) + }; + + for i in 0..SignalSlice::get_number_of_cells(&signal_previous_value){ + let memory_response_access = SignalSlice::access_value_by_index(&signal_previous_value, i); + let signal_was_assigned = match memory_response_access{ + Ok(v) => v, + Err(err) => return Err(err) + }; + if signal_was_assigned { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + } + } + + + + let access_response = SignalSlice::insert_values( + signal_slice, + array_access, + &new_value_slice, + true + ); + + match access_response{ + Ok(_) => {}, + Err(err) => return Err(err) + }; + Result::Ok(()) } \ No newline at end of file diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 7ff45b570..d637e8b5e 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -8,6 +8,8 @@ use crate::ast::Meta; use std::mem; use num_bigint_dig::BigInt; +use crate::assignment_utils::*; + pub struct BusRepresentation { pub node_pointer: Option, pub meta: Option, @@ -246,97 +248,21 @@ impl BusRepresentation { FieldTypes::Signal(ref mut signal_slice) =>{ // First we add the tags --> similar to what we do in execute - let (tags_defs, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let previous_tags = mem::take(tags_info); + let (tags_definitions, tags_info) = self.field_tags.get_mut(field_name).unwrap(); let signal_is_init = SignalSlice::get_number_of_inserts(&signal_slice) > 0; - for (tag, value) in previous_tags{ - let tag_state = tags_defs.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if signal_is_init { - // only keep value if same as previous - let to_store_value = if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !signal_is_init{ // first init, add new tags - for (tag, value) in tags{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_defs.insert(tag.clone(), state); - } - } - } + perform_tag_propagation(tags_info, tags_definitions, &tags, signal_is_init); - // Similar to what we do to assign components - - let signal_previous_value = SignalSlice::access_values( - &signal_slice, - &remaining_access.array_access, - )?; - - let new_value_slice = &SignalSlice::new_with_route(slice_route, &true); - - SignalSlice::check_correct_dims( - &signal_previous_value, - &Vec::new(), - &new_value_slice, - true - )?; - - let dim_slice: usize = SignalSlice::get_number_of_cells(new_value_slice); - for i in 0..dim_slice{ - let signal_was_assigned = SignalSlice::access_value_by_index(&signal_previous_value, i)?; - if signal_was_assigned { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - } - } - - SignalSlice::insert_values( - signal_slice, - &remaining_access.array_access, - &new_value_slice, - true - )?; + // Perform the signal assignment + perform_signal_assignment(signal_slice, &remaining_access.array_access, slice_route)?; // Update the value of unnasigned fields + let mut dim_slice = 1; + for i in slice_route { + dim_slice *= *i; + } + match self.unassigned_fields.get_mut(field_name){ Some(left) => { *left -= dim_slice; @@ -347,6 +273,20 @@ impl BusRepresentation { None => {} } + // Update the value of the signal tags it is complete + let signal_is_completely_initialized = + SignalSlice::get_number_of_inserts(signal_slice) == + SignalSlice::get_number_of_cells(signal_slice); + + if signal_is_completely_initialized { + + for (tag, value) in tags_info{ + let tag_state = tags_definitions.get_mut(tag).unwrap(); + tag_state.complete = true; + + } + } + Result::Ok(()) } FieldTypes::Bus(_) => unreachable!(), @@ -495,8 +435,7 @@ impl BusRepresentation { FieldTypes::Bus(ref mut bus_slice) =>{ // First we add the tags --> similar to what we do in execute - let (tags_defs, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let previous_tags = mem::take(tags_info); + let (tags_definitions, tags_info) = self.field_tags.get_mut(field_name).unwrap(); let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ @@ -508,59 +447,8 @@ impl BusRepresentation { } } - for (tag, value) in previous_tags{ - let tag_state = tags_defs.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if bus_is_init { - // only keep value if same as previous - let to_store_value = if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags.contains_key(&tag){ - let value_new = tags.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !bus_is_init{ // first init, add new tags - for (tag, value) in tags{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_defs.insert(tag.clone(), state); - } - } - } + perform_tag_propagation(tags_info, tags_definitions, &tags, bus_is_init); + // We completely assign each one of the buses @@ -588,6 +476,26 @@ impl BusRepresentation { None => {} } + // Update the value of the signal tags it is complete + let mut bus_is_completely_init = true; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + match BusSlice::access_value_by_index(bus_slice, i){ + Ok(bus) => { + bus_is_init &= bus.has_assignment(); + } + Err(_) => unreachable!() + } + } + + if bus_is_completely_init { + + for (tag, value) in tags_info{ + let tag_state = tags_definitions.get_mut(tag).unwrap(); + tag_state.complete = true; + + } + } + Result::Ok(()) } FieldTypes::Signal(_) => unreachable!(), @@ -636,62 +544,8 @@ impl BusRepresentation { } }; - let previous_tags = mem::take(tags_info); - - for (tag, value) in previous_tags{ - let tag_state = tags_definition.get(&tag).unwrap(); - if tag_state.defined{// is signal defined by user - if tag_state.value_defined{ - // already with value, store the same value - tags_info.insert(tag, value); - } else{ - if is_init { - // only keep value if same as previous - let to_store_value = if tags_propagated.contains_key(&tag){ - let value_new = tags_propagated.get(&tag).unwrap(); - if value != *value_new{ - None - } else{ - value - } - } else{ - None - }; - tags_info.insert(tag, to_store_value); - } else{ - // always keep - if tags_propagated.contains_key(&tag){ - let value_new = tags_propagated.get(&tag).unwrap(); - tags_info.insert(tag, value_new.clone()); - } else{ - tags_info.insert(tag, None); - } - } - } - } else{ - // it is not defined by user - if tags_propagated.contains_key(&tag){ - let value_new = tags_propagated.get(&tag).unwrap(); - if value == *value_new{ - tags_info.insert(tag, value); - } else{ - tags_info.remove(&tag); - } - } else{ - tags_info.remove(&tag); - } - } - } - if !is_init{ // first init, add new tags - for (tag, value) in tags_propagated{ - if !tags_info.contains_key(&tag){ // in case it is a new tag (not defined by user) - tags_info.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; - tags_definition.insert(tag.clone(), state); - } - } - } - + // perform the tag assignment + perform_tag_propagation(tags_info, tags_definition, &tags_propagated, is_init); match value{ @@ -739,10 +593,17 @@ impl BusRepresentation { true )?; } + } // Update the value of unnasigned fields - self.unassigned_fields.remove(field_name); + self.unassigned_fields.remove(field_name); + // Update the value of the complete tags + for (tag, value) in tags_info{ + let tag_state = tags_definition.get_mut(tag).unwrap(); + tag_state.complete = true; + + } } Ok(()) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index f69a626e4..cb395f84e 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -14,7 +14,7 @@ use super::environment_utils::{ }, }; -use crate::assignment_utils::perform_tag_propagation; +use crate::assignment_utils::*; use program_structure::constants::UsefulConstants; @@ -1266,61 +1266,19 @@ fn perform_assign( // Perform the signal assignment - - let memory_response_for_signal_previous_value = SignalSlice::access_values( - reference_to_signal_content, - &accessing_information.before_signal, - ); - let signal_previous_value = treat_result_with_memory_error( - memory_response_for_signal_previous_value, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); - let new_value_slice = &SignalSlice::new_with_route(r_slice.route(), &true); - - let correct_dims_result = SignalSlice::check_correct_dims( - &signal_previous_value, - &Vec::new(), - &new_value_slice, - true - ); + + let signal_assignment_response = perform_signal_assignment(reference_to_signal_content, &accessing_information.before_signal, &r_slice.route()); + treat_result_with_memory_error_void( - correct_dims_result, + signal_assignment_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - for i in 0..SignalSlice::get_number_of_cells(&signal_previous_value){ - let signal_was_assigned = treat_result_with_memory_error( - SignalSlice::access_value_by_index(&signal_previous_value, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - if signal_was_assigned { - let access_response = Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - treat_result_with_memory_error( - access_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - } - } - - - - let access_response = SignalSlice::insert_values( - reference_to_signal_content, - &accessing_information.before_signal, - &new_value_slice, - true - ); + // Update complete tags if completely init let signal_is_completely_initialized = SignalSlice::get_number_of_inserts(reference_to_signal_content) == SignalSlice::get_number_of_cells(reference_to_signal_content); @@ -1348,15 +1306,6 @@ fn perform_assign( } } - - - treat_result_with_memory_error_void( - access_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - Option::Some(r_slice) }} else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { @@ -1783,15 +1732,10 @@ fn perform_assign( } else if FoldedValue::valid_bus_slice(&r_folded){ // case assigning a bus (complete or field) if accessing_information.field_access.is_none(){ - // We are assigning the original buses // We assign the tags if r_folded.tags.is_some(){ - // Perform the tag assignment - - let new_tags = r_folded.tags.unwrap(); - let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ let accessed_bus = treat_result_with_memory_error( @@ -1802,18 +1746,28 @@ fn perform_assign( )?; bus_is_init |= accessed_bus.has_assignment(); } + + // Perform the tag assignment + let new_tags = r_folded.tags.unwrap(); perform_tag_propagation(tags_info, tags_definition, &new_tags, bus_is_init); - } + // We are assigning the original buses + let value_left = treat_result_with_memory_error( + BusSlice::access_values(&bus_slice, &accessing_information.array_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let mut signals_values: Vec = Vec::new(); - for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + for i in 0..BusSlice::get_number_of_cells(&value_left){ // We completely assign each one of them and generate // an arithmetic slice with the result let mut accessed_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(bus_slice, i), + BusSlice::access_value_by_index(&value_left, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1833,6 +1787,38 @@ fn perform_assign( signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); } + + // Update the final tags + let mut bus_is_completely_init = true; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + let accessed_bus = treat_result_with_memory_error( + BusSlice::access_value_by_index(bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + bus_is_completely_init &= accessed_bus.has_assignment(); + } + if bus_is_completely_init{ + for (tag, value) in tags_info{ + let tag_state = tags_definition.get_mut(tag).unwrap(); + tag_state.complete = true; + match actual_node{ + ExecutedStructure::Template(node) =>{ + if !tag_state.value_defined{ + node.add_tag_signal(symbol, &tag, value.clone()); + } + }, + ExecutedStructure::Bus(node) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); + } + } + } + } + let mut ae_signals = Vec::new(); for signal_name in signals_values{ ae_signals.push(AExpr::Signal { symbol: signal_name }); @@ -1886,6 +1872,7 @@ fn perform_assign( signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); } + let mut ae_signals = Vec::new(); for signal_name in signals_values{ ae_signals.push(AExpr::Signal { symbol: signal_name }); From 9cd07f90ab13934388222151d87136427de1f2c7 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 11:53:25 -0700 Subject: [PATCH 067/189] small changes clara --- .../component_representation.rs | 62 ++++++------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 9f14884ca..663617bdb 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -5,6 +5,8 @@ use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; use crate::ast::Meta; +use crate::assignment_utils::*; + pub struct ComponentRepresentation { pub node_pointer: Option, pub is_parallel: bool, @@ -428,6 +430,8 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); } + // Check that the assignment satisfies the tags requisites + let tags_input = component.inputs_tags.get_mut(signal_name).unwrap(); for (t, value) in tags_input{ if !tags.contains_key(t){ @@ -442,38 +446,20 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { } } + + // Perform the assignment let inputs_response = component.inputs.get_mut(signal_name).unwrap(); - let signal_previous_value = SignalSlice::access_values( - inputs_response, - &access, - )?; - - let new_value_slice = &SignalSlice::new_with_route(slice_route, &true); - - SignalSlice::check_correct_dims( - &signal_previous_value, - &Vec::new(), - &new_value_slice, - true - )?; - - for i in 0..SignalSlice::get_number_of_cells(&signal_previous_value){ - let signal_was_assigned = SignalSlice::access_value_by_index(&signal_previous_value, i)?; - if signal_was_assigned { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - } - } - SignalSlice::insert_values( - inputs_response, - &access, - &new_value_slice, - true - )?; - let dim = SignalSlice::get_number_of_cells(new_value_slice); + perform_signal_assignment(inputs_response, &access, slice_route)?; + + // Update the value of unnasigned fields + let mut dim_slice = 1; + for i in slice_route { + dim_slice *= *i; + } match component.unassigned_inputs.get_mut(signal_name){ Some(left) => { - *left -= dim; + *left -= dim_slice; if *left == 0 { component.unassigned_inputs.remove(signal_name); } @@ -522,30 +508,20 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { &access, )?; - let initial_value = BusSlice::get_reference_to_single_value(bus_slice, &access)?; - let new_value_slice = &BusSlice::new_with_route(slice_route, initial_value); - BusSlice::check_correct_dims( &bus_previous_value, &Vec::new(), - &new_value_slice, + &bus_slice, true )?; for i in 0..BusSlice::get_number_of_cells(&bus_previous_value){ - let bus = BusSlice::access_value_by_index(&bus_previous_value, i)?; - if bus.has_assignment() { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - } + let mut bus = BusSlice::access_value_by_index(&bus_previous_value, i)?; + let assigned_bus = BusSlice::access_value_by_index(&bus_previous_value, i)?; + bus.completely_assign_bus(&assigned_bus)?; } - BusSlice::insert_values( - inputs_response, - &access, - &new_value_slice, - true - )?; - let dim = BusSlice::get_number_of_cells(new_value_slice); + let dim = BusSlice::get_number_of_cells(&bus_previous_value); match component.unassigned_inputs.get_mut(bus_name){ Some(left) => { *left -= dim; From 21167678cee246ae28dd10d9cf5d15626af4983b Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 20 May 2024 12:09:51 -0700 Subject: [PATCH 068/189] component representation --- .../component_representation.rs | 176 +++++++++++++++++- 1 file changed, 172 insertions(+), 4 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 663617bdb..86260bf93 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -15,6 +15,8 @@ pub struct ComponentRepresentation { unassigned_tags: HashSet, to_assign_inputs: Vec<(String, Vec, Vec)>, to_assign_input_buses: Vec<(String, Vec, Vec, BusSlice)>, + to_assign_input_bus_buses: Vec<(String, AccessingInformationBus, Vec, BusSlice)>, + to_assign_input_signal_buses: Vec<(String, AccessingInformationBus, Vec)>, inputs: HashMap, input_buses: HashMap, pub inputs_tags: BTreeMap, @@ -41,6 +43,8 @@ impl Default for ComponentRepresentation { to_assign_input_buses: Vec::new(), input_buses: HashMap::new(), output_buses: HashMap::new(), + to_assign_input_bus_buses: Vec::new(), + to_assign_input_signal_buses: Vec::new(), } } } @@ -61,6 +65,8 @@ impl Clone for ComponentRepresentation { to_assign_input_buses: self.to_assign_input_buses.clone(), input_buses: self.input_buses.clone(), output_buses: self.output_buses.clone(), + to_assign_input_bus_buses: Vec::new(), + to_assign_input_signal_buses: Vec::new(), } } } @@ -118,6 +124,8 @@ impl ComponentRepresentation { to_assign_input_buses: Vec::new(), input_buses: HashMap::new(), output_buses: HashMap::new(), + to_assign_input_bus_buses: Vec::new(), + to_assign_input_signal_buses: Vec::new(), }; Result::Ok(()) } @@ -349,7 +357,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { */ - fn handle_tag_assignment(component: &mut ComponentRepresentation, signal_name: &str, tags: TagInfo) -> Option> { + fn handle_tag_assignment(component: &mut ComponentRepresentation, signal_name: &str, tags: &TagInfo) -> Option> { if !component.is_preinitialized() { return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent))); } @@ -390,7 +398,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { tags: TagInfo, ) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, signal_name, tags) { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, signal_name, &tags) { //if Some, then an error was detected. return value; } @@ -398,6 +406,36 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { Result::Ok(()) } + //assign_value_to_bus_bus //y hay que llamar a assign_bus_field. + pub fn assign_value_to_bus_complete( + component: &mut ComponentRepresentation, + signal_name: &str, + access: &[SliceCapacity], + slice_route: &[SliceCapacity], + tags: TagInfo, + bus_slice: BusSlice + ) -> Result<(), MemoryError> { + if !component.is_initialized{ + ComponentRepresentation::assign_value_to_bus_no_init( + component, + signal_name, + access, + slice_route, + tags, + bus_slice + ) + } else { + ComponentRepresentation::assign_value_to_bus_init( + component, + signal_name, + access, + slice_route, + tags, + &bus_slice + ) + } + } + pub fn assign_value_to_bus_no_init( component: &mut ComponentRepresentation, bus_name: &str, @@ -407,7 +445,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { bus_slice: BusSlice ) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, &tags) { return value; } component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(), slice_route.to_vec(),bus_slice)); @@ -547,4 +585,134 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { pub fn has_unassigned_inputs(&self) -> bool{ !self.unassigned_inputs.is_empty() } -} \ No newline at end of file + + fn check_input_errors(component: &mut ComponentRepresentation, bus_name: &str, tags: &TagInfo) -> Option> { + if !component.is_preinitialized() { + return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent))); + } + if !component.input_buses.contains_key(bus_name){ + return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput))); + } + let tags_input = component.inputs_tags.get_mut(bus_name).unwrap(); + + + for (t, value) in tags_input{ + if !tags.contains_key(t){ + return Some(Result::Err(MemoryError::AssignmentMissingTags(bus_name.to_string(), t.clone()))); + } else{ + // We are in the case where the component is initialized, so we + // assume that all tags already have their value and check if it is + // the same as the one we are receiving + if value != tags.get(t).unwrap(){ + return Some(Result::Err(MemoryError::AssignmentTagInputTwice(bus_name.to_string(), t.clone()))); + } + } + } + None + } + + //assign_value_to_bus_signal y hay que llamar a assign_signal_field. + pub fn assign_value_to_bus_bus( + component: &mut ComponentRepresentation, + signal_name: &str, + remaining_access: &AccessingInformationBus, + slice_route: &[SliceCapacity], + tags: TagInfo, + bus_slice: BusSlice + ) -> Result<(), MemoryError> { + if !component.is_initialized{ + ComponentRepresentation::assign_value_to_bus_bus_no_init( + component, + signal_name, + remaining_access, + slice_route, + tags, + bus_slice + ) + } else { + ComponentRepresentation::assign_value_to_bus_bus_init( + component, + signal_name, + remaining_access, + slice_route, + tags, + &bus_slice + ) + } + } + + fn assign_value_to_bus_bus_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: &AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: &BusSlice) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, &tags) { + return value; + } + + let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); + let signal_previous_value = BusSlice::access_values( + inputs_response, + &remaining_access.array_access, + )?; + + let initial_value = BusSlice::get_reference_to_single_value(&inputs_response, &remaining_access.array_access)?; + initial_value.assign_value_to_field_bus(bus_name, remaining_access, slice_route, bus_slice, tags) + + } + + fn assign_value_to_bus_bus_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: &AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: BusSlice) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, &tags) { + return value; + } + component.to_assign_input_bus_buses.push((bus_name.to_string(), *remaining_access, slice_route.to_vec(),bus_slice)); + Result::Ok(()) + } + + pub fn assign_value_to_bus_signal( + component: &mut ComponentRepresentation, + signal_name: &str, + remaining_access: AccessingInformationBus, + slice_route: &[SliceCapacity], + tags: &TagInfo, + ) -> Result<(), MemoryError> { + if !component.is_initialized{ + ComponentRepresentation::assign_value_to_bus_signal_no_init( + component, + signal_name, + remaining_access, + slice_route, + tags + ) + } else { + ComponentRepresentation::assign_value_to_bus_signal_init( + component, + signal_name, + remaining_access, + slice_route, + tags + ) + } + } + + fn assign_value_to_bus_signal_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: &TagInfo) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, tags) { + return value; + } + + let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); + let signal_previous_value = BusSlice::access_values( + inputs_response, + &remaining_access.array_access, + )?; + + let initial_value = BusSlice::get_reference_to_single_value(&inputs_response, &remaining_access.array_access)?; + initial_value.assign_value_to_field_signal(bus_name, &remaining_access, slice_route, *tags) + + } + + fn assign_value_to_bus_signal_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: &TagInfo) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, &tags) { + return value; + } + component.to_assign_input_signal_buses.push((bus_name.to_string(), remaining_access, slice_route.to_vec())); + Result::Ok(()) + } +} + From fb958f1aec3e69a50848269da7f8b4ead2c8a0ea Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 20 May 2024 14:01:40 -0700 Subject: [PATCH 069/189] Component representation --- .../component_representation.rs | 43 +++++++++++-------- .../src/execution_data/executed_template.rs | 2 +- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 86260bf93..932a22f6b 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -151,7 +151,14 @@ impl ComponentRepresentation { } for (symbol, route) in node.bus_inputs() { - let bus_slice = BusSlice::new_with_route(route, &BusRepresentation::default()); + let mut initial_value_bus = BusRepresentation::default(); + let bus_node = node.bus_connexions.get(symbol).unwrap().inspect.goes_to; + BusRepresentation::initialize_bus( + &mut initial_value_bus, + bus_node, + scheme, + )?; + let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); if bus_slice_size > 0{ component.unassigned_inputs @@ -357,7 +364,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { */ - fn handle_tag_assignment(component: &mut ComponentRepresentation, signal_name: &str, tags: &TagInfo) -> Option> { + fn handle_tag_assignment(component: &mut ComponentRepresentation, signal_name: &str, tags: TagInfo) -> Option> { if !component.is_preinitialized() { return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent))); } @@ -398,7 +405,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { tags: TagInfo, ) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, signal_name, &tags) { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, signal_name, tags) { //if Some, then an error was detected. return value; } @@ -445,7 +452,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { bus_slice: BusSlice ) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, &tags) { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { return value; } component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(), slice_route.to_vec(),bus_slice)); @@ -615,7 +622,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { pub fn assign_value_to_bus_bus( component: &mut ComponentRepresentation, signal_name: &str, - remaining_access: &AccessingInformationBus, + remaining_access: AccessingInformationBus, slice_route: &[SliceCapacity], tags: TagInfo, bus_slice: BusSlice @@ -641,7 +648,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { } } - fn assign_value_to_bus_bus_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: &AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: &BusSlice) -> Result<(), MemoryError> { + fn assign_value_to_bus_bus_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: &BusSlice) -> Result<(), MemoryError> { if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, &tags) { return value; } @@ -652,16 +659,16 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { &remaining_access.array_access, )?; - let initial_value = BusSlice::get_reference_to_single_value(&inputs_response, &remaining_access.array_access)?; - initial_value.assign_value_to_field_bus(bus_name, remaining_access, slice_route, bus_slice, tags) + let initial_value = BusSlice::get_mut_reference_to_single_value(inputs_response, &remaining_access.array_access)?; + initial_value.assign_value_to_field_bus(bus_name, &remaining_access, slice_route, bus_slice, tags) } - fn assign_value_to_bus_bus_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: &AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: BusSlice) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, &tags) { + fn assign_value_to_bus_bus_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: BusSlice) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { return value; } - component.to_assign_input_bus_buses.push((bus_name.to_string(), *remaining_access, slice_route.to_vec(),bus_slice)); + component.to_assign_input_bus_buses.push((bus_name.to_string(), remaining_access, slice_route.to_vec(),bus_slice)); Result::Ok(()) } @@ -670,7 +677,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { signal_name: &str, remaining_access: AccessingInformationBus, slice_route: &[SliceCapacity], - tags: &TagInfo, + tags: TagInfo, ) -> Result<(), MemoryError> { if !component.is_initialized{ ComponentRepresentation::assign_value_to_bus_signal_no_init( @@ -691,8 +698,8 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { } } - fn assign_value_to_bus_signal_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: &TagInfo) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, tags) { + fn assign_value_to_bus_signal_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, &tags) { return value; } @@ -702,13 +709,13 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { &remaining_access.array_access, )?; - let initial_value = BusSlice::get_reference_to_single_value(&inputs_response, &remaining_access.array_access)?; - initial_value.assign_value_to_field_signal(bus_name, &remaining_access, slice_route, *tags) + let initial_value = BusSlice::get_mut_reference_to_single_value(inputs_response, &remaining_access.array_access)?; + initial_value.assign_value_to_field_signal(bus_name, &remaining_access, slice_route, tags) } - fn assign_value_to_bus_signal_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: &TagInfo) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, &tags) { + fn assign_value_to_bus_signal_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo) -> Result<(), MemoryError> { + if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { return value; } component.to_assign_input_signal_buses.push((bus_name.to_string(), remaining_access, slice_route.to_vec())); diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 92f4f10a6..89c0a82fa 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -85,7 +85,7 @@ pub struct ExecutedTemplate { pub is_custom_gate: bool, pub underscored_signals: Vec, connexions: Vec, - bus_connexions: HashMap, + pub bus_connexions: HashMap, } impl ExecutedTemplate { From b26c99b4ae38f9f42e1b9f8d35e35e00bb92a1b8 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 20 May 2024 14:17:57 -0700 Subject: [PATCH 070/189] perform_bus_slice -> more modular code in execute --- constraint_generation/src/assignment_utils.rs | 44 +++++++++++++++- constraint_generation/src/execute.rs | 50 +++++++------------ program_structure/src/utils/memory_slice.rs | 9 ++++ 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index b565e3477..d5b1c01c5 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -144,4 +144,46 @@ pub fn perform_signal_assignment(signal_slice: &mut SignalSlice, array_access: & Err(err) => return Err(err) }; Result::Ok(()) -} \ No newline at end of file +} + + +pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCapacity], assigned_bus_slice: &BusSlice)-> Result<(), MemoryError>{ + + let mut value_left = match BusSlice::access_values(&bus_slice, array_access){ + Ok(value) => value, + Err(err) => return Err(err) + }; + + let correct_dims_result = BusSlice::check_correct_dims( + &value_left, + &Vec::new(), + &assigned_bus_slice, + true + ); + match correct_dims_result{ + Ok(_) => {}, + Err(err) => return Err(err) + }; + + for i in 0..BusSlice::get_number_of_cells(&value_left){ + // We completely assign each one of them + let memory_response_access = BusSlice::get_mut_reference_to_single_value_by_index(&mut value_left, i); + let accessed_bus = match memory_response_access{ + Ok(v) => v, + Err(err) => return Err(err) + }; + let memory_response_assign = BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i); + + let assigned_bus = match memory_response_assign{ + Ok(v) => v, + Err(err) => return Err(err) + }; + match accessed_bus.completely_assign_bus(&assigned_bus){ + Ok(_) =>{}, + Err(err) => return Err(err) + }; + + } + + Ok(()) +} diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index cb395f84e..fc52bb4d8 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1549,7 +1549,7 @@ fn perform_assign( for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let mut value_left = treat_result_with_memory_error( - BusSlice::access_value_by_index(&bus_slice, i), + BusSlice::get_mut_reference_to_single_value_by_index(bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1641,7 +1641,7 @@ fn perform_assign( for i in 0..BusSlice::get_number_of_cells(bus_content){ let accessed_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(bus_content, i), + BusSlice::get_reference_to_single_value_by_index(bus_content, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1730,6 +1730,7 @@ fn perform_assign( unreachable!(); } } else if FoldedValue::valid_bus_slice(&r_folded){ + let assigned_bus_slice = r_folded.bus_slice.as_ref().unwrap(); // case assigning a bus (complete or field) if accessing_information.field_access.is_none(){ @@ -1739,7 +1740,7 @@ fn perform_assign( let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ let accessed_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(bus_slice, i), + BusSlice::get_reference_to_single_value_by_index(bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1753,33 +1754,20 @@ fn perform_assign( } - // We are assigning the original buses - let value_left = treat_result_with_memory_error( - BusSlice::access_values(&bus_slice, &accessing_information.array_access), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - + // We assign the original buses + let bus_assignment_response = perform_bus_assignment(bus_slice, &accessing_information.array_access, assigned_bus_slice); + treat_result_with_memory_error_void( + bus_assignment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + // Generate an arithmetic slice for the accessed buses let mut signals_values: Vec = Vec::new(); - for i in 0..BusSlice::get_number_of_cells(&value_left){ - // We completely assign each one of them and generate - // an arithmetic slice with the result - let mut accessed_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(&value_left, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(r_folded.bus_slice.as_ref().unwrap(), i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - treat_result_with_memory_error( - accessed_bus.completely_assign_bus(&assigned_bus), + BusSlice::get_reference_to_single_value_by_index(r_folded.bus_slice.as_ref().unwrap(), i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1792,7 +1780,7 @@ fn perform_assign( let mut bus_is_completely_init = true; for i in 0..BusSlice::get_number_of_cells(bus_slice){ let accessed_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(bus_slice, i), + BusSlice::get_reference_to_single_value_by_index(bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1864,7 +1852,7 @@ fn perform_assign( // We generate an arithmetic slice with the result let assigned_bus = treat_result_with_memory_error( - BusSlice::access_value_by_index(&bus_slice, i), + BusSlice::get_reference_to_single_value_by_index(&bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -2265,7 +2253,7 @@ fn execute_bus( for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let value_left = treat_result_with_memory_error( - BusSlice::access_value_by_index(&bus_slice, i), + BusSlice::get_reference_to_single_value_by_index(&bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -2353,7 +2341,7 @@ fn execute_bus( for i in 0..BusSlice::get_number_of_cells(&slice){ let value_left = treat_result_with_memory_error( - BusSlice::access_value_by_index(&slice, i), + BusSlice::get_reference_to_single_value_by_index(&slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index f0c74670e..3de056c4b 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -326,6 +326,15 @@ impl MemorySlice { let cell = MemorySlice::get_initial_cell(memory_slice, access)?; Result::Ok(&mut memory_slice.values[cell]) } + pub fn get_mut_reference_to_single_value_by_index<'a>( + memory_slice: &'a mut MemorySlice, + index: usize, + ) -> Result<&'a mut C, MemoryError> { + if index > MemorySlice::get_number_of_cells(memory_slice) { + return Result::Err(MemoryError::OutOfBoundsError); + } + Result::Ok(&mut memory_slice.values[index]) + } pub fn get_number_of_cells(memory_slice: &MemorySlice) -> SliceCapacity { memory_slice.values.len() } From eaadd830a7a73e64de2ad000a5f79839bf74469e Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Tue, 21 May 2024 11:21:22 +0200 Subject: [PATCH 071/189] Modified some tags. --- tests/circomlib/bitify.circom | 12 ++++ tests/circomlib/eddsa.circom | 26 +++---- tests/circomlib/montgomery.circom | 2 +- tests/circomlib/pointbits.circom | 110 +++++++++++++++++++----------- 4 files changed, 97 insertions(+), 53 deletions(-) diff --git a/tests/circomlib/bitify.circom b/tests/circomlib/bitify.circom index 018bb746c..ee964270b 100644 --- a/tests/circomlib/bitify.circom +++ b/tests/circomlib/bitify.circom @@ -100,4 +100,16 @@ template Num2BitsNeg(n) { in ==> isZero.in; lc1 + isZero.out * maxpot === maxpot - in; +} + +template Num2BitsNeg_strict() { + signal input in; + BinaryNumber(254) output {unique} out; + + component aliasCheck = AliasCheck(); + component n2bn = Num2BitsNeg(254); + + in ==> n2bn.in; + n2bn.out ==> aliasCheck.in; + aliasCheck.out ==> out; } \ No newline at end of file diff --git a/tests/circomlib/eddsa.circom b/tests/circomlib/eddsa.circom index ab6ea39ee..5baa77073 100644 --- a/tests/circomlib/eddsa.circom +++ b/tests/circomlib/eddsa.circom @@ -26,9 +26,9 @@ include "escalarmulfix.circom"; template EdDSAVerifier(n) { BinaryNumber(n) input msg; - BinaryNumber(256) input A; - BinaryNumber(256) input R8; - BinaryNumber(256) input S; + BinaryPoint(254) input A; + BinaryPoint(254) input R8; + BinaryPoint(254) input S; Point pA; Point pR8; @@ -37,14 +37,11 @@ template EdDSAVerifier(n) { // Ensure S compConstant.in.bits[i]; - } + compConstant.in <== S.binY; compConstant.out === 0; - S.bits[254] === 0; - S.bits[255] === 0; + S.signX === 0; // Convert A to Field elements (And verify A) @@ -64,10 +61,15 @@ template EdDSAVerifier(n) { component hash = Pedersen(512+n); - for (i=0; i<256; i++) { - hash.in.bits[i] <== R8.bits[i]; - hash.in.bits[256+i] <== A.bits[i]; + for (i=0; i<254; i++) { + hash.in.bits[i] <== R8.binY.bits[i]; + hash.in.bits[256+i] <== A.binY.bits[i]; } + hash.in.bits[254] <== 0; + hash.in.bits[510] <== 0; + hash.in.bits[255] <== R8.signX; + hash.in.bits[511] <== A.signY; + for (i=0; i Date: Tue, 21 May 2024 16:23:21 +0200 Subject: [PATCH 072/189] Improved comments explaining the circuits of the babyjub and montgomery circomlib files. --- tests/circomlib/babyjub.circom | 68 ++++++++++++------ tests/circomlib/montgomery.circom | 110 ++++++++++++++++++------------ 2 files changed, 113 insertions(+), 65 deletions(-) diff --git a/tests/circomlib/babyjub.circom b/tests/circomlib/babyjub.circom index 35a79f061..b7183b853 100644 --- a/tests/circomlib/babyjub.circom +++ b/tests/circomlib/babyjub.circom @@ -22,22 +22,43 @@ include "bitify.circom"; include "montgomery.circom"; include "escalarmulfix.circom"; -// The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) +// The templates and functions of this file only work for finite field F_p = bn128, +// with the prime number p = 21888242871839275222246405745257275088548364400416034343698204186575808495617. /* -*** BabyAdd(): template that receives two points of the Baby Jubjub curve in Edwards form and returns the addition of the points. - - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in Edwards form - p2 = (x2, y2) -> bus representing a point of the curve in Edwards form - - Outputs: pout = (xout, yout) -> bus representing a point of the curve in Edwards form, pout = p1 + p2 - - Example: - - tau = d * x1 * x2 * y1 * y2 - + The Baby-Jubjub Montgomery elliptic curve defined over the finite field bn128 is given by the equation + + B*v^2 = u^3 + A*u^2 + u, A = 168698, B = 1 + + This curve is birationally equivalent to the twisted Edwards elliptic curve + + a*x^2 + y^2 = 1 + d*x^2*y^2, a = 168700 = (A+2)/B, d = 168696 = (A-2)/B + + u u-1 1+y 1+y + via the map (u,v) -> (x,y) = [ --- , ----- ] with inverse (x,y) -> (u,v) = [ ----- , --------- ] + v u+1 1-y (1-y)*x + + Since a is not a square in bn128, the twisted Edwards curve is a quadratic twist of the Edwards curve - x1 * y2 + y1 * x2 y1 * y2 - x1 * x2 - [xout, yout] = [ ----------------------- , ----------------------- ] - 1 + d * tau 1 - d * tau + x'^2 + y'^2 = 1 + d'*x'^2*y'^2 + + via the map (x,y) -> (x',y') = [ sqrt(a)*x , y ] + + where d' = 9706598848417545097372247223557719406784115219466060233080913168975159366771. + We will be working with the twisted Edwards form of the Baby-Jubjub curve because the algorithms for adding, doubling + and multiplying points by a scalar are faster this way. +*/ + +/* +*** BabyAdd(): template that receives two points of the Baby-Jubjub curve in twisted Edwards form and returns the addition of the points. + - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in twisted Edwards form + p2 = (x2, y2) -> bus representing a point of the curve in twisted Edwards form + - Outputs: pout = (xout, yout) -> bus representing a point of the curve in twisted Edwards form, pout = p1 + p2 + + Twisted Edwards Addition Law: + x1*y2 + y1*x2 y1*y2 - a * x1*x2 + [xout, yout] = [x1, y1] + [x2, y2] = [ --------------------- , --------------------- ] + 1 + d * x1*x2*y1*y2 1 - d * x1*x2*y1*y2 */ @@ -68,11 +89,11 @@ template BabyAdd() { /* -*** BabyDouble(): template that receives a point pin of the Baby Jubjub curve in Edwards form and returns the point 2 * pin. - - Inputs: pin = (x1, y1) -> bus representing a point of the curve in Edwards form - - Outputs: pout = (x2, y2) -> bus representing a point of the curve in Edwards form, 2 * pin = pout +*** BabyDouble(): template that receives a point pin of the Baby-Jubjub curve in twisted Edwards form and returns the point 2 * pin. + - Inputs: pin = (x1, y1) -> bus representing a point of the curve in twisted Edwards form + - Outputs: pout = (x2, y2) -> bus representing a point of the curve in twisted Edwards form, 2 * pin = pout - Example: BabyDouble()(p) = BabyAdd()(p, p) + Twisted Edwards Doubling Law: 2 * [x, y] = [x, y] + [x, y] */ @@ -89,12 +110,13 @@ template BabyDbl() { /* -*** BabyCheck(): template that receives an input point pin and checks if it belongs to the Baby Jubjub curve. +*** BabyCheck(): template that receives an input point pin and checks if it belongs to the Baby-Jubjub curve in twisted Edwards form. - Inputs: pin = (x1, y1) -> bus representing the point that we want to check - Outputs: pout = (x2, y2) -> two field values representing the same point as the input but with the babyedwards tag - to point out it is a point of the Baby Jubjub curve in Edwards form + attached to point out it is a point of the Baby-Jubjub curve in twisted Edwards form - Example: The set of solutions of BabyCheck()(p) are the points of the Baby Jubjub curve in Edwards form + The set of solutions of BabyCheck()(p) are the points of the Baby-Jubjub curve in twisted Edwards form. + They must fulfil the equation a*x^2 + y^2 = 1 + d*x^2*y^2, a = 168700, d = 168696. */ @@ -120,8 +142,10 @@ template BabyCheck() { /* -*** BabyPbk(): template that receives an input in representing a value in the prime subgroup with order r = 2736030358979909402780800718157159386076813972158567259200215660948447373041, - and returns the point of the BabyJubjub curve in * P with P being the point P = (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203) +*** BabyPbk(): template that receives an input in representing a value in the prime subgroup with order + r = 2736030358979909402780800718157159386076813972158567259200215660948447373041, + and returns the point of the Baby-Jubjub curve in twisted Edwards form in * P, with P being the point + P = (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203) This template is used to extract the public key from the private key. - Inputs: in -> field value in [1,r-1] diff --git a/tests/circomlib/montgomery.circom b/tests/circomlib/montgomery.circom index 7142beb65..eaeba6925 100644 --- a/tests/circomlib/montgomery.circom +++ b/tests/circomlib/montgomery.circom @@ -19,29 +19,53 @@ pragma circom 2.1.5; - // The templates and functions of this file only work for prime field bn128 (21888242871839275222246405745257275088548364400416034343698204186575808495617) - +// The templates and functions of this file only work for finite field F_p = bn128, +// with the prime number p = 21888242871839275222246405745257275088548364400416034343698204186575808495617. /* Source: https://en.wikipedia.org/wiki/Montgomery_curve */ +/* + The Baby-Jubjub Montgomery elliptic curve defined over the finite field bn128 is given by the equation + + B*v^2 = u^3 + A*u^2 + u, A = 168698, B = 1 + + This curve is birationally equivalent to the twisted Edwards elliptic curve + + a*x^2 + y^2 = 1 + d*x^2*y^2, a = 168700 = (A+2)/B, d = 168696 = (A-2)/B + + u u-1 1+y 1+y + via the map (u,v) -> (x,y) = [ --- , ----- ] with inverse (x,y) -> (u,v) = [ ----- , --------- ] + v u+1 1-y (1-y)*x + + Since a is not a square in bn128, the twisted Edwards curve is a quadratic twist of the Edwards curve + + x'^2 + y'^2 = 1 + d'*x'^2*y'^2 + + via the map (x,y) -> (x',y') = [ sqrt(a)*x , y ] + + where d' = 9706598848417545097372247223557719406784115219466060233080913168975159366771. + Here circuits are provided to transform a point of the Baby-Jubjub curve in twisted Edwards to its Montgomery form and vice versa. + Circuits to add and double points of the Baby-Jubjub Montgomery curve are provided as well. +*/ + bus Point { signal x,y; } /* -*** Edwards2Montgomery(): template that receives an input pin representing a point of an elliptic curve in Edwards form +*** Edwards2Montgomery(): template that receives a point of the Baby-Jubjub curve in twisted Edwards form and returns the equivalent point in Montgomery form. - - Inputs: pin -> bus representing a point of the curve in Edwards form - - Outputs: pout -> bus representing a point of the curve in Montgomery form + - Inputs: pin -> bus representing a point of the Baby-Jubjub curve in twisted Edwards form + - Outputs: pout -> bus representing a point of the Baby-Jubjub curve in Montgomery form - Example: if we consider the input pin = (x, y), then the circuit produces the following output pout = (u, v). + Map from twisted Edwards elliptic curve to its birationally equivalent Montgomery curve: - 1 + y 1 + y - (u, v) = [ ------- , ---------- ] - 1 - y (1 - y)x + 1 + y 1 + y + (x, y) -> (u, v) = [ ------- , ----------- ] + 1 - y (1 - y)*x */ @@ -57,16 +81,16 @@ template Edwards2Montgomery() { } /* -*** Montgomery2Edwards(): template that receives an input pin representing a point of an elliptic curve in Montgomery form - and returns the equivalent point in Edwards form. - - Inputs: pin -> bus representing a point of the curve in Montgomery form - - Outputs: pout -> bus representing a point of the curve in Edwards form +*** Montgomery2Edwards(): template that receives an input pin representing a point of the Baby-Jubjub curve in Montgomery form + and returns the equivalent point in twisted Edwards form. + - Inputs: pin -> bus representing a point of the Baby-Jubjub curve in Montgomery form + - Outputs: pout -> bus representing a point of the curve Baby-Jubjub in twisted Edwards form - Example: if we consider the input pin = (u, v), then the circuit produces the following output pout = (x, y) + Map from Montgomery elliptic curve to its birationally equivalent twisted Edwards curve: - u u - 1 - (x, y) = [ ---, ------- ] - v u + 1 + u u - 1 + (u, v) -> (x, y) = [ ---, ------- ] + v u + 1 */ @@ -83,34 +107,33 @@ template Montgomery2Edwards() { /* -*** MontgomeryAdd(): template that receives two inputs pin1, pin2 representing points of the Baby Jubjub curve in Montgomery form +*** MontgomeryAdd(): template that receives two inputs pin1, pin2 representing points of the Baby-Jubjub curve in Montgomery form and returns the addition of the points. - - Inputs: pin1 -> bus representing a point of the curve in Montgomery form - pin2 -> bus representing a point of the curve in Montgomery form - - Outputs: pout -> bus representing the point pin1 + pin2 in Montgomery form + - Inputs: pin1 -> bus representing a point of the Baby-Jubjub curve in Montgomery form + pin2 -> bus representing a point of the Baby-Jubjub curve in Montgomery form + - Outputs: pout -> bus representing the point pin1 + pin2 of the Baby-Jubjub curve in Montgomery form - Example: if we consider the inputs pin1 = (x1, y1) and pin2 = (x2, y2), then the circuit produces the following output pout = (x3, y3): + Montgomery Addition Law: + + y2 - y1 y2 - y1 y2 - y1 + [x3, y3] = [x1, y1] + [x2, y2] = [ B*( --------- )^2 - A - x1 - x2, ( --------- )*(A + 2*x1 + x2) - B*( --------- )^3 - y1 ] + x2 - x1 x2 - x1 x2 - x1 y2 - y1 lamda = --------- x2 - x1 - x3 = B * lamda^2 - A - x1 -x2 + x3 = B*lamda^2 - A - x1 -x2 - y3 = lamda * ( x1 - x3 ) - y1 - - where A and B are two constants defined below. - */ + y3 = lamda*( x1 - x3 ) - y1 +*/ template MontgomeryAdd() { Point input {babymontgomery} pin1, pin2; Point output {babymontgomery} pout; - var a = 168700; - var d = 168696; - - var A = (2 * (a + d)) / (a - d); - var B = 4 / (a - d); + var A = 168698; + var B = 1; signal lamda; @@ -122,13 +145,17 @@ template MontgomeryAdd() { } /* -*** MontgomeryDouble(): template that receives an input pin representing a point of the Baby Jubjub curve in Montgomery form +*** MontgomeryDouble(): template that receives an input pin representing a point of the Baby-Jubjub curve in Montgomery form and returns the point 2 * pin. - - Inputs: pin -> bus representing a point of the curve in Montgomery form - - Outputs: pout -> bus representing the point 2*pin in Montgomery form + - Inputs: pin -> bus representing a point of the Baby-Jubjub curve in Montgomery form + - Outputs: pout -> bus representing the point 2*pin of the Baby-Jubjub curve in Montgomery form - Example: if we consider the input pin = (x1, y1), then the circuit produces the following output pout = (x2, y2): + Montgomery Doubling Law: + + 3*x1^2 + 2*A*x1 + 1 3*x1^2 + 2*A*x1 + 1 3*x1^2 + 2*A*x1 + 1 + [x2, y2] = 2*[x1, y1] = [ B*( --------------------- )^2 - A - x1 - x2, ( --------------------- )*(A + 2*x1 + x2) - B*( --------------------- )^3 - y1 ] + 2*B*y1 2*B*y1 2*B*y1 x1_2 = x1*x1 @@ -136,9 +163,9 @@ template MontgomeryAdd() { lamda = --------------------- 2*B*y1 - x2 = B * lamda^2 - A - x1 -x1 + x2 = B*lamda^2 - A - x1 -x1 - y2 = lamda * ( x1 - x2 ) - y1 + y2 = lamda*( x1 - x2 ) - y1 */ @@ -146,11 +173,8 @@ template MontgomeryDouble() { Point input {babymontgomery} pin; Point output {babymontgomery} pout; - var a = 168700; - var d = 168696; - - var A = (2 * (a + d)) / (a - d); - var B = 4 / (a - d); + var A = 168698; + var B = 1; signal lamda; signal x1_2; From d7e39f1af060a647a5832061041940a80e6d7ef9 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 22 May 2024 00:08:18 -0700 Subject: [PATCH 073/189] fixing bugs and continue in execute --- constraint_generation/src/assignment_utils.rs | 28 +- .../environment_utils/bus_representation.rs | 101 ++-- .../component_representation.rs | 46 +- constraint_generation/src/execute.rs | 432 ++++++++++-------- program_structure/src/utils/memory_slice.rs | 71 +++ 5 files changed, 391 insertions(+), 287 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index d5b1c01c5..ca767fa4b 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -148,40 +148,38 @@ pub fn perform_signal_assignment(signal_slice: &mut SignalSlice, array_access: & pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCapacity], assigned_bus_slice: &BusSlice)-> Result<(), MemoryError>{ - - let mut value_left = match BusSlice::access_values(&bus_slice, array_access){ - Ok(value) => value, - Err(err) => return Err(err) - }; let correct_dims_result = BusSlice::check_correct_dims( - &value_left, - &Vec::new(), + &bus_slice, + &array_access, &assigned_bus_slice, true ); + + let value_left = match BusSlice::access_values_by_mut_reference(bus_slice, array_access){ + Ok(value) => value, + Err(err) => return Err(err) + }; match correct_dims_result{ Ok(_) => {}, Err(err) => return Err(err) }; - for i in 0..BusSlice::get_number_of_cells(&value_left){ - // We completely assign each one of them - let memory_response_access = BusSlice::get_mut_reference_to_single_value_by_index(&mut value_left, i); - let accessed_bus = match memory_response_access{ - Ok(v) => v, - Err(err) => return Err(err) - }; - let memory_response_assign = BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i); + let mut index = 0; + for accessed_bus in value_left{ + // We completely assign each one of them + let memory_response_assign = BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, index); let assigned_bus = match memory_response_assign{ Ok(v) => v, Err(err) => return Err(err) }; + match accessed_bus.completely_assign_bus(&assigned_bus){ Ok(_) =>{}, Err(err) => return Err(err) }; + index += 1; } diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index d637e8b5e..1555b75fe 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -218,15 +218,14 @@ impl BusRepresentation { match field{ FieldTypes::Bus(bus_slice)=>{ - let memory_response = BusSlice::access_values( - &bus_slice, + let memory_response = BusSlice::access_values_by_mut_reference( + bus_slice, &remaining_access.array_access ); match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let mut resulting_bus = - BusSlice::unwrap_to_single(bus_slice); + Result::Ok(mut bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice.get_mut(0).unwrap(); resulting_bus.assign_value_to_field_signal( remaining_access.field_access.as_ref().unwrap(), &remaining_access.remaining_access.as_ref().unwrap(), @@ -280,7 +279,7 @@ impl BusRepresentation { if signal_is_completely_initialized { - for (tag, value) in tags_info{ + for (tag, _value) in tags_info{ let tag_state = tags_definitions.get_mut(tag).unwrap(); tag_state.complete = true; @@ -316,15 +315,14 @@ impl BusRepresentation { match field{ FieldTypes::Bus(bus_slice)=>{ - let memory_response = BusSlice::access_values( - &bus_slice, + let memory_response = BusSlice::access_values_by_mut_reference( + bus_slice, &remaining_access.array_access ); match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let mut resulting_bus = - BusSlice::unwrap_to_single(bus_slice); + Result::Ok(mut bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice.get_mut(0).unwrap(); resulting_bus.assign_value_to_field_tag( remaining_access.field_access.as_ref().unwrap(), &remaining_access.remaining_access.as_ref().unwrap(), @@ -356,7 +354,7 @@ impl BusRepresentation { FieldTypes::Bus(s) =>{ // TODO, include info about assignments, no recorrer todo for i in 0..BusSlice::get_number_of_cells(s){ - let accessed_bus = BusSlice::access_value_by_index(&s, i)?; + let accessed_bus = BusSlice::get_reference_to_single_value_by_index(&s, i)?; if accessed_bus.has_assignment(){ return Result::Err(MemoryError::AssignmentTagAfterInit) } @@ -404,15 +402,14 @@ impl BusRepresentation { match field{ FieldTypes::Bus(bus_slice)=>{ - let memory_response = BusSlice::access_values( - &bus_slice, + let memory_response = BusSlice::access_values_by_mut_reference( + bus_slice, &remaining_access.array_access ); match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let mut resulting_bus = - BusSlice::unwrap_to_single(bus_slice); + Result::Ok(mut bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice.get_mut(0).unwrap(); resulting_bus.assign_value_to_field_bus( remaining_access.field_access.as_ref().unwrap(), &remaining_access.remaining_access.as_ref().unwrap(), @@ -439,7 +436,7 @@ impl BusRepresentation { let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::access_value_by_index(bus_slice, i){ + match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ Ok(bus) => { bus_is_init |= bus.has_assignment(); } @@ -452,17 +449,19 @@ impl BusRepresentation { // We completely assign each one of the buses - let bus_previous_value = BusSlice::access_values( + let bus_previous_value = BusSlice::access_values_by_mut_reference( bus_slice, &remaining_access.array_access, )?; - let dim_slice: usize = BusSlice::get_number_of_cells(&bus_previous_value); - for i in 0..dim_slice{ - let mut bus_assigned = BusSlice::access_value_by_index(&bus_previous_value, i)?; - let value = BusSlice::access_value_by_index(&assigned_bus, i)?; + let mut index = 0; + let dim_slice = bus_previous_value.len(); + + for bus_assigned in bus_previous_value{ + let value = BusSlice::get_reference_to_single_value_by_index(&assigned_bus, index)?; bus_assigned.completely_assign_bus(&value)?; + index += 1; } // Update the value of unnasigned fields @@ -479,9 +478,9 @@ impl BusRepresentation { // Update the value of the signal tags it is complete let mut bus_is_completely_init = true; for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::access_value_by_index(bus_slice, i){ + match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ Ok(bus) => { - bus_is_init &= bus.has_assignment(); + bus_is_completely_init &= bus.has_assignment(); } Err(_) => unreachable!() } @@ -489,7 +488,7 @@ impl BusRepresentation { if bus_is_completely_init { - for (tag, value) in tags_info{ + for (tag, _value) in tags_info{ let tag_state = tags_definitions.get_mut(tag).unwrap(); tag_state.complete = true; @@ -530,7 +529,7 @@ impl BusRepresentation { FieldTypes::Bus(bus_slice) =>{ let mut bus_is_init = false; for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::access_value_by_index(bus_slice, i){ + match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ Ok(bus) => { bus_is_init |= bus.has_assignment(); } @@ -549,23 +548,17 @@ impl BusRepresentation { match value{ - FieldTypes::Bus(bus_slice) =>{ + FieldTypes::Bus(ref mut bus_slice) =>{ + let bus_slice_assigned = match assigned_bus.fields.get(field_name).unwrap(){ FieldTypes::Bus(bs) => bs, FieldTypes::Signal(_) => unreachable!(), }; - for i in 0..BusSlice::get_number_of_cells(&bus_slice){ - let mut accessed_bus = match BusSlice::access_value_by_index(&bus_slice, i){ - Ok(v) => v, - Err(_) => unreachable!(), - }; - let value_assigned = match BusSlice::access_value_by_index(bus_slice_assigned, i){ - Ok(v) => v, - Err(_) => unreachable!(), - }; - accessed_bus.completely_assign_bus(&value_assigned)?; + let assignment_result = perform_bus_assignment(bus_slice, &[], bus_slice_assigned); + if assignment_result.is_err(){ + return Err(assignment_result.err().unwrap()); } }, FieldTypes::Signal(signal_slice)=>{ @@ -575,16 +568,17 @@ impl BusRepresentation { let new_value_slice = &SignalSlice::new_with_route(signal_slice.route(), &true); - let dim_slice: usize = SignalSlice::get_number_of_cells(signal_slice); - for i in 0..dim_slice{ - let signal_was_assigned = match SignalSlice::access_value_by_index(&signal_slice, i){ - Ok(v) => v, - Err(_) => unreachable!() - }; - if signal_was_assigned { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); - } - } + // Not needed because we know that it has not been assigned? + // let dim_slice: usize = SignalSlice::get_number_of_cells(signal_slice); + // for i in 0..dim_slice{ + // let signal_was_assigned = match SignalSlice::access_value_by_index(&signal_slice, i){ + // Ok(v) => v, + // Err(_) => unreachable!() + // }; + // if signal_was_assigned { + // return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + // } + // } SignalSlice::insert_values( signal_slice, @@ -599,10 +593,9 @@ impl BusRepresentation { // Update the value of unnasigned fields self.unassigned_fields.remove(field_name); // Update the value of the complete tags - for (tag, value) in tags_info{ + for (tag, _value) in tags_info{ let tag_state = tags_definition.get_mut(tag).unwrap(); tag_state.complete = true; - } } Ok(()) @@ -630,7 +623,7 @@ impl BusRepresentation { let mut prefixes = Vec::new(); unfold_signals(accessed_name, 0, dims, &mut prefixes); for i in 0..BusSlice::get_number_of_cells(&bus_slice){ - let access = BusSlice::access_value_by_index(&bus_slice, i); + let access = BusSlice::get_reference_to_single_value_by_index(&bus_slice, i); match access{ Ok(bus) =>{ diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 932a22f6b..2d27175df 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -14,7 +14,7 @@ pub struct ComponentRepresentation { unassigned_inputs: HashMap, unassigned_tags: HashSet, to_assign_inputs: Vec<(String, Vec, Vec)>, - to_assign_input_buses: Vec<(String, Vec, Vec, BusSlice)>, + to_assign_input_buses: Vec<(String, Vec, BusSlice)>, to_assign_input_bus_buses: Vec<(String, AccessingInformationBus, Vec, BusSlice)>, to_assign_input_signal_buses: Vec<(String, AccessingInformationBus, Vec)>, inputs: HashMap, @@ -203,7 +203,7 @@ impl ComponentRepresentation { let to_assign = component.to_assign_input_buses.clone(); for s in to_assign{ let tags_input = component.inputs_tags.get(&s.0).unwrap(); - ComponentRepresentation::assign_value_to_bus_init(component, &s.0, &s.1, &s.2, tags_input.clone(), &s.3)?; + ComponentRepresentation::assign_value_to_bus_init(component, &s.0, &s.1, tags_input.clone(), &s.2)?; } Result::Ok(()) @@ -418,7 +418,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { component: &mut ComponentRepresentation, signal_name: &str, access: &[SliceCapacity], - slice_route: &[SliceCapacity], tags: TagInfo, bus_slice: BusSlice ) -> Result<(), MemoryError> { @@ -427,7 +426,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { component, signal_name, access, - slice_route, tags, bus_slice ) @@ -436,7 +434,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { component, signal_name, access, - slice_route, tags, &bus_slice ) @@ -447,7 +444,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { component: &mut ComponentRepresentation, bus_name: &str, access: &[SliceCapacity], - slice_route: &[SliceCapacity], tags: TagInfo, bus_slice: BusSlice ) -> Result<(), MemoryError> { @@ -455,7 +451,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { return value; } - component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(), slice_route.to_vec(),bus_slice)); + component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(),bus_slice)); Result::Ok(()) } @@ -520,7 +516,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { component: &mut ComponentRepresentation, bus_name: &str, access: &[SliceCapacity], - slice_route: &[SliceCapacity], tags: TagInfo, bus_slice : &BusSlice, ) -> Result<(), MemoryError> { @@ -547,26 +542,17 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { } } - let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); - let bus_previous_value = BusSlice::access_values( - inputs_response, - &access, - )?; - - BusSlice::check_correct_dims( - &bus_previous_value, - &Vec::new(), - &bus_slice, - true - )?; + // Perform the bus assignment - for i in 0..BusSlice::get_number_of_cells(&bus_previous_value){ - let mut bus = BusSlice::access_value_by_index(&bus_previous_value, i)?; - let assigned_bus = BusSlice::access_value_by_index(&bus_previous_value, i)?; - bus.completely_assign_bus(&assigned_bus)?; + let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); + let assignment_result = perform_bus_assignment(inputs_response, &access, bus_slice); + match assignment_result { + Ok(_) =>{}, + Err(err) => return Err(err) } - - let dim = BusSlice::get_number_of_cells(&bus_previous_value); + + // Update the unassigned inputs + let dim = BusSlice::get_number_of_cells(&bus_slice); match component.unassigned_inputs.get_mut(bus_name){ Some(left) => { *left -= dim; @@ -654,10 +640,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { } let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); - let signal_previous_value = BusSlice::access_values( - inputs_response, - &remaining_access.array_access, - )?; let initial_value = BusSlice::get_mut_reference_to_single_value(inputs_response, &remaining_access.array_access)?; initial_value.assign_value_to_field_bus(bus_name, &remaining_access, slice_route, bus_slice, tags) @@ -704,10 +686,6 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { } let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); - let signal_previous_value = BusSlice::access_values( - inputs_response, - &remaining_access.array_access, - )?; let initial_value = BusSlice::get_mut_reference_to_single_value(inputs_response, &remaining_access.array_access)?; initial_value.assign_value_to_field_signal(bus_name, &remaining_access, slice_route, tags) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index fc52bb4d8..9aa025c39 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -70,7 +70,7 @@ impl RuntimeInformation { struct FoldedValue { pub arithmetic_slice: Option, - pub bus_slice: Option, + pub bus_slice: Option<(String, BusSlice)>, // stores the name of the bus and the value pub node_pointer: Option, pub bus_node_pointer: Option, pub is_parallel: Option, @@ -348,6 +348,8 @@ fn execute_statement( &mut runtime.runtime_errors, &runtime.call_trace, )?; + + // TODO: CASE BUSES let full_symbol = format!("{}{}", constrained.left, @@ -1309,10 +1311,9 @@ fn perform_assign( Option::Some(r_slice) }} else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { + let accessing_information = accessing_information.other_access.as_ref().unwrap(); - if accessing_information.tag_access.is_some() { - unreachable!() - } + let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); let component_slice = treat_result_with_environment_error( environment_response, @@ -1339,82 +1340,238 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - if accessing_information.signal_access.is_none() { - let (prenode_pointer, is_parallel) = safe_unwrap_to_valid_node_pointer(r_folded, line!()); - let memory_result = ComponentRepresentation::preinitialize_component( - component, - is_parallel, - prenode_pointer, - &runtime.exec_program, - is_anonymous_component, - meta - ); - treat_result_with_memory_error_void( - memory_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - if component.is_ready_initialize() { - // calls to execute and initialize the component - let pretemplate_info = runtime.exec_program.get_prenode_value(prenode_pointer).unwrap(); - let inputs_tags = component.inputs_tags.clone(); - let result = execute_template_call_complete( - pretemplate_info.template_name(), - pretemplate_info.parameter_instances().clone(), - inputs_tags, - program_archive, - runtime, - flags, - )?; - let (node_pointer, _is_parallel) = safe_unwrap_to_valid_node_pointer(result, line!()); - - let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); - let component_slice = treat_result_with_environment_error( - environment_response, + + if accessing_information.tag_access.is_some() { + // in this case it is a a.bus.field assign + //unreachable!() + // TODO + Option::None + } else{ + // in this case it is a complete bus or a.signal or a.bus assignment + if accessing_information.signal_access.is_none() { + // case complete bus assignment + let (prenode_pointer, is_parallel) = safe_unwrap_to_valid_node_pointer(r_folded, line!()); + let memory_result = ComponentRepresentation::preinitialize_component( + component, + is_parallel, + prenode_pointer, + &runtime.exec_program, + is_anonymous_component, + meta + ); + treat_result_with_memory_error_void( + memory_result, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let memory_response = if is_anonymous_component { - ComponentSlice::get_mut_reference_to_single_value( - component_slice, - &Vec::new(), - ) + if component.is_ready_initialize() { + // calls to execute and initialize the component + let pretemplate_info = runtime.exec_program.get_prenode_value(prenode_pointer).unwrap(); + let inputs_tags = component.inputs_tags.clone(); + let result = execute_template_call_complete( + pretemplate_info.template_name(), + pretemplate_info.parameter_instances().clone(), + inputs_tags, + program_archive, + runtime, + flags, + )?; + let (node_pointer, _is_parallel) = safe_unwrap_to_valid_node_pointer(result, line!()); + + let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); + let component_slice = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let memory_response = if is_anonymous_component { + ComponentSlice::get_mut_reference_to_single_value( + component_slice, + &Vec::new(), + ) + } else{ + ComponentSlice::get_mut_reference_to_single_value( + component_slice, + &accessing_information.before_signal, + ) + }; + let component = treat_result_with_memory_error( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let init_result = ComponentRepresentation::initialize_component( + component, + node_pointer, + &mut runtime.exec_program, + ); + treat_result_with_memory_error( + init_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + match actual_node{ + ExecutedStructure::Template(node) =>{ + let data = SubComponentData { + name: symbol.to_string(), + is_parallel: component.is_parallel, + goes_to: node_pointer, + indexed_with: accessing_information.before_signal.clone(), + }; + node.add_arrow(full_symbol.clone(), data); + }, + ExecutedStructure::Bus(_) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); + } + } + } + Option::None + } else { + // case field assignment (bus or signal) + let assigned_ae_slice = if FoldedValue::valid_arithmetic_slice(&r_folded){ + // it is signal assignment + let signal_accessed = accessing_information.signal_access.clone().unwrap(); + let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); + let tags = if r_folded.tags.is_some() { + r_folded.tags.unwrap() + } else { + TagInfo::new() + }; + + let memory_response = ComponentRepresentation::assign_value_to_signal( + component, + &signal_accessed, + &accessing_information.after_signal, + &arithmetic_slice.route(), + tags, + ); + treat_result_with_memory_error_void( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + arithmetic_slice + } else if FoldedValue::valid_bus_slice(&r_folded){ + // it is a bus input + let bus_accessed = accessing_information.signal_access.clone().unwrap(); + let (name_bus, assigned_bus_slice) = r_folded.bus_slice.unwrap(); + let tags = if r_folded.tags.is_some() { + r_folded.tags.unwrap() + } else { + TagInfo::new() + }; + + // Generate an arithmetic slice for the assigned buses + let mut signals_values: Vec = Vec::new(); + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ + let assigned_bus = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + signals_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + } + let mut ae_signals = Vec::new(); + for signal_name in signals_values{ + ae_signals.push(AExpr::Signal { symbol: signal_name }); + } + + + let memory_response = ComponentRepresentation::assign_value_to_bus_complete( + component, + &bus_accessed, + &accessing_information.after_signal, + tags, + assigned_bus_slice + ); + treat_result_with_memory_error_void( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals) + } else{ - ComponentSlice::get_mut_reference_to_single_value( - component_slice, - &accessing_information.before_signal, - ) + unreachable!(); }; - let component = treat_result_with_memory_error( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let init_result = ComponentRepresentation::initialize_component( - component, - node_pointer, - &mut runtime.exec_program, - ); - treat_result_with_memory_error( - init_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; + if !component.is_initialized && component.is_ready_initialize() { + // calls to execute and initialize the component + let pretemplate_info = runtime.exec_program.get_prenode_value( + component.node_pointer.unwrap() + ).unwrap(); + let inputs_tags = component.inputs_tags.clone(); + + let folded_result = execute_template_call_complete( + pretemplate_info.template_name(), + pretemplate_info.parameter_instances().clone(), + inputs_tags, + program_archive, + runtime, + flags, + )?; + + let (node_pointer, _is_parallel) = safe_unwrap_to_valid_node_pointer(folded_result, line!()); + + let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); + let component_slice = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let memory_response = if is_anonymous_component { + ComponentSlice::get_mut_reference_to_single_value( + component_slice, + &Vec::new(), + ) + } else{ + ComponentSlice::get_mut_reference_to_single_value( + component_slice, + &accessing_information.before_signal, + ) + }; + let component = treat_result_with_memory_error( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let init_result = ComponentRepresentation::initialize_component( + component, + node_pointer, + &mut runtime.exec_program, + ); + treat_result_with_memory_error_void( + init_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; match actual_node{ ExecutedStructure::Template(node) =>{ let data = SubComponentData { name: symbol.to_string(), - is_parallel: component.is_parallel, goes_to: node_pointer, + is_parallel: component.is_parallel, indexed_with: accessing_information.before_signal.clone(), }; - node.add_arrow(full_symbol.clone(), data); + let component_symbol = create_component_symbol(symbol, &accessing_information); + node.add_arrow(component_symbol, data); }, ExecutedStructure::Bus(_) =>{ unreachable!(); @@ -1423,106 +1580,11 @@ fn perform_assign( unreachable!(); } } - } - Option::None - } else { - let signal_accessed = accessing_information.signal_access.clone().unwrap(); - debug_assert!(FoldedValue::valid_arithmetic_slice(&r_folded)); - let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); - let tags = if r_folded.tags.is_some() { - r_folded.tags.unwrap() - } else { - TagInfo::new() - }; - - let memory_response = ComponentRepresentation::assign_value_to_signal( - component, - &signal_accessed, - &accessing_information.after_signal, - &arithmetic_slice.route(), - tags, - ); - treat_result_with_memory_error_void( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - if !component.is_initialized && component.is_ready_initialize() { - // calls to execute and initialize the component - let pretemplate_info = runtime.exec_program.get_prenode_value( - component.node_pointer.unwrap() - ).unwrap(); - let inputs_tags = component.inputs_tags.clone(); - - let folded_result = execute_template_call_complete( - pretemplate_info.template_name(), - pretemplate_info.parameter_instances().clone(), - inputs_tags, - program_archive, - runtime, - flags, - )?; - - let (node_pointer, _is_parallel) = safe_unwrap_to_valid_node_pointer(folded_result, line!()); - - let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); - let component_slice = treat_result_with_environment_error( - environment_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let memory_response = if is_anonymous_component { - ComponentSlice::get_mut_reference_to_single_value( - component_slice, - &Vec::new(), - ) - } else{ - ComponentSlice::get_mut_reference_to_single_value( - component_slice, - &accessing_information.before_signal, - ) - }; - let component = treat_result_with_memory_error( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - - let init_result = ComponentRepresentation::initialize_component( - component, - node_pointer, - &mut runtime.exec_program, - ); - treat_result_with_memory_error_void( - init_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - match actual_node{ - ExecutedStructure::Template(node) =>{ - let data = SubComponentData { - name: symbol.to_string(), - goes_to: node_pointer, - is_parallel: component.is_parallel, - indexed_with: accessing_information.before_signal.clone(), - }; - let component_symbol = create_component_symbol(symbol, &accessing_information); - node.add_arrow(component_symbol, data); - }, - ExecutedStructure::Bus(_) =>{ - unreachable!(); - }, - ExecutedStructure::None => { - unreachable!(); - } } + Option::Some(assigned_ae_slice) } - Option::Some(arithmetic_slice) } + } else if ExecutionEnvironment::has_bus(&runtime.environment, symbol){ let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); @@ -1594,14 +1656,15 @@ fn perform_assign( } else if FoldedValue::valid_arithmetic_slice(&r_folded){ // case assigning a signal of the bus or a tag if meta.get_type_knowledge().is_signal(){ - let value_left = treat_result_with_memory_error( - BusSlice::access_values(&bus_slice, &accessing_information.array_access), + let mut value_left = treat_result_with_memory_error( + BusSlice::access_values_by_mut_reference(bus_slice, &accessing_information.array_access), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - - let mut single_bus = safe_unwrap_to_single(value_left, line!()); + + assert!(value_left.len() == 1); + let single_bus = value_left.get_mut(0).unwrap(); assert!(accessing_information.field_access.is_some()); @@ -1695,14 +1758,15 @@ fn perform_assign( } } else{ // in case it is a tag of one its fields - let value_left = treat_result_with_memory_error( - BusSlice::access_values(&bus_slice, &accessing_information.array_access), + let mut value_left = treat_result_with_memory_error( + BusSlice::access_values_by_mut_reference(bus_slice, &accessing_information.array_access), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let mut single_bus = safe_unwrap_to_single(value_left, line!()); + assert!(value_left.len() == 1); + let single_bus = value_left.get_mut(0).unwrap(); assert!(accessing_information.field_access.is_some()); @@ -1730,7 +1794,7 @@ fn perform_assign( unreachable!(); } } else if FoldedValue::valid_bus_slice(&r_folded){ - let assigned_bus_slice = r_folded.bus_slice.as_ref().unwrap(); + let (name_bus, assigned_bus_slice) = r_folded.bus_slice.as_ref().unwrap(); // case assigning a bus (complete or field) if accessing_information.field_access.is_none(){ @@ -1767,14 +1831,18 @@ fn perform_assign( let mut signals_values: Vec = Vec::new(); for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(r_folded.bus_slice.as_ref().unwrap(), i), + BusSlice::get_reference_to_single_value_by_index(assigned_bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); + signals_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); } + let mut ae_signals = Vec::new(); + for signal_name in signals_values{ + ae_signals.push(AExpr::Signal { symbol: signal_name }); + } // Update the final tags let mut bus_is_completely_init = true; @@ -1807,25 +1875,21 @@ fn perform_assign( } } - let mut ae_signals = Vec::new(); - for signal_name in signals_values{ - ae_signals.push(AExpr::Signal { symbol: signal_name }); - } Some(AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals)) } else{ - let value_left = treat_result_with_memory_error( - BusSlice::access_values(&bus_slice, &accessing_information.array_access), + let mut value_left = treat_result_with_memory_error( + BusSlice::access_values_by_mut_reference(bus_slice, &accessing_information.array_access), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let mut single_bus = safe_unwrap_to_single(value_left, line!()); - + assert!(value_left.len() == 1); + let single_bus = value_left.get_mut(0).unwrap(); assert!(accessing_information.field_access.is_some()); - let bus_slice = r_folded.bus_slice.unwrap(); + let (name_bus, bus_slice) = r_folded.bus_slice.unwrap(); let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() } else { @@ -1857,7 +1921,7 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values.append(&mut assigned_bus.get_accesses_bus(symbol)); + signals_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); } @@ -2269,7 +2333,7 @@ fn execute_bus( } } - Result::Ok(FoldedValue{bus_slice: Some(bus_slice), tags: Some(tags_propagated), ..FoldedValue::default()}) + Result::Ok(FoldedValue{bus_slice: Some((symbol.to_string(), bus_slice)), tags: Some(tags_propagated), ..FoldedValue::default()}) } else{ if meta.get_type_knowledge().is_tag(){ // Case we are accessing a tag of the bus @@ -2367,7 +2431,7 @@ fn execute_bus( } } - Result::Ok(FoldedValue{bus_slice: Some(slice), tags: Some(tags_propagated), ..FoldedValue::default()}) + Result::Ok(FoldedValue{bus_slice: Some((symbol, slice)), tags: Some(tags_propagated), ..FoldedValue::default()}) } else if meta.get_type_knowledge().is_signal(){ // Case we return a signal diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 3de056c4b..8b5a177ce 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -185,6 +185,62 @@ impl MemorySlice { Result::Ok(MemorySlice { route: size, values, number_inserts: 0 }) } + fn generate_references_from_access<'a>( + memory_slice: &'a MemorySlice, + access: &[SliceCapacity], + ) -> Result, MemoryError> { + if access.is_empty() { + let mut values = Vec::new(); + for v in &memory_slice.values{ + values.push(v); + } + return Ok(values); + } + + let (size, number_of_cells) = + MemorySlice::generate_new_route_from_access(memory_slice, access)?; + let mut values = Vec::with_capacity(number_of_cells); + let initial_cell = MemorySlice::get_initial_cell(memory_slice, access)?; + let mut offset = 0; + while offset < number_of_cells { + let new_value = &memory_slice.values[initial_cell + offset]; + values.push(new_value); + offset += 1; + } + + Ok(values) + } + + fn generate_mut_references_from_access<'a>( + memory_slice: &'a mut MemorySlice, + access: &[SliceCapacity], + ) -> Result, MemoryError> { + // TODO: improve, no traverse complete vector + + if access.is_empty() { + let mut values = Vec::new(); + for v in &mut memory_slice.values{ + values.push(v); + } + return Ok(values); + } + + let (size, number_of_cells) = + MemorySlice::generate_new_route_from_access(memory_slice, access)?; + let mut values = Vec::with_capacity(number_of_cells); + let initial_cell = MemorySlice::get_initial_cell(memory_slice, access)?; + + let mut index = 0; + for v in &mut memory_slice.values{ + if index >= initial_cell && index < initial_cell + number_of_cells{ + values.push(v); + } + index += 1; + } + + Ok(values) + } + // User operations pub fn new(initial_value: &C) -> MemorySlice { MemorySlice::new_with_route(&[], initial_value) @@ -282,6 +338,21 @@ impl MemorySlice { ) -> Result, MemoryError> { MemorySlice::generate_slice_from_access(memory_slice, access) } + + pub fn access_values_by_reference<'a>( + memory_slice: &'a MemorySlice, + access: &[SliceCapacity], + ) -> Result, MemoryError> { + MemorySlice::generate_references_from_access(memory_slice, access) + } + + pub fn access_values_by_mut_reference<'a>( + memory_slice: &'a mut MemorySlice, + access: &[SliceCapacity], + ) -> Result, MemoryError> { + MemorySlice::generate_mut_references_from_access(memory_slice, access) + } + pub fn access_value_by_index( memory_slice: &MemorySlice, index: usize, From b5972793d5aac3c34817d33450ec21eef0f935c6 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 22 May 2024 18:31:45 -0700 Subject: [PATCH 074/189] init of input buses --- .../environment_utils/bus_representation.rs | 6 ++++- .../component_representation.rs | 1 + constraint_generation/src/execute.rs | 25 ++++++++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 1555b75fe..4203a823b 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -50,6 +50,7 @@ impl BusRepresentation { component: &mut BusRepresentation, node_pointer: NodePointer, scheme: &ExecutedProgram, + is_input_bus: bool ) -> Result<(), MemoryError> { let possible_node = ExecutedProgram::get_bus_node(scheme, node_pointer); assert!(possible_node.is_some()); @@ -58,8 +59,10 @@ impl BusRepresentation { // Distinguir si es bus o señal y crear la Slice correspondiente // En caso de los buses, crear e inicializar componentRepresentation de todos + // if input bus all signals are set initialize to true, else to false + for (symbol, route) in node.signal_fields() { - let signal_slice = SignalSlice::new_with_route(route, &false); + let signal_slice = SignalSlice::new_with_route(route, &is_input_bus); let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); if signal_slice_size > 0{ component.unassigned_fields @@ -79,6 +82,7 @@ impl BusRepresentation { &mut bus_field, bus_node, scheme, + is_input_bus )?; let bus_slice = BusSlice::new_with_route(route, &bus_field); let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 2d27175df..231fdb589 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -157,6 +157,7 @@ impl ComponentRepresentation { &mut initial_value_bus, bus_node, scheme, + false // it is not initialized at the begining )?; let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 9aa025c39..9d7c174fe 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -327,12 +327,17 @@ fn execute_statement( program_archive, flags )?; + + if let Option::Some(node) = actual_node { if *op == AssignOp::AssignConstraintSignal || (*op == AssignOp::AssignSignal && flags.inspect){ debug_assert!(possible_constraint.is_some()); let constrained = possible_constraint.unwrap(); let mut needs_double_arrow = Vec::new(); + + //let symbols_left = generate_symbols_from_access(var, &access_information, runtime); + for i in 0..AExpressionSlice::get_number_of_cells(&constrained.right){ let value_right = treat_result_with_memory_error( AExpressionSlice::access_value_by_index(&constrained.right, i), @@ -654,7 +659,7 @@ fn execute_bus_statement( execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, false), VariableType::Bus(_id, _signal_type, tag_list) => - execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, false), + execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, true), _ =>{ unreachable!() @@ -1586,6 +1591,9 @@ fn perform_assign( } } else if ExecutionEnvironment::has_bus(&runtime.environment, symbol){ + + // we check if it is an input bus, in that case all signals are initialized to true + let is_input_bus = ExecutionEnvironment::has_input_bus(&runtime.environment, symbol); let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); @@ -1601,13 +1609,12 @@ fn perform_assign( if FoldedValue::valid_bus_node_pointer(&r_folded){ // in this case we are performing an assigment of the type in the node_pointer // to the bus in the left - + let bus_pointer = r_folded.bus_node_pointer.unwrap(); // in this case we cannot assign to a single value of the array debug_assert!(accessing_information.array_access.len() == 0); debug_assert!(accessing_information.field_access.is_none()); - for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let mut value_left = treat_result_with_memory_error( @@ -1621,6 +1628,7 @@ fn perform_assign( &mut value_left, bus_pointer, &runtime.exec_program, + is_input_bus ); treat_result_with_memory_error_void( memory_result, @@ -2112,6 +2120,14 @@ fn create_index_appendix(indexing: &[usize]) -> String { appendix } + +// fn create_symbols_form_access_bus(symbol: &str, access_information: &AccessingInformationBus,runtime: &RuntimeInformation)-> Vec{ +// let prefix = create_symbol_bus(symbol, access_information); +// if ExecutionEnvironment::has_bus(&runtime.environment, symbol) { +// execute_signal(meta, name, access, program_archive, runtime, flags)? +// } +// } + fn execute_variable( meta: &Meta, symbol: &str, @@ -2303,7 +2319,8 @@ fn execute_bus( if access_information.field_access.is_none() { // Case we are accessing the complete bus or array of buses - + let symbol = create_symbol_bus(symbol, &access_information); + let mut tags_propagated = TagInfo::new(); for (tag, value) in tags{ let state = tags_definitions.get(tag).unwrap(); From 190d38f706a2080a6ed2e5d024a2f87c6a0c44fb Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 22 May 2024 19:29:47 -0700 Subject: [PATCH 075/189] adding info signal names for assignment --- constraint_generation/src/execute.rs | 157 ++++++++++++++++++++------- 1 file changed, 116 insertions(+), 41 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 9d7c174fe..d2b791c4f 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -336,8 +336,6 @@ fn execute_statement( let mut needs_double_arrow = Vec::new(); - //let symbols_left = generate_symbols_from_access(var, &access_information, runtime); - for i in 0..AExpressionSlice::get_number_of_cells(&constrained.right){ let value_right = treat_result_with_memory_error( AExpressionSlice::access_value_by_index(&constrained.right, i), @@ -347,19 +345,13 @@ fn execute_statement( )?; - let access_left = treat_result_with_memory_error( - AExpressionSlice::get_access_index(&constrained.right, i), + let signal_left = treat_result_with_memory_error( + AExpressionSlice::access_value_by_index(&constrained.left, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - // TODO: CASE BUSES - - let full_symbol = format!("{}{}", - constrained.left, - create_index_appendix(&access_left), - ); if let AssignOp::AssignConstraintSignal = op { if value_right.is_nonquadratic() { let err = Result::Err(ExecutionError::NonQuadraticConstraint); @@ -371,15 +363,22 @@ fn execute_statement( )?; } else { let p = runtime.constants.get_p().clone(); - let symbol = AExpr::Signal { symbol: full_symbol }; + let symbol = signal_left; let expr = AExpr::sub(&symbol, &value_right, &p); let ctr = AExpr::transform_expression_to_constraint_form(expr, &p).unwrap(); node.add_constraint(ctr); } } else if let AssignOp::AssignSignal = op {// needs fix, check case arrays //debug_assert!(possible_constraint.is_some()); + let signal_name = match signal_left{ + AExpr::Signal { symbol } =>{ + symbol + }, + _ => unreachable!() + }; + if !value_right.is_nonquadratic() && !node.is_custom_gate { - needs_double_arrow.push(full_symbol); + needs_double_arrow.push(signal_name); } } } @@ -1092,7 +1091,7 @@ enum ExecutedStructure<'a>{ } struct Constrained { - left: String, + left: AExpressionSlice, right: AExpressionSlice, } @@ -1122,7 +1121,7 @@ fn perform_assign( create_symbol(symbol, &accessing_information.other_access.as_ref().unwrap()) }; - let possible_arithmetic_slice = if ExecutionEnvironment::has_variable(&runtime.environment, symbol) + let possible_arithmetic_slices = if ExecutionEnvironment::has_variable(&runtime.environment, symbol) { let accessing_information = accessing_information.other_access.as_ref().unwrap(); debug_assert!(accessing_information.signal_access.is_none()); @@ -1313,7 +1312,17 @@ fn perform_assign( } } - Option::Some(r_slice) + // Get left arithmetic slice + let mut l_signal_names = Vec::new();; + unfold_signals(full_symbol, 0, r_slice.route(), &mut l_signal_names); + let mut l_expressions = Vec::new(); + for signal_name in l_signal_names{ + l_expressions.push(AExpr::Signal { symbol: signal_name }); + } + let l_slice = AExpressionSlice::new_array(r_slice.route().to_vec(), l_expressions); + + // We return both the left and right slices + Option::Some((l_slice, r_slice)) }} else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { @@ -1354,7 +1363,7 @@ fn perform_assign( } else{ // in this case it is a complete bus or a.signal or a.bus assignment if accessing_information.signal_access.is_none() { - // case complete bus assignment + // case complete component assignment let (prenode_pointer, is_parallel) = safe_unwrap_to_valid_node_pointer(r_folded, line!()); let memory_result = ComponentRepresentation::preinitialize_component( component, @@ -1466,7 +1475,16 @@ fn perform_assign( &runtime.call_trace, )?; - arithmetic_slice + // Get left arithmetic slice + let mut l_signal_names = Vec::new(); + unfold_signals(full_symbol, 0, arithmetic_slice.route(), &mut l_signal_names); + let mut l_expressions = Vec::new(); + for signal_name in l_signal_names{ + l_expressions.push(AExpr::Signal { symbol: signal_name }); + } + let l_slice = AExpressionSlice::new_array(arithmetic_slice.route().to_vec(), l_expressions); + + (l_slice, arithmetic_slice) } else if FoldedValue::valid_bus_slice(&r_folded){ // it is a bus input let bus_accessed = accessing_information.signal_access.clone().unwrap(); @@ -1477,8 +1495,10 @@ fn perform_assign( TagInfo::new() }; - // Generate an arithmetic slice for the assigned buses - let mut signals_values: Vec = Vec::new(); + // Generate an arithmetic slice for the buses left and right + let mut signals_values_right: Vec = Vec::new(); + let mut signals_values_left: Vec = Vec::new(); + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i), @@ -1486,11 +1506,18 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + // TODO: do not call twice to get_accesses + signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", full_symbol, i))); + } + + let mut ae_signals_right = Vec::new(); + for signal_name in signals_values_right{ + ae_signals_right.push(AExpr::Signal { symbol: signal_name }); } - let mut ae_signals = Vec::new(); - for signal_name in signals_values{ - ae_signals.push(AExpr::Signal { symbol: signal_name }); + let mut ae_signals_left = Vec::new(); + for signal_name in signals_values_left{ + ae_signals_left.push(AExpr::Signal { symbol: signal_name }); } @@ -1507,7 +1534,12 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals) + + // Generate the ae expressions + + let ae_right = AExpressionSlice::new_array([ae_signals_right.len()].to_vec(), ae_signals_right); + let ae_left = AExpressionSlice::new_array([ae_signals_left.len()].to_vec(), ae_signals_left); + (ae_left, ae_right) } else{ unreachable!(); @@ -1586,6 +1618,9 @@ fn perform_assign( } } } + + + Option::Some(assigned_ae_slice) } } @@ -1695,7 +1730,17 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - Some(arithmetic_slice) + + // Get left arithmetic slice + let mut l_signal_names = Vec::new();; + unfold_signals(full_symbol, 0, arithmetic_slice.route(), &mut l_signal_names); + let mut l_expressions = Vec::new(); + for signal_name in l_signal_names{ + l_expressions.push(AExpr::Signal { symbol: signal_name }); + } + let l_slice = AExpressionSlice::new_array(arithmetic_slice.route().to_vec(), l_expressions); + Some((l_slice, arithmetic_slice)) + } else if meta.get_type_knowledge().is_tag(){ // in case we are assigning a tag of the complete bus assert!(accessing_information.array_access.len() == 0); @@ -1836,7 +1881,8 @@ fn perform_assign( )?; // Generate an arithmetic slice for the accessed buses - let mut signals_values: Vec = Vec::new(); + let mut signals_values_left: Vec = Vec::new(); + let mut signals_values_right = Vec::new(); for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( BusSlice::get_reference_to_single_value_by_index(assigned_bus_slice, i), @@ -1844,12 +1890,17 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", full_symbol, i))); + signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); } - let mut ae_signals = Vec::new(); - for signal_name in signals_values{ - ae_signals.push(AExpr::Signal { symbol: signal_name }); + let mut ae_signals_left = Vec::new(); + for signal_name in signals_values_left{ + ae_signals_left.push(AExpr::Signal { symbol: signal_name }); + } + let mut ae_signals_right = Vec::new(); + for signal_name in signals_values_right{ + ae_signals_right.push(AExpr::Signal { symbol: signal_name }); } // Update the final tags @@ -1883,7 +1934,12 @@ fn perform_assign( } } - Some(AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals)) + // Update the left slice + let l_slice = AExpressionSlice::new_array([ae_signals_left.len()].to_vec(), ae_signals_left); + let r_slice = AExpressionSlice::new_array([ae_signals_right.len()].to_vec(), ae_signals_right); + + + Some((l_slice, r_slice)) } else{ let mut value_left = treat_result_with_memory_error( @@ -1918,8 +1974,10 @@ fn perform_assign( &runtime.call_trace, )?; + // Update the left and right slices + let mut signals_values_left: Vec = Vec::new(); + let mut signals_values_right: Vec = Vec::new(); - let mut signals_values: Vec = Vec::new(); for i in 0..BusSlice::get_number_of_cells(&bus_slice){ // We generate an arithmetic slice with the result @@ -1929,16 +1987,22 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); - + signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", full_symbol, i))); + signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + } - let mut ae_signals = Vec::new(); - for signal_name in signals_values{ - ae_signals.push(AExpr::Signal { symbol: signal_name }); + let mut ae_signals_left = Vec::new(); + for signal_name in signals_values_left{ + ae_signals_left.push(AExpr::Signal { symbol: signal_name }); } - Some(AExpressionSlice::new_array([ae_signals.len()].to_vec(), ae_signals)) - + let mut ae_signals_right = Vec::new(); + for signal_name in signals_values_right{ + ae_signals_right.push(AExpr::Signal { symbol: signal_name }); + } + let l_slice = AExpressionSlice::new_array([ae_signals_left.len()].to_vec(), ae_signals_left); + let r_slice = AExpressionSlice::new_array([ae_signals_right.len()].to_vec(), ae_signals_right); + Some((l_slice, r_slice)) } } else{ @@ -1949,8 +2013,8 @@ fn perform_assign( } else { unreachable!(); }; - if let Option::Some(arithmetic_slice) = possible_arithmetic_slice { - let ret = Constrained { left: full_symbol, right: arithmetic_slice }; + if let Option::Some((arithmetic_slice_left, arithmetic_slice_right)) = possible_arithmetic_slices { + let ret = Constrained { left: arithmetic_slice_left, right: arithmetic_slice_right }; Result::Ok(Some(ret)) } else { Result::Ok(None) @@ -3092,6 +3156,17 @@ pub fn get_final_array_access_bus_accessing(access: &AccessingInformationBus)->& } +pub fn generate_symbols_from_access(symbol: &str, access: &TypesAccess, runtime: & RuntimeInformation)->Vec{ + if access.other_access.is_some(){ + let access = access.other_access.as_ref().unwrap(); + let (_, _ ,signal_slice) = runtime.environment.get_signal(symbol).unwrap(); + let route = signal_slice.route(); + + } + Vec::new() +} + + //************************************************* Safe transformations ************************************************* fn safe_unwrap_to_single_arithmetic_expression(folded_value: FoldedValue, line: u32) -> AExpr { From 00269be132e7ec31504081b5e142a110b12e32a4 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 23 May 2024 11:59:43 -0700 Subject: [PATCH 076/189] solving small issues --- compiler/src/hir/very_concrete_program.rs | 3 +- .../environment_utils/bus_representation.rs | 53 ++- .../component_representation.rs | 13 +- constraint_generation/src/execute.rs | 330 ++++++++++++------ .../src/execution_data/filters.rs | 3 + tests/circomlib/escalarmulfix.circom | 5 +- 6 files changed, 283 insertions(+), 124 deletions(-) diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index f6834f9d7..02e20507e 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -215,7 +215,8 @@ impl VCP { quick_knowledge: HashMap::new(), prime: config.prime, }; - super::merger::run_preprocessing(&mut vcp, config.program); + // TODO: continue from here + //super::merger::run_preprocessing(&mut vcp, config.program); vcp } pub fn add_witness_list(&mut self, witness: Rc>) { diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 4203a823b..0fd6252de 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -56,11 +56,9 @@ impl BusRepresentation { assert!(possible_node.is_some()); let node = possible_node.unwrap(); - // Distinguir si es bus o señal y crear la Slice correspondiente - // En caso de los buses, crear e inicializar componentRepresentation de todos // if input bus all signals are set initialize to true, else to false - + // initialice the signals for (symbol, route) in node.signal_fields() { let signal_slice = SignalSlice::new_with_route(route, &is_input_bus); let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); @@ -70,10 +68,26 @@ impl BusRepresentation { } let field_signal = FieldTypes::Signal(signal_slice); component.fields.insert(symbol.clone(), field_signal); + + // add the tags + if node.signal_to_tags.get(symbol).is_some(){ + let defined_tags = node.signal_to_tags.get(symbol).unwrap(); + let mut definitions = BTreeMap::new(); + let mut values = BTreeMap::new(); + for (tag, value) in defined_tags{ + let tag_state = TagState{defined:true, value_defined: value.is_some(), complete: true}; + definitions.insert(tag.clone(), tag_state); + values.insert(tag.clone(), value.clone()); + + } + component.field_tags.insert(symbol.clone(), (definitions, values)); + } else{ + component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); + } } + // now the buses let bus_connexions = node.bus_connexions(); - for (symbol, route) in node.bus_fields() { let bus_node = bus_connexions.get(symbol).unwrap().inspect.goes_to; @@ -92,6 +106,37 @@ impl BusRepresentation { } let field_bus = FieldTypes::Bus(bus_slice); component.fields.insert(symbol.clone(), field_bus); + + // add the tags + if node.signal_to_tags.get(symbol).is_some(){ + let defined_tags = node.signal_to_tags.get(symbol).unwrap(); + let mut definitions = BTreeMap::new(); + let mut values = BTreeMap::new(); + for (tag, value) in defined_tags{ + let tag_state = TagState{defined:true, value_defined: value.is_some(), complete: true}; + definitions.insert(tag.clone(), tag_state); + values.insert(tag.clone(), value.clone()); + + } + component.field_tags.insert(symbol.clone(), (definitions, values)); + } else{ + component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); + } + // add the tags + if node.signal_to_tags.get(symbol).is_some(){ + let defined_tags = node.signal_to_tags.get(symbol).unwrap(); + let mut definitions = BTreeMap::new(); + let mut values = BTreeMap::new(); + for (tag, value) in defined_tags{ + let tag_state = TagState{defined:true, value_defined: value.is_some(), complete: true}; + definitions.insert(tag.clone(), tag_state); + values.insert(tag.clone(), value.clone()); + + } + component.field_tags.insert(symbol.clone(), (definitions, values)); + } else{ + component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); + } } component.node_pointer = Option::Some(node_pointer); diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 231fdb589..0bc8db3d8 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -189,8 +189,17 @@ impl ComponentRepresentation { } for (symbol, route) in node.bus_outputs() { - component.output_buses.insert(symbol.clone(), BusSlice::new_with_route(route, &BusRepresentation::default())); - insert_tags_output(node, symbol, component); + let mut initial_value_bus = BusRepresentation::default(); + let bus_node = node.bus_connexions.get(symbol).unwrap().inspect.goes_to; + BusRepresentation::initialize_bus( + &mut initial_value_bus, + bus_node, + scheme, + true // it is initialized at the begining + )?; + let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); + + component.output_buses.insert(symbol.clone(), bus_slice); } component.node_pointer = Option::Some(node_pointer); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index d2b791c4f..18727983a 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -767,31 +767,40 @@ fn execute_expression( }; let f_value = execute_expression(value, program_archive, runtime, flags)?; - let slice_value = safe_unwrap_to_arithmetic_slice(f_value, line!()); + if FoldedValue::valid_arithmetic_slice(&f_value){ + let slice_value = safe_unwrap_to_arithmetic_slice(f_value, line!()); - let mut dims = vec![usable_dimension]; - for dim in slice_value.route() { - dims.push(*dim); - } - - let mut array_slice = AExpressionSlice::new_with_route(&dims, &AExpr::default()); - let mut row: SliceCapacity = 0; - while row < usable_dimension { - let memory_insert_result = AExpressionSlice::insert_values( - &mut array_slice, - &[row], - &slice_value, - false - ); - treat_result_with_memory_error_void( - memory_insert_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - row += 1; + let mut dims = vec![usable_dimension]; + for dim in slice_value.route() { + dims.push(*dim); + } + + let mut array_slice = AExpressionSlice::new_with_route(&dims, &AExpr::default()); + let mut row: SliceCapacity = 0; + while row < usable_dimension { + let memory_insert_result = AExpressionSlice::insert_values( + &mut array_slice, + &[row], + &slice_value, + false + ); + treat_result_with_memory_error_void( + memory_insert_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + row += 1; + } + FoldedValue { arithmetic_slice: Option::Some(array_slice), ..FoldedValue::default() } + } else if FoldedValue::valid_bus_node_pointer(&f_value){ + let node_pointer = safe_unwrap_to_valid_bus_node_pointer(f_value, line!()); + + FoldedValue { bus_node_pointer: Option::Some(node_pointer), ..FoldedValue::default() } + } else{ + unreachable!(); } - FoldedValue { arithmetic_slice: Option::Some(array_slice), ..FoldedValue::default() } + } InfixOp { meta, lhe, infix_op, rhe, .. } => { let l_fold = execute_expression(lhe, program_archive, runtime, flags)?; @@ -1499,6 +1508,7 @@ fn perform_assign( let mut signals_values_right: Vec = Vec::new(); let mut signals_values_left: Vec = Vec::new(); + // TODO: get the correct final index for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i), @@ -1506,9 +1516,18 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - // TODO: do not call twice to get_accesses - signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); - signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", full_symbol, i))); + // TODO: do not call twice to get_accesses and better index + + let access_index = treat_result_with_memory_error( + BusSlice::get_access_index(&assigned_bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let string_index = create_index_appendix(&access_index); + + signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", name_bus, string_index))); + signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", full_symbol, string_index))); } let mut ae_signals_right = Vec::new(); @@ -1890,8 +1909,17 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", full_symbol, i))); - signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + // TODO + let access_index = treat_result_with_memory_error( + BusSlice::get_access_index(&assigned_bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let string_index = create_index_appendix(&access_index); + + signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", name_bus, string_index))); + signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", full_symbol, string_index))); } let mut ae_signals_left = Vec::new(); @@ -1953,7 +1981,7 @@ fn perform_assign( let single_bus = value_left.get_mut(0).unwrap(); assert!(accessing_information.field_access.is_some()); - let (name_bus, bus_slice) = r_folded.bus_slice.unwrap(); + let (name_bus, bus_slice) = r_folded.bus_slice.as_ref().unwrap(); let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() } else { @@ -1987,8 +2015,18 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; - signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", full_symbol, i))); - signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}[{}]", name_bus, i))); + + // TODO + let access_index = treat_result_with_memory_error( + BusSlice::get_access_index(&assigned_bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let string_index = create_index_appendix(&access_index); + + signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", name_bus, string_index))); + signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", full_symbol, string_index))); } @@ -2577,109 +2615,170 @@ fn execute_component( runtime: &mut RuntimeInformation, flags: FlagsExecution ) -> Result { - let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; - if access_information.undefined { - let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); - return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); - } - let environment_response = + + + // TODO: cases access signal/bus inside a bus, all in same case + if meta.get_type_knowledge().is_signal(){ + + let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; + if access_information.undefined { + let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); + return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); + } + + let environment_response = ExecutionEnvironment::get_component_res(&runtime.environment, symbol); - let component_slice = treat_result_with_environment_error( - environment_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let memory_response = if runtime.anonymous_components.contains_key(symbol) { - ComponentSlice::access_values(component_slice, &Vec::new()) - } else{ - ComponentSlice::access_values(component_slice, &access_information.before_signal) - }; - let slice_result = treat_result_with_memory_error( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let resulting_component = safe_unwrap_to_single(slice_result, line!()); - - if let Some(acc) = access_information.tag_access { - let (tags_signal, _) = treat_result_with_memory_error( - resulting_component.get_signal(&access_information.signal_access.unwrap()), + let component_slice = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let memory_response = if runtime.anonymous_components.contains_key(symbol) { + ComponentSlice::access_values(component_slice, &Vec::new()) + } else{ + ComponentSlice::access_values(component_slice, &access_information.before_signal) + }; + let slice_result = treat_result_with_memory_error( + memory_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; + let resulting_component = safe_unwrap_to_single(slice_result, line!()); - if tags_signal.contains_key(&acc) { - let value_tag = tags_signal.get(&acc).unwrap(); - if let Some(value_tag) = value_tag { - let a_value = AExpr::Number { value: value_tag.clone() }; - let ae_slice = AExpressionSlice::new(&a_value); - Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - } - else { - let error = MemoryError::TagValueNotInitializedAccess; - treat_result_with_memory_error( - Result::Err(error), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )? + if let Some(acc) = access_information.tag_access { + let (tags_signal, _) = treat_result_with_memory_error( + resulting_component.get_signal(&access_information.signal_access.unwrap()), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + if tags_signal.contains_key(&acc) { + let value_tag = tags_signal.get(&acc).unwrap(); + if let Some(value_tag) = value_tag { + let a_value = AExpr::Number { value: value_tag.clone() }; + let ae_slice = AExpressionSlice::new(&a_value); + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) + } + else { + let error = MemoryError::TagValueNotInitializedAccess; + treat_result_with_memory_error( + Result::Err(error), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + } else { + unreachable!() } + + } + else if let Option::Some(signal_name) = &access_information.signal_access { + let access_after_signal = &access_information.after_signal; + let (tags_signal, signal) = treat_result_with_memory_error( + resulting_component.get_signal(signal_name), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let slice = SignalSlice::access_values(signal, &access_after_signal); + let slice = treat_result_with_memory_error( + slice, + meta, + &mut runtime.runtime_errors, + &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), + tags: Option::Some(tags_signal.clone()), + ..FoldedValue::default() + }); + treat_result_with_memory_error( + result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + ) } else { - unreachable!() + let read_result = if resulting_component.is_ready_initialize() { + Result::Ok(resulting_component) + } else { + Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent)) + }; + + let checked_component = treat_result_with_memory_error( + read_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + Result::Ok(FoldedValue { + node_pointer: checked_component.node_pointer, + is_parallel: Some(false), + ..FoldedValue::default() + }) + } + } else if meta.get_type_knowledge().is_bus(){ + let access_information = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; + if access_information.undefined { + let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); + return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); } - } - else if let Option::Some(signal_name) = &access_information.signal_access { - let access_after_signal = &access_information.after_signal; - let (tags_signal, signal) = treat_result_with_memory_error( - resulting_component.get_signal(signal_name), + let environment_response = + ExecutionEnvironment::get_component_res(&runtime.environment, symbol); + let component_slice = treat_result_with_environment_error( + environment_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let slice = SignalSlice::access_values(signal, &access_after_signal); - let slice = treat_result_with_memory_error( - slice, + let memory_response = if runtime.anonymous_components.contains_key(symbol) { + ComponentSlice::access_values(component_slice, &Vec::new()) + } else{ + ComponentSlice::access_values(component_slice, &access_information.array_access) + }; + let slice_result = treat_result_with_memory_error( + memory_response, meta, &mut runtime.runtime_errors, &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), - tags: Option::Some(tags_signal.clone()), - ..FoldedValue::default() - }); - treat_result_with_memory_error( - result, + // TODO: just case accessing complete bus + let resulting_component = safe_unwrap_to_single(slice_result, line!()); + let result_access = resulting_component.get_complete_bus(access_information.field_access.as_ref().unwrap()); + let (tags_bus, bus_slice) = treat_result_with_memory_error( + result_access, meta, &mut runtime.runtime_errors, &runtime.call_trace, - ) - } else { - let read_result = if resulting_component.is_ready_initialize() { - Result::Ok(resulting_component) - } else { - Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent)) - }; - - let checked_component = treat_result_with_memory_error( - read_result, + )?; + let slice = BusSlice::access_values(bus_slice, &access_information.remaining_access.as_ref().unwrap().array_access); + let slice = treat_result_with_memory_error( + slice, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - + let symbol = create_symbol_bus(symbol, &access_information); + Result::Ok(FoldedValue { - node_pointer: checked_component.node_pointer, - is_parallel: Some(false), + bus_slice: Some((symbol, slice)), + tags: Some(tags_bus.clone()), ..FoldedValue::default() }) } + else{ + // TODO: REFRACT AND CHANGE ACCESSING_INFORMATION + unreachable!() + } + } fn prepare_environment_for_call( @@ -2688,10 +2787,15 @@ fn prepare_environment_for_call( program_archive: &ProgramArchive, ) -> ExecutionEnvironment { let functions = program_archive.get_function_names(); + let templates = program_archive.get_template_names(); + let arg_names = if functions.contains(id) { program_archive.get_function_data(id).get_name_of_params() - } else { + } else if templates.contains(id){ program_archive.get_template_data(id).get_name_of_params() + } else { + // case bus + program_archive.get_bus_data(id).get_name_of_params() }; let mut environment = ExecutionEnvironment::new(); @@ -3156,16 +3260,6 @@ pub fn get_final_array_access_bus_accessing(access: &AccessingInformationBus)->& } -pub fn generate_symbols_from_access(symbol: &str, access: &TypesAccess, runtime: & RuntimeInformation)->Vec{ - if access.other_access.is_some(){ - let access = access.other_access.as_ref().unwrap(); - let (_, _ ,signal_slice) = runtime.environment.get_signal(symbol).unwrap(); - let route = signal_slice.route(); - - } - Vec::new() -} - //************************************************* Safe transformations ************************************************* @@ -3181,6 +3275,10 @@ fn safe_unwrap_to_valid_node_pointer(folded_value: FoldedValue, line: u32) -> (N debug_assert!(FoldedValue::valid_node_pointer(&folded_value), "Caused by call at {}", line); (folded_value.node_pointer.unwrap(), folded_value.is_parallel.unwrap()) } +fn safe_unwrap_to_valid_bus_node_pointer(folded_value: FoldedValue, line: u32) -> NodePointer { + debug_assert!(FoldedValue::valid_bus_node_pointer(&folded_value), "Caused by call at {}", line); + folded_value.bus_node_pointer.unwrap() +} fn safe_unwrap_to_single(slice: MemorySlice, line: u32) -> C { debug_assert!(slice.is_single(), "Caused by call at {}", line); MemorySlice::unwrap_to_single(slice) diff --git a/constraint_generation/src/execution_data/filters.rs b/constraint_generation/src/execution_data/filters.rs index 20b080ab4..31a3fd1bb 100644 --- a/constraint_generation/src/execution_data/filters.rs +++ b/constraint_generation/src/execution_data/filters.rs @@ -189,6 +189,9 @@ fn apply_computed_expr(expr: &mut Expression, analysis: &Analysis) { *rhe = Box::new(computed_or_original(analysis, rhe)); apply_computed_expr(rhe, analysis); } + BusCall{args, ..} =>{ + apply_computed_expr_vec(args, analysis); + } _ => {unreachable!("Anonymous calls should not be reachable at this point."); } } } diff --git a/tests/circomlib/escalarmulfix.circom b/tests/circomlib/escalarmulfix.circom index 7118a2073..eef4b3325 100644 --- a/tests/circomlib/escalarmulfix.circom +++ b/tests/circomlib/escalarmulfix.circom @@ -283,4 +283,7 @@ template EscalarMulFix(n, BASE) { } else { adders[nsegments-2].pout ==> out; } -} \ No newline at end of file +} + + + From ed902e65507a2af588642b4d3a4b47b84214a4bb Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 23 May 2024 15:06:22 -0700 Subject: [PATCH 077/189] improving component and bus representation access -> now works for any case and more modular code --- constraint_generation/src/assignment_utils.rs | 13 ++ .../environment_utils/bus_representation.rs | 99 ++++++++- .../component_representation.rs | 129 ++++++++--- .../src/environment_utils/slice_types.rs | 7 + constraint_generation/src/execute.rs | 210 +++++++----------- 5 files changed, 296 insertions(+), 162 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index ca767fa4b..ef1e38802 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -12,6 +12,19 @@ use std::mem; // Utils for assigning tags +pub fn check_tags_access(tags_values: &TagInfo, tags_definitions: &TagDefinitions)-> TagInfo{ + let mut tags_propagated = TagInfo::new(); + for (tag, value) in tags_values{ + let state = tags_definitions.get(tag).unwrap(); + if state.value_defined || state.complete{ + tags_propagated.insert(tag.clone(), value.clone()); + } else if state.defined{ + tags_propagated.insert(tag.clone(), None); + } + } + tags_propagated +} + pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut TagDefinitions, assigned_tags: &TagInfo, is_init: bool){ // Study the tags: add the new ones and copy their content. /* diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 0fd6252de..4a7529e4d 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,6 +1,6 @@ use program_structure::ast::Access; -use super::slice_types::{AExpressionSlice, FieldTypes, MemoryError, TypeInvalidAccess, TypeAssignmentError, SignalSlice, BusSlice, SliceCapacity,TagInfo, TagDefinitions, TagState}; +use super::slice_types::{AExpressionSlice, BusSlice, FieldTypes, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TagState, TypeAssignmentError, TypeInvalidAccess}; use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap, HashSet}; @@ -84,6 +84,9 @@ impl BusRepresentation { } else{ component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); } + if is_input_bus{ + component.unassigned_fields.remove(symbol); + } } // now the buses @@ -137,6 +140,9 @@ impl BusRepresentation { } else{ component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); } + if is_input_bus{ + component.unassigned_fields.remove(symbol); + } } component.node_pointer = Option::Some(node_pointer); @@ -145,6 +151,97 @@ impl BusRepresentation { Result::Ok(()) } + pub fn get_field( + &self, + field_name: &str, + remaining_access: &AccessingInformationBus + ) -> Result<(Option, FoldedResult), MemoryError>{ + + let field = self.fields.get(field_name).unwrap(); + let (tags_defs, tags_info) = self.field_tags.get(field_name).unwrap(); + if remaining_access.field_access.is_some(){ + // we are still considering an intermediate bus or a tag, check cases + let next_access = remaining_access.field_access.as_ref().unwrap(); + if tags_info.contains_key(next_access){ + // case tag, return its value + let value_tag = tags_info.get(next_access).unwrap(); + match value_tag{ + None =>{ + let error = MemoryError::TagValueNotInitializedAccess; + Result::Err(error) + }, + Some(v) =>{ + let folded_tag = FoldedResult::Tag(v.clone()); + Result::Ok((None, folded_tag)) + } + } + } else{ + // case bus, access to the next field + match field{ + FieldTypes::Bus(bus_slice)=>{ + + let memory_response = BusSlice::access_values_by_reference( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice[0]; + resulting_bus.get_field( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap() + ) + } + Result::Err(err)=>{ + return Err(err); + } + } + } + FieldTypes::Signal(_) => unreachable!(), + } + } + + } else{ + // in this case there is no need for recursion, final access + + match field{ + FieldTypes::Signal(signal_slice) =>{ + // Case it is just a signal or an array of signals, + // in this case there is no need for recursion + + // compute which tags are propagated + let propagated_tags = check_tags_access(tags_info, tags_defs); + + let accessed_slice_result = SignalSlice::access_values(&signal_slice, &remaining_access.array_access); + match accessed_slice_result{ + Ok(slice) =>{ + let folded_slice = FoldedResult::Signal(slice); + Result::Ok((Some(propagated_tags), folded_slice)) + }, + Err(err) => Err(err) + } + } + FieldTypes::Bus(bus_slice) => { + // Case it is just a bus or an array of buses, + // in this case there is no need for recursion + + // compute which tags are propagated + let propagated_tags = check_tags_access(tags_info, tags_defs); + + let accessed_slice_result = BusSlice::access_values(&bus_slice, &remaining_access.array_access); + match accessed_slice_result{ + Ok(slice) =>{ + let folded_slice = FoldedResult::Bus(slice); + Result::Ok((Some(propagated_tags), folded_slice)) + }, + Err(err) => Err(err) + } + }, + } + } + } + pub fn get_field_signal( &self, field_name: &str, diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 0bc8db3d8..f90dfd67d 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -1,4 +1,4 @@ -use super::slice_types::{BusSlice, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TypeAssignmentError, TypeInvalidAccess}; +use super::slice_types::{FoldedResult, BusSlice, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TypeAssignmentError, TypeInvalidAccess}; use crate::execution_data::type_definitions::AccessingInformationBus; use crate::{environment_utils::slice_types::BusRepresentation, execution_data::type_definitions::NodePointer}; use crate::execution_data::ExecutedProgram; @@ -218,42 +218,14 @@ impl ComponentRepresentation { Result::Ok(()) } -/* - pub fn signal_has_value( - component: &ComponentRepresentation, - signal_name: &str, - access: &[SliceCapacity], - ) -> Result { - if component.node_pointer.is_none() { - return Result::Err(MemoryError::InvalidAccess); - } - if component.outputs.contains_key(signal_name) && !component.unassigned_inputs.is_empty() { - return Result::Err(MemoryError::InvalidAccess); - } - if !component.is_initialized{ - return Result::Err(MemoryError::InvalidAccess); - } - - let slice = if component.inputs.contains_key(signal_name) { - component.inputs.get(signal_name).unwrap() - } else { - component.outputs.get(signal_name).unwrap() - }; - let enabled_slice = SignalSlice::access_values(&slice, &access)?; - let mut enabled = false; - for i in 0..SignalSlice::get_number_of_cells(&enabled_slice) { - enabled |= SignalSlice::get_reference_to_single_value_by_index(&enabled_slice, i)?; - } - Result::Ok(enabled) - } -*/ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { if self.node_pointer.is_none() { return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent))); } - if self.output_buses.contains_key(bus_name) && !self.unassigned_inputs.is_empty() { + // in case it is an output signal or bus + if (self.outputs.contains_key(bus_name) || self.output_buses.contains_key(bus_name)) && !self.unassigned_inputs.is_empty() { // we return the name of an input that has not been assigned let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal)))); @@ -265,6 +237,100 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal)))); } Result::Ok(()) +} + +pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<((Option, FoldedResult)), MemoryError>{ + if let Result::Err(value) = self.check_initialized_inputs(field_name) { + return Err(value); + } + + if self.inputs.contains_key(field_name) || self.outputs.contains_key(field_name){ + // in this case we are accessing a signal + let (tag_info, signal_slice) = if self.inputs.contains_key(field_name) { + (self.inputs_tags.get(field_name).unwrap(), self.inputs.get(field_name).unwrap()) + } else { + (self.outputs_tags.get(field_name).unwrap(), self.outputs.get(field_name).unwrap()) + }; + + if remaining_access.field_access.is_some(){ + // in case it is a tag access + assert!(remaining_access.array_access.len() == 0); + let value_tag = tag_info.get(remaining_access.field_access.as_ref().unwrap()).unwrap(); + match value_tag{ + None =>{ + let error = MemoryError::TagValueNotInitializedAccess; + Result::Err(error) + }, + Some(v) =>{ + let folded_tag = FoldedResult::Tag(v.clone()); + Result::Ok((None, folded_tag)) + } + } + } else{ + // case signals + // We access to the selected signal if it is an array + let accessed_slice_result = SignalSlice::access_values(signal_slice, &remaining_access.array_access); + match accessed_slice_result{ + Ok(slice) =>{ + let folded_slice = FoldedResult::Signal(slice); + Result::Ok((Some(tag_info.clone()), folded_slice)) + }, + Err(err) => Err(err) + } + } + } else{ + // in this case we are accessing a bus + let (tag_info, bus_slice) = if self.input_buses.contains_key(field_name) { + (self.inputs_tags.get(field_name).unwrap(), self.input_buses.get(field_name).unwrap()) + } else { + (self.outputs_tags.get(field_name).unwrap(), self.output_buses.get(field_name).unwrap()) + }; + + if remaining_access.field_access.is_some(){ + // In this case we need to access to values of the bus or one of its tags + let next_array_access = &remaining_access.array_access; + let next_field_access = remaining_access.field_access.as_ref().unwrap(); + let next_remaining_access = remaining_access.remaining_access.as_ref().unwrap(); + if tag_info.contains_key(remaining_access.field_access.as_ref().unwrap()){ + // in this case we are returning a tag + assert!(next_array_access.len() == 0); + let value_tag = tag_info.get(next_field_access).unwrap(); + match value_tag{ + None =>{ + let error = MemoryError::TagValueNotInitializedAccess; + Result::Err(error) + }, + Some(v) =>{ + let folded_tag = FoldedResult::Tag(v.clone()); + Result::Ok((None, folded_tag)) + } + } + } else{ + // in this case we are returning a field of the bus + + let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); + let accessed_bus = match accessed_slice_result{ + Ok(slice) =>{ + BusSlice::unwrap_to_single(slice) + }, + Err(err) => return Err(err) + }; + accessed_bus.get_field(next_field_access, next_remaining_access) + } + } else{ + // We are accessing the complete bus + let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); + + match accessed_slice_result{ + Ok(slice) =>{ + let folded_slice = FoldedResult::Bus(slice); + Result::Ok((Some(tag_info.clone()), folded_slice)) + }, + Err(err) => Err(err) + } + } + } + } pub fn get_signal_field_bus(&self, bus_name: &str,remaining_access: &AccessingInformationBus) -> Result<((TagDefinitions, TagInfo), SignalSlice), MemoryError> { if let Result::Err(value) = self.check_initialized_inputs(bus_name) { @@ -277,6 +343,7 @@ fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) }; let initial_value = BusSlice::get_reference_to_single_value(bus_slice.1, &[])?; + let (tags,slice) = initial_value.get_field_signal( bus_name, remaining_access diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index 9c559b241..29953a6f1 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -29,3 +29,10 @@ pub enum FieldTypes { // For each field, we store the info depending on if it is Signal(SignalSlice), Bus(BusSlice), } + +pub enum FoldedResult { // For each possible returning value, we store the info depending on if it is a signal o a bus + // Depending on the case we store a different slice + Signal(SignalSlice), + Bus(BusSlice), + Tag(BigInt) +} \ No newline at end of file diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 18727983a..74a7225c4 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -10,7 +10,8 @@ use super::environment_utils::{ slice_types::{ AExpressionSlice, ArithmeticExpression as ArithmeticExpressionGen, ComponentRepresentation, ComponentSlice, MemoryError, TypeInvalidAccess, TypeAssignmentError, MemorySlice, - SignalSlice, SliceCapacity, TagInfo, TagState, BusSlice, BusRepresentation + SignalSlice, SliceCapacity, TagInfo, TagState, BusSlice, BusRepresentation, + FoldedResult }, }; @@ -2618,93 +2619,96 @@ fn execute_component( // TODO: cases access signal/bus inside a bus, all in same case - if meta.get_type_knowledge().is_signal(){ - let access_information = treat_accessing(meta, access, program_archive, runtime, flags)?; - if access_information.undefined { - let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); - return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); - } + let access_information = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; + if access_information.undefined { + let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); + return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); + } - let environment_response = + let environment_response = ExecutionEnvironment::get_component_res(&runtime.environment, symbol); - let component_slice = treat_result_with_environment_error( - environment_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let memory_response = if runtime.anonymous_components.contains_key(symbol) { - ComponentSlice::access_values(component_slice, &Vec::new()) - } else{ - ComponentSlice::access_values(component_slice, &access_information.before_signal) - }; - let slice_result = treat_result_with_memory_error( - memory_response, + let component_slice = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let memory_response = if runtime.anonymous_components.contains_key(symbol) { + ComponentSlice::access_values(component_slice, &Vec::new()) + } else{ + ComponentSlice::access_values(component_slice, &access_information.array_access) + }; + let slice_result = treat_result_with_memory_error( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let resulting_component = safe_unwrap_to_single(slice_result, line!()); + + if let Option::Some(signal_name) = &access_information.field_access { + let remaining_access = access_information.remaining_access.as_ref().unwrap(); + let symbol = create_symbol_bus(symbol, &access_information); + + let (tags, result) = treat_result_with_memory_error( + resulting_component.get_io_value(signal_name, remaining_access), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let resulting_component = safe_unwrap_to_single(slice_result, line!()); - if let Some(acc) = access_information.tag_access { - let (tags_signal, _) = treat_result_with_memory_error( - resulting_component.get_signal(&access_information.signal_access.unwrap()), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - - if tags_signal.contains_key(&acc) { - let value_tag = tags_signal.get(&acc).unwrap(); - if let Some(value_tag) = value_tag { - let a_value = AExpr::Number { value: value_tag.clone() }; - let ae_slice = AExpressionSlice::new(&a_value); - Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - } - else { - let error = MemoryError::TagValueNotInitializedAccess; - treat_result_with_memory_error( - Result::Err(error), + match result{ + FoldedResult::Signal(signals) =>{ + let result = signal_to_arith(symbol, signals) + .map(|s| FoldedValue { + arithmetic_slice: Option::Some(s), + tags: Option::Some(tags.unwrap()), + ..FoldedValue::default() + }); + treat_result_with_memory_error( + result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + ) + }, + FoldedResult::Bus(buses) =>{ + // Check that all the buses are completely assigned + + for i in 0..BusSlice::get_number_of_cells(&buses){ + let value_left = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&buses, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, - )? + )?; + + if value_left.has_unassigned_fields(){ + treat_result_with_memory_error( + Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } } - } else { - unreachable!() - } - - } - else if let Option::Some(signal_name) = &access_information.signal_access { - let access_after_signal = &access_information.after_signal; - let (tags_signal, signal) = treat_result_with_memory_error( - resulting_component.get_signal(signal_name), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let slice = SignalSlice::access_values(signal, &access_after_signal); - let slice = treat_result_with_memory_error( - slice, - meta, - &mut runtime.runtime_errors, - &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), - tags: Option::Some(tags_signal.clone()), + Ok(FoldedValue { + bus_slice: Option::Some((symbol, buses)), + tags: Option::Some(tags.unwrap()), ..FoldedValue::default() - }); - treat_result_with_memory_error( - result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - ) - } else { + }) + + }, + FoldedResult::Tag(value) =>{ + let a_value = AExpr::Number { value }; + let ae_slice = AExpressionSlice::new(&a_value); + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) + + } + } + + } else { let read_result = if resulting_component.is_ready_initialize() { Result::Ok(resulting_component) } else { @@ -2723,61 +2727,7 @@ fn execute_component( is_parallel: Some(false), ..FoldedValue::default() }) - } - } else if meta.get_type_knowledge().is_bus(){ - let access_information = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; - if access_information.undefined { - let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); - return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); - } - - let environment_response = - ExecutionEnvironment::get_component_res(&runtime.environment, symbol); - let component_slice = treat_result_with_environment_error( - environment_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let memory_response = if runtime.anonymous_components.contains_key(symbol) { - ComponentSlice::access_values(component_slice, &Vec::new()) - } else{ - ComponentSlice::access_values(component_slice, &access_information.array_access) - }; - let slice_result = treat_result_with_memory_error( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - // TODO: just case accessing complete bus - let resulting_component = safe_unwrap_to_single(slice_result, line!()); - let result_access = resulting_component.get_complete_bus(access_information.field_access.as_ref().unwrap()); - let (tags_bus, bus_slice) = treat_result_with_memory_error( - result_access, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let slice = BusSlice::access_values(bus_slice, &access_information.remaining_access.as_ref().unwrap().array_access); - let slice = treat_result_with_memory_error( - slice, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let symbol = create_symbol_bus(symbol, &access_information); - - Result::Ok(FoldedValue { - bus_slice: Some((symbol, slice)), - tags: Some(tags_bus.clone()), - ..FoldedValue::default() - }) - } - else{ - // TODO: REFRACT AND CHANGE ACCESSING_INFORMATION - unreachable!() - } + } } From e91e8441aeff00846a68c3ee6d8eb96de76608fb Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 23 May 2024 16:15:45 -0700 Subject: [PATCH 078/189] refractor of execute_bus() and removing unused --- constraint_generation/src/assignment_utils.rs | 14 +- .../environment_utils/bus_representation.rs | 115 +------- .../component_representation.rs | 256 +++++++----------- constraint_generation/src/execute.rs | 172 ++++-------- .../src/execution_data/executed_bus.rs | 7 +- 5 files changed, 154 insertions(+), 410 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index ef1e38802..b1c7a620e 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -1,11 +1,9 @@ -use super::environment_utils::{ - - slice_types::{ - AExpressionSlice, ArithmeticExpression as ArithmeticExpressionGen, ComponentRepresentation, - ComponentSlice, MemoryError, TypeInvalidAccess, TypeAssignmentError, MemorySlice, - SignalSlice, SliceCapacity, TagInfo, TagState, TagDefinitions, BusSlice, BusRepresentation - }, -}; +use super::environment_utils:: + + slice_types::{MemoryError, TypeAssignmentError, + SignalSlice, SliceCapacity, TagInfo, TagState, TagDefinitions, + BusSlice + }; use std::mem; diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 4a7529e4d..b5576970d 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,11 +1,9 @@ -use program_structure::ast::Access; -use super::slice_types::{AExpressionSlice, BusSlice, FieldTypes, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TagState, TypeAssignmentError, TypeInvalidAccess}; +use super::slice_types::{BusSlice, FieldTypes, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TagState, TypeAssignmentError}; use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; -use std::collections::{BTreeMap,HashMap, HashSet}; +use std::collections::{BTreeMap,HashMap}; use crate::ast::Meta; -use std::mem; use num_bigint_dig::BigInt; use crate::assignment_utils::*; @@ -50,7 +48,7 @@ impl BusRepresentation { component: &mut BusRepresentation, node_pointer: NodePointer, scheme: &ExecutedProgram, - is_input_bus: bool + is_output_bus: bool ) -> Result<(), MemoryError> { let possible_node = ExecutedProgram::get_bus_node(scheme, node_pointer); assert!(possible_node.is_some()); @@ -60,7 +58,7 @@ impl BusRepresentation { // if input bus all signals are set initialize to true, else to false // initialice the signals for (symbol, route) in node.signal_fields() { - let signal_slice = SignalSlice::new_with_route(route, &is_input_bus); + let signal_slice = SignalSlice::new_with_route(route, &is_output_bus); let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); if signal_slice_size > 0{ component.unassigned_fields @@ -84,7 +82,7 @@ impl BusRepresentation { } else{ component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); } - if is_input_bus{ + if is_output_bus{ component.unassigned_fields.remove(symbol); } } @@ -99,7 +97,7 @@ impl BusRepresentation { &mut bus_field, bus_node, scheme, - is_input_bus + is_output_bus )?; let bus_slice = BusSlice::new_with_route(route, &bus_field); let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); @@ -140,7 +138,7 @@ impl BusRepresentation { } else{ component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); } - if is_input_bus{ + if is_output_bus{ component.unassigned_fields.remove(symbol); } } @@ -242,104 +240,7 @@ impl BusRepresentation { } } - pub fn get_field_signal( - &self, - field_name: &str, - remaining_access: &AccessingInformationBus - ) -> Result<((TagDefinitions, TagInfo), SignalSlice), MemoryError> { - // TODO: REMOVE CLONE - - let field = self.fields.get(field_name).unwrap(); - let field_tags = self.field_tags.get(field_name).unwrap(); - if remaining_access.field_access.is_some(){ - // we are still considering a bus - match field{ - FieldTypes::Bus(bus_slice)=>{ - - let memory_response = BusSlice::access_values( - &bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let resulting_bus = - BusSlice::unwrap_to_single(bus_slice); - resulting_bus.get_field_signal( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap() - ) - } - Result::Err(err)=>{ - return Err(err); - } - } - } - FieldTypes::Signal(_) => unreachable!(), - } - - } else{ - match field{ - FieldTypes::Signal(signals) =>{ - // Case it is just a signal or an array of signals, - // in this case there is no need for recursion - assert!(remaining_access.field_access.is_none()); - Ok((field_tags.clone(), signals.clone())) - } - FieldTypes::Bus(_) => unreachable!(), - } - } - - // Returns the tags and a SignalSlice with true/false values - } - - pub fn get_field_bus( - &self, - field_name: &str, - remaining_access: &AccessingInformationBus - ) -> Result<((TagDefinitions, TagInfo), BusSlice), MemoryError> { - // TODO: REMOVE CLONE - - let field = self.fields.get(field_name).unwrap(); - let field_tags = self.field_tags.get(field_name).unwrap(); - - if remaining_access.field_access.is_some(){ - // we are still considering an intermediate bus - match field{ - FieldTypes::Bus(bus_slice)=>{ - - let memory_response = BusSlice::access_values( - &bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.is_single()); - let resulting_bus = - BusSlice::unwrap_to_single(bus_slice); - resulting_bus.get_field_bus( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap()) - } - Result::Err(err)=>{ - return Err(err); - } - } - } - FieldTypes::Signal(_) => unreachable!(), - } - } else{ - match field{ - FieldTypes::Bus(buses) =>{ - // Case it is the final array of buses that we must return - - assert!(remaining_access.field_access.is_none()); - Ok((field_tags.clone(), buses.clone())) - } - FieldTypes::Signal(_) => unreachable!(), - } - } - } + pub fn has_unassigned_fields(&self) -> bool{ self.node_pointer.is_none() || !self.unassigned_fields.is_empty() diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index f90dfd67d..6da37da0f 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -220,81 +220,42 @@ impl ComponentRepresentation { } -fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { - if self.node_pointer.is_none() { - return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent))); - } - // in case it is an output signal or bus - if (self.outputs.contains_key(bus_name) || self.output_buses.contains_key(bus_name)) && !self.unassigned_inputs.is_empty() { - // we return the name of an input that has not been assigned - let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); - return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal)))); - } - - if !self.is_initialized { - // we return the name of an input with tags that has not been assigned - let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); - return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal)))); - } - Result::Ok(()) -} - -pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<((Option, FoldedResult)), MemoryError>{ - if let Result::Err(value) = self.check_initialized_inputs(field_name) { - return Err(value); + fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { + if self.node_pointer.is_none() { + return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent))); + } + // in case it is an output signal or bus + if (self.outputs.contains_key(bus_name) || self.output_buses.contains_key(bus_name)) && !self.unassigned_inputs.is_empty() { + // we return the name of an input that has not been assigned + let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); + return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal)))); + } + + if !self.is_initialized { + // we return the name of an input with tags that has not been assigned + let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); + return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal)))); + } + Result::Ok(()) } - - if self.inputs.contains_key(field_name) || self.outputs.contains_key(field_name){ - // in this case we are accessing a signal - let (tag_info, signal_slice) = if self.inputs.contains_key(field_name) { - (self.inputs_tags.get(field_name).unwrap(), self.inputs.get(field_name).unwrap()) - } else { - (self.outputs_tags.get(field_name).unwrap(), self.outputs.get(field_name).unwrap()) - }; - - if remaining_access.field_access.is_some(){ - // in case it is a tag access - assert!(remaining_access.array_access.len() == 0); - let value_tag = tag_info.get(remaining_access.field_access.as_ref().unwrap()).unwrap(); - match value_tag{ - None =>{ - let error = MemoryError::TagValueNotInitializedAccess; - Result::Err(error) - }, - Some(v) =>{ - let folded_tag = FoldedResult::Tag(v.clone()); - Result::Ok((None, folded_tag)) - } - } - } else{ - // case signals - // We access to the selected signal if it is an array - let accessed_slice_result = SignalSlice::access_values(signal_slice, &remaining_access.array_access); - match accessed_slice_result{ - Ok(slice) =>{ - let folded_slice = FoldedResult::Signal(slice); - Result::Ok((Some(tag_info.clone()), folded_slice)) - }, - Err(err) => Err(err) - } + + pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<((Option, FoldedResult)), MemoryError>{ + if let Result::Err(value) = self.check_initialized_inputs(field_name) { + return Err(value); } - } else{ - // in this case we are accessing a bus - let (tag_info, bus_slice) = if self.input_buses.contains_key(field_name) { - (self.inputs_tags.get(field_name).unwrap(), self.input_buses.get(field_name).unwrap()) - } else { - (self.outputs_tags.get(field_name).unwrap(), self.output_buses.get(field_name).unwrap()) - }; - - if remaining_access.field_access.is_some(){ - // In this case we need to access to values of the bus or one of its tags - let next_array_access = &remaining_access.array_access; - let next_field_access = remaining_access.field_access.as_ref().unwrap(); - let next_remaining_access = remaining_access.remaining_access.as_ref().unwrap(); - if tag_info.contains_key(remaining_access.field_access.as_ref().unwrap()){ - // in this case we are returning a tag - assert!(next_array_access.len() == 0); - let value_tag = tag_info.get(next_field_access).unwrap(); + + if self.inputs.contains_key(field_name) || self.outputs.contains_key(field_name){ + // in this case we are accessing a signal + let (tag_info, signal_slice) = if self.inputs.contains_key(field_name) { + (self.inputs_tags.get(field_name).unwrap(), self.inputs.get(field_name).unwrap()) + } else { + (self.outputs_tags.get(field_name).unwrap(), self.outputs.get(field_name).unwrap()) + }; + + if remaining_access.field_access.is_some(){ + // in case it is a tag access + assert!(remaining_access.array_access.len() == 0); + let value_tag = tag_info.get(remaining_access.field_access.as_ref().unwrap()).unwrap(); match value_tag{ None =>{ let error = MemoryError::TagValueNotInitializedAccess; @@ -306,105 +267,70 @@ pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInforma } } } else{ - // in this case we are returning a field of the bus - - let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); - let accessed_bus = match accessed_slice_result{ + // case signals + // We access to the selected signal if it is an array + let accessed_slice_result = SignalSlice::access_values(signal_slice, &remaining_access.array_access); + match accessed_slice_result{ Ok(slice) =>{ - BusSlice::unwrap_to_single(slice) + let folded_slice = FoldedResult::Signal(slice); + Result::Ok((Some(tag_info.clone()), folded_slice)) }, - Err(err) => return Err(err) - }; - accessed_bus.get_field(next_field_access, next_remaining_access) + Err(err) => Err(err) + } } } else{ - // We are accessing the complete bus - let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); - - match accessed_slice_result{ - Ok(slice) =>{ - let folded_slice = FoldedResult::Bus(slice); - Result::Ok((Some(tag_info.clone()), folded_slice)) - }, - Err(err) => Err(err) - } - } - } - -} - pub fn get_signal_field_bus(&self, bus_name: &str,remaining_access: &AccessingInformationBus) -> Result<((TagDefinitions, TagInfo), SignalSlice), MemoryError> { - if let Result::Err(value) = self.check_initialized_inputs(bus_name) { - return Err(value); - } - - let bus_slice = if self.input_buses.contains_key(bus_name) { - (self.inputs_tags.get(bus_name).unwrap(), self.input_buses.get(bus_name).unwrap()) - } else { - (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) - }; - let initial_value = BusSlice::get_reference_to_single_value(bus_slice.1, &[])?; - - let (tags,slice) = initial_value.get_field_signal( - bus_name, - remaining_access - )?; - Result::Ok((tags,slice)) - } - - pub fn get_bus_field_bus(&self, bus_name: &str,remaining_access: &AccessingInformationBus) -> Result<((TagDefinitions, TagInfo), BusSlice), MemoryError> { - if let Result::Err(value) = self.check_initialized_inputs(bus_name) { - return Err(value); - } - - let bus_slice = if self.input_buses.contains_key(bus_name) { - (self.inputs_tags.get(bus_name).unwrap(), self.input_buses.get(bus_name).unwrap()) - } else { - (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) - }; - let initial_value = BusSlice::get_reference_to_single_value(bus_slice.1, &[])?; - let (tags,slice) = initial_value.get_field_bus( - bus_name, - remaining_access - )?; - Result::Ok((tags,slice)) - } + // in this case we are accessing a bus + let (tag_info, bus_slice) = if self.input_buses.contains_key(field_name) { + (self.inputs_tags.get(field_name).unwrap(), self.input_buses.get(field_name).unwrap()) + } else { + (self.outputs_tags.get(field_name).unwrap(), self.output_buses.get(field_name).unwrap()) + }; - pub fn get_complete_bus(&self, bus_name: &str) -> Result<(&TagInfo, &BusSlice), MemoryError> { - if let Result::Err(value) = self.check_initialized_inputs(bus_name) { - return Err(value); - } - - let slice = if self.input_buses.contains_key(bus_name) { - (self.inputs_tags.get(bus_name).unwrap(), self.input_buses.get(bus_name).unwrap()) - } else { - (self.outputs_tags.get(bus_name).unwrap(), self.output_buses.get(bus_name).unwrap()) - }; - Result::Ok(slice) - } - - pub fn get_signal(&self, signal_name: &str) -> Result<(&TagInfo, &SignalSlice), MemoryError> { - - if self.node_pointer.is_none() { - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent)); - } - if self.outputs.contains_key(signal_name) && !self.unassigned_inputs.is_empty() { - // we return the name of an input that has not been assigned - let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal))); - } - - if !self.is_initialized { - // we return the name of an input with tags that has not been assigned - let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal))); + if remaining_access.field_access.is_some(){ + // In this case we need to access to values of the bus or one of its tags + let next_array_access = &remaining_access.array_access; + let next_field_access = remaining_access.field_access.as_ref().unwrap(); + let next_remaining_access = remaining_access.remaining_access.as_ref().unwrap(); + if tag_info.contains_key(remaining_access.field_access.as_ref().unwrap()){ + // in this case we are returning a tag + assert!(next_array_access.len() == 0); + let value_tag = tag_info.get(next_field_access).unwrap(); + match value_tag{ + None =>{ + let error = MemoryError::TagValueNotInitializedAccess; + Result::Err(error) + }, + Some(v) =>{ + let folded_tag = FoldedResult::Tag(v.clone()); + Result::Ok((None, folded_tag)) + } + } + } else{ + // in this case we are returning a field of the bus + + let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); + let accessed_bus = match accessed_slice_result{ + Ok(slice) =>{ + BusSlice::unwrap_to_single(slice) + }, + Err(err) => return Err(err) + }; + accessed_bus.get_field(next_field_access, next_remaining_access) + } + } else{ + // We are accessing the complete bus + let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); + + match accessed_slice_result{ + Ok(slice) =>{ + let folded_slice = FoldedResult::Bus(slice); + Result::Ok((Some(tag_info.clone()), folded_slice)) + }, + Err(err) => Err(err) + } + } } - let slice = if self.inputs.contains_key(signal_name) { - (self.inputs_tags.get(signal_name).unwrap(), self.inputs.get(signal_name).unwrap()) - } else { - (self.outputs_tags.get(signal_name).unwrap(), self.outputs.get(signal_name).unwrap()) - }; - Result::Ok(slice) } pub fn assign_value_to_signal( diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 74a7225c4..68bf13a7e 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2419,6 +2419,7 @@ fn execute_bus( &mut runtime.runtime_errors, &runtime.call_trace, )?; + if access_information.field_access.is_none() { // Case we are accessing the complete bus or array of buses @@ -2455,77 +2456,46 @@ fn execute_bus( Result::Ok(FoldedValue{bus_slice: Some((symbol.to_string(), bus_slice)), tags: Some(tags_propagated), ..FoldedValue::default()}) } else{ - if meta.get_type_knowledge().is_tag(){ - // Case we are accessing a tag of the bus - let acc = access_information.field_access.unwrap(); - if tags.contains_key(&acc) { - let value_tag = tags.get(&acc).unwrap(); - let state = tags_definitions.get(&acc).unwrap(); - if let Some(value_tag) = value_tag { // tag has value - // access only allowed when (1) it is value defined by user or (2) it is completely assigned - if state.value_defined || state.complete{ - let a_value = AExpr::Number { value: value_tag.clone() }; - let ae_slice = AExpressionSlice::new(&a_value); - Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - } else{ - let error = MemoryError::TagValueNotInitializedAccess; - treat_result_with_memory_error( - Result::Err(error), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )? - } - - } - else { - let error = MemoryError::TagValueNotInitializedAccess; - treat_result_with_memory_error( - Result::Err(error), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )? - } - } - else { - unreachable!() - } + // access to the field or tag - } else{ - // Case we are accessing a field of the bus - let resulting_bus = safe_unwrap_to_single(bus_slice, line!()); - let symbol = create_symbol_bus(symbol, &access_information); + let resulting_bus = safe_unwrap_to_single(bus_slice, line!()); + let symbol = create_symbol_bus(symbol, &access_information); - - if meta.get_type_knowledge().is_bus(){ - // Case we return a bus - - let (tags_bus, bus) = treat_result_with_memory_error( - resulting_bus.get_field_bus( - access_information.field_access.as_ref().unwrap(), - access_information.remaining_access.as_ref().unwrap() - ), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; + // access to the field + let field_name = access_information.field_access.as_ref().unwrap(); + let remaining_access = access_information.remaining_access.as_ref().unwrap(); - let final_array_access = get_final_array_access_bus_accessing(&access_information); - - let slice = BusSlice::access_values(&bus, final_array_access); - let slice = treat_result_with_memory_error( - slice, + + let (tags, result) = treat_result_with_memory_error( + resulting_bus.get_field(field_name, remaining_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + // match the result and generate the output + match result{ + FoldedResult::Signal(signals) =>{ + // Generate signal slice and check that all assigned + let result = signal_to_arith(symbol, signals) + .map(|s| FoldedValue { + arithmetic_slice: Option::Some(s), + tags: Option::Some(tags.unwrap()), + ..FoldedValue::default() + }); + treat_result_with_memory_error( + result, meta, &mut runtime.runtime_errors, &runtime.call_trace, - )?; - + ) + }, + FoldedResult::Bus(buses) =>{ // Check that all the buses are completely assigned - for i in 0..BusSlice::get_number_of_cells(&slice){ + for i in 0..BusSlice::get_number_of_cells(&buses){ let value_left = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&slice, i), + BusSlice::get_reference_to_single_value_by_index(&buses, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -2533,77 +2503,29 @@ fn execute_bus( if value_left.has_unassigned_fields(){ treat_result_with_memory_error( - Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), - meta, + Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), + meta, &mut runtime.runtime_errors, &runtime.call_trace, - )?; - } - } - - let mut tags_propagated = TagInfo::new(); - for (tag, value) in tags{ - let state = tags_definitions.get(tag).unwrap(); - if state.value_defined || state.complete{ - tags_propagated.insert(tag.clone(), value.clone()); - } else if state.defined{ - tags_propagated.insert(tag.clone(), None); + )?; } } - - Result::Ok(FoldedValue{bus_slice: Some((symbol, slice)), tags: Some(tags_propagated), ..FoldedValue::default()}) - - } else if meta.get_type_knowledge().is_signal(){ - // Case we return a signal - - let ((tags_definitions, tags), signal) = treat_result_with_memory_error( - resulting_bus.get_field_signal( - access_information.field_access.as_ref().unwrap(), - access_information.remaining_access.as_ref().unwrap() - ), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - - let final_array_access = get_final_array_access_bus_accessing(&access_information); - - let slice = SignalSlice::access_values(&signal, final_array_access); - let slice = treat_result_with_memory_error( - slice, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; + Ok(FoldedValue { + bus_slice: Option::Some((symbol, buses)), + tags: Option::Some(tags.unwrap()), + ..FoldedValue::default() + }) - let mut tags_propagated = TagInfo::new(); - for (tag, value) in &tags{ - let state = tags_definitions.get(tag).unwrap(); - if state.value_defined || state.complete{ - tags_propagated.insert(tag.clone(), value.clone()); - } else if state.defined{ - tags_propagated.insert(tag.clone(), None); - } - } + }, + FoldedResult::Tag(value) =>{ + // return the tag value + let a_value = AExpr::Number { value }; + let ae_slice = AExpressionSlice::new(&a_value); + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - let result = signal_to_arith(symbol, slice) - .map(|s| FoldedValue { - arithmetic_slice: Option::Some(s), - tags: Option::Some(tags_propagated), - ..FoldedValue::default() - }); - treat_result_with_memory_error( - result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - ) - } - else{ - unreachable!() } - } + } } diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index e023231d6..a52f1e1c1 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -1,11 +1,8 @@ use super::type_definitions::*; -use circom_algebra::algebra::ArithmeticExpression; -use compiler::hir::very_concrete_program::*; + use dag::DAG; use num_bigint::BigInt; -use program_structure::ast::{SignalType, Statement}; -use std::collections::{HashMap, HashSet}; -use crate::execution_data::AExpressionSlice; +use std::collections::HashMap; use crate::execution_data::TagInfo; From dfd9e7ca437995803003a3fcf0ef140dfd7d0d52 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Fri, 24 May 2024 19:06:38 +0200 Subject: [PATCH 079/189] Added tags specifications and a new test for buses. --- tests/buses/bus_test_correct_4.circom | 14 ++++++++++++++ tests/circomlib/babyjub.circom | 5 +++++ tests/circomlib/montgomery.circom | 5 +++++ 3 files changed, 24 insertions(+) create mode 100644 tests/buses/bus_test_correct_4.circom diff --git a/tests/buses/bus_test_correct_4.circom b/tests/buses/bus_test_correct_4.circom new file mode 100644 index 000000000..e2670018c --- /dev/null +++ b/tests/buses/bus_test_correct_4.circom @@ -0,0 +1,14 @@ +pragma circom 2.0.0; + +bus Point (n) { + signal {binary} x[n], y[n]; +} + +template Main { + Point(2) input pin; + Point(3) output pout; + + pout <== pin; +} + +component main {public [pin]} = Main(); \ No newline at end of file diff --git a/tests/circomlib/babyjub.circom b/tests/circomlib/babyjub.circom index b7183b853..2314b9594 100644 --- a/tests/circomlib/babyjub.circom +++ b/tests/circomlib/babyjub.circom @@ -49,6 +49,11 @@ include "escalarmulfix.circom"; and multiplying points by a scalar are faster this way. */ +/* + spec tag babyedwards: 168700*(p.x)^2 + (p.y)^2 = 1 + 168696*(p.x)^2*(p.y)^2 + spec tag babymontgomery: (p.y)^2 = (p.x)^3 + 168698*(p.x)^2 + p.x +*/ + /* *** BabyAdd(): template that receives two points of the Baby-Jubjub curve in twisted Edwards form and returns the addition of the points. - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in twisted Edwards form diff --git a/tests/circomlib/montgomery.circom b/tests/circomlib/montgomery.circom index eaeba6925..62d65d881 100644 --- a/tests/circomlib/montgomery.circom +++ b/tests/circomlib/montgomery.circom @@ -51,6 +51,11 @@ Circuits to add and double points of the Baby-Jubjub Montgomery curve are provided as well. */ +/* + spec tag babyedwards: 168700*(p.x)^2 + (p.y)^2 = 1 + 168696*(p.x)^2*(p.y)^2 + spec tag babymontgomery: (p.y)^2 = (p.x)^3 + 168698*(p.x)^2 + p.x +*/ + bus Point { signal x,y; } From 08516174ff20b7619a2ae29f58726124a7768bfa Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 24 May 2024 16:02:44 -0700 Subject: [PATCH 080/189] continue working on assignments --- constraint_generation/src/assignment_utils.rs | 13 +- .../environment_utils/bus_representation.rs | 484 +++++++--------- .../component_representation.rs | 526 +++++++++--------- .../src/environment_utils/slice_types.rs | 9 + constraint_generation/src/execute.rs | 65 +-- .../src/execution_data/type_definitions.rs | 1 + 6 files changed, 520 insertions(+), 578 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index b1c7a620e..17e9248fd 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -158,7 +158,7 @@ pub fn perform_signal_assignment(signal_slice: &mut SignalSlice, array_access: & } -pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCapacity], assigned_bus_slice: &BusSlice)-> Result<(), MemoryError>{ +pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCapacity], assigned_bus_slice: &BusSlice, is_input: bool)-> Result<(), MemoryError>{ let correct_dims_result = BusSlice::check_correct_dims( &bus_slice, @@ -166,15 +166,16 @@ pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCap &assigned_bus_slice, true ); + match correct_dims_result{ + Ok(_) => {}, + Err(err) => return Err(err) + }; let value_left = match BusSlice::access_values_by_mut_reference(bus_slice, array_access){ Ok(value) => value, Err(err) => return Err(err) }; - match correct_dims_result{ - Ok(_) => {}, - Err(err) => return Err(err) - }; + let mut index = 0; @@ -186,7 +187,7 @@ pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCap Err(err) => return Err(err) }; - match accessed_bus.completely_assign_bus(&assigned_bus){ + match accessed_bus.completely_assign_bus(&assigned_bus, is_input){ Ok(_) =>{}, Err(err) => return Err(err) }; diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index b5576970d..2933f2862 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,5 +1,5 @@ -use super::slice_types::{BusSlice, FieldTypes, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TagState, TypeAssignmentError}; +use super::slice_types::{BusSlice, FieldTypes, FoldedArgument, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TagState, TypeAssignmentError}; use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap}; @@ -108,7 +108,7 @@ impl BusRepresentation { let field_bus = FieldTypes::Bus(bus_slice); component.fields.insert(symbol.clone(), field_bus); - // add the tags + // add the tags if node.signal_to_tags.get(symbol).is_some(){ let defined_tags = node.signal_to_tags.get(symbol).unwrap(); let mut definitions = BTreeMap::new(); @@ -246,320 +246,244 @@ impl BusRepresentation { self.node_pointer.is_none() || !self.unassigned_fields.is_empty() } - pub fn assign_value_to_field_signal( + pub fn assign_value_to_field( &mut self, field_name: &str, remaining_access: &AccessingInformationBus, - slice_route: &[SliceCapacity], - tags: TagInfo, + assigned_value: FoldedArgument, + tags: Option, + is_input: bool, ) -> Result<(), MemoryError> { + + // We later distinguish the case of tags + // check if we need to access to another bus or if it is the final access + let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); + let (status_tags, info_tags) = self.field_tags.get_mut(field_name).unwrap(); - self.has_assignment = true; - - let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); - - // TODO: add quick check if completely assigned + if remaining_access.field_access.is_some(){ + // case still intermediate access or a tag + let next_access = remaining_access.field_access.as_ref().unwrap(); - if remaining_access.field_access.is_some(){ - // we are still considering a bus - match field{ - FieldTypes::Bus(bus_slice)=>{ - - let memory_response = BusSlice::access_values_by_mut_reference( - bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(mut bus_slice) =>{ - assert!(bus_slice.len() == 1); - let resulting_bus = bus_slice.get_mut(0).unwrap(); - resulting_bus.assign_value_to_field_signal( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap(), - slice_route, - tags, - ) - } - Result::Err(err)=>{ - return Err(err); + // Distinguish between tag and intermediate access + if info_tags.contains_key(next_access){ + + // it is tag assignment -> check if valid + match field{ + FieldTypes::Signal(s) =>{ + let signal_is_init = SignalSlice::get_number_of_inserts(&s) > 0; + if signal_is_init{ + return Result::Err(MemoryError::AssignmentTagAfterInit) + } } + FieldTypes::Bus(s) =>{ + // TODO, include info about assignments, no recorrer todo + for i in 0..BusSlice::get_number_of_cells(s){ + let accessed_bus = BusSlice::get_reference_to_single_value_by_index(&s, i)?; + if accessed_bus.has_assignment(){ + return Result::Err(MemoryError::AssignmentTagAfterInit) + } + } + } } - } - FieldTypes::Signal(_) => unreachable!(), - } - - } else{ - // in this case we are in a signal - match field{ - FieldTypes::Signal(ref mut signal_slice) =>{ + // Get the assigned value + let value = match assigned_value{ + FoldedArgument::Tag(value) =>{ + value + }, + _ => unreachable!() + }; - // First we add the tags --> similar to what we do in execute - let (tags_definitions, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - - let signal_is_init = SignalSlice::get_number_of_inserts(&signal_slice) > 0; - - perform_tag_propagation(tags_info, tags_definitions, &tags, signal_is_init); - - // Perform the signal assignment - perform_signal_assignment(signal_slice, &remaining_access.array_access, slice_route)?; - - // Update the value of unnasigned fields - let mut dim_slice = 1; - for i in slice_route { - dim_slice *= *i; + let possible_tag = info_tags.get_mut(next_access); + if let Some(val) = possible_tag { + if let Some(_) = val { + Result::Err(MemoryError::AssignmentTagTwice) + } else { // we add the info saying that the tag is defined + let tag_state = status_tags.get_mut(next_access).unwrap(); + tag_state.value_defined = true; + *val = Option::Some(value.clone()); + Result::Ok(()) + + } + } else{ + unreachable!() } - - match self.unassigned_fields.get_mut(field_name){ - Some(left) => { - *left -= dim_slice; - if *left == 0 { - self.unassigned_fields.remove(field_name); + } else{ + // it is intermediate access + self.has_assignment = true; + + match field{ + FieldTypes::Bus(bus_slice)=>{ + // case bus -> apply recursion + let memory_response = BusSlice::access_values_by_mut_reference( + bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(mut bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice.get_mut(0).unwrap(); + resulting_bus.assign_value_to_field( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap(), + assigned_value, + tags, + is_input + ) + } + Result::Err(err)=>{ + return Err(err); + } } } - None => {} - } - - // Update the value of the signal tags it is complete - let signal_is_completely_initialized = - SignalSlice::get_number_of_inserts(signal_slice) == - SignalSlice::get_number_of_cells(signal_slice); - - if signal_is_completely_initialized { - - for (tag, _value) in tags_info{ - let tag_state = tags_definitions.get_mut(tag).unwrap(); - tag_state.complete = true; - + FieldTypes::Signal(_) => { + // no possible, already checked in check_types + unreachable!() } } - - Result::Ok(()) } - FieldTypes::Bus(_) => unreachable!(), - } - } - } - - - - pub fn assign_value_to_field_tag( - &mut self, - field_name: &str, - remaining_access: &AccessingInformationBus, - value: BigInt, - ) -> Result<(), MemoryError> { - let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); - - // we need to stop when there is something like bus.field.tag - // distance 2 between the tag and where we add it - - // the access with distance 2 - let next_access = remaining_access.remaining_access.as_ref().unwrap(); + } else{ + // case final assignment of signal or bus + let tags = tags.unwrap(); - if next_access.field_access.is_some(){ - // we are still considering a bus - match field{ - FieldTypes::Bus(bus_slice)=>{ - - let memory_response = BusSlice::access_values_by_mut_reference( - bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(mut bus_slice) =>{ - assert!(bus_slice.len() == 1); - let resulting_bus = bus_slice.get_mut(0).unwrap(); - resulting_bus.assign_value_to_field_tag( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap(), - value - ) - } - Result::Err(err)=>{ - return Err(err); + // first propagate the tags or check if conditions satisfied if input + let is_init = match field{ + FieldTypes::Signal(signal_slice) =>{ + SignalSlice::get_number_of_inserts(&signal_slice) > 0 + }, + FieldTypes::Bus(bus_slice) =>{ + let mut bus_is_init = false; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ + Ok(bus) => { + bus_is_init |= bus.has_assignment(); + } + Err(_) => unreachable!() + } } + bus_is_init } + }; + if !is_input{ + // case no input, just propagate + perform_tag_propagation(info_tags, status_tags, &tags, is_init); + } else{ + // TODO: REMOVE MOVE ERROR + + // in case input check if tags are satisfied + // for (t, value) in info_tags{ + // if !tags.contains_key(t){ + // return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); + // } else{ + // if !is_init{ + // // First assignment of input tag + // *value = tags.get(t).unwrap().clone(); + // } + // else{ + // // already given a value, check that it is the same + // // if not return error + // if value != tags.get(t).unwrap(){ + // return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); + // } + // } + // } + // } } - FieldTypes::Signal(_) => unreachable!(), - } - - } else{ - // just add the tag to the field - // distance 2 (self.field.tag) - let tag = remaining_access.field_access.as_ref().unwrap(); - let (tags_status, tags_value) = self.field_tags.get_mut(field_name).unwrap(); + // then assign the values to the signal or bus + match field{ + FieldTypes::Signal(signal_slice) =>{ + let route = match assigned_value{ + FoldedArgument::Signal(signal_slice_route) =>{ + signal_slice_route + }, + _ => unreachable!() + }; + perform_signal_assignment(signal_slice, &remaining_access.array_access, route)?; + }, + FieldTypes::Bus(bus_slice) =>{ + let assigned_bus_slice = match assigned_value{ + FoldedArgument::Bus(bus_slice) =>{ + bus_slice + }, + _ => unreachable!() + }; + perform_bus_assignment(bus_slice, &remaining_access.array_access, assigned_bus_slice, is_input)?; - match field{ - FieldTypes::Signal(s) =>{ - let signal_is_init = SignalSlice::get_number_of_inserts(&s) > 0; - if signal_is_init{ - return Result::Err(MemoryError::AssignmentTagAfterInit) } } - FieldTypes::Bus(s) =>{ - // TODO, include info about assignments, no recorrer todo - for i in 0..BusSlice::get_number_of_cells(s){ - let accessed_bus = BusSlice::get_reference_to_single_value_by_index(&s, i)?; - if accessed_bus.has_assignment(){ - return Result::Err(MemoryError::AssignmentTagAfterInit) - } - } - } - } - - let possible_tag = tags_value.get_mut(tag); - if let Some(val) = possible_tag { - if let Some(_) = val { - Result::Err(MemoryError::AssignmentTagTwice) - } else { // we add the info saying that the tag is defined - let tag_state = tags_status.get_mut(tag).unwrap(); - tag_state.value_defined = true; - tags_value.insert(tag.clone(), Option::Some(value)); - Result::Ok(()) - - } - } else{ - unreachable!("Tag does not exist"); - } - } - } - - - pub fn assign_value_to_field_bus( - &mut self, - field_name: &str, - remaining_access: &AccessingInformationBus, - slice_route: &[SliceCapacity], - assigned_bus: &BusSlice, - tags: TagInfo - ) -> Result<(), MemoryError> { - - self.has_assignment = true; - - - let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); - - // TODO: add quick check if completely assigned + // Update the value of unnasigned fields + let slice_route = match assigned_value{ + FoldedArgument::Signal(signal_slice_route) =>{ + signal_slice_route + }, + FoldedArgument::Bus(bus_slice) =>{ + bus_slice.route() + }, + _ => unreachable!() + }; - if remaining_access.field_access.is_some(){ - // we are still considering a bus - match field{ - FieldTypes::Bus(bus_slice)=>{ - - let memory_response = BusSlice::access_values_by_mut_reference( - bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(mut bus_slice) =>{ - assert!(bus_slice.len() == 1); - let resulting_bus = bus_slice.get_mut(0).unwrap(); - resulting_bus.assign_value_to_field_bus( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap(), - slice_route, - assigned_bus, - tags - ) - } - Result::Err(err)=>{ - return Err(err); - } - } + let mut dim_slice = 1; + for i in slice_route { + dim_slice *= *i; } - FieldTypes::Signal(_) => unreachable!(), - } - - } else{ - // in this case we are in a signal - match field{ - FieldTypes::Bus(ref mut bus_slice) =>{ - - // First we add the tags --> similar to what we do in execute - let (tags_definitions, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let mut bus_is_init = false; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ - Ok(bus) => { - bus_is_init |= bus.has_assignment(); - } - Err(_) => unreachable!() + match self.unassigned_fields.get_mut(field_name){ + Some(left) => { + *left -= dim_slice; + if *left == 0 { + self.unassigned_fields.remove(field_name); } } + None => {} + } - perform_tag_propagation(tags_info, tags_definitions, &tags, bus_is_init); - - - // We completely assign each one of the buses - - let bus_previous_value = BusSlice::access_values_by_mut_reference( - bus_slice, - &remaining_access.array_access, - )?; - - let mut index = 0; - let dim_slice = bus_previous_value.len(); - - for bus_assigned in bus_previous_value{ - let value = BusSlice::get_reference_to_single_value_by_index(&assigned_bus, index)?; - - bus_assigned.completely_assign_bus(&value)?; - index += 1; - } - - // Update the value of unnasigned fields - match self.unassigned_fields.get_mut(field_name){ - Some(left) => { - *left -= dim_slice; - if *left == 0 { - self.unassigned_fields.remove(field_name); - } - } - None => {} - } + // Update the value of the signal tags it is complete - // Update the value of the signal tags it is complete - let mut bus_is_completely_init = true; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ - Ok(bus) => { - bus_is_completely_init &= bus.has_assignment(); + let is_completely_initialized = match field{ + FieldTypes::Signal(signal_slice) =>{ + SignalSlice::get_number_of_inserts(signal_slice) == + SignalSlice::get_number_of_cells(signal_slice) + }, + FieldTypes::Bus(bus_slice) =>{ + let mut bus_is_completely_init = true; + for i in 0..BusSlice::get_number_of_cells(bus_slice){ + match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ + Ok(bus) => { + bus_is_completely_init &= bus.has_assignment(); + } + Err(_) => unreachable!() } - Err(_) => unreachable!() } + bus_is_completely_init } - if bus_is_completely_init { + }; + + if is_completely_initialized && !is_input{ - for (tag, _value) in tags_info{ - let tag_state = tags_definitions.get_mut(tag).unwrap(); - tag_state.complete = true; - - } + for (tag, _value) in info_tags{ + let tag_state = status_tags.get_mut(tag).unwrap(); + tag_state.complete = true; } - - Result::Ok(()) } - FieldTypes::Signal(_) => unreachable!(), + Ok(()) } - } + } - - pub fn completely_assign_bus(&mut self, assigned_bus: &BusRepresentation)-> Result<(), MemoryError>{ + pub fn completely_assign_bus(&mut self, assigned_bus: &BusRepresentation, is_input: bool)-> Result<(), MemoryError>{ if self.has_assignment{ return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); } self.has_assignment = true; for (field_name, value) in &mut self.fields{ - // update the tags + // get the tags that are propagated let (tags_definition, tags_info) = self.field_tags.get_mut(field_name).unwrap(); + let (tags_assigned_definition, tags_assigned_info) = assigned_bus.field_tags.get(field_name).unwrap(); let mut tags_propagated = TagInfo::new(); @@ -591,9 +515,33 @@ impl BusRepresentation { }; // perform the tag assignment - perform_tag_propagation(tags_info, tags_definition, &tags_propagated, is_init); + if !is_input{ + // case no input, just propagate + perform_tag_propagation(tags_info, tags_definition, &tags_propagated, is_init); + } else{ + // TODO: REMOVE MOVE ERROR + // in case input check if tags are satisfied + // for (t, value) in tags_info{ + // if !tags_propagated.contains_key(t){ + // return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); + // } else{ + // if !is_init{ + // // First assignment of input tag + // *value = tags_propagated.get(t).unwrap().clone(); + // } + // else{ + // // already given a value, check that it is the same + // // if not return error + // if value != tags_propagated.get(t).unwrap(){ + // return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); + // } + // } + // } + // } + } + // perform the assignment match value{ FieldTypes::Bus(ref mut bus_slice) =>{ @@ -602,7 +550,7 @@ impl BusRepresentation { FieldTypes::Signal(_) => unreachable!(), }; - let assignment_result = perform_bus_assignment(bus_slice, &[], bus_slice_assigned); + let assignment_result = perform_bus_assignment(bus_slice, &[], bus_slice_assigned, is_input); if assignment_result.is_err(){ return Err(assignment_result.err().unwrap()); diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 6da37da0f..d2ead8c8d 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -1,4 +1,4 @@ -use super::slice_types::{FoldedResult, BusSlice, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TypeAssignmentError, TypeInvalidAccess}; +use super::slice_types::{FoldedResult, FoldedArgument, BusSlice, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TypeAssignmentError, TypeInvalidAccess}; use crate::execution_data::type_definitions::AccessingInformationBus; use crate::{environment_utils::slice_types::BusRepresentation, execution_data::type_definitions::NodePointer}; use crate::execution_data::ExecutedProgram; @@ -15,8 +15,7 @@ pub struct ComponentRepresentation { unassigned_tags: HashSet, to_assign_inputs: Vec<(String, Vec, Vec)>, to_assign_input_buses: Vec<(String, Vec, BusSlice)>, - to_assign_input_bus_buses: Vec<(String, AccessingInformationBus, Vec, BusSlice)>, - to_assign_input_signal_buses: Vec<(String, AccessingInformationBus, Vec)>, + to_assign_input_bus_fields: Vec<(String, AccessingInformationBus, FoldedResult)>, inputs: HashMap, input_buses: HashMap, pub inputs_tags: BTreeMap, @@ -43,8 +42,7 @@ impl Default for ComponentRepresentation { to_assign_input_buses: Vec::new(), input_buses: HashMap::new(), output_buses: HashMap::new(), - to_assign_input_bus_buses: Vec::new(), - to_assign_input_signal_buses: Vec::new(), + to_assign_input_bus_fields: Vec::new(), } } } @@ -65,8 +63,7 @@ impl Clone for ComponentRepresentation { to_assign_input_buses: self.to_assign_input_buses.clone(), input_buses: self.input_buses.clone(), output_buses: self.output_buses.clone(), - to_assign_input_bus_buses: Vec::new(), - to_assign_input_signal_buses: Vec::new(), + to_assign_input_bus_fields: self.to_assign_input_bus_fields.clone(), } } } @@ -124,8 +121,7 @@ impl ComponentRepresentation { to_assign_input_buses: Vec::new(), input_buses: HashMap::new(), output_buses: HashMap::new(), - to_assign_input_bus_buses: Vec::new(), - to_assign_input_signal_buses: Vec::new(), + to_assign_input_bus_fields: Vec::new(), }; Result::Ok(()) } @@ -204,16 +200,23 @@ impl ComponentRepresentation { component.node_pointer = Option::Some(node_pointer); - let to_assign = component.to_assign_inputs.clone(); - for s in to_assign{ - let tags_input = component.inputs_tags.get(&s.0).unwrap(); - ComponentRepresentation::assign_value_to_signal_init(component, &s.0, &s.1, &s.2, tags_input.clone())?; + let to_assign = std::mem::replace(&mut component.to_assign_inputs, vec![]); + + for (signal_name, access, route) in &to_assign{ + let tags_input = component.inputs_tags[signal_name].clone(); + component.assign_value_to_signal_init(signal_name, access, route, &tags_input)?; + } + + let to_assign = std::mem::replace(&mut component.to_assign_input_buses, vec![]); + for (signal_name, access, bus_slice) in &to_assign{ + let tags_input = component.inputs_tags[signal_name].clone(); + component.assign_value_to_bus_init(signal_name, access, bus_slice, &tags_input)?; } - let to_assign = component.to_assign_input_buses.clone(); - for s in to_assign{ - let tags_input = component.inputs_tags.get(&s.0).unwrap(); - ComponentRepresentation::assign_value_to_bus_init(component, &s.0, &s.1, tags_input.clone(), &s.2)?; + let to_assign = std::mem::replace(&mut component.to_assign_input_bus_fields, vec![]); + for (signal_name, access, field_value) in &to_assign{ + let tags_input = component.inputs_tags[signal_name].clone(); + component.assign_value_to_bus_field_init(signal_name, access, field_value, tags_input)?; } Result::Ok(()) @@ -222,24 +225,24 @@ impl ComponentRepresentation { fn check_initialized_inputs(&self, bus_name: &str) -> Result<(), MemoryError> { if self.node_pointer.is_none() { - return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent))); + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedComponent)); } // in case it is an output signal or bus if (self.outputs.contains_key(bus_name) || self.output_buses.contains_key(bus_name)) && !self.unassigned_inputs.is_empty() { // we return the name of an input that has not been assigned let ex_signal = self.unassigned_inputs.iter().next().unwrap().0.clone(); - return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal)))); + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputs(ex_signal))); } if !self.is_initialized { // we return the name of an input with tags that has not been assigned let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); - return (Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal)))); + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal))); } Result::Ok(()) } - pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<((Option, FoldedResult)), MemoryError>{ + pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<(Option, FoldedResult), MemoryError>{ if let Result::Err(value) = self.check_initialized_inputs(field_name) { return Err(value); } @@ -333,12 +336,14 @@ impl ComponentRepresentation { } + // Assign signals: Operations to assign signals -> case init and no init + pub fn assign_value_to_signal( component: &mut ComponentRepresentation, signal_name: &str, access: &[SliceCapacity], slice_route: &[SliceCapacity], - tags: TagInfo, + tags: &TagInfo, ) -> Result<(), MemoryError> { if !component.is_initialized{ ComponentRepresentation::assign_value_to_signal_no_init( @@ -359,217 +364,243 @@ impl ComponentRepresentation { } } - /* - Tags: - - If an input receives a value that does not contain a expected tag ==> error - - If an input receives a tag whose value is different to the expected (the one received earlier) ==> error - - */ - - - fn handle_tag_assignment(component: &mut ComponentRepresentation, signal_name: &str, tags: TagInfo) -> Option> { - if !component.is_preinitialized() { - return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent))); - } - if !component.inputs_tags.contains_key(signal_name){ - return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput))); - } - let tags_input = component.inputs_tags.get_mut(signal_name).unwrap(); - let is_first_assignment_signal = component.unassigned_tags.contains(signal_name); - component.unassigned_tags.remove(signal_name); - // We copy tags in any case, complete or incomplete assignment - // The values of the tags must be the same than the ones stored before + pub fn assign_value_to_signal_no_init( + component: &mut ComponentRepresentation, + signal_name: &str, + access: &[SliceCapacity], + slice_route: &[SliceCapacity], + tags: &TagInfo, + ) -> Result<(), MemoryError> { - for (t, value) in tags_input{ - if !tags.contains_key(t){ - return Some(Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone()))); - } else{ - if is_first_assignment_signal{ - *value = tags.get(t).unwrap().clone(); - } - else{ - // already given a value, check that it is the same - if value != tags.get(t).unwrap(){ - return Some(Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone()))); - } - } - } - } - None + // check that the tags are correct and update values + ComponentRepresentation::handle_tag_assignment_no_init(component, signal_name, tags)?; + component.to_assign_inputs.push((signal_name.to_string(), access.to_vec(), slice_route.to_vec())); + + Result::Ok(()) } - - - pub fn assign_value_to_signal_no_init( - component: &mut ComponentRepresentation, + pub fn assign_value_to_signal_init( + self: &mut ComponentRepresentation, signal_name: &str, access: &[SliceCapacity], slice_route: &[SliceCapacity], - tags: TagInfo, + tags: &TagInfo, ) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, signal_name, tags) { - //if Some, then an error was detected. - return value; + if !self.is_preinitialized() { + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); } - component.to_assign_inputs.push((signal_name.to_string(), access.to_vec(), slice_route.to_vec())); + + if !self.inputs.contains_key(signal_name){ + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); + } + + // Check that the assignment satisfies the tags requisites + + ComponentRepresentation::handle_tag_assignment_init(self, signal_name, tags); + + + // Perform the assignment + let inputs_response = self.inputs.get_mut(signal_name).unwrap(); + + perform_signal_assignment(inputs_response, &access, slice_route)?; + + // Update the value of unnasigned fields + ComponentRepresentation::update_unassigned_inputs(self, signal_name, slice_route); + Result::Ok(()) + } - //assign_value_to_bus_bus //y hay que llamar a assign_bus_field. - pub fn assign_value_to_bus_complete( - component: &mut ComponentRepresentation, - signal_name: &str, - access: &[SliceCapacity], - tags: TagInfo, - bus_slice: BusSlice - ) -> Result<(), MemoryError> { - if !component.is_initialized{ - ComponentRepresentation::assign_value_to_bus_no_init( - component, - signal_name, - access, - tags, - bus_slice - ) - } else { - ComponentRepresentation::assign_value_to_bus_init( - component, - signal_name, - access, - tags, - &bus_slice - ) - } + // Assign buses: Operations to assign buses -> case init and no init + + pub fn assign_value_to_bus( + component: &mut ComponentRepresentation, + bus_name: &str, + access: &[SliceCapacity], + bus_slice: BusSlice, + tags: &TagInfo, + ) -> Result<(), MemoryError> { + if !component.is_initialized{ + ComponentRepresentation::assign_value_to_bus_no_init( + component, + bus_name, + access, + bus_slice, + tags + ) + } else { + ComponentRepresentation::assign_value_to_bus_init( + component, + bus_name, + access, + &bus_slice, + tags + ) } + } pub fn assign_value_to_bus_no_init( component: &mut ComponentRepresentation, bus_name: &str, access: &[SliceCapacity], - tags: TagInfo, - bus_slice: BusSlice + bus_slice: BusSlice, + tags: &TagInfo, ) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { - return value; - } - component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(),bus_slice)); + // check that the tags are correct and update values + ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, tags)?; + component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(), bus_slice)); + Result::Ok(()) } - pub fn assign_value_to_signal_init( - component: &mut ComponentRepresentation, - signal_name: &str, + pub fn assign_value_to_bus_init( + self: &mut ComponentRepresentation, + bus_name: &str, access: &[SliceCapacity], - slice_route: &[SliceCapacity], - tags: TagInfo, + bus_slice: &BusSlice, + tags: &TagInfo, ) -> Result<(), MemoryError> { - if !component.is_preinitialized() { + if !self.is_preinitialized() { return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); } - if !component.inputs.contains_key(signal_name){ + if !self.input_buses.contains_key(bus_name){ return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); } // Check that the assignment satisfies the tags requisites - let tags_input = component.inputs_tags.get_mut(signal_name).unwrap(); - for (t, value) in tags_input{ - if !tags.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone())); - } else{ - // We are in the case where the component is initialized, so we - // assume that all tags already have their value and check if it is - // the same as the one we are receiving - if value != tags.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone())); - } - } - } + ComponentRepresentation::handle_tag_assignment_init(self, bus_name, tags); // Perform the assignment - let inputs_response = component.inputs.get_mut(signal_name).unwrap(); + let inputs_response = self.input_buses.get_mut(bus_name).unwrap(); - perform_signal_assignment(inputs_response, &access, slice_route)?; + perform_bus_assignment(inputs_response, &access, bus_slice, true)?; // Update the value of unnasigned fields - let mut dim_slice = 1; - for i in slice_route { - dim_slice *= *i; - } - match component.unassigned_inputs.get_mut(signal_name){ - Some(left) => { - *left -= dim_slice; - if *left == 0 { - component.unassigned_inputs.remove(signal_name); - } - } - None => {} - } + ComponentRepresentation::update_unassigned_inputs(self, bus_name, bus_slice.route()); Result::Ok(()) } + - pub fn assign_value_to_bus_init( + + // Assign bus field: Operations to assign bus fields -> case init and no init + + pub fn assign_value_to_bus_field( component: &mut ComponentRepresentation, bus_name: &str, - access: &[SliceCapacity], + access: &AccessingInformationBus, + field_value: FoldedResult, + tags: &TagInfo, + ) -> Result<(), MemoryError> { + if !component.is_initialized{ + ComponentRepresentation::assign_value_to_bus_field_no_init( + component, + bus_name, + access, + field_value, + tags + ) + } else { + ComponentRepresentation::assign_value_to_bus_field_init( + component, + bus_name, + access, + &field_value, + tags.clone() + ) + } + } + + pub fn assign_value_to_bus_field_no_init( + component: &mut ComponentRepresentation, + bus_name: &str, + access: &AccessingInformationBus, + field_value: FoldedResult, + tags: &TagInfo, + ) -> Result<(), MemoryError> { + + // check that the tags are correct and update values + ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, tags)?; + component.to_assign_input_bus_fields.push((bus_name.to_string(), access.clone(), field_value)); + + Result::Ok(()) + } + + pub fn assign_value_to_bus_field_init( + self: &mut ComponentRepresentation, + bus_name: &str, + access: &AccessingInformationBus, + field_value: &FoldedResult, tags: TagInfo, - bus_slice : &BusSlice, ) -> Result<(), MemoryError> { - if !component.is_preinitialized() { + if !self.is_preinitialized() { return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); } - if !component.input_buses.contains_key(bus_name){ + if !self.input_buses.contains_key(bus_name){ return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); } - let tags_input = component.inputs_tags.get_mut(bus_name).unwrap(); - for (t, value) in tags_input{ - if !tags.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(bus_name.to_string(), t.clone())); - } else{ - // We are in the case where the component is initialized, so we - // assume that all tags already have their value and check if it is - // the same as the one we are receiving - if value != tags.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(bus_name.to_string(), t.clone())); - } - } - } + + // Get the assigned input bus + let inputs_slice = self.input_buses.get_mut(bus_name).unwrap(); + + let access_result = BusSlice::access_values_by_mut_reference(inputs_slice, &access.array_access); + let mut accessed_bus = match access_result{ + Ok(value) => value, + Err(err) => return Err(err) + }; + + assert!(accessed_bus.len() == 1); + let single_bus = accessed_bus.get_mut(0).unwrap(); + assert!(access.field_access.is_some()); - // Perform the bus assignment + // call to bus representation to perform the assignment - let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); - let assignment_result = perform_bus_assignment(inputs_response, &access, bus_slice); - match assignment_result { - Ok(_) =>{}, - Err(err) => return Err(err) - } - // Update the unassigned inputs - let dim = BusSlice::get_number_of_cells(&bus_slice); - match component.unassigned_inputs.get_mut(bus_name){ - Some(left) => { - *left -= dim; - if *left == 0 { - component.unassigned_inputs.remove(bus_name); - } + let route_signal; + + let folded_arg = match field_value{ + FoldedResult::Signal (ss)=>{ + route_signal = ss.route().to_vec(); + FoldedArgument::Signal(&route_signal) + }, + FoldedResult::Bus (bs)=>{ + FoldedArgument::Bus(&bs) + }, + FoldedResult::Tag(_) =>{ + unreachable!() } - None => {} + }; + + single_bus.assign_value_to_field( + access.field_access.as_ref().unwrap(), + access.remaining_access.as_ref().unwrap(), + folded_arg, + Some(tags), + false + )?; + + + // In case it is completely assigned update unassigned + + if !single_bus.has_unassigned_fields(){ + ComponentRepresentation::update_unassigned_inputs(self, bus_name, &[1]); } Result::Ok(()) } + pub fn is_preinitialized(&self) -> bool { self.node_pointer.is_some() } @@ -581,126 +612,83 @@ impl ComponentRepresentation { pub fn has_unassigned_inputs(&self) -> bool{ !self.unassigned_inputs.is_empty() } + + + /* + Tags: + - If an input receives a value that does not contain a expected tag ==> error + - If an input receives a tag whose value is different to the expected (the one received earlier) ==> error + + */ + - fn check_input_errors(component: &mut ComponentRepresentation, bus_name: &str, tags: &TagInfo) -> Option> { + fn handle_tag_assignment_no_init(component: &mut ComponentRepresentation, signal_name: &str, tags: &TagInfo) -> Result<(), MemoryError> { + if !component.is_preinitialized() { - return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent))); + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); } - if !component.input_buses.contains_key(bus_name){ - return Some(Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput))); + if !component.inputs_tags.contains_key(signal_name){ + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); } - let tags_input = component.inputs_tags.get_mut(bus_name).unwrap(); - - + + let tags_input = component.inputs_tags.get_mut(signal_name).unwrap(); + let is_first_assignment_signal = component.unassigned_tags.contains(signal_name); + component.unassigned_tags.remove(signal_name); + + // We copy tags in any case, complete or incomplete assignment + // The values of the tags must be the same than the ones stored before + + for (t, value) in tags_input{ + if !tags.contains_key(t){ + return Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone())); + } else{ + if is_first_assignment_signal{ + *value = tags.get(t).unwrap().clone(); + } + else{ + // already given a value, check that it is the same + if value != tags.get(t).unwrap(){ + return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone())); + } + } + } + } + Result::Ok(()) + } + + fn handle_tag_assignment_init(component: &ComponentRepresentation, signal_name: &str, tags: &TagInfo)-> Result<(), MemoryError>{ + let tags_input = component.inputs_tags.get(signal_name).unwrap(); for (t, value) in tags_input{ if !tags.contains_key(t){ - return Some(Result::Err(MemoryError::AssignmentMissingTags(bus_name.to_string(), t.clone()))); + return Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone())); } else{ - // We are in the case where the component is initialized, so we + // We are in the case wher.e the component is initialized, so we // assume that all tags already have their value and check if it is // the same as the one we are receiving if value != tags.get(t).unwrap(){ - return Some(Result::Err(MemoryError::AssignmentTagInputTwice(bus_name.to_string(), t.clone()))); + return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone())); } } } - None + Ok(()) } - //assign_value_to_bus_signal y hay que llamar a assign_signal_field. - pub fn assign_value_to_bus_bus( - component: &mut ComponentRepresentation, - signal_name: &str, - remaining_access: AccessingInformationBus, - slice_route: &[SliceCapacity], - tags: TagInfo, - bus_slice: BusSlice - ) -> Result<(), MemoryError> { - if !component.is_initialized{ - ComponentRepresentation::assign_value_to_bus_bus_no_init( - component, - signal_name, - remaining_access, - slice_route, - tags, - bus_slice - ) - } else { - ComponentRepresentation::assign_value_to_bus_bus_init( - component, - signal_name, - remaining_access, - slice_route, - tags, - &bus_slice - ) - } - } - - fn assign_value_to_bus_bus_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: &BusSlice) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, &tags) { - return value; - } - - let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); - - let initial_value = BusSlice::get_mut_reference_to_single_value(inputs_response, &remaining_access.array_access)?; - initial_value.assign_value_to_field_bus(bus_name, &remaining_access, slice_route, bus_slice, tags) - - } - - fn assign_value_to_bus_bus_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo, bus_slice: BusSlice) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { - return value; - } - component.to_assign_input_bus_buses.push((bus_name.to_string(), remaining_access, slice_route.to_vec(),bus_slice)); - Result::Ok(()) - } - - pub fn assign_value_to_bus_signal( - component: &mut ComponentRepresentation, - signal_name: &str, - remaining_access: AccessingInformationBus, - slice_route: &[SliceCapacity], - tags: TagInfo, - ) -> Result<(), MemoryError> { - if !component.is_initialized{ - ComponentRepresentation::assign_value_to_bus_signal_no_init( - component, - signal_name, - remaining_access, - slice_route, - tags - ) - } else { - ComponentRepresentation::assign_value_to_bus_signal_init( - component, - signal_name, - remaining_access, - slice_route, - tags - ) - } - } + // Auxiliar function to update the unasigned inputs - fn assign_value_to_bus_signal_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::check_input_errors(component, bus_name, &tags) { - return value; + fn update_unassigned_inputs(component: &mut ComponentRepresentation, signal_name: &str, slice_route: &[usize]){ + let mut dim_slice = 1; + for i in slice_route { + dim_slice *= *i; } - - let inputs_response = component.input_buses.get_mut(bus_name).unwrap(); - - let initial_value = BusSlice::get_mut_reference_to_single_value(inputs_response, &remaining_access.array_access)?; - initial_value.assign_value_to_field_signal(bus_name, &remaining_access, slice_route, tags) - - } - - fn assign_value_to_bus_signal_no_init(component: &mut ComponentRepresentation, bus_name: &str, remaining_access: AccessingInformationBus, slice_route: &[usize], tags: TagInfo) -> Result<(), MemoryError> { - if let Some(value) = ComponentRepresentation::handle_tag_assignment(component, bus_name, tags) { - return value; + match component.unassigned_inputs.get_mut(signal_name){ + Some(left) => { + *left -= dim_slice; + if *left == 0 { + component.unassigned_inputs.remove(signal_name); + } + } + None => {} } - component.to_assign_input_signal_buses.push((bus_name.to_string(), remaining_access, slice_route.to_vec())); - Result::Ok(()) } } diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index 29953a6f1..e5426fe99 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -30,9 +30,18 @@ pub enum FieldTypes { // For each field, we store the info depending on if it is Bus(BusSlice), } +#[derive(Clone)] pub enum FoldedResult { // For each possible returning value, we store the info depending on if it is a signal o a bus // Depending on the case we store a different slice Signal(SignalSlice), Bus(BusSlice), Tag(BigInt) +} + + +pub enum FoldedArgument<'a> { // For each possible argument, we store the info depending on if it is a signal o a bus + // Depending on the case we store a different slice + Signal(&'a Vec), + Bus(&'a BusSlice), + Tag(&'a BigInt) } \ No newline at end of file diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 68bf13a7e..bf78916e1 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -10,8 +10,8 @@ use super::environment_utils::{ slice_types::{ AExpressionSlice, ArithmeticExpression as ArithmeticExpressionGen, ComponentRepresentation, ComponentSlice, MemoryError, TypeInvalidAccess, TypeAssignmentError, MemorySlice, - SignalSlice, SliceCapacity, TagInfo, TagState, BusSlice, BusRepresentation, - FoldedResult + SignalSlice, SliceCapacity, TagInfo, BusSlice, BusRepresentation, + FoldedResult, FoldedArgument }, }; @@ -276,7 +276,7 @@ fn execute_statement( &mut runtime.environment, actual_node, ), - VariableType::Bus(id, signal_type, tag_list) => { + VariableType::Bus(_id, signal_type, tag_list) => { execute_bus_declaration( name, &usable_dimensions, @@ -1312,7 +1312,7 @@ fn perform_assign( node.add_tag_signal(symbol, &tag, value.clone()); } }, - ExecutedStructure::Bus(node) =>{ + ExecutedStructure::Bus(_) =>{ unreachable!(); }, ExecutedStructure::None => { @@ -1323,7 +1323,7 @@ fn perform_assign( } // Get left arithmetic slice - let mut l_signal_names = Vec::new();; + let mut l_signal_names = Vec::new(); unfold_signals(full_symbol, 0, r_slice.route(), &mut l_signal_names); let mut l_expressions = Vec::new(); for signal_name in l_signal_names{ @@ -1476,7 +1476,7 @@ fn perform_assign( &signal_accessed, &accessing_information.after_signal, &arithmetic_slice.route(), - tags, + &tags, ); treat_result_with_memory_error_void( memory_response, @@ -1541,12 +1541,12 @@ fn perform_assign( } - let memory_response = ComponentRepresentation::assign_value_to_bus_complete( + let memory_response = ComponentRepresentation::assign_value_to_bus( component, &bus_accessed, &accessing_information.after_signal, - tags, - assigned_bus_slice + assigned_bus_slice, + &tags, ); treat_result_with_memory_error_void( memory_response, @@ -1717,7 +1717,7 @@ fn perform_assign( None } else if FoldedValue::valid_arithmetic_slice(&r_folded){ - // case assigning a signal of the bus or a tag + // case assigning a field of the bus if meta.get_type_knowledge().is_signal(){ let mut value_left = treat_result_with_memory_error( BusSlice::access_values_by_mut_reference(bus_slice, &accessing_information.array_access), @@ -1728,9 +1728,8 @@ fn perform_assign( assert!(value_left.len() == 1); let single_bus = value_left.get_mut(0).unwrap(); - - assert!(accessing_information.field_access.is_some()); + let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() @@ -1738,11 +1737,12 @@ fn perform_assign( TagInfo::new() }; - let memory_response = single_bus.assign_value_to_field_signal( + let memory_response = single_bus.assign_value_to_field( accessing_information.field_access.as_ref().unwrap(), accessing_information.remaining_access.as_ref().unwrap(), - &arithmetic_slice.route(), - tags, + FoldedArgument::Signal(&arithmetic_slice.route().to_vec()), + Some(tags), + false ); treat_result_with_memory_error_void( memory_response, @@ -1752,7 +1752,7 @@ fn perform_assign( )?; // Get left arithmetic slice - let mut l_signal_names = Vec::new();; + let mut l_signal_names = Vec::new(); unfold_signals(full_symbol, 0, arithmetic_slice.route(), &mut l_signal_names); let mut l_expressions = Vec::new(); for signal_name in l_signal_names{ @@ -1763,9 +1763,11 @@ fn perform_assign( } else if meta.get_type_knowledge().is_tag(){ // in case we are assigning a tag of the complete bus + // or one of its fields assert!(accessing_information.array_access.len() == 0); assert!(accessing_information.field_access.is_some()); if accessing_information.remaining_access.as_ref().unwrap().field_access.is_none(){ + // case tag of the complete bus let tag = accessing_information.field_access.as_ref().unwrap(); let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); let (reference_to_tags, reference_to_tags_defined, bus_content) = treat_result_with_environment_error( @@ -1850,10 +1852,12 @@ fn perform_assign( } else { unreachable!(); }; - let memory_response = single_bus.assign_value_to_field_tag( + let memory_response = single_bus.assign_value_to_field( accessing_information.field_access.as_ref().unwrap(), accessing_information.remaining_access.as_ref().unwrap(), - value, + FoldedArgument::Tag(&value), + None, + false ); treat_result_with_memory_error_void( memory_response, @@ -1892,7 +1896,7 @@ fn perform_assign( } // We assign the original buses - let bus_assignment_response = perform_bus_assignment(bus_slice, &accessing_information.array_access, assigned_bus_slice); + let bus_assignment_response = perform_bus_assignment(bus_slice, &accessing_information.array_access, assigned_bus_slice, false); treat_result_with_memory_error_void( bus_assignment_response, meta, @@ -1953,7 +1957,7 @@ fn perform_assign( node.add_tag_signal(symbol, &tag, value.clone()); } }, - ExecutedStructure::Bus(node) =>{ + ExecutedStructure::Bus(_) =>{ unreachable!(); }, ExecutedStructure::None => { @@ -1989,12 +1993,12 @@ fn perform_assign( TagInfo::new() }; - let memory_response = single_bus.assign_value_to_field_bus( + let memory_response = single_bus.assign_value_to_field( accessing_information.field_access.as_ref().unwrap(), accessing_information.remaining_access.as_ref().unwrap(), - &bus_slice.route(), - &bus_slice, - tags, + FoldedArgument::Bus(bus_slice), + Some(tags), + false ); treat_result_with_memory_error_void( memory_response, @@ -2829,7 +2833,7 @@ fn execute_bus_call( debug_assert!(runtime.block_type == BlockType::Known); let args_names = program_archive.get_bus_data(id).get_name_of_params(); - let template_body = program_archive.get_bus_data(id).get_body_as_vec(); + let bus_body = program_archive.get_bus_data(id).get_body_as_vec(); let mut args_to_values = BTreeMap::new(); debug_assert_eq!(args_names.len(), parameter_values.len()); let mut instantiation_name = format!("{}(", id); @@ -2852,14 +2856,13 @@ fn execute_bus_call( } else { let analysis = std::mem::replace(&mut runtime.analysis, Analysis::new(program_archive.id_max)); - let code = program_archive.get_bus_data(id).get_body().clone(); let mut node = ExecutedBus::new( id.to_string(), instantiation_name, args_to_values, ); execute_sequence_of_bus_statements( - template_body, + bus_body, program_archive, runtime, &mut node, @@ -3123,14 +3126,6 @@ fn treat_accessing_bus( } -pub fn get_final_array_access_bus_accessing(access: &AccessingInformationBus)->&Vec{ - let mut last_access = access; - while last_access.field_access.is_some(){ - last_access = &last_access.remaining_access.as_ref().unwrap(); - } - &last_access.array_access -} - //************************************************* Safe transformations ************************************************* diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index 243454e9d..bd0f06695 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -34,6 +34,7 @@ pub struct BusData { pub remaining_access: Option, // may not appear } */ +#[derive(Clone)] pub struct AccessingInformationBus { pub undefined: bool, pub array_access: Vec, From 34da3d76b13ac550cb28b32c09bf9b173743950b Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 24 May 2024 16:50:59 -0700 Subject: [PATCH 081/189] finishing components --- constraint_generation/src/execute.rs | 263 ++++++++++++++------------- 1 file changed, 141 insertions(+), 122 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index bf78916e1..80290e68a 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -297,7 +297,7 @@ fn execute_statement( } Substitution { meta, var, access, op, rhe, .. } => { let access_information = - if ExecutionEnvironment::has_bus(&runtime.environment, var){ + if ExecutionEnvironment::has_bus(&runtime.environment, var) || ExecutionEnvironment::has_component(&runtime.environment, var){ let access_bus = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; TypesAccess{bus_access: Some(access_bus), other_access: None} } else{ @@ -669,7 +669,7 @@ fn execute_bus_statement( Substitution { meta, var, access, op, rhe, .. } => { // different access information depending if bus or other variable let access_information = - if ExecutionEnvironment::has_bus(&runtime.environment, var){ + if ExecutionEnvironment::has_bus(&runtime.environment, var) || ExecutionEnvironment::has_component(&runtime.environment, var){ let access_bus = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; TypesAccess{bus_access: Some(access_bus), other_access: None} } else{ @@ -1336,7 +1336,7 @@ fn perform_assign( }} else if ExecutionEnvironment::has_component(&runtime.environment, symbol) { - let accessing_information = accessing_information.other_access.as_ref().unwrap(); + let accessing_information = accessing_information.bus_access.as_ref().unwrap(); let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); let component_slice = treat_result_with_environment_error( @@ -1355,7 +1355,7 @@ fn perform_assign( } else{ ComponentSlice::get_mut_reference_to_single_value( component_slice, - &accessing_information.before_signal, + &accessing_information.array_access, ) }; let component = treat_result_with_memory_error( @@ -1365,119 +1365,131 @@ fn perform_assign( &runtime.call_trace, )?; - if accessing_information.tag_access.is_some() { - // in this case it is a a.bus.field assign - //unreachable!() - // TODO - Option::None - } else{ - // in this case it is a complete bus or a.signal or a.bus assignment - if accessing_information.signal_access.is_none() { - // case complete component assignment - let (prenode_pointer, is_parallel) = safe_unwrap_to_valid_node_pointer(r_folded, line!()); - let memory_result = ComponentRepresentation::preinitialize_component( + + // We distinguish the different cases + if accessing_information.field_access.is_none() { + // case complete component assignment + let (prenode_pointer, is_parallel) = safe_unwrap_to_valid_node_pointer(r_folded, line!()); + let memory_result = ComponentRepresentation::preinitialize_component( + component, + is_parallel, + prenode_pointer, + &runtime.exec_program, + is_anonymous_component, + meta + ); + treat_result_with_memory_error_void( + memory_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + if component.is_ready_initialize() { + // calls to execute and initialize the component + let pretemplate_info = runtime.exec_program.get_prenode_value(prenode_pointer).unwrap(); + let inputs_tags = component.inputs_tags.clone(); + let result = execute_template_call_complete( + pretemplate_info.template_name(), + pretemplate_info.parameter_instances().clone(), + inputs_tags, + program_archive, + runtime, + flags, + )?; + let (node_pointer, _is_parallel) = safe_unwrap_to_valid_node_pointer(result, line!()); + + let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); + let component_slice = treat_result_with_environment_error( + environment_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let memory_response = if is_anonymous_component { + ComponentSlice::get_mut_reference_to_single_value( + component_slice, + &Vec::new(), + ) + } else{ + ComponentSlice::get_mut_reference_to_single_value( + component_slice, + &accessing_information.array_access, + ) + }; + let component = treat_result_with_memory_error( + memory_response, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + let init_result = ComponentRepresentation::initialize_component( component, - is_parallel, - prenode_pointer, - &runtime.exec_program, - is_anonymous_component, - meta + node_pointer, + &mut runtime.exec_program, ); - treat_result_with_memory_error_void( - memory_result, + treat_result_with_memory_error( + init_result, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - if component.is_ready_initialize() { - // calls to execute and initialize the component - let pretemplate_info = runtime.exec_program.get_prenode_value(prenode_pointer).unwrap(); - let inputs_tags = component.inputs_tags.clone(); - let result = execute_template_call_complete( - pretemplate_info.template_name(), - pretemplate_info.parameter_instances().clone(), - inputs_tags, - program_archive, - runtime, - flags, - )?; - let (node_pointer, _is_parallel) = safe_unwrap_to_valid_node_pointer(result, line!()); - - let environment_response = ExecutionEnvironment::get_mut_component_res(&mut runtime.environment, symbol); - let component_slice = treat_result_with_environment_error( - environment_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let memory_response = if is_anonymous_component { - ComponentSlice::get_mut_reference_to_single_value( - component_slice, - &Vec::new(), - ) - } else{ - ComponentSlice::get_mut_reference_to_single_value( - component_slice, - &accessing_information.before_signal, - ) - }; - let component = treat_result_with_memory_error( - memory_response, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - - let init_result = ComponentRepresentation::initialize_component( - component, - node_pointer, - &mut runtime.exec_program, - ); - treat_result_with_memory_error( - init_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - match actual_node{ - ExecutedStructure::Template(node) =>{ - let data = SubComponentData { - name: symbol.to_string(), - is_parallel: component.is_parallel, - goes_to: node_pointer, - indexed_with: accessing_information.before_signal.clone(), - }; - node.add_arrow(full_symbol.clone(), data); - }, - ExecutedStructure::Bus(_) =>{ - unreachable!(); - }, - ExecutedStructure::None => { - unreachable!(); - } - } + match actual_node{ + ExecutedStructure::Template(node) =>{ + let data = SubComponentData { + name: symbol.to_string(), + is_parallel: component.is_parallel, + goes_to: node_pointer, + indexed_with: accessing_information.array_access.clone(), + }; + node.add_arrow(full_symbol.clone(), data); + }, + ExecutedStructure::Bus(_) =>{ + unreachable!(); + }, + ExecutedStructure::None => { + unreachable!(); + } } - Option::None - } else { - // case field assignment (bus or signal) - let assigned_ae_slice = if FoldedValue::valid_arithmetic_slice(&r_folded){ - // it is signal assignment - let signal_accessed = accessing_information.signal_access.clone().unwrap(); + } + + Option::None + } else { + + let remaining_access = accessing_information.remaining_access.as_ref().unwrap(); + let assigned_ae_slice = + if FoldedValue::valid_arithmetic_slice(&r_folded) + { + + // it is signal assignment of a input signal or a field of the bus + let signal_accessed = accessing_information.field_access.as_ref().unwrap(); let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() } else { TagInfo::new() }; - - let memory_response = ComponentRepresentation::assign_value_to_signal( - component, - &signal_accessed, - &accessing_information.after_signal, - &arithmetic_slice.route(), - &tags, - ); + + let memory_response = if remaining_access.field_access.is_none(){ + ComponentRepresentation::assign_value_to_signal( + component, + &signal_accessed, + &remaining_access.array_access, + &arithmetic_slice.route(), + &tags, + ) + } else{ + // TODO + let aux_slice = SignalSlice::new_with_route(arithmetic_slice.route(), &true); + ComponentRepresentation::assign_value_to_bus_field( + component, + &signal_accessed, + &remaining_access, + FoldedResult::Signal(aux_slice), + &tags, + ) + }; treat_result_with_memory_error_void( memory_response, meta, @@ -1497,7 +1509,7 @@ fn perform_assign( (l_slice, arithmetic_slice) } else if FoldedValue::valid_bus_slice(&r_folded){ // it is a bus input - let bus_accessed = accessing_information.signal_access.clone().unwrap(); + let bus_accessed = accessing_information.field_access.as_ref().unwrap(); let (name_bus, assigned_bus_slice) = r_folded.bus_slice.unwrap(); let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() @@ -1540,14 +1552,26 @@ fn perform_assign( ae_signals_left.push(AExpr::Signal { symbol: signal_name }); } - - let memory_response = ComponentRepresentation::assign_value_to_bus( - component, - &bus_accessed, - &accessing_information.after_signal, - assigned_bus_slice, - &tags, - ); + let memory_response = + if remaining_access.field_access.is_none() + { + + ComponentRepresentation::assign_value_to_bus( + component, + &bus_accessed, + &remaining_access.array_access, + assigned_bus_slice, + &tags, + ) + } else{ + ComponentRepresentation::assign_value_to_bus_field( + component, + &bus_accessed, + &remaining_access, + FoldedResult::Bus(assigned_bus_slice), + &tags, + ) + }; treat_result_with_memory_error_void( memory_response, meta, @@ -1598,7 +1622,7 @@ fn perform_assign( } else{ ComponentSlice::get_mut_reference_to_single_value( component_slice, - &accessing_information.before_signal, + &accessing_information.array_access, ) }; let component = treat_result_with_memory_error( @@ -1625,9 +1649,9 @@ fn perform_assign( name: symbol.to_string(), goes_to: node_pointer, is_parallel: component.is_parallel, - indexed_with: accessing_information.before_signal.clone(), + indexed_with: accessing_information.array_access.clone(), }; - let component_symbol = create_component_symbol(symbol, &accessing_information); + let component_symbol = create_component_symbol(symbol, &accessing_information.array_access); node.add_arrow(component_symbol, data); }, ExecutedStructure::Bus(_) =>{ @@ -1638,13 +1662,8 @@ fn perform_assign( } } } - - - Option::Some(assigned_ae_slice) } - } - } else if ExecutionEnvironment::has_bus(&runtime.environment, symbol){ // we check if it is an input bus, in that case all signals are initialized to true @@ -2185,8 +2204,8 @@ fn create_array_accessed_symbol(symbol: &str, array_access: &Vec) -> Stri appendix.push_str(&access); format!("{}{}", symbol, appendix) } -fn create_component_symbol(symbol: &str, access_information: &AccessingInformation) -> String { - create_array_accessed_symbol(symbol, &access_information.before_signal) +fn create_component_symbol(symbol: &str, access_information: &Vec) -> String { + create_array_accessed_symbol(symbol, &access_information) } fn create_symbol(symbol: &str, access_information: &AccessingInformation) -> String { From 408a2c5318051ce9fad42c4a0b5c11415fc1a4f9 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 24 May 2024 16:53:43 -0700 Subject: [PATCH 082/189] fix in babyedwards -> detected missing tag --- tests/circomlib/escalarmulfix.circom | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/circomlib/escalarmulfix.circom b/tests/circomlib/escalarmulfix.circom index eef4b3325..eefb8a330 100644 --- a/tests/circomlib/escalarmulfix.circom +++ b/tests/circomlib/escalarmulfix.circom @@ -242,7 +242,8 @@ template EscalarMulFix(n, BASE) { var nWindows; signal {binary} aux_0 <== 0; - + + Point {babyedwards} aux; for (s=0; s Date: Sat, 25 May 2024 13:32:16 +0200 Subject: [PATCH 083/189] Corrected error in pointbits. --- tests/circomlib/pointbits.circom | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/circomlib/pointbits.circom b/tests/circomlib/pointbits.circom index e25fcb8bf..480c1f658 100644 --- a/tests/circomlib/pointbits.circom +++ b/tests/circomlib/pointbits.circom @@ -76,7 +76,7 @@ bus BinaryPoint(n) { template Bits2Point(n) { - BinaryPoint(n) {babyedwardsbin} input in; + BinaryPoint(n) input {babyedwardsbin} in; Point output {babyedwards} pout; var i; @@ -110,7 +110,7 @@ template Bits2Point(n) { } template Bits2Point_Strict() { - BinaryPoint(254) {babyedwardsbin} input in; + BinaryPoint(254) input {babyedwardsbin} in; Point output {babyedwards} pout; var i; @@ -146,7 +146,7 @@ template Bits2Point_Strict() { template Point2Bits(n) { Point input {babyedwards} pin; - BinaryPoint(n) {babyedwardsbin} output out; + BinaryPoint(n) output {babyedwardsbin} out; var i; @@ -164,7 +164,7 @@ template Point2Bits(n) { template Point2Bits_Strict() { Point input {babyedwards} pin; - BinaryPoint(254) {babyedwardsbin} output out; + BinaryPoint(254) output {babyedwardsbin} out; var i; From 75fba3d1b44b0d3e817c4a57dd2d040565bc4347 Mon Sep 17 00:00:00 2001 From: Sacul231 Date: Sat, 25 May 2024 16:20:23 +0200 Subject: [PATCH 084/189] Corrected errors on eddsa file from circomlib. --- tests/circomlib/eddsa.circom | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/circomlib/eddsa.circom b/tests/circomlib/eddsa.circom index 5baa77073..b03d2025c 100644 --- a/tests/circomlib/eddsa.circom +++ b/tests/circomlib/eddsa.circom @@ -68,7 +68,7 @@ template EdDSAVerifier(n) { hash.in.bits[254] <== 0; hash.in.bits[510] <== 0; hash.in.bits[255] <== R8.signX; - hash.in.bits[511] <== A.signY; + hash.in.bits[511] <== A.signX; for (i=0; i Date: Sat, 25 May 2024 19:52:51 +0200 Subject: [PATCH 085/189] solving issue recursive buses --- constraint_generation/src/execute.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 80290e68a..7a57012d2 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -655,11 +655,11 @@ fn execute_bus_statement( }; match xtype { - VariableType::Signal(_signal_type, tag_list) => - execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, false), + VariableType::Signal(_signal_type, tag_list) => + execute_declaration_bus(name, &usable_dimensions, tag_list, &mut runtime.environment, actual_node, false), VariableType::Bus(_id, _signal_type, tag_list) => - execute_declaration_bus(name, &usable_dimensions, tag_list, actual_node, true), + execute_declaration_bus(name, &usable_dimensions, tag_list, &mut runtime.environment, actual_node, true), _ =>{ unreachable!() @@ -1039,13 +1039,22 @@ fn execute_declaration_bus( signal_name: &str, dimensions: &[SliceCapacity], list_tags: &Vec, + environment: &mut ExecutionEnvironment, actual_node: &mut ExecutedBus, is_bus: bool, ) { + let mut tags = TagInfo::new(); + for t in list_tags{ + tags.insert(t.clone(), None); + } + if is_bus{ actual_node.add_bus(signal_name, dimensions); + environment_shortcut_add_bus_intermediate(environment, signal_name, dimensions, &tags); } else{ actual_node.add_signal(signal_name, dimensions); + environment_shortcut_add_intermediate(environment, signal_name, dimensions, &tags); + } for t in list_tags{ actual_node.add_tag_signal(signal_name, t, None); From 73351497776deaa83f6db698a74dbbd32baf27ac Mon Sep 17 00:00:00 2001 From: clararod9 Date: Sat, 25 May 2024 20:14:04 +0200 Subject: [PATCH 086/189] fix missing check unasigned fields --- .../src/environment_utils/bus_representation.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 2933f2862..ff702a8a5 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -328,7 +328,21 @@ impl BusRepresentation { assigned_value, tags, is_input - ) + )?; + + // Update from unassigned if it is completely assigned + if !resulting_bus.has_unassigned_fields(){ + match self.unassigned_fields.get_mut(field_name){ + Some(left) => { + *left -= 1; + if *left == 0 { + self.unassigned_fields.remove(field_name); + } + } + None => {} + } + } + Result::Ok(()) } Result::Err(err)=>{ return Err(err); From f4d62bcdae2ec1ebdde1dd099d683a4e55a4926e Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 28 May 2024 16:53:54 +0200 Subject: [PATCH 087/189] minors --- constraint_generation/src/assignment_utils.rs | 2 +- .../environment_utils/bus_representation.rs | 130 +++++++++--------- .../component_representation.rs | 22 ++- constraint_generation/src/execute.rs | 26 +--- .../src/execution_data/executed_bus.rs | 5 - .../src/execution_data/executed_template.rs | 4 +- program_structure/src/utils/memory_slice.rs | 4 +- .../src/decorators/type_reduction.rs | 16 +-- 8 files changed, 92 insertions(+), 117 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index 17e9248fd..83ab056c0 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -10,7 +10,7 @@ use std::mem; // Utils for assigning tags -pub fn check_tags_access(tags_values: &TagInfo, tags_definitions: &TagDefinitions)-> TagInfo{ +pub fn compute_propagated_tags(tags_values: &TagInfo, tags_definitions: &TagDefinitions)-> TagInfo{ let mut tags_propagated = TagInfo::new(); for (tag, value) in tags_values{ let state = tags_definitions.get(tag).unwrap(); diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index ff702a8a5..cb021993d 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -4,7 +4,6 @@ use crate::execution_data::type_definitions::{NodePointer, AccessingInformationB use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap}; use crate::ast::Meta; -use num_bigint_dig::BigInt; use crate::assignment_utils::*; @@ -162,16 +161,24 @@ impl BusRepresentation { let next_access = remaining_access.field_access.as_ref().unwrap(); if tags_info.contains_key(next_access){ // case tag, return its value - let value_tag = tags_info.get(next_access).unwrap(); - match value_tag{ - None =>{ - let error = MemoryError::TagValueNotInitializedAccess; - Result::Err(error) - }, - Some(v) =>{ - let folded_tag = FoldedResult::Tag(v.clone()); - Result::Ok((None, folded_tag)) + + // access only allowed when (1) it is value defined by user or (2) it is completely assigned + let state = tags_defs.get(next_access).unwrap(); + if state.value_defined || state.complete{ + let value_tag = tags_info.get(next_access).unwrap(); + match value_tag{ + None =>{ + let error = MemoryError::TagValueNotInitializedAccess; + Result::Err(error) + }, + Some(v) =>{ + let folded_tag = FoldedResult::Tag(v.clone()); + Result::Ok((None, folded_tag)) + } } + } else{ + let error = MemoryError::TagValueNotInitializedAccess; + Result::Err(error) } } else{ // case bus, access to the next field @@ -209,7 +216,7 @@ impl BusRepresentation { // in this case there is no need for recursion // compute which tags are propagated - let propagated_tags = check_tags_access(tags_info, tags_defs); + let propagated_tags = compute_propagated_tags(tags_info, tags_defs); let accessed_slice_result = SignalSlice::access_values(&signal_slice, &remaining_access.array_access); match accessed_slice_result{ @@ -225,7 +232,7 @@ impl BusRepresentation { // in this case there is no need for recursion // compute which tags are propagated - let propagated_tags = check_tags_access(tags_info, tags_defs); + let propagated_tags = compute_propagated_tags(tags_info, tags_defs); let accessed_slice_result = BusSlice::access_values(&bus_slice, &remaining_access.array_access); match accessed_slice_result{ @@ -385,23 +392,23 @@ impl BusRepresentation { // TODO: REMOVE MOVE ERROR // in case input check if tags are satisfied - // for (t, value) in info_tags{ - // if !tags.contains_key(t){ - // return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); - // } else{ - // if !is_init{ - // // First assignment of input tag - // *value = tags.get(t).unwrap().clone(); - // } - // else{ - // // already given a value, check that it is the same - // // if not return error - // if value != tags.get(t).unwrap(){ - // return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); - // } - // } - // } - // } + for (t, value) in info_tags{ + if !tags.contains_key(t){ + return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); + } else{ + if !is_init{ + // First assignment of input tag + *value = tags.get(t).unwrap().clone(); + } + else{ + // already given a value, check that it is the same + // if not return error + if value != tags.get(t).unwrap(){ + return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); + } + } + } + } } // then assign the values to the signal or bus @@ -477,10 +484,9 @@ impl BusRepresentation { if is_completely_initialized && !is_input{ - for (tag, _value) in info_tags{ - let tag_state = status_tags.get_mut(tag).unwrap(); - tag_state.complete = true; - } + for (_tag, state) in status_tags{ + state.complete = true; + } } Ok(()) } @@ -488,28 +494,20 @@ impl BusRepresentation { } pub fn completely_assign_bus(&mut self, assigned_bus: &BusRepresentation, is_input: bool)-> Result<(), MemoryError>{ + if self.has_assignment{ return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); } + self.has_assignment = true; for (field_name, value) in &mut self.fields{ // get the tags that are propagated - let (tags_definition, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let (tags_assigned_definition, tags_assigned_info) = assigned_bus.field_tags.get(field_name).unwrap(); - - let mut tags_propagated = TagInfo::new(); - for (tag, value) in tags_assigned_info{ - let state = tags_assigned_definition.get(tag).unwrap(); - if state.value_defined || state.complete{ - tags_propagated.insert(tag.clone(), value.clone()); - } else if state.defined{ - tags_propagated.insert(tag.clone(), None); - } - } + let tags_propagated = compute_propagated_tags(tags_assigned_info, tags_assigned_definition); + // TODO: check if the bus is initialized -> not needed always is not? let is_init = match value{ FieldTypes::Bus(bus_slice) =>{ let mut bus_is_init = false; @@ -527,6 +525,7 @@ impl BusRepresentation { SignalSlice::get_number_of_inserts(&signal_slice) > 0 } }; + assert!(!is_init); // perform the tag assignment if !is_input{ @@ -534,25 +533,24 @@ impl BusRepresentation { perform_tag_propagation(tags_info, tags_definition, &tags_propagated, is_init); } else{ - // TODO: REMOVE MOVE ERROR // in case input check if tags are satisfied - // for (t, value) in tags_info{ - // if !tags_propagated.contains_key(t){ - // return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); - // } else{ - // if !is_init{ - // // First assignment of input tag - // *value = tags_propagated.get(t).unwrap().clone(); - // } - // else{ - // // already given a value, check that it is the same - // // if not return error - // if value != tags_propagated.get(t).unwrap(){ - // return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); - // } - // } - // } - // } + for (t, value) in tags_info{ + if !tags_propagated.contains_key(t){ + return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); + } else{ + if !is_init{ + // First assignment of input tag + *value = tags_propagated.get(t).unwrap().clone(); + } + else{ + // already given a value, check that it is the same + // if not return error + if value != tags_propagated.get(t).unwrap(){ + return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); + } + } + } + } } // perform the assignment @@ -601,10 +599,10 @@ impl BusRepresentation { // Update the value of unnasigned fields self.unassigned_fields.remove(field_name); + // Update the value of the complete tags - for (tag, _value) in tags_info{ - let tag_state = tags_definition.get_mut(tag).unwrap(); - tag_state.complete = true; + for (_tag, state) in tags_definition{ + state.complete = true; } } Ok(()) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index d2ead8c8d..70ccff266 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -1,4 +1,4 @@ -use super::slice_types::{FoldedResult, FoldedArgument, BusSlice, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TypeAssignmentError, TypeInvalidAccess}; +use super::slice_types::{FoldedResult, FoldedArgument, BusSlice, MemoryError, SignalSlice, SliceCapacity, TagInfo, TypeAssignmentError, TypeInvalidAccess}; use crate::execution_data::type_definitions::AccessingInformationBus; use crate::{environment_utils::slice_types::BusRepresentation, execution_data::type_definitions::NodePointer}; use crate::execution_data::ExecutedProgram; @@ -191,7 +191,7 @@ impl ComponentRepresentation { &mut initial_value_bus, bus_node, scheme, - true // it is initialized at the begining + true // the outputs of the component are initialized at the begining )?; let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); @@ -294,6 +294,8 @@ impl ComponentRepresentation { let next_array_access = &remaining_access.array_access; let next_field_access = remaining_access.field_access.as_ref().unwrap(); let next_remaining_access = remaining_access.remaining_access.as_ref().unwrap(); + + // we distingish between tags or buses if tag_info.contains_key(remaining_access.field_access.as_ref().unwrap()){ // in this case we are returning a tag assert!(next_array_access.len() == 0); @@ -321,7 +323,8 @@ impl ComponentRepresentation { accessed_bus.get_field(next_field_access, next_remaining_access) } } else{ - // We are accessing the complete bus + + // In this case we are accessing the complete bus let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); match accessed_slice_result{ @@ -396,13 +399,11 @@ impl ComponentRepresentation { } // Check that the assignment satisfies the tags requisites - - ComponentRepresentation::handle_tag_assignment_init(self, signal_name, tags); + ComponentRepresentation::handle_tag_assignment_init(self, signal_name, tags)?; // Perform the assignment let inputs_response = self.inputs.get_mut(signal_name).unwrap(); - perform_signal_assignment(inputs_response, &access, slice_route)?; // Update the value of unnasigned fields @@ -472,13 +473,10 @@ impl ComponentRepresentation { } // Check that the assignment satisfies the tags requisites - - ComponentRepresentation::handle_tag_assignment_init(self, bus_name, tags); - + ComponentRepresentation::handle_tag_assignment_init(self, bus_name, tags)?; // Perform the assignment let inputs_response = self.input_buses.get_mut(bus_name).unwrap(); - perform_bus_assignment(inputs_response, &access, bus_slice, true)?; // Update the value of unnasigned fields @@ -564,8 +562,6 @@ impl ComponentRepresentation { assert!(access.field_access.is_some()); // call to bus representation to perform the assignment - - let route_signal; let folded_arg = match field_value{ @@ -673,7 +669,7 @@ impl ComponentRepresentation { Ok(()) } - // Auxiliar function to update the unasigned inputs + // Auxiliar function to update the unassigned inputs fn update_unassigned_inputs(component: &mut ComponentRepresentation, signal_name: &str, slice_route: &[usize]){ let mut dim_slice = 1; diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 7a57012d2..0ba3b2b6f 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -29,7 +29,6 @@ use super::{ }; use circom_algebra::num_bigint::BigInt; use std::collections::{HashMap, BTreeMap}; -use std::mem; use crate::FlagsExecution; type AExpr = ArithmeticExpressionGen; type AnonymousComponentsInfo = BTreeMap)>; @@ -616,7 +615,7 @@ fn execute_bus_statement( use Statement::*; let id = stmt.get_meta().elem_id; Analysis::reached(&mut runtime.analysis, id); - let res = match stmt { + let _res = match stmt { InitializationBlock { initializations, .. } => { execute_sequence_of_bus_statements( initializations, @@ -2377,15 +2376,8 @@ fn execute_signal( &runtime.call_trace, )?; - let mut tags_propagated = TagInfo::new(); - for (tag, value) in tags{ - let state = tags_definitions.get(tag).unwrap(); - if state.value_defined || state.complete{ - tags_propagated.insert(tag.clone(), value.clone()); - } else if state.defined{ - tags_propagated.insert(tag.clone(), None); - } - } + // check which tags are propagated + let tags_propagated = compute_propagated_tags(tags, tags_definitions); Result::Ok(FoldedValue { arithmetic_slice: Option::Some(arith_slice), @@ -2457,15 +2449,9 @@ fn execute_bus( // Case we are accessing the complete bus or array of buses let symbol = create_symbol_bus(symbol, &access_information); - let mut tags_propagated = TagInfo::new(); - for (tag, value) in tags{ - let state = tags_definitions.get(tag).unwrap(); - if state.value_defined || state.complete{ - tags_propagated.insert(tag.clone(), value.clone()); - } else if state.defined{ - tags_propagated.insert(tag.clone(), None); - } - } + // Compute which tags are propagated + let tags_propagated = compute_propagated_tags(tags, tags_definitions); + // Check that all the buses are completely assigned for i in 0..BusSlice::get_number_of_cells(&bus_slice){ diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index a52f1e1c1..c75b63f02 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -1,6 +1,5 @@ use super::type_definitions::*; -use dag::DAG; use num_bigint::BigInt; use std::collections::HashMap; use crate::execution_data::TagInfo; @@ -73,10 +72,6 @@ impl ExecutedBus { } } - fn build_signals(&self, dag: &mut DAG) { - - } - pub fn bus_name(&self) -> &String { &self.bus_name } diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 89c0a82fa..109cb4d17 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -510,13 +510,13 @@ fn generate_bus_symbols(dag: &mut DAG, state: State, config: &SignalConfig, bus_ let ex_bus2 = buses.get(bus_connection.inspect.goes_to).unwrap(); if state.dim == config.dimensions.len() { for (signal, signal_dims) in ex_bus2.signal_fields(){ - let mut signal_name = format!("{}.{}",state.name,signal); + let signal_name = format!("{}.{}",state.name,signal); let state = State { basic_name: signal.clone(), name: signal_name, dim: 0 }; let config = SignalConfig { signal_type: config.signal_type, dimensions: signal_dims, is_public: config.is_public }; generate_symbols(dag, state, &config); } for (bus, bus_dims) in ex_bus2.bus_fields(){ - let mut bus_name = format!("{}.{}",state.name,bus); + let bus_name = format!("{}.{}",state.name,bus); let state = State { basic_name: bus.clone(), name: bus_name, dim: 0 }; let config = SignalConfig { signal_type: config.signal_type, dimensions: &bus_dims, is_public: config.is_public }; generate_bus_symbols(dag, state, &config, ex_bus2.bus_connexions(), buses); diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 8b5a177ce..c6df80829 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -197,7 +197,7 @@ impl MemorySlice { return Ok(values); } - let (size, number_of_cells) = + let (_size, number_of_cells) = MemorySlice::generate_new_route_from_access(memory_slice, access)?; let mut values = Vec::with_capacity(number_of_cells); let initial_cell = MemorySlice::get_initial_cell(memory_slice, access)?; @@ -225,7 +225,7 @@ impl MemorySlice { return Ok(values); } - let (size, number_of_cells) = + let (_size, number_of_cells) = MemorySlice::generate_new_route_from_access(memory_slice, access)?; let mut values = Vec::with_capacity(number_of_cells); let initial_cell = MemorySlice::get_initial_cell(memory_slice, access)?; diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 2a5b15d50..37903b28d 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -307,14 +307,14 @@ fn reduce_types_in_vec_of_expressions(vec: &mut [Expression], environment: &Envi } // Errors -fn name_not_found_in_bus_error(signal: String, what: String, meta: &Meta, reports: &mut ReportCollection) { - let message = "Bus or signal not defined in bus".to_string(); - let error_code = ReportCode::InvalidSignalAccessInBus; - let mut report = Report::error(message, error_code); - let message = signal + &" is not defined in ".to_string() + what.as_str(); - report.add_primary(meta.file_location(), meta.get_file_id(), message); - reports.push(report); -} +// fn name_not_found_in_bus_error(signal: String, what: String, meta: &Meta, reports: &mut ReportCollection) { +// let message = "Bus or signal not defined in bus".to_string(); +// let error_code = ReportCode::InvalidSignalAccessInBus; +// let mut report = Report::error(message, error_code); +// let message = signal + &" is not defined in ".to_string() + what.as_str(); +// report.add_primary(meta.file_location(), meta.get_file_id(), message); +// reports.push(report); +// } fn name_not_found_in_component_error(signal: String, what: String, meta: &Meta, reports: &mut ReportCollection) { let message = "Bus or signal not defined in component".to_string(); From f8477a3aca88536ecac64e4f7ba63684c3be402d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 29 May 2024 17:38:17 +0200 Subject: [PATCH 088/189] solving todos and minors --- .../environment_utils/bus_representation.rs | 64 +++++++++---------- .../src/environment_utils/environment.rs | 2 - constraint_generation/src/execute.rs | 7 +- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index cb021993d..3e202c6af 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -303,13 +303,13 @@ impl BusRepresentation { let possible_tag = info_tags.get_mut(next_access); if let Some(val) = possible_tag { if let Some(_) = val { + // already assigned value, return error Result::Err(MemoryError::AssignmentTagTwice) } else { // we add the info saying that the tag is defined let tag_state = status_tags.get_mut(next_access).unwrap(); tag_state.value_defined = true; *val = Option::Some(value.clone()); Result::Ok(()) - } } else{ unreachable!() @@ -389,8 +389,6 @@ impl BusRepresentation { // case no input, just propagate perform_tag_propagation(info_tags, status_tags, &tags, is_init); } else{ - // TODO: REMOVE MOVE ERROR - // in case input check if tags are satisfied for (t, value) in info_tags{ if !tags.contains_key(t){ @@ -507,25 +505,26 @@ impl BusRepresentation { let (tags_assigned_definition, tags_assigned_info) = assigned_bus.field_tags.get(field_name).unwrap(); let tags_propagated = compute_propagated_tags(tags_assigned_info, tags_assigned_definition); - // TODO: check if the bus is initialized -> not needed always is not? - let is_init = match value{ - FieldTypes::Bus(bus_slice) =>{ - let mut bus_is_init = false; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ - Ok(bus) => { - bus_is_init |= bus.has_assignment(); - } - Err(_) => unreachable!() - } - } - bus_is_init - }, - FieldTypes::Signal(signal_slice)=>{ - SignalSlice::get_number_of_inserts(&signal_slice) > 0 - } - }; - assert!(!is_init); + // TODO: REMOVE check if the bus is initialized -> not needed, always is not? + let is_init = false; + // let is_init = match value{ + // FieldTypes::Bus(bus_slice) =>{ + // let mut bus_is_init = false; + // for i in 0..BusSlice::get_number_of_cells(bus_slice){ + // match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ + // Ok(bus) => { + // bus_is_init |= bus.has_assignment(); + // } + // Err(_) => unreachable!() + // } + // } + // bus_is_init + // }, + // FieldTypes::Signal(signal_slice)=>{ + // SignalSlice::get_number_of_inserts(&signal_slice) > 0 + // } + // }; + // assert!(!is_init); // perform the tag assignment if !is_input{ @@ -538,17 +537,18 @@ impl BusRepresentation { if !tags_propagated.contains_key(t){ return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); } else{ - if !is_init{ + //if !is_init{ + // Not needed check, always not init, if not error // First assignment of input tag *value = tags_propagated.get(t).unwrap().clone(); - } - else{ - // already given a value, check that it is the same - // if not return error - if value != tags_propagated.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); - } - } + //} + // else{ + // // already given a value, check that it is the same + // // if not return error + // if value != tags_propagated.get(t).unwrap(){ + // return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); + // } + // } } } } @@ -575,7 +575,7 @@ impl BusRepresentation { let new_value_slice = &SignalSlice::new_with_route(signal_slice.route(), &true); - // Not needed because we know that it has not been assigned? + // : Not needed because we know that it has not been assigned? // let dim_slice: usize = SignalSlice::get_number_of_cells(signal_slice); // for i in 0..dim_slice{ // let signal_was_assigned = match SignalSlice::access_value_by_index(&signal_slice, i){ diff --git a/constraint_generation/src/environment_utils/environment.rs b/constraint_generation/src/environment_utils/environment.rs index 86fbf0cd3..f1be900e7 100644 --- a/constraint_generation/src/environment_utils/environment.rs +++ b/constraint_generation/src/environment_utils/environment.rs @@ -17,8 +17,6 @@ use crate::ast::Meta; pub type ExecutionEnvironmentError = CircomEnvironmentError; pub type ExecutionEnvironment = CircomEnvironment; -// TODO: ADD environment buses -> BusSlice - pub fn environment_shortcut_add_component( environment: &mut ExecutionEnvironment, component_name: &str, diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 0ba3b2b6f..ae04f025c 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1488,7 +1488,6 @@ fn perform_assign( &tags, ) } else{ - // TODO let aux_slice = SignalSlice::new_with_route(arithmetic_slice.route(), &true); ComponentRepresentation::assign_value_to_bus_field( component, @@ -1529,7 +1528,8 @@ fn perform_assign( let mut signals_values_right: Vec = Vec::new(); let mut signals_values_left: Vec = Vec::new(); - // TODO: get the correct final index + // TODO: in case all bus slices contain the same types not needed of + // traversing all of them? for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i), @@ -2556,9 +2556,6 @@ fn execute_component( runtime: &mut RuntimeInformation, flags: FlagsExecution ) -> Result { - - - // TODO: cases access signal/bus inside a bus, all in same case let access_information = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; if access_information.undefined { From 75fbaf81fb30359c2f67c9f24bedf396f4020cd0 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 30 May 2024 17:58:34 +0200 Subject: [PATCH 089/189] fixing minors --- constraint_generation/src/assignment_utils.rs | 1 + .../environment_utils/bus_representation.rs | 20 ++--- .../component_representation.rs | 7 +- constraint_generation/src/execute.rs | 73 +++++++++++++++---- program_structure/src/utils/memory_slice.rs | 10 ++- 5 files changed, 78 insertions(+), 33 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index 83ab056c0..dd886ac47 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -171,6 +171,7 @@ pub fn perform_bus_assignment(bus_slice: &mut BusSlice, array_access: &[SliceCap Err(err) => return Err(err) }; + let value_left = match BusSlice::access_values_by_mut_reference(bus_slice, array_access){ Ok(value) => value, Err(err) => return Err(err) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 3e202c6af..3a89de2b0 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -107,21 +107,6 @@ impl BusRepresentation { let field_bus = FieldTypes::Bus(bus_slice); component.fields.insert(symbol.clone(), field_bus); - // add the tags - if node.signal_to_tags.get(symbol).is_some(){ - let defined_tags = node.signal_to_tags.get(symbol).unwrap(); - let mut definitions = BTreeMap::new(); - let mut values = BTreeMap::new(); - for (tag, value) in defined_tags{ - let tag_state = TagState{defined:true, value_defined: value.is_some(), complete: true}; - definitions.insert(tag.clone(), tag_state); - values.insert(tag.clone(), value.clone()); - - } - component.field_tags.insert(symbol.clone(), (definitions, values)); - } else{ - component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); - } // add the tags if node.signal_to_tags.get(symbol).is_some(){ let defined_tags = node.signal_to_tags.get(symbol).unwrap(); @@ -497,6 +482,11 @@ impl BusRepresentation { return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); } + // check that they are the same instance of buses + if self.node_pointer != assigned_bus.node_pointer{ + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::DifferentBusInstances)); + } + self.has_assignment = true; for (field_name, value) in &mut self.fields{ diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 70ccff266..5e775cef8 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -525,7 +525,10 @@ impl ComponentRepresentation { ) -> Result<(), MemoryError> { // check that the tags are correct and update values - ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, tags)?; + //ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, tags)?; + + // TODO: add the info of the fields, not of the bus + component.to_assign_input_bus_fields.push((bus_name.to_string(), access.clone(), field_value)); Result::Ok(()) @@ -582,7 +585,7 @@ impl ComponentRepresentation { access.remaining_access.as_ref().unwrap(), folded_arg, Some(tags), - false + true // it is an input so check tags instead of propagate )?; diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index ae04f025c..96b2f385b 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -579,25 +579,58 @@ fn execute_statement( } UnderscoreSubstitution{ meta, rhe, op} =>{ let f_result = execute_expression(rhe, program_archive, runtime, flags)?; - let arithmetic_slice = safe_unwrap_to_arithmetic_slice(f_result, line!()); - if *op == AssignOp::AssignConstraintSignal{ - for i in 0..AExpressionSlice::get_number_of_cells(&arithmetic_slice){ - let value_cell = treat_result_with_memory_error( - AExpressionSlice::access_value_by_index(&arithmetic_slice, i), + if FoldedValue::valid_arithmetic_slice(&f_result){ + let arithmetic_slice = safe_unwrap_to_arithmetic_slice(f_result, line!()); + if *op == AssignOp::AssignConstraintSignal{ + for i in 0..AExpressionSlice::get_number_of_cells(&arithmetic_slice){ + let value_cell = treat_result_with_memory_error( + AExpressionSlice::access_value_by_index(&arithmetic_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let constraint_expression = AExpr::transform_expression_to_constraint_form( + value_cell, + runtime.constants.get_p(), + ).unwrap(); + if let Option::Some(node) = actual_node { + for signal in constraint_expression.take_signals(){ + node.add_underscored_signal(signal); + } + } + } + } + } else if FoldedValue::valid_bus_slice(&f_result){ + // TODO: improve, only generate values once + let (bus_name, bus_slice) = safe_unwrap_to_bus_slice(f_result, line!()); + let mut signal_values = Vec::new(); + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + let assigned_bus = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&bus_slice, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - let constraint_expression = AExpr::transform_expression_to_constraint_form( - value_cell, - runtime.constants.get_p(), - ).unwrap(); - if let Option::Some(node) = actual_node { - for signal in constraint_expression.take_signals(){ - node.add_underscored_signal(signal); - } - } + + let access_index = treat_result_with_memory_error( + BusSlice::get_access_index(&bus_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let string_index = create_index_appendix(&access_index); + + signal_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", bus_name, string_index))); } + + if let Option::Some(node) = actual_node { + for signal_name in &signal_values{ + node.add_underscored_signal(signal_name); + } + } + + } else{ + unreachable!() } Option::None } @@ -3157,6 +3190,10 @@ fn safe_unwrap_to_valid_bus_node_pointer(folded_value: FoldedValue, line: u32) - debug_assert!(FoldedValue::valid_bus_node_pointer(&folded_value), "Caused by call at {}", line); folded_value.bus_node_pointer.unwrap() } +fn safe_unwrap_to_bus_slice(folded_value: FoldedValue, line: u32) -> (String, BusSlice) { + debug_assert!(FoldedValue::valid_arithmetic_slice(&folded_value), "Caused by call at {}", line); + folded_value.bus_slice.unwrap() +} fn safe_unwrap_to_single(slice: MemorySlice, line: u32) -> C { debug_assert!(slice.is_single(), "Caused by call at {}", line); MemorySlice::unwrap_to_single(slice) @@ -3248,6 +3285,10 @@ fn treat_result_with_memory_error_void( TypeAssignmentError::NoInitializedComponent =>{ Report::error("Exception caused by invalid assignment: trying to assign a value to a signal of a component that has not been initialized".to_string(), RuntimeError) + }, + TypeAssignmentError::DifferentBusInstances =>{ + Report::error("Exception caused by invalid assignment: trying to assign a different instance of the bus. The instances of the buses should be equal".to_string(), + RuntimeError) } } }, @@ -3355,6 +3396,10 @@ pub fn treat_result_with_memory_error( TypeAssignmentError::NoInitializedComponent =>{ Report::error("Exception caused by invalid assignment: trying to assign a value to a signal of a component that has not been initialized".to_string(), RuntimeError) + }, + TypeAssignmentError::DifferentBusInstances =>{ + Report::error("Exception caused by invalid assignment: trying to assign a different instance of the bus. The instances of the buses should be equal".to_string(), + RuntimeError) } } }, diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index c6df80829..5d6d71976 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -12,7 +12,8 @@ pub enum TypeInvalidAccess { pub enum TypeAssignmentError { MultipleAssignments, AssignmentOutput, - NoInitializedComponent + NoInitializedComponent, + DifferentBusInstances } pub enum MemoryError { @@ -37,13 +38,18 @@ pub type SimpleSlice = MemorySlice; The attribute route stores the dimensions of the slice, used to navigate through them. The length of values is equal to multiplying all the values in route. */ -#[derive(Eq, PartialEq)] pub struct MemorySlice { route: Vec, values: Vec, number_inserts: usize, } +impl PartialEq for MemorySlice { + fn eq(&self, other: &Self) -> bool{ + self.route == other.route && self.values == other.values + } +} + impl Clone for MemorySlice { fn clone(&self) -> Self { MemorySlice { From 496ba6377c9d30f5ee8ccad1ff7550bcd3163bf9 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 4 Jun 2024 10:27:38 +0200 Subject: [PATCH 090/189] working on buses: constraint equality with buses --- constraint_generation/src/execute.rs | 99 +++++++++++++++++---- program_structure/src/utils/memory_slice.rs | 1 + 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 96b2f385b..d58262cf0 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -415,29 +415,80 @@ fn execute_statement( debug_assert!(actual_node.is_some()); let f_left = execute_expression(lhe, program_archive, runtime, flags)?; let f_right = execute_expression(rhe, program_archive, runtime, flags)?; - let arith_left = safe_unwrap_to_arithmetic_slice(f_left, line!()); - let arith_right = safe_unwrap_to_arithmetic_slice(f_right, line!()); - - let correct_dims_result = AExpressionSlice::check_correct_dims(&arith_left, &Vec::new(), &arith_right, true); - treat_result_with_memory_error_void( - correct_dims_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - for i in 0..AExpressionSlice::get_number_of_cells(&arith_left){ - let value_left = treat_result_with_memory_error( - AExpressionSlice::access_value_by_index(&arith_left, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - let value_right = treat_result_with_memory_error( - AExpressionSlice::access_value_by_index(&arith_right, i), + + let (arith_left, arith_right) = if FoldedValue::valid_arithmetic_slice(&f_left) && FoldedValue::valid_arithmetic_slice(&f_right){ + let left = safe_unwrap_to_arithmetic_slice(f_left, line!()); + let right = safe_unwrap_to_arithmetic_slice(f_right, line!()); + let correct_dims_result = AExpressionSlice::check_correct_dims(&left, &Vec::new(), &right, true); + treat_result_with_memory_error_void( + correct_dims_result, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; + (left.destruct().1, right.destruct().1) + } else if FoldedValue::valid_bus_slice(&f_left) && FoldedValue::valid_bus_slice(&f_right){ + let (name_left, slice_left) = safe_unwrap_to_bus_slice(f_left, line!()); + let (name_right, slice_right) = safe_unwrap_to_bus_slice(f_right, line!()); + + // Generate an arithmetic slice for the buses left and right + let mut signals_values_right: Vec = Vec::new(); + let mut signals_values_left: Vec = Vec::new(); + + // TODO: in case all bus slices contain the same types not needed of + // traversing all of them? + for i in 0..BusSlice::get_number_of_cells(&slice_left){ + let left_i = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&slice_left, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let right_i = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&slice_right, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + // ensure same type of bus + if left_i.node_pointer != right_i.node_pointer{ + treat_result_with_memory_error( + Result::Err(MemoryError::MismatchedInstances), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } + + // TODO: do not call twice to get_accesses and better index + + let access_index = treat_result_with_memory_error( + BusSlice::get_access_index(&slice_left, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let string_index = create_index_appendix(&access_index); + + signals_values_right.append(&mut left_i.get_accesses_bus(&format!("{}{}", name_left, string_index))); + signals_values_left.append(&mut left_i.get_accesses_bus(&format!("{}{}", name_right, string_index))); + } + let mut ae_signals_left = Vec::new(); + for signal_name in signals_values_left{ + ae_signals_left.push(AExpr::Signal { symbol: signal_name }); + } + let mut ae_signals_right = Vec::new(); + for signal_name in signals_values_right{ + ae_signals_right.push(AExpr::Signal { symbol: signal_name }); + } + (ae_signals_left, ae_signals_right) + } else{ + unreachable!() + }; + + for i in 0..arith_left.len(){ + let value_left = &arith_left[i]; + let value_right = &arith_right[i]; let possible_non_quadratic = AExpr::sub( &value_left, @@ -3301,6 +3352,11 @@ fn treat_result_with_memory_error_void( orig, given), RuntimeError) }, + MemoryError::MismatchedInstances => { + Report::error( + format!("Typing error found: mismatched instances.\n Trying to compare two different instances of a bus, the instances must be equal"), + RuntimeError) + }, MemoryError::UnknownSizeDimension => { Report::error("Array dimension with unknown size".to_string(), RuntimeError) @@ -3434,6 +3490,11 @@ pub fn treat_result_with_memory_error( orig, given), RuntimeError) }, + MemoryError::MismatchedInstances => { + Report::error( + format!("Typing error found: mismatched instances.\n Trying to compare two different instances of a bus, the instances must be equal"), + RuntimeError) + }, MemoryError::UnknownSizeDimension => { Report::error("Array dimension with unknown size".to_string(), RuntimeError) } diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 5d6d71976..7c1a93d7a 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -21,6 +21,7 @@ pub enum MemoryError { AssignmentError(TypeAssignmentError), InvalidAccess(TypeInvalidAccess), UnknownSizeDimension, + MismatchedInstances, MismatchedDimensions(usize, usize), MismatchedDimensionsWeak(usize, usize), AssignmentMissingTags(String, String), From f3c1ea601f774d28127676ec8cf696b6d32f2632 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 4 Jun 2024 12:10:52 +0200 Subject: [PATCH 091/189] fixing missing check: tags in bus inputs when assigning just a single field --- .../src/environment_utils/bus_representation.rs | 13 ++++++++++++- .../environment_utils/component_representation.rs | 6 +++--- tests/circomlib/babyjub.circom | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 3a89de2b0..43b6ce108 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -306,10 +306,21 @@ impl BusRepresentation { match field{ FieldTypes::Bus(bus_slice)=>{ // case bus -> apply recursion + + // no tags assigned to the complete bus + // Check in case input if it is expecting tags, if so return error + if is_input{ + if !info_tags.is_empty(){ + let (possible_tag, _) = info_tags.iter().next().unwrap(); + return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), possible_tag.clone())); + } + } + + let memory_response = BusSlice::access_values_by_mut_reference( bus_slice, &remaining_access.array_access - ); + ); match memory_response{ Result::Ok(mut bus_slice) =>{ assert!(bus_slice.len() == 1); diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 5e775cef8..68d00d808 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -524,11 +524,11 @@ impl ComponentRepresentation { tags: &TagInfo, ) -> Result<(), MemoryError> { - // check that the tags are correct and update values - //ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, tags)?; + // check that the tags are correct and update values, in this case none inputs + // are assigned to the complete bus + ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, &TagInfo::new())?; // TODO: add the info of the fields, not of the bus - component.to_assign_input_bus_fields.push((bus_name.to_string(), access.clone(), field_value)); Result::Ok(()) diff --git a/tests/circomlib/babyjub.circom b/tests/circomlib/babyjub.circom index 2314b9594..d778dbb36 100644 --- a/tests/circomlib/babyjub.circom +++ b/tests/circomlib/babyjub.circom @@ -177,4 +177,4 @@ template BabyPbk() { mulFix.e <== pvkBits.out; A <== mulFix.out; -} \ No newline at end of file +} From f5a6f2ce38e19275c66754d33cecc68ef680714f Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 4 Jun 2024 15:12:03 +0200 Subject: [PATCH 092/189] allowing bus initializations both with <== and with <--. --- parser/src/lang.lalrpop | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index b837d0c79..f7fe32d8a 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -298,13 +298,13 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols, init) }, -// "(" ",")*> ")" => { -// let (bus_type,xtype) = bus_header; -// let mut symbols = symbols; -// let meta = Meta::new(s,e); -// symbols.push(symbol); -// ast_shortcuts::split_bus_declaration_into_single_nodes_and_multisubstitution(meta,bus_type,xtype,symbols, init) -// }, + /*( "(" ",")*> ")" => { + let (bus_type,xtype) = bus_header; + let mut symbols = symbols; + let meta = Meta::new(s,e); + symbols.push(symbol); + ast_shortcuts::split_bus_declaration_into_single_nodes_and_multisubstitution(meta,bus_type,xtype,symbols, init) + },*/ "var" ",")*> => { let mut symbols = symbols; @@ -342,9 +342,16 @@ ParseDeclaration : Statement = { let mut symbols = symbols; let meta = Meta::new(s,e); symbols.push(symbol); - ast_shortcuts::split_bus_declaration_into_single_nodes(meta,bus_type,xtype,symbols,AssignOp::AssignSignal) + ast_shortcuts::split_bus_declaration_into_single_nodes(meta,bus_type,xtype,symbols,AssignOp::AssignConstraintSignal) }, + ",")*> => { + let (bus_type,xtype) = bus_header; + let mut symbols = symbols; + let meta = Meta::new(s,e); + symbols.push(symbol); + ast_shortcuts::split_bus_declaration_into_single_nodes(meta,bus_type,xtype,symbols,AssignOp::AssignSignal) +}, }; From 23be5c82cf3b5629184cdfdb1e80ae4efc646125 Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 4 Jun 2024 15:14:22 +0200 Subject: [PATCH 093/189] allowing bus initializations both with <== and with <--. --- parser/src/lang.lalrpop | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index f7fe32d8a..f2cb5e6db 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -298,13 +298,13 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols, init) }, - /*( "(" ",")*> ")" => { - let (bus_type,xtype) = bus_header; - let mut symbols = symbols; - let meta = Meta::new(s,e); - symbols.push(symbol); - ast_shortcuts::split_bus_declaration_into_single_nodes_and_multisubstitution(meta,bus_type,xtype,symbols, init) - },*/ + // ( "(" ",")*> ")" => { + // let (bus_type,xtype) = bus_header; + // let mut symbols = symbols; + // let meta = Meta::new(s,e); + // symbols.push(symbol); + // ast_shortcuts::split_bus_declaration_into_single_nodes_and_multisubstitution(meta,bus_type,xtype,symbols, init) + // }, "var" ",")*> => { let mut symbols = symbols; From ce45b7100d1d85f7e97b2f3f61ecb0869a25b1bb Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 11 Jun 2024 03:44:56 +0200 Subject: [PATCH 094/189] adding more information in bus error typecheck --- .../src/program_library/error_code.rs | 7 +- type_analysis/src/analyzers/type_check.rs | 103 +++++++++++++++--- 2 files changed, 92 insertions(+), 18 deletions(-) diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 8ce2b0e03..eed974848 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -63,7 +63,8 @@ pub enum ReportCode { ParallelOperatorWithWrongTypes, InfixOperatorWithWrongTypes, InvalidArgumentInCall, - InvalidArgumentInBusInstantiation, + InvalidArgumentInBusInstantiationT, + InvalidArgumentInBusInstantiationB, InconsistentReturnTypesInBlock, InconsistentStaticInformation, InvalidArrayAccess(usize, usize), @@ -74,6 +75,7 @@ pub enum ReportCode { InvalidArraySizeT, InvalidArraySizeB, InvalidArrayType, + InvalidArrayTypeB, ForStatementIllConstructed, BadArrayAccess, AssigningAComponentTwice, @@ -84,6 +86,7 @@ pub enum ReportCode { InvalidPartialArray, MustBeSingleArithmetic(usize), MustBeSingleArithmeticT, + MustBeSingleArithmeticB, MustBeArithmetic, OutputTagCannotBeModifiedOutside, MustBeSameDimension(usize, usize), @@ -176,6 +179,7 @@ impl fmt::Display for ReportCode { InvalidArraySize(..) => "T2033", InvalidArraySizeT => "T2033", InvalidArrayType => "T2034", + InvalidArrayType => "T2034", ForStatementIllConstructed => "T2035", BadArrayAccess => "T2035", AssigningAComponentTwice => "T2036", @@ -187,6 +191,7 @@ impl fmt::Display for ReportCode { InvalidPartialArray => "T2043", MustBeSingleArithmetic(..) => "T2044", MustBeSingleArithmeticT => "T2044", + MustBeSingleArithmeticB => "T2044", ExpectedDimDiffGotDim(..) => "T2045", MustBeSameDimension(..) => "T2046", MustBeArithmetic => "T2047", diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index b27f2afa8..67eebce6b 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -350,12 +350,18 @@ fn type_statement( } SymbolInformation::Signal(dim) | SymbolInformation::Var(dim) => { - if rhe_type.is_template() || rhe_type.is_bus() { + if rhe_type.is_template() { add_report( ReportCode::WrongTypesInAssignOperationExpression, meta, &mut analysis_information.reports, ) + } else if rhe_type.is_bus() { + add_report( + ReportCode::WrongTypesInAssignOperationBus, + meta, + &mut analysis_information.reports, + ) } else if dim != rhe_type.dim() { add_report( ReportCode::WrongTypesInAssignOperationDims(dim, rhe_type.dim()), @@ -365,12 +371,18 @@ fn type_statement( } } SymbolInformation::Tag => { - if rhe_type.is_template() || rhe_type.is_bus() { + if rhe_type.is_template() { add_report( ReportCode::WrongTypesInAssignOperationExpression, meta, &mut analysis_information.reports, ) + } else if rhe_type.is_bus() { + add_report( + ReportCode::WrongTypesInAssignOperationBus, + meta, + &mut analysis_information.reports, + ) } else if 0 != rhe_type.dim() { add_report( ReportCode::WrongTypesInAssignOperationDims(0, rhe_type.dim()), @@ -444,12 +456,18 @@ fn type_statement( } else { return; }; - if arg_type.is_template() || arg_type.is_bus() { + if arg_type.is_template() { add_report( ReportCode::MustBeSingleArithmeticT, meta, &mut analysis_information.reports, ) + } else if arg_type.is_bus() { + add_report( + ReportCode::MustBeSingleArithmeticB, + meta, + &mut analysis_information.reports, + ) } else if arg_type.dim() > 0 { add_report( ReportCode::MustBeSingleArithmetic(arg_type.dim()), @@ -467,13 +485,19 @@ fn type_statement( } else { return; }; - if arg_type.is_template() || arg_type.is_bus() { + if arg_type.is_template() { add_report( ReportCode::MustBeSingleArithmeticT, meta, &mut analysis_information.reports, ) - } else if arg_type.dim() > 0 { + } else if arg_type.is_bus() { + add_report( + ReportCode::MustBeSingleArithmeticB, + meta, + &mut analysis_information.reports, + ) + } else if arg_type.dim() > 0 { add_report( ReportCode::MustBeSingleArithmetic(arg_type.dim()), meta, @@ -510,13 +534,19 @@ fn type_statement( } else { return; }; - if cond_type.is_template() || cond_type.is_bus() { + if cond_type.is_template() { add_report( ReportCode::MustBeSingleArithmeticT, cond.get_meta(), &mut analysis_information.reports, ) - } else if cond_type.dim() > 0 { + } else if cond_type.is_bus() { + add_report( + ReportCode::MustBeSingleArithmeticB, + cond.get_meta(), + &mut analysis_information.reports, + ) + } else if cond_type.dim() > 0 { add_report( ReportCode::MustBeSingleArithmetic(cond_type.dim()), cond.get_meta(), @@ -532,13 +562,19 @@ fn type_statement( } else { return; }; - if cond_type.is_template() || cond_type.is_bus() { + if cond_type.is_template() { add_report( ReportCode::MustBeSingleArithmeticT, cond.get_meta(), &mut analysis_information.reports, ) - }else if cond_type.dim() > 0 { + } else if cond_type.is_bus() { + add_report( + ReportCode::MustBeSingleArithmeticB, + cond.get_meta(), + &mut analysis_information.reports, + ) + } else if cond_type.dim() > 0 { add_report( ReportCode::MustBeSingleArithmetic(cond_type.dim()), cond.get_meta(), @@ -592,12 +628,18 @@ fn type_expression( } let inferred_dim = values_types[0].dim(); for (expression, value_type) in values.iter().zip(values_types.iter()) { - if value_type.is_template() || value_type.is_bus() { + if value_type.is_template() { add_report( ReportCode::InvalidArrayType, expression.get_meta(), &mut analysis_information.reports, ); + } else if value_type.is_bus() { + add_report( + ReportCode::InvalidArrayTypeB, + expression.get_meta(), + &mut analysis_information.reports, + ); } else if inferred_dim != value_type.dim() { add_report( ReportCode::NonHomogeneousArray(inferred_dim, value_type.dim()), @@ -618,13 +660,19 @@ fn type_expression( ); }; let dim_type = type_expression(dimension, program_archive, analysis_information)?; - if dim_type.is_template() || dim_type.is_bus() { + if dim_type.is_template() { add_report( ReportCode::InvalidArrayType, expression.get_meta(), &mut analysis_information.reports, ); - } else if dim_type.dim() != 0 { + } else if dim_type.is_bus() { + add_report( + ReportCode::InvalidArrayTypeB, + expression.get_meta(), + &mut analysis_information.reports, + ); + }else if dim_type.dim() != 0 { add_report( ReportCode::InvalidArrayType, expression.get_meta(), @@ -695,12 +743,18 @@ fn type_expression( } else { return Result::Ok(if_true_type); }; - if cond_type.is_template() || cond_type.is_bus() { + if cond_type.is_template() { add_report( ReportCode::MustBeSingleArithmeticT, cond.get_meta(), &mut analysis_information.reports, ) + } else if cond_type.is_bus() { + add_report( + ReportCode::MustBeSingleArithmeticB, + cond.get_meta(), + &mut analysis_information.reports, + ) } else if cond_type.dim() > 0 { add_report( @@ -827,9 +881,15 @@ fn type_expression( let mut concrete_types = Vec::new(); let mut success = Result::Ok(()); for (arg_expr, arg_type) in args.iter().zip(arg_types.iter()) { - if arg_type.is_template() || arg_type.is_bus() { + if arg_type.is_template() { + success = add_report_and_end( + ReportCode::InvalidArgumentInBusInstantiationT, + arg_expr.get_meta(), + &mut analysis_information.reports, + ); + } else if arg_type.is_bus() { success = add_report_and_end( - ReportCode::InvalidArgumentInBusInstantiation, + ReportCode::InvalidArgumentInBusInstantiationB, arg_expr.get_meta(), &mut analysis_information.reports, ); @@ -905,12 +965,18 @@ fn treat_access( access_info.0 += 1; } if let Result::Ok(index_type) = index_response { - if index_type.is_template() || index_type.is_bus() { + if index_type.is_template() { add_report( ReportCode::InvalidArraySizeT, index.get_meta(), &mut analysis_information.reports, ); + } else if index_type.is_bus() { + add_report( + ReportCode::InvalidArraySizeB, + index.get_meta(), + &mut analysis_information.reports, + ); } else if index_type.dim() > 0 { add_report( @@ -1256,6 +1322,7 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio InvalidTagAccess => "Tag not found in signal: only accesses to tags that appear in the definition of the signal are allowed".to_string(), InvalidTagAccessAfterArray => "Invalid access to the tag of an array element: tags belong to complete arrays, not to individual positions.\n Hint: instead of signal[pos].tag use signal.tag".to_string(), InvalidArrayType => "Components can not be declared inside inline arrays".to_string(), + InvalidArrayTypeB => "Buses can not be declared inside inline arrays".to_string(), InfixOperatorWithWrongTypes | PrefixOperatorWithWrongTypes => { "Type not allowed by the operator".to_string() } @@ -1280,7 +1347,8 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio expected, found) } InvalidArgumentInCall => "Components can not be passed as arguments".to_string(), - InvalidArgumentInBusInstantiation => "Components or buses can not be passed as arguments".to_string(), + InvalidArgumentInBusInstantiationT => "Components can not be passed as arguments".to_string(), + InvalidArgumentInBusInstantiationB => "Buses can not be passed as arguments".to_string(), UnableToTypeFunction => "Unable to infer the type of this function".to_string(), MustBeSingleArithmetic(dim) => { format!("Must be a single arithmetic expression.\n Found expression of {} dimensions", dim) @@ -1288,6 +1356,7 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio MustBeSingleArithmeticT => { format!("Must be a single arithmetic expression.\n Found component") } + MustBeSingleArithmeticB => format!("Must be a single arithmetic expression.\n Found bus"), MustBeArithmetic => "Must be a single arithmetic expression or an array of arithmetic expressions. \n Found component".to_string(), OutputTagCannotBeModifiedOutside => "Output tag from a subcomponent cannot be modified".to_string(), MustBeSameDimension(dim_1, dim_2) =>{ From 3390b8fe08ef2e9d6bcb6ba9a3768246dfbdfda1 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 13 Jun 2024 10:02:29 +0200 Subject: [PATCH 095/189] signals and buses order fixed, starting to work on code generation --- compiler/src/circuit_design/build.rs | 2 + compiler/src/hir/analysis_utilities.rs | 76 +++++- compiler/src/hir/component_preprocess.rs | 6 +- compiler/src/hir/merger.rs | 68 ++++- compiler/src/hir/very_concrete_program.rs | 44 ++- .../intermediate_representation/translate.rs | 43 ++- .../src/compute_constants.rs | 1 + .../environment_utils/bus_representation.rs | 75 ++---- .../component_representation.rs | 87 +++--- constraint_generation/src/execute.rs | 16 +- .../src/execution_data/executed_bus.rs | 83 +++++- .../src/execution_data/executed_program.rs | 2 +- .../src/execution_data/executed_template.rs | 254 +++++++++--------- .../src/execution_data/type_definitions.rs | 11 +- 14 files changed, 524 insertions(+), 244 deletions(-) diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 1e71090cc..859ae5ed4 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -88,6 +88,7 @@ fn build_template_instances( params: Vec::new(), header: header.clone(), signals: template.signals, + buses: template.buses, constants: instance_values, files: &c_info.file_library, triggers: template.triggers, @@ -153,6 +154,7 @@ fn build_function_instances( params: params.clone(), fresh_cmp_id: 0, signals: Vec::with_capacity(0), + buses: Vec::with_capacity(0), triggers: Vec::with_capacity(0), clusters: Vec::with_capacity(0), constants: Vec::with_capacity(0), diff --git a/compiler/src/hir/analysis_utilities.rs b/compiler/src/hir/analysis_utilities.rs index 5d685b15b..5599ece98 100644 --- a/compiler/src/hir/analysis_utilities.rs +++ b/compiler/src/hir/analysis_utilities.rs @@ -6,6 +6,14 @@ use std::collections::HashMap; pub type E = VarEnvironment; +pub struct InfoBus { + pub size: usize, + pub signals: HashMap, + pub buses: HashMap +} + + + pub struct GenericFunction { pub name: String, pub params_names: Vec, @@ -14,10 +22,11 @@ pub struct GenericFunction { } pub struct State { - pub external_signals: HashMap>, + pub external_signals: HashMap, HashMap)>, pub generic_functions: HashMap, pub vcf_collector: Vec, pub quick_knowledge: HashMap, + pub buses_info: HashMap } pub fn build_function_knowledge(program: ProgramArchive) -> State { @@ -39,25 +48,56 @@ pub fn build_function_knowledge(program: ProgramArchive) -> State { vcf_collector: Vec::new(), generic_functions, quick_knowledge: HashMap::new(), + buses_info: HashMap::new() } } -pub fn build_component_info(triggers: &Vec) -> HashMap> { +pub fn build_component_info(triggers: &Vec) -> + HashMap, HashMap)> { let mut external_signals = HashMap::new(); for trigger in triggers { let mut signals = HashMap::new(); + let mut buses = HashMap::new(); for s in &trigger.external_signals { signals.insert(s.name.clone(), s.lengths.clone()); } - let signals = match external_signals.remove(&trigger.component_name) { - None => signals, - Some(old) => max_vct(signals, old), + for s in &trigger.external_buses { + buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + } + let (signals, buses) = match external_signals.remove(&trigger.component_name){ + None => (signals, buses), + Some((old_signals, old_buses)) =>{ + (max_vct(signals, old_signals), max_vct_bus(buses, old_buses)) + } }; - external_signals.insert(trigger.component_name.clone(), signals); + external_signals.insert(trigger.component_name.clone(), (signals, buses)); } external_signals } + +pub fn build_buses_info(buses: &Vec) -> HashMap{ + + let mut info_buses = HashMap::new(); + for bus in buses{ + info_buses.insert(bus.name.clone(), build_single_bus_info(bus)); + } + info_buses +} + +fn build_single_bus_info(bus: &Bus) -> InfoBus{ + let size = bus.size(); + let mut signals = HashMap::new(); + for s in &bus.signals{ + signals.insert(s.name.clone(), s.lengths.clone()); + } + let mut buses = HashMap::new(); + for s in &bus.buses{ + buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + } + InfoBus{size, signals, buses} +} + fn max_vct(l: HashMap, mut r: HashMap) -> HashMap { let mut result = HashMap::new(); @@ -75,6 +115,30 @@ fn max_vct(l: HashMap, mut r: HashMap) -> HashMap, mut r: HashMap) -> HashMap { + fn compute_max_bus(l: InfoBus, r: InfoBus) ->InfoBus{ + let size = std::cmp::max(l.size, r.size); + let signals = max_vct(l.signals, r.signals); + let buses = max_vct_bus(l.buses, r.buses); + InfoBus{size, signals, buses} + } + let mut result = HashMap::new(); + + for (s, (tl, bl)) in l { + if r.contains_key(&s) { + let (tr, br) = r.remove(&s).unwrap(); + let tmax = std::cmp::max(tl, tr); + let bmax = compute_max_bus(bl, br); + result.insert(s, (tmax, bmax)); + } else{ + result.insert(s, (tl, bl)); + } + } + for (s, (tr, br)) in r{ + result.insert(s, (tr, br)); + } + result +} pub fn build_environment(constants: &[Argument], params: &[Param]) -> E { let mut environment = E::new(); for constant in constants { diff --git a/compiler/src/hir/component_preprocess.rs b/compiler/src/hir/component_preprocess.rs index 60362f04f..ebc55675f 100644 --- a/compiler/src/hir/component_preprocess.rs +++ b/compiler/src/hir/component_preprocess.rs @@ -109,8 +109,10 @@ fn should_be_removed(stmt: &Statement) -> bool { use VariableType::*; if let InitializationBlock { xtype, .. } = stmt { Component == *xtype || AnonymousComponent == *xtype - } else if let Substitution { meta, .. } = stmt { - meta.get_type_knowledge().is_component() || meta.get_type_knowledge().is_tag() + } else if let Substitution { meta, rhe, .. } = stmt { + meta.get_type_knowledge().is_component() + || meta.get_type_knowledge().is_tag() + || rhe.is_bus_call() || rhe.is_bus_call_array() } else { false } diff --git a/compiler/src/hir/merger.rs b/compiler/src/hir/merger.rs index 4cb428b79..3cd1fd98a 100644 --- a/compiler/src/hir/merger.rs +++ b/compiler/src/hir/merger.rs @@ -23,6 +23,7 @@ fn produce_vcf(vcp: &VCP, state: &mut State) { let constants = &n.header; let params = vec![]; state.external_signals = build_component_info(&n.triggers); + state.buses_info = build_buses_info(&n.buses); let mut env = build_environment(constants, ¶ms); produce_vcf_stmt(code, state, &mut env); } @@ -40,6 +41,7 @@ fn link_circuit(vcp: &mut VCP, state: &mut State) { for node in &mut vcp.templates { let mut env = build_environment(&node.header, &vec![]); state.external_signals = build_component_info(&node.triggers); + state.buses_info = build_buses_info(&node.buses); link_stmt(&mut node.code, state, &mut env); } let mut linked_vcf_collector = state.vcf_collector.clone(); @@ -117,6 +119,7 @@ fn produce_vcf_stmt(stmt: &Statement, state: &mut State, environment: &mut E) { } fn produce_vcf_expr(expr: &Expression, state: &mut State, environment: &E) { + if expr.is_infix() { produce_vcf_infix(expr, state, environment); } else if expr.is_prefix() { @@ -133,6 +136,8 @@ fn produce_vcf_expr(expr: &Expression, state: &mut State, environment: &E) { produce_vcf_array(expr, state, environment); } else if expr.is_parallel(){ produce_vcf_parallel(expr, state, environment); + } else if expr.is_bus_call(){ + produce_vcf_bus_call(expr, state, environment); } else { unreachable!(); } @@ -189,6 +194,7 @@ fn produce_vcf_substitution(stmt: &Statement, state: &mut State, environment: &E produce_vcf_expr(index, state, environment); } } + } else { unreachable!(); } @@ -280,6 +286,17 @@ fn produce_vcf_call(expr: &Expression, state: &mut State, environment: &E) { } } +fn produce_vcf_bus_call(expr: &Expression, state: &mut State, environment: &E) { + use Expression::BusCall; + if let BusCall { id, args, .. } = expr { + for arg in args { + produce_vcf_expr(arg, state, environment); + } + } else { + unreachable!(); + } +} + fn produce_vcf_variable(expr: &Expression, state: &mut State, environment: &E) { use Access::ArrayAccess; use Expression::Variable; @@ -498,6 +515,8 @@ fn link_expression(expr: &mut Expression, state: &State, env: &E) { link_prefix(expr, state, env); } else if expr.is_parallel(){ link_parallel(expr, state, env); + } else if expr.is_bus_call(){ + link_bus_call(expr, state, env); } else { unreachable!(); } @@ -521,6 +540,17 @@ fn link_call(expr: &mut Expression, state: &State, env: &E) { } } +fn link_bus_call(expr: &mut Expression, state: &State, env: &E) { + use Expression::BusCall; + if let BusCall { args, .. } = expr { + for arg in args.iter_mut() { + link_expression(arg, state, env); + } + } else { + unreachable!(); + } +} + fn link_array(expr: &mut Expression, state: &State, env: &E) { use Expression::{ArrayInLine, UniformArray}; if let ArrayInLine { values, .. } = expr { @@ -609,18 +639,52 @@ fn cast_type_variable(expr: &Expression, state: &State, environment: &E) -> VCT if let Variable { name, access, .. } = expr { let mut xtype = environment.get_variable(name).unwrap().clone(); xtype.reverse(); + let mut possible_bus_info = if state.buses_info.contains_key(name){ + Some(state.buses_info.get(name).unwrap()) + } else{ + None + }; for acc in access { match acc { Access::ArrayAccess(_) => { xtype.pop(); } Access::ComponentAccess(signal) => { - xtype = state.external_signals.get(name).unwrap().get(signal).unwrap().clone(); - xtype.reverse(); + // case buses + if possible_bus_info.is_some(){ + let bus = possible_bus_info.unwrap(); + if bus.signals.contains_key(signal){ + xtype = bus.signals.get(signal).unwrap().clone(); + xtype.reverse(); + possible_bus_info = None; + } else{ + let aux_info = bus.buses.get(signal).unwrap(); + xtype = aux_info.0.clone(); + xtype.reverse(); + possible_bus_info = Some(&aux_info.1); + } + } else{ + // case io component + let (signals, buses) = state.external_signals.get(name).unwrap(); + if signals.contains_key(signal){ + // case io signal + xtype = signals.get(signal).unwrap().clone(); + xtype.reverse(); + possible_bus_info = None; + } else{ + let aux_info = buses.get(signal).unwrap(); + xtype = aux_info.0.clone(); + xtype.reverse(); + possible_bus_info = Some(&aux_info.1); + } + } } } } xtype.reverse(); + if possible_bus_info.is_some(){ + xtype.push(possible_bus_info.unwrap().size); + } xtype } else { unreachable!(); diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 02e20507e..f73570d42 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -39,6 +39,29 @@ impl Signal { } } +#[derive(Clone)] +pub struct Bus{ + pub name: String, + pub lengths: Vec, + pub xtype: SignalType, + pub signals: Vec, + pub buses: Vec>, + pub local_id: usize, + pub dag_local_id: usize, +} +impl Bus{ + pub fn size(&self) -> usize{ + let mut total_size = 0; + for signal in &self.signals{ + total_size += signal.size(); + } + for bus in &self.buses{ + total_size += bus.size(); + } + self.lengths.iter().fold(total_size, |p, c| p * (*c)) + } +} + #[derive(Clone)] pub struct Component { pub name: String, @@ -60,6 +83,7 @@ pub struct Trigger { pub component_name: String, pub indexed_with: Vec, pub external_signals: Vec, + pub external_buses: Vec, pub has_inputs: bool, pub is_parallel: bool, } @@ -93,6 +117,7 @@ pub struct TemplateInstance { pub number_of_intermediates: usize, pub signals: Vec, pub signals_to_tags: BTreeMap, + pub buses: Vec, pub components: Vec, pub number_of_components: usize, pub triggers: Vec, @@ -131,6 +156,7 @@ impl TemplateInstance { number_of_intermediates: 0, number_of_components: config.number_of_components, signals: Vec::new(), + buses: Vec::new(), components: config.components, triggers: config.triggers, clusters: config.clusters, @@ -154,6 +180,21 @@ impl TemplateInstance { } self.signals.push(signal); } + pub fn add_bus(&mut self, bus: Bus) { + use SignalType::*; + match bus.xtype { + Input => { + self.number_of_inputs += bus.size(); + } + Output => { + self.number_of_outputs += bus.size(); + } + Intermediate => { + self.number_of_intermediates += bus.size(); + } + } + self.buses.push(bus); + } } #[derive(Eq, PartialEq, Clone)] @@ -215,8 +256,7 @@ impl VCP { quick_knowledge: HashMap::new(), prime: config.prime, }; - // TODO: continue from here - //super::merger::run_preprocessing(&mut vcp, config.program); + super::merger::run_preprocessing(&mut vcp, config.program); vcp } pub fn add_witness_list(&mut self, witness: Rc>) { diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 04309bb23..fb7e38145 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -24,12 +24,23 @@ pub struct SignalInfo{ lengths: Vec, } +#[derive(Clone)] +pub struct BusInfo{ + signal_type: SignalType, + lengths: Vec, + signals: HashMap, + buses: HashMap>, +} + + #[derive(Clone)] pub struct TemplateDB { // one per template instance pub signal_addresses: Vec, // stores the type and the length of signal pub signal_info: Vec>, + // stores the type, fields and length of a bus + pub bus_info: Vec>, // template_name to usize pub indexes: HashMap, // one per generic template, gives its signal to code correspondence @@ -41,6 +52,7 @@ impl TemplateDB { indexes: HashMap::with_capacity(templates.len()), signal_addresses: Vec::with_capacity(templates.len()), signal_info: Vec::with_capacity(templates.len()), + bus_info: Vec::with_capacity(templates.len()), signals_id: Vec::with_capacity(templates.len()), }; for tmp in templates { @@ -59,6 +71,24 @@ impl TemplateDB { } fn add_instance(db: &mut TemplateDB, instance: &TemplateInstance) { + fn add_bus(xtype: SignalType, lengths: Vec, info_signals: Vec, info_buses: Vec>)-> BusInfo{ + let mut signals = HashMap::new(); + for signal in info_signals{ + let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; + signals.insert(signal.name, info); + } + let mut buses = HashMap::new(); + for bus in info_buses.clone(){ + let info = add_bus(bus.xtype, bus.lengths, bus.signals, bus.buses); + buses.insert(bus.name, Box::new(info)); + } + BusInfo{ + signal_type: xtype, + lengths: lengths, + signals, + buses + } + } if !db.indexes.contains_key(&instance.template_name) { let index = db.signals_id.len(); db.indexes.insert(instance.template_name.clone(), index); @@ -80,9 +110,15 @@ impl TemplateDB { let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; signal_info.insert(signal.name, info); } - initialize_signals(&mut state, instance.signals.clone()); + let mut bus_info = HashMap::new(); + for bus in instance.buses.clone(){ + let info = add_bus(bus.xtype, bus.lengths, bus.signals, bus.buses); + bus_info.insert(bus.name, info); + } + initialize_signals(&mut state, instance.signals.clone(), instance.buses.clone()); db.signal_addresses.push(state.environment); db.signal_info.push(signal_info); + db.bus_info.push(bus_info); } } @@ -238,7 +274,7 @@ fn initialize_constants(state: &mut State, constants: Vec) { } } -fn initialize_signals(state: &mut State, signals: Vec) { +fn initialize_signals(state: &mut State, signals: Vec, buses: Vec) { for signal in signals { let size = signal.lengths.iter().fold(1, |p, c| p * (*c)); let address = state.reserve_signal(size); @@ -1357,6 +1393,7 @@ pub struct CodeInfo<'a> { pub message_id: usize, pub params: Vec, pub signals: Vec, + pub buses: Vec, pub files: &'a FileLibrary, pub constants: Vec, pub components: Vec, @@ -1393,7 +1430,7 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { ); state.string_table = code_info.string_table; initialize_components(&mut state, code_info.components); - initialize_signals(&mut state, code_info.signals); + initialize_signals(&mut state, code_info.signals, code_info.buses); initialize_constants(&mut state, code_info.constants); initialize_parameters(&mut state, code_info.params); diff --git a/constraint_generation/src/compute_constants.rs b/constraint_generation/src/compute_constants.rs index d16020959..36d9c740c 100644 --- a/constraint_generation/src/compute_constants.rs +++ b/constraint_generation/src/compute_constants.rs @@ -151,6 +151,7 @@ fn treat_declaration(stmt: &mut Statement, context: &Context, reports: &mut Repo AnonymousComponent => { meta.get_mut_memory_knowledge().set_concrete_dimensions(vec![]); }, + _ => { for d in dimensions.iter_mut() { let execution_response = treat_dimension(d, context, reports, flags, prime); diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 43b6ce108..513f768bc 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -56,56 +56,38 @@ impl BusRepresentation { // if input bus all signals are set initialize to true, else to false // initialice the signals - for (symbol, route) in node.signal_fields() { - let signal_slice = SignalSlice::new_with_route(route, &is_output_bus); - let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); - if signal_slice_size > 0{ - component.unassigned_fields - .insert(symbol.clone(), signal_slice_size); - } - let field_signal = FieldTypes::Signal(signal_slice); - component.fields.insert(symbol.clone(), field_signal); - - // add the tags - if node.signal_to_tags.get(symbol).is_some(){ - let defined_tags = node.signal_to_tags.get(symbol).unwrap(); - let mut definitions = BTreeMap::new(); - let mut values = BTreeMap::new(); - for (tag, value) in defined_tags{ - let tag_state = TagState{defined:true, value_defined: value.is_some(), complete: true}; - definitions.insert(tag.clone(), tag_state); - values.insert(tag.clone(), value.clone()); - + for info_field in node.fields() { + let symbol = &info_field.name; + let route = &info_field.length; + if !info_field.is_bus{ + let signal_slice = SignalSlice::new_with_route(&route, &is_output_bus); + let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); + if signal_slice_size > 0{ + component.unassigned_fields + .insert(symbol.clone(), signal_slice_size); } - component.field_tags.insert(symbol.clone(), (definitions, values)); + let field_signal = FieldTypes::Signal(signal_slice); + component.fields.insert(symbol.clone(), field_signal); } else{ - component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); - } - if is_output_bus{ - component.unassigned_fields.remove(symbol); + let bus_connexions = node.bus_connexions(); + let bus_node = bus_connexions.get(symbol).unwrap().inspect.goes_to; + let mut bus_field = BusRepresentation::default(); + BusRepresentation::initialize_bus( + &mut bus_field, + bus_node, + scheme, + is_output_bus + )?; + let bus_slice = BusSlice::new_with_route(&route, &bus_field); + let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); + if bus_slice_size > 0{ + component.unassigned_fields + .insert(symbol.clone(), bus_slice_size); + } + let field_bus = FieldTypes::Bus(bus_slice); + component.fields.insert(symbol.clone(), field_bus); } - } - - // now the buses - let bus_connexions = node.bus_connexions(); - for (symbol, route) in node.bus_fields() { - let bus_node = bus_connexions.get(symbol).unwrap().inspect.goes_to; - let mut bus_field = BusRepresentation::default(); - BusRepresentation::initialize_bus( - &mut bus_field, - bus_node, - scheme, - is_output_bus - )?; - let bus_slice = BusSlice::new_with_route(route, &bus_field); - let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); - if bus_slice_size > 0{ - component.unassigned_fields - .insert(symbol.clone(), bus_slice_size); - } - let field_bus = FieldTypes::Bus(bus_slice); - component.fields.insert(symbol.clone(), field_bus); // add the tags if node.signal_to_tags.get(symbol).is_some(){ @@ -127,6 +109,7 @@ impl BusRepresentation { } } + component.node_pointer = Option::Some(node_pointer); diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 68d00d808..a06394b34 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -136,34 +136,37 @@ impl ComponentRepresentation { let node = possible_node.unwrap(); component.is_initialized = true; - 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{ - component.unassigned_inputs - .insert(symbol.clone(), signal_slice_size); - } - component.inputs.insert(symbol.clone(), signal_slice); - } - - for (symbol, route) in node.bus_inputs() { - let mut initial_value_bus = BusRepresentation::default(); - let bus_node = node.bus_connexions.get(symbol).unwrap().inspect.goes_to; - BusRepresentation::initialize_bus( - &mut initial_value_bus, - bus_node, - scheme, - false // it is not initialized at the begining - )?; - let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); - let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); - if bus_slice_size > 0{ - component.unassigned_inputs - .insert(symbol.clone(), bus_slice_size); + for info_wire in node.inputs() { + let symbol = &info_wire.name; + let route = &info_wire.length; + if !info_wire.is_bus{ + 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{ + component.unassigned_inputs + .insert(symbol.clone(), signal_slice_size); + } + component.inputs.insert(symbol.clone(), signal_slice); + } else{ + let mut initial_value_bus = BusRepresentation::default(); + let bus_node = node.bus_connexions.get(symbol).unwrap().inspect.goes_to; + BusRepresentation::initialize_bus( + &mut initial_value_bus, + bus_node, + scheme, + false // it is not initialized at the begining + )?; + let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); + let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); + if bus_slice_size > 0{ + component.unassigned_inputs + .insert(symbol.clone(), bus_slice_size); + } + component.input_buses.insert(symbol.clone(), bus_slice); } - component.input_buses.insert(symbol.clone(), bus_slice); } + fn insert_tags_output(node: &crate::execution_data::ExecutedTemplate, symbol: &String, component: &mut ComponentRepresentation) { let tags_output = node.signal_to_tags.get(symbol); let component_tags_output = component.outputs_tags.get_mut(symbol); @@ -179,25 +182,27 @@ impl ComponentRepresentation { } } - for (symbol, route) in node.outputs() { - component.outputs.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); + for info_wire in node.outputs() { + let symbol = &info_wire.name; + let route = &info_wire.length; + if !info_wire.is_bus{ + component.outputs.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); + } else{ + let mut initial_value_bus = BusRepresentation::default(); + let bus_node = node.bus_connexions.get(symbol).unwrap().inspect.goes_to; + BusRepresentation::initialize_bus( + &mut initial_value_bus, + bus_node, + scheme, + true // the outputs of the component are initialized at the begining + )?; + let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); + + component.output_buses.insert(symbol.clone(), bus_slice); + } insert_tags_output(node, symbol, component); } - for (symbol, route) in node.bus_outputs() { - let mut initial_value_bus = BusRepresentation::default(); - let bus_node = node.bus_connexions.get(symbol).unwrap().inspect.goes_to; - BusRepresentation::initialize_bus( - &mut initial_value_bus, - bus_node, - scheme, - true // the outputs of the component are initialized at the begining - )?; - let bus_slice = BusSlice::new_with_route(route, &initial_value_bus); - - component.output_buses.insert(symbol.clone(), bus_slice); - } - component.node_pointer = Option::Some(node_pointer); let to_assign = std::mem::replace(&mut component.to_assign_inputs, vec![]); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index d58262cf0..b40e705de 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1102,15 +1102,15 @@ fn execute_signal_declaration( } else{ environment_shortcut_add_input(environment, signal_name, dimensions, &tags); } - node.add_input(signal_name, dimensions); + node.add_input(signal_name, dimensions, false); } Output => { environment_shortcut_add_output(environment, signal_name, dimensions, &tags); - node.add_output(signal_name, dimensions); + node.add_output(signal_name, dimensions, false); } Intermediate => { environment_shortcut_add_intermediate(environment, signal_name, dimensions, &tags); - node.add_intermediate(signal_name, dimensions); + node.add_intermediate(signal_name, dimensions, false); } } } else { @@ -1166,15 +1166,15 @@ fn execute_bus_declaration( } else{ environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tags); } - node.add_bus_input(bus_name, dimensions); + node.add_input(bus_name, dimensions, true); } Output => { environment_shortcut_add_bus_output(environment, bus_name, dimensions, &tags); - node.add_bus_output(bus_name, dimensions); + node.add_output(bus_name, dimensions, true); } Intermediate => { environment_shortcut_add_bus_intermediate(environment, bus_name, dimensions, &tags); - node.add_bus_intermediate(bus_name, dimensions); + node.add_intermediate(bus_name, dimensions, true); } } } else { @@ -1804,11 +1804,14 @@ fn perform_assign( )?; } + let bus_info = runtime.exec_program.get_bus_node(bus_pointer).unwrap(); + let size = bus_info.size; match actual_node{ ExecutedStructure::Template(node) =>{ let data = BusData { name: symbol.to_string(), goes_to: bus_pointer, + size, }; let component_symbol = create_array_accessed_symbol(symbol, &accessing_information.array_access); node.add_bus_arrow(component_symbol, data); @@ -1817,6 +1820,7 @@ fn perform_assign( let data = BusData { name: symbol.to_string(), goes_to: bus_pointer, + size }; let component_symbol = create_array_accessed_symbol(symbol, &accessing_information.array_access); node.add_bus_arrow(component_symbol, data); diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index c75b63f02..852325600 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -3,6 +3,9 @@ use super::type_definitions::*; use num_bigint::BigInt; use std::collections::HashMap; use crate::execution_data::TagInfo; +use compiler::hir::very_concrete_program::*; +use crate::ast::SignalType; + pub struct BusConnexion{ @@ -16,8 +19,7 @@ pub struct BusConnexion{ pub struct ExecutedBus { pub bus_name: String, pub report_name: String, - pub signal_fields: SignalCollector, - pub bus_fields: BusCollector, + pub fields: WireCollector, pub parameter_instances: ParameterContext, pub signal_to_tags: TagContext, pub bus_connexions: HashMap, @@ -34,8 +36,7 @@ impl ExecutedBus { report_name, bus_name: name, parameter_instances: instance, - signal_fields: Vec::new(), - bus_fields: Vec::new(), + fields: Vec::new(), signal_to_tags: TagContext::new(), bus_connexions: HashMap::new(), size: 0, @@ -48,17 +49,45 @@ impl ExecutedBus { } pub fn add_bus_arrow(&mut self, component_name: String, data: BusData) { + + let mut dimensions = &vec![]; + for wire_data in &self.fields{ + if *wire_data.name == component_name{ + dimensions = &wire_data.length; + } + } + let mut total_size = data.size; + for v in dimensions{ + total_size *= v; + } + self.size += total_size; + let cnn = BusConnexion { full_name: component_name.clone(), inspect: data, dag_offset: 0, dag_jump: 0}; self.bus_connexions.insert(component_name, cnn); } pub fn add_signal(&mut self, signal_name: &str, dimensions: &[usize]) { - self.signal_fields.push((signal_name.to_string(), dimensions.to_vec())); + let info_signal = WireData{ + name: signal_name.to_string(), + length: dimensions.to_vec(), + is_bus: false + }; + self.fields.push(info_signal); + let mut total_size = 1; + for v in dimensions{ + total_size *= v; + } + self.size += total_size; } pub fn add_bus(&mut self, bus_name: &str, dimensions: &[usize]) { - self.bus_fields.push((bus_name.to_string(), dimensions.to_vec())); + let info_bus = WireData{ + name: bus_name.to_string(), + length: dimensions.to_vec(), + is_bus: true + }; + self.fields.push(info_bus); } pub fn add_tag_signal(&mut self, signal_name: &str, tag_name: &str, value: Option){ @@ -80,15 +109,47 @@ impl ExecutedBus { &self.parameter_instances } - pub fn signal_fields(&self) -> &SignalCollector { - &self.signal_fields - } - pub fn bus_fields(&self) -> &BusCollector { - &self.bus_fields + pub fn fields(&self) -> &WireCollector { + &self.fields } pub fn bus_connexions(&self) -> &HashMap{ &self.bus_connexions } + + // TODO: use same category for the bus and signal + pub fn build_bus( + &self, + name: String, + lengths: Vec, + local_id: usize, + dag_local_id: usize, + xtype: SignalType, + buses_info: &Vec + ) -> Bus{ + let mut local_id_aux = local_id; + let mut dag_local_id_aux = dag_local_id; + let mut signals = Vec::new(); + let mut buses = Vec::new(); + + for info_field in &self.fields{ + let (name, lengths) = (&info_field.name, &info_field.length); + if !info_field.is_bus{ + let signal = Signal { name: name.clone(), lengths: lengths.clone(), local_id: local_id_aux, dag_local_id: dag_local_id_aux, xtype}; + local_id_aux += signal.size(); + dag_local_id_aux += signal.size(); + signals.push(signal); + } else{ + let bus_node = self.bus_connexions.get(name).unwrap().inspect.goes_to; + let exe_bus = buses_info.get(bus_node).unwrap(); + let bus = exe_bus.build_bus(name.clone(), lengths.clone(), local_id_aux, dag_local_id_aux, xtype, buses_info); + local_id_aux += bus.size(); + dag_local_id_aux += bus.size(); + buses.push(Box::new(bus)); + } + } + Bus{name, lengths, xtype, local_id, dag_local_id, signals, buses} + } + } \ No newline at end of file diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index 80cd4689a..5697f0018 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -180,7 +180,7 @@ impl ExecutedProgram { } for exe in self.model { - let tmp_instance = exe.export_to_circuit(&mut temp_instances); + let tmp_instance = exe.export_to_circuit(&mut temp_instances, &self.model_buses); temp_instances.push(tmp_instance); } diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 109cb4d17..895f612f6 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -66,12 +66,9 @@ pub struct ExecutedTemplate { pub code: Statement, pub template_name: String, pub report_name: String, - pub inputs: SignalCollector, - pub bus_inputs: BusCollector, - pub outputs: SignalCollector, - pub bus_outputs: BusCollector, - pub intermediates: SignalCollector, - pub bus_intermediates: BusCollector, + pub inputs: WireCollector, + pub outputs: WireCollector, + pub intermediates: WireCollector, pub ordered_signals: Vec, pub constraints: Vec, pub components: ComponentCollector, @@ -111,12 +108,9 @@ impl ExecutedTemplate { parameter_instances: instance, signal_to_tags: tag_instances.clone(), tag_instances, - inputs: SignalCollector::new(), - outputs: SignalCollector::new(), - intermediates: SignalCollector::new(), - bus_inputs: BusCollector::new(), - bus_outputs: BusCollector::new(), - bus_intermediates: BusCollector::new(), + inputs: WireCollector::new(), + outputs: WireCollector::new(), + intermediates: WireCollector::new(), ordered_signals: Vec::new(), constraints: Vec::new(), components: ComponentCollector::new(), @@ -145,32 +139,34 @@ impl ExecutedTemplate { self.bus_connexions.insert(bus_name, cnn); } - // Same with buses - - pub fn add_input(&mut self, input_name: &str, dimensions: &[usize]) { - self.inputs.push((input_name.to_string(), dimensions.to_vec())); - } - - pub fn add_output(&mut self, output_name: &str, dimensions: &[usize]) { - self.outputs.push((output_name.to_string(), dimensions.to_vec())); - } - - pub fn add_intermediate(&mut self, intermediate_name: &str, dimensions: &[usize]) { - self.intermediates.push((intermediate_name.to_string(), dimensions.to_vec())); - } - - pub fn add_bus_input(&mut self, input_name: &str, dimensions: &[usize]) { - self.bus_inputs.push((input_name.to_string(), dimensions.to_vec())); + pub fn add_input(&mut self, input_name: &str, dimensions: &[usize], is_bus: bool) { + let wire_info = WireData{ + name: input_name.to_string(), + length: dimensions.to_vec(), + is_bus + }; + self.inputs.push(wire_info); } - pub fn add_bus_output(&mut self, output_name: &str, dimensions: &[usize]) { - self.bus_outputs.push((output_name.to_string(), dimensions.to_vec())); + pub fn add_output(&mut self, output_name: &str, dimensions: &[usize], is_bus: bool) { + let wire_info = WireData{ + name: output_name.to_string(), + length: dimensions.to_vec(), + is_bus + }; + self.outputs.push(wire_info); } - pub fn add_bus_intermediate(&mut self, intermediate_name: &str, dimensions: &[usize]) { - self.bus_intermediates.push((intermediate_name.to_string(), dimensions.to_vec())); + pub fn add_intermediate(&mut self, intermediate_name: &str, dimensions: &[usize], is_bus: bool) { + let wire_info = WireData{ + name: intermediate_name.to_string(), + length: dimensions.to_vec(), + is_bus + }; + self.inputs.push(wire_info); } + // TODO: same for buses -> needed for custom gates 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(); @@ -228,30 +224,18 @@ impl ExecutedTemplate { &self.tag_instances } - pub fn inputs(&self) -> &SignalCollector { + pub fn inputs(&self) -> &WireCollector { &self.inputs } - pub fn outputs(&self) -> &SignalCollector { + pub fn outputs(&self) -> &WireCollector { &self.outputs } - pub fn intermediates(&self) -> &SignalCollector { + pub fn intermediates(&self) -> &WireCollector { &self.intermediates } - pub fn bus_inputs(&self) -> &BusCollector { - &self.bus_inputs - } - - pub fn bus_outputs(&self) -> &BusCollector { - &self.bus_outputs - } - - pub fn bus_intermediates(&self) -> &BusCollector { - &self.bus_intermediates - } - pub fn insert_in_dag(&mut self, dag: &mut DAG, buses_info : &Vec) { let parameters = { let mut parameters = vec![]; @@ -277,54 +261,46 @@ impl ExecutedTemplate { } fn build_wires(&self, dag: &mut DAG, buses_info : &Vec) { - for (name, dim) in self.outputs() { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 1, dimensions: dim, is_public: false }; - generate_symbols(dag, state, &config); - } - for (name, dim) in self.bus_outputs() { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 1, dimensions: dim, is_public: false }; - generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); - } - for (name, dim) in self.inputs() { - if self.public_inputs.contains(name) { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: true }; + for wire_data in self.outputs() { + let state = State { basic_name: wire_data.name.clone(), name: wire_data.name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 1, dimensions: &wire_data.length, is_public: false }; + if wire_data.is_bus{ + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } else{ generate_symbols(dag, state, &config); } } - for (name, dim) in self.bus_inputs() { - if self.public_inputs.contains(name) { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: true }; - generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + for wire_data in self.inputs() { + if self.public_inputs.contains(&wire_data.name) { + let state = State { basic_name: wire_data.name.clone(), name: wire_data.name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 0, dimensions: &wire_data.length, is_public: true }; + if wire_data.is_bus{ + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } else{ + generate_symbols(dag, state, &config); + } } } - for (name, dim) in self.inputs() { - if !self.public_inputs.contains(name) { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: false }; - generate_symbols(dag, state, &config); + for wire_data in self.inputs() { + if !self.public_inputs.contains(&wire_data.name) { + let state = State { basic_name: wire_data.name.clone(), name: wire_data.name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 0, dimensions: &wire_data.length, is_public: false }; + if wire_data.is_bus{ + generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } else{ + generate_symbols(dag, state, &config); + } } } - for (name, dim) in self.bus_inputs() { - if !self.public_inputs.contains(name) { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 0, dimensions: dim, is_public: false }; + for wire_data in self.intermediates() { + let state = State { basic_name: wire_data.name.clone(), name: wire_data.name.clone(), dim: 0 }; + let config = SignalConfig { signal_type: 2, dimensions: &wire_data.length, is_public: false }; + if wire_data.is_bus{ generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } else{ + generate_symbols(dag, state, &config); } } - for (name, dim) in self.intermediates() { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 2, dimensions: dim, is_public: false }; - generate_symbols(dag, state, &config); - } - for (name, dim) in self.bus_intermediates() { - let state = State { basic_name: name.clone(), name: name.clone(), dim: 0 }; - let config = SignalConfig { signal_type: 2, dimensions: dim, is_public: false }; - generate_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); - } } fn build_connexions(&mut self, dag: &mut DAG) { @@ -365,7 +341,7 @@ impl ExecutedTemplate { } } - pub fn export_to_circuit(self, instances: &mut [TemplateInstance]) -> TemplateInstance { + pub fn export_to_circuit(self, instances: &mut [TemplateInstance], buses_info : &Vec) -> TemplateInstance { use SignalType::*; fn build_triggers( instances: &mut [TemplateInstance], @@ -384,7 +360,8 @@ impl ExecutedTemplate { is_parallel: data.is_parallel || instances[data.goes_to].is_parallel, runs: instances[data.goes_to].template_header.clone(), template_id: data.goes_to, - external_signals: instances[data.goes_to].signals.clone(), + external_signals: instances[data.goes_to].signals.clone(), // TODO: only copy signals that are external + external_buses: instances[data.goes_to].buses.clone(), has_inputs: instances[data.goes_to].number_of_inputs > 0, }; triggers.push(trigger); @@ -435,7 +412,7 @@ impl ExecutedTemplate { let mut public = vec![]; let mut not_public = vec![]; for s in self.inputs { - if self.public_inputs.contains(&s.0) { + if self.public_inputs.contains(&s.name) { public.push(s); } else { not_public.push(s); @@ -443,33 +420,68 @@ impl ExecutedTemplate { } let mut local_id = 0; let mut dag_local_id = 1; - for (name, lengths) in self.outputs { - let signal = Signal { name, lengths, local_id, dag_local_id, xtype: Output}; - local_id += signal.size(); - dag_local_id += signal.size(); - instance.add_signal(signal); + for s in self.outputs { + if s.is_bus{ + let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; + let exe_bus = buses_info.get(bus_node).unwrap(); + let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Output, buses_info); + local_id += bus.size(); + dag_local_id += bus.size(); + instance.add_bus(bus); + } else{ + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Output}; + local_id += signal.size(); + dag_local_id += signal.size(); + instance.add_signal(signal); + } } - for (name, lengths) in public { - let signal = Signal { name, lengths, local_id, dag_local_id, xtype: Input}; - local_id += signal.size(); - dag_local_id += signal.size(); - instance.add_signal(signal); + + for s in public { + if s.is_bus{ + let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; + let exe_bus = buses_info.get(bus_node).unwrap(); + let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Input, buses_info); + local_id += bus.size(); + dag_local_id += bus.size(); + instance.add_bus(bus); + } else{ + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input}; + local_id += signal.size(); + dag_local_id += signal.size(); + instance.add_signal(signal); + } } - for (name, lengths) in not_public { - let signal = Signal { name, lengths, local_id, dag_local_id, xtype: Input}; - local_id += signal.size(); - dag_local_id += signal.size(); - instance.add_signal(signal); + for s in not_public { + if s.is_bus{ + let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; + let exe_bus = buses_info.get(bus_node).unwrap(); + let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Input, buses_info); + local_id += bus.size(); + dag_local_id += bus.size(); + instance.add_bus(bus); + } else{ + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input}; + local_id += signal.size(); + dag_local_id += signal.size(); + instance.add_signal(signal); + } } - for (name, lengths) in self.intermediates { - let signal = Signal { name, lengths, local_id, dag_local_id, xtype: Intermediate}; - local_id += signal.size(); - dag_local_id += signal.size(); - instance.add_signal(signal); + for s in self.intermediates { + if s.is_bus{ + let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; + let exe_bus = buses_info.get(bus_node).unwrap(); + let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Intermediate, buses_info); + local_id += bus.size(); + dag_local_id += bus.size(); + instance.add_bus(bus); + } else{ + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Intermediate}; + local_id += signal.size(); + dag_local_id += signal.size(); + instance.add_signal(signal); + } } - // Here we need to add the buses - instance } @@ -505,22 +517,22 @@ fn generate_symbols(dag: &mut DAG, state: State, config: &SignalConfig) { } } +// TODO: move to bus? fn generate_bus_symbols(dag: &mut DAG, state: State, config: &SignalConfig, bus_connexions: &HashMap, buses: &Vec) { let bus_connection = bus_connexions.get(&state.basic_name).unwrap(); let ex_bus2 = buses.get(bus_connection.inspect.goes_to).unwrap(); if state.dim == config.dimensions.len() { - for (signal, signal_dims) in ex_bus2.signal_fields(){ - let signal_name = format!("{}.{}",state.name,signal); - let state = State { basic_name: signal.clone(), name: signal_name, dim: 0 }; - let config = SignalConfig { signal_type: config.signal_type, dimensions: signal_dims, is_public: config.is_public }; - generate_symbols(dag, state, &config); - } - for (bus, bus_dims) in ex_bus2.bus_fields(){ - let bus_name = format!("{}.{}",state.name,bus); - let state = State { basic_name: bus.clone(), name: bus_name, dim: 0 }; - let config = SignalConfig { signal_type: config.signal_type, dimensions: &bus_dims, is_public: config.is_public }; - generate_bus_symbols(dag, state, &config, ex_bus2.bus_connexions(), buses); + for info_field in ex_bus2.fields(){ + let signal_name = format!("{}.{}",state.name, info_field.name); + let state = State { basic_name: info_field.name.clone(), name: signal_name, dim: 0 }; + let config = SignalConfig { signal_type: config.signal_type, dimensions: &info_field.length, is_public: config.is_public }; + if info_field.is_bus{ + generate_bus_symbols(dag, state, &config, ex_bus2.bus_connexions(), buses); + } else{ + generate_symbols(dag, state, &config); + } } + } else { let mut index = 0; while index < config.dimensions[state.dim] { diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index bd0f06695..d7d9385cb 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -9,9 +9,13 @@ pub type Constraint = ConstraintGen; pub type ParameterContext = BTreeMap; pub type TagContext = BTreeMap; pub type TagInfo = BTreeMap>; -// From name to dimensions -pub type SignalCollector = Vec<(String, Vec)>; -pub type BusCollector = Vec<(String, Vec)>; +// From name to dimensions and if it is bus or not +pub struct WireData{ + pub name: String, + pub length: Vec, + pub is_bus: bool +} +pub type WireCollector = Vec; pub type ComponentCollector = Vec<(String, Vec)>; pub struct SubComponentData { pub name: String, @@ -23,6 +27,7 @@ pub struct SubComponentData { pub struct BusData { pub name: String, pub goes_to: NodePointer, + pub size: usize, } /* From 5bfb78b683550689411914bb173ec4503683696e Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 14 Jun 2024 13:31:14 +0200 Subject: [PATCH 096/189] adding plonk ordered signals generation --- constraint_generation/src/execute.rs | 2 - .../src/execution_data/executed_template.rs | 76 ++++++++++++++++--- .../src/execution_data/type_definitions.rs | 1 + dag/src/lib.rs | 15 +++- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index b40e705de..66cf952d0 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1094,7 +1094,6 @@ fn execute_signal_declaration( tags.insert(t.clone(), None); } if let Option::Some(node) = actual_node { - node.add_ordered_signal(signal_name, dimensions); match signal_type { Input => { if let Some(tags_input) = node.tag_instances().get(signal_name){ @@ -1158,7 +1157,6 @@ fn execute_bus_declaration( tags.insert(t.clone(), None); } if let Option::Some(node) = actual_node { - //node.add_ordered_signal(signal_name, dimensions); match signal_type { Input => { if let Some(tags_input) = node.tag_instances().get(bus_name){ diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 895f612f6..ffb649202 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -69,7 +69,7 @@ pub struct ExecutedTemplate { pub inputs: WireCollector, pub outputs: WireCollector, pub intermediates: WireCollector, - pub ordered_signals: Vec, + pub ordered_signals: WireCollector, pub constraints: Vec, pub components: ComponentCollector, pub number_of_components: usize, @@ -111,7 +111,7 @@ impl ExecutedTemplate { inputs: WireCollector::new(), outputs: WireCollector::new(), intermediates: WireCollector::new(), - ordered_signals: Vec::new(), + ordered_signals: WireCollector::new(), constraints: Vec::new(), components: ComponentCollector::new(), number_of_components: 0, @@ -145,7 +145,8 @@ impl ExecutedTemplate { length: dimensions.to_vec(), is_bus }; - self.inputs.push(wire_info); + self.inputs.push(wire_info.clone()); + self.ordered_signals.push(wire_info); } pub fn add_output(&mut self, output_name: &str, dimensions: &[usize], is_bus: bool) { @@ -154,7 +155,8 @@ impl ExecutedTemplate { length: dimensions.to_vec(), is_bus }; - self.outputs.push(wire_info); + self.outputs.push(wire_info.clone()); + self.ordered_signals.push(wire_info); } pub fn add_intermediate(&mut self, intermediate_name: &str, dimensions: &[usize], is_bus: bool) { @@ -163,7 +165,8 @@ impl ExecutedTemplate { length: dimensions.to_vec(), is_bus }; - self.inputs.push(wire_info); + self.inputs.push(wire_info.clone()); + self.ordered_signals.push(wire_info); } // TODO: same for buses -> needed for custom gates @@ -183,9 +186,7 @@ impl ExecutedTemplate { generated_symbols } } - for signal in generate_symbols(signal_name.to_string(), 0, dimensions) { - self.ordered_signals.push(signal); - } + } pub fn add_tag_signal(&mut self, signal_name: &str, tag_name: &str, value: Option){ @@ -251,11 +252,11 @@ impl ExecutedTemplate { dag.add_node( self.report_name.clone(), parameters, - self.ordered_signals.clone(), // pensar si calcularlo en este momento para no hacer clone self.is_parallel, self.is_custom_gate ); self.build_wires(dag, buses_info); + self.build_ordered_signals(dag, buses_info); self.build_connexions(dag); self.build_constraints(dag); } @@ -303,6 +304,18 @@ impl ExecutedTemplate { } } + fn build_ordered_signals(&self, dag: &mut DAG, buses_info : &Vec) { + for wire_data in &self.ordered_signals { + let state = State { basic_name: wire_data.name.clone(), name: wire_data.name.clone(), dim: 0 }; + let config = OrderedSignalConfig { dimensions: &wire_data.length }; + if wire_data.is_bus{ + generate_ordered_bus_symbols(dag, state, &config, &self.bus_connexions, buses_info ); + } else{ + generate_ordered_symbols(dag, state, &config); + } + } + } + fn build_connexions(&mut self, dag: &mut DAG) { self.connexions.sort_by(|l, r| { use std::cmp::Ordering; @@ -544,6 +557,51 @@ fn generate_bus_symbols(dag: &mut DAG, state: State, config: &SignalConfig, bus_ } } + +struct OrderedSignalConfig<'a> { + dimensions: &'a [usize], +} +fn generate_ordered_symbols(dag: &mut DAG, state: State, config: &OrderedSignalConfig) { + if state.dim == config.dimensions.len() { + dag.add_ordered_signal(state.name); + } else { + let mut index = 0; + while index < config.dimensions[state.dim] { + let new_state = + State { basic_name: state.basic_name.clone(), name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; + generate_ordered_symbols(dag, new_state, config); + index += 1; + } + } +} + +// TODO: move to bus? +fn generate_ordered_bus_symbols(dag: &mut DAG, state: State, config: &OrderedSignalConfig, bus_connexions: &HashMap, buses: &Vec) { + let bus_connection = bus_connexions.get(&state.basic_name).unwrap(); + let ex_bus2 = buses.get(bus_connection.inspect.goes_to).unwrap(); + if state.dim == config.dimensions.len() { + for info_field in ex_bus2.fields(){ + let signal_name = format!("{}.{}",state.name, info_field.name); + let state = State { basic_name: info_field.name.clone(), name: signal_name, dim: 0 }; + let config = OrderedSignalConfig {dimensions: &info_field.length }; + if info_field.is_bus{ + generate_ordered_bus_symbols(dag, state, &config, ex_bus2.bus_connexions(), buses); + } else{ + generate_ordered_symbols(dag, state, &config); + } + } + + } else { + let mut index = 0; + while index < config.dimensions[state.dim] { + let new_state = + State { basic_name: state.basic_name.clone(), name: format!("{}[{}]", state.name, index), dim: state.dim + 1 }; + generate_ordered_bus_symbols(dag, new_state, config, bus_connexions, buses); + index += 1; + } + } +} + fn as_big_int(exprs: Vec>) -> Vec { let mut numbers = Vec::with_capacity(exprs.len()); for e in exprs { diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index d7d9385cb..5086ea02d 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -10,6 +10,7 @@ pub type ParameterContext = BTreeMap; pub type TagContext = BTreeMap; pub type TagInfo = BTreeMap>; // From name to dimensions and if it is bus or not +#[derive(Clone)] pub struct WireData{ pub name: String, pub length: Vec, diff --git a/dag/src/lib.rs b/dag/src/lib.rs index 8c51193c8..19d325da3 100644 --- a/dag/src/lib.rs +++ b/dag/src/lib.rs @@ -161,7 +161,6 @@ impl Node { id: usize, template_name: String, parameters: Vec, - ordered_signals: Vec, is_parallel: bool, is_custom_gate: bool ) -> Node { @@ -169,7 +168,6 @@ impl Node { template_name, entry: Edge::new_entry(id), parameters, number_of_components: 1, - ordered_signals, is_parallel, has_parallel_sub_cmp: false, is_custom_gate, @@ -215,6 +213,10 @@ impl Node { self.intermediates_length += 1; } + fn add_ordered_signal(&mut self, name: String){ + self.ordered_signals.push(name); + } + fn add_constraint(&mut self, constraint: Constraint) { self.constraints.push(constraint) } @@ -372,13 +374,12 @@ impl DAG { &mut self, template_name: String, parameters: 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, parameters, ordered_signals, is_parallel, is_custom_gate) + Node::new(id, template_name, parameters, is_parallel, is_custom_gate) ); self.adjacency.push(vec![]); id @@ -402,6 +403,12 @@ impl DAG { } } + pub fn add_ordered_signal(&mut self, name: String) { + if let Option::Some(node) = self.get_mut_main() { + node.add_ordered_signal(name); + } + } + pub fn add_constraint(&mut self, constraint: Constraint) { if let Option::Some(node) = self.get_mut_main() { node.add_constraint(constraint); From 48543e9762a3a746ebcc92eb838df7c15139f7c4 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 17 Jun 2024 13:29:47 +0200 Subject: [PATCH 097/189] mixing signals and buses in wires in code generation phase --- compiler/src/circuit_design/build.rs | 28 ++- compiler/src/hir/analysis_utilities.rs | 39 ++-- compiler/src/hir/merger.rs | 11 +- compiler/src/hir/very_concrete_program.rs | 110 +++++++--- .../src/intermediate_representation/mod.rs | 2 +- .../intermediate_representation/translate.rs | 191 +++++++++++++----- .../src/execution_data/executed_bus.rs | 9 +- .../src/execution_data/executed_program.rs | 4 +- .../src/execution_data/executed_template.rs | 39 +--- 9 files changed, 277 insertions(+), 156 deletions(-) diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 859ae5ed4..9b06ff979 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -87,8 +87,7 @@ fn build_template_instances( message_id: tmp_id, params: Vec::new(), header: header.clone(), - signals: template.signals, - buses: template.buses, + wires: template.wires, constants: instance_values, files: &c_info.file_library, triggers: template.triggers, @@ -153,8 +152,7 @@ fn build_function_instances( functions: &c_info.functions, params: params.clone(), fresh_cmp_id: 0, - signals: Vec::with_capacity(0), - buses: Vec::with_capacity(0), + wires: Vec::with_capacity(0), triggers: Vec::with_capacity(0), clusters: Vec::with_capacity(0), constants: Vec::with_capacity(0), @@ -268,9 +266,9 @@ fn initialize_c_producer(vcp: &VCP, database: &TemplateDB, version: &str) -> CPr fn main_input_list(main: &TemplateInstance) -> InputList { use program_structure::ast::SignalType::*; let mut input_list = vec![]; - for s in &main.signals { - if s.xtype == Input { - input_list.push((s.name.clone(), s.dag_local_id, s.size())); + for s in &main.wires { + if s.xtype() == Input { + input_list.push((s.name().clone(), s.dag_local_id(), s.size())); } } input_list @@ -309,12 +307,12 @@ fn build_io_map(vcp: &VCP, database: &TemplateDB) -> TemplateInstanceIOMap { fn build_input_output_list(instance: &TemplateInstance, database: &TemplateDB) -> InputOutputList { use program_structure::ast::SignalType::*; let mut io_list = vec![]; - for s in &instance.signals { - if s.xtype != Intermediate { + for s in &instance.wires { + if s.xtype() != Intermediate { let def = IODef { - code: TemplateDB::get_signal_id(database, &instance.template_name, &s.name), - offset: s.local_id, - lengths: s.lengths.clone(), + code: TemplateDB::get_signal_id(database, &instance.template_name, s.name()), + offset: s.local_id(), + lengths: s.lengths().clone(), }; io_list.push(def); } @@ -334,9 +332,9 @@ fn write_main_inputs_log(vcp: &VCP) { const INPUT_LOG: &str = "./log_input_signals.txt"; let main = vcp.get_main_instance().unwrap(); let mut writer = BufWriter::new(File::create(INPUT_LOG).unwrap()); - for signal in &main.signals { - if signal.xtype == Input { - let name = format!("main.{}", &signal.name); + for signal in &main.wires { + if signal.xtype() == Input { + let name = format!("main.{}", &signal.name()); let length = signal.size(); let msg = format!("{} {}\n", name, length); writer.write_all(msg.as_bytes()).unwrap(); diff --git a/compiler/src/hir/analysis_utilities.rs b/compiler/src/hir/analysis_utilities.rs index 5599ece98..1f33a0b78 100644 --- a/compiler/src/hir/analysis_utilities.rs +++ b/compiler/src/hir/analysis_utilities.rs @@ -58,12 +58,17 @@ pub fn build_component_info(triggers: &Vec) -> for trigger in triggers { let mut signals = HashMap::new(); let mut buses = HashMap::new(); - for s in &trigger.external_signals { - signals.insert(s.name.clone(), s.lengths.clone()); - } - for s in &trigger.external_buses { - buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + for s in &trigger.external_wires { + match s{ + Wire::TSignal(s) =>{ + signals.insert(s.name.clone(), s.lengths.clone()); + }, + Wire::TBus(s) =>{ + buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + } + } } + let (signals, buses) = match external_signals.remove(&trigger.component_name){ None => (signals, buses), Some((old_signals, old_buses)) =>{ @@ -76,11 +81,13 @@ pub fn build_component_info(triggers: &Vec) -> external_signals } -pub fn build_buses_info(buses: &Vec) -> HashMap{ +pub fn build_buses_info(wires: &Vec) -> HashMap{ let mut info_buses = HashMap::new(); - for bus in buses{ - info_buses.insert(bus.name.clone(), build_single_bus_info(bus)); + for s in wires{ + if let Wire::TBus(bus) = s{ + info_buses.insert(bus.name.clone(), build_single_bus_info(bus)); + } } info_buses } @@ -88,13 +95,19 @@ pub fn build_buses_info(buses: &Vec) -> HashMap{ fn build_single_bus_info(bus: &Bus) -> InfoBus{ let size = bus.size(); let mut signals = HashMap::new(); - for s in &bus.signals{ - signals.insert(s.name.clone(), s.lengths.clone()); - } let mut buses = HashMap::new(); - for s in &bus.buses{ - buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + + for s in &bus.wires{ + match s{ + Wire::TSignal(s) =>{ + signals.insert(s.name.clone(), s.lengths.clone()); + } + Wire::TBus(s) =>{ + buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + } + } } + InfoBus{size, signals, buses} } diff --git a/compiler/src/hir/merger.rs b/compiler/src/hir/merger.rs index 3cd1fd98a..98a8c4545 100644 --- a/compiler/src/hir/merger.rs +++ b/compiler/src/hir/merger.rs @@ -4,7 +4,7 @@ use super::sugar_cleaner; use super::very_concrete_program::*; use program_structure::ast::*; use program_structure::program_archive::ProgramArchive; -use num_traits::{ToPrimitive}; +use num_traits::ToPrimitive; pub fn run_preprocessing(vcp: &mut VCP, program_archive: ProgramArchive) { @@ -23,7 +23,7 @@ fn produce_vcf(vcp: &VCP, state: &mut State) { let constants = &n.header; let params = vec![]; state.external_signals = build_component_info(&n.triggers); - state.buses_info = build_buses_info(&n.buses); + state.buses_info = build_buses_info(&n.wires); let mut env = build_environment(constants, ¶ms); produce_vcf_stmt(code, state, &mut env); } @@ -41,7 +41,7 @@ fn link_circuit(vcp: &mut VCP, state: &mut State) { for node in &mut vcp.templates { let mut env = build_environment(&node.header, &vec![]); state.external_signals = build_component_info(&node.triggers); - state.buses_info = build_buses_info(&node.buses); + state.buses_info = build_buses_info(&node.wires); link_stmt(&mut node.code, state, &mut env); } let mut linked_vcf_collector = state.vcf_collector.clone(); @@ -288,7 +288,7 @@ fn produce_vcf_call(expr: &Expression, state: &mut State, environment: &E) { fn produce_vcf_bus_call(expr: &Expression, state: &mut State, environment: &E) { use Expression::BusCall; - if let BusCall { id, args, .. } = expr { + if let BusCall { args, .. } = expr { for arg in args { produce_vcf_expr(arg, state, environment); } @@ -650,8 +650,8 @@ fn cast_type_variable(expr: &Expression, state: &State, environment: &E) -> VCT xtype.pop(); } Access::ComponentAccess(signal) => { - // case buses if possible_bus_info.is_some(){ + // case buses let bus = possible_bus_info.unwrap(); if bus.signals.contains_key(signal){ xtype = bus.signals.get(signal).unwrap().clone(); @@ -672,6 +672,7 @@ fn cast_type_variable(expr: &Expression, state: &State, environment: &E) -> VCT xtype.reverse(); possible_bus_info = None; } else{ + // case io bus let aux_info = buses.get(signal).unwrap(); xtype = aux_info.0.clone(); xtype.reverse(); diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index f73570d42..3003f358d 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -24,6 +24,74 @@ impl PartialEq for Argument { } } +#[derive(Clone)] +pub enum Wire{ + TSignal(Signal), + TBus(Bus) +} +impl Wire { + pub fn size(&self) -> usize { + match self{ + Wire::TSignal(s) => { + s.size() + }, + Wire::TBus(s) => { + s.size() + }, + } + } + pub fn xtype(&self) -> SignalType { + match self{ + Wire::TSignal(s) => { + s.xtype + }, + Wire::TBus(s) => { + s.xtype + }, + } + } + pub fn name(&self) -> &String { + match self{ + Wire::TSignal(s) => { + &s.name + }, + Wire::TBus(s) => { + &s.name + }, + } + } + pub fn lengths(&self) -> &Vec { + match self{ + Wire::TSignal(s) => { + &s.lengths + }, + Wire::TBus(s) => { + &s.lengths + }, + } + } + pub fn local_id(&self) -> usize { + match self{ + Wire::TSignal(s) => { + s.local_id + }, + Wire::TBus(s) => { + s.local_id + }, + } + } + pub fn dag_local_id(&self) -> usize { + match self{ + Wire::TSignal(s) => { + s.dag_local_id + }, + Wire::TBus(s) => { + s.dag_local_id + }, + } + } +} + #[derive(Clone)] pub struct Signal { pub name: String, @@ -44,19 +112,15 @@ pub struct Bus{ pub name: String, pub lengths: Vec, pub xtype: SignalType, - pub signals: Vec, - pub buses: Vec>, + pub wires: Vec, pub local_id: usize, pub dag_local_id: usize, } impl Bus{ pub fn size(&self) -> usize{ let mut total_size = 0; - for signal in &self.signals{ - total_size += signal.size(); - } - for bus in &self.buses{ - total_size += bus.size(); + for wire in &self.wires{ + total_size += wire.size(); } self.lengths.iter().fold(total_size, |p, c| p * (*c)) } @@ -82,8 +146,7 @@ pub struct Trigger { pub template_id: usize, pub component_name: String, pub indexed_with: Vec, - pub external_signals: Vec, - pub external_buses: Vec, + pub external_wires: Vec, pub has_inputs: bool, pub is_parallel: bool, } @@ -115,9 +178,8 @@ pub struct TemplateInstance { pub number_of_inputs: usize, pub number_of_outputs: usize, pub number_of_intermediates: usize, - pub signals: Vec, + pub wires: Vec, pub signals_to_tags: BTreeMap, - pub buses: Vec, pub components: Vec, pub number_of_components: usize, pub triggers: Vec, @@ -155,8 +217,7 @@ impl TemplateInstance { number_of_outputs: 0, number_of_intermediates: 0, number_of_components: config.number_of_components, - signals: Vec::new(), - buses: Vec::new(), + wires: Vec::new(), components: config.components, triggers: config.triggers, clusters: config.clusters, @@ -164,10 +225,10 @@ impl TemplateInstance { } } - pub fn add_signal(&mut self, signal: Signal) { + pub fn add_signal(&mut self, wire: Wire) { use SignalType::*; - let new_signals = signal.lengths.iter().fold(1, |r, c| r * (*c)); - match signal.xtype { + let new_signals = wire.size(); + match wire.xtype() { Input => { self.number_of_inputs += new_signals; } @@ -178,22 +239,7 @@ impl TemplateInstance { self.number_of_intermediates += new_signals; } } - self.signals.push(signal); - } - pub fn add_bus(&mut self, bus: Bus) { - use SignalType::*; - match bus.xtype { - Input => { - self.number_of_inputs += bus.size(); - } - Output => { - self.number_of_outputs += bus.size(); - } - Intermediate => { - self.number_of_intermediates += bus.size(); - } - } - self.buses.push(bus); + self.wires.push(wire); } } diff --git a/compiler/src/intermediate_representation/mod.rs b/compiler/src/intermediate_representation/mod.rs index 8448d98d9..c002c1af0 100644 --- a/compiler/src/intermediate_representation/mod.rs +++ b/compiler/src/intermediate_representation/mod.rs @@ -15,4 +15,4 @@ mod value_bucket; pub mod ir_interface; pub mod translate; -pub use ir_interface::{Instruction, InstructionList, InstructionPointer}; +pub use ir_interface::InstructionList; diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index fb7e38145..5e409848c 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -11,11 +11,26 @@ use std::collections::{HashMap, BTreeMap, HashSet}; type Length = usize; pub type E = VarEnvironment; pub type FieldTracker = ConstantTracker; + +#[derive(Clone)] +pub struct FieldInfo{ + offset: usize, + bus_fields: Option>, +} + #[derive(Clone)] pub struct SymbolInfo { access_instruction: InstructionPointer, dimensions: Vec, is_component: bool, + is_bus: bool, + bus_fields: Option>, +} + +#[derive(Clone)] +pub enum WireInfo{ + Signal(SignalInfo), + Bus(BusInfo) } #[derive(Clone)] @@ -28,19 +43,15 @@ pub struct SignalInfo{ pub struct BusInfo{ signal_type: SignalType, lengths: Vec, - signals: HashMap, - buses: HashMap>, + fields: HashMap, } - #[derive(Clone)] pub struct TemplateDB { // one per template instance pub signal_addresses: Vec, // stores the type and the length of signal - pub signal_info: Vec>, - // stores the type, fields and length of a bus - pub bus_info: Vec>, + pub wire_info: Vec>, // template_name to usize pub indexes: HashMap, // one per generic template, gives its signal to code correspondence @@ -51,8 +62,7 @@ impl TemplateDB { let mut database = TemplateDB { indexes: HashMap::with_capacity(templates.len()), signal_addresses: Vec::with_capacity(templates.len()), - signal_info: Vec::with_capacity(templates.len()), - bus_info: Vec::with_capacity(templates.len()), + wire_info: Vec::with_capacity(templates.len()), signals_id: Vec::with_capacity(templates.len()), }; for tmp in templates { @@ -70,31 +80,35 @@ impl TemplateDB { &db.signal_addresses[instance_id] } + fn add_instance(db: &mut TemplateDB, instance: &TemplateInstance) { - fn add_bus(xtype: SignalType, lengths: Vec, info_signals: Vec, info_buses: Vec>)-> BusInfo{ - let mut signals = HashMap::new(); - for signal in info_signals{ - let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; - signals.insert(signal.name, info); - } - let mut buses = HashMap::new(); - for bus in info_buses.clone(){ - let info = add_bus(bus.xtype, bus.lengths, bus.signals, bus.buses); - buses.insert(bus.name, Box::new(info)); + fn build_bus_info(xtype: SignalType, lengths: Vec, info_wires: Vec)-> BusInfo{ + let mut fields = HashMap::new(); + for s in info_wires{ + match s{ + Wire::TSignal(signal) =>{ + let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; + fields.insert(signal.name, WireInfo::Signal(info)); + }, + Wire::TBus(bus) =>{ + let info = build_bus_info(bus.xtype, bus.lengths, bus.wires); + fields.insert(bus.name, WireInfo::Bus(info)); + } + } } + BusInfo{ signal_type: xtype, lengths: lengths, - signals, - buses + fields, } } if !db.indexes.contains_key(&instance.template_name) { let index = db.signals_id.len(); db.indexes.insert(instance.template_name.clone(), index); let mut correspondence = HashMap::new(); - for (id, signal) in instance.signals.iter().enumerate() { - correspondence.insert(signal.name.clone(), id); + for (id, signal) in instance.wires.iter().enumerate() { + correspondence.insert(signal.name().clone(), id); } db.signals_id.push(correspondence); } @@ -105,23 +119,26 @@ impl TemplateDB { HashMap::with_capacity(0), instance.signals_to_tags.clone(), ); - let mut signal_info = HashMap::new(); - for signal in instance.signals.clone() { - let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; - signal_info.insert(signal.name, info); - } - let mut bus_info = HashMap::new(); - for bus in instance.buses.clone(){ - let info = add_bus(bus.xtype, bus.lengths, bus.signals, bus.buses); - bus_info.insert(bus.name, info); + let mut wire_info = HashMap::new(); + for wire in instance.wires.clone() { + match wire{ + Wire::TSignal(signal) =>{ + let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; + wire_info.insert(signal.name, WireInfo::Signal(info)); + }, + Wire::TBus(bus) =>{ + let info = build_bus_info(bus.xtype, bus.lengths, bus.wires); + wire_info.insert(bus.name, WireInfo::Bus(info)); + } + } } - initialize_signals(&mut state, instance.signals.clone(), instance.buses.clone()); + initialize_signals(&mut state, instance.wires.clone()); db.signal_addresses.push(state.environment); - db.signal_info.push(signal_info); - db.bus_info.push(bus_info); + db.wire_info.push(wire_info); } } + struct State { field_tracker: FieldTracker, environment: E, @@ -210,7 +227,13 @@ fn initialize_parameters(state: &mut State, params: Vec) { }; let address_instruction = address_instruction.allocate(); let symbol_info = - SymbolInfo { dimensions: lengths, access_instruction: address_instruction.clone(), is_component:false }; + SymbolInfo { + dimensions: lengths, + access_instruction: address_instruction.clone(), + is_component:false, + is_bus: false, + bus_fields: None + }; state.environment.add_variable(&p.name, symbol_info); } } @@ -229,7 +252,13 @@ fn initialize_constants(state: &mut State, constants: Vec) { } .allocate(); let symbol_info = - SymbolInfo { access_instruction: address_instruction.clone(), dimensions, is_component:false }; + SymbolInfo { + access_instruction: address_instruction.clone(), + dimensions, + is_component:false, + is_bus: false, + bus_fields: None + }; state.environment.add_variable(&arg.name, symbol_info); let mut index = 0; for value in arg.values { @@ -274,10 +303,38 @@ fn initialize_constants(state: &mut State, constants: Vec) { } } -fn initialize_signals(state: &mut State, signals: Vec, buses: Vec) { - for signal in signals { - let size = signal.lengths.iter().fold(1, |p, c| p * (*c)); +fn initialize_signals(state: &mut State, wires: Vec) { + fn build_field_info(wire: Wire, mut offset: usize) -> FieldInfo{ + + let possible_fields = match wire{ + Wire::TSignal(_) =>{ + None + }, + Wire::TBus(b) =>{ + let mut fields = HashMap::new(); + for field in b.wires{ + offset += field.size(); + let name = field.name().clone(); + let info = build_field_info(field, offset); + fields.insert(name, info); + } + Some(fields) + } + }; + FieldInfo{ + bus_fields: possible_fields, + offset + } + + } + for wire in wires{ + let size = wire.size(); let address = state.reserve_signal(size); + let dimensions = wire.lengths().clone(); + let name = wire.name().clone(); + let xtype = wire.xtype(); + + let wire_info = build_field_info(wire, 0); let instruction = ValueBucket { line: 0, message_id: state.message_id, @@ -286,9 +343,16 @@ fn initialize_signals(state: &mut State, signals: Vec, buses: Vec) op_aux_no: 0, } .allocate(); - let info = SymbolInfo { access_instruction: instruction, dimensions: signal.lengths, is_component:false }; - state.environment.add_variable(&signal.name, info); - state.signal_to_type.insert(signal.name.clone(), signal.xtype); + let info = SymbolInfo { + access_instruction: instruction, + dimensions, + is_component:false, + is_bus: wire_info.bus_fields.is_some(), + bus_fields: wire_info.bus_fields + }; + state.environment.add_variable(&name, info); + state.signal_to_type.insert(name.to_string(), xtype); + } } @@ -304,7 +368,13 @@ fn initialize_components(state: &mut State, components: Vec) { op_aux_no: 0, } .allocate(); - let info = SymbolInfo { access_instruction: instruction, dimensions: component.lengths, is_component: true }; + let info = SymbolInfo { + access_instruction: instruction, + dimensions: component.lengths, + is_component: true, + is_bus: false, + bus_fields: None, + }; state.environment.add_variable(&component.name, info); } } @@ -591,7 +661,14 @@ fn translate_declaration(stmt: Statement, state: &mut State, context: &Context) op_aux_no: 0, } .allocate(); - let info = SymbolInfo { access_instruction: instruction, dimensions, is_component: false }; + // TODO: check if this is only used for signals + let info = SymbolInfo { + access_instruction: instruction, + dimensions, + is_component: false, + is_bus: false, + bus_fields: None, + }; state.environment.add_variable(&name, info); } else { unreachable!() @@ -823,7 +900,7 @@ fn translate_variable( state: &mut State, context: &Context, ) -> InstructionPointer { - use Expression::{Variable}; + use Expression::Variable; if let Variable { meta, name, access, .. } = expression { let tag_access = check_tag_access(&name, &access, state); if tag_access.is_some(){ @@ -971,13 +1048,22 @@ impl ProcessedSymbol { af_index.push(translate_expression(exp, state, context)); } ComponentAccess(name) => { + // TODO: case buses let possible_cmp_id = state.component_to_instance.get(&symbol_name).unwrap().clone(); for cmp_id in possible_cmp_id{ - let aux = context.tmp_database.signal_info[cmp_id].get(&name).unwrap(); - signal_type = Some(aux.signal_type); - let mut new_length = aux.lengths.clone(); - new_length.reverse(); - multiple_possible_lengths.push(new_length); + let aux = context.tmp_database.wire_info[cmp_id].get(&name).unwrap(); + match aux{ + WireInfo::Signal(aux) => { + signal_type = Some(aux.signal_type); + let mut new_length = aux.lengths.clone(); + new_length.reverse(); + multiple_possible_lengths.push(new_length); + } + WireInfo::Bus(aux) =>{ + unreachable!() + } + } + } signal = Some(name); } @@ -1392,8 +1478,7 @@ pub struct CodeInfo<'a> { pub header: String, pub message_id: usize, pub params: Vec, - pub signals: Vec, - pub buses: Vec, + pub wires: Vec, pub files: &'a FileLibrary, pub constants: Vec, pub components: Vec, @@ -1430,7 +1515,7 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { ); state.string_table = code_info.string_table; initialize_components(&mut state, code_info.components); - initialize_signals(&mut state, code_info.signals, code_info.buses); + initialize_signals(&mut state, code_info.wires); initialize_constants(&mut state, code_info.constants); initialize_parameters(&mut state, code_info.params); diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index 852325600..5b8626400 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -129,8 +129,7 @@ impl ExecutedBus { ) -> Bus{ let mut local_id_aux = local_id; let mut dag_local_id_aux = dag_local_id; - let mut signals = Vec::new(); - let mut buses = Vec::new(); + let mut wires = Vec::new(); for info_field in &self.fields{ let (name, lengths) = (&info_field.name, &info_field.length); @@ -138,17 +137,17 @@ impl ExecutedBus { let signal = Signal { name: name.clone(), lengths: lengths.clone(), local_id: local_id_aux, dag_local_id: dag_local_id_aux, xtype}; local_id_aux += signal.size(); dag_local_id_aux += signal.size(); - signals.push(signal); + wires.push(Wire::TSignal(signal)); } else{ let bus_node = self.bus_connexions.get(name).unwrap().inspect.goes_to; let exe_bus = buses_info.get(bus_node).unwrap(); let bus = exe_bus.build_bus(name.clone(), lengths.clone(), local_id_aux, dag_local_id_aux, xtype, buses_info); local_id_aux += bus.size(); dag_local_id_aux += bus.size(); - buses.push(Box::new(bus)); + wires.push(Wire::TBus(bus)); } } - Bus{name, lengths, xtype, local_id, dag_local_id, signals, buses} + Bus{name, lengths, xtype, local_id, dag_local_id, wires} } diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index 5697f0018..f24fe0530 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -130,8 +130,8 @@ impl ExecutedProgram { pub fn add_bus_node_to_scheme( &mut self, - mut node: ExecutedBus, - analysis: Analysis, // not needed? + node: ExecutedBus, + _analysis: Analysis, // not needed? ) -> NodePointer { //use super::filters::*; // Clean code??? diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index ffb649202..fe0bf4ad7 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -169,26 +169,6 @@ impl ExecutedTemplate { self.ordered_signals.push(wire_info); } - // TODO: same for buses -> needed for custom gates - 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 - } - } - - } - pub fn add_tag_signal(&mut self, signal_name: &str, tag_name: &str, value: Option){ let tags_signal = self.signal_to_tags.get_mut(signal_name); if tags_signal.is_none(){ @@ -373,8 +353,7 @@ impl ExecutedTemplate { is_parallel: data.is_parallel || instances[data.goes_to].is_parallel, runs: instances[data.goes_to].template_header.clone(), template_id: data.goes_to, - external_signals: instances[data.goes_to].signals.clone(), // TODO: only copy signals that are external - external_buses: instances[data.goes_to].buses.clone(), + external_wires: instances[data.goes_to].wires.clone(), // TODO: only copy signals that are external has_inputs: instances[data.goes_to].number_of_inputs > 0, }; triggers.push(trigger); @@ -440,12 +419,12 @@ impl ExecutedTemplate { let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Output, buses_info); local_id += bus.size(); dag_local_id += bus.size(); - instance.add_bus(bus); + instance.add_signal(Wire::TBus(bus)); } else{ let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Output}; local_id += signal.size(); dag_local_id += signal.size(); - instance.add_signal(signal); + instance.add_signal(Wire::TSignal(signal)); } } @@ -456,12 +435,12 @@ impl ExecutedTemplate { let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Input, buses_info); local_id += bus.size(); dag_local_id += bus.size(); - instance.add_bus(bus); + instance.add_signal(Wire::TBus(bus)); } else{ let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input}; local_id += signal.size(); dag_local_id += signal.size(); - instance.add_signal(signal); + instance.add_signal(Wire::TSignal(signal)); } } for s in not_public { @@ -471,12 +450,12 @@ impl ExecutedTemplate { let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Input, buses_info); local_id += bus.size(); dag_local_id += bus.size(); - instance.add_bus(bus); + instance.add_signal(Wire::TBus(bus)); } else{ let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input}; local_id += signal.size(); dag_local_id += signal.size(); - instance.add_signal(signal); + instance.add_signal(Wire::TSignal(signal)); } } for s in self.intermediates { @@ -486,12 +465,12 @@ impl ExecutedTemplate { let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Intermediate, buses_info); local_id += bus.size(); dag_local_id += bus.size(); - instance.add_bus(bus); + instance.add_signal(Wire::TBus(bus)); } else{ let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Intermediate}; local_id += signal.size(); dag_local_id += signal.size(); - instance.add_signal(signal); + instance.add_signal(Wire::TSignal(signal)); } } From 3490bd36d99cfb965e6f27171053834d4c5202fd Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 17 Jun 2024 13:38:56 +0200 Subject: [PATCH 098/189] fixing minor in error code definitions --- program_structure/src/program_library/error_code.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index eed974848..28cede3fe 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -179,7 +179,7 @@ impl fmt::Display for ReportCode { InvalidArraySize(..) => "T2033", InvalidArraySizeT => "T2033", InvalidArrayType => "T2034", - InvalidArrayType => "T2034", + InvalidArrayTypeB => "T2034", ForStatementIllConstructed => "T2035", BadArrayAccess => "T2035", AssigningAComponentTwice => "T2036", @@ -234,10 +234,11 @@ impl fmt::Display for ReportCode { TupleError => "TAC02", UnderscoreWithNoSignalWarning => "TAC03", BusWrongNumberOfArguments => "BU01", - InvalidArgumentInBusInstantiation => "BU02", - InvalidSignalAccessInBus => "BU03", - MustBeSameBus => "BU04", - MustBeBus => "BU05", + InvalidArgumentInBusInstantiationT => "BU02", + InvalidArgumentInBusInstantiationB => "BU03", + InvalidSignalAccessInBus => "BU04", + MustBeSameBus => "BU05", + MustBeBus => "BU06", }; f.write_str(string_format) } From 03d2fa21b0e4653d101c979365b41bfd3df0eb1f Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 17 Jun 2024 15:00:12 +0200 Subject: [PATCH 099/189] adding missing check in component preprocess -> removing bus call substitutions --- compiler/src/hir/component_preprocess.rs | 20 +++++++++++++++---- .../intermediate_representation/translate.rs | 3 ++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/compiler/src/hir/component_preprocess.rs b/compiler/src/hir/component_preprocess.rs index ebc55675f..85f48a587 100644 --- a/compiler/src/hir/component_preprocess.rs +++ b/compiler/src/hir/component_preprocess.rs @@ -70,18 +70,30 @@ fn rm_init(stmt: &mut Statement) { use Statement::InitializationBlock; use VariableType::*; if let InitializationBlock { initializations, xtype, .. } = stmt { - if let Signal(..) = xtype { + + if let Signal(..) = xtype { let work = std::mem::take(initializations); for mut i in work { if i.is_substitution() { initializations.push(i); + } else if i.is_block(){ + rm_block(&mut i); + initializations.push(i); } - else if i.is_block(){ + } + } else if let Bus(..) = xtype{ + let work = std::mem::take(initializations); + for mut i in work { + if i.is_substitution() { + if !should_be_removed(&i) { + initializations.push(i); + } + } else if i.is_block(){ rm_block(&mut i); initializations.push(i); } } - } else { + }else { let filter = std::mem::take(initializations); for mut s in filter { rm_statement(&mut s); @@ -110,7 +122,7 @@ fn should_be_removed(stmt: &Statement) -> bool { if let InitializationBlock { xtype, .. } = stmt { Component == *xtype || AnonymousComponent == *xtype } else if let Substitution { meta, rhe, .. } = stmt { - meta.get_type_knowledge().is_component() + meta.get_type_knowledge().is_component() || meta.get_type_knowledge().is_tag() || rhe.is_bus_call() || rhe.is_bus_call_array() } else { diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 5e409848c..f3e4b389d 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -661,7 +661,6 @@ fn translate_declaration(stmt: Statement, state: &mut State, context: &Context) op_aux_no: 0, } .allocate(); - // TODO: check if this is only used for signals let info = SymbolInfo { access_instruction: instruction, dimensions, @@ -875,6 +874,7 @@ fn check_tag_access(name_signal: &String, access: &Vec, state: &mut Stat let symbol_info = state.environment.get_variable(name_signal).unwrap().clone(); let mut value_tag = None; + // TODO: case tags of buses -> future work if !symbol_info.is_component{ for acc in access { match acc { @@ -1049,6 +1049,7 @@ impl ProcessedSymbol { } ComponentAccess(name) => { // TODO: case buses + let possible_cmp_id = state.component_to_instance.get(&symbol_name).unwrap().clone(); for cmp_id in possible_cmp_id{ let aux = context.tmp_database.wire_info[cmp_id].get(&name).unwrap(); From 4dd86a355d60fc2aa80934a831e975f0461832f9 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 18 Jun 2024 09:44:15 +0200 Subject: [PATCH 100/189] solving minor --- constraint_generation/src/execution_data/executed_template.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index fe0bf4ad7..b4440fef6 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -165,7 +165,7 @@ impl ExecutedTemplate { length: dimensions.to_vec(), is_bus }; - self.inputs.push(wire_info.clone()); + self.intermediates.push(wire_info.clone()); self.ordered_signals.push(wire_info); } From 923b78fa3528b5674999ce44147370342f2847ec Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 21 Jun 2024 10:05:01 +0200 Subject: [PATCH 101/189] new changes --- code_producers/src/c_elements/common/main.cpp | 4 +- .../call_bucket.rs | 8 +- .../load_bucket.rs | 8 +- .../location_rule.rs | 6 +- .../store_bucket.rs | 8 +- .../intermediate_representation/translate.rs | 341 +++++++++++++----- compiler/src/ir_processing/reduce_stack.rs | 4 +- 7 files changed, 275 insertions(+), 104 deletions(-) diff --git a/code_producers/src/c_elements/common/main.cpp b/code_producers/src/c_elements/common/main.cpp index 18d846c91..d63555251 100644 --- a/code_producers/src/c_elements/common/main.cpp +++ b/code_producers/src/c_elements/common/main.cpp @@ -267,13 +267,13 @@ int main (int argc, char *argv[]) { std::cerr << "Not all inputs have been set. Only " << get_main_input_signal_no()-ctx->getRemaingInputsToBeSet() << " out of " << get_main_input_signal_no() << std::endl; assert(false); } - /* + for (uint i = 0; igetWitness(i, &x); std::cout << i << ": " << Fr_element2str(&x) << std::endl; } - */ + //auto t_mid = std::chrono::high_resolution_clock::now(); //std::cout << std::chrono::duration(t_mid-t_start).count()< { + LocationRule::Mapped { signal_code, indexes, offset } => { + // TODO: add the offset match &data.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { @@ -422,8 +423,9 @@ impl WriteC for CallBucket { let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &data.dest { (location.produce_c(producer, parallel), template_header.clone()) - } else if let LocationRule::Mapped { signal_code, indexes } = &data.dest { - let mut map_prologue = vec![]; + } else if let LocationRule::Mapped { signal_code, indexes , offset} = &data.dest { + // TODO: add the offset + let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); let mut map_access = format!("{}->{}[{}].defs[{}].offset", circom_calc_wit(), template_ins_2_io_info(), diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 18001e331..d09f800db 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -93,7 +93,8 @@ impl WriteWasm for LoadBucket { instructions.push(";; end of load bucket".to_string()); } } - LocationRule::Mapped { signal_code, indexes } => { + LocationRule::Mapped { signal_code, indexes , offset} => { + // TODO: ADD THE OFFSET match &self.address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { @@ -191,8 +192,9 @@ impl WriteC for LoadBucket { let (mut src_prologue, src_index) = if let LocationRule::Indexed { location, .. } = &self.src { location.produce_c(producer, parallel) - } else if let LocationRule::Mapped { signal_code, indexes } = &self.src { - let mut map_prologue = vec![]; + } else if let LocationRule::Mapped { signal_code, indexes , offset} = &self.src { + // TODO: add the offset + let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); let mut map_access = format!("{}->{}[{}].defs[{}].offset", circom_calc_wit(), template_ins_2_io_info(), diff --git a/compiler/src/intermediate_representation/location_rule.rs b/compiler/src/intermediate_representation/location_rule.rs index e28e19c1d..b266a70ee 100644 --- a/compiler/src/intermediate_representation/location_rule.rs +++ b/compiler/src/intermediate_representation/location_rule.rs @@ -3,7 +3,7 @@ use super::ir_interface::*; #[derive(Clone)] pub enum LocationRule { Indexed { location: InstructionPointer, template_header: Option }, - Mapped { signal_code: usize, indexes: Vec }, + Mapped { signal_code: usize, indexes: Vec, offset: usize }, } impl ToString for LocationRule { @@ -15,10 +15,10 @@ impl ToString for LocationRule { let header_msg = template_header.as_ref().map_or("NONE".to_string(), |v| v.clone()); format!("INDEXED: ({}, {})", location_msg, header_msg) } - Mapped { signal_code, indexes } => { + Mapped { signal_code, indexes, offset } => { let code_msg = signal_code.to_string(); let index_mgs: Vec = indexes.iter().map(|i| i.to_string()).collect(); - format!("MAPPED: ({}, {:?})", code_msg, index_mgs) + format!("MAPPED: ({}, {:?} {})", code_msg, index_mgs, offset) } } } diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 25111ddf1..41d84f77a 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -101,7 +101,8 @@ impl WriteWasm for StoreBucket { } instructions.push(add32()); } - LocationRule::Mapped { signal_code, indexes } => { + LocationRule::Mapped { signal_code, indexes, offset } => { + // TODO: ADD THE OFFSET match &self.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { @@ -307,8 +308,9 @@ impl WriteC for StoreBucket { let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &self.dest { (location.produce_c(producer, parallel), template_header.clone()) - } else if let LocationRule::Mapped { signal_code, indexes } = &self.dest { - //if Mapped must be SubcmpSignal + } else if let LocationRule::Mapped { signal_code, indexes , offset} = &self.dest { + // TODO: add the offset + //if Mapped must be SubcmpSignal let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); let mut map_access = format!("{}->{}[{}].defs[{}].offset", diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index f3e4b389d..bfc43f072 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -15,13 +15,46 @@ pub type FieldTracker = ConstantTracker; #[derive(Clone)] pub struct FieldInfo{ offset: usize, + lengths: Vec, + size: usize, bus_fields: Option>, } +fn build_field_info(wire: Wire, offset: usize) -> FieldInfo{ + + let lengths = wire.lengths().clone(); + let size = wire.size(); + let mut aux_offset = offset; + let possible_fields = match wire{ + Wire::TSignal(_) =>{ + None + }, + Wire::TBus(b) =>{ + let mut fields = HashMap::new(); + for field in b.wires{ + let size = field.size(); + let name = field.name().clone(); + let info = build_field_info(field, aux_offset); + fields.insert(name, info); + aux_offset += size; + } + Some(fields) + } + }; + FieldInfo{ + bus_fields: possible_fields, + offset, + lengths, + size + } + +} + #[derive(Clone)] pub struct SymbolInfo { access_instruction: InstructionPointer, dimensions: Vec, + size: usize, // needed, in case it is a bus to dont have to compute it again is_component: bool, is_bus: bool, bus_fields: Option>, @@ -37,13 +70,15 @@ pub enum WireInfo{ pub struct SignalInfo{ signal_type: SignalType, lengths: Vec, + size: usize, } #[derive(Clone)] pub struct BusInfo{ signal_type: SignalType, lengths: Vec, - fields: HashMap, + fields: HashMap, + size: usize, } #[derive(Clone)] @@ -82,27 +117,6 @@ impl TemplateDB { fn add_instance(db: &mut TemplateDB, instance: &TemplateInstance) { - fn build_bus_info(xtype: SignalType, lengths: Vec, info_wires: Vec)-> BusInfo{ - let mut fields = HashMap::new(); - for s in info_wires{ - match s{ - Wire::TSignal(signal) =>{ - let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; - fields.insert(signal.name, WireInfo::Signal(info)); - }, - Wire::TBus(bus) =>{ - let info = build_bus_info(bus.xtype, bus.lengths, bus.wires); - fields.insert(bus.name, WireInfo::Bus(info)); - } - } - } - - BusInfo{ - signal_type: xtype, - lengths: lengths, - fields, - } - } if !db.indexes.contains_key(&instance.template_name) { let index = db.signals_id.len(); db.indexes.insert(instance.template_name.clone(), index); @@ -120,15 +134,26 @@ impl TemplateDB { instance.signals_to_tags.clone(), ); let mut wire_info = HashMap::new(); - for wire in instance.wires.clone() { + for wire in &instance.wires { match wire{ Wire::TSignal(signal) =>{ - let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; - wire_info.insert(signal.name, WireInfo::Signal(info)); + let info = SignalInfo{ + size: signal.size(), + signal_type: signal.xtype, + lengths: signal.lengths.clone(), + }; + wire_info.insert(signal.name.clone(), WireInfo::Signal(info)); }, Wire::TBus(bus) =>{ - let info = build_bus_info(bus.xtype, bus.lengths, bus.wires); - wire_info.insert(bus.name, WireInfo::Bus(info)); + let fields = build_field_info(wire.clone(), 0); + + let info = BusInfo{ + size: bus.size(), + signal_type: bus.xtype, + lengths: bus.lengths.clone(), + fields: fields.bus_fields.unwrap() + }; + wire_info.insert(bus.name.clone(), WireInfo::Bus(info)); } } } @@ -232,7 +257,8 @@ fn initialize_parameters(state: &mut State, params: Vec) { access_instruction: address_instruction.clone(), is_component:false, is_bus: false, - bus_fields: None + bus_fields: None, + size: full_size }; state.environment.add_variable(&p.name, symbol_info); } @@ -257,7 +283,8 @@ fn initialize_constants(state: &mut State, constants: Vec) { dimensions, is_component:false, is_bus: false, - bus_fields: None + bus_fields: None, + size }; state.environment.add_variable(&arg.name, symbol_info); let mut index = 0; @@ -304,29 +331,7 @@ fn initialize_constants(state: &mut State, constants: Vec) { } fn initialize_signals(state: &mut State, wires: Vec) { - fn build_field_info(wire: Wire, mut offset: usize) -> FieldInfo{ - - let possible_fields = match wire{ - Wire::TSignal(_) =>{ - None - }, - Wire::TBus(b) =>{ - let mut fields = HashMap::new(); - for field in b.wires{ - offset += field.size(); - let name = field.name().clone(); - let info = build_field_info(field, offset); - fields.insert(name, info); - } - Some(fields) - } - }; - FieldInfo{ - bus_fields: possible_fields, - offset - } - } for wire in wires{ let size = wire.size(); let address = state.reserve_signal(size); @@ -348,7 +353,8 @@ fn initialize_signals(state: &mut State, wires: Vec) { dimensions, is_component:false, is_bus: wire_info.bus_fields.is_some(), - bus_fields: wire_info.bus_fields + bus_fields: wire_info.bus_fields, + size }; state.environment.add_variable(&name, info); state.signal_to_type.insert(name.to_string(), xtype); @@ -374,6 +380,7 @@ fn initialize_components(state: &mut State, components: Vec) { is_component: true, is_bus: false, bus_fields: None, + size }; state.environment.add_variable(&component.name, info); } @@ -667,6 +674,7 @@ fn translate_declaration(stmt: Statement, state: &mut State, context: &Context) is_component: false, is_bus: false, bus_fields: None, + size }; state.environment.add_variable(&name, info); } else { @@ -875,7 +883,7 @@ fn check_tag_access(name_signal: &String, access: &Vec, state: &mut Stat let symbol_info = state.environment.get_variable(name_signal).unwrap().clone(); let mut value_tag = None; // TODO: case tags of buses -> future work - if !symbol_info.is_component{ + if !symbol_info.is_component && !symbol_info.is_bus{ for acc in access { match acc { ArrayAccess(..) => {}, @@ -983,6 +991,9 @@ fn build_signal_location( indexes: Vec, context: &Context, state: &State, + dimensions: Vec, + size: usize, + offset: usize ) -> LocationRule { use ClusterType::*; let database = &context.tmp_database; @@ -991,12 +1002,19 @@ fn build_signal_location( Mixed { tmp_name } => { let signal_code = TemplateDB::get_signal_id(database, tmp_name, signal); let indexes = indexing_instructions_filter(indexes, state); - LocationRule::Mapped { signal_code, indexes } + LocationRule::Mapped { signal_code, indexes, offset } } Uniform { instance_id, header, .. } => { let env = TemplateDB::get_instance_addresses(database, *instance_id); let location = env.get_variable(signal).unwrap().clone(); - let full_address = compute_full_address(state, location, indexes); + let full_address = compute_full_address( + state, + location.access_instruction, + dimensions, + size, + indexes, + offset + ); LocationRule::Indexed { location: full_address, template_header: Some(header.clone()) } } } @@ -1011,6 +1029,8 @@ struct SymbolDef { struct ProcessedSymbol { line: usize, length: usize, + symbol_dimensions: Vec, + symbol_size: usize, message_id: usize, name: String, symbol: SymbolInfo, @@ -1018,6 +1038,7 @@ struct ProcessedSymbol { signal: Option, signal_type: Option, before_signal: Vec, + offset: usize, // in case it is a bus indicate the offset of the field } impl ProcessedSymbol { @@ -1028,12 +1049,24 @@ impl ProcessedSymbol { let symbol_info = state.environment.get_variable(&symbol_name).unwrap().clone(); let mut lengths = symbol_info.dimensions.clone(); lengths.reverse(); - let mut with_length = symbol_info.dimensions.iter().fold(1, |r, c| r * (*c)); + let mut with_length = symbol_info.size; let mut signal = None; let mut signal_type = state.signal_to_type.get(&symbol_name).cloned(); let mut bf_index = vec![]; let mut af_index = vec![]; let mut multiple_possible_lengths: Vec> = vec![]; + let mut is_bus = symbol_info.is_bus; + let mut is_component = symbol_info.is_component; + let mut bus_fields = symbol_info.bus_fields.clone(); + let mut offset = 0; + + let mut symbol_size = symbol_info.size; + let mut symbol_dimensions = symbol_info.dimensions.clone(); + + if symbol_name == "segments"{ + println!("OJO"); + } + for acc in definition.acc { match acc { ArrayAccess(exp) if signal.is_none() => { @@ -1042,31 +1075,77 @@ impl ProcessedSymbol { bf_index.push(translate_expression(exp, state, context)); } ArrayAccess(exp) => { + let mut is_first = true; for possible_length in &mut multiple_possible_lengths{ - possible_length.pop(); + + let aux_length = possible_length.pop(); + if is_first{ + with_length /= aux_length.unwrap(); + is_first = false; + } } + af_index.push(translate_expression(exp, state, context)); } ComponentAccess(name) => { - // TODO: case buses - - let possible_cmp_id = state.component_to_instance.get(&symbol_name).unwrap().clone(); - for cmp_id in possible_cmp_id{ - let aux = context.tmp_database.wire_info[cmp_id].get(&name).unwrap(); - match aux{ - WireInfo::Signal(aux) => { - signal_type = Some(aux.signal_type); - let mut new_length = aux.lengths.clone(); - new_length.reverse(); - multiple_possible_lengths.push(new_length); - } - WireInfo::Bus(aux) =>{ - unreachable!() + if is_component{ + let possible_cmp_id = state.component_to_instance.get(&symbol_name).unwrap().clone(); + let mut is_first = true; + for cmp_id in possible_cmp_id{ + let aux = context.tmp_database.wire_info[cmp_id].get(&name).unwrap(); + match aux{ + WireInfo::Signal(aux) => { + signal_type = Some(aux.signal_type); + let mut new_length = aux.lengths.clone(); + new_length.reverse(); + multiple_possible_lengths.push(new_length); + if is_first{ + with_length = aux.size; + bus_fields = None; + + symbol_size = aux.size; + symbol_dimensions = aux.lengths.clone(); + is_first = false + } + } + WireInfo::Bus(aux) =>{ + signal_type = Some(aux.signal_type); + let mut new_length = aux.lengths.clone(); + new_length.reverse(); + multiple_possible_lengths.push(new_length); + if is_first{ + with_length = aux.size; + symbol_size = aux.size; + symbol_dimensions = aux.lengths.clone(); + + // case buses: update the info + is_bus = true; + bus_fields = Some(aux.fields.clone()); + is_first = false; + } + } } } - + is_component = false; + signal = Some(name); + } else if is_bus{ + let fields = bus_fields.unwrap(); + let field_info = fields.get(&name).unwrap(); + let mut new_length = field_info.lengths.clone(); + new_length.reverse(); + multiple_possible_lengths = vec![new_length.clone()]; + lengths = new_length; + with_length = field_info.size; + + is_bus = field_info.bus_fields.is_some(); + bus_fields = field_info.bus_fields.clone(); + offset = field_info.offset; + symbol_size = field_info.size; + symbol_dimensions = field_info.lengths.clone(); + } else{ + unreachable!() } - signal = Some(name); + } } } @@ -1074,10 +1153,12 @@ impl ProcessedSymbol { let mut is_first = true; for possible_length in multiple_possible_lengths{ if is_first{ - with_length = possible_length.iter().fold(1, |r, c| r * (*c)); + // TODO: does not work in case buses + //with_length = possible_length.iter().fold(1, |r, c| r * (*c)); is_first = false; } else{ + // TODO: case buses -> take into account the size of the elem, possible lengths if with_length != possible_length.iter().fold(1, |r, c| r * (*c)){ unreachable!("On development: Circom compiler does not accept for now the assignment of arrays of unknown sizes during the execution of loops"); } @@ -1085,6 +1166,16 @@ impl ProcessedSymbol { } } + // TODO: improve cases, unnecesary clone + // in case it is a signal of a subcomponent we use the offset when + // building the signal location, if not use late + let (remaining_offset, remaining_size, remaining_dimensions) = if signal.is_some(){ + // they go to the original vector + (0, symbol_info.size, symbol_info.dimensions.clone()) + } else{ + (offset, symbol_size, symbol_dimensions.clone()) + }; + let signal_location = signal.map(|signal_name| { build_signal_location( &signal_name, @@ -1092,18 +1183,26 @@ impl ProcessedSymbol { af_index, context, state, + symbol_dimensions, + symbol_size, + offset ) }); + + ProcessedSymbol { xtype: meta.get_type_knowledge().get_reduces_to(), line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), message_id: state.message_id, length: with_length, + symbol_dimensions: remaining_dimensions, + symbol_size: remaining_size, symbol: symbol_info, name: symbol_name, before_signal: bf_index, signal: signal_location, - signal_type + signal_type, + offset: remaining_offset } } @@ -1115,7 +1214,14 @@ impl ProcessedSymbol { ) -> InstructionPointer { let data = if let Option::Some(signal) = self.signal { let dest_type = AddressType::SubcmpSignal { - cmp_address: compute_full_address(state, self.symbol, self.before_signal), + cmp_address: compute_full_address( + state, + self.symbol.access_instruction, + self.symbol_dimensions, + self.symbol_size, + self.before_signal, + self.offset + ), is_output: self.signal_type.unwrap() == SignalType::Output, uniform_parallel_value: state.component_to_parallel.get(&self.name).unwrap().uniform_parallel_value, input_information : match self.signal_type.unwrap() { @@ -1130,8 +1236,14 @@ impl ProcessedSymbol { dest: signal, } } else { - let address = compute_full_address(state, self.symbol, self.before_signal); - let xtype = match self.xtype { + let address = compute_full_address( + state, + self.symbol.access_instruction, + self.symbol_dimensions, + self.symbol_size, + self.before_signal, + self.offset + ); let xtype = match self.xtype { TypeReduction::Variable => AddressType::Variable, _ => AddressType::Signal, }; @@ -1157,7 +1269,14 @@ impl ProcessedSymbol { fn into_store(self, src: InstructionPointer, state: &State) -> InstructionPointer { if let Option::Some(signal) = self.signal { let dest_type = AddressType::SubcmpSignal { - cmp_address: compute_full_address(state, self.symbol, self.before_signal), + cmp_address: compute_full_address( + state, + self.symbol.access_instruction, + self.symbol_dimensions, + self.symbol_size, + self.before_signal, + self.offset + ), uniform_parallel_value: state.component_to_parallel.get(&self.name).unwrap().uniform_parallel_value, is_output: self.signal_type.unwrap() == SignalType::Output, input_information : match self.signal_type.unwrap() { @@ -1176,7 +1295,14 @@ impl ProcessedSymbol { } .allocate() } else { - let address = compute_full_address(state, self.symbol, self.before_signal); + let address = compute_full_address( + state, + self.symbol.access_instruction, + self.symbol_dimensions, + self.symbol_size, + self.before_signal, + self.offset + ); let xtype = match self.xtype { TypeReduction::Variable => AddressType::Variable, _ => AddressType::Signal, @@ -1197,7 +1323,14 @@ impl ProcessedSymbol { fn into_load(self, state: &State) -> InstructionPointer { if let Option::Some(signal) = self.signal { let dest_type = AddressType::SubcmpSignal { - cmp_address: compute_full_address(state, self.symbol, self.before_signal), + cmp_address: compute_full_address( + state, + self.symbol.access_instruction, + self.symbol_dimensions, + self.symbol_size, + self.before_signal, + self.offset + ), uniform_parallel_value: state.component_to_parallel.get(&self.name).unwrap().uniform_parallel_value, is_output: self.signal_type.unwrap() == SignalType::Output, input_information : match self.signal_type.unwrap() { @@ -1214,7 +1347,14 @@ impl ProcessedSymbol { } .allocate() } else { - let address = compute_full_address(state, self.symbol, self.before_signal); + let address = compute_full_address( + state, + self.symbol.access_instruction, + self.symbol_dimensions, + self.symbol_size, + self.before_signal, + self.offset + ); let xtype = match self.xtype { TypeReduction::Variable => AddressType::Variable, _ => AddressType::Signal, @@ -1233,16 +1373,38 @@ impl ProcessedSymbol { fn compute_full_address( state: &State, - symbol: SymbolInfo, + symbol_access_instr: InstructionPointer, + dimensions: Vec, + size: usize, indexed_with: Vec, + offset: usize, ) -> InstructionPointer { - if symbol.dimensions.is_empty() { - symbol.access_instruction + + let at = symbol_access_instr; + let offset_bucket = ValueBucket { + line: at.get_line(), + message_id: at.get_message_id(), + parse_as: ValueType::U32, + op_aux_no: 0, + value: offset, + }.allocate(); + + if dimensions.is_empty() { + if offset != 0{ + ComputeBucket { + line: at.get_line(), + message_id: at.get_message_id(), + op_aux_no: 0, + op: OperatorType::AddAddress, + stack: vec![at, offset_bucket], + }.allocate() + } else{ + at + } } else { - let at = symbol.access_instruction; - let mut with_dimensions = symbol.dimensions; + let mut with_dimensions = dimensions; with_dimensions.reverse(); - let mut linear_length = with_dimensions.iter().fold(1, |p, c| p * (*c)); + let mut linear_length = size; let index_stack = indexing_instructions_filter(indexed_with, state); let mut stack = vec![]; for instruction in index_stack { @@ -1266,6 +1428,9 @@ fn compute_full_address( .allocate(); stack.push(jump); } + if offset != 0{ + stack.push(offset_bucket); + } stack.push(at); fold(OperatorType::AddAddress, stack, state) } diff --git a/compiler/src/ir_processing/reduce_stack.rs b/compiler/src/ir_processing/reduce_stack.rs index c59bed223..ac239c818 100644 --- a/compiler/src/ir_processing/reduce_stack.rs +++ b/compiler/src/ir_processing/reduce_stack.rs @@ -159,7 +159,7 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { let location = Allocate::allocate(reduce_instruction(*location)); Indexed { location, template_header } } - Mapped { signal_code, indexes } => { + Mapped { signal_code, indexes, offset } => { let no_indexes = InstructionList::len(&indexes); let work = indexes; let mut indexes = InstructionList::with_capacity(no_indexes); @@ -167,7 +167,7 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { let index = Allocate::allocate(reduce_instruction(*index)); InstructionList::push(&mut indexes, index); } - Mapped { signal_code, indexes } + Mapped { signal_code, indexes, offset } } } } From df5ce1d2f0e59d1a663ab77f23374d270b4bef4e Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 25 Jun 2024 14:12:13 +0200 Subject: [PATCH 102/189] Allowing only main'components input buses without tags --- type_analysis/src/analyzers/type_check.rs | 28 ++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 67eebce6b..49313aef8 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1,6 +1,6 @@ use super::type_given_function::type_given_function; use super::type_register::TypeRegister; -use program_structure::ast::*; +use program_structure::{ast::*, bus_data, program_archive}; use program_structure::ast::Expression::Call; use program_structure::environment::CircomEnvironment; use program_structure::error_code::ReportCode; @@ -121,10 +121,15 @@ fn check_main_has_tags(initial_expression: &Expression, program_archive: &Progra if let Call { id, .. } = initial_expression { let inputs = program_archive.get_template_data(id).get_inputs(); let mut tag_in_inputs = false; - for input in inputs { - if !input.1.get_tags().is_empty(){ + for (_name,info) in inputs { + if !info.get_tags().is_empty(){ tag_in_inputs = true; break; + } else if let WireType::Bus(bus_name) = info.get_type() { + if check_bus_contains_tag_recursive(bus_name, program_archive){ + tag_in_inputs = true; + break; + } } } tag_in_inputs @@ -132,6 +137,23 @@ fn check_main_has_tags(initial_expression: &Expression, program_archive: &Progra else { unreachable!()} } +fn check_bus_contains_tag_recursive(bus_name: String, program_archive: &ProgramArchive) -> bool { + let bus_data = program_archive.get_bus_data(&bus_name); + let mut tag_in_inputs = false; + for (_name, info) in bus_data.get_fields() { + if !info.get_tags().is_empty(){ + tag_in_inputs = true; + break; + } else if let WireType::Bus(bus_name) = info.get_type() { + if check_bus_contains_tag_recursive(bus_name, program_archive){ + tag_in_inputs = true; + break; + } + } + } + tag_in_inputs +} + fn type_statement( statement: &Statement, program_archive: &ProgramArchive, From e37bc5314a1f4f883083bc92c4c10cedaaf89ae4 Mon Sep 17 00:00:00 2001 From: miguelis Date: Tue, 25 Jun 2024 15:11:22 +0200 Subject: [PATCH 103/189] Removing a panic, when the number of signals passed to the anonymous component is greater than the number of signals defined by the template --- parser/src/syntax_sugar_remover.rs | 9 ++++----- type_analysis/src/analyzers/type_check.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/parser/src/syntax_sugar_remover.rs b/parser/src/syntax_sugar_remover.rs index bfc28b2da..d6e326579 100644 --- a/parser/src/syntax_sugar_remover.rs +++ b/parser/src/syntax_sugar_remover.rs @@ -502,14 +502,13 @@ pub fn remove_anonymous_from_expression( else{ let inputs = template.unwrap().get_declaration_inputs(); let mut n_expr = 0; + if inputs.len() != signals.len() { + return Result::Err(anonymous_general_error(meta.clone(),"The number of template input signals must coincide with the number of input parameters ".to_string())); + } for value in signals { inputs_to_assignments.insert(inputs[n_expr].0.clone(), (AssignOp::AssignConstraintSignal, value)); n_expr += 1; - } - - if inputs.len() != inputs_to_assignments.len() { - return Result::Err(anonymous_general_error(meta.clone(),"The number of template input signals must coincide with the number of input parameters ".to_string())); - } + } } diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 49313aef8..e62b3c75d 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1,6 +1,6 @@ use super::type_given_function::type_given_function; use super::type_register::TypeRegister; -use program_structure::{ast::*, bus_data, program_archive}; +use program_structure::ast::*; use program_structure::ast::Expression::Call; use program_structure::environment::CircomEnvironment; use program_structure::error_code::ReportCode; From eeef819d74ff7578748e8b2425ed53126fdb6027 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 25 Jun 2024 22:56:00 +0200 Subject: [PATCH 104/189] working on translate and minor in execute --- .../call_bucket.rs | 4 +- .../load_bucket.rs | 4 +- .../location_rule.rs | 6 +- .../store_bucket.rs | 4 +- .../intermediate_representation/translate.rs | 164 ++++++++++-------- compiler/src/ir_processing/reduce_stack.rs | 4 +- .../environment_utils/bus_representation.rs | 12 +- 7 files changed, 113 insertions(+), 85 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index e11ceb87f..7b553022e 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -195,7 +195,7 @@ impl WriteWasm for CallBucket { } instructions.push(add32()); } - LocationRule::Mapped { signal_code, indexes, offset } => { + LocationRule::Mapped { signal_code, indexes } => { // TODO: add the offset match &data.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { @@ -423,7 +423,7 @@ impl WriteC for CallBucket { let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &data.dest { (location.produce_c(producer, parallel), template_header.clone()) - } else if let LocationRule::Mapped { signal_code, indexes , offset} = &data.dest { + } else if let LocationRule::Mapped { signal_code, indexes} = &data.dest { // TODO: add the offset let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index d09f800db..e177c0739 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -93,7 +93,7 @@ impl WriteWasm for LoadBucket { instructions.push(";; end of load bucket".to_string()); } } - LocationRule::Mapped { signal_code, indexes , offset} => { + LocationRule::Mapped { signal_code, indexes} => { // TODO: ADD THE OFFSET match &self.address_type { AddressType::SubcmpSignal { cmp_address, .. } => { @@ -192,7 +192,7 @@ impl WriteC for LoadBucket { let (mut src_prologue, src_index) = if let LocationRule::Indexed { location, .. } = &self.src { location.produce_c(producer, parallel) - } else if let LocationRule::Mapped { signal_code, indexes , offset} = &self.src { + } else if let LocationRule::Mapped { signal_code, indexes } = &self.src { // TODO: add the offset let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); diff --git a/compiler/src/intermediate_representation/location_rule.rs b/compiler/src/intermediate_representation/location_rule.rs index b266a70ee..e28e19c1d 100644 --- a/compiler/src/intermediate_representation/location_rule.rs +++ b/compiler/src/intermediate_representation/location_rule.rs @@ -3,7 +3,7 @@ use super::ir_interface::*; #[derive(Clone)] pub enum LocationRule { Indexed { location: InstructionPointer, template_header: Option }, - Mapped { signal_code: usize, indexes: Vec, offset: usize }, + Mapped { signal_code: usize, indexes: Vec }, } impl ToString for LocationRule { @@ -15,10 +15,10 @@ impl ToString for LocationRule { let header_msg = template_header.as_ref().map_or("NONE".to_string(), |v| v.clone()); format!("INDEXED: ({}, {})", location_msg, header_msg) } - Mapped { signal_code, indexes, offset } => { + Mapped { signal_code, indexes } => { let code_msg = signal_code.to_string(); let index_mgs: Vec = indexes.iter().map(|i| i.to_string()).collect(); - format!("MAPPED: ({}, {:?} {})", code_msg, index_mgs, offset) + format!("MAPPED: ({}, {:?})", code_msg, index_mgs) } } } diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 41d84f77a..5522c9505 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -101,7 +101,7 @@ impl WriteWasm for StoreBucket { } instructions.push(add32()); } - LocationRule::Mapped { signal_code, indexes, offset } => { + LocationRule::Mapped { signal_code, indexes } => { // TODO: ADD THE OFFSET match &self.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { @@ -308,7 +308,7 @@ impl WriteC for StoreBucket { let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &self.dest { (location.produce_c(producer, parallel), template_header.clone()) - } else if let LocationRule::Mapped { signal_code, indexes , offset} = &self.dest { + } else if let LocationRule::Mapped { signal_code, indexes} = &self.dest { // TODO: add the offset //if Mapped must be SubcmpSignal let mut map_prologue = vec![]; diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index bfc43f072..1a57d6159 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -988,12 +988,12 @@ fn bigint_to_cid(field_tracker: &mut FieldTracker, big: &BigInt) -> usize { fn build_signal_location( signal: &str, cmp_name: &str, - indexes: Vec, + indexes: Vec>, context: &Context, state: &State, - dimensions: Vec, - size: usize, - offset: usize + dimensions: Vec>, + size: Vec, + offset: Vec ) -> LocationRule { use ClusterType::*; let database = &context.tmp_database; @@ -1001,8 +1001,10 @@ fn build_signal_location( match cmp_type { Mixed { tmp_name } => { let signal_code = TemplateDB::get_signal_id(database, tmp_name, signal); - let indexes = indexing_instructions_filter(indexes, state); - LocationRule::Mapped { signal_code, indexes, offset } + // TODO: list of indexes and offsets instead of just index + let indexes = indexing_instructions_filter(indexes[0].clone(), state); + + LocationRule::Mapped { signal_code, indexes } } Uniform { instance_id, header, .. } => { let env = TemplateDB::get_instance_addresses(database, *instance_id); @@ -1029,16 +1031,17 @@ struct SymbolDef { struct ProcessedSymbol { line: usize, length: usize, - symbol_dimensions: Vec, - symbol_size: usize, + symbol_dimensions: Vec>, // the dimensions of each one of the buses + symbol_size: Vec, // the sizes of the buses message_id: usize, name: String, symbol: SymbolInfo, xtype: TypeReduction, signal: Option, signal_type: Option, - before_signal: Vec, - offset: usize, // in case it is a bus indicate the offset of the field + before_signal: Vec>, + // in case it is a bus indicate the offset of the field + offset: Vec, } impl ProcessedSymbol { @@ -1050,29 +1053,28 @@ impl ProcessedSymbol { let mut lengths = symbol_info.dimensions.clone(); lengths.reverse(); let mut with_length = symbol_info.size; - let mut signal = None; + let mut accessed_component_signal = None; let mut signal_type = state.signal_to_type.get(&symbol_name).cloned(); - let mut bf_index = vec![]; - let mut af_index = vec![]; + + let mut before_index = vec![]; // indexes accessed before component + let mut after_indexes = vec![]; + let mut current_index = vec![]; // indexes accessed after component (or no component) + let mut multiple_possible_lengths: Vec> = vec![]; let mut is_bus = symbol_info.is_bus; let mut is_component = symbol_info.is_component; let mut bus_fields = symbol_info.bus_fields.clone(); - let mut offset = 0; - let mut symbol_size = symbol_info.size; - let mut symbol_dimensions = symbol_info.dimensions.clone(); - - if symbol_name == "segments"{ - println!("OJO"); - } + let mut offset = Vec::new(); + let mut symbol_size = vec![symbol_info.size]; + let mut symbol_dimensions = vec![symbol_info.dimensions.clone()]; for acc in definition.acc { match acc { - ArrayAccess(exp) if signal.is_none() => { + ArrayAccess(exp) if accessed_component_signal.is_none() => { let length = lengths.pop().unwrap(); with_length /= length; - bf_index.push(translate_expression(exp, state, context)); + current_index.push(translate_expression(exp, state, context)); } ArrayAccess(exp) => { let mut is_first = true; @@ -1085,7 +1087,7 @@ impl ProcessedSymbol { } } - af_index.push(translate_expression(exp, state, context)); + current_index.push(translate_expression(exp, state, context)); } ComponentAccess(name) => { if is_component{ @@ -1103,8 +1105,8 @@ impl ProcessedSymbol { with_length = aux.size; bus_fields = None; - symbol_size = aux.size; - symbol_dimensions = aux.lengths.clone(); + symbol_size = vec![aux.size]; + symbol_dimensions = vec![aux.lengths.clone()]; is_first = false } } @@ -1115,8 +1117,8 @@ impl ProcessedSymbol { multiple_possible_lengths.push(new_length); if is_first{ with_length = aux.size; - symbol_size = aux.size; - symbol_dimensions = aux.lengths.clone(); + symbol_size = vec![aux.size]; + symbol_dimensions = vec![aux.lengths.clone()]; // case buses: update the info is_bus = true; @@ -1126,8 +1128,13 @@ impl ProcessedSymbol { } } } + + // The current indexes are before index + assert!(after_indexes.len() == 0); + before_index = std::mem::take(&mut current_index); + is_component = false; - signal = Some(name); + accessed_component_signal = Some(name); } else if is_bus{ let fields = bus_fields.unwrap(); let field_info = fields.get(&name).unwrap(); @@ -1139,9 +1146,14 @@ impl ProcessedSymbol { is_bus = field_info.bus_fields.is_some(); bus_fields = field_info.bus_fields.clone(); - offset = field_info.offset; - symbol_size = field_info.size; - symbol_dimensions = field_info.lengths.clone(); + + offset.push(field_info.offset); + symbol_size.push(field_info.size); + symbol_dimensions.push(field_info.lengths.clone()); + + // We move the current index into the after_indexes + let aux_index = std::mem::take(&mut current_index); + after_indexes.push(aux_index); } else{ unreachable!() } @@ -1149,7 +1161,12 @@ impl ProcessedSymbol { } } } - if signal.is_some(){ + + // We add the latest indexes into after_indexes + let aux_index = std::mem::take(&mut current_index); + after_indexes.push(aux_index); + + if accessed_component_signal.is_some(){ let mut is_first = true; for possible_length in multiple_possible_lengths{ if is_first{ @@ -1169,18 +1186,28 @@ impl ProcessedSymbol { // TODO: improve cases, unnecesary clone // in case it is a signal of a subcomponent we use the offset when // building the signal location, if not use late - let (remaining_offset, remaining_size, remaining_dimensions) = if signal.is_some(){ + let (remaining_offset, remaining_size, remaining_dimensions, remaining_indexes) = if accessed_component_signal.is_some(){ // they go to the original vector - (0, symbol_info.size, symbol_info.dimensions.clone()) + ( + Vec::new(), + vec![symbol_info.size.clone()], + vec![symbol_info.dimensions.clone()], + vec![before_index] + ) } else{ - (offset, symbol_size, symbol_dimensions.clone()) + ( + offset.clone(), + symbol_size.clone(), + symbol_dimensions.clone(), + after_indexes.clone() + ) }; - let signal_location = signal.map(|signal_name| { + let signal_location = accessed_component_signal.map(|signal_name| { build_signal_location( &signal_name, &symbol_name, - af_index, + after_indexes, context, state, symbol_dimensions, @@ -1199,7 +1226,7 @@ impl ProcessedSymbol { symbol_size: remaining_size, symbol: symbol_info, name: symbol_name, - before_signal: bf_index, + before_signal: remaining_indexes, signal: signal_location, signal_type, offset: remaining_offset @@ -1374,39 +1401,27 @@ impl ProcessedSymbol { fn compute_full_address( state: &State, symbol_access_instr: InstructionPointer, - dimensions: Vec, - size: usize, - indexed_with: Vec, - offset: usize, + dimensions: Vec>, // for each one of the bus accesses one dimensions + size: Vec, // each one of the field sizes + indexed_with: Vec>, // each one of the accesses + offset: Vec, // each one of the field offsets ) -> InstructionPointer { let at = symbol_access_instr; - let offset_bucket = ValueBucket { - line: at.get_line(), - message_id: at.get_message_id(), - parse_as: ValueType::U32, - op_aux_no: 0, - value: offset, - }.allocate(); - - if dimensions.is_empty() { - if offset != 0{ - ComputeBucket { - line: at.get_line(), - message_id: at.get_message_id(), - op_aux_no: 0, - op: OperatorType::AddAddress, - stack: vec![at, offset_bucket], - }.allocate() - } else{ - at - } - } else { - let mut with_dimensions = dimensions; + let mut stack = vec![]; + + + let number_bus_access = offset.len(); + assert!(number_bus_access == dimensions.len() - 1); + assert!(number_bus_access == size.len() - 1); + + let mut index = 0; + + for mut with_dimensions in dimensions{ with_dimensions.reverse(); - let mut linear_length = size; - let index_stack = indexing_instructions_filter(indexed_with, state); - let mut stack = vec![]; + let mut linear_length = size[index]; + // TODO: not needed clone + let index_stack = indexing_instructions_filter(indexed_with[index].clone(), state); for instruction in index_stack { let dimension_length = with_dimensions.pop().unwrap(); linear_length /= dimension_length; @@ -1428,12 +1443,21 @@ fn compute_full_address( .allocate(); stack.push(jump); } - if offset != 0{ + if index != number_bus_access && offset[index] != 0{ + let offset_bucket = ValueBucket { + line: at.get_line(), + message_id: at.get_message_id(), + parse_as: ValueType::U32, + op_aux_no: 0, + value: offset[index], + }.allocate(); stack.push(offset_bucket); } - stack.push(at); - fold(OperatorType::AddAddress, stack, state) + index += 1; } + + stack.push(at); + fold(OperatorType::AddAddress, stack, state) } fn indexing_instructions_filter( diff --git a/compiler/src/ir_processing/reduce_stack.rs b/compiler/src/ir_processing/reduce_stack.rs index ac239c818..c59bed223 100644 --- a/compiler/src/ir_processing/reduce_stack.rs +++ b/compiler/src/ir_processing/reduce_stack.rs @@ -159,7 +159,7 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { let location = Allocate::allocate(reduce_instruction(*location)); Indexed { location, template_header } } - Mapped { signal_code, indexes, offset } => { + Mapped { signal_code, indexes } => { let no_indexes = InstructionList::len(&indexes); let work = indexes; let mut indexes = InstructionList::with_capacity(no_indexes); @@ -167,7 +167,7 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { let index = Allocate::allocate(reduce_instruction(*index)); InstructionList::push(&mut indexes, index); } - Mapped { signal_code, indexes, offset } + Mapped { signal_code, indexes } } } } diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 513f768bc..3383c06c5 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -43,11 +43,12 @@ impl Clone for BusRepresentation { impl BusRepresentation { + pub fn initialize_bus( component: &mut BusRepresentation, node_pointer: NodePointer, scheme: &ExecutedProgram, - is_output_bus: bool + is_initialized: bool, ) -> Result<(), MemoryError> { let possible_node = ExecutedProgram::get_bus_node(scheme, node_pointer); assert!(possible_node.is_some()); @@ -55,12 +56,15 @@ impl BusRepresentation { // if input bus all signals are set initialize to true, else to false + if is_initialized{ + component.has_assignment = true; + } // initialice the signals for info_field in node.fields() { let symbol = &info_field.name; let route = &info_field.length; if !info_field.is_bus{ - let signal_slice = SignalSlice::new_with_route(&route, &is_output_bus); + let signal_slice = SignalSlice::new_with_route(&route, &is_initialized); let signal_slice_size = SignalSlice::get_number_of_cells(&signal_slice); if signal_slice_size > 0{ component.unassigned_fields @@ -76,7 +80,7 @@ impl BusRepresentation { &mut bus_field, bus_node, scheme, - is_output_bus + is_initialized )?; let bus_slice = BusSlice::new_with_route(&route, &bus_field); let bus_slice_size = BusSlice::get_number_of_cells(&bus_slice); @@ -104,7 +108,7 @@ impl BusRepresentation { } else{ component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); } - if is_output_bus{ + if is_initialized{ component.unassigned_fields.remove(symbol); } } From 4531e6510a980cabf72ee2b228bfcca582345f95 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 26 Jun 2024 11:04:54 +0200 Subject: [PATCH 105/189] adding info input buses --- .../src/c_elements/c_code_generator.rs | 4 ++- code_producers/src/c_elements/mod.rs | 2 +- code_producers/src/components/mod.rs | 21 +++++++++++- code_producers/src/wasm_elements/mod.rs | 2 +- .../src/wasm_elements/wasm_code_generator.rs | 4 ++- compiler/src/circuit_design/build.rs | 32 +++++++++++++++++-- compiler/src/hir/very_concrete_program.rs | 1 + 7 files changed, 59 insertions(+), 7 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 2556b539d..7c0596a70 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -653,7 +653,9 @@ pub fn generate_dat_file(dat_file: &mut dyn Write, producer: &CProducer) -> std: //dfile.flush()?; let aux = producer.get_main_input_list(); - let map = generate_hash_map(&aux); + // TODO: change generate_hash_map to new inputlist + //let map = generate_hash_map(&aux); + let map = Vec::new(); let hashmap = generate_dat_from_hash_map(&map); //bytes u64 --> u64 //let hml = 256 as u32; //dfile.write_all(&hml.to_be_bytes())?; diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 47aef5eec..821ed1bbe 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -68,7 +68,7 @@ impl Default for CProducer { prime_str: "bn128".to_string(), number_of_main_outputs: 1, number_of_main_inputs: 2, - main_input_list: [("in1".to_string(), 2, 1), ("in2".to_string(), 3, 1)].to_vec(), //[].to_vec(), + main_input_list: Vec::new(), //[].to_vec(), signals_in_witness: 20, witness_to_signal_list: [ 0, 1, 2, 3, 4, 5, 6, 12, 16, 19, 24, 27, 33, 42, 46, 50, 51, 65, 78, 79, diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index 3c1dcc5cc..a465c1671 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -8,7 +8,26 @@ pub struct IODef { } // It is an array that contains (name, start position, size) -pub type InputList = Vec<(String, usize, usize)>; + +pub struct SignalInfo{ + pub name: String, + pub size: usize, + pub start: usize, +} + +pub struct BusInfo{ + pub name: String, + pub size: usize, + pub start: usize, + pub fields: Vec +} + +pub enum WireInfo{ + Signal(SignalInfo), + Bus(BusInfo) +} + +pub type InputList = Vec; pub type TemplateList = Vec; pub struct InfoParallel{ pub name: String, diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index 57e7e6b54..e98cb525f 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -76,7 +76,7 @@ impl Default for WASMProducer { size_32_shift: 5, number_of_main_outputs: 0, //2, number_of_main_inputs: 0, // 4, - main_input_list: [("in1".to_string(), 1, 1), ("in2".to_string(), 2, 1)].to_vec(), //("inpair".to_string(),2), + main_input_list: Vec::new(), //("inpair".to_string(),2), signals_in_witness: 0, //20, witness_to_signal_list: [].to_vec(), //[0,1,2,3,4,5,6,12,16,19,24,27,33,42,46,50,51,65,78,79].to_vec(), message_list: [].to_vec(), //["Main".to_string(),"Hola Herme".to_string(),"Hola Albert".to_string()].to_vec(), diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index f5440660c..828052348 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -567,7 +567,9 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { producer.get_shared_rw_memory_start() - 8, "\\00\\00\\00\\00\\00\\00\\00\\80" )); - let map = generate_hash_map(&producer.get_main_input_list()); + // TODO: change generate_hash_map to new inputlist + let map = Vec::new(); + //let map = generate_hash_map(&producer.get_main_input_list()); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_input_signals_hashmap_start(), diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 9b06ff979..28cabc444 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -265,10 +265,38 @@ fn initialize_c_producer(vcp: &VCP, database: &TemplateDB, version: &str) -> CPr fn main_input_list(main: &TemplateInstance) -> InputList { use program_structure::ast::SignalType::*; + use crate::hir::very_concrete_program::Wire::*; + fn build_info_wire(wire: &Wire) -> WireInfo{ + match wire{ + TSignal(info) =>{ + WireInfo::Signal( + SignalInfo{ + name: info.name.clone(), + size: info.size(), + start: info.dag_local_id + } + ) + }, + TBus(info) =>{ + let mut info_fields = Vec::new(); + for field in &info.wires{ + info_fields.push(build_info_wire(field)); + } + WireInfo::Bus( + BusInfo{ + name: info.name.clone(), + size: info.size(), + start: info.dag_local_id, + fields: info_fields + } + ) + } + } + } let mut input_list = vec![]; for s in &main.wires { - if s.xtype() == Input { - input_list.push((s.name().clone(), s.dag_local_id(), s.size())); + if s.xtype() == Input { + input_list.push(build_info_wire(s)); } } input_list diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 3003f358d..a6fd50e46 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -24,6 +24,7 @@ impl PartialEq for Argument { } } +// TODO: precompute the size and store #[derive(Clone)] pub enum Wire{ TSignal(Signal), From 5da67f04ac1b0d8362bd74fd3849e462e89b2122 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 26 Jun 2024 16:23:09 +0200 Subject: [PATCH 106/189] adding access in mapped --- .../call_bucket.rs | 13 +++++-- .../ir_interface.rs | 1 + .../load_bucket.rs | 26 +++++++++----- .../location_rule.rs | 24 ++++++++++++- .../store_bucket.rs | 11 ++++-- .../intermediate_representation/translate.rs | 34 +++++++++++++------ compiler/src/ir_processing/build_stack.rs | 18 +++++++++- compiler/src/ir_processing/reduce_stack.rs | 31 ++++++++++++----- compiler/src/ir_processing/set_arena_size.rs | 17 ++++++++-- 9 files changed, 139 insertions(+), 36 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 7b553022e..5ad5bbb6c 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -225,7 +225,11 @@ impl WriteWasm for CallBucket { ))); // get position in component io signal to info list let signal_code_in_bytes = signal_code * 4; //position in the list of the signal code instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is - //now we have first the offset and then the all size dimensions but the last one + + // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED + // descomentar todo lo siguiente, quitado para evitar error + + /* //now we have first the offset and then the all size dimensions but the last one if indexes.len() <= 1 { instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); if indexes.len() == 1 { @@ -260,6 +264,7 @@ impl WriteWasm for CallBucket { instructions.push(mul32()); // We have the total move in bytes instructions.push(add32()); // add to the offset of the signal } + */ instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), @@ -431,7 +436,10 @@ impl WriteC for CallBucket { circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); - if indexes.len()>0 { + // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED + // descomentar todo lo siguiente, quitado para evitar error + /* + if indexes.len()>0 { map_prologue.push(format!("{{")); map_prologue.push(format!("uint map_index_aux[{}];",indexes.len().to_string())); let (mut index_code_0, mut map_index) = indexes[0].produce_c(producer, parallel); @@ -449,6 +457,7 @@ impl WriteC for CallBucket { } map_access = format!("{}+{}",map_access,map_index); } + */ ((map_prologue, map_access),Some(template_id_in_component(sub_component_pos_in_memory.clone()))) } else { assert!(false); diff --git a/compiler/src/intermediate_representation/ir_interface.rs b/compiler/src/intermediate_representation/ir_interface.rs index 5dc9fc33d..4f0c34e28 100644 --- a/compiler/src/intermediate_representation/ir_interface.rs +++ b/compiler/src/intermediate_representation/ir_interface.rs @@ -6,6 +6,7 @@ pub use super::compute_bucket::{ComputeBucket, OperatorType}; pub use super::create_component_bucket::CreateCmpBucket; pub use super::load_bucket::LoadBucket; pub use super::location_rule::LocationRule; +pub use super::location_rule::AccessType; pub use super::log_bucket::LogBucket; pub use super::loop_bucket::LoopBucket; pub use super::return_bucket::ReturnBucket; diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index e177c0739..68f235c44 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -121,7 +121,9 @@ impl WriteWasm for LoadBucket { ))); // get position in component io signal to info list let signal_code_in_bytes = signal_code * 4; //position in the list of the signal code instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is - //now we have first the offset and then the all size dimensions but the last one + // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED + // descomentar todo lo siguiente, quitado para evitar error //now we have first the offset and then the all size dimensions but the last one + /* if indexes.len() <= 1 { instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); if indexes.len() == 1 { @@ -154,6 +156,7 @@ impl WriteWasm for LoadBucket { instructions.push(mul32()); // We have the total move in bytes instructions.push(add32()); // add to the offset of the signal } + */ instructions.push(get_local(producer.get_sub_cmp_load_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), @@ -200,24 +203,29 @@ impl WriteC for LoadBucket { circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); - if indexes.len()>0 { + // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED + // descomentar todo lo siguiente, quitado para evitar error + /* + if indexes.len()>0 { let (mut index_code_0, mut map_index) = indexes[0].produce_c(producer, parallel); map_prologue.append(&mut index_code_0); for i in 1..indexes.len() { - let (mut index_code, index_exp) = indexes[i].produce_c(producer, parallel); - map_prologue.append(&mut index_code); - map_index = format!("({})*{}->{}[{}].defs[{}].lengths[{}]+{}", - map_index, circom_calc_wit(), template_ins_2_io_info(), - template_id_in_component(sub_component_pos_in_memory.clone()), - signal_code.to_string(), (i-1).to_string(),index_exp); + let (mut index_code, index_exp) = indexes[i].produce_c(producer, parallel); + map_prologue.append(&mut index_code); + map_index = format!("({})*{}->{}[{}].defs[{}].lengths[{}]+{}", + map_index, circom_calc_wit(), template_ins_2_io_info(), + template_id_in_component(sub_component_pos_in_memory.clone()), + signal_code.to_string(), (i-1).to_string(),index_exp); } map_access = format!("{}+{}",map_access,map_index); - } + }*/ (map_prologue, map_access) } else { assert!(false); (vec![], "".to_string()) }; + + prologue.append(&mut src_prologue); let access = match &self.address_type { AddressType::Variable => { diff --git a/compiler/src/intermediate_representation/location_rule.rs b/compiler/src/intermediate_representation/location_rule.rs index e28e19c1d..c5c52d035 100644 --- a/compiler/src/intermediate_representation/location_rule.rs +++ b/compiler/src/intermediate_representation/location_rule.rs @@ -1,9 +1,31 @@ use super::ir_interface::*; +#[derive(Clone)] +pub enum AccessType{ + Indexed(Vec), // Case accessing an array + Qualified(usize), // Case accessing a field -> id field +} + +impl ToString for AccessType { + fn to_string(&self) -> String { + match &self{ + AccessType::Indexed(index) =>{ + index.iter().map(|i| i.to_string()).collect() + } + AccessType::Qualified(value) =>{ + format!("field({})", value) + } + } + } +} + +// Example: accessing a[2][3].b[2].c +// [Indexed([2, 3]), Qualified(id_b), Indexed([2]), Qualified(id_c)] + #[derive(Clone)] pub enum LocationRule { Indexed { location: InstructionPointer, template_header: Option }, - Mapped { signal_code: usize, indexes: Vec }, + Mapped { signal_code: usize, indexes: Vec }, } impl ToString for LocationRule { diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 5522c9505..c9901d4c8 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -130,6 +130,9 @@ impl WriteWasm for StoreBucket { let signal_code_in_bytes = signal_code * 4; //position in the list of the signal code instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one + // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED + // descomentar todo lo siguiente, quitado para evitar error + /* if indexes.len() <= 1 { instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); if indexes.len() == 1 { @@ -162,6 +165,7 @@ impl WriteWasm for StoreBucket { instructions.push(mul32()); // We have the total move in bytes instructions.push(add32()); // add to the offset of the signal } + */ instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), @@ -317,7 +321,10 @@ impl WriteC for StoreBucket { circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); - if indexes.len()>0 { + // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED + // descomentar todo lo siguiente, quitado para evitar error + /* + if indexes.len()>0 { map_prologue.push(format!("{{")); map_prologue.push(format!("uint map_index_aux[{}];",indexes.len().to_string())); let (mut index_code_0, mut map_index) = indexes[0].produce_c(producer, parallel); @@ -334,7 +341,7 @@ impl WriteC for StoreBucket { signal_code.to_string(),(i-1).to_string(),i.to_string()); } map_access = format!("{}+{}",map_access,map_index); - } + }*/ ((map_prologue, map_access),Some(template_id_in_component(sub_component_pos_in_memory.clone()))) } else { assert!(false); diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 1a57d6159..3fc413a54 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -18,9 +18,10 @@ pub struct FieldInfo{ lengths: Vec, size: usize, bus_fields: Option>, + field_id: usize } -fn build_field_info(wire: Wire, offset: usize) -> FieldInfo{ +fn build_field_info(wire: Wire, offset: usize, field_id: usize) -> FieldInfo{ let lengths = wire.lengths().clone(); let size = wire.size(); @@ -31,12 +32,14 @@ fn build_field_info(wire: Wire, offset: usize) -> FieldInfo{ }, Wire::TBus(b) =>{ let mut fields = HashMap::new(); + let mut aux_id = 0; for field in b.wires{ let size = field.size(); let name = field.name().clone(); - let info = build_field_info(field, aux_offset); + let info = build_field_info(field, aux_offset, aux_id); fields.insert(name, info); aux_offset += size; + aux_id += 1; } Some(fields) } @@ -45,7 +48,8 @@ fn build_field_info(wire: Wire, offset: usize) -> FieldInfo{ bus_fields: possible_fields, offset, lengths, - size + size, + field_id } } @@ -145,7 +149,7 @@ impl TemplateDB { wire_info.insert(signal.name.clone(), WireInfo::Signal(info)); }, Wire::TBus(bus) =>{ - let fields = build_field_info(wire.clone(), 0); + let fields = build_field_info(wire.clone(), 0, 0); let info = BusInfo{ size: bus.size(), @@ -339,7 +343,7 @@ fn initialize_signals(state: &mut State, wires: Vec) { let name = wire.name().clone(); let xtype = wire.xtype(); - let wire_info = build_field_info(wire, 0); + let wire_info = build_field_info(wire, 0, 0); let instruction = ValueBucket { line: 0, message_id: state.message_id, @@ -993,7 +997,8 @@ fn build_signal_location( state: &State, dimensions: Vec>, size: Vec, - offset: Vec + offset: Vec, + field_ids: Vec ) -> LocationRule { use ClusterType::*; let database = &context.tmp_database; @@ -1001,10 +1006,16 @@ fn build_signal_location( match cmp_type { Mixed { tmp_name } => { let signal_code = TemplateDB::get_signal_id(database, tmp_name, signal); - // TODO: list of indexes and offsets instead of just index - let indexes = indexing_instructions_filter(indexes[0].clone(), state); - LocationRule::Mapped { signal_code, indexes } + let mut accesses = Vec::new(); + let mut i = 0; + for indexes in indexes{ + let filtered = indexing_instructions_filter(indexes, state); + accesses.push(AccessType::Indexed(filtered)); + accesses.push(AccessType::Qualified(field_ids[i])); + i+=1; + } + LocationRule::Mapped { signal_code, indexes: accesses } } Uniform { instance_id, header, .. } => { let env = TemplateDB::get_instance_addresses(database, *instance_id); @@ -1066,6 +1077,7 @@ impl ProcessedSymbol { let mut bus_fields = symbol_info.bus_fields.clone(); let mut offset = Vec::new(); + let mut field_ids = Vec::new(); let mut symbol_size = vec![symbol_info.size]; let mut symbol_dimensions = vec![symbol_info.dimensions.clone()]; @@ -1148,6 +1160,7 @@ impl ProcessedSymbol { bus_fields = field_info.bus_fields.clone(); offset.push(field_info.offset); + field_ids.push(field_info.field_id); symbol_size.push(field_info.size); symbol_dimensions.push(field_info.lengths.clone()); @@ -1212,7 +1225,8 @@ impl ProcessedSymbol { state, symbol_dimensions, symbol_size, - offset + offset, + field_ids ) }); diff --git a/compiler/src/ir_processing/build_stack.rs b/compiler/src/ir_processing/build_stack.rs index f17b30e64..ee6fc1ab5 100644 --- a/compiler/src/ir_processing/build_stack.rs +++ b/compiler/src/ir_processing/build_stack.rs @@ -127,7 +127,23 @@ pub fn build_location(bucket: &mut LocationRule, fresh: usize) -> usize { use LocationRule::*; match bucket { Indexed { location, .. } => build_instruction(location, fresh), - Mapped { indexes, .. } => build_list(indexes, fresh), + Mapped { indexes, .. } => { + let mut max_depth = 0; + for acc in indexes{ + match acc{ + AccessType::Indexed(ind) =>{ + let depth = build_list(ind, fresh); + max_depth = std::cmp::max(max_depth, depth); + }, + AccessType::Qualified(_) =>{ + + } + } + + } + max_depth + } + } } diff --git a/compiler/src/ir_processing/reduce_stack.rs b/compiler/src/ir_processing/reduce_stack.rs index c59bed223..edc4ce2d2 100644 --- a/compiler/src/ir_processing/reduce_stack.rs +++ b/compiler/src/ir_processing/reduce_stack.rs @@ -159,15 +159,30 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { let location = Allocate::allocate(reduce_instruction(*location)); Indexed { location, template_header } } - Mapped { signal_code, indexes } => { - let no_indexes = InstructionList::len(&indexes); - let work = indexes; - let mut indexes = InstructionList::with_capacity(no_indexes); - for index in work { - let index = Allocate::allocate(reduce_instruction(*index)); - InstructionList::push(&mut indexes, index); + Mapped { signal_code, indexes: accesses } => { + let no_accesses = accesses.len(); + let work_accesses = accesses; + let mut accesses = Vec::with_capacity(no_accesses); + for acc in work_accesses{ + match acc{ + AccessType::Indexed(indexes) =>{ + let no_indexes = InstructionList::len(&indexes); + let work = indexes; + let mut indexes = InstructionList::with_capacity(no_indexes); + for index in work { + let index = Allocate::allocate(reduce_instruction(*index)); + InstructionList::push(&mut indexes, index); + } + accesses.push(AccessType::Indexed(indexes)); + } + AccessType::Qualified(pos) =>{ + accesses.push(acc); + + } + } } - Mapped { signal_code, indexes } + + Mapped { signal_code, indexes: accesses } } } } diff --git a/compiler/src/ir_processing/set_arena_size.rs b/compiler/src/ir_processing/set_arena_size.rs index 8d772b8e0..6c4a2ad99 100644 --- a/compiler/src/ir_processing/set_arena_size.rs +++ b/compiler/src/ir_processing/set_arena_size.rs @@ -98,10 +98,21 @@ pub fn visit_store(bucket: &mut StoreBucket, function_to_arena_size: &HashMap) {} pub fn visit_location(bucket: &mut LocationRule, function_to_arena_size: &HashMap) { - use LocationRule::*; + match bucket { - Indexed { location, .. } => visit_instruction(location, function_to_arena_size), - Mapped { indexes, .. } => visit_list(indexes, function_to_arena_size), + LocationRule::Indexed { location, .. } => visit_instruction(location, function_to_arena_size), + LocationRule::Mapped { indexes, .. } => { + for access in indexes{ + match access{ + AccessType::Indexed(instr) =>{ + visit_list(instr, function_to_arena_size) + }, + AccessType::Qualified(_) =>{ + + } + } + } + } } } From cb95b8d4f352a4f1c661f3fdbf4459231537ce9d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 26 Jun 2024 20:24:54 +0200 Subject: [PATCH 107/189] refractoring: storing info of the buses in a single table --- code_producers/src/components/mod.rs | 2 +- compiler/src/circuit_design/build.rs | 15 +-- compiler/src/hir/analysis_utilities.rs | 34 +++--- compiler/src/hir/merger.rs | 10 +- compiler/src/hir/very_concrete_program.rs | 60 ++++++----- .../intermediate_representation/translate.rs | 101 +++++++----------- .../src/execution_data/executed_bus.rs | 86 ++++++++++----- .../src/execution_data/executed_program.rs | 16 ++- .../src/execution_data/executed_template.rs | 98 ++++++++++++----- 9 files changed, 252 insertions(+), 170 deletions(-) diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index a465c1671..a3e374ff7 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -19,7 +19,7 @@ pub struct BusInfo{ pub name: String, pub size: usize, pub start: usize, - pub fields: Vec + pub bus_id: usize } pub enum WireInfo{ diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 28cabc444..11929b78f 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -93,6 +93,7 @@ fn build_template_instances( triggers: template.triggers, clusters: template.clusters, functions: &c_info.functions, + buses: &c_info.buses, fresh_cmp_id: cmp_id, components: template.components, template_database: &c_info.template_database, @@ -162,6 +163,7 @@ fn build_function_instances( template_database: &c_info.template_database, string_table : string_table, signals_to_tags: BTreeMap::new(), + buses: &c_info.buses }; let mut function_info = FunctionCodeInfo { name, @@ -272,22 +274,19 @@ fn main_input_list(main: &TemplateInstance) -> InputList { WireInfo::Signal( SignalInfo{ name: info.name.clone(), - size: info.size(), + size: info.size, start: info.dag_local_id } ) }, TBus(info) =>{ - let mut info_fields = Vec::new(); - for field in &info.wires{ - info_fields.push(build_info_wire(field)); - } + WireInfo::Bus( BusInfo{ name: info.name.clone(), - size: info.size(), + size: info.size, start: info.dag_local_id, - fields: info_fields + bus_id: info.bus_id } ) } @@ -385,6 +384,7 @@ struct CircuitInfo { file_library: FileLibrary, functions: HashMap>, template_database: TemplateDB, + buses: Vec } pub fn build_circuit(vcp: VCP, flag: CompilationFlags, version: &str) -> Circuit { @@ -402,6 +402,7 @@ pub fn build_circuit(vcp: VCP, flag: CompilationFlags, version: &str) -> Circuit template_database, file_library: vcp.file_library, functions: vcp.quick_knowledge, + buses: vcp.buses }; let (field_tracker, string_table) = diff --git a/compiler/src/hir/analysis_utilities.rs b/compiler/src/hir/analysis_utilities.rs index 1f33a0b78..dc9f877f3 100644 --- a/compiler/src/hir/analysis_utilities.rs +++ b/compiler/src/hir/analysis_utilities.rs @@ -52,7 +52,7 @@ pub fn build_function_knowledge(program: ProgramArchive) -> State { } } -pub fn build_component_info(triggers: &Vec) -> +pub fn build_component_info(triggers: &Vec, buses_table: &Vec) -> HashMap, HashMap)> { let mut external_signals = HashMap::new(); for trigger in triggers { @@ -64,7 +64,7 @@ pub fn build_component_info(triggers: &Vec) -> signals.insert(s.name.clone(), s.lengths.clone()); }, Wire::TBus(s) =>{ - buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); + buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s.bus_id, buses_table))); } } } @@ -81,34 +81,38 @@ pub fn build_component_info(triggers: &Vec) -> external_signals } -pub fn build_buses_info(wires: &Vec) -> HashMap{ +pub fn build_buses_info(wires: &Vec, buses_table: &Vec) -> HashMap{ let mut info_buses = HashMap::new(); for s in wires{ if let Wire::TBus(bus) = s{ - info_buses.insert(bus.name.clone(), build_single_bus_info(bus)); + info_buses.insert(bus.name.clone(), build_single_bus_info(bus.bus_id, buses_table)); } } info_buses } -fn build_single_bus_info(bus: &Bus) -> InfoBus{ - let size = bus.size(); +fn build_single_bus_info(bus_id: usize, buses_table: &Vec) -> InfoBus{ + let bus_instance = buses_table.get(bus_id).unwrap(); let mut signals = HashMap::new(); let mut buses = HashMap::new(); - for s in &bus.wires{ - match s{ - Wire::TSignal(s) =>{ - signals.insert(s.name.clone(), s.lengths.clone()); - } - Wire::TBus(s) =>{ - buses.insert(s.name.clone(), (s.lengths.clone(), build_single_bus_info(s))); - } + for (name,s) in &bus_instance.fields{ + if s.bus_id.is_none(){ // case signal + signals.insert( + name.clone(), + s.dimensions.clone() + ); + } else{ + let bus_id = s.bus_id.unwrap(); + buses.insert( + name.clone(), + (s.dimensions.clone(), build_single_bus_info(bus_id, buses_table)) + ); } } - InfoBus{size, signals, buses} + InfoBus{size: bus_instance.size, signals, buses} } fn max_vct(l: HashMap, mut r: HashMap) -> HashMap { diff --git a/compiler/src/hir/merger.rs b/compiler/src/hir/merger.rs index 98a8c4545..8ddf322a9 100644 --- a/compiler/src/hir/merger.rs +++ b/compiler/src/hir/merger.rs @@ -22,14 +22,14 @@ fn produce_vcf(vcp: &VCP, state: &mut State) { let code = &n.code; let constants = &n.header; let params = vec![]; - state.external_signals = build_component_info(&n.triggers); - state.buses_info = build_buses_info(&n.wires); + state.external_signals = build_component_info(&n.triggers, &vcp.buses); + state.buses_info = build_buses_info(&n.wires, &vcp.buses); let mut env = build_environment(constants, ¶ms); produce_vcf_stmt(code, state, &mut env); } let mut index = 0; while index < state.vcf_collector.len() { - state.external_signals = build_component_info(&vec![]); + state.external_signals = build_component_info(&vec![], &vcp.buses); let mut env = build_environment(&vec![], &state.vcf_collector[index].params_types); let body = state.vcf_collector[index].body.clone(); produce_vcf_stmt(&body, state, &mut env); @@ -40,8 +40,8 @@ fn produce_vcf(vcp: &VCP, state: &mut State) { fn link_circuit(vcp: &mut VCP, state: &mut State) { for node in &mut vcp.templates { let mut env = build_environment(&node.header, &vec![]); - state.external_signals = build_component_info(&node.triggers); - state.buses_info = build_buses_info(&node.wires); + state.external_signals = build_component_info(&node.triggers, &vcp.buses); + state.buses_info = build_buses_info(&node.wires, &vcp.buses); link_stmt(&mut node.code, state, &mut env); } let mut linked_vcf_collector = state.vcf_collector.clone(); diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index a6fd50e46..146e04487 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -31,16 +31,7 @@ pub enum Wire{ TBus(Bus) } impl Wire { - pub fn size(&self) -> usize { - match self{ - Wire::TSignal(s) => { - s.size() - }, - Wire::TBus(s) => { - s.size() - }, - } - } + pub fn xtype(&self) -> SignalType { match self{ Wire::TSignal(s) => { @@ -91,6 +82,16 @@ impl Wire { }, } } + pub fn size(&self) -> usize { + match self{ + Wire::TSignal(s) => { + s.size + }, + Wire::TBus(s) => { + s.size + }, + } + } } #[derive(Clone)] @@ -100,31 +101,37 @@ pub struct Signal { pub xtype: SignalType, pub local_id: usize, pub dag_local_id: usize, + pub size: usize, } -impl Signal { - pub fn size(&self) -> usize { - self.lengths.iter().fold(1, |p, c| p * (*c)) - } -} #[derive(Clone)] pub struct Bus{ pub name: String, pub lengths: Vec, pub xtype: SignalType, - pub wires: Vec, pub local_id: usize, pub dag_local_id: usize, + pub bus_id: usize, // position of the bus in the table of the buses + pub size: usize, } -impl Bus{ - pub fn size(&self) -> usize{ - let mut total_size = 0; - for wire in &self.wires{ - total_size += wire.size(); - } - self.lengths.iter().fold(total_size, |p, c| p * (*c)) - } + +#[derive(Clone)] +pub struct FieldInfo{ + pub field_id: usize, + pub offset: usize, + pub dimensions: Vec, + pub size: usize, + pub bus_id: Option, // indicates the position of the bus in the table +} + + + +#[derive(Clone)] +pub struct BusInstance{ + pub name: String, + pub size: usize, + pub fields: HashMap, } #[derive(Clone)] @@ -276,6 +283,8 @@ pub struct VCPConfig { pub templates_in_mixed: Vec, pub program: ProgramArchive, pub prime: String, + pub buses: Vec, + } #[derive(Clone)] @@ -289,6 +298,8 @@ pub struct VCP { pub quick_knowledge: HashMap, pub templates_in_mixed: Vec, pub prime: String, + pub buses: Vec, + } impl VCP { pub fn new(config: VCPConfig) -> VCP { @@ -302,6 +313,7 @@ impl VCP { functions: vec![], quick_knowledge: HashMap::new(), prime: config.prime, + buses: config.buses }; super::merger::run_preprocessing(&mut vcp, config.program); vcp diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 3fc413a54..f7d912927 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -12,47 +12,6 @@ type Length = usize; pub type E = VarEnvironment; pub type FieldTracker = ConstantTracker; -#[derive(Clone)] -pub struct FieldInfo{ - offset: usize, - lengths: Vec, - size: usize, - bus_fields: Option>, - field_id: usize -} - -fn build_field_info(wire: Wire, offset: usize, field_id: usize) -> FieldInfo{ - - let lengths = wire.lengths().clone(); - let size = wire.size(); - let mut aux_offset = offset; - let possible_fields = match wire{ - Wire::TSignal(_) =>{ - None - }, - Wire::TBus(b) =>{ - let mut fields = HashMap::new(); - let mut aux_id = 0; - for field in b.wires{ - let size = field.size(); - let name = field.name().clone(); - let info = build_field_info(field, aux_offset, aux_id); - fields.insert(name, info); - aux_offset += size; - aux_id += 1; - } - Some(fields) - } - }; - FieldInfo{ - bus_fields: possible_fields, - offset, - lengths, - size, - field_id - } - -} #[derive(Clone)] pub struct SymbolInfo { @@ -61,7 +20,7 @@ pub struct SymbolInfo { size: usize, // needed, in case it is a bus to dont have to compute it again is_component: bool, is_bus: bool, - bus_fields: Option>, + bus_id: Option, } #[derive(Clone)] @@ -81,7 +40,7 @@ pub struct SignalInfo{ pub struct BusInfo{ signal_type: SignalType, lengths: Vec, - fields: HashMap, + bus_id: usize, size: usize, } @@ -142,20 +101,19 @@ impl TemplateDB { match wire{ Wire::TSignal(signal) =>{ let info = SignalInfo{ - size: signal.size(), + size: signal.size, signal_type: signal.xtype, lengths: signal.lengths.clone(), }; wire_info.insert(signal.name.clone(), WireInfo::Signal(info)); }, Wire::TBus(bus) =>{ - let fields = build_field_info(wire.clone(), 0, 0); let info = BusInfo{ - size: bus.size(), + size: bus.size, signal_type: bus.xtype, lengths: bus.lengths.clone(), - fields: fields.bus_fields.unwrap() + bus_id: bus.bus_id }; wire_info.insert(bus.name.clone(), WireInfo::Bus(info)); } @@ -240,6 +198,7 @@ struct Context<'a> { tmp_database: &'a TemplateDB, functions: &'a HashMap>, cmp_to_type: HashMap, + buses: &'a Vec } fn initialize_parameters(state: &mut State, params: Vec) { @@ -261,7 +220,7 @@ fn initialize_parameters(state: &mut State, params: Vec) { access_instruction: address_instruction.clone(), is_component:false, is_bus: false, - bus_fields: None, + bus_id: None, size: full_size }; state.environment.add_variable(&p.name, symbol_info); @@ -287,7 +246,7 @@ fn initialize_constants(state: &mut State, constants: Vec) { dimensions, is_component:false, is_bus: false, - bus_fields: None, + bus_id: None, size }; state.environment.add_variable(&arg.name, symbol_info); @@ -343,7 +302,15 @@ fn initialize_signals(state: &mut State, wires: Vec) { let name = wire.name().clone(); let xtype = wire.xtype(); - let wire_info = build_field_info(wire, 0, 0); + let (is_bus, bus_id) = match wire{ + Wire::TBus(bus) =>{ + (true, Some(bus.bus_id)) + }, + Wire::TSignal(_) =>{ + (false, None) + } + }; + let instruction = ValueBucket { line: 0, message_id: state.message_id, @@ -356,8 +323,8 @@ fn initialize_signals(state: &mut State, wires: Vec) { access_instruction: instruction, dimensions, is_component:false, - is_bus: wire_info.bus_fields.is_some(), - bus_fields: wire_info.bus_fields, + is_bus, + bus_id, size }; state.environment.add_variable(&name, info); @@ -383,7 +350,7 @@ fn initialize_components(state: &mut State, components: Vec) { dimensions: component.lengths, is_component: true, is_bus: false, - bus_fields: None, + bus_id: None, size }; state.environment.add_variable(&component.name, info); @@ -677,7 +644,7 @@ fn translate_declaration(stmt: Statement, state: &mut State, context: &Context) dimensions, is_component: false, is_bus: false, - bus_fields: None, + bus_id: None, size }; state.environment.add_variable(&name, info); @@ -1074,7 +1041,13 @@ impl ProcessedSymbol { let mut multiple_possible_lengths: Vec> = vec![]; let mut is_bus = symbol_info.is_bus; let mut is_component = symbol_info.is_component; - let mut bus_fields = symbol_info.bus_fields.clone(); + + let mut bus_fields = if symbol_info.bus_id.is_some(){ + let id = symbol_info.bus_id.unwrap(); + Some(context.buses.get(id).unwrap().fields.clone()) + } else{ + None + }; let mut offset = Vec::new(); let mut field_ids = Vec::new(); @@ -1134,7 +1107,8 @@ impl ProcessedSymbol { // case buses: update the info is_bus = true; - bus_fields = Some(aux.fields.clone()); + + bus_fields = Some(context.buses.get(aux.bus_id).unwrap().fields.clone()); is_first = false; } } @@ -1150,19 +1124,24 @@ impl ProcessedSymbol { } else if is_bus{ let fields = bus_fields.unwrap(); let field_info = fields.get(&name).unwrap(); - let mut new_length = field_info.lengths.clone(); + let mut new_length = field_info.dimensions.clone(); new_length.reverse(); multiple_possible_lengths = vec![new_length.clone()]; lengths = new_length; with_length = field_info.size; - is_bus = field_info.bus_fields.is_some(); - bus_fields = field_info.bus_fields.clone(); + is_bus = field_info.bus_id.is_some(); + bus_fields = if field_info.bus_id.is_some(){ + let id = field_info.bus_id.unwrap(); + Some(context.buses.get(id).unwrap().fields.clone()) + } else{ + None + }; offset.push(field_info.offset); field_ids.push(field_info.field_id); symbol_size.push(field_info.size); - symbol_dimensions.push(field_info.lengths.clone()); + symbol_dimensions.push(field_info.dimensions.clone()); // We move the current index into the after_indexes let aux_index = std::mem::take(&mut current_index); @@ -1696,6 +1675,7 @@ pub struct CodeInfo<'a> { pub component_to_parallel: HashMap, pub string_table: HashMap, pub signals_to_tags: BTreeMap, + pub buses: &'a Vec } pub struct CodeOutput { @@ -1729,6 +1709,7 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { functions: code_info.functions, cmp_to_type: code_info.cmp_to_type, tmp_database: code_info.template_database, + buses: code_info.buses }; create_components(&mut state, &code_info.triggers, code_info.clusters); diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index 5b8626400..a4649998e 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -4,7 +4,6 @@ use num_bigint::BigInt; use std::collections::HashMap; use crate::execution_data::TagInfo; use compiler::hir::very_concrete_program::*; -use crate::ast::SignalType; @@ -24,6 +23,7 @@ pub struct ExecutedBus { pub signal_to_tags: TagContext, pub bus_connexions: HashMap, pub size: usize, + pub bus_id: Option, } impl ExecutedBus { @@ -40,6 +40,7 @@ impl ExecutedBus { signal_to_tags: TagContext::new(), bus_connexions: HashMap::new(), size: 0, + bus_id: None, } } @@ -117,37 +118,66 @@ impl ExecutedBus { &self.bus_connexions } - // TODO: use same category for the bus and signal - pub fn build_bus( + pub fn build_bus_info( &self, - name: String, - lengths: Vec, - local_id: usize, - dag_local_id: usize, - xtype: SignalType, + bus_id: usize, + bus_table: &mut Vec>, buses_info: &Vec - ) -> Bus{ - let mut local_id_aux = local_id; - let mut dag_local_id_aux = dag_local_id; - let mut wires = Vec::new(); - - for info_field in &self.fields{ - let (name, lengths) = (&info_field.name, &info_field.length); - if !info_field.is_bus{ - let signal = Signal { name: name.clone(), lengths: lengths.clone(), local_id: local_id_aux, dag_local_id: dag_local_id_aux, xtype}; - local_id_aux += signal.size(); - dag_local_id_aux += signal.size(); - wires.push(Wire::TSignal(signal)); - } else{ - let bus_node = self.bus_connexions.get(name).unwrap().inspect.goes_to; - let exe_bus = buses_info.get(bus_node).unwrap(); - let bus = exe_bus.build_bus(name.clone(), lengths.clone(), local_id_aux, dag_local_id_aux, xtype, buses_info); - local_id_aux += bus.size(); - dag_local_id_aux += bus.size(); - wires.push(Wire::TBus(bus)); + ){ + if bus_table[bus_id].is_none(){ + let mut total_size = 0; + let mut offset = 0; + let mut wires = HashMap::new(); + let mut field_id = 0; + for info_field in &self.fields{ + let (name, lengths) = (&info_field.name, &info_field.length); + if !info_field.is_bus{ + // Case signal + let size = lengths.iter().fold(1, |p, c| p * (*c)); + let signal = FieldInfo { + field_id, + dimensions: lengths.clone(), + size, + offset, + bus_id: None + }; + wires.insert(name.clone(), signal); + total_size += size; + offset += size; + field_id += 1; + + } else{ + let bus_node = self.bus_connexions.get(name).unwrap().inspect.goes_to; + if bus_table[bus_node].is_none(){ + let exe_bus = buses_info.get(bus_node).unwrap(); + exe_bus.build_bus_info(bus_node, bus_table, buses_info); + } + let bus_instance = bus_table.get(bus_node).unwrap().as_ref().unwrap(); + + let size = lengths.iter().fold(bus_instance.size, |p, c| p * (*c)); + let bus = FieldInfo { + field_id, + dimensions: lengths.clone(), + size, + offset, + bus_id: Some(bus_node) + }; + wires.insert(name.clone(), bus); + total_size += size; + offset += size; + field_id += 1; + + } } + bus_table[bus_id] = Some( + BusInstance{ + name: self.bus_name.clone(), + size: total_size, + fields: wires + } + ) + } - Bus{name, lengths, xtype, local_id, dag_local_id, wires} } diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index f24fe0530..f9ed7059a 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -179,8 +179,21 @@ impl ExecutedProgram { exe.insert_in_dag(&mut dag, &self.model_buses); } + let mut wrapped_buses_table = vec![None; self.model_buses.len()]; + let mut index = 0; + for exe_bus in &self.model_buses{ + exe_bus.build_bus_info(index, &mut wrapped_buses_table, &self.model_buses); + index += 1; + } + + let mut buses_table = Vec::new(); + for info in wrapped_buses_table{ + buses_table.push(info.unwrap()); + } + + for exe in self.model { - let tmp_instance = exe.export_to_circuit(&mut temp_instances, &self.model_buses); + let tmp_instance = exe.export_to_circuit(&mut temp_instances, &buses_table); temp_instances.push(tmp_instance); } @@ -210,6 +223,7 @@ impl ExecutedProgram { templates_in_mixed: mixed, program, prime: self.prime, + buses: buses_table }; let vcp = VCP::new(config); Result::Ok((dag, vcp, warnings)) diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index b4440fef6..24d1cfb07 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -334,7 +334,7 @@ impl ExecutedTemplate { } } - pub fn export_to_circuit(self, instances: &mut [TemplateInstance], buses_info : &Vec) -> TemplateInstance { + pub fn export_to_circuit(self, instances: &mut [TemplateInstance], buses_info : &Vec) -> TemplateInstance { use SignalType::*; fn build_triggers( instances: &mut [TemplateInstance], @@ -415,15 +415,25 @@ impl ExecutedTemplate { for s in self.outputs { if s.is_bus{ let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; - let exe_bus = buses_info.get(bus_node).unwrap(); - let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Output, buses_info); - local_id += bus.size(); - dag_local_id += bus.size(); + let info_bus = buses_info.get(bus_node).unwrap(); + let size = s.length.iter().fold(info_bus.size, |p, c| p * (*c)); + let bus = Bus{ + name: s.name, + lengths: s.length, + local_id, + dag_local_id, + bus_id: bus_node, + size, + xtype: Output, + }; + local_id += bus.size; + dag_local_id += bus.size; instance.add_signal(Wire::TBus(bus)); } else{ - let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Output}; - local_id += signal.size(); - dag_local_id += signal.size(); + let size = s.length.iter().fold(1, |p, c| p * (*c)); + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Output, size}; + local_id += signal.size; + dag_local_id += signal.size; instance.add_signal(Wire::TSignal(signal)); } } @@ -431,45 +441,75 @@ impl ExecutedTemplate { for s in public { if s.is_bus{ let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; - let exe_bus = buses_info.get(bus_node).unwrap(); - let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Input, buses_info); - local_id += bus.size(); - dag_local_id += bus.size(); + let info_bus = buses_info.get(bus_node).unwrap(); + let size = s.length.iter().fold(info_bus.size, |p, c| p * (*c)); + let bus = Bus{ + name: s.name, + lengths: s.length, + local_id, + dag_local_id, + bus_id: bus_node, + size, + xtype: Input, + }; + local_id += bus.size; + dag_local_id += bus.size; instance.add_signal(Wire::TBus(bus)); } else{ - let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input}; - local_id += signal.size(); - dag_local_id += signal.size(); + let size = s.length.iter().fold(1, |p, c| p * (*c)); + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input, size}; + local_id += signal.size; + dag_local_id += signal.size; instance.add_signal(Wire::TSignal(signal)); } } for s in not_public { if s.is_bus{ let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; - let exe_bus = buses_info.get(bus_node).unwrap(); - let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Input, buses_info); - local_id += bus.size(); - dag_local_id += bus.size(); + let info_bus = buses_info.get(bus_node).unwrap(); + let size = s.length.iter().fold(info_bus.size, |p, c| p * (*c)); + let bus = Bus{ + name: s.name, + lengths: s.length, + local_id, + dag_local_id, + bus_id: bus_node, + size, + xtype: Input, + }; + local_id += bus.size; + dag_local_id += bus.size; instance.add_signal(Wire::TBus(bus)); } else{ - let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input}; - local_id += signal.size(); - dag_local_id += signal.size(); + let size = s.length.iter().fold(1, |p, c| p * (*c)); + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Input, size}; + local_id += signal.size; + dag_local_id += signal.size; instance.add_signal(Wire::TSignal(signal)); } } for s in self.intermediates { if s.is_bus{ let bus_node = self.bus_connexions.get(&s.name).unwrap().inspect.goes_to; - let exe_bus = buses_info.get(bus_node).unwrap(); - let bus = exe_bus.build_bus(s.name, s.length, local_id, dag_local_id, Intermediate, buses_info); - local_id += bus.size(); - dag_local_id += bus.size(); + let info_bus = buses_info.get(bus_node).unwrap(); + let size = s.length.iter().fold(info_bus.size, |p, c| p * (*c)); + let bus = Bus{ + name: s.name, + lengths: s.length, + local_id, + dag_local_id, + bus_id: bus_node, + size, + xtype: Intermediate, + }; + local_id += bus.size; + dag_local_id += bus.size; instance.add_signal(Wire::TBus(bus)); } else{ - let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Intermediate}; - local_id += signal.size(); - dag_local_id += signal.size(); + let size = s.length.iter().fold(1, |p, c| p * (*c)); + let signal = Signal { name: s.name, lengths: s.length, local_id, dag_local_id, xtype: Intermediate, size}; + local_id += signal.size; + dag_local_id += signal.size; instance.add_signal(Wire::TSignal(signal)); } } From 5e2795eded4c07197dbeb4ce8ad732f3134b6497 Mon Sep 17 00:00:00 2001 From: alrubio Date: Thu, 27 Jun 2024 10:09:36 +0200 Subject: [PATCH 108/189] wasm_producer modified to handle buses in heterogeneus arrays of components --- code_producers/src/wasm_elements/mod.rs | 34 +++++++++++++++++++++++-- compiler/src/circuit_design/template.rs | 2 +- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index e98cb525f..89f34d88e 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -3,6 +3,7 @@ pub mod wasm_code_generator; use crate::components::*; type WasmInstruction = String; +type FieldMap = Vec>; pub struct WASMProducer { pub main_signal_offset: usize, @@ -57,6 +58,10 @@ pub struct WASMProducer { create_loop_counter_tag: String, merror_tag: String, string_table: Vec, + //New for buses + num_of_bus_instances: usize, //total number of different bus instances + size_of_bus_fields: usize, //total number of fields in all differen bus intances + busid2fieldoffsetlist: FieldMap, //for every busId (0..num-1) provides de offset of each field (0..n-1) in it } impl Default for WASMProducer { @@ -119,7 +124,11 @@ impl Default for WASMProducer { create_loop_counter_tag: "$createloopcounter".to_string(), merror_tag: "$merror".to_string(), string_table: Vec::new(), - } + //New for buses + num_of_bus_instances: 0, + size_of_bus_fields: 0, + busid2fieldoffsetlist: Vec::new(), + } } } @@ -245,6 +254,19 @@ impl WASMProducer { } n * 4 } + //New for buses + pub fn get_number_of_bus_instances(&self) -> usize { + self.num_of_bus_instances + } + + pub fn get_size_of_bus_fields(&self) -> usize { + self.size_of_bus_fields + } + + pub fn get_busid_2_field_offset_list(&self) -> &FieldMap { + &self.busid2fieldoffsetlist + } + // end pub fn get_message_list(&self) -> &MessageList { &self.message_list } @@ -308,8 +330,16 @@ impl WASMProducer { let b = self.get_number_of_io_signals() * 4; a + b } + pub fn get_bus_instance_to_field_info_start(&self) -> usize { + self.get_io_signals_info_start() + self.get_io_signals_info_size() + } + pub fn get_field_info_start(&self) -> usize { + let a = self.get_bus_instance_to_field_info_start(); + let b = self.get_number_of_bus_instances() * 4; + a + b + } pub fn get_message_buffer_counter_position(&self) -> usize { - self.get_io_signals_info_start() + self.get_io_signals_info_size() + self.get_field_info_start() + self.get_size_of_bus_fields() } pub fn get_message_buffer_start(&self) -> usize { self.get_message_buffer_counter_position() + 4 diff --git a/compiler/src/circuit_design/template.rs b/compiler/src/circuit_design/template.rs index 399ca43e8..806108778 100644 --- a/compiler/src/circuit_design/template.rs +++ b/compiler/src/circuit_design/template.rs @@ -47,7 +47,7 @@ impl WriteWasm for TemplateCodeInfo { instructions.push(set_constant(&producer.get_component_free_pos().to_string())); instructions.push(load32(None)); instructions.push(set_local(producer.get_offset_tag())); - // set component id + // set template id instructions.push(get_local(producer.get_offset_tag())); instructions.push(set_constant(&self.id.to_string())); instructions.push(store32(None)); From bbe0500b1530d5568135f11d01ac34d741d4b478 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 27 Jun 2024 11:04:16 +0200 Subject: [PATCH 109/189] working on inputs info --- .../src/c_elements/c_code_generator.rs | 11 +++--- code_producers/src/c_elements/mod.rs | 15 +++++++- code_producers/src/components/mod.rs | 21 +++--------- code_producers/src/wasm_elements/mod.rs | 15 +++++++- .../src/wasm_elements/wasm_code_generator.rs | 9 +++-- compiler/src/circuit_design/build.rs | 30 +++++++--------- compiler/src/hir/very_concrete_program.rs | 4 +-- .../intermediate_representation/translate.rs | 6 ++-- .../environment_utils/bus_representation.rs | 34 ++----------------- 9 files changed, 64 insertions(+), 81 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 7c0596a70..5ec19413d 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -469,17 +469,17 @@ pub fn collect_function_headers(functions: Vec) -> Vec { //--------------- generate all kinds of Data for the .dat file --------------- -pub fn generate_hash_map(signal_name_list: &Vec<(String, usize, usize)>) -> Vec<(u64, u64, u64)> { +pub fn generate_hash_map(signal_name_list: &Vec) -> Vec<(u64, u64, u64)> { assert!(signal_name_list.len() <= 256); let len = 256; let mut hash_map = vec![(0, 0, 0); len]; for i in 0..signal_name_list.len() { - let h = hasher(&signal_name_list[i].0); + let h = hasher(&signal_name_list[i].name); let mut p = (h % 256) as usize; while hash_map[p].1 != 0 { p = (p + 1) % 256; } - hash_map[p] = (h, signal_name_list[i].1 as u64, signal_name_list[i].2 as u64); + hash_map[p] = (h, signal_name_list[i].start as u64, signal_name_list[i].size as u64); } hash_map } @@ -653,9 +653,8 @@ pub fn generate_dat_file(dat_file: &mut dyn Write, producer: &CProducer) -> std: //dfile.flush()?; let aux = producer.get_main_input_list(); - // TODO: change generate_hash_map to new inputlist - //let map = generate_hash_map(&aux); - let map = Vec::new(); + // TODO: change generate_hash_map to new inputlist using buses + let map = generate_hash_map(&aux); let hashmap = generate_dat_from_hash_map(&map); //bytes u64 --> u64 //let hml = 256 as u32; //dfile.write_all(&hml.to_be_bytes())?; diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 821ed1bbe..b0d1798b6 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -68,7 +68,20 @@ impl Default for CProducer { prime_str: "bn128".to_string(), number_of_main_outputs: 1, number_of_main_inputs: 2, - main_input_list: Vec::new(), //[].to_vec(), + main_input_list: [ + InputInfo{ + name:"in1".to_string(), + size:1, + start: 2, + bus_id: None + }, + InputInfo{ + name:"in2".to_string(), + size:1, + start: 3, + bus_id: None + }, + ].to_vec(), signals_in_witness: 20, witness_to_signal_list: [ 0, 1, 2, 3, 4, 5, 6, 12, 16, 19, 24, 27, 33, 42, 46, 50, 51, 65, 78, 79, diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index a3e374ff7..32937ad4b 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -7,27 +7,16 @@ pub struct IODef { pub lengths: Vec, } -// It is an array that contains (name, start position, size) - -pub struct SignalInfo{ +// Previously an array that contains, now struct (name, start position, size, bus_id (if any)) +#[derive(Clone)] +pub struct InputInfo{ pub name: String, - pub size: usize, pub start: usize, -} - -pub struct BusInfo{ - pub name: String, pub size: usize, - pub start: usize, - pub bus_id: usize -} - -pub enum WireInfo{ - Signal(SignalInfo), - Bus(BusInfo) + pub bus_id: Option } -pub type InputList = Vec; +pub type InputList = Vec; pub type TemplateList = Vec; pub struct InfoParallel{ pub name: String, diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index e98cb525f..9bd89bc3c 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -76,7 +76,20 @@ impl Default for WASMProducer { size_32_shift: 5, number_of_main_outputs: 0, //2, number_of_main_inputs: 0, // 4, - main_input_list: Vec::new(), //("inpair".to_string(),2), + main_input_list: [ + InputInfo{ + name:"in1".to_string(), + size:1, + start: 1, + bus_id: None + }, + InputInfo{ + name:"in2".to_string(), + size:1, + start: 2, + bus_id: None + } + ].to_vec(), signals_in_witness: 0, //20, witness_to_signal_list: [].to_vec(), //[0,1,2,3,4,5,6,12,16,19,24,27,33,42,46,50,51,65,78,79].to_vec(), message_list: [].to_vec(), //["Main".to_string(),"Hola Herme".to_string(),"Hola Albert".to_string()].to_vec(), diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 828052348..f6cef4768 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -226,17 +226,17 @@ pub fn get_initial_size_of_memory(producer: &WASMProducer) -> usize { //------------------- generate all kinds of Data ------------------ -pub fn generate_hash_map(signal_name_list: &Vec<(String, usize, usize)>) -> Vec<(u64, usize, usize)> { +pub fn generate_hash_map(signal_name_list: &Vec) -> Vec<(u64, usize, usize)> { assert!(signal_name_list.len() <= 256); let len = 256; let mut hash_map = vec![(0, 0, 0); len]; for i in 0..signal_name_list.len() { - let h = hasher(&signal_name_list[i].0); + let h = hasher(&signal_name_list[i].name); let mut p = (h % 256) as usize; while hash_map[p].1 != 0 { p = (p + 1) % 256; } - hash_map[p] = (h, signal_name_list[i].1, signal_name_list[i].2); + hash_map[p] = (h, signal_name_list[i].start, signal_name_list[i].size); } hash_map } @@ -568,8 +568,7 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { "\\00\\00\\00\\00\\00\\00\\00\\80" )); // TODO: change generate_hash_map to new inputlist - let map = Vec::new(); - //let map = generate_hash_map(&producer.get_main_input_list()); + let map = generate_hash_map(&producer.get_main_input_list()); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_input_signals_hashmap_start(), diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 11929b78f..fca65e8d4 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -268,27 +268,23 @@ fn initialize_c_producer(vcp: &VCP, database: &TemplateDB, version: &str) -> CPr fn main_input_list(main: &TemplateInstance) -> InputList { use program_structure::ast::SignalType::*; use crate::hir::very_concrete_program::Wire::*; - fn build_info_wire(wire: &Wire) -> WireInfo{ + fn build_info_wire(wire: &Wire) -> InputInfo{ match wire{ TSignal(info) =>{ - WireInfo::Signal( - SignalInfo{ - name: info.name.clone(), - size: info.size, - start: info.dag_local_id - } - ) + InputInfo{ + name: info.name.clone(), + size: info.size, + start: info.dag_local_id, + bus_id: None + } }, TBus(info) =>{ - - WireInfo::Bus( - BusInfo{ - name: info.name.clone(), - size: info.size, - start: info.dag_local_id, - bus_id: info.bus_id - } - ) + InputInfo{ + name: info.name.clone(), + size: info.size, + start: info.dag_local_id, + bus_id: Some(info.bus_id) + } } } } diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 146e04487..2138f411b 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -116,7 +116,7 @@ pub struct Bus{ pub size: usize, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FieldInfo{ pub field_id: usize, pub offset: usize, @@ -127,7 +127,7 @@ pub struct FieldInfo{ -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct BusInstance{ pub name: String, pub size: usize, diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index f7d912927..332e47c2b 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -982,6 +982,7 @@ fn build_signal_location( accesses.push(AccessType::Qualified(field_ids[i])); i+=1; } + unreachable!("TODO: mixed array"); LocationRule::Mapped { signal_code, indexes: accesses } } Uniform { instance_id, header, .. } => { @@ -1027,6 +1028,7 @@ impl ProcessedSymbol { use Access::*; let symbol_name = definition.symbol; let meta = definition.meta; + let symbol_info = state.environment.get_variable(&symbol_name).unwrap().clone(); let mut lengths = symbol_info.dimensions.clone(); lengths.reverse(); @@ -1035,8 +1037,8 @@ impl ProcessedSymbol { let mut signal_type = state.signal_to_type.get(&symbol_name).cloned(); let mut before_index = vec![]; // indexes accessed before component - let mut after_indexes = vec![]; - let mut current_index = vec![]; // indexes accessed after component (or no component) + let mut after_indexes = vec![]; // indexes accessed after component (or no component) + let mut current_index = vec![]; let mut multiple_possible_lengths: Vec> = vec![]; let mut is_bus = symbol_info.is_bus; diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 3383c06c5..3d840d772 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -493,26 +493,7 @@ impl BusRepresentation { let (tags_assigned_definition, tags_assigned_info) = assigned_bus.field_tags.get(field_name).unwrap(); let tags_propagated = compute_propagated_tags(tags_assigned_info, tags_assigned_definition); - // TODO: REMOVE check if the bus is initialized -> not needed, always is not? let is_init = false; - // let is_init = match value{ - // FieldTypes::Bus(bus_slice) =>{ - // let mut bus_is_init = false; - // for i in 0..BusSlice::get_number_of_cells(bus_slice){ - // match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ - // Ok(bus) => { - // bus_is_init |= bus.has_assignment(); - // } - // Err(_) => unreachable!() - // } - // } - // bus_is_init - // }, - // FieldTypes::Signal(signal_slice)=>{ - // SignalSlice::get_number_of_inserts(&signal_slice) > 0 - // } - // }; - // assert!(!is_init); // perform the tag assignment if !is_input{ @@ -525,18 +506,9 @@ impl BusRepresentation { if !tags_propagated.contains_key(t){ return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); } else{ - //if !is_init{ - // Not needed check, always not init, if not error - // First assignment of input tag - *value = tags_propagated.get(t).unwrap().clone(); - //} - // else{ - // // already given a value, check that it is the same - // // if not return error - // if value != tags_propagated.get(t).unwrap(){ - // return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); - // } - // } + // Not needed check, always not init, if not error + // First assignment of input tag + *value = tags_propagated.get(t).unwrap().clone(); } } } From fe621a8fd85c43d879b51d34043ec98d02d4174d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 27 Jun 2024 11:26:50 +0200 Subject: [PATCH 110/189] adding info buses to wasm producer --- code_producers/src/wasm_elements/mod.rs | 6 +++--- compiler/src/circuit_design/build.rs | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index e93c78d6c..4a338ea3c 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -59,9 +59,9 @@ pub struct WASMProducer { merror_tag: String, string_table: Vec, //New for buses - num_of_bus_instances: usize, //total number of different bus instances - size_of_bus_fields: usize, //total number of fields in all differen bus intances - busid2fieldoffsetlist: FieldMap, //for every busId (0..num-1) provides de offset of each field (0..n-1) in it + pub num_of_bus_instances: usize, //total number of different bus instances + pub size_of_bus_fields: usize, //total number of fields in all differen bus intances + pub busid2fieldoffsetlist: FieldMap, //for every busId (0..num-1) provides de offset of each field (0..n-1) in it } impl Default for WASMProducer { diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index fca65e8d4..4dc991eb0 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -228,6 +228,15 @@ fn initialize_wasm_producer(vcp: &VCP, database: &TemplateDB, wat_flag:bool, ver producer.template_instance_list = build_template_list(vcp); producer.field_tracking.clear(); producer.wat_flag = wat_flag; + + // add the info of the buses + ( + producer.num_of_bus_instances, + producer.size_of_bus_fields, + producer.busid2fieldoffsetlist + ) = get_info_buses(&vcp.buses); + + (producer.major_version, producer.minor_version, producer.patch_version) = get_number_version(version); producer } @@ -376,6 +385,22 @@ fn get_number_version(version: &str) -> (usize, usize, usize) { ) } +fn get_info_buses(buses: &Vec)->(usize, usize, Vec>){ + let mut n_buses = 0; + let mut n_fields = 0; + let mut bus_to_fields_offsets = Vec::new(); + for bus in buses{ + let mut field_offsets = vec![0; bus.fields.len()]; + for (_, field_info) in &bus.fields{ + field_offsets[field_info.field_id] = field_info.offset; + n_fields += 1; + } + bus_to_fields_offsets.push(field_offsets); + n_buses += 1; + } + (n_buses, n_fields, bus_to_fields_offsets) +} + struct CircuitInfo { file_library: FileLibrary, functions: HashMap>, From 7ef8d9942f552dbb08ad072f265b4164bfc4561c Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 27 Jun 2024 11:37:20 +0200 Subject: [PATCH 111/189] printing output wasm for testing --- .../src/wasm_elements/common/generate_witness.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code_producers/src/wasm_elements/common/generate_witness.js b/code_producers/src/wasm_elements/common/generate_witness.js index eabb86e58..d6f066e59 100755 --- a/code_producers/src/wasm_elements/common/generate_witness.js +++ b/code_producers/src/wasm_elements/common/generate_witness.js @@ -8,10 +8,10 @@ if (process.argv.length != 5) { const buffer = readFileSync(process.argv[2]); wc(buffer).then(async witnessCalculator => { - // const w= await witnessCalculator.calculateWitness(input,0); - // for (let i=0; i< w.length; i++){ - // console.log(w[i]); - // } + const w= await witnessCalculator.calculateWitness(input,0); + for (let i=0; i< w.length; i++){ + console.log(w[i]); + } const buff= await witnessCalculator.calculateWTNSBin(input,0); writeFile(process.argv[4], buff, function(err) { if (err) throw err; From 81f52e09a13d46551978d9c18fbf21d5dc67b4b1 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 28 Jun 2024 15:25:39 +0200 Subject: [PATCH 112/189] changes mixed arrays -> storing more info buses --- code_producers/src/c_elements/mod.rs | 16 ++++++++-------- code_producers/src/components/mod.rs | 11 +++++++++++ code_producers/src/lib.rs | 11 +++++++++++ code_producers/src/wasm_elements/mod.rs | 1 - compiler/src/circuit_design/build.rs | 19 +++++++++++++------ 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index b0d1798b6..769a34199 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -38,24 +38,24 @@ impl Default for CProducer { my_map.insert( 0, vec![ - IODef { code: 0, offset: 0, lengths: [2, 3].to_vec() }, - IODef { code: 1, offset: 6, lengths: [].to_vec() }, - IODef { code: 2, offset: 7, lengths: [2].to_vec() }, + IODef { code: 0, offset: 0, lengths: [2, 3].to_vec(), size: 6 }, + IODef { code: 1, offset: 6, lengths: [].to_vec(), size: 1 }, + IODef { code: 2, offset: 7, lengths: [2].to_vec(), size: 2 }, ], ); my_map.insert( 1, vec![ - IODef { code: 0, offset: 0, lengths: [3].to_vec() }, - IODef { code: 1, offset: 3, lengths: [4, 8, 6].to_vec() }, + IODef { code: 0, offset: 0, lengths: [3].to_vec(), size: 3 }, + IODef { code: 1, offset: 3, lengths: [4, 8, 6].to_vec(), size: 192 }, ], ); my_map.insert( 2, vec![ - IODef { code: 0, offset: 0, lengths: [].to_vec() }, - IODef { code: 1, offset: 1, lengths: [4].to_vec() }, - IODef { code: 2, offset: 5, lengths: [2, 6].to_vec() }, + IODef { code: 0, offset: 0, lengths: [].to_vec(), size: 1 }, + IODef { code: 1, offset: 1, lengths: [4].to_vec(), size: 4 }, + IODef { code: 2, offset: 5, lengths: [2, 6].to_vec(), size: 12 }, ], ); CProducer { diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index 32937ad4b..74c385a70 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -5,6 +5,7 @@ pub struct IODef { pub code: usize, pub offset: usize, pub lengths: Vec, + pub size: usize, } // Previously an array that contains, now struct (name, start position, size, bus_id (if any)) @@ -16,6 +17,16 @@ pub struct InputInfo{ pub bus_id: Option } +#[derive(Default, Clone)] +pub struct FieldData{ + pub dimensions: Vec, + pub size: usize, + pub offset: usize, + pub bus_id: Option +} + +pub type FieldMap = Vec>; + pub type InputList = Vec; pub type TemplateList = Vec; pub struct InfoParallel{ diff --git a/code_producers/src/lib.rs b/code_producers/src/lib.rs index 8d77960cf..ea21686d3 100644 --- a/code_producers/src/lib.rs +++ b/code_producers/src/lib.rs @@ -4,3 +4,14 @@ pub mod c_elements; pub mod wasm_elements; pub mod components; + + +#[derive(Default, Clone)] +pub struct FieldData{ + pub dimensions: Vec, + pub size: usize, + pub offset: usize, + pub bus_id: Option +} + +pub type FieldMap = Vec>; diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index 4a338ea3c..d20a05973 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -3,7 +3,6 @@ pub mod wasm_code_generator; use crate::components::*; type WasmInstruction = String; -type FieldMap = Vec>; pub struct WASMProducer { pub main_signal_offset: usize, diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 4dc991eb0..564cb0706 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -345,6 +345,7 @@ fn build_input_output_list(instance: &TemplateInstance, database: &TemplateDB) - code: TemplateDB::get_signal_id(database, &instance.template_name, s.name()), offset: s.local_id(), lengths: s.lengths().clone(), + size: s.size() }; io_list.push(def); } @@ -385,20 +386,26 @@ fn get_number_version(version: &str) -> (usize, usize, usize) { ) } -fn get_info_buses(buses: &Vec)->(usize, usize, Vec>){ +fn get_info_buses(buses: &Vec)->(usize, usize, FieldMap){ let mut n_buses = 0; let mut n_fields = 0; - let mut bus_to_fields_offsets = Vec::new(); + let mut bus_to_fields_data = Vec::new(); for bus in buses{ - let mut field_offsets = vec![0; bus.fields.len()]; + let mut field_data = vec![FieldData::default(); bus.fields.len()]; for (_, field_info) in &bus.fields{ - field_offsets[field_info.field_id] = field_info.offset; + let data = FieldData{ + offset: field_info.offset, + size: field_info.size, + dimensions: field_info.dimensions.clone(), + bus_id: field_info.bus_id + }; + field_data[field_info.field_id] = data; n_fields += 1; } - bus_to_fields_offsets.push(field_offsets); + bus_to_fields_data.push(field_data); n_buses += 1; } - (n_buses, n_fields, bus_to_fields_offsets) + (n_buses, n_fields, bus_to_fields_data) } struct CircuitInfo { From 7e96aeb22b08fee179f6e1b1881ca8a59781168f Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 28 Jun 2024 18:01:35 +0200 Subject: [PATCH 113/189] adding info buses c producer --- code_producers/src/c_elements/mod.rs | 23 +++++++++++++++++++++++ compiler/src/circuit_design/build.rs | 8 ++++++++ 2 files changed, 31 insertions(+) diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 769a34199..0b661e3dd 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -30,6 +30,10 @@ pub struct CProducer { pub patch_version: usize, name_tag: String, string_table: Vec, + //New for buses + pub num_of_bus_instances: usize, //total number of different bus instances + pub size_of_bus_fields: usize, //total number of fields in all differen bus intances + pub busid2fieldoffsetlist: FieldMap, //for every busId (0..num-1) provides de offset, size, dimensions and busId of each field (0..n-1) in it } impl Default for CProducer { @@ -58,6 +62,7 @@ impl Default for CProducer { IODef { code: 2, offset: 5, lengths: [2, 6].to_vec(), size: 12 }, ], ); + CProducer { main_header: "Main_0".to_string(), main_is_parallel: false, @@ -109,6 +114,10 @@ impl Default for CProducer { patch_version: 0, name_tag: "name".to_string(), string_table: Vec::new(), + //New for buses + num_of_bus_instances: 0, + size_of_bus_fields: 0, + busid2fieldoffsetlist: Vec::new(), } } } @@ -188,4 +197,18 @@ impl CProducer { pub fn set_string_table(&mut self, string_table: Vec) { self.string_table = string_table; } + + //New for buses + pub fn get_number_of_bus_instances(&self) -> usize { + self.num_of_bus_instances + } + + pub fn get_size_of_bus_fields(&self) -> usize { + self.size_of_bus_fields + } + + pub fn get_busid_2_field_offset_list(&self) -> &FieldMap { + &self.busid2fieldoffsetlist + } + // end } diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 564cb0706..91999a9c2 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -270,6 +270,14 @@ fn initialize_c_producer(vcp: &VCP, database: &TemplateDB, version: &str) -> CPr producer.io_map = build_io_map(vcp, database); producer.template_instance_list = build_template_list_parallel(vcp); producer.field_tracking.clear(); + + // add the info of the buses + ( + producer.num_of_bus_instances, + producer.size_of_bus_fields, + producer.busid2fieldoffsetlist + ) = get_info_buses(&vcp.buses); + (producer.major_version, producer.minor_version, producer.patch_version) = get_number_version(version); producer } From 0302685e9ca886b1c326459fb43d3120b7e6d18a Mon Sep 17 00:00:00 2001 From: alrubio Date: Tue, 2 Jul 2024 13:52:37 +0200 Subject: [PATCH 114/189] adding buses to code generation --- code_producers/src/c_elements/mod.rs | 16 ++- code_producers/src/wasm_elements/mod.rs | 54 +++++++--- .../src/wasm_elements/wasm_code_generator.rs | 98 ++++++++++++++++++- compiler/src/circuit_design/build.rs | 12 +-- compiler/src/circuit_design/circuit.rs | 8 ++ 5 files changed, 151 insertions(+), 37 deletions(-) diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 0b661e3dd..385fd4136 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -32,8 +32,8 @@ pub struct CProducer { string_table: Vec, //New for buses pub num_of_bus_instances: usize, //total number of different bus instances - pub size_of_bus_fields: usize, //total number of fields in all differen bus intances - pub busid2fieldoffsetlist: FieldMap, //for every busId (0..num-1) provides de offset, size, dimensions and busId of each field (0..n-1) in it +// pub size_of_bus_fields: usize, //total number of fields in all differen bus intances + pub busid_field_info: FieldMap, //for every busId (0..num-1) provides de offset, size, dimensions and busId of each field (0..n-1) in it } impl Default for CProducer { @@ -116,8 +116,8 @@ impl Default for CProducer { string_table: Vec::new(), //New for buses num_of_bus_instances: 0, - size_of_bus_fields: 0, - busid2fieldoffsetlist: Vec::new(), +// size_of_bus_fields: 0, + busid_field_info: Vec::new(), } } } @@ -203,12 +203,8 @@ impl CProducer { self.num_of_bus_instances } - pub fn get_size_of_bus_fields(&self) -> usize { - self.size_of_bus_fields - } - - pub fn get_busid_2_field_offset_list(&self) -> &FieldMap { - &self.busid2fieldoffsetlist + pub fn get_busid_field_info(&self) -> &FieldMap { + &self.busid_field_info } // end } diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index d20a05973..2d94a2cc4 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -59,8 +59,8 @@ pub struct WASMProducer { string_table: Vec, //New for buses pub num_of_bus_instances: usize, //total number of different bus instances - pub size_of_bus_fields: usize, //total number of fields in all differen bus intances - pub busid2fieldoffsetlist: FieldMap, //for every busId (0..num-1) provides de offset of each field (0..n-1) in it +// pub size_of_bus_fields: usize, //total number of fields in all differen bus intances ??? + pub busid_field_info: FieldMap, //for every busId (0..num-1) provides de offset, the dimensions and size of each field (0..n-1) in it } impl Default for WASMProducer { @@ -138,8 +138,8 @@ impl Default for WASMProducer { string_table: Vec::new(), //New for buses num_of_bus_instances: 0, - size_of_bus_fields: 0, - busid2fieldoffsetlist: Vec::new(), +// size_of_bus_fields: 0, + busid_field_info: Vec::new(), } } } @@ -256,11 +256,11 @@ impl WASMProducer { let mut n = 0; for (_c, v) in &self.io_map { for s in v { - // since we take offset and all lengths but last one + // since we take offset, size and all lengths but last one if s.lengths.len() == 0 { - n += 1; + n += 2; } else { - n += s.lengths.len(); + n += s.lengths.len() + 1; } } } @@ -271,12 +271,31 @@ impl WASMProducer { self.num_of_bus_instances } - pub fn get_size_of_bus_fields(&self) -> usize { - self.size_of_bus_fields + pub fn get_number_of_bus_fields(&self) -> usize { + let mut n = 0; + for v in &self.busid_field_info { + n += v.len(); + } + n } - pub fn get_busid_2_field_offset_list(&self) -> &FieldMap { - &self.busid2fieldoffsetlist + pub fn get_size_of_bus_info(&self) -> usize { + let mut n = 0; + for v in &self.busid_field_info { + for s in v { + // since we take offset, size, busid and all lengths but last one + if s.dimensions.len() == 0 { + n += 3; + } else { + n += s.dimensions.len() + 2; + } + } + } + n + } + + pub fn get_busid_field_info(&self) -> &FieldMap { + &self.busid_field_info } // end pub fn get_message_list(&self) -> &MessageList { @@ -342,16 +361,21 @@ impl WASMProducer { let b = self.get_number_of_io_signals() * 4; a + b } - pub fn get_bus_instance_to_field_info_start(&self) -> usize { + pub fn get_bus_instance_to_field_start(&self) -> usize { self.get_io_signals_info_start() + self.get_io_signals_info_size() } - pub fn get_field_info_start(&self) -> usize { - let a = self.get_bus_instance_to_field_info_start(); + pub fn get_field_to_info_start(&self) -> usize { + let a = self.get_bus_instance_to_field_start(); let b = self.get_number_of_bus_instances() * 4; a + b } + pub fn get_field_info_start(&self) -> usize { + let a = self.get_field_to_info_start(); + let b = self.get_number_of_bus_fields() * 4; + a + b + } pub fn get_message_buffer_counter_position(&self) -> usize { - self.get_field_info_start() + self.get_size_of_bus_fields() + self.get_field_info_start() + self.get_size_of_bus_info() } pub fn get_message_buffer_start(&self) -> usize { self.get_message_buffer_counter_position() + 4 diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index f6cef4768..0a12d9e44 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -290,11 +290,11 @@ pub fn generate_data_io_signals_to_info( for s in value { assert_eq!(s.code, n); io_signals.push_str(&&wasm_hexa(4, &BigInt::from(pos))); - //do not store code and the first one of lengths + //do not store code and the first one of lengths (offset + size + length-1(if >0) if s.lengths.len() == 0 { - pos += 4; + pos += 8; } else { - pos += s.lengths.len() * 4; + pos += s.lengths.len() * 4 + 4; } n += 1; } @@ -310,7 +310,7 @@ pub fn generate_data_io_signals_info( io_map: &TemplateInstanceIOMap, ) -> String { let mut io_signals_info = "".to_string(); - for c in 0..producer.get_number_of_components() { + for c in 0..producer.get_number_of_template_instances() { match io_map.get(&c) { Some(value) => { for s in value { @@ -319,6 +319,12 @@ pub fn generate_data_io_signals_info( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); + // add the actual size of the elements + io_signals_info.push_str(&&wasm_hexa( + 4, + &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), + )); + // add the dimensions except the first one for i in 1..s.lengths.len() { io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); } @@ -330,6 +336,75 @@ pub fn generate_data_io_signals_info( io_signals_info } + +pub fn generate_data_bus_instance_to_field( + producer: &WASMProducer, + field_map: &FieldMap, +) -> String { + let mut field_map_data = "".to_string(); + let mut s = producer.get_field_to_info_start(); + for c in 0..producer.get_number_of_bus_instances() { + field_map_data.push_str(&&wasm_hexa(4, &BigInt::from(s))); + s += field_map[c].len() * 4; + } + field_map_data +} + +pub fn generate_data_field_to_info( + producer: &WASMProducer, + field_map: &FieldMap, +) -> String { + let mut bus_fields = "".to_string(); + let mut pos = producer.get_field_info_start(); + for c in 0..producer.get_number_of_bus_instances() { + for s in &field_map[c] { + bus_fields.push_str(&&wasm_hexa(4, &BigInt::from(pos))); + //do not store the first one of lengths + if s.dimensions.len() == 0 { + pos += 12; + } else { + pos += s.dimensions.len() * 4 + 8; + } + } + } + bus_fields +} + +pub fn generate_data_field_info( + producer: &WASMProducer, + field_map: &FieldMap, +) -> String { + let mut field_info = "".to_string(); + for c in 0..producer.get_number_of_bus_instances() { + for s in &field_map[c] { + // add the actual offset in memory, taking into account the size of field nums + field_info.push_str(&&wasm_hexa( + 4, + &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), + )); + // add the actual size in memory, taking into account the size of field nums + field_info.push_str(&&wasm_hexa( + 4, + &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), + )); + // add the busid (if not bus add the number if bus instantiations) + match s.bus_id { + Some(value) => { + field_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); + } + None => { + field_info.push_str(&&wasm_hexa(4, &BigInt::from(producer.get_number_of_bus_instances()))); + } + } + // add all dimensions but first one + for i in 1..s.dimensions.len() { + field_info.push_str(&&wasm_hexa(4, &BigInt::from(s.dimensions[i]))); + } + } + } + field_info +} + pub fn generate_data_constants(producer: &WASMProducer, constant_list: &Vec) -> String { let mut constant_list_data = "".to_string(); // For short/long form @@ -596,6 +671,21 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { producer.get_io_signals_info_start(), generate_data_io_signals_info(&producer, producer.get_io_map()) )); + wdata.push(format!( + "(data (i32.const {}) \"{}\")", + producer.get_bus_instance_to_field_start(), + generate_data_bus_instance_to_field(&producer, producer.get_busid_field_info()) + )); + wdata.push(format!( + "(data (i32.const {}) \"{}\")", + producer.get_field_to_info_start(), + generate_data_field_to_info(&producer, producer.get_busid_field_info()) + )); + wdata.push(format!( + "(data (i32.const {}) \"{}\")", + producer.get_field_info_start(), + generate_data_field_info(&producer, producer.get_busid_field_info()) + )); let ml = producer.get_message_list(); let m = producer.get_message_list_start(); for i in 0..ml.len() { diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 91999a9c2..8ca6a6fbb 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -232,8 +232,7 @@ fn initialize_wasm_producer(vcp: &VCP, database: &TemplateDB, wat_flag:bool, ver // add the info of the buses ( producer.num_of_bus_instances, - producer.size_of_bus_fields, - producer.busid2fieldoffsetlist + producer.busid_field_info ) = get_info_buses(&vcp.buses); @@ -274,8 +273,7 @@ fn initialize_c_producer(vcp: &VCP, database: &TemplateDB, version: &str) -> CPr // add the info of the buses ( producer.num_of_bus_instances, - producer.size_of_bus_fields, - producer.busid2fieldoffsetlist + producer.busid_field_info ) = get_info_buses(&vcp.buses); (producer.major_version, producer.minor_version, producer.patch_version) = get_number_version(version); @@ -394,9 +392,8 @@ fn get_number_version(version: &str) -> (usize, usize, usize) { ) } -fn get_info_buses(buses: &Vec)->(usize, usize, FieldMap){ +fn get_info_buses(buses: &Vec)->(usize, FieldMap){ let mut n_buses = 0; - let mut n_fields = 0; let mut bus_to_fields_data = Vec::new(); for bus in buses{ let mut field_data = vec![FieldData::default(); bus.fields.len()]; @@ -408,12 +405,11 @@ fn get_info_buses(buses: &Vec)->(usize, usize, FieldMap){ bus_id: field_info.bus_id }; field_data[field_info.field_id] = data; - n_fields += 1; } bus_to_fields_data.push(field_data); n_buses += 1; } - (n_buses, n_fields, bus_to_fields_data) + (n_buses, bus_to_fields_data) } struct CircuitInfo { diff --git a/compiler/src/circuit_design/circuit.rs b/compiler/src/circuit_design/circuit.rs index 4ec5242f3..94e051ea7 100644 --- a/compiler/src/circuit_design/circuit.rs +++ b/compiler/src/circuit_design/circuit.rs @@ -359,6 +359,10 @@ impl WriteC for Circuit { "uint get_size_of_io_map() {{return {};}}\n", producer.get_io_map().len() )); + code.push(format!( + "uint get_size_of_bus_list() {{return {};}}\n", + producer.get_busid_field_info().len() + )); //code.append(&mut generate_message_list_def(producer, producer.get_message_list())); // Functions to release the memory @@ -477,6 +481,10 @@ impl WriteC for Circuit { "uint get_size_of_io_map() {{return {};}}\n", producer.get_io_map().len() )); + code.push(format!( + "uint get_size_of_bus_list() {{return {};}}\n", + producer.get_busid_field_info().len() + )); //code.append(&mut generate_message_list_def(producer, producer.get_message_list())); // Functions to release the memory From 107190ec09bffd5ac50156fadeacb8035f0b9365 Mon Sep 17 00:00:00 2001 From: alrubio Date: Thu, 4 Jul 2024 10:56:05 +0200 Subject: [PATCH 115/189] first complete version of wasm handling of buses in heterogeneous components --- code_producers/src/c_elements/mod.rs | 16 +-- code_producers/src/components/mod.rs | 1 + code_producers/src/wasm_elements/mod.rs | 20 +-- .../src/wasm_elements/wasm_code_generator.rs | 38 +++--- compiler/src/circuit_design/build.rs | 3 +- compiler/src/hir/very_concrete_program.rs | 10 ++ .../call_bucket.rs | 114 ++++++++++------- .../load_bucket.rs | 110 +++++++++++------ .../store_bucket.rs | 116 +++++++++++------- 9 files changed, 277 insertions(+), 151 deletions(-) diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 385fd4136..639e37470 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -42,24 +42,24 @@ impl Default for CProducer { my_map.insert( 0, vec![ - IODef { code: 0, offset: 0, lengths: [2, 3].to_vec(), size: 6 }, - IODef { code: 1, offset: 6, lengths: [].to_vec(), size: 1 }, - IODef { code: 2, offset: 7, lengths: [2].to_vec(), size: 2 }, + IODef { code: 0, offset: 0, lengths: [2, 3].to_vec(), size: 6, bus_id:None }, + IODef { code: 1, offset: 6, lengths: [].to_vec(), size: 1, bus_id:None }, + IODef { code: 2, offset: 7, lengths: [2].to_vec(), size: 2, bus_id:None }, ], ); my_map.insert( 1, vec![ - IODef { code: 0, offset: 0, lengths: [3].to_vec(), size: 3 }, - IODef { code: 1, offset: 3, lengths: [4, 8, 6].to_vec(), size: 192 }, + IODef { code: 0, offset: 0, lengths: [3].to_vec(), size: 3, bus_id:None }, + IODef { code: 1, offset: 3, lengths: [4, 8, 6].to_vec(), size: 192, bus_id:None }, ], ); my_map.insert( 2, vec![ - IODef { code: 0, offset: 0, lengths: [].to_vec(), size: 1 }, - IODef { code: 1, offset: 1, lengths: [4].to_vec(), size: 4 }, - IODef { code: 2, offset: 5, lengths: [2, 6].to_vec(), size: 12 }, + IODef { code: 0, offset: 0, lengths: [].to_vec(), size: 1, bus_id:None }, + IODef { code: 1, offset: 1, lengths: [4].to_vec(), size: 4, bus_id:None }, + IODef { code: 2, offset: 5, lengths: [2, 6].to_vec(), size: 12, bus_id:None }, ], ); diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index 74c385a70..d2ff7c4a0 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -6,6 +6,7 @@ pub struct IODef { pub offset: usize, pub lengths: Vec, pub size: usize, + pub bus_id: Option } // Previously an array that contains, now struct (name, start position, size, bus_id (if any)) diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index 2d94a2cc4..4691faad7 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -256,12 +256,15 @@ impl WASMProducer { let mut n = 0; for (_c, v) in &self.io_map { for s in v { - // since we take offset, size and all lengths but last one + // since we take offset, size, busid and all lengths but last one if s.lengths.len() == 0 { - n += 2; + n += 1; } else { - n += s.lengths.len() + 1; + n += s.lengths.len() + 2; } + if let Some(_) = &s.bus_id { + n += 1; + } } } n * 4 @@ -283,15 +286,18 @@ impl WASMProducer { let mut n = 0; for v in &self.busid_field_info { for s in v { - // since we take offset, size, busid and all lengths but last one + // since we take offset, busid (if it is) and all lengths but first one and size if not zero if s.dimensions.len() == 0 { - n += 3; + n += 1; } else { - n += s.dimensions.len() + 2; + n += s.dimensions.len() + 1; } + if let Some(_) = &s.bus_id { + n += 1; + } } } - n + n * 4 } pub fn get_busid_field_info(&self) -> &FieldMap { diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 0a12d9e44..5a8c2fc95 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -324,6 +324,15 @@ pub fn generate_data_io_signals_info( 4, &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), )); + // add the busid (if not bus add the number if bus instantiations) + match s.bus_id { + Some(value) => { + io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); + } + None => { + io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(producer.get_number_of_bus_instances()))); + } + } // add the dimensions except the first one for i in 1..s.lengths.len() { io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); @@ -382,24 +391,21 @@ pub fn generate_data_field_info( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); - // add the actual size in memory, taking into account the size of field nums - field_info.push_str(&&wasm_hexa( - 4, - &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), - )); - // add the busid (if not bus add the number if bus instantiations) - match s.bus_id { - Some(value) => { - field_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); - } - None => { - field_info.push_str(&&wasm_hexa(4, &BigInt::from(producer.get_number_of_bus_instances()))); + if s.dimensions.len() > 0 { // if it is an array + // add all dimensions but first one + for i in 1..s.dimensions.len() { + field_info.push_str(&&wasm_hexa(4, &BigInt::from(s.dimensions[i]))); } + // add the actual size in memory, if array + field_info.push_str(&&wasm_hexa( + 4, + &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), + )); + } + // add the busid if it contains buses + if let Some(value) = s.bus_id { + field_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); } - // add all dimensions but first one - for i in 1..s.dimensions.len() { - field_info.push_str(&&wasm_hexa(4, &BigInt::from(s.dimensions[i]))); - } } } field_info diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 8ca6a6fbb..02c3ee8d9 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -351,7 +351,8 @@ fn build_input_output_list(instance: &TemplateInstance, database: &TemplateDB) - code: TemplateDB::get_signal_id(database, &instance.template_name, s.name()), offset: s.local_id(), lengths: s.lengths().clone(), - size: s.size() + size: s.size(), + bus_id: s.bus_id() }; io_list.push(def); } diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 2138f411b..1a1c568b2 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -92,6 +92,16 @@ impl Wire { }, } } + pub fn bus_id(&self) -> Option { + match self{ + Wire::TSignal(_s) => { + None + }, + Wire::TBus(s) => { + Some(s.bus_id) + }, + } + } } #[derive(Clone)] diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 5ad5bbb6c..947e1a3ae 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -196,7 +196,6 @@ impl WriteWasm for CallBucket { instructions.push(add32()); } LocationRule::Mapped { signal_code, indexes } => { - // TODO: add the offset match &data.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { @@ -225,46 +224,79 @@ impl WriteWasm for CallBucket { ))); // get position in component io signal to info list let signal_code_in_bytes = signal_code * 4; //position in the list of the signal code instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is - - // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED - // descomentar todo lo siguiente, quitado para evitar error - - /* //now we have first the offset and then the all size dimensions but the last one - if indexes.len() <= 1 { - instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); - if indexes.len() == 1 { - let mut instructions_idx0 = - indexes[0].produce_wasm(producer); - instructions.append(&mut instructions_idx0); - let size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&size.to_string())); - instructions.push(mul32()); - instructions.push(add32()); - } - } else { - instructions.push(set_local(producer.get_io_info_tag())); - instructions.push(get_local(producer.get_io_info_tag())); - instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); - // compute de move with 2 or more dimensions - let mut instructions_idx0 = indexes[0].produce_wasm(producer); - instructions.append(&mut instructions_idx0); // start with dimension 0 - for i in 1..indexes.len() { - instructions.push(get_local(producer.get_io_info_tag())); - let offsetdim = 4 * i; - instructions.push(load32(Some(&offsetdim.to_string()))); // get size of ith dimension - instructions.push(mul32()); // multiply the current move by size of the ith dimension - let mut instructions_idxi = - indexes[i].produce_wasm(producer); - instructions.append(&mut instructions_idxi); - instructions.push(add32()); // add move upto dimension i - } - //we have the total move; and is multiplied by the size of memory Fr in bytes - let size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&size.to_string())); - instructions.push(mul32()); // We have the total move in bytes - instructions.push(add32()); // add to the offset of the signal - } - */ + //now we have first the offset, and then the all size dimensions but the last one + if indexes.len() == 0 { + instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); + } else { + instructions.push(tee_local(producer.get_io_info_tag())); + instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) + // if the first access is qualified we place the address of the bus_id + if let AccessType::Qualified(_) = &indexes[0] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // it is a bus, so the bus_id is in the second position + } + let mut idxpos = 0; + while idxpos < indexes.len() { + if let AccessType::Indexed(index_list) = &indexes[idxpos] { + let mut infopos = 0; + assert!(index_list.len() > 0); + //We first compute the number of elements as + //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] + //first position in the array access + let mut instructions_idx0 = index_list[0].produce_wasm(producer); + instructions.append(&mut instructions_idx0); + for i in 1..index_list.len() { + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of dimension of [1] (recall that first dimension is not added) + instructions.push(load32(Some(&infopos.to_string()))); // second dimension + instructions.push(mul32()); + let mut instructions_idxi = index_list[i].produce_wasm(producer); + instructions.append(&mut instructions_idxi); + instructions.push(add32()); + } + let field_size = producer.get_size_32_bits_in_memory() * 4; + instructions.push(set_constant(&field_size.to_string())); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of size + instructions.push(load32(Some(&infopos.to_string()))); // size + instructions.push(mul32()); // size mult by size of field in bytes + instructions.push(mul32()); // total offset in the array + instructions.push(add32()); // to the current offset + idxpos += 1; + if idxpos < indexes.len() { + //next must be Qualified + if let AccessType::Indexed(_) = &indexes[idxpos] { + assert!(false); + } + // we add the type of bus it is + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; + instructions.push(load32(Some(&infopos.to_string()))); // bus_id + } + } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { + //we have on the stack the bus_id + instructions.push(load32(Some( + &producer.get_bus_instance_to_field_start().to_string() + ))); // get position in the bus to field in memory + let field_no_bytes = field_no * 4; + instructions.push(load32(Some(&field_no_bytes.to_string()))); // get position in the field info in memory + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(tee_local(producer.get_io_info_tag())); + } + let field_size = producer.get_size_32_bits_in_memory() * 4; + instructions.push(set_constant(&field_size.to_string())); + instructions.push(load32(None)); // get the offset + instructions.push(mul32()); // mult by size of field in bytes + instructions.push(add32()); // add to the current offset + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // bus_id + } + } else { + assert!(false); + } + } + } instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 68f235c44..3c539850d 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -121,42 +121,79 @@ impl WriteWasm for LoadBucket { ))); // get position in component io signal to info list let signal_code_in_bytes = signal_code * 4; //position in the list of the signal code instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is - // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED - // descomentar todo lo siguiente, quitado para evitar error //now we have first the offset and then the all size dimensions but the last one - /* - if indexes.len() <= 1 { - instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); - if indexes.len() == 1 { - let mut instructions_idx0 = indexes[0].produce_wasm(producer); - instructions.append(&mut instructions_idx0); - let size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&size.to_string())); - instructions.push(mul32()); - instructions.push(add32()); - } - } else { - instructions.push(set_local(producer.get_io_info_tag())); - instructions.push(get_local(producer.get_io_info_tag())); - instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); - // compute de move with 2 or more dimensions - let mut instructions_idx0 = indexes[0].produce_wasm(producer); - instructions.append(&mut instructions_idx0); // start with dimension 0 - for i in 1..indexes.len() { - instructions.push(get_local(producer.get_io_info_tag())); - let offsetdim = 4 * i; - instructions.push(load32(Some(&offsetdim.to_string()))); // get size of ith dimension - instructions.push(mul32()); // multiply the current move by size of the ith dimension - let mut instructions_idxi = indexes[i].produce_wasm(producer); - instructions.append(&mut instructions_idxi); - instructions.push(add32()); // add move upto dimension i - } - //we have the total move; and is multiplied by the size of memory Fr in bytes - let size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&size.to_string())); - instructions.push(mul32()); // We have the total move in bytes - instructions.push(add32()); // add to the offset of the signal - } - */ + //now we have first the offset, and then the all size dimensions but the last one + if indexes.len() == 0 { + instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); + } else { + instructions.push(tee_local(producer.get_io_info_tag())); + instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) + // if the first access is qualified we place the address of the bus_id + if let AccessType::Qualified(_) = &indexes[0] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // it is a bus, so the bus_id is in the second position + } + let mut idxpos = 0; + while idxpos < indexes.len() { + if let AccessType::Indexed(index_list) = &indexes[idxpos] { + let mut infopos = 0; + assert!(index_list.len() > 0); + //We first compute the number of elements as + //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] + //first position in the array access + let mut instructions_idx0 = index_list[0].produce_wasm(producer); + instructions.append(&mut instructions_idx0); + for i in 1..index_list.len() { + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of dimension of [1] (recall that first dimension is not added) + instructions.push(load32(Some(&infopos.to_string()))); // second dimension + instructions.push(mul32()); + let mut instructions_idxi = index_list[i].produce_wasm(producer); + instructions.append(&mut instructions_idxi); + instructions.push(add32()); + } + let field_size = producer.get_size_32_bits_in_memory() * 4; + instructions.push(set_constant(&field_size.to_string())); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of size + instructions.push(load32(Some(&infopos.to_string()))); // size + instructions.push(mul32()); // size mult by size of field in bytes + instructions.push(mul32()); // total offset in the array + instructions.push(add32()); // to the current offset + idxpos += 1; + if idxpos < indexes.len() { + //next must be Qualified + if let AccessType::Indexed(_) = &indexes[idxpos] { + assert!(false); + } + // we add the type of bus it is + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; + instructions.push(load32(Some(&infopos.to_string()))); // bus_id + } + } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { + //we have on the stack the bus_id + instructions.push(load32(Some( + &producer.get_bus_instance_to_field_start().to_string() + ))); // get position in the bus to field in memory + let field_no_bytes = field_no * 4; + instructions.push(load32(Some(&field_no_bytes.to_string()))); // get position in the field info in memory + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(tee_local(producer.get_io_info_tag())); + } + let field_size = producer.get_size_32_bits_in_memory() * 4; + instructions.push(set_constant(&field_size.to_string())); + instructions.push(load32(None)); // get the offset + instructions.push(mul32()); // mult by size of field in bytes + instructions.push(add32()); // add to the current offset + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // bus_id + } + } else { + assert!(false); + } + } + } instructions.push(get_local(producer.get_sub_cmp_load_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), @@ -196,7 +233,6 @@ impl WriteC for LoadBucket { if let LocationRule::Indexed { location, .. } = &self.src { location.produce_c(producer, parallel) } else if let LocationRule::Mapped { signal_code, indexes } = &self.src { - // TODO: add the offset let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); let mut map_access = format!("{}->{}[{}].defs[{}].offset", diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index c9901d4c8..be9e9faa6 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -102,7 +102,6 @@ impl WriteWasm for StoreBucket { instructions.push(add32()); } LocationRule::Mapped { signal_code, indexes } => { - // TODO: ADD THE OFFSET match &self.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { @@ -119,8 +118,8 @@ impl WriteWasm for StoreBucket { instructions.push(mul32()); instructions.push(add32()); instructions.push(load32(None)); //subcomponent block - instructions.push(set_local(producer.get_sub_cmp_tag())); - instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(tee_local(producer.get_sub_cmp_tag())); + //instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(load32(None)); // get template id A instructions.push(set_constant("4")); //size in byte of i32 instructions.push(mul32()); @@ -130,48 +129,84 @@ impl WriteWasm for StoreBucket { let signal_code_in_bytes = signal_code * 4; //position in the list of the signal code instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one - // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED - // descomentar todo lo siguiente, quitado para evitar error - /* - if indexes.len() <= 1 { - instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); - if indexes.len() == 1 { - let mut instructions_idx0 = indexes[0].produce_wasm(producer); - instructions.append(&mut instructions_idx0); - let size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&size.to_string())); - instructions.push(mul32()); - instructions.push(add32()); - } - } else { - instructions.push(set_local(producer.get_io_info_tag())); - instructions.push(get_local(producer.get_io_info_tag())); - instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); - // compute de move with 2 or more dimensions - let mut instructions_idx0 = indexes[0].produce_wasm(producer); - instructions.append(&mut instructions_idx0); // start with dimension 0 - for i in 1..indexes.len() { - instructions.push(get_local(producer.get_io_info_tag())); - let offsetdim = 4 * i; - instructions.push(load32(Some(&offsetdim.to_string()))); // get size of ith dimension - instructions.push(mul32()); // multiply the current move by size of the ith dimension - let mut instructions_idxi = indexes[i].produce_wasm(producer); - instructions.append(&mut instructions_idxi); - instructions.push(add32()); // add move upto dimension i - } - //we have the total move; and is multiplied by the size of memory Fr in bytes - let size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&size.to_string())); - instructions.push(mul32()); // We have the total move in bytes - instructions.push(add32()); // add to the offset of the signal - } - */ + if indexes.len() == 0 { + instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); + } else { + instructions.push(tee_local(producer.get_io_info_tag())); + instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) + // if the first access is qualified we place the address of the bus_id + if let AccessType::Qualified(_) = &indexes[0] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // it is a bus, so the bus_id is in the second position + } + let mut idxpos = 0; + while idxpos < indexes.len() { + if let AccessType::Indexed(index_list) = &indexes[idxpos] { + let mut infopos = 0; + assert!(index_list.len() > 0); + //We first compute the number of elements as + //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] + //first position in the array access + let mut instructions_idx0 = index_list[0].produce_wasm(producer); + instructions.append(&mut instructions_idx0); + for i in 1..index_list.len() { + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of dimension of [1] (recall that first dimension is not added) + instructions.push(load32(Some(&infopos.to_string()))); // second dimension + instructions.push(mul32()); + let mut instructions_idxi = index_list[i].produce_wasm(producer); + instructions.append(&mut instructions_idxi); + instructions.push(add32()); + } + let field_size = producer.get_size_32_bits_in_memory() * 4; + instructions.push(set_constant(&field_size.to_string())); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of size + instructions.push(load32(Some(&infopos.to_string()))); // size + instructions.push(mul32()); // size mult by size of field in bytes + instructions.push(mul32()); // total offset in the array + instructions.push(add32()); // to the current offset + idxpos += 1; + if idxpos < indexes.len() { + //next must be Qualified + if let AccessType::Indexed(_) = &indexes[idxpos] { + assert!(false); + } + // we add the type of bus it is + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; + instructions.push(load32(Some(&infopos.to_string()))); // bus_id + } + } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { + //we have on the stack the bus_id + instructions.push(load32(Some( + &producer.get_bus_instance_to_field_start().to_string() + ))); // get position in the bus to field in memory + let field_no_bytes = field_no * 4; + instructions.push(load32(Some(&field_no_bytes.to_string()))); // get position in the field info in memory + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(tee_local(producer.get_io_info_tag())); + } + let field_size = producer.get_size_32_bits_in_memory() * 4; + instructions.push(set_constant(&field_size.to_string())); + instructions.push(load32(None)); // get the offset + instructions.push(mul32()); // mult by size of field in bytes + instructions.push(add32()); // add to the current offset + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // bus_id + } + } else { + assert!(false); + } + } + } instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), )); instructions.push(add32()); - instructions.push(load32(None)); //subcomponent start_of_signals + instructions.push(load32(None)); //subcomponent start_of_signals: first info in the subcomponent instructions.push(add32()); // we get the position of the signal (with indexes) in memory } _ => { @@ -313,7 +348,6 @@ impl WriteC for StoreBucket { if let LocationRule::Indexed { location, template_header } = &self.dest { (location.produce_c(producer, parallel), template_header.clone()) } else if let LocationRule::Mapped { signal_code, indexes} = &self.dest { - // TODO: add the offset //if Mapped must be SubcmpSignal let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); From 19dee2129b4a98c8f9339c304d8461d52a2b8c56 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 4 Jul 2024 12:19:54 +0200 Subject: [PATCH 116/189] removing check sizes translate for testing --- compiler/src/intermediate_representation/translate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 332e47c2b..420e9e95d 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -1171,7 +1171,7 @@ impl ProcessedSymbol { else{ // TODO: case buses -> take into account the size of the elem, possible lengths if with_length != possible_length.iter().fold(1, |r, c| r * (*c)){ - unreachable!("On development: Circom compiler does not accept for now the assignment of arrays of unknown sizes during the execution of loops"); + //unreachable!("On development: Circom compiler does not accept for now the assignment of arrays of unknown sizes during the execution of loops"); } } } From 1a3780409e4aecc19d1930e96e81884de6ee98b5 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 4 Jul 2024 19:55:37 +0200 Subject: [PATCH 117/189] adding check sizes, first version, needs improvement --- .../intermediate_representation/translate.rs | 111 ++++++++++++------ 1 file changed, 76 insertions(+), 35 deletions(-) diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 420e9e95d..aaf29bb34 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -7,6 +7,7 @@ use program_structure::ast::*; use program_structure::file_definition::FileLibrary; use program_structure::utils::environment::VarEnvironment; use std::collections::{HashMap, BTreeMap, HashSet}; +use std::mem; type Length = usize; pub type E = VarEnvironment; @@ -982,7 +983,6 @@ fn build_signal_location( accesses.push(AccessType::Qualified(field_ids[i])); i+=1; } - unreachable!("TODO: mixed array"); LocationRule::Mapped { signal_code, indexes: accesses } } Uniform { instance_id, header, .. } => { @@ -1030,9 +1030,12 @@ impl ProcessedSymbol { let meta = definition.meta; let symbol_info = state.environment.get_variable(&symbol_name).unwrap().clone(); + + // TODO: move the the struct defined later let mut lengths = symbol_info.dimensions.clone(); lengths.reverse(); - let mut with_length = symbol_info.size; + let mut with_length: usize = symbol_info.size; + let mut accessed_component_signal = None; let mut signal_type = state.signal_to_type.get(&symbol_name).cloned(); @@ -1040,10 +1043,17 @@ impl ProcessedSymbol { let mut after_indexes = vec![]; // indexes accessed after component (or no component) let mut current_index = vec![]; + // we store the possible sizes and lengths -> in heterogeneus arrays + // they may be multiple + // TODO: store in single struct let mut multiple_possible_lengths: Vec> = vec![]; + let mut multiple_possible_sizes: Vec = vec![]; + let mut multiple_possible_bus_fields: Vec> = vec![]; + let mut is_bus = symbol_info.is_bus; let mut is_component = symbol_info.is_component; + // TODO: not needed let mut bus_fields = if symbol_info.bus_id.is_some(){ let id = symbol_info.bus_id.unwrap(); Some(context.buses.get(id).unwrap().fields.clone()) @@ -1059,19 +1069,18 @@ impl ProcessedSymbol { for acc in definition.acc { match acc { ArrayAccess(exp) if accessed_component_signal.is_none() => { + // in this case we have a single possible length and size let length = lengths.pop().unwrap(); with_length /= length; current_index.push(translate_expression(exp, state, context)); } ArrayAccess(exp) => { - let mut is_first = true; + // in this case we need to study all possible sizes and lenghts + let mut index = 0; for possible_length in &mut multiple_possible_lengths{ - let aux_length = possible_length.pop(); - if is_first{ - with_length /= aux_length.unwrap(); - is_first = false; - } + multiple_possible_sizes[index] /= aux_length.unwrap(); + index += 1; } current_index.push(translate_expression(exp, state, context)); @@ -1088,8 +1097,9 @@ impl ProcessedSymbol { let mut new_length = aux.lengths.clone(); new_length.reverse(); multiple_possible_lengths.push(new_length); + multiple_possible_sizes.push(aux.size); + if is_first{ - with_length = aux.size; bus_fields = None; symbol_size = vec![aux.size]; @@ -1102,14 +1112,15 @@ impl ProcessedSymbol { let mut new_length = aux.lengths.clone(); new_length.reverse(); multiple_possible_lengths.push(new_length); + multiple_possible_sizes.push(aux.size); + multiple_possible_bus_fields.push(context.buses.get(aux.bus_id).unwrap().fields.clone()); + if is_first{ - with_length = aux.size; symbol_size = vec![aux.size]; symbol_dimensions = vec![aux.lengths.clone()]; // case buses: update the info is_bus = true; - bus_fields = Some(context.buses.get(aux.bus_id).unwrap().fields.clone()); is_first = false; } @@ -1124,26 +1135,58 @@ impl ProcessedSymbol { is_component = false; accessed_component_signal = Some(name); } else if is_bus{ - let fields = bus_fields.unwrap(); - let field_info = fields.get(&name).unwrap(); - let mut new_length = field_info.dimensions.clone(); - new_length.reverse(); - multiple_possible_lengths = vec![new_length.clone()]; - lengths = new_length; - with_length = field_info.size; - - is_bus = field_info.bus_id.is_some(); - bus_fields = if field_info.bus_id.is_some(){ - let id = field_info.bus_id.unwrap(); - Some(context.buses.get(id).unwrap().fields.clone()) + // case no component access + if accessed_component_signal.is_none(){ + let fields = bus_fields.unwrap(); + let field_info = fields.get(&name).unwrap(); + let mut new_length = field_info.dimensions.clone(); + new_length.reverse(); + lengths = new_length; + with_length = field_info.size; + + + is_bus = field_info.bus_id.is_some(); + bus_fields = if field_info.bus_id.is_some(){ + let id = field_info.bus_id.unwrap(); + Some(context.buses.get(id).unwrap().fields.clone()) + } else{ + None + }; + + offset.push(field_info.offset); + field_ids.push(field_info.field_id); + symbol_size.push(field_info.size); + symbol_dimensions.push(field_info.dimensions.clone()); } else{ - None - }; + // set to new to start the size check again + let old_possible_fields = mem::take(&mut multiple_possible_bus_fields); + multiple_possible_lengths = vec![]; + multiple_possible_sizes = vec![]; + let mut is_first = true; + + for possible_fields in old_possible_fields{ + let field_info = possible_fields.get(&name).unwrap(); + let mut new_length = field_info.dimensions.clone(); + new_length.reverse(); + multiple_possible_lengths.push(new_length); + multiple_possible_sizes.push(field_info.size); + + if field_info.bus_id.is_some(){ + let id = field_info.bus_id.unwrap(); + multiple_possible_bus_fields.push(context.buses.get(id).unwrap().fields.clone()) + } + if is_first{ + is_bus = field_info.bus_id.is_some(); - offset.push(field_info.offset); - field_ids.push(field_info.field_id); - symbol_size.push(field_info.size); - symbol_dimensions.push(field_info.dimensions.clone()); + offset.push(field_info.offset); + field_ids.push(field_info.field_id); + symbol_size.push(field_info.size); + symbol_dimensions.push(field_info.dimensions.clone()); + } + is_first = false; + } + } + // We move the current index into the after_indexes let aux_index = std::mem::take(&mut current_index); @@ -1162,16 +1205,14 @@ impl ProcessedSymbol { if accessed_component_signal.is_some(){ let mut is_first = true; - for possible_length in multiple_possible_lengths{ + for possible_size in multiple_possible_sizes{ if is_first{ - // TODO: does not work in case buses - //with_length = possible_length.iter().fold(1, |r, c| r * (*c)); + with_length = possible_size; is_first = false; } else{ - // TODO: case buses -> take into account the size of the elem, possible lengths - if with_length != possible_length.iter().fold(1, |r, c| r * (*c)){ - //unreachable!("On development: Circom compiler does not accept for now the assignment of arrays of unknown sizes during the execution of loops"); + if with_length != possible_size{ + unreachable!("On development: Circom compiler does not accept for now the assignment of arrays of unknown sizes during the execution of loops"); } } } From dee8d42f79f64a7e92eafec304b0a1881dda4185 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 9 Jul 2024 18:26:44 +0200 Subject: [PATCH 118/189] refractor translate --- code_producers/src/lib.rs | 10 - compiler/src/circuit_design/build.rs | 4 +- .../intermediate_representation/translate.rs | 491 ++++++++++-------- 3 files changed, 275 insertions(+), 230 deletions(-) diff --git a/code_producers/src/lib.rs b/code_producers/src/lib.rs index ea21686d3..46fd883c6 100644 --- a/code_producers/src/lib.rs +++ b/code_producers/src/lib.rs @@ -5,13 +5,3 @@ pub mod wasm_elements; pub mod components; - -#[derive(Default, Clone)] -pub struct FieldData{ - pub dimensions: Vec, - pub size: usize, - pub offset: usize, - pub bus_id: Option -} - -pub type FieldMap = Vec>; diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 02c3ee8d9..993f101de 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -14,9 +14,9 @@ fn matching_lengths_and_offsets(list: &InputOutputList) { let mut prev = 0; let mut offset = 0; for signal in list { - debug_assert_eq!(signal.offset, prev + offset); + //debug_assert_eq!(signal.offset, prev + offset); prev = signal.offset; - offset = signal.lengths.iter().fold(1, |p, c| p * (*c)); + offset = signal.lengths.iter().fold(signal.size, |p, c| p * (*c)); } } diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index aaf29bb34..e977e4409 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -24,26 +24,16 @@ pub struct SymbolInfo { bus_id: Option, } -#[derive(Clone)] -pub enum WireInfo{ - Signal(SignalInfo), - Bus(BusInfo) -} #[derive(Clone)] -pub struct SignalInfo{ +pub struct WireInfo{ signal_type: SignalType, lengths: Vec, size: usize, + bus_id: Option, // in case signal it is none } -#[derive(Clone)] -pub struct BusInfo{ - signal_type: SignalType, - lengths: Vec, - bus_id: usize, - size: usize, -} + #[derive(Clone)] pub struct TemplateDB { @@ -101,22 +91,22 @@ impl TemplateDB { for wire in &instance.wires { match wire{ Wire::TSignal(signal) =>{ - let info = SignalInfo{ + let info = WireInfo{ size: signal.size, signal_type: signal.xtype, lengths: signal.lengths.clone(), + bus_id: None }; - wire_info.insert(signal.name.clone(), WireInfo::Signal(info)); + wire_info.insert(signal.name.clone(), info); }, Wire::TBus(bus) =>{ - - let info = BusInfo{ + let info = WireInfo{ size: bus.size, signal_type: bus.xtype, lengths: bus.lengths.clone(), - bus_id: bus.bus_id + bus_id: Some(bus.bus_id) }; - wire_info.insert(bus.name.clone(), WireInfo::Bus(info)); + wire_info.insert(bus.name.clone(), info); } } } @@ -963,10 +953,9 @@ fn build_signal_location( indexes: Vec>, context: &Context, state: &State, - dimensions: Vec>, - size: Vec, - offset: Vec, - field_ids: Vec + dimensions: Vec, + size: usize, + bus_accesses: Vec, ) -> LocationRule { use ClusterType::*; let database = &context.tmp_database; @@ -977,10 +966,16 @@ fn build_signal_location( let mut accesses = Vec::new(); let mut i = 0; - for indexes in indexes{ - let filtered = indexing_instructions_filter(indexes, state); - accesses.push(AccessType::Indexed(filtered)); - accesses.push(AccessType::Qualified(field_ids[i])); + let len_indexes = indexes.len(); + for index in indexes{ + let filtered = indexing_instructions_filter(index, state); + if filtered.len() > 0{ + accesses.push(AccessType::Indexed(filtered)); + } + if i != len_indexes -1{ + // The last access is just an index + accesses.push(AccessType::Qualified(bus_accesses[i].field_id)); + } i+=1; } LocationRule::Mapped { signal_code, indexes: accesses } @@ -993,8 +988,9 @@ fn build_signal_location( location.access_instruction, dimensions, size, + bus_accesses, indexes, - offset + ); LocationRule::Indexed { location: full_address, template_header: Some(header.clone()) } } @@ -1007,11 +1003,26 @@ struct SymbolDef { acc: Vec, } +// It stores the possible lengths and sizes of the access +// --> Case heterogeneus components -> might be different +struct PossibleInfo{ + possible_sizes: Vec, + possible_lengths: Vec>, + possible_bus_fields: Option>> +} + +struct BusAccessInfo{ + offset: usize, + field_id: usize, + size: usize, + lengths: Vec +} + struct ProcessedSymbol { line: usize, length: usize, - symbol_dimensions: Vec>, // the dimensions of each one of the buses - symbol_size: Vec, // the sizes of the buses + symbol_dimensions: Vec, // the dimensions of last symbol + symbol_size: usize, // the size of the last symbol message_id: usize, name: String, symbol: SymbolInfo, @@ -1019,170 +1030,159 @@ struct ProcessedSymbol { signal: Option, signal_type: Option, before_signal: Vec>, - // in case it is a bus indicate the offset of the field - offset: Vec, + // in case it is a bus indicate the bus accesses info + bus_accesses: Vec, } impl ProcessedSymbol { fn new(definition: SymbolDef, state: &mut State, context: &Context) -> ProcessedSymbol { use Access::*; + + // Getting the symbol info let symbol_name = definition.symbol; let meta = definition.meta; - let symbol_info = state.environment.get_variable(&symbol_name).unwrap().clone(); - - // TODO: move the the struct defined later - let mut lengths = symbol_info.dimensions.clone(); - lengths.reverse(); - let mut with_length: usize = symbol_info.size; - - let mut accessed_component_signal = None; let mut signal_type = state.signal_to_type.get(&symbol_name).cloned(); - - let mut before_index = vec![]; // indexes accessed before component - let mut after_indexes = vec![]; // indexes accessed after component (or no component) - let mut current_index = vec![]; - - // we store the possible sizes and lengths -> in heterogeneus arrays - // they may be multiple - // TODO: store in single struct - let mut multiple_possible_lengths: Vec> = vec![]; - let mut multiple_possible_sizes: Vec = vec![]; - let mut multiple_possible_bus_fields: Vec> = vec![]; - let mut is_bus = symbol_info.is_bus; let mut is_component = symbol_info.is_component; - - // TODO: not needed - let mut bus_fields = if symbol_info.bus_id.is_some(){ + let mut accessed_component_signal = None; + + // Initializing the status (single case by now) + let mut length = symbol_info.dimensions.clone(); + length.reverse(); + let bus_fields = if symbol_info.bus_id.is_some(){ let id = symbol_info.bus_id.unwrap(); - Some(context.buses.get(id).unwrap().fields.clone()) + Some(vec![context.buses.get(id).unwrap().fields.clone()]) } else{ None }; + let mut possible_status = PossibleInfo{ + possible_lengths: vec![length], + possible_sizes: vec![symbol_info.size], + possible_bus_fields: bus_fields, + }; + + // Arrays to store the index accesses (before and after the component access) + let mut before_index: Vec = vec![]; // indexes accessed before component + let mut after_indexes: Vec> = vec![]; // indexes accessed after component (or no component) + // we groud the same bus accesses in same position + let mut current_index: Vec = vec![]; // current accesses, updating now - let mut offset = Vec::new(); - let mut field_ids = Vec::new(); - let mut symbol_size = vec![symbol_info.size]; - let mut symbol_dimensions = vec![symbol_info.dimensions.clone()]; + // Information about the current and accessed fields + let mut accessed_fields_info: Vec = Vec::new(); + let mut initial_symbol_size = symbol_info.size; + let mut initial_symbol_dimensions = symbol_info.dimensions.clone(); for acc in definition.acc { match acc { - ArrayAccess(exp) if accessed_component_signal.is_none() => { - // in this case we have a single possible length and size - let length = lengths.pop().unwrap(); - with_length /= length; - current_index.push(translate_expression(exp, state, context)); - } + ArrayAccess(exp) => { - // in this case we need to study all possible sizes and lenghts + // we need to study all possible sizes and lenghts let mut index = 0; - for possible_length in &mut multiple_possible_lengths{ + for possible_length in &mut possible_status.possible_lengths{ let aux_length = possible_length.pop(); - multiple_possible_sizes[index] /= aux_length.unwrap(); + possible_status.possible_sizes[index] /= aux_length.unwrap(); index += 1; } current_index.push(translate_expression(exp, state, context)); } + ComponentAccess(name) => { + // we distinguish the cases component and bus if is_component{ + let possible_cmp_id = state.component_to_instance.get(&symbol_name).unwrap().clone(); let mut is_first = true; + + // We init the possible lenghts and sizes + possible_status.possible_lengths = Vec::new(); + possible_status.possible_sizes = Vec::new(); + for cmp_id in possible_cmp_id{ - let aux = context.tmp_database.wire_info[cmp_id].get(&name).unwrap(); - match aux{ - WireInfo::Signal(aux) => { - signal_type = Some(aux.signal_type); - let mut new_length = aux.lengths.clone(); - new_length.reverse(); - multiple_possible_lengths.push(new_length); - multiple_possible_sizes.push(aux.size); - - if is_first{ - bus_fields = None; - - symbol_size = vec![aux.size]; - symbol_dimensions = vec![aux.lengths.clone()]; - is_first = false - } + // aux contains the info about the accessed wire + let aux = context.tmp_database.wire_info[cmp_id].get(&name).unwrap(); + signal_type = Some(aux.signal_type); + // update the possible status + let mut new_length = aux.lengths.clone(); + new_length.reverse(); + possible_status.possible_lengths.push(new_length); + possible_status.possible_sizes.push(aux.size); + + if aux.bus_id.is_some(){ + let fields = context.buses.get(aux.bus_id.unwrap()).unwrap().fields.clone(); + if is_first{ + is_bus = true; + possible_status.possible_bus_fields = Some(vec![fields]); + } else{ + possible_status.possible_bus_fields.as_mut().unwrap().push(fields); } - WireInfo::Bus(aux) =>{ - signal_type = Some(aux.signal_type); - let mut new_length = aux.lengths.clone(); - new_length.reverse(); - multiple_possible_lengths.push(new_length); - multiple_possible_sizes.push(aux.size); - multiple_possible_bus_fields.push(context.buses.get(aux.bus_id).unwrap().fields.clone()); - - if is_first{ - symbol_size = vec![aux.size]; - symbol_dimensions = vec![aux.lengths.clone()]; - - // case buses: update the info - is_bus = true; - bus_fields = Some(context.buses.get(aux.bus_id).unwrap().fields.clone()); - is_first = false; - } + + } else{ + if is_first{ + is_bus = false; + possible_status.possible_bus_fields = None; } } + + if is_first{ + // this will be used in the case of + // homogeneus component + initial_symbol_size = aux.size; + initial_symbol_dimensions = aux.lengths.clone(); + is_first = false + } + } // The current indexes are before index assert!(after_indexes.len() == 0); + before_index = std::mem::take(&mut current_index); is_component = false; accessed_component_signal = Some(name); + } else if is_bus{ - // case no component access - if accessed_component_signal.is_none(){ - let fields = bus_fields.unwrap(); - let field_info = fields.get(&name).unwrap(); + + // set to new to start the size check again + let old_possible_fields = mem::take(&mut possible_status.possible_bus_fields.unwrap()); + possible_status.possible_lengths = vec![]; + possible_status.possible_sizes = vec![]; + possible_status.possible_bus_fields = None; // Just to have an init + + let mut is_first = true; + + // check each one of the options for the field sizes + for possible_fields in old_possible_fields{ + let field_info = possible_fields.get(&name).unwrap(); let mut new_length = field_info.dimensions.clone(); new_length.reverse(); - lengths = new_length; - with_length = field_info.size; - + possible_status.possible_lengths.push(new_length); + possible_status.possible_sizes.push(field_info.size); - is_bus = field_info.bus_id.is_some(); - bus_fields = if field_info.bus_id.is_some(){ + if field_info.bus_id.is_some(){ let id = field_info.bus_id.unwrap(); - Some(context.buses.get(id).unwrap().fields.clone()) - } else{ - None - }; - - offset.push(field_info.offset); - field_ids.push(field_info.field_id); - symbol_size.push(field_info.size); - symbol_dimensions.push(field_info.dimensions.clone()); - } else{ - // set to new to start the size check again - let old_possible_fields = mem::take(&mut multiple_possible_bus_fields); - multiple_possible_lengths = vec![]; - multiple_possible_sizes = vec![]; - let mut is_first = true; - - for possible_fields in old_possible_fields{ - let field_info = possible_fields.get(&name).unwrap(); - let mut new_length = field_info.dimensions.clone(); - new_length.reverse(); - multiple_possible_lengths.push(new_length); - multiple_possible_sizes.push(field_info.size); - - if field_info.bus_id.is_some(){ - let id = field_info.bus_id.unwrap(); - multiple_possible_bus_fields.push(context.buses.get(id).unwrap().fields.clone()) - } + let fields = context.buses.get(id).unwrap().fields.clone(); if is_first{ - is_bus = field_info.bus_id.is_some(); - - offset.push(field_info.offset); - field_ids.push(field_info.field_id); - symbol_size.push(field_info.size); - symbol_dimensions.push(field_info.dimensions.clone()); + possible_status.possible_bus_fields = Some(vec![fields]); + } else{ + possible_status.possible_bus_fields.as_mut().unwrap().push(fields); } + } else{ + possible_status.possible_bus_fields = None; + } + if is_first{ + is_bus = field_info.bus_id.is_some(); + accessed_fields_info.push({ + BusAccessInfo{ + offset: field_info.offset, + field_id: field_info.field_id, + size: field_info.size, + lengths: field_info.dimensions.clone() + } + }); + is_first = false; } } @@ -1203,9 +1203,15 @@ impl ProcessedSymbol { let aux_index = std::mem::take(&mut current_index); after_indexes.push(aux_index); + if accessed_component_signal.is_some(){ + // Case accessing a io signal of a subcomponent + + // First check that the possible sizes are all equal let mut is_first = true; - for possible_size in multiple_possible_sizes{ + let mut with_length: usize = 0; + + for possible_size in possible_status.possible_sizes{ if is_first{ with_length = possible_size; is_first = false; @@ -1216,57 +1222,76 @@ impl ProcessedSymbol { } } } - } - - // TODO: improve cases, unnecesary clone - // in case it is a signal of a subcomponent we use the offset when - // building the signal location, if not use late - let (remaining_offset, remaining_size, remaining_dimensions, remaining_indexes) = if accessed_component_signal.is_some(){ - // they go to the original vector - ( - Vec::new(), - vec![symbol_info.size.clone()], - vec![symbol_info.dimensions.clone()], - vec![before_index] - ) - } else{ - ( - offset.clone(), - symbol_size.clone(), - symbol_dimensions.clone(), - after_indexes.clone() - ) - }; - let signal_location = accessed_component_signal.map(|signal_name| { - build_signal_location( - &signal_name, + // Compute the signal location inside the component + let signal_location = build_signal_location( + &accessed_component_signal.unwrap(), &symbol_name, after_indexes, context, state, - symbol_dimensions, - symbol_size, - offset, - field_ids - ) - }); + initial_symbol_dimensions, + initial_symbol_size, + accessed_fields_info, + ); - ProcessedSymbol { - xtype: meta.get_type_knowledge().get_reduces_to(), - line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), - message_id: state.message_id, - length: with_length, - symbol_dimensions: remaining_dimensions, - symbol_size: remaining_size, - symbol: symbol_info, - name: symbol_name, - before_signal: remaining_indexes, - signal: signal_location, - signal_type, - offset: remaining_offset + // compute the component location + ProcessedSymbol { + xtype: meta.get_type_knowledge().get_reduces_to(), + line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), + message_id: state.message_id, + length: with_length, + symbol_dimensions: symbol_info.dimensions.clone(), + symbol_size: symbol_info.size, + symbol: symbol_info, + name: symbol_name, + before_signal: vec![before_index], + signal: Some(signal_location), + signal_type, + bus_accesses: Vec::new() + } + } else{ + + assert!(possible_status.possible_sizes.len() == 1); + let with_length: usize = possible_status.possible_sizes[0]; + + ProcessedSymbol { + xtype: meta.get_type_knowledge().get_reduces_to(), + line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), + message_id: state.message_id, + length: with_length, + symbol_dimensions: initial_symbol_dimensions, + symbol_size: initial_symbol_size, + symbol: symbol_info, + name: symbol_name, + before_signal: after_indexes, + signal: None, + signal_type, + bus_accesses: accessed_fields_info + } } + + // TODO: improve cases, unnecesary clone + // in case it is a signal of a subcomponent we use the offset when + // building the signal location, if not use late + // let (remaining_offset, remaining_size, remaining_dimensions, remaining_indexes) = if accessed_component_signal.is_some(){ + // // they go to the original vector + // ( + // Vec::new(), + // vec![symbol_info.size.clone()], + // vec![symbol_info.dimensions.clone()], + // vec![before_index] + // ) + // } else{ + // ( + // offset.clone(), + // symbol_size.clone(), + // symbol_dimensions.clone(), + // after_indexes.clone() + // ) + // }; + } fn into_call_assign( @@ -1282,8 +1307,8 @@ impl ProcessedSymbol { self.symbol.access_instruction, self.symbol_dimensions, self.symbol_size, + self.bus_accesses, self.before_signal, - self.offset ), is_output: self.signal_type.unwrap() == SignalType::Output, uniform_parallel_value: state.component_to_parallel.get(&self.name).unwrap().uniform_parallel_value, @@ -1304,8 +1329,8 @@ impl ProcessedSymbol { self.symbol.access_instruction, self.symbol_dimensions, self.symbol_size, - self.before_signal, - self.offset + self.bus_accesses, + self.before_signal, ); let xtype = match self.xtype { TypeReduction::Variable => AddressType::Variable, _ => AddressType::Signal, @@ -1337,8 +1362,8 @@ impl ProcessedSymbol { self.symbol.access_instruction, self.symbol_dimensions, self.symbol_size, + self.bus_accesses, self.before_signal, - self.offset ), uniform_parallel_value: state.component_to_parallel.get(&self.name).unwrap().uniform_parallel_value, is_output: self.signal_type.unwrap() == SignalType::Output, @@ -1363,8 +1388,8 @@ impl ProcessedSymbol { self.symbol.access_instruction, self.symbol_dimensions, self.symbol_size, - self.before_signal, - self.offset + self.bus_accesses, + self.before_signal, ); let xtype = match self.xtype { TypeReduction::Variable => AddressType::Variable, @@ -1391,8 +1416,8 @@ impl ProcessedSymbol { self.symbol.access_instruction, self.symbol_dimensions, self.symbol_size, + self.bus_accesses, self.before_signal, - self.offset ), uniform_parallel_value: state.component_to_parallel.get(&self.name).unwrap().uniform_parallel_value, is_output: self.signal_type.unwrap() == SignalType::Output, @@ -1415,8 +1440,8 @@ impl ProcessedSymbol { self.symbol.access_instruction, self.symbol_dimensions, self.symbol_size, - self.before_signal, - self.offset + self.bus_accesses, + self.before_signal, ); let xtype = match self.xtype { TypeReduction::Variable => AddressType::Variable, @@ -1437,29 +1462,68 @@ impl ProcessedSymbol { fn compute_full_address( state: &State, symbol_access_instr: InstructionPointer, - dimensions: Vec>, // for each one of the bus accesses one dimensions - size: Vec, // each one of the field sizes + mut dimensions: Vec, // for each one of the bus accesses one dimensions + size: usize, // each one of the field sizes + bus_accesses: Vec, indexed_with: Vec>, // each one of the accesses - offset: Vec, // each one of the field offsets ) -> InstructionPointer { let at = symbol_access_instr; let mut stack = vec![]; - let number_bus_access = offset.len(); - assert!(number_bus_access == dimensions.len() - 1); - assert!(number_bus_access == size.len() - 1); + let number_bus_access = bus_accesses.len(); + assert!(number_bus_access == indexed_with.len() - 1); + + // add the initial indexing + dimensions.reverse(); + let mut linear_length = size; + // TODO: not needed clone + let index_stack = indexing_instructions_filter(indexed_with[0].clone(), state); + for instruction in index_stack { + let dimension_length = dimensions.pop().unwrap(); + linear_length /= dimension_length; + let inst = ValueBucket { + line: at.get_line(), + message_id: at.get_message_id(), + parse_as: ValueType::U32, + op_aux_no: 0, + value: linear_length, + } + .allocate(); + let jump = ComputeBucket { + line: at.get_line(), + message_id: at.get_message_id(), + op_aux_no: 0, + op: OperatorType::MulAddress, + stack: vec![inst, instruction], + } + .allocate(); + stack.push(jump); + } + + let mut index = 1; + + + for mut access in bus_accesses{ - let mut index = 0; + if access.offset != 0{ + let offset_bucket = ValueBucket { + line: at.get_line(), + message_id: at.get_message_id(), + parse_as: ValueType::U32, + op_aux_no: 0, + value: access.offset, + }.allocate(); + stack.push(offset_bucket); + } - for mut with_dimensions in dimensions{ - with_dimensions.reverse(); - let mut linear_length = size[index]; + access.lengths.reverse(); + let mut linear_length = access.size; // TODO: not needed clone let index_stack = indexing_instructions_filter(indexed_with[index].clone(), state); for instruction in index_stack { - let dimension_length = with_dimensions.pop().unwrap(); + let dimension_length = access.lengths.pop().unwrap(); linear_length /= dimension_length; let inst = ValueBucket { line: at.get_line(), @@ -1479,16 +1543,7 @@ fn compute_full_address( .allocate(); stack.push(jump); } - if index != number_bus_access && offset[index] != 0{ - let offset_bucket = ValueBucket { - line: at.get_line(), - message_id: at.get_message_id(), - parse_as: ValueType::U32, - op_aux_no: 0, - value: offset[index], - }.allocate(); - stack.push(offset_bucket); - } + index += 1; } From fcccb9c0b7ca91f610098da36624bb98555ec1a2 Mon Sep 17 00:00:00 2001 From: alrubio Date: Thu, 11 Jul 2024 12:00:56 +0200 Subject: [PATCH 119/189] adding code for debugging and fixing bugs --- .../src/c_elements/c_code_generator.rs | 9 +++- .../src/c_elements/common/circom.hpp | 11 ++-- .../common/witness_calculator.js | 3 ++ code_producers/src/wasm_elements/mod.rs | 3 +- .../src/wasm_elements/wasm_code_generator.rs | 52 +++++++++++++------ 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 5ec19413d..9e38e2b15 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -18,8 +18,8 @@ const CIRCOM_HASH_ENTRY_FIELDS: [&str; 3] = ["hash", "signalid", "signalsize"]; const S_CIRCOM_COMPONENT: &str = "Circom_Component"; const CIRCOM_COMPONENT_FIELDS: [&str; 4] = ["templateID", "signalStart", "inputCounter", "subcomponents"]; -const S_IO_DEF: &str = "IODef"; -const IO_DEF_FIELDS: [&str; 2] = ["offset", "lengths"]; +const S_IOField_DEF: &str = "IOFieldDef"; +const IOField_DEF_FIELDS: [&str; 4] = ["offset", "size", "lengths", "busid"]; // Global variables pub const SIZE_INPUT_HASHMAP: usize = 256; @@ -143,6 +143,11 @@ pub fn template_ins_2_io_info() -> CInstruction { format!("{}", TEMP_INS_2_IO_INFO) } +pub const BUS_INS_2_Field_INFO: &str = "busInsId2FieldInfo"; +pub fn bus_ins_2_field_info() -> CInstruction { + format!("{}", BUS_INS_2_Field_INFO) +} + pub fn template_id_in_component(idx: CInstruction) -> CInstruction { format!("{}->componentMemory[{}].templateId", CIRCOM_CALC_WIT, idx) } diff --git a/code_producers/src/c_elements/common/circom.hpp b/code_producers/src/c_elements/common/circom.hpp index eabc686f6..617784b4c 100644 --- a/code_producers/src/c_elements/common/circom.hpp +++ b/code_producers/src/c_elements/common/circom.hpp @@ -20,15 +20,17 @@ struct __attribute__((__packed__)) HashSignalInfo { u64 signalsize; }; -struct IODef { +struct IOFieldDef { u32 offset; + u32 size; u32 len; u32 *lengths; + u32 busid; }; -struct IODefPair { +struct IOFieldDefPair { u32 len; - IODef* defs; + IOFieldDef* defs; }; struct Circom_Circuit { @@ -36,7 +38,8 @@ struct Circom_Circuit { HashSignalInfo* InputHashMap; u64* witness2SignalList; FrElement* circuitConstants; - std::map templateInsId2IOSignalInfo; + std::map templateInsId2IOSignalInfo; + IOFieldDefPair* busInsId2FieldInfo; }; diff --git a/code_producers/src/wasm_elements/common/witness_calculator.js b/code_producers/src/wasm_elements/common/witness_calculator.js index 20e6e20ad..ab65bc929 100755 --- a/code_producers/src/wasm_elements/common/witness_calculator.js +++ b/code_producers/src/wasm_elements/common/witness_calculator.js @@ -18,6 +18,9 @@ module.exports = async function builder(code, options) { const instance = await WebAssembly.instantiate(wasmModule, { runtime: { + printDebug : function(value) { + console.log("printDebug:",value); + }, exceptionHandler : function(code) { let err; if (code == 1) { diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index 4691faad7..d602fa713 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -256,12 +256,13 @@ impl WASMProducer { let mut n = 0; for (_c, v) in &self.io_map { for s in v { - // since we take offset, size, busid and all lengths but last one + // we take always offset, and size and all lengths but last one if len !=0, if s.lengths.len() == 0 { n += 1; } else { n += s.lengths.len() + 2; } + // we take the bus_id if it has type bus if let Some(_) = &s.bus_id { n += 1; } diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 5a8c2fc95..3c4d5b97c 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -313,30 +313,33 @@ pub fn generate_data_io_signals_info( for c in 0..producer.get_number_of_template_instances() { match io_map.get(&c) { Some(value) => { - for s in value { + println!("Template Instance: {}", c); + for s in value { // add the actual offset in memory, taking into account the size of field nums + println!("Offset: {}", s.offset); io_signals_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); - // add the actual size of the elements - io_signals_info.push_str(&&wasm_hexa( - 4, - &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), - )); - // add the busid (if not bus add the number if bus instantiations) - match s.bus_id { - Some(value) => { + println!("Length: {}", s.lengths.len()); + if s.lengths.len() > 0 { // if it is an array + // add the dimensions except the first one + for i in 1..s.lengths.len() { + println!("Index: {}, {}", i, s.lengths[i]); + io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); + } + // add the actual size of the elements + println!("Size: {}", s.size); + io_signals_info.push_str(&&wasm_hexa( + 4, + &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), + )); + } + // add the busid if it is a bus + if let Some(value) = s.bus_id { + println!("Bus_id: {}", value); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); - } - None => { - io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(producer.get_number_of_bus_instances()))); - } } - // add the dimensions except the first one - for i in 1..s.lengths.len() { - io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); - } } } None => (), @@ -587,6 +590,10 @@ pub fn generate_imports_list() -> Vec { "(import \"runtime\" \"showSharedRWMemory\" (func $showSharedRWMemory (type $_t_void)))" .to_string(), ); + imports.push( + "(import \"runtime\" \"printDebug\" (func $printDebug (type $_t_i32)))" + .to_string(), + ); imports } @@ -650,43 +657,52 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { )); // TODO: change generate_hash_map to new inputlist let map = generate_hash_map(&producer.get_main_input_list()); + wdata.push(format!(";; hash_map")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_input_signals_hashmap_start(), generate_data_from_hash_map(&map) )); let s = generate_data_witness_to_signal_list(producer.get_witness_to_signal_list()); + wdata.push(format!(";; witness_to_signal_list")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_witness_signal_id_list_start(), s )); + wdata.push(format!(";; signal memory")); wdata.push(format!("(data (i32.const {}) \"{}{}\")",producer.get_signal_memory_start(),"\\00\\00\\00\\00\\00\\00\\00\\80",wasm_hexa(producer.get_size_32_bit()*4, &BigInt::from(1)))); //setting 'one' as long normal 1 + wdata.push(format!(";; template_instance_to_io_signal")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_template_instance_to_io_signal_start(), generate_data_template_instance_to_io(&producer, producer.get_io_map()) )); + wdata.push(format!(";; io_signals_to_info")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_io_signals_to_info_start(), generate_data_io_signals_to_info(&producer, producer.get_io_map()) )); + wdata.push(format!(";; io_signals_info")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_io_signals_info_start(), generate_data_io_signals_info(&producer, producer.get_io_map()) )); + wdata.push(format!(";; bus_instance_to_field")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_bus_instance_to_field_start(), generate_data_bus_instance_to_field(&producer, producer.get_busid_field_info()) )); + wdata.push(format!(";; field_to_info")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_field_to_info_start(), generate_data_field_to_info(&producer, producer.get_busid_field_info()) )); + wdata.push(format!(";; field_info")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_field_info_start(), @@ -694,6 +710,7 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { )); let ml = producer.get_message_list(); let m = producer.get_message_list_start(); + wdata.push(format!(";; messages_in_bytes")); for i in 0..ml.len() { if ml[i].len() < producer.get_size_of_message_in_bytes() { wdata.push(format!( @@ -726,6 +743,7 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { )); } } + wdata.push(format!(";; constants")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_constant_numbers_start(), From f77fd0482d554c32ba01a662a8fd8030e90b4aab Mon Sep 17 00:00:00 2001 From: alrubio Date: Fri, 12 Jul 2024 11:09:40 +0200 Subject: [PATCH 120/189] fixing bug --- .../src/wasm_elements/wasm_code_generator.rs | 16 +++++++++++----- .../intermediate_representation/call_bucket.rs | 5 +++-- .../intermediate_representation/load_bucket.rs | 9 ++++++--- .../intermediate_representation/store_bucket.rs | 5 ++++- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 3c4d5b97c..b6e5f7d7f 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -291,11 +291,14 @@ pub fn generate_data_io_signals_to_info( assert_eq!(s.code, n); io_signals.push_str(&&wasm_hexa(4, &BigInt::from(pos))); //do not store code and the first one of lengths (offset + size + length-1(if >0) - if s.lengths.len() == 0 { - pos += 8; - } else { + if s.lengths.len() == 0 { //only offset + pos += 4; + } else { // offest + length -1 + size pos += s.lengths.len() * 4 + 4; } + if let Some(_) = s.bus_id { + pos += 4; + } n += 1; } } @@ -373,10 +376,13 @@ pub fn generate_data_field_to_info( bus_fields.push_str(&&wasm_hexa(4, &BigInt::from(pos))); //do not store the first one of lengths if s.dimensions.len() == 0 { - pos += 12; + pos += 4; } else { - pos += s.dimensions.len() * 4 + 8; + pos += s.dimensions.len() * 4 + 4; } + if let Some(_) = s.bus_id { + pos += 4; + } } } bus_fields diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 947e1a3ae..63de168fd 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -184,8 +184,9 @@ impl WriteWasm for CallBucket { instructions.push(mul32()); instructions.push(add32()); instructions.push(load32(None)); //subcomponent block - instructions.push(set_local(producer.get_sub_cmp_tag())); - instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(tee_local(producer.get_sub_cmp_tag())); + //instructions.push(set_local(producer.get_sub_cmp_tag())); + //instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), )); diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 3c539850d..24c885717 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -98,7 +98,7 @@ impl WriteWasm for LoadBucket { match &self.address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { - instructions.push(";; is subcomponent".to_string()); + instructions.push(";; is subcomponent mapped".to_string()); } instructions.push(get_local(producer.get_offset_tag())); instructions.push(set_constant( @@ -111,8 +111,9 @@ impl WriteWasm for LoadBucket { instructions.push(mul32()); instructions.push(add32()); instructions.push(load32(None)); //subcomponent block - instructions.push(set_local(producer.get_sub_cmp_load_tag())); - instructions.push(get_local(producer.get_sub_cmp_load_tag())); + instructions.push(tee_local(producer.get_sub_cmp_load_tag())); + //instructions.push(set_local(producer.get_sub_cmp_load_tag())); + //instructions.push(get_local(producer.get_sub_cmp_load_tag())); instructions.push(load32(None)); // get template id A instructions.push(set_constant("4")); //size in byte of i32 instructions.push(mul32()); @@ -123,8 +124,10 @@ impl WriteWasm for LoadBucket { instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one if indexes.len() == 0 { + instructions.push(";; has no indexes".to_string()); instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); } else { + instructions.push(";; has indexes".to_string()); instructions.push(tee_local(producer.get_io_info_tag())); instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) // if the first access is qualified we place the address of the bus_id diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index be9e9faa6..dd37f2379 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -105,7 +105,7 @@ impl WriteWasm for StoreBucket { match &self.dest_address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { - instructions.push(";; is subcomponent".to_string()); + instructions.push(";; is subcomponent mapped".to_string()); } instructions.push(get_local(producer.get_offset_tag())); instructions.push(set_constant( @@ -119,6 +119,7 @@ impl WriteWasm for StoreBucket { instructions.push(add32()); instructions.push(load32(None)); //subcomponent block instructions.push(tee_local(producer.get_sub_cmp_tag())); + //instructions.push(set_local(producer.get_sub_cmp_tag())); //instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(load32(None)); // get template id A instructions.push(set_constant("4")); //size in byte of i32 @@ -130,8 +131,10 @@ impl WriteWasm for StoreBucket { instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one if indexes.len() == 0 { + instructions.push(";; has no indexes".to_string()); instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); } else { + instructions.push(";; has indexes".to_string()); instructions.push(tee_local(producer.get_io_info_tag())); instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) // if the first access is qualified we place the address of the bus_id From dd0e48624ef2aaec06a828fc4b9693c7c3c3c05f Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 12 Jul 2024 14:24:35 +0200 Subject: [PATCH 121/189] fixing stored size: store single element in arrays --- compiler/src/circuit_design/build.rs | 14 +++++++++++-- .../intermediate_representation/translate.rs | 20 ------------------- .../src/execution_data/executed_template.rs | 10 +++++++++- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 993f101de..88d73ae54 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -346,12 +346,17 @@ fn build_input_output_list(instance: &TemplateInstance, database: &TemplateDB) - use program_structure::ast::SignalType::*; let mut io_list = vec![]; for s in &instance.wires { + let mut total_array_size = 1; + for len in s.lengths(){ + total_array_size *= len; + } + let individual_size = s.size() / total_array_size; if s.xtype() != Intermediate { let def = IODef { code: TemplateDB::get_signal_id(database, &instance.template_name, s.name()), offset: s.local_id(), lengths: s.lengths().clone(), - size: s.size(), + size: individual_size, bus_id: s.bus_id() }; io_list.push(def); @@ -399,9 +404,14 @@ fn get_info_buses(buses: &Vec)->(usize, FieldMap){ for bus in buses{ let mut field_data = vec![FieldData::default(); bus.fields.len()]; for (_, field_info) in &bus.fields{ + let mut total_array_size = 1; + for len in &field_info.dimensions{ + total_array_size *= len; + } + let individual_size = field_info.size / total_array_size; let data = FieldData{ offset: field_info.offset, - size: field_info.size, + size: individual_size, dimensions: field_info.dimensions.clone(), bus_id: field_info.bus_id }; diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index e977e4409..48b9c16b7 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -1272,26 +1272,6 @@ impl ProcessedSymbol { } } - // TODO: improve cases, unnecesary clone - // in case it is a signal of a subcomponent we use the offset when - // building the signal location, if not use late - // let (remaining_offset, remaining_size, remaining_dimensions, remaining_indexes) = if accessed_component_signal.is_some(){ - // // they go to the original vector - // ( - // Vec::new(), - // vec![symbol_info.size.clone()], - // vec![symbol_info.dimensions.clone()], - // vec![before_index] - // ) - // } else{ - // ( - // offset.clone(), - // symbol_size.clone(), - // symbol_dimensions.clone(), - // after_indexes.clone() - // ) - // }; - } fn into_call_assign( diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 24d1cfb07..d4e6651b0 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -345,6 +345,14 @@ impl ExecutedTemplate { let data = cnn.inspect; instances[data.goes_to].is_parallel_component |= data.is_parallel; instances[data.goes_to].is_not_parallel_component |= !(data.is_parallel); + + let mut external_wires = Vec::new(); + for wire in &instances[data.goes_to].wires{ + if wire.xtype() != SignalType::Intermediate{ + external_wires.push(wire.clone()); + } + } + let trigger = Trigger { offset: cnn.dag_offset, component_offset: cnn.dag_component_offset, @@ -353,7 +361,7 @@ impl ExecutedTemplate { is_parallel: data.is_parallel || instances[data.goes_to].is_parallel, runs: instances[data.goes_to].template_header.clone(), template_id: data.goes_to, - external_wires: instances[data.goes_to].wires.clone(), // TODO: only copy signals that are external + external_wires, has_inputs: instances[data.goes_to].number_of_inputs > 0, }; triggers.push(trigger); From 543600cbf7654b27adbb953172107fafef46ba88 Mon Sep 17 00:00:00 2001 From: alrubio Date: Sat, 13 Jul 2024 07:59:47 +0200 Subject: [PATCH 122/189] bug fixed --- .../common/witness_calculator.js | 6 ++--- code_producers/src/wasm_elements/mod.rs | 2 +- .../src/wasm_elements/wasm_code_generator.rs | 26 ++++++++++--------- .../load_bucket.rs | 1 - 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/code_producers/src/wasm_elements/common/witness_calculator.js b/code_producers/src/wasm_elements/common/witness_calculator.js index ab65bc929..f5b31a4fe 100755 --- a/code_producers/src/wasm_elements/common/witness_calculator.js +++ b/code_producers/src/wasm_elements/common/witness_calculator.js @@ -18,9 +18,9 @@ module.exports = async function builder(code, options) { const instance = await WebAssembly.instantiate(wasmModule, { runtime: { - printDebug : function(value) { - console.log("printDebug:",value); - }, + //printDebug : function(value) { + // console.log("printDebug:",value); + //}, exceptionHandler : function(code) { let err; if (code == 1) { diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index d602fa713..553882057 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -260,7 +260,7 @@ impl WASMProducer { if s.lengths.len() == 0 { n += 1; } else { - n += s.lengths.len() + 2; + n += s.lengths.len() + 1; } // we take the bus_id if it has type bus if let Some(_) = &s.bus_id { diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index b6e5f7d7f..0d70ce3c3 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -316,31 +316,32 @@ pub fn generate_data_io_signals_info( for c in 0..producer.get_number_of_template_instances() { match io_map.get(&c) { Some(value) => { - println!("Template Instance: {}", c); + //println!("Template Instance: {}", c); for s in value { // add the actual offset in memory, taking into account the size of field nums - println!("Offset: {}", s.offset); + //println!("Offset: {}", s.offset); io_signals_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); - println!("Length: {}", s.lengths.len()); + //println!("Length: {}", s.lengths.len()); if s.lengths.len() > 0 { // if it is an array // add the dimensions except the first one for i in 1..s.lengths.len() { - println!("Index: {}, {}", i, s.lengths[i]); + //println!("Index: {}, {}", i, s.lengths[i]); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); } // add the actual size of the elements - println!("Size: {}", s.size); + //println!("Size: {}", s.size); io_signals_info.push_str(&&wasm_hexa( 4, - &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), + &BigInt::from(s.size), + //&BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), )); } // add the busid if it is a bus if let Some(value) = s.bus_id { - println!("Bus_id: {}", value); + //println!("Bus_id: {}", value); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); } } @@ -408,7 +409,8 @@ pub fn generate_data_field_info( // add the actual size in memory, if array field_info.push_str(&&wasm_hexa( 4, - &BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), + &BigInt::from(s.size), + //&BigInt::from(s.size * producer.get_size_32_bits_in_memory() * 4), )); } // add the busid if it contains buses @@ -596,10 +598,10 @@ pub fn generate_imports_list() -> Vec { "(import \"runtime\" \"showSharedRWMemory\" (func $showSharedRWMemory (type $_t_void)))" .to_string(), ); - imports.push( - "(import \"runtime\" \"printDebug\" (func $printDebug (type $_t_i32)))" - .to_string(), - ); +// imports.push( +// "(import \"runtime\" \"printDebug\" (func $printDebug (type $_t_i32)))" +// .to_string(), +// ); imports } diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 24c885717..f3b5f4255 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -94,7 +94,6 @@ impl WriteWasm for LoadBucket { } } LocationRule::Mapped { signal_code, indexes} => { - // TODO: ADD THE OFFSET match &self.address_type { AddressType::SubcmpSignal { cmp_address, .. } => { if producer.needs_comments() { From 26ed9a7aed215aa570c77ceddf788a6217893891 Mon Sep 17 00:00:00 2001 From: alrubio Date: Mon, 15 Jul 2024 18:21:03 +0200 Subject: [PATCH 123/189] bug fixed in wasm generation with buses and c++ first version for IR --- .../src/c_elements/c_code_generator.rs | 3 +- .../src/c_elements/common/circom.hpp | 2 +- code_producers/src/c_elements/mod.rs | 8 +- .../call_bucket.rs | 79 +++++++++++------ .../load_bucket.rs | 82 +++++++++++++----- .../store_bucket.rs | 85 +++++++++++++------ 6 files changed, 181 insertions(+), 78 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 9e38e2b15..4b380a5b5 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -21,6 +21,7 @@ const CIRCOM_COMPONENT_FIELDS: [&str; 4] = const S_IOField_DEF: &str = "IOFieldDef"; const IOField_DEF_FIELDS: [&str; 4] = ["offset", "size", "lengths", "busid"]; + // Global variables pub const SIZE_INPUT_HASHMAP: usize = 256; const G_INPUT_HASHMAP: &str = "inputHashMap"; // type HashSignalInfo[256] @@ -269,7 +270,7 @@ pub fn my_input_counter() -> CInstruction { pub const TEMPLATE_INS_ID_2_IO_SIGNAL_INFO: &str = "templateInsId2IOSignalInfo"; pub fn declare_template_ins_id_2_io_signal_info() -> CInstruction { format!( - "std::map {} = {}->{}", + "std::map {} = {}->{}", TEMPLATE_INS_ID_2_IO_SIGNAL_INFO, CIRCOM_CALC_WIT, TEMPLATE_INS_ID_2_IO_SIGNAL_INFO ) } diff --git a/code_producers/src/c_elements/common/circom.hpp b/code_producers/src/c_elements/common/circom.hpp index 617784b4c..4a475654e 100644 --- a/code_producers/src/c_elements/common/circom.hpp +++ b/code_producers/src/c_elements/common/circom.hpp @@ -25,7 +25,7 @@ struct IOFieldDef { u32 size; u32 len; u32 *lengths; - u32 busid; + u32 busId; }; struct IOFieldDefPair { diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 639e37470..e7cd583df 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -30,10 +30,10 @@ pub struct CProducer { pub patch_version: usize, name_tag: String, string_table: Vec, - //New for buses - pub num_of_bus_instances: usize, //total number of different bus instances -// pub size_of_bus_fields: usize, //total number of fields in all differen bus intances - pub busid_field_info: FieldMap, //for every busId (0..num-1) provides de offset, size, dimensions and busId of each field (0..n-1) in it + //New for buses + pub num_of_bus_instances: usize, //total number of different bus instances + //pub size_of_bus_fields: usize, //total number of fields in all differen bus intances + pub busid_field_info: FieldMap, //for every busId (0..num-1) provides de offset, size, dimensions and busId of each field (0..n-1) in it } impl Default for CProducer { diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 63de168fd..00e449252 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -288,10 +288,13 @@ impl WriteWasm for CallBucket { instructions.push(set_constant(&field_size.to_string())); instructions.push(load32(None)); // get the offset instructions.push(mul32()); // mult by size of field in bytes - instructions.push(add32()); // add to the current offset - if let AccessType::Qualified(_) = &indexes[idxpos] { - instructions.push(get_local(producer.get_io_info_tag())); - instructions.push(load32(Some("4"))); // bus_id + instructions.push(add32()); // add to the current offset + idxpos += 1; + if idxpos < indexes.len() { + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // bus_id + } } } else { assert!(false); @@ -462,35 +465,63 @@ impl WriteC for CallBucket { if let LocationRule::Indexed { location, template_header } = &data.dest { (location.produce_c(producer, parallel), template_header.clone()) } else if let LocationRule::Mapped { signal_code, indexes} = &data.dest { - // TODO: add the offset let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); let mut map_access = format!("{}->{}[{}].defs[{}].offset", circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); - // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED - // descomentar todo lo siguiente, quitado para evitar error - /* - if indexes.len()>0 { + if indexes.len() > 0 { map_prologue.push(format!("{{")); - map_prologue.push(format!("uint map_index_aux[{}];",indexes.len().to_string())); - let (mut index_code_0, mut map_index) = indexes[0].produce_c(producer, parallel); - map_prologue.append(&mut index_code_0); - map_prologue.push(format!("map_index_aux[0]={};",map_index)); - map_index = format!("map_index_aux[0]"); - for i in 1..indexes.len() { - let (mut index_code, index_exp) = indexes[i].produce_c(producer, parallel); - map_prologue.append(&mut index_code); - map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); - map_index = format!("({})*{}->{}[{}].defs[{}].lengths[{}]+map_index_aux[{}]", - map_index, circom_calc_wit(), template_ins_2_io_info(), - template_id_in_component(sub_component_pos_in_memory.clone()), - signal_code.to_string(),(i-1).to_string(),i.to_string()); + //cur_def contains a pointer to the definion of the next acces. + //The first time it is taken from template_ins_2_io_info + map_prologue.push(format!("IOFieldDef *cur_def = &({}->{}[{}].defs[{}]);", + circom_calc_wit(), template_ins_2_io_info(), + template_id_in_component(sub_component_pos_in_memory.clone()), + signal_code.to_string())); + map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); + let mut idxpos = 0; + while idxpos < indexes.len() { + if let AccessType::Indexed(index_list) = &indexes[idxpos] { + map_prologue.push(format!("{{")); + map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); + //We first compute the number of elements as + //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with + // map_index_aux[i] = computation of index_list[i] + let (mut index_code_0, mut map_index) = index_list[0].produce_c(producer, parallel); + map_prologue.append(&mut index_code_0); + map_prologue.push(format!("map_index_aux[0]={};",map_index)); + map_index = format!("map_index_aux[0]"); + for i in 1..index_list.len() { + let (mut index_code, index_exp) = index_list[i].produce_c(producer, parallel); + map_prologue.append(&mut index_code); + map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); + map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", + map_index,(i-1).to_string(),i.to_string()); + } + map_prologue.push(format!("map_accesses_aux[{}] = {}", idxpos.to_string(), map_index)); + map_prologue.push(format!("}}")); + // add to the access expression the computed offset in the array + // multiplied buy the size of the elements + map_access = format!("{}+map_accesses_aux[{}]*cur_def->size", + map_access, idxpos.to_string()); + } else if let AccessType::Qualified(_) = &indexes[idxpos] { + // we already have the cur_def + map_prologue.push(format!("map_accesses_aux[{}] = cur_def.offset", idxpos.to_string())); + } else { + assert!(false); + } + idxpos += 1; + if idxpos < indexes.len() { + if let AccessType::Qualified(field_no) = &indexes[idxpos] { + // we get the next definition in cur_def from the bus bus_id + map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", + circom_calc_wit(), bus_ins_2_field_info(), + field_no.to_string())); + } + } } - map_access = format!("{}+{}",map_access,map_index); } - */ ((map_prologue, map_access),Some(template_id_in_component(sub_component_pos_in_memory.clone()))) } else { assert!(false); diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index f3b5f4255..0187bf4a6 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -123,10 +123,10 @@ impl WriteWasm for LoadBucket { instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one if indexes.len() == 0 { - instructions.push(";; has no indexes".to_string()); + //instructions.push(";; has no indexes".to_string()); instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); } else { - instructions.push(";; has indexes".to_string()); + //instructions.push(";; has indexes".to_string()); instructions.push(tee_local(producer.get_io_info_tag())); instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) // if the first access is qualified we place the address of the bus_id @@ -186,10 +186,13 @@ impl WriteWasm for LoadBucket { instructions.push(set_constant(&field_size.to_string())); instructions.push(load32(None)); // get the offset instructions.push(mul32()); // mult by size of field in bytes - instructions.push(add32()); // add to the current offset - if let AccessType::Qualified(_) = &indexes[idxpos] { - instructions.push(get_local(producer.get_io_info_tag())); - instructions.push(load32(Some("4"))); // bus_id + instructions.push(add32()); // add to the current offset + idxpos += 1; + if idxpos < indexes.len() { + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // bus_id + } } } else { assert!(false); @@ -241,22 +244,57 @@ impl WriteC for LoadBucket { circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); - // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED - // descomentar todo lo siguiente, quitado para evitar error - /* - if indexes.len()>0 { - let (mut index_code_0, mut map_index) = indexes[0].produce_c(producer, parallel); - map_prologue.append(&mut index_code_0); - for i in 1..indexes.len() { - let (mut index_code, index_exp) = indexes[i].produce_c(producer, parallel); - map_prologue.append(&mut index_code); - map_index = format!("({})*{}->{}[{}].defs[{}].lengths[{}]+{}", - map_index, circom_calc_wit(), template_ins_2_io_info(), - template_id_in_component(sub_component_pos_in_memory.clone()), - signal_code.to_string(), (i-1).to_string(),index_exp); - } - map_access = format!("{}+{}",map_access,map_index); - }*/ + if indexes.len() > 0 { + map_prologue.push(format!("{{")); + //cur_def contains a pointer to the definion of the next acces. + //The first time it is taken from template_ins_2_io_info + map_prologue.push(format!("IOFieldDef *cur_def = &({}->{}[{}].defs[{}]);", + circom_calc_wit(), template_ins_2_io_info(), + template_id_in_component(sub_component_pos_in_memory.clone()), + signal_code.to_string())); + map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); + let mut idxpos = 0; + while idxpos < indexes.len() { + if let AccessType::Indexed(index_list) = &indexes[idxpos] { + map_prologue.push(format!("{{")); + map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); + //We first compute the number of elements as + //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with + // map_index_aux[i] = computation of index_list[i] + let (mut index_code_0, mut map_index) = index_list[0].produce_c(producer, parallel); + map_prologue.append(&mut index_code_0); + map_prologue.push(format!("map_index_aux[0]={};",map_index)); + map_index = format!("map_index_aux[0]"); + for i in 1..index_list.len() { + let (mut index_code, index_exp) = index_list[i].produce_c(producer, parallel); + map_prologue.append(&mut index_code); + map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); + map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", + map_index,(i-1).to_string(),i.to_string()); + } + map_prologue.push(format!("map_accesses_aux[{}] = {}", idxpos.to_string(), map_index)); + map_prologue.push(format!("}}")); + // add to the access expression the computed offset in the array + // multiplied buy the size of the elements + map_access = format!("{}+map_accesses_aux[{}]*cur_def->size", + map_access, idxpos.to_string()); + } else if let AccessType::Qualified(_) = &indexes[idxpos] { + // we already have the cur_def + map_prologue.push(format!("map_accesses_aux[{}] = cur_def.offset", idxpos.to_string())); + } else { + assert!(false); + } + idxpos += 1; + if idxpos < indexes.len() { + if let AccessType::Qualified(field_no) = &indexes[idxpos] { + // we get the next definition in cur_def from the bus bus_id + map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", + circom_calc_wit(), bus_ins_2_field_info(), + field_no.to_string())); + } + } + } + } (map_prologue, map_access) } else { assert!(false); diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index dd37f2379..909e80d8a 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -131,10 +131,10 @@ impl WriteWasm for StoreBucket { instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one if indexes.len() == 0 { - instructions.push(";; has no indexes".to_string()); + //instructions.push(";; has no indexes".to_string()); instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); } else { - instructions.push(";; has indexes".to_string()); + //instructions.push(";; has indexes".to_string()); instructions.push(tee_local(producer.get_io_info_tag())); instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) // if the first access is qualified we place the address of the bus_id @@ -194,10 +194,13 @@ impl WriteWasm for StoreBucket { instructions.push(set_constant(&field_size.to_string())); instructions.push(load32(None)); // get the offset instructions.push(mul32()); // mult by size of field in bytes - instructions.push(add32()); // add to the current offset - if let AccessType::Qualified(_) = &indexes[idxpos] { - instructions.push(get_local(producer.get_io_info_tag())); - instructions.push(load32(Some("4"))); // bus_id + instructions.push(add32()); // add to the current offset + idxpos += 1; + if idxpos < indexes.len() { + if let AccessType::Qualified(_) = &indexes[idxpos] { + instructions.push(get_local(producer.get_io_info_tag())); + instructions.push(load32(Some("4"))); // bus_id + } } } else { assert!(false); @@ -358,27 +361,57 @@ impl WriteC for StoreBucket { circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); - // TODO: INDEXES MIGHT BE INDEX OR QUALIFIED - // descomentar todo lo siguiente, quitado para evitar error - /* - if indexes.len()>0 { - map_prologue.push(format!("{{")); - map_prologue.push(format!("uint map_index_aux[{}];",indexes.len().to_string())); - let (mut index_code_0, mut map_index) = indexes[0].produce_c(producer, parallel); - map_prologue.append(&mut index_code_0); - map_prologue.push(format!("map_index_aux[0]={};",map_index)); - map_index = format!("map_index_aux[0]"); - for i in 1..indexes.len() { - let (mut index_code, index_exp) = indexes[i].produce_c(producer, parallel); - map_prologue.append(&mut index_code); - map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); - map_index = format!("({})*{}->{}[{}].defs[{}].lengths[{}]+map_index_aux[{}]", - map_index, circom_calc_wit(), template_ins_2_io_info(), + if indexes.len() > 0 { + map_prologue.push(format!("{{")); + //cur_def contains a pointer to the definion of the next acces. + //The first time it is taken from template_ins_2_io_info + map_prologue.push(format!("IOFieldDef *cur_def = &({}->{}[{}].defs[{}]);", + circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), - signal_code.to_string(),(i-1).to_string(),i.to_string()); - } - map_access = format!("{}+{}",map_access,map_index); - }*/ + signal_code.to_string())); + map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); + let mut idxpos = 0; + while idxpos < indexes.len() { + if let AccessType::Indexed(index_list) = &indexes[idxpos] { + map_prologue.push(format!("{{")); + map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); + //We first compute the number of elements as + //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with + // map_index_aux[i] = computation of index_list[i] + let (mut index_code_0, mut map_index) = index_list[0].produce_c(producer, parallel); + map_prologue.append(&mut index_code_0); + map_prologue.push(format!("map_index_aux[0]={};",map_index)); + map_index = format!("map_index_aux[0]"); + for i in 1..index_list.len() { + let (mut index_code, index_exp) = index_list[i].produce_c(producer, parallel); + map_prologue.append(&mut index_code); + map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); + map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", + map_index,(i-1).to_string(),i.to_string()); + } + map_prologue.push(format!("map_accesses_aux[{}] = {}", idxpos.to_string(), map_index)); + map_prologue.push(format!("}}")); + // add to the access expression the computed offset in the array + // multiplied buy the size of the elements + map_access = format!("{}+map_accesses_aux[{}]*cur_def->size", + map_access, idxpos.to_string()); + } else if let AccessType::Qualified(_) = &indexes[idxpos] { + // we already have the cur_def + map_prologue.push(format!("map_accesses_aux[{}] = cur_def.offset", idxpos.to_string())); + } else { + assert!(false); + } + idxpos += 1; + if idxpos < indexes.len() { + if let AccessType::Qualified(field_no) = &indexes[idxpos] { + // we get the next definition in cur_def from the bus bus_id + map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", + circom_calc_wit(), bus_ins_2_field_info(), + field_no.to_string())); + } + } + } + } ((map_prologue, map_access),Some(template_id_in_component(sub_component_pos_in_memory.clone()))) } else { assert!(false); From da4fb106f09a383fb9e6ccf61dd65bffd699f239 Mon Sep 17 00:00:00 2001 From: alrubio Date: Tue, 16 Jul 2024 13:55:36 +0200 Subject: [PATCH 124/189] bug fixed in wasm generation with buses --- .../src/c_elements/common/calcwit.hpp | 3 ++- .../common/witness_calculator.js | 6 ++--- .../src/wasm_elements/wasm_code_generator.rs | 26 ++++++++++++------- .../call_bucket.rs | 2 ++ .../load_bucket.rs | 2 ++ .../store_bucket.rs | 8 +++--- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/code_producers/src/c_elements/common/calcwit.hpp b/code_producers/src/c_elements/common/calcwit.hpp index 363de21d1..1cee1e7de 100644 --- a/code_producers/src/c_elements/common/calcwit.hpp +++ b/code_producers/src/c_elements/common/calcwit.hpp @@ -26,7 +26,8 @@ class Circom_CalcWit { FrElement *signalValues; Circom_Component* componentMemory; FrElement* circuitConstants; - std::map templateInsId2IOSignalInfo; + std::map templateInsId2IOSignalInfo; + IOFieldDefPair* busInsId2FieldInfo; std::string* listOfTemplateMessages; // parallelism diff --git a/code_producers/src/wasm_elements/common/witness_calculator.js b/code_producers/src/wasm_elements/common/witness_calculator.js index f5b31a4fe..ab65bc929 100755 --- a/code_producers/src/wasm_elements/common/witness_calculator.js +++ b/code_producers/src/wasm_elements/common/witness_calculator.js @@ -18,9 +18,9 @@ module.exports = async function builder(code, options) { const instance = await WebAssembly.instantiate(wasmModule, { runtime: { - //printDebug : function(value) { - // console.log("printDebug:",value); - //}, + printDebug : function(value) { + console.log("printDebug:",value); + }, exceptionHandler : function(code) { let err; if (code == 1) { diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 0d70ce3c3..e254a30dd 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -316,23 +316,23 @@ pub fn generate_data_io_signals_info( for c in 0..producer.get_number_of_template_instances() { match io_map.get(&c) { Some(value) => { - //println!("Template Instance: {}", c); + println!("Template Instance: {}", c); for s in value { // add the actual offset in memory, taking into account the size of field nums - //println!("Offset: {}", s.offset); + println!("Offset: {}", s.offset); io_signals_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); - //println!("Length: {}", s.lengths.len()); + println!("Length: {}", s.lengths.len()); if s.lengths.len() > 0 { // if it is an array // add the dimensions except the first one for i in 1..s.lengths.len() { - //println!("Index: {}, {}", i, s.lengths[i]); + println!("Index: {}, {}", i, s.lengths[i]); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); } // add the actual size of the elements - //println!("Size: {}", s.size); + println!("Size: {}", s.size); io_signals_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.size), @@ -341,7 +341,7 @@ pub fn generate_data_io_signals_info( } // add the busid if it is a bus if let Some(value) = s.bus_id { - //println!("Bus_id: {}", value); + println!("Bus_id: {}", value); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); } } @@ -395,18 +395,23 @@ pub fn generate_data_field_info( ) -> String { let mut field_info = "".to_string(); for c in 0..producer.get_number_of_bus_instances() { + println!("Bus Instance: {}", c); for s in &field_map[c] { // add the actual offset in memory, taking into account the size of field nums + println!("Offset: {}", s.offset); field_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); + println!("Length: {}", s.dimensions.len()); if s.dimensions.len() > 0 { // if it is an array // add all dimensions but first one for i in 1..s.dimensions.len() { + println!("Index: {}, {}", i, s.dimensions[i]); field_info.push_str(&&wasm_hexa(4, &BigInt::from(s.dimensions[i]))); } // add the actual size in memory, if array + println!("Size: {}", s.size); field_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.size), @@ -415,6 +420,7 @@ pub fn generate_data_field_info( } // add the busid if it contains buses if let Some(value) = s.bus_id { + println!("Bus_id: {}", value); field_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); } } @@ -598,10 +604,10 @@ pub fn generate_imports_list() -> Vec { "(import \"runtime\" \"showSharedRWMemory\" (func $showSharedRWMemory (type $_t_void)))" .to_string(), ); -// imports.push( -// "(import \"runtime\" \"printDebug\" (func $printDebug (type $_t_i32)))" -// .to_string(), -// ); + imports.push( + "(import \"runtime\" \"printDebug\" (func $printDebug (type $_t_i32)))" + .to_string(), + ); imports } diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 00e449252..cef5b7001 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -276,6 +276,8 @@ impl WriteWasm for CallBucket { } } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { //we have on the stack the bus_id + instructions.push(set_constant("4")); //size in byte of i32 + instructions.push(mul32()); //maybe better in the memory like this instructions.push(load32(Some( &producer.get_bus_instance_to_field_start().to_string() ))); // get position in the bus to field in memory diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 0187bf4a6..eb3b8fedf 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -174,6 +174,8 @@ impl WriteWasm for LoadBucket { } } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { //we have on the stack the bus_id + instructions.push(set_constant("4")); //size in byte of i32 + instructions.push(mul32()); //maybe better in the memory like this instructions.push(load32(Some( &producer.get_bus_instance_to_field_start().to_string() ))); // get position in the bus to field in memory diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 909e80d8a..d49c8b54d 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -131,13 +131,13 @@ impl WriteWasm for StoreBucket { instructions.push(load32(Some(&signal_code_in_bytes.to_string()))); // get where the info of this signal is //now we have first the offset, and then the all size dimensions but the last one if indexes.len() == 0 { - //instructions.push(";; has no indexes".to_string()); + instructions.push(";; has no indexes".to_string()); instructions.push(load32(None)); // get signal offset (it is already the actual one in memory); } else { - //instructions.push(";; has indexes".to_string()); + instructions.push(";; has indexes".to_string()); instructions.push(tee_local(producer.get_io_info_tag())); instructions.push(load32(None)); // get offset; first slot in io_info (to start adding offsets) - // if the first access is qualified we place the address of the bus_id + // if the first access is qualified we place the address of the bus_id on the stack if let AccessType::Qualified(_) = &indexes[0] { instructions.push(get_local(producer.get_io_info_tag())); instructions.push(load32(Some("4"))); // it is a bus, so the bus_id is in the second position @@ -182,6 +182,8 @@ impl WriteWasm for StoreBucket { } } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { //we have on the stack the bus_id + instructions.push(set_constant("4")); //size in byte of i32 + instructions.push(mul32()); //maybe better in the memory like this instructions.push(load32(Some( &producer.get_bus_instance_to_field_start().to_string() ))); // get position in the bus to field in memory From 0983f852f96b6d9206bcaabdfec6fb3d0210ebb3 Mon Sep 17 00:00:00 2001 From: alrubio Date: Tue, 16 Jul 2024 14:59:09 +0200 Subject: [PATCH 125/189] bug fixed in wasm generation with buses --- compiler/src/intermediate_representation/call_bucket.rs | 8 ++++---- compiler/src/intermediate_representation/load_bucket.rs | 8 ++++---- compiler/src/intermediate_representation/store_bucket.rs | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index cef5b7001..54c2a365b 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -283,13 +283,13 @@ impl WriteWasm for CallBucket { ))); // get position in the bus to field in memory let field_no_bytes = field_no * 4; instructions.push(load32(Some(&field_no_bytes.to_string()))); // get position in the field info in memory - if let AccessType::Qualified(_) = &indexes[idxpos] { + if idxpos +1 < indexes.len() { instructions.push(tee_local(producer.get_io_info_tag())); } - let field_size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&field_size.to_string())); + //let field_size = producer.get_size_32_bits_in_memory() * 4; + //instructions.push(set_constant(&field_size.to_string())); instructions.push(load32(None)); // get the offset - instructions.push(mul32()); // mult by size of field in bytes + //instructions.push(mul32()); // mult by size of field in bytes instructions.push(add32()); // add to the current offset idxpos += 1; if idxpos < indexes.len() { diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index eb3b8fedf..d22756246 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -181,13 +181,13 @@ impl WriteWasm for LoadBucket { ))); // get position in the bus to field in memory let field_no_bytes = field_no * 4; instructions.push(load32(Some(&field_no_bytes.to_string()))); // get position in the field info in memory - if let AccessType::Qualified(_) = &indexes[idxpos] { + if idxpos +1 < indexes.len() { instructions.push(tee_local(producer.get_io_info_tag())); } - let field_size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&field_size.to_string())); + //let field_size = producer.get_size_32_bits_in_memory() * 4; + //instructions.push(set_constant(&field_size.to_string())); instructions.push(load32(None)); // get the offset - instructions.push(mul32()); // mult by size of field in bytes + //instructions.push(mul32()); // mult by size of field in bytes instructions.push(add32()); // add to the current offset idxpos += 1; if idxpos < indexes.len() { diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index d49c8b54d..db40c4754 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -189,13 +189,13 @@ impl WriteWasm for StoreBucket { ))); // get position in the bus to field in memory let field_no_bytes = field_no * 4; instructions.push(load32(Some(&field_no_bytes.to_string()))); // get position in the field info in memory - if let AccessType::Qualified(_) = &indexes[idxpos] { + if idxpos +1 < indexes.len() { instructions.push(tee_local(producer.get_io_info_tag())); } - let field_size = producer.get_size_32_bits_in_memory() * 4; - instructions.push(set_constant(&field_size.to_string())); + //let field_size = producer.get_size_32_bits_in_memory() * 4; + //instructions.push(set_constant(&field_size.to_string())); instructions.push(load32(None)); // get the offset - instructions.push(mul32()); // mult by size of field in bytes + //instructions.push(mul32()); // mult by size of field in bytes instructions.push(add32()); // add to the current offset idxpos += 1; if idxpos < indexes.len() { From 7934a505f65715b4f405567b7b5823dd4af175c3 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 16 Jul 2024 19:34:57 +0200 Subject: [PATCH 126/189] moving heterogeneux accesses inside heterogeneus accesses outside --- compiler/src/hir/sugar_cleaner.rs | 37 ++++++++++++++++++---- compiler/src/ir_processing/reduce_stack.rs | 2 +- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/compiler/src/hir/sugar_cleaner.rs b/compiler/src/hir/sugar_cleaner.rs index 693d58c6b..30561cff7 100644 --- a/compiler/src/hir/sugar_cleaner.rs +++ b/compiler/src/hir/sugar_cleaner.rs @@ -1,16 +1,19 @@ use super::very_concrete_program::*; use program_structure::ast::*; use num_traits::{ToPrimitive}; - +use std::collections::HashSet; struct ExtendedSyntax { initializations: Vec, } -struct Context {} +struct Context { + mixed_components: HashSet, +} struct State { fresh_id: usize, + inside_mixed_component: bool, } impl State { pub fn produce_id(&mut self) -> String { @@ -27,17 +30,24 @@ impl State { -Inline array removal -Initialization Block removal (no longer needed) -Uniform array removal + -Access to heterogeneus variables nested removal */ pub fn clean_sugar(vcp: &mut VCP) { - let mut state = State { fresh_id: 0 }; + let mut state = State { fresh_id: 0, inside_mixed_component: false}; for template in &mut vcp.templates { - let context = Context {}; + let mut mixed_components = HashSet::new(); + for cluster in &template.clusters{ + if let ClusterType::Mixed{..} = &cluster.xtype{ + mixed_components.insert(cluster.cmp_name.clone()); + } + } + let context = Context {mixed_components}; let trash = extend_statement(&mut template.code, &mut state, &context); assert!(trash.is_empty()); } for vcf in &mut vcp.functions { - let context = Context {}; + let context = Context {mixed_components: HashSet::new()}; let trash = extend_statement(&mut vcf.body, &mut state, &context); assert!(trash.is_empty()); } @@ -236,9 +246,13 @@ fn extend_number(_expr: &mut Expression, _state: &mut State, _context: &Context) fn extend_variable(expr: &mut Expression, state: &mut State, context: &Context) -> ExtendedSyntax { use Expression::Variable; - if let Variable { access, .. } = expr { + if let Variable { access, name, .. } = expr { let mut inits = vec![]; + let old_state_mixed = state.inside_mixed_component; // to recover at the end + let is_mixed_component = context.mixed_components.contains(name); + state.inside_mixed_component |= is_mixed_component; // to extend the indexes for acc in access { + if let Access::ArrayAccess(e) = acc { let mut expand = extend_expression(e, state, context); inits.append(&mut expand.initializations); @@ -247,6 +261,17 @@ fn extend_variable(expr: &mut Expression, state: &mut State, context: &Context) *e = expr.pop().unwrap(); } } + // recover all mixed_component state + state.inside_mixed_component = old_state_mixed; + + // in this case we move the value to initializations and return + // the new variable instead of the expression + // new_id = expr + if state.inside_mixed_component && is_mixed_component{ + let id = state.produce_id(); + *expr = rmv_sugar(&id, expr.clone(), &mut inits); + } + ExtendedSyntax { initializations: inits } } else { unreachable!(); diff --git a/compiler/src/ir_processing/reduce_stack.rs b/compiler/src/ir_processing/reduce_stack.rs index edc4ce2d2..a8bcf3045 100644 --- a/compiler/src/ir_processing/reduce_stack.rs +++ b/compiler/src/ir_processing/reduce_stack.rs @@ -175,7 +175,7 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { } accesses.push(AccessType::Indexed(indexes)); } - AccessType::Qualified(pos) =>{ + AccessType::Qualified(_) =>{ accesses.push(acc); } From aab9ba1d81e760f5ee6442ec5d7b0d1a55909567 Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 17 Jul 2024 12:23:17 +0200 Subject: [PATCH 127/189] first complete version of C code generation for buses --- .../src/c_elements/c_code_generator.rs | 76 ++++++++++++++++++- .../src/c_elements/common/calcwit.cpp | 1 + .../src/c_elements/common/circom.hpp | 3 +- code_producers/src/c_elements/common/main.cpp | 40 ++++++++-- compiler/src/circuit_design/circuit.rs | 4 +- .../call_bucket.rs | 10 ++- .../load_bucket.rs | 31 +++----- .../store_bucket.rs | 16 ++-- 8 files changed, 139 insertions(+), 42 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 4b380a5b5..600934027 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -624,11 +624,79 @@ pub fn generate_dat_io_signals_info( v.reverse(); io_signals_info.append(&mut v); } + let s32 = s.size as u32; + let mut v: Vec = s32.to_be_bytes().to_vec(); + v.reverse(); + io_signals_info.append(&mut v); + let b32 = if let Some(value) = s.bus_id { + value as u32 + } else { + 0 as u32 + }; + let mut v = b32.to_be_bytes().to_vec(); + v.reverse(); + io_signals_info.append(&mut v); } } io_signals_info } +pub fn generate_dat_bus_field_info( + _producer: &CProducer, + field_map: &FieldMap, +) -> Vec { + // println!("size: {}",field_map.len()); + let mut bus_field_info = vec![]; + //let t32 = field_map.len() as u32; + //let mut v: Vec = t32.to_be_bytes().to_vec(); + //v.reverse(); + //bus_field_info.append(&mut v); + for c in 0..field_map.len() { + //println!("field_def_len: {}",field_map[c].len()); + let l32 = field_map[c].len() as u32; + let mut v: Vec = l32.to_be_bytes().to_vec(); + v.reverse(); + bus_field_info.append(&mut v); + for s in &field_map[c] { + //println!("offset: {}",s.offset); + let l32 = s.offset as u32; + let mut v: Vec = l32.to_be_bytes().to_vec(); + v.reverse(); + bus_field_info.append(&mut v); + let n32: u32; + if s.dimensions.len() > 0 { + n32 = (s.dimensions.len() - 1) as u32; + } else { + n32 = 0; + } + // println!("dims-1: {}",n32); + let mut v: Vec = n32.to_be_bytes().to_vec(); + v.reverse(); + bus_field_info.append(&mut v); + for i in 1..s.dimensions.len() { + // println!("dims {}: {}",i,s.lengths[i]); + let pos = s.dimensions[i] as u32; + let mut v: Vec = pos.to_be_bytes().to_vec(); + v.reverse(); + bus_field_info.append(&mut v); + } + let s32 = s.size as u32; + let mut v: Vec = s32.to_be_bytes().to_vec(); + v.reverse(); + bus_field_info.append(&mut v); + let b32 = if let Some(value) = s.bus_id { + value as u32 + } else { + 0 as u32 + }; + let mut v = b32.to_be_bytes().to_vec(); + v.reverse(); + bus_field_info.append(&mut v); + } + } + bus_field_info +} + // in main fix one to 1 /* @@ -678,6 +746,11 @@ pub fn generate_dat_file(dat_file: &mut dyn Write, producer: &CProducer) -> std: //dfile.write_all(&ioml.to_be_bytes())?; let iomap = generate_dat_io_signals_info(&producer, producer.get_io_map()); dat_file.write_all(&iomap)?; + if producer.get_io_map().len() > 0 { + //otherwise it is not used + let fieldmap = generate_dat_bus_field_info(&producer, producer.get_busid_field_info()); + dat_file.write_all(&fieldmap)?; + } /* let ml = producer.get_message_list(); let mll = ml.len() as u64; @@ -689,7 +762,7 @@ pub fn generate_dat_file(dat_file: &mut dyn Write, producer: &CProducer) -> std: dfile.write_all(m)?; dfile.flush()?; } - */ + */ dat_file.flush()?; Ok(()) } @@ -987,6 +1060,7 @@ pub fn generate_c_file(name: String, producer: &CProducer) -> std::io::Result<() producer.get_field_constant_list().len() )); code.push(format!("uint get_size_of_io_map() {{return {};}}\n", producer.get_io_map().len())); + code.push(format!("uint get_size_of_bus_field_map() {{return {};}}\n", producer.get_busid_field_info().len())); // let mut ml_def = generate_message_list_def(producer, producer.get_message_list()); // code.append(&mut ml_def); diff --git a/code_producers/src/c_elements/common/calcwit.cpp b/code_producers/src/c_elements/common/calcwit.cpp index 949fea418..e8b73141c 100644 --- a/code_producers/src/c_elements/common/calcwit.cpp +++ b/code_producers/src/c_elements/common/calcwit.cpp @@ -35,6 +35,7 @@ Circom_CalcWit::Circom_CalcWit (Circom_Circuit *aCircuit, uint maxTh) { componentMemory = new Circom_Component[get_number_of_components()]; circuitConstants = circuit ->circuitConstants; templateInsId2IOSignalInfo = circuit -> templateInsId2IOSignalInfo; + busInsId2FieldInfo = circuit -> busInsId2FieldInfo; maxThread = maxTh; diff --git a/code_producers/src/c_elements/common/circom.hpp b/code_producers/src/c_elements/common/circom.hpp index 4a475654e..3281a621f 100644 --- a/code_producers/src/c_elements/common/circom.hpp +++ b/code_producers/src/c_elements/common/circom.hpp @@ -22,9 +22,9 @@ struct __attribute__((__packed__)) HashSignalInfo { struct IOFieldDef { u32 offset; - u32 size; u32 len; u32 *lengths; + u32 size; u32 busId; }; @@ -84,5 +84,6 @@ uint get_size_of_input_hashmap(); uint get_size_of_witness(); uint get_size_of_constants(); uint get_size_of_io_map(); +uint get_size_of_bus_field_map(); #endif // __CIRCOM_H diff --git a/code_producers/src/c_elements/common/main.cpp b/code_producers/src/c_elements/common/main.cpp index d63555251..b0ec09711 100644 --- a/code_producers/src/c_elements/common/main.cpp +++ b/code_producers/src/c_elements/common/main.cpp @@ -54,7 +54,8 @@ Circom_Circuit* loadCircuit(std::string const &datFileName) { memcpy((void *)(circuit->circuitConstants), (void *)(bdata+inisize), dsize); } - std::map templateInsId2IOSignalInfo1; + std::map templateInsId2IOSignalInfo1; + IOFieldDefPair* busInsId2FieldInfo1; if (get_size_of_io_map()>0) { u32 index[get_size_of_io_map()]; inisize += dsize; @@ -66,12 +67,11 @@ Circom_Circuit* loadCircuit(std::string const &datFileName) { u32 dataiomap[(sb.st_size-inisize)/sizeof(u32)]; memcpy((void *)dataiomap, (void *)(bdata+inisize), sb.st_size-inisize); u32* pu32 = dataiomap; - for (int i = 0; i < get_size_of_io_map(); i++) { u32 n = *pu32; - IODefPair p; + IOFieldDefPair p; p.len = n; - IODef defs[n]; + IOFieldDef defs[n]; pu32 += 1; for (u32 j = 0; j templateInsId2IOSignalInfo = move(templateInsId2IOSignalInfo1); - + circuit->busInsId2FieldInfo = busInsId2FieldInfo1; + munmap(bdata, sb.st_size); return circuit; diff --git a/compiler/src/circuit_design/circuit.rs b/compiler/src/circuit_design/circuit.rs index 94e051ea7..27ac9e111 100644 --- a/compiler/src/circuit_design/circuit.rs +++ b/compiler/src/circuit_design/circuit.rs @@ -360,7 +360,7 @@ impl WriteC for Circuit { producer.get_io_map().len() )); code.push(format!( - "uint get_size_of_bus_list() {{return {};}}\n", + "uint get_size_of_bus_field_map() {{return {};}}\n", producer.get_busid_field_info().len() )); //code.append(&mut generate_message_list_def(producer, producer.get_message_list())); @@ -482,7 +482,7 @@ impl WriteC for Circuit { producer.get_io_map().len() )); code.push(format!( - "uint get_size_of_bus_list() {{return {};}}\n", + "uint get_size_of_bus_field_map() {{return {};}}\n", producer.get_busid_field_info().len() )); //code.append(&mut generate_message_list_def(producer, producer.get_message_list())); diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 54c2a365b..18aa7e8cc 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -474,6 +474,8 @@ impl WriteC for CallBucket { template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); if indexes.len() > 0 { + map_prologue.push(format!("{{")); + map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); map_prologue.push(format!("{{")); //cur_def contains a pointer to the definion of the next acces. //The first time it is taken from template_ins_2_io_info @@ -481,7 +483,6 @@ impl WriteC for CallBucket { circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string())); - map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_list) = &indexes[idxpos] { @@ -501,15 +502,15 @@ impl WriteC for CallBucket { map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", map_index,(i-1).to_string(),i.to_string()); } - map_prologue.push(format!("map_accesses_aux[{}] = {}", idxpos.to_string(), map_index)); + map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); // add to the access expression the computed offset in the array // multiplied buy the size of the elements - map_access = format!("{}+map_accesses_aux[{}]*cur_def->size", + map_access = format!("{}+map_accesses_aux[{}]", map_access, idxpos.to_string()); } else if let AccessType::Qualified(_) = &indexes[idxpos] { // we already have the cur_def - map_prologue.push(format!("map_accesses_aux[{}] = cur_def.offset", idxpos.to_string())); + map_prologue.push(format!("map_accesses_aux[{}] = cur_def->offset;", idxpos.to_string())); } else { assert!(false); } @@ -523,6 +524,7 @@ impl WriteC for CallBucket { } } } + map_prologue.push(format!("}}")); } ((map_prologue, map_access),Some(template_id_in_component(sub_component_pos_in_memory.clone()))) } else { diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index d22756246..80a21bbe9 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -247,42 +247,31 @@ impl WriteC for LoadBucket { template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string()); if indexes.len() > 0 { - map_prologue.push(format!("{{")); - //cur_def contains a pointer to the definion of the next acces. + //cur_def contains a string that goes to the definion of the next acces. //The first time it is taken from template_ins_2_io_info - map_prologue.push(format!("IOFieldDef *cur_def = &({}->{}[{}].defs[{}]);", + let mut cur_def = format!("{}->{}[{}].defs[{}]", circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), - signal_code.to_string())); - map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); + signal_code.to_string()); let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_list) = &indexes[idxpos] { - map_prologue.push(format!("{{")); - map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); //We first compute the number of elements as - //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with - // map_index_aux[i] = computation of index_list[i] + //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] let (mut index_code_0, mut map_index) = index_list[0].produce_c(producer, parallel); map_prologue.append(&mut index_code_0); - map_prologue.push(format!("map_index_aux[0]={};",map_index)); - map_index = format!("map_index_aux[0]"); for i in 1..index_list.len() { let (mut index_code, index_exp) = index_list[i].produce_c(producer, parallel); map_prologue.append(&mut index_code); - map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); - map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", - map_index,(i-1).to_string(),i.to_string()); + map_index = format!("({})*({}.lengths[{}])+{}", + map_index,cur_def,(i-1).to_string(),index_exp); } - map_prologue.push(format!("map_accesses_aux[{}] = {}", idxpos.to_string(), map_index)); - map_prologue.push(format!("}}")); // add to the access expression the computed offset in the array // multiplied buy the size of the elements - map_access = format!("{}+map_accesses_aux[{}]*cur_def->size", - map_access, idxpos.to_string()); + map_access = format!("{}+({})*{}.size", map_access, map_index, cur_def); } else if let AccessType::Qualified(_) = &indexes[idxpos] { // we already have the cur_def - map_prologue.push(format!("map_accesses_aux[{}] = cur_def.offset", idxpos.to_string())); + map_access = format!("{}+{}.offset", map_access, cur_def); } else { assert!(false); } @@ -290,9 +279,9 @@ impl WriteC for LoadBucket { if idxpos < indexes.len() { if let AccessType::Qualified(field_no) = &indexes[idxpos] { // we get the next definition in cur_def from the bus bus_id - map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", + cur_def = format!("{}->{}[{}.busId].defs[{}]", circom_calc_wit(), bus_ins_2_field_info(), - field_no.to_string())); + cur_def, field_no.to_string()); } } } diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index db40c4754..23a5078e0 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -365,13 +365,14 @@ impl WriteC for StoreBucket { signal_code.to_string()); if indexes.len() > 0 { map_prologue.push(format!("{{")); + map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); + map_prologue.push(format!("{{")); //cur_def contains a pointer to the definion of the next acces. //The first time it is taken from template_ins_2_io_info map_prologue.push(format!("IOFieldDef *cur_def = &({}->{}[{}].defs[{}]);", circom_calc_wit(), template_ins_2_io_info(), template_id_in_component(sub_component_pos_in_memory.clone()), signal_code.to_string())); - map_prologue.push(format!("uint map_accesses_aux[{}];",indexes.len().to_string())); let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_list) = &indexes[idxpos] { @@ -391,15 +392,15 @@ impl WriteC for StoreBucket { map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", map_index,(i-1).to_string(),i.to_string()); } - map_prologue.push(format!("map_accesses_aux[{}] = {}", idxpos.to_string(), map_index)); + map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); // add to the access expression the computed offset in the array // multiplied buy the size of the elements - map_access = format!("{}+map_accesses_aux[{}]*cur_def->size", + map_access = format!("{}+map_accesses_aux[{}]", map_access, idxpos.to_string()); } else if let AccessType::Qualified(_) = &indexes[idxpos] { // we already have the cur_def - map_prologue.push(format!("map_accesses_aux[{}] = cur_def.offset", idxpos.to_string())); + map_prologue.push(format!("map_accesses_aux[{}] = cur_def->offset;", idxpos.to_string())); } else { assert!(false); } @@ -413,6 +414,7 @@ impl WriteC for StoreBucket { } } } + map_prologue.push(format!("}}")); } ((map_prologue, map_access),Some(template_id_in_component(sub_component_pos_in_memory.clone()))) } else { @@ -617,14 +619,14 @@ impl WriteC for StoreBucket { } _ => (), } - if let AddressType::SubcmpSignal { .. } = &self.dest_address_type { - prologue.push(format!("}}")); - } if let LocationRule::Mapped { indexes, .. } = &self.dest { if indexes.len() > 0 { prologue.push(format!("}}")); } } + if let AddressType::SubcmpSignal { .. } = &self.dest_address_type { + prologue.push(format!("}}")); + } (prologue, "".to_string()) } From e43ebffb42b96a564b4833060e15ff56db6d5c1a Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 17 Jul 2024 13:37:22 +0200 Subject: [PATCH 128/189] adding error message unknown component assignment --- constraint_generation/src/execute.rs | 4 ++++ program_structure/src/program_library/error_code.rs | 2 ++ type_analysis/src/analyzers/unknown_known_analysis.rs | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 66cf952d0..2ad654abf 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2020,6 +2020,10 @@ fn perform_assign( // Generate an arithmetic slice for the accessed buses let mut signals_values_left: Vec = Vec::new(); let mut signals_values_right = Vec::new(); + + // For now we can take advantage of the following: all buses in a slice + // are equals so we only call once to generate the accesses + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ let assigned_bus = treat_result_with_memory_error( BusSlice::get_reference_to_single_value_by_index(assigned_bus_slice, i), diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 28cede3fe..cc1e86820 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -37,6 +37,7 @@ pub enum ReportCode { UnreachableSignals, UnknownIndex, UnknownDimension, + UnknownTemplateAssignment, SameFunctionDeclaredTwice, SameTemplateDeclaredTwice, SameSymbolDeclaredTwice, @@ -213,6 +214,7 @@ impl fmt::Display for ReportCode { RuntimeWarning => "T3002", UnknownDimension => "T20460", UnknownTemplate => "T20461", + UnknownTemplateAssignment => "T2O461-A", NonQuadratic => "T20462", NonConstantArrayLength => "T20463", NonComputableExpression => "T20464", diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 81e825611..aef3d5829 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -198,6 +198,11 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma add_report(ReportCode::NonQuadratic, meta, file_id, &mut reports); } } + else if environment.has_component(var){ + if access_tag == Unknown { + add_report(ReportCode::UnknownTemplateAssignment, meta, file_id, &mut reports); + } + } } } } @@ -520,6 +525,7 @@ fn add_report( let message = match error_code { UnknownDimension => "The length of every array must known during the constraint generation phase".to_string(), UnknownTemplate => "Every component instantiation must be resolved during the constraint generation phase".to_string(), + UnknownTemplateAssignment => "Assigments to signals within an unknown access to an array of components are not allowed".to_string(), UnknownBus => "Parameters of a bus must be known during the constraint generation phase".to_string(), NonQuadratic => "Non-quadratic constraint was detected statically, using unknown index will cause the constraint to be non-quadratic".to_string(), UnreachableConstraints => "There are constraints depending on the value of the condition and it can be unknown during the constraint generation phase".to_string(), From 5951c4b3a3a00156f1d8b3ec09f4c15a2605293f Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 17 Jul 2024 16:50:06 +0200 Subject: [PATCH 129/189] bug fixed --- compiler/src/intermediate_representation/call_bucket.rs | 8 ++++---- compiler/src/intermediate_representation/store_bucket.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 18aa7e8cc..780ee05b3 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -499,21 +499,21 @@ impl WriteC for CallBucket { let (mut index_code, index_exp) = index_list[i].produce_c(producer, parallel); map_prologue.append(&mut index_code); map_prologue.push(format!("map_index_aux[{}]={};",i.to_string(),index_exp)); + // multiply the offset inthe array by the size of the elements map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", map_index,(i-1).to_string(),i.to_string()); } map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); - // add to the access expression the computed offset in the array - // multiplied buy the size of the elements - map_access = format!("{}+map_accesses_aux[{}]", - map_access, idxpos.to_string()); } else if let AccessType::Qualified(_) = &indexes[idxpos] { // we already have the cur_def map_prologue.push(format!("map_accesses_aux[{}] = cur_def->offset;", idxpos.to_string())); } else { assert!(false); } + // add to the access expression the computed offset + map_access = format!("{}+map_accesses_aux[{}]", + map_access, idxpos.to_string()); idxpos += 1; if idxpos < indexes.len() { if let AccessType::Qualified(field_no) = &indexes[idxpos] { diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 23a5078e0..82019f359 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -392,18 +392,18 @@ impl WriteC for StoreBucket { map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", map_index,(i-1).to_string(),i.to_string()); } + // multiply the offset inthe array by the size of the elements map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); - // add to the access expression the computed offset in the array - // multiplied buy the size of the elements - map_access = format!("{}+map_accesses_aux[{}]", - map_access, idxpos.to_string()); } else if let AccessType::Qualified(_) = &indexes[idxpos] { // we already have the cur_def map_prologue.push(format!("map_accesses_aux[{}] = cur_def->offset;", idxpos.to_string())); } else { assert!(false); } + // add to the access expression the computed offset + map_access = format!("{}+map_accesses_aux[{}]", + map_access, idxpos.to_string()); idxpos += 1; if idxpos < indexes.len() { if let AccessType::Qualified(field_no) = &indexes[idxpos] { From 18b511f0d3c5b1c6f753b382a4d0503fe599ba27 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 17 Jul 2024 18:06:12 +0200 Subject: [PATCH 130/189] adding field name to FieldData --- code_producers/src/components/mod.rs | 3 ++- compiler/src/circuit_design/build.rs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index d2ff7c4a0..b34d23002 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -23,7 +23,8 @@ pub struct FieldData{ pub dimensions: Vec, pub size: usize, pub offset: usize, - pub bus_id: Option + pub bus_id: Option, + pub name: String } pub type FieldMap = Vec>; diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 88d73ae54..adc6effe0 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -403,7 +403,7 @@ fn get_info_buses(buses: &Vec)->(usize, FieldMap){ let mut bus_to_fields_data = Vec::new(); for bus in buses{ let mut field_data = vec![FieldData::default(); bus.fields.len()]; - for (_, field_info) in &bus.fields{ + for (name, field_info) in &bus.fields{ let mut total_array_size = 1; for len in &field_info.dimensions{ total_array_size *= len; @@ -413,7 +413,8 @@ fn get_info_buses(buses: &Vec)->(usize, FieldMap){ offset: field_info.offset, size: individual_size, dimensions: field_info.dimensions.clone(), - bus_id: field_info.bus_id + bus_id: field_info.bus_id, + name: name.clone() }; field_data[field_info.field_id] = data; } From dcb2415aa1dd0c5bf9cb7d357fb4f2d6ffa37364 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 17 Jul 2024 20:48:33 +0200 Subject: [PATCH 131/189] first version sizes for c --- .../call_bucket.rs | 64 ++++++++++++++----- .../ir_interface.rs | 2 +- .../load_bucket.rs | 16 ++++- .../store_bucket.rs | 47 ++++++++++---- .../intermediate_representation/translate.rs | 32 +++++++--- .../src/intermediate_representation/types.rs | 10 ++- .../src/ir_processing/build_inputs_info.rs | 17 ++++- constraint_generation/src/execute.rs | 1 + 8 files changed, 144 insertions(+), 45 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 18aa7e8cc..88ef5f41d 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -92,16 +92,25 @@ impl WriteWasm for CallBucket { instructions.push(get_local(producer.get_call_lvar_tag())); instructions.push(set_constant(&count.to_string())); instructions.push(add32()); - if self.argument_types[i].size > 1 { + // TODO: We compute the possible sizes, case multiple size + // Now in case Multiple we just return the first value + // See below case C (complete) + let arg_size = match &self.argument_types[i].size{ + SizeOption::Single(value) => *value, + SizeOption::Multiple(values) => { + values[0] + } + }; + if arg_size > 1 { instructions.push(set_local(producer.get_store_aux_1_tag())); } let mut instructions_arg = p.produce_wasm(producer); instructions.append(&mut instructions_arg); - if self.argument_types[i].size == 1 { + if arg_size == 1 { instructions.push(call("$Fr_copy")); } else { instructions.push(set_local(producer.get_store_aux_2_tag())); - instructions.push(set_constant(&self.argument_types[i].size.to_string())); + instructions.push(set_constant(&arg_size.to_string())); instructions.push(set_local(producer.get_copy_counter_tag())); instructions.push(add_block()); instructions.push(add_loop()); @@ -131,7 +140,7 @@ impl WriteWasm for CallBucket { if producer.needs_comments() { instructions.push(format!(";; end copying argument {}", i)); } - count += self.argument_types[i].size * 4 * producer.get_size_32_bits_in_memory(); + count += arg_size * 4 * producer.get_size_32_bits_in_memory(); i += 1; } } @@ -317,7 +326,16 @@ impl WriteWasm for CallBucket { } } } - instructions.push(set_constant(&data.context.size.to_string())); + // TODO: We compute the possible sizes, case multiple size + // Now in case Multiple we just return the first value + // See below case C (complete) + let data_size = match &data.context.size{ + SizeOption::Single(value) => *value, + SizeOption::Multiple(values) => { + values[0] + } + }; + instructions.push(set_constant(&data_size.to_string())); instructions.push(call(&format!("${}", self.symbol))); instructions.push(tee_local(producer.get_merror_tag())); instructions.push(add_if()); @@ -339,7 +357,7 @@ impl WriteWasm for CallBucket { instructions.push(load32(Some( &producer.get_input_counter_address_in_component().to_string(), ))); //remaining inputs to be set - instructions.push(set_constant(&data.context.size.to_string())); + instructions.push(set_constant(&data_size.to_string())); instructions.push(sub32()); instructions.push(store32(Some( &producer.get_input_counter_address_in_component().to_string(), @@ -425,9 +443,16 @@ impl WriteC for CallBucket { let (mut prologue_value, src) = p.produce_c(producer, parallel); prologue.append(&mut prologue_value); let arena_position = format!("&{}[{}]", L_VAR_FUNC_CALL_STORAGE, count); - if self.argument_types[i].size > 1 { + // TODO, CASE CALL ARGUMENTS + let size = match &self.argument_types[i].size{ + SizeOption::Single(value) => *value, + SizeOption::Multiple(values) => { + values[0] + } + }; + if size > 1 { let copy_arguments = - vec![arena_position, src, self.argument_types[i].size.to_string()]; + vec![arena_position, src, size.to_string()]; prologue .push(format!("{};", build_call("Fr_copyn".to_string(), copy_arguments))); } else { @@ -436,7 +461,7 @@ impl WriteC for CallBucket { .push(format!("{};", build_call("Fr_copy".to_string(), copy_arguments))); } prologue.push(format!("// end copying argument {}", i)); - count += self.argument_types[i].size; + count += size; i += 1; } let result; @@ -459,9 +484,18 @@ impl WriteC for CallBucket { let (mut cmp_prologue, cmp_index) = cmp_address.produce_c(producer, parallel); prologue.append(&mut cmp_prologue); prologue.push(format!("{{")); - prologue.push(format!("uint {} = {};", cmp_index_ref, cmp_index)); - + prologue.push(format!("uint {} = {};", cmp_index_ref, cmp_index)); } + let size = match &data.context.size{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + prologue.push(format!("int size_store[{}] = {};", + values.len(), + set_list(values.to_vec()) + )); + format!("size_store[{}]", cmp_index_ref) + } + }; let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &data.dest { @@ -551,7 +585,7 @@ impl WriteC for CallBucket { } }; call_arguments.push(result_ref); - call_arguments.push(data.context.size.to_string()); + call_arguments.push(size.clone()); prologue.push(format!("{};", build_call(self.symbol.clone(), call_arguments))); if let LocationRule::Mapped { indexes, .. } = &data.dest { if indexes.len() > 0 { @@ -561,9 +595,9 @@ impl WriteC for CallBucket { // if output and parallel send notify if let AddressType::Signal = &data.dest_address_type { if parallel.unwrap() && data.dest_is_output { - if data.context.size > 0 { + if size != "0" { prologue.push(format!("{{")); - prologue.push(format!("for (int i = 0; i < {}; i++) {{",data.context.size)); + prologue.push(format!("for (int i = 0; i < {}; i++) {{", size)); prologue.push(format!("{}->componentMemory[{}].mutexes[{}+i].lock();",CIRCOM_CALC_WIT,CTX_INDEX,dest_index.clone())); prologue.push(format!("{}->componentMemory[{}].outputIsSet[{}+i]=true;",CIRCOM_CALC_WIT,CTX_INDEX,dest_index.clone())); prologue.push(format!("{}->componentMemory[{}].mutexes[{}+i].unlock();",CIRCOM_CALC_WIT,CTX_INDEX,dest_index.clone())); @@ -588,7 +622,7 @@ impl WriteC for CallBucket { ); let sub_cmp_counter_decrease = format!( "{} -= {}", - sub_cmp_counter, &data.context.size + sub_cmp_counter, size ); if let InputInformation::Input{status} = input_information { if let StatusInput::NoLast = status { diff --git a/compiler/src/intermediate_representation/ir_interface.rs b/compiler/src/intermediate_representation/ir_interface.rs index 4f0c34e28..72c489d8c 100644 --- a/compiler/src/intermediate_representation/ir_interface.rs +++ b/compiler/src/intermediate_representation/ir_interface.rs @@ -12,7 +12,7 @@ pub use super::loop_bucket::LoopBucket; pub use super::return_bucket::ReturnBucket; pub use super::store_bucket::StoreBucket; pub use super::log_bucket::LogBucketArg; -pub use super::types::{InstrContext, ValueType}; +pub use super::types::{InstrContext, ValueType, SizeOption}; pub use super::value_bucket::ValueBucket; use crate::translating_traits::*; diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 80a21bbe9..31c23cb21 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -303,13 +303,25 @@ impl WriteC for LoadBucket { } AddressType::SubcmpSignal { uniform_parallel_value, is_output, .. } => { if *is_output { + // We compute the possible sizes, case multiple size + let size = match &self.context.size{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + prologue.push(format!("int size_load[{}] = {};", + values.len(), + set_list(values.to_vec()) + )); + format!("size_load[{}]", cmp_index_ref) + } + }; if uniform_parallel_value.is_some(){ if uniform_parallel_value.unwrap(){ prologue.push(format!("{{")); prologue.push(format!("int aux1 = {};",cmp_index_ref.clone())); prologue.push(format!("int aux2 = {};",src_index.clone())); // check each one of the outputs of the assignment, we add i to check them one by one - prologue.push(format!("for (int i = 0; i < {}; i++) {{",self.context.size)); + + prologue.push(format!("for (int i = 0; i < {}; i++) {{", size)); prologue.push(format!("ctx->numThreadMutex.lock();")); prologue.push(format!("ctx->numThread--;")); //prologue.push(format!("printf(\"%i \\n\", ctx->numThread);")); @@ -345,7 +357,7 @@ impl WriteC for LoadBucket { prologue.push(format!("int aux1 = {};",cmp_index_ref.clone())); prologue.push(format!("int aux2 = {};",src_index.clone())); // check each one of the outputs of the assignment, we add i to check them one by one - prologue.push(format!("for (int i = 0; i < {}; i++) {{",self.context.size)); + prologue.push(format!("for (int i = 0; i < {}; i++) {{", size)); prologue.push(format!("ctx->numThreadMutex.lock();")); prologue.push(format!("ctx->numThread--;")); //prologue.push(format!("printf(\"%i \\n\", ctx->numThread);")); diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 23a5078e0..2c964b4a8 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -53,7 +53,18 @@ impl WriteWasm for StoreBucket { fn produce_wasm(&self, producer: &WASMProducer) -> Vec { use code_producers::wasm_elements::wasm_code_generator::*; let mut instructions = vec![]; - if self.context.size == 0 { + + // TODO: We compute the possible sizes, case multiple size + // Now in case Multiple we just return the first value + // See below case C (complete) + let size = match &self.context.size{ + SizeOption::Single(value) => *value, + SizeOption::Multiple(values) => { + values[0] + } + }; + + if size == 0 { return vec![]; } if producer.needs_comments() { @@ -226,16 +237,16 @@ impl WriteWasm for StoreBucket { if producer.needs_comments() { instructions.push(";; getting src".to_string()); } - if self.context.size > 1 { + if size > 1 { instructions.push(set_local(producer.get_store_aux_1_tag())); } let mut instructions_src = self.src.produce_wasm(producer); instructions.append(&mut instructions_src); - if self.context.size == 1 { + if size == 1 { instructions.push(call("$Fr_copy")); } else { instructions.push(set_local(producer.get_store_aux_2_tag())); - instructions.push(set_constant(&self.context.size.to_string())); + instructions.push(set_constant(&size.to_string())); instructions.push(set_local(producer.get_copy_counter_tag())); instructions.push(add_block()); instructions.push(add_loop()); @@ -273,7 +284,7 @@ impl WriteWasm for StoreBucket { instructions.push(load32(Some( &producer.get_input_counter_address_in_component().to_string(), ))); //remaining inputs to be set - instructions.push(set_constant(&self.context.size.to_string())); + instructions.push(set_constant(&size.to_string())); instructions.push(sub32()); instructions.push(store32(Some( &producer.get_input_counter_address_in_component().to_string(), @@ -349,9 +360,21 @@ impl WriteC for StoreBucket { if let AddressType::SubcmpSignal { cmp_address, .. } = &self.dest_address_type { let (mut cmp_prologue, cmp_index) = cmp_address.produce_c(producer, parallel); prologue.append(&mut cmp_prologue); - prologue.push(format!("{{")); - prologue.push(format!("uint {} = {};", cmp_index_ref, cmp_index)); - } + prologue.push(format!("{{")); + prologue.push(format!("uint {} = {};", cmp_index_ref, cmp_index)); + } + // We compute the possible sizes, case multiple sizes + let size = match &self.context.size{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + prologue.push(format!("int size_store[{}] = {};", + values.len(), + set_list(values.clone()) + )); + format!("size_store[{}]", cmp_index_ref) + } + }; + let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &self.dest { (location.produce_c(producer, parallel), template_header.clone()) @@ -455,13 +478,13 @@ impl WriteC for StoreBucket { prologue.append(&mut src_prologue); prologue.push(format!("// end load src")); std::mem::drop(src_prologue); - if self.context.size > 1 { - let copy_arguments = vec![aux_dest, src, self.context.size.to_string()]; + if size != "1" && size != "0" { + let copy_arguments = vec![aux_dest, src, size.clone()]; prologue.push(format!("{};", build_call("Fr_copyn".to_string(), copy_arguments))); if let AddressType::Signal = &self.dest_address_type { if parallel.unwrap() && self.dest_is_output { prologue.push(format!("{{")); - prologue.push(format!("for (int i = 0; i < {}; i++) {{",self.context.size)); + prologue.push(format!("for (int i = 0; i < {}; i++) {{", size)); prologue.push(format!("{}->componentMemory[{}].mutexes[{}+i].lock();",CIRCOM_CALC_WIT,CTX_INDEX,aux_dest_index.clone())); prologue.push(format!("{}->componentMemory[{}].outputIsSet[{}+i]=true;",CIRCOM_CALC_WIT,CTX_INDEX,aux_dest_index.clone())); prologue.push(format!("{}->componentMemory[{}].mutexes[{}+i].unlock();",CIRCOM_CALC_WIT,CTX_INDEX,aux_dest_index.clone())); @@ -494,7 +517,7 @@ impl WriteC for StoreBucket { ); let sub_cmp_counter_decrease = format!( "{} -= {}", - sub_cmp_counter, self.context.size + sub_cmp_counter, size ); if let InputInformation::Input{status} = input_information { if let StatusInput::NoLast = status { diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 48b9c16b7..c95634f11 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -1,6 +1,7 @@ use super::ir_interface::*; use crate::hir::very_concrete_program::*; use crate::intermediate_representation::log_bucket::LogBucketArg; +use crate::intermediate_representation::types::SizeOption; use constant_tracking::ConstantTracker; use num_bigint_dig::BigInt; use program_structure::ast::*; @@ -274,7 +275,7 @@ fn initialize_constants(state: &mut State, constants: Vec) { dest_is_output: false, dest_address_type: AddressType::Variable, dest: LocationRule::Indexed { location: full_address, template_header: None }, - context: InstrContext { size: 1 }, + context: InstrContext { size: SizeOption::Single(1) }, src: content, } .allocate(); @@ -667,7 +668,11 @@ fn translate_constraint_equality(stmt: Statement, state: &mut State, context: &C let length = if let Variable { meta, name, access} = lhe.clone() { let def = SymbolDef { meta, symbol: name, acc: access }; - ProcessedSymbol::new(def, state, context).length + let aux = ProcessedSymbol::new(def, state, context).length; + match aux{ + SizeOption::Single(value) => value, + SizeOption::Multiple(_) => unreachable!("Should be single possible lenght"), + } } else {1}; let lhe_pointer = translate_expression(lhe, state, context); @@ -1020,7 +1025,7 @@ struct BusAccessInfo{ struct ProcessedSymbol { line: usize, - length: usize, + length: SizeOption, symbol_dimensions: Vec, // the dimensions of last symbol symbol_size: usize, // the size of the last symbol message_id: usize, @@ -1209,20 +1214,27 @@ impl ProcessedSymbol { // First check that the possible sizes are all equal let mut is_first = true; + let mut all_equal = true; let mut with_length: usize = 0; - for possible_size in possible_status.possible_sizes{ + for possible_size in &possible_status.possible_sizes{ if is_first{ - with_length = possible_size; + with_length = *possible_size; is_first = false; } else{ - if with_length != possible_size{ - unreachable!("On development: Circom compiler does not accept for now the assignment of arrays of unknown sizes during the execution of loops"); + if with_length != *possible_size{ + all_equal = false; } } } + let size = if all_equal{ + SizeOption::Single(with_length) + } else{ + SizeOption::Multiple(possible_status.possible_sizes) + }; + // Compute the signal location inside the component let signal_location = build_signal_location( &accessed_component_signal.unwrap(), @@ -1241,7 +1253,7 @@ impl ProcessedSymbol { xtype: meta.get_type_knowledge().get_reduces_to(), line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), message_id: state.message_id, - length: with_length, + length: size, symbol_dimensions: symbol_info.dimensions.clone(), symbol_size: symbol_info.size, symbol: symbol_info, @@ -1260,7 +1272,7 @@ impl ProcessedSymbol { xtype: meta.get_type_knowledge().get_reduces_to(), line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), message_id: state.message_id, - length: with_length, + length: SizeOption::Single(with_length), symbol_dimensions: initial_symbol_dimensions, symbol_size: initial_symbol_size, symbol: symbol_info, @@ -1724,7 +1736,7 @@ fn translate_call_arguments( .iter() .fold(1, |r, c| r * (*c)); let instr = translate_expression(arg, state, context); - info.argument_data.push(InstrContext { size: length }); + info.argument_data.push(InstrContext { size: SizeOption::Single(length) }); info.arguments.push(instr); } info diff --git a/compiler/src/intermediate_representation/types.rs b/compiler/src/intermediate_representation/types.rs index 7968e214d..773dd760a 100644 --- a/compiler/src/intermediate_representation/types.rs +++ b/compiler/src/intermediate_representation/types.rs @@ -14,7 +14,13 @@ impl ToString for ValueType { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] +pub enum SizeOption{ + Single(usize), + Multiple(Vec) +} + +#[derive(Clone, PartialEq, Eq)] pub struct InstrContext { - pub size: usize, + pub size: SizeOption, } diff --git a/compiler/src/ir_processing/build_inputs_info.rs b/compiler/src/ir_processing/build_inputs_info.rs index 49e6edb9b..d16f48df3 100644 --- a/compiler/src/ir_processing/build_inputs_info.rs +++ b/compiler/src/ir_processing/build_inputs_info.rs @@ -96,9 +96,14 @@ pub fn visit_call( inside_loop: bool )-> bool { use ReturnType::*; - if let Final(data) = &mut bucket.return_info { - if data.context.size > 0{ + let needs_consider = match data.context.size{ + SizeOption::Single(value) if value == 0 =>{ + false + } + _ => true + }; + if needs_consider{ visit_address_type( &mut data.dest_address_type, known_last_component, @@ -216,7 +221,13 @@ pub fn visit_store( found_unknown_address: bool, inside_loop: bool )-> bool{ - if bucket.context.size > 0{ + let needs_consider = match bucket.context.size{ + SizeOption::Single(value) if value == 0 =>{ + false + } + _ => true + }; + if needs_consider{ visit_address_type( &mut bucket.dest_address_type, known_last_component, diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 2ad654abf..2626125f3 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1448,6 +1448,7 @@ fn perform_assign( &accessing_information.array_access, ) }; + let component = treat_result_with_memory_error( memory_response, meta, From c7f3609624f5d7a7bfc72c64375ac6bab988b2fa Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 18 Jul 2024 15:47:09 +0200 Subject: [PATCH 132/189] adding symbol_dim info to Mapped --- .../intermediate_representation/call_bucket.rs | 18 ++++++++++++++---- .../ir_interface.rs | 1 + .../intermediate_representation/load_bucket.rs | 18 ++++++++++++++---- .../location_rule.rs | 10 ++++++++-- .../store_bucket.rs | 18 ++++++++++++++---- .../intermediate_representation/translate.rs | 6 +++++- compiler/src/ir_processing/build_stack.rs | 2 +- compiler/src/ir_processing/reduce_stack.rs | 7 ++++--- compiler/src/ir_processing/set_arena_size.rs | 2 +- 9 files changed, 62 insertions(+), 20 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 780ee05b3..ede020829 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -238,8 +238,13 @@ impl WriteWasm for CallBucket { } let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_list) = &indexes[idxpos] { - let mut infopos = 0; + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + + // TODO: using the dim info + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + + let mut infopos = 0; assert!(index_list.len() > 0); //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] @@ -485,8 +490,13 @@ impl WriteC for CallBucket { signal_code.to_string())); let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_list) = &indexes[idxpos] { - map_prologue.push(format!("{{")); + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + + // TODO: using the dim info + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + + map_prologue.push(format!("{{")); map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); //We first compute the number of elements as //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with diff --git a/compiler/src/intermediate_representation/ir_interface.rs b/compiler/src/intermediate_representation/ir_interface.rs index 4f0c34e28..a65c856ec 100644 --- a/compiler/src/intermediate_representation/ir_interface.rs +++ b/compiler/src/intermediate_representation/ir_interface.rs @@ -7,6 +7,7 @@ pub use super::create_component_bucket::CreateCmpBucket; pub use super::load_bucket::LoadBucket; pub use super::location_rule::LocationRule; pub use super::location_rule::AccessType; +pub use super::location_rule::IndexedInfo; pub use super::log_bucket::LogBucket; pub use super::loop_bucket::LoopBucket; pub use super::return_bucket::ReturnBucket; diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 80a21bbe9..46d7758fe 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -136,8 +136,13 @@ impl WriteWasm for LoadBucket { } let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_list) = &indexes[idxpos] { - let mut infopos = 0; + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + + // TODO: using the dim info + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + + let mut infopos = 0; assert!(index_list.len() > 0); //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] @@ -255,8 +260,13 @@ impl WriteC for LoadBucket { signal_code.to_string()); let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_list) = &indexes[idxpos] { - //We first compute the number of elements as + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + + // TODO: using the dim info + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + + //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] let (mut index_code_0, mut map_index) = index_list[0].produce_c(producer, parallel); map_prologue.append(&mut index_code_0); diff --git a/compiler/src/intermediate_representation/location_rule.rs b/compiler/src/intermediate_representation/location_rule.rs index c5c52d035..3501d5cd8 100644 --- a/compiler/src/intermediate_representation/location_rule.rs +++ b/compiler/src/intermediate_representation/location_rule.rs @@ -1,8 +1,14 @@ use super::ir_interface::*; +#[derive(Clone)] +pub struct IndexedInfo{ + pub indexes: Vec, + pub symbol_dim: usize +} + #[derive(Clone)] pub enum AccessType{ - Indexed(Vec), // Case accessing an array + Indexed(IndexedInfo), // Case accessing an array Qualified(usize), // Case accessing a field -> id field } @@ -10,7 +16,7 @@ impl ToString for AccessType { fn to_string(&self) -> String { match &self{ AccessType::Indexed(index) =>{ - index.iter().map(|i| i.to_string()).collect() + index.indexes.iter().map(|i| i.to_string()).collect() } AccessType::Qualified(value) =>{ format!("field({})", value) diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 82019f359..5656a61c1 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -144,8 +144,13 @@ impl WriteWasm for StoreBucket { } let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_list) = &indexes[idxpos] { - let mut infopos = 0; + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + + // TODO: using the dim info + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + + let mut infopos = 0; assert!(index_list.len() > 0); //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] @@ -375,8 +380,13 @@ impl WriteC for StoreBucket { signal_code.to_string())); let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_list) = &indexes[idxpos] { - map_prologue.push(format!("{{")); + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + + // TODO: using the dim info + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + + map_prologue.push(format!("{{")); map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); //We first compute the number of elements as //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 48b9c16b7..8430b9fa3 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -970,7 +970,11 @@ fn build_signal_location( for index in indexes{ let filtered = indexing_instructions_filter(index, state); if filtered.len() > 0{ - accesses.push(AccessType::Indexed(filtered)); + let index_info = IndexedInfo{ + indexes: filtered, + symbol_dim: dimensions.len() + }; + accesses.push(AccessType::Indexed(index_info)); } if i != len_indexes -1{ // The last access is just an index diff --git a/compiler/src/ir_processing/build_stack.rs b/compiler/src/ir_processing/build_stack.rs index ee6fc1ab5..0ac90fa3e 100644 --- a/compiler/src/ir_processing/build_stack.rs +++ b/compiler/src/ir_processing/build_stack.rs @@ -132,7 +132,7 @@ pub fn build_location(bucket: &mut LocationRule, fresh: usize) -> usize { for acc in indexes{ match acc{ AccessType::Indexed(ind) =>{ - let depth = build_list(ind, fresh); + let depth = build_list(&mut ind.indexes, fresh); max_depth = std::cmp::max(max_depth, depth); }, AccessType::Qualified(_) =>{ diff --git a/compiler/src/ir_processing/reduce_stack.rs b/compiler/src/ir_processing/reduce_stack.rs index a8bcf3045..0723f681e 100644 --- a/compiler/src/ir_processing/reduce_stack.rs +++ b/compiler/src/ir_processing/reduce_stack.rs @@ -166,14 +166,15 @@ pub fn reduce_location_rule(lc: LocationRule) -> LocationRule { for acc in work_accesses{ match acc{ AccessType::Indexed(indexes) =>{ - let no_indexes = InstructionList::len(&indexes); - let work = indexes; + let no_indexes = InstructionList::len(&indexes.indexes); + let work = indexes.indexes; + let symbol_dim = indexes.symbol_dim; let mut indexes = InstructionList::with_capacity(no_indexes); for index in work { let index = Allocate::allocate(reduce_instruction(*index)); InstructionList::push(&mut indexes, index); } - accesses.push(AccessType::Indexed(indexes)); + accesses.push(AccessType::Indexed(IndexedInfo{indexes, symbol_dim})); } AccessType::Qualified(_) =>{ accesses.push(acc); diff --git a/compiler/src/ir_processing/set_arena_size.rs b/compiler/src/ir_processing/set_arena_size.rs index 6c4a2ad99..b80b37a7a 100644 --- a/compiler/src/ir_processing/set_arena_size.rs +++ b/compiler/src/ir_processing/set_arena_size.rs @@ -105,7 +105,7 @@ pub fn visit_location(bucket: &mut LocationRule, function_to_arena_size: &HashMa for access in indexes{ match access{ AccessType::Indexed(instr) =>{ - visit_list(instr, function_to_arena_size) + visit_list(&mut instr.indexes, function_to_arena_size) }, AccessType::Qualified(_) =>{ From f80898ce5b006c44ea70ea59a602a8aff55d9e81 Mon Sep 17 00:00:00 2001 From: alrubio Date: Thu, 18 Jul 2024 19:32:25 +0200 Subject: [PATCH 133/189] bug fixed in code generation with heterogeneous components --- .../src/c_elements/c_code_generator.rs | 8 +-- .../src/wasm_elements/wasm_code_generator.rs | 10 ++-- .../call_bucket.rs | 53 ++++++++++++++----- .../load_bucket.rs | 45 +++++++++++++--- .../store_bucket.rs | 52 +++++++++++++----- 5 files changed, 125 insertions(+), 43 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 600934027..9d74c9bbb 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -18,8 +18,8 @@ const CIRCOM_HASH_ENTRY_FIELDS: [&str; 3] = ["hash", "signalid", "signalsize"]; const S_CIRCOM_COMPONENT: &str = "Circom_Component"; const CIRCOM_COMPONENT_FIELDS: [&str; 4] = ["templateID", "signalStart", "inputCounter", "subcomponents"]; -const S_IOField_DEF: &str = "IOFieldDef"; -const IOField_DEF_FIELDS: [&str; 4] = ["offset", "size", "lengths", "busid"]; +const S_IOFIELD_DEF: &str = "IOFieldDef"; +const IOFIELD_DEF_FIELDS: [&str; 4] = ["offset", "size", "lengths", "busid"]; // Global variables @@ -144,9 +144,9 @@ pub fn template_ins_2_io_info() -> CInstruction { format!("{}", TEMP_INS_2_IO_INFO) } -pub const BUS_INS_2_Field_INFO: &str = "busInsId2FieldInfo"; +pub const BUS_INS_2_FIELD_INFO: &str = "busInsId2FieldInfo"; pub fn bus_ins_2_field_info() -> CInstruction { - format!("{}", BUS_INS_2_Field_INFO) + format!("{}", BUS_INS_2_FIELD_INFO) } pub fn template_id_in_component(idx: CInstruction) -> CInstruction { diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index e254a30dd..5206c41ac 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -319,20 +319,20 @@ pub fn generate_data_io_signals_info( println!("Template Instance: {}", c); for s in value { // add the actual offset in memory, taking into account the size of field nums - println!("Offset: {}", s.offset); + //println!("Offset: {}", s.offset); io_signals_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); - println!("Length: {}", s.lengths.len()); + //println!("Length: {}", s.lengths.len()); if s.lengths.len() > 0 { // if it is an array // add the dimensions except the first one for i in 1..s.lengths.len() { - println!("Index: {}, {}", i, s.lengths[i]); + //println!("Index: {}, {}", i, s.lengths[i]); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(s.lengths[i]))); } // add the actual size of the elements - println!("Size: {}", s.size); + //println!("Size: {}", s.size); io_signals_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.size), @@ -341,7 +341,7 @@ pub fn generate_data_io_signals_info( } // add the busid if it is a bus if let Some(value) = s.bus_id { - println!("Bus_id: {}", value); + //println!("Bus_id: {}", value); io_signals_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); } } diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index ede020829..6fa43d630 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -238,13 +238,10 @@ impl WriteWasm for CallBucket { } let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_info) = &indexes[idxpos] { - - // TODO: using the dim info - let index_list = &index_info.indexes; - let dim = index_info.symbol_dim; - - let mut infopos = 0; + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + let mut infopos = 0; assert!(index_list.len() > 0); //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] @@ -260,12 +257,34 @@ impl WriteWasm for CallBucket { instructions.append(&mut instructions_idxi); instructions.push(add32()); } + assert!(index_list.len() <= dim); + let diff = dim - index_list.len(); + if diff > 0 { + //println!("There is difference: {}",diff); + //instructions.push(format!(";; There is a difference {}", diff)); + // must be last access + assert!(idxpos+1 == indexes.len()); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of the next dimension + instructions.push(load32(Some(&infopos.to_string()))); // length of next dimension + for _i in 1..diff { + //instructions.push(format!(";; Next dim {}", i)); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of the next dimension + instructions.push(load32(Some(&infopos.to_string()))); // length of next dimension + instructions.push(mul32()); // multiply with previous dimensions + } + } // after this we have the product of the remaining dimensions let field_size = producer.get_size_32_bits_in_memory() * 4; instructions.push(set_constant(&field_size.to_string())); instructions.push(get_local(producer.get_io_info_tag())); infopos += 4; //position in io or bus info of size instructions.push(load32(Some(&infopos.to_string()))); // size instructions.push(mul32()); // size mult by size of field in bytes + if diff > 0 { + //instructions.push(format!(";; Multiply dimensions")); + instructions.push(mul32()); // total size of the content according to the missing dimensions + } instructions.push(mul32()); // total offset in the array instructions.push(add32()); // to the current offset idxpos += 1; @@ -491,12 +510,9 @@ impl WriteC for CallBucket { let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_info) = &indexes[idxpos] { - - // TODO: using the dim info - let index_list = &index_info.indexes; - let dim = index_info.symbol_dim; - - map_prologue.push(format!("{{")); + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + map_prologue.push(format!("{{")); map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); //We first compute the number of elements as //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with @@ -513,6 +529,17 @@ impl WriteC for CallBucket { map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", map_index,(i-1).to_string(),i.to_string()); } + assert!(index_list.len() <= dim); + if dim - index_list.len() > 0 { + map_prologue.push(format!("//There is a difference {};",dim - index_list.len())); + // must be last access + assert!(idxpos+1 == indexes.len()); + for i in index_list.len()..dim { + map_index = format!("{}*cur_def->lengths[{}]", + map_index, (i-1).to_string()); + } // after this we have multiplied by the remaining dimensions + } + // multiply the offset in the array (after multiplying by the missing dimensions) by the size of the elements map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); } else if let AccessType::Qualified(_) = &indexes[idxpos] { diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 46d7758fe..e2b23a1df 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -158,12 +158,34 @@ impl WriteWasm for LoadBucket { instructions.append(&mut instructions_idxi); instructions.push(add32()); } + assert!(index_list.len() <= dim); + let diff = dim - index_list.len(); + if diff > 0 { + //println!("There is difference: {}",diff); + //instructions.push(format!(";; There is a difference {}", diff)); + // must be last access + assert!(idxpos+1 == indexes.len()); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of the next dimension + instructions.push(load32(Some(&infopos.to_string()))); // length of next dimension + for _i in 1..diff { + //instructions.push(format!(";; Next dim {}", i)); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of the next dimension + instructions.push(load32(Some(&infopos.to_string()))); // length of next dimension + instructions.push(mul32()); // multiply with previous dimensions + } + } // after this we have the product of the remaining dimensions let field_size = producer.get_size_32_bits_in_memory() * 4; instructions.push(set_constant(&field_size.to_string())); instructions.push(get_local(producer.get_io_info_tag())); infopos += 4; //position in io or bus info of size instructions.push(load32(Some(&infopos.to_string()))); // size instructions.push(mul32()); // size mult by size of field in bytes + if diff > 0 { + //instructions.push(format!(";; Multiply dimensions")); + instructions.push(mul32()); // total size of the content according to the missing dimensions + } instructions.push(mul32()); // total offset in the array instructions.push(add32()); // to the current offset idxpos += 1; @@ -261,12 +283,9 @@ impl WriteC for LoadBucket { let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_info) = &indexes[idxpos] { - - // TODO: using the dim info - let index_list = &index_info.indexes; - let dim = index_info.symbol_dim; - - //We first compute the number of elements as + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] let (mut index_code_0, mut map_index) = index_list[0].produce_c(producer, parallel); map_prologue.append(&mut index_code_0); @@ -276,8 +295,18 @@ impl WriteC for LoadBucket { map_index = format!("({})*({}.lengths[{}])+{}", map_index,cur_def,(i-1).to_string(),index_exp); } - // add to the access expression the computed offset in the array - // multiplied buy the size of the elements + assert!(index_list.len() <= dim); + if dim - index_list.len() > 0 { + map_prologue.push(format!("//There is a difference {};",dim - index_list.len())); + // must be last access + assert!(idxpos+1 == indexes.len()); + for i in index_list.len()..dim { + map_index = format!("{}*{}.lengths[{}]", + map_index, cur_def, (i-1).to_string()); + } // after this we have multiplied by the remaining dimensions + } + // multiply the offset in the array (after multiplying by the missing dimensions) by the size of the elements + // and add it to the access expression map_access = format!("{}+({})*{}.size", map_access, map_index, cur_def); } else if let AccessType::Qualified(_) = &indexes[idxpos] { // we already have the cur_def diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 5656a61c1..41588b066 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -145,12 +145,9 @@ impl WriteWasm for StoreBucket { let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_info) = &indexes[idxpos] { - - // TODO: using the dim info - let index_list = &index_info.indexes; - let dim = index_info.symbol_dim; - - let mut infopos = 0; + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + let mut infopos = 0; assert!(index_list.len() > 0); //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] @@ -166,12 +163,34 @@ impl WriteWasm for StoreBucket { instructions.append(&mut instructions_idxi); instructions.push(add32()); } + assert!(index_list.len() <= dim); + let diff = dim - index_list.len(); + if diff > 0 { + //println!("There is difference: {}",diff); + //instructions.push(format!(";; There is a difference {}", diff)); + // must be last access + assert!(idxpos+1 == indexes.len()); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of the next dimension + instructions.push(load32(Some(&infopos.to_string()))); // length of next dimension + for _i in 1..diff { + //instructions.push(format!(";; Next dim {}", i)); + instructions.push(get_local(producer.get_io_info_tag())); + infopos += 4; //position in io or bus info of the next dimension + instructions.push(load32(Some(&infopos.to_string()))); // length of next dimension + instructions.push(mul32()); // multiply with previous dimensions + } + } // after this we have the product of the remaining dimensions let field_size = producer.get_size_32_bits_in_memory() * 4; instructions.push(set_constant(&field_size.to_string())); instructions.push(get_local(producer.get_io_info_tag())); infopos += 4; //position in io or bus info of size instructions.push(load32(Some(&infopos.to_string()))); // size instructions.push(mul32()); // size mult by size of field in bytes + if diff > 0 { + //instructions.push(format!(";; Multiply dimensions")); + instructions.push(mul32()); // total size of the content according to the missing dimensions + } instructions.push(mul32()); // total offset in the array instructions.push(add32()); // to the current offset idxpos += 1; @@ -381,12 +400,9 @@ impl WriteC for StoreBucket { let mut idxpos = 0; while idxpos < indexes.len() { if let AccessType::Indexed(index_info) = &indexes[idxpos] { - - // TODO: using the dim info - let index_list = &index_info.indexes; - let dim = index_info.symbol_dim; - - map_prologue.push(format!("{{")); + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + map_prologue.push(format!("{{")); map_prologue.push(format!("uint map_index_aux[{}];",index_list.len().to_string())); //We first compute the number of elements as //((map_index_aux[0] * length_of_dim[1]) + map_index_aux[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + map_index_aux[n-1] with @@ -402,7 +418,17 @@ impl WriteC for StoreBucket { map_index = format!("({})*cur_def->lengths[{}]+map_index_aux[{}]", map_index,(i-1).to_string(),i.to_string()); } - // multiply the offset inthe array by the size of the elements + assert!(index_list.len() <= dim); + if dim - index_list.len() > 0 { + map_prologue.push(format!("//There is a difference {};",dim - index_list.len())); + // must be last access + assert!(idxpos+1 == indexes.len()); + for i in index_list.len()..dim { + map_index = format!("{}*cur_def->lengths[{}]", + map_index, (i-1).to_string()); + } // after this we have multiplied by the remaining dimensions + } + // multiply the offset in the array (after multiplying by the missing dimensions) by the size of the elements map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); } else if let AccessType::Qualified(_) = &indexes[idxpos] { From 8d1e888c003338496eb1f29c68df0287c01bda9b Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 19 Jul 2024 13:17:45 +0200 Subject: [PATCH 134/189] solving issue dims --- compiler/src/intermediate_representation/translate.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 8430b9fa3..bbe9e73ec 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -970,9 +970,14 @@ fn build_signal_location( for index in indexes{ let filtered = indexing_instructions_filter(index, state); if filtered.len() > 0{ + let symbol_dim = if i == 0{ + dimensions.len() // dimensions is the length of the first symbol + } else{ + bus_accesses[i-1].lengths.len() // if not return length of the bus + }; let index_info = IndexedInfo{ indexes: filtered, - symbol_dim: dimensions.len() + symbol_dim }; accesses.push(AccessType::Indexed(index_info)); } From 7ccb2a63351357c84ae4343d0883fa10c9b3f66b Mon Sep 17 00:00:00 2001 From: alrubio Date: Sat, 20 Jul 2024 08:37:17 +0200 Subject: [PATCH 135/189] bug fixed in code generation with heterogeneous components --- .../call_bucket.rs | 14 ++++---------- .../load_bucket.rs | 14 ++++---------- .../location_rule.rs | 3 ++- .../store_bucket.rs | 19 ++++++++----------- 4 files changed, 18 insertions(+), 32 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 6fa43d630..657792845 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -542,8 +542,10 @@ impl WriteC for CallBucket { // multiply the offset in the array (after multiplying by the missing dimensions) by the size of the elements map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); - } else if let AccessType::Qualified(_) = &indexes[idxpos] { - // we already have the cur_def + } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { + map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", + circom_calc_wit(), bus_ins_2_field_info(), + field_no.to_string())); map_prologue.push(format!("map_accesses_aux[{}] = cur_def->offset;", idxpos.to_string())); } else { assert!(false); @@ -552,14 +554,6 @@ impl WriteC for CallBucket { map_access = format!("{}+map_accesses_aux[{}]", map_access, idxpos.to_string()); idxpos += 1; - if idxpos < indexes.len() { - if let AccessType::Qualified(field_no) = &indexes[idxpos] { - // we get the next definition in cur_def from the bus bus_id - map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", - circom_calc_wit(), bus_ins_2_field_info(), - field_no.to_string())); - } - } } map_prologue.push(format!("}}")); } diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index e2b23a1df..e4494dd43 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -308,21 +308,15 @@ impl WriteC for LoadBucket { // multiply the offset in the array (after multiplying by the missing dimensions) by the size of the elements // and add it to the access expression map_access = format!("{}+({})*{}.size", map_access, map_index, cur_def); - } else if let AccessType::Qualified(_) = &indexes[idxpos] { - // we already have the cur_def + } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { + cur_def = format!("{}->{}[{}.busId].defs[{}]", + circom_calc_wit(), bus_ins_2_field_info(), + cur_def, field_no.to_string()); map_access = format!("{}+{}.offset", map_access, cur_def); } else { assert!(false); } idxpos += 1; - if idxpos < indexes.len() { - if let AccessType::Qualified(field_no) = &indexes[idxpos] { - // we get the next definition in cur_def from the bus bus_id - cur_def = format!("{}->{}[{}.busId].defs[{}]", - circom_calc_wit(), bus_ins_2_field_info(), - cur_def, field_no.to_string()); - } - } } } (map_prologue, map_access) diff --git a/compiler/src/intermediate_representation/location_rule.rs b/compiler/src/intermediate_representation/location_rule.rs index 3501d5cd8..47fdefc80 100644 --- a/compiler/src/intermediate_representation/location_rule.rs +++ b/compiler/src/intermediate_representation/location_rule.rs @@ -16,7 +16,8 @@ impl ToString for AccessType { fn to_string(&self) -> String { match &self{ AccessType::Indexed(index) =>{ - index.indexes.iter().map(|i| i.to_string()).collect() + + format!("Indexed({},{})", index.symbol_dim, index.indexes.iter().map(|i| i.to_string()).collect::()) } AccessType::Qualified(value) =>{ format!("field({})", value) diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 41588b066..fd26a343f 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -370,6 +370,8 @@ impl WriteC for StoreBucket { let mut prologue = vec![]; let cmp_index_ref = "cmp_index_ref".to_string(); let aux_dest_index = "aux_dest_index".to_string(); + //prologue.push(format!("// store bucket. Line {}", self.line)); //.to_string() + if let AddressType::SubcmpSignal { cmp_address, .. } = &self.dest_address_type { let (mut cmp_prologue, cmp_index) = cmp_address.produce_c(producer, parallel); prologue.append(&mut cmp_prologue); @@ -380,7 +382,8 @@ impl WriteC for StoreBucket { if let LocationRule::Indexed { location, template_header } = &self.dest { (location.produce_c(producer, parallel), template_header.clone()) } else if let LocationRule::Mapped { signal_code, indexes} = &self.dest { - //if Mapped must be SubcmpSignal + //if Mapped must be SubcmpSignal + //println!("Line {} is Mapped: {}",self.line, self.dest.to_string()); let mut map_prologue = vec![]; let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref.clone()); let mut map_access = format!("{}->{}[{}].defs[{}].offset", @@ -431,8 +434,10 @@ impl WriteC for StoreBucket { // multiply the offset in the array (after multiplying by the missing dimensions) by the size of the elements map_prologue.push(format!("map_accesses_aux[{}] = {}*cur_def->size;", idxpos.to_string(), map_index)); map_prologue.push(format!("}}")); - } else if let AccessType::Qualified(_) = &indexes[idxpos] { - // we already have the cur_def + } else if let AccessType::Qualified(field_no) = &indexes[idxpos] { + map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", + circom_calc_wit(), bus_ins_2_field_info(), + field_no.to_string())); map_prologue.push(format!("map_accesses_aux[{}] = cur_def->offset;", idxpos.to_string())); } else { assert!(false); @@ -441,14 +446,6 @@ impl WriteC for StoreBucket { map_access = format!("{}+map_accesses_aux[{}]", map_access, idxpos.to_string()); idxpos += 1; - if idxpos < indexes.len() { - if let AccessType::Qualified(field_no) = &indexes[idxpos] { - // we get the next definition in cur_def from the bus bus_id - map_prologue.push(format!("cur_def = &({}->{}[cur_def->busId].defs[{}]);", - circom_calc_wit(), bus_ins_2_field_info(), - field_no.to_string())); - } - } } map_prologue.push(format!("}}")); } From afdf66bbcdc0a18ff8787a753e9d8bc84c1b3cfb Mon Sep 17 00:00:00 2001 From: clararod9 Date: Sat, 20 Jul 2024 10:33:08 +0200 Subject: [PATCH 136/189] minors execute --- compiler/src/hir/very_concrete_program.rs | 1 - .../load_bucket.rs | 1 - .../component_representation.rs | 21 ++++++++++++------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 1a1c568b2..2b5b4acd2 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -24,7 +24,6 @@ impl PartialEq for Argument { } } -// TODO: precompute the size and store #[derive(Clone)] pub enum Wire{ TSignal(Signal), diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index e2b23a1df..c15977bb2 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -138,7 +138,6 @@ impl WriteWasm for LoadBucket { while idxpos < indexes.len() { if let AccessType::Indexed(index_info) = &indexes[idxpos] { - // TODO: using the dim info let index_list = &index_info.indexes; let dim = index_info.symbol_dim; diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index a06394b34..1a5bf0e22 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -15,7 +15,7 @@ pub struct ComponentRepresentation { unassigned_tags: HashSet, to_assign_inputs: Vec<(String, Vec, Vec)>, to_assign_input_buses: Vec<(String, Vec, BusSlice)>, - to_assign_input_bus_fields: Vec<(String, AccessingInformationBus, FoldedResult)>, + to_assign_input_bus_fields: Vec<(String, AccessingInformationBus, FoldedResult, TagInfo)>, inputs: HashMap, input_buses: HashMap, pub inputs_tags: BTreeMap, @@ -219,9 +219,8 @@ impl ComponentRepresentation { } let to_assign = std::mem::replace(&mut component.to_assign_input_bus_fields, vec![]); - for (signal_name, access, field_value) in &to_assign{ - let tags_input = component.inputs_tags[signal_name].clone(); - component.assign_value_to_bus_field_init(signal_name, access, field_value, tags_input)?; + for (signal_name, access, field_value, tags_input) in to_assign{ + component.assign_value_to_bus_field_init(&signal_name, &access, &field_value, tags_input)?; } Result::Ok(()) @@ -531,10 +530,18 @@ impl ComponentRepresentation { // check that the tags are correct and update values, in this case none inputs // are assigned to the complete bus - ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, &TagInfo::new())?; + ComponentRepresentation::handle_tag_assignment_no_init( + component, + bus_name, + &TagInfo::new())?; - // TODO: add the info of the fields, not of the bus - component.to_assign_input_bus_fields.push((bus_name.to_string(), access.clone(), field_value)); + component.to_assign_input_bus_fields.push(( + bus_name.to_string(), + access.clone(), + field_value, + tags.clone() + ) + ); Result::Ok(()) } From 26ecf7e51cf9c2b397eca150b34f09558e57cc92 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 22 Jul 2024 13:53:04 +0200 Subject: [PATCH 137/189] Adding buses documentation --- mkdocs/docs/circom-language/buses.md | 209 ++++++++++++++++++ .../circom-insight/unknowns.md | 33 +++ .../docs/circom-language/reserved-keywords.md | 3 +- mkdocs/docs/circom-language/scoping.md | 2 +- mkdocs/docs/circom-language/tags.md | 16 ++ 5 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 mkdocs/docs/circom-language/buses.md diff --git a/mkdocs/docs/circom-language/buses.md b/mkdocs/docs/circom-language/buses.md new file mode 100644 index 000000000..403ab64b4 --- /dev/null +++ b/mkdocs/docs/circom-language/buses.md @@ -0,0 +1,209 @@ +# Buses +circom 2.2.0 introduces a new feature called __signal buses__. + + + +## Definition +A bus is a collection of different but related signals grouped under one name. They are similar to structs in programming languages like C++, helping to make the code more organized and easier to manage. + +Buses can be defined at the same level as templates and can be used as inputs, intermediates or ouputs within a template. + +``` +bus NameBus(param1,...,paramN){ + //signals, + //arrays, + //other buses... +} + +``` + +In many circuits we have pairs of signals `x` and `y`, which represent the two components of a point. With the new bus feature, we can define a `Point` bus as follows: + +``` +bus Point{ + signal x; + signal y; +} +``` + +This way, it is clear that `x` and `y` should be understood as a single point rather than two independent signals. + +Using buses, we can modify many templates from the circomlib to make them more readable and organized. Let us consider the `Edwards2Montgomery` template from `montgomery.circom`: + +``` +template Edwards2Montgomery () { + Point input { edwards_point } in ; + Point output { montgomery_point } out ; + + out.x <–- (1 + in.y ) / (1 - in.y ) ; + out.y <–- out.x / in.x ; + + out.x * (1 - in.y ) === (1 + in.y ) ; + out.y * in.x === out.x ; + } +``` + +Here, we have a template with an input `Point` `in` expected to be in Edwards format, and an output `Point` `out` in Montgomery format. + +The power of buses lies in expressing properties about a collection of related signals. For example, the two signals inside the bus `in` (respectively `out`) must satisfy the equations for the Edwards curve (respectively the Montgomery curve). Before circom 2.2.0, this could not be expressed using tags in circom. +But now, we can tag each bus with the corresponding expected format. + +Besides tagging buses defined in a template, we can also tag their different fields. Let us see this feature in the following example: + +``` +bus Book { + signal {maxvalue} title[50]; + signal {maxvalue} author[50]; + signal pages; + signal {maxvalue} year; +}; +``` + +The `Book` bus has four different fields: +signal arrays `title` and `author` whose letters have a maximum value, the number of `pages`, and the publication `year`, which also has a maximum value. Using buses makes your code clearer and more readable. It is easier to understand that a `Book` bus represents a book with its fields, rather than dealing with individual signals. + +``` +template OldBook(){ + Book input book; + Book output {old} old_book; + signal check <== LessThan(book.year.maxvalue)([book.year,1950]); + check === 1; + old_book <== book; +} +``` + +As mentioned above, tags work at both levels: at the level of the whole bus, expressing that the book was written before 1950, and at the level of the bus signals, expressing the different correctness properties about them. + +## Approaching a Type System via Buses and Tags +The introduction of buses in circom 2.2.0 brings us closer to having a robust type system. By enforcing compatibility rules in the bus assignments and enabling tagging at both the bus and signal level, buses provide a structured way to manage and verify the relationships between different signals. The combined use of buses and tags emulates the advantages of a traditional type system within circom, enhancing code clarity, reducing errors, and improving overall organization. + +When assigning one bus to another, they both need to be the same type of bus. Otherwise, the compiler reports an error. + +``` +bus B1(){ + signal x; +} + +bus B2{ + signal x; +} + +template B1toB2(){ + B1 input b1; + B2 output b2; + b2 <== b1; +} + +``` +For the previous example, the compiler reports: +``` +error[T2059]: Typing error found + ┌─ "example.circom":80:5 + │ + │ b2 <== b1; + │ ^^^^^^^^^ Assignee and assigned types do not match. +``` + +In this case, the transformation from one type to another should be explicitly done as follows: `b2.x <== b1.x;`. + +Consider again the `OldBook` template and a possible instantiation: `Book old <== OldBook()(b);` Similar to tags, whenever a template is instantiated, the compiler checks if the type of `b` is equals to `Book`. If it is not, an error is reported. The compiler also checks if the bus' fields have the same tags. + +## Buses inside Buses +We can have buses inside the definition other buses, as long as we do not define buses recursively. To illustrate this, let us consider now, a new kind of bus, `Person`, which contains some information about a person: + +``` +bus Date{ + signal day; + signal month; + signal year; +} + +bus Person{ + signal name[50]; + Book books[10]; + Date birthday; +} +``` + +## Parameterized Buses +Buses can have parameters as well. These parameters must be known during compilation time and can be used to define arrays or other buses inside themselves. + +Let us generalize the `Point` bus for a given dimension. + +``` +bus Point(dim){ + signal x[dim]; +} +``` + +Thanks to this definition, we can define other like lines and figures. + +``` +bus Line(dim){ + PointN(dim) start; + PointN(dim) end; +} + +bus Figure(num_sides, dim){ + Line(dim) side[num_sides]; +} +``` +Notice that the `Figure` bus is defined by two parameters: the number of sides and the dimension of its points. Using this bus, we can define every kind of figure in a very simple way. For instance: + +``` +bus Triangle2D(){ + Figure(3,2) triangle; +} + +bus Square3D(){ + Figure(4,3) square; +} +``` + +We define a `Triangle2D` bus with three lines whose points are 2-dimensional, and a `Square3D` bus, whose points are 3-dimensional. + +``` +template well_defined_figure(num_sides, dimension){ + Figure(num_sides,dimension) input t; + Figure(num_sides,dimension) {correct_t} output t; + var all_equals = 0; + var isequal = 0; + for(var i = 0; i < num_sides; i=i+1){ + for(var j = 0; j < dimension; j=j+1){ + isequal = IsEqual()([t.side[i].end.x[j],t.side[(i+1)%num_sides].start.x[j]]); + all_equals += isequal; + } + } + all_equals === num_sides; + correct_t <== t; +} +``` + +The previous template defines a correctness check for any figure: the ending point of a line must be the starting point of the next line. Otherwise, the figure is not well defined, and the witness generation will fail. + +## Buses as Circuit Inputs +Similar to signals, buses can be part of the inputs of the main circuit. Thus, we must indicate their values if we want to generate a witness for the circuit. As usual, we indicate the value of the input buses following a JSON format. Let us consider again the `Person` bus and an input `p` of this kind, we would indicate its values as follows: + +``` +["p": {"name": ["80","82",...], + "books": [ + { "title": [...], + "author": [...], + "pages": "30", + "year": "1953" + }, + ..., + { "title": [...], + "author": [...], + "pages": "121", + "year": "1990" + } + ], + "birthday": + { "day": "1", + "month": "1", + "year": "1992" + } + } +] +``` diff --git a/mkdocs/docs/circom-language/circom-insight/unknowns.md b/mkdocs/docs/circom-language/circom-insight/unknowns.md index 38c1ba881..b982ab002 100644 --- a/mkdocs/docs/circom-language/circom-insight/unknowns.md +++ b/mkdocs/docs/circom-language/circom-insight/unknowns.md @@ -62,6 +62,39 @@ component main = A(); In the code above, an array is defined with an unknown size of value `in` (as signals are always considered unknown). +## Bus +A bus definition must be parametrized only by known values. + +```text +pragma circom 2.0.0; + +bus b(n){ + signal array[n]; +} + +template A(){ + signal input in; + b(in) out; + for(i = 0; i < in; i++){ + out.array[i] <== i; + } +} + +component main = A(); +``` + +In the code above, the array inside the bus `out` is initialized depending on the size of signal `in`, whose value is unknown at compilation time. Thus, the compiler arises an error: +```` +error[T20467]: Typing error found + ┌─ "pruebas.circom":9:4 + │ +9 │ b(in) out; + │ ^^^^^^^^^ Parameters of a bus must be known during the constraint generation phase + +previous errors were found``` + + + ## Control Flow If `if-else` or `for-loop`blocks have unknown conditions, then the block is considered unknown and no constraint can be generated inside it. Consequently, constraint can only be generated in a control flow with known conditions. diff --git a/mkdocs/docs/circom-language/reserved-keywords.md b/mkdocs/docs/circom-language/reserved-keywords.md index a0cd7e4fd..07b6e5741 100644 --- a/mkdocs/docs/circom-language/reserved-keywords.md +++ b/mkdocs/docs/circom-language/reserved-keywords.md @@ -1,7 +1,7 @@ # Reserved Keywords The list of reserved keywords is the following: - + * **signal:** Declare a new signal. * **input:** Declare the signal as input. * **output:** Declare the signal as output. @@ -22,5 +22,6 @@ The list of reserved keywords is the following: * **parallel:** To generate C code with the parallel component or template. * **pragma circom**: Instruction to check the compiler version. * **pragma custom_templates**: Instruction to indicate the usage of custom templates. +* **bus**: Definition of a bus of signals. diff --git a/mkdocs/docs/circom-language/scoping.md b/mkdocs/docs/circom-language/scoping.md index f6d64bf85..233e46b77 100644 --- a/mkdocs/docs/circom-language/scoping.md +++ b/mkdocs/docs/circom-language/scoping.md @@ -1,6 +1,6 @@ # Scoping -Circom has static scoping like C and Rust. However, we have that signals and components must have global scoping and hence they should be defined at the top-level block of the template that defines them or, since circom 2.1.5, inside (nested) `if` blocks, but only if conditions are known at compilation time. +Circom has static scoping like C and Rust. However, we have that signals, buses and components must have global scoping and hence they should be defined at the top-level block of the template that defines them or, since circom 2.1.5, inside (nested) `if` blocks, but only if conditions are known at compilation time. ```text pragma circom 2.1.5; diff --git a/mkdocs/docs/circom-language/tags.md b/mkdocs/docs/circom-language/tags.md index 3e172e0a7..1f464997f 100644 --- a/mkdocs/docs/circom-language/tags.md +++ b/mkdocs/docs/circom-language/tags.md @@ -112,3 +112,19 @@ template A(){ } ``` The compilation of the previous code throws the next error "Invalid assignment: tags cannot be assigned to a signal already initialized", since a position of the array (out[0]) already has a value, then the value of max cannot be modified after the first assignment. + +## Tags in buses +Similar to signals, buses and their fields can also be tagged in their declarations. + +``` +bus Book { + signal {maxvalue} title[50]; + signal pages; + signal {maxvalue} year; +}; + +bus Person{ + signal name[50]; + Book {old} name; +} +``` \ No newline at end of file From fbac9f6e85f99cdafc0577b372a2df68f109b3fc Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 22 Jul 2024 16:42:18 +0200 Subject: [PATCH 138/189] Documentation on buses --- mkdocs/docs/circom-language/buses.md | 42 +++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/mkdocs/docs/circom-language/buses.md b/mkdocs/docs/circom-language/buses.md index 403ab64b4..2d8b410da 100644 --- a/mkdocs/docs/circom-language/buses.md +++ b/mkdocs/docs/circom-language/buses.md @@ -54,25 +54,27 @@ Besides tagging buses defined in a template, we can also tag their different fie bus Book { signal {maxvalue} title[50]; signal {maxvalue} author[50]; - signal pages; + signal {maxvalue} sold_copies; signal {maxvalue} year; }; ``` The `Book` bus has four different fields: -signal arrays `title` and `author` whose letters have a maximum value, the number of `pages`, and the publication `year`, which also has a maximum value. Using buses makes your code clearer and more readable. It is easier to understand that a `Book` bus represents a book with its fields, rather than dealing with individual signals. +signal arrays `title` and `author` whose letters have a maximum value, the number of sold copies `sold_copies`, and the publication `year`, which also has a maximum value. Using buses makes your code clearer and more readable. It is easier to understand that a `Book` bus represents a book with its fields, rather than dealing with individual signals. ``` -template OldBook(){ +template BestSeller2024(){ Book input book; - Book output {old} old_book; - signal check <== LessThan(book.year.maxvalue)([book.year,1950]); - check === 1; - old_book <== book; + Book output {best_seller2024} best_book; + signal check_copies <== LessThan(book.sold_copies.maxvalue)([1000000,book.sold_copies]); + check_copies === 1; + signal check_2024 <== IsEqual()([book.year,2024]); + check_2024 === 1; + best_book <== book; } ``` -As mentioned above, tags work at both levels: at the level of the whole bus, expressing that the book was written before 1950, and at the level of the bus signals, expressing the different correctness properties about them. +As mentioned above, tags work at both levels: at the level of the whole bus, expressing that the book is a best-seller in 2024 (it sold more than 1 million copies), and at the level of the bus signals, expressing the different correctness properties about the book's fields. ## Approaching a Type System via Buses and Tags The introduction of buses in circom 2.2.0 brings us closer to having a robust type system. By enforcing compatibility rules in the bus assignments and enabling tagging at both the bus and signal level, buses provide a structured way to manage and verify the relationships between different signals. The combined use of buses and tags emulates the advantages of a traditional type system within circom, enhancing code clarity, reducing errors, and improving overall organization. @@ -106,12 +108,18 @@ error[T2059]: Typing error found In this case, the transformation from one type to another should be explicitly done as follows: `b2.x <== b1.x;`. -Consider again the `OldBook` template and a possible instantiation: `Book old <== OldBook()(b);` Similar to tags, whenever a template is instantiated, the compiler checks if the type of `b` is equals to `Book`. If it is not, an error is reported. The compiler also checks if the bus' fields have the same tags. +Consider again the `BestSeller2024` template and a possible instantiation: `Book seller <== BestSeller2024()(b);` Similar to tags, whenever a template is instantiated, the compiler checks if the type of `b` is equals to `Book`. If it is not, an error is reported. The compiler also checks if the bus' fields have the same tags. ## Buses inside Buses We can have buses inside the definition other buses, as long as we do not define buses recursively. To illustrate this, let us consider now, a new kind of bus, `Person`, which contains some information about a person: ``` +bus Film{ + signal title[50]; + signal director[50]; + signal year; +} + bus Date{ signal day; signal month; @@ -120,7 +128,7 @@ bus Date{ bus Person{ signal name[50]; - Book books[10]; + Film films[10]; Date birthday; } ``` @@ -152,11 +160,11 @@ Notice that the `Figure` bus is defined by two parameters: the number of sides a ``` bus Triangle2D(){ - Figure(3,2) triangle; + Figure(3,2) {well_defined} triangle; } bus Square3D(){ - Figure(4,3) square; + Figure(4,3) {well_defined} square; } ``` @@ -186,16 +194,14 @@ Similar to signals, buses can be part of the inputs of the main circuit. Thus, w ``` ["p": {"name": ["80","82",...], - "books": [ + "films": [ { "title": [...], - "author": [...], - "pages": "30", + "director": [...], "year": "1953" }, ..., { "title": [...], - "author": [...], - "pages": "121", + "director": [...], "year": "1990" } ], @@ -207,3 +213,5 @@ Similar to signals, buses can be part of the inputs of the main circuit. Thus, w } ] ``` + +Like public input signals, public input buses cannot be tagged. Otherwise, the compiler will report an error. \ No newline at end of file From e42ff3bbf7cb9738c1bf8861ba446ea3c71e8732 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 22 Jul 2024 21:22:36 +0200 Subject: [PATCH 139/189] minor improvements on execute --- .../intermediate_representation/translate.rs | 2 - .../environment_utils/bus_representation.rs | 31 ++- .../component_representation.rs | 10 +- constraint_generation/src/execute.rs | 229 ++++++++++++++---- program_structure/src/utils/memory_slice.rs | 2 + 5 files changed, 211 insertions(+), 63 deletions(-) diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index bbe9e73ec..94e5f894b 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -1467,7 +1467,6 @@ fn compute_full_address( // add the initial indexing dimensions.reverse(); let mut linear_length = size; - // TODO: not needed clone let index_stack = indexing_instructions_filter(indexed_with[0].clone(), state); for instruction in index_stack { let dimension_length = dimensions.pop().unwrap(); @@ -1509,7 +1508,6 @@ fn compute_full_address( access.lengths.reverse(); let mut linear_length = access.size; - // TODO: not needed clone let index_stack = indexing_instructions_filter(indexed_with[index].clone(), state); for instruction in index_stack { let dimension_length = access.lengths.pop().unwrap(); diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 3d840d772..502ecaa86 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -13,7 +13,7 @@ pub struct BusRepresentation { fields: BTreeMap, pub field_tags: BTreeMap, unassigned_fields: HashMap, - has_assignment: bool + has_assignment: bool, } impl Default for BusRepresentation { @@ -139,7 +139,7 @@ impl BusRepresentation { if state.value_defined || state.complete{ let value_tag = tags_info.get(next_access).unwrap(); match value_tag{ - None =>{ + Option::None =>{ let error = MemoryError::TagValueNotInitializedAccess; Result::Err(error) }, @@ -233,7 +233,24 @@ impl BusRepresentation { tags: Option, is_input: bool, ) -> Result<(), MemoryError> { - + // TODO: move to auxiliar function to do not repeat effort + // We update the has_assignment value if not tag and not empty + let has_assignment = match assigned_value{ + FoldedArgument::Signal(dimensions)=>{ + let total_size = dimensions.iter().fold(1, |acc, x| acc * x); + total_size > 0 + }, + FoldedArgument::Bus(slice)=>{ + let route = slice.route(); + let total_size = route.iter().fold(1, |acc, x| acc * x); + total_size > 0 + }, + FoldedArgument::Tag(_) => false + }; + if has_assignment{ + self.has_assignment = true; + } + // We later distinguish the case of tags // check if we need to access to another bus or if it is the final access let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); @@ -255,7 +272,6 @@ impl BusRepresentation { } } FieldTypes::Bus(s) =>{ - // TODO, include info about assignments, no recorrer todo for i in 0..BusSlice::get_number_of_cells(s){ let accessed_bus = BusSlice::get_reference_to_single_value_by_index(&s, i)?; if accessed_bus.has_assignment(){ @@ -288,7 +304,6 @@ impl BusRepresentation { } } else{ // it is intermediate access - self.has_assignment = true; match field{ FieldTypes::Bus(bus_slice)=>{ @@ -329,7 +344,7 @@ impl BusRepresentation { self.unassigned_fields.remove(field_name); } } - None => {} + Option::None => {} } } Result::Ok(()) @@ -438,7 +453,7 @@ impl BusRepresentation { self.unassigned_fields.remove(field_name); } } - None => {} + Option::None => {} } // Update the value of the signal tags it is complete @@ -477,7 +492,7 @@ impl BusRepresentation { pub fn completely_assign_bus(&mut self, assigned_bus: &BusRepresentation, is_input: bool)-> Result<(), MemoryError>{ if self.has_assignment{ - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignmentsBus)); } // check that they are the same instance of buses diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 1a5bf0e22..7da0dd663 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -78,7 +78,7 @@ impl ComponentRepresentation { meta: &Meta, ) -> Result<(), MemoryError>{ if !is_anonymous_component && component.is_preinitialized() { - return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignments)); + return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::MultipleAssignmentsComponent)); } let possible_node = ExecutedProgram::get_prenode(scheme, prenode_pointer); assert!(possible_node.is_some()); @@ -264,7 +264,7 @@ impl ComponentRepresentation { assert!(remaining_access.array_access.len() == 0); let value_tag = tag_info.get(remaining_access.field_access.as_ref().unwrap()).unwrap(); match value_tag{ - None =>{ + Option::None =>{ let error = MemoryError::TagValueNotInitializedAccess; Result::Err(error) }, @@ -305,7 +305,7 @@ impl ComponentRepresentation { assert!(next_array_access.len() == 0); let value_tag = tag_info.get(next_field_access).unwrap(); match value_tag{ - None =>{ + Option::None =>{ let error = MemoryError::TagValueNotInitializedAccess; Result::Err(error) }, @@ -597,7 +597,7 @@ impl ComponentRepresentation { access.remaining_access.as_ref().unwrap(), folded_arg, Some(tags), - true // it is an input so check tags instead of propagate + true, // it is an input so check tags instead of propagate )?; @@ -698,7 +698,7 @@ impl ComponentRepresentation { component.unassigned_inputs.remove(signal_name); } } - None => {} + Option::None => {} } } } diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 2ad654abf..db866543c 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -435,17 +435,32 @@ fn execute_statement( let mut signals_values_right: Vec = Vec::new(); let mut signals_values_left: Vec = Vec::new(); - // TODO: in case all bus slices contain the same types not needed of - // traversing all of them? - for i in 0..BusSlice::get_number_of_cells(&slice_left){ + // Check that the dimensions of the slices are equal + let correct_dims_result = BusSlice::check_correct_dims(&slice_left, &Vec::new(), &slice_right, true); + treat_result_with_memory_error_void( + correct_dims_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + // Check that the types of the buses are equal + // and get the accesses inside the bus + // We assume that the buses in the slice are all of the same type + // Generate the arithmetic slices containing the signals + // Use just the first to generate the bus accesses + + let mut inside_bus_signals = Vec::new(); + + if BusSlice::get_number_of_cells(&slice_left) > 0{ let left_i = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&slice_left, i), + BusSlice::get_reference_to_single_value_by_index(&slice_left, 0), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; let right_i = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&slice_right, i), + BusSlice::get_reference_to_single_value_by_index(&slice_right, 0), meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -459,8 +474,12 @@ fn execute_statement( &runtime.call_trace, )?; } + // generate the inside signals + inside_bus_signals = left_i.get_accesses_bus(""); - // TODO: do not call twice to get_accesses and better index + } + + for i in 0..BusSlice::get_number_of_cells(&slice_left){ let access_index = treat_result_with_memory_error( BusSlice::get_access_index(&slice_left, i), @@ -469,18 +488,31 @@ fn execute_statement( &runtime.call_trace, )?; let string_index = create_index_appendix(&access_index); - - signals_values_right.append(&mut left_i.get_accesses_bus(&format!("{}{}", name_left, string_index))); - signals_values_left.append(&mut left_i.get_accesses_bus(&format!("{}{}", name_right, string_index))); + + for s in &inside_bus_signals{ + signals_values_right.push( + format!( + "{}{}{}", name_right, string_index, s.clone() + )); + signals_values_left.push( + format!( + "{}{}{}", name_left, string_index, s.clone() + )); + } + } + + // Transform the signal names into Arithmetic Expressions let mut ae_signals_left = Vec::new(); for signal_name in signals_values_left{ ae_signals_left.push(AExpr::Signal { symbol: signal_name }); } + let mut ae_signals_right = Vec::new(); for signal_name in signals_values_right{ ae_signals_right.push(AExpr::Signal { symbol: signal_name }); } + (ae_signals_left, ae_signals_right) } else{ unreachable!() @@ -652,17 +684,29 @@ fn execute_statement( } } } else if FoldedValue::valid_bus_slice(&f_result){ - // TODO: improve, only generate values once let (bus_name, bus_slice) = safe_unwrap_to_bus_slice(f_result, line!()); let mut signal_values = Vec::new(); - for i in 0..BusSlice::get_number_of_cells(&bus_slice){ - let assigned_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&bus_slice, i), + + // Get the accesses inside the bus + // We assume that the buses in the slice are all of the same type + // Generate the arithmetic slices containing the signals + // Use just the first to generate the bus accesses + + let mut inside_bus_signals = Vec::new(); + + if BusSlice::get_number_of_cells(&bus_slice) > 0{ + let left_i = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&bus_slice, 0), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - + // generate the inside signals + inside_bus_signals = left_i.get_accesses_bus(""); + } + + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ + let access_index = treat_result_with_memory_error( BusSlice::get_access_index(&bus_slice, i), meta, @@ -671,7 +715,13 @@ fn execute_statement( )?; let string_index = create_index_appendix(&access_index); - signal_values.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", bus_name, string_index))); + for s in &inside_bus_signals{ + signal_values.push( + format!( + "{}{}{}", bus_name, string_index, s.clone() + )); + } + } if let Option::Some(node) = actual_node { @@ -1610,17 +1660,26 @@ fn perform_assign( let mut signals_values_right: Vec = Vec::new(); let mut signals_values_left: Vec = Vec::new(); - // TODO: in case all bus slices contain the same types not needed of - // traversing all of them? - for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ - let assigned_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, i), + + // Generate the arithmetic slices containing the signals + // We assume that the buses in the slice are all of the same type + // Use just the first to generate the bus accesses + + let mut inside_bus_signals = Vec::new(); + + if BusSlice::get_number_of_cells(&assigned_bus_slice) > 0{ + let left_i = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, 0), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - // TODO: do not call twice to get_accesses and better index - + // generate the inside signals + inside_bus_signals = left_i.get_accesses_bus(""); + } + + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ + let access_index = treat_result_with_memory_error( BusSlice::get_access_index(&assigned_bus_slice, i), meta, @@ -1629,9 +1688,19 @@ fn perform_assign( )?; let string_index = create_index_appendix(&access_index); - signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", name_bus, string_index))); - signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", full_symbol, string_index))); - } + for s in &inside_bus_signals{ + signals_values_right.push( + format!( + "{}{}{}", name_bus, string_index, s.clone() + )); + signals_values_left.push( + format!( + "{}{}{}", full_symbol, string_index, s.clone() + )); + } + } + + // Transform the signal names into AExpr let mut ae_signals_right = Vec::new(); for signal_name in signals_values_right{ @@ -1754,7 +1823,8 @@ fn perform_assign( } Option::Some(assigned_ae_slice) } - } else if ExecutionEnvironment::has_bus(&runtime.environment, symbol){ + } else if ExecutionEnvironment::has_bus(&runtime.environment, symbol) + { // we check if it is an input bus, in that case all signals are initialized to true let is_input_bus = ExecutionEnvironment::has_input_bus(&runtime.environment, symbol); @@ -1770,6 +1840,13 @@ fn perform_assign( let accessing_information = accessing_information.bus_access.as_ref().unwrap(); + // in case the accessing information is undef do not perform changes + // TODO: possible improvement? + + if accessing_information.undefined{ + return Ok(None) + } + if FoldedValue::valid_bus_node_pointer(&r_folded){ // in this case we are performing an assigment of the type in the node_pointer // to the bus in the left @@ -1832,6 +1909,7 @@ fn perform_assign( } else if FoldedValue::valid_arithmetic_slice(&r_folded){ // case assigning a field of the bus if meta.get_type_knowledge().is_signal(){ + let mut value_left = treat_result_with_memory_error( BusSlice::access_values_by_mut_reference(bus_slice, &accessing_information.array_access), meta, @@ -2021,17 +2099,24 @@ fn perform_assign( let mut signals_values_left: Vec = Vec::new(); let mut signals_values_right = Vec::new(); - // For now we can take advantage of the following: all buses in a slice - // are equals so we only call once to generate the accesses + // We assume that the buses in the slice are all of the same type + // Use just the first to generate the bus accesses - for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ - let assigned_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(assigned_bus_slice, i), + let mut inside_bus_signals = Vec::new(); + + if BusSlice::get_number_of_cells(&assigned_bus_slice) > 0{ + let left_i = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, 0), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - // TODO + // generate the inside signals + inside_bus_signals = left_i.get_accesses_bus(""); + } + + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ + let access_index = treat_result_with_memory_error( BusSlice::get_access_index(&assigned_bus_slice, i), meta, @@ -2040,10 +2125,19 @@ fn perform_assign( )?; let string_index = create_index_appendix(&access_index); - signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", name_bus, string_index))); - signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", full_symbol, string_index))); - - } + for s in &inside_bus_signals{ + signals_values_right.push( + format!( + "{}{}{}", name_bus, string_index, s.clone() + )); + signals_values_left.push( + format!( + "{}{}{}", full_symbol, string_index, s.clone() + )); + } + } + + // Transform the signal names into AExpr let mut ae_signals_left = Vec::new(); for signal_name in signals_values_left{ ae_signals_left.push(AExpr::Signal { symbol: signal_name }); @@ -2128,17 +2222,25 @@ fn perform_assign( let mut signals_values_left: Vec = Vec::new(); let mut signals_values_right: Vec = Vec::new(); - for i in 0..BusSlice::get_number_of_cells(&bus_slice){ - // We generate an arithmetic slice with the result - - let assigned_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&bus_slice, i), + // Generate the arithmetic slices containing the signals + // We assume that the buses in the slice are all of the same type + // Use just the first to generate the bus accesses + + let mut inside_bus_signals = Vec::new(); + + if BusSlice::get_number_of_cells(&assigned_bus_slice) > 0{ + let left_i = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&assigned_bus_slice, 0), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - - // TODO + // generate the inside signals + inside_bus_signals = left_i.get_accesses_bus(""); + } + + for i in 0..BusSlice::get_number_of_cells(&assigned_bus_slice){ + let access_index = treat_result_with_memory_error( BusSlice::get_access_index(&assigned_bus_slice, i), meta, @@ -2147,10 +2249,19 @@ fn perform_assign( )?; let string_index = create_index_appendix(&access_index); - signals_values_right.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", name_bus, string_index))); - signals_values_left.append(&mut assigned_bus.get_accesses_bus(&format!("{}{}", full_symbol, string_index))); + for s in &inside_bus_signals{ + signals_values_right.push( + format!( + "{}{}{}", name_bus, string_index, s.clone() + )); + signals_values_left.push( + format!( + "{}{}{}", full_symbol, string_index, s.clone() + )); + } + } - } + // Transform the signal names into AExpr let mut ae_signals_left = Vec::new(); for signal_name in signals_values_left{ @@ -3331,8 +3442,19 @@ fn treat_result_with_memory_error_void( } MemoryError::AssignmentError(type_asig_error) => { match type_asig_error{ + TypeAssignmentError::MultipleAssignmentsComponent =>{ + Report::error( + format!("Exception caused by invalid assignment\n The component has been assigned previously"), + RuntimeError) + }, + TypeAssignmentError::MultipleAssignmentsBus =>{ + Report::error( + format!("Exception caused by invalid assignment\n Bus contains fields that have been previously initialized"), + RuntimeError) + }, TypeAssignmentError::MultipleAssignments =>{ - Report::error("Exception caused by invalid assignment: signal already assigned".to_string(), + Report::error( + format!("Exception caused by invalid assignment\n Signal has been already assigned"), RuntimeError) }, TypeAssignmentError::AssignmentOutput =>{ @@ -3447,8 +3569,19 @@ pub fn treat_result_with_memory_error( }, MemoryError::AssignmentError(type_asig_error) => { match type_asig_error{ + TypeAssignmentError::MultipleAssignmentsComponent =>{ + Report::error( + format!("Exception caused by invalid assignment\n The component has been assigned previously"), + RuntimeError) + }, + TypeAssignmentError::MultipleAssignmentsBus =>{ + Report::error( + format!("Exception caused by invalid assignment\n Bus contains fields that have been previously initialized"), + RuntimeError) + }, TypeAssignmentError::MultipleAssignments =>{ - Report::error("Exception caused by invalid assignment: signal already assigned".to_string(), + Report::error( + format!("Exception caused by invalid assignment\n Signal has been already assigned"), RuntimeError) }, TypeAssignmentError::AssignmentOutput =>{ diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 7c1a93d7a..6c2c0f934 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -10,6 +10,8 @@ pub enum TypeInvalidAccess { } pub enum TypeAssignmentError { + MultipleAssignmentsComponent, + MultipleAssignmentsBus, MultipleAssignments, AssignmentOutput, NoInitializedComponent, From 665c3989e1237c82bad765045edb69897770f103 Mon Sep 17 00:00:00 2001 From: alrubio Date: Tue, 23 Jul 2024 14:09:47 +0200 Subject: [PATCH 140/189] Reading qualified inputs for JS added --- code_producers/src/c_elements/mod.rs | 4 +- code_producers/src/components/mod.rs | 5 +- .../common/witness_calculator.js | 49 ++++++++++- code_producers/src/wasm_elements/mod.rs | 83 +++++++++++++++++++ .../src/wasm_elements/wasm_code_generator.rs | 36 ++++++-- compiler/src/circuit_design/build.rs | 2 + 6 files changed, 165 insertions(+), 14 deletions(-) mode change 100755 => 100644 code_producers/src/wasm_elements/common/witness_calculator.js diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index e7cd583df..181bd0efe 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -77,12 +77,14 @@ impl Default for CProducer { InputInfo{ name:"in1".to_string(), size:1, + dimensions: Vec::new(), start: 2, bus_id: None }, InputInfo{ name:"in2".to_string(), - size:1, + size:1, + dimensions: Vec::new(), start: 3, bus_id: None }, diff --git a/code_producers/src/components/mod.rs b/code_producers/src/components/mod.rs index b34d23002..211041254 100644 --- a/code_producers/src/components/mod.rs +++ b/code_producers/src/components/mod.rs @@ -13,15 +13,16 @@ pub struct IODef { #[derive(Clone)] pub struct InputInfo{ pub name: String, + pub dimensions: Vec, pub start: usize, - pub size: usize, + pub size: usize, //full size (not only the content if array) pub bus_id: Option } #[derive(Default, Clone)] pub struct FieldData{ pub dimensions: Vec, - pub size: usize, + pub size: usize, // it is only the size of the content if array pub offset: usize, pub bus_id: Option, pub name: String diff --git a/code_producers/src/wasm_elements/common/witness_calculator.js b/code_producers/src/wasm_elements/common/witness_calculator.js old mode 100755 new mode 100644 index ab65bc929..f4c778825 --- a/code_producers/src/wasm_elements/common/witness_calculator.js +++ b/code_producers/src/wasm_elements/common/witness_calculator.js @@ -131,9 +131,14 @@ class WitnessCalculator { return this.instance.exports.getVersion(); } - async _doCalculateWitness(input, sanityCheck) { + async _doCalculateWitness(input_orig, sanityCheck) { //input is assumed to be a map from signals to arrays of bigints this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); + let prefix = ""; + var input = new Object(); + //console.log("Input: ", input_orig); + qualify_input(prefix,input_orig,input); + //console.log("Input after: ",input); const keys = Object.keys(input); var input_counter = 0; keys.forEach( (k) => { @@ -174,7 +179,6 @@ class WitnessCalculator { async calculateWitness(input, sanityCheck) { const w = []; - await this._doCalculateWitness(input, sanityCheck); for (let i=0; i 0) { + let t = typeof a[0]; + for (let i = 1; i { + let new_prefix = prefix == ""? k : prefix + "." + k; + qualify_input(new_prefix,input[k],input1); + }); + } else { + input1[prefix] = input; + } + return input; +} + function toArray32(rem,size) { const res = []; //new Uint32Array(size); //has no unshift const radix = BigInt(0x100000000); diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index 553882057..668aedca8 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -84,12 +84,14 @@ impl Default for WASMProducer { InputInfo{ name:"in1".to_string(), size:1, + dimensions: Vec::new(), start: 1, bus_id: None }, InputInfo{ name:"in2".to_string(), size:1, + dimensions: Vec::new(), start: 2, bus_id: None } @@ -200,6 +202,87 @@ impl WASMProducer { pub fn get_main_input_list(&self) -> &InputList { &self.main_input_list } + fn get_accesses(&self, pos: usize, dims: &Vec) -> Vec<(String,usize)> { + if pos >= dims.len() { + vec![("".to_string(),0)] + } else { + let mut res: Vec<(String,usize)> = vec![]; + let res1 = self.get_accesses(pos+1, dims); + let mut elems:usize = 1; + let mut epos = pos + 1; + while epos < dims.len() { + elems *= dims[epos]; + epos += 1; + } + let mut jump = 0; + for i in 0..dims[pos] { + for j in 0..res1.len() { + let (a,s) = &res1[j]; + res.push((format!("[{}]{}",i,a),jump+s)); + } + jump += elems; + } + res + } + } + fn get_qualified_names (&self, busid: usize, start: usize, prefix: String) -> InputList { + let mut buslist = vec![]; + //println!("BusId: {}", busid); + for io in &self.busid_field_info[busid] { + let name = format!("{}.{}",prefix.clone(),io.name); + let new_start = start + io.offset; + //print!("name: {}, start: {}", name, new_start); + if let Some(value) = io.bus_id { + let accesses = self.get_accesses(0,&io.dimensions); + //println!("accesses list: {:?}", accesses); + for (a,s) in &accesses { + let prefix = format!("{}{}",name.clone(),a); + let mut ios = self.get_qualified_names (value,new_start+s*io.size,prefix); + buslist.append(&mut ios); + } + } + else { + //println!(""); + let mut total_size = io.size; + for i in &io.dimensions { + total_size *= i; + } + let ioinfo = { + InputInfo{ + name: name, + dimensions: io.dimensions.clone(), + size: total_size, + start: new_start, + bus_id: None + } }; + buslist.push(ioinfo); + } + } + buslist + } + + pub fn get_main_input_list_with_qualifiers(&self) -> InputList { + let mut iolist = vec![]; + for io in &self.main_input_list { + if let Some(value) = io.bus_id { + let mut elems:usize = 1; + for i in &io.dimensions { + elems *= i; + } + let size:usize = io.size/elems; + let accesses = self.get_accesses(0,&io.dimensions); + for (a,s) in &accesses { + let prefix = format!("{}{}",io.name.clone(),a); + let mut ios = self.get_qualified_names (value,io.start+s*size,prefix); + iolist.append(&mut ios); + } + } + else { + iolist.push(io.clone()); + } + } + iolist + } pub fn get_number_of_witness(&self) -> usize { self.signals_in_witness } diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 5206c41ac..5b01bcfdf 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -3,6 +3,7 @@ use num_bigint_dig::BigInt; use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; +use std::collections::{HashMap}; pub fn wasm_hexa(nbytes: usize, num: &BigInt) -> String { let inbytes = num.to_str_radix(16).to_string(); @@ -316,7 +317,7 @@ pub fn generate_data_io_signals_info( for c in 0..producer.get_number_of_template_instances() { match io_map.get(&c) { Some(value) => { - println!("Template Instance: {}", c); + //println!("Template Instance: {}", c); for s in value { // add the actual offset in memory, taking into account the size of field nums //println!("Offset: {}", s.offset); @@ -395,23 +396,23 @@ pub fn generate_data_field_info( ) -> String { let mut field_info = "".to_string(); for c in 0..producer.get_number_of_bus_instances() { - println!("Bus Instance: {}", c); + //println!("Bus Instance: {}", c); for s in &field_map[c] { // add the actual offset in memory, taking into account the size of field nums - println!("Offset: {}", s.offset); + //println!("Offset: {}", s.offset); field_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.offset * producer.get_size_32_bits_in_memory() * 4), )); - println!("Length: {}", s.dimensions.len()); + //println!("Length: {}", s.dimensions.len()); if s.dimensions.len() > 0 { // if it is an array // add all dimensions but first one for i in 1..s.dimensions.len() { - println!("Index: {}, {}", i, s.dimensions[i]); + //println!("Index: {}, {}", i, s.dimensions[i]); field_info.push_str(&&wasm_hexa(4, &BigInt::from(s.dimensions[i]))); } // add the actual size in memory, if array - println!("Size: {}", s.size); + //println!("Size: {}", s.size); field_info.push_str(&&wasm_hexa( 4, &BigInt::from(s.size), @@ -420,7 +421,7 @@ pub fn generate_data_field_info( } // add the busid if it contains buses if let Some(value) = s.bus_id { - println!("Bus_id: {}", value); + //println!("Bus_id: {}", value); field_info.push_str(&&wasm_hexa(4, &BigInt::from(value))); } } @@ -669,8 +670,25 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { producer.get_shared_rw_memory_start() - 8, "\\00\\00\\00\\00\\00\\00\\00\\80" )); - // TODO: change generate_hash_map to new inputlist - let map = generate_hash_map(&producer.get_main_input_list()); + let mut input_list_with_qualifiers = producer.get_main_input_list_with_qualifiers(); + //for io in &input_list_with_qualifiers { + // println!("Name: {}, Start: {}, Size: {}",io.name, io.start, io.size); + //} + let input_list = producer.get_main_input_list(); + let mut id_to_info: HashMap = HashMap::new(); + for io in &input_list_with_qualifiers { + id_to_info.insert(io.name.clone(),(io.start, io.size)); + } + for io in input_list { + if id_to_info.contains_key(&io.name) { + let (st,sz) = id_to_info[&io.name]; + assert!(st == io.start && sz == io.size); + } else { + input_list_with_qualifiers.push(io.clone()); + } + } + + let map = generate_hash_map(&input_list_with_qualifiers); wdata.push(format!(";; hash_map")); wdata.push(format!( "(data (i32.const {}) \"{}\")", diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index adc6effe0..688d05efd 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -288,6 +288,7 @@ fn main_input_list(main: &TemplateInstance) -> InputList { TSignal(info) =>{ InputInfo{ name: info.name.clone(), + dimensions: info.lengths.clone(), size: info.size, start: info.dag_local_id, bus_id: None @@ -296,6 +297,7 @@ fn main_input_list(main: &TemplateInstance) -> InputList { TBus(info) =>{ InputInfo{ name: info.name.clone(), + dimensions: info.lengths.clone(), size: info.size, start: info.dag_local_id, bus_id: Some(info.bus_id) From 77dc9b9f7a61fc4d087838fd86163baa8b2fb6aa Mon Sep 17 00:00:00 2001 From: alrubio Date: Tue, 23 Jul 2024 19:48:38 +0200 Subject: [PATCH 141/189] qualified inputs for C++ added --- .../src/c_elements/c_code_generator.rs | 24 +++++- code_producers/src/c_elements/common/main.cpp | 58 ++++++++++++- code_producers/src/c_elements/mod.rs | 82 +++++++++++++++++++ .../common/witness_calculator.js | 1 - 4 files changed, 160 insertions(+), 5 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 9d74c9bbb..39b8af485 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -4,6 +4,7 @@ use serde_json::json; use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; +use std::collections::{HashMap}; // Types const T_U64: &str = "u64"; @@ -726,9 +727,26 @@ pub fn generate_dat_file(dat_file: &mut dyn Write, producer: &CProducer) -> std: //dfile.write_all(&p)?; //dfile.flush()?; - let aux = producer.get_main_input_list(); - // TODO: change generate_hash_map to new inputlist using buses - let map = generate_hash_map(&aux); + let mut input_list_with_qualifiers = producer.get_main_input_list_with_qualifiers(); + //for io in &input_list_with_qualifiers { + // println!("Name: {}, Start: {}, Size: {}",io.name, io.start, io.size); + //} + let input_list = producer.get_main_input_list(); + let mut id_to_info: HashMap = HashMap::new(); + for io in &input_list_with_qualifiers { + id_to_info.insert(io.name.clone(),(io.start, io.size)); + } + for io in input_list { + if id_to_info.contains_key(&io.name) { + let (st,sz) = id_to_info[&io.name]; + assert!(st == io.start && sz == io.size); + } else { + input_list_with_qualifiers.push(io.clone()); + } + } + + + let map = generate_hash_map(&input_list_with_qualifiers); let hashmap = generate_dat_from_hash_map(&map); //bytes u64 --> u64 //let hml = 256 as u32; //dfile.write_all(&hml.to_be_bytes())?; diff --git a/code_producers/src/c_elements/common/main.cpp b/code_producers/src/c_elements/common/main.cpp index b0ec09711..5ce3dab6d 100644 --- a/code_producers/src/c_elements/common/main.cpp +++ b/code_producers/src/c_elements/common/main.cpp @@ -187,11 +187,67 @@ void json2FrElements (json val, std::vector & vval){ } } +json::value_t check_type(std::string prefix, json in){ + if (not in.is_array()) { + return in.type(); + } else { + if (in.size() == 0) return json::value_t::null; + json::value_t t = check_type(prefix, in[0]); + for (uint i = 1; i < in.size(); i++) { + if (t != check_type(prefix, in[i])) { + fprintf(stderr, "Types are not the same in the the key %s\n",prefix.c_str()); + assert(false); + } + } + return t; + } +} + +void qualify_input(std::string prefix, json &in, json &in1); + +void qualify_input_list(std::string prefix, json &in, json &in1){ + if (in.is_array()) { + for (uint i = 0; i 0) { + json::value_t t = check_type(prefix,in); + if (t == json::value_t::object) { + qualify_input_list(prefix,in,in1); + } else { + in1[prefix] = in; + } + } else { + in1[prefix] = in; + } + } else if (in.is_object()) { + for (json::iterator it = in.begin(); it != in.end(); ++it) { + std::string new_prefix = prefix.length() == 0 ? it.key() : prefix + "." + it.key(); + qualify_input(new_prefix,it.value(),in1); + } + } else { + in1[prefix] = in; + } +} void loadJson(Circom_CalcWit *ctx, std::string filename) { std::ifstream inStream(filename); + json jin; + inStream >> jin; json j; - inStream >> j; + + //std::cout << jin << std::endl; + std::string prefix = ""; + qualify_input(prefix, jin, j); + //std::cout << j << std::endl; u64 nItems = j.size(); // printf("Items : %llu\n",nItems); diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index 181bd0efe..607b71bfe 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -158,6 +158,88 @@ impl CProducer { pub fn get_main_input_list(&self) -> &InputList { &self.main_input_list } + fn get_accesses(&self, pos: usize, dims: &Vec) -> Vec<(String,usize)> { + if pos >= dims.len() { + vec![("".to_string(),0)] + } else { + let mut res: Vec<(String,usize)> = vec![]; + let res1 = self.get_accesses(pos+1, dims); + let mut elems:usize = 1; + let mut epos = pos + 1; + while epos < dims.len() { + elems *= dims[epos]; + epos += 1; + } + let mut jump = 0; + for i in 0..dims[pos] { + for j in 0..res1.len() { + let (a,s) = &res1[j]; + res.push((format!("[{}]{}",i,a),jump+s)); + } + jump += elems; + } + res + } + } + fn get_qualified_names (&self, busid: usize, start: usize, prefix: String) -> InputList { + let mut buslist = vec![]; + //println!("BusId: {}", busid); + for io in &self.busid_field_info[busid] { + let name = format!("{}.{}",prefix.clone(),io.name); + let new_start = start + io.offset; + //print!("name: {}, start: {}", name, new_start); + if let Some(value) = io.bus_id { + let accesses = self.get_accesses(0,&io.dimensions); + //println!("accesses list: {:?}", accesses); + for (a,s) in &accesses { + let prefix = format!("{}{}",name.clone(),a); + let mut ios = self.get_qualified_names (value,new_start+s*io.size,prefix); + buslist.append(&mut ios); + } + } + else { + //println!(""); + let mut total_size = io.size; + for i in &io.dimensions { + total_size *= i; + } + let ioinfo = { + InputInfo{ + name: name, + dimensions: io.dimensions.clone(), + size: total_size, + start: new_start, + bus_id: None + } }; + buslist.push(ioinfo); + } + } + buslist + } + + pub fn get_main_input_list_with_qualifiers(&self) -> InputList { + let mut iolist = vec![]; + for io in &self.main_input_list { + if let Some(value) = io.bus_id { + let mut elems:usize = 1; + for i in &io.dimensions { + elems *= i; + } + let size:usize = io.size/elems; + let accesses = self.get_accesses(0,&io.dimensions); + for (a,s) in &accesses { + let prefix = format!("{}{}",io.name.clone(),a); + let mut ios = self.get_qualified_names (value,io.start+s*size,prefix); + iolist.append(&mut ios); + } + } + else { + iolist.push(io.clone()); + } + } + iolist + } + pub fn get_number_of_witness(&self) -> usize { self.signals_in_witness } diff --git a/code_producers/src/wasm_elements/common/witness_calculator.js b/code_producers/src/wasm_elements/common/witness_calculator.js index f4c778825..1560c9a39 100644 --- a/code_producers/src/wasm_elements/common/witness_calculator.js +++ b/code_producers/src/wasm_elements/common/witness_calculator.js @@ -319,7 +319,6 @@ function qualify_input(prefix,input,input1) { } else { input1[prefix] = input; } - return input; } function toArray32(rem,size) { From 27298999b8806a2ad8b08d2d0cd84175a2a992b0 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 23 Jul 2024 20:48:13 +0200 Subject: [PATCH 142/189] solving conflicts --- compiler/src/ir_processing/build_stack.rs | 23 ++------ constraint_generation/src/execute.rs | 68 +++++++---------------- 2 files changed, 26 insertions(+), 65 deletions(-) diff --git a/compiler/src/ir_processing/build_stack.rs b/compiler/src/ir_processing/build_stack.rs index 11be85889..dae3fcca7 100644 --- a/compiler/src/ir_processing/build_stack.rs +++ b/compiler/src/ir_processing/build_stack.rs @@ -144,15 +144,15 @@ pub fn build_value(bucket: &mut ValueBucket, fresh: usize) -> usize { pub fn build_location(bucket: &mut LocationRule, mut fresh: usize) -> (usize, usize) { use LocationRule::*; match bucket { -<<<<<<< HEAD Indexed { location, .. } => build_instruction(location, fresh), Mapped { indexes, .. } => { - let mut max_depth = 0; + let mut max_stack = fresh; for acc in indexes{ match acc{ AccessType::Indexed(ind) =>{ - let depth = build_list(&mut ind.indexes, fresh); - max_depth = std::cmp::max(max_depth, depth); + let (depth, new_fresh) = build_instruction_address(i, fresh); + max_stack = std::cmp::max(max_stack, depth); + fresh = new_fresh; }, AccessType::Qualified(_) =>{ @@ -160,22 +160,9 @@ pub fn build_location(bucket: &mut LocationRule, mut fresh: usize) -> (usize, us } } - max_depth - } - -======= - Indexed { location, .. } => - build_instruction_address(location, fresh), - Mapped { indexes, .. } => { - let mut max_stack = fresh; - for i in indexes{ - let (depth, new_fresh) = build_instruction_address(i, fresh); - max_stack = std::cmp::max(max_stack, depth); - fresh = new_fresh; - } (max_stack, fresh) } ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 + } } diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 3a9f82be2..27dc76175 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -294,20 +294,7 @@ fn execute_statement( name, &usable_dimensions, ), -<<<<<<< HEAD - VariableType::Signal(signal_type, tag_list) => execute_signal_declaration( - name, - &usable_dimensions, - tag_list, - *signal_type, - &mut runtime.environment, - actual_node, - ), - VariableType::Bus(_id, signal_type, tag_list) => { - execute_bus_declaration( -======= - VariableType::Signal(signal_type, tag_list) => - { + VariableType::Signal(signal_type, tag_list) => { if runtime.block_type == BlockType::Unknown{ // Case not valid constraint Known/Unknown let err = Result::Err(ExecutionError::DeclarationInUnknown); @@ -319,7 +306,6 @@ fn execute_statement( )?; } execute_signal_declaration( ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 name, &usable_dimensions, tag_list, @@ -327,11 +313,27 @@ fn execute_statement( &mut runtime.environment, actual_node, ) -<<<<<<< HEAD - } -======= }, ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 + VariableType::Bus(_id, signal_type, tag_list) => { + if runtime.block_type == BlockType::Unknown{ + // Case not valid constraint Known/Unknown + let err = Result::Err(ExecutionError::DeclarationInUnknown); + treat_result_with_execution_error( + err, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } + execute_bus_declaration( + name, + &usable_dimensions, + tag_list, + *signal_type, + &mut runtime.environment, + actual_node, + ) + }, _ =>{ unreachable!() } @@ -487,7 +489,6 @@ fn execute_statement( let f_left = execute_expression(lhe, program_archive, runtime, flags)?; let f_right = execute_expression(rhe, program_archive, runtime, flags)?; -<<<<<<< HEAD let (arith_left, arith_right) = if FoldedValue::valid_arithmetic_slice(&f_left) && FoldedValue::valid_arithmetic_slice(&f_right){ let left = safe_unwrap_to_arithmetic_slice(f_left, line!()); @@ -495,23 +496,6 @@ fn execute_statement( let correct_dims_result = AExpressionSlice::check_correct_dims(&left, &Vec::new(), &right, true); treat_result_with_memory_error_void( correct_dims_result, -======= - let arith_left = safe_unwrap_to_arithmetic_slice(f_left, line!()); - let arith_right = safe_unwrap_to_arithmetic_slice(f_right, line!()); - - - - let correct_dims_result = AExpressionSlice::check_correct_dims(&arith_left, &Vec::new(), &arith_right, true); - treat_result_with_memory_error_void( - correct_dims_result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - for i in 0..AExpressionSlice::get_number_of_cells(&arith_left){ - let value_left = treat_result_with_memory_error( - AExpressionSlice::access_value_by_index(&arith_left, i), ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 meta, &mut runtime.runtime_errors, &runtime.call_trace, @@ -1274,7 +1258,6 @@ fn execute_signal_declaration( } } -<<<<<<< HEAD fn execute_declaration_bus( signal_name: &str, dimensions: &[SliceCapacity], @@ -1299,15 +1282,6 @@ fn execute_declaration_bus( for t in list_tags{ actual_node.add_tag_signal(signal_name, t, None); } -======= -/* - In case the assignment could be a constraint generator the returned value is the constraint - that will be created -*/ -struct Constrained { - left: String, - right: AExpressionSlice, ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 } fn execute_bus_declaration( From 9fa024202cee244044a949ffd2b81d4bda789631 Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 24 Jul 2024 09:41:59 +0200 Subject: [PATCH 143/189] Merge of the code generation done --- .../src/c_elements/c_code_generator.rs | 41 +----- code_producers/src/c_elements/mod.rs | 88 +------------ code_producers/src/wasm_elements/mod.rs | 86 +------------ .../src/wasm_elements/wasm_code_generator.rs | 39 +----- compiler/src/circuit_design/build.rs | 121 ++++++++++++++++-- 5 files changed, 123 insertions(+), 252 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index 58ae335af..ad0b6a185 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -4,7 +4,6 @@ use serde_json::json; use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; -use std::collections::{HashMap}; // Types const T_U64: &str = "u64"; @@ -476,22 +475,12 @@ pub fn collect_function_headers(functions: Vec) -> Vec { //--------------- generate all kinds of Data for the .dat file --------------- -<<<<<<< HEAD -pub fn generate_hash_map(signal_name_list: &Vec) -> Vec<(u64, u64, u64)> { - assert!(signal_name_list.len() <= 256); - let len = 256; - let mut hash_map = vec![(0, 0, 0); len]; - for i in 0..signal_name_list.len() { - let h = hasher(&signal_name_list[i].name); - let mut p = (h % 256) as usize; -======= -pub fn generate_hash_map(signal_name_list: &Vec<(String, usize, usize)>, size: usize) -> Vec<(u64, u64, u64)> { +pub fn generate_hash_map(signal_name_list: &Vec, size: usize) -> Vec<(u64, u64, u64)> { assert!(signal_name_list.len() <= size); let mut hash_map = vec![(0, 0, 0); size]; for i in 0..signal_name_list.len() { - let h = hasher(&signal_name_list[i].0); + let h = hasher(&signal_name_list[i].name); let mut p = h as usize % size; ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 while hash_map[p].1 != 0 { p = (p + 1) % size; } @@ -736,31 +725,11 @@ pub fn generate_dat_file(dat_file: &mut dyn Write, producer: &CProducer) -> std: //dfile.write_all(&p)?; //dfile.flush()?; -<<<<<<< HEAD - let mut input_list_with_qualifiers = producer.get_main_input_list_with_qualifiers(); - //for io in &input_list_with_qualifiers { - // println!("Name: {}, Start: {}, Size: {}",io.name, io.start, io.size); - //} - let input_list = producer.get_main_input_list(); - let mut id_to_info: HashMap = HashMap::new(); - for io in &input_list_with_qualifiers { - id_to_info.insert(io.name.clone(),(io.start, io.size)); - } - for io in input_list { - if id_to_info.contains_key(&io.name) { - let (st,sz) = id_to_info[&io.name]; - assert!(st == io.start && sz == io.size); - } else { - input_list_with_qualifiers.push(io.clone()); - } - } - - - let map = generate_hash_map(&input_list_with_qualifiers); -======= +//<<<<<<< HEAD +//======= let aux = producer.get_main_input_list(); let map = generate_hash_map(&aux,producer.get_input_hash_map_entry_size()); ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 +//>>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 let hashmap = generate_dat_from_hash_map(&map); //bytes u64 --> u64 //let hml = producer.get_input_hash_map_entry_size() as u32; //dfile.write_all(&hml.to_be_bytes())?; diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index d45b7f914..ddc811c6d 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -158,94 +158,12 @@ impl CProducer { pub fn get_main_input_list(&self) -> &InputList { &self.main_input_list } -<<<<<<< HEAD - fn get_accesses(&self, pos: usize, dims: &Vec) -> Vec<(String,usize)> { - if pos >= dims.len() { - vec![("".to_string(),0)] - } else { - let mut res: Vec<(String,usize)> = vec![]; - let res1 = self.get_accesses(pos+1, dims); - let mut elems:usize = 1; - let mut epos = pos + 1; - while epos < dims.len() { - elems *= dims[epos]; - epos += 1; - } - let mut jump = 0; - for i in 0..dims[pos] { - for j in 0..res1.len() { - let (a,s) = &res1[j]; - res.push((format!("[{}]{}",i,a),jump+s)); - } - jump += elems; - } - res - } - } - fn get_qualified_names (&self, busid: usize, start: usize, prefix: String) -> InputList { - let mut buslist = vec![]; - //println!("BusId: {}", busid); - for io in &self.busid_field_info[busid] { - let name = format!("{}.{}",prefix.clone(),io.name); - let new_start = start + io.offset; - //print!("name: {}, start: {}", name, new_start); - if let Some(value) = io.bus_id { - let accesses = self.get_accesses(0,&io.dimensions); - //println!("accesses list: {:?}", accesses); - for (a,s) in &accesses { - let prefix = format!("{}{}",name.clone(),a); - let mut ios = self.get_qualified_names (value,new_start+s*io.size,prefix); - buslist.append(&mut ios); - } - } - else { - //println!(""); - let mut total_size = io.size; - for i in &io.dimensions { - total_size *= i; - } - let ioinfo = { - InputInfo{ - name: name, - dimensions: io.dimensions.clone(), - size: total_size, - start: new_start, - bus_id: None - } }; - buslist.push(ioinfo); - } - } - buslist - } - - pub fn get_main_input_list_with_qualifiers(&self) -> InputList { - let mut iolist = vec![]; - for io in &self.main_input_list { - if let Some(value) = io.bus_id { - let mut elems:usize = 1; - for i in &io.dimensions { - elems *= i; - } - let size:usize = io.size/elems; - let accesses = self.get_accesses(0,&io.dimensions); - for (a,s) in &accesses { - let prefix = format!("{}{}",io.name.clone(),a); - let mut ios = self.get_qualified_names (value,io.start+s*size,prefix); - iolist.append(&mut ios); - } - } - else { - iolist.push(io.clone()); - } - } - iolist - } - -======= +//<<<<<<< HEAD +//======= pub fn get_input_hash_map_entry_size(&self) -> usize { std::cmp::max(usize::pow(2,(self.main_input_list.len() as f32).log2().ceil() as u32),256) } ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 +//>>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 pub fn get_number_of_witness(&self) -> usize { self.signals_in_witness } diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index 58a46debc..a932660e8 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -202,91 +202,11 @@ impl WASMProducer { pub fn get_main_input_list(&self) -> &InputList { &self.main_input_list } -<<<<<<< HEAD - fn get_accesses(&self, pos: usize, dims: &Vec) -> Vec<(String,usize)> { - if pos >= dims.len() { - vec![("".to_string(),0)] - } else { - let mut res: Vec<(String,usize)> = vec![]; - let res1 = self.get_accesses(pos+1, dims); - let mut elems:usize = 1; - let mut epos = pos + 1; - while epos < dims.len() { - elems *= dims[epos]; - epos += 1; - } - let mut jump = 0; - for i in 0..dims[pos] { - for j in 0..res1.len() { - let (a,s) = &res1[j]; - res.push((format!("[{}]{}",i,a),jump+s)); - } - jump += elems; - } - res - } - } - fn get_qualified_names (&self, busid: usize, start: usize, prefix: String) -> InputList { - let mut buslist = vec![]; - //println!("BusId: {}", busid); - for io in &self.busid_field_info[busid] { - let name = format!("{}.{}",prefix.clone(),io.name); - let new_start = start + io.offset; - //print!("name: {}, start: {}", name, new_start); - if let Some(value) = io.bus_id { - let accesses = self.get_accesses(0,&io.dimensions); - //println!("accesses list: {:?}", accesses); - for (a,s) in &accesses { - let prefix = format!("{}{}",name.clone(),a); - let mut ios = self.get_qualified_names (value,new_start+s*io.size,prefix); - buslist.append(&mut ios); - } - } - else { - //println!(""); - let mut total_size = io.size; - for i in &io.dimensions { - total_size *= i; - } - let ioinfo = { - InputInfo{ - name: name, - dimensions: io.dimensions.clone(), - size: total_size, - start: new_start, - bus_id: None - } }; - buslist.push(ioinfo); - } - } - buslist - } - - pub fn get_main_input_list_with_qualifiers(&self) -> InputList { - let mut iolist = vec![]; - for io in &self.main_input_list { - if let Some(value) = io.bus_id { - let mut elems:usize = 1; - for i in &io.dimensions { - elems *= i; - } - let size:usize = io.size/elems; - let accesses = self.get_accesses(0,&io.dimensions); - for (a,s) in &accesses { - let prefix = format!("{}{}",io.name.clone(),a); - let mut ios = self.get_qualified_names (value,io.start+s*size,prefix); - iolist.append(&mut ios); - } - } - else { - iolist.push(io.clone()); - } - } - iolist -======= +//HEAD +//======= pub fn get_input_hash_map_entry_size(&self) -> usize { std::cmp::max(usize::pow(2,(self.main_input_list.len() as f32).log2().ceil() as u32),256) ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 +//>>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 } pub fn get_number_of_witness(&self) -> usize { self.signals_in_witness diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 854f7a0b5..4f93ac858 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -3,7 +3,6 @@ use num_bigint_dig::BigInt; use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; -use std::collections::{HashMap}; pub fn wasm_hexa(nbytes: usize, num: &BigInt) -> String { let inbytes = num.to_str_radix(16).to_string(); @@ -227,22 +226,12 @@ pub fn get_initial_size_of_memory(producer: &WASMProducer) -> usize { //------------------- generate all kinds of Data ------------------ -<<<<<<< HEAD -pub fn generate_hash_map(signal_name_list: &Vec) -> Vec<(u64, usize, usize)> { - assert!(signal_name_list.len() <= 256); - let len = 256; - let mut hash_map = vec![(0, 0, 0); len]; - for i in 0..signal_name_list.len() { - let h = hasher(&signal_name_list[i].name); - let mut p = (h % 256) as usize; -======= -pub fn generate_hash_map(signal_name_list: &Vec<(String, usize, usize)>, size: usize) -> Vec<(u64, usize, usize)> { +pub fn generate_hash_map(signal_name_list: &Vec, size: usize) -> Vec<(u64, usize, usize)> { assert!(signal_name_list.len() <= size); let mut hash_map = vec![(0, 0, 0); size]; for i in 0..signal_name_list.len() { - let h = hasher(&signal_name_list[i].0); + let h = hasher(&signal_name_list[i].name); let mut p = h as usize % size; ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 while hash_map[p].1 != 0 { p = (p + 1) % size; } @@ -679,30 +668,8 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { producer.get_shared_rw_memory_start() - 8, "\\00\\00\\00\\00\\00\\00\\00\\80" )); -<<<<<<< HEAD - let mut input_list_with_qualifiers = producer.get_main_input_list_with_qualifiers(); - //for io in &input_list_with_qualifiers { - // println!("Name: {}, Start: {}, Size: {}",io.name, io.start, io.size); - //} - let input_list = producer.get_main_input_list(); - let mut id_to_info: HashMap = HashMap::new(); - for io in &input_list_with_qualifiers { - id_to_info.insert(io.name.clone(),(io.start, io.size)); - } - for io in input_list { - if id_to_info.contains_key(&io.name) { - let (st,sz) = id_to_info[&io.name]; - assert!(st == io.start && sz == io.size); - } else { - input_list_with_qualifiers.push(io.clone()); - } - } - - let map = generate_hash_map(&input_list_with_qualifiers); - wdata.push(format!(";; hash_map")); -======= let map = generate_hash_map(&producer.get_main_input_list(),producer.get_input_hash_map_entry_size()); ->>>>>>> 9f3da35a8ac3107190f8c85c8cf3ea1a0f8780a4 + wdata.push(format!(";; hash_map")); wdata.push(format!( "(data (i32.const {}) \"{}\")", producer.get_input_signals_hashmap_start(), diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 655ce0400..6e1fe401b 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -223,11 +223,6 @@ fn initialize_wasm_producer(vcp: &VCP, database: &TemplateDB, wat_flag:bool, ver producer.signals_in_witness = producer.witness_to_signal_list.len(); producer.number_of_main_inputs = vcp.templates[initial_node].number_of_inputs; producer.number_of_main_outputs = vcp.templates[initial_node].number_of_outputs; - producer.main_input_list = main_input_list(&vcp.templates[initial_node]); - producer.io_map = build_io_map(vcp, database); - producer.template_instance_list = build_template_list(vcp); - producer.field_tracking.clear(); - producer.wat_flag = wat_flag; // add the info of the buses ( @@ -235,6 +230,11 @@ fn initialize_wasm_producer(vcp: &VCP, database: &TemplateDB, wat_flag:bool, ver producer.busid_field_info ) = get_info_buses(&vcp.buses); + producer.main_input_list = main_input_list(&vcp.templates[initial_node],&producer.busid_field_info); + producer.io_map = build_io_map(vcp, database); + producer.template_instance_list = build_template_list(vcp); + producer.field_tracking.clear(); + producer.wat_flag = wat_flag; (producer.major_version, producer.minor_version, producer.patch_version) = get_number_version(version); producer @@ -265,22 +265,22 @@ fn initialize_c_producer(vcp: &VCP, database: &TemplateDB, version: &str) -> CPr producer.signals_in_witness = producer.witness_to_signal_list.len(); producer.number_of_main_inputs = vcp.templates[initial_node].number_of_inputs; producer.number_of_main_outputs = vcp.templates[initial_node].number_of_outputs; - producer.main_input_list = main_input_list(&vcp.templates[initial_node]); - producer.io_map = build_io_map(vcp, database); - producer.template_instance_list = build_template_list_parallel(vcp); - producer.field_tracking.clear(); - // add the info of the buses ( producer.num_of_bus_instances, producer.busid_field_info ) = get_info_buses(&vcp.buses); + producer.main_input_list = main_input_list(&vcp.templates[initial_node],&producer.busid_field_info); + producer.io_map = build_io_map(vcp, database); + producer.template_instance_list = build_template_list_parallel(vcp); + producer.field_tracking.clear(); + (producer.major_version, producer.minor_version, producer.patch_version) = get_number_version(version); producer } -fn main_input_list(main: &TemplateInstance) -> InputList { +fn main_input_list(main: &TemplateInstance, buses: &FieldMap) -> InputList { use program_structure::ast::SignalType::*; use crate::hir::very_concrete_program::Wire::*; fn build_info_wire(wire: &Wire) -> InputInfo{ @@ -305,13 +305,110 @@ fn main_input_list(main: &TemplateInstance) -> InputList { } } } + fn get_accesses(pos: usize, dims: &Vec) -> Vec<(String,usize)> { + if pos >= dims.len() { + vec![("".to_string(),0)] + } else { + let mut res: Vec<(String,usize)> = vec![]; + let res1 = get_accesses(pos+1, dims); + let mut elems:usize = 1; + let mut epos = pos + 1; + while epos < dims.len() { + elems *= dims[epos]; + epos += 1; + } + let mut jump = 0; + for i in 0..dims[pos] { + for j in 0..res1.len() { + let (a,s) = &res1[j]; + res.push((format!("[{}]{}",i,a),jump+s)); + } + jump += elems; + } + res + } + } + fn get_qualified_names (busid: usize, start: usize, prefix: String, buses: &FieldMap) -> InputList { + let mut buslist = vec![]; + //println!("BusId: {}", busid); + for io in &buses[busid] { + let name = format!("{}.{}",prefix.clone(),io.name); + let new_start = start + io.offset; + //print!("name: {}, start: {}", name, new_start); + if let Some(value) = io.bus_id { + let accesses = get_accesses(0,&io.dimensions); + //println!("accesses list: {:?}", accesses); + for (a,s) in &accesses { + let prefix = format!("{}{}",name.clone(),a); + let mut ios = get_qualified_names (value,new_start+s*io.size,prefix,buses); + buslist.append(&mut ios); + } + } + else { + //println!(""); + let mut total_size = io.size; + for i in &io.dimensions { + total_size *= i; + } + let ioinfo = { + InputInfo{ + name: name, + dimensions: io.dimensions.clone(), + size: total_size, + start: new_start, + bus_id: None + } }; + buslist.push(ioinfo); + } + } + buslist + } + pub fn get_main_input_list_with_qualifiers(buses: &FieldMap, input_list: &InputList) -> InputList { + let mut iolist = vec![]; + for io in input_list { + if let Some(value) = io.bus_id { + let mut elems:usize = 1; + for i in &io.dimensions { + elems *= i; + } + let size:usize = io.size/elems; + let accesses = get_accesses(0,&io.dimensions); + for (a,s) in &accesses { + let prefix = format!("{}{}",io.name.clone(),a); + let mut ios = get_qualified_names (value,io.start+s*size,prefix,buses); + iolist.append(&mut ios); + } + } + else { + iolist.push(io.clone()); + } + } + iolist + } let mut input_list = vec![]; for s in &main.wires { if s.xtype() == Input { input_list.push(build_info_wire(s)); } } - input_list + let mut input_list_with_qualifiers = get_main_input_list_with_qualifiers(buses,&input_list); + //for io in &input_list_with_qualifiers { + // println!("Name: {}, Start: {}, Size: {}",io.name, io.start, io.size); + //} +// let input_list = producer.get_main_input_list(); + let mut id_to_info: HashMap = HashMap::new(); + for io in &input_list_with_qualifiers { + id_to_info.insert(io.name.clone(),(io.start, io.size)); + } + for io in input_list { + if id_to_info.contains_key(&io.name) { + let (st,sz) = id_to_info[&io.name]; + assert!(st == io.start && sz == io.size); + } else { + input_list_with_qualifiers.push(io.clone()); + } + } + input_list_with_qualifiers } fn build_template_list(vcp: &VCP) -> TemplateList { From 55adaedb48e0c9fa7eef4fa389147e19432e0398 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 24 Jul 2024 13:09:37 +0200 Subject: [PATCH 144/189] solving conflicts build_stack --- compiler/src/ir_processing/build_stack.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/src/ir_processing/build_stack.rs b/compiler/src/ir_processing/build_stack.rs index dae3fcca7..7310a5529 100644 --- a/compiler/src/ir_processing/build_stack.rs +++ b/compiler/src/ir_processing/build_stack.rs @@ -144,15 +144,17 @@ pub fn build_value(bucket: &mut ValueBucket, fresh: usize) -> usize { pub fn build_location(bucket: &mut LocationRule, mut fresh: usize) -> (usize, usize) { use LocationRule::*; match bucket { - Indexed { location, .. } => build_instruction(location, fresh), + Indexed { location, .. } => build_instruction_address(location, fresh), Mapped { indexes, .. } => { let mut max_stack = fresh; for acc in indexes{ match acc{ AccessType::Indexed(ind) =>{ - let (depth, new_fresh) = build_instruction_address(i, fresh); - max_stack = std::cmp::max(max_stack, depth); - fresh = new_fresh; + for i in &mut ind.indexes{ + let (depth, new_fresh) = build_instruction_address(i, fresh); + max_stack = std::cmp::max(max_stack, depth); + fresh = new_fresh; + } }, AccessType::Qualified(_) =>{ From c9b2df000749694245727272a48ad7d331279527 Mon Sep 17 00:00:00 2001 From: Miguel Isabel Date: Wed, 24 Jul 2024 15:45:22 +0200 Subject: [PATCH 145/189] Update buses.md with inputs info --- mkdocs/docs/circom-language/buses.md | 59 ++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/mkdocs/docs/circom-language/buses.md b/mkdocs/docs/circom-language/buses.md index 2d8b410da..9d4ddc3c2 100644 --- a/mkdocs/docs/circom-language/buses.md +++ b/mkdocs/docs/circom-language/buses.md @@ -190,28 +190,61 @@ template well_defined_figure(num_sides, dimension){ The previous template defines a correctness check for any figure: the ending point of a line must be the starting point of the next line. Otherwise, the figure is not well defined, and the witness generation will fail. ## Buses as Circuit Inputs -Similar to signals, buses can be part of the inputs of the main circuit. Thus, we must indicate their values if we want to generate a witness for the circuit. As usual, we indicate the value of the input buses following a JSON format. Let us consider again the `Person` bus and an input `p` of this kind, we would indicate its values as follows: +Similar to signals, buses can be part of the main circuit's inputs. Therefore, we must specify their values to generate a witness for the circuit. For each circuit input bus, values can be specified in two ways: +- __Serialized Format__: Indicate the value of every signal, bus, or array field in a single array, following the bus's definition order. +- __JSON Format__: Provide values using a fully qualified JSON format with field names. Note that you cannot mix both methods within a single bus. If you start defining an input using field names, you must use this method consistently throughout. + +Let us consider again the `Person` bus: ``` -["p": {"name": ["80","82",...], +bus Film{ + signal title[2]; + signal director[2]; + signal year; +} + +bus Date{ + signal day; + signal month; + signal year; +} + +bus Person{ + signal name[2]; + Film films[2]; + Date birthday; +} +``` + +To indicate values for an input `p` of this kind, we would indicate its values as one of the following ways: + +- __Serialized format__: +``` +{"p": ["80","82","20","21","30","31","1953","40","41","50","51","1990","1","1","1992"] +} +``` + + - __JSON format__: +``` +{"p": {"name": ["80","82"], "films": [ - { "title": [...], - "director": [...], + { "title": ["20","21"], + "director": ["30","31"], "year": "1953" }, - ..., - { "title": [...], - "director": [...], + { "title": ["40","41"], + "director": ["50","51"], "year": "1990" } - ], - "birthday": - { "day": "1", - "month": "1", + ], + "birthday": + { "day": "1", + "month": "1", "year": "1992" } } -] +} + ``` -Like public input signals, public input buses cannot be tagged. Otherwise, the compiler will report an error. \ No newline at end of file +Like public input signals, public input buses cannot be tagged. Otherwise, the compiler will report an error. From 3aa572bfe44907f7984e60adcb6aa42306949a23 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 25 Jul 2024 11:17:40 +0200 Subject: [PATCH 146/189] adding multiple size for inputs of heterogeneus buses --- code_producers/src/c_elements/c_code_generator.rs | 10 ++++++++++ .../src/intermediate_representation/call_bucket.rs | 12 +++++++----- .../src/intermediate_representation/load_bucket.rs | 6 ++++-- .../intermediate_representation/store_bucket.rs | 11 ++++++----- .../src/intermediate_representation/translate.rs | 14 +++++++++++--- compiler/src/intermediate_representation/types.rs | 2 +- 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/code_producers/src/c_elements/c_code_generator.rs b/code_producers/src/c_elements/c_code_generator.rs index ad0b6a185..4460b04e1 100644 --- a/code_producers/src/c_elements/c_code_generator.rs +++ b/code_producers/src/c_elements/c_code_generator.rs @@ -377,6 +377,16 @@ pub fn set_list(elems: Vec) -> String { set_string } +pub fn set_list_tuple(elems: Vec<(usize, usize)>) -> String { + let mut set_string = "{".to_string(); + for (elem_a, elem_b) in elems { + set_string = format!("{}{{{},{}}},", set_string, elem_a, elem_b); + } + set_string.pop(); + set_string .push('}'); + set_string +} + pub fn set_list_bool(elems: Vec) -> String { let mut set_string = "{".to_string(); for elem in elems { diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 2116325a2..8b5c83ee2 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -98,7 +98,7 @@ impl WriteWasm for CallBucket { let arg_size = match &self.argument_types[i].size{ SizeOption::Single(value) => *value, SizeOption::Multiple(values) => { - values[0] + values[0].1 } }; if arg_size > 1 { @@ -356,7 +356,7 @@ impl WriteWasm for CallBucket { let data_size = match &data.context.size{ SizeOption::Single(value) => *value, SizeOption::Multiple(values) => { - values[0] + values[0].1 } }; instructions.push(set_constant(&data_size.to_string())); @@ -471,7 +471,7 @@ impl WriteC for CallBucket { let size = match &self.argument_types[i].size{ SizeOption::Single(value) => *value, SizeOption::Multiple(values) => { - values[0] + values[0].1 } }; if size > 1 { @@ -515,9 +515,11 @@ impl WriteC for CallBucket { SizeOption::Multiple(values) => { prologue.push(format!("int size_store[{}] = {};", values.len(), - set_list(values.to_vec()) + set_list_tuple(values.to_vec()) )); - format!("size_store[{}]", cmp_index_ref) + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_store[{}]", temp_id) } }; diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index fe5310830..cced54c90 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -341,9 +341,11 @@ impl WriteC for LoadBucket { SizeOption::Multiple(values) => { prologue.push(format!("int size_load[{}] = {};", values.len(), - set_list(values.to_vec()) + set_list_tuple(values.to_vec()) )); - format!("size_load[{}]", cmp_index_ref) + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_load[{}]", temp_id) } }; if uniform_parallel_value.is_some(){ diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index da22c8566..b564b0a70 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -60,7 +60,7 @@ impl WriteWasm for StoreBucket { let size = match &self.context.size{ SizeOption::Single(value) => *value, SizeOption::Multiple(values) => { - values[0] + values[0].1 } }; @@ -393,11 +393,12 @@ impl WriteC for StoreBucket { let size = match &self.context.size{ SizeOption::Single(value) => value.to_string(), SizeOption::Multiple(values) => { - prologue.push(format!("int size_store[{}] = {};", - values.len(), - set_list(values.clone()) + prologue.push(format!("std::map size_store {};", + set_list_tuple(values.clone()) )); - format!("size_store[{}]", cmp_index_ref) + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_store[{}]", temp_id) } }; diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 31656a20d..f5a6f3803 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -1022,7 +1022,8 @@ struct SymbolDef { struct PossibleInfo{ possible_sizes: Vec, possible_lengths: Vec>, - possible_bus_fields: Option>> + possible_bus_fields: Option>>, + possible_cmp_id: Vec } struct BusAccessInfo{ @@ -1074,6 +1075,7 @@ impl ProcessedSymbol { possible_lengths: vec![length], possible_sizes: vec![symbol_info.size], possible_bus_fields: bus_fields, + possible_cmp_id: vec![0], }; // Arrays to store the index accesses (before and after the component access) @@ -1112,6 +1114,7 @@ impl ProcessedSymbol { // We init the possible lenghts and sizes possible_status.possible_lengths = Vec::new(); possible_status.possible_sizes = Vec::new(); + possible_status.possible_cmp_id = Vec::new(); for cmp_id in possible_cmp_id{ // aux contains the info about the accessed wire @@ -1122,7 +1125,7 @@ impl ProcessedSymbol { new_length.reverse(); possible_status.possible_lengths.push(new_length); possible_status.possible_sizes.push(aux.size); - + possible_status.possible_cmp_id.push(cmp_id); if aux.bus_id.is_some(){ let fields = context.buses.get(aux.bus_id.unwrap()).unwrap().fields.clone(); if is_first{ @@ -1226,6 +1229,9 @@ impl ProcessedSymbol { let mut all_equal = true; let mut with_length: usize = 0; + let mut multiple_sizes = vec![]; + let mut index = 0; + for possible_size in &possible_status.possible_sizes{ if is_first{ with_length = *possible_size; @@ -1236,12 +1242,14 @@ impl ProcessedSymbol { all_equal = false; } } + multiple_sizes.push((possible_status.possible_cmp_id[index], *possible_size)); + index += 1; } let size = if all_equal{ SizeOption::Single(with_length) } else{ - SizeOption::Multiple(possible_status.possible_sizes) + SizeOption::Multiple(multiple_sizes) }; // Compute the signal location inside the component diff --git a/compiler/src/intermediate_representation/types.rs b/compiler/src/intermediate_representation/types.rs index 773dd760a..95b490031 100644 --- a/compiler/src/intermediate_representation/types.rs +++ b/compiler/src/intermediate_representation/types.rs @@ -17,7 +17,7 @@ impl ToString for ValueType { #[derive(Clone, PartialEq, Eq)] pub enum SizeOption{ Single(usize), - Multiple(Vec) + Multiple(Vec<(usize, usize)>) // The first value indicates the cmp_id, the second the size } #[derive(Clone, PartialEq, Eq)] From ee3a61424964900dd7699eba62bf6433f955796a Mon Sep 17 00:00:00 2001 From: Oleg Lomaka Date: Tue, 30 Jul 2024 05:34:22 -0400 Subject: [PATCH 147/189] Make some types public so that other projects can use Circom libraries to compile circuits and access their intermediate representation. --- .../address_type.rs | 18 +++++++++++++++++- .../branch_bucket.rs | 2 +- .../compute_bucket.rs | 2 +- compiler/src/lib.rs | 4 ++-- parser/Cargo.toml | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compiler/src/intermediate_representation/address_type.rs b/compiler/src/intermediate_representation/address_type.rs index ec05b3e90..cfdb3bc11 100644 --- a/compiler/src/intermediate_representation/address_type.rs +++ b/compiler/src/intermediate_representation/address_type.rs @@ -13,6 +13,22 @@ pub enum InputInformation { Input {status: StatusInput}, } +impl ToString for InputInformation { + fn to_string(&self) -> String { + use InputInformation::*; + match self { + NoInput => "NO_INPUT".to_string(), + Input { status } => { + match status { + StatusInput::Last => "LAST".to_string(), + StatusInput::NoLast => "NO_LAST".to_string(), + StatusInput::Unknown => "UNKNOWN".to_string(), + } + } + } + } +} + #[derive(Clone)] pub enum AddressType { Variable, @@ -26,7 +42,7 @@ impl ToString for AddressType { match self { Variable => "VARIABLE".to_string(), Signal => "SIGNAL".to_string(), - SubcmpSignal { cmp_address, .. } => format!("SUBCOMPONENT:{}", cmp_address.to_string()), + SubcmpSignal { cmp_address, input_information, .. } => format!("SUBCOMPONENT:{}:{}", cmp_address.to_string(), input_information.to_string()), } } } diff --git a/compiler/src/intermediate_representation/branch_bucket.rs b/compiler/src/intermediate_representation/branch_bucket.rs index 830b361ef..e0de88c19 100644 --- a/compiler/src/intermediate_representation/branch_bucket.rs +++ b/compiler/src/intermediate_representation/branch_bucket.rs @@ -46,7 +46,7 @@ impl ToString for BranchBucket { else_body = format!("{}{};", else_body, i.to_string()); } format!( - "IF(line:{},template_id:{},cond:{},if:{},else{})", + "IF(line:{},template_id:{},cond:{},if:{},else:{})", line, template_id, cond, if_body, else_body ) } diff --git a/compiler/src/intermediate_representation/compute_bucket.rs b/compiler/src/intermediate_representation/compute_bucket.rs index 1f14a1ffa..31a4498cb 100644 --- a/compiler/src/intermediate_representation/compute_bucket.rs +++ b/compiler/src/intermediate_representation/compute_bucket.rs @@ -3,7 +3,7 @@ use crate::translating_traits::*; use code_producers::c_elements::*; use code_producers::wasm_elements::*; -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum OperatorType { Mul, Div, diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index a9c4871e0..d7f2352ac 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -1,6 +1,6 @@ #[allow(dead_code)] -mod circuit_design; -mod intermediate_representation; +pub mod circuit_design; +pub mod intermediate_representation; mod ir_processing; pub extern crate num_bigint_dig as num_bigint; pub extern crate num_traits; diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 02a86510b..38c94f9bb 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -13,7 +13,7 @@ num-traits = "0.2.6" [dependencies] program_structure = {path = "../program_structure"} -lalrpop-util = "0.19.9" +lalrpop-util = { version="0.19.9", features = ["lexer"]} regex = "1.1.2" rustc-hex = "2.0.1" num-bigint-dig = "0.6.0" From addc61c5457c88cfb8a5445f4a9fb60b60fbd060 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Fri, 2 Aug 2024 18:25:26 +0300 Subject: [PATCH 148/189] add hardhat-zkit to community tools --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 022b4eab5..226ab62e9 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ TOOLS + [PICUS: a static analyzer for verifying weak and strong safety for circom circuits](https://github.com/Veridise/Picus) ++ [Hardhat-zkit - an ultimate environment for circom development](https://github.com/dl-solarity/hardhat-zkit) + More information about the notions of weak and strong safety in circom circuits [here](https://ieeexplore.ieee.org/document/10002421). [ico-website]: https://img.shields.io/website?up_color=blue&up_message=circom&url=https%3A%2F%2Fiden3.io%2Fcircom From 1513bec0b025fb761af4dc4cc2aebfa44d512cc6 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Wed, 7 Aug 2024 11:56:24 +0300 Subject: [PATCH 149/189] clean up readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 226ab62e9..5d6790777 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ TOOLS + [PICUS: a static analyzer for verifying weak and strong safety for circom circuits](https://github.com/Veridise/Picus) -+ [Hardhat-zkit - an ultimate environment for circom development](https://github.com/dl-solarity/hardhat-zkit) ++ [Hardhat-zkit: the ultimate typescript environment for circom development](https://github.com/dl-solarity/hardhat-zkit) More information about the notions of weak and strong safety in circom circuits [here](https://ieeexplore.ieee.org/document/10002421). From 31a87ff6e023f5e220c092d89a59a3d7825db8a9 Mon Sep 17 00:00:00 2001 From: Miguel Isabel Date: Thu, 22 Aug 2024 00:28:59 +0200 Subject: [PATCH 150/189] Update basic-operators.md Removing unnecesary brackets --- mkdocs/docs/circom-language/basic-operators.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs/docs/circom-language/basic-operators.md b/mkdocs/docs/circom-language/basic-operators.md index 089615a22..7ff89ffec 100644 --- a/mkdocs/docs/circom-language/basic-operators.md +++ b/mkdocs/docs/circom-language/basic-operators.md @@ -105,9 +105,9 @@ All bitwise operators are performed modulo p. For all ```k``` with ```0=< k <= p/2``` (integer division) we have that * ```x >> k = x/(2**k)``` -* ```x << k = (x*(2{**}k)~ & ~mask) % p ``` +* ```x << k = (x*(2**k)~ & ~mask) % p ``` -where b is the number of significant bits of p and mask is ```2{**}b - 1```. +where b is the number of significant bits of p and mask is ```2**b - 1```. For all ```k``` with ```p/2 +1<= k < p``` we have that From 570911a57afb3459b211921a9c6c699a9e9f5463 Mon Sep 17 00:00:00 2001 From: miguelis Date: Thu, 22 Aug 2024 11:03:47 +0200 Subject: [PATCH 151/189] Applying modulo field prime number to every constant in the AST --- circom/src/parser_user.rs | 5 ++++- parser/src/lang.lalrpop | 13 ++++++------- parser/src/lib.rs | 4 +++- parser/src/parser_logic.rs | 5 +++-- .../src/abstract_syntax_tree/ast_shortcuts.rs | 8 ++++---- .../src/abstract_syntax_tree/expression_builders.rs | 6 +++++- type_analysis/src/decorators/constants_handler.rs | 2 +- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/circom/src/parser_user.rs b/circom/src/parser_user.rs index cd93e3b52..c77d711b9 100644 --- a/circom/src/parser_user.rs +++ b/circom/src/parser_user.rs @@ -1,4 +1,5 @@ use super::input_user::Input; +use program_structure::constants::UsefulConstants; use program_structure::error_definition::Report; use program_structure::program_archive::ProgramArchive; use crate::VERSION; @@ -6,7 +7,9 @@ use crate::VERSION; pub fn parse_project(input_info: &Input) -> Result { let initial_file = input_info.input_file().to_string(); - let result_program_archive = parser::run_parser(initial_file, VERSION, input_info.get_link_libraries().to_vec()); + //We get the prime number from the input + let prime = UsefulConstants::new(&input_info.prime()).get_p().clone(); + let result_program_archive = parser::run_parser(initial_file, VERSION, input_info.get_link_libraries().to_vec(), &prime); match result_program_archive { Result::Err((file_library, report_collection)) => { Report::print_reports(&report_collection, &file_library); diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index 90dc96f74..7a0db7940 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -9,8 +9,7 @@ use program_structure::ast::produce_report; use program_structure::error_definition::Report; use program_structure::error_code::ReportCode; -grammar<'err>(file_id: usize, errors:&'err mut Vec); - +grammar<'err>(file_id: usize, errors:&'err mut Vec, field: &BigInt); CommaSepList:Vec = { ",")*> => { e.push(t); @@ -342,10 +341,10 @@ ParseSubstitution : Statement = { => ast_shortcuts::assign_with_op_shortcut(ExpressionInfixOpcode::BitXor,Meta::new(s,e),variable,rhe), "++" - => ast_shortcuts::plusplus(Meta::new(s,e),variable), + => ast_shortcuts::plusplus(Meta::new(s,e),variable, field), "--" - => ast_shortcuts::subsub(Meta::new(s,e),variable), + => ast_shortcuts::subsub(Meta::new(s,e),variable, field), "++" => { @@ -653,10 +652,10 @@ Expression0: Expression = { => build_variable(Meta::new(s,e),"_".to_string(),Vec::new()), - => build_number(Meta::new(s,e),value), + => build_number(Meta::new(s,e),value, field), - => build_number(Meta::new(s,e),value), + => build_number(Meta::new(s,e),value, field), "(" ")", @@ -664,7 +663,7 @@ Expression0: Expression = { ParseError::UnrecognizedToken { ref token, .. } => { errors.push(produce_report(ReportCode::IllegalExpression, token.0..token.2, file_id)); // doesn't matter - build_number(Meta::new(0,0),BigInt::from(0)) + build_number(Meta::new(0,0),BigInt::from(0), field) } _ => unreachable!(), } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 825e385fd..e9a45b5bb 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -12,6 +12,7 @@ mod parser_logic; mod syntax_sugar_remover; use include_logic::{FileStack, IncludesGraph}; +use num_bigint::BigInt; use program_structure::ast::{produce_compiler_version_report, produce_report, produce_report_with_message, produce_version_warning_report, Expression}; use program_structure::error_code::ReportCode; use program_structure::error_definition::ReportCollection; @@ -60,6 +61,7 @@ pub fn run_parser( file: String, version: &str, link_libraries: Vec, + field: &BigInt, ) -> Result<(ProgramArchive, ReportCollection), (FileLibrary, ReportCollection)> { let mut file_library = FileLibrary::new(); let mut definitions = Vec::new(); @@ -78,7 +80,7 @@ pub fn run_parser( } let file_id = file_library.add_file(path.clone(), src.clone()); let program = - parser_logic::parse_file(&src, file_id).map_err(|e| (file_library.clone(), e))?; + parser_logic::parse_file(&src, file_id, field).map_err(|e| (file_library.clone(), e))?; if let Some(main) = program.main_component { main_components.push((file_id, main, program.custom_gates)); } diff --git a/parser/src/parser_logic.rs b/parser/src/parser_logic.rs index a572c53e7..04a28b772 100644 --- a/parser/src/parser_logic.rs +++ b/parser/src/parser_logic.rs @@ -1,4 +1,5 @@ use super::lang; +use num_bigint::BigInt; use program_structure::ast::{AST}; use program_structure::ast::produce_report; use program_structure::error_code::ReportCode; @@ -83,14 +84,14 @@ pub fn preprocess(expr: &str, file_id: FileID) -> Result Result { +pub fn parse_file(src: &str, file_id: FileID, field: &BigInt) -> Result { use lalrpop_util::ParseError::*; let mut errors = Vec::new(); let preprocess = preprocess(src, file_id)?; let ast = lang::ParseAstParser::new() - .parse(file_id, &mut errors, &preprocess) + .parse(file_id, &mut errors, field, &preprocess) // TODO: is this always fatal? .map_err(|parse_error| match parse_error { InvalidToken { location } => diff --git a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs index 08fb66c0a..ad4c73818 100644 --- a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs +++ b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs @@ -27,13 +27,13 @@ pub fn assign_with_op_shortcut( build_substitution(meta, var, access, AssignOp::AssignVar, infix) } -pub fn plusplus(meta: Meta, variable: (String, Vec)) -> Statement { - let one = build_number(meta.clone(), BigInt::from(1)); +pub fn plusplus(meta: Meta, variable: (String, Vec), field: &BigInt) -> Statement { + let one = build_number(meta.clone(), BigInt::from(1), field); assign_with_op_shortcut(ExpressionInfixOpcode::Add, meta, variable, one) } -pub fn subsub(meta: Meta, variable: (String, Vec)) -> Statement { - let one = build_number(meta.clone(), BigInt::from(1)); +pub fn subsub(meta: Meta, variable: (String, Vec), field: &BigInt) -> Statement { + let one = build_number(meta.clone(), BigInt::from(1), field); assign_with_op_shortcut(ExpressionInfixOpcode::Sub, meta, variable, one) } diff --git a/program_structure/src/abstract_syntax_tree/expression_builders.rs b/program_structure/src/abstract_syntax_tree/expression_builders.rs index 0e7d2a0ba..ed88cef48 100644 --- a/program_structure/src/abstract_syntax_tree/expression_builders.rs +++ b/program_structure/src/abstract_syntax_tree/expression_builders.rs @@ -43,7 +43,11 @@ pub fn build_variable(meta: Meta, name: String, access: Vec) -> Expressi Variable { meta, name, access } } -pub fn build_number(meta: Meta, value: BigInt) -> Expression { +pub fn build_number(meta: Meta, value: BigInt, field: &BigInt) -> Expression { + Expression::Number(meta, value % field) +} + +pub fn build_number_without_field(meta: Meta, value: BigInt) -> Expression { Expression::Number(meta, value) } diff --git a/type_analysis/src/decorators/constants_handler.rs b/type_analysis/src/decorators/constants_handler.rs index bbffe78d7..a16180625 100644 --- a/type_analysis/src/decorators/constants_handler.rs +++ b/type_analysis/src/decorators/constants_handler.rs @@ -420,7 +420,7 @@ fn expand_expression(expr: Expression, environment: &ExpressionHolder) -> Expres } fn expand_number(meta: Meta, value: BigInt) -> Expression { - build_number(meta, value) + build_number_without_field(meta, value) } fn expand_array( From 9a4215bce3ed9d138dae2352f625b04ea4a5b95c Mon Sep 17 00:00:00 2001 From: miguelis Date: Thu, 22 Aug 2024 11:15:04 +0200 Subject: [PATCH 152/189] Remove unnecessary brackets and fix the formula for the bitwise left shift operator in the basic-operators.md file. --- mkdocs/docs/circom-language/basic-operators.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs/docs/circom-language/basic-operators.md b/mkdocs/docs/circom-language/basic-operators.md index 089615a22..7ff89ffec 100644 --- a/mkdocs/docs/circom-language/basic-operators.md +++ b/mkdocs/docs/circom-language/basic-operators.md @@ -105,9 +105,9 @@ All bitwise operators are performed modulo p. For all ```k``` with ```0=< k <= p/2``` (integer division) we have that * ```x >> k = x/(2**k)``` -* ```x << k = (x*(2{**}k)~ & ~mask) % p ``` +* ```x << k = (x*(2**k)~ & ~mask) % p ``` -where b is the number of significant bits of p and mask is ```2{**}b - 1```. +where b is the number of significant bits of p and mask is ```2**b - 1```. For all ```k``` with ```p/2 +1<= k < p``` we have that From b1f795d95bb2b9610b99c794597f4f6b41a02640 Mon Sep 17 00:00:00 2001 From: miguelis Date: Thu, 22 Aug 2024 11:28:51 +0200 Subject: [PATCH 153/189] Refactor complement_254 function to handle sign correctly --- circom_algebra/src/modular_arithmetic.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/circom_algebra/src/modular_arithmetic.rs b/circom_algebra/src/modular_arithmetic.rs index 4eb9cc728..f1d5790f2 100644 --- a/circom_algebra/src/modular_arithmetic.rs +++ b/circom_algebra/src/modular_arithmetic.rs @@ -95,6 +95,7 @@ pub fn multi_inv(values: &Vec, field: &BigInt) -> Vec{ // 254 bit complement pub fn complement_254(elem: &BigInt, field: &BigInt) -> BigInt { let (sign, mut bit_repr) = bit_representation(elem); + let new_sign = if elem == &BigInt::from(0) { Sign::Plus } else { sign}; while bit_repr.len() > 254 { bit_repr.pop(); } @@ -104,7 +105,7 @@ pub fn complement_254(elem: &BigInt, field: &BigInt) -> BigInt { for bit in &mut bit_repr { *bit = if *bit == 0 { 1 } else { 0 }; } - let cp = BigInt::from_radix_le(sign, &bit_repr, 2).unwrap(); + let cp = BigInt::from_radix_le(new_sign, &bit_repr, 2).unwrap(); modulus(&cp, field) } From 620c25de281b80f6314156eda19163a7e8aa722f Mon Sep 17 00:00:00 2001 From: alrubio Date: Fri, 20 Sep 2024 07:24:04 +0200 Subject: [PATCH 154/189] extending dynamic template output array size to wasm --- compiler/src/circuit_design/template.rs | 1 + .../call_bucket.rs | 46 +++++++++++++------ .../store_bucket.rs | 42 +++++++++++------ 3 files changed, 63 insertions(+), 26 deletions(-) diff --git a/compiler/src/circuit_design/template.rs b/compiler/src/circuit_design/template.rs index 806108778..7b9c4b687 100644 --- a/compiler/src/circuit_design/template.rs +++ b/compiler/src/circuit_design/template.rs @@ -99,6 +99,7 @@ impl WriteWasm for TemplateCodeInfo { instructions.push(format!(" (local {} i32)", producer.get_create_loop_offset_tag())); instructions.push(format!(" (local {} i32)", producer.get_create_loop_counter_tag())); instructions.push(format!(" (local {} i32)", producer.get_merror_tag())); + instructions.push(format!(" (local {} i32)", producer.get_result_size_tag())); // used when calling functions assigned to inputs of subcomponents let local_info_size_u32 = producer.get_local_info_size_u32(); // in the future we can add some info like pointer to run father or text father //set lvar (start of auxiliar memory for vars) instructions.push(set_constant("0")); diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 8b5c83ee2..85470c2cc 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -98,6 +98,7 @@ impl WriteWasm for CallBucket { let arg_size = match &self.argument_types[i].size{ SizeOption::Single(value) => *value, SizeOption::Multiple(values) => { + assert!(false); //should never be the case! values[0].1 } }; @@ -222,8 +223,9 @@ impl WriteWasm for CallBucket { instructions.push(mul32()); instructions.push(add32()); instructions.push(load32(None)); //subcomponent block - instructions.push(set_local(producer.get_sub_cmp_tag())); - instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(tee_local(producer.get_sub_cmp_tag())); + //instructions.push(set_local(producer.get_sub_cmp_tag())); + //instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(load32(None)); // get template id A instructions.push(set_constant("4")); //size in byte of i32 instructions.push(mul32()); @@ -350,16 +352,27 @@ impl WriteWasm for CallBucket { } } } - // TODO: We compute the possible sizes, case multiple size - // Now in case Multiple we just return the first value - // See below case C (complete) - let data_size = match &data.context.size{ - SizeOption::Single(value) => *value, - SizeOption::Multiple(values) => { - values[0].1 - } - }; - instructions.push(set_constant(&data_size.to_string())); + // We check if we have to compute the possible sizes, case multiple size + match &data.context.size{ + SizeOption::Single(value) => { + instructions.push(set_constant(&value.to_string())); + } + SizeOption::Multiple(values) => { //create a nested if-else with all cases + for i in 0..values.len() { + instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(load32(None)); // get template id + instructions.push(set_constant(&values[i].0.to_string())); //Add id in list + instructions.push(add_if()); + instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list + instructions.push(add_else()); + } + instructions.push(set_constant("0")); //default o complete the last else + for _i in 0..values.len() { + instructions.push(add_end()); + } + instructions.push(tee_local(producer.get_result_size_tag())); + } + }; instructions.push(call(&format!("${}", self.symbol))); instructions.push(tee_local(producer.get_merror_tag())); instructions.push(add_if()); @@ -381,7 +394,14 @@ impl WriteWasm for CallBucket { instructions.push(load32(Some( &producer.get_input_counter_address_in_component().to_string(), ))); //remaining inputs to be set - instructions.push(set_constant(&data_size.to_string())); + match &data.context.size{ + SizeOption::Single(value) => { + instructions.push(set_constant(&value.to_string())); + } + SizeOption::Multiple(_) => { + instructions.push(get_local(producer.get_result_size_tag())); + } + }; instructions.push(sub32()); instructions.push(store32(Some( &producer.get_input_counter_address_in_component().to_string(), diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index b564b0a70..eed87777b 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -54,13 +54,13 @@ impl WriteWasm for StoreBucket { use code_producers::wasm_elements::wasm_code_generator::*; let mut instructions = vec![]; - // TODO: We compute the possible sizes, case multiple size - // Now in case Multiple we just return the first value - // See below case C (complete) - let size = match &self.context.size{ - SizeOption::Single(value) => *value, + // We check if we have to compute the possible sizes, case multiple size + let mut is_multiple = false; + let (size,values) = match &self.context.size{ + SizeOption::Single(value) => (*value,vec![]), SizeOption::Multiple(values) => { - values[0].1 + is_multiple = true; + (values.len(),values.clone()) } }; @@ -101,8 +101,9 @@ impl WriteWasm for StoreBucket { instructions.push(mul32()); instructions.push(add32()); instructions.push(load32(None)); //subcomponent block - instructions.push(set_local(producer.get_sub_cmp_tag())); - instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(tee_local(producer.get_sub_cmp_tag())); + //instructions.push(set_local(producer.get_sub_cmp_tag())); + //instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(set_constant( &producer.get_signal_start_address_in_component().to_string(), )); @@ -132,7 +133,7 @@ impl WriteWasm for StoreBucket { instructions.push(tee_local(producer.get_sub_cmp_tag())); //instructions.push(set_local(producer.get_sub_cmp_tag())); //instructions.push(get_local(producer.get_sub_cmp_tag())); - instructions.push(load32(None)); // get template id A + instructions.push(load32(None)); // get template id instructions.push(set_constant("4")); //size in byte of i32 instructions.push(mul32()); instructions.push(load32(Some( @@ -261,17 +262,32 @@ impl WriteWasm for StoreBucket { if producer.needs_comments() { instructions.push(";; getting src".to_string()); } - if size > 1 { + if is_multiple || size > 1 { instructions.push(set_local(producer.get_store_aux_1_tag())); } let mut instructions_src = self.src.produce_wasm(producer); instructions.append(&mut instructions_src); - if size == 1 { + if !is_multiple && size == 1 { instructions.push(call("$Fr_copy")); } else { instructions.push(set_local(producer.get_store_aux_2_tag())); - instructions.push(set_constant(&size.to_string())); - instructions.push(set_local(producer.get_copy_counter_tag())); + if is_multiple { //create a nested if-else with all cases + for i in 0..size { + instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(load32(None)); // get template id + instructions.push(set_constant(&values[i].0.to_string())); //Add id in list + instructions.push(add_if()); + instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list + instructions.push(add_else()); + } + instructions.push(set_constant("0")); //default o complete the last else + for _i in 0..size { + instructions.push(add_end()); + } + } else { + instructions.push(set_constant(&size.to_string())); + } + instructions.push(set_local(producer.get_copy_counter_tag())); instructions.push(add_block()); instructions.push(add_loop()); instructions.push(get_local(producer.get_copy_counter_tag())); From dae7e33e38fadfaeb4581134e65a7835cbeb9564 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 23 Sep 2024 00:18:12 +0200 Subject: [PATCH 155/189] solving issue assignment sizes --- compiler/src/hir/type_inference.rs | 26 ++++++-- .../store_bucket.rs | 23 ++++++- .../intermediate_representation/translate.rs | 66 +++++++++++++++++-- 3 files changed, 104 insertions(+), 11 deletions(-) diff --git a/compiler/src/hir/type_inference.rs b/compiler/src/hir/type_inference.rs index 02b82ee9d..ae70002bc 100644 --- a/compiler/src/hir/type_inference.rs +++ b/compiler/src/hir/type_inference.rs @@ -2,7 +2,7 @@ use super::analysis_utilities::*; use super::very_concrete_program::*; use program_structure::ast::*; use std::collections::HashSet; -use num_traits::{ToPrimitive}; +use num_traits::ToPrimitive; struct SearchInfo { environment: E, @@ -75,8 +75,16 @@ fn infer_type_block(stmt: &Statement, state: &State, context: &mut SearchInfo) - let mut returns = Option::None; let mut index = 0; context.environment.add_variable_block(); - while index < stmts.len() && returns.is_none() { - returns = infer_type_stmt(&stmts[index], state, context); + while index < stmts.len(){ + let new_value = infer_type_stmt(&stmts[index], state, context); + if new_value.is_some(){ + if returns.is_none(){ + returns = new_value; + } else{ + let max = std::cmp::max(new_value.unwrap(), returns.unwrap()); + returns = Some(max); + } + } index += 1; } context.environment.remove_variable_block(); @@ -109,14 +117,20 @@ fn infer_type_conditional( if let IfThenElse { if_case, else_case, .. } = stmt { let mut returns = infer_type_stmt(if_case, state, context); if let Option::Some(s) = else_case { - if returns.is_none() { - returns = infer_type_stmt(s, state, context); + let else_returns = infer_type_stmt(s, state, context); + if else_returns.is_some(){ + if returns.is_none(){ + returns = else_returns; + } else{ + let max = std::cmp::max(returns.unwrap(), else_returns.unwrap()); + returns = Some(max); + } } } returns } else { unreachable!(); - } + } } fn infer_type_while(stmt: &Statement, state: &State, context: &mut SearchInfo) -> Option { diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index eed87777b..b3334b4ea 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -8,6 +8,7 @@ pub struct StoreBucket { pub line: usize, pub message_id: usize, pub context: InstrContext, + pub src_context: InstrContext, pub dest_is_output: bool, pub dest_address_type: AddressType, pub dest: LocationRule, @@ -406,7 +407,7 @@ impl WriteC for StoreBucket { prologue.push(format!("uint {} = {};", cmp_index_ref, cmp_index)); } // We compute the possible sizes, case multiple sizes - let size = match &self.context.size{ + let expr_size = match &self.context.size{ SizeOption::Single(value) => value.to_string(), SizeOption::Multiple(values) => { prologue.push(format!("std::map size_store {};", @@ -417,6 +418,26 @@ impl WriteC for StoreBucket { format!("size_store[{}]", temp_id) } }; + // We compute the possible sizes for the src, case multiple sizes + let src_size = match &self.src_context.size{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + prologue.push(format!("std::map size_src_store {};", + set_list_tuple(values.clone()) + )); + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_src_store[{}]", temp_id) + } + }; + let size = match(&self.context.size, &self.src_context.size){ + (SizeOption::Single(v1), SizeOption::Single(v2)) =>{ + std::cmp::min(v1, v2).to_string() + }, + (_, _) => { + format!("std::min({}, {})", expr_size, src_size) + } + }; let ((mut dest_prologue, dest_index), my_template_header) = if let LocationRule::Indexed { location, template_header } = &self.dest { diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index f5a6f3803..c4184768a 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -276,6 +276,8 @@ fn initialize_constants(state: &mut State, constants: Vec) { dest_address_type: AddressType::Variable, dest: LocationRule::Indexed { location: full_address, template_header: None }, context: InstrContext { size: SizeOption::Single(1) }, + src_context: InstrContext {size: SizeOption::Single(1)}, + src: content, } .allocate(); @@ -610,8 +612,9 @@ fn translate_standard_case( state: &mut State, context: &Context, ) -> InstructionPointer { + let src_size: SizeOption = get_expression_size(&info.src, state, context); let src = translate_expression(info.src, state, context); - info.prc_symbol.into_store(src, state) + info.prc_symbol.into_store(src, state, src_size) } // End of substitution utils @@ -741,11 +744,17 @@ fn translate_log(stmt: Statement, state: &mut State, context: &Context) { fn translate_return(stmt: Statement, state: &mut State, context: &Context) { use Statement::Return; if let Return { meta, value, .. } = stmt { - let return_type = context.functions.get(&context.translating).unwrap(); + + let src_size: SizeOption = get_expression_size(&value, state, context); + // it is always a Single, not possible multiple options --> ENSURE + let with_size = match src_size{ + SizeOption::Single(v) => v, + SizeOption::Multiple(_) => unreachable!("Not possible multiple sizes"), + }; let return_bucket = ReturnBucket { line: context.files.get_line(meta.start, meta.get_file_id()).unwrap(), message_id: state.message_id, - with_size: return_type.iter().fold(1, |p, c| p * (*c)), + with_size, value: translate_expression(value, state, context), } .allocate(); @@ -1363,7 +1372,7 @@ impl ProcessedSymbol { .allocate() } - fn into_store(self, src: InstructionPointer, state: &State) -> InstructionPointer { + fn into_store(self, src: InstructionPointer, state: &State, src_size: SizeOption) -> InstructionPointer { if let Option::Some(signal) = self.signal { let dest_type = AddressType::SubcmpSignal { cmp_address: compute_full_address( @@ -1387,6 +1396,7 @@ impl ProcessedSymbol { line: self.line, message_id: self.message_id, context: InstrContext { size: self.length }, + src_context: InstrContext {size: src_size}, dest_is_output: false, dest_address_type: dest_type, } @@ -1412,6 +1422,7 @@ impl ProcessedSymbol { dest_is_output: self.signal_type.map_or(false, |t| t == SignalType::Output), dest: LocationRule::Indexed { location: address, template_header: None }, context: InstrContext { size: self.length }, + src_context: InstrContext {size: src_size}, } .allocate() } @@ -1757,6 +1768,51 @@ fn translate_call_arguments( info } +/******** Auxiliar functions to get the size of an expression ************/ + +fn get_expression_size(expression: &Expression, state: &mut State, context: &Context) -> SizeOption{ + if expression.is_infix() { + SizeOption::Single(1) + } else if expression.is_prefix() { + SizeOption::Single(1) + } else if expression.is_variable() { + get_variable_size(expression, state, context) + } else if expression.is_number() { + SizeOption::Single(1) + } else if expression.is_call() { + unreachable!("This case should be unreachable") + } else if expression.is_array() { + unreachable!("This expression is syntactic sugar") + } else if expression.is_switch() { + unreachable!("This expression is syntactic sugar") + } else { + unreachable!("Unknown expression") + } +} + +fn get_variable_size( + expression: &Expression, + state: &mut State, + context: &Context, +) -> SizeOption { + use Expression::Variable; + if let Variable { meta, name, access, .. } = expression { + let tag_access = check_tag_access(&name, &access, state); + if tag_access.is_some(){ + SizeOption::Single(1) + } else{ + let def = SymbolDef { meta: meta.clone(), symbol: name.clone(), acc: access.clone() }; + ProcessedSymbol::new(def, state, context).length + } + } else { + unreachable!() + } +} + + +/*************************************************************/ + + pub struct ParallelClusters{ pub positions_to_parallel: BTreeMap, bool>, pub uniform_parallel_value: Option, @@ -1836,3 +1892,5 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { string_table : state.string_table } } + + From c05e941a8c393501163caafc28aa56cbf0f1b071 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 23 Sep 2024 11:40:12 +0200 Subject: [PATCH 156/189] case return solved --- compiler/src/intermediate_representation/return_bucket.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/intermediate_representation/return_bucket.rs b/compiler/src/intermediate_representation/return_bucket.rs index b4b541e41..6ecec4570 100644 --- a/compiler/src/intermediate_representation/return_bucket.rs +++ b/compiler/src/intermediate_representation/return_bucket.rs @@ -100,9 +100,12 @@ impl WriteC for ReturnBucket { instructions.push("// return bucket".to_string()); let (mut instructions_value, src) = self.value.produce_c(producer, parallel); instructions.append(&mut instructions_value); + if self.with_size > 1 { + let final_size = format!("std::min({},{})", self.with_size, FUNCTION_DESTINATION_SIZE); + let copy_arguments = - vec![FUNCTION_DESTINATION.to_string(), src, FUNCTION_DESTINATION_SIZE.to_string()]; + vec![FUNCTION_DESTINATION.to_string(), src, final_size]; instructions.push(format!("{};", build_call("Fr_copyn".to_string(), copy_arguments))); } else { let copy_arguments = vec![FUNCTION_DESTINATION.to_string(), src]; From e9f47b1f15be8db03bff5728375fed4cfa0e9748 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 23 Sep 2024 12:11:39 +0200 Subject: [PATCH 157/189] solving case multiple in src --- .../store_bucket.rs | 11 +++- .../intermediate_representation/translate.rs | 50 ++++++++++++++----- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index b3334b4ea..f9ad5e179 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -11,6 +11,7 @@ pub struct StoreBucket { pub src_context: InstrContext, pub dest_is_output: bool, pub dest_address_type: AddressType, + pub src_address_type: Option, pub dest: LocationRule, pub src: InstructionPointer, } @@ -397,7 +398,9 @@ impl WriteC for StoreBucket { use c_code_generator::*; let mut prologue = vec![]; let cmp_index_ref = "cmp_index_ref".to_string(); + let src_index_ref = "aux_src_index".to_string(); let aux_dest_index = "aux_dest_index".to_string(); + //prologue.push(format!("// store bucket. Line {}", self.line)); //.to_string() if let AddressType::SubcmpSignal { cmp_address, .. } = &self.dest_address_type { @@ -406,6 +409,12 @@ impl WriteC for StoreBucket { prologue.push(format!("{{")); prologue.push(format!("uint {} = {};", cmp_index_ref, cmp_index)); } + if self.src_address_type.is_some() { + let (mut cmp_prologue, cmp_index) = self.src_address_type.as_ref().unwrap().produce_c(producer, parallel); + prologue.append(&mut cmp_prologue); + prologue.push(format!("{{")); + prologue.push(format!("uint {} = {};", src_index_ref, cmp_index)); + } // We compute the possible sizes, case multiple sizes let expr_size = match &self.context.size{ SizeOption::Single(value) => value.to_string(), @@ -425,7 +434,7 @@ impl WriteC for StoreBucket { prologue.push(format!("std::map size_src_store {};", set_list_tuple(values.clone()) )); - let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,src_index_ref); let temp_id = template_id_in_component(sub_component_pos_in_memory); format!("size_src_store[{}]", temp_id) } diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index c4184768a..95d9b098c 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -277,7 +277,7 @@ fn initialize_constants(state: &mut State, constants: Vec) { dest: LocationRule::Indexed { location: full_address, template_header: None }, context: InstrContext { size: SizeOption::Single(1) }, src_context: InstrContext {size: SizeOption::Single(1)}, - + src_address_type: None, src: content, } .allocate(); @@ -612,9 +612,9 @@ fn translate_standard_case( state: &mut State, context: &Context, ) -> InstructionPointer { - let src_size: SizeOption = get_expression_size(&info.src, state, context); + let (src_size, src_address)= get_expression_size(&info.src, state, context); let src = translate_expression(info.src, state, context); - info.prc_symbol.into_store(src, state, src_size) + info.prc_symbol.into_store(src, state, src_size, src_address) } // End of substitution utils @@ -745,7 +745,7 @@ fn translate_return(stmt: Statement, state: &mut State, context: &Context) { use Statement::Return; if let Return { meta, value, .. } = stmt { - let src_size: SizeOption = get_expression_size(&value, state, context); + let (src_size, _) = get_expression_size(&value, state, context); // it is always a Single, not possible multiple options --> ENSURE let with_size = match src_size{ SizeOption::Single(v) => v, @@ -1372,7 +1372,13 @@ impl ProcessedSymbol { .allocate() } - fn into_store(self, src: InstructionPointer, state: &State, src_size: SizeOption) -> InstructionPointer { + fn into_store( + self, src: + InstructionPointer, + state: &State, + src_size: SizeOption, + src_address: Option + ) -> InstructionPointer { if let Option::Some(signal) = self.signal { let dest_type = AddressType::SubcmpSignal { cmp_address: compute_full_address( @@ -1399,6 +1405,7 @@ impl ProcessedSymbol { src_context: InstrContext {size: src_size}, dest_is_output: false, dest_address_type: dest_type, + src_address_type: src_address } .allocate() } else { @@ -1423,6 +1430,7 @@ impl ProcessedSymbol { dest: LocationRule::Indexed { location: address, template_header: None }, context: InstrContext { size: self.length }, src_context: InstrContext {size: src_size}, + src_address_type: src_address } .allocate() } @@ -1770,15 +1778,16 @@ fn translate_call_arguments( /******** Auxiliar functions to get the size of an expression ************/ -fn get_expression_size(expression: &Expression, state: &mut State, context: &Context) -> SizeOption{ +fn get_expression_size(expression: &Expression, state: &mut State, context: &Context) + -> (SizeOption, Option){ if expression.is_infix() { - SizeOption::Single(1) + (SizeOption::Single(1), None) } else if expression.is_prefix() { - SizeOption::Single(1) + (SizeOption::Single(1), None) } else if expression.is_variable() { get_variable_size(expression, state, context) } else if expression.is_number() { - SizeOption::Single(1) + (SizeOption::Single(1), None) } else if expression.is_call() { unreachable!("This case should be unreachable") } else if expression.is_array() { @@ -1794,15 +1803,32 @@ fn get_variable_size( expression: &Expression, state: &mut State, context: &Context, -) -> SizeOption { +) -> (SizeOption, Option) { use Expression::Variable; if let Variable { meta, name, access, .. } = expression { let tag_access = check_tag_access(&name, &access, state); if tag_access.is_some(){ - SizeOption::Single(1) + (SizeOption::Single(1), None) } else{ let def = SymbolDef { meta: meta.clone(), symbol: name.clone(), acc: access.clone() }; - ProcessedSymbol::new(def, state, context).length + let aux_symbol = ProcessedSymbol::new(def, state, context); + + let size = aux_symbol.length; + let possible_address = match size{ + SizeOption::Multiple(_)=>{ + let address = compute_full_address( + state, + aux_symbol.symbol.access_instruction, + aux_symbol.symbol_dimensions, + aux_symbol.symbol_size, + aux_symbol.bus_accesses, + aux_symbol.before_signal, + ); + Some(address) + }, + SizeOption::Single(_) => None + }; + (size, possible_address) } } else { unreachable!() From 9cb396e1217b97cdd343f66466469327497bacd0 Mon Sep 17 00:00:00 2001 From: alrubio Date: Mon, 23 Sep 2024 12:15:06 +0200 Subject: [PATCH 158/189] inpunt counter bug fixed and minor changes --- .../call_bucket.rs | 9 ++-- .../store_bucket.rs | 52 ++++++++++++------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 85470c2cc..4971f5382 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -97,9 +97,9 @@ impl WriteWasm for CallBucket { // See below case C (complete) let arg_size = match &self.argument_types[i].size{ SizeOption::Single(value) => *value, - SizeOption::Multiple(values) => { + SizeOption::Multiple(_value) => { assert!(false); //should never be the case! - values[0].1 + 0 } }; if arg_size > 1 { @@ -490,8 +490,9 @@ impl WriteC for CallBucket { // TODO, CASE CALL ARGUMENTS let size = match &self.argument_types[i].size{ SizeOption::Single(value) => *value, - SizeOption::Multiple(values) => { - values[0].1 + SizeOption::Multiple(_values) => { + assert!(false); //should never be the case! + 0 } }; if size > 1 { diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index b3334b4ea..735d33b97 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -56,16 +56,24 @@ impl WriteWasm for StoreBucket { let mut instructions = vec![]; // We check if we have to compute the possible sizes, case multiple size - let mut is_multiple = false; - let (size,values) = match &self.context.size{ + let mut is_multiple_dest = false; + let (size_dest,values_dest) = match &self.context.size{ SizeOption::Single(value) => (*value,vec![]), SizeOption::Multiple(values) => { - is_multiple = true; + is_multiple_dest = true; (values.len(),values.clone()) } }; - - if size == 0 { +/* let mut is_multiple_src = false; + let (size_src,values_dest_src) = match &self.src_context.size{ + SizeOption::Single(value) => (*value,vec![]), + SizeOption::Multiple(values) => { + is_multiple_src = true; + (values.len(),values.clone()) + } + }; +*/ + if size_dest == 0 {//size_src == 0 || return vec![]; } if producer.needs_comments() { @@ -263,30 +271,31 @@ impl WriteWasm for StoreBucket { if producer.needs_comments() { instructions.push(";; getting src".to_string()); } - if is_multiple || size > 1 { - instructions.push(set_local(producer.get_store_aux_1_tag())); - } - let mut instructions_src = self.src.produce_wasm(producer); - instructions.append(&mut instructions_src); - if !is_multiple && size == 1 { + if !is_multiple_dest && size_dest == 1 { // ) || (!is_multiple_src && size_src == 1) { + let mut instructions_src = self.src.produce_wasm(producer); + instructions.append(&mut instructions_src); instructions.push(call("$Fr_copy")); } else { + instructions.push(set_local(producer.get_store_aux_1_tag())); + let mut instructions_src = self.src.produce_wasm(producer); + instructions.append(&mut instructions_src); instructions.push(set_local(producer.get_store_aux_2_tag())); - if is_multiple { //create a nested if-else with all cases - for i in 0..size { + if is_multiple_dest { //create a nested if-else with all cases + for i in 0..size_dest { instructions.push(get_local(producer.get_sub_cmp_tag())); instructions.push(load32(None)); // get template id - instructions.push(set_constant(&values[i].0.to_string())); //Add id in list + instructions.push(set_constant(&values_dest[i].0.to_string())); //Add id in list instructions.push(add_if()); - instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list + instructions.push(set_constant(&values_dest[i].1.to_string())); //Add corresponding size in list instructions.push(add_else()); } instructions.push(set_constant("0")); //default o complete the last else - for _i in 0..size { + for _i in 0..size_dest { instructions.push(add_end()); } + instructions.push(tee_local(producer.get_result_size_tag())); } else { - instructions.push(set_constant(&size.to_string())); + instructions.push(set_constant(&size_dest.to_string())); } instructions.push(set_local(producer.get_copy_counter_tag())); instructions.push(add_block()); @@ -325,7 +334,14 @@ impl WriteWasm for StoreBucket { instructions.push(load32(Some( &producer.get_input_counter_address_in_component().to_string(), ))); //remaining inputs to be set - instructions.push(set_constant(&size.to_string())); + match &self.context.size{ + SizeOption::Single(value) => { + instructions.push(set_constant(&value.to_string())); + } + SizeOption::Multiple(_) => { + instructions.push(get_local(producer.get_result_size_tag())); + } + }; instructions.push(sub32()); instructions.push(store32(Some( &producer.get_input_counter_address_in_component().to_string(), From 006d7b8de7fffe8b1131eaa488ba1f820b5f3685 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 24 Sep 2024 15:28:45 +0200 Subject: [PATCH 159/189] solving minor case call and error unknown accesses to components --- compiler/src/intermediate_representation/call_bucket.rs | 3 +-- constraint_generation/src/execute.rs | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 85470c2cc..daf34e8d9 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -533,8 +533,7 @@ impl WriteC for CallBucket { let size = match &data.context.size{ SizeOption::Single(value) => value.to_string(), SizeOption::Multiple(values) => { - prologue.push(format!("int size_store[{}] = {};", - values.len(), + prologue.push(format!("std::map size_store {};", set_list_tuple(values.to_vec()) )); let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 4cda5a301..87d5afe46 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1614,6 +1614,12 @@ fn perform_assign( &Vec::new(), ) } else{ + // in case the component is undef then we do not perform any changes + // TODO: possible improvement? + if accessing_information.undefined{ + return Ok(None) + } + ComponentSlice::get_mut_reference_to_single_value( component_slice, &accessing_information.array_access, From 27bff309f75cbeaa4d1ca4c312b2e32d7d0bc467 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 24 Sep 2024 22:43:07 +0200 Subject: [PATCH 160/189] minors --- compiler/src/intermediate_representation/load_bucket.rs | 5 ++--- compiler/src/intermediate_representation/store_bucket.rs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index cced54c90..9e4b523da 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -339,9 +339,8 @@ impl WriteC for LoadBucket { let size = match &self.context.size{ SizeOption::Single(value) => value.to_string(), SizeOption::Multiple(values) => { - prologue.push(format!("int size_load[{}] = {};", - values.len(), - set_list_tuple(values.to_vec()) + prologue.push(format!("std::map size_store {};", + set_list_tuple(values.clone()) )); let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); let temp_id = template_id_in_component(sub_component_pos_in_memory); diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 1794493ba..d93070483 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -428,7 +428,6 @@ impl WriteC for StoreBucket { if self.src_address_type.is_some() { let (mut cmp_prologue, cmp_index) = self.src_address_type.as_ref().unwrap().produce_c(producer, parallel); prologue.append(&mut cmp_prologue); - prologue.push(format!("{{")); prologue.push(format!("uint {} = {};", src_index_ref, cmp_index)); } // We compute the possible sizes, case multiple sizes From abb690bbbb2ff047afd76c30086ea34ea990b400 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 24 Sep 2024 23:11:27 +0200 Subject: [PATCH 161/189] case main with no inputs only executing once' --- compiler/src/circuit_design/circuit.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/src/circuit_design/circuit.rs b/compiler/src/circuit_design/circuit.rs index e1b32bc7b..8dee26286 100644 --- a/compiler/src/circuit_design/circuit.rs +++ b/compiler/src/circuit_design/circuit.rs @@ -535,22 +535,27 @@ impl WriteC for Circuit { // let start_msg = "printf(\"Starting...\\n\");".to_string(); // let end_msg = "printf(\"End\\n\");".to_string(); - let main_template_run = if producer.main_is_parallel{ - producer.main_header.clone() + "_run_parallel" + let run_call = if producer.number_of_main_inputs > 0{ + + let main_template_run = if producer.main_is_parallel{ + producer.main_header.clone() + "_run_parallel" + } else{ + producer.main_header.clone() + "_run" + }; + let mut run_args = vec![]; + // run_args.push(CTX_INDEX.to_string()); + run_args.push("0".to_string()); + run_args.push(CIRCOM_CALC_WIT.to_string()); + format!("{};", build_call(main_template_run, run_args.clone())) } else{ - producer.main_header.clone() + "_run" + "// no input signals, the creation will automatically execute".to_string() }; - let mut run_args = vec![]; - // run_args.push(CTX_INDEX.to_string()); - run_args.push("0".to_string()); - run_args.push(CIRCOM_CALC_WIT.to_string()); - let run_call = format!("{};", build_call(main_template_run, run_args.clone())); let main_run_body = vec![ctx_index, run_call]; - code_write = build_callable(run_circuit, run_circuit_args, main_run_body) + "\n"; + code_write = build_callable(run_circuit, run_circuit_args, main_run_body) + "\n"; writer.write_all(code_write.as_bytes()).map_err(|_| {})?; writer.flush().map_err(|_| {}) - + } } From 58b2b70a341e5cd58e74d8945a80951c0875aa63 Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 25 Sep 2024 07:03:58 +0200 Subject: [PATCH 162/189] handling multiple sizes in source of stores in wasm --- .../store_bucket.rs | 85 ++++++++++++------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 1794493ba..4ee5d0e7d 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -65,16 +65,16 @@ impl WriteWasm for StoreBucket { (values.len(),values.clone()) } }; -/* let mut is_multiple_src = false; - let (size_src,values_dest_src) = match &self.src_context.size{ + let mut is_multiple_src = false; + let (size_src,values_src) = match &self.src_context.size{ SizeOption::Single(value) => (*value,vec![]), SizeOption::Multiple(values) => { is_multiple_src = true; (values.len(),values.clone()) } }; -*/ - if size_dest == 0 {//size_src == 0 || + + if size_dest == 0 || size_src == 0 { return vec![]; } if producer.needs_comments() { @@ -272,33 +272,36 @@ impl WriteWasm for StoreBucket { if producer.needs_comments() { instructions.push(";; getting src".to_string()); } - if !is_multiple_dest && size_dest == 1 { // ) || (!is_multiple_src && size_src == 1) { + if (!is_multiple_dest && size_dest == 1) || (!is_multiple_src && size_src == 1) { + //min to copy is 1 let mut instructions_src = self.src.produce_wasm(producer); instructions.append(&mut instructions_src); instructions.push(call("$Fr_copy")); } else { - instructions.push(set_local(producer.get_store_aux_1_tag())); - let mut instructions_src = self.src.produce_wasm(producer); - instructions.append(&mut instructions_src); - instructions.push(set_local(producer.get_store_aux_2_tag())); - if is_multiple_dest { //create a nested if-else with all cases - for i in 0..size_dest { - instructions.push(get_local(producer.get_sub_cmp_tag())); - instructions.push(load32(None)); // get template id - instructions.push(set_constant(&values_dest[i].0.to_string())); //Add id in list - instructions.push(add_if()); - instructions.push(set_constant(&values_dest[i].1.to_string())); //Add corresponding size in list - instructions.push(add_else()); + instructions.push(set_local(producer.get_store_aux_1_tag())); //set address destination + if !is_multiple_dest && !is_multiple_src { + instructions.push(set_constant(&std::cmp::min(&size_dest,&size_src).to_string())); + } else { + if is_multiple_dest { //create a nested if-else with all cases + let mut instr_if = create_if_selection(&values_dest,producer.get_sub_cmp_tag()); + instructions.append(&mut instr_if); + } else { + instructions.push(set_constant(&size_dest.to_string())); } - instructions.push(set_constant("0")); //default o complete the last else - for _i in 0..size_dest { - instructions.push(add_end()); + if is_multiple_src { //create a nested if-else with all cases + let mut instr_if = create_if_selection(&values_src,producer.get_sub_cmp_tag()); + instructions.append(&mut instr_if); + } else { + instructions.push(set_constant(&size_dest.to_string())); } - instructions.push(tee_local(producer.get_result_size_tag())); - } else { - instructions.push(set_constant(&size_dest.to_string())); } + instructions.push(tee_local(producer.get_result_size_tag())); instructions.push(set_local(producer.get_copy_counter_tag())); + + let mut instructions_src = self.src.produce_wasm(producer); // compute the address of the source + instructions.append(&mut instructions_src); + instructions.push(set_local(producer.get_store_aux_2_tag())); // set address source + instructions.push(add_block()); instructions.push(add_loop()); instructions.push(get_local(producer.get_copy_counter_tag())); @@ -335,14 +338,13 @@ impl WriteWasm for StoreBucket { instructions.push(load32(Some( &producer.get_input_counter_address_in_component().to_string(), ))); //remaining inputs to be set - match &self.context.size{ - SizeOption::Single(value) => { - instructions.push(set_constant(&value.to_string())); - } - SizeOption::Multiple(_) => { - instructions.push(get_local(producer.get_result_size_tag())); - } - }; + if (!is_multiple_dest && size_dest == 1) || (!is_multiple_src && size_src == 1) { + instructions.push(set_constant("1"));} + else if !is_multiple_dest && !is_multiple_src { + instructions.push(set_constant(&std::cmp::min(&size_dest,&size_src).to_string())); + } else { + instructions.push(get_local(producer.get_result_size_tag())); + } instructions.push(sub32()); instructions.push(store32(Some( &producer.get_input_counter_address_in_component().to_string(), @@ -409,6 +411,27 @@ impl WriteWasm for StoreBucket { } } +fn create_if_selection( + values: &Vec<(usize, usize)>, + local: &str +) -> Vec { + use code_producers::wasm_elements::wasm_code_generator::*; + let mut instructions = vec![]; + for i in 0..values.len() { + instructions.push(get_local(local)); + instructions.push(load32(None)); // get template id + instructions.push(set_constant(&values[i].0.to_string())); //Add id in list + instructions.push(add_if()); + instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list + instructions.push(add_else()); + } + instructions.push(set_constant("0")); //default o complete the last else + for _i in 0..values.len() { + instructions.push(add_end()); + } + instructions +} + impl WriteC for StoreBucket { fn produce_c(&self, producer: &CProducer, parallel: Option) -> (Vec, String) { use c_code_generator::*; From 8c7e2c7253db0970a16b61a956113e0303a5e178 Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 25 Sep 2024 08:53:18 +0200 Subject: [PATCH 163/189] handling multiple sizes in source of stores in wasm completed --- code_producers/src/wasm_elements/mod.rs | 5 ++++ .../src/wasm_elements/wasm_code_generator.rs | 6 ++++ .../store_bucket.rs | 30 +++++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/code_producers/src/wasm_elements/mod.rs b/code_producers/src/wasm_elements/mod.rs index a932660e8..58d49879e 100644 --- a/code_producers/src/wasm_elements/mod.rs +++ b/code_producers/src/wasm_elements/mod.rs @@ -36,6 +36,7 @@ pub struct WASMProducer { signal_offset_tag: String, signal_start_tag: String, sub_cmp_tag: String, + sub_cmp_src_tag: String, sub_cmp_load_tag: String, io_info_tag: String, result_address_tag: String, @@ -117,6 +118,7 @@ impl Default for WASMProducer { signal_offset_tag: "$signaloffset".to_string(), signal_start_tag: "$signalstart".to_string(), sub_cmp_tag: "$subcmp".to_string(), + sub_cmp_src_tag: "$subcmpsrc".to_string(), sub_cmp_load_tag: "$subcmpload".to_string(), io_info_tag: "$ioinfo".to_string(), result_address_tag: "$resultaddress".to_string(), @@ -424,6 +426,9 @@ impl WASMProducer { pub fn get_sub_cmp_tag(&self) -> &str { &self.sub_cmp_tag } + pub fn get_sub_cmp_src_tag(&self) -> &str { + &self.sub_cmp_src_tag + } pub fn get_sub_cmp_load_tag(&self) -> &str { &self.sub_cmp_load_tag } diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index 4f93ac858..bf348f072 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -147,6 +147,12 @@ pub fn gt32_u() -> WasmInstruction { pub fn ge32_u() -> WasmInstruction { "i32.ge_u".to_string() } +pub fn lt32_u() -> WasmInstruction { + "i32.lt_u".to_string() +} +pub fn le32_u() -> WasmInstruction { + "i32.le_u".to_string() +} pub fn eq32() -> WasmInstruction { "i32.eq".to_string() } diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index c769b528d..ae1b7313b 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -289,11 +289,35 @@ impl WriteWasm for StoreBucket { instructions.push(set_constant(&size_dest.to_string())); } if is_multiple_src { //create a nested if-else with all cases - let mut instr_if = create_if_selection(&values_src,producer.get_sub_cmp_tag()); - instructions.append(&mut instr_if); + if self.src_address_type.is_some() { + instructions.push(get_local(producer.get_offset_tag())); + instructions.push(set_constant( + &producer.get_sub_component_start_in_component().to_string(), + )); + instructions.push(add32()); + let mut instr_cmp_src = self.src_address_type.as_ref().unwrap().produce_wasm(producer); + instructions.append(&mut instr_cmp_src); + instructions.push(set_constant("4")); //size in byte of i32 + instructions.push(mul32()); + instructions.push(add32()); + instructions.push(load32(None)); //subcomponent block + instructions.push(set_local(producer.get_sub_cmp_tag())); + let mut instr_if = create_if_selection(&values_src,producer.get_sub_cmp_src_tag()); + instructions.append(&mut instr_if); + } else { + assert!(false); + } } else { - instructions.push(set_constant(&size_dest.to_string())); + instructions.push(set_constant(&size_src.to_string())); } + instructions.push(tee_local(producer.get_aux_0_tag())); + instructions.push(tee_local(producer.get_aux_1_tag())); + instructions.push(lt32_u()); + instructions.push(add_if()); + instructions.push(set_local(producer.get_aux_0_tag())); + instructions.push(add_else()); + instructions.push(set_local(producer.get_aux_1_tag())); + instructions.push(add_end()); } instructions.push(tee_local(producer.get_result_size_tag())); instructions.push(set_local(producer.get_copy_counter_tag())); From b3ba731f2b3770f7314ed98423657496aa466a76 Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 25 Sep 2024 15:20:53 +0200 Subject: [PATCH 164/189] bugs fixed in wasm code generation for multiple sizes --- .../src/wasm_elements/wasm_code_generator.rs | 21 ++++++++++ .../call_bucket.rs | 17 +++----- .../store_bucket.rs | 41 ++++++------------- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index bf348f072..c070ee482 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -193,6 +193,27 @@ pub fn add_return() -> WasmInstruction { "return".to_string() } +pub fn create_if_selection( + values: &Vec<(usize, usize)>, + local: &str +) -> Vec { + let mut instructions = vec![]; + for i in 0..values.len() { + instructions.push(get_local(local)); + instructions.push(set_constant(&values[i].0.to_string())); //Add id in list + instructions.push(eq32()); + instructions.push(format!("{} (result i32)", add_if())); + instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list + instructions.push(add_else()); + } + instructions.push(set_constant("0")); //default o complete the last else + for _i in 0..values.len() { + instructions.push(add_end()); + } + instructions +} + + // ----- exception codes and other constants ----------------- pub fn default_memory_for_stack_kib() -> usize { diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 0ea82d8ec..b96d7e878 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -358,18 +358,11 @@ impl WriteWasm for CallBucket { instructions.push(set_constant(&value.to_string())); } SizeOption::Multiple(values) => { //create a nested if-else with all cases - for i in 0..values.len() { - instructions.push(get_local(producer.get_sub_cmp_tag())); - instructions.push(load32(None)); // get template id - instructions.push(set_constant(&values[i].0.to_string())); //Add id in list - instructions.push(add_if()); - instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list - instructions.push(add_else()); - } - instructions.push(set_constant("0")); //default o complete the last else - for _i in 0..values.len() { - instructions.push(add_end()); - } + instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(load32(None)); // get template id + instructions.push(set_local(producer.get_aux_0_tag())); + let mut instr_if = create_if_selection(&values,producer.get_aux_0_tag()); + instructions.append(&mut instr_if); instructions.push(tee_local(producer.get_result_size_tag())); } }; diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index ae1b7313b..0d8ea66a4 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -283,7 +283,10 @@ impl WriteWasm for StoreBucket { instructions.push(set_constant(&std::cmp::min(&size_dest,&size_src).to_string())); } else { if is_multiple_dest { //create a nested if-else with all cases - let mut instr_if = create_if_selection(&values_dest,producer.get_sub_cmp_tag()); + instructions.push(get_local(producer.get_sub_cmp_tag())); + instructions.push(load32(None)); // get template id + instructions.push(set_local(producer.get_aux_0_tag())); + let mut instr_if = create_if_selection(&values_dest,producer.get_aux_0_tag()); instructions.append(&mut instr_if); } else { instructions.push(set_constant(&size_dest.to_string())); @@ -300,9 +303,10 @@ impl WriteWasm for StoreBucket { instructions.push(set_constant("4")); //size in byte of i32 instructions.push(mul32()); instructions.push(add32()); - instructions.push(load32(None)); //subcomponent block - instructions.push(set_local(producer.get_sub_cmp_tag())); - let mut instr_if = create_if_selection(&values_src,producer.get_sub_cmp_src_tag()); + instructions.push(load32(None)); //subcomponent block + instructions.push(load32(None)); // get template id + instructions.push(set_local(producer.get_aux_0_tag())); + let mut instr_if = create_if_selection(&values_src,producer.get_aux_0_tag()); instructions.append(&mut instr_if); } else { assert!(false); @@ -313,13 +317,13 @@ impl WriteWasm for StoreBucket { instructions.push(tee_local(producer.get_aux_0_tag())); instructions.push(tee_local(producer.get_aux_1_tag())); instructions.push(lt32_u()); - instructions.push(add_if()); - instructions.push(set_local(producer.get_aux_0_tag())); + instructions.push(format!("{} (result i32)", add_if())); + instructions.push(get_local(producer.get_aux_0_tag())); instructions.push(add_else()); - instructions.push(set_local(producer.get_aux_1_tag())); + instructions.push(get_local(producer.get_aux_1_tag())); instructions.push(add_end()); + instructions.push(tee_local(producer.get_result_size_tag())); } - instructions.push(tee_local(producer.get_result_size_tag())); instructions.push(set_local(producer.get_copy_counter_tag())); let mut instructions_src = self.src.produce_wasm(producer); // compute the address of the source @@ -434,27 +438,6 @@ impl WriteWasm for StoreBucket { instructions } } - -fn create_if_selection( - values: &Vec<(usize, usize)>, - local: &str -) -> Vec { - use code_producers::wasm_elements::wasm_code_generator::*; - let mut instructions = vec![]; - for i in 0..values.len() { - instructions.push(get_local(local)); - instructions.push(load32(None)); // get template id - instructions.push(set_constant(&values[i].0.to_string())); //Add id in list - instructions.push(add_if()); - instructions.push(set_constant(&values[i].1.to_string())); //Add corresponding size in list - instructions.push(add_else()); - } - instructions.push(set_constant("0")); //default o complete the last else - for _i in 0..values.len() { - instructions.push(add_end()); - } - instructions -} impl WriteC for StoreBucket { fn produce_c(&self, producer: &CProducer, parallel: Option) -> (Vec, String) { From 55e06d634ad1f9856ace5fa6b8f21912488df863 Mon Sep 17 00:00:00 2001 From: miguelis Date: Wed, 25 Sep 2024 16:47:04 +0200 Subject: [PATCH 165/189] Refactor parsing logic for signal and bus headers (input and output can be indicated before signals / bus names) --- parser/src/lang.lalrpop | 63 +++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index 3bc07432f..c2cfd59b9 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -164,45 +164,72 @@ ParseSignalType: SignalType = { "output" => SignalType::Output }; -ParseHeader: (SignalType, Vec) = { - + + +ParseTagsVector: Vec = { + => { - let s = match signal_type { - None => SignalType::Intermediate, - Some(st) => st, - }; - let t = match tags_list { + match tags_list { None => Vec::new(), Some(tl) => tl, - }; - (s,t) + } } } SignalHeader : VariableType = { - "signal" + "signal" => { - let (s,t) = header; - VariableType::Signal(s, t) + let signal_type = match signal_type { + None => SignalType::Intermediate, + Some(st) => st, + }; + VariableType::Signal(signal_type, tags_list) + }, + "signal" + => { + VariableType::Signal(signal_type, tags_list) } }; BusHeader : (Expression, VariableType) = { - + + => { + let wire = match wire_type { + None => SignalType::Intermediate, + Some(st) => st, + }; + let bus_builder = build_bus_call(Meta::new(s,e),id.clone(),Vec::new()); + (bus_builder, VariableType::Bus(id, wire, tags_list)) + }, + + "(" ")" + + => { + let wire = match wire_type { + None => SignalType::Intermediate, + Some(st) => st, + }; + let bus_builder = match args { + None => build_bus_call(Meta::new(s,e),id.clone(),Vec::new()), + Some(a) => build_bus_call(Meta::new(s,e),id.clone(),a), + }; + (bus_builder,VariableType::Bus(id, wire, tags_list)) + }, + + => { let bus_builder = build_bus_call(Meta::new(s,e),id.clone(),Vec::new()); - let (s,t) = header; - (bus_builder, VariableType::Bus(id, s, t)) + (bus_builder, VariableType::Bus(id, wire, tags_list)) }, - "(" ")" + "(" ")" + => { let bus_builder = match args { None => build_bus_call(Meta::new(s,e),id.clone(),Vec::new()), Some(a) => build_bus_call(Meta::new(s,e),id.clone(),a), }; - let (s,t) = header; - (bus_builder,VariableType::Bus(id, s, t)) + (bus_builder,VariableType::Bus(id, wire, tags_list)) } }; From f97b7cad87f23b5dc8d234a4af0795296a8406b9 Mon Sep 17 00:00:00 2001 From: miguelis Date: Wed, 25 Sep 2024 18:28:56 +0200 Subject: [PATCH 166/189] Complement function depends on the number of bits of the prime number --- circom_algebra/src/algebra.rs | 4 ++-- circom_algebra/src/modular_arithmetic.rs | 13 ++++++------- constraint_generation/src/execute.rs | 2 +- mkdocs/docs/circom-language/basic-operators.md | 8 ++++---- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/circom_algebra/src/algebra.rs b/circom_algebra/src/algebra.rs index bb3a47b46..235b7e951 100644 --- a/circom_algebra/src/algebra.rs +++ b/circom_algebra/src/algebra.rs @@ -554,13 +554,13 @@ impl ArithmeticExpression { } // Bit operations - pub fn complement_254( + pub fn complement( elem: &ArithmeticExpression, field: &BigInt, ) -> ArithmeticExpression { use ArithmeticExpression::*; if let Number { value } = elem { - Number { value: modular_arithmetic::complement_254(value, field) } + Number { value: modular_arithmetic::complement(value, field) } } else { NonQuadratic } diff --git a/circom_algebra/src/modular_arithmetic.rs b/circom_algebra/src/modular_arithmetic.rs index f1d5790f2..60c386c05 100644 --- a/circom_algebra/src/modular_arithmetic.rs +++ b/circom_algebra/src/modular_arithmetic.rs @@ -91,15 +91,14 @@ pub fn multi_inv(values: &Vec, field: &BigInt) -> Vec{ } //Bit operations - -// 254 bit complement -pub fn complement_254(elem: &BigInt, field: &BigInt) -> BigInt { +pub fn complement(elem: &BigInt, field: &BigInt) -> BigInt { let (sign, mut bit_repr) = bit_representation(elem); let new_sign = if elem == &BigInt::from(0) { Sign::Plus } else { sign}; - while bit_repr.len() > 254 { + let nbits = field.bits(); + while bit_repr.len() > nbits { bit_repr.pop(); } - for _i in bit_repr.len()..254 { + for _i in bit_repr.len()..nbits { bit_repr.push(0); } for bit in &mut bit_repr { @@ -253,8 +252,8 @@ mod tests { .expect("generating the big int was not possible"); let big_num = BigInt::parse_bytes("1234".as_bytes(), 10) .expect("generating the big int was not possible"); - let big_num_complement = complement_254(&big_num, &field); - let big_num_complement_complement = complement_254(&big_num_complement, &field); + let big_num_complement = complement(&big_num, &field); + let big_num_complement_complement = complement(&big_num_complement, &field); let big_num_modulus = modulus(&big_num, &field); assert_eq!(big_num_complement_complement, big_num_modulus); } diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 887d52c38..1a4a3061a 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2079,7 +2079,7 @@ fn execute_prefix_op( let result = match prefix_op { BoolNot => AExpr::not(value, field), Sub => AExpr::prefix_sub(value, field), - Complement => AExpr::complement_254(value, field), + Complement => AExpr::complement(value, field), }; Result::Ok(result) } diff --git a/mkdocs/docs/circom-language/basic-operators.md b/mkdocs/docs/circom-language/basic-operators.md index 7ff89ffec..c2940bc7f 100644 --- a/mkdocs/docs/circom-language/basic-operators.md +++ b/mkdocs/docs/circom-language/basic-operators.md @@ -95,8 +95,8 @@ All bitwise operators are performed modulo p. | :--- | :--- | :--- | | & | a & b | Bitwise AND | | \| | a \| b | Bitwise OR | -| ~ | ~a | Complement 254 bits | -| ^ | a ^ b | XOR 254 bits | +| ~ | ~a | Complement to the number of bits of the prime number | +| ^ | a ^ b | Bitwise XOR | | >> | a >> 4 | Right shift operator | | << | a << 4 | Left shift operator | @@ -122,8 +122,8 @@ There are operators that combine bitwise operators with a final assignment. | :--- | :--- | :--- | | &= | a &= b | Bitwise AND and assignment | | \|= | a \|= b | Bitwise OR and assignment | -| ~= | ~=a | Complement 254 bits and assignment | -| ^= | a ^= b | XOR 254 bits and assignment | +| ~= | ~=a | Complement to the number of bits of the prime number and assignment | +| ^= | a ^= b | Bitwise XOR and assignment | | >>= | a >>= 4 | Right shift operator and assignment | | <<= | a <<= 4 | Left shift operator and assignment | From 5c3f0c4b9bc55258b96c9004b537fcbb62a7bd4f Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 25 Sep 2024 20:18:00 +0200 Subject: [PATCH 167/189] allowing array assignments of different sizes case variables --- constraint_generation/src/execute.rs | 18 +++++++--- program_structure/src/utils/memory_slice.rs | 40 ++++++++++++--------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 87d5afe46..d4ae15065 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -3531,10 +3531,20 @@ fn treat_result_with_memory_error_void( match memory_error { Result::Ok(()) => Result::Ok(()), Result::Err(MemoryError::MismatchedDimensionsWeak(dim_given, dim_original)) => { - let report = Report::warning( - format!("Typing warning: Mismatched dimensions, assigning to an array an expression of smaller length, the remaining positions are not modified. Initially all variables are initialized to 0.\n Expected length: {}, given {}", - dim_original, dim_given), - RuntimeError); + + let report = if dim_given < dim_original{ + Report::warning( + format!("Typing warning: Mismatched dimensions, assigning to an array an expression of smaller length, the remaining positions are not modified. Initially all variables are initialized to 0.\n Expected length: {}, given {}", + dim_original, dim_given), + RuntimeError + ) + } else{ + Report::warning( + format!("Typing warning: Mismatched dimensions, assigning to an array an expression of greater length, the remaining positions of the expression are not assigned to the array.\n Expected length: {}, given {}", + dim_original, dim_given), + RuntimeError + ) + }; add_report_to_runtime(report, meta, runtime_errors, call_trace); Ok(()) }, diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 35e0be714..c918a1ba6 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -144,10 +144,19 @@ impl MemorySlice { } if new_values.route[i] > memory_slice.route[initial_index_new + i] { - return Result::Err(MemoryError::MismatchedDimensions( - new_values.route[i], - memory_slice.route[initial_index_new + i], - )); + if is_strict{ + return Result::Err(MemoryError::MismatchedDimensions( + new_values.route[i], + memory_slice.route[initial_index_new + i], + )); + } + else{ + // case variables: we allow the assignment of smaller arrays + return Result::Err(MemoryError::MismatchedDimensionsWeak( + new_values.route[i], + memory_slice.route[initial_index_new + i], + )); + } } i += 1; } @@ -281,11 +290,6 @@ impl MemorySlice { Result::Ok(_) => { let mut cell = MemorySlice::get_initial_cell(memory_slice, access)?; - // if MemorySlice::get_number_of_cells(new_values) - // > (MemorySlice::get_number_of_cells(memory_slice) - cell) - // { - // return Result::Err(MemoryError::OutOfBoundsError); - memory_slice.number_inserts += MemorySlice::get_number_of_cells(new_values); for value in new_values.values.iter() { memory_slice.values[cell] = value.clone(); @@ -295,15 +299,19 @@ impl MemorySlice { } Result::Err(MemoryError::MismatchedDimensionsWeak(dim_1, dim_2)) => { let mut cell = MemorySlice::get_initial_cell(memory_slice, access)?; - // if MemorySlice::get_number_of_cells(new_values) - // > (MemorySlice::get_number_of_cells(memory_slice) - cell) - // { - // return Result::Err(MemoryError::OutOfBoundsError); - // } - for value in new_values.values.iter() { - memory_slice.values[cell] = value.clone(); + + // We assign the min between the number of cells in the new values and the memory slice + let number_inserts = std::cmp::min( + MemorySlice::get_number_of_cells(new_values), + MemorySlice::get_number_of_cells(memory_slice) + ); + + memory_slice.number_inserts += number_inserts; + for i in 0..number_inserts{ + memory_slice.values[cell] = new_values.values[i].clone(); cell += 1; } + Result::Err(MemoryError::MismatchedDimensionsWeak(dim_1, dim_2)) } Result::Err(error) => return Err(error), From 838b6d27d9e1f8e57204d1caec934027c6c4a56c Mon Sep 17 00:00:00 2001 From: erhant Date: Mon, 30 Sep 2024 16:55:50 +0300 Subject: [PATCH 168/189] Add Circomkit to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5d6790777..a6f82a3e6 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ TOOLS + [PICUS: a static analyzer for verifying weak and strong safety for circom circuits](https://github.com/Veridise/Picus) + [Hardhat-zkit: the ultimate typescript environment for circom development](https://github.com/dl-solarity/hardhat-zkit) ++ ++ [Circomkit: a testing & development environment for circom](https://github.com/erhant/circomkit) More information about the notions of weak and strong safety in circom circuits [here](https://ieeexplore.ieee.org/document/10002421). From 098f883601e7dce5ff9e91959408ee30990026c9 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 2 Oct 2024 11:43:14 +0200 Subject: [PATCH 169/189] minor --- constraint_generation/src/execute.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index d4ae15065..26e3ec2a2 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2437,16 +2437,20 @@ fn execute_conditional_statement( AExpr::get_boolean_equivalence(&ae_cond, runtime.constants.get_p()); if let Some(cond_bool_value) = possible_cond_bool_value { let (ret_value, can_simplify) = match false_case { - Some(else_stmt) if !cond_bool_value => { + Option::Some(else_stmt) if !cond_bool_value => { execute_statement(else_stmt, program_archive, runtime, actual_node, flags)? } - None if !cond_bool_value => (None, true), + Option::None if !cond_bool_value => (None, true), _ => execute_statement(true_case, program_archive, runtime, actual_node, flags)?, }; Result::Ok((ret_value, can_simplify, Option::Some(cond_bool_value))) } else { let previous_block_type = runtime.block_type; runtime.block_type = BlockType::Unknown; + // TODO: here instead of executing both branches what we do is to store the values + // that we assign in each one of the branches and assign later: if we assign in both + // of them a signal we return an error. If we assign in just one then we dont return error + // (maybe a warning indicating that the variable may not get assigned in the if) let (mut ret_value, mut can_simplify) = execute_statement(true_case, program_archive, runtime, actual_node, flags)?; if let Option::Some(else_stmt) = false_case { let (else_ret, can_simplify_else) = execute_statement(else_stmt, program_archive, runtime, actual_node, flags)?; From 6ee4622cb539fb5e23cd3d676b36e97851beaf78 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 2 Oct 2024 11:48:41 +0200 Subject: [PATCH 170/189] removing debugging messages --- code_producers/src/c_elements/common/main.cpp | 4 ++-- code_producers/src/wasm_elements/common/generate_witness.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code_producers/src/c_elements/common/main.cpp b/code_producers/src/c_elements/common/main.cpp index 5ce3dab6d..eff4a0808 100644 --- a/code_producers/src/c_elements/common/main.cpp +++ b/code_producers/src/c_elements/common/main.cpp @@ -351,13 +351,13 @@ int main (int argc, char *argv[]) { std::cerr << "Not all inputs have been set. Only " << get_main_input_signal_no()-ctx->getRemaingInputsToBeSet() << " out of " << get_main_input_signal_no() << std::endl; assert(false); } - + /* for (uint i = 0; igetWitness(i, &x); std::cout << i << ": " << Fr_element2str(&x) << std::endl; } - + */ //auto t_mid = std::chrono::high_resolution_clock::now(); //std::cout << std::chrono::duration(t_mid-t_start).count()< { const w= await witnessCalculator.calculateWitness(input,0); + /* for (let i=0; i< w.length; i++){ console.log(w[i]); - } + }*/ const buff= await witnessCalculator.calculateWTNSBin(input,0); writeFile(process.argv[4], buff, function(err) { if (err) throw err; From c6f8bc7795c5630064a120069eaadc6149f02332 Mon Sep 17 00:00:00 2001 From: miguelis Date: Wed, 2 Oct 2024 13:43:25 +0200 Subject: [PATCH 171/189] Refactor anonymous component statement handling in parser to improve error report --- parser/src/lang.lalrpop | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index faadd3e38..af274bfa8 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -324,13 +324,6 @@ ParseDeclaration : Statement = { ast_shortcuts::split_declaration_into_single_nodes_and_multisubstitution(meta,xtype,symbols, init) }, - // ( "(" ",")*> ")" => { - // let (bus_type,xtype) = bus_header; - // let mut symbols = symbols; - // let meta = Meta::new(s,e); - // symbols.push(symbol); - // ast_shortcuts::split_bus_declaration_into_single_nodes_and_multisubstitution(meta,bus_type,xtype,symbols, init) - // }, "var" ",")*> => { let mut symbols = symbols; @@ -523,8 +516,17 @@ ParseStatement2 : Statement = { "assert" "(" ")" Semicolon => build_assert(Meta::new(s,e),arg), - Semicolon - => build_anonymous_component_statement(Meta::new(s,e), lhe), + Semicolon + => { + match lhe { + Expression::AnonymousComp { .. } => build_anonymous_component_statement(Meta::new(s,e), lhe), + _ => { + errors.push(produce_report(ReportCode::IllegalExpression, s..e, file_id)); + //doesn't matter + build_log_call(Meta::new(s,e),Vec::new()) + } , + } + }, ParseBlock }; @@ -707,7 +709,8 @@ Expression3 = InfixOpTier; // ops: Unary - ! ~ Expression2 = PrefixOpTier; -ExpressionAnonymous: Expression = { +// function call, array inline, anonymous component call +Expression1: Expression = { "(" ")" "(" ")" => {let params = match args { None => Vec::new(), @@ -718,11 +721,7 @@ ExpressionAnonymous: Expression = { Some(a) => a }; build_anonymous_component(Meta::new(s,e),id,params,signals,names,false)} -} - -// function call, array inline, anonymous component call -Expression1: Expression = { - ExpressionAnonymous, + , "(" ")" => match args { From a5763a21c77988e5036dfc1bdf9aa1145455dbd1 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 3 Oct 2024 18:11:07 +0200 Subject: [PATCH 172/189] removing warnings --- compiler/src/intermediate_representation/translate.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 95d9b098c..0860a1659 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -185,10 +185,10 @@ impl State { } struct Context<'a> { - translating: String, + _translating: String, files: &'a FileLibrary, tmp_database: &'a TemplateDB, - functions: &'a HashMap>, + _functions: &'a HashMap>, cmp_to_type: HashMap, buses: &'a Vec } @@ -1892,8 +1892,8 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { let context = Context { files: code_info.files, - translating: code_info.header, - functions: code_info.functions, + _translating: code_info.header, + _functions: code_info.functions, cmp_to_type: code_info.cmp_to_type, tmp_database: code_info.template_database, buses: code_info.buses From 849207dece5b3813b2df78e192ab9a88dcec2ea1 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 4 Oct 2024 10:53:19 +0200 Subject: [PATCH 173/189] removing warning --- compiler/src/intermediate_representation/ir_interface.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/intermediate_representation/ir_interface.rs b/compiler/src/intermediate_representation/ir_interface.rs index b9209c406..88e5e6497 100644 --- a/compiler/src/intermediate_representation/ir_interface.rs +++ b/compiler/src/intermediate_representation/ir_interface.rs @@ -33,7 +33,7 @@ pub trait ObtainMeta { } pub trait CheckCompute { - fn has_compute_in(&self) -> bool; + fn _has_compute_in(&self) -> bool; } pub type InstructionList = Vec; @@ -97,7 +97,7 @@ impl ObtainMeta for Instruction { } impl CheckCompute for Instruction { - fn has_compute_in(&self) -> bool { + fn _has_compute_in(&self) -> bool { use Instruction::*; match self { Load(_v) => {true From e24b1390057b83044c938909d083427301692bf5 Mon Sep 17 00:00:00 2001 From: miguelis Date: Fri, 4 Oct 2024 12:02:16 +0200 Subject: [PATCH 174/189] Fixing report errors when missing parenthesis --- parser/src/lang.lalrpop | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index af274bfa8..e71e69630 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -758,15 +758,7 @@ Expression0: Expression = { => build_number(Meta::new(s,e),value, field), "(" ")", - - => match <>.error { - ParseError::UnrecognizedToken { ref token, .. } => { - errors.push(produce_report(ReportCode::IllegalExpression, token.0..token.2, file_id)); - // doesn't matter - build_number(Meta::new(0,0),BigInt::from(0), field) - } - _ => unreachable!(), - } + }; // ==================================================================== From 2fdc254fc9d40ab59a2c5892ae652854f9acec73 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 4 Oct 2024 12:10:42 +0200 Subject: [PATCH 175/189] setting default simplification option to --01 --- circom/src/input_user.rs | 4 +- tests/buses/bus_test_correct_1.circom | 35 --- tests/buses/bus_test_correct_2.circom | 29 --- tests/buses/bus_test_correct_3.circom | 40 ---- tests/buses/bus_test_correct_4.circom | 14 -- tests/buses/bus_test_error_1.circom | 42 ---- tests/buses/bus_test_error_2.circom | 31 --- tests/buses/bus_test_error_3.circom | 28 --- tests/buses/bus_test_error_4.circom | 47 ----- tests/buses/bus_test_error_5.circom | 51 ----- tests/buses/bus_test_error_6.circom | 46 ---- tests/circomlib/aliascheck.circom | 31 --- tests/circomlib/babyjub.circom | 180 ---------------- tests/circomlib/binsub.circom | 81 ------- tests/circomlib/binsum.circom | 103 --------- tests/circomlib/bitify.circom | 115 ---------- tests/circomlib/comparators.circom | 177 ---------------- tests/circomlib/compconstant.circom | 73 ------- tests/circomlib/eddsa.circom | 127 ----------- tests/circomlib/escalarmulany.circom | 177 ---------------- tests/circomlib/escalarmulfix.circom | 292 -------------------------- tests/circomlib/montgomery.circom | 194 ----------------- tests/circomlib/mux1.circom | 48 ----- tests/circomlib/mux2.circom | 63 ------ tests/circomlib/mux3.circom | 75 ------- tests/circomlib/mux4.circom | 119 ----------- tests/circomlib/pedersen.circom | 224 -------------------- tests/circomlib/pointbits.circom | 181 ---------------- tests/circomlib/sign.circom | 33 --- tests/circomlib/switcher.circom | 42 ---- 30 files changed, 2 insertions(+), 2700 deletions(-) delete mode 100644 tests/buses/bus_test_correct_1.circom delete mode 100644 tests/buses/bus_test_correct_2.circom delete mode 100644 tests/buses/bus_test_correct_3.circom delete mode 100644 tests/buses/bus_test_correct_4.circom delete mode 100644 tests/buses/bus_test_error_1.circom delete mode 100644 tests/buses/bus_test_error_2.circom delete mode 100644 tests/buses/bus_test_error_3.circom delete mode 100644 tests/buses/bus_test_error_4.circom delete mode 100644 tests/buses/bus_test_error_5.circom delete mode 100644 tests/buses/bus_test_error_6.circom delete mode 100644 tests/circomlib/aliascheck.circom delete mode 100644 tests/circomlib/babyjub.circom delete mode 100644 tests/circomlib/binsub.circom delete mode 100644 tests/circomlib/binsum.circom delete mode 100644 tests/circomlib/bitify.circom delete mode 100644 tests/circomlib/comparators.circom delete mode 100644 tests/circomlib/compconstant.circom delete mode 100644 tests/circomlib/eddsa.circom delete mode 100644 tests/circomlib/escalarmulany.circom delete mode 100644 tests/circomlib/escalarmulfix.circom delete mode 100644 tests/circomlib/montgomery.circom delete mode 100644 tests/circomlib/mux1.circom delete mode 100644 tests/circomlib/mux2.circom delete mode 100644 tests/circomlib/mux3.circom delete mode 100644 tests/circomlib/mux4.circom delete mode 100644 tests/circomlib/pedersen.circom delete mode 100644 tests/circomlib/pointbits.circom delete mode 100644 tests/circomlib/sign.circom delete mode 100644 tests/circomlib/switcher.circom diff --git a/circom/src/input_user.rs b/circom/src/input_user.rs index 9417b067a..735ee5de6 100644 --- a/circom/src/input_user.rs +++ b/circom/src/input_user.rs @@ -264,8 +264,8 @@ mod input_processing { else { Result::Err(eprintln!("{}", Colour::Red.paint("invalid number of rounds"))) } }, - (false, false, false, true) => Ok(SimplificationStyle::O2(usize::MAX)), - (false, false, false, false) => Ok(SimplificationStyle::O2(usize::MAX)), + (false, false, false, true) => Ok(SimplificationStyle::O1), + (false, false, false, false) => Ok(SimplificationStyle::O1), } } diff --git a/tests/buses/bus_test_correct_1.circom b/tests/buses/bus_test_correct_1.circom deleted file mode 100644 index a7e6822c1..000000000 --- a/tests/buses/bus_test_correct_1.circom +++ /dev/null @@ -1,35 +0,0 @@ -pragma circom 2.0.0; - -bus Point (n) { - signal {binary} x[n], y[n]; -} - -template Main(n) { - Point(n) output {babyedwards} pout; - - Point(n) {babyedwards} pin; - for (var i=0; i. -*/ -pragma circom 2.0.0; - -include "compconstant.circom"; -include "bitify.circom"; - -template AliasCheck() { - BinaryNumber(254) input in; - BinaryNumber(254) output {unique} out; - - signal greater <== CompConstant(-1)(in); - greater === 0; - out <== in; -} \ No newline at end of file diff --git a/tests/circomlib/babyjub.circom b/tests/circomlib/babyjub.circom deleted file mode 100644 index d778dbb36..000000000 --- a/tests/circomlib/babyjub.circom +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.1.5; - -include "bitify.circom"; -include "montgomery.circom"; -include "escalarmulfix.circom"; - -// The templates and functions of this file only work for finite field F_p = bn128, -// with the prime number p = 21888242871839275222246405745257275088548364400416034343698204186575808495617. - -/* - The Baby-Jubjub Montgomery elliptic curve defined over the finite field bn128 is given by the equation - - B*v^2 = u^3 + A*u^2 + u, A = 168698, B = 1 - - This curve is birationally equivalent to the twisted Edwards elliptic curve - - a*x^2 + y^2 = 1 + d*x^2*y^2, a = 168700 = (A+2)/B, d = 168696 = (A-2)/B - - u u-1 1+y 1+y - via the map (u,v) -> (x,y) = [ --- , ----- ] with inverse (x,y) -> (u,v) = [ ----- , --------- ] - v u+1 1-y (1-y)*x - - Since a is not a square in bn128, the twisted Edwards curve is a quadratic twist of the Edwards curve - - x'^2 + y'^2 = 1 + d'*x'^2*y'^2 - - via the map (x,y) -> (x',y') = [ sqrt(a)*x , y ] - - where d' = 9706598848417545097372247223557719406784115219466060233080913168975159366771. - We will be working with the twisted Edwards form of the Baby-Jubjub curve because the algorithms for adding, doubling - and multiplying points by a scalar are faster this way. -*/ - -/* - spec tag babyedwards: 168700*(p.x)^2 + (p.y)^2 = 1 + 168696*(p.x)^2*(p.y)^2 - spec tag babymontgomery: (p.y)^2 = (p.x)^3 + 168698*(p.x)^2 + p.x -*/ - -/* -*** BabyAdd(): template that receives two points of the Baby-Jubjub curve in twisted Edwards form and returns the addition of the points. - - Inputs: p1 = (x1, y1) -> bus representing a point of the curve in twisted Edwards form - p2 = (x2, y2) -> bus representing a point of the curve in twisted Edwards form - - Outputs: pout = (xout, yout) -> bus representing a point of the curve in twisted Edwards form, pout = p1 + p2 - - Twisted Edwards Addition Law: - x1*y2 + y1*x2 y1*y2 - a * x1*x2 - [xout, yout] = [x1, y1] + [x2, y2] = [ --------------------- , --------------------- ] - 1 + d * x1*x2*y1*y2 1 - d * x1*x2*y1*y2 - -*/ - -template BabyAdd() { - Point input {babyedwards} p1,p2; - Point output {babyedwards} pout; - - signal beta; - signal gamma; - signal delta; - signal tau; - - var a = 168700; - var d = 168696; - - beta <== p1.x*p2.y; - gamma <== p1.y*p2.x; - delta <== (-a*p1.x + p1.y)*(p2.x + p2.y); - tau <== beta * gamma; - - pout.x <-- (beta + gamma) / (1 + d*tau); - (1 + d*tau) * pout.x === (beta + gamma); - - pout.y <-- (delta + a*beta - gamma) / (1 - d*tau); - (1 - d*tau)*pout.y === (delta + a*beta - gamma); -} - - - -/* -*** BabyDouble(): template that receives a point pin of the Baby-Jubjub curve in twisted Edwards form and returns the point 2 * pin. - - Inputs: pin = (x1, y1) -> bus representing a point of the curve in twisted Edwards form - - Outputs: pout = (x2, y2) -> bus representing a point of the curve in twisted Edwards form, 2 * pin = pout - - Twisted Edwards Doubling Law: 2 * [x, y] = [x, y] + [x, y] - -*/ - -template BabyDbl() { - Point input {babyedwards} pin; - Point output {babyedwards} pout; - - component adder = BabyAdd(); - - adder.p1 <== pin; - adder.p2 <== pin; - adder.pout ==> pout; -} - - -/* -*** BabyCheck(): template that receives an input point pin and checks if it belongs to the Baby-Jubjub curve in twisted Edwards form. - - Inputs: pin = (x1, y1) -> bus representing the point that we want to check - - Outputs: pout = (x2, y2) -> two field values representing the same point as the input but with the babyedwards tag - attached to point out it is a point of the Baby-Jubjub curve in twisted Edwards form - - The set of solutions of BabyCheck()(p) are the points of the Baby-Jubjub curve in twisted Edwards form. - They must fulfil the equation a*x^2 + y^2 = 1 + d*x^2*y^2, a = 168700, d = 168696. - -*/ - - -template BabyCheck() { - Point input pin; - Point output {babyedwards} pout; - - // Point p2; - signal x2; - signal y2; - - var a = 168700; - var d = 168696; - - x2 <== pin.x*pin.x; //x2 = pin.x^2 - y2 <== pin.y*pin.y; //y2 = pin.y^2 - - a*x2 + y2 === 1 + d*x2*y2; - - pout <== pin; -} - - -/* -*** BabyPbk(): template that receives an input in representing a value in the prime subgroup with order - r = 2736030358979909402780800718157159386076813972158567259200215660948447373041, - and returns the point of the Baby-Jubjub curve in twisted Edwards form in * P, with P being the point - P = (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203) - -This template is used to extract the public key from the private key. - - Inputs: in -> field value in [1,r-1] - - Outputs: A = (x, y) -> two field values representing a point of the curve in Edwards form, in * P = A - -*/ - -template BabyPbk() { - signal input {minvalue, maxvalue} in; - Point output {babyedwards} A; - - - var r = 2736030358979909402780800718157159386076813972158567259200215660948447373041; - assert(in.minvalue > 0 && in.maxvalue < r); - var BASE8[2] = [ - 5299619240641551281634865583518297030282874472190772894086521144482721001553, - 16950150798460657717958625567821834550301663161624707787222815936182638968203 - ]; - - component pvkBits = Num2Bits(253); - pvkBits.in <== in; - - component mulFix = EscalarMulFix(253, BASE8); - - mulFix.e <== pvkBits.out; - A <== mulFix.out; -} diff --git a/tests/circomlib/binsub.circom b/tests/circomlib/binsub.circom deleted file mode 100644 index 42e93831d..000000000 --- a/tests/circomlib/binsub.circom +++ /dev/null @@ -1,81 +0,0 @@ - /* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ - -/* -This component creates a binary substraction. - - -Main Constraint: - (in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1)) + - + 2^n - - (in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1)) - === - out[0] * 2^0 + out[1] * 2^1 + + out[n-1] *2^(n-1) + aux - - - out[0] * (out[0] - 1) === 0 - out[1] * (out[0] - 1) === 0 - . - . - . - out[n-1] * (out[n-1] - 1) === 0 - aux * (aux-1) == 0 - -*/ -pragma circom 2.0.0; - -include "bitify.circom"; - -template BinSub(n) { - BinaryNumber(n) input in[2]; - BinaryNumber(n) output out; - - signal aux; - - var lin = 2**n; - var lout = 0; - - var i; - var pot = 1; - - for (i=0; i> i) & 1; - - // Ensure out is binary - out.bits[i] * (out.bits[i] - 1) === 0; - - lout = lout + out.bits[i]*pot; - pot *= 2; - } - - aux <-- (lin >> n) & 1; - aux*(aux-1) === 0; - lout = lout + aux*(2**n); - - // Ensure the sum; - lin === lout; -} \ No newline at end of file diff --git a/tests/circomlib/binsum.circom b/tests/circomlib/binsum.circom deleted file mode 100644 index ccf5b03e0..000000000 --- a/tests/circomlib/binsum.circom +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ - -/* - -Binary Sum -========== - -This component creates a binary sum componet of ops operands and n bits each operand. - -e is Number of carries: Depends on the number of operands in the input. - -Main Constraint: - in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) + - + in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) + - + .. - + in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) + - === - out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1) - -To waranty binary outputs: - - out[0] * (out[0] - 1) === 0 - out[1] * (out[0] - 1) === 0 - . - . - . - out[n+e-1] * (out[n+e-1] - 1) == 0 - - */ - - -/* - This function calculates the number of extra bits in the output to do the full sum. -*/ -pragma circom 2.0.0; - -include "bitify.circom"; - -function nbits(a) { - var n = 1; - var r = 0; - while (n-1> k) & 1; - - // Ensure out is binary - out.bits[k] * (out.bits[k] - 1) === 0; - - lout += out.bits[k] * e2; - - e2 = e2+e2; - } - - // Ensure the sum; - - lin === lout; -} \ No newline at end of file diff --git a/tests/circomlib/bitify.circom b/tests/circomlib/bitify.circom deleted file mode 100644 index ee964270b..000000000 --- a/tests/circomlib/bitify.circom +++ /dev/null @@ -1,115 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "comparators.circom"; -include "aliascheck.circom"; - -bus BinaryNumber(n) { - signal {binary} bits[n]; -} - -template Num2Bits(n) { - signal input in; - BinaryNumber(n) output out; - var lc1=0; - - var e2=1; - for (var i=0; i> i) & 1; - out.bits[i] * (out.bits[i] - 1) === 0; - lc1 += out.bits[i] * e2; - e2 = e2 + e2; - } - - lc1 === in; -} - -template Num2Bits_strict() { - signal input in; - BinaryNumber(254) output {unique} out; - - component aliasCheck = AliasCheck(); - component n2b = Num2Bits(254); - - in ==> n2b.in; - n2b.out ==> aliasCheck.in; - aliasCheck.out ==> out; -} - -template Bits2Num(n) { - BinaryNumber(n) input in; - signal output out; - var lc1=0; - - var e2 = 1; - for (var i=0; i out; -} - -template Bits2Num_strict() { - BinaryNumber(254) input in; - signal output out; - - component aliasCheck = AliasCheck(); - component b2n = Bits2Num(254); - - in ==> aliasCheck.in; - aliasCheck.out ==> b2n.in; - b2n.out ==> out; -} - -template Num2BitsNeg(n) { - signal input in; - BinaryNumber(n) output out; - - component isZero = IsZero(); - - var lc1 = 0; - var pot = 1; - var maxpot = 2**n; - var neg = n == 0 ? 0 : maxpot - in; - - for (var i=0; i> i) & 1; - out.bits[i] * (out.bits[i] - 1) === 0; - lc1 += out.bits[i] * pot; - pot *= 2; - } - - in ==> isZero.in; - - lc1 + isZero.out * maxpot === maxpot - in; -} - -template Num2BitsNeg_strict() { - signal input in; - BinaryNumber(254) output {unique} out; - - component aliasCheck = AliasCheck(); - component n2bn = Num2BitsNeg(254); - - in ==> n2bn.in; - n2bn.out ==> aliasCheck.in; - aliasCheck.out ==> out; -} \ No newline at end of file diff --git a/tests/circomlib/comparators.circom b/tests/circomlib/comparators.circom deleted file mode 100644 index b9cf146c4..000000000 --- a/tests/circomlib/comparators.circom +++ /dev/null @@ -1,177 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "bitify.circom"; - -bus Pair { - signal s[2]; -} - -template IsZero() { - signal input in; - signal output out; - - signal inv; - - inv <-- in!=0 ? 1/in : 0; - - out <== -in*inv + 1; - in*out === 0; -} - -template ForceZero() { - signal input in; - signal output {zero} out; - - component isz = IsZero(); - - in ==> isz.in; - isz.out === 1; - in ==> out; -} - - -template IsEqual() { - signal input in[2]; - signal output out; - - component isz = IsZero(); - - in[1] - in[0] ==> isz.in; - isz.out ==> out; -} - -template ForceEqual() { - signal input in[2]; - Pair output {equal} out; - - component ise = IsEqual(); - - in ==> ise.in; - ise.out === 1; - in ==> out.s; -} - -template ForceEqualIfEnabled() { - signal input enabled; - signal input in[2]; - - component isz = IsZero(); - - in[1] - in[0] ==> isz.in; - - (1 - isz.out)*enabled === 0; -} - - -// N is the number of bits the input have. -// The MSF is the sign bit. -template LessThan(n) { - assert(n <= 252); - signal input in[2]; - signal output out; - - component n2b = Num2Bits(n+1); - - n2b.in <== in[0] + (1< out; -} - -template ForceLessEqThan(n) { - signal input in[2]; - Pair output {le} out; - - component leq = LessEqThan(n); - leq.in <== in; - leq.out === 1; - out.s <== in; -} - -// N is the number of bits the input have. -// The MSF is the sign bit. -template GreaterThan(n) { - signal input in[2]; - signal output out; - - component lt = LessThan(n); - - lt.in[0] <== in[1]; - lt.in[1] <== in[0]; - lt.out ==> out; -} - -template ForceGreaterThan(n) { - signal input in[2]; - Pair output {gt} out; - - component greaterThan = GreaterThan(n); - greaterThan.in <== in; - greaterThan.out === 1; - out.s <== in; -} - -// N is the number of bits the input have. -// The MSF is the sign bit. -template GreaterEqThan(n) { - signal input in[2]; - signal output out; - - component lt = LessThan(n); - - lt.in[0] <== in[1]; - lt.in[1] <== in[0]+1; - lt.out ==> out; -} - -template ForceGreaterEqThan(n) { - signal input in[2]; - Pair output {ge} out; - - component geq = GreaterEqThan(n); - geq.in <== in; - geq.out === 1; - out.s <== in; -} \ No newline at end of file diff --git a/tests/circomlib/compconstant.circom b/tests/circomlib/compconstant.circom deleted file mode 100644 index 3acf3315e..000000000 --- a/tests/circomlib/compconstant.circom +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "bitify.circom"; - -// Returns 1 if in (in binary) > ct - -template CompConstant(ct) { - BinaryNumber(254) input in; - signal output {binary} out; - - signal parts[127]; - signal sout; - - var clsb; - var cmsb; - var slsb; - var smsb; - - var sum=0; - - var b = (1 << 128)-1; - var a = 1; - var e = 1; - var i; - - for (i=0; i<127; i++) { - clsb = (ct >> (i*2)) & 1; - cmsb = (ct >> (i*2+1)) & 1; - slsb = in.bits[i*2]; - smsb = in.bits[i*2+1]; - - if ((cmsb==0)&&(clsb==0)) { - parts[i] <== -b*smsb*slsb + b*smsb + b*slsb; - } else if ((cmsb==0)&&(clsb==1)) { - parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a; - } else if ((cmsb==1)&&(clsb==0)) { - parts[i] <== b*smsb*slsb - a*smsb + a; - } else { - parts[i] <== -a*smsb*slsb + a; - } - - sum = sum + parts[i]; - - b = b-e; - a = a+e; - e = e*2; - } - - sout <== sum; - - component num2bits = Num2Bits(135); - - num2bits.in <== sout; - out <== num2bits.out.bits[127]; -} \ No newline at end of file diff --git a/tests/circomlib/eddsa.circom b/tests/circomlib/eddsa.circom deleted file mode 100644 index b03d2025c..000000000 --- a/tests/circomlib/eddsa.circom +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "compconstant.circom"; -include "pointbits.circom"; -include "pedersen.circom"; -include "escalarmulany.circom"; -include "escalarmulfix.circom"; - -template EdDSAVerifier(n) { - BinaryNumber(n) input msg; - BinaryPoint(254) input A; - BinaryPoint(254) input R8; - BinaryPoint(254) input S; - - Point pA; - Point pR8; - - var i; - -// Ensure S. -*/ -pragma circom 2.0.0; - -include "montgomery.circom"; -include "babyjub.circom"; -include "comparators.circom"; - -template Multiplexor2() { - signal input sel; - signal input in[2][2]; - signal output out[2]; - - out[0] <== (in[1][0] - in[0][0])*sel + in[0][0]; - out[1] <== (in[1][1] - in[0][1])*sel + in[0][1]; -} - -template BitElementMulAny() { - signal input sel; - Point input {babymontgomery} dblIn; - Point input {babymontgomery} addIn; - Point output {babymontgomery} dblOut; - Point output {babymontgomery} addOut; - - component doubler = MontgomeryDouble(); - component adder = MontgomeryAdd(); - component selector = Multiplexor2(); - - - sel ==> selector.sel; - - dblIn ==> doubler.pin; - doubler.pout ==> adder.pin1; - addIn ==> adder.pin2; - addIn.x ==> selector.in[0][0]; - addIn.y ==> selector.in[0][1]; - adder.pout.x ==> selector.in[1][0]; - adder.pout.y ==> selector.in[1][1]; - - doubler.pout ==> dblOut; - selector.out[0] ==> addOut.x; - selector.out[1] ==> addOut.y; -} - -// pin is edwards point -// n must be <= 248 -// returns pout in twisted edwards -// dbl is in montgomery to be linked; - -template SegmentMulAny(n) { - BinaryNumber(n) input e; - Point input {babyedwards} pin; - Point output {babyedwards} pout; - Point output {babymontgomery} dbl; - - component bits[n-1]; - - component e2m = Edwards2Montgomery(); - - pin ==> e2m.pin; - - var i; - - bits[0] = BitElementMulAny(); - e2m.pout ==> bits[0].dblIn; - e2m.pout ==> bits[0].addIn; - e.bits[1] ==> bits[0].sel; - - for (i=1; i bits[i].dblIn; - bits[i-1].addOut ==> bits[i].addIn; - e.bits[i+1] ==> bits[i].sel; - } - - bits[n-2].dblOut ==> dbl; - - component m2e = Montgomery2Edwards(); - - bits[n-2].addOut ==> m2e.pin; - - component eadder = BabyAdd(); - - m2e.pout ==> eadder.p1; - -pin.x ==> eadder.p2.x; - pin.y ==> eadder.p2.y; - - component lastSel = Multiplexor2(); - - e.bits[0] ==> lastSel.sel; - eadder.pout.x ==> lastSel.in[0][0]; - eadder.pout.y ==> lastSel.in[0][1]; - m2e.pout.x ==> lastSel.in[1][0]; - m2e.pout.y ==> lastSel.in[1][1]; - - lastSel.out[0] ==> pout.x; - lastSel.out[1] ==> pout.y; -} - -// This function assumes that p is in the subgroup and it is different to 0 - -template EscalarMulAny(n) { - BinaryNumber(n) input e; // Input in binary format - Point input {babyedwards} pin; // Point (Twisted format) - Point output {babyedwards} pout; // Point (Twisted format) - - var nsegments = (n-1)\148 +1; - var nlastsegment = n - (nsegments-1)*148; - - component segments[nsegments]; - component doublers[nsegments-1]; - component m2e[nsegments-1]; - component adders[nsegments-1]; - component zeropoint = IsZero(); - zeropoint.in <== pin.x; - - var s; - var i; - var nseg; - - for (s=0; s segments[s].e.bits[i]; - } - - if (s==0) { - // force G8 point if input point is zero - segments[s].pin.x <== pin.x + (5299619240641551281634865583518297030282874472190772894086521144482721001553 - pin.x)*zeropoint.out; - segments[s].pin.y <== pin.y + (16950150798460657717958625567821834550301663161624707787222815936182638968203 - pin.y)*zeropoint.out; - } else { - doublers[s-1] = MontgomeryDouble(); - m2e[s-1] = Montgomery2Edwards(); - adders[s-1] = BabyAdd(); - - segments[s-1].dbl ==> doublers[s-1].pin; - doublers[s-1].pout ==> m2e[s-1].pin; - m2e[s-1].pout ==> segments[s].pin; - - if (s==1) { - segments[s-1].pout ==> adders[s-1].p1; - } else { - adders[s-2].pout ==> adders[s-1].p1; - } - segments[s].pout ==> adders[s-1].p2; - } - } - - if (nsegments == 1) { - segments[0].pout.x*(1-zeropoint.out) ==> pout.x; - segments[0].pout.y+(1-segments[0].pout.y)*zeropoint.out ==> pout.y; - } else { - adders[nsegments-2].pout.x*(1-zeropoint.out) ==> pout.x; - adders[nsegments-2].pout.y+(1-adders[nsegments-2].pout.y)*zeropoint.out ==> pout.y; - } -} \ No newline at end of file diff --git a/tests/circomlib/escalarmulfix.circom b/tests/circomlib/escalarmulfix.circom deleted file mode 100644 index eefb8a330..000000000 --- a/tests/circomlib/escalarmulfix.circom +++ /dev/null @@ -1,292 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.1.5; - -include "mux3.circom"; -include "montgomery.circom"; -include "babyjub.circom"; -include "bitify.circom"; - -/* - - The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243 - First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B - - Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B - - And Finaly we compute the result: RES = SQ - Q - - As you can see the input of the adders cannot be equal nor zero, except for the last - substraction that it's done in montgomery. - - A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input - is the output of the windows that it's going to be <= 2^246*B -*/ - -/* - -*** WindowMulFix(): template that given a point in Montgomery representation base and a binary input in, calculates: - out = base + base*in[0] + 2*base*in[1] + 4*base*in[2] - out8 = 8*base - - This circuit is used in order to multiply a fixed point of the BabyJub curve by a escalar (k * p with p a fixed point of the curve). - - Inputs: in[3] -> binary value - requires tag binary - base -> input curve point in Montgomery representation - - Outputs: out -> output curve point in Montgomery representation - out8 -> output curve point in Montgomery representation - - */ - -template WindowMulFix() { - BinaryNumber(3) input in; - Point input {babymontgomery} base; - Point output {babymontgomery} out; - Point output {babymontgomery} out8; // Returns 8*Base (To be linked) - - component mux = MultiMux3(2); - - mux.s <== in.bits; - - component dbl2 = MontgomeryDouble(); - component adr3 = MontgomeryAdd(); - component adr4 = MontgomeryAdd(); - component adr5 = MontgomeryAdd(); - component adr6 = MontgomeryAdd(); - component adr7 = MontgomeryAdd(); - component adr8 = MontgomeryAdd(); - -// in[0] -> 1*BASE - - mux.c[0][0] <== base.x; - mux.c[1][0] <== base.y; - -// in[1] -> 2*BASE - - dbl2.pin <== base; - mux.c[0][1] <== dbl2.pout.x; - mux.c[1][1] <== dbl2.pout.y; - -// in[2] -> 3*BASE - - adr3.pin1 <== base; - adr3.pin2 <== dbl2.pout; - mux.c[0][2] <== adr3.pout.x; - mux.c[1][2] <== adr3.pout.y; - -// in[3] -> 4*BASE - - adr4.pin1 <== base; - adr4.pin2 <== adr3.pout; - mux.c[0][3] <== adr4.pout.x; - mux.c[1][3] <== adr4.pout.y; - -// in[4] -> 5*BASE - - adr5.pin1 <== base; - adr5.pin2 <== adr4.pout; - mux.c[0][4] <== adr5.pout.x; - mux.c[1][4] <== adr5.pout.y; - -// in[5] -> 6*BASE - - adr6.pin1 <== base; - adr6.pin2 <== adr5.pout; - mux.c[0][5] <== adr6.pout.x; - mux.c[1][5] <== adr6.pout.y; - -// in[6] -> 7*BASE - - adr7.pin1 <== base; - adr7.pin2 <== adr6.pout; - mux.c[0][6] <== adr7.pout.x; - mux.c[1][6] <== adr7.pout.y; - -// in[7] -> 8*BASE - - adr8.pin1 <== base; - adr8.pin2 <== adr7.pout; - mux.c[0][7] <== adr8.pout.x; - mux.c[1][7] <== adr8.pout.y; - - out8 <== adr8.pout; - - out.x <== mux.out[0]; - out.y <== mux.out[1]; -} - - -/* - -*** SegmentMulFix(nWindows): template used to perform a segment of the multiplications needed to perform a multiplication of a scalar times a fix base (k * BASE). - - Inputs: e[3 * nWindows] -> binary representation of the scalar - requires tag binary - base -> input curve point in Edwards representation - - Outputs: out -> output curve point in Edwards representation - dbl -> output curve point in Montgomery representation (to be linked to the next segment) - - */ - -template SegmentMulFix(nWindows) { - BinaryNumber(nWindows*3) input e; - Point input {babyedwards} base; - Point output {babyedwards} out; - Point output {babymontgomery} dbl; - - var i; - var j; - - // Convert the base to montgomery - - component e2m = Edwards2Montgomery(); - e2m.pin <== base; - - component windows[nWindows]; - component adders[nWindows]; - component cadders[nWindows]; - - // In the last step we add an extra doubler so that numbers do not match. - component dblLast = MontgomeryDouble(); - - for (i=0; i out; - - windows[nWindows-1].out8 ==> dbl; -} - - -/* - -*** EscalarMulFix(n, BASE): template that does a multiplication of a scalar times a fixed point BASE. - It receives a point in Edwards representation BASE and a binary input e representing a value k using n bits, - and calculates the point k * p. - - Inputs: e[n] -> binary representation of the scalar k - requires tag binary - - Outputs: out -> output curve point in Edwards representation, out = k * BASE - - */ - - -template EscalarMulFix(n, BASE) { - BinaryNumber(n) input e; // Input in binary format - Point output {babyedwards} out; // Point (Twisted format) - - var nsegments = (n-1)\246 + 1; // 249 probably would work. But I'm not sure and for security I keep 246 - var nlastsegment = n - (nsegments-1)*249; - - component segments[nsegments]; - - component m2e[nsegments-1]; - component adders[nsegments-1]; - - var s; - var i; - var nseg; - var nWindows; - - signal {binary} aux_0 <== 0; - - Point {babyedwards} aux; - for (s=0; s m2e[s-1].pin; - - m2e[s-1].pout ==> segments[s].base; - - if (s==1) { - segments[s-1].out ==> adders[s-1].p1; - } else { - adders[s-2].pout ==> adders[s-1].p1; - } - segments[s].out ==> adders[s-1].p2; - } - } - - if (nsegments == 1) { - segments[0].out ==> out; - } else { - adders[nsegments-2].pout ==> out; - } -} - - - diff --git a/tests/circomlib/montgomery.circom b/tests/circomlib/montgomery.circom deleted file mode 100644 index 62d65d881..000000000 --- a/tests/circomlib/montgomery.circom +++ /dev/null @@ -1,194 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ - - pragma circom 2.1.5; - -// The templates and functions of this file only work for finite field F_p = bn128, -// with the prime number p = 21888242871839275222246405745257275088548364400416034343698204186575808495617. - -/* - Source: https://en.wikipedia.org/wiki/Montgomery_curve - -*/ - -/* - The Baby-Jubjub Montgomery elliptic curve defined over the finite field bn128 is given by the equation - - B*v^2 = u^3 + A*u^2 + u, A = 168698, B = 1 - - This curve is birationally equivalent to the twisted Edwards elliptic curve - - a*x^2 + y^2 = 1 + d*x^2*y^2, a = 168700 = (A+2)/B, d = 168696 = (A-2)/B - - u u-1 1+y 1+y - via the map (u,v) -> (x,y) = [ --- , ----- ] with inverse (x,y) -> (u,v) = [ ----- , --------- ] - v u+1 1-y (1-y)*x - - Since a is not a square in bn128, the twisted Edwards curve is a quadratic twist of the Edwards curve - - x'^2 + y'^2 = 1 + d'*x'^2*y'^2 - - via the map (x,y) -> (x',y') = [ sqrt(a)*x , y ] - - where d' = 9706598848417545097372247223557719406784115219466060233080913168975159366771. - Here circuits are provided to transform a point of the Baby-Jubjub curve in twisted Edwards to its Montgomery form and vice versa. - Circuits to add and double points of the Baby-Jubjub Montgomery curve are provided as well. -*/ - -/* - spec tag babyedwards: 168700*(p.x)^2 + (p.y)^2 = 1 + 168696*(p.x)^2*(p.y)^2 - spec tag babymontgomery: (p.y)^2 = (p.x)^3 + 168698*(p.x)^2 + p.x -*/ - -bus Point { - signal x,y; -} - -/* -*** Edwards2Montgomery(): template that receives a point of the Baby-Jubjub curve in twisted Edwards form - and returns the equivalent point in Montgomery form. - - Inputs: pin -> bus representing a point of the Baby-Jubjub curve in twisted Edwards form - - Outputs: pout -> bus representing a point of the Baby-Jubjub curve in Montgomery form - - Map from twisted Edwards elliptic curve to its birationally equivalent Montgomery curve: - - 1 + y 1 + y - (x, y) -> (u, v) = [ ------- , ----------- ] - 1 - y (1 - y)*x - -*/ - -template Edwards2Montgomery() { - Point input {babyedwards} pin; - Point output {babymontgomery} pout; - - pout.x <-- (1 + pin.y) / (1 - pin.y); - pout.y <-- pout.x / pin.x; - - pout.x * (1 - pin.y) === (1 + pin.y); - pout.y * pin.x === pout.x; -} - -/* -*** Montgomery2Edwards(): template that receives an input pin representing a point of the Baby-Jubjub curve in Montgomery form - and returns the equivalent point in twisted Edwards form. - - Inputs: pin -> bus representing a point of the Baby-Jubjub curve in Montgomery form - - Outputs: pout -> bus representing a point of the curve Baby-Jubjub in twisted Edwards form - - Map from Montgomery elliptic curve to its birationally equivalent twisted Edwards curve: - - u u - 1 - (u, v) -> (x, y) = [ ---, ------- ] - v u + 1 - - */ - -template Montgomery2Edwards() { - Point input {babymontgomery} pin; - Point output {babyedwards} pout; - - pout.x <-- pin.x / pin.y; - pout.y <-- (pin.x - 1) / (pin.x + 1); - - pout.x * pin.y === pin.x; - pout.y * (pin.x + 1) === pin.x - 1; -} - - -/* -*** MontgomeryAdd(): template that receives two inputs pin1, pin2 representing points of the Baby-Jubjub curve in Montgomery form - and returns the addition of the points. - - Inputs: pin1 -> bus representing a point of the Baby-Jubjub curve in Montgomery form - pin2 -> bus representing a point of the Baby-Jubjub curve in Montgomery form - - Outputs: pout -> bus representing the point pin1 + pin2 of the Baby-Jubjub curve in Montgomery form - - Montgomery Addition Law: - - y2 - y1 y2 - y1 y2 - y1 - [x3, y3] = [x1, y1] + [x2, y2] = [ B*( --------- )^2 - A - x1 - x2, ( --------- )*(A + 2*x1 + x2) - B*( --------- )^3 - y1 ] - x2 - x1 x2 - x1 x2 - x1 - - y2 - y1 - lamda = --------- - x2 - x1 - - x3 = B*lamda^2 - A - x1 -x2 - - y3 = lamda*( x1 - x3 ) - y1 -*/ - -template MontgomeryAdd() { - Point input {babymontgomery} pin1, pin2; - Point output {babymontgomery} pout; - - var A = 168698; - var B = 1; - - signal lamda; - - lamda <-- (pin2.y - pin1.y) / (pin2.x - pin1.x); - lamda * (pin2.x - pin1.x) === pin2.y - pin1.y; - - pout.x <== B*lamda*lamda - A - pin1.x - pin2.x; - pout.y <== lamda * (pin1.x - pout.x) - pin1.y; -} - -/* -*** MontgomeryDouble(): template that receives an input pin representing a point of the Baby-Jubjub curve in Montgomery form - and returns the point 2 * pin. - - Inputs: pin -> bus representing a point of the Baby-Jubjub curve in Montgomery form - - Outputs: pout -> bus representing the point 2*pin of the Baby-Jubjub curve in Montgomery form - - - Montgomery Doubling Law: - - 3*x1^2 + 2*A*x1 + 1 3*x1^2 + 2*A*x1 + 1 3*x1^2 + 2*A*x1 + 1 - [x2, y2] = 2*[x1, y1] = [ B*( --------------------- )^2 - A - x1 - x2, ( --------------------- )*(A + 2*x1 + x2) - B*( --------------------- )^3 - y1 ] - 2*B*y1 2*B*y1 2*B*y1 - - x1_2 = x1*x1 - - 3*x1_2 + 2*A*x1 + 1 - lamda = --------------------- - 2*B*y1 - - x2 = B*lamda^2 - A - x1 -x1 - - y2 = lamda*( x1 - x2 ) - y1 - - */ - -template MontgomeryDouble() { - Point input {babymontgomery} pin; - Point output {babymontgomery} pout; - - var A = 168698; - var B = 1; - - signal lamda; - signal x1_2; - - x1_2 <== pin.x * pin.x; - - lamda <-- (3*x1_2 + 2*A*pin.x + 1) / (2*B*pin.y); - lamda * (2*B*pin.y) === (3*x1_2 + 2*A*pin.x + 1); - - pout.x <== B*lamda*lamda - A - 2*pin.x; - pout.y <== lamda * (pin.x - pout.x) - pin.y; -} \ No newline at end of file diff --git a/tests/circomlib/mux1.circom b/tests/circomlib/mux1.circom deleted file mode 100644 index eb0b896fc..000000000 --- a/tests/circomlib/mux1.circom +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -template MultiMux1(n) { - signal input c[n][2]; // Constants - signal input s; // Selector - signal output out[n]; - - for (var i=0; i mux.s; - - mux.out[0] ==> out; -} \ No newline at end of file diff --git a/tests/circomlib/mux2.circom b/tests/circomlib/mux2.circom deleted file mode 100644 index 31985d7ae..000000000 --- a/tests/circomlib/mux2.circom +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -template MultiMux2(n) { - signal input c[n][4]; // Constants - signal input s[2]; // Selector - signal output out[n]; - - signal a10[n]; - signal a1[n]; - signal a0[n]; - signal a[n]; - - signal s10; - s10 <== s[1] * s[0]; - - for (var i=0; i mux.s[i]; - } - - mux.out[0] ==> out; -} \ No newline at end of file diff --git a/tests/circomlib/mux3.circom b/tests/circomlib/mux3.circom deleted file mode 100644 index 6e05d8511..000000000 --- a/tests/circomlib/mux3.circom +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -template MultiMux3(n) { - signal input c[n][8]; // Constants - signal input s[3]; // Selector - signal output out[n]; - - signal a210[n]; - signal a21[n]; - signal a20[n]; - signal a2[n]; - - signal a10[n]; - signal a1[n]; - signal a0[n]; - signal a[n]; - - // 4 constrains for the intermediary variables - signal s10; - s10 <== s[1] * s[0]; - - for (var i=0; i mux.s[i]; - } - - mux.out[0] ==> out; -} \ No newline at end of file diff --git a/tests/circomlib/mux4.circom b/tests/circomlib/mux4.circom deleted file mode 100644 index 29c3285a7..000000000 --- a/tests/circomlib/mux4.circom +++ /dev/null @@ -1,119 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -template MultiMux4(n) { - signal input c[n][16]; // Constants - signal input s[4]; // Selector - signal output out[n]; - - signal a3210[n]; - signal a321[n]; - signal a320[n]; - signal a310[n]; - signal a32[n]; - signal a31[n]; - signal a30[n]; - signal a3[n]; - - signal a210[n]; - signal a21[n]; - signal a20[n]; - signal a10[n]; - signal a2[n]; - signal a1[n]; - signal a0[n]; - signal a[n]; - - // 4 constrains for the intermediary variables - signal s10; - s10 <== s[1] * s[0]; - signal s20; - s20 <== s[2] * s[0]; - signal s21; - s21 <== s[2] * s[1]; - signal s210; - s210 <== s21 * s[0]; - - - for (var i=0; i mux.s[i]; - } - - mux.out[0] ==> out; -} \ No newline at end of file diff --git a/tests/circomlib/pedersen.circom b/tests/circomlib/pedersen.circom deleted file mode 100644 index 2beb6e414..000000000 --- a/tests/circomlib/pedersen.circom +++ /dev/null @@ -1,224 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "montgomery.circom"; -include "mux3.circom"; -include "babyjub.circom"; - -template Window4() { - BinaryNumber(4) input in; - Point input {babymontgomery} base; - Point output {babymontgomery} out; - Point output {babymontgomery} out8; // Returns 8*Base (To be linked) - - component mux = MultiMux3(2); - - mux.s <== in.bits; - - component dbl2 = MontgomeryDouble(); - component adr3 = MontgomeryAdd(); - component adr4 = MontgomeryAdd(); - component adr5 = MontgomeryAdd(); - component adr6 = MontgomeryAdd(); - component adr7 = MontgomeryAdd(); - component adr8 = MontgomeryAdd(); - -// in[0] -> 1*BASE - - mux.c[0][0] <== base.x; - mux.c[1][0] <== base.y; - -// in[1] -> 2*BASE - dbl2.pin <== base; - mux.c[0][1] <== dbl2.pout.x; - mux.c[1][1] <== dbl2.pout.y; - -// in[2] -> 3*BASE - adr3.pin1 <== base; - adr3.pin2 <== dbl2.pout; - mux.c[0][2] <== adr3.pout.x; - mux.c[1][2] <== adr3.pout.y; - -// in[3] -> 4*BASE - adr4.pin1 <== base; - adr4.pin2 <== adr3.pout; - mux.c[0][3] <== adr4.pout.x; - mux.c[1][3] <== adr4.pout.y; - -// in[4] -> 5*BASE - adr5.pin1 <== base; - adr5.pin2 <== adr4.pout; - mux.c[0][4] <== adr5.pout.x; - mux.c[1][4] <== adr5.pout.y; - -// in[5] -> 6*BASE - adr6.pin1 <== base; - adr6.pin2 <== adr5.pout; - mux.c[0][5] <== adr6.pout.x; - mux.c[1][5] <== adr6.pout.y; - -// in[6] -> 7*BASE - adr7.pin1 <== base; - adr7.pin2 <== adr6.pout; - mux.c[0][6] <== adr7.pout.x; - mux.c[1][6] <== adr7.pout.y; - -// in[7] -> 8*BASE - adr8.pin1 <== base; - adr8.pin2 <== adr7.pout; - mux.c[0][7] <== adr8.pout.x; - mux.c[1][7] <== adr8.pout.y; - - out8 <== adr8.pout; - - out.x <== mux.out[0]; - out.y <== - mux.out[1]*2*in.bits[3] + mux.out[1]; // Negate y if in[3] is one -} - - -template Segment(nWindows) { - BinaryNumber(nWindows*4) input in; - Point input {babyedwards} base; - Point output {babyedwards} out; - - var i; - var j; - - // Convert the base to montgomery - - component e2m = Edwards2Montgomery(); - e2m.pin <== base; - - component windows[nWindows]; - component doublers1[nWindows-1]; - component doublers2[nWindows-1]; - component adders[nWindows-1]; - - for (i=0; i 1) { - m2e.pin <== adders[nWindows-2].pout; - } else { - m2e.pin <== windows[0].out; - } - - out <== m2e.pout; -} - -template Pedersen(n) { - BinaryNumber(n) input in; - Point output {babyedwards} pout; - - var BASE[10][2] = [ - [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317], - [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094], - [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896], - [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654], - [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506], - [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003], - [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236], - [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695], - [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506], - [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481] - - ]; - - var nSegments = ((n-1)\200)+1; - - component segments[nSegments]; - - var i; - var j; - var nBits; - var nWindows; - for (i=0; i1) { - packPoint.in[0] <== adders[nSegments-2].xout; - packPoint.in[1] <== adders[nSegments-2].yout; - } else { - packPoint.in[0] <== segments[0].out[0]; - packPoint.in[1] <== segments[0].out[1]; - } - - out[0] <== packPoint.out[0]; - out[1] <== packPoint.out[1]; -*/ - - if (nSegments>1) { - pout <== adders[nSegments-2].pout; - } else { - pout <== segments[0].out; - } -} \ No newline at end of file diff --git a/tests/circomlib/pointbits.circom b/tests/circomlib/pointbits.circom deleted file mode 100644 index 480c1f658..000000000 --- a/tests/circomlib/pointbits.circom +++ /dev/null @@ -1,181 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "bitify.circom"; -include "aliascheck.circom"; -include "compconstant.circom"; -include "babyjub.circom"; - - -function sqrt(n) { - - if (n == 0) { - return 0; - } - - // Test that have solution - var res = n ** ((-1) >> 1); -// if (res!=1) assert(false, "SQRT does not exists"); - if (res!=1) return 0; - - var m = 28; - var c = 19103219067921713944291392827692070036145651957329286315305642004821462161904; - var t = n ** 81540058820840996586704275553141814055101440848469862132140264610111; - var r = n ** ((81540058820840996586704275553141814055101440848469862132140264610111+1)>>1); - var sq; - var i; - var b; - var j; - - while ((r != 0)&&(t != 1)) { - sq = t*t; - i = 1; - while (sq!=1) { - i++; - sq = sq*sq; - } - - // b = c ^ m-i-1 - b = c; - for (j=0; j< m-i-1; j ++) b = b*b; - - m = i; - c = b*b; - t = t*c; - r = r*b; - } - - if (r < 0 ) { - r = -r; - } - - return r; -} - -bus BinaryPoint(n) { - BinaryNumber(n) binY; - signal {binary} signX; -} - - -template Bits2Point(n) { - BinaryPoint(n) input {babyedwardsbin} in; - Point output {babyedwards} pout; - - var i; - - // Check aliasing - component b2nY = Bits2Num(n); - b2nY.in <== in.binY; - pout.y <== b2nY.out; - - var a = 168700; - var d = 168696; - - var y2 = pout.y * pout.y; - - var x = sqrt( (1-y2)/(a - d*y2) ); - - if (in.signX == 1) x = -x; - - pout.x <-- x; - - component babyCheck = BabyCheck(); - babyCheck.pin <== pout; - - component n2bX = Num2Bits(n); - n2bX.in <== pout.x; - - component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); - signCalc.in <== n2bX.out; - - signCalc.out === in.signX; -} - -template Bits2Point_Strict() { - BinaryPoint(254) input {babyedwardsbin} in; - Point output {babyedwards} pout; - - var i; - - // Check aliasing - component b2nsY = Bits2Num_strict(); - b2nsY.in <== in.binY; - pout.y <== b2nsY.out; - - var a = 168700; - var d = 168696; - - var y2 = pout.y * pout.y; - - var x = sqrt( (1-y2)/(a - d*y2) ); - - if (in.signX == 1) x = -x; - - pout.x <-- x; - - component babyCheck = BabyCheck(); - babyCheck.pin <== pout; - - component n2bsX = Num2Bits_strict(); - n2bsX.in <== pout.x; - - component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); - signCalc.in <== n2bsX.out; - - signCalc.out === in.signX; -} - - -template Point2Bits(n) { - Point input {babyedwards} pin; - BinaryPoint(n) output {babyedwardsbin} out; - - var i; - - component n2bX = Num2Bits(n); - n2bX.in <== pin.x; - component n2bY = Num2Bits(n); - n2bY.in <== pin.y; - - component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); - signCalc.in <== n2bX.out; - - out.binY <== n2bY.out; - out.signX <== signCalc.out; -} - -template Point2Bits_Strict() { - Point input {babyedwards} pin; - BinaryPoint(254) output {babyedwardsbin} out; - - var i; - - component n2bsX = Num2Bits_strict(); - n2bsX.in <== pin.x; - component n2bsY = Num2Bits_strict(); - n2bsY.in <== pin.y; - - component signCalc = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); - signCalc.in <== n2bsX.out; - - out.binY <== n2bsY.out; - out.signX <== signCalc.out; -} \ No newline at end of file diff --git a/tests/circomlib/sign.circom b/tests/circomlib/sign.circom deleted file mode 100644 index 8f4bdb5c6..000000000 --- a/tests/circomlib/sign.circom +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ -pragma circom 2.0.0; - -include "compconstant.circom"; - -template Sign() { - BinaryNumber(254) input in; - signal output sign; - - component comp = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808); - - var i; - - comp.in <== in; - sign <== comp.out; -} \ No newline at end of file diff --git a/tests/circomlib/switcher.circom b/tests/circomlib/switcher.circom deleted file mode 100644 index cc102be42..000000000 --- a/tests/circomlib/switcher.circom +++ /dev/null @@ -1,42 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ - -/* - Assume sel is binary. - - If sel == 0 then outL = L and outR=R - If sel == 1 then outL = R and outR=L - - */ - -pragma circom 2.0.0; - -template Switcher() { - signal input {binary} sel; - signal input L; - signal input R; - signal output outL; - signal output outR; - - signal aux; - - aux <== (R-L)*sel; // We create aux in order to have only one multiplication - outL <== aux + L; - outR <== -aux + R; -} \ No newline at end of file From 46868140d6658736d48c82bbace905b8ec29af58 Mon Sep 17 00:00:00 2001 From: miguelis Date: Fri, 4 Oct 2024 12:49:28 +0200 Subject: [PATCH 176/189] --O1 is now the default option. Updating the documentation accordingly. --- .../circom-insight/simplification.md | 8 +++++--- .../circom-language/formats/constraints-json.md | 17 +++++++++-------- .../formats/simplification-json.md | 12 ++++++------ mkdocs/docs/circom-language/formats/sym.md | 10 +++++----- .../docs/getting-started/compilation-options.md | 2 +- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/mkdocs/docs/circom-language/circom-insight/simplification.md b/mkdocs/docs/circom-language/circom-insight/simplification.md index 244025ccb..06273cfda 100644 --- a/mkdocs/docs/circom-language/circom-insight/simplification.md +++ b/mkdocs/docs/circom-language/circom-insight/simplification.md @@ -1,6 +1,6 @@ # Constraint simplification -Constraint simplification is a key part of the `circom` compiler. Full simplification is activated by default, and its associated flag is `--O2` (see the [compilation options](../../getting-started/compilation-options.md)). Simplification is not applied when the flag `--O0` is activated, and a weaker (and faster) form of simplification is applied when using the flag `--O1`. +Constraint simplification is a key part of the `circom` compiler. A fast simplification `--O1` is activated by default (it only applies constant and renaming simplifications), and its associated flag is `--O1` (see the [compilation options](../../getting-started/compilation-options.md)). Simplification is not applied when the flag `--O0` is activated, and a full form of simplification is applied when using the flag `--O2`. Let us explain the performed simplification in detail. @@ -16,7 +16,7 @@ In the context of [Groth16], the statement to be proved is that given the public In case we are using the PLONK proof system (instead of Groth16), since additions are not free we cannot remove linear constraints anymore. Still we can remove equalities between signals or equalities between signals and constants which is made with the flag --O1 (see below). Moreover, note that if we apply linear simplification to a constraint system in PLONK format, the resulting constraints will in general not be in PLONK format anymore, and transforming the result back to PLONK format may lead to a worse result than the original. For this reason, when using PLONK, it is always recommended to use the --O1 flag. -Once we have explained why removing any private signal (including the private inputs) and applying linear simplification is correct, let us explain what kind of simplification is applied when we enable the flag `--O1` or the flag `--O2` (which is activated by default). Notice that if we do not want to apply any simplification we must use the flag `--O0`. +Once we have explained why removing any private signal (including the private inputs) and applying linear simplification is correct, let us explain what kind of simplification is applied when we enable the flag `--O1` (which is activated by default) or the flag `--O2`. Notice that if we do not want to apply any simplification we must use the flag `--O0`. * Flag ```--O1``` removes two kinds of simple constraints: a) ```signal = K```, being K is a constant in $F_p$ and b) ```signal1 = signal2```. In both cases, at least one of the signals must be private, and it is the one that will be replaced by the other side. Note that there are usually many equalities between two signals in constraints defined by circom programs as they are many times used to connect components with their sub components. @@ -30,6 +30,8 @@ Only one of these flags/options can be enabled in the compilation. In case we want to see the simplification applied we can use the flag [```--simplification_substitution```](../../getting-started/compilation-options.md) to obtain a json file whose format is described [here](../formats/simplification-json.md). -Note that, although the full simplification applied `--O2` can significantly reduce the number of constraints and signals, which has a positive impact in the time and space needed to compute the proof, this is the most time and space consuming phase of the compilation process. Hence, with large circuits, say with millions of constraints, compilation can take a long time (even minutes or hours) and can run in out-of-memory exceptions. In such cases, it is recommended to only use the `--O2` flag in the final steps of the project development. +Starting with circom 2.2.0, we have set `--O1` as the default simplification option. This decision aligns with the growing use of Plonk, as `--O2` is not compatible with it. + +Note that, using the full simplification `--O2` can significantly reduce the number of constraints and signals, which has a positive impact in the time and space needed to compute the proof. However, this is the most time and space consuming phase of the compilation process. Hence, with large circuits, say with millions of constraints, compilation can take a long time (even minutes or hours) and can run in out-of-memory exceptions. In such cases, it is recommended to only use the `--O2` flag in the final steps of the project development. [Groth16] Jens Groth. "On the Size of Pairing-Based Non-interactive Arguments". Advances in Cryptology -- EUROCRYPT 2016, pages 305--326. Springer Berlin Heidelberg, 2016. diff --git a/mkdocs/docs/circom-language/formats/constraints-json.md b/mkdocs/docs/circom-language/formats/constraints-json.md index cff7e63dc..31b9be1a7 100644 --- a/mkdocs/docs/circom-language/formats/constraints-json.md +++ b/mkdocs/docs/circom-language/formats/constraints-json.md @@ -47,19 +47,21 @@ template Main() { if we run ```text -circom simplify.circom --json --wasm +circom basic.circom --json --wasm ``` -a file 'basic_contraints.json' is generated that contains +a file 'basic_contraints.json' is generated and it contains two constraints: ```text { "constraints": [ -[{"2":"21888242871839275222246405745257275088548364400416034343698204186575808495616"},{"0":"1","2":"2","3":"1"},{"1":"21888242871839275222246405745257275088548364400416034343698204186575808495616"}] +[{"2":"21888242871839275222246405745257275088548364400416034343698204186575808495616"},{"4":"1"},{"1":"21888242871839275222246405745257275088548364400416034343698204186575808495616"}], +[{},{},{"0":"1","2":"2","3":"1","4":"21888242871839275222246405745257275088548364400416034343698204186575808495616"}] ] } ``` -where we can see that only one constraint is taken after applying the simplification (since the --O2 simplification is the default). + As we can see, only constant and renaming (equalities between signals) simplifications have been aplied +(since the --O1 simplification is the default). Instead, if we run @@ -82,16 +84,15 @@ to indicate that we do not want to apply any simplification the generated file ' Finaly, if we run ```text -circom basic.circom --json --wasm --O1 +circom basic.circom --json --wasm --O2 ``` -to indicate that we only want to apply constant and renaming (equalities between signals) simplifications, the generated file 'basic_constraints.json' contains +we can see that only one constraint is taken after applying the full simplification: ```text { "constraints": [ -[{"2":"21888242871839275222246405745257275088548364400416034343698204186575808495616"},{"4":"1"},{"1":"21888242871839275222246405745257275088548364400416034343698204186575808495616"}], -[{},{},{"0":"1","2":"2","3":"1","4":"21888242871839275222246405745257275088548364400416034343698204186575808495616"}] +[{"2":"21888242871839275222246405745257275088548364400416034343698204186575808495616"},{"0":"1","2":"2","3":"1"},{"1":"21888242871839275222246405745257275088548364400416034343698204186575808495616"}] ] } ``` diff --git a/mkdocs/docs/circom-language/formats/simplification-json.md b/mkdocs/docs/circom-language/formats/simplification-json.md index 7e582f6fc..4d1034e83 100644 --- a/mkdocs/docs/circom-language/formats/simplification-json.md +++ b/mkdocs/docs/circom-language/formats/simplification-json.md @@ -47,12 +47,11 @@ a file 'simplify_substitutions.json' is generated that contains ```text { "5" : {"2":"1"}, -"4" : {"1":"1"}, -"6" : {"0":"1","2":"2","3":"1"} +"4" : {"1":"1"} } ``` -where we can see that three signals have been substituted (since the --O2 simplification is the default). +where we can see that two signals have been substituted (since the `--O1` simplification is the default). Instead, if we run @@ -69,14 +68,15 @@ to indicate that we do not want to apply any simplification, the generated file Finally, if we run ```text -circom simplify.circom --r1cs --wasm --simplification_substitution --O1 +circom simplify.circom --r1cs --wasm --simplification_substitution --O2 ``` -to indicate that we only want to apply constant and renaming (equalities between signals) simplifications, the generated file 'simplify_substitutions.json' contains +to indicate that we want to apply the full form of simplification, the generated file 'simplify_substitutions.json' contains: ```text { "5" : {"2":"1"}, -"4" : {"1":"1"} +"4" : {"1":"1"}, +"6" : {"0":"1","2":"2","3":"1"} } ``` diff --git a/mkdocs/docs/circom-language/formats/sym.md b/mkdocs/docs/circom-language/formats/sym.md index a64cfc0a7..ea7dd7cf9 100644 --- a/mkdocs/docs/circom-language/formats/sym.md +++ b/mkdocs/docs/circom-language/formats/sym.md @@ -48,10 +48,10 @@ a file 'symbols.sym' is generated that contains 3,3,1,main.in[1] 4,-1,0,main.c.out 5,-1,0,main.c.in[0] -6,-1,0,main.c.in[1] +6,4,0,main.c.in[1] ``` -where we can see that three signals have been eliminated (since the --O2 simplification is the default). +where we can see that two signals have been eliminated (since the `--O1` simplification is the default). Instead, if we run @@ -72,10 +72,10 @@ to indicate that we do not want to apply any simplification the generated file ' Finally, if we run ```text -circom symbols.circom --r1cs --wasm --sym --O1 +circom symbols.circom --r1cs --wasm --sym --O2 ``` -to indicate that we only want to apply constant and renaming (equalities between signals) simplifications the generated file 'symbols.sym' contains +to indicate that we want to apply the full form of simplification, the generated file 'symbols.sym' contains ```text 1,1,1,main.out @@ -83,5 +83,5 @@ to indicate that we only want to apply constant and renaming (equalities between 3,3,1,main.in[1] 4,-1,0,main.c.out 5,-1,0,main.c.in[0] -6,4,0,main.c.in[1] +6,-1,0,main.c.in[1] ``` diff --git a/mkdocs/docs/getting-started/compilation-options.md b/mkdocs/docs/getting-started/compilation-options.md index 229e4628e..aec3befd1 100644 --- a/mkdocs/docs/getting-started/compilation-options.md +++ b/mkdocs/docs/getting-started/compilation-options.md @@ -39,7 +39,7 @@ In the following, we explain these options. ##### Flags and options related to the compiler's output * Flag ```--r1cs``` outputs the constraints in binary R1CS format (see the detailed format [here](https://github.com/iden3/r1csfile/blob/master/doc/r1cs_bin_format.md)). * Flag ```--sym``` outputs for every signal of the circuit: the unique number given by the compiler, the circom qualified name, the number of the witness signal that contains it and the (unique) number of the component (given by the compiler) it belongs (see the detailed format and examples [here](../circom-language/formats/sym.md)). -* Flag ```--simplification_substitution``` outputs the substitutions performed by the --O1 and --O2 (default) constraint simplification options in json format (see the detailed format [here](../circom-language/formats/simplification-json.md)). +* Flag ```--simplification_substitution``` outputs the substitutions performed by the --O1 (default) and --O2 constraint simplification options in json format (see the detailed format [here](../circom-language/formats/simplification-json.md)). * Flag ```--wasm``` produces a WebAssembly program that receives the private and public inputs and generates the circuit witness. * Flag ```-c / --c``` produces a C++ program that receives the private and public inputs and generates the circuit witness. * Flag ```--wat``` compiles the circuit to wat. From 1f3bb1263467e9de1afc7aead3c447e5c9dd2c99 Mon Sep 17 00:00:00 2001 From: Miguel Isabel Date: Fri, 4 Oct 2024 13:14:07 +0200 Subject: [PATCH 177/189] Update RELEASES.md --- RELEASES.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 182e2b6ed..f991c7e35 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,21 @@ # Release notes +## October 04, 2024 circom 2.2.0 +#### New features +- Buses: more information [here](https://github.com/iden3/circom/blob/master/mkdocs/docs/circom-language/buses.md). + +#### Extensions +- input/output declaration can now be made before signal keyword, though the previous way remains supported. +- Allowing array assignments of different sizes. +- Improving error reports when parsing. +- Improving documentation. + +#### Fixed bugs +- Main with no inputs is now executed once. +- Fixing complement function to depend on the prime number used. +- Applying modulo prime number to any constant in the circuit. +- Fixing minor panic: the number of signals passed to the anonymous component must be equal to the actual number of inputs. + + ## April 23, 2024 circom 2.1.9 #### Extensions From 71a368c4b2378630ee740f6237b0bcb03bca8a8e Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:48:02 +0200 Subject: [PATCH 178/189] Update simplification.md --- mkdocs/docs/circom-language/circom-insight/simplification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs/docs/circom-language/circom-insight/simplification.md b/mkdocs/docs/circom-language/circom-insight/simplification.md index 06273cfda..d74329f09 100644 --- a/mkdocs/docs/circom-language/circom-insight/simplification.md +++ b/mkdocs/docs/circom-language/circom-insight/simplification.md @@ -2,7 +2,7 @@ Constraint simplification is a key part of the `circom` compiler. A fast simplification `--O1` is activated by default (it only applies constant and renaming simplifications), and its associated flag is `--O1` (see the [compilation options](../../getting-started/compilation-options.md)). Simplification is not applied when the flag `--O0` is activated, and a full form of simplification is applied when using the flag `--O2`. -Let us explain the performed simplification in detail. +Let us explain the kind of simplification we can perform in detail. As pointed out in Section 2.3 (Quadratic arithmetic programs) of the [Groth16 paper](https://eprint.iacr.org/2016/260) (where ZK-SNARKs based on arithmetic circuits were introduced): From 6f6bfed1100ad115e7d3af37c0d9c5d8ffcbaff2 Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:49:46 +0200 Subject: [PATCH 179/189] Update RELEASES.md --- RELEASES.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index f991c7e35..69204ddd2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,9 +2,12 @@ ## October 04, 2024 circom 2.2.0 #### New features - Buses: more information [here](https://github.com/iden3/circom/blob/master/mkdocs/docs/circom-language/buses.md). - + +#### Changes +- input/output keywords are the first token in declarations (though having it after "signal" is still accepted). +- The default option for constraint simplification is --O1 (instead of --O2 which was the default until now). More information in [here](https://github.com/iden3/circom/blob/master/mkdocs/docs/circom-language/circom-insight/simplification.md). + #### Extensions -- input/output declaration can now be made before signal keyword, though the previous way remains supported. - Allowing array assignments of different sizes. - Improving error reports when parsing. - Improving documentation. From 503a54e2e3db058ba58ae0da8272a808e1e7b795 Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:14:07 +0200 Subject: [PATCH 180/189] Update simplification.md --- mkdocs/docs/circom-language/circom-insight/simplification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs/docs/circom-language/circom-insight/simplification.md b/mkdocs/docs/circom-language/circom-insight/simplification.md index d74329f09..5b99baec7 100644 --- a/mkdocs/docs/circom-language/circom-insight/simplification.md +++ b/mkdocs/docs/circom-language/circom-insight/simplification.md @@ -30,7 +30,7 @@ Only one of these flags/options can be enabled in the compilation. In case we want to see the simplification applied we can use the flag [```--simplification_substitution```](../../getting-started/compilation-options.md) to obtain a json file whose format is described [here](../formats/simplification-json.md). -Starting with circom 2.2.0, we have set `--O1` as the default simplification option. This decision aligns with the growing use of Plonk, as `--O2` is not compatible with it. +Since circom 2.2.0, we have set `--O1` as the default simplification option. This decision aligns with the growing use of Plonk, as `--O2` is not compatible with it. Note that, using the full simplification `--O2` can significantly reduce the number of constraints and signals, which has a positive impact in the time and space needed to compute the proof. However, this is the most time and space consuming phase of the compilation process. Hence, with large circuits, say with millions of constraints, compilation can take a long time (even minutes or hours) and can run in out-of-memory exceptions. In such cases, it is recommended to only use the `--O2` flag in the final steps of the project development. From 5facb07c9803e22e65d6a37b28dfcb2ed5235c1c Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 4 Oct 2024 14:31:35 +0200 Subject: [PATCH 181/189] updating version to 2.2.0 --- Cargo.lock | 18 +++++++++--------- circom/Cargo.toml | 2 +- circom_algebra/Cargo.toml | 2 +- code_producers/Cargo.toml | 2 +- compiler/Cargo.toml | 2 +- constraint_generation/Cargo.toml | 2 +- dag/Cargo.toml | 2 +- parser/Cargo.toml | 2 +- program_structure/Cargo.toml | 2 +- type_analysis/Cargo.toml | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d82e1294..c20ef2532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,7 +105,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "circom" -version = "2.1.9" +version = "2.2.0" dependencies = [ "ansi_term", "clap", @@ -122,7 +122,7 @@ dependencies = [ [[package]] name = "circom_algebra" -version = "2.1.4" +version = "2.2.0" dependencies = [ "constant_tracking", "num-bigint-dig", @@ -146,7 +146,7 @@ dependencies = [ [[package]] name = "code_producers" -version = "2.1.9" +version = "2.2.0" dependencies = [ "handlebars", "lz_fnv", @@ -175,7 +175,7 @@ dependencies = [ [[package]] name = "compiler" -version = "2.1.9" +version = "2.2.0" dependencies = [ "code_producers", "constant_tracking", @@ -190,7 +190,7 @@ version = "2.0.0" [[package]] name = "constraint_generation" -version = "2.1.9" +version = "2.2.0" dependencies = [ "ansi_term", "circom_algebra", @@ -250,7 +250,7 @@ dependencies = [ [[package]] name = "dag" -version = "2.1.8" +version = "2.2.0" dependencies = [ "circom_algebra", "constraint_list", @@ -655,7 +655,7 @@ dependencies = [ [[package]] name = "parser" -version = "2.1.9" +version = "2.2.0" dependencies = [ "lalrpop", "lalrpop-util", @@ -754,7 +754,7 @@ dependencies = [ [[package]] name = "program_structure" -version = "2.1.9" +version = "2.2.0" dependencies = [ "codespan", "codespan-reporting", @@ -1047,7 +1047,7 @@ dependencies = [ [[package]] name = "type_analysis" -version = "2.1.9" +version = "2.2.0" dependencies = [ "num-bigint-dig", "num-traits", diff --git a/circom/Cargo.toml b/circom/Cargo.toml index 0f0879078..1d8460576 100644 --- a/circom/Cargo.toml +++ b/circom/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "circom" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/circom_algebra/Cargo.toml b/circom_algebra/Cargo.toml index 30e713dbf..2ac52577b 100644 --- a/circom_algebra/Cargo.toml +++ b/circom_algebra/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "circom_algebra" -version = "2.1.4" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/code_producers/Cargo.toml b/code_producers/Cargo.toml index dc024320d..7be46e41a 100644 --- a/code_producers/Cargo.toml +++ b/code_producers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "code_producers" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 0e8ef09d3..a211d6b87 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compiler" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/constraint_generation/Cargo.toml b/constraint_generation/Cargo.toml index faef4dd43..cfbc6a7a9 100644 --- a/constraint_generation/Cargo.toml +++ b/constraint_generation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "constraint_generation" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/dag/Cargo.toml b/dag/Cargo.toml index 403523089..4896145d5 100644 --- a/dag/Cargo.toml +++ b/dag/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dag" -version = "2.1.8" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 02a86510b..3da91d3c6 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parser" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" build = "build.rs" diff --git a/program_structure/Cargo.toml b/program_structure/Cargo.toml index 19417f0aa..6b88c1df9 100644 --- a/program_structure/Cargo.toml +++ b/program_structure/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "program_structure" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" diff --git a/type_analysis/Cargo.toml b/type_analysis/Cargo.toml index bccfbdf64..97b7881d3 100644 --- a/type_analysis/Cargo.toml +++ b/type_analysis/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "type_analysis" -version = "2.1.9" +version = "2.2.0" authors = ["Costa Group UCM","iden3"] edition = "2018" From db8e9cfea3fa175c2e7f8b8f62133dc21063c5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clara=20Rodr=C3=ADguez?= Date: Fri, 4 Oct 2024 14:53:35 +0200 Subject: [PATCH 182/189] Update mkdocs.yml --- mkdocs/mkdocs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkdocs/mkdocs.yml b/mkdocs/mkdocs.yml index 59ed4c0e6..c553bd39c 100644 --- a/mkdocs/mkdocs.yml +++ b/mkdocs/mkdocs.yml @@ -58,6 +58,8 @@ nav: - New features circom 2.1: - Anonymous Components and tuples: 'circom-language/anonymous-components-and-tuples.md' - Tags: 'circom-language/tags.md' + - New features circom 2.2: + - Buses: 'circom-language/buses.md' - Code Quality: - Code Assertion: 'circom-language/code-quality/code-assertion.md' - Debugging Operations: 'circom-language/code-quality/debugging-operations.md' From 6a57d80e1720b07097adefb5f56e0eefc6f25136 Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:54:51 +0200 Subject: [PATCH 183/189] Fixing examples in buses doc --- mkdocs/docs/circom-language/buses.md | 44 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/mkdocs/docs/circom-language/buses.md b/mkdocs/docs/circom-language/buses.md index 9d4ddc3c2..1a25d9261 100644 --- a/mkdocs/docs/circom-language/buses.md +++ b/mkdocs/docs/circom-language/buses.md @@ -20,7 +20,7 @@ bus NameBus(param1,...,paramN){ In many circuits we have pairs of signals `x` and `y`, which represent the two components of a point. With the new bus feature, we can define a `Point` bus as follows: ``` -bus Point{ +bus Point(){ signal x; signal y; } @@ -32,8 +32,8 @@ Using buses, we can modify many templates from the circomlib to make them more r ``` template Edwards2Montgomery () { - Point input { edwards_point } in ; - Point output { montgomery_point } out ; + input Point() { edwards_point } in ; + output Point() { montgomery_point } out ; out.x <–- (1 + in.y ) / (1 - in.y ) ; out.y <–- out.x / in.x ; @@ -51,7 +51,7 @@ But now, we can tag each bus with the corresponding expected format. Besides tagging buses defined in a template, we can also tag their different fields. Let us see this feature in the following example: ``` -bus Book { +bus Book () { signal {maxvalue} title[50]; signal {maxvalue} author[50]; signal {maxvalue} sold_copies; @@ -64,8 +64,8 @@ signal arrays `title` and `author` whose letters have a maximum value, the numb ``` template BestSeller2024(){ - Book input book; - Book output {best_seller2024} best_book; + input Book() book; + output Book() {best_seller2024} best_book; signal check_copies <== LessThan(book.sold_copies.maxvalue)([1000000,book.sold_copies]); check_copies === 1; signal check_2024 <== IsEqual()([book.year,2024]); @@ -86,13 +86,13 @@ bus B1(){ signal x; } -bus B2{ +bus B2() { signal x; } template B1toB2(){ - B1 input b1; - B2 output b2; + input B1() b1; + output B2() b2; b2 <== b1; } @@ -114,22 +114,22 @@ Consider again the `BestSeller2024` template and a possible instantiation: `Book We can have buses inside the definition other buses, as long as we do not define buses recursively. To illustrate this, let us consider now, a new kind of bus, `Person`, which contains some information about a person: ``` -bus Film{ +bus Film() { signal title[50]; signal director[50]; signal year; } -bus Date{ +bus Date() { signal day; signal month; signal year; } -bus Person{ +bus Person() { signal name[50]; - Film films[10]; - Date birthday; + Film() films[10]; + Date() birthday; } ``` @@ -139,7 +139,7 @@ Buses can have parameters as well. These parameters must be known during compila Let us generalize the `Point` bus for a given dimension. ``` -bus Point(dim){ +bus PointN(dim){ signal x[dim]; } ``` @@ -172,8 +172,8 @@ We define a `Triangle2D` bus with three lines whose points are 2-dimensional, an ``` template well_defined_figure(num_sides, dimension){ - Figure(num_sides,dimension) input t; - Figure(num_sides,dimension) {correct_t} output t; + input Figure(num_sides,dimension) t; + output Figure(num_sides,dimension) {well_defined} correct_t; var all_equals = 0; var isequal = 0; for(var i = 0; i < num_sides; i=i+1){ @@ -197,22 +197,22 @@ Similar to signals, buses can be part of the main circuit's inputs. Therefore, w Let us consider again the `Person` bus: ``` -bus Film{ +bus Film() { signal title[2]; signal director[2]; signal year; } -bus Date{ +bus Date() { signal day; signal month; signal year; } -bus Person{ +bus Person() { signal name[2]; - Film films[2]; - Date birthday; + Film() films[2]; + Date() birthday; } ``` From f28bb578b886461d7d1deba59793d1ac25309453 Mon Sep 17 00:00:00 2001 From: miguelis Date: Fri, 4 Oct 2024 22:54:07 +0200 Subject: [PATCH 184/189] Refactor variable tag analysis in unknown_known_analysis.rs --- .../src/analyzers/unknown_known_analysis.rs | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 6cab2edf7..61487d809 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -399,9 +399,9 @@ fn tag(expression: &Expression, environment: &Environment) -> Tag { use Tag::*; match expression { Number(_, _) => Known, - Variable { meta, name, access,.. } => { + Variable { meta, name,.. } => { let reduced_type = meta.get_type_knowledge().get_reduces_to(); - let mut symbol_tag = match reduced_type { + match reduced_type { TypeReduction::Variable => { let (tag, is_array) = environment.get_variable_or_break(name, file!(), line!()); if *is_array{ @@ -414,23 +414,6 @@ fn tag(expression: &Expression, environment: &Environment) -> Tag { TypeReduction::Bus(_) => Unknown, TypeReduction::Component(_) => *environment.get_component_or_break(name, file!(), line!()), TypeReduction::Tag => Known, - }; - - - let mut index = 0; - loop { - if index == access.len() { - break symbol_tag; - } - if symbol_tag == Unknown { - break Unknown; - } - if let Access::ArrayAccess(exp) = &access[index] { - symbol_tag = tag(exp, environment); - } else if !environment.has_intermediate(name) { - symbol_tag = Unknown; - } - index += 1; } } ArrayInLine { values, .. } From 16a07c64e2f5af1175dc1634bc68a52b90f9995e Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 4 Oct 2024 23:59:52 +0200 Subject: [PATCH 185/189] solving minor issue: access of bus tags --- constraint_generation/src/execute.rs | 34 +++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index cef5124cf..f48f26a47 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2806,8 +2806,40 @@ fn execute_bus( } Result::Ok(FoldedValue{bus_slice: Some((symbol.to_string(), bus_slice)), tags: Some(tags_propagated), ..FoldedValue::default()}) + } else if tags.contains_key(access_information.field_access.as_ref().unwrap()){ + // case tags + let acc = access_information.field_access.unwrap(); + let value_tag = tags.get(&acc).unwrap(); + let state = tags_definitions.get(&acc).unwrap(); + if let Some(value_tag) = value_tag { // tag has value + // access only allowed when (1) it is value defined by user or (2) it is completely assigned + if state.value_defined || state.complete{ + let a_value = AExpr::Number { value: value_tag.clone() }; + let ae_slice = AExpressionSlice::new(&a_value); + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) + } else{ + let error = MemoryError::TagValueNotInitializedAccess; + treat_result_with_memory_error( + Result::Err(error), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + + } + else { + let error = MemoryError::TagValueNotInitializedAccess; + treat_result_with_memory_error( + Result::Err(error), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + } else{ - // access to the field or tag + // access to the field or tag of a field let resulting_bus = safe_unwrap_to_single(bus_slice, line!()); let symbol = create_symbol_bus(symbol, &access_information); From 89e2443e3afb084e1dc02953a048eb898b5e7db0 Mon Sep 17 00:00:00 2001 From: Albert Rubio <34064782+alrubio@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:09:16 +0200 Subject: [PATCH 186/189] Minor --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 69204ddd2..3f7e198d1 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,5 @@ # Release notes -## October 04, 2024 circom 2.2.0 +## October 07, 2024 circom 2.2.0 #### New features - Buses: more information [here](https://github.com/iden3/circom/blob/master/mkdocs/docs/circom-language/buses.md). From e87b89f8c5cf7163fc464f287b992b8cd7ac35a8 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 7 Oct 2024 18:37:59 +0200 Subject: [PATCH 187/189] When --O2, we must apply --O2 --- circom/src/input_user.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/circom/src/input_user.rs b/circom/src/input_user.rs index 735ee5de6..88c46418f 100644 --- a/circom/src/input_user.rs +++ b/circom/src/input_user.rs @@ -263,8 +263,7 @@ mod input_processing { else {Ok(SimplificationStyle::O2(no_rounds))}} else { Result::Err(eprintln!("{}", Colour::Red.paint("invalid number of rounds"))) } }, - - (false, false, false, true) => Ok(SimplificationStyle::O1), + (false, false, false, true) => Ok(SimplificationStyle::O2(usize::MAX)), (false, false, false, false) => Ok(SimplificationStyle::O1), } } From 9fd40a34f42912ee52230f8b6a114d78f6df1a48 Mon Sep 17 00:00:00 2001 From: miguelis Date: Mon, 7 Oct 2024 18:50:34 +0200 Subject: [PATCH 188/189] Refactor help message for --O1 option in input_user.rs to clarify --O1 is the default option --- circom/src/input_user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circom/src/input_user.rs b/circom/src/input_user.rs index 88c46418f..d396d3dbd 100644 --- a/circom/src/input_user.rs +++ b/circom/src/input_user.rs @@ -367,7 +367,7 @@ mod input_processing { .long("O1") .hidden(false) .takes_value(false) - .help("Only applies signal to signal and signal to constant simplification") + .help("Only applies signal to signal and signal to constant simplification. This is the default option") .display_order(460) ) .arg( From 79fb0bc9f3c7be1edc91e23a05ad57e671a5ed51 Mon Sep 17 00:00:00 2001 From: Artem Chystiakov Date: Tue, 8 Oct 2024 18:12:39 +0300 Subject: [PATCH 189/189] wasm build 2.2.0 --- npm/bin/circom.wasm | Bin 10483819 -> 10701949 bytes npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm/bin/circom.wasm b/npm/bin/circom.wasm index 8acb4ac7d9e549a73bbf08c35489e25b5c164004..113844c18117de2137b631bbca23b3be6b36eda1 100755 GIT binary patch delta 2265717 zcmdSC34j#Ey+1zPb6-2N>@~YR3p2C#F1xcgh;p=wnkXJgRPtgB=HX(SAH0y2oQ9hsB{xcVs1;f>Wo}VgaR$G5({oOn00)f_SRaX|>sc*-pRR zhCfQPfmN%`<8eDF1vqi%c0$5Vm($|5x!kzXvRZ6}&t?-vQ8{SON#JVB;dtFPtJ7`^ zQAH@n|1o?vkjVk6PFGuQt~=L_2V5a;AL<}d^0KnBBuVn(pXBp7ygr}TC*c?Wq%5BV zb(;T_V}5%+2}-gcHo57xMR9R zEP}^D61P|il&8Hj(sDd*i`OCfJRV=6t4O)tcae~zJm&jJsJPhUv{SA0M_9D>snj?# zlzAD>%TQffL9`$mHA}aXd~J5Oo7eyk3=cTKA2CB5*nm@65X@0J{IT;yJ9g>5t z4!1L1@<}DGEW6hS<93uvkf$p>-I?w}!*)1)yiPJjCMt#nKEO+I^jMrWkHu{zow7eM zgw|yI*=z}>A86I^4x~uN1;YmF?D`#ATyCZ<$L4gohz5q!VR4YHFzbO6B7sBGBqOWU zV%1v!oPryUfV(*tb16iHM7V9!l#KMdc77Pw_<2 zG}xb&wTbK?&@1cGdWO?AD~1yitu`mj$j;g|l~cY;%PVE<+L-%>WdIM^0FY!;LDGfY zO^7|ppukVzHc?@YGBFTKFJr{g!YcV1pYxh$V6Q& zic-~R0l1Rufjl4txKIzZVW8z1nV2Xq<$`#r9a`XP@iYersd}m$n!^)vIKT)j_~R{C z#{1tw2&>z}n;QI8uFaak`YdA2 z4c7~z(BOa?4uLs77y}f|&=89rr~`&clo4|JqxMgaoaycasHYBzBmo9sjCy}(DZn4& zkZC|S9Kyr$^VX8*B9jMtcwr9Ni3tZeWoiq?g>EP(nVZ`WF+hc2=O%J^Br|H=_#Y}m zO?J>9a$zupmWpl-BmocehSbQ>_U&L1+*6JCgXfdHa6eR#{5attm#!QN<%2=eD-77h z{R&wQQ38_fjAYORkW>r-5fUaSU0S3(4<17>z?q(Ivv>#t*&q}R8fbV#{={ZSC3ZA2 z4-F06CE&>+Ngk`qD=GKq_6umEHctj=o4iNvC5kUEXE2&ChAyNHN(K%B$vyFYoh+Tq zFqifHP&JXR{W$X9+M-GL!z zZmzOPnmQl{Ou!roe_2_XtCF`NX7f;16?qoo(~5ByJT$BdcQ#uHH8^{h$CcUPs`8NN zr_mPu^@guPJ0shW+||^sYWN*JcjPEyeqZ>53-fF6dux6OzxU_&%FhrWs|*1uayv8V z7qX)f4g85ULwPm-N_URaQyYb0*D2XO>#g^Jw- z{=Vry#x?%sj{n(f{qy6E`>mf?KeisQ9&)?(dfo$VND+f+B! z_EGI?w$Zj%Y;CrcwxzZ;btkNk*-qFVuldOKwe6&Br}g`Wd+p8k&#cF-iC68b?XTO% zJJ;Da+BevzIo8-GHMF?a+uyKnwNG|#vmdpq&O`S7_5=1$>>t}dwI8%ka87nS;T+v? z+CItgv}20nNyk%;7RPkQR7b1hJ;&RQ&5pzNqmJ#4Db9Nx_c$gxCpjN?wlq$4j&Qu- ze95`QxzxGH`KGhg`I)oB`EtVfit}~n2-jlgI_Ia(-OfGEoz7j(W6p!lkDMEwhn?-t zz0OaZA2@e7k2?1|4>*rFKXmSMzUBPb`L6Rl=XU4&&h^eOo%gubINxx7R_SQmIJ zus*ONupzK9usN_PuqE(X;E=B+Fg@^8U`gQVz>L5%foB8H1!e|j2VM-!3Cs=53%n4R z6?i@{Kd>OMFt8}FIIz$^#{al~ynnQRoc}TZSpRGO`vWie_XgSn2LmhpOa0HJjSNmq z+Y`7yI3;aH+S6&1)1FLwDKH_>l6ETLU+~+~|v){~KpZ#6K zj_d>3Z)Lxp{YLgZIpZ52$ay?xY0k9J@#wnHTcHi1^`Xt7w?kV)+d}V#-V41S+7a3l zY7gxVeHhvoIuP0)Ivx5hG%j~+u9EwB?i0Cc?!?@kphhdv2?8af<0 z5;__>7U~Ec4`qE8`aE(SlU~Ye&3id-Y2GVJT}f0KR&uTDbl!J)-{&<;%KVbPiK)^w=}Dkl{_wu=i2QrP_l8G??+f1_ejq$5{9yQ@ z@WbKJ;W6Py!jFc>hR1~;3oGIA;m5;Igw^nb@Wk+>aAI;0JU_f3{9<@vcu{z9cuDxBaBKMG@Y3)r;br0F z;T7SP;kNLq@T=k1!mGothu;XV39k*m8D1BDE4)6uA-plXDZDwnCH!{yo$%K1w(z^* z_rlx5?}tA~gm;8@hIfT`hxdfr!w13#!yknYg+C5|68>Dc1JC53AWR~N1-+*7!#u)T0X$;6UL zC3_1WE*Vqua?vwI`-LmFJ4#tZt*+C z+lsdqzg_%s@$TXS#runQ6{{sm2HzmhQPL_OC(oynx>8aBD%0`ymQ`THIqU_7k2g_T_n#=DkOMFxM zZRvgGBg>bTFD!q#ytVwT@)ye&l`kv*y6oGsSIWODJ5~05*^2VE@|ESw%h#80Dc@AS zxqL)LbH&Hy2g)C=xUb^=iU%qlsu)%AV1-&Sxnfeq#ES71Pgkty{ba>c71Jx;=sm4s zT}?~Hv5KP=hbxX$%!s%3Ufuh(-n)9Q>AkM^+TL#_dhhPNtoQQX(<|pzuJ8R;<@@o? zm9JNBkG~uLqViOwQuSTsV^!m-cEnFtepWfVYH!t7mB%ZetD0Z6sA_ff$;wsnW0l`j zK3z4hs-vzNq@La$Ed()ui|b@oy_1jz8FN zf7L@(4>jCZHLB{Nc;aCF-uS-wNA>OT596cb6XVasABm5RkBL7T9~GZe_h8k8x`}lU zR6Q7fqGo)}ruh2!hWN(#^7xAQiOT!qYvNB;JzF)a>W%p8@zwFk@hS01Rnw}bSG`%e zwz8$_$*P6%7vnF*m&6yx7sX$RFO9z(Z;d|}pA~;TK0E$Gd|rHRd`=?1AU;37y>eIl zQ2e9#&iKLj{`i6TXYsEqKd*YeYHro0%1zZi4QA z*C;h(YDU*QTJuQFN7WD4EUwvG^JdM)nhiCZYu47RuX(R#OU^wUi(Vz zw%YZzn`*b$Zm8W-`(Eu^wVP|V*1lQ$cI~^h>uTSreX4eP?c~}gYt`DRwUcU}seQlp z)!OBCvuj_hT~;@%c7E-=+PSqa)XuDZwst}7qT0o^OKab&d%1R7-ICgO>%Ol0rtaIi zQ*|%bO;6MvsGVFlrEY57lXcVTme##e_jv6SwQaSB>OQXfr0&zY@wHQGr`1lZo!t09 z{j%Eab@$cZTR*aXVg1JXx9d06Z>fK)eqH_g`VI9*>!&r$Y?#|Hui?dpBMqN7s14sX zjBj|n;aL5IhQ$r9HoVsGMC0m)*BjnwnAAA2aYCco=y~<6S>j_qZgg3KbLxW&>b;i= zLP8uQ4w5aUV$0<3M_Bw88N=g7eiIzu+}vylK1aV%OK|ZbTq7305Wqa3H)09ST%-)^ z{d3`%x@tmNu5d)X<*NQSsF7bc4puupa$l>gth~&#jmlWO!FLxafvWZ!lea86VwEFJ zg+SkI@vasznIzn8#XoUS1oQ-B!eGCJsEb(SP*bUBiHUyHFNX<^T73d&;5X{@OKKX_ z9aF-UYV#j+ZNZ5BuQO%q?Q)xQ`0ryDd5~ID9S8|W)u?RGQ-4z(NH1^!b;KEQ$wKfb zt3Kk6*zb+nfpJ(d&fkA zgotS1CHgrJAX-i|rHK~7N`$+pABq$s<%d^jQCGZ+z)Ic%mJ46DnG^?I#7R`x7~Y{^2YH1^gWkfbXu!8DuS<@c+n zC)&alhT1H!ps0vBPw>mE)$TH#cWJjA)C8!e|1Ce~dPeC# znrU_TWP5JN#3>^$rQ$!bicgA6+K}Gs%pe8W8W-NEyENe$M(KbcxZo+5Aw(?S;6Wzo zn>9JI6q2|I+m12yicp?<{MtU*YRQd*($UJtex0AAR$tc#i%QJ>ptUjeLU+DD$hP27 zWxhS_GH)xV#!0TP&Rj-@br6yAkkucoTS#Tu%P`5Y;MT*@q8k6{JCYm~vJG9d?U$U6b z^oXH9Uow)8$O=cK3cbW=4{CT~inmdxr-}Lb%-?tGRz$f&O<$Lle@W-orTazbr0-{P5}pj*GWlPv%eI}#oRQuQZs{zz)$88L%J1SV z>NPK=TsJuvO?LX4Q1q-wgq>0^rzR71?^5CHx#gMmWbRd0SO1u*xTCSA2NQgX)hNTq zhtFDbdW*d)`MR$=XXyoN9Qgs0F1_CMHg$MwpC;kg>fX{oKUcf;4^1(r+@kh;xle8y z9|*uHIpv{EF}35QExVGZA!YlWOz4MBAz$AseWbj0>)kVBmL}QV6k`-wBbMJs++>K`ttX%d_NjY-8lpG#%)o$B;THtGv5>r)UlByl_E-XhQ8G_sMPMV_VB+?rcP zwcK2!?%tH0%A%JK4xRELLyp|&smm9d=3YEssrnU-F#n^q&!2@~aYDx0n0h+?ruKqh z&HA~bi+a6q>ZjSzPrvT<(}G%bT@BM~Ihj(+i8Jczs-=DM)V-Us zGfQl@Q%}g1@09E3oDdLyG{PJ%XL*+-+`}t)izf@1_pQY})Sg3^k zr0>aBOD_?~801S>-d|rLRQ*5r=HS-E_Jcb2XIV>!tG5Mb8lb7$}wfw zhb=Tv!7W~i0R&Mp>uRAola~w(_Pf220F^~a_2*X$Jqh<6$sFl}{TQI8Qy$8({AwYe za_mHo1jms%*zfm7G9ww0fL413s+(meo=)Nw`w*Y|(gZ~Oo)mdT682#a~>POIS|{kkeYa1{=lI+I<^c{f*)>y7p)k zTebT|bhS2$^XY0Sv(B>j5%&}9>1X+xuHJr@lXP|WvwTHYUq8#2banN!d_h-dKg$Wa zIuiXXpA#VVvwTKZdq2x@y4w0#I&hU+9ZmGh>|(yBDR`KaMOLxZK~o-NG!q<6n4jZ$ z`9vKP080<*>A|KltEG>Xlt}qqdU~o^B|#loHkpntg3%0NK~=*9q1A4Est?+85Z5 zdI$*<$ubl2W-mjIrg~_Ry8AjoA{+Y_cr-i3j6;SuV%4p1;7_;}-ux4xx{lX`*~2Vv zM5H{L6;c~uGQ`XgZvx{D5?3V)`Ud-Ryb&K2)e8DhkO_H;Ua-X|Sol-J?t2XO=XxVO z&^9!4j;7OG+tYXf6$g=;Tb;2C_C`=DE^|gQ^m#3>_SBJl>M%X!^5Is&%>%@9s~|T7 zjuPAsOlCn37{%N^baNrAm;kG2b&^%0?cgeJXTpb#aO;3hs2Q$j#i3(UGn7xUMCitp zh^Ceh+gw2CM%$t*+FmPN(bhWX>S+`YYxjrfDmIGy>54|%uHEmXE85_8y81wvcE6df zAbP&1kGNWco4tL+69o5wqlIZk>}YqB32^kYOrk3qv!GX8X4d8ab(>1u++7z5duo}5h z*a}>GZxAlHfR8a532pp615N||3QJkbQv$3T<1eF8JD&(&uMWIHnBEPR_AXcsnX&L! zCLPORGZx82%ajyxOt7mz8Y+}(V{~xrqlrepe0x*O&!;x1+mhR8@|FlM7025(QI?7m z?8s?;-4gVXF`IE`T8M~#kz_|EE(RZckxOqg?lO~&BGc9+&udl>4;6|MYstt*kTe^` zn*fe%ZX>Xj+%2y2sn2HU8pWXugu)xeHhN4Q>`Mz#l2f|YskPqqPD87ko%GhKzroR1 zqlu3+*mxDFa=G#7Bn$F*s$b3vE?1xXxsadu`zdQB$~fu4XNW)0v4zqsUb%fLRZ=0J zoQ7-gfyFEpD@W`a5#STG<)eg=^^iF$h7Rd^mSm16O~}wgWOT`KG9^bKlGP>0tdtx= zBw zwmbX6;5~%6pCtgh7Ue(_P~OXoMq6ls>9VQ*;7FD#8pL@oRiiW0vMbF9tSJZ}b6&`5 z6jECj2u0S`5pC-5E2FvMS1+n757u2TKDbcbGqC@oG43)V4%w&Ac#wN?fYH$;sNk22 z)Ukv5_geT^-zNnJAA2kLHDTdRrC-ej6~|_Qli;hf@e8Uk@AoFjI)b&MU<^xtLWHJD z9c(g1nN}0;(KWxarzVu45g{0Br4dmn=v(@)Xc!DJ6P5r@gC|KOQC^w;?%-W1+OWub zH!ZH}3y~47Fe_HfNJk>AV_D^Tb|XMatEtU_K(Cs9aaN8vw^<$cRA`)fWN=mwarGiq zxGbwy4IE7KJFPy<{K|sjsV&rU^i1FY|_zPC+1JR};<9ji4UjNQQsGX$E~K^ur(9jz9} zEmS*Rj7QKGlr8erqOwqlUi{-*HDk0TTLd^T(4((mE3tTc06UbdP$iVbSm=MqC%AP_ z)b99wOw=q@)LS;LJ~GAN7wYhv>oU~pUx(~|@-Uni(5PH=N#3=5$ZQ|%$J(A9zR;$P zd>yE4Gu~PR86#e8oG;34c#&l3!NrJYAmWe`TtaZnT4||{I@OksFU?M{umUT0F$f2M zce6!Nfhc228xt%s7xlkX9GC4@o{q}x&{`9`{)b%UD38n$mo|tc1A+iFED`;Uhb2S$ z9C?V66ZDG2(lJKn>BbP5CBqVVvhm);tarP$kJSZ3#xSz4IEb|QyO@<$d4R1{ycDfF zxynN$LL_c>XltPKE{6=vbq{08qH*?SFc)z&itFi$`?XdkegUucY$%DK|A=@o*lljZ zd);OSnX+4+y>0e3%as^|x-lk-*<{NVfCYIzD+77DG0omL=W-@xTf`A$N+bb8zcy5a z@id4*aS-5ONTRqzoz_7S2YF14W}FZH3NfQ)yQHi4Jt zT^~2R?N*vOfHq7O!|b$&W~+=Tw_k?W5@q6Lct=rQVQ~9pIiQMTV4MSs=?#TrsfOw4 z#_vN0lktO|c8BIt1Ia<>cJoNm7<7_}YQr>$SBJ~JKq(jx+_2Lrr19VhZLCTL#EYpv zzoGOec#WBJLunuJRSbECmP$|DSW2q{({3#73$F72m0rXCc4KMGNK@atu@s3<3}tE8 z-B57>9{qA?X{ERd7(On`Q=c7LN~;{v52S4M)Sfbzx_fA8y7(HyUkjwiesdju<$r6? z>r~hNyfgF+%Fk5iT@yK5>tu|b{}gZX0N%qv`Vi{t(;nn>K5MBbcG#A-}n=)+;#k^ z0NGynZAGE7^0rJQ47rVx|NAy1E0b>{VQ*zA-?5a~a71@0KN=p#?;XRj$fV30-hkiz z!>Lr-pQ%*spW{v@4Bx#VTDTT?|y8FxEMsz(T1!NB-NfS(fh*njp$-pckrSUG~xOW-dVxRJmy4E&D3 z47{2^|NV?!0{b&?9)Y(qa5sTd8JN}%a03Ge5O|t_e0>?1$I|7$8uxc;BBMiKm!2D5+UIK?Oa0P*PG4LpXa~at4Lx8&&cr}6k2N}Ht z_GjQc0&ivDZUUz=Fl`^e4GbJW;AsZ_k-*A_7`+7kl7Slu9K*ox2wcvkz)sSIz1M|atj0kpn_^@n}Oz;PN>FS8V zLZKZB62@@6~ zd1SF>dwwTwyI{WJe9aiI9!aYG4xin0@3;Bvs_;grpl@f@1~qBgC^wIrhcc`_HUq8Q z`vsrKN?&I#ts94q0k35y3?iSIH!$LTPj4vZcA)<9`cOn|EfM|bD;E@q(O*y`uZS18 z&XK&LOp&}s@Su%aKqhc@7s<=)lDEpUR(7Va$(#5n4m5X(#_klu$jInnBEz&u&*sM& zc`1!Sz2?^$IikE?T~H!sHgLBB1hfeA2AdDyVcHBn9~5O>QJhb)NY`SZf&#>~n$_dG z1LTv(J%3S-+H+WjQ(aOb2H=Ph(~RW*McC5QGG>>X{WC1tT>VnZW>SEIO zWO-rvL=U3B5kC2CU7oshw2k7sw*1BwQrjy-nT}*=w+m%slbRb6AMh7#a!~jt85MD@<7%l9EQ3Sl()aaL)HQa#rp*#ws&sUq>&PsLc zfq^#l(Zl^6PA!;T9XBL9Q~hXdR?jnxOxUP~`#>}mZB(P(pKDYTNjhtk?d9ufy7%Y% zda_Z?cr$xiUGTCo+>!G^GGj(iG3m))BXLdAQMm^!PRi^gM6~lfL+JIL*zBVh_ z>!A*;`;c<9PVp2QTcCH6d0_KDVbepdi5_B-k8@DJOOdBw@{D#tL_*Zr>2gWNffN1b z99x_<7?d`ybe70DG188?^X{gp?_`R@dW4Bp=FES<=!C0<>s}e7xRQglQm!zXct#)w zIt^5moOnJj5uIuHTEu!28i1c|_^NEVKC3i^HOAbzdfL8vR|S&w0V{QR$t_z9&Do4z z51k>dyGKC+aU~y_1HAL&{;phVx{m`=P>5&nbzsu)&1X zJzn{LgV#GFLvW}yU)SZT9edzyJsv^dbZ1c)Tr(iQSjUbraEvyl2G_803)`dGj_t*K ztgOy|)DtETvP1}}kKSC7W++YGY;+40O2%ah;}wmCXtoy-ae+2jq$Ndi0cWWRs$nm^ z5o!=Ddv$l&T{>mTE&q{~LEVrL5t4HiK0#S9CHH4m5Mslo9UI;ttuZ^s8Bwf6Vm%Ec zICKxm5=?d?f_Cm0x)q1A;K`gKJ8YG^S3;A*E=6hD5ES9{D&ua*YDoGy(@+I|QFkar zx{HyH=B`OQpbD2r8S0>4qz637RCVv}K&&o#&y4td#HwD?(Ie|mf~HwCnBM5U^}2L< zv*8<)_i9Ub0@w3{Zmsj?FA;t9VL)g3*QnC}W%;Y?_mxU|7!JKoox$wXz=Ngv%Ce`^ z)4SL{l${q2k*4V_CQQ7hC_8|F#cYY~&7fXY{bt5R>A46iKrS*b7TSbB0CMHfE!*Go z$JcSLCVy#U8wyqTuPS}r)|{<$On0aQ?r2QUO|~YoBE*>hJH_zZ)m6R3SfYzj)az}n z@0pl3-k?jxE125xs&NMS@D~|VLnm3RH^zUCh|kpW0*d_8f1cuhdtMEX9PPEFG&=}2 zJW{eHYCYRo*j3UehR>y#X%lSe4z3usk5p~H=?seObpwqbm`6*s9#UrTY+^qJM+ zoB7|`F2`l~DOoE6`V4hDHs70r3KVlX1VqOJn z<%QZb50Do&#lQvYT)g-D1P>GR(2f*lCm6g;>C6i!WQLIe)N!Is%q}vRZB>U|DiO1T zmRtp9H(nmiQNO-a!g9K@VhOFew_h%W)G3!qu7t+BDU<@jLdZ$f!Nj(j)x$+>k$e9E zQ8ujibzwd#YOxN|XXy~W2HsG_f_=uIj0?;n|BjJq3Ojb;ou3_h!t(ykcy%QO{GoGZ z3u3XO2uIvIA~WY^lc{3cGN%8iBgO?$_1HTbvs1rKG-JntCMMRw6V-YT2wllAli)$- z7cq4UKJ8RS-mI2g#w5nfL#b-bO{~?hP@_amsn&sjov53Y+-Z^!9n=yd7wZ7s9+D18 z%g4p%&>C^lK>6d4{+Rbs`r`zfB}MT<{W*Kl0CKY+92opD3wQ9K&J<0NZV|cm_i3sg zLQYYYS*>T)RKiT)nKXsqTFj9|$z;G|HMbXLj6#aSEC>X{z6{oIkQdtBs_BKDilYb8 zvOW=d+z-7td5b@!My?>0KDLzNXdb;nBIm>0&9N&ang|a3NXjbfKmj5Gh}*Shu2FH3 z*=&NZE0;d|EZWbf&)y)ss=V+*Sh;y-rWPa;ROH1O>ZWh7G;{aQDqP4lX(q*dET2hH zOdrmy7FH?M3nZm#RyOVj&#Dz(V;IKI$_y}H=3|pU*xUYJmt3Munk&CJQvgI_F`U~eCPC^SClHppQGl!$<{lh+%TK!x^;G~uv%%E zO<@-sXA|bHX8#Vq!=9&bj7Og@%`sjg*wBy-ZgJ4UYGvc|6t?l*^9a>YD&}0GQ)9=Y z|C#d}y_PTLP%XZ>yp}xW=X0skxOMIYegkhNVOuzt0+WV4pR4qom#a~3qeVs%(=GET z@@Lx36?p+Z{z8MUXTn!|-B+qJYE_TjT+vf2D{5ucNA4@7V*&p2g$tNg(6K1(FCcnJ z=`kMxNy_i$S7{{#^_KQPrs{p5l;qboe;^EFL7XY3CP{1|&7rS~m1irzofXuyv|vG| zk826<;kMugWy^wInHqZt5#%m?u@x_CTHi^5K3Bd%{btiEgYnCIocVpFY~|BeNM4hk z32UPdrEppIJ!^SS=Da#}G-%KAYTnDfupM$iS{2v#VCXr{4(G!z9p8{0y{C(1`{rD+;d7cr*V)bEBhmJnN)t)kGz->u4b>87P# zJui^2emfvDn5$FO{D6t>1!Q5zSJq@D66EPDIh!Y=qZZ_s zSW1SL;y}temXf8VILR;|P@G8>vHJx;PDF}BKoN%&MN|b&Tf_1(Me^$9TAQ2mn=QmQ z>*5g&3YABgAZ)THc>fY5@mh9;6{T58yty%ffKKGZ4YVI>M1RU|GMnT*O51Cty5@T$ z8Jhp^H<*Z8-iT@=J=qHD!+;w{Abr1XP$(qp0y;_D=!$*At{&gpBTH?$(Cbk*+eBZs z{KA7IC_CpCoY_Il5#_VhCFQO3gre19z@?T&bk}IH(8*DpA){!ka>?tJo|hRS4|Yf> ze|^0!@fy2z@C_4wI~B9a8(E@T-$h~fVI|%wGt?k~?XB>ONMuxWHo#Lwdb3*T7M$w1pJZk`u{Q!pHmmYJPlodRnx5ht z3zfIl!5A;IMftC_MTyZ5K`b~624+XkO2yI` z4sH>}K?L`f3*me*OqtJe73z`)@giQ?z+IQ(%t=tdG+vpx)fUEF!LO(R6ULk9XIO9@ z-QyM1r{uj^BYw3|8S>^W!ffS*H?I`mTBw|QQ>vP;4In{la1+5yo{V&cJNSY*gEDws zEH~*TD8%2W3zBGFCs8F+*9{a$EL3){%P#yvC&)$YqIJoKKraIQX~vXOYr$tgF33_U z-wJ8-d0Zw#wKo;QpB#1L8S7ac=vj52$@5=f5HA+``;1(eOVs z$`l|!Hda+uzf~|$Gp;VRQ1&y|ffmi{P>R>tr-{0$;quaumGHnCdCT!Aq3~!`Ev{qW1{>C6=w-NFLsLusW*CW zegAsB)045|A!4Pi91Jna&jQc#FmS4}%^#7(CV`_k8xGB=|{}GV_g-2#AzcG0_zKOyid$ZcSz|x{OqE z-ebtc;Kv*}&=4_};E@zEEWuAxp1;pZg$7g4n03u}oIGKcQvT zj9DYwU_+DKBCT+0OA~a{l{>Iih&O}9EGHP_d?6Lju+N(BH#19~Q;{Gh@z4BR9yN++ z^#xNopp2g~^tNs!Z?rd)C=SL znKq24bnzrulRP9EgmSx?#PHOc#7NpYvlzRR;%P=trBqVjx1_dFxf(}~1!V@YyG137~M_B6;! zBsKatE2=jPa*Aecc5S-d+1%o8i6XhZl1i8^w*>1tQ{6jd|De03yOQBZ_MynwiOTa4 z+)A@-N{v_GvY|C%A`+!9C@4~!$78m?Ox9VBP? zX_M0vx{j1C#-OfCKeLYc9NzwuMlg!iRiv|`)n#Vqd_=sKiP+i6Hs@-5mc=G7oKA$2(AO~ZuJdf?b(3~ddJ44fF!-=yDJEyQ2g3f*7Duz6o z6eE*TXWF{$Za!p1H|gC?;_q{t`h-H)0gwJfZycO&QlkDOW#q<(Q%Sdw%&t$Vqz>Uo z-gAV6H+-a@6yfWjP^@* zeMa-8mvVZ(VN5f7LEr3dDumC(&VZ?+c3_S2{LV7B-jlqn?Am#OIO0(yv@0UMxlq03 z-pX9%r@MYkNl)$?gsIf_U6;@z!f&$k)wG!xr8~lG0YMqMTTfPA-c57wn|D+0^gVU> z9n603*h3TcPwpu;&8K5u0nMkYTh{dbi78p1X1}2Q4j$+op|v8cP=cKhn}A=_j`|eu zURpf4aBsD~K2F)N-o;KezH4u7m%?FI+ws>g%2qzun{(MwCW;8fM+cu~@S>35;GdpY z#MZ(2v<=RJ;;Z5*Q$47Or7GzMGkhGCI0(qrD}s{oGmvVU0>Wax37;UBBCrx!cd|rG zqD2MkAQTpG#xqU%vZxpVtFpMkETxV}nSLlokEi(4O%*xHl?QWwTAExxW7Y3BRfPR1 z><);{i-kBO1x9g*IA%po@**ti(juP_le-@B73E+?#B}}^%RiE@#cKJRt>*lT4rcgM z@~eA#dvespqiwWEhvR#dZ3ips9!c^I^ZZoY;LA18pJeyPUZ0$CWwrs62)~@Bb%1|kjC+5ve1o1=GI&*&_CC^Dy zWvZ~%6Z!=|9=da>(Ka*YvFxsMo(U;=rgY7tPW*{msz`=|;1sl!B8xf~Q4e3|PWg<( z+LZk3JLhLY*qV}Od$)PoQ}XQZHqT)#PlDSLJSsJ!POb4|3Zhfp<{8OPvC~vHirsa_ zqaFOGqEGZ9YLZt9P+|~R%}?2GDy}u8ZD-t*_-uXbz04? z2p)|NpMWz9T?envPXHt@&bLjl#aR*FlKeJz)&i};MeKT@0s^Jh8(eX68L`aK3uiok z{2G(L=EvW1zhZc1ECigD7mbxOd1kfmGZ%%1nCK=GFBNaoz1Inb9+alKyEmi$6TT;h7Vvp%#2n5(+Pv=^ajIwfnZceI(aOiVzBYW1qKUeRI$9M%P zL1*t-yoZVfyK(%M|MxM0kGJU5*LER_6*c;g?miT-0E6#rMMOHfh*I_ne`YI?g51WA zx@|TNc^2e$oY%|KMLBpo<=!X!nJ)Vg3vm0Ng`njE)A}n8L@#SlJhV|>MPk=q10^uMfW|K#e z8jLi&M>d(0TK!Fw!VgoD=?-Xc{uQllp;QNsj{ zn%n%mTq~}CKvtvJM&%I2=LNj>_mlzE7^j0`MXrOb(*ZbPkLln^yJ>Ndmo_m^%<0VA z%v^(HMkY8|?R(;dx-9KvZ8lQ0UVP-$XFfl8U_xsLU%jJ)zSjGI-37|D>t>(q!LZ{9 zNsR`W^r0-Q@U2!MSz7X=bG&3r+_Ih$E<^%9my1e!a2T6*ZTHFa)siF4)V&cJ6Cvi;>x@Nyj(J2N` zSWKt7_v@wTL^9&(5G5EqjV4v$?6pzab!;ar6pjuopLE886NQpk65w5rDti^`F@!`n`f}(j94$;@ao*>56+piCrsu)1NWxe zDXF*PQ*TG7-i}PYJ%#pWLZvmoPAO0l_Tn5Y@4;~cDicKXg@VIgns(b zOlHyPbBI16xP`+L2*#o0ls<~!u^c|>13ZeuhX`)w@OFYv+7qn6TDoCvS(H~3e27=Z z+GIN&5vTb97z?$0%@26^-QhF0?X|=}r{=ub&tJ^Ypts`lf64bUaS*M)&q_XqQaeAL zkbDZm>HKt5@+qvd^V5?)qhd4x{!|}cqT)lz$7pAr3vW+8-P!f&+T>F>jAU72Xfr-m z#DXEVdZ~T}Zl_=y8ud{9IDUf}s~%-T{zZq$OLPZQd)3p=1XBah^6-w4_9Q{b=6nTg>zWrIRc;JNuo3BV}5ujzE2J05jDsQp#yhFC~1VH*ytHuy5${Ukf1lV}dz z_e8Ki-L_1vgZwvIht|)~9eN!^PLS;-dz}f?>#!b0Ya+|Y+D zE?S>KS~ok!ttPE^H@+Ze$}2=Kp5l)nfy8-fopaWgoq7p%^-Z3QN|sQqr&p(@m+I-I zsp$yzVuHpiURi>FZ-Q6APFW>;V5h9|LsqE*cFHQHn@(A!bavb&rKcXV+UD(J)tz>5 z!E;cQrWyfPa>neiXRf@QHotL7RrF^#>3irSrQp}rlOlFy#&<>Hi5JzqZ~L;9z2C*f1uaUC@0Sb9l+E8iEw;>f{6B@F>Tj_q zN&Cp!G527XCt#^e2%e%eT))$stST|fiOxv zW)-s3YXu>*oQF5ttaez1Qnyi&8np=_arJEVLYr{4iN>8G-;bhBwh6Ch(pUydWK2x>#Vk#5r8?Y> zzVquBRmCp+``?MUm=LqW@lHUd)g-=3%UT+Tr&iVM7KVfkTlFQUY?(BJ(-)~9yM=Iu zmIDFTj)?Y&c(vFi{Ph<}J!2w*tNB!lKf=rjoDI5`b{sLHc`s&5^5}^$2YCwp>fTFk zZX>JWuMui*m+)`uFgLz9xf16?oe!N=Mw4QnFg1V7UL3?tXcU(Lrc{F))H)9{rt3XI zL50R59ikBYfVVDwMBv%W_3ySEREig0!=pmz%~pLC_YN%LMrhY^@X2QN$3IUm)ed$; zO!gjDFT8U^TM#8X&r`?zWPlgOPBWGl@EObYzE%%DUQwjaTDIAevzAzHZ3=EgyIn9Co%7(M*;C2H~7@4Q~jx5X!I?*bt;%mL?3;_X3Tl`R3J=RV7WR6kl4XzKRmm&eMb{b!(oGsg?(X3~}Eg zbznfCMTnmVgpv!;p>*K{Y{LE8BQE2mRKVHnQCf}0ke^jEYO1OZ|a_?wOkHiU7c7fC%al?i(xMnT(vFu+Cnuw z6V`H6P0tZ>#Bo#AXok@6BODr!?-p@7@QDH!(Sf<06GR8-=@9X)f;1c~Z|DPwC(oab zjx*6=G&9`}FwM-=GM*Dw-ia`LK#>tP5_^4!ux6`4m^wXE$nbTwjm|Pbqd%ieew-y# zRM~(snA8bQEOUT&59b}oLXtI2$B17$;BgBHlc7{d+@cGoMvxQKyHGuP0NZ{;NK&@d9isk912@9BSivgX5 zv`vnX8^Hu7>+WmztAEPrRP);NsriY}c~m^PYYRxzTEJFPFpM3a_vqRJ@GXaP@LsRC z0E8BF(Kf`7{-YadT$n3V3v<-HAtBtmgXwEKhLIX7ObS_}0V;OVif?{mp-?l`WmDBf zxk7=*XvG0_Z?0Kp)Mn40;`Vb;9OU{7GW{`%(T#v&AA%A<6{lD|orkZBg0g%`D7eg^ z3}^qbW;2p4{i6AhoptsvqsZN3oJx~3Db49#39eRaP6=JW%~UIMG1$PVxfrv6yX<|H z=>>#!QhGEn>!hNYJW&s0=80K6Q4hH0iP=a@pp(-h#d&HD&#Fgj@;paD@3hQICb>i9LBDi{eBOCr|8!MCg(|3ckZf4%j3|-?2nLh*_&)(Fh5AXf(>? zE<|H=T_i*c=sI7B7IL(sA8JFF?+U&|I9Ok6pxv58TSN;`C^w9o_)uoy;7O0b<3tq$ zeM2P zNGjF0aH+2{XKNSwh<73zX2~OQ^MlQJFiOA^yvRqY)!xOz6>fY&b0d->cJ;1e;kRY6 zMkoun1^7-PT?-qK1eSf#Vs%%3q|_!_y!+Iedf^Y^VXK-xu{tmRFebUr_)i^I)jy;Tn^+wbKS6xz z)p;>0xA}?cdb-LF4h;7^V_Ak*ZL96y6K^!?ybtXm?TsFdgBB0$_;M{?tTXk=F}8jX z5w#@)_1G18dFp@>1Jk33>x>InWW+LqJjEs-MzD{h6+(6v_^eiE1{aKEyvxh(BXBMx)BJpJr945kQXkO>edFhTSVX6?&90gk@4Ss~L zPF|B2Qd`t&IwovOw}fo5WmKq<3Dr%=!4M6s5vB;Z891q$j>=)IK02wIzGKxr24Y1G zOs@Wejv;S)^(?_<$N7;FryNqZ+#rRs&1)?zevqakhp9D{Ldaof>oDpymBN+$m{u4! zJed>aG5vziV|J0=%1YrWt+pOL(1*&Wm^tC=q%^Os4&QoVt{$wFDR}g0kInYq$E<~D zNzJrQ#Cv>DQK*j(pt~|L+{fBNbEH_n<(YyHsVKmQTKt#RXr{1GPiD$k>0;TF;{$}c zlzFWa1p1;NVzfF`9LqBxfeJzCNnd8{7{nc0Z08cg%K7T2+xV0TqaH#Rkp*)A9iU5S) z34so)jDT1y$+i$ttV&Iutg=Rox(Kbd$_{>KL90-HDaJb#P02tEfsDvvT8rS6)7doK zj)*0kUO*;Ayn@72PZ=zQu=fKTu(dLs0|>@k&YT`s!0(`)f1EBU z*hUMLIHNLuur6UCx-J=*qD#!WnsiBTVr~Pe^Ga1*?o1P`)0?>FY4)JE7B;vP20Vjsk3rk{38-6lm6Wte84`o@bO*XL_`j zCtJ<7jotSm&gDRoXfy5THne&d-d& zcd@f9!T)%j2y}5)H?Z-APBn9oP+6^u181xg6|4#RkVnH$F&;z`4H{Svs16?_R7ssm zAqS2X;-%E3g9Q2}(EGR~g^leCd;sFjz-Qor5+8P72;0C=M+|ra7D~aQ{60zxcyqKo zh!L^|_p^Mqh%JyTdmvdBKANz7&r4z`U4X(OMzfHZdhO8k9&S#ocPYMnP2W)In3sK_ z(sH@&ci3uvSCdSWLgJMY`^avhDXq7qOwbQW_mp{k{EjDUQkWf5UTDgh+z}H{ z)32`x1q>@<`ve)K`A)Pf5m7qo&daiU=^A7oq1Oqg2p$*;+oxhs6f@P+lKf6NKmQ%p zC8tq1n(3=#RDj1U8P-M&GLeznU?tV(dWgAa`nJK3m}bdDg&?DiUJlPJ)rg70ly4n~ zgVfWX_s^pvca`t=6_~yap>x~~QqUO{xSe$q17gAtqM%9oPBSJDgI{pgK#Hv?xQtnX zuG5|xeF;+gEVBqrQW41^U=xebRB5rK;cHaAdg)uSSP&q0B`nH{+mA`bh){`I_&0Yj z2?mgTP=^h}(H8LWi7+txntZ$<&WT2RMz@w#$1F?I=p}MZmc?}l9E1IN$N@H6iB0v| zpqK~CBuhO%32UaFYpTX1R?SvW53w9#Qb{?-|11qo-4hh^of5Z(0oY=YTjm!#lWwH)@R>N@h7AnocK=8#~Lge-O#S-9*K}?y1P`o(f7%rQ-Z} zH6+8n)f~zYX~quUaFKG@SIe@xM|-AL`qLlQO3mN#GjYq*y&2&MUs3~7FM7n@A8|(5 z0QSVY9@F`C`Ys)P{$ed_6jA18t@;;Vp4A*M7L?eNv3F_?m^bIug5HRDY3MLzBtX8B zogPnZIs?LRIdvO9^_3@Fr*)3zwvKM#E8VBD7Azq227MI@hlwS1#IG{)GE7YsVGpd; zDA!HSQD2x~vnQiZunwdn`#)AZP2-70TLr&jW;75&iHg=iaB621sL?ynDgd+mq%hUv zcbCT0#4Y`CkTNM!y)aRluEtfnz0#-+@2E+KX_9&xL#H{GZiUYMBwR=umWY_~02i|z zcH_eh=i-n>=VGR27T6!j%wj^KbHD5}ae;Dd5{mh= zcPiSKM7!%Lsl-`(O7)o@V*Z)h-(^3n{kcs%n%kdpd;+=evwiCE#`CU;`4QtQC=i6X zCJd^mA>!jEX*Rduc3afxmk-F-M%F5 zb9}xOCAsCWF(S2fD{$%iq*HscWX2flXApJQeNF*6)!>gjA-91*z3#VVIe|? zB{bjH;8OdRCL1-u#^7h5NIqiXejd5IA!Z0LYCf~;FvH|+So@%@&U*LVnUZdBn?91( z1-E+LJ6ZXm&PWi>%an#rhJwU8eHpGR5@Dy*%NQH%T`EM+TBSVGp3J@K>gpf!K|~D? z@=UQBW%&5;S#hPe*t?Ri+uS)zFIeNqPZ_`cf9!n=fL+tM|Ji$=IcFYclF2(k;>-vp zo60JFbD}k22nv& zyyN}<{l4|sd!MuC5s9e&V`QJbzx7`0d#!JMYpt3a9e5Xt{-w2Ft_xxmcT#!-)deGr z$&3_3B1^#x5%NS>j)*hbO34xAJ_@{Ppre6cHPm9^u#71#R6$PTRo>Gs3%3q`_EfG% zjS_Y>=hm1T%!gk*vNrtb^a||56ZKgWmiUoGOfF&&xb8)BKSg4qX~-+&OPpDV)($@z zr9Md2VliYyB0@v1-;HIP?IaOY{Pa5RqyrQ?$L+MWm9@2UJME69d(lK35#y?BwGDl# z__(&Wy0W@juI=3-79SUOxazX(hzepigCj?^>qV9kH3>l$dlWM2S{UT7=470b>S5v1 zl7kPWrPysWsk2KMk1%J4PrR5|FvNA?f?;l50>@Ad-eVjMSXwV3(rW0mokx;^=}zh@ zXbEa0!d`zEJm9;ZOQXZ%FR2(*#!3S0_b zk~5V3Sg%-Zl!F3g0+vWdCsce;eHk9A@hKg9n7e4XFXr~)_ajHv3>>5#Nny(? zx-eo_`k9(Hw}&mw4-Xr(&wyL%{=@y76XLlAPl-HfY>%^@%tUvh>+pg9C%PUVSw1TG z$nlZqqmqxR>d2TzQyML4gD1MMq`{CjbldH=Z=C23o9OPa<4!wIba&Zx_-?!J@s+QR z7&&Usy(YSQ@3ZgM_8aZ*KhZtl>jxebOmxS5W1@TTME8(?ndpA=TNB-HA9~o~M@)48 z^*i7F-oJf+qWgm%PIQ0t zJn@*uw>266o(u-@(@(wQ{jVIfB|xub{Ci74Qyl*S$3KhaONj}a$%mPPaHBZ3T1uJ^ zGX9%3&AtL^KvoaJ!U;0R<7GY;y8bJa4^r50iS>%>ziL5CRc5cc{u&E=T)|ditDxrx zuNgRMaET)|xKBm+I}3Q7kJn&VG|~KJI@I;wu(0I{_BYpm)56*m>~+_F%fg;iu$Nr_ zZ4C>K_a9NfmtFrI8}Ts(TkZPqTG*osw#N0}v#=)=Y#nP^1N*P;31HMU&KhU6^OW;6 z{-yn`aGoJNa9(zv#mmb!(n`F&;r|8EW*4*XBC73NjPpFtWKihtYU-*))7J^nS~-!S~!0snRk@Yo6ecE-Qk zJs$iLWqm3Xq{0Kvb18pI987E+f7C&>_p$ILD6ZY{pC@rV==lpc2NROG78niKUs#WG z_-G@Yu5j%MGdtRbOh#$DJnNMH=PCdK+|UV!^}#(@C~z@a`;2tMCnWPzor7vu;Kmc= zi;`c)Tue%L4+XTwzl;T+&W_QwVo`$@cG}Oa&K)J;ce3C81;23oI~*M18+Fs|ifZSo zrY<5WJi=B!%Ex1TydNw3H)DI8c&)QE_II6rpBsZMb>=zOs94 z9#=c}IVW`d-ycpm;iMBz_|*v~{5lcmq!Uh#eV-EirU{vhb53|BSr^1t((X@KD4wxPhkDf=i zI%$7DZFP?N57Zb$W^1e}BEv=WevgbZ_*XFTEMaC* z@R=BjQKRR9fbkcopTyJGVF_RwZ2tr1IbTl;AnZUDaFDRWuaE69bnm%N`Cp(w`;>>I zLH7OHT=dj)u79QJ3jYC3{~YmCOImt1T6*ZU&ZtiQ3(~`wC@tZ&4*w8zt&%TCkL^*M zvC^k$BwoZ}$9W%_w82E({bR-Kknp>rbR5qu|0lLxWeI|{!t&F$FtU!)8h&!FeMavnzyvyIs@!wUaoL@Ux7Y+IMD&; zfZ(dCE{EG_^jD3ujqZTrW?0+P;7g7F*^E4jF zRso;a^Klm+i}|>Zaqj2iJU$-bqn(ep_;{O-3m9(}AGh*x8y^e#Si(me zAA6w79seEF`)L0>sUo4z@^L>OtN3_P%D4_TR}@;gO>2I zijTE?yurtt;iLPyBZ5!)-o)CT!N){CCi5|ckLi3|&c_veT+7Fw`M8CTMSMKU$76gf z<>PTap5|i(AJ6eoiGNl2*AM@ev1-rrv5Jo%WckzixQLIXd_2L&GCr2`@ki!yDIb%W zB;;c{AI*F`z$h0pw1toJ`S~IruV?)IKo-(NBZS@e26PDi74dHy{9Bai`4eCTyYyK; z-s0m_W_lVQXY(OAf|;Vg5O zJ5OTD@wCI4^0Q%&1BV{a=M(2sr^y}Xp6Z_Fp6-r!&u}M(KRs~hAA-BwMeg11J@~uV zUF_cH-tRu(E^!}pA99~?A9mZ^N8Cr<$KbXHZJ`=#8NRshR>Skoye+!)Zu(6QL@<8p z@N*$sG{RlLy~)))SbT(Al-C}3n-3@ql>QPXt6Lk~gt*j1iWSAGx=*Apg8C{S8~6%u zV2zIOJVHK|5VftZs<2jv#8dDTmDf{JRQU|~yG_vqH(RL9D8mIjcrBJ>oCIYM(NhSuMg}weZtyR$0JbvGCIcelp?{{<4LSxA7|gUrl(R+joWpvFIFvUb0Ef6gZ0} z{BIUM!Df{Q{6!0&C~y`{_$muOOW-E~UJ3XM8lEo(Rdr`e5R0xt(DOFQB!RPN!k@G7 z$u_HMz}qeS9D)A<@d;mP;Zp?84zB_HSqEP9%RWa@(|zbAs0+a%{p09#G?G7G=JW>p9H6Bd4< zz*#imk6UELEPSSoKLGIiH9T4L zK!n_9QUrBT(F|B@0_vJ=R)YY)*TOHeMH7CHgC9r_mw$QB+@h=wM zA`x%1-&f1`eEa<;`M$+|UnBXD(wWb#7CxsW-nH@_+-xIUCx9F6_gu+{=v72UQM`Eq zX90xYWaD2iaQ0?B;88v|NWRzEcsI)Twek(Wck=z41T@D+xmmJe(GAFIu7&?u;J*WW z8^EJ1Z;|vZHr{;so^8Kxm2_lHOm~fi-!=~J4;i0rVZfhk!0nR375009d|z(A|03U) z+3&wf0c<<-xhe%d6!0s{;eo#`0%ny5_}c*;0{!W0{DpClNG02ER<$HG+t!WnuknvUOO z;VS;ua9o5W_>|t`!ipY|1pDcXKC$peEgZyF_}Ic96L>2%QvWje>wng%53- z$0gtnq$vbgX3!-+5ka4}z-0ow(`3Icmi_W5h}pkq(>y5wcQFmo=v^D|R1^S~S9k{j zdi%K>H`AA z&XXd}W+p&|6>>z-S8XwcMI{N=NCK|<#j|-$pic@ki1PWnfR~j-em%;)wIpb*BzU3(`i4Li zPDGi%X|tiUE!Z{$x@m7oDupyrs<#FDh?KxVct>)1zzqI!8}P0KEHMG95lr!(1UzU0 zRAm{kP68eZ7(#q`+~)PZ3Sj`rC&KOzB;a9_SA^joNoM(Yer&4E;Oks4__&hEGUT1-)3h+_Zi%nE0&BmX`fWjS!sOkT7 z0W7pB$IJI$?DrY+{a5>aW=Z%2`M%wTPn7Rl?e|&oeVhG0+l0f5M96EB0I=MmzbDK0 z&G!2o`Tn#0o+95j*zc+G9d**VCEw@Cchoi0^tbK*^93-+W_Ur#_l5HPCmSA?d{38e zSg&;hE-LxHSiY~a;g`twtiS?h2;g%2{l}8;OXa)ShR>95m|k^(&HToyEC!ntcC8J# zEDC`BScsZ zXWIO(K2_%bPmn&&u+TqAR00KSVa(PoyhZ|+nSiLP=19PD69C(^PI0XSJjwh|wLm5M zpCWKvM1KnUG@(s4>UENS1%Vb(=0>nnOgZx+*vSTVJz<3jl2^phZV;&H097lI^>3Ddc1AwIMEzm`w)1Qb^P>Rb&bc<=Rtb24+5Df%n!|sag-TPV*yy)Qz$!*R&eUW9VSz8eUmD=u@<-!^VO4lb?s%%E4s_qVE zRQMI6M#Fcf0CkJ2>h6+HX;BnskpOjzSjOE1_^VA35hmWF@Sh=t|1>STS7N_R*nb$< zVhfWIwzznoz+Yj`95;)Ps;#dwk0YbDs-_YuO+ASrxMZNJ?taN;4Ws|W6!|~|`>}y7 z5!h>t_ag&)FoONiz#bCV-x==*3dU}D*g~avg^>XQ+9cq0M*laHg@Uam?0W|Gh{SsX zFlns}4Xdx>5?=U@iTfzy7HrKQlTTaerSi$TDg1w2a(U`^af2d_lbm?UDycAUVQxVBR?aZj}{ ziEBstG=YypT!GsWhs@{t0|N?!O(v&H@>o*tU>M1kZ(8!R&eule8|p> zLI#=C69hIMv1N!XT1*5S_GbwoeF=iFbIxLdf=z$6q(6h{*#$%!8Tv^QZGiclEYZ$1 z#R%Fkw{s#mOR<Y zFh1GZP?OKa0-wrKD*^*l`ro+(VpE~2y@H)bm}g*@NaAUPxdt{vVCNHN)eXhMF8~ZH z)hHeK#dS|K?~jaK%&28h9E+vTZbl3&8|yLN5^L&wXFK7|^1ea;LHeEWfi=D`S+;Ee z7UfMGxUk4O;r;aciFof@Oxs7lpTw&5hL?m1=taj)9jQ*gvs1BZEpTSqL%)-| z*V0i{$1mu2A}Nk76FB2k>v!f;rQewk{7>$e`8R8n#|JZF;#>_Y>C=>s-a{7hnw5@} z6#?9qfed7U1OEJsz_ku|p)eU+tE6-iC8+fYz_IJPk!$~Kfe9CwyXo5p4U0cV??`iU+lj}I` z<~q?i%Q@Sb!r?2 zr`fp-{z!COqF>gP&QYUfYRHO?ITUF%#2??n1E-+;dx@h7g!@Xnl%zgzKl zn{&If!1;^wS7#yIQt!YYJz4K^7CCo2_tZJ}IQKe>;SqcvJcsXh9tu}~edyr8ct|`A zFNu!+R=|IPfAFDjRyys@bI$YlQ=a^EreBQ>0k1f(Vzj1a_{g`$4D2)AxKVh@jl%OU3`hOUtq+=& zqlEI407J~;pIdjd7Vj`9!&g8R2oo~jX)*Sz zb@-e5y#jIHz&rMRNJU^0h68{~2NN*gY4OEkzUv39DXhHm!2;Ldy@yWtD&BkQgs-Ug z!pr!r)8VW2JJY>{_g)$fQ!LilRe>+6_rfat_R--l=y#+G3eV%CuMT()@BMT_7<~C& zSczY_NJ~qe)$c42)?0sohI2E)K%EY@Presmmh}hea2R9do#|lJ^taIPWiU|C#ZJZ+ z#!GRxgQ?QrN=JZoQr?*m21zVGtGKX1`a|?P?5ALgs)B9$ox}C8erMW;^m`8Pu#!uB z4$~5je-Vip2?j)YXJQz^vCiuj?!#{bei!TCd)2SRzX$KzAZ;G;@7C`u0A^}|vw*ww zJM+9#zq2eDCmE*@!0PM|#mhqcZi`j-rF5bTa7z~R1mEnQK4eNrcr(k5`d*K@Vj?ggJ4*6cV8oy{^jXx3}v(3jS zd|YWh_QVIBI1vrwzZbq>(^84{#>Y(au@64}Xg>DE2W)vN+Sl-L5kB_AFDy!|w7iFS zZzThP)sD4RA21pDcMy6$Uhd?}G#z{=1hh+o5VM5`B0gXQBDJfJsrXn#=oGxL5cxO< zA9oWv881wD4?ia114Y8IkY6y_z<&-e6Y;{7@&S99e;=VR#K=oP%OF()w=f)Jli}0I-;=Q6h`)bOaUSCP?^SK({de%E1T27^ z4SSCecp`V_;1`=RXBZ+gg?k1RFU04aQKL@}6txA>m|5ER; zq`I&>Nf*I*>SE%L4I2183cj=a{VCirW&DqXOC|yTu7BbB$WevX=)%UL1_gFXxA4On ze@7G`xIbi<=mrnkEPqp)TzJFIWN8Y~!$4J8dRWelXN5Bt!6@iDt>65>Q zsghsh`=P23dH;5e4;!9a_?Aj6@84AY1Etr6%|&V~?}z9b!|vw7is8S^-!UpPc|S;@7Y7VeN7Yqg5Pv-;ZvjfPIZyO!2#~WC{;j ze(X)*n5CZX7WPtAllMKP%A&Np1?*0!s1J0k5vqO?>#I7#R|H1qQ)IKdZq?iT7+wPh zWBl%_Qpx)+s;^<@aSJ=Eu95eh6dZF2x3HsXxxDW{zhUCvFjYZJLR=UJ1YP8Pdj*H> z!Np_@yI}FVt?B`JABtT%gl(f>^4>r{WWefmZDAR33tQK4g6|fFsLbUZvms3G(f@En zCJoC6rbT$K@y9U)b0N&qUCx6rGj}-$;#R!^=08MEOsieaf5@uj9rGV%gn59W0`(Q%sa^AxXGR?!r{5xtLBHJk8_8GRR??h!{%Gu3TL-)+`eADzs@^$EFOB6S@d?! zRQf!$ujr}Mgm}a;j%}>RHQbHvM_zp;e{qva6(Zmqh_`Wy_BXt~?$zT%r`a8_J+o`b z7I70cE+)uwHno<&JmMTb`4KLTX!I-g3XlK2JJ_weH2m7NuJ5c15C6p7mU*0eDbJU_zW=54Y?}UXGcl$%LYzue&H{g&sLY1h##w`bf0tu z`VYrthwk733pg9~xARxUXQk-R_EX)`{v6mrf9Au5k9Y&Z(eHVEoSVbTrn~!MAc`Nm zL&DqqY-810ufDp7t5)9*pL@?MhBf&84(vWNOa#oLo4135t6i&iG(j$f2X5!l{K_4i!)j-8vK96m_$Udf>nf zT<^o~XD;ajH{JQR9k~e=f*pvgMh@BGER@$ch&<*SN3htp|6Lhf}w8wBRXjNk-!+{b)9+r8)X{a8F z6X9tu0on<@s^~fnLRYVO7wJGU5CFZTu+t`sBjfvV*= zOrIof@LO2Xu{U@_wrS34s}uyG!SDsiR<93Rsv=uDTC*ajD!l$ZZ~G)O+OuOmgp>bM z`A}co@#ljNnLRaA!;NFQ%%(Od2Q%x;ZIM-MMhn4mMY;a2jTj#p~5C&-M=K+{hGlrYt3I4 zWW5~tOSHd8q2TaUZp9dI1l*pK=nf@KlW6!2+aU|GBL0v{_XuuU@TZ2Co#GC5D#L}R zxFax{@1Eig!D#ji+--qxdk5~0?p5Q%qXW0ev{MU05Rx}ap`0E~Lu`~PR0I^U?HAVj z**+s%W6d`-w<4|iuV$S}GxWHA;oNU|TZL2ZK{v#REv=oF4>r0BDpW&_v|uxT%OiG$ zWhp*-F8FAfib2)l;h3;$P+V8~c;{lpSbzGjONbn$ZY5~4bLKwBWRLC*4;|grIy~Z3cmF}ttOg_+nJ_Yt^;$1H zxzgKez#8_Rzny>nWeLu;J~Uj@k!n#_qqw&qesQc{6VCj#yJfe@8y9_~lDAPa9?UxV z@VF*d)QsvNOOrnMK1D^Gr=|^aixGFYy+jQ&l4*QS3^Q}f`RT)~2zss_Y1zCcg2z@M zZKzSQ8S1OmP)8+`w?K_8mA6^p=q;4DBnJ^=b0PSIr(1a&sOsE^(`_?Qp0%*O29g@0 z7MdNfhFbhJf;DkjiS3V83&MeCs04|UH@2|%AqWbZ3aMqG5J*mDpY>~rf2chsCe)zs z=$#ccm$FppN4T|6Bqvr}gqU-{fLqUie)N}9-NJ4L^JXP6PqQznl;&Ska&8s)SGcg! z8xl4x0|#Gj`#3QJNb)S4V`FsoC2Ek7ENzgPTjztkGDglA;{*Jt0y6t3qiB?EhWSZH zIzB3!472&T@b(IC$goN~eros-%df$#BtC{ua}2}7C%ApVS#PcIiUH^f*dTq6m7{8C zQn4XtbRbJkhMbp0JY6>A0M3`OY^W?&V?2p+3Sp44p)k^$?}(OE(CQZ=V@>NCqkbLS zit80c|5|`@fIpZ8f+HEE!Eh64a;insr67$oIfXQAr9zr-PjvfN^0NjdguO0zcdkoS zxVKeIjfE`M%9&;lMqXexvNk;YkM7pn*oy@qBX1&d`P=y`l1LWTzvJ}@S6=Q8-kWp2 z1ivWP!D5rY89Cv-YVsErr@4LqOKO&wdgd{&D;Eoxd1`eR^G=8sXz5TE%v=LP!n~4+ zY^*sXCnhq7tT)Qqnq*HXa+?sJvGv*;W7bulOpl0bQib#h5>aHaPmW6V3A5|0Pwadp zF~w6;BsDw3t%k15vkl`4?|97XZzNvnY>e6}d1XEv-ds8x`zWpXswmBE7M9J%whUqt zJUNj~avaEU!*M>l_MpgSF;K`(-NL!oxc#ZRfHR0NSp2z8zDWGIU%6!NwG*d=|A3RP z0Y(v=ba_&R*|aoXAWz=tG+q!LsB=4!rEzN~no-gd>tQFVwaVP#W>!|aezUULF4VR! zfY-#v=JVn;wJE%2PI4HuW+O%?&1-J`!g!5z35_NYHu1^I7U2!oxP7|jHMJ#*%V#z8 zY)oD=w642`9gU+#cQEEVHP?(8c6KnlWkK3dzUfBxg|=|qh0rE&kyTfcb9rP+UZS)K zBr=k-M4MoCB01;US)AOO6X!H5W7dzT|EV-9zekMI zAijzTmcK>J45a!A_cK{@JTh;~rI;j=-L*cm$)4p5sOS1Ipq^bYpwqnAym7!+(S9S- zQ&hi5qGO`SX}6lLiJAijdDz8n{{uT79K`4R(2PZW9abmByWgV<$O&i4{6M2YoW^B-Fd{xbF!a49t@r*Z==*;^5BmNnt-Jm?>1xsy z39WK7U9A^g%}DFL&2+^@uQa(iC#}2wIq7OaT2qyH+$^tXcs2H{RC%=|t@k$5RY!ES zBCWgrIq7OmT2nXEm0pU7(N)4uZ1lj7lD(Jau{264RK*gHC4SRmsgARcgvSyL{gqsP z4gY?vJ2aqSGB)K<`nF!RpMZ3j59l?XDR}1^PaieamZ|zQ+!-9R^`Gr=l}7nA5%(u} zT*)Z&?wH{D+es!nXKE*^bs)s#oO8-`#;~aT2GVPwS1E8(W2_PlSfSOcOlNxyH6y(` zZT`Ztk2qP;)Y6n^nubDAM@FA=`wPDVkpdu4FFwTFXE8G>cad3J6Np)S!; zL7bghI@4ATCV9UXF@&>vBu9J|Q)b$E?Mj#D#1AX9|NialR@)lXoHQ#%5nY${=sM(t z#~rcjfG~K%tE6X1ReYIST;p5%8_|=dv$1p4=y-io04!j@Aau47V zWU@~n5A$x2U03MqVHqF}ynX8QVilTgyz_jl^b>KgV@hEeqP1dSQpO(f1aUZ+ZCQ3B zVkhthCz*7NI4Vgg;?!8g=^R^#EUnotkY$9$meaF)W5W`v_!-e9r_d#rhA!B0rq@?x z#Us4t1b3_L%sS7EG<0dM^!kb?NchbbZ^(t?J=g#`;YZC0el)w3A7OyduxpYm=?bu< zN^1yLoPZ0@&FQQuXpVT(W#ZU?+sX5AM#M_P)O|HQg$zTA@nxoJN( zq*63qUtnIdy!u-HBJUnL@1D#%h%yIFHXnyvg;dg;-cPaOftnGfG<~3Mx-dh~OfS^{ z-O2C>Xi0kD20Lfc>fBq`xsR@MUtQ;ZDm&dDB*)(yC&*G4u=EyaYHTzuK>JCO{VgxQ z!fO~X(reT_+%$(gdpdY|VQf)H1H`P&c2`|`K<2=^xb z_8H;M<8R#vcQxr@H8>w~gAGc0(=g*=uMzG#gpY=fC&XXsqiuYD|Z<8lca>95eb!Lkk7?qR*DhUfNmjlYUUZDuPLJ>B5Lt=^? zz)o!;Y;3$2!(WNTwLKqMT<4I?vB14Fjog>!z1~9Z+fasP{Pz6M8@!?64_drl^rOh( zz^x8-5%yf9i+nD$58^AQR-t@QtN0gyT48e)P5>&7a{^0H4YlL~pN(q4{2+wLu?(K~ z(0DJr0Rvl0mXKWJZBD6lohDaMyRaA`U$8HbZ>-WJ*FVI`HDK>|UiVUZRpbgHgYZ+8 zZ|E11Yk$ps!0HUS>ZqUk}GJk zlw6^^2)TkxgsbxnTgve!9r$Mz<+XIqM^(mDS9pGg&>=5)xv9F*npg2q@`%zE=+ll-z~1 zkUQ62g3|0oVkgPdj%|qO za+*iF6t)5_z|iFYlsiF*Q5|)_2zLTy73gvje?gZ*r$D4R{03RJ@E7Db%g}2x0U#Qo zOH7m6DI}4A(*hfQe=i|UxG1JZFH7^-CwaKCqi`+c-b zf(mPJUq=NA2=4dRxDQ+h?n5X8R|WZj%YyvC?ODWm;IiO8a5jPah%dMgoEO|jxZpk{ zkKjIVUT`0hhqw>Pqi`Sb%W*&8pq6Qh&1A1iQT#k{A6i=YozU%VT-(+M{n4EY{p*cu z?deyhm<;ZyaH=n6F#9?n1o>RkU3TVl1f8U5@FD9ugnYz2Ot|Y zC%;AMS5!~H#w}SJMG9opI8uohFia5>5Jxg$!BmLiA)sz0x)J1$$cOcx13?0oX{*Ly$|A=S_4^Cin3}=c?{S@()! zkS1hNZ8aZkvg(6q+rv0;9j%bhBdyO8oC~f3cVMnB~9W{l!z32815BmgbJgHV*Glmneg4Wd-qJ@YS zZAfX#z{6N2EE~cJS;Hw2L58p==Y@v-VU`+xip8gG^ics*Wx!CtG#sy(TzbrgQx44z zfP?7AEnX43Uw69R-D=OXvm?Fc_%P0sVT_OAQW+AJu^CE#aacSo+jqngy4-@XG-Fs> z@$OHN1w>>5e27N%Ny&n3F87#L6Xa}SR1rVnF|8KnWCJ}$wZtCSR2kXt%~Wk^+IXIo ztEvoKY~02Qul)14i90;y1~(V(Int>K|L}xYV-9#}zQJwyLHR`Jw;TL{4->6_f+!dK3~K|ssTya&q<{r$E4t(&Ee)imcLoRj4;B`!E|@v zD1R~f6MRENP z#%-unegL3+WPtsV3R)#l;6~;Fm#fk^!bWeQM1Xn?tcHp7ER)u-~BJA6ZxQ@F3=n2H3e}QT%p2$a~s5?tLJUlE| z3KxVp_Rs4f1i}6Zg(EptYGW=BbJ2%fB+j2OB_}c%-#+?#M`pk4Ao38 zJaQQhkKma?!ESqHT6hkT=nH{a*O0?^)UI4b^Cc5=wV4tlh^^PM{h_h^L>=&Ew9GE^ zyQ6)_cl1Fm*b0avcW|=UFO;JVC~X$GIqo8D*1s+M1qTPWkGue;(m1Lz#^fi*uABYG-UD6G z?*!B<;5zPH&ibDwp#$mjfdjbUa1)DLqzh4&J`{0iBbE#Rg;EuV4jpH3#gwVg-qsRVPt5^wd-K>Aez zfV~F}Vq9zX+PIma72H)u2G2Gin^SkT&~?^-9rcv(7-6e8Y9uYS0#AVJU>w5f;1+YW zn)y*p6dqs6joKPbju_iep$K0VomC5MR?zWbMg_)JkcpG`2nu3(TH#$&bo7Qn-exbX zZE@?VC02y<7P*z>s$z1QliWy69SwA@rA_kK1$011JMxhV#0pK+Fui&TSUIUE9D!@9 zzf~>+W98!XF6yMQa`9zy+88^pLGD8K>_oNm+Nf-+(nS2S9Cp53KVY9e;n^3uh419m zAr|um0niX70mYnDb~MoZXd~GibtV~-#e1_MM?xGB-nP`;KZvq4#;N4k*xYzYv(*5Y zD#h587TG9x4L!t+)RSe4zf4a|s2amj54&4RC3^VtjxLc2Y1wf|e`kaWkW#WA+t5>( z3@(nwDgihP$vm^rElO#63IKkCDYSo=n{bu99ZXn!`L$ zQ?bs^6mwf*p2!c(Gvs3tKYHnqR({}MzhVK=mh+>4X#7~pk6Inl#t+~@3q=pEv6dLK z_<`9cbXXp`rz?aCKqQTZK}RGL_68uJ84@K^H$@Bkg{U`EB(N1xR1PUZO6~l~DU#O? zWXv)m`J6qV1EgQBr?$s-_PtHy^|$k9T$Qq<@O%Z2ZZb%$+{&b%QzjlAU>(l#D#c+n zR4MMPY3QONTO8aYSH2pSmP~NFL5?o#7mj!o>w$4PDRtJ`Ig^$LF*U^tOYPJbOtr_P z0aK-{2vfNt5y#X3`X^D-nUJ2X?$BMLEWxU}L@V((`I#6=(=nq2F*-sEL5TXC zJK7yxtm2GWl#e8Wgj4T!2Y!=Ml7ml`%(AF7RZPTE-DK)sG;ws83?RX5Fc1G-&~V6uzWtg;7lBrF0nbT%}4 z-vn56a$tUHIXeXg&Kibn<>0YWX3E#$grP;9o`Sf^>1s?aG>22}b_b0vC2;WDx~ZRa zT9sz|>x_Ym?XTVp%14_ArISH9_lp^nNwZTXwX<-#PdKD9yM6eJ_uU@HDk%j$g@!f% zYO#wXCewKyFpudMl@r9lFBT1m%=2(S53e1gF~L}xuzY4-X>>YIrt!!$Wg4G`Z-^h8 z#z%{YVrzEx$qqJWq+UU7bMXIo;zZHKLSTDE*9(EvvONDK2={pPRm!rJ!1fBW5{L+- zQCzU7>^MbZgEIZ8a<~Ww<3=+<=}=lpu%_E#p=H`=S)nM?Xroxfhv8RM0Sqfyc%n;n z*;=tc=`a|oI>7ZU-t^^F=(J*Gq={BD9%3hAEtW;b>Bpdqcw)9%d`;uP`LfKze1STW zn@Y_-oFMc;1VpSvRyIyIF$nQvT^(T%RnG9NW4yujMz@@iMjSWtz{vN1o*fd_9hj}8 z$u()IjP7D!b2?pKCSgDq!g_-4S-FcLU^+8YB_hE12sFYwSSSo}tq5qwK=B4X?kpBf zP`WeT!D?ZL@uVB;CfZKr5{{19R~Gkeq;B>q;wO3)y%`yUKR7nK)z}XrS&QIEW2{MkMOZ<=PS2dtq1<~ z=dwkHB-@L9wKx-Aw!;0stmy9HVo;kVa5eW`dO~DyZ3(}y#@iy$k~Q9T7ZyUS?+!7m z)jxj5?Z$N^a4G8iI+DLW<8Hf?IwQ0i$7$i-M67mX)gqo;-yqI1vOI!yDIWFDRZw+c zs4R5If(N|qVEwGX3He`p76*nNc?fR!tb0PW3u`ttrK@(6J+$WVs`@_Rwa>aki>gb- zFg+Z|Y%MDzwP7WE<5_oG9(#>tFi3@P>y_?yJP&=$O84Kk9I0&B+q>l!>0|HD$c76)*nU7*oLtC;fB(R(-PL$sXbms6BYd<- zC2dC^qo-TpxOR7_^L9A=fNXzwU#z{w<6-VS=X*TN{j2jmIm~_6=iHOc>07FfAmm}* zaMm&BOC6K@lf$iU^>(mFR4z!OfB5uA?$=QkZX`LV+XsZhk&H`fSf`ebK!>P%NSsT< z(OIkrCvTeRqlPJQZbNwKCs@s{UF8faa}b7!OH5_oecc(BahA$El{@O&O}>fv3BHN>v<#_8qodx1G&1`0k|f?J zkF`JYB>3GvftIs*069q3r|lnb09R}tz_?;Uf5lQh@sB-#Yc>zymwNy|+B|???g54Hr1qmY!*6W^8kLiDR9o_0sL|g;DXHq_~jnJC7TEEOF4i$n2G#~v;myt zMJ@|%;bHH)I~^fb8*2i&6-xnhWsF%1I$U=VdqpcRAWh7$riTx`?+ysKIY4eS%S88z z&X9dYnTBd4kb~y!M4E<>T(KG@>tipuVFPZQFhIe2EjM3fa6&!bGq=K>M7ey5cj{aR zroGZjt(ro&+3g=YwZ28)YK7g*v}qXwh%D&zngW~f2mQU8g7LgQ7f1Pr4~*G$i}3Xi z+#ZLck2*5HFP0AL`RAyBj%7n3EOPBr!K;x*X#4TfeI+`fs=e^WiM^#$6dM{KWki7(8n}bq{d{h2Q(s z-Ir$6p32}n<5Tyhebv?gnt-u7iJ!{)3T_QBd#kMRHtP>iwZhg}F~ZR|_=3sa4i&@4 z`UA#>bHASLe?gm9a4x;z8SlWj@q1L<_`RPpe)kLacf9!h(!X-NU(s${a<#O!ZR?^F zCf#jZ@9Qw>9_@NZpoO=)-XYF_Fz0y(#9DZS=ly4QTBwT|Sl+_$P0#yQy5)HP6w5I& zMdd}Wz=!~UdA@3cE?0=j`9ooW^^WKGK zS7D4Dnj4r0CE1~v_z$o2_Sp@qp+o7;Mo%UqQa(x&rm_v6T`4Ezy5TNofs1y%9hPS) zbYgsR`f3H->HNYS5J#w)XI_Y6P~2zpVClk4CM{T-3OPi!zB(ySLgK zHEgvWwRSyfT#$~9+G;autHQ<_j9Pp6+Zv2odw5ZecV5bO zczq3Bb#$xcCE*)$y}q(YZS}#=q4+^s=ouFV;vt3JCAsjq0k}Msi{y4+@aCO>5DB=m zH8w4Yytt`YCU*kPNkgIA=x_GMtZn*))hD_&;eL;KgN~6gu#=yQL^LHzNuB&a5G(mX zw?wurmi7&>keq@mjLn~qy;6>*C%f?LgSH%<8+G3yx-vknZgtOB7M-}Y63D;aL<39d;WRQ9`^iWxZ$wKt^U{nNM#Ym40|tAIG71$4mp^KVPlIt4V{~9 zag+&D)J+qOzD81x^_yLDUP8{l10E$3$DeJWXc8uv+NUW%oAmy4wg`@UY%Wg~v~A1# zgNf#HH-=;wWrd7TJ+4V9-HL<5byvgpm!o+K z`X4n%UD4iZHJ0j-)pZqs*;`*eMP!ugZ_C_e49LrK{%JWms2}HDLDMb5+5W?dhMsa1 z4h|NF{H3LO!;cN-j!i#qfc_^lj{=uHlP zn+!10)txU$P^;o3kif=?Mh+ca&5jMkv#p|7oq`0_L;}+(2_!&!&m2h1$W1|5!yfuQ6U zeF>zp<_nbBWDcFGS?A(>9-NnKcozGs6P^Wihe%Eu$GIQUJ78qPG6Bq@%fUvFxAr$& z2^~qJIyzjT`3vaAOhy@51P@breQkSd~U!)8E3ws)PyESK^u)+tLL3 zB0rN;026YaH4`R=8kgg*?em@%QA?QE2Jo<8V=%Gx<6%{C9>)IPU?#Q!JPemzpazyf z)rFshiERK63yi3YBw4qa*b2kM;ymp73a>gQ-~6_8@#bmq7SPlrszjN5Yr%07Rem?* zTQz!6q|sb#xHSS!R0r7tRwX{rIDQGbgdy^|cqfrp1qvBjps`36H|C&_fYz-*yCx^= zCQ5s$)!IuB5uVr?CaMr+r_qBtDND=F`Kl-u($I56U)flUw6|xv)tK$NfTd|3y*kh!-h`*ruHg0NJZHPNY*klBn zuruHVe1#leN4my=V3AUn^HGM%qwZpj7OxBO;*7o^((7XJBKkt#N0X)XrBt@fYKWjv zrDh1l8cGeQ2I|R@(d}aQ$A1(fRZFQGPy47C8+1>^sOf6@6l(pnk78W=DCUAMRQo7q zssBXU$0eIs`>6YCp!_30gZ44$PbmvE>#2Qs#|DOtl+LaWtIj~N@FePoK=u>Wji?PEp)Zv(wO?(^0@fNCk)2ipI+Xdi#Cit8uxElRBoZkkSjW@y7hLz+5*Qmf9NSNUBp5RjR?PPu%bZ3G) zbAv=or&_aeXWYmlWw&px&8+PHrUn_>0pb7tFKGsRYX$kx|CX3^Crkebtna zR)ogYd7yuk(a^J)F#0fm9Gk9;K4#k1ON>5Pfk`*|;C#W9rs!EA9DZ$6I5os&B5GrY8@5lln#bYk2_;Lc)X4tR1^2J_T4+C;RP6x3E?B0|jp zMa`H_p2(xFS3L*}a!%fVQs(oDEot$(Fwt#L%|lEu;0W!VnY+2V8)F`D)4$R>_bU=&R+WLs^2 zZ`AA&4Iq022h*0bODY z4b)JG{_PUJ%4^b4cvHIZ4c#=3F&(-QHhjV5Z#Ru~J9dga(~y~^A7~ZJV|A6d<4PV!0cq$;&xDZt_CzbJ zHi3pbdmiOF(u9hJCr(3r;!i3ejHrZLxi6tACa&E8gAdd0G#MhEX2f%euVNy@Ex3Lv zcrLDuYr~&R@doc;HpP6DhR-}~(yTKyg+~p{Zi#F3CO{=gbZXie+!J#8=r}masxCn? z>o*@iaB>3r92BX!^%U?7a_dIgezh0mH1V7vpYw`GdBZYiL*-P16CF6oN~I4@tS0N! z0LN+~je#t&V>7{%b7n_R;E2fS{>)ijI%|eyia?+d#7AZV)Hvyzl#wx~gT_Y&@e?Cs z90Pe`PWgpX)xv=i3~16dDMsB*$$*L}1h^^7AF^r6@5nRolCXWi7wN|R1v_S5(tp!* ze~0pC;HD|R)*33l8>n3agjn*1C5O_Ihxu z!*lb!0kQMr2CDPpDk+5E?IH3e$Gd&khW;VmkexBpq%tL}%*dV@X{_x13Y-Zx@MUj1 z+I>v*m8gjhr)(9Y2OVE#S|{2{e-{c5L@1X=2U2i>~g~o3sR7uK?JWVOo9(g*#{TkcA zlp9r1j?)!iV3-#W?eEv#q}vntDEV*6I8L@28m~nm4xoEhvavBIZ&p zYWFnl9Z~f;6`~24Dov|sCdkiUnz2aZXZFf8^OD-uS~W+}GYN>&V}^P23ozYCD4Iga zo*0hB(C|&R&9(Bbo*0G8^wvi7CgLDwLh!1ppnp;XuQ_@*E_e|?A$S#vYL)1luRPDI?|a5Fb`e^!KB zl^VAYJUbr^3^p$!c7&wmr}o=Y8Bv$U6Ln#q)5mqQxOD8YX&c?CHKuA7yQbH0pg|Uy za2d{64yN-|{FWLX;2Nn^j10*(1>K^m^ToQrU+z1Cg;vBS$=E$(RQ^kQE)a{+-mVT^Xu;Ia}*R4L0CW1D4+ zh@cQ4!nues5_we)Nycc9mo`*HVWH8uQ~w83)F;rlA&+Q6unfM)pbEdI;;W>7VFOQB zjt#VT68Ouo%wxEf5BG+u(hb8dzyB$v8NzDq{ZCT+bXu@!8{O6dwq;;0WcvaIlN*v4 z_$sxGBj;jV3ALEGxg2;{WvBx-45DxYTHNR^mQApVOIJo*xvfC=WP~p%z(qOEnZIhq z83e6m&D^*x#gr1xJTl+5+VGB}y*@t!Gj5Y_>C6%oplt?GC8K%5hTGIL#*8t7ET)7R zt2F494(X;s(T&_-C}qUxrovtwrR*@J7pK%lbYrgQS&~LKlVfz#TCjBU)G=PIy02$m zcbN6Oh*{54%o@qkm^E|jgjwGLE@E)KfjcnQi6<|;`?>U@u3eZ1dW?|%7MKfSNUxV9 zJ^%JRZGLJd44l6)uMR5lS%XTFP*R7pEntKgf0a^FEeY@l-iY6*+)pgv8_kMoGm?$N`lG@jArkq#Qu}7(RMPah-xe;n-+KOsFonnH^aUlG z-ma8+R>CkIZ#l$AJH-cwxlET|E#gDf z2BkBadd9>D1|Q}4h?<}`m54*8?3?i`-qQ3g#81#$T$wMUx3w|(Vd!m58ofP|i|DN_ zk{_2I0{J1zertE+M{6WMZc_3C$Vn>Qsxw3CdWyBcIhq4cH zA+-SBF|{zTlvfHk!|os?>KDXFHY zg%u|AhhmlGyMm?K?6iKsR|%}K#+{jm}~+D zsF-nDsq|CT?Vucrq6g*6Vunl1srBPLXdJX$Z9>~p$N=I+Tq$l zeO9!?HM}!EKI5?y9$PqWTFwGYpfs@}pkrcX zpe0tVY`r917n7z+n4A0Cpn~78Cgms_hfR`-Ude1J-zZ1J zp5OHb1&b*@m&e6tf;JcHnHvRcj5gb9G;J<{WW}f)ON4ES(WNc~bZPa{Hj%CRLwQ?hxp-p|KSY|WNOzYyhjnBp})nDt!-MiE+>OpF0xe>uV#Em z1~>=P*#D^9NX)ow^;H@UpO74F`?S??rWHQeJ6mNIKGMW2(nhJEX2flQ;gSF94Jlp* z^73&Ndm5Q-UiQ%U4u5%;J=}k?Wsfwp+`Q~zMHfyTR*ZDhEqegN{z;cT(r|6_vd75G z=4FqKvg`rE`R82rNTZw0%O3D?gzJi3xrnV;P;3A4FM9x;|4ElU((rjfHo8opy~Zx% zz5IdO_pnZUf?8xY$))cy--!~Rpt*UTq$9JJuyu*scTc2DUkq!Brn1x3R2HS^sVuC3 zHR5FRzs;OdwP3arx92xQS%_IAXKD9`YBPCC*rC)F1U?U3x^(<~5z#+S_X) zvx0H+T9Y=&vt#}=YokG~I??TPZEJp4gUtD#SW^~a5*M4G!bSkgqPgroVKi8nG#cm) zZ^-Aa%-@V5~SPr`G_65U^GCDxl_OROch7Ok?f_EJb3*Q$wZtt`D=knP*^fNbsjZWUxx ziCP8OFy6p&g>1MCTCzi|1j4ZmC{wkP9O5Ss&P=3Joded!5YC)l^idkZZRRQ% z1k!TcbB}rw2lh+IRVH1VVyxWERsMmw3Xtu~%vENjA>7|8oEqbz(G-cXU!F*pqaI%V zTb(E@Siyr->Re#~ZDJMBYAeqLUf+N#e-Lr$ZVwDBH9eOtTa6-9)^W)t)H?3& z+=T;HBG%gm+FeVm>xqS2%H!7X+wgh_i^t$$IpeWpK&Q>+)!Nf-X*Cv@QgAua!8j@?qXd`R zQD)jI3E^q0B!pL@^Aj!!xQ)kaXA7D{+Z58W&OB{E^CptDUM`VpAR8Uspt<0Kij_e1 zw55{pp5ECyvqq9Om*{AX1m_Nv`%6zvQSBC_k-=srjPd#ZiwQel2oqkChJBlvFb^+C ztYdFx!ZGz?Lzu8Z^M5QRydsSZ=2t|zNNd7bS!u$Z`HZzeCF_PJybMA(Z&j0eI(lY( zvr*p|VH)T`FMjJPS11Fw&`)8sY}Bjrd(p`kyDxAo5;ZuevBf-0Fwt%{CR6Hd0;+6% zff(Ij^?+5T((WE_6Dx=n{!2@3eMXxycabVX-+XaOpams9C2tdFCTiFA1|U{Pe1_T} z;aOv=;5I8)B6x9Wg!88=4<$HCML;UK?NuYasdQ4Bry_9wNu&zEz$5D=aD74)RWVf& z7|&R44FR`D#-so>v<~^LD+HLkxScqIFykFRQ?C<&N``5o{aXkLxnyYf?yn=;dUf=d0=-ONfiv(gP_rGn?1ij{6_Sm}&3d|r|F zdh?XI@ZjUTt-IPqJspSoC|$t1fx?P2gqkCkl0|b=OUgZsIZ`xvHs z`Vas{pe_IntR6z9(VgMpwle%q%Hu*Z{7%T@#7@b_EEhu0r6Cz-*TpxFPKUJ)^)v_G z;ho!Z`lwxO@HAq$Ig+9)J9dC4}1HATKNl2cL9F`9LvXDs=R4N?FcfNtC6#ropZhcZs=}|8{U~4^SaY~XFRq8TYoM34Y5dsWl1Ls4E z8YgLL{3xfWaa~T%zd%GojXra=6j@uo8P8-dnf4GQ6B5IrXgOT?2c$!$pc!UV_cjk0 zhS3Dkf)HPDv6;lZSf>k$PH^vd`9(Ei}?w(?}nok!arnt8P|~G>zbZ zck!Pxwf2U&=!3qxnzCaD)dtb1>gw9|lS?PDg;p+|1ir(XOw^kJtf{rg3#=#Q800;l z?}l1H05|bF0Eq~xfD+~q0F3839wZf^3`|sobPUA+`&a02p$uUEQho#b+wkkR3*wew z{|b%$%ZdH$1%>=g`LQDbP&A<2XcP^!85#igV|-k_4IncH8{5G?aeJQ}fn;a_IYzXQ z)6W0;0Hj{qXQR_)79?pwUG8&b&MBB>#8w`-*Z*@BQNXOo8OAW=BtNDU3D7ZdF=Fop z;&^6^AQ5!KWLM+}7{6{KNZ7K9iJ34?+G4GzLw0Zb>>Ku8{W_jlnFS8 zNYIg7!Sj1llQgFJ)w!fB<_eM;>(o$m%+H3o8H zHc^%E>G-AJEuJNecMh?SDQpJ;_lRv^y+y*N-)CT){Zvea9?X}opUMtej?B$r( zhGMtfP((;L>!FAwCj|+lOXr1s#*`o(RNzg^aRX4pM&Y&tJBXG`+ z6>3h`O8F*{Ejs05LI5%?QE)#S3;c{6@Q2-Ffi;3kow2|T<$(53hcuko%mGt%&dnT9 zT{Z@Zoyq}$wB67fKTi%gX>N+KdNT+7@^L_*Qddgg#^Qi8(r{*8xenO1`1}&+fZd&Q z(_jI+SD|F$9mvePObtv5*=}oe=?a~7(6ti^Ol9@_HxQ$yo&bM#Rjvz7&d+qD$!%$; zARS;|>il;-R5>G-=cFO!P1yQIRqo3<|0R-OXOy;;0Kq=HA{O|u$>?X)#JZ)3X-p_p z#D>Htqa9#EgSLc_lB^j#i3uU+qPv)dsRe06{#42JM{Q#M>xL@dB`-><@*8J9T2*SL z<5E(>NEf#Nt~W1AW}o0i#>`SHCb>xA?*=cDMISN4W6ekG*;r}QD_+J%NTai?`M`ih zTL$hI_X67H%%V@kv|t$#tA}P%S{Y@CDTt>NNArkc5qn%g3V6M+ihu9 zlO?o_hy`3sB%q~^7Hg2a?rdYSOH;k%8WP2cJHpel$tPUihr+%j$MqYIwImIFpDnqT zUd$U+C11lEmB3V7x1_TzAiSx8BT4R!M;E#-JvPJK8uGShT`g#Uu{AStfxC z63uF|Oac>FWN{;tGqzx^^NB4OXd|cw>xGziVQ?dwQEt)%?9*UdW^jYyVt=u?iM^NI zZI?O_nbr$s@s;GAqt5rbW^rYx6F2r6&bK0oI$`^%uJ5c15C6p7mfHo+y>gE}=E4nE zUsZ%(7?QJoFuz+wAwsV5wg`6HE3?ikI5om+0-T+t zj?i3(zEsPU$d+9L8?U`R11m&0gkYTq7gf2cF7I!RH55URHF+)}He#(-d``vF&`1m% zFol$e{4cc`AN~cu_Rnnkm!_uQ9xrK;y*mA3#X*C@ z{oZpc^(9-}N3Lw$dgYdvY?XINOE%FVu5`$ZN?B9wvLm8?KxvAm)R>%N2L(EY84I~Z zuLVO7{-Re-=i=@wIz`AWfS?pndeLh)X0fRbvWz#Ca_trCS=VG6up?%jF@bVt_5^Io zK^=7*gigqEtcumMVXLJn5D}m+UQ6!F@tvBj&rADop=ch%BCF)F0m3q?%@cdsRN>g( zJtCv(fc!_I9;!YqSzHMy@BZAZUYuj`YJjWNI;0)p-2@$h5V#NlnE;U#-ea$wj5+qW z3qj@CAhdR7HmvuveRgh+-RWuenypDvt6HLb$8~b*j`)-WC>lyt5;G5+&1C#(^2vDQS0r6R5z4g zNCo%%iUWC@R8nRrZ=YnP8vUKbg$+yj;HMz(M!S;FWwh{^>%GC4CZBn|H)`kdCNr4WhC@xu`C%5@kUyu*&*!ft8@SZ~-vSwc)Whcte8b*acQb zt(lRA`p@UQs`!1jZP}kU+xv$a9HoziNRdQJ+Ud=^J?`bJw?r`}SyG6@pEp*!&`L1pBuY3>!?V{6R?=?i#N0 z>yt2yT2SQ=i-2chuR)bRTpSA_yKqI6$lmW4t0-)<96pL*Rww7bkb#*=Z^acTs*>|x z%|zKDCaRM2-%7$zm7M>ff(24(L_}S3{%MX)jJswtKjIa>>MHW+s&hD`(Ha4@8qO)w z&xpgGj?;j2t|#>!=KdIyLe;g9meSRADkW%P4~qC)5iUsI!4HJPVfg7e())&rp{ga- z(_3*+WH_$xp#B3fM5=Yt%2;UKfIc5^9Y&D>GvQ@h>|R zYDE*soY?A8@I zhz;rx19;PcqiAh!fI3UJGW_+Qz53pmAK-9Z@y)383x2llwQ%;Iy|0*wf?;SzCssAj z`c+}!7H^+^dU7BMwK{x8HeC3@_BhC3av>Z3{R6jlSC&oMO=!SE3ZqdktA&nHN@!&` zuH7AqyZ444knNAj%-UPLAy~TYIp5pXSsQ+JzPF=$)%bAN=iHN7$C3;7hN}zqs*)G% ziI%d}t=($Vhau^;zwA+L7z8ul5EIUFB zP}{^u!yOCtjS3t%v5ww=Nu^Ec`RB<#BxI`cOTDYMAX74w3I2@uv68b|U)7q1vrl%g z8H)SS2;(HzmJJVo-`!E|F}E$5FQ$b=etADP2C90pB}xHZ2>*&oTXnR8$&+oFDm4VW z?ta-5#4Z5LCh9|t{xZ=x5h~3k*nESA)GW>L|OON#m z+&i@#HB4Y!n*3buSpm8vFC&a(+8`m0e;jzWgt@8nx1*7-WPic;3BfDTA~Ue)o#p%4 z!lAj#m552XjdF#PO2)Q4@o7bgexGpB0vNWVCO}1pTX@%b&@vO<)5Y{=%GW_!NJsJQ zW&>3{MDSK}$`;URX+F58T*KUoQ$XhN_Aus}HuUpkY?;q(L;#uu#D|(W5L0jBFL+YEbMULvufaZygIT;4t%7q+JPTnT!vO82R>Z>!|Z+~0^mL)00ij-mGXW= zIol-9Xp0E|gSlW1=9T>La;YIQ?W8T+!~_81$B?*00JQ%oJJ`829G&$_4Td9?7EmlT z80xGCj>UbDpcHU2s4q(UsCjGVi3iGa-{FiNquZFsbks5u&o9qJYb)B&bBu5`15tzf8GW=#kP2?;&${H$rO1|c505Ffqp->H^wTV2&ATNwD-kr8q7>s8yOs$A9Xgg}O29Oa1BGi+bafrIyBxDfi*5}kU zfC$wM0I5A+U3X%#$!yP!h+ZQhp?58`3G}G(zSE@6dQCDPX32WC-q>z%EZ4}5dtJ5q z6dYjmIB3*CXZ~?36r_IaiXes00>K8c;iy8ysah!nA59ktihxY|`=e|PP`lbsAXSP; zA%knuoqHHTH$*rn+XJ%%dr}|J=#2gr8L3?AUD<1l;2ffF((lCxpufIT zWLuaU+2L4N8(1BpfXMN<%YtSZ(o#Df{89*fagqOc>=5YZuo0E&v9lj6x@a-o@q1%b zALVsP;WxD$Y=}(>arC`|&5wEGo38Nl`pGORK766ipXWpm#rua63$876!>ew z`3|amS!-)Fz#d{{s+{FsVns@{FZet_2dRoPUPt?~)YP(&d)e1GJv{G+S0S6BV>O)n0S)ZbYA7gW%DQdh$5P&#AwX|^& z1eDzV5mX8a8KarM5}Jt$B8XygVBk}4Rd&vBL8C*6Q%`&ueS13^18vP!IlmVQYT*A-9E=!y~peedIfES8t&WeF5DO3$5Yn*+CkTMq1 zy6G6H;4&CBw zX&z+i00>M-s_={Ia|%(F%yCc;QWF3sF9p;+4V5r+{>lBg?Xy={!Kr%7>8JE~!uX4X zfaf=A;8S+@%zkS&8Wb@+F@RpL(mL7=+7OmdY^d%YGTb(gy&g)IV-cHd!sI^26lB>IH*#Q+29hqv7^zh(>zo2b2{eeKbCZL{+0|S7L5ke7A4-my8n-_irS6aGP00VGk_nP) zTe5|F@Z4WT$yNO8w*RGiO1A$&9phoq@Uw=V?z7bMCnmkPG4 zaYR2mJ&_?mehHb^Hx>996ELUY69G}1}a=uoR+y(Vj^GzVFqOo!hBX^KLo zqi$pT2Pgo?Q@u8`e{?T2rcvphPMePT9}Fpxlj09oXqRnN3uB5@hP;+~gvAH`3B$#2 z%oqNmq~8_)G%Q%hwNXnnuExi}I*9Tyd~^fLy0#7u!NV)(n; z!{fPda#KP5>QOjP%gS)gY#(R>In|HK|}3Fsd1RQQNe1linxShC{lwe1egGJ{67YZ~jUX;j*T?0`0_u|~fP z`*wun#a|aEydi%L`N2(F8{z$iinSn~4Uk)QgnI1!kDrg}p z>^YV%1=W}g#b8@Jg{E(CzxXr^-InMY{WaR2B_9zW4;m>+2s~qS;vebCQEm{~rn|Qm zO`IB`9pz(WJMumeO*-r@wPd?7BHPBnW=B0l`uCUzeC@elqX0;<;yUP5yG2`(4z176 zW<_wuXQ4a|q%rahYa79h?;4yR7P&c=kyVe=8l7Ot&+E@BdZ2{>Yzwn8t5FYh>{Hy> z!FuYs&@o0zhFtuiOx!riWOSm8&stch&aBmo+TpB6(pWeEp_%E-%duy`Vb51L^9dh zmxi#d@ue9=L$MAGGGM)drAbDI1KDahiy4e2ng&w%kij~Ufr?IQTvW+%5i_oZt>j2r zqeYz8F6+5Im@!ZWSEv;b9EH;4eT4`C^yfgh(B(Si<*G>hfVdQTT&!h$3Vr_LE*ESu zi;$R=V!x!LOYNLM>;s3Bs-sm1tznwJMnOPLx=uh1B86pm=QEfEDiIp`$TUzDDvYW^ zMeuvURx-^l!csHH#{y^j^@_c$DHmF5uB|tf|3{f#n=xOluLVlIBm^zO$KikxXl`-c zr@nfW^Pa$ZtL7f<^bM1E07dRT+Uab-OgZ$5(Mbjxf;gf(Y<1(whj*yGzfY#?8EBV6 z4A$!(<{Pr<0ZBS-QbuF_xWM6_$2T%tsvwhmyU*9sj zAt@pIs`EiRKgl5VmRh9N-npOEI*Fqs^jW2Zuq?%4*t??@RY3`Qtcmmyo$ z6)7W)p+LZ~1$27Ps!y$`!g&y;>lF~Rfa`(5{Tk3|PHd;1SP=!+q-u_=xGF`r8{Kwh zs8+UK+k?0_It}i93`Gb`Voh#k({XTbE!M{dphp|iRjx>?RXgqW`71ETbdAw{!e0ak zJ!1Ga8sp0vWMLK-DXbSn4cC_ZJctpCo03pIwsdOuH$y}^Y<5EqV3_%idU&xEp3r*R zgH(4oMhe2{LD8Xh-$R{)-uGxr1*@ndz~LjKK9)^VR9Lqs0zJH9Yo?;!M{$W>TIM{~ zna1#2sGQ@wv#8;?@D7JOkcVTF5(5U$3Lc2U8Rcm37k*V{GO%jeixrueW!d-tYt};kgZp6zJ6$f{rL8^MT zvf%;XLtGoRQ3UR_@|OesL{-#MOjLuSu{{U-#;&1IB!6NndZ=otp;{@_7uAG%bmUJp z%~1|jOAW;I%*LVq+Ip+;_fB;7)xnUh4z5+>llhlNHrd9c{7n)TNqpfPd>> z#y^dxpvy0m?!83u@0!0h{=M!6(7!G9@b5QHWMSEqV+2q4NHX&PHmBOtB;u-p!AqZc z2ALU>#fDnLm;S1jn<5lrz*zWw6bP6mWuClK<+KdOOv%;kE9AQztkVylvWpXIIaFIX%k|H4kMfuh#hhF|s~g4_O-v^DhVanLyG4fbfK+;v0Qk zn#0o8wR=WsNsGz2jHDIU)1iEfCq~{Q)c+5Wv^K>oHHIbbI5giP)8CDDQoHMg0z4#UjBv4vQ=Cc z)bcs>oUdcn5?w@!M>Y_67(g^(;ESA)2LsNRuLzv#B?%U0qnu%IP6#tGr%1*UsW7Sv zHYe=}?*<+Q(7r`E6dZq5%~8v#LHWc-k%zs?8< z@)yC6&klR%XEU}d`GD5H>w)*867BSK{hie~xMP}`5f2C~T zuax7$@h@Kt5~9z(BGDTrUvfa}QplH_VtgHP5|ZZO3fd=0ox^YrN%y&)8BMS%2YAg3 z(Lg?elxlA4XssG_*8?yKkI_vbFM&VQ7G7Z<-GnR2P29PO=)&q26;}z-Ncki?EEXd> zC}4_3v;t(Op&ARgJLm~kI@%)0X^aY^s*ovE9~Em3vlNb}LLM61DXG3+s%W+PZwsxq5UqL!qt$=+bVZZXVMz8(thC^C#g-T8 zbVWJ1B8q{L#00~huDGKfss1ku-ZEJ2Ov_P8@(^U2Yt3oEI#U5yj<~A8!3D=oX@6aZ zi$ii)z>^QZs9np;FN!N3q$VECtld#jy*^}@pTZr+oTB_@U2EX@DCa=I$s?(AcCtDM zHHhJr^Ebpp80QRxw-O_4-o{;Un{do>y;xL}N;e*hN)b&CznIkcw|pAfLdn=xOScURXlv zNy8+h&V_-_$RhIe`f)8P`;T_6Ua0e@G4B%U967M1{fS&_5If}1MqJ?*PTL6fDbRBQ zG@+L(e$@?imI8+q>O4tuQTO5qE!ig~xBzwBtgbs2@T~4V;qXrN)F14|k)oY<$$)Bo zk24(6kSx^qn~@BOcHRXeVHE9re~^WGl6IbBnh}A-14FY=-z!zwpEsib`D{VIoK#^sMY&FX7?8BMl;9qOm7YH zOb4i_0D4)9@V+> z7-t9LF9sdaIbR>qDa~PnE3qp2&?fbXW1VBinoa6s^~U$jr25@r$5X}QoDAuM>Cxbn z=UYYi9gJ*pXruQ3WOQ}X=i!!Vy=vri^(wz}1I`#zcz{Q4P5NcQv#E*O11`8RElDi# zjZu6^AOg~3gog#OzFLnsLlDv=stt#df`JRhnks($8_GYy={325hfS5tb3h!ws8c1sit{uz zVa-iEj|7z~zTKbjN2B5Au@~7Zcl-FaxTSVau|A0tW8>rC$= zE!bOvoMX$mRXTic(BU6&JAkt;5d~8WNUEW;Op$Hki~4aqwxtQN=<5;`>}~i<(8zac061$Iu~D<$RCh9+e1x~eg!gIpoGE`r<~-AOxfm1p0*Yg zA>+yTY?G|hpF-5be<;}tz;GXJ`Tfz!#bzWc9US(Zy4+GvzpJZNHlUdbAj(6J)09d@ zQy84a42>Stb4~?b&AQoiTwj0#o1xyrOho!Z`K}#@XX9b)lx~#tkk$qdW5;ykVISIS z#M9VGQNO^k59#EQ0w5SC>-w9PmAGGIVI!) z{j@oJik*C_>OZ0%j|w06v0@wmju5&EPFF(3)LI-_DN$t!dIfgh%B!RVY2*P+39sPE z_jylh&w0{x0}tEg=lF6CE?_F>9#ZO)V%mWI@$<;vy9;1ik z3}7MPB6`ShF3=l6fefnzn?hbQqQIcNKaPXYs2a%(YoY*s_4Q^}cTqsoCH2X#+AUfx);TvG2d$B*mRQE8@S6yLSVsCL zY4JjQ^M9QbC4xEP;+M#0!V|G%q9~71bYSml`n4S-A9IMT3e@P~EQ7U3sj$`V(?if- z`Rl?Ux1_%lAK)Y;4DSm=j=7yrT83;GjWObn^17rjkI2hj=V)~No55T}q2~DOE!Drk z>6*1S9nO?*eC?Otwi5((kdo#x$4ZB^NX_`2Jz60-hC6bS1?B-b1W$YB-h$!A%pnty z$%jLxaD`*?WuSmeVG}{A6Fo?>4E6lRHIPqS<)~{;b=n{% zJ-0FGL1LM*+3tSTRgN5U5>4YKnMTtu=C^xLrbJh4rqbV~ywh+N2o5BZY2~>i+qvDo zMq(;Z3Gl&$E++jSNfjLP*M`h$ut%$zRg~8y>&|L?i;O1wGtqpSgc;Y?o6m2?GH7WHqd4!iduiK`(>MG-EZDY*DZHu-#h)h2p{#>NjNm+IgG; zmeSNjhiqHgjobvz!dM#6mf&OZg`wQKJ(zx|U!5{T6T%9TeuZnL2<09Ym_8+e`c$hE z1TIY>Q3#w3i_e!y_C#z1FT{&X87an0dk_Yvaz%mB3!Q^qOXytMXOyVC@iB9dMo`9w z)-^fN!jUArk;H|W_CX)u~=p{ z4x7X%Mal@o57&qvYUi2Gs1s|)3Yaz0-tB~pZ*3?y4%T$nO7m*$+nhe==}vr`GqVwu z8m$;)2DNB&a+=!uHm5aE(*X43%OR6-4lXl`PMr7wf}9P5sBM@Cg=r$=Gy-Y zph^5$ShKz!Xuhm&e7)1I&iuXY4PpxS7^d*Ka2==pX(KR&U9zB}RUa^g=t0u|yetmX z?1zdpy<7tG{?e%Q(I4 zYLXX|{s(mkywmKWJo21k$}$B5D5L{kezZ! zV@YUR6} z@zgdjg%-ePgcqP49`KmH$P5ym^dd8G|DYM*7cmV|WatnB!7fAWeUuA`JU4gPi>GH* zv4ajZ2NWAbtD!5bnH216xjon7LS6$Ke`~rDpA_e~0vZ`SDNNB`Gbzli@7vNS+#fbk z|5TV|-%Q;T?l;<)F{HVMEJ8%_G0nv-qWl2oy4fashfx!s=eT-MHw>B$(CFfaVb#!Q zv51#}YJU@}%d)x#FUvxHrdoUw9>g$SB>e{fMcs^;gvi518Me`$ow!#k#uB@5(zj%b zlaY(GwT+d&ApHy#r(01eEh%GLNe?8m3=q&Hey3(iOsBReVdid+omp*kVml6sjyReo zLkrSaImJQETjaQLZH%@z)@n>Leo>S#eYTwOA!Zj%_5#Ea8X)L8_`^VdU<@+=CB|T| zQlDkyA2>OlkvZNN4T-g%BFz*Ij;zTW93BKBB~{~Mr$a1=gG)tY5VKy5L2UJj$6Q1rAjtvL|ZPkG!RChtPy|I`DNlX5O*k_UJI8EaoL7MXS86b)o4LEdiA>jj= zF7&VLpU~fb(GvNVP3lR@q5isVPV>k|q}H&`N~Cj#B@oaUq@CRtY1`q<^w3+JdFN}f z*-)>45$Xlfu_4A~D?_;~v1+%y2rHk`D<(TA4%NB&No}=eu&7kmSCdZLSdS}%SZdUA zG#HUN_r4Vd{~OdJ&)Uao_k!bx$?!kavmo$i)Bd6wQ`DnJI};lNhmtjxZNsrxP5IYU zyL$I~oo)>lm@pHtL)w)3ESMMl4Y5+zDV|Z9-mj-;|k;PteZDw3xOGVb;k$b)`3x9?zF&{ z@G$k%2b?yy7lo#%O&`FJAe89|$7!evJNuiAlZt zpoDe{iJUA|rvgZ@N?{*T3JgZ`mwazjWL&I>6}%oNEvc_vCm>584(0 z6F)|P=9pLqg_nP$71#iLV6ejw)XS?PENU7Vju;b^cLF+>XJHu7H%M=CGVc823Dc1c z%hbZul+oi*iheji`fLnQQ7)vUS^2bjz&4-C_%H^X<{)EO0i$j$iPv%%dMTwMoNpMG zYVwQ0RI`C2FjUjdXGWYlf5fR9!i4lzUH8zeiOZM5edB zTif#v2@MG_OAGv1+E!ziI$g1nEelaaUZ_&Y9VkRX>{tZ;U67PNnIZ zW}V!nR-ZDuq<*ohb<8aNp#Ta#X8Ay70cJvcGkl?vhYldTFL?Q~dURK7?=atj--cz6 zD~!#LiQN}^@?+FFPZe5Dm?@P*3Iv)$dNklS9mxb8>EXv3wwSQ)JVW)Rnea)5jG?=UZdTN1XF$us z#*ZuH^FZYAzL3r58SsG6Z`7hW7<4Z_C#U;{!7YXHW*qFZ=?FnLFj! zz1-<_5g&?r+v)9|+B(55fH-U(XP4g!IwV_-!7{n+Qzo}XNTCxbX@4Fq)RW1rT)4N(roo3;qjeae<2}Ml!&#KK6>=LP5+2)?)#_zP3h4XXk zRA)TO`f*nze>{4JHF9ZxgFCh()*lWsq{x{y{<=AA^Ws@vd&ay0(Q+;{ERp^H_a^pl z^-V{$sWE4_q}4Yj*i8^OHlNJ?T4U{zd(iyd)}Fx-IcSZ@ZhlBJTI7s6X5!HE*if4| zR*l^83GJtXPu9%xnu!ReMHgN3i8YythRXYWdg=S_Nzh^vkI+!^LL=TD5{QJ$VoGHJ z1Y4jR8||L)(g^W>$QCGuyleKH-r83)G#Q-UN(>&HTKGs;ui8GrcITK8pv%E-kG%(w zqP`p0)sVqxh3PFCAUSLme3gl6r@GbD&R6;9RX+A=g#PQvc~Fxu_4Y@)+FrM-oSIl=H9AQvnG6tBZvpj&5ZWF= zTZ$INC(DA(m_zIU%fLbsBH4Ls7DuA6G4)if7+vN*nf0ObFA;u z>mBOp*S@-CLfL}w!ySqyuC+T9+g}AE2${v2&py`K9_&*>a?xiOxt~v{TX&~OH20jF z>2M(|l`XYoPFGt;tjTaK=br7f9QEjjrj=Fk9rj`Bw4b+jyiv=N|$4xhluVWt&|zgaksL!YG!Ptvd&-S}F0>Ms$dm?HRU=dyXhEp_^Q#tt(^PE)PE&Iz zaE2hp0z6Txb81*fNCx6)Eb?Ypbs%n>)>)gN(QkQmCg!wC*&9+Kc7z$fDv73)TgAYq=@OrARR9W8CPf1k*vuQa^Ve<)#; z#tHv%EBGzkQHzvuGFDSXBua%<9Li_j!CF29*>pJgjiBBDi%>VNamJn)0~DzUqJT83 zmcG9L$#TuoHPH^hFvh8g?tsZ(x3sSdEF&E36k0C~5d%!g$)~H$D`}Vji)+mV9Na@W zwd9XSbgDa6ilqQ7sa@@z+FlBj6)_S0ER5w)wn!pSb1NXISx2BAhGD4>pZ4kw*%@@` zap+-^8%#|U^+45gpLSsHi3Z96peZe02LtV`Gf=3A993S?H|#)VrM%^ZEXx$yt+Ol- z1uLh96IF}MnvTWS0BK+(jUO9+hwXVJ6+1;uL_{)|^Sq^;^rXJf`R@7^Wul4@XlNTs z6OsU^exedE#fK%Da)&bP_OR7(*tvaah=prbpHNELmc7QmcKomk8KL|kCk!aR;e@38 zBdT*m(GY$eC>qSyR5bAGqYP$6sMlv3EsDsVVGV)k8QxomvddLdcBg2MTe{Xcq7(w- z0OnFA@Q}8Ff9X1=4edwnLCghY_2@rhK!UbWcg+knRA*KSBqsr~SV_q+0w4$XqRpWu zaU?mBEwU}6O%#|1vSFy)3GYSPufJwUZ1w(+>fnUGJF%#o(AuRbTE94WmGKL$^wQ+= z$NVC<=IPs7b9Si9$f<9yMR5O<>dCdvVYsw@S}sTF%irtE$Mt11F0KGqHJ?7YJyjAT z!J554X;n?1ahf8ydy9%+7DGqE$EHO8&fSE~8#Z=SK;O@os{GIGZL0W{>}2axs{C>H z2(-TN%T_Ngmweo<;PP30+5T~tD7N?GE<2dMO5RPnO70e3<&F#RF87V3l{Ky=1D{$l zb5iHlbyufPhI#_K80&n*Q6^55o7>l2t^8XXyR2V*YR}9bQLE4%0FyPhE_A!#Pv`yR z20tM-bErW;7|U7DF6W?uLcAFK61*J!w{k#~G6TDvMP*ke8x}x>DFeHVX&7I7d75G# zXB4>KSk6j}ixpLT<1r~%ZZFs8OhLcjm`_-t(?TvmTtw$A z{3(8&14d^+jI|>M+zkpCAT&Tu@g{)=oI=hn2Ra#D24;;`j2dM!K^eGH&rO`|!Dh`= z0)R!814_^-E|HfV4_txJNYEf-<^;U349#cu5-l9p3@Kh0VCXm10x{vEmPAlX zUbb!Bgh;o62%_G3Z!ptKsHZO;T{`TabXRx-yWO3k|{dj9C^Ww0T)&>E|9p7n2vFuHr|R0|fxzKKQ={x$zP{!shk&-lFgs zLQM6u_UIY#T0bl5XI0jOF6xJf@JM3maNPF956Yb_nLd#zOl>d^0_EPQxook>j21(?v$ zDtfBXU9c6k0|BsZC`%*5B5^=)2~b9XfJO?6oITqvYGk=!w%v_#y=(?RA5@MswhynT z^R?y(x|)1L&RE$W3t4Q{%>>ln|zYD#@F0+26n!n#zQD5HflnU`^+TZQGpj zUep1rZU@xKU(9|8)%%l6@4)449l3TJsafWIDSJX+0OXKOQ2`u0t6^s9>IWM?qKE$) zj{I%kZ+!ifsNoStzT2_$bXz>U%k5MH=@VQv{ofk9^2={rVV?{kAPLo}hQt+k5{E>U zI#qZ*`;dkqRM=Rba8R`=S7dSNhS;FRi*i1aDe|=3&;-r|q?9QNlqvWhmJ{R(P=!Qe z608**m5yN{EzjyTq-jS32|;yH@fKN8@HRoxkz@iV^)hn{h4U?Xsdb5?o^A zowexjMB>N#Ne zNU~6t2v!KvltdFAVaX6w|Ak|f)WVI8CCri9^UKaswH@RLOu7i9#ib9Eic2r%6c?}D zAhTm>bsyY}6Xh%iOK?sJWImmN0M8)daPmPn%6TXwF{`K|Q7QN?d?xUfo@#kfXmnld zPFy$l2Gk@Z3mXn>AA%bSpKQZ$Z_}o^m)3YXvozYI8!e&~I*4uA>f|jv_NWN}c`7RBNM|c8&u+y!U^s`)oKW7NP2Zc3fD%PCel8AiGV-eH;H0oaWe z?X+qkly@o6qx*=};7TMNumu;y8lQ+4hLG4oAyJnMc(NTAWJGeXt86i(v7G>_=6;kR z0cly|+RLIwhQu2!c+~AF8Xu)4R41Sr3B9Ow?Rim)YdK@8kz^87iDKyZYouCPw_uZI zQG9)wy626VmTIvPD2`nMh?&g}oF-1lP; z{{ntNy{7k-1$0stDMU8czYzt57gS}&8GVyFj-nSA14RH?X^yIcm8 zJAs6au3CV0uxlW|W5Dweq{??v7ZuXzLJWQaYrQcc_>R`nq~4V90l^2zb|cyVl^kT_ zA^Wka-j7MAh&o{A05JZBs|y<$){Gumd0<*3`J0^pRs%l4-{6z5E*LEEf@X_g|LIHm zo1iXnd~&KR0cN*UCD3sBg0l}=z9(U;N=I*7y`{-(u35)v0Q->EF~vQg53o!NTz}3w z&I(kk!Fm>)KllVE{2V^x>WGOy7;Usi5td>kWn^}%759foN=LA^A;oHHthw1}gG>Ht zAl-A_HfKy;(@P4=2W%}YhXfLgShfv#(frn#U426Vg{H>Y=Xaf9*j^sZ&o25&GNuQ0r9ut(kS z)|rR0OQNql8JzmA+f_LUd`9aE)0hV%zhUkmDrp+$xq5w)_i*#Xlm*;ZK~O=lXkVp{ zOm%s^kr*?)l&i{rbml^v3g?$L^@``5qhLkbbm!P4%mr%ob53tls6+2vQ~}Xad)`0C zNBK>EbWXr!$+J$6>iSqu3w|H|v7X@3bljES)O9Q_sJC4`|13JFD^eeN$IO}DM!j-5 z-i>fu)!N<1f18I>}>Q)f=A+6xcSAv$JSZI~zDuM@5IiX96=RLZk zja8sNbTRUh>ibVRud}XGy-zuB!uT(HO4R6I(3kJ(%hUSOzE9rG)0cPdbISN&#Xg6c z@2~80z6*8uMNd1&<8Is2&MCMnJmbv7-GXQ2yYuvAmA>5ej57}J9?^I9ucgRDeK}2E z{_)q&zoM4o_B$t{$^yQH~4W6j)zH8>2GY9V6DT;12`Q0;rl3D&u-rakv`myDnJmKaqZtusoJq6r>a5l|K zAn^3x5=fAH^KJI2g%nT$3C@tdC|vvwbG}=y`&vB`bRd!QSFA^O{Ml$7 zdnJFn+^yqyO#WO*&&Y6F{KggPB*$HRd_dw3;X8pr-9|s2R*&B8w5s*5FI{APPG!^X zNtm+p-cYKfw5>_4enY8Etx3C=01%BCcQZ&F1kRYS` zzu{x`+~S#3eEsRj?lDzJ1k|@-*G0uBMSP0-Nv#M+t&jqiEf*9)&w9C`V77HbtTFwD zuk5fL2O6g&{sGTmI~4zegkXtr1cyHjnh--IB3CKRru3b<@t7H}RFACdo~rua+u;;F z_mU0t%iW${vbd7)=c^gho4Dr7KGa#~PH$=+C&>dO=dmHHP~9#Ak4gAvFDibUBwO{r zsZ873J(HRq#%1p}XTK_N^32_0iD4CmwG)KUU-WrOjqeNx8!9(ABomn`lAi3FsL!Ba zQ?_I{S{l=aOFqO1K|X>?Q4GiYaD9OlthrH*RquQ_)tJ*HC$~Ch{0palW_CfHz1A(z z?g+;Eoj`J=B>XS@EjE5IfAfNyV0ppTGR0knU)A*;C}L9{mZ3rnZ0kKfc4V>gaH`2>ve^WkYC2=(;Z%dTDoW7M zBYtO@T6$JXXUuO8&$VS)&K3#WU&>nhd%ot-=npkmT72O)0XG%wU@cH&nN}>7pg~US z5Pxo{Pr-H>&D|P{R3;)gfK1dBKoLfE5DS=( zg-Weics=8+UxYZRFsl2W*G;FijR%@1A+dX3Un+M#X-8VRQ(62XtC)HCE zv6Xw+O=l?};h&>6j~Wk8qSZZlwdt^?RC4V%cdF{AyI-%Sk85%Z*9B)UxL8`Sf4;HI z&HZ(s>7JAJcz8g$pe~ru)T7S)3`C};g&i%`Mt?p6nghjP18s2)UVcIKvT_sj^hH16 zWxdA5e(HmZ%grE5u6C@~TU5vocrZO?_IbCqz?@qyl7O8}3rdrhUk3A@tK+cBE%+tg z4do^rftoBHRW8A_<)UlFdqw`>E&_E{TD1v8Zs#njjG`$e0i#+o1XFaF@@`30PU$!q zRw>w3-Y7lsTB&b@4}?uy%9(fuSBO!;Gqv>19aH+iT#Yyii3;i#t7u?G8QZ7mn<=U- zYWFD}GwikBR2LuRzH<;*pE$}Doyou%9VOLsw0i}ODoyidTsEz4RiImm+_NsSEm@a0 zRg;&G0~zX1_?sMc&ZoP(x-fzLFaQADF8-w`IV545{K|q=aCv=8$DC2f{t|UkPi(vg z_P$Hi4R7ff_bSW>PHwdQ?YP1c=C6Y&2~(Jl^r4&(e>twrxI#%+9>pud@>{%Axum}G z>KW~J|5x%vPW7Qp`-HJXe7>01E#r)G5q%cdgtq%7k(M@YZ?p0OD}_Ml&+JNlJd{&nEZ-O zQEGHRcX-qie7GHQdllNio_2Ni2{g7xrZs%ZE&ih7gBl(&o7MOEMC%@hTGwO(fICVOtY(qLL#vT|<$eT5`K)odz zUoqcl16$Q-zD=$%lF~wl`(SNkW3^u%F;)XXSW5QHLb~nfw zve%lMfI;1Z@u(p*yk$abOopqp=0jtU(dInXiVeF(x)!s?m>LOs4AUvzDl?pb*#;kA z{lfM#HUxQ%I)1XITY;c_;7_EluM%-v++OK1@GM}5JJG{|qa7nWOX!y~p5L1UKIdl}Ewa2)F z^)=-*O*G2Axa}wYMs1(o^Z?|#-On`4z-8V%_h0Q#EmwPf-Edqc(5Kw3&Oc_xBD?<| z)T4b(a~n1xhZ(e?yDw8WP8C&B@vhn9jJh}NUkE>GP}_umvoO7isF$E2Rx{qy!En^= zZy&Gz{r=Hy)8etAU@g=*rTxdj!n96BM~qom4`lqC)=WE#YOC|M&VIjjmhOl!$OhzkA1QnriZQ&hDzLaxULc z0TFG$QN6qAeTX&$Kha`(ZLd+Y2));k2GnZ0^$2h^C`XLrOQdd3ilJ`~PW+CSHf z^}d?1?m8$$A+ZDytwDzfq8FIKKU7omgTq2GHu%oH$>9dS<}+v92M|FCO2f+1=}leg z)kidC)%_pn2-S!$`+;E<{BQCDYcslb?FR;-CXxH^#xe*=)@qPY`V3BbGsGi4QFv%P{061lcf_!L$!kNFH(+3?p>) z)4iz^%TTWyQ7l7H+3>Lp8X_V+il2%WtPUE>5CZalX)MDqV4;>k0$EH{K%H2IL;ZAU zEQ9`1Bv9Q-Am#qqu?&N|VtPF^mSMP(Lt`1FWE` zV!s{Q4>$z9&+SzgG_{xZ>mt}6-^EN}}5wyIIIVBEp$9ywu;Xr_eAiI;>okLx8_6Y^R~%EY0C z!;b9VxwHS(;VGKXrlF1$H3=TPa9NjVE|Egfz7S{QG>WRwrbZLZK}p8Lann_kZ`Jk0c-XSXG^RS^L=J_I1yzC6~3o%6{$^RlK#_K5zHB=a(k1T5$O3F8y-> zPrl?&x@sFw247z0a8f7iKnd9TzI6rUtK3b>`u)7o>i&<;Z)(`a$x9R;x>emUeRjun zSI#dkxOO`yaw{EYIx#6w@`=LviF<}V?q1{%DP6q%R<(IgwnhEyq{*H3Pj6M$YbO6) z;m1tHEwvS|yH%a@wNgv*MGHN~(%E*EOP{ChtK4yB!)z=6w$d8=iwMU0*qoagly%Rd ziJ~6Aack-Qbvme~T{WlI1aHyx@V!^fxxU`_3xAe6%9Lvx9OUIEa@!iLCgmkx-FmKP zwy^X>z?2mK^%kwg^T_{=A-Cog&XO(za8naUW6|Q$Ll4ENiKEKEB{**f;mtr*rvkS_ zM8K$%zGcm>_8}wx2e`MyBl+VYd}0TUF3h=)79BHZI;8i#8$y{@Dmd-T&$v25fw`W)pqP;Ggu%f3mYGtzq**B9rzTzvlMmc+QK%Uwa8OApBj*DsE^}d55e9J)RDM{*7vcix3;|l~|NPmB zi}9;4H*q!QgZqU~@ajVExRO7b<|c4DG0r}nWnarHj6){ymMs>;7701Dm1Ru0&f$asR7YEvU z_vEfh5|0ynfP=0<-%jp=)0R!joAjHOG`h$WmrTI92-DbSKWOp94uHSU-fekVjhtcf zh198d>3aI?HXI`%LAQPOV?i(XT4i8ppZ#MAN}Zbc5j2Tx$o!{%aJN;gruel+Si2+!|9gLukn@E8{j z2dqKV&bHO(FLf)g+F=un2nWzr3Mg5mp$n@RRaf%RHKJ-!!&)S=mJFky?)l!)<6M>~ zs3*o8GfTboG6=Vj#+O{?jyqbKWhjOGkZy#KH;*fjsPNv*4?SJ2Mbfi9m$~h%YR|_< zmFG9;I&e&j{vlHvR%Ra8R0boig|P>nTB>65U5z@74hFvk&H&!@4aPw`P!GvLk}bUAJQE0P1avt=p)`h3`5_pExYHO$ zCH=jaOmHF0qD){3uQ7oY^^p&@wp91>?BxKvK)xgrRAZO!6g{cKfp-$2PDR`qo51AT zi#eu7^ngfL!r1B|9T(joq)Qv5I}%e4<2d_Q0(aBKCInMXOzwp!xtn2?#7OB&tQ%<| z4*yVfd)pu{qcX&NY1tVavoGXY7^u2qva7J2AgfzZQ1^eN(lI|7EH5}ol*s8IL`Y-1 z(HM`+Vt9aVGTs>KZ_((l%Kh%>F0Z|eCp}^~ z=B@&O9BBdOIA2^~Uib*MsOy35CrllEy3B<<$Hy0mje@bTmt%?7yt*uWRUPz-P2iJw zdA0c??t*FvYy^*UbA=5}0Beu|frG1o3G^L`Ou&8&!nNmf@PdcDjN%s2g_{DQ!o47` zoaZ=z^mDa%nVZjiQUpbBl&UUsJ%J04x^dZQNRrZNM1Klg?p)^1e$RR|YNLb=TbKr( zi&K39_(?gu(r^MlH*mtxgnigJbT{xK&mmn>yx#BNh;lp_R#6(&adWNbl6JU2T) z>9Y@)rrAjk7sPevacNLZpKfif_Pe3K5hf^78vzzMzkkP0Yzcp_eYX5v-@={W=kMbc zJAR;eBIggVjQ>jiAt`H~3iS*$P$N}!M7%Db6~}N z@sk^@_OVj282hk^E&;jdQwcc?WU5d^+3_2#zlV(Uv5nTWFs3~V3ngOO_k4bG*L7Pn zY4wRU)@be!7oKUos_)uw6Hu;~DBeifiLSyxJ=pp`EiV|Q0B`6Um#d%L;m!!YDyjEf zXN|MorB+{bboXrPF)V+R6nBdEaROvV2kHxH2Wkd?oqmUU!A}NwQ~VK*znYsXeQKFK zE*pKSn!6fWTWgBz9la_3q&+e0!&J*YGQ7Fmvd4utw^?>Mym`{H4-0Q5*>T8aD?qMIh5|g8MC1@P3l^^E=*_cBqsvli-rFxZXPqSBE zsm^ol6RbznX4hW8+uykMGC=F%l>NamYj?5oAOl#a?Aj<#p>@lr?Z2BAgm)qKDCRv# zIS*+c{H;>-UcFqeun~^2bpKH;s_>XQQ9bsi&IQ@&R6@Wd_z}b$JcihJN|)-ITS}wH z2lWz9$p%^I=fqua%WGVac)fBOfQ`^huX=pebaiHf{W<$b%hYoX_9Xk4%hbfI zJ$7^mHKR9!V<|pd`7`&hFBgbD(?89H>Jehit76t~}^cK^(Mg}wh4<^0^eynUM} zb0A@1P>>>Fy`cB??{2y6Ge37*EE~nY_6v7KaX04yh@rXzx3S&PI*tLP87O2Z^wl6>xQ`CN;9^uHd&Pf(#k1 zyrW{G2*yHO_Y)JTjI1tAoJMhdVp8;#@3NkF_pKJ%x1DiiEyt*T8oT2=aF zdr^(*nK6pQxtF2@oM1 z4}iymZA<*qF1rlu;wa3bJQd7xha&pDh0wQle7v3LS^S!K$KbsvEb-l9LjLPGsm3RrazP{KGY4JSMBpOX*JwPPz- z9srJBfo6EaeT|a6EZ$fA1EH;pAL}_)*6=-cjOsC#2tb5i$6`RH6Z)N}!6%hP??49t ze}EZ#Xhe%qn`=>dYYTH>FeFF+DaYq(%8lumh(LzIL705X)e#HVbKY z0pcZ#i6g~da`*r-PVE8B;wS^XHGZDR`2?8~l7N#AUsEY?3E({CV2xu%pfL#LP(cN2 zAS0ulDI&Sc&CnDw4LWH;6{Ob%9?mQyS4NNm3RBBnIL5{G0i7V%huq;i)-V%0nOXKs zj*F|$h^*{}`3skj(~F@>!UC_7&3085t74;d!{!w@V5MT92D z;W)!#x}Z_}L0+eOK+akAE9kHx3tMhO)R90y=~gmC9cUXd(@EtopE)`T2ZQ#3x_+R} zV!ZbA@8#OVj4`Ad1Hqz0c0{V$ijY+P*nHTqLH;0#QqTIjeofe1O#vW*}?k`(MVqkz8N7WatQ-g%+2nlFM)nDiV~o$6Wc^tzB$nSLCaUDjOnO!IZ+YM z%oG&?CQvyk8PNm>91?hZ0F52xf*|t{pJXbqbYj&@m^9M$3gffTcf2JP&Man9qDP99;rf9PQ4K^X_Juij{jdjS6{1~k z(QDd;HlM5$8Y?X+;f^X!k>`I;(#FJIc*yk$w&&m?UN|vC=fHsINA!at2(S#+C&U&E zC}C{9B4Fh1N~e+tzhS63|0%1rR8s5yepK!(3Rvh{5@iF%#-G3w?a_lb;5e|x;L;be zDBO5@HG|?sU`mp+B7F}MxatuPi+75C;(|4o$jP9vmU}A=YJ+8RPNP&=Fp`FtTGhmfy>p<Ca|)xZ@i#^xG>kY&&34n*7}YBna|fM#PNmW4VS6QpdDok^xVQw3u z4GJ2R4ah9}wYu#S(H*G2=c6<#n1hE{d$6702bV9#TE|mLzqlh*{%&b$Z#j&~Z|X z0oueA2)XN;(&?(5g?Y|~c@AbewRB}$i~8f^?yIV)sfj#bjrhCRo+8+}lTf4CfZ5T1 z2E@iCUqMHPr^ef9+u@N_$wK*EDg-o6N% zL%zNcp7@mS@HtmdMph6jBSJEg6Ldj;jvoMRuqLrUCnhhLoool(V3tJ+f87MX&^sh_ zfHQ$M z-eo;)NCuwqpwwMdffih%!yvmCW3sy#N&}jLAv6RuB^^rcK#DXd17JWc0;M@=yV8gW z#^T3DfWk4tH602-E$EHw!50nk0k`I_hUP6;ffy@RXgjLFr3jL2V;e^W1>gpA^1fi; zE&R3w`Vx-%6|EdKoV4UK40$vsehR2PE=d21Cb1=r08oH>T>v0*PsSU~;g5zZSg>^o zhhJ#|pb>;A1XTu)h;!(p&;w7DQG9RIQ90ltC^Epoa9zA$ru1@=sILF>i0C?07PjYd z3IDLOf!x&qoP+51JpKna0BqYJW1u0TECWG6bz%QGNuDyBjb1#$-(=BX9mSSP?a*c6 z(8)!hmNGeDQE~MH(!?V5%ctDNs@bEH$Y`a3EFbZI0lPx`dbwaVV|w*s3RWF~hk$FE z$iR+g*(>RtQJQ5h=M`ef1;NTm1FH{cX3mgnazO~?+B8u`89YMGSm*kYeuBCIAM+$w zlhXx%&`;Oj3+fUrNlbD&D2sI-{K9IAe?MLKh?+PHXrZf^DT_Oxv_P6SQYw{ot=D)4 z_SHW7j0${DNNusvVKyeecUoIjHrp}6N}7PplI$h>?9;d=l6prTZi2|S5d>Wu6Ai@; zEX$ZmrEMuF5rs@Qf(~OrH3P+ReBlIwFxB#*gVHGlc|R`vYoxdrvqp0<=a@Qhormv2+uzjo(l2EMry zipcNWs^0!<82<0SMP2l3IHf{a|CL|E{t4smy}x!lvpYz|C_dhL+f%=G-(sE9ycp5$ z;3}`Jz`qlUKWvE^#@%NhRc`Txl})LX79$E9k4~##8Wv&6@`S~58>R%AioIsI47GbG z)4?+H%WyaBv!|E4$ZEZEH&U@Ql&W4gV)I8WnvqDXSYRy!-^Pa}uao~y>hfCr>hYBx znv1#B@|x*3)P`hOR5p6nV(cR=e9T5I5C{tQc!2(LFNRV{)Qt-;YHC8$Tb2ZM!zB&B zj?~m@B7tov^IDe{gCRr4Y({~e;|e@qPJWNVGj;<{u-mb?ZE3~uIz4s^-Ne6>yVz6- zJ;ApfsCl#`F++F2i);FXcBxR4=A~;@b^?8a{KpQ{0F8@J04E-vxXcur z^S2UvB(WKN?e@vtef0K3Vl%byckYZaw}{ZlB~u37#MJ>!fJn{FKV1iY=k^X;1}mIp z{^NIUUqS2XA?hXlo&TcR4!Gm1H-Co>1vZUs89NPJA19a(qOrJQ=~X~l>OTafK|n$E znLHEkSA7pPGhYKTv3_5Eo`$kimoZ@je$BGa@Ln0%KR{=S zPm$`O00cTdEw211?y-t3UuVG9nhOgm1~vP&qq&+NO_i`Vv0j1%T37;*ykcq;;Q=U6 ztk^z$(@;A(9l*w2jKrsVd~-aJnygSX{rCm1P(EnaMN7stj?cVCoR2C_c)01UB#?uP zoR*otK>N`FEOBWG<3O-^@w(+01+{2K8IGc`PTtAEvNR`C1cJb$6<8WO#)$8?CQ;{I zNw60*g#S0o^zdUosDdTx2uk{02j!{85iu=LDM+`Tup{XMxu@i=wlyjCculd#hAW2L z%p7-06z@3O+LS}C87JQADjne%4DnjItJCVrnqn)4E4Hqt*Z}UT5HctR)V8{@rrgb@ zx*F6VtlACiMZ1fN^x;o{F!hdryOtH#nF=aCnHlvJ4=p!1n>WDJ)^^bF|V$j5(6tJ>Y)7 zN;2u(`x{%-&Fic;m6j5jLHKVbfM(g};^$XX+h?t5$=yHQsZRW?HOcvZ;LB?B?bF*T zfmJZ+|0jx`fuax%lT6--zo2x*9si`h_E~Ftaqmyr?aBVSz3e#5dDR=NP8<0pufM?( zGx(!Badg2CZ?G;JJMa*T1k?(H7D7%kj?Md)U;I(M_jA_OU4#5J8I)fWe>2`#H?>c(s>Dy!yht4;lOz#3ouXTB}N-PW%hUw}QW|A)AT z4YFUpx-xL#xLcP38}si9e!4mTj^L*QS|9vO=KOC2Kf&#A#?cag{V)EwG$9%jdP6!N ziajXU>N7W5t-&A=r|{5D^~)QrE;B0C^?7TodS-i1pM53lw0E~ovf(_@|M|vusjuDB z^9ep&I2M!+51Thz#~e2B6L!AY-@@d{Rx6e5t z`f~mqb53Wy_e?KKy|3=_UgOmT2v~`+XRCqD*7)Sj5ARe&VC zxRSq_h6=y0{zmlsIX=&I>pCi|$TQIpRuN$${;@~5xc|XI>Zz;TH(09o#NHY)mI+Oj_oqu3dL)Lc^zq4 z%ruD|{r8rsCmzfq-+}tdC)~qv`H8+1u6EDYXL4WngDhLybhVsgH~$COh0%bSoHZun<;{yy2fR~;O15CG@bDh5U`7@)oWHk!VkVEK9p^5(4EWK z2{rAZELv69Ka_nvE>Av`Wj%XVyS&W#QTFhZ6m3$Q*SII+(Y!~p%=WqWN7=VTcitLE z;^Di;9*)0z=OY3u9JSh|?tLWNW&&Z>GyJDbZL0R9vilyv1jClB<9{YDko%#rKlL6X z_Gidr6Z_-rw5<%?tVUNgcL)46L*J!sX22kb`i_{ykO+wQhI@MP(q-4EiK2)&%yUpqT#QkW%mfTl7;X7~xHN5$_fkujQ=cC(P)J7gcdc6~!q2=cO8L z8;1<|42ft!m8@r4=!+lRqu!u^Ed>t8se(M7g{Ee-&Ys|BO1kMWHV3*Dd_$W-yeqgv zYS-d4-5Zz$pkl)y$^SsZDd$1H3i=wY)Z6a4+5Ld6F1^YiZxuZM#UOLGzyhaP+~y|ikeEqL8zpP za=*W|_VYG#W-gTIUh<4=7qdWA~Re2w_IpO1b`Kem28 zI<5Sc&GAj2kIo4X$Kt`;A`1&M9m$W8`2W2v0@@qmORtW`${*^9ql3|lRlRjTz3}=Y z|HSOQ^9F&?9WVGNFsX+RM*ojKcitYI9Dnjb*Sn8=1HJph2OSiCG~?g>Ms%F2B~J$9 z4}2r)Eq`fq{E=_ClI6*%>ZSfoavTCh>zfXrz46E2jQ&&TWh}m9+LMuZ$+x1h=pU{; z7`?}xIJbRUf@f)1!x#V>d)TA}wE_W<=99%Jx3Hpg2Yi%v-k zKlfNPTK?kZ_^Xe(?&mcFgG`(MO3$B(@BEjv>(hH#9w2}M!UVv^NPKv%1-~8G5*6t(L#a#b_$m}ZLx+{=*vo5 ztkkOmPxe=;?Q+~W;q3AFs@tN|=Ry&Hoe;12epDSPo7ky@6;5ybM|b%oZ#(@(WAWeJ z6)ieJ280A(58_D@P=5#}&=O2h-%*VjQ|&YE4cCED#+D2=h&8Q6Q)|qkse8|4J=6EX zZC@z;IxqL(YA?t4-^DCN4@b?)wR>-kPkb0FTwi{U5}n;0h@btJD@IT9^|?B>+ai(6 zSdXo*gbrn<(%oPbzwY7adG>zo@u)sPcn5;=l9n3$;=|Di9vx9-=8~aA8(X;EHa4qv z{1cd2M6XeO{PW+BUNAeXN1<3&x3V5`6s!HYgkpKxE49xjW`zumlwz%#Q!MJxxmkp1 z4ccr&(Z;I@sqm+#{HY){kKOKcH*q$b|q zb%0;B0Y=|AYQtdjr1+0+Pvz5T<$DZ=%i@dvsk4Y0y9*7-e482Zs=HjdCrb4-#x6_l z?jWz~@h9$%dhPkXyQ7ycDL68X$7q{3ZIh^_fz^qRQ_DWO%x1g`CvA3nbJj7>NP z6ywVu@KL8$({W^`%~?%fF3h;DL;WgeTfiA$6LXB&6mPgQHQzc?xsmC8^Bdg3`BnR( z(I`=$-)U5u|No}4K`M|t@EKgk)KXiZe>tXJns%2Z|I;m2evRW8V&HuzI#T5BbXmvFT9lMBAN*{7v>AybM1a z@ig`Ft5#Lm=KUp}Q*wby*fm^NS?>j}qk!@k>x2F)mjK_ns>H(E<8lbWDYF~1q4p_r zSi}7jtZ?~odzz#2--woo2$JRE(93Ah>~0$*XAj7Q(1>W31s$kh&!{9*w?afic|ebF zU04^`(?oCnv9`Rd*6W)+@im``7Mmpc_-CSe8!LKK$?y5aNT6y1@zr|r=6gy?eoicr&C2R&gGz*F2OHXwrC1alJjywvM)$C=@qm6$C9bn-#5CfZk5#1h!G zV6RHrm6lC(ky=~%F6hCHEvrBb0&O!#m}Zm4VO!!nO} zBZ$Q27eC#=d9T)(1HD*MfVpPT*GoQ)P9QLC&G%R3lFDyDk_;m`3fGFye|F=Ia-K&O zUSKz2Z@qrMeqYn@-Gwz><#Xq`yAVI{;P{f}3g!^juYFYV)4qBZUw6^Xe&x|kUf=eS zKB4dOmm`>J$%BK4C3~Pod$aauz49o9pwpE{S*u)mls4OyH9O-aJc`Ln+Uv?-Tpb=T z`7A7J!(B(e^2i$U`t!Q-=%&s8XJ2`gA)^zPm`7cCG`m)z%Vgc zAtEpS30%k&!0<>9!t3U~kZC$F&*X(n)7zf&Mx)s-WU}G>G%sXw0G{fFO!IqN7c!++ zL*4ha?%y0%IE&2n*7LB5zZ3uL*Sp^@!{?J5$KG+YOoob_xb7R>rprJNd1S4u2&Sz+VXnr%r#n{$q?dM{g%es@<#{`+4!6@1=xijt#4;j^n%wt zXG6UHWA&x+^WMDnq6J$Y;N{x46+=)O_>WBSgjf9Elqr6qL#Fuo+)i|>8QVrmkgo{p zvnrYGcB0SNLpHmiW_juDKI434*8P4vk=1m=9ZDq-=oz@3$bl^h%-MjY{~;Dlf~{sC zz;v_UPLwo=8Bc>U=56%6)8Td^ulygk6DhPiAsB8aO3?Bjw-X_nOOOud?2X{F+lYuX zr6~Jtr{&g_r`=AJ5aTi4PLxpWthW;-?M^51=+qJ$kpP_CPL#AY`|U(wwv$(ih{ zM6-d>ss9eQ6D6-FHw(>vJJIx-9}e-mGjAtKYR(+RjN6G$o$u{LPy2oj1In#<55#0O zmEOqspCh5{B1!+p z{T$Ei{T!zcd~!vX4rx!cyOT3eQ==Q3<&_r0rfm*cw6%wKVf@y7O7 zQ%C(d2Xgym@u8JHr^J8u{NuR*c3nj|^;ClsOdJLA@6j8Gp5;*+L+eJ$bO9^}VPF#-9<;A&wpL%_KWKLW zZ9U)GTBz;A(fGpaR*c8*cy`aove8DBZJLFxO|R0~V~$}fXi%pvo1<}bV$VtKg*s+l zQRaloWfp*oLxcJVR?GXa(XLI^9dgaF+AW3|H>qu`z{8Q`&us=_42V60L*3*MeoUwC z5Y22i?&-FaVw^%%a0$D6rSPYUblJ(z@}t73fd+MdyIp9Gy>wd%+P zJ-TB}&$HU}Z?1ivCN)I!cX9*Ekz^+&0hE`7UQNZeuiwfHf8N3NdAGSQlSNzu7!>@> z1Y0saty>i9zyNjC19L)z@lB#Y&MEEWNTD~AYee_= z`qXC4?tp@rkqHhIW?Q@UVM~0oLu9qfD{xlqOQf@mIn-hEwfE4DQvx|Fxvp%u5d?TMNe(&yYl^YY#>$n^+OaGR!_9Lq&~i}zSJT* z)ig(4mu5}pn#5+RdP^JX%j!$BCPiq135uXXeJQ)~0yCYU{PY_BH9Oj1PiJR$|GLVN zKxpZk;H&nfFfA!=YqyCBa-6GE_eozO(>x!gQ(e0~VV!y#o;gy>c!oJ*M>o$i;-X$8 zSw`;vI%qS+T~@Z;%Z~T5+pKJ>m({)O7AxEAWeqDsbe5l}HJj^7A0LXpa$3*Q z_6n7kS_n#O-I5wxn`Ww5O9~yS+xw+DZz`7@LqK%|0ck&f$ZV8bk9Frq`KXnlm^AV* z%7?7%K`&deZoQ%7>sEN57lu*ZYh`zPSs3MAR(89Wg;CySWuNx4Y?L>3Ym~S2KlM@e z47fB4hag)!A4IsfCR>N~nVcG{Gn+@(Ms-&&PhA`R0xaX$);`#=k!7GqomCFA7Pp?= zbK-X|Xhw7LpCw6G;nMONq2VK1*3hTwG7N+#GRJQf`ZN8 zNDFEk+N!cOD3U%LboWmIxE0(Bn8JnIU35; z=!S`vwlu=;l^gT-7DZhi>B#QXaD363weI-iXZM`YGtxgaI8Y&7+3!AQEZ*HcUX5Sy zD?Qa$pp@acGAk5|Nb_aAFB)WcoMkJ9^M-VX2R2+oVSNOF>g1!6VR(Me!9h+0C~;C( z{EHvyS>9%=O$!@@tjpt(|(IThTM75MbtmK8Vw+@gZEzvD#m@vMrI(TB1EntXrq z%Lbew<#}t%ufcXDPW;uNfnVzx#SEkj`p#&Yhs)MU(J$C8k)hj6XfVlcOK*NsE2bDC zmD>)HRwt^KuM^o)u^dmddj8@>09hm7i&s;u*R4Wm0IGJ63ADj@ajWMY?HpnBOVj$U zRRWK?Y$!-EZH(ZB4vqEttJ?BOUQNi&wl@T>998xzvwBt{{oA(X#Y52hkwdp8Q|Q?L zWLDtw^VzJxr|^!fz$f{htiZ|O{;a?WVZi_{g`!--VP!#z2 ztl~;tJsR1k#P!({Ynb)CoHAj$qW&zamX7d~V!_%=1g-74Rg%RzZRMuTD1aRdESN*r z#i###51E()J0=rZ@mZV(BMaYz0R)IZeDIshr{u)ZLB#U3sDXshA@+pP+ux#BP08~mEIv9CgQ~e&om3b%qx&yP3c-{{aYG(>p9c3dXMR+1J}jZ{Q5bg&q`K=cZ(d772)Aa z$`kG0)DOHMzWHxgpA=7heqvSpo?q)3XfK{vQ7SD#$f4R9bZ|43bd+L8rB0$<{l^7E z+w_AhJ6rTg3e!#bheyhTcp6AI2i%qkCG*TxTZgPrgUBL=ux6B~mAr(BB(>~kO5v|_ zs#^{-0v+4!5iM=fFL6;-3A;Cqu+rgxGu(R(gju@msje_CZMQ&(rnTX>95Lr zhoaVZrCZ3)vsKL{=us-d14>ZOR(8(eWKhdBTftyq2IX?9wvO0H@ZI9%t*C&Zsp|?g zlQJ%3Dw78BP%p>U1q`oF)T=2PxmZI*yZb{~{JK~747PVrGp({MytW05riGiNrHsDF zzF5I(0H|ia96n_D#-DBo9pbciPn`^^%W(eafRRvhV8H$Jpv}JHM;8!BaC*t54w&8T zR&Rrqa)YGFWbEs0jPbq4sJE|)8;_<#94Fw71GpLY-A2j+ACaASD@L_Ox#&<-b^wz-Zl zSx7G}pR2bf$ZW?)O$SM;+PYg<+hu-JJ!>qqo=M}U3EHu=45MB95Ai?xU!92zP#%{%07 zLo8VSmB}(B$;(>?ngbi_{oeE@lKGK?G;4axfHM72ZSz2L)EnGDT1F$>3}}*~_LKRO z3)ZBI$a!C)j(MT;Ue2W|U*aC*e0fLr6TTG@YA>`YhdHzx4IU>@%uC?Y@qBXx;&DWa zRa^2Dc=;JtZhpUNOU?o>UTwwZ`m371z>8N}aoy#UTn1je+=|TsSZ(1o@X|3WmDiF2 z90y+79<<^UteDNK@_hr%mFr5U)JrTT>%k>@M(PqJ=q9*CS8k|V$F}?IE>Y}U^NR8= z?q_SVRHrcozi^ds2?TRdpw^LmYy>&4Zyi~|%C#S!FICQ^7WitG@buRnvUN#+e9hfG zqiskbk96D2GXjA-NBzy(-}sW#FweDew!H24#ieLq(?HW!t)tdSp*c&dXM{&{3p+G- zL5KFX^?G{?r?scP;1_X#BSBWpISQ9JKQzaH8y7U7q!}l!*E!Xo1o_{JS;N0MYiZ3 z&Pz)0sByOCCn-de974*PmO$wol*C2Q@E1Yay7~bry3Z;KmJ)=mJ@mX>LzNbpLDbZP z<;J*%$|=r6W#6QA?V!BWelD6?PYi=VJ~xdtILK9P-3U0ko(MTLPQ9>*aB@Z?_Dfcv zr0H0ju}6lRE7nyGh`U$3&vPj|pd36)`k?=VT=zrc$Z}FFZD`$ZCIA)5jzF8#wJjoR z@xTD>@l7a@MUbGttN}-XG+Z79N-WKjFn)g7s00(=4sfXq9|x;VgfL$=jWmNylXbv2 z6EIaLfznbMa zZZ)1XMb`BO%8sz*=usk8Mi7e6LEZq{i|GZLn2Xe$IE!kC@<2n|AcPm{bc9)YTll5= zJ5`z#?oc5ZHSLg%SIAMvA(qr9HPieycZv2dYvt`0z<6Q-NMSg@QTq)A)htV(+Pa!8 zvYggL5kmsQ@czQc4%04V1mY+S-|q$%mSNg%mTQB8_0$mD|lTBw%Vfmv{QM| zZG_G|`Cg}Nm(s44N=X`an+iJiK-C>{K3Y4|!3t5^&DIou^D_rg8{uM86s8Xkx)fjz z=Tfj4JL|h)+g=3n+5vO)S6f>Euauc5Tl+QcZT*~8MOdj9*&c~$uYCgNB+YtgQt-7C z(wYufXSjB-e^DG5GxkDms0#$@JXnOd1qn(r)xIpq15*H};GJr-MXBc?o7)XiW9x_+ zJXCnBAGqfn(2+17B49^AYV&|1m^f$iY)hI2Tiz_b&gmA9wSpvD3pUl{WBp`gA$PIN z;}m+kTZjv`H3@ms=jwj9Pj^~R%9?M$lgC(JG8SUikI;I(En(_hXJ&8_xsFcE*K`fV zHx#nFp%5!v2c+p_rjr^H@2zbZ0mYW^KW-X?%2?AK6oJwI0e!ZKR@f5GA*HQ?93B-~ zRb6LW>6pBn@yX89`cid{i1L-o+KBlzbk6EeYKs#T&k9DP`5w3VSz8>alzkfYcp#opEYT^mmfrUs_BIj=^HT9bd=8quG>*H!J5eUL)+8^}5 zOtu~Akdv+!r)}LuV2Ob27YCnl2SW0i zJP~_+g>P0e1G$L{Fa@pv&5VUGlwLM>hsk0&rm5dyFTP}Gl<)8p3A+x zj{bFJ`ITByCT*9YHV|=AsdZnvnA)yf$EXao0|RO;6Arr2$`)GLtX9aqP4Ci%Nh9TR zCAN=bvyKEW&U!ZK1k32rG%J28n{^aWan@-)w+vFwhEnC+`rHcxKj8!`iHPnd!XS28#?ku2^9w z6{h;>#|%Y2Z!A8)p69h`wBL`M?DBU|np%+o(~ z+shkh36ZZYZAw9B*>LT0L?ir!H4-+d<+vn_4DVlBb*f1JjvB9^eMX-XNxFoG^gSno zL<&@r6D+GU3nc{mo$J6}%0Ufdef~0wz_0m=52GZjXtwZ^Yh&^6hvRL-&Sp1K_~-naLpSU z2{$fF)skrZaxbU2pf@i|iwh2+ADV5h0TeG1e_^Y$OT zhS4Ikf&EvSD-hmn!!T<;qn&cIV!eYutFw|uE>VDfHVsWKQQ1j-zUN9@(o0Tjw1%&&x>^@ShZ;0N?e59;!2l}8#`?H7ib>d=hW65<-ObFW?q&u&d2@5Yyb|=jlIAXT zJbflg+Q%-;WS({wW{K2>k6g`nl4S(NSkg;sWcxH!V(C zU()8Pc3R$<^{(n~y?$A2SoVI@S#>sqUyuBm5HKXl3`7mKQ)16$jLE8(+q^6Ptt6?*SBV;b#1r|Fk|zcx8!EmwAaVyj%B>Kn zd3y?tY`uN{i|RdfRm{?2DF&1YVcVzll9$6W$#u#F&+~ohqD21I1OAJ~P({VY2)r)U z_ShakyzPxk#@fYeY8Xs+0ZE&?=SC9iIA7uzk`9_B=Qz?T-j+CqqvVNjlswV6+U5JI zP5~Xqb!`fb0^xT0FUF-sN&!jUJG-GTeBE0WI{Alu?K~r zUBgXK(MjUPzE!KUEM|k-oqL&`$Ou?HYxHd7_BFZt zPQ=2t?gsOfO2Ba$B*%(u*BVQf2Qs0a;CAR_FPlr(^^}LrS%O> zsgdo)(#Z`?HeKbmrCrYKNV3uJnhj0u!3vJsONB1a;wr}QmI!~71$h16pAJ`wChU>C7`UUzO+yTz9#C+3Ps>* zNqu>t2qZ17FG`ApoJmC(0F2x2BKkZ+L_%)Shy4N#RlF8KK}ZB`HoLP`i?W=v)pwV9 zetqHqBs};8mt4XNPuQy8v8*9m)0@o?=$K9mx2A=JUnDiRTj7>IN`5uGe6q;`_smgZ1I#3&&Dfd@(YpWUc3b)ygG$P!lyj7oJGX`&m?y<2m{=^G2 z)2XAxc}RpV&eK`{YU^5K#^!NerkgMm25lbiWxC7CxziUwbuXUOt)1b4+d&O~aMp&O z3B{{z!PHFar#6gRLMPY*#s~+qqYV$c2@~)A^uW)x!*;Ye(EITfNk@;%hhmaW`4n5j zB2%4876DVy(Zmm})qVR+nJP=Q{~@)*7n*TDjslxmqYn&}gO`SFO7)SLI0NN2X)E1M zMqgcTPvN_l=$c%Cj-q3M@%51!7h)J2C+rAt0;5LCQqc`MLJSmZG&8F zGyxsJL+lefvk^+NHX7s?OoY`Z29lZGfq_ab5w6J;a8hcCuubULFA=^8CHp1LFsWs~ zwnoHGVpF6PUuucTOo&>A4t!{Y?R;8lb>a_;5SxW$8HX`D=DH*a7Y&*y>BJ!!1C`Hp zX_Za}f@y{m4h=BB8A~*%&l)%GMW)(2Opax?%_cPL)h-QcE8QA1TI*<~WQ~b-vc}{>%{6AJl%;F2JJ`F(+)+kv6e0_9?pT>3 zZQCGnBZM&5+*6YU^(Ys>)yW7MNQ@BaO%$L^8fkdX{bB+rr%|WbAc=XRLFKKGV9?+o zDwrWE#tzXutBuH1dhY9Dm<+6C7>7!`q~h4sbBiyF@+tTVH# z(9go(bZf+XTI`S9DofT8%wKaj<_%w|TJ6|b0~rC&uwAC+yHO18(2+7)EXNPrqSn>T zmt;K>@PNy^Cum90X9kT~J%{W@k5!CqUHPz@c?<#R=B8WI$Vu##v@lJ2)YIB*UG2(M z+iE4db0x3XZbf@?MORx1yFfy(wSKLY?8}v0ZzVE?@^;BouuIU{8R|NiCE9Yy*(FYY zIqJfD{&Wlz?w1dSiN)IOF+)_SEgB}yiQuwmo9wdc&a#PZvNLU>V4Lhniwl;?x!cn6 zf@#7ETZ9E5oedKf8q+Nk>Z7TX-8p`N+BF5k;8$k13nuesfxYEc0d3g2)r^8rE)kfN z%a&=CO*5x-YGhgpWGdq!BU2PU)SwIK{Sct&$1YSi4KDi1DSUoq+Fb-{Lc(=DG;C7D zem&OaXKFWy!vhCkZSa~efimJdiqdEK03%_rxz_h|TV@t3E4-wdse32Pvg!MF;@?3z zcG`7gCQI{~iA3KgvtinP2G)bF59LxZB-_YT{pvY1{bMN@eZ0omIoXY9dbWI#45_9s z4fdI$UpVfS1e zJ<@zeICwh?HAl{~!H^5PA|Bi$&2e8IJ<{C5!2w0Cj>+;Ao7HKgxlD~hr1_NHDNnV- z?cO;;&67y;sa{0QPbSj5O{jU-Y@z0|e}2M|<^)nm(G_+Vo|~vY_XYe!BhAm&T6MNi z^M9X6^FwlI<2iULk>(Z$peT?Ik?Wlz&Ec1RXbGt=In9RC{I@ZZ0QSO~Ha`2m_AFaw z?R1VNQMCGT)8p~~y`AgqR?gG8E{e~b>(cglZDw9^d@Zg1mkr^Dsh2KkJ=A;gP!Cs+ zlg5f`_&A`@=+{>To>=H)qaVDqd&2Pqp?rf-UN~(qq}k{rjZ|R+&~nJY9fcS`jASzo zeXS~!q!dgNSv@&hS&N?}u&A!xdiPnT0ZfT&IB!jxn-80g%4ns$n-9->aPxUspS8zI zDj&)uGdbyzykBX`m#K$tWw$&z!Zs(Ko*J4~o46>T$ugSx5Vh;^pWSj}_09BhHX$`Z z&10z5NmiC%NT`diKVM)~2KEb||U?o2Pyy{8H`Y;jy z;x#=3JqrgH4An-4;|s6psfz_UG+u7qhs&`Gnk=_=VK_%wuBii2$oat0awF5uIUh!K zp4eW+psRW2MfS#bMI2<~b9bclT>5r>q%#$yg_6g-rQ{IJE*9wW&$E%Q_#)j8#hG;_ z%Ht5c^6=5FY+3yImLZSD208q3lImvFL1isaqC92y;1wK4ThmCpirhQobyMciT@f)- zs+2u1pR1HBv|jrc9kPVo{FenmvhyzgYZsbuA)1hMAsAhK!2wXVXxXXn-nyyOIy-lu zRdwuH?aOv-Gv6LN(;I5v-%Lk}YNRi`DDm6>zGu-Yjc+m|Kj_iNJUzqSuK4B;^o&Nk z;)Z{W{C&>}?F9qnCUP6SKkMTi7G7hilKx=qXsYj{uJwlBoL}D zI2_Zhlk@QEP%~ZqQ`QwsO2I#81rG1mvVxNx;BRLo4)6D}0+vdp(@Q^?ir;npOn8TZ z*A`)(xFW%^&5&o(Nb|D6E5%eALuKiJP?f!i+d=pqB7 zKQ2y}bRmV=eSA%GK0YOa)I{ebrs6!Dj4j=zFOuQIH3VHHC@F{;&oF}XI7p9-pT z03Jfj6#;aF`}`jpd}GY?oWg0|2nWCfnY}I;gvf-+JaWf?_K7 zsKwS0ud`b}E46P* zu%(UCOuX}>J!5B3A>E2j*jOY?QoogMiC+B+l|eFhq}J%(QCXwUi+7$^?TOcXtf$%@ zUbvuC8_~8mJ*KhSgNxOU9OO|ksRg&FB74lzo0O+gYK1UUvl);`9th->u&R|mDJjEo zY)LJU3r0J?_SQri|PY#KxFAY-xO0s73A?i*}#^aXqNoYKBp zozxfjxN=D-tUYfkN#m-VjQfY0;Sd7@#fLhW^VNZTd6jbBGZGCGzhX7BdVqwITHoZv zFrTj!M1E&&HJn=1(*}gZ=LJwHXu#Um5d)SYI$dL}X6;d^18vrOzHjTr9Czy>AFXmL zK6D+Rj<}0}vtXOxi?b{=)qEuU zH$Y0dJjD98U7&^f zsTN!2;D0pSHCP!Ow1fZ9$l)lw(3*5I!gj% zPIAJ-ILO!zqdFA~J~{k_y{7R*nhV_NU2Iu6(BZ7%lbass@C{TG7&OY88BNnE`1G|B z*Z}+DQyZFSL~t#Ed<<{-&uG^qn+sGZ1o(dxoklc=bD$GufxfIDx zjtLRT91luzw5~|$wZJ-;r^N-~x|(l*H;9rA~!d zT{$3-vT{K5`Bh5E6Wtb&J~7)3nlRmw?PyU&+=(NiAZo6da!9e1V0 z1$5|$h!aEs9XcV>_VNPT>xhUK7to<2B3@iThmMGNac6YAm*~G4Y@gyo^5+;;X21v3 z){Q3flOK5+bC(Ot$N<(f?vPRG@Jb1^Gx9CB4jOy#W=86w<4+0iq%1S*Mwq3Bn2g)vz6??h1X5?ur4!3N*ogTAK>ul zeWi-VyRu`P3c^)iav*1H>Sr#q-++M>%ZpWu5>1VS?d54=HAvM|vPRh{2$B_>iJ(&u z$UkAnhDS(1_DC$BJfYkS46|kWJdQRI-}FOGu3o|B5Hu30yZsl{`%u~W8`RBTLtE7V zEp4#}WHK%@R&Go+29e#Z-TsTldZssq#P177Mf%kJH28`KM-Xj(f+f*JpB}Im+SY1f zD+yl-&UWOE*B~$LZO56Y43t$Adz(EG%91CBva1JteiTeO!z6n!Ky#MM?1TQ3AylUi zQ;PtT>B{Mx5psNU`HaQ!r*B$ZBk2d~tfuUdIvg_OOC=?DH{CYvaEP&- z-PnYMJeOM7RUG%4Ob^-)#HM}N2%v0rNMm8Pg#JE)wq-){4ejoxv~~>=Q(C!qG0tt7 zpXk5=g={O;NgA>(y0q1T4I^wZm_$%iHFu~fs+zry8np<}aeSrL1WA7|NZ1ww*o_2_}z>1g}kc=)|>$Q)tYP z@?XqJ?{o_6Rrjgc;OHsaT(wp)86oM2jjB(s^e_MGt?uK~l&Ro>tiYXq|B@BBZ|sq* zz@2{omK99W#;K)CzfYqgrZTuLUoDVUkw=ivw!ZAt44MJ#fWnDk3n)?FM&n6(jc17T zjPlyYKzfjYofpUvpS-T~CJl+=lq^g=?dr8d|5_iVlV6c@sUyWmX4#|#C8qWu5}Uh@ zaw;Pd-CMz)Y>>2F8IkzS@vbaEJGM5HoQi_X+cO1urrw@I5%s*aqquuSX_iBKHkVJ^ z7MjQ4^AU2ML6;9EoJ{U{`h2F?&lT1WnTRzlOPXF!RYma>8?}HZg=-eUJlsB*us-uS zQ%WsNMdtVc?dHBHdVVUlrTUCGe%epX^Ye^3ei;8#@%*@4fVS}XSX@Z`DLQ_1=(*^h z5$;{I+eFUh`|0fZIh43^j0R>pe`XjmZMS58YKDx-ABhkxKIb-Mu;Dx!r-J(J6V~%i zG0zpM5zq9Ab@Z|!@>$Hnf3mw$i31dO*&0^{tce(l#_Me%~~r zrrf%N@Oz7>@imOr#6@XF+xV>yA`4SVcA%XJFgIp!?8{k=Ar>TDPovMIm}#8>3^gl| zBM_C;osbCuw&r-MJa9tTA3qoTy{v0P|(I>Ds6-J7E~5yl~eL z!>HYuLy)wpA*jm`MC_?yD)FWSgs`9Bbinv`1O^N>GdnXe42TW#D^du+DyAoa4F)s^ zu!XjNs*Kdw!uO@{6{mDjw1}~5Q;S$it_!X6|J6ly3f|O`EE3B)(>g{ z@RBEu#R+RBpLJMt|4`UMf~1B?VnnR2kS!ZvX2Z@2`9@j!K$TWMS#pJ65BLI%U!rEO zk-Ha(5^>(0LTKyO^m3k7+s5dxP{GY!TO5UUgr{6Pt+OE)cdH|i;3b*pJJhQ7TEx>T z*qIf;iWKb13fyMj9SYjK<3{_Qtcr~GRi(XI!5S;rmld2v0S;9a$gIaxuolk%gFKtV z9^rGU>Q;S%k#u;n_O)+A^?hxI=MiI$GW#w84!$hGE0Vac^`L*9;Ol`QS+VRXGMRS| zHI~?P+-HT@W__*0R<&tXK@|i!6(*r))=BHHwLWQ`qfKDZpRGMYJyAlK1mZ1AWRz!B zWQptgQl)`wr_|^&O0XrW*l|N+8DXvZT<%@6Y9`NYUu!cPpvRfEVEk4k;g6m=DG}QE zcA6%vnuOq+KQ~XVc-6b54EoIbd|b+VWL_{KLL!lF1P{1)qRM_MpGT?~(|kTwmCcAT zQ*D4u`E44k4UMP-ZvsSnNGaq)&(H#fZMi;>_zuc-4MFbfgy~@bwYI4uxkqnhhYqce zBz8mC9!pj6$De`5_no|MCl9*&)jV(kwi-+KmXIyf`fXso2BT5~b7Tbir z_4P#9{IBX?U_ zby&xasnprCToI{#XJ*xX+Tr|2);xh?`kYH9?B*l(QEby318yh0l;jRY7dF(%n2hG?zHK4 z*50cXBj>no(kJ1jd-RD)n#OsaF_S6$MM16MY!-BB_ScO z5C7O`izbkgkXb_1wn2r8-&E21oF>IaGFWq{CPx&E)72L4yaD`Cx0?CkLc%lxbe(BV z2$4+Y<)Ar}A!$PWx>*`DqTfGcwu{LIC(}}W$o7r{*+G*|bew^gdQT?Mj-w2b<0?;e zjKD5FSgO(nj=fo0$~Uw`3BM*S(%bcgzIWyOree8$NvkVMJ)w?el>p~rmk4xc zL)bZzIBztBtNquE{_?70YB)av4wDAwPZ&Wc&;>>|gvX{qmK(xNg}(Pp>pMH-=#bhm z%HSKFEU$J^CLxxzmPiUdu$H|kyi-!o!AffX!zSdo>C60t*s!92M z7y3^t88*$_J}+rderlmLsYhA{Taqa)p-Px)lo1h8$~l+I zYcU&H@`4FR1k;ot0_;cOj$b<6JGx<|ho#-MFsc@>#T<-lzw)APROy>Hv{(hTqL(cj z9*oMBuF^oYyQjCm&xknO$LCY$cU-b&2)FW?NVEVO$ek5DgEQw#p|jyHbvrazLPS@XBiy+Yd(7dpF^ke!?2b_-zJ zB3fS!44=kgTu9c@+Yt91Sd;NYcCh&nujU@#DXgfkR-;xd~O1Wwo?4+ zxu*k2|J;BS(8G_x3|H-ZT(`l9ZGWpYDlq;`5m%8G7!Q3L^k~^)F-;Uanicr6<%d~; zFIz4XM*S6EwOpPR=+HKeT#=RdvgN9*V6D}-CMihq^fMOD*y5w(~{E3njxbFBd zUr{rveO-$`ObHm~n_(T8T=pi?7fE{^5pwnfhR%h;gR<-@Ly`Bp|3&1pFEt})QnzjH zB=2b{<9zWqLR;%IbG&FFxZE4~GjxT~I9jAc(duuM6gBj41dSZ6)8SqiSckE`+-!dEYw*=_F zX48{JvEfS5qmJNn=cKilfq%vZ4tGU_j7iqXvJ>=m{qm)y7B#x2RJ0S)PMFS9NUths zVdJmag~LQa>o}I!&MyR&AM7kvmVRq_GEq5qQc8TenGIr4hOx~oo3EN#Z@Al;dD^r_ zXc-)Nh`lpy_SOULG0bas{GB5`f8J)Bc8wfQ)8;r_t7!4WDUwW6cDTnCsjA9$Z`W1KAiKH`9nOYB0%g~t7Z^;&)8;^wHfHJW4b%a0#D?Tl`mza)wK z!}ql+Z>ows=`i&CP-TVYV-Mg zpGYs_Y)dbCm$ji%E4hnv-@~Y?)WdAaD#q|D1VnG*n5((nxNPZ&(u?^JjsQpQVlUy} z=Ahczj~m!(g-gDG4IfB%V^qoh_$mN#0uLy2HeWXNG;5wen*bv=3u@W0_j{rWg726l zs@_iI332FDNfU_xj07&P*|mrP5Bs=)9kT~PsYq`> z14uAp*mjHnejX!r-Sx?nfCaEgF5KG(K!agHjo}n22P}Y&fCZ&SDPZAHIZQqml1(4} zK5(tErxb7y*T`PDL5+h2it3PV-`9bgOuY zuPly?5`3oj>UL)NuVCqPi;9lBLL?jun z%vQsuII*A-S%8E|NWS=3H?Qa9N9C`_*R22tU66|>+nlj-`xXj({w#P_c84RSANRnQp{5?kbwRUUMA8+tG zeQ!J}3z+UD+u31l4#Mxe~1Ro;So!J+68To(+u!cul+IzPFUg zXb%=}N@;yJS0^uQwWWut&?+@*rg*h~j#jnYv)#0SscxA%TS8B__CT{N37kChE}MhD z$dpxELda0iz9R`{m2y%z%HFFg;j5%MK0pqz>5G%&A)6*gtI&B^Q{iLX)Z=1tiTefz zNMnVCJc6e7x#U;{AutaKmJYn z9Kyh{-x}&ABzs(2-rE~AY&WRpwhH3|SVh9$-sxXeLMra*S2LgkgJoUmliaIgj_`hY zmquE?C8tp)=x2EP+U7Pop{-Tn#9ymzv&BRRBX)BfkQFA1yFUf zKYDZj9EeqW~ZIS+u18Sb{lG=(>6|Elht&jgxS4L(fKainiu zMft#Jthc@Zif=BEpBy7Oy?Ye>J%f>GDhzK{M&jZJ!N+B5%Uw5g@xY z%eBYCCRxqI0Tw$0NU6U&qyBE-PN=^-&^_!3GpfE6J*Qs`)bxvy9dx!9q3_Yv2D7mP#@<44?UQoTdjSVY5wME zunkA^UcEfEmMyu+gZ+``6UR+VjI{oiLj+yT3^B6psYu z8mzO9#hE^szg5_fx2`TGZrSo*TeGBDK`@V!5`h6T*un5xv(Ud}w zYODZ_%0#ZOlUBpv{N`qPh@lQsXy8=~dn2N{ZI7_$q1wq#vGK&AZkY~FJ}slK!&vUi zxL#g@k^vIXRn?3U&}F}Ogx}lk_e)yQCAu-5P$NBUmn}=M69ICycCYI;C*s?~k|7=J z$NCjjVL4)nsxZohEE8KsyFt3hcc1Bq#&LZ82VOXyu^z{|1d3-}GtwGlWjxf{ZX0xM z7bZiktwVmYeIIfN_S&IXI&o{GE{^NfiZAGTZkot+_K4Ik1TB@?I$-^#0OUp0K19_4 z;zmsSB}N=NoXt)!oUT(Wnk#uM8&8PIY&_V`%Yu!kPNgqWOAH$57G36fEM?3i#)f~c zyT2vgG*?q?_+RS%us$g`l*t1|<3^y*#T2qyC_L1M@S@*CeOj`3D57LZUs$rxlITh3 zLxZ9M6%yF(p@?iZhXEvtjbI0-C7lBU9)U4pOs`I8ANfO^^-y1WMB+2wpn5p}CUM z$y^h(KuYXqQM#sBN>=O>DLpGKt=FvMEyhO&26U4hYrwk){O&us7c>?Y95Ds(Q0fi{UlvC#-7c-(+wn)K?a& zF|w8QXBCPV*0bs-CPlK6%q$V%IDN`)OH%DmWgsw-Bi+wWQtXGMGZ*G0OkElhx04E5tz`Blf=Ou9pd zxzL^J?%ZB;cfGN;+`hYgu!$X);$P?&)TQc&316V{L5#g=G5R3u zKxRzdS1=}%xlGlI=0K`NJ5-QGnCkSg(^b$tZh+|x`NX68U>piG zA@E$HEGg18=%o>wO%zJOCB|!A=%3UpmN{Uz6b!hd=^&B&3>^fd(k6TRU7X*fPkw7P zXqc!an#FEd+}rP}WlzZBFHx6MEqhrr8u!x7F{l<{O`-@?;!gybreRbnr5fyAvwvK( z=Xu+Q#G50<6$d=W0?Y|y8x*8z+%n(_QSu=N^)~YsOWVjinJjOWz3+Ol1u9@lIJey1 zLl#Q(qqz7;x9*$@I#R0713-*xj>gQ!K-&gvh|tN9Rs%z}$OuU~Q|sPNhbLMRAFwT_ zz>10S^76WU-RarYfB-}xPE%0eJ3qf|KE)g&oysrk(F=(7@Ipzl$F3*`z*Uvq9Mt$B zlfie~sye9A7OC^flij{XQhjy{Y>slWs`SE3S()zzDjnSfeLA|y`gTx}IW`#Hv+a$9 zu$ZGf*{48zVd?~Kw@zv8m`3klM1-5N+Ma%$zdITqFsK3_Bu-c30U#C+2xMC0%wA%k zu|qFgOeBf*$``08b-l5ix5caY!K&15HfdscataGJryouHG~sU5`XX^+W29AT`x2Wcqo{t9x$fi(yJeE`5#rof5w;3V$;nbn z0)~+hG>4SYs$RZQHJ(>mi4ez;fX^*il}nrF_ds;#6>!+eD05OGH*i6+c(9HsL+K6cVqI4v(8*(Uy zIy}NI8R?514E2&#bDanM;fu%u{;D4DpvAVxOA9*pEGFf$%tE=Tgyo^_poFs?sP|wB zhP;Uf{TCR)^aB(R`$PWYVX_<3;5=+~o|wU|9Xsg?mBKi|xNnYSrIRYPg+OySDF{u~d zj!JC+RJ1#~wG*hvC00EL%km)c3nf)>YVVPYN=|J|N_m|4F15rrc7cLp+gE;QF&x`w zQw2wycg)j*k2>*DW&-L)7f@LBK|uYD{6J8J4v&ful~66`-rSwZr(}_oN?ZkygCv%O z2{B)LjIHm?TEABK%`Z08G&@WqFR3qmgI%7EftR5@uMcBP_jc-hz_Vgx+j% zMkC(z+}=i8QzNcRSHQt8))wNoYzr}=8>Tf^uT+oB1*7*97mV6T@GtDQcJ-LYI#B`F z5>;UcV5~t0w9RpEf`vgJK@}xY-^A?L+pYz)w#d{#@ku|0gi_s@U{5l<0q?$x!by^ivOK8aU%IN1IaA>|}Dm*|>X(7Qw;mj9T*M$%-`j>VimWseGu~4H~ z?-esjr;W-J-Z+7#ws4}m!KZitGOPp1D9dV`KaC|?Vw-=U7mt*?1Zr+Qj?grmZL1Uc z!jYGCt;}<-V{NgCg(71nnopQX{Dbk<z9d0;y7u z-GL~ycz49@(FPfr-Jq2Mh`h3)IjYH~X>$#Y&vXsh!M%lSLlva>(0MjRL(B?ORmbz- zH}sTP@|3rB*&4$vBSfYwE}JZUlM6RBz9@~S*7c4{n6@y%(ude!{)Xj~^B1tjyv&lx zc^P(@msut`FT+CfGRq=I8G}2aJ|sU7AGVz%B(pJIG7$nDlOLPKAF&1QZW^lBv=)&p zYf9|))|+}Gk8@(l3eL_#5@U_hsa#t zRQ$34y@gs=+UfTa)S;G z{V*%gfuYILWlC$Hv@@2fgp&=eGdLfl;}v|qrrrS$oZb?=A9BBO+F8shA9J1rlk><=t1;Z{pp7xJUCSVC6OMv8KWAsD&gwA5pUj5txcF>V;JCOW zD*zYb|9i3$$Ho0wfiv^BvH~&ls?v9pf)qJt`JD67an3nuCUBFOr4%{sIkA%>r*P10 zUdVZF2jpx`ptkit!`S}Fbo#$KtKyV$ZC2pOxjrj!0%2;7h4?pq+;jYkiEB4om9?-=*Kl&t#YH8% zbtXBu2%gP|)!E2`c@cl-mwVsVvSVljKqc43JfZnX4-*B977wTWusa$^Zui^P6<_$! z>ZQNa%pY8D{r(2-!YW6(W;cI7->ioiR38$I2V})SFx_Gv}is_ z3{2asCZ=FbttIVIy>hbZ(MwpZdmU~vQB}Lh#8dE8S?tH>w}(fyvI^~HZwU@tf1-UQC{ zs#d*BADvm(cI#|cU8$!sge0?_5~)%vO+|6^htFSr&Qt^dfgD5) zVf}?LA}g2rj*?YLnRA87s^p%Ys5gG-*Lu&4w#AKC_CBj!(PF|fHK6><&?$q;6DyO2 zQ%mlnaFSF5Eh``Mwy3V;;Kj=Bmh`{8sB3;&Ln;M(YfoYcOBkXA2Iv)8t!1!v0#l3koK2 zRDMVZ!g$S_&sjGAVLWo`Ig4JrldeUDrjQ&?zte!dXj} zs^1IGUJ{tx>ST1u$b@I(^IrFq(>_ii>zl8)M@{pY>-LPh!_V8p zULNj#9_{{Z@zsB_r`kroiHFx0AAZFi4%bVycW;hA@te`ozU@{L)vk{Z{$?~$etfop zK4kTJXtutgc1^L>@7c2|&sNTO_P9N(@N9C%vme+q4TP29hl*|f>ElAI`eRS?y3OYo z5c?PQQ1^VV-cbAR#TT!(XBy)BiVyzQ9%wes;%H!};jhIPiIXH=|F-B1o8ebQC->iK zuZ`5+vN>+OJvzSp&Ku%~-WEM8JRgfse0#K{oO`%py+3?s|H)(Vd)^+Mu9{zXJ1u?8 zS{lf=^wm)L=id>XRQ}@T__Pb7m8x$qf8ZU_3FUiM#W#PWZz5jvC-t$o_FLs?|A&S;`T=RW7KTWd^M)43=f5UeVPIbnjl~zeF&d8F z@mp!hv*Y`JE9zd9(KD84Le9(Lp^Kv>eIGucc10?uUmPu3^T8wfSt)e$(jjhjR01L- zvhH_e?%v6Xs}ff)EQ@b`b#z<;WdA1($X-LnZ$&2`1+L%9;9|9%z@-a%V6)F!Q+-VA zeH;UQf0*^~@P9d!Jmfl#-Ptq5oTNM08LS;paeU!#BSI4#{ts(&xG=c$h87+p4k7CV z)+L>AxauGOO*rf-bo0`o(U~}mFZgXIE1TgR23>#QweyBXjuE;XCMOKKpG{|2Tl3N& z#IH!N1SA&vd+AWfH8pdpCyG{I=xjxV3htHNxCXNPU3 zb#@N4e>i(KbEbFxw``{S-)hixGq(7eKbZr%vG~-eJQzRx+NgV&Afl*tSLk9<5$z|J z%fl;Bq*3irVG(Vx$SkH-x%SU`V{p8PojjMqMym5k7E~P*-^NHS0!dbqi{BXFyshG&mD{&*1u z_?|P0FaE$DR(;0)DtlHOb$s(iG(iwe{reme4fu}VJ?enZ%LpbXjTZWVKb69ba7>7T zXT|PCvS`fT@}rE^_0ssJU7v5#4`_ ziJYp2`imDw$M+@rY(YG9NiYL~J{>*oi(v+ljH0I-4MHgulyi0Fy^=<{2P?=7-M!pf1X;8tKn3lU0fnKM02Q8fFcc&1pf=L|GXuEa2jf~VeYVY>NzI#*$8RO1rLb?f;8&hiFMngdx{);uG z&cj}PZAV!#?67slYj~Iem&Y9si@^)jQuA5&dc$DeHV&vxh={tTS4|!y;Om30ipC zd3crL@V;wUmG3Z~2fzKahj-@Dhj%R8a`PV#jK$yE>WjyOTTboddw#+eDkhemrtkUt zGg~^k@A<3!DgX9g@z>{dzqDG4EWta3WuC#P_1-7satcmhDUz@df2o#n)8&VYD)PwZ zDg8axf{k%b0WcQb8@Dz_jg#txBSf{Yq>Lz2iA2gGyhf>fuDNtMQy*XYIjuVP5hsa+ zI{(U3#u}>?#zC}_?{8^Owo==Xw8NXF`1Nw;Q(gY|6Tf0%ACWP4ll}f)s%XcwZWruY zIjKY4SC6BAq-~1SVmShKw%gdWQ0UEp2)iC13Na-a}SThE7uN1y|+j+0tM2 z?zeiu*~NHDakM^KDqVc>IY^U>u85u+ruFQ>|7m2y`lj~Y&GEOd@ExdS+oR`@z$w1w zTlJ;!`tz#&wvQBl{-)~CaKs35PWnN-6T!`e*%06S8?~|cO>gtPoAb3LmXWn>iRJ2k z;8kfg+Zh|4Wcs@7td%&YneC`oH?}H-M%NWo-6b}n<*{cy{OudQ-ffpZs#v?{%E(6a z4gYlQpP?zf{M~F^Chil&$qWE9sxJaqjei0F8etUy)Lf_j9SH;tpp}z!d-D#Uq=D9M zn>f>o@(`s%EXS{XyW=(4R2)&>%4jf}`5?Y|=fr6IrgvrZ@Zt|yv)V1i_W5g*cjTC_ zn{n_Ndxj`vj};2c_O9==2aApKc@}@=W7TJ;g5&qDjQ+g;_8;B4$wmK_an4)CF(DuB z=hEl#^YaxJCKW!DRrvjUg#}54Te1o_<}1{a3VX8(Q~3(!Llw$DW))1itlp6W(p;&k z@R6*A*W@dZOvp!ZL)OBz`3h#ntA+Px6%OVrm^H5o@3jhM;V%EH91P})RfTt31#=9( zk_tgc1Z!Uvwx?aVkci^rx8(@TY=6~zo7J;L+x~n{gs1voF1HG0*eDj0rzEOq5hKw* zvkJEE`q_Migb7=lQc&W}`3fnK|C`Z`!O)q=AF~S9MQ1nY!&brOtg{>RP*x%D294i; zRrKus9L;oY{>vGXIyZlZRWK)Mq50--oc)~ggLv`(=kUo34q7F|7gh&b;)g#JFMHqc zbNaq6CMpg5{Xl&F`_>&FuQ~DAT=r)f?+Jt9f}8=_Pr4qbuYUktVZQBe>m4=J6{1x1 zl~9x<#>e`|9w{U&c?6vwwF%3AaI`k?ksb{U>k9#Lw0hIKdSwn?JsZr1qMP;#Lzyoa zto^>dIllB&qf0A9A;m;xG!`m$u3R}+D%tm2hvRF8%PUq`w4Z$SQIgFgi2^Efv~R)Z z$5*^47e;5J#MKx^$)26mR@AEg90si>1~#i)QUJOGFuxFhN&4g^LbDoCoi2$xD*J(% z$#P9s_h@ZtCw8n>8qjBubZC3o9Bs$v-!;BsV)}5{=(OQnasE|HqKD&aK0DEvvyte& zWykk~M&buPhMbtI%hvmD4>+gh-*Iurba=8pRI z4WI2^p{T%Qc8HZM4ZOb+*?n)ca)!x-bgDHSb4cn-Ry{P1Yww~;P zdh4w{lt@zLGD@hx0fEnIaAR7dD_6r>%|s6yTECiWwrh@;W`&U*6oXONBmQc*Yp8c< zDE`r3buB+7K`%qBZ)lX|^|OeyT>a(4UH!fN{iQ1}om{pwSAVtYqwSS>gZ51Twv*>J zsdii?xhJo~Eo)S=nBNei>p5NswTzHGzQSX1oFy!oAu{bChm1svLk8)!_@-6mTH!1% z;K`4cO;{%^QAuv;xhvVk%;)VsS+<72c)=g7Sp2IEWdo4VsuUE02PQw&LB|(gRb4Ve zxE4Boy>+aU(R2*C`Kjp0PFo8kr8qIFuJo4ejlK7-Ur;q;5O2e5!z#y6B{U+cg zH*0r>ulphMe+u74@}CLc6^5OB-<^CnAPyIRI8=^rc=s8Lmnu|x1BHLOV7iblX0lCk*GlgH0GJ7{(lvI$K7nJu#@v~q0pC)?t z$~f2`UD>;6;ss>*;7B;9kFu7Cx1|h9wOabi^V)ZeB@kPCB3*GO0X9j5^&?+?!IF5- zCl}WKs~Rbz&stX}=aVE|CYq=zyYQ8Dsboh_YhN}RuE4E;5$0!ywpU6v0HX><$3SeN zRlIGO39v!Or|(@j-u}zsW<@9Rt9lzRaI?o><%d#+SCujxXh=DtBP8_e=@3Wq=3%6i{{y>$>;yC1hmLtKD@v00^YKFb@%HG~s*&Yi=FgTFH!WD%HD~ z${iYFa#rFoTVbBk+VteDo6_@bj)kPk+^o`iYfrxPqfr#K;}<=z zzNq|n?AM)BAB}JNX!Y{=6Q4S5y!tgI43B?vZ}k<3z~4Kie?|Pz!SUgtED`>|!0Y4M z*T$EuQJ(n<)5!Gu0W&Gt2whhWc9@+(X)tMibT5A3;P}LXf=&LdF5L3x?;0Ls*5f-L zS~}LA&|y+E3gUy0NyG;qD-j=j)O8R?9lE{B0ijYu=`|rXU5XeIX`1h!GH8ZFX?&D8 zV&?Bj<`1>(l!)KTsbU%&8m_XNQLR=7ewmhRvdIsFvJF4PFzN&I!|usR`b>UXZ@mrM zPwygkymeZm766V6#P57*@Az`QE~F$30Bs>)$hOkzYAlR@{Gqefy+)7gWA$-o(*~}w zh0wO{i&#(}3x|o&|Mi}=%I~RL*jMt=rzA-vNnTrC%?HN=C-{KikPmfI{UINeVZE0R z5)-k!tPjNthE5yp?H5gAJjSh$b&b9VclG!no3jLgyK8r%79*p!i zutbS7oD@7iUjI<{`06i(Yce#BK$_1gm6HMW>e5H-gK>>u>^)Jb9|q8|uKJ=akk1DN;uOSGiXJ4C{WF z(jd1kN!8LJ%LwaG>gs}qjy0w-m_xkN`pp_Ur*r`=&@|!UYD?QLGCJk}z8#>?cLCVL z1+eoE(E%fp{c^$hxEYgE3nV0J@uBI2ZE0|9#*p%DF_zXy5s8*}4hphX2Jr%0en6e1 z4;aysj!`8H#BSRof3RrmM89>aWEqnO(bB_B=P@d?@i#Ns?PrLxpy*?duOstNPrNwnaGlmAWe| z#ELB{>i_$F&bfE)Bw57^PFcp&pF3RwFs8wnB*dgRj4^&kYwR3 zkMsZiH0ltNhMNNXG@wGK;ZgynWm#Bu6tb}BS5hIhoK~EV!_U|sz+r^8VuE1yiZqqL zwY^QS1jxT%WG5OUKH&4#C9_+BXs@E+6cLFv)f0ZSgoV& z1}p(*)-hf+s+9-CI__Am5HXeFlTYBTYk=> z{m{$;+4EM3g4tR~(zyR3BJnlEt|r0`Uo(NzUc!p6w=y6dxjhTsY&n6s7ZPz1;am&f zvgj#VFr+}{1;WR?0cY?Gmlaw9lmU64Ym!7x;2rHC)%xh!`UJ8Oq!j?YN4{p9gk6W) zn)n$g2tFeSh^K*tGzEc#uM>Q6FX%_7Wz-dQ(5BdtRhm~~_ax?G9IPbxR)DdS89xGGH*$ijo@bY`S7@7wC1 zAH?dQo(%plmNpGz8#J~T7ejtlvf=3;#)ewU)EOVfM%rzks_Q>QM8#j0swa?KwecZT zYEMne&S_|6QsX-x#zxs2ma2gt#k>g{anc{fKN~Z!O!FL1|96y{cPD$w2@>V}!PHS# ze-s;F|K=Wb*GI9#%8c?}tTlOMZ;oAAqSMfH9QWwnv^jPF^{-bq$6ijDno}DnIsSw3_{22!j5SpwhWCz=@N@-pRN*o=M6BDE47h`!*6gl zNltwv)5n4KJClv!ThLgmdiA%BgAfgo`Xe)GliNbYuteSctc%Da9S=81^eAZGY9W2i znx9iCn9tvMV!AmrZJY6A6}YeMeEh;)8)xeb9n3%oaGdQdwH#BtD3yJHjoVWN8JbeX zEuu%Qwd+Xg85tMlHVSHR7)YR|`e+v{BG_C|DxtLFfL!Us1Z;!W?`!x(C%f>JJ`k`t zml9hGS7!CO2>97))yfHl7#qfHrAt!FE*EHWKXpcOuSFBMd5jYs$6#7GrU3Rx8h1J3 zY1Ba7QYW(GEQAs)jk7a!qTw%u<;NNy+&j%14;_8(cNu=*;tuGidUWt8rOZzRXH?*4 zHx6IL&wlv11V`Fd;@O60mHC7o<7i5q4H(M|!0!$Hc;8HBp!td1Brjfwf{F&2pNnx| zA)?sd}1B{OlEldc;-hv6qH!O!9Nxv5+q$BCbQ$htu0&aC-{W=@HJI|dgsTQ2 zL^m}3FBbfc3qun4y4?mcj4{^?CMzgW`b_VknGR)45O~CwMk3pZ^z<)4DHjo&Y=$b@q z;M|}VU7hN$t}Kq@z7+E3k~FT>s$&iKzaIaywlVBz6#t{UC5@3tZPLpg3U@{cOlh>6 zWEf0F7e|PeH|3m60}_XylW9bOq<1{yJsQ3EtaQV<8PYb+pe$iy4NNN;8?jO3+#@m# zlKX6)w9tV3C9`zyXph`c=EnDav%Kc!?#MakqC3sat0TN43a%97<{fJ2S%ciVnyoL3 zMk5xcS<*}3xC92%CcQBSVzMOIlLQBqu7i6+_?n&yP0S_izhG zTfdFb*5^kn5Y(eYw+|?d5-}VR4fCWo?ts!b9s~%6h{4he3UctT_tKLDE^40@;d(Ei z0^e~|JLUo|BLbJ^dp9rcss;D!b~Wb53g)Y4dDTA%<6p?85bqiif3}GDYzP)x1x2@| zF~4)L5R8LC5+p@D8{HpvR$ptjt#Qj$CjO`yV#5jqoDq&*AONsh2V+Q@_ml9OQwKwf zA-His2>1YgPB{m;&fP2WKbVksEy?~64l%q_u;M-b!yw12C0-OxjcCx-?doYdDHt;N zK~JHyhTDBLXs1(}&0@Z3*GV|nUv#d1KlHl$?wsHKg6_i0!p;gY;nH@?(O+g+Y3)yhOmuQf4SQOVF7K90icZ{|4J=yvouq?R6=P}uQW)aZB(KE~9Q49Yu z`cKa|%*I~G1pUGC*y4N}x25^E^AuM|aM_*|m;B5W2M!vhrJfW=f)i;VnX+a+>@3B} zOb#e68K$^o-xL=RT#^KbqbzIEn4_e)crWa19XVTIhNwK)HSxE^nzzxLY3O6M0E)bQ4S)J zr?d6$KqB0MtlTQP&1upX0)SR@05`rvRivGy)ieZ7)O)-EJiOl5Pzo;vm;Zdb9divA z-6YZu&g84%iPWW9|ECvc6O5nqXizJkpxQV2gcoN6pXhKojIE9Qox$B+cv5-p z;5+gz;S+h=`IMR`*h`s5+Z!;I@VmVq?%B@zidJ(O7TwVAD8A5?f+JG0H9}Y>K-#8?N_lSjL(gU9)dPEbp7RK_1e$fB?e`)vbvLY*DM*&dB%fWWWh?c_i z!y9^p(a{XV=vHzhc*=;{w6~rkCj`uhJ1UW1pwe3Dk5w;}!jP;K_X5CzAK5}%t+jGu zw2jRGc+wnzgf|qyUsS3WRXv8I1jaic?rr$xGxth_xPYIXroUQhz;ij@QIi+(B57De zQqwQEJX@2ccZbx_PpqQ<(5Ul+&Jr0rJZd-&99T1U6q@${M6m?soN<7B<&3Yd|=2j^#%e`PW}Do6$eN%D|nT)@7<6d#kIDE z^bjrlF3iZqU?3tlTyLGU6$P-w`iEaE&ono#X{81$DtoWB#Vz1`qd+GzMR= zG&|ZKC|zf%*G1H2gJV$E}_H8+XSIB)Vn?i;Yj1|{tEkn@#>n_(0W$7PT4!fMG<43P6Nfi6u)>rgfJ!!av{s({H{;cSL|4Oc; z!ZH=y#zA3>F`Q7Ekawzd6dizzYua@)q|o&-;360re4e~9R=~0zi(-vtl(aw4$*p2x zn;4+e>;UO4&Zg8&hZ?4H7ER{CIu;4-HZyicvw7&Fi-h(jxJuIv&~5mv1JvVb`e0EY zRHxvh6$jb!DlLuZ{(2G7hhnP(6)d7Xd3s*LKRGt+=NwBvXExg24+KQ=85_9@ni!w+ z1(NJE!W|ygE^K;!v7+;!kY$-Dnt*6?vA(@R&p2@dn*tT-er7$J!xW7}?x`jN(4;ys z+8Iq}QAu|RH9>I?r}76W6W7F{j4rfhtJN)df_*j=h_eh!0MJ2#C>nSb)Hcx5`n_uh8`6qqeRMs-_F6@e1Uo3l@wCupID*b7RyN>O@|8+B$>;l1O?3{b z9+G{)S1!9Sk1-zHDGy!1YqJs61d^>sakdDD3!_A2xkDHR)5vk8>U^chh*{W1bpmBK z^qa_Q)h&eK>_Lf_}_Y$Q^UDF78##3UpT2^(brK)c~h zcjRKsPAd&Uk)<9VCkyR~_M0VXS?1S}2~=uX&DLqY`VFFn&sb3dk zGDJ`737MOS9E3b+)3lEMp(Q>hn+zfw0mF6%oat8mnott1N}>g(OP072ur&$Pn*2$Y zFzuD-_Hc`#G}vmfMFjn&7W>U%6t%6SmB7Igq!8)gE>)#BC4W1_EwA;@~)e zxmk!f821G_dclk7G89#zr-p*w<%6m@p3n%`XLg;;DQRb?vhUd>t7iBNaS1JDHLT2Bqh0Wd2nIl@FYWnpVbCUh$- zERc!H6zx7Up994&^%Cv3Fc-w6pm+_q;10~!Y@Q2#)(K0~41nf*+JKctKkBh*5_aWT#y3JmwK7d0XBi0g^9d$fk`A( z0Fy{G3vdQ@5VO_5w=eMmEQ4PYup3;Owh7G$A^P&-C7~H1(*j1AAS09x;)mgV3C$0g zPX}^JeYm&DWDFQ0CtZ3_P)ewSrL<~?QWzPnS%6qZ@>&VKAJ9gji8q*RIvN2@i zYlX2EW-4>jRRc)Xh6!a8qHO5=H5L%`t=`7ozOZH3vSALi=!7|Fr#oYParK6?ALeVj z?Q2YwJX#U%R14=35#W>hlNIyybyqcWPutJ8SP3=oDBY3F#Ch3TmfVB1bm>5d7_nM_ALcJI#GR zALg6Yem8WO+7dNl{3L(l6MWC`fnIyF$aO4Ifkn3Szpil z{piDkReNA*F-vGyOtEfqQ#=sb8{=S;P;|Ca3-68xV}b{&Pz&#;w-Z6%{9?v0+LWn# zivS45k3PugHITF;YG+5URV)>s7OxVI)V6`Z=?}L>z_o#ag?0cs_)DxX|JMD&Empot zKc5-$gpy8bO@EVBoAtA7rXB8Q;j9!VO<_zJ?fGWAqtY${ zdhZg~WeG1cmKIts(oL8a7Ux@NXA3BZ`2GB5Y@l?LD_$dwzHYZxyw*sEVzu)l^km5+Ku=b?a?zev?q@li9 z$@BF+&3S?=?k?HHdB}1Km*+W;Oj8@={0jYy~U|+DiEcC z-~e=9qmtc>A6cr~_zfUarC`5&_YcB<6?LVceXQa`1c|sn`GE5qVIm4DpbDK;D{i97 zCfG^oN)Qae_QgU%*f-~&k6A5qbdPmA-lGLN6BHckM#KVoiCQ*t6nGNJ-fKEEU;}?c z?=j;N^{AU^TFldo@IwPovMY;$6nqrbh}6*?&(!e=iGt#o9FQy;w0wgR-T((0?(D;b zjc_@MG0h2M;YG}Bumm&fi6AD9jUYCL+GUWv&W0-lj_D%MSOvxkegzCLp|(-;j@r?r z1NyG9tlS7#;g`=#(1DaN!?#%yFk!d6DxYzrOGtXfD1ZUr;b1&?6hV$^bLt~(NTDl6 z>}JhBt<+}jQbEr@G0%_rOgE(KQlIh{x+fZY1E#Rg)HGB`I%6Z92>vlnztvH*9>WPm zi#I@e2O2FhrpW3JHqX!gk)McE)7={*rXS8tZzL4=oJEFogZnvL^-9S|;v2EqmL zKsaN@F(^P)@P(soIYE<~Etk;hs#nXV(6#QKu;6-}pLWocSl zR~TzWGr>SreOD*TY)gRVP;0xLTEwMJ1QXY?mp! z-U^tWzlH@_si&C@l92ld!J`BOvVUg#Rn9f}x}T%Y6LS3Os+Z?8$l_Hf0}uc+JgkM` zjzeEOzzpw03tN~6!}Zok8Enz4t-GkzlrL)^b!)zIvm)d3mSnm#^1`?L~ih z8t^bvypm{aiyJPGE3FxPKT4m4|*~H>cr@DMUbuSCRg!Qf9`w&Fo$jV=)0mCR^ zz#iARs4tQV^ibFl847h@J)yPkivu5^`x3y^ePuqQBsPRutb$TiK*93JqZMEyJK@tr zryIoet$~Z;#a4DKQzpC-fPIOYen5P1OzKo8_U~7j)J}HM zmDE)S#7FphDlJ@7$<@tJgLy-lFbJRh1GT~yZ%tm(V%^q6QVCDSJi($+>Qh005$GZu zL^N!mx()YSYV~E*w~?7@(9iPoS8H~dmW5c=^O4>yI_veYo6NA0lku<<>?X3qM!b^x zY7;z_sf1=a^gjRikd^u4L$X>=p>Ck-3p|a9)6%l(Mpzt_GONJT$Y^f3-b8VRAi zr%{S6ZE}H9>ct*Xe+7V9z&Z5Retw4d zqsp32&{GV9#SDPP2rQCNh=eFIC@HaP;Uj;fiE0zPL_J#^g-{BhZ|7AB7&Pake%mf; zoyJCoUBX zXrs0V3GR@yn-)+XB#31+VJ|W_I1132xNJ2EX2Ga+*S1K5-RR<0h%hNc(I*k2W}-k` z>zpnd#FrKYG=dO1&VSOXhOVsrl1TN6I%7`+>P?1V%(6$2UgxLlrH>$8*4SB3aE^tp zM^-?Xu2(>iU(+9WvXCr4X>Bs7N@lT8Yj{RrA|f_XPX)*$-Obc{LTd@U!Ad~(f=TT& z1(S%OA-E}qD2=VaR!=wsTYt7|puWkr#MI?+D>5hb6d_(C{O1Q>3IqkR$j}qASph9S z=oO`4+yYvr_XS#}_XS#}2cXp;2V@Ble(4Qai}2^C5VHYTumaXMXgPTU*2OtwBA9@J zJh%n2U}sx_E4SV23~4Y517#QjaEyr?0~PD(QERE}HB|$}E5VNH52;TyQ`stHKTp7B z1xVWgSpw(_fG6VAw-=xV@T`YHWCCkCqXl+CXEab(R!8&f05na-F>+w0p6KvRr)=J6 z*oy6>Rjn_=bSj4`Vtl9KX7Gb%K8x+7d3}L7l%YDYEo&&yhY$R6ydT}=|0h{Rqv>1n zZKPVd8lcCH)>hHz{{yU|(f?_yh<$in@y*U2hEX~WSC)F~UsVHfg3Q!!#2fqR)%~7RSuOlVe2_VM8PwZZsXl#S zTz%qoI`rtYdPKeRjriyaiQKQjkxNlI>E@}+)XcTx#@h3ishif0Yvl83^L&5pxV_M1 z)4FlPvYVxr1{8vF(S8Z5+{C~BdXNa~H<>B5Q6C!T!5iVNkvt}aZH|qcxEIdK?4!En z1=ZP}?QO^x-VF?OtEJb6OW#opfUPPUQ#m$mbH%^SN=NXk4e~XtQ&_ZJ<>)B~=Zv*m zYVf8TZJQ%)2K?HgNkr>hFyoO z2|5sFW{Pn}XBp40K+ZOr#ky|TD8A+?SJ?2FG4vKEdg`DKWJ54|5E7ntQ@>}l4k8Qm z5zq)btb_9JN3Et|oqN?lcCbRhCBjI3WF0XxF+u?V%>xO)%O?P#NO;vxK#2+VYM%I6 zJ;ClY&owq6n8Ybg?06@ZEcMPi@JTO|4YvnyvbGMtHov{)`2^iwXFdTY7K*INC!~=u zHnNrp+%%f+QO5KL&wP&#FkO0DHUm=F;;1ip@Ng;~%GM#k9TKSswtA*0Iu&1m0eHdq z(U*o;@WC-ue_FOjO&0mvEbTavqR10=$iU@5@0V-N#4JY5#c3Qt$uk;~0(pN4HG?|+ z#hF;T_%u)fBm3}^v4l7XQ!M+83wkQ1Unzl}71!+s$CC6LRxiCV+t=-Z-$xy!GD|AK z@Pay|2H%Fmx&@}M>AMA*w9?$Vnuf906esjpnK%%gw5a zYpW~wEMjOD$Tam+t_ItHD*vUi;F3lyc#ObJ2#}!>eTX6hd->U`Q;Fl^7i3WwI7LX| zV-HGkDadFUf~LqDhN$SVkA|(IJBe)st4_GgCc!1f^(~eyaL6}$o1~f+}tcE5I zK*@$d-Qq$1-}{13@(0ObXqXDYLH@4x>b!mKZ@}IB`3`{~V1NgT9Y^@3j@Yq%zSpD2u9i(Sz3$tNc`Fb|h`__|SlzrWL zvaRZ+8#t5klFPr)TTe_kUivvQnsvNLKGXLk{%42E)AZBnxodn)xvY$G%)#f{)>REcry93CTZ zpfMgi&=`*h4~wJDf>=o~?F`RxLFgvdIPjwr8zC4&X=&dJQXvW*@LNhp*?fX%h1C5r zxA`UG$dSqL8q$l5e4^5bV*?JGWIpoOfqMq;+D9Yb;h#z7BYqu``pOwT+xd1=NGiO&K1TSr5iMntNi(}*3Su7|GM zMi`b+7?!5X!m=NAr$y2;H$<4hwuj_Jh^*N8I!@m>nukJW8 zeqetb^^C%~iaG!QtUf(4K8Pnr)|?b?E8-y36DP%aSmc{0#q0Ld3>f9g*>+jF zyrAtwSfB(=cblfsp-A#sb^VF)qx<79jBT{7_B|!uPptwd)xRH|sBbM`7Y^H*E;P63 z(MuPev~g2|q1SHp?kVwIcwD-hdW@aJ%mzC%nFA zS;DcyFLzltD8=Zm+e3&DCN;G<3CTw z12cua+39XzF$3#lSzodGP1Gv#;nQKCR_p5doGu<4DT0y~!=#4Ji3j&-;8BE$jcWyX zH$$A?;%VNJ0*J`67`^f?;YlZ>KoRe7(-NNiA`2R@<4Ur=j^yG>0vj7tt3^xW`migz zK2g2Fk?XbEGo`HAy9R>@=Y-g4SJ1<=G28HhnQV&s1=?ULTw5KziaLXvkhqqB&HxuIoCM- zXp@lI%=F_7BuDe-o#AMtP2?{+Hxm!dHi*4wx-7uXCiU&pOy z;GI@mY*?G{G)H(^7NH-))P%($jGnyB!CU}*0p}8aOhJb!?hR*2DugpEMS-}Z^8?N? zfwK#)R!ksa-Oj+dnBejpZ0L%iYJ)nkTPc4&a%WrN@OHg!3|L6oXTP{C#blF@sXx;#L&59vK&XYJUtNY& zjGAIv4O;abtp=rL!xLN!kyan=Mvy=R@)}B{l*ucSaVnBJEl?)oTKb^wyh0h*(}HP% zQW=K?G-U(DGR_IC>!WU2F2}OOK@~cY3g$p?D)u`(b`VG##uLau431+DhL`$-TpvX6 zXnU7HX!b9LNjBq7A0HWQ8W~g~G2$U~GO<&b4RLyh5Nev$+JHussPs72zD)3gv`B5a z7pMEgB^aQ(1_+vuPM72fTw^d9O5lwm%`)jp`Sxu7)J{pV1cVvSI;A;0mAX%-J*u7;r(zKpx}2i8zr9dajssf=8!kad8|9H=4SQ_dnkP zGHwiagP}{Li=Zo^@ImBl3&`+;qQ1${(PT)q5@d)|o`eqjqCc^({&(mPhfMXLG$Kom zTkl1G5SbzR!wP+v{z5!YCNW4%)3YJa|0MnO>`Nj2!D*;xL@)XiR15tHCE{qGouEHw zOY{dTU+7QQZRjuGLZ1F~H+=dFy7K?%Z>Q*woZ&yr|F%JYevkhDLVs~9?u+40D}U<- zIGqE_3?|tSsHot7&=I(PBBFwZ1=Is-p#FQh*#CtnRIih4Ut5~yCr+TFUYFJnUaSCb z&*^wz(cok}UZc-sf_(yh;&BYKK~&MzAmM!6v`c&E?d#-d-?@>SFOZ2L2yp;1-N8`^r}rrVdK<; zhe3a+!|JI1P*+$Y9fVbCjVvgE#T#ff6waXtA#{acXYv?=-W;#xyNo0|Fkq4yjE3;c zW7KrJZa_BVpu|=UI4X;PE;=Z&)wMo)40X$5>Xs5lB`;7a6Rb;KAOL(nrfBaHxF%l! zs?s2v^iFp(NCROwp4#t6jQ3|(30b3$32v7I%7N0@VL{&LY=X$t%SNpbsVdmRFZMmJ zOCZ0F!IZ0=jpGM?1FlTx?@9;d;x;9@5SUAhR0hC|X~c-Rla~(U_{IJm>M$2%y*hNE zIdmL!p`_OD41AYt$X~S~qC5S&Y~TV7o#~bRVEZQ57d5xC{^aVMv(?F^5%BrXEo=nZ zuE`~Y`~}Rd8G2xtK3kt$|8H&udiwu0bIX3ANL`W{Fdz#DNt5;ykHs2J>-IVruG9oaXObj8C|)M?eV`N9~ePSjFGGGe50^{Wf9J^|TZmABHwAQ!zj?lsQD za+hX^{?-!BTj7motcW?U2{?&pei<{Ga-M%%Q99vsdcYOr{ z2{{Y$y9neX6e;=yG2S(%-@%4IRE$7gElMFm!$;;6dtHGq^C4b1?k{5jxQ_8<0-zBp zh?q$neB3)Ym@FpFTXdu#Bn6$5xdaW6%Q8dgl)#NvfSAiM2FP)|Hho$Sf|h{*tvTQs z;0g$kL<}geP5@BY>!$%9V1<1%ZJ<_sgr*^Xi9X35U`2+J#|l1XqcSeYcpo!>KD!=W zj#GZtqP;r%rD!HnfSBR{F~x!yqFmOB3sf;;tpHKTEQpeEt=B`z7KB`{HJCzm1(?G2 zj{sADv~eY}!4#)~k0~6sqo)A~3rGvAWS9hbz+w_e2ihf(4pO?_d*Q%L0&MQVm2E5n z?CU1r%o4!%0Cfn+;L%|qlk|ZT4PbCq17IF|);S7Q3+Wd^IDT5XSd%_iU_kotoDRxT z!}Z;0Ho0^joFo&@*MRO(t55g6p_!-q`$LOZ-65tz|0JMDk;4aw*Q>@+#4-hf86cA! z5nKs;4Q2qaY-RxGx1Ir*{xSo6&$93hR+d2J1c5!BmjMEC#9B7Lh}y zLF9Dti5Z~V=*5wcjtLVWhgn0&k&o;Mm|bWBNO#Nx05M?#kTcbMHr51+*L`{PGVNMK z%|5|1M4^y1`)M@lfpzuz_fqS9OpiSlLFXBiOVAz~aILCwws_1KVJR67W^D)U^eD0*gq^F<)D|x5upY7e|5lQ~_7*IcImCsp6_41X%by z(nvK?&Ir7otk&nMYy1MAnW;|qWz!CE)&Cu)`g)Iv=`&TCnAG?5#7v~Kp_v(Gr6ov<1eD?DC!l;J4MAZHO+Zl-^#l~w``QDVAZe38X-w(MT~0jVNmbX-`?Yb5av(v~PL! z*73I?Ha`!knbpVWFt)0Q;Un@A z0xyhtUzUCrsfqFHb@h;LyS-xb^N^a^Jmz;;Y#MOGBkH4>^aWWgnPRvV@>AInzZ!TswqO)G)(SRZP{pJNF>)S#pl(LJjy{Qg4;>Z zfD`rhJ`$T{jMW0vC$wX=wp>t8oFu?Ydz7ul&Q$8&hFlVc_KNdms6E3|ly9yM9ohiI z!Ll~gf}I&!?)rqmo*BZxRtx>D+^0YJs3{{s)fladTTyz*f^}kdGSr{ck@t}kOr~vV z5x-G4{-P56MfN~b6Nu)uZ25?GvdkP(v!yHRVdr+^6bc-!8O^u_RI{Dz0v1I9(fFF0 zY`oaS11{J%XxYF&>PJi6#?EznPz}xs3(Q;ygaUTq+ficwgnUzd_&I!QintB=Ih<_Z z={{{bf3(U8p5``|UEvn(Z_J$_)Ng}=;PQ?4{LJXcSTsmao zd^c{5zQn_JqI>71L$(LH5pNfud$G?X43BWbJOZ#bJYtLfEb<6{{`n5AN!p<$JOTqw zWnniL;M@0Sl?C|rr9-}GHHw5-gfE_oLq&WRAp!-h!5JnjBJ2Vqi@*VTy_ET|@W_ib z**6k+yTU9&bb8Gqa6mMcPKyLKro~>KFQn%ggV-|QwRz4UUs*kbRERN1BZe`+Ed|EV zmpIvBX)?J$oPaav&iVE?TJjk~Z*kHZQyupY`Rp$Bn(akK{}4jvt-egkwr^T7tLexmQ&B zj`$F3lUj8+ZW!y`rp}H-5Se|!+}V=d-V{~dicDP}`Cq?1eg~4()jx?B^quvnZ`~T7 z(MK76D``ip4%>Ke;rzJD+z}s)Qwz4#h;)i4GqS+ti{|Q1b#Jj#>)so5=N8&c^2AnF zbKBKVt5sjE9AdR?2^8KNgZhH=Zbwuet^V-3JADf+sGt39P?>sfgWJ#ApdOr2+0;AV zb>+L>j8ygN+in5S&b}vpObLUSiojx4+q-n|DrwyzRrP9V~I)^uZT z*fDBtd;IXezqR+Be2gmJcWhrp6gy^!$QB}+viDdLQTIJiV@&fy@{|jQMFcxp5OAT{ zUviXsFlpD6g$|QQ{vxJct>1ew$RxYy>e`IK-Jd40t{orYIE( zC_fQ~4YpZ$BG!RL@ie+B&i*h-I)qMgBhW!|1#u2?`Jp61U6N=w#(&wU28W?YI%3Nv zBYXjkqgm8h8`J3}zIw&8N~mz-rY@dT!dzfIHWmaC!JhiKS&i$64?VC5ee_RX!I>iL zIu2Xp&PDx#Ga_U84p@-z_#`1}p2ht?o;3?#X;RmA#2ZRG7XF;kkw>DH<+rI{qW%G^ z2rVeW=z$#11uYqeu&9qa;$zwOMtrjNwhluH6g&ox!a5FpFg`3Rb>NzN#Ny)`8-0jF z9?~)>(MwEhpPW(I6P$ejy${p~)(GdW{235l)9iVOOY<7M?kn-cc448L++eGpza-Qd zJ*_roL?}R{${vc3I5NU;p8!BO^#XvK>0LY%yV>@(x@<&_hQG;(a<1@VQF0JQSaCAObpfzA_0h(v=N+I9`{9$_5=VIBaDS_pw-vpee-z zy9sbjCFlk@FdY9x8{8*p)|KTNIQd$UW~5N2Uvz4I69o?0;8CfSAd;E8S`qKpk<-0( zP#xmllAMioapW91RY2q|xwEr5!c6#>{R-S5F$qzsz#i=KbU*d{!|?&bKBAq=t!7;o zHhtm*Op{BCSY<7Z53ZM;9D1(cl&C6Q4YzFcN1w;f%nXpzfs&bWwdlv=M`f{B8y!rg z2MASjsh*InMYCJzGh%b_CDh%1UgXfy3e@u{{^ONu_-W0m#Y*=<@*90_E;<-VJUzyq znl45giA-F=In&vMJ_RU)eIp3_jFMn*MFEI|8-73}acuH0_6=D{+(60!X{5_j|1G=w z0S^|ynU^>h1P8?8uJM_BW5*;&h-v5vF2F;rD2OIf20PKxNOWqNVQDCgEVD?L$op3e zfl&e&WAl8FyP%|)C_(20C1v=UJukJ{N5<4r8^bbfG1#om-v6}P_`$>>N5ghAh$sPG z(GSK$B$x-yB1N~$_k&U&vPRK;bY)UimzP9me1D#q7VkOlDiBz#KA zmD5Sy%UuqRrm^bcHwbt5ULQ+AV%&s2~qs!mT=%=9jr zi8kDedr{%)WgLaUzG2Ai+S}DLtgV@qZ9K!+ORfJ=tAnE}@P8$p@U8Xyap%6k9gpV&K zv+;B}=Yhr9JU(3xn#ET@SQ2G6r6^{7DDl&2sYN0(O&uh2z+^f?!i6&-2PbQoo0e$; zws90j0RfkJYWj-!kV?%ac(o}zNG?8JUA!Vbuo0|3F1-eaU^irzf!QN9hTNL%>kk{% zsul6dF`L167-tIZZ-i~kn+=DEqy_p+%$pxopR9;i*SyL3^K1mBH?v3B#EW=CL#pY~ zcvS=V7*v=6ayX!Le?v1>>HetOyihC0yTs}N)}mUYlBsI%C*nh6;z3Zy zJrN&<6K5`ZBEDM*)Te+p)QTr?+@zd_!)?guI~f7a$}8`zs#fJcix1ML!|-tM1itce z37muHQ(}Qq+jlA<5$r@=mQ*wDo;X}JjoK}i1@re}m~R$Fn6&I@Q7m5UxQQf2$_bKM zCG#?Z8I^iG_=#9(e^-h=w=4M6*D+&Tt3q#!NA*s=`d)QlU-#DPApQEsjBP7l&+hg< zW-J&=U&oAXt9t*Ku~lE}F=M71uu4e{+d5{fXJ*nUGLH-6a5QP zlpK|bkYcp&3?GWp_&2tl{+_1GK!3+Bz$m>SWLBUY{T+2Trlb2EhiN1+gOk!YT~ul- z!Y_Cru$)tkawdB-gbL65Kng6)I3BPxi#6L6%Pi_43s0RSy8y?BC!(!Ltz8ozl!zs; z9R=^rQT5)M`2N}PJOUJlJ#wRp9JW*hn-ymv zP-z$dw$`6uo?&PO8Wdg+f+A1^qjh?zG;yT-EJenwdf*wvayL>1;VEHS%VGmi6!93J zfy0JcHjNWoa3RT}YmMj6V=~hDgEAF*oKtJz-7rc`JZ&4L1}RfB5K4INgJ!8rBOkyH z<;70#2`vWeN#b8Y@G;MXp;Jyy)xlZ3C@bwvEdl7z=dTc6bZ(?m>f&GGqHr;(b@R2g`&!*~rsY|d5bHE`+?a|X zc1c|A^=!OpsI+8ifX^zmvKI|Ri;IfYUC(0kPjfU=M3ZL=f{fi_&+~mQ!P=|z^`MCW zkvP2~c!1uc-2Q0@TGYBIPi!;#t<;kG8GAyRCJG0X!Yu1bbut;CmC5HHBrD_;NM~e- zB(-11tMj^UqZMO3NI`0MIJI}rX)^%ejkU7-1;3io_V-Dsfjx(`eFWLscF_4J1^Er# z_(GRRZ3~uy78PN~3@0FkTbnuGHR7$oWn03U)VdYbgVZB8kFQi6@4EWPxx;T6U!(57 zee!^~c9p7*t7Fw?V0$T`h$H=Y8IkO<0ukS({eN5+kuSWSNVZey23K0Tml02w29XwA zPJ}+CcqX%@vzy&q@VTl7ZyrCephp9Xfgc=$VXJk~p#u*IIdRbqk;~Dz@+(B3%r2ek)r3|r0c&$r_--uI?Q|_e@qc)vT^9b41&WB zVB()D{P`Bh8$WsSZuUHnmQF0CJ!jBs+r@JhP3yv;*&*I#FzF>cITzN9g$HipLwQ@z zLu$oX`snvOe1>bNuHz)-E>YzFI$MamSDoZIo&GUv&~31no^~&*_a~GF(3bU4l<8@? zpo3B^ZK z^>sg0!_+CikC&N)+>_Akzo}*naI4jyzv-mX?esKwF&U}X!5935Db*<+h~Gb=&Z%}Q z)vj+$E}Q-Woyp>Eu~KXGZ@|$?&F63GgZO>*vi$FlnVuXHVc#OP{3E^P(@OpM5taRx z^QWq-T964%VtWusZ4JPERf{_3IH$k;#8P$KQfCmKcO2)`+V{*+Pao%;0<+?*hQv^H z!u(h@e*f{s#4dPPFC`AfLniy1-*yJ$_a!eS#@KCh)O{}{h9|_;iY}&}QO6zc?8<^y z#m2=XSuLndWYlfHNldfezOLfWLvMUJ!J5G*M&U8_Wj|f*bq$-m@kD1oq%Zo>gu&|D zCpygfX_-9&k9V$#W$>tIjj@5ZPISJH$JbACj=_Jc#QatGaZjv z`mq`h$M*@VvXh*H@a^Q29rohNlO6OYp=8{c*I@V#gh9<^5LvN>w(DNZ_{%InQim(NkhAr(a~KE?Sm9%p^4VW9fmDb5i5 z_Lf=I>Y8sixKY|^HK(G-|5P(ibvTS`@UY)*R!xcY5T&ZC`o&|jcs96t{ZwZR5mxcN z-LJ8iwy1SiOj=?uYf-Ca)(<8^XZ$t358u}vpRDHlGv9Y^z{>6MGo3G$zIcVEh}P1X zsTb9vna-lq?legq_0;H^`+-!(Muw%@B^f`fQ}@cx0jVW^QcdbU`Pn~pzn?TD_22Td zD)oRoD^vIAPqfMI=Fik!SE&0=10*`s^QSpqWzUA5?u;C?Rwl#Kq-WEtE10zGDFNA5CRo60z7%k;_$~rupFSS zI}ba&@qG3?XPET|^~QP5622~+xL2SP_27r>U~m&RGP>Ia}OJooy6GZtmP z_XFohzCQ5-=R4ahJN1XoMwI!|e>pd>%ya+coXqF$=R57CR}n_juzCn(aeKRlsZ%{qDgJ%byPpcspIHR5U{FLfmnmgnI$F{70tHUltx0b4lE_9AT z`P|DFVuaQ*_5MZ9a5gpI$Ic{tp8jK}#d<)!{A1^`eHPBuMASMGwod9MzVSps_-E&i zhA$iL3oCUqQ)`GV5qOOPswjYm8XJba}=!hZs8zpY^=#PDL+uzE!2K#lXS?j2`GNviy}h z?^0)?Wj+nWbWf%SBHSp3Lb)d{1Andj$W*>k*x5_aUO!S*mpcpX#Vxt}FL$1|tQXXe z=QyLQ0#q-A>JJ%-V7bj|`5fo#981Mqr|p0jeEbi|j3Mr;Gxa{*4D*_Uz3>2518dlT z8ZOmEyjLV;BT_z5o%5Zu9Nk(;R6RJ)xkSBlg%d+R-oL^bJ}T(PwrgR}?w#k%N6|@F z?s(C+uau$}&foE(yIrM~hJ&th(*C71T38HCHP2B$y2?4T@>2u()dKm=fc(em!>gPr z)+cJOtDPI|<~g}vU+v7W%7PJ-%|DadtrZ$Jhj!Eg=YZYH1Y5PXODru zG;OS@dmU=e#`gNES1A4}O z#BiDKZ)jZVdQqlAG>aaAY&c9#Tf0dE`3c|iJevCkm-Dd!MW_HE^i_U|Hs-L;Qe)s?DJ zixpaWORZDRQ-^3x(vp*=VH1ibi2*^YTtY_<)k`b}wFNg-^3{A?>?h*L2;mohUg+%R z&%Owy0D|!%UfWH-P$O<~M)|1GxecIxYpF%E+$uHeCTDEZ%EfFM7Q+y(Nk-{0kEA5g z7W)|Nl*}HD=?`k%P0nC@jKI&167z7B%!1=UBU?MV)_(v!{JUi+cDL=gYBmM7=sZy>CXPPO``64!_m;z_PDy zQHR`)hOTMJeeZUsOA@})CJE})HYd}6{*7ez@(&&{P-D6%_3PYiZO-MkePfFnafh?X zRxN7SV&_czx)ycyV&@p|rH6Dc(IDIoSeV9gzqhm?u?n`)W>y`nn&4PnZ>>m?jZ4+& zJDmkt|4mm@o-Pf(>lCUpa~}!S;pxtD5q1+CKDSEOJB?(@*V1KL*+wn>`>aMCdY7|r z|K|vKUdIV=c->MTkn)qeoXHK>keO1KyPnC6yOGbvYf@OC_-<#Hp}%5Xvi^F0rkD#j z1$7>Hw{yYXD;6UQ*E*X@qnKdDT)LJqBD$mmIM;1L-s(h0ju7UD1#{HqyPcXrLTFqK zo(JRd`wMDZJ5;fsEmo(tJA2uki`5IbE7YVQY~ zQ!$}(iyw4KEypK)wc;UX>JeM(BM5Cf0mycPdJlQn`TO=++UGBIhR0TtMpfp?>VYbC zU!uXjeU56qxrl1ojC(BFeHYA&)#7oRess=@4aZy8Jh7LHuas|Nu9P=es&wL-Ys8?rM1Jv=4#$u{?xl=c6Bh^|j1!)B_F#8t1G~b55`o=kxdB5MTU+!eG zT)Ctd0T2d8p*X=Fl8$&AnR|j=ou(gy2PvlTTzfmKFzdsQ!#}C4@74@ZFD-YD9<8-Q zEOB6(!_Nipl*s1{{o3e53F08VNa_JKV}&!-`cPfF!nql0)7VFy^DyQ`k2*~g%$TD* z`*Z|XE#PMf0!pxS?JKeUDC5xpDvqRHQN@or*BsD(%cqyX!~rwMjokb#vzyEvCIa6j z+6w1^^EZP;Kv~oiBrmeTZI3F{E02L>@13JQeGHvkmz%oMDYGd^4u3++jWeEb7T7nm z-1RfZs=1nk0~3bl%VJR-0T`tS@rtCbX;C$u&e0jo*|1nV7oMuU8DTS@;VLMAtd$Uu zYC)%yLv6XQta3v2Z3^leWa`VE{-pDbXy!WIAXEtp-M2HP49iKR2YOwC7RZ*r|J=DK z>%XCQ;Jp@DVnK@MlZN!UH*H86ECNWKADD0+9BpY*=F%^KJTY%WsGoz;3KVemQ2oy@ zoCS_94#9EZ)6P})^(}WN)`W%#m$Cubz;uNM*@$PHTahpKgfy+?StqKC&psr~b;>OfJ6f^Uej7`^?&n!}D+%5YL`s0-d|0aH7o4B;fHi`Og6{&QK4IOOpNEu<7?)q?_Ld27 z8U$wa*-&W0qam#NnTGylkjiU|3Ytb|qCM1(zKA71fJ#t;x8w=H2+BbF&j_o{xbf22 z+j>r&zRnq&Cxb=noXPezb5s|ewQYm|O6bOY^ rHRadNNb6UuWK?-WVdvG&zjiM0 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�P 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�&G`h5aor6lZy1-Z%s=(cE(-Dycg6 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

-)gjJ`IP+({ZRg1Bc1! zI9xstN66>nNO|UZj(?Ow28C$(0vsb>h-2khI8M&Q@$yADLB1F#%9r3IISVJtm*Nz& zjsKSsQdO9Z)8uTNF3-Uk@?4xLUyifn9GorB!#VPNoGV{}J#sGg<|!;7iA&`hahbddm&?VtB4DrUCPJkOH{&Y#7F;ct;2QZ>Tr1y(>*U*U zy7#xw0t~{kx#&}@`*T39*5)QlW~HafD`3YaFRS8C(Ea9u-E?zi4;=h({P$R0jJBS z;|w_oXUb>bEcr~FEuV#RDn*=gTR$K%R^X*?O|o|u zp;;jlx5yXaR{3JwCSQWvV{E<(qMqd<)K&Z^t=u zDbAJez+R6+86i);8|TaS-~#zxTqu|0BKdw?Ecw1V#p+Y6D zlpn@b@@iZyKZ0xIDqJhC!FBSZxL#h18{}%-D6hj!y&C`56Pi`nfLr7m+$wLxZSp4E zE8^2hNc{#<_lT{ryhxsPG5QlV?80 zRUqf#0{LoOC@;Z9vi%XrVmTj|$jfl4yd0Ow*WhxmLII&dUV$s+YjKr)9j=xOagBUE zu9a`Vb+Q-N%SE_BUWpr>X>KGmDXhZHaxrd^Z^Ete&A3gz1-Hv3xI?}bcgnZnF8Oxc zEtle+A2t5pLFiTCPTVKoh5O|)JRskV2jzRP>!-j~a4!y#%Wv4(vG%l5&!DRvS`#%ZgDm35*N=3y?n$@t^#=s zZv08(|B-|y6=HC+d=zex$KqD`Xxt{p;&%BM+#w%}JLThWmmG(?<>S4C9)%NduY4lz zljCu}d=egz$KgTwWbFDma1|ur5cw1wDv!ru@~Jo+`^W!8LWByZ;YfJ`j*=(hXn7Kj zk78cvg^;dFUA&X8x|OgSBA z$>-s0`Fxz?x0k<)PRLau1AF8PaGrc2&X;H50yz^G$`|1x`C?owyF!MzO5`E9R33`U zyb8kz<#GtFkoUlq@}9U#-V0aDp}0og8`sLiah<#mu9w4bgX|qaXjIr2H_7|qW;qe(#5jad96Tq0`Bd!9QAi}@ z%BNwEJOSs)r{jD%2^Yv`;6nLKTqK``i{)foB2UDn0rUHR2xTgqjmzZ}Tp>@!mGTr^ zC7*+<UF9c^mGPpT&LhcHA#F;sNNIi__%yaJu|H&X7BBru;F^l0U)OeslfpAmpgfiF4&ou}A(4=gFVre7Or3 z$Y0<>`Ab|Re}#+XZd@XNjZ3`>-w?{=Z*jTYgDd3kaHae`u9APi)p9Sck$=Rs@=v%< z{u$TH-abNu!Y{Z{{uMXLzu{)NAGgTA<5u|(+$R4Ax61>#L;e$Y%75XmUo`&zP3Tr3 zZx5~l`D)xNFTs8CQrs`+;{kaY9+a13*RO%A;2Inv7vNBN#U7mhVG7q$2$u_SgnT`Y zlyAUMvKL3oML0%YiDTs(ah$vg$IHby!EEFIO@u@hZpKOSEjU>&!71{sI90w4r^%%_ zUA_Zn$amsQ`7WF#mtk+V!rg=%`5v4rmt&87AI_6~IA5;71@Z&9P<{{>$q(UTxe}KI z>~%d%C{z|jKk%daD;p_j+Ae~QE~~6mT$!|@@+U) zz8%NOr8r)`BaHJuLE%mciSk`INiM_5^4&N^z6Ynu_u@3U9H-0o;SBkHoGJTomfu`| z6@+XR9>6*BgE&`y2z%s8oF_kw^X1jJKz;-l%2l{XUW1F}M{$W)VJ)FluEu5ZI$SQV z#})DhTq)P!DtRNWmN(%V`7vB8*Wx&xfyrU~x3H@}a233b zL*#eDIR8Tx+9-s{@8WRzJscswk0a%F93_8%qva2AjQkOfl{;{p{4tI<+xY(pAwh*5 zI8pAzN%E&SS^f;C$e-g>xeKSsU*L54OPnEpg)`-D?9Ed6nvgAjgLC9>ajx8hJ@R)r zPyQa~%Rk@(xfd78KjI?!CtMt`*Yz`@M1?+FD*uAZ^QTouVxAg{rd@}sy)UW=>c zYFs0)!?p5yT-UGhe*>Xjg&N!-Z^VuACfp=HhMVPD+#+wrt@7izO@0Em%XPRze$q?m zRCo$^$y;!@T#tL?r*W_R4DOS+;(oaS56Ii_p!_U${T{dqw&M`&AO9N(p(;Fw!{q02 zxcmZ+kehI%{34E$U&7Jy%Q!}E#Qbom{eA-Ca7zq$V2C1k1a9?q8E$2oF4&XqsF9{EF@Cx3+V#k$4&A+ zxLFRvE%FH5D({Qi zln=qK|7iR_ln_Foi|>AN708F-F!^vCE|10$ax{*VkHAs#7#uAhiDTp#94jC79p`_X z!dMFN^3ga!j>U=cF*r#+7AMQc;S@Ozr^?6UH2DOaE}w`q{O0R#7)I`#>gV4`N2LTd}2NozAYc{X_z`D)q-+M8%c(%w(YZ_adWq& zitSf9%Ehm2bR9=)%T1=W`DZD6Xua043fL1mYj_jccI^YSwyPhbwdr1>wFP}dYsavQ zb}!m*X>AMpX>E&L4+ruHTFVD3k5wK=YkMO3;Za`yjMFs1#hPHg@=|55a;b8K@;c=w zX>EZosJ~V1$Ets={HyXmw03fjSk11sH9ur^;3PVZ)(R77{U;r*oyF<2d(vJ=dkAeF zt?eP_kQI~ds&NiciL!HuO38MPIEUnJvYi8;dv(mp)!`f?pRyez+w~8U?Fm+^eU#Q# z;2BywByZB%RnSRmhwLX>I|uf9BybKKNo!9ymew{XUai;Zm_Ub}1I`Rdn&B*3JJzXc zoqV3AcUEAgva`h}U&3uBa zIdL(qtx&FVzVeNK(T38#LK|V%|Hr_N;ZG_!6Z}E86>{qT zCEH0jY)#+^M$y_6I(anNMm*;vJ(X;SG|C$|1gDX01yace(k79;wx-Sm=h9(YIE&U6 zoI`6TnKMHH*|z*Wqa?1{dn zwKeRawUh1_TH94l{!?{l`a!Zi;m}6|Z78kHzYnbq!3WaX+3w_MvYk^gs-O5MyTT@P zIwnxC1)M=^Pdr&OxM}Sq&7!rF%E=2=zna!I;3ir-WX}AhWZOWezM5>8^V76;dA{uh zcI>}W;V)WSLuZ12l%4v}wSg7fgVt6&oYr>zVYGHg;%M!dpP>HJY3&ds)7qg*qqX^* z?46~8GsESYV3GQ-rL{fcJi+y3djhBKCEFG{_lmp8wn5IlVm;aRh;y&lOtux!y~68i zP=|A~cv;!GS-efQHRopG-_lQ1ckUHmD?9g!K4s@#@wc*buh_FXu)M&%g6nS-9kxc! z&Eha+=VlR0wp~1eA=TPb$hNDUdqoP_PO>S~t({J`J(RBgiSmy~^$#xF4scomV75Y&56Iy$|Pieh& zJ^!GBGr`Yfd!hka+oGZC0xPf=t*zkU%16@Lo)|}Kd&bFUsh*`QAiI60hbD|jHSt`UQ++wE3byWKkZUCrG!YkVfH^*i+xvK{+Vncki#L(@BX7TKQgB3e7S za%gRZohQ7SZ1bxM$628>$aV-O(b@`5qqRRu?s68Gt_hqqynt+V=Ls^&wuKkd+7?_zYiIRhTD$wL zqP0Ee&b=SAsz%Fc_@t)CT4<*oUKX9GKCJFTtG3u<4cwZ*q6w<^D@{DJZ( z%AYBJrTndOuX3OA@3eLx1_J$F*PuFf20C2Bwg)EIlh#&fxbg_)k;)Ouk;;cEk5(R| zJXZM_<>Qs({h6yUK^>=Rg431HRGy?fS=p_erkt)kQ+by1#mbi{&rzPIoNL)e0p~95 zp~Ft0>Q#^%FZF$tjruP9%j|3kVSS9 z$le;V#p%5fKn@od0690wN{$zty|68i<53SF2f(2~>PsD82+nZD|41z#4MaSCV*+mM zIR(hZkPqZIH6KVj<1au)ECJjF&InclIegp?cKdj|n0O|jG&419m=^IXh zFGt4t7krKL;6S7UF&v!zH3rDG&;iH84vawRs8Vygh~Pe7^C}<{ums2mB*MGE84d!paW#+$c^t?Rs0OmmrIBw2 zXU5*D^*aH+tsNwS546Y6fouccYx%E0CLnyPlY{0!2IK{@O(X%?CI$nUA!)=zHJ3(t zq2@jOC~`(HTsugkyGV0sWTP~f1dRb_6^({}CSZb=OO7XjGslv^Dd5x-J`ZY*|_+{XdaVB`& zsejuE?{keuH2wp~bnDeWL-;Yc)2ulGWKI1Fq1ds(XQsZcinKoh|8jBkSn5{9m*W_pq6M-C& zFV!ggKRvEUlgWiYHU()CHXjOyDcp4+thoj_KB(kT3XaMtmo4*HF!al;5V z0Xguzp}AHt-UMgS?b5hc%Y}cW`KLez{Dns0UupR_Kz8pF8XeBbOe_2w$i{TuyG}sD z{{&8t(Hi4{OtA2_n)`rEXjhHGQ@|PS0F48Qn4V(!{ z)7W3j(|2JqqaZ^I(lw6O3S)sBATH5-Dv(8-2V|XIp|L`{i~JgJ_E+)06r3e}o5p*9 zOyF&P?Qk!U0k6~exK?-y$eg{XQTP@u-v(qv?`yg616qC%$SOUoQTRW!+%FM+sU403 znbMOQh5xGMp7)&o?gg^$g(rhEM?HbeNMDV@2W$C-+I_TxenT9xwZa4-6L6_U;dxqK zsNLsi6h2SO7XVpeH)<4qo0i`Rr0Mv8&C&lJ)(+2Vh3A266EABNzD3Ko0hz;hGz#AX z&Z6G0@lzm6MED_aX6&CDzoDG{UmU)N0~?#9@QhYG|9!{f1waNUJQ|#1xmRN=EpG>8 z20CdJo~-4f-xJ(k`5lZK8XRM_f(c{}CuR_-0QZ11f)9aA;318|{{_yW_9q~_Yeb#XNTW3R<8Z?O z#G#Gm9e~V97mdQZgR=&6MHTXalftGNn`w*yQts6#yaPBJZGy%wK;}?*vgXL4ospiJ_X4s62Wsr)*Ebhx z9IY`M$N+^;0B1s`YMiO%vw)9sn|e$AJv+IUsZR zqQ)8^6C`}I=Cwd}t2Z?Ye+QgZBSZCPTK{vc_fH4?hBzF91B>Q+AY1>>Kt?G13^?0_ zjP1?$ItiAcIR>0xgnSv%wc89*73MYb5o61fG)0Pfa& zt>%vbne(SKZUi#HqW^;CBCpYUuW8&$Is3mjyrn(717u0;(J1_YmP-N-f-@&FJN{G4 zzXCGhCo~HGx0Z+ObNsac`l%=mv2b7xq{v!n-VVqr=>lZJg!j;LnLX1q?+au}UZnXL zAWLw9M&Z-;q5m^N>6bIK2bq3ng7Z0D0=!Dg#Y~^4xyS?*y`y@6jmyV{o>O&wvc@2#^6}W16M@SDJqZB>xG> z@O}l-U+8`Zg@=JtZimPI-$Fac&>N{e#AEMh|5;#or z5kNl!$kZO_KyGS?;ynm?)W8I8{Y8SX0@g>MCCf_Cml|L08|95~zU)wmzXA`||J z=AQu>;6F49KMu~4IHB<;pxp+5Y@E$La>j#SHID|T{Dfb7h|>--JGIeV78p8c-U-Nv zk~IoX1?M_nFO7YGj6nDRa1P0%fwZ75(emEnFjYIqPEhYbN_L%O{3M+xE(%`jQ*#cUl6C&rS zgs;>7AJ+b#&?tPP=1%zNx4~<@vK>$jMGjoG8inr!XBE8*WLtY*qwqaizE|Ui8b1QE zgymd@&3nS(pjP-yE66zr;f-s*>V>Dqe&ApEwNo-{GzM3}!*FL~eHzG-^<^LvEd2j) z`QC2?t>2$>`TkX%fZ*l(x3#;-gWAMzn#9@5{iw3w_5Qs&z(YVjcN_yU$HI?mE>GjZ zPv_F+q(p<;T!Z%i9k3aP`k#3NY;xSe2q3$2w8mE2-Sz;ejRH){J)FSu0)H{$=aA<-KVv5gD`vW;W`nLy#=z?s2|H8!?E4E1cqjT;b7FX)RA zn7yG6yX?JzatgT~drdjufm6rWxZrtgIfqq*@n|@9KIGh$a5-mn1f7DfxX78C+~d`Y zpB=luk6%to0GEReNi7|HIoQw;9c^y~$-#zG;H(-sdlD8CZQO?V4LR5_H{MCHefR{5nXRLZ zzCbx!aZB;ZJ5=2kBt56 zHoxrjZ%m9fZikMXh46KcHpYX?F7V=>(RK%sEyj)D%#<8ms0HV?lk5@~r9|6L{<1B; zSVbAbAeVi2BQ=`M&>uLekOT)>>T*<}3Y-DTF0wBz+HUZ26rl=y8B!qo>@_2!?T#RO zrtzbkLXeXMKJYuCF9!wIUm9(6=Ubq%3vA4cHZl;Q?ED*r(Z(on*)>j@9c^>~myLU0 zQM8eRb}JkA>&l~zn;@5M?7I2Uh6OG=ewhoRjn|L>Ir@-xN3`(+-vXD7`vVU|8)M)> z_Q@k3iZ)&bmu=|-k3}1=fXgoM`VCGFWgmSbID4?{lkWh34P17WH$E3_+f1^p-2iTK z(2{-ar01iJP2jSPy|E_R_!3;Uv5i`%isXDu4)`m`k!)l8_E**YIG^US0hb2O1j>e64mcAi8*D}3Y}A1rwz+V423(%h z>wj=Oh&_7>oB_&)S^P<-pUZ|>COC5_8)iA+cFABHifw0wmdk$FYH<5tj%z=qNY?l-;oE_jyknG;nfwN9!x8^7~r*hexN&B}`VzQYs1)Sl@6GM?7 z4(;F|%RxE6ItsFyldHLGmdpibgt9fTOv`2KU^O_cGO@mlGY*%%k0Nj;K=wNPRd8V4 z$X-N^R*=1o9pG$qvX^mG%Vja-l;*Pa5Qg%ku_Idzx!{T5vbC@xB*xBw-dgY*>)}8n zN45&;w1R9E90h0Vm8}AwC&tc!Yz?G=vr1$qV4#-E%73Po%SwNa=FUn#`ri~dFalZX zU!en#mHc&@%gX&ma8`k=-0#r-Wu@K-brK}&*kRz*mxXyBIIF;3c(?n%R*;qVOdWu% z@a1T^EVLKt0Ayjk3Y@K67Sh*ieOWlK1!oD%y7*Bo=eoANmT5F`QX~uEk>E_REUqMh zvkl0)cc#{tb?qsd%Q|+E=CY1mrTxpY^=fcd8J4M?z07smLDs3)gEIlLPF)MmB9nFM zI;}5@t_L)im4JG!FAHo9S}seDr!>E1FDz+VGDcG;MY2pBrn#&`M}l+mk!9z_;7pJ# zGq2EGmX+6mv&dx`c?URiEUU(Knz!RxCcEDO?I6p%_27&^R&g7^St7D38+M)}mqpij z&1I1_Npo359jLjifo6g;L4H{z&Cw3B2s%Z3kVViUa3(<3I2VI+ppiArquRf$SvF|@ zvP5Z|??fm|l40P;pg*t%8Lt&&&Cv(WMkfns8IFg*l4A}y6J#$50*ka;I^?WkmZCqMVz3Qn{vUKpb?rc24@N6Ykm}*MJg+J4cfn~ z;2F)FaYh#G27=pfvB(Nt4jfqLvLcrY&H!Zvu1L#efvrl*WkGE*INOpesMTtHSwO4P zT-Lwp!8@=BWx?x|R*?0ru<)4b;UA2)zF|Fe}i1p%x?0AeMcYU2cWPAjo( zjBS#Lm6!|842YFDSIgy4Q?Qj-1G&8naxN>e0SatIVkL&PbJ~cUa{52D64Tn@U2hsy zVkK4~0uI{evJ!Vd-U@QD5?8c$Oc1dWYdgf)o0VcEX8N3tDOTcQaPEYQl^EaAA7gZZ zgII|f2{HEbu2_jj!D&H=mFVl_blm^eN=$-27nsjwC9d~Ffg8jBt(BPB*{Kq-5_7@X z=)_7~49*93u@aNII5`$8u@;;o&;M*C?mz&HP^`qGnxD%`3`>kLQlNiME3vApW8;XG zxE`Dlh?TeloNeNNwG!i#oDw^ym6!$v+O=XOF4G=YO^m*C7DA$YI4X zWi{YjQx_{SzK0{1jp#IRmWWu1Ia>bTT8Txrf0vcG3=W)J{#z?Cr>8U7h?RH%oO8wh zY$ZmfICb)W%Sy~Zd>xo#u@bA`K<=^~!W`6bjk6p$H#f#u1NqJ1{E|XuVT@6V@Z>u| zHB~XjjeMRsq!sEG#u#}}knaK=xC0S@%Xfi_{u*OcfXjD*jOrLW;PW4J_B3k1d8A1` z^OI5I4B+w^pT*#{kjqzf7QY^2+-qBk2!M-JncJKxNj|Hy8l01=d{$>2coMjLMW=py zj4=sZK3Y@tc8pTi zA=dEIaFS1?tcL>wkk4^!1ZT^U&u<(BUyA_ca~nJQ#u~RmE+3zW9~5hkr}F8B_2B=4 zT)q|2kP&Oo$@1xj%;B+qyK~C78zM)<+Pz=C-H@iae7YeAobUh3ryC+KinaFz$Z~KFWy`){kCS4_;VJM`q*!*)=YHzc zvFv`W2d8l^8{nA-W9=dq<9anXa)dwPiWDJULyAN;sKfpiYa3FsL7f8*4~A@L*Mf7d zlMU(yaL$2p$|CHuSmQ$Q;6^3;%SJsjgmx<%%wcd~fUY8{dN6zcSic-ZnR3`^HNizB z2T`gZ?}-4Ui0VI&HBwMSQY1OYVhuiD1m{@Jjhuq~UKEAopf<$I9L&Iv%Y8+ z?7$@-cuYl^a=}RWWN`Lf;ZuTmJ~-nL`OE-Uo4?9#KVc_ijDy!ZxZcIZCjjzYxZcA> zH_>@Ni0{^1{M4yKAC0j*VJT|ivFxdyf)sTCII%XxYm9|zM})&N7oG~v@7xF<2+pxi z_z-Y@HAeUdaAvnQMeTad%v23S#>T7KNcYZO4d9v24?;hTf_S~LR& zBl7#fnXHmjHSl=$ec_pDULz0u?hv(jepZS)z94I&6HV?n+2?tVq*WJvlYL!Cvm?;E z40?w8W?)vI{zC6Wa5S-nAJ_Z?s^SM~?8TK0JqHIa$8UQeGIqa(phD0y-(mayrib*dW z@WwX-RPL$lZk~*EwVZk-TF*dw7|x%7Oh?awYS*dk(cv2)=UI=efvWB4?DVF;fcH`z zPG`r37qS&VG;pw5csjei=d!_SEih`~V6WYy^AQxIz6L>^Miw>{QQ`p=!g=*;ja$4^{EMWRGZR4D;G&pq3By8u{?KLv{EiJ5Js3OSUh3JY=bGgYJf3 zveWym1n*{ZN0;r9CcgM>zxoS#4iNz z~Gf1I6i0=eA1qQxlgjaPJf9fJ2>2HY{s=5*AiR> zxW?n^JEHOGjQh5@THyKxvJ<$D;W~ordsm{^%-sA$5dQ)5;_#>DcUG-D=AsEnBfUl@ zG&bVm8<@gZ;+{P;DH-o310}&f;{Ft_)3_#;%_%g?N(QO3zJr)XVXzn_XNRX2CYU4C8_mtOs%a;)WvFpQ zri$-mru)}tI%CT4ii*PWN?%1KQaGouw9+@PqOibMTv}0FQ0S{HvQwRvYW=YS%z}!_ z^1Nbr|HFVL&C9QVg)pzOxIRTwfb?o zZYzByg?SZ~KJ*h`*(_G)9A9yTFONZ`;AJxC(bRU@$NVTWGNKkvY&-kV4LT^x%IY32 zPIEkJMU>e)UAPY_eW5D6132eR;qAbaT)d-4?TRvoby+vwDG1SfHPk5x;fKIGD*xAG zVvCSW)OubiYPxuKXQt*PNj$yynf}Ur+EFQ<$}h)lK5emqOaUG|6kAks4=!(ZHyS9Xrkr<z!hpZfK6b9BV7NGN}3xJIgac7-`9A>%Tyy|DEd+}OsbA`iA_aBqaD z+8J3XO<#asH}y>%o(${HNBxGhG+TM1r>nLt&4~$9raPAB93Z-#5e@7OWTR|lbG4$S zIXZb4+&M&uJOhz(h!EZioDI^WLcSZ*CM47bJP zU}!My!siC@tI)AuF?%-?`5JX5!tB(#WQH@fEC!zE@;=C8KLPtieJFzCle6%k@?I=e6`&hkK$z#YJcLHuKIcYv%%w?6CN%?lv! zfJ@?=iTn13UGHIaxz14Q458`m&73ZS@|;?10_+FXR}dU)QFtrl_X2gOy_wofoO-Fa z4(9&ooV;?hdsqw=998U5TGjf{I{R-hUm1m&x_CCH=n4)*dO-ADU0hj&xdFXso}Mn8 z*?>BMu7%KMmd%-qX+T~7j2W#S_nDW6^y%W1fesSe?0>M)@-P)WsgaSH_I6V*_V+- zZA_%7%frpAmRYbE@=7aV7;)-DO4K{y=8#@@%=X&m-rYdf!CD{-Pon%Bg~>-D;YvLp zZub9EfZq#wOSNT2R;s6Sk*d1D%#WB-I-jVh@^O)Sd}h>8fFeIV#$NOvq403-{wIylTSN zV>)_1zCz_THB;Kd!Jc&ZMPT*^w};RW)uNf1*#6*^UVF{<5RiRfl06T*n@*g1zp2?e zuEKVMMS|H{8XKCbI@#2`!rKfAj=VP$8B{07{a8wq$TI8zpj=p%83 z87i&99NRPr_Z^hK!i;OrWp7$++#wi(;4ml|X}IU}71T46%~{^D;3IL3!!;gP6=Y2e z)uN}_t>vG=<(h)~OVycVvqMTQZb|cS<>Q*EIoBJc1#!D#_eFO+++ zm4YombPo29$O_fa%{(4n44vQ4P@+3Sk5zc>*Qt`>l?8qUyty)#;?7t+bZ0_G{A|WO z%koP2`Og_1b*>Cca7Pgo*JgzGLa=zO3vd=tOZCmntcyI4Rj3m^&Himf^#+L8{=$9u z0WY5KRm1PG;?%}>%=@C3%=a48;CeG^jzt8ndQHvhmmq?DXas0r6xfQFpgFTMESaxz zQ_ayH;EG*l=T%>uQM|8DHMGoNffF-duii{UUF z0tP1hJaA@Hco=v`7w-(-$HjYq^U)(oRli`FvpRV8zNFfgnYVgoSF819<`q#NR67>x zHYl-=d{C`A&oxJ+jIZ(9+ufaCays@*@Oa3t1tLuQs)JwNcYaCLRhtw2FF?iz`Hs3n z3zw}1;j+~rT(%m7%T|N%ix3`1)>2fIH10Co&&72Wu32T}bMh)Hn-`Y*3d_r}#9j5W zntPR*;#v8!T6Y!t<3}&kYTVK_YemQ_YH_)lKX&~qUSlGHY>)K&fWlXU)ASR*LGvpM z7uZt(jbNAtMmeJW{SMOF-9fmbuo98;SM#dcP+|7=?0Qwz6Dva0frHpcdA++Cqvlqc z=Xr)~R#lbe=+t$az4pfZ5Fi^t^7-0O(jg7?^)!Bh3~6BK>dr&vg$$;p8amHx)xO1R z&Q{DAh<&&)^csud#;QVzpo15u7^1}bV#^yc4CB%3PMFO!rlh18ZE+u}zNs`Xxd3H6 zv#7A#UIH+ZURQJHn{S2o*y2@(`&$zdr)+Vy+@3_L*iRM!rLwNU{k7zJBwC1j{s?+5 zim45ri>{bkd-hx;T;?J-?}(6u4?uH?bMYEPlL)>D=!`UY%M167{Evp(VYyKKy`h#t zM84s*|N84<-s7Sja6Pb*2TusS-OYol>k$M;pc`>HV<(1=v$#D;nC`KZ@{FxsV=0ii z=1)ei!*E9d*!!;yxQB|-!)F-3;GQjjts!iiI&qD;)xThy*O&}9PC6XF*$C?4Mn8u& zvJsrXJtkrNnaM>)y$)026+D-_$YXSPzG;P}^V5CPM{f6yu}^!5!no~D#J*{GlFyr0 zQVGMa0B+3@aia|DQF&ObfNXIRd5gtB#A|3t#j$z!GGZbFF+#Kro(8MqABEx2yghb3c{i6o#Iy1Sb69WDdkJ!eTLWacdx11m zj%xSDcvX`d&07QM>-?^>*xe7<3HnojN&#QKTEEB?QPobjCj zG94ki)Q~0Sh}NQ)zY9ATaCfC+^%65ZAP=M;dNfK9&#@)uuqg50;yvf74emphy5heK z?yScmAba$+z#fkOjZ4k+K>0{L)IrXNlOsUd2`7O}?636I{w46oct$L$-S!Yay*$|yU)qLZ`yQY3GSJp zo3tBr7B4qjH{YoFrhQ)3@hU4V-Z;6}Yg_`&j}QrGO-!gbIO0{ChKv<6>^8HNx5bCf zF7jYVX@c8k*oUg*HnTi^Ib=m}jWJ-1}VoQHQHmcbE_Pmwe>451`(F zV&iZq{6XBaI|y%vF@}3?!Xv&tU?9XNY^nJR2^yk5XPw2|LM=QQ3#=Efku>4~_Jq>f_$U6>N%{|9HQNFv) zd{5@5YRTQ`zPmnEkt;E7?)voXM^U)vt~Ap_mmTz~hrTjfg>OFS444qquH>V}r>fyy zvwwnklt)$J@~Fyy_^1lRqw0uI$kpGDnf>gTSDF27hwQJ-;r7j)Uz_~`Y1xKHU$$U) zt$WXW*j89{+#E!&8{aqY8+d;G*^juw!%=B$)WZ4XN*-AJYyYCzM{VkNZ>)NDBc71D zzh*YO80(jO{Md^y2SV46i-V7FHs^R3UyXY<43V$FJ-dhSRk-i0&TKZ@`EdjaOKx2D zoq=sr?0|8j)41%g*Y4gN@i-F-hn;M@3m+H6*{{2}^!wqSV*px*u@(PG)7yr7?B*7h ztG8!lb#2;!=(;gI{nWZOW_U#B&%O57V7kLw0(U)9{o+Jhj-5(4i-WCAc>f^zwL$WG zg5+DknL_cu1NR(Rgg=aXBm*CL(P{c7Na4F6ejppoDwCJGwXvKi0+1*o*AyvFFX!s_kp$1?^@P^F*Fq^D##p zi-j$lLr=^RRr`WDI;9BiELo9n!##(-(lQ@fPWb}8aYlOrD+a3L+^iV&`m5&U%}&AN z7${!s92XLLGn`n;!r5SbxRBIalcqlk~hseoUOTs&W2T~IT z0Uhkr#QCc#XZ*+bdqJJGDB<-6XHOH}1Dq4G@Gju)^pLyL!)G1NxX=%`Yv>C)*rn6i zDU-s2860*3h0)6u`h^~qb|yPMNtd3z5hJBnTrr~phi7oOM$$4|@8}7)Fyy(*axyqu zoX9T@;sd~Wl1b$J29moa+ymaxC0`28iB$9-2S>~39&mV2EARl&4&+-5xt+Lw2iLpW zklTfO{s@jC=h=5uExg}MZ<_Wm4q5ieHh{7ZJ%lSl zJv%!qwVgY>_YkP4a8MeqF8K5O9(mf+R=BW;7!7~=tcJ1iOXu0w2e(?>Gi7{a+okVC zKNuyZ$<84Qzwkno1e=X;Zk94$;a`LIbMYkDFmCyWkTH{@PuqcOPQq!|a&QvP^#P22 z-hjhIII!39*Mu9+v)hU8&4`O@lERC?W9zJG?lD`vVFc;o#0; zJh;0L6@j}u;U=^uHaAJ|9LVu6z$c>5_`uWjAT7udu%E%*qszqR zPUn}5bOiUg{QJN;15@s23VXxB-ScaL0=Ok8fYm|zA()~$U?<^{VqW{5Q^X8c+%{^r z(s?B%IzE{0Q0RgH+(kP@2PipM1nzE}uc9HKdINR61-x4j$7mFgZwu0YTk}apYWrW! zS>aXRI|tZq_`bUDBWC-M@WCg%#x)4w#S`kXN6mkP&;G$VIq>=qYW!oS8F3Jt-Lut6 zo@}!oGZUua)GW@l%q*dD8xy7H9QxJ}J?)Work_2#msJx+U#`&5VZrcYh_gxNl;@nD@Kgz1x` zJHCr?HctfhAtf!rN@PV***u(h%-07Xt1o}T^n`Q`_c;XWRInORm^i6?*x$!KL!UZtH|HSQ6!Ed~~2G5qB<`so;FbbzQCzb80fPri_(2~jQqFP{<@~!WDt$C?H~SB zUHO!m5ZX~3E{Cnu6AC@xNqSC3NE{CSJ@u^FMIC&`+}iwN@CTstT}YgI;#u>LT{1uAD8snP_T*KXX`;o1|Ta;&Uw zd@4=5baj(B`yAsOC~&wFUKPZz58}54@%2IcIhFc?nH4MNo}D9ZEVwJ0#;L1bGLzGn zG>x-Y6TU*)BH+6_t{S-UM?^~PQ9#^wX}6lD%6FC3E5?uj-hv{h4sg|~+ME;G_q;fD zOSRdh%ck?3V4efQ$~0aCa-exdyW2r?&;E{17n~nwpOSb5Vvf$j@4-Ev<-pa4FPg;( z>!3Il4ySQ(gcRN$>1{)|WL5W_c|$Z$U9)YoIWIp!FDhbaeT85{D!gWTp5el;3H*&U2*jRB+CE!jr*!y7&-q4#^_V1V=9X0f+H$;3OdmJcYzbM>wB;-157? z-4SpjA;G2pP!KN#=Yz0>7XsdctAXOc2I`LBPw1%b0C_gFw<`d?gwz)t-U4C#0&j5hw{M05@HH0ys+o8xDa$R_j3S)yUS#AK}B0 zRj-+CdzKXE<4Jlu6ntORf zXXke7v%|aj$q)>jZigR&6xc8MJSnN}ie|y2atxD1FNtvyy;LIyNs+D7ZsLE0_Ak7T z9}cWXap(=srzYWC2W5o9%Yt}rkpCG${+|KoGmZG)49_Q;I5ZVaW9ywcN$a3C z7T!BzR^X^5T)MGv>BhpP8w;0i46Y*HFpEQ+RpICj@o{Hu?}xRDQy;%!whN8K&FMGH zLH13*t!A(2%2tkvnFXV-6Osb17Hl;K1q5Rupm9dQoA43Zq&32ThJDj-o0%027kjq7 z4r&}2sBtF*{+}WE6CBtXS@Xh&;GX$r^Q?moe?8hbO;>a#!3`5@zz;huTcgNLaL&HM zX^e2h5e~E7V?-;fOV*@LD-bqKemPDrT#hh;t3BJzOQR#(x~dxZ*tIla$92;3nE zmk`{%BRqnu_ue!YSS{Mc*~w}JWb*p}ne|K{ZLK_9@*9o)s=}%~KGmlCdiYWv(SA1p z(R7XH+r_DS-a-}Z!p+XN%;C`zdRY57yX52B$EkL2n+sA!a4`fdWr_9%@KNCT5+{(M zz4^8|r;T`O(jm?++9Y7QR>7u^8GX>gF^-{2~5 zCHA-1Ca85^;e1G4LY%WC1i>3CQAX7G_Fc1IC-Ew~?!sl)-3}_%9A*2sbC)^X)6h{J zJcjLdN?NYM{yQATe{GH+uK3#QA4rYtx>Iq_d*(w_Sa=*q0qC&lee>SvHi^zNlbkFE zSJQW!uSI_aK`t^RlRdcVS%-9&bVbhU%zL8W?t1p)7PxA*C(y~g>yyszADDxBrn@%qSk&-7!r$5U_&^pNM;=MtC3G zGZx_kaqrg808e(whX?VI&YrG#-w3fgxR=3M03v@K_bf2s%W%)xPxviC{0?wVzan25 z#8-n4z@tb&;U+k^6L1`yvy%kCEl{^SFNlu>PjK|rrVnv8LOk+-411e!K4Q4}mqDC{ zgj>$1Fn38rg1hC(L7e-YkT+q3YQlcAOSHuNK%=I*WxqMubG)aj-*2W9+kWKWl#k5z z>8n$m@#%QavlldkzlH2@k`P`K;A-PXW~rwkMfnckAZu=_T6n;`&mLbkr|R*AH}-15 z=2U03U}Kt!KVf!NXFfK^O-$}}_FOAm=33!0*9w=pR=CWy$-UItPt4wl`w(sdlF5=} z>9G^hjlZzo&Rn*ympbu@xytkB-fH=$X7AqH;m%2xV<+2^aL#oc{)Fe^p2Oev-m2kK zGe0@0Pn`Yg8VyzY6FxbJ53;|)q@Fowu84~48)qMnn+ttf=8=7?bN*)b5Ao#mt6uh* znIDo++ds~JuVFN#%!TlAxM%Er2dEbHSWBzzulm-Tk9n>dpbplX{hRd|7-#QpCaJQ1 zSu;JE1J&Zg<}A-w1J%*PW`h4Kh*_7>NE{;;PAlEbr)dtAfDTtA+&Wt{=cC)QK~CWk z;cRm^a%94(C3VZ^W|ydaTB#1mNAK`OYQiE5-(mc6kn(+@ThNqr-GX>yx1cHMb_W9q`pWzl#L*g**1K0uh$vAwCGk!<}m(8ADayf12e{ zbHVXo<2;fx{9#bk=A-rc0?*Y!7iv0E<`N|-Ex1+D7e`zL1iKh}Y zM!SJ$sMTMZuS7Qt53*~9i(NB9+chJ!T?2t**WkvnYqZyZU88xxu3=ENU4t9Pt{JZF z8aOz1&2Vkk4A*vz4kBRJK+&;lhHJY94vt+jI>@dWjrHWg^Ovj7{8o!-<86p@QC4Ez zyggb)Hkh;gnPVISatdS|BZNPNd(QR3c^Zk$QaGP|-JIiu&m~_9p6KE{x6IK({PSTQ zlY4Z)fpex4fC~H8{2==N%sAV;p#{K7&d9Xe(Vz=(W4FUB)EWj!=W{-9>__98_MPdS zcw<(ay%aGXemH^)rvb})c5@m#!gFxX1PY&kd-mfSv()zQ^zhVTtR9|tV-HU)#yS(6 zF^&`5b5W0sJKIEjWSly9!h9)e+<0fc=z}K6RE!(19{Iui(o>PGR-8270#;A?5w9}o z=f%)^yk*%jE32JKKW(-MvA^ooHDsF_bK1PpqjJ;>r!flv51uyD^Hq)$b_K%bkSqLJ z@R2UQ5S%#{`CH(ua^d~Z6S#;YJO}(Do2#my%>JIO6V%3^%*3dM32}DGHlOH>qBx_yviexr>cL)CxM$xY)sSfQCU)*>r4TRfYCY%q@;Vik1ia6$HYZvA zBkuD%TOG#`q5VOO)ZXIs2AWuZI1A^2Q!aK3=YkQ_iJ)?mt#Vx#p2+J}PMM|O)v?bZ zmt3zFce8Hwe09BQ(cQW|%6~(gy_t6p0$^M9-%!1wyY;7#fZ(4Hus8T`P`i3qt^MNR zOu&N^KuZkhG$%xUEqEUnzXP1>BO+f9&h;1JT)?44D|`z$YeM)oN8UW(@To`TUYC^; zNa*=!6F%F6+St=d_ncayj`g&>?ZEh=& z!^Q5UYCYV;kAkx|f!C#2t$Rn_^#mv09g}$yvU+8In zZBwnp@XNqy`5>I}sR(yDI5W6=X?0~P(&4#dncC0`2?ZY2*txg$r02O?R9$bl16%a5 z`Zs&-7N?W!RL_=Y4Ojl|R-{_n$4c-lzg5*jA!_-parPI2X=^3mf_qqB#IXF<>WseD z10K(b+f;pjYof<@yXrf@ddainc6Drk)t=a5pf!v*ejq#mmkdPGcirI>&Hg*o3j-0+ zi96H*=!M6xh_jE`K+iYG>ejjloCd+wKn@Lyfh;1(3kEsitsP|bj@og%)39Gg9kPu; zUO&kCQs&>VyOeLRb)V<&cd5<9!FQ`EL#*`HgYR}SJ`vuy2q65VN7Y|wwO8*9vEr$G zWC$Ac8RONRAW#ahBkA14NTD9sn|Pm*c8eYD0!~GF-ygwYqx4a4X6ewXr7dtk1D+tWkA&))k)k zm(`Gb)FrSg-?}O4Z!gE$9}oH(A=7aG+si6)rgeM5wXZl+H{Ug2qY+M$-&aSL5u2TnslRO88~C=Kvc2YISabH9zD}>o><4v*9odS9e2=TxZ?Y`Y*3JHsD`@ z%<&_@^MFsjrW)2+{ln|PxhwqhYbxy_DTFM7!87M=;-$&s(6d|{(J@?nhn zUp-{C34Z~O$&L~nyM;G2da{+id8?qg*LQ8X^Mx@ecHZKc_=v?;xcsq#Ftz4kt9kfk zkgz>#3BP1C!#TS)CvPr3W#tNF1ypsc8yTw)S>f;47IoxdYt)d`R2=ni3|0C3i*sgV zCJ!p$P#iu6gD)%P&8sZqA-S3OY}f)UpB2uWS6Qf%|7sudTYHo0*dhpX~Yay$5PgiP!D;?+#omaJk*@1iuT{ z-9hdvo2dGa#+ad1TVW&=X7y8PPgu!nz++ZgJCttkZBCCF0^|bBSYUJDuxIDF7$7TWB^c*zciNlaV8{^z{zrq|t_D7CB^0Mahof)-KH!E&ifPk* z*k6Mi8+C#&p}2fTN!e`Y|5Vx5oRLylRSEeV=+U5C1Vn}mtu||3=}cDbjFoP=`pZ>T zhm;rK#ObahF3wWI+1yx*GjK@~8@Ai)@BV;NCWLGP;)#8Xo`g@rJtt$~w8uD13ZI92 zxBuINxC-LyY>rZu0G#-vPbY9-7oHfT-#3U4_n`jWIgoKk0{C-~huk1u9K@dw z;x~eGl9llIA_7fp;rDPyucyo5!61c4g5>-w4{0v_#o&A-mH_vGyEF72I7a}HzXjgc z#V3~F$h=&zXCZVMZD__%`+>jj5ORc(bH38fHnE~v7x?%gu%i7hd`I%m_QUO z{5U7hCROI)i>O0=0sYB3!nsgnN+rUIvRSh#3M=uKl%0~9o?@>eU4)Mm;)N}Q0Np?! zI*g6brTG}~t{T6_YTY_megtwR3i8EkEbrL(UCx|>unR`#;e_Ei!cEh9lD5D>NXL_r zyGzxtu@Z*`$5#b^d_=h$$l93xI|VH|HM`WvwN}D!(tHqp*()GlycQ;Pa2)aPIW`yM z+t*r&zmZ=CIsMOjPc^y!cfwx_InxOL8TVV={K4TLfV{IUcPes5`MgrmY5Tr2p9+`q zq0S68;F6NU68M!?mjQkDVBzAQug)dS;}>p=)!**0V#DV`k&DDj-&bJ|ST`g}1kyUg zb~_7^Xq9+z0iSP&Zr|N%;{$kX3)aott?GZzy=u3LeDHVl*Y8#t4_c*xGz_X!H4j=T z{d4M^#v^IS2j}QfJj<74r(s6Ly!@HIj(Bq}c?D#g@X^rPuCtPyFJRv98anjp&>nka z3(Faq9)OCBJP+c29WEJp+}@p?_sC=L?zZey<`(N2EOUJOfzwe>069>h*%_I*=T9(f zuWDOs_3zesuTv+zG!6sOX3GLH!P!8LOea223u`gb+yl;M0`Ny_@$4A3PmO%Tdcc2p zpN`81Q<{s%zL~}4=qNtuN}R`_!~U7%>+XyE(9v%RAPv}RAPYeAxXy0{Zd>`cI`hlP*{-E1EJPK##QK}Kvt6!LH6*R zoKYjweMvohMw5@62_pi?aa44&%#ov}*h(l)$T;b^b$F`D7;jlQNvwbC7%t9{sVaCSpw&b54{Z)jhVgyd_(4Jo*Tkg*mGos~<5 zkDokBN1a!Z-ot(&2{E679$S~h9D2YhU}<&dgX`ATFxTp?Ixn@N)Q8)w?8I9j83>MCl>5-T-f1)NxH_W?O7Jq~20zX;@L z{R-aUUuxwyYxYT;F#!BKb?s8CRh$pcmU9aWV0nn(FAxq^WtV1odvh$BQBqtX?_Jp+ zQx?5Dp~vDBz83erY=4Qt{)P<2>kM;Ty6bQsOWkl?lAZfTGO{yqYqzkhYd_0Dic*(*R_m#BWdS zw;S9f;W2-6bestB(5b7TJ5re9uPDBz(4{;O%B+TTjYEKJ$`zFb>FH>kO z9M=@$6Yph6A>;+n}JbDGYZSB3WHGZHsK$o?!IwXipZy8<$m z@wAl?eiWRO;xB(wCvLJ{YCrEY=VbFeKw4#w1KR*;Y99Pd?YP;>?=7VuI!CpiutU1! zfNaNjGAs>3bT z`B8)Fok2+&^U!)#yUA+rp8|LGiRot1fZP<}-oADiwkd<_ERSSeg- z{y4@*89UeG{s~+%c0P%F{+KxZ+V_ypxk-?->Rs$ZZ8>2!4_*CvoVvc;9K&znj*g}e z_HlY-J%)W@?<6I7fc8dG*cZ+|_b*=r?Q`ezJaVhh1xMo4zq@DkYl|EERStP|1A#Su z8swWRt*&j1q`y1;ydRKddl8Tg(EPhfE3rybc7wCU?*p<2O{NHYF!&6oH{=5AI`R6C#ds@M0n=_S3OFt4l4RqE83q6!8jY}L3!GXCJz909r!GxcOYH;W1-;i;n6*lzG42JjDC#x;3P}6vTOb?BNg#b==5>Z(XChAVji=p= z$>%H8>*W>YGdqtipE0v+ z?gDk;3A6h}jS1y+*#$vJ@B_hF?7k$N{=l~+W$}d7!e8dsPPOz>Z$4oy=-lX0!6T=? z&U|nMo`53j=ZCLV?vvK2W=Mncn5iCm(u%)4|F~0)vw@*dy8=k{|1`@kfgYm~eVSR4 zwik35FCJHQOD(Uz4xIBs<2*ghI0`q8buVh&bH#_$24?mq-#8PY#OZ`58qX7TI)dWkDtxS*Ud-L)U@R;93ggEMY(9!xYh9OyQp( znO8M!`rsPKIo`Z)`-fqbWsT-1?nf5R@^!;U?q0g(XlSncPOaNuwVt{GZY-InfsAM~kS$0ODRLj&B;2FgPw+U9GrD|~^H+v2 ziF~hOX#9#F)T(U^kN@5=hI7AHB~M%JQ$#Llt%96Z_YFYydG|`!#_ze(6{B`NZH2cE z_P8A$n7I$WR}D{F-rvY2;9tI1zGq<62K(=E!kMdj1K9+mX7f?Av>EkSJUykPZ040o z$%BLaOZeBqKgW*gLo3VYp+45Yohzc#ldm-vLyrX~g|p;G`#EaFI=FL2 zmbC1Izfms!5AY!_&V8M(F8;O$yX02y(H%}XWt0e{c_rbML!WsUZfU*=iJ?2w^c?Pntn(to zy%6pZs_X@;Ys=|BIpeX2E?2u>u-dc}O51uMF5$o6{=z>n4MmUnrGX~AIe0(YU#D}f zSc&chA++Dy4EzJTP*h`sqT%=6+Ntwjv^s=s`q?RTl~aOs^h;i}a@vcpr=dmjk9|wj zM*c#Jt&95Ci&huERL;G>IALI6nr0+F9gG+`tGN05LHF3yv192mr0z3nBdRns>AM$M>KU$WXv9go|lkWT=zFG;%2Wyi_t zObPU9H;TUGt1+F9&G-WJ*w@`Q<1V;y#FV`Jp6Mpx9fdBsiXq{C3C=O-Ti_p=Zk>O% z4J5yjjvEH>N2c3&=+JUFS7Zf{vv8!4dm%ttQ~%j?`?F!JgJ!$6js zRPcXe%58=pv^V25AP4+9ASVi`XvFQeBOQg1`OtN)1<6QM2P;G(mqcf2e~qS@Se1># zUM76f;*veZQE3TZqa!PXbgB=AYj{+yIh*+F6}N&^fPdl z;1D!Xwwm8rX$y4gm=Gu4PC)8PqIdjan`F&%;Lf3-AS7PRdD?218XW0DC~$DU2^egX zy#P;}99#qFm_3X(>(F^#L*wfCKj;2 za336-1XcuHw+R-kC#hNqy&wzBf6hQRL;3eiu;9QY!AGJ0dnQ=0zSL-ZDD^Ki44Pn~ zlnF;R9ci1bP=721nqVc6vGYg(rR4T^bGwT=kFsP#CD;m+;J1gytA9OfwM~O5`P8OYgT zC6ER3S7;yJXtnAlsoaEAx+m#3!AC+-0>a#8n`A?pI@LM~$aYMVYzppK2(T+?k_B?k zL(!>l7n5u)^jMHmSnHa`t2Z{Gy={hoCXFQK@9;>&b-L>qr6fdhbPRqt+PZRN7m$SE zLFzJGVKTL}4@Le3;-C$Rd0Cx)%}Q=vcAitx^MSOIMDa$C8uGf;T9x<9%1zt|Ar?-I zahQ@=t}h`!V%1gSz6O_AbuTlo__4Yit1fi$`SC%2|E$x&^W)EY-CDT3ZVhg~upMz( zSiJpK)@=x`r7HWzyko!@aLNUphbVkN@jC!9vpm_Lm}33}3!0(kORQuwJ=ri8H;cC? z*JVI9k9&a3`x+oq|DfiN0+|ggjpdi)Luf^M_l}EW#T6Ih8B2|wV{vcrF?2$21DllaEy72tmK3i z&Eo@SQ(r@(r8-{6{T5ucO;#PohtlHhKO_=b)EwEr&g|EGJG{}Zr^6H1S$NsMMZEgk zbym;NzPRDv6iLi&5pTa5$D(BEyx|IcEAF@9lFH_1Ncm%~oXYO%i-Nr6{bM zHvTzatRY1pU5l-up__3tVX>9mZZ&*$Mj-XL5^)Lt7w&u6f46tKIPHcL2X^7xaNpL& z!;u(w5K-X0T=LUF`u9MNU8t^EUO!GrVS~3U1=|uhF_oC;tGGs7oJ~K8a~1q>m>13u zm~c|&^5UsKIkkLRqv-H^1{}*$aH06|Khk}HqwDZVjRNsBAD*~Ek3YMGzouNtud)>s z&*$H=&R^iWrm(yWGSPhzy0lq^^Zkda!x8#be~@M<2+RV}|B)6@SZYK_JvD~~lS z9)5%eTKB>|7%bemJPA2-Ao4>xLLb_)!CR+p{^;lNq-3m{E&_kqV2QI0G+3M0jGt5v7IjShCX z`;xFygg+WS9`0;BRBU&fm7IP999S_Nb|q;m;D$Oi=JoIE!&0O12sm5Y`u~TvF9C0= z+WtLBI;Bktv;|tA5Lzg0X$xhhK+7m8l%~uxrIG@L4nRwiG6kGKW*pe)#TlI$hV9H-LLj#g1S!6*I!N?zr)q3R9(tdVfP%b8xqx`kH(YI z=P2Bj_?`Az`B4FWdV5J_HT=m43^=bK7xXN?zSlPR(|{-Mi^7w69su7(VYtVA5AJ;+ z?i2S@LGefFt9@duFNym^T&k5X4&3U>%v1gZNd44I5LGwxOW~&4Vg5F_+sH0Z6x6yh z$F6LiEWfKmaiv``-zSV86voffcx?VR$Zi8=q`$A5C)3X`7W>m$sBzrqz~YxKV)8ONrRJ8xFxCajV~Qp>Y7+u>MAc8 zGnG!0e#51q#o7y zvZ4$aDOK8s z>KJzg9<*ztdmy=Gv#TaCGF6?uw#O5e zASIh^aW#))j}fWKB7ci(P}~Ak2K{*eEZ^cvwd{oBo-MB2Ir|Wnl0S_nncDYSTr|6O zXov4JfycB}$0s|UG_0`P)QZJEO{{Yj?V`YsQ|k&@ijzu^f17JiE_*ny3LjDXJ{XSP~mGD#~RN2)hkzkHvz6!Q0D;-I;z&Row~$pgD2@mW>d2Qh$vlw zQ#hFvo@`chtd1s1U4pg!-Ri^|$#`0=;~*oU@HmLIYXhG4AROh{#D5FqN0nZHhoxLn1Z{R};Y zxGC$*Zv;;(80P6m9%(ws{3h_mC~pQ&oyGrdqRnA%f-Dso{A`)!Jpd>%lm-6>pB&&b z_*3`G{72x8nV~PojhT4`JY|OEUl!kaU7h_G)6@Z)VVcTPne_{X8*uXnZLtH(Ojj+K zW$8{Jqkd>wOhXv^)2!6U^QTPgKf|njY{dXy)W!V5un6dF7bQqP=w3xPo>9gs-Fkxb z-7)!()$iG^$6JExN(WwE)K^^(2km{%Z8(pDIAliss(n0+fH@LS`Fq0>-VL5QGS1im zjW0z;^tfwqR;3D=l7}+um68t0a=hd)G+a^N!90DYlqh;Px;mw8hG?3>i+*LzsMsbJ zv9b{hnNyIXZj+;E7ABV!#%e@UpnUzr1d<_H{N6?kI}yTP|N z_|F30$-qwqZ)`!Uz#9v?HH@e0Qi27*Y=(YMzKtQmGvJLG_!@j)gZ~lm#){+p94^3k z^diRa#1A%vp9fwq05wD(0An+&2cM_?M#gM>(WIWz;IrJc((f8n*9Hh1Q=18%X2zTw zI<97noDOwT_sjnGhw=1Po1R;;En0;e6ZjH5tp_*)T2x_QVnJ~W`e~~eKQ<*A@cT$? z!g3uG@^eWXFdhMoy+3%dL+|v_xcU}CZm-aLP5kTb`N*1Bj1pLvj~rWdioc@^f2&W zgEv~{SKu86|9H&m`bb{uLYe_EYN#pr4u${|!5gdQsWAC_!PC@(6>>+I{2}n9@o{r; z6nz$cN11<3z<+(EV{t7$Z=W@{0$rTq$Vv_w7-)KFEQvXcj|k(V!uV{Br+p|MjJ6>S zj3>%nc!~#?xtNUwCK#PmlndYba!A-m;MIoNr;G`ziq9CTz_Iu@QRoo+soD|}zL zvgOwIl#;yAodD)}C*Wg4yq~~*0z?@8NjeF~r=ZV3M%hylf_54#FqEv2*!lI4^khI4^tfabD&pAlo!EAwhYZmmGAQ z*Zy=5)qdo~m!jQ4*GNmRo_LFQ&^5{mhum^~PP~24HAH8>5ls%cy69}b!0k!3a@f^9?i66`I4WQENfymNa80&M=$kAS ze&8D2nqz9{t46Q^Pjukv5ofoqV((K9*F{)j8mWcjKfS!5k`Wm$Xl(>BuSw|!lf zY5kJLlSf@Wn;Zd7(`@Rh36$ICR{?g?fcAb|=Gni$x@&Hk3&-mpy6%}3F(6r9y4Mn; z8KuoU%@d5gGmK9U;|s!gx~)tLFJ3?9ddGr@#m&cE)9qiNj_^;?c`<9h%h{Tmhr6Po z0@l)`NUe(!NYH#llpvICOhr@c6F1Ks`Y{K>6aj)2_1kUfsrZ>)J#6zqh#ew9A#=vpcZv z^k0v@=+Ubu z{_jQ3o_*-QUc`1K7e(E(H~mKJG{SWrET{Z9yrZBv6x~$$ljk zj&VcKrQoT6euMib&?V5vp_RIlR=4~WDsS}rO^mHhiNnrPojRHUZ8wX z4yY3-4U}piN{r&7IO9Q9Pz31O_3*d?`U!Li^cCnF=rrgg=p)ck&|%O4(7T|wKyQFv z0lffv2J|?H61g9=9kdN}2M8u1&b?AvZ2zyp`n6B1=N7ANhj$lAgiYZJ9KV8oix5X{ zD=jsjEf(8Pxi-k_1ml%CBMh%}18=%YN46E;n#xKnjwwJwLm2MD3mh1m!DGx+=2liOI1e`k#qzZBvgYYr^yNE^^4~yZRV+)TQtSWgqvD_miDAkslVo?#OTifD$}q6xEY_OVR(uM zlD(-3BuJ65z=^ONZ^&Au6M7%xFo>=0%R({iE-sA;5n+fg&P>5uZN9osx!EiOiu z)tYm(bSGY(fGv}jYTv^CY@zgtGc=hd5RV{aOBBb zP#s9NP95#5diBt;4jLxkNaf+P70C4o!ElX*1JRd+fDM(E5S&>j`oxsYh~-4zsuTCe zlubzMxImqT$P=MBzmNM&XEit+N)O<)2{w3vNVb+0^j-;`I>74}Ih4(CV_a77g|GIC zD)c)TPUGPPc;Q`9+)|vl+ugP!tH6Y^l3JLj*A6s(%0KbLtl}Xx>_uO4kts7zFPuq~ z`Ptyd8u(klQ>NLUe)%WSz-#wq>i#dl|2p}jvBRi-!AVMho1>sjD`S!;z>~4%ch&w3 z(f<~BD7LJ|B;JTCOBgJ#oEln*#*^mAqzj-N9fFV}v!QW8rK3Z6Lpj~Ml9iQNQ(05D zsL_$7d|R*XQvOsQ=wK_G9npTIPuyvbM6mzPzChE9W`*!4vt-I6PF&p(Y!i1Xmy@1$mJ>``)&GII1`%87cjkXDFy4 zG#BIF`k~b2Ed`KNZ%qTB$*H`?)F7)BbMU23Rc-n8jSZFchGPDNGS8&eIjw8gG@9;& zXL?7YYRRmZs|Y~Njd=@{N8y>LsVVs*Q?k`n)Hc)y#xyIt!yLPMnOX;%mWj)WW!Y`t z1W(4X8&B#Y=~W10Czb{JB$d5rF=ti>F1IYpFeN;?O5H6VjAlZiUS1_KQ_3=0T>(xN zcLK3ccg7hhi3-e3DQgvJW#IL|y0&GXXEtU212jA`YnL7IBagr1+AKxLiVV~Z@WTU0eie74m6px=ti+;ud%RK=BRk^VY186l7l! zl8hQMAGIS6Z*;fts}bS;!&s}lT89c zXu5wJ%7Oy@MG+M!|Lp3DhCz!KRW#zl9w>pTgbqelXxeb#whpN@$|fm;E~=st0l!dL zF}3S-t>7Ul%_o&|1Zo>0b;@`f5;-hh>9t2x)O**>j zI++GH(frCrM~9_q4J@BYS%v=8cBVck=kknLTAj4mG@12KrT$N*;?JiDLu%-9CFDz;b9MR4MyL&-Cu$`@?7Y7c}6yvue31Lpvvu~5FO$8#Wfj2H?ohrt)vH4Ex$@!pI+*acQ*$`yNVcc=KP zAw+X8&Vk_^ld>6paqy!P1UulS0oLFz-y1vwyeV+wseygKXrj)yz?}k5L;Ni5R=A5A zkMmZQ1qIqo%U1!?R6@@wT~7zTsX14n!A{4uYuhq`(>!*Fyr`;tNJaImiB%2Rj)B0n z3@MY~rs>vo@FXBmA zqcdn>w}&XF;759~A^VgRhdB$JvW<83a*imk&I8}nk}E3ibT@C!#UkawHhKKa-~g%tD&Z`*xdnsl+kkT{m02S6-w8LT(N4aJJsTZZ6NhSUnPtp`k-os^*qtrN- zF3-{ZdT1EpkCh4Z1Yj0*+uWUobNF&V)Jhu3%kbp*atpCe9=E7sR%NCh?+(aP4MIko z-sWD_dLIDV5x%B*Sfg`gL3>8$ipIO#118P|kPm^!QB0~T9CgP*cXXq`sbpNjr@>P$ z_^A6K@YH28PS(gdKaa@mce_&)uRw?*{R2;$<;TV3iUD`KQ|7ZrW{leH!9&JQs}I_| zX8&=(DFWSJy@E57{Ttv4a&dk%jv*9ae_REGJnHTePE`#il`QhNHmuB7zo?hmH_sg2O3qYbl zfKKX>K=_9^(7McMQmks|v8CfnN=OK@?AI55)EDHSy2{{2R0_-I$N)jSZ>%XdP_x}# zX-;W@vKv=CoY(6E-`(r}Fe*~^-{SR$-Pvt}pDmVER4vNJ2NuRYK5*(`_qQhT-Xrc2 zTA*e--K{id=bi4~iX0AkP1!u^;FnYm$X>9xdp9`^VVELx56I3WkItBaVJ1cMC}JI* z2MEWb?xYNvA6$Booke>;b+a-T(Cjovo(-v+ovGzfjC$0)%&>RN|WB!Z@Kd$h_L|q;{s?DpyQ3JXD$fC(Q zO(Gq9oE#q($k@WCpd>;uU{NQ{3g2VV*^n#_7m}@lg4)H^)#@ZR#6vD+40%>3`LvM5 zx<*S<*07xUQ5Dm|#?c=FTB_oo&$^rV)kO!^GJhWzHUrdEr(BiKCe>iyI>(Xrf4AQ0 zSU;^cEl15;9$jLyD3c7(s$SNWIlDrvf4nk5%-P_!`x~f~%V}lksjG5_tqT9gD#@rq zQ<9Yf7cGMRCbYU}`aeXGK@}|HQ0tKt16_qzu&8~(-7;8p!3ClNH$UM{K5gb2T$e!e zYWZocEmz%Ajy4MA&xvGKWf@lCA*&lT-@&M`#8KDZ>S`}!Nw)NVTzw-H>4nVh|5dxv z#Gx4f-)Tm*YTdke?M>-AWDNz|8ZE>BYHw&=YBtrFVHAuU9ld)8eA3#VkNYR5LDx&i$f&08jJy z$&(A76;xo}NV6mL?&7%%7QoGZ^#Rvz_ezsC!hNvE-D?chI}P6QLw96B<>WBmFLpUf zjYhk8R)ZsSX5m=s&}A{Us};lpd)K$zk7`L^Qj(rVzM;YYGBLUGmb+aEWEh3a(_xdtf{=OO&0sT5|+KE!onU1 zls{aV5z+PUrbyJCs4Fi=ZeiG%AMig~Il!vVx%X?)R@B$%+5BwvXU|oFW`pK{=7Op~ z^FZ@K)u0+sEvOE(0JIRa2viSh2z>V3;-VEPT$Br8Mfo()J>T<#X>d!-T*V665(hq0 z7;C5FRy_V^ci5&H&vGP)f{2F4+xcR{oSWPU%~w0>rOjqWcTLp;4G z{G=hCd4u=8S}3n}rJX~PXMQ5ww4K5{9pfYwaRGY6u*h(eUJ(&PJ@aY_r@!}KE0in1 zF^j7!-QcqfD$RzQ_OZh8&cI9PyU{TD9N=Rr@ou2XQ)!GRH&SfAy>x|T=Ie#(1*C9< zSRQ%E3rN|6EsuG&JQ9?aM-F)b=~r)rS|0P#@{qr-$P?{VQM<~AyBnyxcIbi5MAIMI zs&?qXvhU48Q8N#X3N@EfK<_#5`wLZz>T%|-!)~={mqVH~O`$1PB06ntp zM+Bkmo4Id_T~5#1gf@E$hb8eLBVPhb5TGdvkXS9^p1H1Mego<8%SO6T~?!PCB^0WB zfG2$`YUGQ+8xx>|t5gL`m$qL{TZ0^NA#hbrl(;;t{EUy%akYx+M=Fi+uMdm=p)mfz zFun`oGlp*q-dMmk;Je{-S3P5NvyD-J?ocuEbbJBMza3B7+3s_o zP);2N;z=*FhU1B-LNYN@bQ$C6XE)}dM0m$|hJ-+)#Cu~ruUc+Ah=J)QS5>c{531(+ zD`Lw8G0zvNmm(SNG+l6)fp|0-OG8z6u zKwUta-xu4*d&cynusoKK`i%S-@OZP)P>G-5GvZ@K`UFq+3?oFgBbT6v+K7+Cm{9J? z7XO^!nP!jqKplKPfKU^81%Wx{1JQpX#-UH(H4`w;Ue6vDUr+QLi2dPT?TC17 zk|$%PxA(GsF0O8n*Iip%}HbIHi23 zCO8Lzvq8+yg`2R~kVqAt^FZ@K09cQJ%s0SI zSdR}2mBny-Kwgj!)Ch7cbHtuKtPW)hAcG!8smIeKnw%|dDGH}}R(AUkJgqVQg(po$ zui=S~0bkNW4i6Kalu;|5G-A|$C@xR&{L_5jF|lo`XRtr!xY`tKcv8kw@FbIW;7M-` zvhYM!lswI!YJ&4m&CAG>br|_2Vf@lC9_>91^ErITwP+X}y)CYjkI+b#iKWv#b+H3J zQl|*RKN3Gr^W?Ri2EHTm#lPVze}xUdH@V1xw{RbcfzvS^*!hugPxs_aKBR^H7*84$ zzrvF$h)(oU0NclEnZy0L2bHYd^g?GC2b;tld31-NgZKr|Ws;S+JS9Loeed(8A~^q)Ktx>#iX4#*~h#@5wTmf{q`3e>sLUW~jSenx&} z7+)C1uL3_Cb7fr0;>X8-*iJ)26aoEF4cq|tji8%Agv$m1{ARds0pZ?a9Ip!vvl{ps zkTD*@ZUt4>)y-dwoh75+THxy*Qf)mGyt5kez-5coqN9?*8c{V<3Jw12`)e-w{;CfvXCGj$QcKY>dkY(9^` zy%Y2($cPt)@zgC1M1RmwRZ*QQ$9w!RGBA#Z{EhtML4LRtdLjr&o>nx*08fVTPlfSM zWB+5Yr=)cS<{OLfIslU}Ebm@BRj5otNxuiRR)@vcPKk?dPk|ZF%u3Jo=543NdOQ=Z zo>rG@H$XGgBV0Ybb+%{9m<4AF<*jz@Q4(5?Fy94yTLa$*Jhegg?+>0sDk>^k_n5T;L* z==$fVWbw>_(z_EI&W0|%!K+Je_TZ&A^StyXLAmrM2Q9r5zB?DX^#1OgxLW0zJ*N6! zswN*ohH0c{ejoTm1OEy5t_J>n@HE9{`J>=_NItM@o~OWMuKrix@_bLcsl_go7)p}# z0^Bcx0+Hg-cf${)zGU!w8Ezy0O5pbz&)e3)%`dAXN*g?ph%&gYt~wLXuHX?wVZ0PC z0pA3`Eo3*`dq8h#8whWcF#aeG?W>6=E(f;xJQK_bF+Zv^gZ}?kN9tk!-n!J2)@m+T zn$y>#Jec2(vQiUcUi;8jyzrQ(#*&;~BsxCssj?h`W6R^7@s=xaeDk>H0sEv5YJ4vt ztV48}T%4{${{>{1r$#K063w6V1(KuUFi#s4DF&WC^q^TG`*U`g?+(rNG5FJO z6w_jq{b}`XjPERX*sos~I0vA!ApqSFO6Ns5f<>?(hk^HirwtAEUk;w8V$7cgZ!FN> zF#luVZB#=X;9mf!aex=&pYr5RXODw0dSgtVfH$h57@kzqp%)^y*CVcgzcKuMVC=NR zn-{P@?fIsOtc+jZ@GP{<>|G>k-t;U?Jl?xVe)&oTBqIPXetgrDlD`)@?- zJfm|D8lpc0_xlFf!(se>u_>a=ZAQ>bKbCeC8_GQeV&I#e>5shZ^=z@MhXWsp^%3vy_1x_5G(gqRe-I5RpZP0c ze0SKb(Z5?5Pro%vBOQmQeKI3o51wj({pm(DjC6h-umd1#U;$egPdkIg48(--*TOPP zJ+o2%pWta|<@o7~DLd`7G4Lb+GB4)o1|n(*%s&I3)+XS^&F^~d^d}b;$*pV>LWL;I zw}+d^0lHX7i(=e%30Z{y%ag-&gP$>uLEzIt>`y!mD$EbY8cF7kfgxc5t^-e{VgFLN zsUKl}B-|MWz65SsO|btQxV7-Yw9kWYSGCgK01snMcY>$=NA`abZqf+zyWpm=1H4$g z&$Geu=fEQI=wqJhn2K4LdsPoA5{>&kJ^gUVrb?xz@XQaTum*lL+!P=CZ-bjM&iq|r z{4wxd4E~>l@h4PXp@Re0UR=03m`_>V16mwq)+Bo!A(OZ z^EW7B^EajW9duwUJSm?nKs8F`1TXd+^rXrp&mBbC&Y|cy525#ZZD?rk1zwyygwb^1 zup+VQeNX;$IArdeh=?kMd8%C_Pl?l;X!akc@q_4i9D1_(Hk%i*n7~L(5Pf@PC&f_{$7U()@cM zLvuMSGSnd5SWfmpj#jb_&!O)7-76cCGmcIq85BlafD% z`xDR!&_2izb`ekd>#}HZeZ#CS?w;cFKxr4Td;5)6@#e|WCjOrxKy8_hskX=S3k1dt zNCrL+w~@a9p0IJwBIQdwzXE*?`UdnZC^HK;vg64$ei80VpzlFO{0H!tK|e++vqL<7 z0{Cyx&md!fU%>wd^xrW23iw|^zkw>Mv2WvUbX;GD4JL1;o5Ir{+1DuX!4Xe8OKven z>m!~~mNGa79rfhr8WZ^)0gU|BF#Zp5-%-y)JzXP;6zbeQz_f%k4{LYL$I}?}T3FCO zh4({GySNhwN<+w{5k=yG4>77LBa6h*57Ab;!tvvWo;xjj;JEdeXIR|jkwx;;XaY_i z^Hf+GONzvR;|O#=95v)P0>?eaJ^6{ss3N(=ya933@NGl!&K>vk96Jaexd0}EsE=db z3pX`i=Be|c!Ik-CVf+g4omBro)kmI4i=RqMnkAw|i1t0I)B?|YOu$ECBIBx`Rp+h@ z)sPu}M$@u@cVyyMlq=-9NYlnCqNG_C$$(z%%!_|qDDC9G2oYMK zv;;*!P24)^mW?P-GzjNJYv^V|zS$sWY>^xsGQ+~eK-LPPGX}=E;=tQL_AnebW5p>= z0MZRuWn)C2&#>A0z*sTuGf$p*_gJz1Gf#&3=dofJc)w#@k<8=?=z@yPJpDKqjl#_T z37)Er`8cSRtdDuR8OO-e8Kg9W|0eJm241NAEIoo%02~H^8^R)ZK8$}ujX)3oj>a3C zG+han5GC%v;7OWWJF81w?JU~qag0~%W)o6F=NHlmBqBr-h-D7IpRCCkYjgOw02#5C z;FD!IG4QnKy1eI+2F(m8Ed4=y%2{C8ZJIUTaXtQPpszLxVu4>7FLs^w%rGZS5J_h| zW6XC?5OdFX3R)eRP$ct5od8A|h563P*4f3$;`kX)3v-)^;^G-kc5KN+wU?@xC>)=A z+L~8R6azo^3?4&yq(5qgDacdP%5Y`s2#}ItR3LngVI3hpbnsppbXH?iQ@R@ zp6u5BCl$%1(oj5ULNgXmRDkRyQ_gzE`+Wdth}wyaQ9~$%21tixDyhf40B(U z2|f$d6ya!i%7(jhm`o1%Tu{SY8c7@rDr&3nvtMp;>8z(?^FEV{>1N(HS!_S&$rx}IK^#bHd~N;W1q^Ryz_XbvGkng#+td)_l8);YaM zzInP~x)^!^jdjO#QGEf8_sDdyo%pNM#oh~^Y;(>GaruI$&|Ee{bo~u7d&m8b##IT1VP~}IOmX5X&l2m(nX1{FDKXr2cH63G;rrT?koS`2@v9ae z^R%F&eDpw?oPJNKvgT^&&1XC@;uNAVCsl~cUwblQCsn9D7I?=up1jyK;M*Yz@RPpr zWVhN4o-8g2Pii*RAR1tkDgxWT!S11dVrh{w9Fz}g18N5P9fR)opf5m2Ku?zaeRK1~ms+LDyVG$~U0npm#t4&<@ZF&~>0(Pzz8j$OQT?3iB1{ z2q*x06to?*2DB1XS=zD)A8@+mxr1H?t@jSR`JLyz7&~EH%Y6d3|Lo~)@+ZzlD+k4b zOrT#XiMK)pfvpj=S8 zJ8<p_j6*`V>D-k?^X@8%UL zi=q0@@jM3F3wj204`?-LA!r(CBxn#Q7u0qhRCl$iNI3<1AM`4SB6$?gyFg1pb3nzQ zE+7Xe3iQofWDG>I@8J1Q&?b-qybI_hvhWOj9(clScs zzQyQ+Tk^%VeOsD}1HXEjn$Ir`och)CZFEKf444-){ow8o8UQllg;8RG#hbL%>}?zC zUV<(F{eyFf$TWMWBy0vxT@u~*FFWNW;tsQSu${uw9}T5#M4iRkJZ5$cUEMfv=~j!k zAjID*{hKbL%?)M8Qnka%Gl{NdZ?af$aa64N&{DA(q0BMM#375fw$+?vMRKyR6i=Eo zj=+;r8o5l2i}0pRehobJVm!T zzyES|N;?`+)6|yv3b-jb=4ZoA(?sU!EEvt!nSTIohk<_y?v4ij9NeT-mcIx$!Ut}R z^ga-oz$on_s#1aeao!~+^Vc^8Ub1SCcB6^&5|tB`#9N+F9P zpuhF-$5KzZ9Z$ri+ z-2an|V~v`>0!J_(LxEA}OzBZPWanjYj|PnaIp}X`Y))(r9*#WGv8gx3PQu(E#)^?m zy(7(!t`XasdNa&d)`;Cry@j!vw-(70m*8WXfnN~h%bIz!%`e?5mNoN!+T0k`I7B-h zG(pTy@U|=5w^pr^JPhMBV<1r;(TBrLzg|4M0@wJ%k7buYkeb@QwPIg_H!rR0I<*Ss z0wXJA{sy>d-?-~Kk(}rqoV^lqq|V#$Ov4ku<29$!fs-ouat0?49D9M&r17?O;-*AY z^?C4Q#lNi+FD1eRlGlriiQem)m#o)j&3JZ(zcd%|<~&cjn3?3ADO`8hqQsFT??25u zHV9vHZ?`5VHlTxobt{gbv?P)fjooBl8pBPwPqMdqOv~ zzrg$~ofkPRym=XSAYNK{O$B9un7{bK8)7C*Lo@5DQ@Fe}fze7uJK^lj<2{@(k7@kyj&*6#eklf0a-ZcAJ@U%vcMw?0% zM~--K4AZt*9BJuoYwo&PTyE*@mfdx8k?bLMqFs<3)YsI%^+J7ZJ>yx(Kss>9mn3`B zx^WZRg>bZ5VxFHIt`^~j!{2?gxIYwIdvA|QIKNfhk$DoaQO?hA4eTiO&a;@|XgbFGhKU?U#(LYDLV`~b zzmM~#=lyasrWl~-Ka2(a+hN#00qr4b`PO8z?Fk2Vg#(YMfY^1HH?!k4gr#0F_lzmSHWu5!O{O?y zJ?4IHY7zgc3JBBP-Xwop_|W`cCiDGbn3NGX7Y0~O>r5dM2&veXufVbl!8(FTogHDd z#dv~1k7Jf(+po?bAX7S|0dq(jsqe;QTZ^WtA`-}ru_?B%-$cKSXlZy!-4|oC_I)b| zbR1@FrO2|4fC$-W>VX)wYz*Z5Moj>PA3MblCXN-3$UqCwIl48DZPLf$UIyOeh%`(~kQ-X6M@Z1Q` z+-y^_?b0hMK!wP?#ni@n)&O*Q)dc(8^fmfggrTu2cdaSW+F$@mlOiJ(+jbysh>%Wm z*O_uu8Aeo@L+5eAm1Q=VT3H`g0nz#)Z<~x~;6t5z?q(!l8Ko$@0Z{LryTxQxtdEUV zlyl>qV){egPL*`yo%1{wV7mRpob zD`UyeHhC_t9)*7n{AH8>c9|&@xM{fxbbv&W&1|<1#BaVh5rpQ;h1m{UvpkF9XP|vg zOQg-$*`iAfh%`sp4x?)%3EEg3;4#^(uNi=jonxr=EA|)n;Djcm$VLh~+pP~7_>LD$ z82)UZ;jmPlCQ@WaW_EpmUqC2zc9Vhnr&w)|sDR}A%{L|5zQWRngY>({WVM!{$N&P~ zH@%;jEe+@}N5ADwO@bphkkc4LJ~zCDVR{98LdKX)0A#)LFbyE^!CT(urkTIOYZmg) z^>BU;a{USZBaaGrNF^T#2VMsd<8mr!C91?V0CoTa82C{I#L&Io%)Ue6W9Zy%@4@WH zX_!oaCKC+gOhdz<$pnDF!+X8aX3KP!Q#}2yH`PBIfq49|{i_;^0nmceBrSvhpOIQ1 zL2Evl&NIlc5wO0CMoU15zWe|}^u>S}`JT7lvIe=?^PacGBz%k))Bq_h1R$k_0Hm}K zfRwf!afB!hfatOhQ-xz%F0>I*D(wpm)0M`6t~4FcW+|AbTtpya9UsFxmT!KLZO!%! zvOxZNRg(ey4qyzrcU5OpFo`fg1q%VFU?Bh%OeqU17yyyAAJ)(tKH=6dT*LH&F`yR= zKw#~DZ~u0E3-i^Enr(K+)d;2Z?ieL*f6~Y>uZ^YA%73e+*Q9)B;LoqU(@d7x`A#w8 zTa3=+Sn;j*lBE%j+V8ygSvJDa^rAP#axbKFE_z=#S)K=U@e-t8hQs!~_kiVXI8J`= zU1#an(<$cs0IxDQR{!9=-7*c1)XP9B;TUk)yV^3gw=?kGWpA3Xm*@xftxcHY&wNX7DZm z7b25&LRJt0kQIagWCbArS;0ZX5n|o|M7uv=-sb*)wSp!Zrdt66x)tbvZr&)YtH`Mg zW}T&D0vsi7* z(FYCZVby`r=3Pwq2(Umtx5`BQn>Bhomg>NwDUR*YiMAvFvj9-fm3L2cp>-{y(ShG1 z648&NRnOJpks=3zK)m9Ji%3wcmc97GX`nOk;We+*q2K+c>($it^#*~@YQzpQmCnfr+u};Nf z%F;B|XQ4^yf!+$yzdiy-ci>4UdQmXj&sbi77b`5jA^ywoAlpzIyR9EAq0>00(jQR9 z{)hzY8CXId0BI}P(aF}fSZ_~bpi8vf=0uQj0HpEcMYptmiy%56jps+$%4CR8LU|-| zo&i4)X*`N-3-3e7Nl72T76Y{f2K2VT0JjC=9TctB7GP#zxG9{3uN-~3DG)%p;HEHx z+QKD(A#LFo03mHb2lTe^n--DY78nRNg+InQ1F4a|b!JQK1gCgB+Lw}(IYBL-?E|Y4 z?FZ9taOL0StueRM8$moe!rdX8I-^)arK7kW`kZfZ0-E0{<$r%tn<9v@WW-kgwiRH51-r2(J*~f zV?ZC(big>Ot-)?WogKA#8^TlV*-)D%^b5>qR*a)6%oZ*hi`)AJvjQd_oezj zKwL8*)BSgBL7b~KDMrBl^h%sOG-PzbiXcxJwXHY*#Q0phSqeztiEfJZE+iC( zRc7-v-ycmajo58z-re_1bl)<}^Q{QQBkk3u7R7QkS}FD>O$qZFnjWoGk=NKHHp#uk*c(>h?HAvtnN>|00hXD&aO$Yg_z$lcEE!m?Q0G15n!{GJfkj_@)#g zXmg`B!)m_{9mUPy>6JlkC#$uuftTiP9}8p?B&cPP#0KP@dB+=(e%YB>t4`qaT-W-I`3e117M?0LboSS2#dxU=AWBXbl_!&>GkXU=7?!MW{*Zd;49GZVUmu zX#hZ!jqoK|`gomzIU{^GM_4-eo#Ka5UrNUaMEwBgst3z6X^k zfjC(SKs@Qf)Mx~Js2J88Or5NI%ke&21ELfoDG8Ta z#(s;R(EPs4SK|MNCX@S&LvE2WFSkhTvH1;xd(x0ld9YN$y`}oLY>y3EN!a&DPc+aBPznFv> z4YWetPr}Iz>jc;)^LY)h4Ewtn(xVXz=BG-+r_F613~$WmMa5a|mk|X6`K_#2Y{C8r zpk-5D|2Vr1tF0iwvrLkpy3q$d0%QYF7hJY$h&L5jG(}Sw*V=kL@}>hc&RM@h-a0^p zYBR4WuA?pXJRGZF#vKV67}w0+{VYrzB6RfPS&!Z3fJ8qnNZlJT&FvPvp9nDtz>SMTa0lr<}n>8cB_Re8N*$AFYfcgj<^$`rvSZY6Y z%%uDS5>#~!vm>qhkDL5D&}O!o(!q?2I^batBTGrhFsmIf19}G>0#FAW0#FAW0#FAW z0?_W~u$vRY`df&IffIa5{!%TUvZ^RYI|0y^rk*1P^c;l%l%o)Uaufnkj*NiZ7A1fh zM5;a{JP$<9YKcO!K`=5ADXS4Rc&Q6 z_z+uRK)029AYrf-h51lZ84jr!s+a<^`f{BCy<#MQ4oclrqnZg3p_&N+sAfU{vK0pO zp_u{w<*8zwhz3)pWjcZCf(+*|05BYXFoPPRW``ydApqqs1fcwd0F*x?AT5Ug*_HA+ zffoQ63ReR z0X8WH*rXmo2%|{_z#C19c{ZtR3}z59+7$D8R~300tHG_^xvhD~7sk~17(w^FF3`cOMRo#zrGNW+ow_B+@0x3lwBDo&h<`2fm31(GrDh}NI#ZlnvFd=f zVg)ZIEcf*-$P1U$0Zmfpd68*-=@KrmLHPa4eY5=!B0Q=};Ta+egH-Nwhzwfa~ z|3P$GbRbRkNsr_6#)mr~u`6ny^c_59pY*G_l^o`Dfcqo{xKH{XA&h;}HSoqhiFxjm zFi6B)3+ZeG?P!RvLrzvLGORQ?e$6SS-r{TJ{1I?Fs?HcolJ%D#(Pc1T zH{mCXlYYYYI)7>*7T@6MK2x!rE9$d92J{jA7DyOJ zbmsLDU9p|Mf@vj^pq7$gx5UIx+hZX>Ok3?MNnZ&cX*#cD$i~Wi&QI3(67&S%#lh9S zJ{>k`f_k&o0j;ru7oFDl97!9MVtFG>|k+l&(1}bfftStnf zhHC_*vH1xhqtWN0odAS1Tn6}c`MXFu4?+%3>1Agaux5`6Q0qy3DoQ&Dh#&;WlVEtt zBG~;FC;^;a20H*sUN1ukKxGI4Xx7Gn-aZ&G<~RxQw&i#!$0`8*%aka~gpm65EHj{I z`520R4CNR~Ic^E9lP(CzG{zhPtVdD=P|eAR4`9DV2c~w#t3n$kenL}^o;U+q;Hvf&hyhlR^=%YplU7sIDM^jZWsSvK(xt`-2+(EzjO1?$5KZR6+nozp+ z2!KaWjs#f=HcPzi_r-Xv2NAg$)X8G9(Yav;r1{giVIv^V4Fd>#xxv@hWVy*w97x;b zd)Q=o017^^+1IA+FVH8=NO-^5-6u+U35Jq%q*+8nv545>tMRvuC=QtnF&~@^b%2C% zGQ>PjhIHOI8R~&R#>o)#`eaB+{u6(j1DCh>o-kQ%``j70?{?o=bGri%IhD~SIq@*x zXWkd3ly}C*G6nH8gNxna6!&iR-8#>?BXkDGd@$3ckT7PNdCs)X8#6rvfsC03FSZC@ zQc^WM$gl%P6O{POS8!L^4rkzH;TvMIymb~QYqt4jTm6-o<)h!ADO1FKZ()bVt`wV; z6+o%kWS!5GW0%hBW7k$l$i18M>U#VM@FDAQ26Tga84^Z=lYHR(gT8)E{az^kX3oXV z>Bz+{{C5}72|$-kwAwc!S2{n{YJch&HkaW~rkK@D&BMpwL-N3Yo`)|WVa$WZ`xV{l zF;@Nop@p0o%7;w6d1SHN(Ojk_-VVGmaVPkY#2L^N9}fv*;>@?1-AUWLQj+Q*6M?kZ z_{W@#R4V&G1?4FXk;Q?byL@>j|MRyymG@z7EHrFMwBqQ6SwVsQ~K_C`@KE1SKA|3+JOpF2j{d;o+ zi9s9~WND_W*xx`rIh;^|$@Z*)mkH54mIWm68Gw9*&^Kgg4rm1AJeC0J3ia{6KY)<& z-U1}B^kv`vNPkQ0N^FI&T!2RIj8dL|Fj}eY7B8mZkOTZ^dk9*RTA2a91@W3zh!4?9 z1%ME(gaD)!23RY8r5a&0wIFI$D{DC+O)JdnS_uJ2E1M7^L@P!>YK4Fht=tVjo@3PK z%0L36cl&;~SX}3DW@fLiMbC-n)S-%ANYg8N=Ji+f1jHfV@|`2SqQ4$N@80WMSJD6< zsder37xO$c>OAkBQ1Rs}`Wq3l6_~!cCQQ?ty@MDRzJtuXZ^#TCQ(#_ZhK?x^pl61T zDV#vi*WSS~g>S+#!#rmOyga6ma0P-n!L&#G%PAgs*Vn>7=3hZY&=COU^&{k6;BLzB%A?`|k|NUkR#uEfA@H z`L0{B=kCFoN?_C~*51_2`pR2DzTE7B^&FtU2ioHWE&b6D;tfvgT z{Jf*-;Z=y}dq{6e!wK_42Yory_agwUhx*+X)x?%{1owe4a7R=#TN@)lA00dkv(Y8! zqXUaC2&k{<5t+5sN2qQbuNi;Hm*qc)80&$`mQUx%e+MubK(G6;$4du@BS(fEzzPBA z09FV<2e3i_I)D|6I0kSk^icr=;*UeV^uB}OO)Z(%(DY?NsfNjnQP0Kz_iO}+$?yC6 z`)5Klq~}?rh1EMA26+9Y*ixaI^$?@l>r-zou{AXSGR>?HgAxQ-dqLk6ge<4u%~36E zWdOF0baq$kXf=-N3{epk;3|QL3UHMG5W^4qoWnlUeAYhP%x*?d=IN7?Up@%(`X?nU zpnp;VAaMM!?<14t#917AI^t_R?BZFcG9Fp%n+@xK4AxHotp<9&W3#8g`iZxLXX|HP zT0iiF)z9IK{82>pkLR57njRU|i-?K%e5ETI& zRd+;1yfG^9fme_EW|}O|q5Elj%vaOWl6wl@8GehCmW6OU_N{NVf6^(n8{sW*=7S5U z8IUk8pqS^5S?7%ls9FS~%<&dD^TAc0V*To%NolqWg0!GY84zPtn(aik_I!uV91i)J zbIOz$yY1*5c*)Jc+8C>C(&H*XLw!natiw7QFScKY1a*ihP80Q_O0$CiV1nwz;XA}3 zBRUIo5Q#k*lOiJ`K<0oW`uUVL9adwq?Lxm&c-kp{RV3x<7^`(Bk{<(r)@qTLBa)HU zePCbawA$UNrL_yFOzTH2(*%U1wGTir)3zsY7QuW5JLCnFLxi%vinKD$I0F|h`np>z z13z_&)|Y*)ri}koJ@}Qf1c%p1KLms%MLdBv0BB@r*Wc99<^nJj0Ohq^p()v#cgRG55I_3zJ1&P$0%eQ}eh$iE zfGWaz3Hk#Nxb&m%6N}}o8=T_3Uwr?V_s0!tbZq3z2aVivW2lic&ql8EMk7x^Afu6k z7l;1i8{qE`j~L429}#VA_aRS1jX?5llTr+TCZ>`1SW>OiVZ96>NFlac6JSE4AR}uq zHqvH`Gy>cxbO~-01SI0ccCb~H0}0kTV*WR7!}b7dPxEpVon^QB=?$Qc&>KMcnZ`26&?qC%!qR6NI-nnyU1JoX&omg2 zuY=@Q8XF)It;UidKL=UG06qr+j-gT9a>X~z|2lBlZ#lGYNeG~j+5vi*r;j)=e>$QA zdY;ZhM9((miGg6AzJUnYFP+Dhc{+6?K6w7sx87`-dbo&4{-Df4t;2G)JH{G z<6U@z!a%}W8hl{}Z9m4VB}gsNQi`RS%I5Q!IGw)gOYhkJbEo{V1v!w@1cZQ)2?zku z@eg0-s7de%pL)pF!{rm=ijDM=L|C8>fw7odXS*Pw!r;WYx< z(N#b|hzbCRP1k&xeeL)BRRygyOjiK|x(WaUaQNdajO4I0aLm-W!(@3xIK>i6V=Mn_ zI9~7~)y->oqyEDs+;9tkI-8WK*!;h5wW1sV(2sx_c!A#gNt1F4Ko)?=Ink+#)$~11 zTx?SpV()g!ANxt!YRo5ua{4ka)kQhywqYkgrE)xM_ zSY+cSOZG9R_$0D1)t`S%%k4*qelD&8p9$b8D&Yxpn)OD?EdV(xZG}YKQzm5@01Ouj zrEASbx&+9cm(rz-+zp_CBse1s=ow)^)JHY;@OM3~w#s%ryVxH>W7qlV1Fc&Pylnhf z3*56A(_e(4&OGI$IaQvv?F4{~3>iHaTca8RCpr*>UK((;FF_)U*p$*G$3V}Da|_Q%OFtt zVk9lst!3X}5d|UY7gO%RoAUF}>IVRJ5^yhcMp``y;9de)s|3X65&|v8l3E>TJGx3O zAE`RlRSH0Kk7>;D-wPi)7h?U%lw`ZIMp1O&3sZvaXt@F4lgccipH#NRLSIiJqTZB& zKg{WJ%0K{_f}AoWLK$ZPP-Gz+oBC z!vYYI_Qs(}5gY{GvZ@ez|0(?R;&VZhAOnIkb0BQ5aTBkT-Z|pJhpX;2;QYr-Z zCOW_wc?J>-A)#l40eUe2T($He8=L`Gd}IG;%Of9S-P61=-G3ZaA2RP^K%IA4Gf~qA z**s|WMia3U0BA{(!V@ta;E9+H@I;IN+JeznC*K1w$(fn9JdqQzKY>cK=7|^sJP~7_ zCt}R&6EOyOB1Syz6VpUY9{JV*%)_jH`p7ow6IBOv<{O&&Uu2zmfKBE9$IrQEX6`*R zcQN~z8H{DjFpJ#`vTyf}gcfT=$x?iYq`Pp55=km`DrG{2R+SpEgtTZ=Nr{ruLfcnK zQGN4!f1Yzb&pl^;^9T3ydOpwgdG_Z#=Q;GES^d-2hvsS$$aztTU4`aF z3=;FAa;Q+ZC*Mf5EV= zt=8W38oGvMt5oGNP_eujksR>Sn)PJ>18NNk&_a&@%|hh*l|VWHo>;yCKrPO;e9bs) z&J~)-^=lK5N+_A@SAG9ToV7e0tb02z{I?d5!ErBw5L@o+CnhPAixAxUWc@KD;6XT2 zr`GVX8gfNxdfQ!!t2;mz5V=%sFK&k+fC{fv)Z!+eYi&7?yhRDVw>Qy1Vzm-DJu`yStZ zygOLezIphoWNpX#U|mkD@E}c_iF++3mWNBSdUQ4oRd^THX7n@+z^E+`myYiX7wS3W zGp=C(!eac|00Z7r_3m2_{VKCo6t2{Y^<$r)U0J}}Pshf9;u--|IP3--m8%GM%<{~# z;$NrvMEn58jEZn+u@5ee_zM6W@dFq;D#GQtU&4jjLE(C>6=HaSel~hMXk4fWmvpRo z+=}5jt*d_MV^twQ0T<5K0*Y=RiPwP?6M>3S_zQfFt_-)(u6iP9EUXL%wU2R&$h(!{ z&8~R2cgrn|4nLu=P zRKQ0OmZN~b2XGXy15g1w02QzUPyzphFsuUBRWCgg0Wn&4LTzDy=y%~HtHI$XURrTk)|a}IsjSH0mzcg;Kk8Y9Dv^L z9|a9+GSYYq%CGEYT~j5AX+3dI)1>;|7)YA~)XnJ}cB%2-&;o}d3hsvK0vd7a%s+7G zPgdYtXBfy^8yLvpi~$d4BsWG7@}`Y*&p_azEag39P7L6@Q%I!#P?itorZ9LYYX(3q zS`K9r$f2yn3P%oQ3=%_GYpBprX3VJ$->5};h??Tdeuz= zu5M?c;izs5oYk!WQON4H7}c!=KvuW(x;KK#??@QB>ZIC>PN+&Mogv$8{Lv-cHfz9} z^^yl*bnO~0A6o_&M{AIPlh+;^j^r_LCT}FvWb&vrOnfs~_gdF*s;bR;5(~v{82w&( z(llOKVRAFQ=~b!%VB}pC?vv$v$~@z;)#~YbNe3{tUleYV zH5+~?VKOuT7-s7}d@02rNnV3yqPEpz%MlgU6PQ}Lo7Q!attB!pa6lalG}`6VW~ z02sxT_P60N`ITQKz>H2l-8bgz1X$QQ-Pg|M|8M<;EEvuS40NV;-X^o zd^>3T(<@whv_9!bcr<#X`>b(WCg4Lk3m?*nHB}<=U z0%Jk%aN)=!aKZ8@F}ZR88ZjJzMhpj_5#vjQ;TSOhjNf~QOXE53nijE7u3B15jvfr; zFd#u<=uPi*tu0?6%GV3nbbJg{=Ie1A=y!=L6_0*a_X($uJOL#~79D`H=m3;O2cRsT zL>P`N0vJhs!=+uC;2G#*A7{Qvr+~!Eiu&#`Lr z(72Q@G7pV=YR$t3d}zE4WP08pC(8_YdsgvnY~WHtP@|os>agycbtRsGL#FYqdRwmV z+au^dWYEr!HSlemi=GlP?SyrHIoUhyFWiS<$<&m64-H3`69=J{bLTbL`ke$Ux$+=( zSbTdC#?v5;ghprYi&*KfEW&unrZE54Wbfnk6#U&@#~0=i0uA)@cQ^8HKpeXvQ?BOk zZKxP0L*a|2{%woZy9Fw#k6Jb3V|ORLWS9+zmqX{@g?D?QB5KoNcdnP7J28;YofzL;Nx3@VhM&abFVl(ZL*;+^m7Azh1`q|d@R%pqK-Hq?6}1O{dZ=RU;)BUXvS zQ|h|2s@)6&8RD6noG-O#6UD7TCtezs0MmD5V#$YoJF$Lj>bZ!cErty zWo|}F(*OEuN{>(7O6P5=8dw4K3Ufk{RC~icNy>`DaJgOeuKE)j)No8kSe;kIQR=N= z2_mx8M<9O;%rff?m1m%mDD~Ya^#`cT?n0^eh4Uc}VHHaK8ic^W3?cb2J}ts3@FNO+ z^YzGo=f|v4_pPs2>I@R4o(mO6sWV8FdOlRBkCdg}frI5z&tQN;uTi|Oqttr=Q6YD} zAEmw{$E6Gb7z$8*huN!5hb&45rSS*)Cz8n+R2sCO2HBW#NqAA?i_zk!xOs?iH_?gf)eF}1EO9seOtZIsVnsFL7Ur$u(uBh z7iw?g$B`l7X4-N5xG*GK5I=3jMjf5#a{dCK)>X+}js&vHxd0W)UL|)q3}lzXfV&)) zISU@@Q9Y<2#)Ct{m6>U1HTI4uYi+RZ$k1?|tEfGWSk#ym)m6JN->u9);#T_1RlQ68 zhs)0&2^!B|7VeNW+CHp}ACF_37}m~R7M>Dc1phSN=rnt8x)hJg8PM##4|)aylo_#J z>SP0=(!c>umFO?-vh zj&B^mV~__zjuq;@oA7Ful#9$!b}QUFz`a$a`D)f@kZH*xy9Wl&QT9iuiQeF9vp$kc z-m2qP_wWyZy?bC;b`M_95xm(9Gm6FMQJjkX^CV8WTA=wK4aJ8SSQeM$EBdidaUvZm zG^mjg@Sp!juy$ZnoV{n&eQ`zj;ykS(CL-nk2@lWOvZ>z69Kg8$KiE`w5H8d*TrE*Nm7GFQ-VKuu(Vx7a>H6isGev6uE_u&(=z@M%@^;lyp*8*m;4Kg?tF zebffNuW?MC0Ue`1WXaUd=otN5b{WU$H-$}o;ZDcs@4=B>3V;9|qrb2Vy*Ff<0P#U$ zmc{8`$}s)8b{64)=^CW!^BckynRW0(bE}K8vcx6%kd4AwXsqwRfr`<5A>iUEcsCJ* zjACuadUwWDk`Ft2Q7Ohu+UXvR?>_Z(5aIj)6QG4Ygnp2(^!XS0?8u-WBM3 zdV{1;FyruXpc3dXpy`}G8+|5&vQDC6<9i#hkPCtD3U`9#onPC4T=(vZu-~hV-WoK%cnA+r=5KYTiDmJX3D1E`RK>FlAx}>C zJ#+xOWze=Kl;mv0OsD!&d!ptSL0P=-G+~~iJPKE5>J1P_>f=cM^MLl`vz&MprJ9m( zt@$d-8&;s4Czcbhq6{T%dKE?S4#)1rm+Z^h6(WTp>T103mmE5+c!4$Sxjzh zFpwJ?5+wF+ynmn-eE^@$DZ}sKz~U(z5J9a;)1-!2C0)1#7bc#9A2XJpjpG2ll~zOB3QXd1y%|FP^bvu3g^iWVH5Y%~QEo5F*rvM)ap?w$ENsw_=( zxQ#$IQrCnFCcCycs~*XYs<(Twt?K2#)mim?AdafH8wY2=>@^Rvu^f?QUSxUaN(R|@ zWlgwo{AxG|+v1uXVOs{$wszpVfc6uG7rSX$X4A4PO)CMLmO;lAjq#unf5Nu6AY8j` zA=k~R4HqYACz0Am)}wJ}zhn+`@?j_evaWm>S_D9W$cLd4@WVz4C^ht276UG5^R=uw zb><$Ecov%a??0+?a+xvov2b&3=u1K4rpLm?+En~l^H{iL=X($-^|hVdt~~wA5x6fJ zfa*UjPQ5@DI7;d; zI6fX;K6=Q@^`>$RoKv|8P@|!W7kVU%shl;Fn+2Jw8!z-A8v~vQx6XP24pjIw#Omj6 z#{&$wEPf(f-C-A8Xy;m|dJD$q`o}}ALXIfL1y|_)>5#97yO4wF z=)>uKx1I==8fx{&Xm<2m-2~TIo9XmmomHqIiU;ciC=~g^TL?hZb$+le0oQd2xUK`# zZQmFkt!l$x!2_-*!$nhXc%|Nn0|HbxWFsTsXk;+}krF;}AOS}#0Y?mAtbH<^8Q%}T zO(}G7#^5)!tJ^?I$rfMW1oI3VsM@Q0OE8)(hXRd$o#$h~TL^_U0F)q_XnCK*N|^yP zO8vBSW>CF^(rFp}Ie3c;s~@whPK1Ey?8xYLAdF7HVf1YP4x>xJd6$6m&VV|YG?5&f zaA|i@(AfDD`n2H}nUzPHn}EaI69A~b%05j3j#2`Sl7X{NJJQ46r=?V24 z(-^o1P61EB+d~qOYSNgHlxv3yEHedLA+_fYIbREGMt1Z(at8m`Bw& zFM~wPS3*S;Fm@)>XlL^DUC14EiHg4DFgiN8lT{Y@)NFkSjwdz-pb8LQkOZ;{D)U)| zz_S45J?`Em+LtY&V-7Pt+hAKW@R?sRbPDYXrzf!-NNjX*XTrD>sELBq2r+%a?d zE@zq`8$B(SYGs&2+14ESu0(5g4$*jsBG5J5eO z6$fh&@TCpGisLZ+xT&1+2KjX#;64gVrfKn5n=GfrtRUYYXTY7d@5|kIK#pLjs`HA2 zW!s7a{Ww+}AD~`+^;)=h{8!W~8b7!qvz%A~Z@dSt)(ZFnwCy#CWalyj%5nvqxubsd zN(FILFIoY&0JPUHmdzFL0@&{`CBa$&cd-KHO2@Lf0zSGBT@z`WD_|;~tKdNt&wW<$ zFrdF@7mKt>p_J?v#KJcM@=n{b>Lcz8w1{;GRwb?&%nCIu)G`ckbBf zINZ6Zz@_*R_Pq$Z`dJNcPmIMbKEPN459Wv~z6v1^fy`HYN!hw(t1aBS!JQv7je$&? zjdCBEfw}mg=S<>p?e);>459i#b0e8#u^O>fAM+toC&sG}mU$mp98FyZB{7gZXB|yt zAlfKR=Inq5lAs{Akpz!d5r{A^PoX7X^Gd+x1uzGa{qKZFxZ?eGn_rZ{p&3{0#W!Mm z?w=1)LqWxyb}PEe|5|{CcX_UtGz8$HC%{FIA(+Z+GEkA_$vls{9E56d^)@ThaV9d? z4nX%}Fp%eOCEz?tz2oWa^E?)oOXL)?%jLw zKnpH!9mH|4K5(IAkKL&jc^lNa6aeGg!EmeM5pbb$9y=d5cD^$omoYKusWsHcp$`Nw z27DZDQhYUBT2SzRr-ql<`F{w6Y+~8l`*uuKo&lqkzTEkjfOq~G@XkNWa_66c-1#SvPSa7j^ABQd zIuvde@3PmNXv+g=49vZF+TDB%Dwo5v+~Irz;8Fll*fiU40Ge$$0L?ZWfF>JHAq-45 zd}bhYEF8ob@kzLJ*w=8XKil}tVj@bKZ7`6t4G9vn4ZR(<`wt_hAAADyUxFYmwx`+w zDAf)?sdfNLH36hLk!S~?BiOgrPbh;vGNnxHv#ERFjXEruKL*klfbsOF;mY`VsJ4Qt z{9Ls1n)7qfEX(@9K-LEWj_Sa`@wMnC(4r2BzZPxEcx~1CTy!o5{t`<^d@lNRv=0U} z@^7`ta^z%nJP#Ywn+cbQ+^j0)X1|1J-dER>f21A3k zFNEQ6&ejQj+HHbdXvj-|;ic}X&%(HZbr+&ueFSrdVf(DL?`d2EO;3O%;3q%~_z4in z^!$eJ=904Y1W3w_tS3MW_z4in)Q8eT#Ui?#iviy$1UE(ZU*b|`@55z-M{y$en%9HI z9rWYa>%qF0j)s3pi+73yl{;M4sZw=Xit^k_k5V>C_1-rU<0Kr(pk-6Ag1j&+0mRZ< zd=cPbs8Cxgo38rA7XcX1aX7q8j!+t`hx1IeLVpb*tb;y{qm{3D(!Ku~*#®1==$ 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Ξ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 z zTt~_DN`a$P&`i3G)E&5jEWs`>%{4`LaR;^z=!GV5afa(n`uGw8YobO9Jr_I-pJch$ zs#geC`8~1p-r%+Bb!FvX{-UuC2JYk46Y%t&4CZYE>BA2r8>*~d#xN#Aab$09Dg>&VnB383J3Y{|GfI2?HuY_ zog+s^@y?X>ttjqB$)i#HC3+nj%{%q5SN)+vZSOs`*5BUiPcA*v6&tSQ*=8+&04D(Q z?$tyg!39zAw7kQ`ry8qr6-`C;XTk&kGX^Hqg}Ao@o%aJo?MJwX#P7&!c=N6S&$ZwoByd zxaEpOepli)RnB&NgM!qfzwCf8lf=toKj&?k#HTBkTa>ITsF#8YFt~XsTpffsm%<0N zE>acQPF8W?W+zH@DH>hUU+l($NNWq20(j+y5$tA_=iNy>h&C$3%HPWK_!{R+RZ159 zY;st0y+Vr*6cY>E4{~zp=)Q z9d){VMeqHoJi@pE9KE^ee7@sG0Bc!E1FU}~3t;Cf1M(PHb`?JPDgY(m?u^m^!nJ8v z0VtRvEs`I0B=`yesAGl((3&U1V`V|cH2_Kkdo2whay2ZW>ayumB>*B#IUU1S0BTT` z{|P`89F3|_-l7+vg)mk6$FfksmJe3rpSm`0)D&U&o0=kcZ>`R&!$Vz36xBW18!RDU zR%Th5AI;*`%E(+;qm0ZFHD}3pYVzN&t^K1~{66D&u54JFr}MXz78j8#;UcN!l+$uV zZ9dq@&ykcN@0Fe^8#mzT#@;pZt_Hk%Qoa&G;G&3I z15_MS2p@=+5$(!fD_`rKm1L}4E4Me`-C{4%s-e56Q$g$K)G2n&g==MvTe9vbGi?pd zzul6RIj?V4c?0>}eX}apUqg+72U2m@YxI&9)cP;|7u^?JkrJSSDAb+Oxn%Q3e5Qf! z6gA?B^gP=LoC(j6#=O0;X|24uF>h+Twbq-{nD=s+7IbhZKG1RvJ>P^^#mpr(1;!N1 z!t}t5;K<=>VVk{Us@aP@z|(9f9j;y7l&9Lk4RB@%rgt2xJ&KPd84pa+&%C~zn%FAxecsL!jz0y0TB0M{}i6%X3qsq(IoAJ8%-Fyv@yjVsxSC1ymd99Mh z=%h7{-InVUlZq@g`^3=c+bzv`I+ZI>kKh)Z=K4tcNVwM%Wx1Y@#MCWEWGdKt$QB|yaElnxmcK=W-1S*fOL>1g zPA3e6*rdvU9pb_w~1`e*HIPQ+w(PsH%C6$f!9N5 z54o}ff7Ey>SEhF4zb1T2#Dz3?$0*W-C)%?|MVx@evsyPk*7!6>uI|RGx$M-td<5?N8y5Mj)z?u?B8yAb?8@&% zw(UK5oP4<}f5_LfgE#Kk!5j4~s#MQ*Bf?9a;oc{2<~1Gm33b}ykj}zYOyamKiVBO7 z2fA}QhF%#re@VNo&inNyiA@3Fr8i9jmQ zw;!)oTc191`REihYoV_F>ZBM5XvI`@jXQ4i8j2kT3=w}6$`)rb8_To(cpEe_dO}o1 znf*cLaJlU+zK|;I*Pq``^ELoJgCF+i?;1yPbW4WB)wpQy9x@O9A_AR-0 zAg>o~OW|bfcC9LaLmH2XJ+66{XDYN_#04zXPSZjBW}^H#gZMC`xIq3oh^NP#-J}-A zN{VWW1+s*m-^to{;~ucH1#-yU{I(Jzr`_s{?&fh+{LI}@`mNktQhcWuUTZv!$~C=* z-{!H&uBN#*Q$i!um^x;J2-(!2>zF=}kVB2DaOF9Op>w=IetHkjG)@#q=e@ilTc&Q{ zBF+$kqeB6%3u|QKdlmh@=U(0(f(%e86{dF25)|GI*T{Q$_eSp%D8N3ZQ7S|`Y*(r} zXCUR(D_1#k)B@W@*gk$P$+uQg?>iE`!`I81}**ch$S43fl@+mU)K2DC+4e#Ua zZS9ub8fr&9=R=0N#z}b}uW$aPA^^cSs^-GsnkYZNk5@LP=gETQ6%u8I`+2lFCsq4? za4ejYdi;K#YD|V|?0%ko@7f}$_@o>!9+vvY_S~yAc|$rA-u}%zSBpDI{*c98AmaFdj_i6-d~^_qjYT{ zx;8zl+Eo_&ZL0qh)Q?l9zYpO#HtINuRPM=5#$ zdu?1mcSt^n$E>bhOO2$T>SndnAQ~$oBM)_X2{Il8n`x-8VZ#=gBCV%IHq@o)Ei@Hd zC#NR|Zp?Ia_o3lDo$8U#59g`o7ivEAsC7W84~O$7(Wwq2_!#))Y#srLVttN0G=i@s zVzJj9oFHEr$=^bU2Ry)qjw6Jd1<8XR`x-ISbs$$xeSqJF!e2h1SaHZG&=$nd7{#k= zZbaRuZ5{@jJqlT-%U4G64Ql@H8Vy4KMUMPpG(TeO$? zgq3;uVTec8W|R~iYLDxLi=A?m`|1(insQfply4ra!^!~lp<;AcVP$BF0#mD!swyD0 z8rDTNl!;K14|VBKGltSGIy@zzX0VJ@mJ?vvI@FBeDNtXmP&1t#<9Apc!i6@tbOD?0 zcz1Q}*0<>~-rq{B8sV<0Hr-X-nc8!&_Tzj&sYD=0Rd)?{bx;iN%E$R^=dCt&$G9_n zm>%!0VgL56gz6AkQ^%s}}@Hm?@` zp{DF4*5r4H$tY)uR~sXYu(5&C^LSff8f3P_xgyU>YRU8J7TIPTzrBLbgk*TuZ&h8O zTh-77T=@X|l03PqijYO)cno#q^f;b|b0^{Bd8)9?qM0C_2-MODx%0Qkmg9M?qd(ggmF@|zZQnwi(QaBF>n=XyJ=H`;JJ}4n?1A`zDfCbsW$UvDrlnp2# z(%P9I8 z08$bPC!Wur<6R92f5>V4IZ%`h)A&Hkumc4s>?_HnL<)dqE?SZ0+BrNWQaP2X@`rQe z?KvDS9P))6PJYluIf|bAk^^M`8ts(JAEw&3%3i>u*+*t82&I zFIP|JjOy7soj-0h3y{0eY}*-}0&P7%Lp9r@UHLedx;X~kO+mO~K<&aV&VXh&Pj;E9 z`ZRf#;=w&8g+s)j$th~!S2IB-r_1B5O9k)jBCoJ{n3Q zIqjV@o8RrwduO<7_-&oB--TA9uu!tOJcCZEG@HwN`fiY^6U4)oMAl;;4Y(_W_g^W1C9$(1J` z4{7VCikG!tebAf%c{2UP51n=zN?>O>(|xJkJ+2hc zPA=mssm3zC50)*LgD;kmxPN)sg&fa>^p$7ogsE;^UE}tZd_h^2p^&c!yhH~F93jP} z$1T@1Z}B=E(VbpUEr%9hN@2CW^j>?km=Rj=E@1_|d&ugP%_vIN<09gngTOLP({u}bM6p|7j6rFM|e*VM5seU{_( zT<_j>FqI@`s~NHt-U3rP!}=ma-rzk#&+nocgxPSw8@%}M9NnOpq7nMq;dOzI(6Mr+ zBb0j!y?nMKel7I?)&__nAV$HUdKC0xZLYlYO@43a64fxQqwl}T+mN$L)LZc~o9A!6A8q1~IuJRk{oAlDz%uym+x#x)l~YG#l`Z@x z1DoJSw(xdH-@JwQcAnpNMDneCX6U7T7INlqRn$Ll8^0rDP7ywO66E#+JVB1#rpW#7 zZP=Y|%$>KL--0&#Z0F;QH|@8YJNV1STeV<enz++h?zW%d#89(qdg3HZP@+Q;jX zVSL0sUfFUjL!{&@lnj@(U=rCq>vz)I426Q&BX8WthZqNPWO@;=5%aMUO|84q>DKQ^ z7upzH#6K}M=g6k}u?d?2xDVXVyBS+@W#N9FLJ39t`6Hz0>iDrz|2*+AZ&WEyd3NF4 z0vH}b-ntE#Ss|g3qgt3}A|V8ku!AT;CBr{ao607iV5VOKBvyP<8WJZz;S1t)l@R@d zJ%`XY_^M@i2=UOJIQi-U-pY9eMb(@0Q{D}8)$>z61&<@2@~%m$G`W$XT((1RfZ-yh zJy=63?GP{|Gz#9pbm!;EI#`4?zmqlp}vX#9M?H?4hci2wWhWALBcX4Y~5ElUP+) zW*?r!-WB_Wk)J~(#{1$Uybh)B{hX(WB3kPh0?9vE?mB=|;89-R*p`c6lRP=yiNyw<Q`9O>^=26Aih0sm^g4lE z!~gEUB4w+uI3iNpupa#tubXZW+Y=VC#bHtqTRlzad$6Yn^Yq?Vd`yrUvGjb!xgFC0 z!_y;$AB5jXN1ftbZMkSa@W^9 zJ;}e@^ED5_yIRwJQKJVw)`y7N@Y3{qeyYYAh!hVbT_b7iH| ze6jzEirf40!>M5LJC-pgi#@Z*RRg<;gF2qTKThf7D_{7Qk0x2l^&LM*8W8gbp5?y|+-LbFT5yhEU`xjW9B>|H zH7v++zu<}YRp+tXkbd$!7#Q9!e9u+Dk%)7g%sW}PmJYl*T+4Ik zEp8eoBYuK8T*EM3cKeBQe?UI{6Hke^AXg9K40IN1pRPf;_9swwSjT?mjjz*{GG}f1 zFTPnzpLe-*gEcSnuF;qDiu9kV%Cg`xr}#j}FJnJl26VRn3KdJSJoT&EgID>DKUDcw z;-DCD2z-;&Z#r^SG+baC0jXZYiZ>T{~gXgzvakUc*fhTUh{zv zXceIzq+k%ke<#)&hS;NA5~zx5#q{`M}Ox%%>&eP+-gUcY~t(1 z9NFRuj|(k+kJin{IkMjs*jB*oYyZJ3Dz=tt2qB06!5fv|qJ-eUtbkf+@Eu2(N)K+x zvbu&6JN|%m228%yp9-2I|Ae+&zgCD=(HSx@)Ib#(Ql9#gFRQ%4&%sOmrt@=9A-U8G zEOY?khCKQDUjX7Yc`4b-NwBx_UjB>MsbWtKIgY8{so`KS%A*<_6^=Yq^4FZXJw&X5 z#}H9FQ4JsG2;t;K3Se9hfq2a!o}zb;%v~?)`6REo=LLfD=EzisAUke*hgeIn`VFr( zth$oK^nf7}DPfu+6iC9HBCEchEyy+C=XMBS5|w;{o3o7Blf#^%0f7-!5E!A=CsmdO z#{Ew507-SN14WHcCDq~D3EAj3KF9|!!cYsi8bdAM64q_Vn-?TXVC&1O5!5QB5ft;# z8F`Ie2$g(&1TBD+?uVc?{}F<|mnV<$R=?x~Ys@eyvPIF0^vHoLo*M&{k<_IbSO-X~v3p85||t7B7vaFO9UoOmQKx zHgFd%ot7eFfCqB1%#IR0%V^TCV-^hB%LgJvNEuoEdS}7lA#4Cu$H20aT%v{5n+X5j zghO&5V(?FUvq*!feHEMvB6f7`^!fE?o`zNrL^2l@p!ah!F|)GmbQ)?qohCw{u^dcQ zWI!yNeTX;0#K>#&5&(U#c&9w+2%+9pHGt&_6EyI8v z33fHO4$D(qq*c6TEs!A;gJWE~=&bv|WatcY=1 zSW{Upjun|@;DaCPtk;tjGcWF6t)69irfSP)<3wZH9sA+6Q>MB^BMXUe%_~qEJ$*J_ zd}Dl;BS$BQ)Edh79MQ(0H0hF*2GocI)1njSU`G_i8w?R2=mLdM*9kD~1QD0GpV%b0 z27(GrG(1Lo@OpBwcCCUWm>`ZBTXN*S#1g76WO$N@t+<)?k}e;gbftybe3BS0T5zFU z+axdrcx5>1rp3x`$s#N|keVT7utnC-CyDm{IpQ!egOf#Hdyi2}kuE`xPSDeW=rZ~Z zVO^d~7IR~kX{o(b#;vk@RgoZnNfl9YZHj35cWaB0Rm+2&Z5=1wX`-?dRm=TV1eaUt zz{3@%#AJEV$Cj&bB?f|0A;*>S;x@Q_^r;{mj_3lv-q1F>YO1Iw7q~@sSt(0mH~VET z8Kvw|74!?euL9jrg)~vciF|*rCs{HuU63`qUb?vDf3W&X6-BMEol0;f-9c6*Q7hIW zL8WE_Has<$X_dsM=DR9C3~$+_Eg-|&=*r@RbIzV4vPXu9cY0uYQ@N*9!O+jjHC03f zm5NEg?K^9wks%tzS#s?a3M>wz;#qqhP{mysctM7kpag!Z((r8c0u|aj;w;?Bq1^EG zRHdwj6Xko=#EgH5BP-EOU|fuxUR|^(Gq*)?RU6BY`+Rk=1T#1@Q&hKyp>Qc&9?KMr z26R62#sjJ?M`Z~T*k8;NE&WGD2wp{|))4E<1p7}GAe}YE&}jdm(~zI4DF&lkU)8j_ zW!BQry&iT~l|{7#dBX+P7X8Z{xc|cZx4_g__O2r`9Y4u&b%5=(s{Yox%aViZDr}!u zSG@f{)3ZLZb$#)sQi=UpUu1-oZLjTsPwho z-gs1>GmK>h*f8kwN&`Xp?W~jKnI?jK-^`XGPBv~KB4vxFBFwru1OvDzdo(4|q}%5* zuPHdPx-&*Ilc}hUw0fu*D}wgQ&>}SzscKYB#T}@+Wiv6rv>Tj4F&S081CI#oDKCTeYS%7Y(wm9aH$VWAZhjy6$U&==)V&*Um$#>)L_nhvtF|(l#{6 z<;ot-gDu4EVYU`wvi!7#XsUBkfwnD0RcgRF_l*hLl10Mr!mR6%wNi*_7TcIv4db_P?8D$@D4pK)(WOzH#lYexdtvHlbkz(T{OgP(% z1)dT$w#G%=$)Fo@ZO}`G5D+&GD)$m#pR)tP2CG6OchWU-$J>jl{>nGAgHYP=gB`>` z8u_0c^~i7UD3msQQb&l)P#nG8QMB|=FW*Tdifz;=R+9=zfz!@v4R!6LNZwPO#2{m3 zt~}96jI_;Pr3MawCT*fK@-N?>=d*xT|>3u6u@}@#oP97!kU;g7lZ` zx{2?it)8hVq8`0=vlsv*i|Q^a)Ux*lS3yL3`$2wh5)eT5eFfkQiBO>G*Io3$c4rL= zlLD`(JA^x|le67L>aAB#HS~EvDX5-&Gwt>`I+P34dQD8U)0$`msKi8LVxZANqR$VD zZl;9A<(?iQ)gJ+-_Yg|^+O?-pdb|}qh0?z6p(kludkUp}&FF>s!TW$-BC(F;K&v{0 zH2^|K61$BKARz&1DqJRhksgUiYkn_5p%6~?5}DkR#3;Tgmcal#E=qTAB_56KEm|Sl zw%($)@%(gov9}mk;iSTCEFky>>C zqG`G`P&B6}ZaEdfxXYfXo8y;`l>-;;Kawr0|I%@0#tAA&u538Tg^&0duP20dNbtQb zRu#h;rq-~FEc)ceWiL@WInqqO-0|*mE2(-Y0pf?!#WE*fs2>wpMBPZ8 z-EoM0$^x6?NbOA|kKdzE<^Kr}i@)v@6#o9!`<0knG(ff!O;m zbEe3!5hAMeagDvXa?VgO28F|hsjBJ^gRttWYQ`{;RZ@UR2ny^OChkL)dc#$R2IWmt~^3D({qF%kKMm>TP(6&=Sa=M2Son$J#RiGH1hMj=_J2y9aw=7 z+rIsEz=I+eG_=;fs1zCTkVr{9p-k%Vs(pGW9NR&h2$yx3hSm>>I#q3UPF`fT4=ZWg ziVjd)mJi9IKu5InxKb*}Q6EQy$rJZR#>gWNiI!-ouvz^S*>H@gVSJJ+?;9hsEk9Z4 z?Z5}2jftXTl(gRd90Q>k&)yG<1{qg-9Yy1eYFW+8wGWF;R+UhYBV0dx*eIBtisCu( z5%G|fhznhyNQYG`4DG2Xo>7mAF;?QWCuN_1R9ye0Z28B8|4G^9kBO3#vf=;yr0n!> z!ya**p4UEb5a6}+u5e|pd%AsKhijmqo%5712QFgxCPA7{iYfNAZg^6RxbqXm1Ta>` z1V2-6hPxc@P;KbE>_Ac23Ftq}r`fi9ARSw{Y@|ji9Dq1`-oA^K;`gW$I?$BENY`%)WMph`*wW8BhCWh}>h<3{k)>O7tc^BkGf%diSyVNb=yZ;(kjK zMMPEv4UR>~P*qLu`7xDbNVfQ{wv8lySFDj4DHtIGuEwcgcQUc~^l@UEji`IZiRy%? zzm5}=@hyA2Zg}2!;Wj=)q|Ncd4jGFBzzD5}K9s}pY8CRg^8}G%-vCUL14W%@zDjv= zf_TDCQ5P2@5}8g3n<#qLv%BoTy`@+8(czA@zroa4vh3vaiDHu7>pGJlhtu+!}N$oe+Plib3mYRgg8e`rq@Qf*sCGX z`+d3MCVJnHiyi<`e#(W^v%|lmDRN_;{+2NvQ-I#~n~uE5vuL{LXnVr033SNqkEV0k zy;qGu88idxh1GNzNgM3q<>+tQ#>h4^L|Y@jKt4MI8iLdEiy5LF9oeZoQ?yFTr`%ZZ z5Dqg8momb6#^R1R7dkm^rtnb4oijxz^D6AgcS>_r@&kJ<}Uibn*aa<-W5cA4P9<&f(K_BNW6c1kQ<~q;m2+`P8bCJMJnX+IJ^z-xN znMI;$;ITI#jYT)^94lMAAi_zM?fio1>D&1tydwH4SG^z}G#2E^@-GSsO>_T?;!TpB z(-(_5^n7!%*h}HkGOQh(b{!p<7Ot%tw2hJl(?z=6Iy%s0qawC9-pE%(1EQ*JmWz{A zN97gbo~wti<{J#1%Yqf+2u)zlN|6i~^jBA6BS7y(uZn6^`pTfjwN%4JpCu#kJyLD={X*jX;rL3o$se!Kiq(bv{8y->(gpCcs$L{n~5RiKnfS z`a~4^7H=hb+pNcS+)B-eaA)AEH~hDYu6{!dw|I3HE|`mOXQ9PdYO(qTvDhl6BbOsU zI7Ke6Pl+ct2s;LPwFq~$cI6-^R&zH-%y7s96TM=A;ft7cy_h7?B{4|=ffDw~t!UvS z4sds(O-}S{HTxC)FZo@+Bv!dkF%aCq-Gr9+-wkVj>t@IfQ2j<%Y}HftTODfB0pR`V ztrF#Pt3xA#wQfLOc%()gj&6I?-Ujg{*=qDw;nv~t5+hnW9An*dY4iaVEh}@INTw`1 zw`$#k{T{Nd^n2%RqHC-LrNg&!-wtSMPs@mRgni+qE%AqHedS&6 zhGx1`HXl9T$R6nN3Rksxsl_1$p`GM@S(Wm1Kv*9Zy}yJ5XUpg10Y0QkR$VV ziq_HE&P!J&K{EtI`eP^dkqc$BU80h+2>rfim#9n>HfNV2jj!(#acwQz6;-qcqqLNF z^tuzTmd%Y`oB3T-7(ziFX*%Kd8RD5F!`>AGoJ-Kc@OMQeYGL-fVkl_epYICt*G+s+ zJk<6oi31+~6nP&L4R!M}f+hUAL+EyF&oTA3kq`!FpLLE*j0j6<|9hfllAaeb%Om&& zZ971l^JG|R5g&*FP3`fhHp&`~KD4EV<|7wS z_R$cRe*pOq#~Y4*Anu{qWS$SjNL<=k@S&*hTz~qAEdCH{7ac0M2d0#Ha>yQhKZcGj z-6JZxZ8J<5?m2_2Iv%yiYcY&Y>?)M_dXE^?@J+Ro4^IXAH`MqB9N3Jln zz~G!aNk00KsASK@Jt#(VvFamub1XUn^Ts}*F1zf!Pm~8*4cP}B%V{b1iT2i9AS^b; z@W)n0&BcX%BFRdD^Df-dLb1hByFho5n1C9V6=4fdEK@lGrTki?6r8U83S~3*i}-$) z;UvtHZTPMm^5LrPbXk)duRKbwo?K>QJ2p`iB1$U7 z)d!jY+olp~U^1$IB1Sn69X%pn{6tjJrZ}UOKCP&Z0XnR+ix|uopNRR^!X*2=|H8x@ z1~=<~=sCn!ePF5X1YX@8^})Y8xb^gNMR11G!9;z77xWUo#UE(*ydoMWoVn>!al7*r zV7cnkf7SKxJ{8Y3)-;7o8Mv&(CMjj~E7K3+dSI`ACVb&WkmAm=Dv{WQxy|nybOiRnh{PfcD zdj*aFJ1@!0$3)#~XHO8_{DJ8smCdaAxaD*4uyg$h%*W@VQfr%7 zhr*=o&|$N;2?J~oLDLQfxc>xv8jIzH6QV_`kFx|3Su1%XS`m*TlVtakBGWk$ zwTwL}(rsEsfw*g>frG0+)VKpxS=6?i6dkn9kuF?8w1|qB2s)YQqx}?w`zkR-*8fs; z@!@i~im7hXk#M!d7k(+4mkjR2m*VkK*cwi_jL3u-9FY0JudYJoa1W3f6=`Jt{3}tp zg!hJf5SOBa6NGz8;dZ!U8$Rp}S8T)Y6)kFP?s=+&_qIh_L_sE<0`J`euw6MND*G@t zJj2Mh5E6lF{1DQ{SY%k_%Ya}SB^Z0p*9v1NeXTHd?bkQN*e2hIIzEgIhY)iW&=rsM z&C0)@;f5Id$$KKpH?jZYGUx6u|1Fubj=bfJsPP{Oo?Fg{+Z+3Ie$YG6t$`#*0m`ZR zEUsR+Wpl6|-$Dy@S}yt)0`dg8`&*If#GX%{{Z@;s=652tWV2BQOY<#SA4~JeB7}(~ zN7BiwNpjeCqQA4?E6voZ_z}_jEfSewKuYk@Pc5&=gtOxAEL%rNc3XSz;b$pPS*`D1 z8gkUcX0dYXSrO9VV@s_{fpc*Wy@yT>X;{#)4De$g=P>-`2gp!*3<%PpNI<#oMRVsN zbp599wOlazd-15P9D+-_9T4!>??o+&C?pHJ$2B&*h`G|&9bZ!gBBBsO4Rs(QzraIu zIMrp*DUXU$6fs)v-&ZYGcF(I4Bu75lB3SM_C&E(K&}@RGKs_9qM)KR#uZer5d!~Ma zCsd@~U(bQ8T3Q#aV8Uq;c<$<;u{F<&;Z`E}3!J53CnG-vb!Efa^TNLEPMc^TIMBu6 z5yXNTUl32FS-?eoz9>$<{SOQzm=y293*tc)l)1}AF#;PP?^_pPwWgiW`Agz4dJg?b z++OAXWA9twmODc6;Wa>Kl#oTexWw61Py{M7;ju&%R*k4+) zY068vcUWB;e@9Rv%=J-5G60sso-p;1ERs{Ne>rzbr#^QZz!wL7vJ~Ue8nz=u38AJ} za+laoU8z3vO0F0eD@;{=7PUVGC|wPo{=et;dBjHQaQSoV$65dEjSY zxJja8%xRjqR}((!uBw$(VbOmbwRk9ar-oPW%c)~;sP*Z*yPIc(-(x<85tW(r3??9v z6phYEN-|5W{_T_M{02bn8MUIp8P(lSMAwe2I!sYdM6rObE}#G?K8j=o>Zc8k%a&eg zaKr~WEaepS4i84r`pgPS)%VFw4P*FK%4$%zOgg+(z4FfbwEASqnR2QYN!qlBBTBMd z@k|`tGfjjRQ0?e2%92E^L1-_AJq*}uI~eWKCfLCk+_bk4-(geHf$@ZlzB-f&IAKzE!8lM=K?aAyLW zLSfRNqTe?;lQ``2RvceQn6kdCBhim2%a= zkV6sTN}MJGN@TC450k}+)ynDGYZw?-%+#-V~xzGKL8ANExf zA&`ZIHm%wD98WCzR_#~_{5;!xc-Xk2lTS2pce5*6O)A(WHW(YC@zqe{ht1}v1 zxU1FqSh!YTFl&VbLLw*DDiUf|4%7OKdNAiq=2Fxja?YdnE~MFWoVSrLHMco^#DcfA zIU94oC9DBz*;UCcjm)%N$UB#!TfJut%d5Nc4�{?)wGg!{&Vv#4R4oE%=qsL;<9 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

p!*5DzaG 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

W8k6y!utO*vpXwBx4@m0fei3 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

oI?2p?+jedU3*$<~>yB@QOaz_he>l$PKL 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�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 diff --git a/npm/package-lock.json b/npm/package-lock.json index d0aa380a4..84f982e0b 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "@distributedlab/circom2", - "version": "0.2.19-rc.1", + "version": "0.2.20-rc.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@distributedlab/circom2", - "version": "0.2.19-rc.1", + "version": "0.2.20-rc.0", "license": "GPL-3.0", "dependencies": { "@wasmer/wasi": "^0.12.0" diff --git a/npm/package.json b/npm/package.json index d194c8b6e..cfe59c64f 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@distributedlab/circom2", - "version": "0.2.19-rc.1", + "version": "0.2.20-rc.0", "description": "Circom 2.0 in WebAssembly", "main": "dist/index.js", "types": "dist/index.d.ts",

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�QT`IV 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