Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(std_lib)!: modulus bits and modulus bytes methods #697

Merged
merged 16 commits into from
Jan 31, 2023
Merged
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_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
2 changes: 1 addition & 1 deletion crates/nargo/tests/test_data/9_conditional/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn main(a: u32, mut c: [u32; 4], x: [u8; 5], result: pub [u8; 32]){
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_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_bytes_be = [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_bits_be = [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_bytes_be : [u8; 32], bn254_modulus_bits_be : [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_bytes_be[i];
}
let modulus_le_byte_array = std::field::modulus_le_bytes();
for i in 0..32 {
constrain modulus_le_byte_array[i] == bn254_modulus_bytes_be[31-i];
}

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

modulus_size
}
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
2 changes: 1 addition & 1 deletion crates/noirc_abi/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl std::fmt::Display for InputParserError {
write!(f, "duplicate variable name {err_msg}")
}
InputParserError::AbiTypeMismatch(abi_type) => {
write!(f, "cannot parse a string toml type into {:?}", abi_type)
write!(f, "cannot parse a string toml type into {abi_type:?}")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl std::fmt::Display for UnresolvedType {
Bool(is_const) => write!(f, "{is_const}bool"),
String(len) => match len {
None => write!(f, "str[]"),
Some(len) => write!(f, "str[{}]", len),
Some(len) => write!(f, "str[{len}]"),
},
Function(args, ret) => {
let args = vecmap(args, ToString::to_string);
Expand Down
6 changes: 3 additions & 3 deletions crates/noirc_frontend/src/hir/type_check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ pub fn comparator_operand_type_rules(

x_size.unify(y_size, op.location.span, errors, || {
TypeCheckError::Unstructured {
msg: format!("Can only compare arrays of the same length. Here LHS is of length {}, and RHS is {} ", x_size, y_size),
msg: format!("Can only compare arrays of the same length. Here LHS is of length {x_size}, and RHS is {y_size} "),
span: op.location.span,
}
});
Expand All @@ -737,13 +737,13 @@ pub fn comparator_operand_type_rules(
(String(x_size), String(y_size)) => {
x_size.unify(y_size, op.location.span, errors, || {
TypeCheckError::Unstructured {
msg: format!("Can only compare strings of the same length. Here LHS is of length {}, and RHS is {} ", x_size, y_size),
msg: format!("Can only compare strings of the same length. Here LHS is of length {x_size}, and RHS is {y_size} "),
span: op.location.span,
}
});

Ok(Bool(Comptime::No(Some(op.location.span))))
}
(lhs, rhs) => Err(format!("Unsupported types for comparison: {} and {}", lhs, rhs)),
(lhs, rhs) => Err(format!("Unsupported types for comparison: {lhs} and {rhs}")),
}
}
2 changes: 1 addition & 1 deletion crates/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ impl std::fmt::Display for Type {
}
Type::Bool(comptime) => write!(f, "{comptime}bool"),
Type::String(len) => match len.array_length() {
Some(len) => write!(f, "str[{}]", len),
Some(len) => write!(f, "str[{len}]"),
None => write!(f, "str[]]"),
},
Type::Unit => write!(f, "()"),
Expand Down
2 changes: 1 addition & 1 deletion crates/noirc_frontend/src/monomorphisation/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ impl std::fmt::Display for Type {
Signedness::Signed => write!(f, "i{bits}"),
},
Type::Bool => write!(f, "bool"),
Type::String(len) => write!(f, "str[{}]", len),
Type::String(len) => write!(f, "str[{len}]"),
Type::Unit => write!(f, "()"),
Type::Tuple(elems) => {
let elems = vecmap(elems, ToString::to_string);
Expand Down
44 changes: 43 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 std::collections::{BTreeMap, HashMap, VecDeque};

Expand Down Expand Up @@ -552,7 +553,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 @@ -567,18 +568,59 @@ impl Monomorphiser {
ast::Expression::Ident(ident) => match &ident.definition {
Definition::Builtin(opcode) if opcode == "arraylen" => {
let typ = self.interner.id_type(arguments[0]);
dbg!(typ.clone());
jfecher marked this conversation as resolved.
Show resolved Hide resolved
let len = typ.array_length().unwrap();
Some(ast::Expression::Literal(ast::Literal::Integer(
(len as u128).into(),
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_bits)]
fn to_bits(_x : Field, _bit_size: u32) -> [u1] {}
jfecher marked this conversation as resolved.
Show resolved Hide resolved

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] {}
33 changes: 23 additions & 10 deletions noir_stdlib/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,42 @@ mod ecdsa_secp256k1;
mod scalar_mul;
mod sha256;
mod sha512;
mod field;

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

#[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)
// }

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] {}
jfecher marked this conversation as resolved.
Show resolved Hide resolved

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

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

#[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_le_bits)]
// fn modulus_le_bits() -> [u1] {}

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

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

// 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_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_bits(index, n as u32);
let mut current = leaf;
for i in 0..n {
let path_bit = index_bits[i] as bool;
Expand Down