diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index 35b8f7440dd..9b56183d047 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -544,7 +544,7 @@ mod tests { private parameters: [] public parameters: [w2] return values: [w2] - EXPR [ (2, w1) 8 ] + EXPR 0 = 2*w1 + 8 BLACKBOX::RANGE [w1]:8 bits [] BLACKBOX::AND [w1, w2]:4 bits [w3] BLACKBOX::KECCAKF1600 [w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24, w25] [w26, w27, w28, w29, w30, w31, w32, w33, w34, w35, w36, w37, w38, w39, w40, w41, w42, w43, w44, w45, w46, w47, w48, w49, w50] diff --git a/acvm-repo/acir/src/circuit/opcodes.rs b/acvm-repo/acir/src/circuit/opcodes.rs index f8962bad9bf..fb3da6cddba 100644 --- a/acvm-repo/acir/src/circuit/opcodes.rs +++ b/acvm-repo/acir/src/circuit/opcodes.rs @@ -146,16 +146,97 @@ pub enum Opcode { impl std::fmt::Display for Opcode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Opcode::AssertZero(expr) => expr.fmt(f), + Opcode::AssertZero(expr) => { + write!(f, "EXPR ")?; + + // This is set to an index if we show this expression "as a witness assignment", meaning + // that the linear combination at this index must not be printed again. + let mut assignment_witness: Option = None; + + // If true, negate all coefficients when printing. + // This is set to true if we show this expression "as a witness assignment", and the witness + // had a coefficient of 1 and we "moved" everything to the right of the equal sign. + let mut negate_coefficients = false; + + // Find a linear combination with a coefficient of 1 or -1 and, if there are many, + // keep the one with the largest witness. + let linear_witness_one = expr + .linear_combinations + .iter() + .enumerate() + .filter(|(_, (coefficient, _))| { + coefficient.is_one() || (-*coefficient).is_one() + }) + .max_by_key(|(_, (_, witness))| witness); + + // If we find one, show the expression as equaling this witness to everything else + // (this is likely to happen as in ACIR gen we tend to equate a witness to previous expressions) + if let Some((index, (coefficient, witness))) = linear_witness_one { + assignment_witness = Some(index); + negate_coefficients = coefficient.is_one(); + write!(f, "{witness} = ")?; + } else { + write!(f, "0 = ")?; + } + + let mut printed_term = false; + + for (coefficient, witness1, witness2) in &expr.mul_terms { + let witnesses = [*witness1, *witness2]; + display_term(*coefficient, witnesses, printed_term, negate_coefficients, f)?; + printed_term = true; + } + + for (index, (coefficient, witness)) in expr.linear_combinations.iter().enumerate() { + if assignment_witness + .is_some_and(|show_as_assignment_index| show_as_assignment_index == index) + { + // We already printed this term as part of the assignment + continue; + } + + let witnesses = [*witness]; + display_term(*coefficient, witnesses, printed_term, negate_coefficients, f)?; + printed_term = true; + } + + if expr.q_c.is_zero() { + if !printed_term { + write!(f, "0")?; + } + } else { + let coefficient = expr.q_c; + let coefficient = if negate_coefficients { -coefficient } else { coefficient }; + let coefficient_as_string = coefficient.to_string(); + let coefficient_is_negative = coefficient_as_string.starts_with('-'); + + if printed_term { + if coefficient_is_negative { + write!(f, " - ")?; + } else { + write!(f, " + ")?; + } + } + + let coefficient = if printed_term && coefficient_is_negative { + -coefficient + } else { + coefficient + }; + write!(f, "{coefficient}")?; + } + + Ok(()) + } Opcode::BlackBoxFuncCall(g) => g.fmt(f), Opcode::MemoryOp { block_id, op } => { write!(f, "MEM ")?; let is_read = op.operation.is_zero(); if is_read { - write!(f, "(id: {}, read at: {}, value: {}) ", block_id.0, op.index, op.value) + write!(f, "(id: {}, read at: {}, value: {})", block_id.0, op.index, op.value) } else { - write!(f, "(id: {}, write {} at: {}) ", block_id.0, op.value, op.index) + write!(f, "(id: {}, write {} at: {})", block_id.0, op.value, op.index) } } Opcode::MemoryInit { block_id, init, block_type: databus } => { @@ -207,6 +288,46 @@ impl std::fmt::Display for Opcode { } } +fn display_term( + coefficient: F, + witnesses: [Witness; N], + printed_term: bool, + negate_coefficients: bool, + f: &mut std::fmt::Formatter<'_>, +) -> std::fmt::Result { + let coefficient = if negate_coefficients { -coefficient } else { coefficient }; + let coefficient_as_string = coefficient.to_string(); + let coefficient_is_negative = coefficient_as_string.starts_with('-'); + + if printed_term { + if coefficient_is_negative { + write!(f, " - ")?; + } else { + write!(f, " + ")?; + } + } + + let coefficient = + if printed_term && coefficient_is_negative { -coefficient } else { coefficient }; + + if coefficient.is_one() { + // Don't print the coefficient + } else if (-coefficient).is_one() { + write!(f, "-")?; + } else { + write!(f, "{coefficient}*")?; + } + + for (index, witness) in witnesses.iter().enumerate() { + if index != 0 { + write!(f, "*")?; + } + write!(f, "{witness}")?; + } + + Ok(()) +} + impl std::fmt::Debug for Opcode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self, f) diff --git a/acvm-repo/acir/src/native_types/expression/mod.rs b/acvm-repo/acir/src/native_types/expression/mod.rs index 84e929e1bd9..d536ccfbedb 100644 --- a/acvm-repo/acir/src/native_types/expression/mod.rs +++ b/acvm-repo/acir/src/native_types/expression/mod.rs @@ -58,9 +58,12 @@ impl std::fmt::Display for Expression { for i in &self.linear_combinations { write!(f, "({}, {}) ", i.0, i.1)?; } - write!(f, "{}", self.q_c)?; - write!(f, " ]") + let q_c_as_string = self.q_c.to_string(); + if q_c_as_string != "0" { + write!(f, "{} ", self.q_c)?; + } + write!(f, "]") } } diff --git a/acvm-repo/acir/src/parser/lexer.rs b/acvm-repo/acir/src/parser/lexer.rs index 4049980789c..3c6d6592e8a 100644 --- a/acvm-repo/acir/src/parser/lexer.rs +++ b/acvm-repo/acir/src/parser/lexer.rs @@ -64,6 +64,12 @@ impl<'a> Lexer<'a> { ',' => self.single_char_token(Token::Comma), ':' => self.single_char_token(Token::Colon), ';' => self.single_char_token(Token::Semicolon), + '+' => self.single_char_token(Token::Plus), + '-' if self.peek_char().is_none_or(|char| !char.is_ascii_digit()) => { + self.single_char_token(Token::Minus) + } + '*' => self.single_char_token(Token::Star), + '=' => self.single_char_token(Token::Equal), 'w' if self.peek_char().is_some_and(|char| char.is_ascii_digit()) => { let start = self.position; diff --git a/acvm-repo/acir/src/parser/mod.rs b/acvm-repo/acir/src/parser/mod.rs index 0325d7f7c98..a9e0667488d 100644 --- a/acvm-repo/acir/src/parser/mod.rs +++ b/acvm-repo/acir/src/parser/mod.rs @@ -235,7 +235,7 @@ impl<'a> Parser<'a> { while let Some(keyword) = self.peek_keyword() { match keyword { Keyword::Expression => { - let expr = self.parse_arithmetic_expression()?; + let expr = self.parse_assert_zero_expression()?; opcodes.push(Opcode::AssertZero(expr)); } Keyword::BlackBoxFuncCall => { @@ -260,6 +260,86 @@ impl<'a> Parser<'a> { Ok(opcodes) } + fn parse_assert_zero_expression(&mut self) -> ParseResult> { + // 'EXPR' + self.eat_keyword_or_error(Keyword::Expression)?; + + // Parse the left-hand side terms + let lhs_terms = self.parse_terms_or_error()?; + + // '=' + self.eat_or_error(Token::Equal)?; + + // Parse the right-hand side terms + let rhs_terms = self.parse_terms_or_error()?; + + // If we have something like `0 = ...` or `... = 0`, just consider the expressions + // on the non-zero side. Otherwise we could be "moving" terms to the other side and + // negating them, which won't accurately reflect the original expression. + let expression = if is_zero_term(&lhs_terms) { + build_expression_from_terms(rhs_terms.into_iter()) + } else if is_zero_term(&rhs_terms) { + build_expression_from_terms(lhs_terms.into_iter()) + } else { + // "Move" the terms to the left by negating them + let rhs_terms = rhs_terms.into_iter().map(|term| term.negate()).collect::>(); + build_expression_from_terms(lhs_terms.into_iter().chain(rhs_terms)) + }; + + Ok(expression) + } + + fn parse_terms_or_error(&mut self) -> ParseResult> { + let mut terms = Vec::new(); + let mut negative = self.eat(Token::Minus)?; + loop { + let term = self.parse_term_or_error()?; + let term = if negative { term.negate() } else { term }; + terms.push(term); + + if self.eat(Token::Plus)? { + negative = false; + continue; + } + + if self.eat(Token::Minus)? { + negative = true; + continue; + } + + break; + } + Ok(terms) + } + + fn parse_term_or_error(&mut self) -> ParseResult { + if let Some(coefficient) = self.eat_field_element()? { + if self.eat(Token::Star)? { + let w1 = self.eat_witness_or_error()?; + self.parse_linear_or_multiplication_term(coefficient, w1) + } else { + Ok(Term::Constant(coefficient)) + } + } else if let Some(w1) = self.eat_witness()? { + self.parse_linear_or_multiplication_term(FieldElement::one(), w1) + } else { + self.expected_term() + } + } + + fn parse_linear_or_multiplication_term( + &mut self, + coefficient: FieldElement, + w1: Witness, + ) -> Result { + if self.eat(Token::Star)? { + let w2 = self.eat_witness_or_error()?; + Ok(Term::Multiplication(coefficient, w1, w2)) + } else { + Ok(Term::Linear(coefficient, w1)) + } + } + fn parse_arithmetic_expression(&mut self) -> ParseResult> { self.eat_keyword_or_error(Keyword::Expression)?; self.eat_or_error(Token::LeftBracket)?; @@ -308,9 +388,8 @@ impl<'a> Parser<'a> { } } - let Some(q_c) = constant else { - return Err(ParserError::MissingConstantTerm { span: self.token.span() }); - }; + // If a constant isn't provided, we default it to zero + let q_c = constant.unwrap_or_default(); Ok(Expression { mul_terms, linear_combinations, q_c }) } @@ -977,6 +1056,13 @@ impl<'a> Parser<'a> { }) } + fn expected_term(&mut self) -> ParseResult { + Err(ParserError::ExpectedTerm { + found: self.token.token().clone(), + span: self.token.span(), + }) + } + fn expected_token(&mut self, token: Token) -> ParseResult { Err(ParserError::ExpectedToken { token, @@ -994,10 +1080,48 @@ impl<'a> Parser<'a> { } } +fn build_expression_from_terms(terms: impl Iterator) -> Expression { + // Gather all terms, summing the constants + let mut q_c = FieldElement::zero(); + let mut linear_combinations = Vec::new(); + let mut mul_terms = Vec::new(); + + for term in terms { + match term { + Term::Constant(c) => q_c += c, + Term::Linear(c, w) => linear_combinations.push((c, w)), + Term::Multiplication(c, w1, w2) => mul_terms.push((c, w1, w2)), + } + } + + Expression { mul_terms, linear_combinations, q_c } +} + +fn is_zero_term(terms: &[Term]) -> bool { + terms.len() == 1 && matches!(terms[0], Term::Constant(c) if c.is_zero()) +} + fn eof_spanned_token() -> SpannedToken { SpannedToken::new(Token::Eof, Default::default()) } +#[derive(Debug, Clone, Copy)] +enum Term { + Constant(FieldElement), + Linear(FieldElement, Witness), + Multiplication(FieldElement, Witness, Witness), +} + +impl Term { + fn negate(self) -> Self { + match self { + Term::Constant(c) => Term::Constant(-c), + Term::Linear(c, w) => Term::Linear(-c, w), + Term::Multiplication(c, w1, w2) => Term::Multiplication(-c, w1, w2), + } + } +} + type ParseResult = Result; #[derive(Debug, Error)] @@ -1014,10 +1138,10 @@ pub(crate) enum ParserError { ExpectedFieldElement { found: Token, span: Span }, #[error("Expected a witness index, found '{found}'")] ExpectedWitness { found: Token, span: Span }, + #[error("Expected a term, found '{found}'")] + ExpectedTerm { found: Token, span: Span }, #[error("Duplicate constant term in native Expression")] DuplicatedConstantTerm { found: Token, span: Span }, - #[error("Missing constant term in native Expression")] - MissingConstantTerm { span: Span }, #[error("Expected valid black box function name, found '{found}'")] ExpectedBlackBoxFuncName { found: Token, span: Span }, #[error("Number does not fit in u32, got: '{number}'")] @@ -1042,8 +1166,8 @@ impl ParserError { | ExpectedIdentifier { span, .. } | ExpectedFieldElement { span, .. } | ExpectedWitness { span, .. } + | ExpectedTerm { span, .. } | DuplicatedConstantTerm { span, .. } - | MissingConstantTerm { span } | ExpectedBlackBoxFuncName { span, .. } | IntegerLargerThanU32 { span, .. } | IncorrectInputLength { span, .. } diff --git a/acvm-repo/acir/src/parser/tests.rs b/acvm-repo/acir/src/parser/tests.rs index d6a13336af2..98b0e418dea 100644 --- a/acvm-repo/acir/src/parser/tests.rs +++ b/acvm-repo/acir/src/parser/tests.rs @@ -1,3 +1,5 @@ +use insta::assert_snapshot; + use crate::{ circuit::{Circuit, Program}, parser::ParserError, @@ -102,11 +104,11 @@ fn assert_zero_opcodes() { private parameters: [w0, w1, w2, w3, w4] public parameters: [w5, w6, w7, w8, w9] return values: [] - EXPR [ (1, w0) (-1, w5) 0 ] - EXPR [ (1, w1) (-1, w6) 0 ] - EXPR [ (1, w2) (-1, w7) 0 ] - EXPR [ (1, w3) (-1, w8) 0 ] - EXPR [ (1, w4) (-1, w9) 0 ] + EXPR w5 = w0 + EXPR w6 = w1 + EXPR w7 = w2 + EXPR w8 = w3 + EXPR w9 = w4 "; assert_circuit_roundtrip(src); } @@ -118,11 +120,11 @@ fn assert_zero_with_mul_terms() { private parameters: [w0, w1, w2] public parameters: [] return values: [] - EXPR [ (1, w0, w1) (-1, w3) 0 ] - EXPR [ (1, w3, w3) (-1, w4) 0 ] - EXPR [ (1, w4, w4) (-1, w5) 0 ] - EXPR [ (1, w5, w5) (-1, w6) 0 ] - EXPR [ (-1, w2) (1, w6) 0 ] + EXPR w3 = w0*w1 + EXPR w4 = w3*w3 + EXPR w5 = w4*w4 + EXPR w6 = w5*w5 + EXPR w6 = w2 "; assert_circuit_roundtrip(src); } @@ -149,7 +151,7 @@ fn xor() { BLACKBOX::RANGE [w0]:32 bits [] BLACKBOX::RANGE [w1]:32 bits [] BLACKBOX::XOR [w0, w1]:32 bits [w2] - EXPR [ (1, w2) -15 ] + EXPR w2 = 15 "; assert_circuit_roundtrip(src); } @@ -223,22 +225,22 @@ fn aes128_encrypt() { BLACKBOX::RANGE [w58]:8 bits [] BLACKBOX::RANGE [w59]:8 bits [] BLACKBOX::AES128_ENCRYPT [w12, w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24, w25, w26, w27, w28, w29, w30, w31, w32, w33, w34, w35, w36, w37, w38, w39, w40, w41, w42, w43] [w60, w61, w62, w63, w64, w65, w66, w67, w68, w69, w70, w71, w72, w73, w74, w75] - EXPR [ (-1, w44) (1, w60) 0 ] - EXPR [ (-1, w45) (1, w61) 0 ] - EXPR [ (-1, w46) (1, w62) 0 ] - EXPR [ (-1, w47) (1, w63) 0 ] - EXPR [ (-1, w48) (1, w64) 0 ] - EXPR [ (-1, w49) (1, w65) 0 ] - EXPR [ (-1, w50) (1, w66) 0 ] - EXPR [ (-1, w51) (1, w67) 0 ] - EXPR [ (-1, w52) (1, w68) 0 ] - EXPR [ (-1, w53) (1, w69) 0 ] - EXPR [ (-1, w54) (1, w70) 0 ] - EXPR [ (-1, w55) (1, w71) 0 ] - EXPR [ (-1, w56) (1, w72) 0 ] - EXPR [ (-1, w57) (1, w73) 0 ] - EXPR [ (-1, w58) (1, w74) 0 ] - EXPR [ (-1, w59) (1, w75) 0 ] + EXPR w60 = w44 + EXPR w61 = w45 + EXPR w62 = w46 + EXPR w63 = w47 + EXPR w64 = w48 + EXPR w65 = w49 + EXPR w66 = w50 + EXPR w67 = w51 + EXPR w68 = w52 + EXPR w69 = w53 + EXPR w70 = w54 + EXPR w71 = w55 + EXPR w72 = w56 + EXPR w73 = w57 + EXPR w74 = w58 + EXPR w75 = w59 "; assert_circuit_roundtrip(src); } @@ -463,7 +465,7 @@ fn memory_read() { private parameters: [] public parameters: [] return values: [] - MEM (id: 0, read at: EXPR [ (1, w0) 0 ], value: EXPR [ (1, w1) 0 ]) + MEM (id: 0, read at: EXPR [ (1, w0) ], value: EXPR [ (1, w1) ]) "; assert_circuit_roundtrip(src); } @@ -475,7 +477,7 @@ fn memory_write() { private parameters: [] public parameters: [] return values: [] - MEM (id: 3, write EXPR [ (1, w0) 0 ] at: EXPR [ (1, w1) 0 ]) + MEM (id: 3, write EXPR [ (1, w0) ] at: EXPR [ (1, w1) ]) "; assert_circuit_roundtrip(src); } @@ -524,9 +526,9 @@ fn brillig_call() { private parameters: [w0, w1, w2] public parameters: [] return values: [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) (-1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w0, w3) (-1, w1, w3) -1 ] - EXPR [ (-1, w0) (1, w2) 0 ] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) (-1, w1) ]], outputs: [w3] + EXPR 0 = w0*w3 - w1*w3 - 1 + EXPR w2 = w0 "; assert_circuit_roundtrip(src); } @@ -539,9 +541,9 @@ fn brillig_call_with_predicate() { public parameters: [] return values: [] BRILLIG CALL func 0: PREDICATE: EXPR [ 1 ] - inputs: [EXPR [ (1, w0) (-1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w0, w3) (-1, w1, w3) -1 ] - EXPR [ (-1, w0) (1, w2) 0 ] + inputs: [EXPR [ (1, w0) (-1, w1) ]], outputs: [w3] + EXPR 0 = w0*w3 - w1*w3 - 1 + EXPR w2 = w0 "; assert_circuit_roundtrip(src); } @@ -606,97 +608,97 @@ fn array_dynamic() { BLACKBOX::RANGE [w15]:32 bits [] BLACKBOX::RANGE [w16]:32 bits [] BLACKBOX::RANGE [w17]:32 bits [] - EXPR [ (5, w6) (-1, w19) 0 ] + EXPR w19 = 5*w6 BLACKBOX::RANGE [w19]:32 bits [] - EXPR [ (1, w5) (-1, w19) (-1, w20) 0 ] + EXPR w20 = w5 - w19 BLACKBOX::RANGE [w20]:32 bits [] - EXPR [ (1, w20) (-1, w21) -5 ] - EXPR [ (1, w21) (-1, w22) -3 ] - MEM (id: 0, read at: EXPR [ (1, w21) 0 ], value: EXPR [ (1, w23) 0 ]) - EXPR [ (1, w23) -111 ] - MEM (id: 0, read at: EXPR [ (1, w22) 0 ], value: EXPR [ (1, w24) 0 ]) - EXPR [ (1, w24) -101 ] + EXPR w21 = w20 - 5 + EXPR w22 = w21 - 3 + MEM (id: 0, read at: EXPR [ (1, w21) ], value: EXPR [ (1, w23) ]) + EXPR w23 = 111 + MEM (id: 0, read at: EXPR [ (1, w22) ], value: EXPR [ (1, w24) ]) + EXPR w24 = 101 BRILLIG CALL func 0: inputs: [EXPR [ (1, w22) 4294967291 ], EXPR [ 4294967296 ]], outputs: [w25, w26] BLACKBOX::RANGE [w26]:32 bits [] - EXPR [ (1, w22) (-4294967296, w25) (-1, w26) 4294967291 ] - EXPR [ (-1, w25) 0 ] - EXPR [ (-1, w27) 0 ] - MEM (id: 0, write EXPR [ (1, w27) 0 ] at: EXPR [ (1, w22) 0 ]) - MEM (id: 0, read at: EXPR [ (1, w21) 0 ], value: EXPR [ (1, w28) 0 ]) - EXPR [ (1, w28) -111 ] - EXPR [ (-1, w29) 1 ] - MEM (id: 0, read at: EXPR [ (1, w29) 0 ], value: EXPR [ (1, w30) 0 ]) - EXPR [ (1, w30) 0 ] + EXPR w26 = w22 - 4294967296*w25 + 4294967291 + EXPR w25 = 0 + EXPR w27 = 0 + MEM (id: 0, write EXPR [ (1, w27) ] at: EXPR [ (1, w22) ]) + MEM (id: 0, read at: EXPR [ (1, w21) ], value: EXPR [ (1, w28) ]) + EXPR w28 = 111 + EXPR w29 = 1 + MEM (id: 0, read at: EXPR [ (1, w29) ], value: EXPR [ (1, w30) ]) + EXPR w30 = 0 BRILLIG CALL func 0: inputs: [EXPR [ (1, w21) 4294967286 ], EXPR [ 4294967296 ]], outputs: [w31, w32] BLACKBOX::RANGE [w31]:1 bits [] BLACKBOX::RANGE [w32]:32 bits [] - EXPR [ (1, w21) (-4294967296, w31) (-1, w32) 4294967286 ] - EXPR [ (-1, w21, w31) (1, w21) (-1, w33) 0 ] - MEM (id: 0, read at: EXPR [ (1, w33) 0 ], value: EXPR [ (1, w34) 0 ]) - EXPR [ (-1, w31, w34) (2, w31) (1, w34) (-1, w35) -2 ] + EXPR w32 = w21 - 4294967296*w31 + 4294967286 + EXPR w33 = -w21*w31 + w21 + MEM (id: 0, read at: EXPR [ (1, w33) ], value: EXPR [ (1, w34) ]) + EXPR w35 = -w31*w34 + 2*w31 + w34 - 2 BLACKBOX::RANGE [w35]:32 bits [] BRILLIG CALL func 0: inputs: [EXPR [ (1, w21) 4294967291 ], EXPR [ 4294967296 ]], outputs: [w36, w37] BLACKBOX::RANGE [w36]:1 bits [] BLACKBOX::RANGE [w37]:32 bits [] - EXPR [ (1, w21) (-4294967296, w36) (-1, w37) 4294967291 ] - EXPR [ (1, w31, w36) (-1, w36) 0 ] - EXPR [ (-1, w21, w31) (1, w21) (-1, w38) 0 ] - MEM (id: 0, read at: EXPR [ (1, w38) 0 ], value: EXPR [ (1, w39) 0 ]) - MEM (id: 0, read at: EXPR [ (1, w27) 0 ], value: EXPR [ (1, w40) 0 ]) - MEM (id: 0, read at: EXPR [ (1, w29) 0 ], value: EXPR [ (1, w41) 0 ]) - EXPR [ (-1, w42) 2 ] - MEM (id: 0, read at: EXPR [ (1, w42) 0 ], value: EXPR [ (1, w43) 0 ]) - EXPR [ (-1, w44) 3 ] - MEM (id: 0, read at: EXPR [ (1, w44) 0 ], value: EXPR [ (1, w45) 0 ]) - EXPR [ (-1, w46) 4 ] - MEM (id: 0, read at: EXPR [ (1, w46) 0 ], value: EXPR [ (1, w47) 0 ]) + EXPR w37 = w21 - 4294967296*w36 + 4294967291 + EXPR w36 = w31*w36 + EXPR w38 = -w21*w31 + w21 + MEM (id: 0, read at: EXPR [ (1, w38) ], value: EXPR [ (1, w39) ]) + MEM (id: 0, read at: EXPR [ (1, w27) ], value: EXPR [ (1, w40) ]) + MEM (id: 0, read at: EXPR [ (1, w29) ], value: EXPR [ (1, w41) ]) + EXPR w42 = 2 + MEM (id: 0, read at: EXPR [ (1, w42) ], value: EXPR [ (1, w43) ]) + EXPR w44 = 3 + MEM (id: 0, read at: EXPR [ (1, w44) ], value: EXPR [ (1, w45) ]) + EXPR w46 = 0 + MEM (id: 0, read at: EXPR [ (1, w46) ], value: EXPR [ (1, w47) ]) INIT (id: 3, len: 5, witnesses: [w40, w41, w43, w45, w47]) - EXPR [ (-1, w31, w35) (1, w31, w39) (1, w35) (-1, w48) 0 ] - MEM (id: 3, write EXPR [ (1, w48) 0 ] at: EXPR [ (1, w38) 0 ]) - MEM (id: 3, read at: EXPR [ (1, w46) 0 ], value: EXPR [ (1, w49) 0 ]) - MEM (id: 0, read at: EXPR [ (1, w46) 0 ], value: EXPR [ (1, w50) 0 ]) - EXPR [ (-1, w31, w36) 0 ] - EXPR [ (1, w21, w31) (-1, w51) 0 ] - MEM (id: 0, read at: EXPR [ (1, w51) 0 ], value: EXPR [ (1, w52) 0 ]) - EXPR [ (-1, w31, w52) (1, w52) (-1, w53) 0 ] - MEM (id: 0, write EXPR [ (1, w53) 0 ] at: EXPR [ (1, w51) 0 ]) - MEM (id: 0, read at: EXPR [ (1, w46) 0 ], value: EXPR [ (1, w54) 0 ]) - EXPR [ (-1, w31) (-1, w55) 1 ] - EXPR [ (-1, w31, w49) (1, w31, w50) (1, w49) (-1, w56) 0 ] - EXPR [ (1, w31, w54) (1, w55, w56) -109 ] - EXPR [ (-1, w57) 246 ] - EXPR [ (-1, w58) 159 ] - EXPR [ (-1, w59) 32 ] - EXPR [ (-1, w60) 176 ] - EXPR [ (-1, w61) 8 ] + EXPR w48 = -w31*w35 + w31*w39 + w35 + MEM (id: 3, write EXPR [ (1, w48) ] at: EXPR [ (1, w38) ]) + MEM (id: 3, read at: EXPR [ (1, w46) ], value: EXPR [ (1, w49) ]) + MEM (id: 0, read at: EXPR [ (1, w46) ], value: EXPR [ (1, w50) ]) + EXPR 0 = -w31*w36 + EXPR w51 = w21*w31 + MEM (id: 0, read at: EXPR [ (1, w51) ], value: EXPR [ (1, w52) ]) + EXPR w53 = -w31*w52 + w52 + MEM (id: 0, write EXPR [ (1, w53) ] at: EXPR [ (1, w51) ]) + MEM (id: 0, read at: EXPR [ (1, w46) ], value: EXPR [ (1, w54) ]) + EXPR w55 = -w31 + 1 + EXPR w56 = -w31*w49 + w31*w50 + w49 + EXPR 0 = w31*w54 + w55*w56 - 109 + EXPR w57 = 246 + EXPR w58 = 159 + EXPR w59 = 32 + EXPR w60 = 176 + EXPR w61 = 8 INIT (id: 4, len: 5, witnesses: [w57, w58, w59, w60, w61]) - MEM (id: 4, read at: EXPR [ (1, w7) 0 ], value: EXPR [ (1, w62) 0 ]) - MEM (id: 4, read at: EXPR [ (1, w8) 0 ], value: EXPR [ (1, w63) 0 ]) - MEM (id: 4, read at: EXPR [ (1, w9) 0 ], value: EXPR [ (1, w64) 0 ]) - MEM (id: 4, read at: EXPR [ (1, w10) 0 ], value: EXPR [ (1, w65) 0 ]) - MEM (id: 4, read at: EXPR [ (1, w11) 0 ], value: EXPR [ (1, w66) 0 ]) - BRILLIG CALL func 1: inputs: [EXPR [ (1, w62) (1, w63) (1, w64) (1, w65) (1, w66) 0 ]], outputs: [w67] - EXPR [ (1, w62, w67) (1, w63, w67) (1, w64, w67) (1, w65, w67) (1, w66, w67) -1 ] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w18) 0 ], EXPR [ 4294967296 ]], outputs: [w68, w69] + MEM (id: 4, read at: EXPR [ (1, w7) ], value: EXPR [ (1, w62) ]) + MEM (id: 4, read at: EXPR [ (1, w8) ], value: EXPR [ (1, w63) ]) + MEM (id: 4, read at: EXPR [ (1, w9) ], value: EXPR [ (1, w64) ]) + MEM (id: 4, read at: EXPR [ (1, w10) ], value: EXPR [ (1, w65) ]) + MEM (id: 4, read at: EXPR [ (1, w11) ], value: EXPR [ (1, w66) ]) + BRILLIG CALL func 1: inputs: [EXPR [ (1, w62) (1, w63) (1, w64) (1, w65) (1, w66) ]], outputs: [w67] + EXPR 0 = w62*w67 + w63*w67 + w64*w67 + w65*w67 + w66*w67 - 1 + BRILLIG CALL func 0: inputs: [EXPR [ (1, w18) ], EXPR [ 4294967296 ]], outputs: [w68, w69] BLACKBOX::RANGE [w68]:222 bits [] BLACKBOX::RANGE [w69]:32 bits [] - EXPR [ (1, w18) (-4294967296, w68) (-1, w69) 0 ] - EXPR [ (-1, w68) (-1, w70) 5096253676302562286669017222071363378443840053029366383258766538131 ] + EXPR w69 = w18 - 4294967296*w68 + EXPR w70 = -w68 + 5096253676302562286669017222071363378443840053029366383258766538131 BLACKBOX::RANGE [w70]:222 bits [] BRILLIG CALL func 1: inputs: [EXPR [ (-1, w68) 5096253676302562286669017222071363378443840053029366383258766538131 ]], outputs: [w71] - EXPR [ (-1, w68, w71) (5096253676302562286669017222071363378443840053029366383258766538131, w71) (1, w72) -1 ] - EXPR [ (-1, w68, w72) (5096253676302562286669017222071363378443840053029366383258766538131, w72) 0 ] - EXPR [ (1, w69, w72) (268435455, w72) (-1, w73) 0 ] + EXPR w72 = w68*w71 - 5096253676302562286669017222071363378443840053029366383258766538131*w71 + 1 + EXPR 0 = -w68*w72 + 5096253676302562286669017222071363378443840053029366383258766538131*w72 + EXPR w73 = w69*w72 + 268435455*w72 BLACKBOX::RANGE [w73]:32 bits [] BRILLIG CALL func 0: inputs: [EXPR [ (-1, w69) 4294967299 ], EXPR [ 4294967296 ]], outputs: [w74, w75] BLACKBOX::RANGE [w74]:1 bits [] BLACKBOX::RANGE [w75]:32 bits [] - EXPR [ (-1, w69) (-4294967296, w74) (-1, w75) 4294967299 ] - EXPR [ (-1, w17, w74) (1, w17) (-3, w74) (-1, w76) 3 ] + EXPR w75 = -w69 - 4294967296*w74 + 4294967299 + EXPR w76 = -w17*w74 + w17 - 3*w74 + 3 BLACKBOX::RANGE [w76]:32 bits [] - EXPR [ (-1, w74, w76) (1, w76) (-1, w77) 0 ] - MEM (id: 1, read at: EXPR [ (1, w77) 0 ], value: EXPR [ (1, w78) 0 ]) - EXPR [ (1, w15, w74) (-1, w74, w78) (-1, w15) (1, w78) 0 ] + EXPR w77 = -w74*w76 + w76 + MEM (id: 1, read at: EXPR [ (1, w77) ], value: EXPR [ (1, w78) ]) + EXPR w78 = -w15*w74 + w74*w78 + w15 "; assert_circuit_roundtrip(src); } @@ -711,15 +713,15 @@ fn fold_basic() { return values: [] CALL func 1: PREDICATE: EXPR [ 1 ] inputs: [w0, w1], outputs: [w2] - + func 1 current witness: w3 private parameters: [w0, w1] public parameters: [] return values: [w2] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) (-1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w0, w3) (-1, w1, w3) -1 ] - EXPR [ (-1, w0) (1, w2) 0 ] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) (-1, w1) ]], outputs: [w3] + EXPR 0 = w0*w3 - w1*w3 - 1 + EXPR w2 = w0 "; assert_program_roundtrip(src); } @@ -734,15 +736,15 @@ fn fold_basic_mismatched_ids() { return values: [] CALL func 1: PREDICATE: EXPR [ 1 ] inputs: [w0, w1], outputs: [w2] - + func 2 current witness: w3 private parameters: [w0, w1] public parameters: [] return values: [w2] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) (-1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w0, w3) (-1, w1, w3) -1 ] - EXPR [ (-1, w0) (1, w2) 0 ] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) (-1, w1) ]], outputs: [w3] + EXPR w0*w3 - w1*w3 - 1 = 0 + EXPR w0 = w2 "; let result = Program::from_str(src).err().unwrap(); let ParserError::UnexpectedFunctionId { expected, found, .. } = result.get_error() else { @@ -751,3 +753,41 @@ fn fold_basic_mismatched_ids() { assert_eq!(expected, 1); assert_eq!(found, 2); } + +#[test] +fn assert_zero_equation() { + let src = " + current witness: w9 + private parameters: [w0, w1, w2, w2] + public parameters: [] + return values: [] + EXPR -w0 + w1 - 10 + 20 + w0*w2 = w2 - w3 + w0*w1 - w1*w2 - 30 + "; + let circuit = Circuit::from_str(src).unwrap(); + assert_snapshot!(circuit.to_string(), @r" + current witness: w9 + private parameters: [w0, w1, w2] + public parameters: [] + return values: [] + EXPR w3 = -w0*w2 + w0*w1 - w1*w2 + w0 - w1 + w2 - 40 + "); +} + +#[test] +fn does_not_negate_when_equal_to_zero() { + let src = " + current witness: w9 + private parameters: [w0, w1, w2] + public parameters: [] + return values: [] + EXPR w0*w1 + w0*w2 = 0 + "; + let circuit = Circuit::from_str(src).unwrap(); + assert_snapshot!(circuit.to_string(), @r" + current witness: w9 + private parameters: [w0, w1, w2] + public parameters: [] + return values: [] + EXPR 0 = w0*w1 + w0*w2 + "); +} diff --git a/acvm-repo/acir/src/parser/token.rs b/acvm-repo/acir/src/parser/token.rs index 8bd00af391f..7cc805ac06c 100644 --- a/acvm-repo/acir/src/parser/token.rs +++ b/acvm-repo/acir/src/parser/token.rs @@ -48,6 +48,14 @@ pub(crate) enum Token { LeftParen, /// ) RightParen, + /// + + Plus, + /// - + Minus, + /// * + Star, + /// = + Equal, Eof, } @@ -75,6 +83,10 @@ impl std::fmt::Display for Token { Token::RightBracket => write!(f, "]"), Token::LeftParen => write!(f, "("), Token::RightParen => write!(f, ")"), + Token::Plus => write!(f, "+"), + Token::Minus => write!(f, "-"), + Token::Star => write!(f, "*"), + Token::Equal => write!(f, "="), Token::Eof => write!(f, "(end of stream)"), } } diff --git a/acvm-repo/acvm/src/compiler/optimizers/general.rs b/acvm-repo/acvm/src/compiler/optimizers/general.rs index 41ccc1e6dec..788981b33af 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/general.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/general.rs @@ -93,7 +93,7 @@ mod tests { return values: [] // The first multiplication should be removed - EXPR [ (0, w0, w1) (1, w0, w1) 0 ] + EXPR 0*w0*w1 + w0*w1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = optimize(circuit); @@ -102,7 +102,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (1, w0, w1) 0 ] + EXPR 0 = w0*w1 "); } @@ -115,7 +115,7 @@ mod tests { return values: [] // The first linear combination should be removed - EXPR [ (0, w0) (1, w1) 0 ] + EXPR 0*w0 + w1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = optimize(circuit); @@ -124,7 +124,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (1, w1) 0 ] + EXPR w1 = 0 "); } @@ -138,7 +138,7 @@ mod tests { // There are all mul terms with the same variables so we should end up with just one // that is the sum of all the coefficients - EXPR [ (2, w0, w1) (3, w1, w0) (4, w0, w1) 0 ] + EXPR 2*w0*w1 + 3*w1*w0 + 4*w0*w1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = optimize(circuit); @@ -147,7 +147,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (9, w0, w1) 0 ] + EXPR 0 = 9*w0*w1 "); } @@ -158,7 +158,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (2, w0, w1) (3, w1, w0) (-5, w0, w1) 0 ] + EXPR 2*w0*w1 + 3*w1*w0 - 5*w0*w1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = optimize(circuit); @@ -167,7 +167,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ 0 ] + EXPR 0 = 0 "); } @@ -181,7 +181,7 @@ mod tests { // These are all linear terms with the same variable so we should end up with just one // that is the sum of all the coefficients - EXPR [ (1, w0) (2, w0) (3, w0) 0 ] + EXPR w0 + 2*w0 + 3*w0 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = optimize(circuit); @@ -190,7 +190,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (6, w0) 0 ] + EXPR 0 = 6*w0 "); } @@ -201,7 +201,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (1, w0) (2, w0) (-3, w0) 0 ] + EXPR w0 + 2*w0 - 3*w0 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = optimize(circuit); @@ -210,7 +210,7 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ 0 ] + EXPR 0 = 0 "); } } diff --git a/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs b/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs index d574f8dd6d8..7d13dfbe427 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/merge_expressions.rs @@ -304,8 +304,8 @@ mod tests { public parameters: [] return values: [] BRILLIG CALL func 0: inputs: [], outputs: [w1] - EXPR [ (2, w0) (3, w1) (1, w2) 1 ] - EXPR [ (2, w0) (2, w1) (1, w5) 1 ] + EXPR 2*w0 + 3*w1 + w2 + 1 = 0 + EXPR 2*w0 + 2*w1 + w5 + 1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = merge_expressions(circuit.clone()); @@ -319,8 +319,8 @@ mod tests { private parameters: [w0] public parameters: [] return values: [w1, w2] - EXPR [ (-1, w0, w0) (1, w1) 0 ] - EXPR [ (-1, w1) (1, w2) 0 ] + EXPR -w0*w0 + w1 = 0 + EXPR -w1 + w2 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = merge_expressions(circuit.clone()); @@ -334,10 +334,10 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (1, w0, w0) (-1, w4) 0 ] - EXPR [ (1, w0, w1) (1, w5) 0 ] - EXPR [ (-1, w2) (1, w4) (1, w5) 0 ] - EXPR [ (1, w2) (-1, w3) (1, w4) (1, w5) 0 ] + EXPR w0*w0 - w4 = 0 + EXPR w0*w1 + w5 = 0 + EXPR -w2 + w4 + w5 = 0 + EXPR w2 - w3 + w4 + w5 = 0 BLACKBOX::RANGE [w3]:32 bits [] "; let circuit = Circuit::from_str(src).unwrap(); @@ -348,8 +348,8 @@ mod tests { private parameters: [w0, w1] public parameters: [] return values: [] - EXPR [ (1, w0, w1) (1, w5) 0 ] - EXPR [ (2, w0, w0) (-1, w3) (2, w5) 0 ] + EXPR w5 = -w0*w1 + EXPR w3 = 2*w0*w0 + 2*w5 BLACKBOX::RANGE [w3]:32 bits [] "); } @@ -367,8 +367,8 @@ mod tests { return values: [w2] BRILLIG CALL func 0: inputs: [], outputs: [w3] BLACKBOX::AND [w0, w1]:8 bits [w4] - EXPR [ (1, w3) (-1, w4) 0 ] - EXPR [ (-1, w2) (1, w4) 0 ] + EXPR w3 - w4 = 0 + EXPR -w2 + w4 = 0 "; let circuit = Circuit::from_str(src).unwrap(); let optimized_circuit = merge_expressions(circuit.clone()); diff --git a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs index 38e743400a1..b18582a89c4 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -349,10 +349,10 @@ mod tests { return values: [] BLACKBOX::RANGE [w1]:16 bits [] BLACKBOX::RANGE [w1]:16 bits [] - EXPR [ 0 ] - EXPR [ 0 ] - EXPR [ 0 ] - EXPR [ 0 ] + EXPR 0 = 0 + EXPR 0 = 0 + EXPR 0 = 0 + EXPR 0 = 0 "; let circuit = Circuit::from_str(src).unwrap(); @@ -366,10 +366,10 @@ mod tests { public parameters: [] return values: [] BLACKBOX::RANGE [w1]:16 bits [] - EXPR [ 0 ] - EXPR [ 0 ] - EXPR [ 0 ] - EXPR [ 0 ] + EXPR 0 = 0 + EXPR 0 = 0 + EXPR 0 = 0 + EXPR 0 = 0 "); } @@ -382,7 +382,7 @@ mod tests { public parameters: [] return values: [] BLACKBOX::RANGE [w1]:16 bits [] - EXPR [ (1, w1) 0 ] + EXPR w1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); @@ -395,7 +395,7 @@ mod tests { private parameters: [] public parameters: [] return values: [] - EXPR [ (1, w1) 0 ] + EXPR w1 = 0 "); } @@ -420,7 +420,7 @@ mod tests { BLACKBOX::RANGE [w1]:64 bits [] // assert w1 == 0 - EXPR [ (1, w1) 0 ] + EXPR w1 = 0 "; let circuit = Circuit::from_str(src).unwrap(); @@ -441,10 +441,10 @@ mod tests { public parameters: [] return values: [] BLACKBOX::RANGE [w1]:32 bits [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w2) 0 ]], outputs: [] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w2) ]], outputs: [] BLACKBOX::RANGE [w1]:16 bits [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w2) 0 ]], outputs: [] - EXPR [ (1, w1) 0 ] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w2) ]], outputs: [] + EXPR w1 = 0 "); // Applying again should have no effect (despite the range having the same bit size as the assert). @@ -478,7 +478,7 @@ mod tests { public parameters: [] return values: [] INIT (id: 0, len: 8, witnesses: [w0, w0, w0, w0, w0, w0, w0, w0]) - MEM (id: 0, read at: EXPR [ (1, w1) 0 ], value: EXPR [ (1, w2) 0 ]) + MEM (id: 0, read at: EXPR [ (1, w1) ], value: EXPR [ (1, w2) ]) "); } } diff --git a/compiler/noirc_evaluator/src/acir/tests/arrays.rs b/compiler/noirc_evaluator/src/acir/tests/arrays.rs index f45df4b61d8..2b235dcb579 100644 --- a/compiler/noirc_evaluator/src/acir/tests/arrays.rs +++ b/compiler/noirc_evaluator/src/acir/tests/arrays.rs @@ -49,12 +49,12 @@ fn constant_array_access_out_of_bounds() { private parameters: [] public parameters: [] return values: [] - EXPR [ (-1, w0) 0 ] - EXPR [ (-1, w1) 1 ] + EXPR w0 = 0 + EXPR w1 = 1 INIT (id: 0, len: 2, witnesses: [w0, w1]) - EXPR [ (-1, w2) 5 ] - MEM (id: 0, read at: EXPR [ (1, w2) 0 ], value: EXPR [ (1, w3) 0 ]) - EXPR [ (1, w3) 0 ] + EXPR w2 = 5 + MEM (id: 0, read at: EXPR [ (1, w2) ], value: EXPR [ (1, w3) ]) + EXPR w3 = 0 "); } @@ -96,8 +96,8 @@ fn generates_memory_op_for_dynamic_read() { public parameters: [] return values: [] INIT (id: 0, len: 3, witnesses: [w0, w1, w2]) - MEM (id: 0, read at: EXPR [ (1, w3) 0 ], value: EXPR [ (1, w4) 0 ]) - EXPR [ (1, w4) -10 ] + MEM (id: 0, read at: EXPR [ (1, w3) ], value: EXPR [ (1, w4) ]) + EXPR w4 = 10 "); } @@ -120,17 +120,17 @@ fn generates_memory_op_for_dynamic_write() { public parameters: [] return values: [w4, w5, w6] INIT (id: 1, len: 3, witnesses: [w0, w1, w2]) - EXPR [ (-1, w7) 10 ] - MEM (id: 1, write EXPR [ (1, w7) 0 ] at: EXPR [ (1, w3) 0 ]) - EXPR [ (-1, w8) 0 ] - MEM (id: 1, read at: EXPR [ (1, w8) 0 ], value: EXPR [ (1, w9) 0 ]) - EXPR [ (-1, w10) 1 ] - MEM (id: 1, read at: EXPR [ (1, w10) 0 ], value: EXPR [ (1, w11) 0 ]) - EXPR [ (-1, w12) 2 ] - MEM (id: 1, read at: EXPR [ (1, w12) 0 ], value: EXPR [ (1, w13) 0 ]) - EXPR [ (1, w4) (-1, w9) 0 ] - EXPR [ (1, w5) (-1, w11) 0 ] - EXPR [ (1, w6) (-1, w13) 0 ] + EXPR w7 = 10 + MEM (id: 1, write EXPR [ (1, w7) ] at: EXPR [ (1, w3) ]) + EXPR w8 = 0 + MEM (id: 1, read at: EXPR [ (1, w8) ], value: EXPR [ (1, w9) ]) + EXPR w10 = 1 + MEM (id: 1, read at: EXPR [ (1, w10) ], value: EXPR [ (1, w11) ]) + EXPR w12 = 2 + MEM (id: 1, read at: EXPR [ (1, w12) ], value: EXPR [ (1, w13) ]) + EXPR w9 = w4 + EXPR w11 = w5 + EXPR w13 = w6 "); } @@ -149,7 +149,7 @@ fn generates_predicated_index_for_dynamic_read() { // w0, w1, w2 represents the array // So w3 represents our index and w4 is our predicate - // We can see that before the read we have `EXPR [ (1, w3, w4) (-1, w5) 0 ]` + // We can see that before the read we have `w3*w4 - w5 = 0` // As the index is zero this is a simplified version of `index*predicate + (1-predicate)*offset` // w5 is then used as the index which we use to read from the memory block assert_circuit_snapshot!(program, @r" @@ -161,9 +161,9 @@ fn generates_predicated_index_for_dynamic_read() { INIT (id: 0, len: 3, witnesses: [w0, w1, w2]) BLACKBOX::RANGE [w3]:32 bits [] BLACKBOX::RANGE [w4]:1 bits [] - EXPR [ (1, w3, w4) (-1, w5) 0 ] - MEM (id: 0, read at: EXPR [ (1, w5) 0 ], value: EXPR [ (1, w6) 0 ]) - EXPR [ (1, w6) -10 ] + EXPR w5 = w3*w4 + MEM (id: 0, read at: EXPR [ (1, w5) ], value: EXPR [ (1, w6) ]) + EXPR w6 = 10 "); } @@ -180,15 +180,15 @@ fn generates_predicated_index_and_dummy_value_for_dynamic_write() { let program = ssa_to_acir_program(src); // Similar to the `generates_predicated_index_for_dynamic_read` test we can - // see how `EXPR [ (1, w3, w4) (-1, w8) 0 ]` forms our predicated index. + // see how `w3*w4 - w8 = 0` forms our predicated index. // However, now we also have extra logic for generating a dummy value. // The original value we want to write is `Field 10` and our predicate is `w4`. // We read the value at the predicated index into `w9`. This is our dummy value. // We can then see how we form our new store value with: - // `EXPR [ (-1, w4, w9) (10, w4) (1, w9) (-1, w10) 0 ]` -> (predicate*value + (1-predicate)*dummy) - // `(10, w4)` -> predicate*value - // `(-1, w4, w9)` -> (-predicate * dummy) - // `(1, w9)` -> dummy + // `EXPR -w4*w9 + 10*w4 + w9 - w10 = 0` -> (predicate*value + (1-predicate)*dummy) + // `10*w4` -> predicate*value + // `-w4*w9` -> (-predicate * dummy) + // `w9` -> dummy // As expected, we then store `w10` at the predicated index `w8`. assert_circuit_snapshot!(program, @r" func 0 @@ -199,20 +199,20 @@ fn generates_predicated_index_and_dummy_value_for_dynamic_write() { INIT (id: 0, len: 3, witnesses: [w0, w1, w2]) BLACKBOX::RANGE [w3]:32 bits [] BLACKBOX::RANGE [w4]:1 bits [] - EXPR [ (1, w3, w4) (-1, w8) 0 ] - MEM (id: 0, read at: EXPR [ (1, w8) 0 ], value: EXPR [ (1, w9) 0 ]) + EXPR w8 = w3*w4 + MEM (id: 0, read at: EXPR [ (1, w8) ], value: EXPR [ (1, w9) ]) INIT (id: 1, len: 3, witnesses: [w0, w1, w2]) - EXPR [ (-1, w4, w9) (10, w4) (1, w9) (-1, w10) 0 ] - MEM (id: 1, write EXPR [ (1, w10) 0 ] at: EXPR [ (1, w8) 0 ]) - EXPR [ (-1, w11) 0 ] - MEM (id: 1, read at: EXPR [ (1, w11) 0 ], value: EXPR [ (1, w12) 0 ]) - EXPR [ (-1, w13) 1 ] - MEM (id: 1, read at: EXPR [ (1, w13) 0 ], value: EXPR [ (1, w14) 0 ]) - EXPR [ (-1, w15) 2 ] - MEM (id: 1, read at: EXPR [ (1, w15) 0 ], value: EXPR [ (1, w16) 0 ]) - EXPR [ (1, w5) (-1, w12) 0 ] - EXPR [ (1, w6) (-1, w14) 0 ] - EXPR [ (1, w7) (-1, w16) 0 ] + EXPR w10 = -w4*w9 + 10*w4 + w9 + MEM (id: 1, write EXPR [ (1, w10) ] at: EXPR [ (1, w8) ]) + EXPR w11 = 0 + MEM (id: 1, read at: EXPR [ (1, w11) ], value: EXPR [ (1, w12) ]) + EXPR w13 = 1 + MEM (id: 1, read at: EXPR [ (1, w13) ], value: EXPR [ (1, w14) ]) + EXPR w15 = 2 + MEM (id: 1, read at: EXPR [ (1, w15) ], value: EXPR [ (1, w16) ]) + EXPR w12 = w5 + EXPR w14 = w6 + EXPR w16 = w7 "); } @@ -237,7 +237,7 @@ fn zero_length_array_constant() { private parameters: [] public parameters: [] return values: [] - EXPR [ 1 ] + EXPR 0 = 1 "); } @@ -264,6 +264,6 @@ fn zero_length_array_dynamic_predicate() { private parameters: [w0] public parameters: [] return values: [] - EXPR [ (1, w0) 0 ] + EXPR w0 = 0 "); } diff --git a/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs b/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs index e0cd71fc08c..719ff18a90b 100644 --- a/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs +++ b/compiler/noirc_evaluator/src/acir/tests/brillig_call.rs @@ -45,12 +45,12 @@ fn multiple_brillig_calls_one_bytecode() { private parameters: [w0, w1] public parameters: [] return values: [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w2] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w3] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w4] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w5] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w6] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w7] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w2] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w3] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w4] + BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w5] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w6] + BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w7] unconstrained func 0 0: @2 = const u32 1 @@ -152,23 +152,23 @@ fn multiple_brillig_stdlib_calls() { BLACKBOX::RANGE [w0]:32 bits [] BLACKBOX::RANGE [w1]:32 bits [] BLACKBOX::RANGE [w2]:32 bits [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w1, w3) -1 ] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w4, w5] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w1) ]], outputs: [w3] + EXPR 0 = w1*w3 - 1 + BRILLIG CALL func 1: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w4, w5] BLACKBOX::RANGE [w4]:32 bits [] BLACKBOX::RANGE [w5]:32 bits [] - EXPR [ (1, w1) (-1, w5) (-1, w6) -1 ] + EXPR w6 = w1 - w5 - 1 BLACKBOX::RANGE [w6]:32 bits [] - EXPR [ (-1, w1, w4) (1, w0) (-1, w5) 0 ] - EXPR [ (-1, w2) (1, w4) 0 ] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w2) 0 ]], outputs: [w7] - EXPR [ (1, w2, w7) -1 ] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w1) 0 ], EXPR [ (1, w2) 0 ]], outputs: [w8, w9] + EXPR w5 = -w1*w4 + w0 + EXPR w4 = w2 + BRILLIG CALL func 0: inputs: [EXPR [ (1, w2) ]], outputs: [w7] + EXPR 0 = w2*w7 - 1 + BRILLIG CALL func 1: inputs: [EXPR [ (1, w1) ], EXPR [ (1, w2) ]], outputs: [w8, w9] BLACKBOX::RANGE [w9]:32 bits [] - EXPR [ (1, w2) (-1, w9) (-1, w10) -1 ] + EXPR w10 = w2 - w9 - 1 BLACKBOX::RANGE [w10]:32 bits [] - EXPR [ (-1, w2, w8) (1, w1) (-1, w9) 0 ] - EXPR [ (1, w8) -1 ] + EXPR w9 = -w2*w8 + w1 + EXPR w8 = 1 unconstrained func 0 0: @21 = const u32 1 @@ -240,27 +240,27 @@ fn brillig_stdlib_calls_with_regular_brillig_call() { BLACKBOX::RANGE [w0]:32 bits [] BLACKBOX::RANGE [w1]:32 bits [] BLACKBOX::RANGE [w2]:32 bits [] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w1, w3) -1 ] - BRILLIG CALL func 2: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w4, w5] + BRILLIG CALL func 1: inputs: [EXPR [ (1, w1) ]], outputs: [w3] + EXPR 0 = w1*w3 - 1 + BRILLIG CALL func 2: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w4, w5] BLACKBOX::RANGE [w4]:32 bits [] BLACKBOX::RANGE [w5]:32 bits [] - EXPR [ (1, w1) (-1, w5) (-1, w6) -1 ] + EXPR w6 = w1 - w5 - 1 BLACKBOX::RANGE [w6]:32 bits [] - EXPR [ (-1, w1, w4) (1, w0) (-1, w5) 0 ] - EXPR [ (-1, w2) (1, w4) 0 ] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w7] + EXPR w5 = -w1*w4 + w0 + EXPR w4 = w2 + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w7] BLACKBOX::RANGE [w7]:32 bits [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w8] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w8] BLACKBOX::RANGE [w8]:32 bits [] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w2) 0 ]], outputs: [w9] - EXPR [ (1, w2, w9) -1 ] - BRILLIG CALL func 2: inputs: [EXPR [ (1, w1) 0 ], EXPR [ (1, w2) 0 ]], outputs: [w10, w11] + BRILLIG CALL func 1: inputs: [EXPR [ (1, w2) ]], outputs: [w9] + EXPR 0 = w2*w9 - 1 + BRILLIG CALL func 2: inputs: [EXPR [ (1, w1) ], EXPR [ (1, w2) ]], outputs: [w10, w11] BLACKBOX::RANGE [w11]:32 bits [] - EXPR [ (1, w2) (-1, w11) (-1, w12) -1 ] + EXPR w12 = w2 - w11 - 1 BLACKBOX::RANGE [w12]:32 bits [] - EXPR [ (-1, w2, w10) (1, w1) (-1, w11) 0 ] - EXPR [ (1, w10) -1 ] + EXPR w11 = -w2*w10 + w1 + EXPR w10 = 1 unconstrained func 0 0: @2 = const u32 1 @@ -374,29 +374,29 @@ fn brillig_stdlib_calls_with_multiple_acir_calls() { BLACKBOX::RANGE [w0]:32 bits [] BLACKBOX::RANGE [w1]:32 bits [] BLACKBOX::RANGE [w2]:32 bits [] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w1) 0 ]], outputs: [w3] - EXPR [ (1, w1, w3) -1 ] - BRILLIG CALL func 2: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w4, w5] + BRILLIG CALL func 1: inputs: [EXPR [ (1, w1) ]], outputs: [w3] + EXPR 0 = w1*w3 - 1 + BRILLIG CALL func 2: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w4, w5] BLACKBOX::RANGE [w4]:32 bits [] BLACKBOX::RANGE [w5]:32 bits [] - EXPR [ (1, w1) (-1, w5) (-1, w6) -1 ] + EXPR w6 = w1 - w5 - 1 BLACKBOX::RANGE [w6]:32 bits [] - EXPR [ (-1, w1, w4) (1, w0) (-1, w5) 0 ] - EXPR [ (-1, w2) (1, w4) 0 ] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w7] + EXPR w5 = -w1*w4 + w0 + EXPR w4 = w2 + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w7] BLACKBOX::RANGE [w7]:32 bits [] - BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) 0 ], EXPR [ (1, w1) 0 ]], outputs: [w8] + BRILLIG CALL func 0: inputs: [EXPR [ (1, w0) ], EXPR [ (1, w1) ]], outputs: [w8] BLACKBOX::RANGE [w8]:32 bits [] CALL func 1: PREDICATE: EXPR [ 1 ] inputs: [w0, w1], outputs: [w9] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w2) 0 ]], outputs: [w10] - EXPR [ (1, w2, w10) -1 ] - BRILLIG CALL func 2: inputs: [EXPR [ (1, w1) 0 ], EXPR [ (1, w2) 0 ]], outputs: [w11, w12] + BRILLIG CALL func 1: inputs: [EXPR [ (1, w2) ]], outputs: [w10] + EXPR 0 = w2*w10 - 1 + BRILLIG CALL func 2: inputs: [EXPR [ (1, w1) ], EXPR [ (1, w2) ]], outputs: [w11, w12] BLACKBOX::RANGE [w12]:32 bits [] - EXPR [ (1, w2) (-1, w12) (-1, w13) -1 ] + EXPR w13 = w2 - w12 - 1 BLACKBOX::RANGE [w13]:32 bits [] - EXPR [ (-1, w2, w11) (1, w1) (-1, w12) 0 ] - EXPR [ (1, w11) -1 ] + EXPR w12 = -w2*w11 + w1 + EXPR w11 = 1 func 1 current witness: w5 @@ -405,12 +405,12 @@ fn brillig_stdlib_calls_with_multiple_acir_calls() { return values: [w2] BLACKBOX::RANGE [w0]:32 bits [] BLACKBOX::RANGE [w1]:32 bits [] - EXPR [ (1, w0) (-1, w1) (-1, w3) 0 ] - BRILLIG CALL func 1: inputs: [EXPR [ (1, w3) 0 ]], outputs: [w4] - EXPR [ (1, w3, w4) (1, w5) -1 ] - EXPR [ (1, w3, w5) 0 ] - EXPR [ (1, w5) 0 ] - EXPR [ (-1, w0) (1, w2) 0 ] + EXPR w3 = w0 - w1 + BRILLIG CALL func 1: inputs: [EXPR [ (1, w3) ]], outputs: [w4] + EXPR w5 = -w3*w4 + 1 + EXPR 0 = w3*w5 + EXPR w5 = 0 + EXPR w2 = w0 unconstrained func 0 0: @2 = const u32 1 diff --git a/compiler/noirc_evaluator/src/acir/tests/call.rs b/compiler/noirc_evaluator/src/acir/tests/call.rs index 5424d82abb3..e47b6fab008 100644 --- a/compiler/noirc_evaluator/src/acir/tests/call.rs +++ b/compiler/noirc_evaluator/src/acir/tests/call.rs @@ -64,15 +64,15 @@ fn basic_call_with_outputs_assert(inline_type: InlineType) { inputs: [w0, w1], outputs: [w2] CALL func 1: PREDICATE: EXPR [ 1 ] inputs: [w0, w1], outputs: [w3] - EXPR [ (1, w2) (-1, w3) 0 ] - + EXPR w3 = w2 + func 1 current witness: w2 private parameters: [w0, w1] public parameters: [] return values: [w2] - EXPR [ (1, w0) (-1, w1) 0 ] - EXPR [ (-1, w0) (1, w2) 0 ] + EXPR w1 = w0 + EXPR w2 = w0 "); } @@ -107,15 +107,15 @@ fn call_output_as_next_call_input(inline_type: InlineType) { inputs: [w0, w1], outputs: [w2] CALL func 1: PREDICATE: EXPR [ 1 ] inputs: [w2, w1], outputs: [w3] - EXPR [ (1, w2) (-1, w3) 0 ] - + EXPR w3 = w2 + func 1 current witness: w2 private parameters: [w0, w1] public parameters: [] return values: [w2] - EXPR [ (1, w0) (-1, w1) 0 ] - EXPR [ (-1, w0) (1, w2) 0 ] + EXPR w1 = w0 + EXPR w2 = w0 "); } @@ -154,24 +154,24 @@ fn basic_nested_call(inline_type: InlineType) { inputs: [w0, w1], outputs: [w2] CALL func 1: PREDICATE: EXPR [ 1 ] inputs: [w0, w1], outputs: [w3] - EXPR [ (1, w2) (-1, w3) 0 ] - + EXPR w3 = w2 + func 1 current witness: w4 private parameters: [w0, w1] public parameters: [] return values: [w2] - EXPR [ (1, w0) (-1, w3) 2 ] + EXPR w3 = w0 + 2 CALL func 2: PREDICATE: EXPR [ 1 ] inputs: [w3, w1], outputs: [w4] - EXPR [ (1, w2) (-1, w4) 0 ] - + EXPR w4 = w2 + func 2 current witness: w2 private parameters: [w0, w1] public parameters: [] return values: [w2] - EXPR [ (1, w0) (-1, w1) 0 ] - EXPR [ (-1, w0) (1, w2) 0 ] + EXPR w1 = w0 + EXPR w2 = w0 "); } diff --git a/compiler/noirc_evaluator/src/acir/tests/mod.rs b/compiler/noirc_evaluator/src/acir/tests/mod.rs index 49620a12b2b..7d639e4f2ab 100644 --- a/compiler/noirc_evaluator/src/acir/tests/mod.rs +++ b/compiler/noirc_evaluator/src/acir/tests/mod.rs @@ -95,7 +95,7 @@ fn unchecked_mul_should_not_have_range_check() { return values: [w2] BLACKBOX::RANGE [w0]:32 bits [] BLACKBOX::RANGE [w1]:32 bits [] - EXPR [ (-1, w0, w1) (1, w2) 0 ] + EXPR w2 = w0*w1 "); }