Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into jf/stop-cloning-traits
Browse files Browse the repository at this point in the history
kevaundray authored Dec 9, 2023
2 parents 5b36d17 + 4000fb2 commit c4d4de9
Showing 12 changed files with 79 additions and 62 deletions.
16 changes: 13 additions & 3 deletions .github/workflows/test-js-packages.yml
Original file line number Diff line number Diff line change
@@ -418,11 +418,13 @@ jobs:
run: |
yarn test:integration
# This is a noop job which depends on all test jobs
# This is a job which depends on all test jobs and reports the overall status.
# This allows us to add/remove test jobs without having to update the required workflows.
tests-end:
name: End
runs-on: ubuntu-latest
# We want this job to always run (even if the dependant jobs fail) as we want this job to fail rather than skipping.
if: ${{ always() }}
needs:
- test-acvm_js-node
- test-acvm_js-browser
@@ -435,5 +437,13 @@ jobs:
- test-integration

steps:
- name: Noop
run: echo "noop"
- name: Report overall success
run: |
if [[ $FAIL == true ]]; then
exit 1
else
exit 0
fi
env:
# We treat any skipped or failing jobs as a failure for the workflow as a whole.
FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ This crate's minimum supported rustc version is 1.71.1.

## Working on this project

This project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. Please follow [our guidelines](https://noir-lang.org/getting_started/nargo_installation/#option-4-compile-from-source) to setup your environment for working on the project.
This project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. Please follow [our guidelines](https://noir-lang.org/getting_started/nargo_installation/#option-3-compile-from-source) to setup your environment for working on the project.

### Building against a different local/remote version of Barretenberg

24 changes: 23 additions & 1 deletion acvm-repo/acir_field/src/generic_ark.rs
Original file line number Diff line number Diff line change
@@ -272,7 +272,10 @@ impl<F: PrimeField> FieldElement<F> {
}
pub fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
let hex_as_bytes = hex::decode(value).ok()?;
// Values of odd length require an additional "0" prefix
let sanitized_value =
if value.len() % 2 == 0 { value.to_string() } else { format!("0{}", value) };
let hex_as_bytes = hex::decode(sanitized_value).ok()?;
Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
}

@@ -446,6 +449,25 @@ mod tests {
assert_eq!(minus_i_field_element.to_hex(), string);
}
}

#[test]
fn deserialize_even_and_odd_length_hex() {
// Test cases of (odd, even) length hex strings
let hex_strings =
vec![("0x0", "0x00"), ("0x1", "0x01"), ("0x002", "0x0002"), ("0x00003", "0x000003")];
for (i, case) in hex_strings.into_iter().enumerate() {
let i_field_element =
crate::generic_ark::FieldElement::<ark_bn254::Fr>::from(i as i128);
let odd_field_element =
crate::generic_ark::FieldElement::<ark_bn254::Fr>::from_hex(case.0).unwrap();
let even_field_element =
crate::generic_ark::FieldElement::<ark_bn254::Fr>::from_hex(case.1).unwrap();

assert_eq!(i_field_element, odd_field_element);
assert_eq!(odd_field_element, even_field_element);
}
}

#[test]
fn max_num_bits_smoke() {
let max_num_bits_bn254 = crate::generic_ark::FieldElement::<ark_bn254::Fr>::max_num_bits();
11 changes: 3 additions & 8 deletions compiler/noirc_evaluator/src/ssa/function_builder/mod.rs
Original file line number Diff line number Diff line change
@@ -314,16 +314,11 @@ impl FunctionBuilder {
(FieldElement::max_num_bits(), self.insert_binary(predicate, BinaryOp::Mul, pow))
};

let instruction = Instruction::Binary(Binary { lhs, rhs: pow, operator: BinaryOp::Mul });
if max_bit <= bit_size {
self.insert_instruction(instruction, None).first()
self.insert_binary(lhs, BinaryOp::Mul, pow)
} else {
let result = self.insert_instruction(instruction, None).first();
self.insert_instruction(
Instruction::Truncate { value: result, bit_size, max_bit_size: max_bit },
None,
)
.first()
let result = self.insert_binary(lhs, BinaryOp::Mul, pow);
self.insert_truncate(result, bit_size, max_bit)
}
}

