Skip to content

Commit 286b647

Browse files
committed
Merge branch 'next' into md/opt-sol-honk
2 parents 303b2f2 + 46737cb commit 286b647

File tree

349 files changed

+10210
-2897
lines changed

Some content is hidden

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

349 files changed

+10210
-2897
lines changed

.github/workflows/fund-sepolia-accounts.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ on:
1717
required: false
1818
type: string
1919
default: master
20+
funding_amount:
21+
description: The amount of ETH to fund each account with
22+
required: true
23+
type: number
24+
default: 5
2025
secrets:
2126
GCP_SA_KEY:
2227
required: true
@@ -43,6 +48,11 @@ on:
4348
required: false
4449
type: string
4550
default: master
51+
funding_amount:
52+
description: The amount of ETH to fund each account with
53+
required: true
54+
type: number
55+
default: 5
4656

4757
jobs:
4858
fund-sepolia-accounts:
@@ -79,7 +89,7 @@ jobs:
7989
if [[ "${{ steps.get-mnemonic.outputs.new_mnemonic }}" == "true" ]]; then
8090
echo "Generating new mnemonic"
8191
else
82-
MNEMONIC="${{ steps.get-mnemonic.outputs.mnemonic }}"
92+
export MNEMONIC="${{ steps.get-mnemonic.outputs.mnemonic }}"
8393
echo "Using mnemonic from GCP"
8494
fi
8595
@@ -89,7 +99,7 @@ jobs:
8999
export ETHEREUM_HOST="https://json-rpc.${{ secrets.GCP_SEPOLIA_URL }}?key=${{ secrets.GCP_SEPOLIA_API_KEY }}"
90100
91101
echo "Funding accounts..."
92-
$REPO/spartan/scripts/prepare_sepolia_accounts.sh ${{ inputs.values_file }} 30 "$MNEMONIC_FILE"
102+
$REPO/spartan/scripts/prepare_sepolia_accounts.sh ${{ inputs.values_file }} ${{ inputs.funding_amount }} "$MNEMONIC_FILE"
93103
mnemonic=$(cat "$MNEMONIC_FILE")
94104
rm "$MNEMONIC_FILE"
95105
echo "::add-mask::$mnemonic"

.test_patterns.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ tests:
249249
error_regex: "ContractFunctionExecutionError: The contract function"
250250
owners:
251251
- *mitch
252+
- regex: "src/e2e_block_building"
253+
error_regex: "✕ detects an upcoming reorg and builds a block for the correct slot"
254+
owners:
255+
- *palla
252256

253257
# Nightly GKE tests
254258
- regex: "spartan/bootstrap.sh"

barretenberg/cpp/pil/vm2/alu.pil

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace alu;
99
pol commit sel;
1010

1111
pol commit sel_op_add;
12+
pol commit sel_op_sub;
13+
pol commit sel_op_mul;
1214
pol commit sel_op_eq;
1315
pol commit sel_op_lt;
1416
pol commit sel_op_lte;
@@ -37,24 +39,29 @@ pol commit cf;
3739
pol commit helper1;
3840

3941
// maximum bits the number can hold (i.e. 8 for a u8):
40-
// TODO(MW): Now unused since we redirect the LT/LTE range checks to GT gadget - remove?
4142
pol commit max_bits;
4243
// maximum value the number can hold (i.e. 255 for a u8), we 'mod' by max_value + 1
4344
pol commit max_value;
4445
// we need a selector to conditionally lookup ff_gt when inputs a, b are fields:
4546
pol commit sel_is_ff;
47+
// we need a selector to conditionally perform u128 multiplication:
48+
pol commit sel_is_u128;
4649

4750
pol IS_NOT_FF = 1 - sel_is_ff;
51+
pol IS_NOT_U128 = 1 - sel_is_u128;
4852

4953
sel * (1 - sel) = 0;
5054
cf * (1 - cf) = 0;
5155
sel_is_ff * (1 - sel_is_ff) = 0;
56+
sel_is_u128 * (1 - sel_is_u128) = 0;
5257

