Skip to content

Commit 23cde9a

Browse files
authored
Merge branch 'backport-to-v4-next-staging' into claudebox/backport-22617-v4-next
2 parents aaf8d20 + bb75dd9 commit 23cde9a

32 files changed

Lines changed: 452 additions & 281 deletions

File tree

barretenberg/cpp/src/barretenberg/api/aztec_process.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,21 @@ bool process_aztec_artifact(const std::string& input_path, const std::string& ou
258258
return true;
259259
}
260260

261+
// Strip __aztec_nr_internals__ prefix from function names.
262+
// The #[aztec] macro generates wrapper functions with this prefix; we strip it so
263+
// the exported ABI exposes the original developer-written names.
264+
const std::string internal_prefix = "__aztec_nr_internals__";
265+
for (auto& function : artifact_json["functions"]) {
266+
auto& name = function["name"];
267+
if (name.is_string()) {
268+
std::string fn_name = name.get<std::string>();
269+
if (fn_name.size() >= internal_prefix.size() &&
270+
fn_name.compare(0, internal_prefix.size(), internal_prefix) == 0) {
271+
name = fn_name.substr(internal_prefix.size());
272+
}
273+
}
274+
}
275+
261276
// Filter to private constrained functions
262277
std::vector<nlohmann::json*> private_functions;
263278
for (auto& function : artifact_json["functions"]) {
@@ -266,14 +281,13 @@ bool process_aztec_artifact(const std::string& input_path, const std::string& ou
266281
}
267282
}
268283

