Skip to content

Commit

Permalink
Merge pull request #194 from iden3/in_work
Browse files Browse the repository at this point in the history
Merging release 2.1.6
  • Loading branch information
clararod9 authored Jun 22, 2023
2 parents ce903c6 + c30cf6b commit ca1b7d4
Show file tree
Hide file tree
Showing 17 changed files with 521 additions and 206 deletions.
15 changes: 15 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
# Release notes

## June 21, 2023 circom 2.1.6
#### Extensions
- Improving tag propagation: array case.
- Handling new prime numbers: pallas, vesta, grumpkin
- Improving array access index computation in the code generated intermediate representation: using cheap addition and multiplication operations when possible.
- Updating the documentation.

#### Bugs
- Fixing a bug while parsing anonymous components.
- Fixing a problem in calls to anonymous components with signal names.
- Fixing a bug in wasm witness generation that happened when doing a call inside an array index.
- Executing the main method without inputs in wasm witness generation.


## March 15, 2023 circom 2.1.5

#### Extensions
Expand Down
13 changes: 12 additions & 1 deletion code_producers/src/wasm_elements/wasm_code_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ pub fn init_generator(producer: &WASMProducer) -> Vec<WasmInstruction> {
instructions.push(header);
instructions.push(" (param $t i32)".to_string());
instructions.push(" (local $i i32)".to_string());
instructions.push(format!(" (local {} i32)", producer.get_merror_tag()));
// initialize set counter
instructions.push(set_constant(&producer.get_remaining_input_signal_counter().to_string()));
instructions.push(";; Number of Main inputs".to_string());
Expand Down Expand Up @@ -832,8 +833,18 @@ pub fn init_generator(producer: &WASMProducer) -> Vec<WasmInstruction> {
// instructions.push(store32(None));
instructions.push(set_constant(&next_to_one.to_string()));
let funcname = format!("${}_create", producer.get_main_header());
instructions.push(call(&funcname));
instructions.push(call(&funcname));
instructions.push(drop());
if producer.get_number_of_main_inputs() == 0 {
instructions.push(set_constant(&producer.get_component_tree_start().to_string()));
let funcname = format!("${}_run", producer.get_main_header());
instructions.push(call(&funcname));
instructions.push(tee_local(producer.get_merror_tag()));
instructions.push(add_if());
instructions.push(get_local("$merror"));
instructions.push(call("$exceptionHandler"));
instructions.push(add_end());
}
instructions.push(")".to_string());
instructions
}
Expand Down
17 changes: 15 additions & 2 deletions compiler/src/hir/sugar_cleaner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,21 @@ fn extend_substitution(
context: &Context,
) -> Vec<Statement> {
use Statement::Substitution;
if let Substitution { rhe, .. } = stmt {
extend_expression(rhe, state, context).initializations
if let Substitution { rhe, access, .. } = stmt {
let mut expands = extend_expression(rhe, state, context).initializations;

let mut inits = vec![];
for acc in access {
if let Access::ArrayAccess(e) = acc {
let mut expand = extend_expression(e, state, context);
inits.append(&mut expand.initializations);
let mut expr = vec![e.clone()];
sugar_filter(&mut expr, state, &mut inits);
*e = expr.pop().unwrap();
}
}
expands.append(&mut inits);
expands
} else {
unreachable!()
}
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/intermediate_representation/call_bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ impl ToString for CallBucket {
fn to_string(&self) -> String {
let line = self.line.to_string();
let template_id = self.message_id.to_string();
let ret = match &self.return_info {
ReturnType::Intermediate { op_aux_no } => {format!("Intermediate({})",op_aux_no.to_string())}
_ => {format!("Final")}
};
let mut args = "".to_string();
for i in &self.arguments {
args = format!("{}{},", args, i.to_string());
}
format!("CALL(line:{},template_id:{},id:{},args:{})", line, template_id, self.symbol, args)
format!("CALL(line:{},template_id:{},id:{},return_type:{},args:{})", line, template_id, self.symbol, ret, args)
}
}

Expand Down Expand Up @@ -144,6 +148,9 @@ impl WriteWasm for CallBucket {
instructions.push(get_local(producer.get_merror_tag()));
instructions.push(add_return());
instructions.push(add_end());
instructions.push(get_local(producer.get_expaux_tag()));
instructions.push(set_constant(&op_aux_no.to_string()));
instructions.push(add32());
}
ReturnType::Final(data) => {
let mut my_template_header = Option::<String>::None;
Expand Down
177 changes: 147 additions & 30 deletions compiler/src/intermediate_representation/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,45 +1151,162 @@ fn compute_full_address(
fn indexing_instructions_filter(
indexing: Vec<InstructionPointer>,
state: &State,
) -> Vec<InstructionPointer> {
use Instruction::{Value, Compute};
) -> Vec<InstructionPointer>{
let mut index_stack = vec![];
for i in indexing {
match *i {
Value(v) if v.parse_as == ValueType::U32 => {
index_stack.push(v.allocate());
}
Value(mut v) if v.parse_as == ValueType::BigInt => {
v.parse_as = ValueType::U32;
let field = state.field_tracker.get_constant(v.value).unwrap();
v.value = usize::from_str_radix(field, 10).unwrap_or_else(|_| usize::MAX);
index_stack.push(v.allocate());
}
Compute(mut v) if v.op == OperatorType::Add => {
v.stack = indexing_instructions_filter(v.stack, state);
v.op = OperatorType::AddAddress;
index_stack.push(v.into_instruction().allocate());
}
Compute(mut v) if v.op == OperatorType::Mul => {
v.stack = indexing_instructions_filter(v.stack, state);
v.op = OperatorType::MulAddress;
index_stack.push(v.into_instruction().allocate());

let (possible_to_usize, _) = check_if_possible_to_usize_single(&i, state);

if possible_to_usize{
let new_index = convert_to_usize_single(i, state);
index_stack.push(new_index);
} else{

let to_usize = ComputeBucket {
line: i.get_line(),
message_id: i.get_message_id(),
op_aux_no: 0,
op: OperatorType::ToAddress,
stack: vec![i.allocate()],
}.allocate();
index_stack.push(to_usize);

}
}
index_stack
}

fn check_if_possible_to_usize_single( // returns if it is possible to convert to usize and if it is a small usize
// we consider that a usize is small if it is a number < 100
// we consider that a multiplication is usize if at least one of its operands is usize
// and the other is usize
index: &InstructionPointer,
state: &State,
)-> (bool, bool){

use Instruction::{Value, Compute};

match &**index {
Value(v) if v.parse_as == ValueType::U32 => {
(true, v.value < 100)
}
Value(v) if v.parse_as == ValueType::BigInt => {
let field = state.field_tracker.get_constant(v.value).unwrap();
let new_value = usize::from_str_radix(field, 10);

match new_value{
Ok(_) =>{
(true, new_value.unwrap() < 100)
}
_ =>{
(false, false)
}
}
op => {
let to_address = ComputeBucket {
line: op.get_line(),
message_id: op.get_message_id(),
op_aux_no: 0,
op: OperatorType::ToAddress,
stack: vec![op.allocate()],
};
index_stack.push(to_address.allocate());

}
Compute(v) if v.op == OperatorType::Add => {
let (are_usize, _) = check_if_possible_to_usize_multiple(&v.stack, state);
(are_usize, false)
}
Compute(v) if v.op == OperatorType::Mul => {
let (are_usize, are_small) = check_if_possible_to_usize_multiple(&v.stack, state);
(are_usize && are_small, false)
}
Compute(_) =>{
(false, false)
}
_ => {
// Case variable
(true, false)
}
}
}

fn check_if_possible_to_usize_multiple( // returns if all of them are usize and if the number of non small usizes is at most one
indexing: &Vec<InstructionPointer>,
state: &State,
) -> (bool, bool) {
let mut is_usize = true;
let mut number_non_small = 0;
for i in indexing {
let (is_usize_i, is_small_i) = check_if_possible_to_usize_single(i, state);
is_usize &= is_usize_i;
if !is_small_i{
number_non_small += 1;
}
}
(is_usize, number_non_small <= 1)
}



fn convert_to_usize_single(
index: InstructionPointer,
state: &State,
)-> InstructionPointer{

use Instruction::{Value, Compute};

match *index {
Value(v) if v.parse_as == ValueType::U32 => {
v.allocate()
}
Value(mut v) if v.parse_as == ValueType::BigInt => {
let field = state.field_tracker.get_constant(v.value).unwrap();
let new_value = usize::from_str_radix(field, 10);

match new_value{
Ok(value) =>{
v.parse_as = ValueType::U32;
v.value = value;
v.allocate()
}
_ =>{
unreachable!()
}
}

}
Compute(mut v) if v.op == OperatorType::Add => {
v.stack = convert_to_usize_multiple(v.stack, state);
v.op = OperatorType::AddAddress;
v.into_instruction().allocate()
}
Compute(mut v) if v.op == OperatorType::Mul => {
v.stack = convert_to_usize_multiple(v.stack, state);
v.op = OperatorType::MulAddress;
v.into_instruction().allocate()
}
Compute(_) =>{
unreachable!()
}
_ => {
// Case variable
ComputeBucket {
line: index.get_line(),
message_id: index.get_message_id(),
op_aux_no: 0,
op: OperatorType::ToAddress,
stack: vec![index.allocate()],
}.allocate()
}

}
}

fn convert_to_usize_multiple(
indexing: Vec<InstructionPointer>,
state: &State,
) -> Vec<InstructionPointer> {
let mut index_stack = vec![];
for i in indexing {
let new_index = convert_to_usize_single(i, state);
index_stack.push(new_index);
}
index_stack
}


fn fold(using: OperatorType, mut stack: Vec<InstructionPointer>, state: &State) -> InstructionPointer {
let instruction = stack.pop().unwrap();
if stack.len() == 0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ impl ComponentRepresentation {
let to_assign = component.to_assign_inputs.clone();

for s in to_assign{
ComponentRepresentation::assign_value_to_signal_init(component, &s.0, &s.1, &s.2)?;
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(())
}
Expand Down Expand Up @@ -228,10 +229,18 @@ impl ComponentRepresentation {
signal_name,
access,
slice_route,
tags
)
}
}

/*
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
*/

pub fn assign_value_to_signal_no_init(
component: &mut ComponentRepresentation,
signal_name: &str,
Expand All @@ -247,18 +256,21 @@ impl ComponentRepresentation {
}

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);

for (t, value) in tags_input{
if !tags.contains_key(t){
return Result::Err(MemoryError::AssignmentMissingTags(t.clone()));
} else{
if component.unassigned_tags.contains(signal_name){
if is_first_assignment_signal{
*value = tags.get(t).unwrap().clone();
component.unassigned_tags.remove(signal_name);
}
else{
// already given a value, check that it is the same
if value != tags.get(t).unwrap(){
return Result::Err(MemoryError::AssignmentTagTwice);
return Result::Err(MemoryError::AssignmentTagInputTwice(t.clone()));
}
}
}
Expand All @@ -272,11 +284,27 @@ impl ComponentRepresentation {
signal_name: &str,
access: &[SliceCapacity],
slice_route: &[SliceCapacity],
tags: TagInfo,
) -> Result<(), MemoryError> {

if !component.inputs.contains_key(signal_name){
return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput));
}

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(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(t.clone()));
}
}
}

let inputs_response = component.inputs.get_mut(signal_name).unwrap();
let signal_previous_value = SignalSlice::access_values(
inputs_response,
Expand Down
Loading

0 comments on commit ca1b7d4

Please sign in to comment.