Skip to content

Commit

Permalink
chore: Sync to noir-lang/noir
Browse files Browse the repository at this point in the history
chore: uses sha256compression opcode in Noir and implements acvm solver for it (AztecProtocol/aztec-packages#4511)
chore!: move noir out of yarn-project (AztecProtocol/aztec-packages#4479)
feat!: note type ids (AztecProtocol/aztec-packages#4500)
chore: Pull noir (AztecProtocol/aztec-packages#4546)
feat: Added cast opcode and cast calldata (AztecProtocol/aztec-packages#4423)
refactor: cleanup of `abi.nr` in `aztec-nr` (AztecProtocol/aztec-packages#4473)
  • Loading branch information
AztecBot committed Feb 13, 2024
1 parent 6ff518a commit cf7b00e
Show file tree
Hide file tree
Showing 24 changed files with 386 additions and 197 deletions.
56 changes: 55 additions & 1 deletion acvm-repo/acir/codegen/acir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,16 @@ namespace Circuit {
static BinaryIntOp bincodeDeserialize(std::vector<uint8_t>);
};

struct Cast {
Circuit::MemoryAddress destination;
Circuit::MemoryAddress source;
uint32_t bit_size;

friend bool operator==(const Cast&, const Cast&);
std::vector<uint8_t> bincodeSerialize() const;
static Cast bincodeDeserialize(std::vector<uint8_t>);
};

struct JumpIfNot {
Circuit::MemoryAddress condition;
uint64_t location;
Expand Down Expand Up @@ -590,7 +600,7 @@ namespace Circuit {
static Stop bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<BinaryFieldOp, BinaryIntOp, JumpIfNot, JumpIf, Jump, CalldataCopy, Call, Const, Return, ForeignCall, Mov, Load, Store, BlackBox, Trap, Stop> value;
std::variant<BinaryFieldOp, BinaryIntOp, Cast, JumpIfNot, JumpIf, Jump, CalldataCopy, Call, Const, Return, ForeignCall, Mov, Load, Store, BlackBox, Trap, Stop> value;

friend bool operator==(const BrilligOpcode&, const BrilligOpcode&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -4300,6 +4310,50 @@ Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable<Circuit::BrilligOpcode
return obj;
}

namespace Circuit {

inline bool operator==(const BrilligOpcode::Cast &lhs, const BrilligOpcode::Cast &rhs) {
if (!(lhs.destination == rhs.destination)) { return false; }
if (!(lhs.source == rhs.source)) { return false; }
if (!(lhs.bit_size == rhs.bit_size)) { return false; }
return true;
}

inline std::vector<uint8_t> BrilligOpcode::Cast::bincodeSerialize() const {
auto serializer = serde::BincodeSerializer();
serde::Serializable<BrilligOpcode::Cast>::serialize(*this, serializer);
return std::move(serializer).bytes();
}

inline BrilligOpcode::Cast BrilligOpcode::Cast::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<BrilligOpcode::Cast>::deserialize(deserializer);
if (deserializer.get_buffer_offset() < input.size()) {
throw serde::deserialization_error("Some input bytes were not read");
}
return value;
}

} // end of namespace Circuit

template <>
template <typename Serializer>
void serde::Serializable<Circuit::BrilligOpcode::Cast>::serialize(const Circuit::BrilligOpcode::Cast &obj, Serializer &serializer) {
serde::Serializable<decltype(obj.destination)>::serialize(obj.destination, serializer);
serde::Serializable<decltype(obj.source)>::serialize(obj.source, serializer);
serde::Serializable<decltype(obj.bit_size)>::serialize(obj.bit_size, serializer);
}

template <>
template <typename Deserializer>
Circuit::BrilligOpcode::Cast serde::Deserializable<Circuit::BrilligOpcode::Cast>::deserialize(Deserializer &deserializer) {
Circuit::BrilligOpcode::Cast obj;
obj.destination = serde::Deserializable<decltype(obj.destination)>::deserialize(deserializer);
obj.source = serde::Deserializable<decltype(obj.source)>::deserialize(deserializer);
obj.bit_size = serde::Deserializable<decltype(obj.bit_size)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const BrilligOpcode::JumpIfNot &lhs, const BrilligOpcode::JumpIfNot &rhs) {
Expand Down
28 changes: 14 additions & 14 deletions acvm-repo/acir/tests/test_program_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,11 @@ fn simple_brillig_foreign_call() {
let bytes = Circuit::serialize_circuit(&circuit);

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 215, 148, 150, 246,
212, 175, 216, 31, 244, 51, 61, 244, 226, 65, 196, 247, 171, 24, 33, 136, 122, 209, 129,
144, 176, 132, 101, 247, 4, 160, 144, 217, 196, 45, 41, 218, 203, 91, 207, 241, 168, 117,
94, 90, 230, 37, 238, 144, 216, 27, 249, 11, 87, 156, 131, 239, 223, 248, 207, 186, 81,
235, 150, 67, 173, 221, 189, 95, 18, 34, 97, 64, 0, 116, 135, 40, 214, 136, 1, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 16, 67, 227, 21, 74, 233,
212, 79, 177, 127, 208, 159, 233, 224, 226, 32, 226, 247, 139, 168, 16, 68, 93, 244, 45,
119, 228, 142, 144, 92, 0, 20, 50, 7, 237, 76, 213, 190, 50, 245, 26, 175, 218, 231, 165,
57, 175, 148, 14, 137, 179, 147, 191, 114, 211, 221, 216, 240, 59, 63, 107, 221, 115, 104,
181, 103, 244, 43, 36, 10, 38, 68, 108, 25, 253, 238, 136, 1, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down Expand Up @@ -305,15 +305,15 @@ fn complex_brillig_foreign_call() {
let bytes = Circuit::serialize_circuit(&circuit);

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 73, 14, 131, 48, 12, 28, 147, 166, 165, 167,
126, 161, 82, 251, 128, 180, 47, 224, 47, 85, 111, 32, 56, 242, 124, 130, 24, 68, 176, 2,
23, 130, 4, 35, 89, 206, 50, 137, 71, 182, 147, 28, 128, 96, 128, 241, 150, 113, 44, 156,
135, 24, 121, 5, 189, 219, 134, 143, 164, 187, 203, 237, 165, 49, 59, 129, 70, 179, 131,
198, 177, 31, 14, 90, 239, 148, 117, 73, 154, 63, 19, 121, 63, 23, 111, 214, 219, 149, 243,
27, 125, 206, 117, 208, 63, 85, 222, 161, 248, 32, 167, 72, 162, 245, 235, 44, 166, 94, 20,
21, 251, 30, 196, 253, 213, 85, 83, 254, 91, 163, 168, 90, 234, 43, 24, 191, 213, 190, 172,
156, 235, 17, 126, 59, 49, 142, 68, 120, 75, 220, 7, 166, 84, 90, 68, 72, 194, 139, 180,
136, 25, 58, 46, 103, 45, 188, 25, 5, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 125, 177, 163, 35, 179,
154, 35, 8, 51, 7, 232, 204, 9, 188, 139, 184, 83, 116, 233, 241, 173, 152, 98, 12, 213,
141, 21, 244, 65, 232, 39, 175, 233, 35, 73, 155, 3, 32, 204, 48, 206, 18, 158, 19, 175,
37, 60, 175, 228, 209, 30, 195, 143, 226, 197, 178, 103, 105, 76, 110, 160, 209, 156, 160,
209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 241,
250, 201, 99, 206, 251, 96, 95, 161, 242, 14, 193, 243, 40, 162, 105, 253, 219, 12, 75, 47,
146, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 136, 249, 87, 249, 105,
231, 220, 4, 249, 237, 132, 56, 20, 224, 109, 113, 223, 88, 82, 153, 34, 64, 34, 14, 164,
69, 172, 48, 2, 23, 243, 6, 31, 25, 5, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down
47 changes: 46 additions & 1 deletion acvm-repo/acvm/src/pwg/blackbox/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use acir::{
native_types::{Witness, WitnessMap},
BlackBoxFunc, FieldElement,
};
use acvm_blackbox_solver::BlackBoxResolutionError;
use acvm_blackbox_solver::{sha256compression, BlackBoxResolutionError};

use crate::pwg::{insert_value, witness_to_value};
use crate::OpcodeResolutionError;
Expand Down Expand Up @@ -86,3 +86,48 @@ fn write_digest_to_outputs(

Ok(())
}

pub(crate) fn solve_sha_256_permutation_opcode(
initial_witness: &mut WitnessMap,
inputs: &[FunctionInput],
hash_values: &[FunctionInput],
outputs: &[Witness],
black_box_func: BlackBoxFunc,
) -> Result<(), OpcodeResolutionError> {
let mut message = [0; 16];
if inputs.len() != 16 {
return Err(OpcodeResolutionError::BlackBoxFunctionFailed(
black_box_func,
format!("Expected 16 inputs but encountered {}", &message.len()),
));
}
for (i, input) in inputs.iter().enumerate() {
let value = witness_to_value(initial_witness, input.witness)?;
message[i] = value.to_u128() as u32;
}

if hash_values.len() != 8 {
return Err(OpcodeResolutionError::BlackBoxFunctionFailed(
black_box_func,
format!("Expected 8 values but encountered {}", hash_values.len()),
));
}
let mut state = [0; 8];
for (i, hash) in hash_values.iter().enumerate() {
let value = witness_to_value(initial_witness, hash.witness)?;
state[i] = value.to_u128() as u32;
}

sha256compression(&mut state, &message);
let outputs: [Witness; 8] = outputs.try_into().map_err(|_| {
OpcodeResolutionError::BlackBoxFunctionFailed(
black_box_func,
format!("Expected 8 outputs but encountered {}", outputs.len()),
)
})?;
for (output_witness, value) in outputs.iter().zip(state.into_iter()) {
insert_value(output_witness, FieldElement::from(value as u128), initial_witness)?;
}

Ok(())
}
12 changes: 10 additions & 2 deletions acvm-repo/acvm/src/pwg/blackbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mod signature;

use fixed_base_scalar_mul::{embedded_curve_add, fixed_base_scalar_mul};
// Hash functions should eventually be exposed for external consumers.
use hash::solve_generic_256_hash_opcode;
use hash::{solve_generic_256_hash_opcode, solve_sha_256_permutation_opcode};
use logic::{and, xor};
use pedersen::pedersen;
use range::solve_range_opcode;
Expand Down Expand Up @@ -205,6 +205,14 @@ pub(crate) fn solve(
bigint_solver.bigint_to_bytes(*input, outputs, initial_witness)
}
BlackBoxFuncCall::Poseidon2Permutation { .. } => todo!(),
BlackBoxFuncCall::Sha256Compression { .. } => todo!(),
BlackBoxFuncCall::Sha256Compression { inputs, hash_values, outputs } => {
solve_sha_256_permutation_opcode(
initial_witness,
inputs,
hash_values,
outputs,
bb_func.get_black_box_func(),
)
}
}
}
14 changes: 7 additions & 7 deletions acvm-repo/acvm_js/test/shared/complex_foreign_call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js';

// See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`.
export const bytecode = Uint8Array.from([
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 73, 14, 131, 48, 12, 28, 147, 166, 165, 167, 126, 161, 82, 251, 128, 180,
47, 224, 47, 85, 111, 32, 56, 242, 124, 130, 24, 68, 176, 2, 23, 130, 4, 35, 89, 206, 50, 137, 71, 182, 147, 28, 128,
96, 128, 241, 150, 113, 44, 156, 135, 24, 121, 5, 189, 219, 134, 143, 164, 187, 203, 237, 165, 49, 59, 129, 70, 179,
131, 198, 177, 31, 14, 90, 239, 148, 117, 73, 154, 63, 19, 121, 63, 23, 111, 214, 219, 149, 243, 27, 125, 206, 117,
208, 63, 85, 222, 161, 248, 32, 167, 72, 162, 245, 235, 44, 166, 94, 20, 21, 251, 30, 196, 253, 213, 85, 83, 254, 91,
163, 168, 90, 234, 43, 24, 191, 213, 190, 172, 156, 235, 17, 126, 59, 49, 142, 68, 120, 75, 220, 7, 166, 84, 90, 68,
72, 194, 139, 180, 136, 25, 58, 46, 103, 45, 188, 25, 5, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 125, 177, 163, 35, 179, 154, 35, 8, 51, 7, 232, 204,
9, 188, 139, 184, 83, 116, 233, 241, 173, 152, 98, 12, 213, 141, 21, 244, 65, 232, 39, 175, 233, 35, 73, 155, 3, 32,
204, 48, 206, 18, 158, 19, 175, 37, 60, 175, 228, 209, 30, 195, 143, 226, 197, 178, 103, 105, 76, 110, 160, 209, 156,
160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 241, 250, 201, 99, 206, 251,
96, 95, 161, 242, 14, 193, 243, 40, 162, 105, 253, 219, 12, 75, 47, 146, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96,
20, 85, 75, 253, 136, 249, 87, 249, 105, 231, 220, 4, 249, 237, 132, 56, 20, 224, 109, 113, 223, 88, 82, 153, 34, 64,
34, 14, 164, 69, 172, 48, 2, 23, 243, 6, 31, 25, 5, 0, 0,
]);
export const initialWitnessMap: WitnessMap = new Map([
[1, '0x0000000000000000000000000000000000000000000000000000000000000001'],
Expand Down
8 changes: 4 additions & 4 deletions acvm-repo/acvm_js/test/shared/foreign_call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js';

// See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`.
export const bytecode = Uint8Array.from([
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 215, 148, 150, 246, 212, 175, 216, 31, 244, 51,
61, 244, 226, 65, 196, 247, 171, 24, 33, 136, 122, 209, 129, 144, 176, 132, 101, 247, 4, 160, 144, 217, 196, 45, 41,
218, 203, 91, 207, 241, 168, 117, 94, 90, 230, 37, 238, 144, 216, 27, 249, 11, 87, 156, 131, 239, 223, 248, 207, 186,
81, 235, 150, 67, 173, 221, 189, 95, 18, 34, 97, 64, 0, 116, 135, 40, 214, 136, 1, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 16, 67, 227, 21, 74, 233, 212, 79, 177, 127, 208, 159,
233, 224, 226, 32, 226, 247, 139, 168, 16, 68, 93, 244, 45, 119, 228, 142, 144, 92, 0, 20, 50, 7, 237, 76, 213, 190,
50, 245, 26, 175, 218, 231, 165, 57, 175, 148, 14, 137, 179, 147, 191, 114, 211, 221, 216, 240, 59, 63, 107, 221, 115,
104, 181, 103, 244, 43, 36, 10, 38, 68, 108, 25, 253, 238, 136, 1, 0, 0,
]);
export const initialWitnessMap: WitnessMap = new Map([
[1, '0x0000000000000000000000000000000000000000000000000000000000000005'],
Expand Down
2 changes: 1 addition & 1 deletion acvm-repo/blackbox_solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ thiserror.workspace = true

blake2 = "0.10.6"
blake3 = "1.5.0"
sha2 = "0.10.6"
sha2 = { version="0.10.6", features = ["compress",] }
sha3 = "0.10.6"
keccak = "0.1.4"
k256 = { version = "0.11.0", features = [
Expand Down
10 changes: 10 additions & 0 deletions acvm-repo/blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ pub fn keccak256(inputs: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError> {
.map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Keccak256, err))
}

pub fn sha256compression(state: &mut [u32; 8], msg_blocks: &[u32; 16]) {
let mut blocks = [0_u8; 64];
for (i, block) in msg_blocks.iter().enumerate() {
let bytes = block.to_be_bytes();
blocks[i * 4..i * 4 + 4].copy_from_slice(&bytes);
}
let blocks: GenericArray<u8, sha2::digest::typenum::U64> = blocks.into();
sha2::compress256(state, &[blocks]);
}

const KECCAK_LANES: usize = 25;

pub fn keccakf1600(
Expand Down
5 changes: 5 additions & 0 deletions acvm-repo/brillig/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ pub enum BrilligOpcode {
lhs: MemoryAddress,
rhs: MemoryAddress,
},
Cast {
destination: MemoryAddress,
source: MemoryAddress,
bit_size: u32,
},
JumpIfNot {
condition: MemoryAddress,
location: Label,
Expand Down
33 changes: 31 additions & 2 deletions acvm-repo/brillig_vm/src/black_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use acir::brillig::{BlackBoxOp, HeapArray, HeapVector, Value};
use acir::{BlackBoxFunc, FieldElement};
use acvm_blackbox_solver::{
blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, keccakf1600,
sha256, BlackBoxFunctionSolver, BlackBoxResolutionError,
sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError,
};

use crate::Memory;
Expand Down Expand Up @@ -185,7 +185,36 @@ pub(crate) fn evaluate_black_box<Solver: BlackBoxFunctionSolver>(
BlackBoxOp::BigIntFromLeBytes { .. } => todo!(),
BlackBoxOp::BigIntToLeBytes { .. } => todo!(),
BlackBoxOp::Poseidon2Permutation { .. } => todo!(),
BlackBoxOp::Sha256Compression { .. } => todo!(),
BlackBoxOp::Sha256Compression { input, hash_values, output } => {
let mut message = [0; 16];
let inputs = read_heap_vector(memory, input);
if inputs.len() != 16 {
return Err(BlackBoxResolutionError::Failed(
BlackBoxFunc::Sha256Compression,
format!("Expected 16 inputs but encountered {}", &inputs.len()),
));
}
for (i, input) in inputs.iter().enumerate() {
message[i] = input.to_u128() as u32;
}
let mut state = [0; 8];
let values = read_heap_vector(memory, hash_values);
if values.len() != 8 {
return Err(BlackBoxResolutionError::Failed(
BlackBoxFunc::Sha256Compression,
format!("Expected 8 values but encountered {}", &values.len()),
));
}
for (i, value) in values.iter().enumerate() {
state[i] = value.to_u128() as u32;
}

sha256compression(&mut state, &message);
let state = state.map(|x| Value::from(x as u128));

memory.write_slice(memory.read_ref(output.pointer), &state);
Ok(())
}
}
}

Expand Down
47 changes: 47 additions & 0 deletions acvm-repo/brillig_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> {
self.increment_program_counter()
}
}
Opcode::Cast { destination: destination_address, source: source_address, bit_size } => {
let source_value = self.memory.read(*source_address);
let casted_value = self.cast(*bit_size, source_value);
self.memory.write(*destination_address, casted_value);
self.increment_program_counter()
}
Opcode::Jump { location: destination } => self.set_program_counter(*destination),
Opcode::JumpIf { condition, location: destination } => {
// Check if condition is true
Expand Down Expand Up @@ -511,6 +517,13 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> {
.write(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into());
Ok(())
}

/// Casts a value to a different bit size.
fn cast(&self, bit_size: u32, value: Value) -> Value {
let lhs_big = BigUint::from_bytes_be(&value.to_field().to_be_bytes());
let mask = BigUint::from(2_u32).pow(bit_size) - 1_u32;
FieldElement::from_be_bytes_reduce(&(lhs_big & mask).to_bytes_be()).into()
}
}

pub(crate) struct DummyBlackBoxSolver;
Expand Down Expand Up @@ -708,6 +721,40 @@ mod tests {
assert_eq!(output_value, Value::from(false));
}

#[test]
fn cast_opcode() {
let calldata = vec![Value::from((2_u128.pow(32)) - 1)];

let opcodes = &[
Opcode::CalldataCopy {
destination_address: MemoryAddress::from(0),
size: 1,
offset: 0,
},
Opcode::Cast {
destination: MemoryAddress::from(1),
source: MemoryAddress::from(0),
bit_size: 8,
},
Opcode::Stop { return_data_offset: 1, return_data_size: 1 },
];
let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver);

let status = vm.process_opcode();
assert_eq!(status, VMStatus::InProgress);

let status = vm.process_opcode();
assert_eq!(status, VMStatus::InProgress);

let status = vm.process_opcode();
assert_eq!(status, VMStatus::Finished { return_data_offset: 1, return_data_size: 1 });

let VM { memory, .. } = vm;

let casted_value = memory.read(MemoryAddress::from(1));
assert_eq!(casted_value, Value::from(2_u128.pow(8) - 1));
}

#[test]
fn mov_opcode() {
let calldata = vec![Value::from(1u128), Value::from(2u128), Value::from(3u128)];
Expand Down
Loading

0 comments on commit cf7b00e

Please sign in to comment.