269-
if (private_functions.empty()) {
284+
if (!private_functions.empty()) {
285+
// Generate VKs
286+
generate_vks_for_functions(cache_dir, private_functions, force);
287+
} else {
270288
info("No private constrained functions found");
271-
return true;
272289
}
273290

274-
// Generate VKs
275-
generate_vks_for_functions(cache_dir, private_functions, force);
276-
277291
// Write updated JSON back to file
278292
std::ofstream out_file(output_path);
279293
out_file << artifact_json.dump(2) << std::endl;

docs/bootstrap.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ source $(git rev-parse --show-toplevel)/ci3/source_bootstrap
44
repo_root=$(git rev-parse --show-toplevel)
55
export BB=${BB:-$repo_root/barretenberg/cpp/build/bin/bb}
66
export NARGO=${NARGO:-$repo_root/noir/noir-repo/target/release/nargo}
7-
export TRANSPILER=${TRANSPILER:-$repo_root/avm-transpiler/target/release/avm-transpiler}
87
export BB_HASH=${BB_HASH:-$($repo_root/barretenberg/cpp/bootstrap.sh hash)}
98

109
# We search the docs/*.md files to find included code, and use those as our rebuild dependencies.

docs/examples/bootstrap.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ REPO_ROOT=$(git rev-parse --show-toplevel)
66

77
export BB=${BB:-"$REPO_ROOT/barretenberg/cpp/build/bin/bb"}
88
export NARGO=${NARGO:-"$REPO_ROOT/noir/noir-repo/target/release/nargo"}
9-
export TRANSPILER=${TRANSPILER:-"$REPO_ROOT/avm-transpiler/target/release/avm-transpiler"}
10-
export STRIP_AZTEC_NR_PREFIX=${STRIP_AZTEC_NR_PREFIX:-"$REPO_ROOT/noir-projects/noir-contracts/scripts/strip_aztec_nr_prefix.sh"}
119
export BB_HASH=${BB_HASH:-$("$REPO_ROOT/barretenberg/cpp/bootstrap.sh" hash)}
1210
export NOIR_HASH=${NOIR_HASH:-$("$REPO_ROOT/noir/bootstrap.sh" hash)}
1311

noir-projects/aztec-nr/aztec/src/oracle/auth_witness.nr

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,37 @@ unconstrained fn get_auth_witness_oracle<let N: u32>(_message_hash: Field) -> [F
55
pub unconstrained fn get_auth_witness<let N: u32>(message_hash: Field) -> [Field; N] {
66
get_auth_witness_oracle(message_hash)
77
}
8+
9+
/// Fetches an auth witness and casts each field to a byte.
10+
///
11+
/// Each field is range-checked to `[0, 256)` before casting to prevent silent truncation (e.g. a field value of
12+
/// `b + 256` would truncate to the same byte as `b`).
13+
pub unconstrained fn get_auth_witness_as_bytes<let N: u32>(message_hash: Field) -> [u8; N] {
14+
let witness = get_auth_witness::<N>(message_hash);
15+
let mut result: [u8; N] = [0; N];
16+
for i in 0..N {
17+
assert(witness[i].lt(256), "auth witness field is not a single byte");
18+
result[i] = witness[i] as u8;
19+
}
20+
result
21+
}
22+
23+
mod test {
24+
use super::get_auth_witness_as_bytes;
25+
use std::test::OracleMock;
26+
27+
#[test]
28+
unconstrained fn get_auth_witness_as_bytes_casts_valid_witness() {
29+
let witness: [Field; 3] = [0, 127, 255];
30+
let _ = OracleMock::mock("aztec_utl_getAuthWitness").returns(witness);
31+
let bytes: [u8; 3] = get_auth_witness_as_bytes(0);
32+
assert_eq(bytes, [0, 127, 255]);
33+
}
34+
35+
#[test(should_fail_with = "auth witness field is not a single byte")]
36+
unconstrained fn get_auth_witness_as_bytes_rejects_field_above_byte_range() {
37+
let witness: [Field; 1] = [256];
38+
let _ = OracleMock::mock("aztec_utl_getAuthWitness").returns(witness);
39+
let _: [u8; 1] = get_auth_witness_as_bytes(0);
40+
}
41+
}

noir-projects/noir-contracts/bootstrap.sh

Lines changed: 8 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/env bash
2-
# TODO: THIS SCRIPT SHOULD NOW BE ABLE TO REPLACE TRANSPILATION AND VK GENERATION WITH 'bb aztec_process'.
32
#
43
# Some notes if you have to work on this script.
54
# - First of all, I'm sorry (edit: not sorry). It's a beautiful script but it's no fun to debug. I got carried away.
@@ -30,77 +29,12 @@ export PLATFORM_TAG=any
3029

3130
export BB=${BB:-../../barretenberg/cpp/build/bin/bb}
3231
export NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo}
33-
export TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler}
34-
export STRIP_AZTEC_NR_PREFIX=${STRIP_AZTEC_NR_PREFIX:-./scripts/strip_aztec_nr_prefix.sh}
3532
export BB_HASH=${BB_HASH:-$(../../barretenberg/cpp/bootstrap.sh hash)}
3633
export NOIR_HASH=${NOIR_HASH:-$(../../noir/bootstrap.sh hash)}
3734

38-
export tmp_dir=./target/tmp
39-
40-
# Remove our tmp dir from last run.
41-
# Note: This can use BASH 'trap' for better cleanliness, but the script has been hitting edge-cases so is (temporarily?) simplified.
42-
rm -rf $tmp_dir
43-
mkdir -p $tmp_dir
44-
4535
# Set common flags for parallel.
4636
export PARALLEL_FLAGS="-j${PARALLELISM:-16} --halt now,fail=1 --memsuspend $(memsuspend_limit)"
4737

