Skip to content

Commit 942f705

Browse files
authored
feat: FunctionSelector type (#1518)
Fixes #1424
1 parent 79df831 commit 942f705

File tree

70 files changed

+621
-389
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+621
-389
lines changed

circuits/cpp/src/aztec3/circuits/abis/.test.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ TEST(abi_tests, native_read_write_call_context)
5151
TEST(abi_tests, native_read_write_function_data)
5252
{
5353
FunctionData<NT> const function_data = {
54-
.function_selector = 11,
54+
.function_selector =
55+
FunctionSelector<NT>{
56+
.value = 11,
57+
},
5558
.is_private = false,
5659
.is_constructor = false,
5760
};
@@ -67,7 +70,10 @@ TEST(abi_tests, native_read_write_function_data)
6770
TEST(abi_tests, native_to_circuit_function_data)
6871
{
6972
FunctionData<NT> const native_function_data = {
70-
.function_selector = 11,
73+
.function_selector =
74+
FunctionSelector<NT>{
75+
.value = 11,
76+
},
7177
.is_private = false,
7278
.is_constructor = false,
7379
};

circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ TEST(abi_tests, compute_function_leaf)
191191
{
192192
// Construct FunctionLeafPreimage with some randomized fields
193193
auto const preimage = FunctionLeafPreimage<NT>{
194-
.function_selector = engine.get_random_uint32(),
194+
.function_selector =
195+
FunctionSelector<NT>{
196+
.value = engine.get_random_uint32(),
197+
},
195198
.is_private = static_cast<bool>(engine.get_random_uint8() & 1),
196199
.vk_hash = NT::fr::random_element(),
197200
.acir_hash = NT::fr::random_element(),
@@ -279,7 +282,12 @@ TEST(abi_tests, compute_function_tree)
279282
TEST(abi_tests, hash_constructor)
280283
{
281284
// Randomize required values
282-
auto const func_data = FunctionData<NT>{ .function_selector = 10, .is_private = true, .is_constructor = false };
285+
auto const func_data = FunctionData<NT>{ .function_selector =
286+
FunctionSelector<NT>{
287+
.value = 10,
288+
},
289+
.is_private = true,
290+
.is_constructor = false };
283291

284292
NT::fr const args_hash = NT::fr::random_element();
285293
NT::fr const constructor_vk_hash = NT::fr::random_element();

circuits/cpp/src/aztec3/circuits/abis/function_data.hpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include "aztec3/circuits/abis/function_selector.hpp"
34
#include "aztec3/constants.hpp"
45
#include "aztec3/utils/types/circuit_types.hpp"
56
#include "aztec3/utils/types/convert.hpp"
@@ -17,7 +18,7 @@ template <typename NCT> struct FunctionData {
1718
using boolean = typename NCT::boolean;
1819
using fr = typename NCT::fr;
1920

20-
uint32 function_selector; // e.g. 1st 4-bytes of abi-encoding of function.
21+
FunctionSelector<NCT> function_selector;
2122
boolean is_internal = false;
2223
boolean is_private = false;
2324
boolean is_constructor = false;
@@ -38,7 +39,7 @@ template <typename NCT> struct FunctionData {
3839
auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); };
3940

4041
FunctionData<CircuitTypes<Builder>> function_data = {
41-
to_ct(function_selector),
42+
function_selector.to_circuit_type(builder),
4243
to_ct(is_internal),
4344
to_ct(is_private),
4445
to_ct(is_constructor),
@@ -50,10 +51,11 @@ template <typename NCT> struct FunctionData {
5051
template <typename Builder> FunctionData<NativeTypes> to_native_type() const
5152
{
5253
static_assert(std::is_same<CircuitTypes<Builder>, NCT>::value);
54+
auto to_native_type = []<typename T>(T& e) { return e.template to_native_type<Builder>(); };
5355
auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt<Builder>(e); };
5456

5557
FunctionData<NativeTypes> function_data = {
56-
to_nt(function_selector),
58+
to_native_type(function_selector),
5759
to_nt(is_internal),
5860
to_nt(is_private),
5961
to_nt(is_constructor),
@@ -66,7 +68,7 @@ template <typename NCT> struct FunctionData {
6668
{
6769
static_assert(!(std::is_same<NativeTypes, NCT>::value));
6870

69-
fr(function_selector).set_public();
71+
function_selector.set_public();
7072
fr(is_internal).set_public();
7173
fr(is_private).set_public();
7274
fr(is_constructor).set_public();
@@ -76,7 +78,7 @@ template <typename NCT> struct FunctionData {
7678
fr hash() const
7779
{
7880
std::vector<fr> const inputs = {
79-
fr(function_selector),
81+
fr(function_selector.value),
8082
fr(is_internal),
8183
fr(is_private),
8284
fr(is_constructor),

circuits/cpp/src/aztec3/circuits/abis/function_leaf_preimage.hpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include "aztec3/circuits/abis/function_selector.hpp"
34
#include "aztec3/constants.hpp"
45
#include "aztec3/utils/types/circuit_types.hpp"
56
#include "aztec3/utils/types/convert.hpp"
@@ -31,7 +32,7 @@ template <typename NCT> struct FunctionLeafPreimage {
3132
using fr = typename NCT::fr;
3233
using uint32 = typename NCT::uint32;
3334

34-
uint32 function_selector = 0;
35+
FunctionSelector<NCT> function_selector = {};
3536
boolean is_internal = false;
3637
boolean is_private = false;
3738
fr vk_hash = 0;
@@ -54,7 +55,11 @@ template <typename NCT> struct FunctionLeafPreimage {
5455
auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); };
5556

5657
FunctionLeafPreimage<CircuitTypes<Builder>> preimage = {
57-
to_ct(function_selector), to_ct(is_internal), to_ct(is_private), to_ct(vk_hash), to_ct(acir_hash),
58+
function_selector.to_circuit_type(builder),
59+
to_ct(is_internal),
60+
to_ct(is_private),
61+
to_ct(vk_hash),
62+
to_ct(acir_hash),
5863
};
5964

6065
return preimage;
@@ -63,10 +68,11 @@ template <typename NCT> struct FunctionLeafPreimage {
6368
template <typename Builder> FunctionLeafPreimage<NativeTypes> to_native_type() const
6469
{
6570
static_assert(std::is_same<CircuitTypes<Builder>, NCT>::value);
71+
auto to_native_type = []<typename T>(T& e) { return e.template to_native_type<Builder>(); };
6672
auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt<Builder>(e); };
6773

6874
FunctionLeafPreimage<NativeTypes> preimage = {
69-
to_nt(function_selector), to_nt(is_internal), to_nt(is_private), to_nt(vk_hash), to_nt(acir_hash),
75+
to_native_type(function_selector), to_nt(is_internal), to_nt(is_private), to_nt(vk_hash), to_nt(acir_hash),
7076
};
7177

7278
return preimage;
@@ -86,7 +92,7 @@ template <typename NCT> struct FunctionLeafPreimage {
8692
fr hash() const
8793
{
8894
std::vector<fr> const inputs = {
89-
function_selector, fr(is_internal), fr(is_private), vk_hash, acir_hash,
95+
function_selector.value, fr(is_internal), fr(is_private), vk_hash, acir_hash,
9096
};
9197
return NCT::compress(inputs, GeneratorIndex::FUNCTION_LEAF);
9298
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
#include "aztec3/utils/types/circuit_types.hpp"
4+
#include "aztec3/utils/types/convert.hpp"
5+
#include "aztec3/utils/types/native_types.hpp"
6+
7+
#include "barretenberg/serialize/msgpack.hpp"
8+
9+
namespace aztec3::circuits::abis {
10+
11+
using aztec3::utils::types::CircuitTypes;
12+
using aztec3::utils::types::NativeTypes;
13+
14+
template <typename NCT> struct FunctionSelector {
15+
using uint32 = typename NCT::uint32;
16+
using boolean = typename NCT::boolean;
17+
using fr = typename NCT::fr;
18+
19+
uint32 value; // e.g. 1st 4-bytes of abi-encoding of function.
20+
21+
MSGPACK_FIELDS(value);
22+
23+
boolean operator==(FunctionSelector<NCT> const& other) const { return value == other.value; };
24+
25+
template <typename Builder> FunctionSelector<CircuitTypes<Builder>> to_circuit_type(Builder& builder) const
26+
{
27+
static_assert((std::is_same<NativeTypes, NCT>::value));
28+
29+
// Capture the circuit builder:
30+
auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); };
31+
32+
FunctionSelector<CircuitTypes<Builder>> function_selector = {
33+
to_ct(value),
34+
};
35+
36+
return function_selector;
37+
};
38+
39+
template <typename Builder> FunctionSelector<NativeTypes> to_native_type() const
40+
{
41+
static_assert(std::is_same<CircuitTypes<Builder>, NCT>::value);
42+
auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt<Builder>(e); };
43+
44+
FunctionSelector<NativeTypes> function_selector = {
45+
to_nt(value),
46+
};
47+
48+
return function_selector;
49+
};
50+
51+
void set_public()
52+
{
53+
static_assert(!(std::is_same<NativeTypes, NCT>::value));
54+
55+
fr(value).set_public();
56+
}
57+
};
58+
59+
} // namespace aztec3::circuits::abis

circuits/cpp/src/aztec3/circuits/apps/.test.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ class state_var_tests : public ::testing::Test {
7575
uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL));
7676

7777
FunctionData<NT> const function_data{
78-
.function_selector = 1, // TODO: deduce this from the contract, somehow.
78+
.function_selector =
79+
FunctionSelector<NT>{
80+
.value = 1, // TODO: deduce this from the contract, somehow.
81+
},
7982
.is_private = true,
8083
.is_constructor = false,
8184
};

circuits/cpp/src/aztec3/circuits/apps/contract.tpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace aztec3::circuits::apps {
1313

1414
using NT = aztec3::utils::types::NativeTypes;
1515
using aztec3::circuits::abis::FunctionData;
16+
using aztec3::circuits::abis::FunctionSelector;
1617

1718
template <typename NCT> void Contract<NCT>::set_functions(std::vector<FunctionDeclaration<NCT>> const& functions)
1819
{
@@ -22,7 +23,10 @@ template <typename NCT> void Contract<NCT>::set_functions(std::vector<FunctionDe
2223
throw_or_abort("Name already exists");
2324
}
2425
function_datas[function.name] = FunctionData<NCT>{
25-
.function_selector = static_cast<uint32>(i),
26+
.function_selector =
27+
FunctionSelector<NT>{
28+
.value = static_cast<uint32>(i),
29+
},
2630
.is_private = function.is_private,
2731
.is_constructor = function.is_constructor,
2832
};

circuits/cpp/src/aztec3/circuits/apps/function_execution_context.hpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,10 @@ template <typename Builder> class FunctionExecutionContext {
178178

179179
const FunctionData<CT> f_function_data_ct{
180180
// Note: we MUST
181-
.function_selector = f_encoding_ct,
181+
.function_selector =
182+
FunctionSelector<CT>{
183+
.value = f_encoding_ct,
184+
},
182185
.is_private = true,
183186
.is_constructor = false,
184187
};

circuits/cpp/src/aztec3/circuits/apps/test_apps/escrow/.test.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ class escrow_tests : public ::testing::Test {
1616
uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL));
1717

1818
FunctionData<NT> const function_data{
19-
.function_selector = 1, // TODO: deduce this from the contract, somehow.
19+
.function_selector =
20+
FunctionSelector<NT>{
21+
.value = 1, // TODO: deduce this from the contract, somehow.
22+
},
2023
.is_private = true,
2124
.is_constructor = false,
2225
};

circuits/cpp/src/aztec3/circuits/apps/test_apps/private_to_private_function_call/.test.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ TEST(private_to_private_function_call_tests, circuit_private_to_private_function
2222
uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL);
2323

2424
const FunctionData<NT> function_data{
25-
.function_selector = 1, // TODO: deduce this from the contract, somehow.
25+
.function_selector =
26+
FunctionSelector<NT>{
27+
.value = 1, // TODO: deduce this from the contract, somehow.
28+
},
2629
.is_private = true,
2730
.is_constructor = false,
2831
};

circuits/cpp/src/aztec3/circuits/hash.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "aztec3/circuits/abis/function_data.hpp"
44
#include "aztec3/circuits/abis/function_leaf_preimage.hpp"
5+
#include "aztec3/circuits/abis/function_selector.hpp"
56
#include "aztec3/circuits/abis/global_variables.hpp"
67
#include "aztec3/circuits/abis/new_contract_data.hpp"
78
#include "aztec3/circuits/abis/point.hpp"
@@ -16,6 +17,7 @@
1617
namespace aztec3::circuits {
1718

1819
using abis::FunctionData;
20+
using abis::FunctionSelector;
1921
using abis::Point;
2022
using aztec3::circuits::abis::ContractLeafPreimage;
2123
using aztec3::circuits::abis::FunctionLeafPreimage;
@@ -303,7 +305,7 @@ void check_membership(Builder& builder,
303305
* @return NCT::fr
304306
*/
305307
template <typename NCT> typename NCT::fr function_tree_root_from_siblings(
306-
typename NCT::uint32 const& function_selector,
308+
FunctionSelector<NCT> const& function_selector,
307309
typename NCT::boolean const& is_internal,
308310
typename NCT::boolean const& is_private,
309311
typename NCT::fr const& vk_hash,

circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ TEST_F(native_private_kernel_init_tests, contract_deployment_function_data_misma
193193
auto private_inputs = do_private_call_get_kernel_inputs_init(true, constructor, standard_test_args());
194194

195195
// Modify the function selector in function data.
196-
private_inputs.tx_request.function_data.function_selector = numeric::random::get_engine().get_random_uint32();
196+
private_inputs.tx_request.function_data.function_selector = FunctionSelector<NT>{
197+
.value = numeric::random::get_engine().get_random_uint32(),
198+
};
197199

198200
// Invoke the native private kernel circuit
199201
DummyBuilder builder = DummyBuilder("private_kernel_tests__contract_deployment_function_data_mismatch_fails");

circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,10 @@ std::pair<PrivateCallData<NT>, ContractDeploymentData<NT>> create_private_call_d
156156
const Point<NT> msg_sender_pub_key = { .x = 123456789, .y = 123456789 };
157157

158158
FunctionData<NT> const function_data{
159-
.function_selector = 1, // TODO(suyash): deduce this from the contract, somehow.
159+
.function_selector =
160+
FunctionSelector<NT>{
161+
.value = 1, // TODO: deduce this from the contract, somehow.
162+
},
160163
.is_private = true,
161164
.is_constructor = is_constructor,
162165
};

circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ PublicCallStackItem generate_call_stack_item(NT::fr contract_address,
107107
{
108108
NT::uint32 count = seed + 1;
109109
FunctionData<NT> const function_data{
110-
.function_selector = count,
110+
.function_selector =
111+
FunctionSelector<NT>{
112+
.value = count,
113+
},
111114
.is_private = false,
112115
.is_constructor = false,
113116
};
@@ -264,7 +267,10 @@ PublicKernelInputs<NT> get_kernel_inputs_with_previous_kernel(NT::boolean privat
264267
const NT::address msg_sender = NT::fr(1);
265268

266269
FunctionData<NT> const function_data{
267-
.function_selector = 1,
270+
.function_selector =
271+
FunctionSelector<NT>{
272+
.value = 1,
273+
},
268274
.is_private = false,
269275
.is_constructor = false,
270276
};
@@ -640,7 +646,9 @@ TEST(public_kernel_tests, function_selector_must_be_valid)
640646
DummyBuilder dummyBuilder = DummyBuilder("public_kernel_tests__function_selector_must_be_valid");
641647
PublicKernelInputs<NT> inputs = get_kernel_inputs_with_previous_kernel(true);
642648

643-
inputs.public_call.call_stack_item.function_data.function_selector = 0;
649+
inputs.public_call.call_stack_item.function_data.function_selector = FunctionSelector<NT>{
650+
.value = 0,
651+
};
644652
auto public_inputs = native_public_kernel_circuit_private_previous_kernel(dummyBuilder, inputs);
645653
ASSERT_TRUE(dummyBuilder.failed());
646654
ASSERT_EQ(dummyBuilder.get_first_failure().code, CircuitErrorCode::PUBLIC_KERNEL__FUNCTION_SIGNATURE_INVALID);

circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ void common_validate_inputs(DummyBuilder& builder, KernelInput const& public_ker
180180
builder.do_assert(this_call_stack_item.contract_address != 0,
181181
"Contract address must be non-zero",
182182
CircuitErrorCode::PUBLIC_KERNEL__CONTRACT_ADDRESS_INVALID);
183-
builder.do_assert(this_call_stack_item.function_data.function_selector != 0,
183+
builder.do_assert(this_call_stack_item.function_data.function_selector.value != 0,
184184
"Function signature must be non-zero",
185185
CircuitErrorCode::PUBLIC_KERNEL__FUNCTION_SIGNATURE_INVALID);
186186
builder.do_assert(this_call_stack_item.function_data.is_constructor == false,

yarn-project/acir-simulator/src/acvm/deserialize.ts

-9
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,6 @@ export function frToBoolean(fr: Fr): boolean {
5757
return buf[buf.length - 1] !== 0;
5858
}
5959

60-
/**
61-
* Converts a field to a function selector.
62-
* @param fr - The field to convert.
63-
* @returns The function selector.
64-
*/
65-
export function frToSelector(fr: Fr): Buffer {
66-
return fr.toBuffer().slice(-4);
67-
}
68-
6960
/**
7061
* Extracts the return fields of a given partial witness.
7162
* @param acir - The bytecode of the function.

0 commit comments

Comments
 (0)