14 changes: 13 additions & 1 deletion compiler/noirc_evaluator/src/ssa/ir/instruction.rs
Original file line number Diff line number Diff line change
@@ -467,11 +467,23 @@ impl Instruction {
}
None
}
Instruction::Truncate { value, bit_size, .. } => {
Instruction::Truncate { value, bit_size, max_bit_size } => {
if let Some((numeric_constant, typ)) = dfg.get_numeric_constant_with_type(*value) {
let integer_modulus = 2_u128.pow(*bit_size);
let truncated = numeric_constant.to_u128() % integer_modulus;
SimplifiedTo(dfg.make_constant(truncated.into(), typ))
} else if let Value::Instruction { instruction, .. } = &dfg[dfg.resolve(*value)] {
if let Instruction::Truncate { bit_size: src_bit_size, .. } = &dfg[*instruction]
{
// If we're truncating the value to fit into the same or larger bit size then this is a noop.
if src_bit_size <= bit_size && src_bit_size <= max_bit_size {
SimplifiedTo(*value)
} else {
None
}
} else {
None
}
} else {
None
}
49 changes: 12 additions & 37 deletions compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
Original file line number Diff line number Diff line change
@@ -275,16 +275,11 @@ impl<'a> FunctionContext<'a> {
let bit_width =
self.builder.numeric_constant(FieldElement::from(2_i128.pow(bit_size)), Type::field());
let sign_not = self.builder.insert_binary(one, BinaryOp::Sub, sign);
let as_field =
self.builder.insert_instruction(Instruction::Cast(input, Type::field()), None).first();
let sign_field =
self.builder.insert_instruction(Instruction::Cast(sign, Type::field()), None).first();
let as_field = self.builder.insert_cast(input, Type::field());
let sign_field = self.builder.insert_cast(sign, Type::field());
let positive_predicate = self.builder.insert_binary(sign_field, BinaryOp::Mul, as_field);
let two_complement = self.builder.insert_binary(bit_width, BinaryOp::Sub, as_field);
let sign_not_field = self
.builder
.insert_instruction(Instruction::Cast(sign_not, Type::field()), None)
.first();
let sign_not_field = self.builder.insert_cast(sign_not, Type::field());
let negative_predicate =
self.builder.insert_binary(sign_not_field, BinaryOp::Mul, two_complement);
self.builder.insert_binary(positive_predicate, BinaryOp::Add, negative_predicate)
@@ -315,17 +310,8 @@ impl<'a> FunctionContext<'a> {
match operator {
BinaryOpKind::Add | BinaryOpKind::Subtract => {
// Result is computed modulo the bit size
let mut result = self
.builder
.insert_instruction(
Instruction::Truncate {
value: result,
bit_size,
max_bit_size: bit_size + 1,
},
None,
)
.first();
let mut result =
self.builder.insert_truncate(result, bit_size, bit_size + 1);
result = self.builder.insert_cast(result, Type::unsigned(bit_size));

self.check_signed_overflow(result, lhs, rhs, operator, bit_size, location);
@@ -335,17 +321,7 @@ impl<'a> FunctionContext<'a> {
// Result is computed modulo the bit size
let mut result =
self.builder.insert_cast(result, Type::unsigned(2 * bit_size));
result = self
.builder
.insert_instruction(
Instruction::Truncate {
value: result,
bit_size,
max_bit_size: 2 * bit_size,
},
None,
)
.first();
result = self.builder.insert_truncate(result, bit_size, 2 * bit_size);

self.check_signed_overflow(result, lhs, rhs, operator, bit_size, location);
self.builder.insert_cast(result, result_type)
@@ -476,17 +452,16 @@ impl<'a> FunctionContext<'a> {

// Then we check the signed product fits in a signed integer of bit_size-bits
let not_same = self.builder.insert_binary(one, BinaryOp::Sub, same_sign);
let not_same_sign_field = self
.builder
.insert_instruction(Instruction::Cast(not_same, Type::unsigned(bit_size)), None)
.first();
let not_same_sign_field =
self.builder.insert_cast(not_same, Type::unsigned(bit_size));
let positive_maximum_with_offset =
self.builder.insert_binary(half_width, BinaryOp::Add, not_same_sign_field);
let product_overflow_check =
self.builder.insert_binary(product, BinaryOp::Lt, positive_maximum_with_offset);
self.builder.set_location(location).insert_instruction(
Instruction::Constrain(product_overflow_check, one, Some(message)),
None,
self.builder.set_location(location).insert_constrain(
product_overflow_check,
one,
Some(message),
);
}
BinaryOpKind::ShiftLeft => unreachable!("shift is not supported for signed integer"),
9 changes: 6 additions & 3 deletions compiler/noirc_frontend/src/lexer/lexer.rs
Original file line number Diff line number Diff line change
@@ -633,15 +633,18 @@ mod tests {
}

#[test]
fn test_attribute_with_apostrophe() {
let input = r#"#[test(should_fail_with = "the eagle's feathers")]"#;
fn test_attribute_with_common_punctuation() {
let input =
r#"#[test(should_fail_with = "stmt. q? exclaim! & symbols, 1% shouldn't fail")]"#;
let mut lexer = Lexer::new(input);

let token = lexer.next_token().unwrap().token().clone();
assert_eq!(
token,
Token::Attribute(Attribute::Function(FunctionAttribute::Test(
TestScope::ShouldFailWith { reason: "the eagle's feathers".to_owned().into() }
TestScope::ShouldFailWith {
reason: "stmt. q? exclaim! & symbols, 1% shouldn't fail".to_owned().into()
}
)))
);
}
7 changes: 1 addition & 6 deletions compiler/noirc_frontend/src/lexer/token.rs
Original file line number Diff line number Diff line change
@@ -468,13 +468,8 @@ impl Attribute {
.all(|ch| {
ch.is_ascii_alphabetic()
|| ch.is_numeric()
|| ch == '_'
|| ch == '('
|| ch == ')'
|| ch == '='
|| ch == '"'
|| ch.is_ascii_punctuation()
|| ch == ' '
|| ch == '\''
})
.then_some(());

4 changes: 4 additions & 0 deletions test_programs/execution_success/strings/src/main.nr
Original file line number Diff line number Diff line change
@@ -34,6 +34,10 @@ fn main(message: pub str<11>, y: Field, hex_as_string: str<4>, hex_as_field: Fie
assert(hex_as_string == "0x41");
// assert(hex_as_string != 0x41); This will fail with a type mismatch between str[4] and Field
assert(hex_as_field == 0x41);

// Single digit & odd length hex literals are valid
assert(hex_as_field == 0x041);
assert(hex_as_field != 0x1);
}

#[test]
3 changes: 1 addition & 2 deletions tooling/noir_js/.mocharc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"require": "ts-node/register",
"loader": "ts-node/esm",
"require": "tsx",
"extensions": ["ts", "cjs"],
"spec": [
"test/node/**/*.test.ts*"
1 change: 1 addition & 0 deletions tooling/noir_js/package.json
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@
"prettier": "3.0.3",
"ts-node": "^10.9.1",
"tsc-multi": "^1.1.0",
"tsx": "^4.6.2",
"typescript": "^5.2.2"
}
}
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -3715,6 +3715,7 @@ __metadata:
prettier: 3.0.3
ts-node: ^10.9.1
tsc-multi: ^1.1.0
tsx: ^4.6.2
typescript: ^5.2.2
languageName: unknown
linkType: soft

0 comments on commit c4d4de9

Please sign in to comment.