48-
# This computes a vk and adds it to the input function json if it's private, else returns same input.
49-
# stdin has the function json.
50-
# stdout receives the function json with the vk added (if private).
51-
# The function is exported and called by a sub-shell in parallel, so we must "set -eu" etc..
52-
# If debugging, a set -x at the start can help.
53-
function process_function {
54-
set -euo pipefail
55-
local func name bytecode_b64 hash vk
56-
57-
contract_hash=$1
58-
# Read the function json.
59-
func="$(cat)"
60-
name=$(echo "$func" | jq -r '.name')
61-
echo_stderr "Processing function: $name..."
62-
63-
# Check if the function is neither public nor unconstrained.
64-
# TODO: Why do we need to gen keys for functions that are not marked private?
65-
# We allow the jq call to error (set +e) because it returns an error code if the result is false.
66-
# We then differentiate between a real error, and the result being false.
67-
set +e
68-
make_vk=$(echo "$func" | jq -e '(.custom_attributes | index("public") == null) and (.is_unconstrained == false)')
69-
if [ $? -ne 0 ] && [ "$make_vk" != "false" ]; then
70-
echo_stderr "Failed to check function $name is neither public nor unconstrained."
71-
exit 1
72-
fi
73-
set -e
74-
75-
if [ "$make_vk" == "true" ]; then
76-
# It's a private function.
77-
# Build hash, check if in cache.
78-
# If it's in the cache it's extracted to $tmp_dir/$hash
79-
bytecode_b64=$(echo "$func" | jq -r '.bytecode')
80-
hash=$((echo "$BB_HASH"; echo "$bytecode_b64") | sha256sum | tr -d ' -')
81-
82-
if ! cache_download vk-$contract_hash-$hash.tar.gz >&2; then
83-
# It's not in the cache. Generate the vk file and upload it to the cache.
84-
echo_stderr "Generating vk for function: $name..."
85-
86-
local outdir=$(mktemp -d -p $tmp_dir)
87-
echo "$bytecode_b64" | base64 -d | gunzip | $BB write_vk --scheme chonk -b - -o $outdir -v
88-
mv $outdir/vk $tmp_dir/$contract_hash/$hash
89-
90-
cache_upload vk-$contract_hash-$hash.tar.gz $tmp_dir/$contract_hash/$hash
91-
fi
92-
93-
# Return (echo) json containing the base64 encoded verification key.
94-
vk=$(cat $tmp_dir/$contract_hash/$hash | base64 -w 0)
95-
echo "$func" | jq -c --arg vk "$vk" '. + {verification_key: $vk}'
96-
else
97-
echo_stderr "Function $name is neither public nor unconstrained, skipping."
98-
# Not a private function. Return the original function json.
99-
echo "$func"
100-
fi
101-
}
102-
export -f process_function
103-
10438
# Compute hash for a given contract.
10539
# $1 is the contract name, $2 is the folder name (e.g. "contracts" or "examples")
10640
function get_contract_hash {
@@ -159,42 +93,26 @@ function get_contract_path {
15993
}
16094
export -f get_contract_path
16195

162-
# This compiles a noir contract, transpile's public functions, and generates vk's for private functions.
96+
# This compiles a noir contract, transpiles public functions, strips internal prefixes,
97+
# and generates verification keys for private functions via 'bb aztec_process'.
16398
# $1 is the input package name, $2 is the folder name (e.g. "contracts" or "examples")
164-
# On exit it's fully processed json artifact is in the target dir.
99+
# On exit its fully processed json artifact is in the target dir.
165100
# The function is exported and called by a sub-shell in parallel, so we must "set -eu" etc..
166101
function compile {
167102
set -euo pipefail
168-
local contract_name contract_hash
169103

170104
local contract_path=$(get_contract_path "$1" "$2")
171105
local contract=$(grep -oP '(?<=^name = ")[^"]+' "$2/$contract_path/Nargo.toml")
172106
# Calculate filename because nargo...
173-
contract_name=$(cat $2/$contract_path/src/main.nr | awk '/^contract / { print $2 } /^pub contract / { print $3 }')
107+
local contract_name=$(cat $2/$contract_path/src/main.nr | awk '/^contract / { print $2 } /^pub contract / { print $3 }')
174108
local filename="$contract-$contract_name.json"
175109
local json_path="./target/$filename"
176-
contract_hash=$(get_contract_hash $1 $2)
110+
local contract_hash=$(get_contract_hash $1 $2)
177111
if ! cache_download contract-$contract_hash.tar.gz; then
178-
$NARGO compile --package $contract --inliner-aggressiveness 0 --deny-warnings
179-
$TRANSPILER $json_path $json_path
180-
$STRIP_AZTEC_NR_PREFIX $json_path
112+
$NARGO compile --package $contract --inliner-aggressiveness 0 --deny-warnings
113+
$BB aztec_process -i $json_path
181114
cache_upload contract-$contract_hash.tar.gz $json_path
182115
fi
183-
184-
# We segregate equivalent vk's created by process_function. This was done to narrow down potential edge cases with identical VKs
185-
# reading from cache at the same time. Create this folder up-front.
186-
mkdir -p $tmp_dir/$contract_hash
187-
188-
# Pipe each contract function, one per line (jq -c), into parallel calls of process_function.
189-
# The returned jsons from process_function are converted back to a json array in the second jq -s call.
190-
# When slurping (-s) in the last jq, we get an array of two elements:
191-
# .[0] is the original json (at $json_path)
192-
# .[1] is the updated functions on stdin (-)
193-
# * merges their fields.
194-
jq -c '.functions[]' $json_path | \
195-
parallel $PARALLEL_FLAGS --keep-order -N1 --block 8M --pipe process_function $contract_hash | \
196-
jq -s '{functions: .}' | jq -s '.[0] * {functions: .[1].functions}' $json_path - > $tmp_dir/$filename
197-
mv $tmp_dir/$filename $json_path
198116
}
199117
export -f compile
200118

@@ -211,7 +129,7 @@ function build {
211129

212130
if [ "$#" -eq 0 ]; then
213131
rm -rf target
214-
mkdir -p $tmp_dir
132+
mkdir -p target
215133
local contracts=$(grep -oP "(?<=$folder_name/)[^\"]+" Nargo.toml)
216134

217135
# If pinned contracts exist, extract them and skip their compilation.

noir-projects/noir-contracts/contracts/account/ecdsa_k_account_contract/src/main.nr

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ pub contract EcdsaKAccount {
1212
storage::storage,
1313
},
1414
messages::message_delivery::MessageDelivery,
15-
oracle::{auth_witness::get_auth_witness, notes::{get_sender_for_tags, set_sender_for_tags}},
15+
oracle::{
16+
auth_witness::get_auth_witness_as_bytes,
17+
notes::{get_sender_for_tags, set_sender_for_tags},
18+
},
1619
state_vars::SinglePrivateImmutable,
1720
};
1821

@@ -81,14 +84,9 @@ pub contract EcdsaKAccount {
8184
let storage = Storage::init(context);
8285
let public_key = storage.signing_public_key.get_note();
8386

84-
// Load auth witness
8587
// Safety: The witness is only used as a "magical value" that makes the signature verification below pass.
8688
// Hence it's safe.
87-
let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) };
88-
let mut signature: [u8; 64] = [0; 64];
89-
for i in 0..64 {
90-
signature[i] = witness[i] as u8;
91-
}
89+
let signature: [u8; 64] = unsafe { get_auth_witness_as_bytes(outer_hash) };
9290