5358
// TODO: Consider to gate with (1 - sel_tag_err) for op_id. This might help us remove the (1 - sel_tag_err)
5459
// in various operation relations below.
5560
// Note that the op_ids below represent a binary decomposition (see constants_gen.pil):
5661
#[OP_ID_CHECK]
5762
op_id = sel_op_add * constants.AVM_EXEC_OP_ID_ALU_ADD
63+
+ sel_op_sub * constants.AVM_EXEC_OP_ID_ALU_SUB
64+
+ sel_op_mul * constants.AVM_EXEC_OP_ID_ALU_MUL
5865
+ sel_op_eq * constants.AVM_EXEC_OP_ID_ALU_EQ
5966
+ sel_op_lt * constants.AVM_EXEC_OP_ID_ALU_LT
6067
+ sel_op_lte * constants.AVM_EXEC_OP_ID_ALU_LTE
@@ -78,18 +85,28 @@ execution.sel_execute_alu {
7885

7986
// IS_FF CHECKING
8087

81-
// TODO(MW): remove this and check for all (i.e. replace with sel), just being lazy for now. For add, we don't care, for lt we need to differentiate.
8288
pol CHECK_TAG_FF = sel_op_lt + sel_op_lte + sel_op_not;
8389
// We prove that sel_is_ff == 1 <==> ia_tag == MEM_TAG_FF
8490
pol TAG_FF_DIFF = ia_tag - constants.MEM_TAG_FF;
8591
pol commit tag_ff_diff_inv;
8692
#[TAG_IS_FF]
8793
CHECK_TAG_FF * (TAG_FF_DIFF * (sel_is_ff * (1 - tag_ff_diff_inv) + tag_ff_diff_inv) + sel_is_ff - 1) = 0;
8894

95+
// IS_U128 CHECKING
96+
97+
pol CHECK_TAG_U128 = sel_op_mul;
98+
// We prove that sel_is_u128 == 1 <==> ia_tag == MEM_TAG_U128
99+
pol TAG_U128_DIFF = ia_tag - constants.MEM_TAG_U128;
100+
pol commit tag_u128_diff_inv;
101+
#[TAG_IS_U128]
102+
CHECK_TAG_U128 * (TAG_U128_DIFF * (sel_is_u128 * (1 - tag_u128_diff_inv) + tag_u128_diff_inv) + sel_is_u128 - 1) = 0;
103+
104+
// Note: if we never need sel_is_ff and sel_is_u128 in the same op, can combine the above checks into one
105+
89106
// TAG CHECKING
90107

91108
// Will become e.g. sel_op_add * ia_tag + (comparison ops) * MEM_TAG_U1 + ....
92-
pol EXPECTED_C_TAG = (sel_op_add + sel_op_truncate) * ia_tag + (sel_op_eq + sel_op_lt + sel_op_lte) * constants.MEM_TAG_U1;
109+
pol EXPECTED_C_TAG = (sel_op_add + sel_op_sub + sel_op_truncate + sel_op_mul) * ia_tag + (sel_op_eq + sel_op_lt + sel_op_lte) * constants.MEM_TAG_U1;
93110

94111
// The tag of c is generated by the opcode and is never wrong.
95112
// Gating with (1 - sel_tag_err) is necessary because when an error occurs, we have to set the tag to 0,
@@ -120,8 +137,91 @@ sel { ia_tag, max_bits, max_value } in precomputed.sel_tag_parameters { precompu
120137

121138
sel_op_add * (1 - sel_op_add) = 0;
122139

123-
#[ALU_ADD]
124-
sel_op_add * (1 - sel_tag_err) * (ia + ib - ic - cf * (max_value + 1)) = 0;
140+
// SUB
141+
142+
sel_op_sub * (1 - sel_op_sub) = 0;
143+
144+
// ADD & SUB - Shared relation:
145+
146+
// For add, sel_op_add - sel_op_sub = 1 => check a + b - cf * carry = c
147+
// For sub, sel_op_add - sel_op_sub = -1 => check a - b + cf * carry = c
148+
#[ALU_ADD_SUB]
149+
(sel_op_add + sel_op_sub) * (1 - sel_tag_err) * (ia - ic + (sel_op_add - sel_op_sub) * (ib - cf * (max_value + 1))) = 0;
150+
151+
// MUL
152+
153+
sel_op_mul * (1 - sel_op_mul) = 0;
154+
155+
pol commit c_hi;
156+
157+
// MUL - non u128
158+
159+
#[ALU_MUL_NON_U128]
160+
sel_op_mul * IS_NOT_U128 * (1 - sel_tag_err)
161+
* (
162+
ia * ib
163+
- ic
164+
- (max_value + 1) * c_hi
165+
) = 0;
166+
167+
// MUL - u128
168+
169+
pol commit sel_mul_u128;
170+
// sel_op_mul & sel_is_u128:
171+
sel_mul_u128 - sel_is_u128 * sel_op_mul = 0;
172+
173+
// Taken from vm1:
174+
// We express a, b in 64-bit slices: a = a_l + a_h * 2^64
175+
// b = b_l + b_h * 2^64
176+
// => a * b = a_l * b_l + (a_h * b_l + a_l * b_h) * 2^64 + (a_h * b_h) * 2^128 = c_hi_full * 2^128 + c
177+
// => the 'top bits' are given by (c_hi_full - (a_h * b_h)) * 2^128
178+
// We can show for a 64 bit c_hi = c_hi_full - (a_h * b_h) % 2^64 that:
179+
// a_l * b_l + (a_h * b_l + a_l * b_h) * 2^64 = c_hi * 2^128 + c
180+
// Equivalently (cf = 0 if a_h & b_h = 0):
181+
// a * b_l + a_l * b_h * 2^64 = (cf * 2^64 + c_hi) * 2^128 + c
182+
// => no need for a_h in final relation
183+
184+
pol commit a_lo;
185+
pol commit a_hi;
186+
pol commit b_lo;
187+
pol commit b_hi;
188+
pol TWO_POW_64 = 2 ** 64;
189+
190+
#[A_MUL_DECOMPOSITION]
191+
sel_mul_u128 * (ia - (a_lo + TWO_POW_64 * a_hi)) = 0;
192+
#[B_MUL_DECOMPOSITION]
193+
sel_mul_u128 * (ib - (b_lo + TWO_POW_64 * b_hi)) = 0;
194+
195+
#[ALU_MUL_U128]
196+
sel_mul_u128 * (1 - sel_tag_err)
197+
* (
198+
ia * b_lo + a_lo * b_hi * TWO_POW_64 // a * b without the hi bits
199+
- ic // c_lo
200+
- (max_value + 1) * (cf * TWO_POW_64 + c_hi) // c_hi * 2^128 + (cf ? 2^192 : 0)
201+
) = 0;
202+
203+
// TODO: Once lookups support expression in tuple, we can inline constant_64 into the lookup.
204+
// Note: only used for MUL, so gated by sel_op_mul
205+
pol commit constant_64;
206+
sel_op_mul * (64 - constant_64) = 0;
207+
208+
#[RANGE_CHECK_MUL_U128_A_LO]
209+
sel_mul_u128 { a_lo, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };
210+
211+
#[RANGE_CHECK_MUL_U128_A_HI]
212+
sel_mul_u128 { a_hi, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };
213+
214+
#[RANGE_CHECK_MUL_U128_B_LO]
215+
sel_mul_u128 { b_lo, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };
216+
217+
#[RANGE_CHECK_MUL_U128_B_HI]
218+
sel_mul_u128 { b_hi, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };
219+
220+
// No need to range_check c_hi for cases other than u128 because we know a and b's size from the tags and have looked
221+
// up max_value. i.e. we cannot provide a malicious c, c_hi such that a + b - c_hi * 2^n = c passes for n < 128.
222+
// No need to range_check c_lo = ic because the memory write will ensure ic <= max_value.
223+
#[RANGE_CHECK_MUL_U128_C_HI]
224+
sel_mul_u128 { c_hi, constant_64 } in range_check.sel { range_check.value, range_check.rng_chk_bits };
125225

126226
// EQ
127227

@@ -280,21 +380,21 @@ sel_op_truncate = sel_trunc_non_trivial + sel_trunc_trivial;
280380
#[TRUNC_TRIVIAL_CASE]
281381
sel_trunc_trivial * (ia - ic) = 0;
282382

283-
pol commit lo_128; // 128-bit low limb of ia.
284-
pol commit hi_128; // 128-bit high limb of ia.
383+
// NOTE: reusing a_lo and a_hi columns from MUL in TRUNC:
384+
// For truncate, a_lo = 128-bit low limb of ia and a_hi = 128-bit high limb of ia.
285385
pol commit mid;
286386

287387
#[LARGE_TRUNC_CANONICAL_DEC]
288-
sel_trunc_gte_128 { ia, lo_128, hi_128 }
388+
sel_trunc_gte_128 { ia, a_lo, a_hi }
289389
in
290390
ff_gt.sel_dec { ff_gt.a, ff_gt.a_lo, ff_gt.a_hi };
291391

292392
#[SMALL_TRUNC_VAL_IS_LO]
293-
sel_trunc_lt_128 * (lo_128 - ia) = 0;
393+
sel_trunc_lt_128 * (a_lo - ia) = 0;
294394

295-
// lo_128 = ic + mid * 2^ia_tag_bits, where 2^ia_tag_bits is max_value + 1.
395+
// a_lo = ic + mid * 2^ia_tag_bits, where 2^ia_tag_bits is max_value + 1.
296396
#[TRUNC_LO_128_DECOMPOSITION]
297-
sel_trunc_non_trivial * (ic + mid * (max_value + 1) - lo_128) = 0;
397+
sel_trunc_non_trivial * (ic + mid * (max_value + 1) - a_lo) = 0;
298398

299399
// TODO: Once lookups support expression in tuple, we can inline mid_bits into the lookup.
300400
pol commit mid_bits;
@@ -305,4 +405,4 @@ mid_bits = sel_trunc_non_trivial * (128 - max_bits);
305405
// is supported by our range_check gadget.
306406
// No need to range_check ic because the memory write will ensure ic <= max_value.
307407
#[RANGE_CHECK_TRUNC_MID]
308-
sel_trunc_non_trivial {mid, mid_bits} in range_check.sel { range_check.value, range_check.rng_chk_bits };
408+
sel_trunc_non_trivial { mid, mid_bits } in range_check.sel { range_check.value, range_check.rng_chk_bits };

barretenberg/cpp/pil/vm2/execution.pil

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ include "sha256.pil";
88
include "ecc_mem.pil";
99
include "poseidon2_mem.pil";
1010
include "scalar_mul.pil";
11-
include "to_radix.pil";
11+
include "to_radix_mem.pil";
1212
include "ff_gt.pil";
1313
include "gt.pil";
1414
include "context.pil";
@@ -288,16 +288,72 @@ pol commit expected_tag_reg[7];
288288

289289
pol commit sel_should_check_gas;
290290
sel_should_check_gas = sel_should_read_registers * (1 - sel_register_read_error);
291-
292291
// NOTE: Gas is constrained in gas.pil.
293292
// The "output we want is" sel_out_of_gas from gas.pil.
294293

294+
//////////////////////////////////////////
295+
// Bitwise, Dynamic L2 Gas Calculation
296+
//////////////////////////////////////////
295297
// For bitwise, the tag determines the dynamic_l2_gas_factor
296298
#[DYN_L2_FACTOR_BITWISE]
297299
sel_gas_bitwise { mem_tag_reg[0], dynamic_l2_gas_factor }
298300
in
299301
precomputed.sel_tag_parameters { precomputed.clk, precomputed.tag_byte_length };
300302

303+
//////////////////////////////////////////
304+
// ToRadixBE, Dynamic L2 Gas Calculation
305+
//////////////////////////////////////////
306+
// The dynamic l2 gas factor depends on the number of limbs (located in register[2]) and
307+
// the number of limbs that the field modulus, p, decomposes into given a radix (num_p_limbs).
308+
309+
// num_p_limbs is stored in a precomputed table that supports radix values in the range [0, 256].
310+
// To ensure the lookup never fails if radix > 256, we just set num_p_limbs to 32.
311+
// It is expected that an error will later be thrown when the to_radix subtrace validates the radix (located in register[1])
312+
313+
// TODO: Theoretically, because we have access to a GreaterThan gadget - we could compare 257 > radix (instead of radix > 256)
314+
// This potentially more optimal for the circuit as the boolen result of this can be used directly in the GET_SAFE_LIMBS lookup
315+
316+
// In reality to keep the simulator cleaner and more sane, we will perform radix > 256.
317+
pol commit two_five_six;
318+
sel_gas_to_radix * (two_five_six - 256) = 0; // While we don't support constants in lookups
319+
320+
pol commit sel_radix_gt_256; // sel_radix_gt_256 = 1 iff radix > 256
321+
#[CHECK_RADIX_GT_256]
322+
sel_gas_to_radix { /*radix=*/register[1], two_five_six, sel_radix_gt_256 }
323+
in
324+
gt.sel { gt.input_a, gt.input_b, gt.res };
325+
326+
// Boolean for if we should look up the num_p_limbs value
327+
pol commit sel_lookup_num_p_limbs;
328+
sel_lookup_num_p_limbs = sel_gas_to_radix * (1 - sel_radix_gt_256);
329+
330+
// If radix > 256, num_p_limbs has to equal 32 - otherwise we rely on the lookup
331+
pol commit num_p_limbs;
332+
#[NUM_P_LIMBS_CEIL]
333+
sel_gas_to_radix * (sel_radix_gt_256 * (num_p_limbs - 32)) = 0;
334+
335+
#[GET_P_LIMBS]
336+
sel_lookup_num_p_limbs { /*radix=*/register[1], num_p_limbs }
337+
in
338+
precomputed.sel_to_radix_p_limb_counts
339+
{ precomputed.clk, precomputed.to_radix_num_limbs_for_p };
340+
341+
// We now compute the dynamic l2 gas factor as max(num_limbs, num_p_limbs)
342+
// The easiest way to do this is to do check if num_limbs > num_p_limbs.
343+
// If so then dynamic_l2_gas_factor = num_limbs
344+
// Otherwise dynamic_l2_gas_factor = num_p_limbs
345+
pol commit sel_use_num_limbs;
346+
#[GET_MAX_LIMBS]
347+
sel_gas_to_radix { /*num_limbs=*/register[2], num_p_limbs, sel_use_num_limbs }
348+
in
349+
gt.sel { gt.input_a, gt.input_b, gt.res };
350+
351+
#[DYN_L2_FACTOR_TO_RADIX_BE] // num_limbs > num_p_limbs ? num_limbs : num_p_limbs
352+
sel_gas_to_radix * ((/*num_limbs=*/register[2] - num_p_limbs) * sel_use_num_limbs + num_p_limbs - dynamic_l2_gas_factor) = 0;
353+
354+
//////////////////////////////////////////
355+
// SSTORE, Dynamic L2 Gas Calculation
356+
//////////////////////////////////////////
301357
// We can probably unconditionally write to the written_public_data_slots_tree here
302358
// to avoid writing later in opcode execution, since the root would be reverted if it errors before
303359
// the opcode execution. However, this feels like an early optimization
@@ -315,6 +371,9 @@ sel_gas_sstore {
315371
written_public_data_slots_tree_check.root
316372
};
317373

374+
// todo(ilyas): we are going to need these kinds of checks in general as well
375+
// i.e. opcodes without dynamic components need to assert dyn_l2 & dyn_da are zero
376+
// i.e. opcodes with only a single dynamic components need to assert the others are zero.
318377
#[SSTORE_DYN_L2_GAS_IS_ZERO]
319378
sel_execute_sstore * dynamic_l2_gas_factor = 0;
320379

barretenberg/cpp/pil/vm2/opcodes/external_call.pil

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ namespace execution;
55
// Register 2 contains allocated da gas
66
// Register 3 contains the address of the contract to call
77

8+
#[skippable_if]
9+
sel_enter_call = 0;
10+
811
// TODO: Remove this as a column when we can lookup with constants
912
pol commit constant_32;
1013
sel_enter_call * (32 - constant_32) = 0;

barretenberg/cpp/pil/vm2/precomputed.pil

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,11 @@ pol constant opcode_out_of_range;
9696

9797
// Used for getting the number of safe limbs for a given radix.
9898
// The selector is on for 1 < clk <= 256
99-
pol constant sel_to_radix_safe_limbs;
99+
pol constant sel_to_radix_p_limb_counts;
100100
// Number of safe limbs for a given radix=clk.
101101
pol constant to_radix_safe_limbs;
102+
// Number of limbs for the decomposition of p given a radix
103+
pol constant to_radix_num_limbs_for_p;
102104

103105
// Radix decompositions of P.
104106
pol constant sel_p_decomposition;

barretenberg/cpp/pil/vm2/to_radix.pil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ namespace to_radix;
139139
#[FETCH_SAFE_LIMBS]
140140
start { radix, safe_limbs }
141141
in
142-
precomputed.sel_to_radix_safe_limbs
142+
precomputed.sel_to_radix_p_limb_counts
143143
{ precomputed.clk, precomputed.to_radix_safe_limbs };
144144

145145
pol commit is_unsafe_limb;

0 commit comments

Comments
 (0)