Skip to content

Commit

Permalink
feat: Add assert_max_bit_size method to Field (#4016)
Browse files Browse the repository at this point in the history
# Description


resolves #4015 

## Problem\*

Resolves <!-- Link to GitHub Issue -->

## Summary\*



## Additional Context



## Documentation\*

Check one:
- [ ] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[Exceptional Case]** Documentation to be submitted in a separate
PR.

# PR Checklist\*

- [ ] I have tested the changes locally.
- [ ] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.

---------

Co-authored-by: Tom French <[email protected]>
Co-authored-by: Tom French <[email protected]>
  • Loading branch information
3 people authored Jan 12, 2024
1 parent 358cdd2 commit bc9a44f
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ impl AcirContext {
self.add_data(constant_data)
}

/// Returns the constant represented by the given variable.
///
/// Panics: if the variable does not represent a constant.
pub(crate) fn constant(&self, var: AcirVar) -> FieldElement {
self.vars[&var].as_constant().expect("ICE - expected the variable to be a constant value")
}

/// Adds a Variable to the context, whose exact value is resolved at
/// runtime.
pub(crate) fn add_variable(&mut self) -> AcirVar {
Expand Down
3 changes: 3 additions & 0 deletions compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1712,6 +1712,9 @@ impl Context {

Ok(Self::convert_vars_to_values(vars, dfg, result_ids))
}
Intrinsic::ApplyRangeConstraint => {
unreachable!("ICE: `Intrinsic::ApplyRangeConstraint` calls should be transformed into an `Instruction::RangeCheck`");
}
Intrinsic::ToRadix(endian) => {
let field = self.convert_value(arguments[0], dfg).into_var()?;
let radix = self.convert_value(arguments[1], dfg).into_var()?;
Expand Down
5 changes: 4 additions & 1 deletion compiler/noirc_evaluator/src/ssa/ir/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub(crate) enum Intrinsic {
SlicePopFront,
SliceInsert,
SliceRemove,
ApplyRangeConstraint,
StrAsBytes,
ToBits(Endian),
ToRadix(Endian),
Expand All @@ -61,6 +62,7 @@ impl std::fmt::Display for Intrinsic {
Intrinsic::SliceInsert => write!(f, "slice_insert"),
Intrinsic::SliceRemove => write!(f, "slice_remove"),
Intrinsic::StrAsBytes => write!(f, "str_as_bytes"),
Intrinsic::ApplyRangeConstraint => write!(f, "apply_range_constraint"),
Intrinsic::ToBits(Endian::Big) => write!(f, "to_be_bits"),
Intrinsic::ToBits(Endian::Little) => write!(f, "to_le_bits"),
Intrinsic::ToRadix(Endian::Big) => write!(f, "to_be_radix"),
Expand All @@ -78,7 +80,7 @@ impl Intrinsic {
/// If there are no side effects then the `Intrinsic` can be removed if the result is unused.
pub(crate) fn has_side_effects(&self) -> bool {
match self {
Intrinsic::AssertConstant => true,
Intrinsic::AssertConstant | Intrinsic::ApplyRangeConstraint => true,

Intrinsic::Sort
| Intrinsic::ArrayLen
Expand Down Expand Up @@ -106,6 +108,7 @@ impl Intrinsic {
"arraysort" => Some(Intrinsic::Sort),
"array_len" => Some(Intrinsic::ArrayLen),
"assert_constant" => Some(Intrinsic::AssertConstant),
"apply_range_constraint" => Some(Intrinsic::ApplyRangeConstraint),
"slice_push_back" => Some(Intrinsic::SlicePushBack),
"slice_push_front" => Some(Intrinsic::SlicePushFront),
"slice_pop_back" => Some(Intrinsic::SlicePopBack),
Expand Down
14 changes: 14 additions & 0 deletions compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,20 @@ pub(super) fn simplify_call(
SimplifyResult::None
}
}
Intrinsic::ApplyRangeConstraint => {
let value = arguments[0];
let max_bit_size = dfg.get_numeric_constant(arguments[1]);
if let Some(max_bit_size) = max_bit_size {
let max_bit_size = max_bit_size.to_u128() as u32;
SimplifyResult::SimplifiedToInstruction(Instruction::RangeCheck {
value,
max_bit_size,
assert_message: Some("call to assert_max_bit_size".to_owned()),
})
} else {
SimplifyResult::None
}
}
Intrinsic::BlackBox(bb_func) => simplify_black_box_func(bb_func, arguments, dfg),
Intrinsic::Sort => simplify_sort(dfg, arguments),
Intrinsic::AsField => {
Expand Down
9 changes: 9 additions & 0 deletions noir_stdlib/src/field.nr
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ impl Field {
#[builtin(to_be_bits)]
fn __to_be_bits(_self: Self, _bit_size: u32) -> [u1] {}

#[builtin(apply_range_constraint)]
fn __assert_max_bit_size(_self: Self, _bit_size: u32) {}

pub fn assert_max_bit_size(self: Self, bit_size: u32) {
crate::assert_constant(bit_size);
assert(bit_size < modulus_num_bits() as u32);
self.__assert_max_bit_size(bit_size);
}

pub fn to_le_bytes(self: Self, byte_size: u32) -> [u8] {
self.to_le_radix(256, byte_size)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "unsafe_range_constraint"
version = "0.1.0"
type = "bin"
authors = [""]

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x = "3"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Test that we can apply a range constraint to a field using
// a builtin.
fn main(x: Field) {
x.assert_max_bit_size(48);
}

0 comments on commit bc9a44f

Please sign in to comment.