9391
// Verify payload signature using Ethereum's signing scheme
9492
// Note that noir expects the hash of the message/challenge as input to the ECDSA verification.

noir-projects/noir-contracts/contracts/account/ecdsa_r_account_contract/src/main.nr

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ pub contract EcdsaRAccount {
1111
storage::storage,
1212
},
1313
messages::message_delivery::MessageDelivery,
14-
oracle::{auth_witness::get_auth_witness, notes::{get_sender_for_tags, set_sender_for_tags}},
14+
oracle::{
15+
auth_witness::get_auth_witness_as_bytes,
16+
notes::{get_sender_for_tags, set_sender_for_tags},
17+
},
1518
state_vars::SinglePrivateImmutable,
1619
};
1720

@@ -79,14 +82,9 @@ pub contract EcdsaRAccount {
7982
let storage = Storage::init(context);
8083
let public_key = storage.signing_public_key.get_note();
8184

82-
// Load auth witness
8385
// Safety: The witness is only used as a "magical value" that makes the signature verification below pass.
8486
// Hence it's safe.
85-
let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) };
86-
let mut signature: [u8; 64] = [0; 64];
87-
for i in 0..64 {
88-
signature[i] = witness[i] as u8;
89-
}
87+
let signature: [u8; 64] = unsafe { get_auth_witness_as_bytes(outer_hash) };
9088

9189
// Verify payload signature using Ethereum's signing scheme
9290
// Note that noir expects the hash of the message/challenge as input to the ECDSA verification.

