Skip to content

Commit

Permalink
feat(std_lib)!: modulus bits/bytes methods, and to_bits -> to_le_bits (
Browse files Browse the repository at this point in the history
…#697)

* added modulus_bits command, have to add modulus

* add modulus_bits and modulus_be_byte_array builtin funcs

* cargo fm

* cargo clippy

* more clippy format fixes

* slight comment fix

* rename modulus to bytes methods

* remove comments and dbg

* rename to have le and be trailing func names

* match rust with endianness before bytes/bits

* tiny comments rename

* to_le_bytes test naming

* remove dbg! stmt
  • Loading branch information
vezenovm authored Jan 31, 2023
1 parent a484e28 commit a20e1c1
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 26 deletions.
2 changes: 1 addition & 1 deletion crates/nargo/tests/test_data/7_function/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn test2(z: Field, t: u32 ) {

fn pow(base: Field, exponent: Field) -> Field {
let mut r = 1 as Field;
let b = std::to_bits(exponent, 32 as u32);
let b = std::field::to_le_bits(exponent, 32 as u32);
for i in 1..33 {
r = r*r;
r = (b[32-i] as Field) * (r * base) + (1 - b[32-i] as Field) * r;
Expand Down
4 changes: 2 additions & 2 deletions crates/nargo/tests/test_data/9_conditional/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ fn main(a: u32, mut c: [u32; 4], x: [u8; 5], result: pub [u8; 32]){
}
}

//Regression for to_bits() constant evaluation
//Regression for to_le_bits() constant evaluation
// binary array representation of u8 1
let as_bits_hardcode_1 = [1, 0];
let mut c1 = 0;
for i in 0..2 {
let mut as_bits = std::to_bits(arr[i] as Field, 2);
let mut as_bits = std::field::to_le_bits(arr[i] as Field, 2);
c1 = c1 + as_bits[0] as Field;

if i == 0 {
Expand Down
5 changes: 5 additions & 0 deletions crates/nargo/tests/test_data/modulus/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
authors = [""]
compiler_version = "0.1"

[dependencies]
3 changes: 3 additions & 0 deletions crates/nargo/tests/test_data/modulus/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bn254_modulus_be_bytes = [48, 100, 78, 114, 225, 49, 160, 41, 184, 80, 69, 182, 129, 129, 88, 93, 40, 51, 232, 72, 121, 185, 112, 145, 67, 225, 245, 147, 240, 0, 0, 1]
bn254_modulus_be_bits = [1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
return = ""
27 changes: 27 additions & 0 deletions crates/nargo/tests/test_data/modulus/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use dep::std;

fn main(bn254_modulus_be_bytes : [u8; 32], bn254_modulus_be_bits : [u1; 254]) -> pub Field {
let modulus_size = std::field::modulus_num_bits();
// NOTE: The constraints used in this circuit will only work when testing nargo with the plonk bn254 backend
constrain modulus_size == 254;

let modulus_be_byte_array = std::field::modulus_be_bytes();
for i in 0..32 {
constrain modulus_be_byte_array[i] == bn254_modulus_be_bytes[i];
}
let modulus_le_byte_array = std::field::modulus_le_bytes();
for i in 0..32 {
constrain modulus_le_byte_array[i] == bn254_modulus_be_bytes[31-i];
}

let modulus_be_bits = std::field::modulus_be_bits();
for i in 0..254 {
constrain modulus_be_bits[i] == bn254_modulus_be_bits[i];
}
let modulus_le_bits = std::field::modulus_le_bits();
for i in 0..254 {
constrain modulus_le_bits[i] == bn254_modulus_be_bits[253-i];
}

modulus_size
}
2 changes: 1 addition & 1 deletion crates/nargo/tests/test_data/to_le_bytes/Prover.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
x = "2040124"
return = [0x3c, 0x21, 0x1f, 0x00]
return = [0x3c, 0x21, 0x1f, 0x00]
2 changes: 1 addition & 1 deletion crates/nargo/tests/test_data/to_le_bytes/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use dep::std;

fn main(x : Field) -> pub [u8; 4] {
// The result of this byte array will be little-endian
let byte_array = std::to_le_bytes(x, 31);
let byte_array = std::field::to_le_bytes(x, 31);
let mut first_four_bytes = [0; 4];
for i in 0..4 {
first_four_bytes[i] = byte_array[i];
Expand Down
4 changes: 2 additions & 2 deletions crates/noirc_evaluator/src/ssa/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl std::fmt::Display for Opcode {
impl Opcode {
pub fn lookup(op_name: &str) -> Option<Opcode> {
match op_name {
"to_bits" => Some(Opcode::ToBits),
"to_le_bits" => Some(Opcode::ToBits),
"to_radix" => Some(Opcode::ToRadix),
_ => BlackBoxFunc::lookup(op_name).map(Opcode::LowLevel),
}
Expand All @@ -29,7 +29,7 @@ impl Opcode {
pub fn name(&self) -> &str {
match self {
Opcode::LowLevel(op) => op.name(),
Opcode::ToBits => "to_bits",
Opcode::ToBits => "to_le_bits",
Opcode::ToRadix => "to_radix",
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/noirc_evaluator/src/ssa/optim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ fn cse_block_with_anchor(
result?;
}

//cannot simplify to_bits() in the previous call because it get replaced with multiple instructions
//cannot simplify to_le_bits() in the previous call because it get replaced with multiple instructions
if let Operation::Intrinsic(opcode, args) = &update2.operation {
let args = args.iter().map(|arg| {
NodeEval::from_id(ctx, *arg).into_const_value().map(|f| f.to_u128())
Expand Down
43 changes: 42 additions & 1 deletion crates/noirc_frontend/src/monomorphisation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use acvm::FieldElement;
use iter_extended::{btree_map, vecmap};
use noirc_abi::Abi;
use std::collections::{BTreeMap, HashMap, VecDeque};
Expand Down Expand Up @@ -574,7 +575,7 @@ impl Monomorphiser {
}))
}

/// Try to evaluate certain builtin functions (currently only 'arraylen')
/// Try to evaluate certain builtin functions (currently only 'arraylen' and field modulus methods)
/// at their callsite.
/// NOTE: Evaluating at the callsite means we cannot track aliased functions.
/// E.g. `let f = std::array::len; f(arr)` will fail to evaluate.
Expand All @@ -595,12 +596,52 @@ impl Monomorphiser {
ast::Type::Field,
)))
}
Definition::Builtin(opcode) if opcode == "modulus_num_bits" => {
Some(ast::Expression::Literal(ast::Literal::Integer(
(FieldElement::max_num_bits() as u128).into(),
ast::Type::Field,
)))
}
Definition::Builtin(opcode) if opcode == "modulus_le_bits" => {
let modulus = FieldElement::modulus();
let bits = modulus.to_radix_le(2);
Some(self.modulus_array_literal(bits, 1))
}
Definition::Builtin(opcode) if opcode == "modulus_be_bits" => {
let modulus = FieldElement::modulus();
let bits = modulus.to_radix_be(2);
Some(self.modulus_array_literal(bits, 1))
}
Definition::Builtin(opcode) if opcode == "modulus_be_bytes" => {
let modulus = FieldElement::modulus();
let bytes = modulus.to_bytes_be();
Some(self.modulus_array_literal(bytes, 8))
}
Definition::Builtin(opcode) if opcode == "modulus_le_bytes" => {
let modulus = FieldElement::modulus();
let bytes = modulus.to_bytes_le();
Some(self.modulus_array_literal(bytes, 8))
}
_ => None,
},
_ => None,
}
}

fn modulus_array_literal(&self, bytes: Vec<u8>, arr_elem_bits: u32) -> ast::Expression {
let bytes_as_expr = vecmap(bytes, |byte| {
ast::Expression::Literal(ast::Literal::Integer(
(byte as u128).into(),
ast::Type::Integer(crate::Signedness::Unsigned, arr_elem_bits),
))
});
let arr_literal = ast::ArrayLiteral {
contents: bytes_as_expr,
element_type: ast::Type::Integer(crate::Signedness::Unsigned, arr_elem_bits),
};
ast::Expression::Literal(ast::Literal::Array(arr_literal))
}

fn queue_function(
&mut self,
id: node_interner::FuncId,
Expand Down
26 changes: 26 additions & 0 deletions noir_stdlib/src/field.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#[builtin(to_le_bits)]
fn to_le_bits(_x : Field, _bit_size: u32) -> [u1] {}

fn to_le_bytes(x : Field, byte_size: u32) -> [u8] {
to_radix(x, 256, byte_size)
}

#[builtin(to_radix)]
//decompose _x into a _result_len vector over the _radix basis
//_radix must be less than 256
fn to_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] {}

#[builtin(modulus_num_bits)]
fn modulus_num_bits() -> comptime Field {}

#[builtin(modulus_be_bits)]
fn modulus_be_bits() -> [u1] {}

#[builtin(modulus_le_bits)]
fn modulus_le_bits() -> [u1] {}

#[builtin(modulus_be_bytes)]
fn modulus_be_bytes() -> [u8] {}

#[builtin(modulus_le_bytes)]
fn modulus_le_bytes() -> [u8] {}
18 changes: 2 additions & 16 deletions noir_stdlib/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,15 @@ mod ecdsa_secp256k1;
mod scalar_mul;
mod sha256;
mod sha512;


#[builtin(to_bits)]
fn to_bits(_x : Field, _bit_size: u32) -> [u1] {}

fn to_le_bytes(x : Field, byte_size: u32) -> [u8] {
to_radix(x, 256, byte_size)
}

#[builtin(to_radix)]
//decompose _x into a _result_len vector over the _radix basis
//_radix must be less than 256
fn to_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] {}


mod field;

// Returns base^exponent.
// ^ means to the power of and not xor
// Caution: we assume the exponent fits into 32 bits
// using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits
fn pow_32(base: Field, exponent: Field) -> Field {
let mut r = 1 as Field;
let b = crate::to_bits(exponent, 32);
let b = field::to_le_bits(exponent, 32);

for i in 1..33 {
r = r*r;
Expand Down
2 changes: 1 addition & 1 deletion noir_stdlib/src/merkle.nr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn check_membership_in_noir(root : Field, leaf : Field, index : Field, hash_path
// Returns the root of the tree from the provided leaf and its hashpath, using pedersen hash
fn compute_root_from_leaf(leaf : Field, index : Field, hash_path: [Field]) -> Field {
let n = crate::array::len(hash_path);
let index_bits = crate::to_bits(index, n as u32);
let index_bits = crate::field::to_le_bits(index, n as u32);
let mut current = leaf;
for i in 0..n {
let path_bit = index_bits[i] as bool;
Expand Down

0 comments on commit a20e1c1

Please sign in to comment.