Skip to content

Commit

Permalink
Merge e99e959 into 062103e
Browse files Browse the repository at this point in the history
  • Loading branch information
vezenovm authored Aug 28, 2024
2 parents 062103e + e99e959 commit 4e2899a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 6 deletions.
41 changes: 37 additions & 4 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ use std::{
use acvm::{AcirField, FieldElement};
use builtin_helpers::{
block_expression_to_value, check_argument_count, check_function_not_yet_resolved,
check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_function_def,
get_module, get_quoted, get_slice, get_struct, get_trait_constraint, get_trait_def,
get_trait_impl, get_tuple, get_type, get_u32, get_unresolved_type, hir_pattern_to_tokens,
mutate_func_meta_type, parse, replace_func_meta_parameters, replace_func_meta_return_type,
check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_field,
get_function_def, get_module, get_quoted, get_slice, get_struct, get_trait_constraint,
get_trait_def, get_trait_impl, get_tuple, get_type, get_u32, get_unresolved_type,
hir_pattern_to_tokens, mutate_func_meta_type, parse, replace_func_meta_parameters,
replace_func_meta_return_type,
};
use chumsky::{prelude::choice, Parser};
use im::Vector;
use iter_extended::{try_vecmap, vecmap};
use noirc_errors::Location;
use num_bigint::BigUint;
use rustc_hash::FxHashMap as HashMap;

use crate::{
Expand Down Expand Up @@ -49,6 +51,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
match name {
"array_as_str_unchecked" => array_as_str_unchecked(interner, arguments, location),
"array_len" => array_len(interner, arguments, location),
"assert_constant" => Ok(Value::Bool(true)),
"as_slice" => as_slice(interner, arguments, location),
"expr_as_array" => expr_as_array(interner, arguments, return_type, location),
"expr_as_assign" => expr_as_assign(interner, arguments, return_type, location),
Expand Down Expand Up @@ -114,6 +117,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"struct_def_as_type" => struct_def_as_type(interner, arguments, location),
"struct_def_fields" => struct_def_fields(interner, arguments, location),
"struct_def_generics" => struct_def_generics(interner, arguments, location),
"to_le_radix" => to_le_radix(arguments, location),
"trait_constraint_eq" => trait_constraint_eq(interner, arguments, location),
"trait_constraint_hash" => trait_constraint_hash(interner, arguments, location),
"trait_def_as_trait_constraint" => {
Expand Down Expand Up @@ -425,6 +429,35 @@ fn quoted_as_type(
Ok(Value::Type(typ))
}

fn to_le_radix(arguments: Vec<(Value, Location)>, location: Location) -> IResult<Value> {
let (value, radix, limb_count) = check_three_arguments(arguments, location)?;

let value = get_field(value)?;
let radix = get_u32(radix)?;
let limb_count = get_u32(limb_count)?;

// Decompose the integer into its radix digits in little endian form.
let decomposed_integer = compute_to_radix(value, radix);
let decomposed_integer = vecmap(0..limb_count as usize, |i| match decomposed_integer.get(i) {
Some(digit) => Value::U8(*digit),
None => Value::U8(0),
});
Ok(Value::Array(
decomposed_integer.into(),
Type::Integer(Signedness::Unsigned, IntegerBitSize::Eight),
))
}

fn compute_to_radix(field: FieldElement, radix: u32) -> Vec<u8> {
let bit_size = u32::BITS - (radix - 1).leading_zeros();
let radix_big = BigUint::from(radix);
assert_eq!(BigUint::from(2u128).pow(bit_size), radix_big, "ICE: Radix must be a power of 2");
let big_integer = BigUint::from_bytes_be(&field.to_be_bytes());

// Decompose the integer into its radix digits in little endian form.
big_integer.to_radix_le(radix)
}

// fn as_array(self) -> Option<(Type, Type)>
fn type_as_array(
arguments: Vec<(Value, Location)>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ pub(crate) fn get_u32((value, location): (Value, Location)) -> IResult<u32> {
}
}

pub(crate) fn get_u64((value, location): (Value, Location)) -> IResult<u64> {
match value {
Value::U64(value) => Ok(value),
value => {
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::SixtyFour);
type_mismatch(value, expected, location)
}
}
}

pub(crate) fn get_expr(
interner: &NodeInterner,
(value, location): (Value, Location),
Expand Down
31 changes: 29 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/foreign.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use acvm::BlackBoxFunctionSolver;
use acvm::blackbox_solver::BlackBoxFunctionSolver;
use bn254_blackbox_solver::Bn254BlackBoxSolver;
use im::Vector;
use iter_extended::try_vecmap;
use noirc_errors::Location;

Expand All @@ -8,7 +9,9 @@ use crate::{
macros_api::NodeInterner,
};

use super::builtin::builtin_helpers::{check_two_arguments, get_array, get_field, get_u32};
use super::builtin::builtin_helpers::{
check_one_argument, check_two_arguments, get_array, get_field, get_u32, get_u64,
};

pub(super) fn call_foreign(
interner: &mut NodeInterner,
Expand All @@ -18,6 +21,7 @@ pub(super) fn call_foreign(
) -> IResult<Value> {
match name {
"poseidon2_permutation" => poseidon2_permutation(interner, arguments, location),
"keccakf1600" => keccakf1600(interner, arguments, location),
_ => {
let item = format!("Comptime evaluation for builtin function {name}");
Err(InterpreterError::Unimplemented { item, location })
Expand Down Expand Up @@ -47,3 +51,26 @@ fn poseidon2_permutation(
let array = fields.into_iter().map(Value::Field).collect();
Ok(Value::Array(array, typ))
}

fn keccakf1600(
interner: &mut NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let input = check_one_argument(arguments, location)?;
let input_location = input.1;

let (input, typ) = get_array(interner, input)?;

let input = try_vecmap(input, |integer| get_u64((integer, input_location)))?;

let mut state = [0u64; 25];
for (it, input_value) in state.iter_mut().zip(input.iter()) {
*it = *input_value;
}
let result_lanes = acvm::blackbox_solver::keccakf1600(state)
.map_err(|error| InterpreterError::BlackBoxError(error, location))?;

let array: Vector<Value> = result_lanes.into_iter().map(Value::U64).collect();
Ok(Value::Array(array, typ))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "comptime_keccak"
type = "bin"
authors = [""]
compiler_version = ">=0.33.0"

[dependencies]
31 changes: 31 additions & 0 deletions test_programs/compile_success_empty/comptime_keccak/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Tests a very simple program.
//
// The features being tested is keccak256 in brillig
fn main() {
comptime
{
let x = 0xbd;
let result = [
0x5a, 0x50, 0x2f, 0x9f, 0xca, 0x46, 0x7b, 0x26, 0x6d, 0x5b, 0x78, 0x33, 0x65, 0x19, 0x37, 0xe8, 0x05, 0x27, 0x0c, 0xa3, 0xf3, 0xaf, 0x1c, 0x0d, 0xd2, 0x46, 0x2d, 0xca, 0x4b, 0x3b, 0x1a, 0xbf
];
// We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field
// The padding is taken care of by the program
let digest = keccak256([x as u8], 1);
assert(digest == result);
//#1399: variable message size
let message_size = 4;
let hash_a = keccak256([1, 2, 3, 4], message_size);
let hash_b = keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size);

assert(hash_a == hash_b);

let message_size_big = 8;
let hash_c = keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size_big);

assert(hash_a != hash_c);
}
}

comptime fn keccak256<let N: u32>(data: [u8; N], msg_len: u32) -> [u8; 32] {
std::hash::keccak256(data, msg_len)
}

0 comments on commit 4e2899a

Please sign in to comment.