noir-projects/noir-contracts/contracts/account/schnorr_account_contract/src/main.nr

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub contract SchnorrAccount {
2020
},
2121
messages::message_delivery::MessageDelivery,
2222
oracle::{
23-
auth_witness::get_auth_witness,
23+
auth_witness::get_auth_witness_as_bytes,
2424
get_nullifier_membership_witness::get_low_nullifier_membership_witness,
2525
notes::{get_sender_for_tags, set_sender_for_tags},
2626
},
@@ -95,14 +95,9 @@ pub contract SchnorrAccount {
9595
let storage = Storage::init(context);
9696
let public_key = storage.signing_public_key.get_note();
9797

98-
// Load auth witness
9998
// Safety: The witness is only used as a "magical value" that makes the signature verification below pass.
10099
// Hence it's safe.
101-
let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) };
102-
let mut signature: [u8; 64] = [0; 64];
103-
for i in 0..64 {
104-
signature[i] = witness[i] as u8;
105-
}
100+
let signature: [u8; 64] = unsafe { get_auth_witness_as_bytes(outer_hash) };
106101

107102
let pub_key =
108103
std::embedded_curve_ops::EmbeddedCurvePoint { x: public_key.x, y: public_key.y };
@@ -128,11 +123,7 @@ pub contract SchnorrAccount {
128123
inner_hash,
129124
);
130125

131-
let witness: [Field; 64] = get_auth_witness(message_hash);
132-
let mut signature: [u8; 64] = [0; 64];
133-
for i in 0..64 {
134-
signature[i] = witness[i] as u8;
135-
}
126+
let signature: [u8; 64] = get_auth_witness_as_bytes(message_hash);
136127
let pub_key =
137128
std::embedded_curve_ops::EmbeddedCurvePoint { x: public_key.x, y: public_key.y };
138129
let valid_in_private =

noir-projects/noir-contracts/contracts/account/schnorr_hardcoded_account_contract/src/main.nr

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub contract SchnorrHardcodedAccount {
77
authwit::{account::AccountActions, entrypoint::app::AppPayload},
88
context::PrivateContext,
99
macros::functions::{allow_phase_change, external, view},
10-
oracle::{auth_witness::get_auth_witness, notes::set_sender_for_tags},
10+
oracle::{auth_witness::get_auth_witness_as_bytes, notes::set_sender_for_tags},
1111
};
1212
use std::embedded_curve_ops::EmbeddedCurvePoint;
1313

@@ -38,15 +38,9 @@ pub contract SchnorrHardcodedAccount {
3838

3939
#[contract_library_method]
4040
fn is_valid_impl(_context: &mut PrivateContext, outer_hash: Field) -> bool {
41-
// Load auth witness and format as an u8 array
42-
4341
// Safety: The witness is only used as a "magical value" that makes the signature verification below pass.
4442
// Hence it's safe.
45-
let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) };
46-
let mut signature: [u8; 64] = [0; 64];
47-
for i in 0..64 {
48-
signature[i] = witness[i] as u8;
49-
}
43+
let signature: [u8; 64] = unsafe { get_auth_witness_as_bytes(outer_hash) };
5044

5145
// Verify signature using hardcoded public key
5246
schnorr::verify_signature(

noir-projects/noir-contracts/scripts/bootstrap_just_one_contract.sh

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ echo "Compiling contract..."
2828
NARGO=${NARGO:-../../../noir/noir-repo/target/release/nargo}
2929
$NARGO compile --silence-warnings --inliner-aggressiveness 0 --package $CONTRACT_PACKAGE_NAME
3030

31-
# Strip __aztec_nr_internals__ prefix from function names in the ABI.
32-
echo "Stripping aztec nr prefix..."
33-
./strip_aztec_nr_prefix.sh "../target/$JSON_NAME.json"
34-
35-
# Transpile public functions and generate VKs for private functions.
31+
# Transpile public functions, strip internal prefixes, and generate VKs for private functions.
3632
echo "Processing contract artifact..."
3733
BB=${BB:-../../../barretenberg/cpp/build/bin/bb}
3834
"$BB" aztec_process -i "../target/$JSON_NAME.json" -o "../target/$JSON_NAME.json" -f

0 commit comments

Comments
 (0)