diff --git a/crates/nargo/tests/target_tests_data/pass/import/src/main.nr b/crates/nargo/tests/target_tests_data/pass/import/src/main.nr index 212d0f13590..58fb0c3f3f2 100644 --- a/crates/nargo/tests/target_tests_data/pass/import/src/main.nr +++ b/crates/nargo/tests/target_tests_data/pass/import/src/main.nr @@ -1,10 +1,8 @@ mod import; -use dep::std; - use crate::import::hello; fn main(x : Field, y : Field) { - let _k = std::hash::pedersen([x]); + let _k = dep::std::hash::pedersen([x]); let _l = hello(x); constrain x != import::hello(y); diff --git a/crates/nargo/tests/test_data/7_function/src/main.nr b/crates/nargo/tests/test_data/7_function/src/main.nr index a57889838b7..96ca9759a8f 100644 --- a/crates/nargo/tests/test_data/7_function/src/main.nr +++ b/crates/nargo/tests/test_data/7_function/src/main.nr @@ -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::field::to_le_bits(exponent, 32 as u32); + let b = exponent.to_le_bits(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; diff --git a/crates/nargo/tests/test_data/9_conditional/src/main.nr b/crates/nargo/tests/test_data/9_conditional/src/main.nr index 80577b2a12e..0f37f3e92f4 100644 --- a/crates/nargo/tests/test_data/9_conditional/src/main.nr +++ b/crates/nargo/tests/test_data/9_conditional/src/main.nr @@ -36,7 +36,6 @@ fn test4() -> [u32; 4] { } fn main(a: u32, mut c: [u32; 4], x: [u8; 5], result: pub [u8; 32]){ - // Regression test for issue #547 // Warning: it must be kept at the start of main let arr: [u8; 2] = [1, 2]; @@ -49,7 +48,7 @@ fn main(a: u32, mut c: [u32; 4], x: [u8; 5], result: pub [u8; 32]){ //Issue reported in #421 if a == c[0] { constrain c[0] == 0; - } else { + } else { if a == c[1] { constrain c[1] == 0; } else { @@ -64,7 +63,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::field::to_le_bits(arr[i] as Field, 2); + let mut as_bits = (arr[i] as Field).to_le_bits(2); c1 = c1 + as_bits[0] as Field; if i == 0 { diff --git a/crates/nargo/tests/test_data/array_len/src/main.nr b/crates/nargo/tests/test_data/array_len/src/main.nr index 2531bbc42fb..7ed9ebfd1c9 100644 --- a/crates/nargo/tests/test_data/array_len/src/main.nr +++ b/crates/nargo/tests/test_data/array_len/src/main.nr @@ -1,11 +1,11 @@ use dep::std; fn len_plus_1(array: [T]) -> Field { - std::array::len(array) + 1 + array.len() + 1 } fn add_lens(a: [T], b: [Field]) -> Field { - std::array::len(a) + std::array::len(b) + a.len() + b.len() } fn nested_call(b: [Field]) -> Field { @@ -19,13 +19,13 @@ fn main(len3: [u8; 3], len4: [Field; 4]) { constrain nested_call(len4) == 5; // std::array::len returns a comptime value - constrain len4[std::array::len(len3)] == 4; + constrain len4[len3.len()] == 4; // test for std::array::sort let mut unsorted = len3; unsorted[0] = len3[1]; unsorted[1] = len3[0]; constrain unsorted[0] > unsorted[1]; - let sorted = std::array::sort(unsorted); + let sorted = unsorted.sort(); constrain sorted[0] < sorted[1]; } diff --git a/crates/nargo/tests/test_data/hash_to_field/src/main.nr b/crates/nargo/tests/test_data/hash_to_field/src/main.nr index 2b7d59cd8b6..ffc334179ee 100644 --- a/crates/nargo/tests/test_data/hash_to_field/src/main.nr +++ b/crates/nargo/tests/test_data/hash_to_field/src/main.nr @@ -2,4 +2,4 @@ use dep::std; fn main(input : Field) -> pub Field { std::hash::hash_to_field([input]) -} \ No newline at end of file +} diff --git a/crates/nargo/tests/test_data/higher-order-functions/src/main.nr b/crates/nargo/tests/test_data/higher-order-functions/src/main.nr index d0d23e6ef1a..356de9eb6d9 100644 --- a/crates/nargo/tests/test_data/higher-order-functions/src/main.nr +++ b/crates/nargo/tests/test_data/higher-order-functions/src/main.nr @@ -34,15 +34,15 @@ fn main() -> pub Field { /// Test the array functions in std::array fn test_array_functions() { let myarray: [i32; 3] = [1, 2, 3]; - constrain std::array::any(myarray, |n| n > 2); + constrain myarray.any(|n| n > 2); let evens: [i32; 3] = [2, 4, 6]; - constrain std::array::all(evens, |n| n > 1); + constrain evens.all(|n| n > 1); - constrain std::array::fold(evens, 0, |a, b| a + b) == 12; - constrain std::array::reduce(evens, |a, b| a + b) == 12; + constrain evens.fold(0, |a, b| a + b) == 12; + constrain evens.reduce(|a, b| a + b) == 12; - let descending = std::array::sort_via(myarray, |a, b| a > b); + let descending = myarray.sort_via(|a, b| a > b); constrain descending == [3, 2, 1]; } diff --git a/crates/nargo/tests/test_data/strings/src/main.nr b/crates/nargo/tests/test_data/strings/src/main.nr index a22ad06af0f..ca0d1691f86 100644 --- a/crates/nargo/tests/test_data/strings/src/main.nr +++ b/crates/nargo/tests/test_data/strings/src/main.nr @@ -53,4 +53,4 @@ struct Test { a: Field, b: Field, c: [Field; 2], -} \ No newline at end of file +} diff --git a/crates/nargo/tests/test_data/struct_inputs/src/main.nr b/crates/nargo/tests/test_data/struct_inputs/src/main.nr index 61637d95ca1..e022f26947c 100644 --- a/crates/nargo/tests/test_data/struct_inputs/src/main.nr +++ b/crates/nargo/tests/test_data/struct_inputs/src/main.nr @@ -13,7 +13,7 @@ fn main(x : Field, y : pub myStruct, z: pub foo::bar::barStruct, a: pub foo::foo check_inner_struct(a, z); - for i in 0..std::array::len(struct_from_bar.array) { + for i in 0 .. struct_from_bar.array.len() { constrain struct_from_bar.array[i] == z.array[i]; } constrain z.val == struct_from_bar.val; @@ -30,7 +30,7 @@ fn main(x : Field, y : pub myStruct, z: pub foo::bar::barStruct, a: pub foo::foo fn check_inner_struct(a: foo::fooStruct, z: foo::bar::barStruct) { constrain a.bar_struct.val == z.val; - for i in 0..std::array::len(a.bar_struct.array) { + for i in 0.. a.bar_struct.array.len() { constrain a.bar_struct.array[i] == z.array[i]; } } diff --git a/crates/nargo/tests/test_data/to_le_bytes/src/main.nr b/crates/nargo/tests/test_data/to_le_bytes/src/main.nr index 2fb86170230..a5476ec13bf 100644 --- a/crates/nargo/tests/test_data/to_le_bytes/src/main.nr +++ b/crates/nargo/tests/test_data/to_le_bytes/src/main.nr @@ -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::field::to_le_bytes(x, 31); + let byte_array = x.to_le_bytes(31); let mut first_four_bytes = [0; 4]; for i in 0..4 { first_four_bytes[i] = byte_array[i]; @@ -11,4 +11,4 @@ fn main(x : Field) -> pub [u8; 4] { // We were incorrectly mapping our output array from bit decomposition functions during acir generation first_four_bytes[3] = byte_array[31]; first_four_bytes -} \ No newline at end of file +} diff --git a/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs b/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs index 1c5dc4f178f..ef9986796bc 100644 --- a/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -1,6 +1,6 @@ use super::dc_mod::collect_defs; use super::errors::DefCollectorErrorKind; -use crate::graph::CrateId; +use crate::graph::{CrateId, LOCAL_CRATE}; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}; use crate::hir::resolution::errors::ResolverError; use crate::hir::resolution::resolver::Resolver; @@ -226,7 +226,10 @@ fn collect_impls( errors.push(err.into_file_diagnostic(unresolved.file_id)); } } - } else if typ != Type::Error { + // Prohibit defining impls for primitive types if we're in the local crate. + // We should really prevent it for all crates that aren't the noir stdlib but + // there is no way of checking if the current crate is the stdlib currently. + } else if typ != Type::Error && crate_id == LOCAL_CRATE { let span = *span; let error = DefCollectorErrorKind::NonStructTypeInImpl { span }; errors.push(error.into_file_diagnostic(unresolved.file_id)) diff --git a/crates/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index e292672cc3b..88f768a71af 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -369,13 +369,16 @@ fn lookup_method( // In the future we could support methods for non-struct types if we have a context // (in the interner?) essentially resembling HashMap - other => { - errors.push(TypeCheckError::Unstructured { - span: interner.expr_span(expr_id), - msg: format!("Type '{other}' must be a struct type to call methods on it"), - }); - None - } + other => match interner.lookup_primitive_method(other, method_name) { + Some(method_id) => Some(method_id), + None => { + errors.push(TypeCheckError::Unstructured { + span: interner.expr_span(expr_id), + msg: format!("No method named '{method_name}' found for type '{other}'",), + }); + None + } + }, } } diff --git a/crates/noirc_frontend/src/node_interner.rs b/crates/noirc_frontend/src/node_interner.rs index 35b3a7e7a52..c6b7f99f797 100644 --- a/crates/noirc_frontend/src/node_interner.rs +++ b/crates/noirc_frontend/src/node_interner.rs @@ -169,10 +169,11 @@ pub struct NodeInterner { delayed_type_checks: Vec, - // A map from a struct type and method name to a function id for the method - // along with any generic on the struct it may require. E.g. if the impl is - // only for `impl Foo` rather than all Foo, the generics will be `vec![String]`. - struct_methods: HashMap<(StructId, String), (Vec, FuncId)>, + /// A map from a struct type and method name to a function id for the method. + struct_methods: HashMap<(StructId, String), FuncId>, + + /// Methods on primitive types defined in the stdlib. + primitive_methods: HashMap<(TypeMethodKey, String), FuncId>, } type TypeCheckFn = Box Result<(), TypeCheckError>>; @@ -241,6 +242,7 @@ impl Default for NodeInterner { language: Language::R1CS, delayed_type_checks: vec![], struct_methods: HashMap::new(), + primitive_methods: HashMap::new(), }; // An empty block expression is used often, we add this into the `node` on startup @@ -585,16 +587,67 @@ impl NodeInterner { method_id: FuncId, ) -> Option { match self_type { - Type::Struct(struct_type, generics) => { + Type::Struct(struct_type, _generics) => { let key = (struct_type.borrow().id, method_name); - self.struct_methods.insert(key, (generics.clone(), method_id)).map(|(_, id)| id) + self.struct_methods.insert(key, method_id) + } + Type::Error => None, + + other => { + let key = get_type_method_key(self_type).unwrap_or_else(|| { + unreachable!("Cannot add a method to the unsupported type '{}'", other) + }); + self.primitive_methods.insert((key, method_name), method_id) } - other => unreachable!("Tried adding method to non-struct type '{}'", other), } } /// Search by name for a method on the given struct pub fn lookup_method(&self, id: StructId, method_name: &str) -> Option { - self.struct_methods.get(&(id, method_name.to_owned())).map(|(_, id)| *id) + self.struct_methods.get(&(id, method_name.to_owned())).copied() + } + + /// Looks up a given method name on the given primitive type. + pub fn lookup_primitive_method(&self, typ: &Type, method_name: &str) -> Option { + get_type_method_key(typ) + .and_then(|key| self.primitive_methods.get(&(key, method_name.to_owned())).copied()) + } +} + +/// These are the primitive type variants that we support adding methods to +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +enum TypeMethodKey { + /// Fields and integers share methods for ease of use. These methods may still + /// accept only fields or integers, it is just that their names may not clash. + FieldOrInt, + Array, + Bool, + String, + Unit, + Tuple, + Function, +} + +fn get_type_method_key(typ: &Type) -> Option { + use TypeMethodKey::*; + let typ = typ.follow_bindings(); + match &typ { + Type::FieldElement(_) => Some(FieldOrInt), + Type::Array(_, _) => Some(Array), + Type::Integer(_, _, _) => Some(FieldOrInt), + Type::PolymorphicInteger(_, _) => Some(FieldOrInt), + Type::Bool(_) => Some(Bool), + Type::String(_) => Some(String), + Type::Unit => Some(Unit), + Type::Tuple(_) => Some(Tuple), + Type::Function(_, _) => Some(Function), + + // We do not support adding methods to these types + Type::TypeVariable(_) + | Type::NamedGeneric(_, _) + | Type::Forall(_, _) + | Type::Constant(_) + | Type::Error + | Type::Struct(_, _) => None, } } diff --git a/crates/noirc_frontend/src/parser/mod.rs b/crates/noirc_frontend/src/parser/mod.rs index 7b57018d533..20e24a6a55c 100644 --- a/crates/noirc_frontend/src/parser/mod.rs +++ b/crates/noirc_frontend/src/parser/mod.rs @@ -7,8 +7,8 @@ use std::sync::atomic::{AtomicU32, Ordering}; use crate::token::{Keyword, Token}; use crate::{ast::ImportStatement, Expression, NoirStruct}; use crate::{ - BlockExpression, CallExpression, ExpressionKind, ForExpression, Ident, IndexExpression, - LetStatement, NoirFunction, NoirImpl, Path, PathKind, Pattern, Recoverable, Statement, + BlockExpression, ExpressionKind, ForExpression, Ident, IndexExpression, LetStatement, + MethodCallExpression, NoirFunction, NoirImpl, Path, PathKind, Pattern, Recoverable, Statement, UnresolvedType, }; @@ -371,19 +371,15 @@ impl ForRange { expression: array, }); - let ident = |name: &str| Ident::new(name.to_string(), array_span); - - // std::array::len(array) + // array.len() let segments = vec![array_ident]; let array_ident = ExpressionKind::Variable(Path { segments, kind: PathKind::Plain }); - let segments = vec![ident("std"), ident("array"), ident("len")]; - let func_ident = ExpressionKind::Variable(Path { segments, kind: PathKind::Dep }); - - let end_range = ExpressionKind::Call(Box::new(CallExpression { - func: Box::new(Expression::new(func_ident, array_span)), - arguments: vec![Expression::new(array_ident.clone(), array_span)], + let end_range = ExpressionKind::MethodCall(Box::new(MethodCallExpression { + object: Expression::new(array_ident.clone(), array_span), + method_name: Ident::new("len".to_string(), array_span), + arguments: vec![], })); let end_range = Expression::new(end_range, array_span); diff --git a/noir_stdlib/src/array.nr b/noir_stdlib/src/array.nr index 125b044c0b2..f22339aec59 100644 --- a/noir_stdlib/src/array.nr +++ b/noir_stdlib/src/array.nr @@ -1,58 +1,61 @@ -#[builtin(array_len)] -fn len(_input : [T]) -> comptime Field {} -#[builtin(arraysort)] -fn sort(_a: [T; N]) -> [T; N] {} +impl [T; N] { + #[builtin(array_len)] + fn len(_array: Self) -> comptime Field {} -// Sort with a custom sorting function. -fn sort_via(mut a: [T; N], ordering: fn(T, T) -> bool) -> [T; N] { - for i in 1..len(a) { - for j in 0..i { - if ordering(a[i], a[j]) { - let old_a_j = a[j]; - a[j] = a[i]; - a[i] = old_a_j; + #[builtin(arraysort)] + fn sort(_array: Self) -> Self {} + + // Sort with a custom sorting function. + fn sort_via(mut a: Self, ordering: fn(T, T) -> bool) -> Self { + for i in 1 .. a.len() { + for j in 0..i { + if ordering(a[i], a[j]) { + let old_a_j = a[j]; + a[j] = a[i]; + a[i] = old_a_j; + } } } + a } - a -} -// Apply a function to each element of the array and an accumulator value, -// returning the final accumulated value. This function is also sometimes -// called `foldl`, `fold_left`, `reduce`, or `inject`. -fn fold(array: [T; N], mut accumulator: U, f: fn(U, T) -> U) -> U { - for i in 0 .. len(array) { - accumulator = f(accumulator, array[i]); + // Apply a function to each element of the array and an accumulator value, + // returning the final accumulated value. This function is also sometimes + // called `foldl`, `fold_left`, `reduce`, or `inject`. + fn fold(self, mut accumulator: U, f: fn(U, T) -> U) -> U { + for elem in self { + accumulator = f(accumulator, elem); + } + accumulator } - accumulator -} -// Apply a function to each element of the array and an accumulator value, -// returning the final accumulated value. Unlike fold, reduce uses the first -// element of the given array as its starting accumulator value. -fn reduce(array: [T; N], f: fn(T, T) -> T) -> T { - let mut accumulator = array[0]; - for i in 1 .. len(array) { - accumulator = f(accumulator, array[i]); + // Apply a function to each element of the array and an accumulator value, + // returning the final accumulated value. Unlike fold, reduce uses the first + // element of the given array as its starting accumulator value. + fn reduce(self, f: fn(T, T) -> T) -> T { + let mut accumulator = self[0]; + for i in 1 .. self.len() { + accumulator = f(accumulator, self[i]); + } + accumulator } - accumulator -} -// Returns true if all elements in the array satisfy the predicate -fn all(array: [T; N], predicate: fn(T) -> bool) -> bool { - let mut ret = true; - for i in 0 .. len(array) { - ret &= predicate(array[i]); + // Returns true if all elements in the array satisfy the predicate + fn all(self, predicate: fn(T) -> bool) -> bool { + let mut ret = true; + for elem in self { + ret &= predicate(elem); + } + ret } - ret -} -// Returns true if any element in the array satisfies the predicate -fn any(array: [T; N], predicate: fn(T) -> bool) -> bool { - let mut ret = false; - for i in 0 .. len(array) { - ret |= predicate(array[i]); + // Returns true if any element in the array satisfies the predicate + fn any(self, predicate: fn(T) -> bool) -> bool { + let mut ret = false; + for elem in self { + ret |= predicate(elem); + } + ret } - ret } diff --git a/noir_stdlib/src/field.nr b/noir_stdlib/src/field.nr index 0e8a5637842..0c6e33efb10 100644 --- a/noir_stdlib/src/field.nr +++ b/noir_stdlib/src/field.nr @@ -1,14 +1,31 @@ -#[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) -} +impl Field { + #[builtin(to_le_bits)] + fn to_le_bits(_x : Field, _bit_size: u32) -> [u1] {} + + fn to_le_bytes(x : Field, byte_size: u32) -> [u8] { + x.to_radix(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(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] {} + // Returns self to the power of the given exponent value. + // 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(self, exponent: Field) -> Field { + let mut r: Field = 1; + let b = exponent.to_le_bits(32); + + for i in 1..33 { + r *= r; + r = (b[32-i] as Field) * (r * self) + (1 - b[32-i] as Field) * r; + } + r + } +} #[builtin(modulus_num_bits)] fn modulus_num_bits() -> comptime Field {} @@ -23,4 +40,4 @@ fn modulus_le_bits() -> [u1] {} fn modulus_be_bytes() -> [u8] {} #[builtin(modulus_le_bytes)] -fn modulus_le_bytes() -> [u8] {} \ No newline at end of file +fn modulus_le_bytes() -> [u8] {} diff --git a/noir_stdlib/src/hash.nr b/noir_stdlib/src/hash.nr index 40e9ef4511e..bf00fb27619 100644 --- a/noir_stdlib/src/hash.nr +++ b/noir_stdlib/src/hash.nr @@ -1,28 +1,29 @@ + #[foreign(sha256)] -fn sha256(_input : [u8]) -> [u8; 32] {} +fn sha256(_input : [u8; N]) -> [u8; 32] {} #[foreign(blake2s)] -fn blake2s(_input : [u8]) -> [u8; 32] {} +fn blake2s(_input : [u8; N]) -> [u8; 32] {} #[foreign(pedersen)] -fn pedersen(_input : [Field]) -> [Field; 2] {} +fn pedersen(_input : [Field; N]) -> [Field; 2] {} #[foreign(hash_to_field_128_security)] -fn hash_to_field(_input : [Field]) -> Field {} +fn hash_to_field(_input : [Field; N]) -> Field {} // mimc-p/p implementation // constants are (publicly generated) random numbers, for instance using keccak as a ROM. // You must use constants generated for the native field // Rounds number should be ~ log(p)/log(exp) // For 254 bit primes, exponent 7 and 91 rounds seems to be recommended -fn mimc(x: Field, k: Field, constants: [Field], exp : Field) -> Field { +fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field { //round 0 let mut t = x + k; - let mut h = crate::pow_32(t,exp); + let mut h = t.pow_32(exp); //next rounds - for i in 1..crate::array::len(constants) { + for i in 1 .. constants.len() { t = h + k + constants[i]; - h = crate::pow_32(t,exp); + h = t.pow_32(exp); }; h + k } @@ -30,7 +31,7 @@ fn mimc(x: Field, k: Field, constants: [Field], exp : Field) -> Field { global MIMC_BN254_ROUNDS = 91; //mimc implementation with hardcoded parameters for BN254 curve. -fn mimc_bn254(x: [Field]) -> Field { +fn mimc_bn254(array: [Field; N]) -> Field { //mimc parameters let exponent = 7; //generated from seed "mimc" using keccak256 @@ -127,11 +128,11 @@ fn mimc_bn254(x: [Field]) -> Field { 18979889247746272055963929241596362599320706910852082477600815822482192194401, 13602139229813231349386885113156901793661719180900395818909719758150455500533, ]; - + let mut r = 0; - for i in 0 .. crate::array::len(x) { - let h = mimc(x[i], r, constants, exponent); - r = r + x[i] + h; - }; + for elem in array { + let h = mimc(elem, r, constants, exponent); + r = r + elem + h; + } r } diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index dc87dab3d75..b3d903b7262 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -10,19 +10,3 @@ mod field; #[builtin(println)] fn println(_input : T) {} - -// 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 = field::to_le_bits(exponent, 32); - - for i in 1..33 { - r = r*r; - r = (b[32-i] as Field) * (r * base) + (1 - b[32-i] as Field) * r; - }; - r -} - diff --git a/noir_stdlib/src/merkle.nr b/noir_stdlib/src/merkle.nr index 7b6db21d755..9f7c5d5b130 100644 --- a/noir_stdlib/src/merkle.nr +++ b/noir_stdlib/src/merkle.nr @@ -16,8 +16,8 @@ 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::field::to_le_bits(index, n as u32); + let n = hash_path.len(); + let index_bits = index.to_le_bits(n as u32); let mut current = leaf; for i in 0..n { let path_bit = index_bits[i] as bool; diff --git a/noir_stdlib/src/sha256.nr b/noir_stdlib/src/sha256.nr index 8d2d0d12e4d..83e08ada7e8 100644 --- a/noir_stdlib/src/sha256.nr +++ b/noir_stdlib/src/sha256.nr @@ -100,30 +100,26 @@ fn msg_u8_to_u32(msg: [u8; 64]) -> [u32; 16] // SHA-256 hash function #[alternative(sha256)] -fn digest(msg: [u8]) -> [u8; 32] -{ +fn digest(msg: [u8; N]) -> [u8; 32] { let mut msg_block: [u8; 64] = [0; 64]; let mut h: [u32; 8] = [1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]; // Intermediate hash, starting with the canonical initial value let mut c: [u32; 8] = [0; 8]; // Compression of current message block as sequence of u32 let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes let mut i = 0; // Message byte pointer - for k in 0..crate::array::len(msg) - { + for k in 0 .. msg.len() { // Populate msg_block msg_block[i] = msg[k]; i = i + 1; - if i == 64 // Enough to hash block - { + if i == 64 { // Enough to hash block c = sha_c(msg_u8_to_u32(msg_block), h); - for j in 0..8 - { + for j in 0..8 { h[j] = c[j] + h[j]; - }; + } i = 0; } - }; + } // Pad the rest such that we have a [u32; 2] block at the end representing the length // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]). @@ -132,64 +128,52 @@ fn digest(msg: [u8]) -> [u8; 32] // If i >= 57, there aren't enough bits in the current message block to accomplish this, so // the 1 and 0s fill up the current block, which we then compress accordingly. - if i >= 57 // Not enough bits (64) to store length. Fill up with zeros. - { - if i < 64 - { - for _i in 57..64 - { - if i <= 63 - { + if i >= 57 { // Not enough bits (64) to store length. Fill up with zeros. + if i < 64 { + for _i in 57..64 { + if i <= 63 { msg_block[i] = 0; - i = i + 1; + i += 1; } - }; + } } c = h; c = sha_c(msg_u8_to_u32(msg_block), c); - for j in 0..8 - { - h[j] = c[j] + h[j]; - }; + for j in 0..8 { + h[j] += c[j]; + } i = 0; } - for _i in 0..64 // In any case, fill blocks up with zeros until the last 64 (i.e. until i = 56). - { - if i < 56 - { + for _i in 0..64 {// In any case, fill blocks up with zeros until the last 64 (i.e. until i = 56). + if i < 56 { msg_block[i] = 0; i = i + 1; - } else if i < 64 - { - let mut len = 8*crate::array::len(msg) as u64; - for j in 0..8 - { - msg_block[63 - j] = len as u8; - len = len >> 8; - }; - i = i + 8; + } else if i < 64 { + let mut len = 8 * msg.len() as u64; + for j in 0..8 { + msg_block[63 - j] = len as u8; + len >>= 8; } - }; + i += 8; + } + } // Hash final padded block c = h; c = sha_c(msg_u8_to_u32(msg_block), c); - for j in 0..8 - { - h[j] = c[j] + h[j]; - }; + for j in 0..8 { + h[j] += c[j]; + } // Return final hash as byte array - for j in 0..8 - { - for k in 0..4 - { + for j in 0..8 { + for k in 0..4 { out_h[31 - 4*j - k] = h[7 - j] as u8; - h[7-j] = h[7-j] >> 8; - }; - }; + h[7-j] >>= 8; + } + } out_h } diff --git a/noir_stdlib/src/sha512.nr b/noir_stdlib/src/sha512.nr index 45ca27b855d..66a5cc5a169 100644 --- a/noir_stdlib/src/sha512.nr +++ b/noir_stdlib/src/sha512.nr @@ -98,7 +98,7 @@ fn msg_u8_to_u64(msg: [u8; 128]) -> [u64; 16] } // SHA-512 hash function -fn digest(msg: [u8]) -> [u8; 64] +fn digest(msg: [u8; N]) -> [u8; 64] { let mut msg_block: [u8; 128] = [0; 128]; let mut h: [u64; 8] = [7640891576956012808, 13503953896175478587, 4354685564936845355, 11912009170470909681, 5840696475078001361, 11170449401992604703, 2270897969802886507, 6620516959819538809]; // Intermediate hash, starting with the canonical initial value @@ -106,87 +106,71 @@ fn digest(msg: [u8]) -> [u8; 64] let mut out_h: [u8; 64] = [0; 64]; // Digest as sequence of bytes let mut i = 0; // Message byte pointer - for k in 0..crate::array::len(msg) - { + for k in 0 .. msg.len() { // Populate msg_block msg_block[i] = msg[k]; i = i + 1; - if i == 128 // Enough to hash block - { + if i == 128 { // Enough to hash block c = sha_c(msg_u8_to_u64(msg_block), h); - for j in 0..8 - { - h[j] = c[j] + h[j]; - }; + for j in 0..8 { + h[j] += c[j]; + } i = 0; } - }; + } // Pad the rest such that we have a [u64; 2] block at the end representing the length // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]). msg_block[i] = 1 << 7; - i = i + 1; + i += 1; // If i >= 113, there aren't enough bits in the current message block to accomplish this, so // the 1 and 0s fill up the current block, which we then compress accordingly. - if i >= 113 // Not enough bits (128) to store length. Fill up with zeros. - { - - if i < 128 - { - for _i in 113..128 - { - if i <= 127 - { + if i >= 113 { // Not enough bits (128) to store length. Fill up with zeros. + if i < 128 { + for _i in 113..128 { + if i <= 127 { msg_block[i] = 0; - i = i + 1; + i += 1; } - }; + } } c = sha_c(msg_u8_to_u64(msg_block), h); - for j in 0..8 - { - h[j] = c[j] + h[j]; - }; + for j in 0..8 { + h[j] += c[j]; + } i = 0; } - for _i in 0..128 // In any case, fill blocks up with zeros until the last 128 (i.e. until i = 112). - { - if i < 112 - { + for _i in 0..128 {// In any case, fill blocks up with zeros until the last 128 (i.e. until i = 112). + if i < 112 { msg_block[i] = 0; - i = i + 1; - } else if i < 128 - { - let mut len = 8*crate::array::len(msg) as u64; // u128 unsupported - for j in 0..16 - { - msg_block[127 - j] = len as u8; - len = len >> 8; - }; - i = i + 16; // Done. + i += 1; + } else if i < 128 { + let mut len = 8 * msg.len() as u64; // u128 unsupported + for j in 0..16 { + msg_block[127 - j] = len as u8; + len >>= 8; } - }; + i += 16; // Done. + } + } // Hash final padded block c = sha_c(msg_u8_to_u64(msg_block), h); - for j in 0..8 - { - h[j] = c[j] + h[j]; - }; + for j in 0..8 { + h[j] += c[j]; + } // Return final hash as byte array - for j in 0..8 - { - for k in 0..8 - { + for j in 0..8 { + for k in 0..8 { out_h[63 - 8*j - k] = h[7 - j] as u8; - h[7-j] = h[7-j] >> 8; - }; - }; + h[7-j] >>= 8; + } + } out_h }