Skip to content

Commit

Permalink
feat!: add blake3 opcode to brillig (AztecProtocol#3913)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench authored Jan 11, 2024
1 parent 0fca2c4 commit 34fad0a
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 9 deletions.
61 changes: 61 additions & 0 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,15 @@ struct BlackBoxOp {
static Blake2s bincodeDeserialize(std::vector<uint8_t>);
};

struct Blake3 {
Circuit::HeapVector message;
Circuit::HeapArray output;

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

struct Keccak256 {
Circuit::HeapVector message;
Circuit::HeapArray output;
Expand Down Expand Up @@ -547,6 +556,7 @@ struct BlackBoxOp {

std::variant<Sha256,
Blake2s,
Blake3,
Keccak256,
EcdsaSecp256k1,
EcdsaSecp256r1,
Expand Down Expand Up @@ -3035,6 +3045,57 @@ Circuit::BlackBoxOp::Blake2s serde::Deserializable<Circuit::BlackBoxOp::Blake2s>

namespace Circuit {

inline bool operator==(const BlackBoxOp::Blake3& lhs, const BlackBoxOp::Blake3& rhs)
{
if (!(lhs.message == rhs.message)) {
return false;
}
if (!(lhs.output == rhs.output)) {
return false;
}
return true;
}

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

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

} // end of namespace Circuit

template <>
template <typename Serializer>
void serde::Serializable<Circuit::BlackBoxOp::Blake3>::serialize(const Circuit::BlackBoxOp::Blake3& obj,
Serializer& serializer)
{
serde::Serializable<decltype(obj.message)>::serialize(obj.message, serializer);
serde::Serializable<decltype(obj.output)>::serialize(obj.output, serializer);
}

template <>
template <typename Deserializer>
Circuit::BlackBoxOp::Blake3 serde::Deserializable<Circuit::BlackBoxOp::Blake3>::deserialize(Deserializer& deserializer)
{
Circuit::BlackBoxOp::Blake3 obj;
obj.message = serde::Deserializable<decltype(obj.message)>::deserialize(deserializer);
obj.output = serde::Deserializable<decltype(obj.output)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const BlackBoxOp::Keccak256& lhs, const BlackBoxOp::Keccak256& rhs)
{
if (!(lhs.message == rhs.message)) {
Expand Down
52 changes: 51 additions & 1 deletion noir/acvm-repo/acir/codegen/acir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,15 @@ namespace Circuit {
static Blake2s bincodeDeserialize(std::vector<uint8_t>);
};

struct Blake3 {
Circuit::HeapVector message;
Circuit::HeapArray output;

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

struct Keccak256 {
Circuit::HeapVector message;
Circuit::HeapArray output;
Expand Down Expand Up @@ -525,7 +534,7 @@ namespace Circuit {
static EmbeddedCurveDouble bincodeDeserialize(std::vector<uint8_t>);
};

std::variant<Sha256, Blake2s, Keccak256, EcdsaSecp256k1, EcdsaSecp256r1, SchnorrVerify, PedersenCommitment, PedersenHash, FixedBaseScalarMul, EmbeddedCurveAdd, EmbeddedCurveDouble> value;
std::variant<Sha256, Blake2s, Blake3, Keccak256, EcdsaSecp256k1, EcdsaSecp256r1, SchnorrVerify, PedersenCommitment, PedersenHash, FixedBaseScalarMul, EmbeddedCurveAdd, EmbeddedCurveDouble> value;

friend bool operator==(const BlackBoxOp&, const BlackBoxOp&);
std::vector<uint8_t> bincodeSerialize() const;
Expand Down Expand Up @@ -2595,6 +2604,47 @@ Circuit::BlackBoxOp::Blake2s serde::Deserializable<Circuit::BlackBoxOp::Blake2s>
return obj;
}

namespace Circuit {

inline bool operator==(const BlackBoxOp::Blake3 &lhs, const BlackBoxOp::Blake3 &rhs) {
if (!(lhs.message == rhs.message)) { return false; }
if (!(lhs.output == rhs.output)) { return false; }
return true;
}

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

inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector<uint8_t> input) {
auto deserializer = serde::BincodeDeserializer(input);
auto value = serde::Deserializable<BlackBoxOp::Blake3>::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::BlackBoxOp::Blake3>::serialize(const Circuit::BlackBoxOp::Blake3 &obj, Serializer &serializer) {
serde::Serializable<decltype(obj.message)>::serialize(obj.message, serializer);
serde::Serializable<decltype(obj.output)>::serialize(obj.output, serializer);
}

template <>
template <typename Deserializer>
Circuit::BlackBoxOp::Blake3 serde::Deserializable<Circuit::BlackBoxOp::Blake3>::deserialize(Deserializer &deserializer) {
Circuit::BlackBoxOp::Blake3 obj;
obj.message = serde::Deserializable<decltype(obj.message)>::deserialize(deserializer);
obj.output = serde::Deserializable<decltype(obj.output)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const BlackBoxOp::Keccak256 &lhs, const BlackBoxOp::Keccak256 &rhs) {
Expand Down
10 changes: 9 additions & 1 deletion noir/acvm-repo/brillig/src/black_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub enum BlackBoxOp {
Sha256 { message: HeapVector, output: HeapArray },
/// Calculates the Blake2s hash of the inputs.
Blake2s { message: HeapVector, output: HeapArray },
/// Calculates the Blake3 hash of the inputs.
Blake3 { message: HeapVector, output: HeapArray },
/// Calculates the Keccak256 hash of the inputs.
Keccak256 { message: HeapVector, output: HeapArray },
/// Verifies a ECDSA signature over the secp256k1 curve.
Expand Down Expand Up @@ -42,7 +44,13 @@ pub enum BlackBoxOp {
/// Performs scalar multiplication over the embedded curve.
FixedBaseScalarMul { low: RegisterIndex, high: RegisterIndex, result: HeapArray },
/// Performs addtion over the embedded curve.
EmbeddedCurveAdd { input1_x: RegisterIndex, input1_y: RegisterIndex, input2_x: RegisterIndex, input2_y: RegisterIndex, result: HeapArray },
EmbeddedCurveAdd {
input1_x: RegisterIndex,
input1_y: RegisterIndex,
input2_x: RegisterIndex,
input2_y: RegisterIndex,
result: HeapArray,
},
/// Performs point doubling over the embedded curve.
EmbeddedCurveDouble { input1_x: RegisterIndex, input1_y: RegisterIndex, result: HeapArray },
}
9 changes: 8 additions & 1 deletion noir/acvm-repo/brillig_vm/src/black_box.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use acir::brillig::{BlackBoxOp, HeapArray, HeapVector, Value};
use acir::{BlackBoxFunc, FieldElement};
use acvm_blackbox_solver::{
blake2s, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, sha256,
blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, sha256,
BlackBoxFunctionSolver, BlackBoxResolutionError,
};

Expand Down Expand Up @@ -58,6 +58,12 @@ pub(crate) fn evaluate_black_box<Solver: BlackBoxFunctionSolver>(
memory.write_slice(registers.get(output.pointer).to_usize(), &to_value_vec(&bytes));
Ok(())
}
BlackBoxOp::Blake3 { message, output } => {
let message = to_u8_vec(read_heap_vector(memory, registers, message));
let bytes = blake3(message.as_slice())?;
memory.write_slice(registers.get(output.pointer).to_usize(), &to_value_vec(&bytes));
Ok(())
}
BlackBoxOp::Keccak256 { message, output } => {
let message = to_u8_vec(read_heap_vector(memory, registers, message));
let bytes = keccak256(message.as_slice())?;
Expand Down Expand Up @@ -187,6 +193,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc {
match op {
BlackBoxOp::Sha256 { .. } => BlackBoxFunc::SHA256,
BlackBoxOp::Blake2s { .. } => BlackBoxFunc::Blake2s,
BlackBoxOp::Blake3 { .. } => BlackBoxFunc::Blake3,
BlackBoxOp::Keccak256 { .. } => BlackBoxFunc::Keccak256,
BlackBoxOp::EcdsaSecp256k1 { .. } => BlackBoxFunc::EcdsaSecp256k1,
BlackBoxOp::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ pub(crate) fn convert_black_box_call(
unreachable!("ICE: Blake2s expects one array argument and one array result")
}
}
BlackBoxFunc::Blake3 => {
if let ([message], [BrilligVariable::BrilligArray(result_array)]) =
(function_arguments, function_results)
{
let message_vector = convert_array_or_vector(brillig_context, message, bb_func);
brillig_context.black_box_op_instruction(BlackBoxOp::Blake3 {
message: message_vector.to_heap_vector(),
output: result_array.to_heap_array(),
});
} else {
unreachable!("ICE: Blake3 expects one array argument and one array result")
}
}
BlackBoxFunc::Keccak256 => {
if let (
[message, BrilligVariable::Simple(array_size)],
Expand Down Expand Up @@ -171,8 +184,7 @@ pub(crate) fn convert_black_box_call(
}
BlackBoxFunc::EmbeddedCurveAdd => {
if let (
[BrilligVariable::Simple(input1_x), BrilligVariable::Simple(input1_y),
BrilligVariable::Simple(input2_x), BrilligVariable::Simple(input2_y)],
[BrilligVariable::Simple(input1_x), BrilligVariable::Simple(input1_y), BrilligVariable::Simple(input2_x), BrilligVariable::Simple(input2_y)],
[BrilligVariable::BrilligArray(result_array)],
) = (function_arguments, function_results)
{
Expand All @@ -188,7 +200,7 @@ pub(crate) fn convert_black_box_call(
"ICE: EmbeddedCurveAdd expects four register arguments and one array result"
)
}
}
}
BlackBoxFunc::EmbeddedCurveDouble => {
if let (
[BrilligVariable::Simple(input1_x), BrilligVariable::Simple(input1_y)],
Expand Down Expand Up @@ -218,9 +230,6 @@ pub(crate) fn convert_black_box_call(
BlackBoxFunc::RecursiveAggregation => unimplemented!(
"ICE: `BlackBoxFunc::RecursiveAggregation` is not implemented by the Brillig VM"
),
BlackBoxFunc::Blake3 => {
unimplemented!("ICE: `BlackBoxFunc::Blake3` is not implemented by the Brillig VM")
}
BlackBoxFunc::Keccakf1600 => {
unimplemented!("ICE: `BlackBoxFunc::Keccakf1600` is not implemented by the Brillig VM")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ impl DebugShow {
BlackBoxOp::Blake2s { message, output } => {
debug_println!(self.enable_debug_trace, " BLAKE2S {} -> {}", message, output);
}
BlackBoxOp::Blake3 { message, output } => {
debug_println!(self.enable_debug_trace, " BLAKE3 {} -> {}", message, output);
}
BlackBoxOp::EcdsaSecp256k1 {
hashed_msg,
public_key_x,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "brillig_blake3"
type = "bin"
authors = [""]
compiler_version = ">=0.22.0"

[dependencies]
37 changes: 37 additions & 0 deletions noir/test_programs/execution_success/brillig_blake3/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# hello as bytes
# https://connor4312.github.io/blake3/index.html
x = [104, 101, 108, 108, 111]
result = [
0xea,
0x8f,
0x16,
0x3d,
0xb3,
0x86,
0x82,
0x92,
0x5e,
0x44,
0x91,
0xc5,
0xe5,
0x8d,
0x4b,
0xb3,
0x50,
0x6e,
0xf8,
0xc1,
0x4e,
0xb7,
0x8a,
0x86,
0xe9,
0x08,
0xc5,
0x62,
0x4a,
0x67,
0x20,
0x0f,
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use dep::std;

unconstrained fn main(x: [u8; 5], result: [u8; 32]) {
let digest = std::hash::blake3(x);
assert(digest == result);
}

0 comments on commit 34fad0a

Please sign in to comment.