Skip to content

Commit

Permalink
feat!: add blake3 blackbox function to acir format (#3856)
Browse files Browse the repository at this point in the history
Resolves noir-lang/noir#3171

We've started adding breaking changes to the serialisation so I thought
I'd chuck this in.

# Checklist:
Remove the checklist to signal you've completed it. Enable auto-merge if
the PR is ready to merge.
- [ ] If the pull request requires a cryptography review (e.g.
cryptographic algorithm implementations) I have added the 'crypto' tag.
- [x] I have reviewed my diff in github, line by line and removed
unexpected formatting changes, testing logs, or commented-out code.
- [x] Every change is related to the PR description.
- [x] I have
[linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
this pull request to relevant issues (if any exist).
  • Loading branch information
TomAFrench authored Jan 5, 2024
1 parent c98b807 commit 8c96d4c
Show file tree
Hide file tree
Showing 27 changed files with 338 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ void build_constraints(Builder& builder, acir_format const& constraint_system, b
create_blake2s_constraints(builder, constraint);
}

// Add blake3 constraints
for (const auto& constraint : constraint_system.blake3_constraints) {
create_blake3_constraints(builder, constraint);
}

// Add keccak constraints
for (const auto& constraint : constraint_system.keccak_constraints) {
create_keccak_constraints(builder, constraint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "barretenberg/dsl/types.hpp"
#include "barretenberg/serialize/msgpack.hpp"
#include "blake2s_constraint.hpp"
#include "blake3_constraint.hpp"
#include "block_constraint.hpp"
#include "ecdsa_secp256k1.hpp"
#include "ecdsa_secp256r1.hpp"
Expand Down Expand Up @@ -30,6 +31,7 @@ struct acir_format {
std::vector<EcdsaSecp256k1Constraint> ecdsa_k1_constraints;
std::vector<EcdsaSecp256r1Constraint> ecdsa_r1_constraints;
std::vector<Blake2sConstraint> blake2s_constraints;
std::vector<Blake3Constraint> blake3_constraints;
std::vector<KeccakConstraint> keccak_constraints;
std::vector<KeccakVarConstraint> keccak_var_constraints;
std::vector<Keccakf1600> keccak_permutations;
Expand All @@ -56,6 +58,7 @@ struct acir_format {
ecdsa_k1_constraints,
ecdsa_r1_constraints,
blake2s_constraints,
blake3_constraints,
keccak_constraints,
keccak_var_constraints,
keccak_permutations,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -144,6 +145,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -209,6 +211,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -297,6 +300,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -404,6 +408,7 @@ TEST_F(AcirFormatTests, TestVarKeccak)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = { keccak },
.keccak_permutations = {},
Expand Down Expand Up @@ -442,6 +447,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = { keccak_permutation },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "barretenberg/common/container.hpp"
#include "barretenberg/common/throw_or_abort.hpp"
#include "barretenberg/dsl/acir_format/blake2s_constraint.hpp"
#include "barretenberg/dsl/acir_format/blake3_constraint.hpp"
#include "barretenberg/dsl/acir_format/block_constraint.hpp"
#include "barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp"
#include "barretenberg/dsl/acir_format/keccak_constraint.hpp"
Expand Down Expand Up @@ -113,6 +114,17 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, aci
}),
.result = map(arg.outputs, [](auto& e) { return e.value; }),
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::Blake3>) {
af.blake3_constraints.push_back(Blake3Constraint{
.inputs = map(arg.inputs,
[](auto& e) {
return Blake3Input{
.witness = e.witness.value,
.num_bits = e.num_bits,
};
}),
.result = map(arg.outputs, [](auto& e) { return e.value; }),
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::SchnorrVerify>) {
af.schnorr_constraints.push_back(SchnorrConstraint{
.message = map(arg.message, [](auto& e) { return e.witness.value; }),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "blake3_constraint.hpp"
#include "round.hpp"

namespace acir_format {

template <typename Builder> void create_blake3_constraints(Builder& builder, const Blake3Constraint& constraint)
{
using byte_array_ct = proof_system::plonk::stdlib::byte_array<Builder>;
using field_ct = proof_system::plonk::stdlib::field_t<Builder>;

// Create byte array struct
byte_array_ct arr(&builder);

// Get the witness assignment for each witness index
// Write the witness assignment to the byte_array
for (const auto& witness_index_num_bits : constraint.inputs) {
auto witness_index = witness_index_num_bits.witness;
auto num_bits = witness_index_num_bits.num_bits;

// XXX: The implementation requires us to truncate the element to the nearest byte and not bit
auto num_bytes = round_to_nearest_byte(num_bits);

field_ct element = field_ct::from_witness_index(&builder, witness_index);
byte_array_ct element_bytes(element, num_bytes);

arr.write(element_bytes);
}

byte_array_ct output_bytes = proof_system::plonk::stdlib::blake3s<Builder>(arr);

// Convert byte array to vector of field_t
auto bytes = output_bytes.bytes();

for (size_t i = 0; i < bytes.size(); ++i) {
builder.assert_equal(bytes[i].normalize().witness_index, constraint.result[i]);
}
}

template void create_blake3_constraints<UltraCircuitBuilder>(UltraCircuitBuilder& builder,
const Blake3Constraint& constraint);
template void create_blake3_constraints<GoblinUltraCircuitBuilder>(GoblinUltraCircuitBuilder& builder,
const Blake3Constraint& constraint);

} // namespace acir_format
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
#include "barretenberg/dsl/types.hpp"
#include "barretenberg/serialize/msgpack.hpp"
#include <cstdint>
#include <vector>

namespace acir_format {

struct Blake3Input {
uint32_t witness;
uint32_t num_bits;

// For serialization, update with any new fields
MSGPACK_FIELDS(witness, num_bits);
friend bool operator==(Blake3Input const& lhs, Blake3Input const& rhs) = default;
};

struct Blake3Constraint {
std::vector<Blake3Input> inputs;
std::vector<uint32_t> result;

// For serialization, update with any new fields
MSGPACK_FIELDS(inputs, result);
friend bool operator==(Blake3Constraint const& lhs, Blake3Constraint const& rhs) = default;
};

template <typename Builder> void create_blake3_constraints(Builder& builder, const Blake3Constraint& constraint);

} // namespace acir_format
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed)
.ecdsa_k1_constraints = { ecdsa_k1_constraint },
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -138,6 +139,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier)
.ecdsa_k1_constraints = { ecdsa_k1_constraint },
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -174,6 +176,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail)
.ecdsa_k1_constraints = { ecdsa_k1_constraint },
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ TEST(ECDSASecp256r1, test_hardcoded)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = { ecdsa_r1_constraint },
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -173,6 +174,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = { ecdsa_r1_constraint },
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -213,6 +215,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = { ecdsa_r1_constraint },
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -248,6 +251,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = { ecdsa_r1_constraint },
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Builder create_inner_circuit()
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down Expand Up @@ -248,6 +249,7 @@ Builder create_outer_circuit(std::vector<Builder>& inner_circuits)
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
Expand Down
62 changes: 62 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 @@ -70,6 +70,15 @@ struct BlackBoxFuncCall {
static Blake2s bincodeDeserialize(std::vector<uint8_t>);
};

struct Blake3 {
std::vector<Circuit::FunctionInput> inputs;
std::vector<Circuit::Witness> outputs;

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

struct SchnorrVerify {
Circuit::FunctionInput public_key_x;
Circuit::FunctionInput public_key_y;
Expand Down Expand Up @@ -182,6 +191,7 @@ struct BlackBoxFuncCall {
RANGE,
SHA256,
Blake2s,
Blake3,
SchnorrVerify,
PedersenCommitment,
PedersenHash,
Expand Down Expand Up @@ -2045,6 +2055,58 @@ Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable<Circuit::BlackBoxFuncCa

namespace Circuit {

inline bool operator==(const BlackBoxFuncCall::Blake3& lhs, const BlackBoxFuncCall::Blake3& rhs)
{
if (!(lhs.inputs == rhs.inputs)) {
return false;
}
if (!(lhs.outputs == rhs.outputs)) {
return false;
}
return true;
}

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

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

template <>
template <typename Deserializer>
Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable<Circuit::BlackBoxFuncCall::Blake3>::deserialize(
Deserializer& deserializer)
{
Circuit::BlackBoxFuncCall::Blake3 obj;
obj.inputs = serde::Deserializable<decltype(obj.inputs)>::deserialize(deserializer);
obj.outputs = serde::Deserializable<decltype(obj.outputs)>::deserialize(deserializer);
return obj;
}

namespace Circuit {

inline bool operator==(const BlackBoxFuncCall::SchnorrVerify& lhs, const BlackBoxFuncCall::SchnorrVerify& rhs)
{
if (!(lhs.public_key_x == rhs.public_key_x)) {
Expand Down
Loading

0 comments on commit 8c96d4c

Please sign in to comment.