From 66a2d43432607ec43eaac5b0ee7ac69f44d18d92 Mon Sep 17 00:00:00 2001 From: Miranda Wood Date: Fri, 17 May 2024 15:59:44 +0100 Subject: [PATCH 01/37] feat: remove total logs len from pre tail kernels + add to L1 (#6466) ## Remove total logs length Now individual logs lengths are tracked inside the kernels, we can accurately calculate DA gas and don't need the total lengths (`(un)encrypted_log_preimages_length`). This PR removes them. However, we should be checking that logs emitted on L1 are the lengths claimed in the circuits since they originate in untrusted contexts. ## Add length check to L1 To allow for this check, total lengths are calculated when converting to `CombinedAccumulatedData` at the 'end' of the tail kernels. In the circuit, these are maintained throughout the rollup stages and included in the `txsEffectHash`. On L1, when we re-calculate the hash, the lengths of the raw logs are accumulated and asserted to match those given in the block. A mismatch suggests that a user may have claimed their log was shorter than reality to try and pay less gas (and the sequencer missed it or is dishonest). --- - [x] Remove total logs length from pre-tail kernel circuits - [x] Calculate the total length when converting to `CombinedAccumulatedData` - [x] Add lengths to `txEffectsHash` and check against raw logs on L1 --- --- .../vm/avm_trace/aztec_constants.hpp | 8 +-- .../src/core/libraries/ConstantsGen.sol | 8 +-- l1-contracts/src/core/libraries/Errors.sol | 3 + .../core/libraries/decoders/TxsDecoder.sol | 67 ++++++++++++++++--- l1-contracts/test/decoders/Decoders.t.sol | 20 ++++-- .../decoders/helpers/TxsDecoderHelper.sol | 2 +- l1-contracts/test/fixtures/empty_block_0.json | 14 ++-- l1-contracts/test/fixtures/empty_block_1.json | 18 ++--- l1-contracts/test/fixtures/mixed_block_0.json | 16 ++--- l1-contracts/test/fixtures/mixed_block_1.json | 20 +++--- .../aztec/src/context/private_context.nr | 12 ---- .../aztec/src/context/public_context.nr | 5 -- .../oracle/enqueue_public_function_call.nr | 1 - .../kernel_circuit_public_inputs_composer.nr | 2 - ...e_kernel_circuit_public_inputs_composer.nr | 6 -- .../src/private_kernel_init.nr | 29 +++++--- .../src/private_kernel_inner.nr | 28 +++++--- .../src/private_kernel_reset.nr | 3 +- .../src/private_kernel_tail_to_public.nr | 4 -- .../crates/public-kernel-lib/src/common.nr | 11 +-- .../src/public_kernel_app_logic.nr | 22 ++++-- .../src/public_kernel_setup.nr | 25 ++++--- .../src/public_kernel_teardown.nr | 24 ++++--- .../src/reset/transient_data.nr | 31 +-------- .../crates/rollup-lib/src/components.nr | 16 ++++- .../combined_accumulated_data.nr | 16 +++-- .../private_accumulated_data.nr | 14 ---- .../private_accumulated_data_builder.nr | 59 +++++++--------- .../public_accumulated_data.nr | 14 ---- .../public_accumulated_data_builder.nr | 9 --- .../types/src/abis/private_call_stack_item.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 15 +---- .../types/src/abis/public_call_stack_item.nr | 4 +- .../src/abis/public_circuit_public_inputs.nr | 9 +-- .../crates/types/src/constants.nr | 8 +-- .../crates/types/src/tests/fixture_builder.nr | 4 -- .../private_circuit_public_inputs_builder.nr | 9 --- .../src/tests/public_call_data_builder.nr | 1 - .../public_circuit_public_inputs_builder.nr | 3 - .../src/logs/function_l2_logs.test.ts | 8 +++ .../src/logs/function_l2_logs.ts | 10 +++ .../circuit-types/src/logs/tx_l2_logs.test.ts | 8 +++ .../circuit-types/src/logs/tx_l2_logs.ts | 9 +++ .../circuit-types/src/tx/processed_tx.ts | 44 ++++++++++-- .../circuit-types/src/tx_effect.test.ts | 2 +- yarn-project/circuit-types/src/tx_effect.ts | 27 ++++++-- yarn-project/circuits.js/src/constants.gen.ts | 4 -- .../private_call_stack_item.test.ts.snap | 4 +- ...private_circuit_public_inputs.test.ts.snap | 4 +- .../public_call_stack_item.test.ts.snap | 8 +-- .../public_circuit_public_inputs.test.ts.snap | 4 +- .../kernel/private_accumulated_data.ts | 15 ----- .../structs/kernel/public_accumulated_data.ts | 18 ----- .../structs/private_circuit_public_inputs.ts | 20 ------ .../structs/public_circuit_public_inputs.ts | 9 --- .../circuits.js/src/tests/factories.ts | 5 -- .../src/type_conversion.ts | 11 --- .../simulator/src/avm/journal/journal.ts | 9 --- .../src/client/client_execution_context.ts | 4 +- .../src/client/private_execution.test.ts | 25 ++----- yarn-project/simulator/src/mocks/fixtures.ts | 1 - .../src/public/abstract_phase_manager.ts | 1 - .../simulator/src/public/execution.ts | 4 -- yarn-project/simulator/src/public/executor.ts | 3 - .../simulator/src/public/index.test.ts | 5 +- 65 files changed, 381 insertions(+), 443 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp index badf02f827f..caa72df3834 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp @@ -116,7 +116,7 @@ const size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + - (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 2 + HEADER_LENGTH + TX_CONTEXT_LENGTH; + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; const size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + @@ -124,7 +124,7 @@ const size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + - 1 + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; const size_t PRIVATE_CALL_STACK_ITEM_LENGTH = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; @@ -149,7 +149,7 @@ const size_t PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + - (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + 2 + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); const size_t PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + @@ -157,7 +157,7 @@ const size_t PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = const size_t PUBLIC_ACCUMULATED_DATA_LENGTH = (MAX_NEW_NOTE_HASHES_PER_TX * NOTE_HASH_LENGTH) + (MAX_NEW_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * 1) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + - (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + 2 + + (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + GAS_LENGTH; const size_t PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 866beb88514..cb991f7b17d 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -148,7 +148,7 @@ library Constants { + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) - + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 2 + HEADER_LENGTH + TX_CONTEXT_LENGTH; + + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) @@ -157,7 +157,7 @@ library Constants { + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 - + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 1 + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH /* revert_code */ + 1 + 2 * GAS_LENGTH /* transaction_fee */ + 1; uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; @@ -186,7 +186,7 @@ library Constants { + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) - + 2 + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH @@ -196,7 +196,7 @@ library Constants { ) + (MAX_NEW_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * 1) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) - + 2 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + GAS_LENGTH; uint256 internal constant PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 7b47ffde25a..3168976f28f 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -51,6 +51,9 @@ library Errors { error Registry__RollupNotRegistered(address rollup); // 0xa1fee4cf error Registry__RollupAlreadyRegistered(address rollup); // 0x3c34eabf + //TxsDecoder + error TxsDecoder__InvalidLogsLength(uint256 expected, uint256 actual); // 0x829ca981 + // HeaderLib error HeaderLib__InvalidHeaderSize(uint256 expected, uint256 actual); // 0xf3ccb247 diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 9f3a29bc495..3fd6fdb4077 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.18; // Libraries +import {Errors} from "../Errors.sol"; import {Constants} from "../ConstantsGen.sol"; import {Hash} from "../Hash.sol"; @@ -53,6 +54,8 @@ library TxsDecoder { uint256 nullifier; uint256 l2ToL1Msgs; uint256 publicData; + uint256 encryptedLogsLength; + uint256 unencryptedLogsLength; } struct Counts { @@ -66,6 +69,9 @@ library TxsDecoder { struct ConsumablesVars { bytes32[] baseLeaves; bytes baseLeaf; + uint256 kernelNoteEncryptedLogsLength; + uint256 kernelEncryptedLogsLength; + uint256 kernelUnencryptedLogsLength; bytes32 noteEncryptedLogsHash; bytes32 encryptedLogsHash; bytes32 unencryptedLogsHash; @@ -148,9 +154,38 @@ library TxsDecoder { * Compute encrypted and unencrypted logs hashes corresponding to the current leaf. * Note: will advance offsets by the number of bytes processed. */ - (vars.noteEncryptedLogsHash, offset) = computeKernelLogsHash(offset, _body, true); - (vars.encryptedLogsHash, offset) = computeKernelLogsHash(offset, _body, false); - (vars.unencryptedLogsHash, offset) = computeKernelLogsHash(offset, _body, false); + offsets.encryptedLogsLength = offset; + offset += 0x20; + offsets.unencryptedLogsLength = offset; + offset += 0x20; + + (vars.noteEncryptedLogsHash, offset, vars.kernelNoteEncryptedLogsLength) = + computeKernelLogsHash(offset, _body, true); + (vars.encryptedLogsHash, offset, vars.kernelEncryptedLogsLength) = + computeKernelLogsHash(offset, _body, false); + (vars.unencryptedLogsHash, offset, vars.kernelUnencryptedLogsLength) = + computeKernelLogsHash(offset, _body, false); + + // We throw to ensure that the byte len we charge for DA gas in the kernels matches the actual chargable log byte len + // Without this check, the user may provide the kernels with a lower log len than reality + if ( + uint256(bytes32(slice(_body, offsets.encryptedLogsLength, 0x20))) + != vars.kernelNoteEncryptedLogsLength + vars.kernelEncryptedLogsLength + ) { + revert Errors.TxsDecoder__InvalidLogsLength( + uint256(bytes32(slice(_body, offsets.encryptedLogsLength, 0x20))), + vars.kernelNoteEncryptedLogsLength + vars.kernelEncryptedLogsLength + ); + } + if ( + uint256(bytes32(slice(_body, offsets.unencryptedLogsLength, 0x20))) + != vars.kernelUnencryptedLogsLength + ) { + revert Errors.TxsDecoder__InvalidLogsLength( + uint256(bytes32(slice(_body, offsets.unencryptedLogsLength, 0x20))), + vars.kernelUnencryptedLogsLength + ); + } // Insertions are split into multiple `bytes.concat` to work around stack too deep. vars.baseLeaf = bytes.concat( @@ -185,6 +220,10 @@ library TxsDecoder { Constants.PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP ) ), + bytes.concat( + slice(_body, offsets.encryptedLogsLength, 0x20), + slice(_body, offsets.unencryptedLogsLength, 0x20) + ), bytes.concat(vars.noteEncryptedLogsHash, vars.encryptedLogsHash, vars.unencryptedLogsHash) ); @@ -194,7 +233,7 @@ library TxsDecoder { // We pad base leaves with hashes of empty tx effect. for (uint256 i = numTxEffects; i < vars.baseLeaves.length; i++) { // Value taken from tx_effect.test.ts "hash of empty tx effect matches snapshot" test case - vars.baseLeaves[i] = hex"00543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7"; + vars.baseLeaves[i] = hex"009f12fb98ebbf4e5deef4cf51ade63094a795b891880217958b226707c95f43"; } } @@ -207,13 +246,12 @@ library TxsDecoder { * @param _body - The L2 block calldata. * @return The hash of the logs and offset in a block after processing the logs. * @dev We have logs preimages on the input and we need to perform the same hashing process as is done in the app - * circuit (hashing the logs) and in the kernel circuit (accumulating the logs hashes). In each iteration of - * kernel, the kernel computes a hash of the previous iteration's logs hash (the hash in the previous kernel's - * public inputs) and the current iteration private circuit public inputs logs hash. + * circuit (hashing the logs) and in the kernel circuit (accumulating the logs hashes). The tail kernel + * circuit flat hashes all the app log hashes. * * E.g. for resulting logs hash of a kernel with 3 iterations would be computed as: * - * kernelPublicInputsLogsHash = sha256(sha256(sha256(I1_LOGS), sha256(I2_LOGS)), sha256(I3_LOGS)) + * kernelPublicInputsLogsHash = sha256((sha256(I1_LOGS), sha256(I2_LOGS)), sha256(I3_LOGS)) * * where I1_LOGS, I2_LOGS and I3_LOGS are logs emitted in the first, second and third function call. * @@ -229,6 +267,10 @@ library TxsDecoder { * I1_LOGS_LEN (i) is the length of the logs in the first iteration. * I1_LOGS are all the logs emitted in the first iteration. * I2_LOGS_LEN (j) ... + * @dev The circuit outputs a total logs len based on the byte length that the user pays DA gas for. + * In terms of the encoding above, this is the raw log length (i, j, or k) + 4 for each log. + * For the example above, kernelLogsLength = (i + 4) + (j + 4) + (k + 4). Since we already track + * the total remainingLogsLength, we just remove the bytes holding function logs length. * * @dev Link to a relevant discussion: * https://discourse.aztec.network/t/proposal-forcing-the-sequencer-to-actually-submit-data-to-l1/426/9 @@ -236,10 +278,11 @@ library TxsDecoder { function computeKernelLogsHash(uint256 _offsetInBlock, bytes calldata _body, bool noteLogs) internal pure - returns (bytes32, uint256) + returns (bytes32, uint256, uint256) { uint256 offset = _offsetInBlock; uint256 remainingLogsLength = read4(_body, offset); + uint256 kernelLogsLength = remainingLogsLength; offset += 0x4; bytes memory flattenedLogHashes; // The hash input @@ -253,6 +296,8 @@ library TxsDecoder { // Decrease remaining logs length by this privateCircuitPublicInputsLogs's length (len(I?_LOGS)) and 4 bytes for I?_LOGS_LEN remainingLogsLength -= (privateCircuitPublicInputLogsLength + 0x4); + kernelLogsLength -= 0x4; + while (privateCircuitPublicInputLogsLength > 0) { uint256 singleCallLogsLength = read4(_body, offset); offset += 0x4; @@ -268,7 +313,7 @@ library TxsDecoder { // Not having a 0 value hash for empty logs causes issues with empty txs used for padding. if (flattenedLogHashes.length == 0) { - return (0, offset); + return (0, offset, 0); } // padded to MAX_LOGS * 32 bytes @@ -284,7 +329,7 @@ library TxsDecoder { bytes32 kernelPublicInputsLogsHash = Hash.sha256ToField(flattenedLogHashes); - return (kernelPublicInputsLogsHash, offset); + return (kernelPublicInputsLogsHash, offset, kernelLogsLength); } /** diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index 74ae5449f31..c13673936e2 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -174,9 +174,11 @@ contract DecodersTest is DecoderBase { bytes memory iterationLogsLength = hex"00000000"; // 4 empty bytes indicating that length of this iteration's logs is 0 bytes memory encodedLogs = abi.encodePacked(kernelLogsLength, iterationLogsLength); - (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); + (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = + txsHelper.computeKernelLogsHash(encodedLogs); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); + assertEq(logsLength, 0, "Incorrect logs length"); assertEq(logsHash, bytes32(0), "Incorrect logs hash"); } @@ -190,7 +192,8 @@ contract DecodersTest is DecoderBase { // Note: 00000004 is the length of 1 log within function logs bytes memory encodedLogs = abi.encodePacked(hex"0000000c00000008", hex"00000004", firstFunctionCallLogs); - (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); + (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = + txsHelper.computeKernelLogsHash(encodedLogs); bytes32 privateCircuitPublicInputsLogsHashFirstCall = Hash.sha256ToField(firstFunctionCallLogs); @@ -202,6 +205,8 @@ contract DecodersTest is DecoderBase { ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); + // We take 8 as the user does not pay for the gas of the overall len (hex"0000002400000008") + assertEq(logsLength, encodedLogs.length - 8, "Incorrect logs length"); assertEq(logsHash, referenceLogsHash, "Incorrect logs hash"); } @@ -222,7 +227,8 @@ contract DecodersTest is DecoderBase { hex"00000010", secondFunctionCallLogs ); - (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); + (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = + txsHelper.computeKernelLogsHash(encodedLogs); bytes32 referenceLogsHashFromIteration1 = Hash.sha256ToField(firstFunctionCallLogs); @@ -238,6 +244,8 @@ contract DecodersTest is DecoderBase { ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); + // We take 12 as the user does not pay for the gas of the function logs len bytes (hex"00000014") or overall len (hex"0000002400000008") + assertEq(logsLength, encodedLogs.length - 12, "Incorrect logs length"); assertEq(logsHash, referenceLogsHashFromIteration2, "Incorrect logs hash"); } @@ -263,7 +271,8 @@ contract DecodersTest is DecoderBase { hex"00000010", thirdFunctionCallLogs ); - (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); + (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = + txsHelper.computeKernelLogsHash(encodedLogs); bytes32 referenceLogsHashFromIteration1 = Hash.sha256ToField(firstFunctionCallLogs); @@ -281,6 +290,9 @@ contract DecodersTest is DecoderBase { ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); + // We take 16 as the user does not pay for the gas of the function logs len bytes (hex"00000014"), + // empty logs len bytes (hex"00000000") or overall len (hex"0000002400000008") + assertEq(logsLength, encodedLogs.length - 16, "Incorrect logs length"); assertEq(logsHash, referenceLogsHashFromIteration3, "Incorrect logs hash"); } diff --git a/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol b/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol index e4c7a6a1a96..3c6714b1f57 100644 --- a/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol +++ b/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol @@ -13,7 +13,7 @@ contract TxsDecoderHelper { function computeKernelLogsHash(bytes calldata _kernelLogs) external pure - returns (bytes32, uint256) + returns (bytes32, uint256, uint256) { return TxsDecoder.computeKernelLogsHash(0, _kernelLogs, false); } diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index e7e90d6eb2a..aacfd5c955c 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -8,23 +8,23 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x28db6a7d7f6d68e8eae12643769246709897c59c72fc94b5b6ce00655b245e42", + "archive": "0x12a6236f076e51298ca7c5c4d0c9898239c5f829e1f2673a18a922d5ee50a4fd", "body": "0x00000000", - "txsEffectsHash": "0x00f6922770c8d944eb7b03abaad695fa06ad1c395d3fbe216dfb508691d16a2f", + "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c3", "txTreeHeight": 1, - "txsEffectsHash": "0x00f6922770c8d944eb7b03abaad695fa06ad1c395d3fbe216dfb508691d16a2f" + "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x4fdc8e41d48477a1e7f9b7a5de5dc36546fdd89e", - "feeRecipient": "0x2aa0b5a2607f90e00553c29ce8bf75a8a453bc167be277fdcbe7c0ff284852fd", + "coinbase": "0xf98794b6b717c6c7d6806a8ebb8cb1327144f0c7", + "feeRecipient": "0x1eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a4", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -55,8 +55,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf00000001000000000000000000000000000000000000000000000000000000000000000100f6922770c8d944eb7b03abaad695fa06ad1c395d3fbe216dfb508691d16a2f00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004fdc8e41d48477a1e7f9b7a5de5dc36546fdd89e2aa0b5a2607f90e00553c29ce8bf75a8a453bc167be277fdcbe7c0ff284852fd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00f30a1da4a60be604e620ab3c0e4f960d0d47b647cde7c460e64a6c7e667e33", + "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000f98794b6b717c6c7d6806a8ebb8cb1327144f0c71eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x0081ff51b8e6caf79d8d0616b407a5cf7c3d939bf568a94100d6e7b5dbaf2cff", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index ddaeffe7c95..c2c09d34ff9 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,23 +8,23 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x133f7fd0f4773b3d206b02f672a0fdd1e1a1ea9e562063c758ce4ddf6d92d079", + "archive": "0x19d445841fdaa62cfa9752aae068322e538729535b9fc4e195fd4e7b010f2e91", "body": "0x00000000", - "txsEffectsHash": "0x00f6922770c8d944eb7b03abaad695fa06ad1c395d3fbe216dfb508691d16a2f", + "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c3", "txTreeHeight": 1, - "txsEffectsHash": "0x00f6922770c8d944eb7b03abaad695fa06ad1c395d3fbe216dfb508691d16a2f" + "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1715590033, + "timestamp": 1715940661, "version": 1, - "coinbase": "0x4fdc8e41d48477a1e7f9b7a5de5dc36546fdd89e", - "feeRecipient": "0x2aa0b5a2607f90e00553c29ce8bf75a8a453bc167be277fdcbe7c0ff284852fd", + "coinbase": "0xf98794b6b717c6c7d6806a8ebb8cb1327144f0c7", + "feeRecipient": "0x1eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a4", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -32,7 +32,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x28db6a7d7f6d68e8eae12643769246709897c59c72fc94b5b6ce00655b245e42" + "root": "0x12a6236f076e51298ca7c5c4d0c9898239c5f829e1f2673a18a922d5ee50a4fd" }, "stateReference": { "l1ToL2MessageTree": { @@ -55,8 +55,8 @@ } } }, - "header": "0x28db6a7d7f6d68e8eae12643769246709897c59c72fc94b5b6ce00655b245e4200000002000000000000000000000000000000000000000000000000000000000000000100f6922770c8d944eb7b03abaad695fa06ad1c395d3fbe216dfb508691d16a2f00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006641d3914fdc8e41d48477a1e7f9b7a5de5dc36546fdd89e2aa0b5a2607f90e00553c29ce8bf75a8a453bc167be277fdcbe7c0ff284852fd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00dacc45bae55cf4217a7a66cd1ff9c2fb65726a10c8d4835a8a7c7a9ac0f18c", + "header": "0x12a6236f076e51298ca7c5c4d0c9898239c5f829e1f2673a18a922d5ee50a4fd000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000066472d35f98794b6b717c6c7d6806a8ebb8cb1327144f0c71eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x008568ca7fc6464f9cb6588e7215e14e0eb49c96dd210a849a0d3369d185c261", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index a45b53a9218..b2d7765f5a4 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,23 +34,23 @@ ] }, "block": { - "archive": "0x14db96bbda96c21937acb03438fd47f6b4e3dcc43e3bae7eb42a510b2ff79336", - "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e0200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341200000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f0000000000000000000000000000000000000000000000000000000000000569000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be0200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c12000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f0000000000000000000000000000000000000000000000000000000000000629000000000000000000000000", - "txsEffectsHash": "0x002ee1d8e2394274380df0be51690be06b2b63ef311e78b40b1265c0f99a9d30", + "archive": "0x1da7e3994972b8e4d8f2dffeb084976254aebcca1a429e576eea74eae6ae20c4", + "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e0200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341200000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f000000000000000000000000000000000000000000000000000000000000056900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be0200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c12000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f000000000000000000000000000000000000000000000000000000000000062900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0x0048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb6", "txTreeHeight": 2, - "txsEffectsHash": "0x002ee1d8e2394274380df0be51690be06b2b63ef311e78b40b1265c0f99a9d30" + "txsEffectsHash": "0x0048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x070d0edcf7534bcdc79c52d27ac37b054cdd4ead", - "feeRecipient": "0x1d71544bd0344426b834affcd4f0ee7b9a91de7f7338543704d18dada2f22cda", + "coinbase": "0x5e42ecbaebd6cd5f6dd356f51c0fa991be9d3084", + "feeRecipient": "0x1387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf269112", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -81,8 +81,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000002002ee1d8e2394274380df0be51690be06b2b63ef311e78b40b1265c0f99a9d3000089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000070d0edcf7534bcdc79c52d27ac37b054cdd4ead1d71544bd0344426b834affcd4f0ee7b9a91de7f7338543704d18dada2f22cda00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00e929996ec411efaf772fb5f834a8c1cdd7acff15860838d97d4a307233f3e9", + "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf0000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000005e42ecbaebd6cd5f6dd356f51c0fa991be9d30841387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf26911200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00ef2466dabd158a72ec68683a56286b12b50ecf9aca3c0849414a7fa63f7a17", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index bb57755621f..5bc3fb47126 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,23 +34,23 @@ ] }, "block": { - "archive": "0x04188e450ea5264545b2711cbe727a9fdc10eaff88627c4a5d609e31f444c799", - "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e0200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f0000000000000000000000000000000000000000000000000000000000000669000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be0200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481200000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c12000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501200000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f0000000000000000000000000000000000000000000000000000000000000729000000000000000000000000", - "txsEffectsHash": "0x001b663907c766f24a512f0fa2ec4603eb4fc404fc4e0d384697ef3b64214a25", + "archive": "0x250babc63de7989f6407cfa75b31762bbecdb77b1a2d6f3a8ad2ccfd348e60c6", + "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e0200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f000000000000000000000000000000000000000000000000000000000000066900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be0200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481200000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c12000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501200000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f000000000000000000000000000000000000000000000000000000000000072900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0x00f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b1", "decodedHeader": { "contentCommitment": { "inHash": "0x00212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb891937", "outHash": "0x00a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd", "txTreeHeight": 2, - "txsEffectsHash": "0x001b663907c766f24a512f0fa2ec4603eb4fc404fc4e0d384697ef3b64214a25" + "txsEffectsHash": "0x00f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b1" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1715589990, + "timestamp": 1715940580, "version": 1, - "coinbase": "0x070d0edcf7534bcdc79c52d27ac37b054cdd4ead", - "feeRecipient": "0x1d71544bd0344426b834affcd4f0ee7b9a91de7f7338543704d18dada2f22cda", + "coinbase": "0x5e42ecbaebd6cd5f6dd356f51c0fa991be9d3084", + "feeRecipient": "0x1387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf269112", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -58,7 +58,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x14db96bbda96c21937acb03438fd47f6b4e3dcc43e3bae7eb42a510b2ff79336" + "root": "0x1da7e3994972b8e4d8f2dffeb084976254aebcca1a429e576eea74eae6ae20c4" }, "stateReference": { "l1ToL2MessageTree": { @@ -81,8 +81,8 @@ } } }, - "header": "0x14db96bbda96c21937acb03438fd47f6b4e3dcc43e3bae7eb42a510b2ff79336000000020000000000000000000000000000000000000000000000000000000000000002001b663907c766f24a512f0fa2ec4603eb4fc404fc4e0d384697ef3b64214a2500212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006641d366070d0edcf7534bcdc79c52d27ac37b054cdd4ead1d71544bd0344426b834affcd4f0ee7b9a91de7f7338543704d18dada2f22cda00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00c8e7dc62f509a09c1d4c39def1725ac8fd4303197c7bd591951270b2a0df3b", + "header": "0x1da7e3994972b8e4d8f2dffeb084976254aebcca1a429e576eea74eae6ae20c400000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000066472ce45e42ecbaebd6cd5f6dd356f51c0fa991be9d30841387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf26911200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00481dfc48bdb367e200298beada39daf0837e3d33e81257e92e65d48a5e0a81", "numTxs": 4 } } \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index abc74607c84..869000fac77 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -68,8 +68,6 @@ struct PrivateContext { note_encrypted_logs_hashes: BoundedVec, encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, last_nullifier_key_validation_request: Option, } @@ -131,8 +129,6 @@ impl PrivateContext { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, last_nullifier_key_validation_request: Option::none() } } @@ -176,8 +172,6 @@ impl PrivateContext { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage, encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, historical_header: self.historical_header, tx_context: self.inputs.tx_context } @@ -266,7 +260,6 @@ impl PrivateContext { let len = 44 + log_slice.len().to_field(); let side_effect = LogHash { value: log_hash, counter, length: len }; self.unencrypted_logs_hashes.push(side_effect); - self.unencrypted_log_preimages_length += len; // call oracle let _void = emit_unencrypted_log_private_internal(contract_address, event_selector, log, counter); } @@ -287,7 +280,6 @@ impl PrivateContext { let len = 44 + N * 32; let side_effect = LogHash { value: log_hash, counter, length: len }; self.unencrypted_logs_hashes.push(side_effect); - self.unencrypted_log_preimages_length += len; } // TODO(1139): Convert to generic input once we encrypt inside the circuit pub fn emit_encrypted_log( @@ -314,7 +306,6 @@ impl PrivateContext { let log_hash = compute_encrypted_log_hash(encrypted_log); let side_effect = LogHash { value: log_hash, counter, length: len }; self.encrypted_logs_hashes.push(side_effect); - self.encrypted_log_preimages_length += len; } pub fn emit_note_encrypted_log( @@ -351,7 +342,6 @@ impl PrivateContext { let log_hash = compute_encrypted_log_hash(encrypted_log); let side_effect = NoteLogHash { value: log_hash, counter, length: len, note_hash_counter }; self.note_encrypted_logs_hashes.push(side_effect); - self.encrypted_log_preimages_length += len; } pub fn call_private_function( @@ -671,8 +661,6 @@ impl Empty for PrivateContext { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, last_nullifier_key_validation_request: Option::none(), } } diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index 1df47065f4a..c9c57643b3e 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -42,7 +42,6 @@ struct PublicContext { new_l2_to_l1_msgs: BoundedVec, unencrypted_logs_hashes: BoundedVec, - unencrypted_log_preimages_length: Field, // Header of a block whose state is used during public execution. Set by sequencer to be a header of a block // previous to the one in which the tx is included. @@ -66,7 +65,6 @@ impl PublicContext { new_nullifiers: BoundedVec::new(), new_l2_to_l1_msgs: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - unencrypted_log_preimages_length: 0, historical_header: inputs.historical_header, prover_address: AztecAddress::zero() } @@ -154,7 +152,6 @@ impl PublicContext { start_side_effect_counter: self.inputs.start_side_effect_counter, end_side_effect_counter: self.side_effect_counter, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, historical_header: self.inputs.historical_header, global_variables: self.inputs.public_global_variables, prover_address: self.prover_address, @@ -285,7 +282,6 @@ impl PublicContextInterface for PublicContext { let len = 44 + log_slice.len().to_field(); let side_effect = LogHash { value: log_hash, counter: self.next_counter(), length: len }; self.unencrypted_logs_hashes.push(side_effect); - self.unencrypted_log_preimages_length += len; // Call oracle to broadcast log let _void = emit_unencrypted_log_oracle(contract_address, event_selector, log, side_effect.counter); } @@ -342,7 +338,6 @@ impl Empty for PublicContext { new_nullifiers: BoundedVec::new(), new_l2_to_l1_msgs: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - unencrypted_log_preimages_length: 0, historical_header: Header::empty(), prover_address: AztecAddress::zero(), } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr b/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr index 39b5a52e859..03ec1ebd9e9 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr @@ -96,7 +96,6 @@ pub fn parse_public_call_stack_item_from_oracle(fields: [Field; ENQUEUE_PUBLIC_F start_side_effect_counter: 0, end_side_effect_counter: 0, unencrypted_logs_hashes: [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_CALL], - unencrypted_log_preimages_length: 0, historical_header: Header::empty(), global_variables: GlobalVariables::empty(), prover_address: AztecAddress::zero(), diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr index c5f8835c4bc..da0ce3470db 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr @@ -221,8 +221,6 @@ impl KernelCircuitPublicInputsComposer { self.public_inputs.end.unencrypted_logs_hashes = array_to_bounded_vec(self.sorted_unencrypted_log_hashes); // TODO: Sort all the side effects below. self.public_inputs.end.new_l2_to_l1_msgs = array_to_bounded_vec(accumulated_data.new_l2_to_l1_msgs); - self.public_inputs.end.encrypted_log_preimages_length = accumulated_data.encrypted_log_preimages_length; - self.public_inputs.end.unencrypted_log_preimages_length = accumulated_data.unencrypted_log_preimages_length; } fn propagate_sorted_public_call_requests(&mut self) { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr index 32e9219529e..4792132f3b1 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr @@ -69,8 +69,6 @@ impl PrivateKernelCircuitPublicInputsComposer { public_inputs.end.note_encrypted_logs_hashes = array_to_bounded_vec(start.note_encrypted_logs_hashes); public_inputs.end.encrypted_logs_hashes = array_to_bounded_vec(start.encrypted_logs_hashes); public_inputs.end.unencrypted_logs_hashes = array_to_bounded_vec(start.unencrypted_logs_hashes); - public_inputs.end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; - public_inputs.end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; public_inputs.end.private_call_stack = array_to_bounded_vec(start.private_call_stack); let _call_request = public_inputs.end.private_call_stack.pop(); public_inputs.end.public_call_stack = array_to_bounded_vec(start.public_call_stack); @@ -202,10 +200,6 @@ impl PrivateKernelCircuitPublicInputsComposer { self.public_inputs.end.note_encrypted_logs_hashes.push(note_logs[i]); } } - - // Add log preimages lengths from current iteration to accumulated lengths. - self.public_inputs.end.encrypted_log_preimages_length += source.private_call_public_inputs.encrypted_log_preimages_length; - self.public_inputs.end.unencrypted_log_preimages_length += source.private_call_public_inputs.unencrypted_log_preimages_length; } unconstrained fn match_log_to_note(self, note_log: NoteLogHash) -> u64 { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index c6ae0c8d193..78dc5415db3 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -60,7 +60,7 @@ mod tests { address::{AztecAddress, EthAddress}, constants::MAX_NEW_NOTE_HASHES_PER_CALL, grumpkin_point::GrumpkinPoint, messaging::l2_to_l1_message::L2ToL1Message, tests::private_call_data_builder::PrivateCallDataBuilder, transaction::tx_request::TxRequest, - utils::arrays::array_length + utils::arrays::{array_length, array_eq} }; struct PrivateKernelInitInputsBuilder { @@ -113,23 +113,30 @@ mod tests { unencrypted_log_preimages_length[1] ); + let expected_unencrypted_logs = [ + builder.private_call.public_inputs.unencrypted_logs_hashes.storage[0], builder.private_call.public_inputs.unencrypted_logs_hashes.storage[1] + ]; + let expected_encrypted_logs = [ + builder.private_call.public_inputs.encrypted_logs_hashes.storage[0], builder.private_call.public_inputs.encrypted_logs_hashes.storage[1] + ]; + let public_inputs = builder.execute(); // Check the first nullifier is hash of the signed tx request let tx_hash = builder.tx_request.hash(); assert_eq(public_inputs.end.new_nullifiers[0].value(), tx_hash); - - // Log preimages length should increase by `(un)encrypted_log_preimages_length` from private input - assert_eq( - public_inputs.end.encrypted_log_preimages_length, encrypted_log_preimages_length.reduce(|a, b| a + b) + assert( + array_eq( + public_inputs.end.encrypted_logs_hashes, + expected_encrypted_logs + ) ); - assert_eq( - public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length.reduce(|a, b| a + b) + assert( + array_eq( + public_inputs.end.unencrypted_logs_hashes, + expected_unencrypted_logs + ) ); - assert_eq(public_inputs.end.encrypted_logs_hashes[0].value, encrypted_logs_hashes[0]); - assert_eq(public_inputs.end.unencrypted_logs_hashes[0].value, unencrypted_logs_hashes[0]); - assert_eq(public_inputs.end.encrypted_logs_hashes[1].value, encrypted_logs_hashes[1]); - assert_eq(public_inputs.end.unencrypted_logs_hashes[1].value, unencrypted_logs_hashes[1]); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index 26018af0064..f3d599ba6e1 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -58,7 +58,7 @@ mod tests { read_request::ReadRequest, log_hash::{LogHash, NoteLogHash} }, address::{AztecAddress, EthAddress}, constants::MAX_NEW_NOTE_HASHES_PER_CALL, - messaging::l2_to_l1_message::L2ToL1Message, utils::{arrays::array_length}, + messaging::l2_to_l1_message::L2ToL1Message, utils::arrays::{array_length, array_eq}, tests::{private_call_data_builder::PrivateCallDataBuilder, fixture_builder::FixtureBuilder} }; @@ -230,19 +230,27 @@ mod tests { prev_unencrypted_log_preimages_length ); + let expected_unencrypted_logs = [ + builder.previous_kernel.unencrypted_logs_hashes.storage[0], builder.private_call.public_inputs.unencrypted_logs_hashes.storage[0] + ]; + let expected_encrypted_logs = [ + builder.previous_kernel.encrypted_logs_hashes.storage[0], builder.private_call.public_inputs.encrypted_logs_hashes.storage[0] + ]; + let public_inputs = builder.execute(); - assert_eq( - public_inputs.end.encrypted_log_preimages_length, encrypted_log_preimages_length + prev_encrypted_log_preimages_length + assert( + array_eq( + public_inputs.end.encrypted_logs_hashes, + expected_encrypted_logs + ) ); - assert_eq( - public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length + assert( + array_eq( + public_inputs.end.unencrypted_logs_hashes, + expected_unencrypted_logs + ) ); - - assert_eq(public_inputs.end.encrypted_logs_hashes[0].value, prev_encrypted_logs_hash); - assert_eq(public_inputs.end.unencrypted_logs_hashes[0].value, prev_unencrypted_logs_hash); - assert_eq(public_inputs.end.encrypted_logs_hashes[1].value, encrypted_logs_hash); - assert_eq(public_inputs.end.unencrypted_logs_hashes[1].value, unencrypted_logs_hash); } #[test(should_fail_with = "Could not find note hash linked to note log.")] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr index 99b827e9be9..db96da72dbb 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr @@ -58,7 +58,7 @@ impl PrivateKernelResetCircuitPrivateInputs { master_nullifier_secret_keys: self.hints.master_nullifier_secret_keys }.validate(); - let removed_logs_len = verify_squashed_transient_note_hashes_and_nullifiers( + verify_squashed_transient_note_hashes_and_nullifiers( previous_public_inputs.end.new_note_hashes, previous_public_inputs.end.new_nullifiers, previous_public_inputs.end.note_encrypted_logs_hashes, @@ -73,7 +73,6 @@ impl PrivateKernelResetCircuitPrivateInputs { previous_public_inputs.end.new_note_hashes = self.outputs.note_hashes; previous_public_inputs.end.new_nullifiers = self.outputs.nullifiers; previous_public_inputs.end.note_encrypted_logs_hashes = self.outputs.note_encrypted_log_hashes; - previous_public_inputs.end.encrypted_log_preimages_length -= removed_logs_len; previous_public_inputs } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index 3fd1370fcf1..a50185244a1 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -361,7 +361,6 @@ mod tests { 0 ) ); - assert_eq(public_inputs.end.encrypted_log_preimages_length as u32, revertible_logs_len); assert_eq( public_inputs.end_non_revertible.gas_used, Gas::new( (3 * DA_BYTES_PER_FIELD + non_revertible_logs_len) * DA_GAS_PER_BYTE, @@ -369,9 +368,6 @@ mod tests { ) + Gas::tx_overhead() ); - assert_eq( - public_inputs.end_non_revertible.encrypted_log_preimages_length as u32, non_revertible_logs_len - ); } #[test(should_fail_with="Non empty note hash read requests")] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index f3d0717b994..133b4e062eb 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr @@ -94,10 +94,8 @@ pub fn initialize_emitted_end_values( circuit_outputs.end.new_l2_to_l1_msgs = array_to_bounded_vec(start.new_l2_to_l1_msgs); circuit_outputs.end.public_data_update_requests = array_to_bounded_vec(start.public_data_update_requests); circuit_outputs.end.unencrypted_logs_hashes = array_to_bounded_vec(start.unencrypted_logs_hashes); - circuit_outputs.end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; circuit_outputs.end.note_encrypted_logs_hashes = array_to_bounded_vec(start.note_encrypted_logs_hashes); circuit_outputs.end.encrypted_logs_hashes = array_to_bounded_vec(start.encrypted_logs_hashes); - circuit_outputs.end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; } let start_non_revertible = previous_kernel.public_inputs.end_non_revertible; @@ -106,10 +104,8 @@ pub fn initialize_emitted_end_values( circuit_outputs.end_non_revertible.new_l2_to_l1_msgs = array_to_bounded_vec(start_non_revertible.new_l2_to_l1_msgs); circuit_outputs.end_non_revertible.public_data_update_requests = array_to_bounded_vec(start_non_revertible.public_data_update_requests); circuit_outputs.end_non_revertible.unencrypted_logs_hashes = array_to_bounded_vec(start_non_revertible.unencrypted_logs_hashes); - circuit_outputs.end_non_revertible.unencrypted_log_preimages_length = start_non_revertible.unencrypted_log_preimages_length; circuit_outputs.end_non_revertible.note_encrypted_logs_hashes = array_to_bounded_vec(start_non_revertible.note_encrypted_logs_hashes); circuit_outputs.end_non_revertible.encrypted_logs_hashes = array_to_bounded_vec(start_non_revertible.encrypted_logs_hashes); - circuit_outputs.end_non_revertible.encrypted_log_preimages_length = start_non_revertible.encrypted_log_preimages_length; let start = previous_kernel.public_inputs.validation_requests; circuit_outputs.validation_requests.max_block_number = start.for_rollup.max_block_number; @@ -162,9 +158,8 @@ fn perform_static_call_checks(public_call: PublicCallData) { let new_l2_to_l1_msgs_length = array_length(public_inputs.new_l2_to_l1_msgs); assert(new_l2_to_l1_msgs_length == 0, "new_l2_to_l1_msgs must be empty for static calls"); - assert( - public_inputs.unencrypted_log_preimages_length == 0, "No unencrypted logs are allowed for static calls" - ); + let new_unencrypted_logs_length = array_length(public_inputs.unencrypted_logs_hashes); + assert(new_unencrypted_logs_length == 0, "No unencrypted logs are allowed for static calls"); } } @@ -580,7 +575,6 @@ pub fn propagate_new_unencrypted_logs(public_call: PublicCallData, public_inputs } } public_inputs.end.unencrypted_logs_hashes.extend_from_bounded_vec(new_logs_to_insert); - public_inputs.end.unencrypted_log_preimages_length += public_call.call_stack_item.public_inputs.unencrypted_log_preimages_length; } pub fn propagate_new_unencrypted_logs_non_revertible( @@ -599,7 +593,6 @@ pub fn propagate_new_unencrypted_logs_non_revertible( } } public_inputs.end_non_revertible.unencrypted_logs_hashes.extend_from_bounded_vec(new_logs_to_insert); - public_inputs.end_non_revertible.unencrypted_log_preimages_length += public_call.call_stack_item.public_inputs.unencrypted_log_preimages_length; } /** diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr index 1e85632b895..4ef4d20284c 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr @@ -320,15 +320,25 @@ mod tests { prev_unencrypted_log_preimages_length ); + let expected_unencrypted_logs = [ + builder.previous_kernel.unencrypted_logs_hashes.storage[0], builder.public_call.public_inputs.unencrypted_logs_hashes.storage[0] + ]; + let expected_encrypted_logs = [builder.previous_kernel.encrypted_logs_hashes.storage[0]]; + let public_inputs = builder.execute(); - assert_eq(public_inputs.end.encrypted_log_preimages_length, prev_encrypted_log_preimages_length); - assert_eq( - public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length + assert( + array_eq( + public_inputs.end.encrypted_logs_hashes, + expected_encrypted_logs + ) + ); + assert( + array_eq( + public_inputs.end.unencrypted_logs_hashes, + expected_unencrypted_logs + ) ); - assert_eq(public_inputs.end.encrypted_logs_hashes[0].value, prev_encrypted_logs_hash); - assert_eq(public_inputs.end.unencrypted_logs_hashes[0].value, prev_unencrypted_logs_hash); - assert_eq(public_inputs.end.unencrypted_logs_hashes[1].value, unencrypted_logs_hash); } #[test(should_fail_with="No contract storage update requests are allowed for static calls")] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr index 9c3f1ba4a98..4dd94c17f6e 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr @@ -436,20 +436,25 @@ mod tests { prev_unencrypted_log_preimages_length ); + let expected_unencrypted_logs = [ + builder.previous_kernel.unencrypted_logs_hashes.storage[0], builder.public_call.public_inputs.unencrypted_logs_hashes.storage[0] + ]; + let expected_encrypted_logs = [builder.previous_kernel.encrypted_logs_hashes.storage[0]]; + let public_inputs = builder.execute(); - assert_eq( - public_inputs.end_non_revertible.encrypted_log_preimages_length, prev_encrypted_log_preimages_length - ); - assert_eq( - public_inputs.end_non_revertible.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length + assert( + array_eq( + public_inputs.end_non_revertible.encrypted_logs_hashes, + expected_encrypted_logs + ) ); - - assert_eq(public_inputs.end_non_revertible.encrypted_logs_hashes[0].value, prev_encrypted_logs_hash); - assert_eq( - public_inputs.end_non_revertible.unencrypted_logs_hashes[0].value, prev_unencrypted_logs_hash + assert( + array_eq( + public_inputs.end_non_revertible.unencrypted_logs_hashes, + expected_unencrypted_logs + ) ); - assert_eq(public_inputs.end_non_revertible.unencrypted_logs_hashes[1].value, unencrypted_logs_hash); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr index af033b1ba8e..f0bfaf0849f 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr @@ -398,19 +398,25 @@ mod tests { prev_unencrypted_log_preimages_length ); + let expected_unencrypted_logs = [ + builder.previous_kernel.unencrypted_logs_hashes.storage[0], builder.public_call.public_inputs.unencrypted_logs_hashes.storage[0] + ]; + let expected_encrypted_logs = [builder.previous_kernel.encrypted_logs_hashes.storage[0]]; + let public_inputs = builder.execute(); - assert_eq( - public_inputs.end_non_revertible.encrypted_log_preimages_length, prev_encrypted_log_preimages_length - ); - assert_eq( - public_inputs.end_non_revertible.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length + assert( + array_eq( + public_inputs.end_non_revertible.encrypted_logs_hashes, + expected_encrypted_logs + ) ); - assert_eq(public_inputs.end_non_revertible.encrypted_logs_hashes[0].value, prev_encrypted_logs_hash); - assert_eq( - public_inputs.end_non_revertible.unencrypted_logs_hashes[0].value, prev_unencrypted_logs_hash + assert( + array_eq( + public_inputs.end_non_revertible.unencrypted_logs_hashes, + expected_unencrypted_logs + ) ); - assert_eq(public_inputs.end_non_revertible.unencrypted_logs_hashes[1].value, unencrypted_logs_hash); } #[test(should_fail_with="Public call cannot be reverted")] diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr index 31ae3dcf3e0..6fd8c6c2fbd 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr @@ -13,7 +13,7 @@ pub fn verify_squashed_transient_note_hashes_and_nullifiers Field { +) { let mut note_hashes_kept = 0; let mut note_hashes_removed = 0; for i in 0..NUM_NOTE_HASHES { @@ -68,7 +68,6 @@ pub fn verify_squashed_transient_note_hashes_and_nullifiers Field { - verify_squashed_transient_note_hashes_and_nullifiers( - self.note_hashes, - self.nullifiers, - self.note_logs, - self.expected_note_hashes, - self.expected_nullifiers, - self.expected_note_logs, - self.transient_nullifier_indexes_for_note_hashes, - self.transient_note_hash_indexes_for_nullifiers, - self.transient_note_hash_indexes_for_logs - ) - } } #[test] @@ -442,15 +424,4 @@ mod tests { builder.verify(); } - - #[test] - fn remove_correct_logs_len() { - let mut builder = TestDataBuilder::default(); - let expected_len_removed = builder.note_logs[0].length; - assert_eq(builder.verify_length(), expected_len_removed); - - let mut builder = TestDataBuilder::default_all_clear(); - let expected_len_removed = builder.note_logs.fold(0, |a, b: NoteLogHash| a + b.length); - assert_eq(builder.verify_length(), expected_len_removed); - } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 17a45be11c3..9a4e8b9715f 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -124,7 +124,7 @@ pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) - ) } -global TX_EFFECTS_HASH_INPUT_FIELDS = 199; +global TX_EFFECTS_HASH_INPUT_FIELDS = 201; // Computes the tx effects hash for a base rollup (a single transaction) // TODO(Alvaro): This is too slow for brillig without the array optimization @@ -142,6 +142,8 @@ pub fn compute_tx_effects_hash( // 2 l2 -> l1 messages -> 2 fields // 32 public data update requests -> 64 fields // 1 contract deployments -> 3 fields + // 1 encrypted logs length --> 1 field | Includes length of note and generic encrypted logs + // 1 unencrypted logs length --> 1 field // 1 note encrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! // 1 encrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! // 1 unencrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! @@ -151,6 +153,8 @@ pub fn compute_tx_effects_hash( let new_nullifiers = combined.new_nullifiers; let new_l2_to_l1_msgs = combined.new_l2_to_l1_msgs; let public_data_update_requests = combined.public_data_update_requests; + let encrypted_logs_length = combined.encrypted_log_preimages_length; + let unencrypted_logs_length = combined.unencrypted_log_preimages_length; let note_encrypted_logs_hash = combined.note_encrypted_logs_hash; let encrypted_logs_hash = combined.encrypted_logs_hash; let unencrypted_logs_hash = combined.unencrypted_logs_hash; @@ -187,6 +191,14 @@ pub fn compute_tx_effects_hash( } offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; + txs_effects_hash_input[offset] = encrypted_logs_length; + + offset += 1; + + txs_effects_hash_input[offset] = unencrypted_logs_length; + + offset += 1; + txs_effects_hash_input[offset] = note_encrypted_logs_hash; offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX; @@ -216,12 +228,14 @@ pub fn compute_tx_effects_hash( fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { // 1 for revert_code // 1 for transaction_fee + // 2 for logs lengths let expected_size = 1 + 1 + MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + MAX_NEW_L2_TO_L1_MSGS_PER_TX + + 2 + NUM_ENCRYPTED_LOGS_HASHES_PER_TX + NUM_ENCRYPTED_LOGS_HASHES_PER_TX + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 1c224a9d35f..4b2eba045ea 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -2,8 +2,8 @@ use crate::{ hash::{compute_tx_logs_hash, compute_tx_note_logs_hash}, abis::{ accumulated_data::public_accumulated_data::PublicAccumulatedData, note_hash::NoteHash, - nullifier::Nullifier, public_data_update_request::PublicDataUpdateRequest, side_effect::SideEffect, - gas::Gas + nullifier::Nullifier, public_data_update_request::PublicDataUpdateRequest, + log_hash::{LogHash, NoteLogHash}, gas::Gas }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, @@ -52,6 +52,12 @@ impl CombinedAccumulatedData { revertible.unencrypted_logs_hashes ) ); + let encrypted_log_preimages_length = non_revertible.encrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length) + + revertible.encrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length) + + non_revertible.note_encrypted_logs_hashes.fold(0, |a, b: NoteLogHash| a + b.length) + + revertible.note_encrypted_logs_hashes.fold(0, |a, b: NoteLogHash| a + b.length); + let unencrypted_log_preimages_length = non_revertible.unencrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length) + + revertible.unencrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length); CombinedAccumulatedData { new_note_hashes: array_merge(non_revertible.new_note_hashes, revertible.new_note_hashes).map(|n: NoteHash| n.value), new_nullifiers: array_merge(non_revertible.new_nullifiers, revertible.new_nullifiers).map(|n: Nullifier| n.value), @@ -62,10 +68,8 @@ impl CombinedAccumulatedData { note_encrypted_logs_hash, encrypted_logs_hash, unencrypted_logs_hash, - encrypted_log_preimages_length: non_revertible.encrypted_log_preimages_length - + revertible.encrypted_log_preimages_length, - unencrypted_log_preimages_length: non_revertible.unencrypted_log_preimages_length - + revertible.unencrypted_log_preimages_length, + encrypted_log_preimages_length, + unencrypted_log_preimages_length, public_data_update_requests: array_merge( non_revertible.public_data_update_requests, revertible.public_data_update_requests diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr index 8d225670ec8..63365b9f5a8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr @@ -21,11 +21,6 @@ struct PrivateAccumulatedData { encrypted_logs_hashes: [LogHash; MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_TX], - // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the - // variable-length data. - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, - private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], } @@ -58,9 +53,6 @@ impl Serialize for PrivateAccumulatedData { fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); } - fields.push(self.encrypted_log_preimages_length); - fields.push(self.unencrypted_log_preimages_length); - for i in 0..MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX { fields.extend_from_array(self.private_call_stack[i].serialize()); } @@ -86,8 +78,6 @@ impl Deserialize for PrivateAccumulatedData { note_encrypted_logs_hashes: reader.read_struct_array(NoteLogHash::deserialize, [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX]), encrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX]), unencrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX]), - encrypted_log_preimages_length: reader.read(), - unencrypted_log_preimages_length: reader.read(), private_call_stack: reader.read_struct_array(CallRequest::deserialize, [CallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX]), public_call_stack: reader.read_struct_array(CallRequest::deserialize, [CallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX]), }; @@ -104,8 +94,6 @@ impl Eq for PrivateAccumulatedData { (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) & (self.unencrypted_logs_hashes == other.unencrypted_logs_hashes) & - (self.encrypted_log_preimages_length == other.encrypted_log_preimages_length) & - (self.unencrypted_log_preimages_length == other.unencrypted_log_preimages_length) & (self.private_call_stack == other.private_call_stack) & (self.public_call_stack == other.public_call_stack) } @@ -120,8 +108,6 @@ impl Empty for PrivateAccumulatedData { note_encrypted_logs_hashes: [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], encrypted_logs_hashes: [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX], - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, private_call_stack: [CallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr index ecf583f00e9..73b88b3385f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr @@ -32,11 +32,6 @@ struct PrivateAccumulatedDataBuilder { encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, - // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the - // variable-length data. - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, - private_call_stack: BoundedVec, public_call_stack: BoundedVec, @@ -51,8 +46,6 @@ impl PrivateAccumulatedDataBuilder { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage, encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, private_call_stack: self.private_call_stack.storage, public_call_stack: self.public_call_stack.storage } @@ -64,6 +57,9 @@ impl PrivateAccumulatedDataBuilder { let encrypted_logs_hash = compute_tx_logs_hash(self.encrypted_logs_hashes.storage); let unencrypted_logs_hash = compute_tx_logs_hash(self.unencrypted_logs_hashes.storage); let gas_used = self.to_metered_gas_used() + Gas::tx_overhead() + teardown_gas; + let encrypted_log_preimages_length = self.encrypted_logs_hashes.storage.fold(0, |a, b: LogHash| a + b.length) + + self.note_encrypted_logs_hashes.storage.fold(0, |a, b: NoteLogHash| a + b.length); + let unencrypted_log_preimages_length = self.unencrypted_logs_hashes.storage.fold(0, |a, b: LogHash| a + b.length); CombinedAccumulatedData { new_note_hashes: self.new_note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash.value), @@ -72,8 +68,8 @@ impl PrivateAccumulatedDataBuilder { note_encrypted_logs_hash, encrypted_logs_hash, unencrypted_logs_hash, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, + encrypted_log_preimages_length, + unencrypted_log_preimages_length, public_data_update_requests: [PublicDataUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], gas_used } @@ -103,11 +99,23 @@ impl PrivateAccumulatedDataBuilder { } } + // note_encrypted_logs_hash_gas + for i in 0..self.note_encrypted_logs_hashes.storage.len() { + let log = self.note_encrypted_logs_hashes.get_unchecked(i); + metered_bytes += log.length as u32; + } + // encrypted_logs_hash_gas - metered_bytes += self.encrypted_log_preimages_length as u32; + for i in 0..self.encrypted_logs_hashes.storage.len() { + let log = self.encrypted_logs_hashes.get_unchecked(i); + metered_bytes += log.length as u32; + } // unencrypted_logs_hash_gas - metered_bytes += self.unencrypted_log_preimages_length as u32; + for i in 0..self.unencrypted_logs_hashes.storage.len() { + let log = self.unencrypted_logs_hashes.get_unchecked(i); + metered_bytes += log.length as u32; + } Gas::new(DA_GAS_PER_BYTE * metered_bytes, 0) } @@ -181,11 +189,9 @@ impl PrivateAccumulatedDataBuilder { let note_encrypted_logs_hash = note_encrypted_logs_hash_private.expose_to_public(); if note_encrypted_logs_hash_private.counter < min_revertible_side_effect_counter { non_revertible_builder.note_encrypted_logs_hashes.push(note_encrypted_logs_hash); - non_revertible_builder.encrypted_log_preimages_length += note_encrypted_logs_hash.length; non_revertible_da_gas_used += note_encrypted_logs_hash.length as u32 * DA_GAS_PER_BYTE; } else { revertible_builder.note_encrypted_logs_hashes.push(note_encrypted_logs_hash); - revertible_builder.encrypted_log_preimages_length += note_encrypted_logs_hash.length; revertible_da_gas_used += note_encrypted_logs_hash.length as u32 * DA_GAS_PER_BYTE; } } @@ -194,11 +200,9 @@ impl PrivateAccumulatedDataBuilder { let encrypted_logs_hash = self.encrypted_logs_hashes.storage[i]; if encrypted_logs_hash.counter < min_revertible_side_effect_counter { non_revertible_builder.encrypted_logs_hashes.push(encrypted_logs_hash); - non_revertible_builder.encrypted_log_preimages_length += encrypted_logs_hash.length; non_revertible_da_gas_used += encrypted_logs_hash.length as u32 * DA_GAS_PER_BYTE; } else { revertible_builder.encrypted_logs_hashes.push(encrypted_logs_hash); - revertible_builder.encrypted_log_preimages_length += encrypted_logs_hash.length; revertible_da_gas_used += encrypted_logs_hash.length as u32 * DA_GAS_PER_BYTE; } } @@ -207,26 +211,13 @@ impl PrivateAccumulatedDataBuilder { let unencrypted_logs_hash = self.unencrypted_logs_hashes.storage[i]; if unencrypted_logs_hash.counter < min_revertible_side_effect_counter { non_revertible_builder.unencrypted_logs_hashes.push(unencrypted_logs_hash); - non_revertible_builder.unencrypted_log_preimages_length += unencrypted_logs_hash.length; non_revertible_da_gas_used += unencrypted_logs_hash.length as u32 * DA_GAS_PER_BYTE; } else { revertible_builder.unencrypted_logs_hashes.push(unencrypted_logs_hash); - revertible_builder.unencrypted_log_preimages_length += unencrypted_logs_hash.length; revertible_da_gas_used += unencrypted_logs_hash.length as u32 * DA_GAS_PER_BYTE; } } - assert( - revertible_builder.encrypted_log_preimages_length - + non_revertible_builder.encrypted_log_preimages_length - == self.encrypted_log_preimages_length, "encrypted logs length mismatch" - ); - assert( - revertible_builder.unencrypted_log_preimages_length - + non_revertible_builder.unencrypted_log_preimages_length - == self.unencrypted_log_preimages_length, "unencrypted logs length mismatch" - ); - revertible_builder.gas_used = Gas::new(revertible_da_gas_used, revertible_l2_gas_used); non_revertible_builder.gas_used = Gas::tx_overhead() + Gas::new(non_revertible_da_gas_used, non_revertible_l2_gas_used); (non_revertible_builder.finish(), revertible_builder.finish()) @@ -352,11 +343,9 @@ mod tests { builder.encrypted_logs_hashes.extend_from_array(non_revertible_enc_log_hashes); builder.encrypted_logs_hashes.extend_from_array(revertible_enc_log_hashes); - builder.encrypted_log_preimages_length = 12; builder.unencrypted_logs_hashes.extend_from_array(non_revertible_unenc_log_hashes); builder.unencrypted_logs_hashes.extend_from_array(revertible_unenc_log_hashes); - builder.unencrypted_log_preimages_length = 20; let public_non_revertible_note_logs = non_revertible_note_logs.map(|n: NoteLogHash| n.expose_to_public()); let public_revertible_note_logs = revertible_note_logs.map(|n: NoteLogHash| n.expose_to_public()); @@ -439,8 +428,8 @@ mod tests { assert_eq( revertible.gas_used, Gas::new( (4 * DA_BYTES_PER_FIELD - + revertible.encrypted_log_preimages_length as u32 - + revertible.unencrypted_log_preimages_length as u32) + + 6 // revertible encrypted logs len + + 10) // revertible unencrypted logs len * DA_GAS_PER_BYTE, 0 ) @@ -450,8 +439,8 @@ mod tests { assert_eq( non_revertible.gas_used, Gas::new( (4 * DA_BYTES_PER_FIELD - + non_revertible.encrypted_log_preimages_length as u32 - + non_revertible.unencrypted_log_preimages_length as u32) + + 6 // non-revertible encrypted logs len + + 10) // non-revertible unencrypted logs len * DA_GAS_PER_BYTE, 0 ) @@ -469,8 +458,6 @@ impl Empty for PrivateAccumulatedDataBuilder { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, private_call_stack: BoundedVec::new(), public_call_stack: BoundedVec::new(), } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data.nr index 06f23069398..66bca07d493 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data.nr @@ -20,11 +20,6 @@ struct PublicAccumulatedData { encrypted_logs_hashes: [LogHash; MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_TX], - // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the - // variable-length data. - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, - public_data_update_requests: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], @@ -41,8 +36,6 @@ impl Empty for PublicAccumulatedData { note_encrypted_logs_hashes: [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], encrypted_logs_hashes: [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX], - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, public_data_update_requests: [PublicDataUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], public_call_stack: [CallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], gas_used: Gas::empty(), @@ -76,9 +69,6 @@ impl Serialize for PublicAccumulatedData { fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); } - fields.push(self.encrypted_log_preimages_length); - fields.push(self.unencrypted_log_preimages_length); - for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { fields.extend_from_array(self.public_data_update_requests[i].serialize()); } @@ -106,8 +96,6 @@ impl Deserialize for PublicAccumulatedData { note_encrypted_logs_hashes: reader.read_struct_array(NoteLogHash::deserialize, [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX]), encrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX]), unencrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX]), - encrypted_log_preimages_length: reader.read(), - unencrypted_log_preimages_length: reader.read(), public_data_update_requests: reader.read_struct_array(PublicDataUpdateRequest::deserialize, [PublicDataUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]), public_call_stack: reader.read_struct_array(CallRequest::deserialize, [CallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX]), gas_used: reader.read_struct(Gas::deserialize), @@ -125,8 +113,6 @@ impl Eq for PublicAccumulatedData { (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) & (self.unencrypted_logs_hashes == other.unencrypted_logs_hashes) & - (self.encrypted_log_preimages_length == other.encrypted_log_preimages_length) & - (self.unencrypted_log_preimages_length == other.unencrypted_log_preimages_length) & (self.public_data_update_requests == other.public_data_update_requests) & (self.public_call_stack == other.public_call_stack) & (self.gas_used == other.gas_used) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr index 104458d673c..bd0d357ed4c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr @@ -21,11 +21,6 @@ struct PublicAccumulatedDataBuilder { encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, - // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the - // variable-length data. - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, - public_data_update_requests: BoundedVec, public_call_stack: BoundedVec, @@ -42,8 +37,6 @@ impl PublicAccumulatedDataBuilder { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage, encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, public_data_update_requests: self.public_data_update_requests.storage, public_call_stack: self.public_call_stack.storage, gas_used: self.gas_used @@ -60,8 +53,6 @@ impl Empty for PublicAccumulatedDataBuilder { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, public_data_update_requests: BoundedVec::new(), public_call_stack: BoundedVec::new(), gas_used: Gas::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 480d95eacd6..18278e5b3d2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -85,6 +85,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x11e550264f1840bab424389aa41ed8a5735c0aa8f94e41bd259caab964ff93dc; + let test_data_empty_hash = 0x1eaa8a277851ba8de6f7630ec75a2324e03a00a6ee99f24dd834faa422bdee4f; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 01b22811e12..9fa97c8695c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -45,11 +45,6 @@ struct PrivateCircuitPublicInputs { encrypted_logs_hashes: [LogHash; MAX_ENCRYPTED_LOGS_PER_CALL], unencrypted_logs_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_CALL], - // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the - // variable-length data. - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, - // Header of a block whose state is used during private execution (not the block the transaction is included in). historical_header: Header, @@ -80,8 +75,6 @@ impl Eq for PrivateCircuitPublicInputs { (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) & (self.unencrypted_logs_hashes == other.unencrypted_logs_hashes) & - (self.encrypted_log_preimages_length == other.encrypted_log_preimages_length) & - (self.unencrypted_log_preimages_length == other.unencrypted_log_preimages_length) & self.historical_header.eq(other.historical_header) & self.tx_context.eq(other.tx_context) } @@ -131,8 +124,6 @@ impl Serialize for PrivateCircuitPublicInp for i in 0..self.unencrypted_logs_hashes.len() { fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); } - fields.push(self.encrypted_log_preimages_length); - fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); fields.extend_from_array(self.tx_context.serialize()); @@ -167,8 +158,6 @@ impl Deserialize for PrivateCircuitPublicI note_encrypted_logs_hashes: reader.read_struct_array(NoteLogHash::deserialize, [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_CALL]), encrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_CALL]), unencrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_CALL]), - encrypted_log_preimages_length: reader.read(), - unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), tx_context: reader.read_struct(TxContext::deserialize), }; @@ -207,8 +196,6 @@ impl Empty for PrivateCircuitPublicInputs { note_encrypted_logs_hashes: [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_CALL], encrypted_logs_hashes: [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_CALL], unencrypted_logs_hashes: [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_CALL], - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, historical_header: Header::empty(), tx_context: TxContext::empty(), } @@ -228,6 +215,6 @@ fn empty_hash() { let inputs = PrivateCircuitPublicInputs::empty(); let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x067b9bd773ae49145e07b395da4f156fb35972e77bd4c40ed980ea8c9b90dd64; + let test_data_empty_hash = 0x0e8b75e4ecf8bed8e361ff2702a1c200d1f4d4394c8f06dc9003eee571982c6c; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr index 6746118086d..7757259ed7f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr @@ -69,7 +69,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test - let test_data_call_stack_item_request_hash = 0x11998b1d33b8ba1c8fa7a6c2f5bc76b31bbaa80400554465c335ba31559ac1f9; + let test_data_call_stack_item_request_hash = 0x1fe90f27924bcd761257c1b4570f5937b6dabcb4b6047ff668a770dea8e13533; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } @@ -87,7 +87,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test - let test_data_call_stack_item_hash = 0x2b7f8b68d96d0011ecc576459899e9451fbd880568ccc7a071d9cf04e59abb65; + let test_data_call_stack_item_hash = 0x2bb94c518916df51853784f16991e7691eddd452831ee1197cd29cdfb492d7b8; assert_eq(call_stack_item.hash(), test_data_call_stack_item_hash); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr index 7a0a61119ad..62c49177b17 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr @@ -38,10 +38,6 @@ struct PublicCircuitPublicInputs { unencrypted_logs_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_CALL], - // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the - // variable-length data. - unencrypted_log_preimages_length: Field, - // Header of a block whose state is used during public execution. Set by sequencer to be a header of a block // previous to the one in which the tx is included. historical_header: Header, @@ -100,7 +96,6 @@ impl Serialize for PublicCircuitPublicInput for i in 0..MAX_UNENCRYPTED_LOGS_PER_CALL{ fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); } - fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); fields.extend_from_array(self.global_variables.serialize()); fields.push(self.prover_address.to_field()); @@ -131,7 +126,6 @@ impl Deserialize for PublicCircuitPublicInp start_side_effect_counter: reader.read() as u32, end_side_effect_counter: reader.read() as u32, unencrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_CALL]), - unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), global_variables: reader.read_struct(GlobalVariables::deserialize), prover_address: reader.read_struct(AztecAddress::deserialize), @@ -169,7 +163,6 @@ impl Empty for PublicCircuitPublicInputs { start_side_effect_counter: 0 as u32, end_side_effect_counter: 0 as u32, unencrypted_logs_hashes: [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_CALL], - unencrypted_log_preimages_length: 0, historical_header: Header::empty(), global_variables: GlobalVariables::empty(), prover_address: AztecAddress::zero(), @@ -195,6 +188,6 @@ fn empty_hash() { let hash = inputs.hash(); // Value from public_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x1e4351db0c9aa20836e7009bc3e6a4555c92622c5e9cb3b49e2ec0fbbf59d0bd; + let test_data_empty_hash = 0x153e47f63e4ae88293bad9aed2802315e4bb3bd2a57f108a27e78e4887490291; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 4b2296ba3e5..ef19cbe4547 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -174,8 +174,8 @@ global STATE_REFERENCE_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_ global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u64 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; global HEADER_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH; -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 2 + HEADER_LENGTH + TX_CONTEXT_LENGTH; -global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 1 + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; +global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; global PUBLIC_CONTEXT_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + GAS_LENGTH + 2; @@ -189,10 +189,10 @@ global COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBA global CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; global CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; -global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + 2 + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); +global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; -global PUBLIC_ACCUMULATED_DATA_LENGTH = (MAX_NEW_NOTE_HASHES_PER_TX * NOTE_HASH_LENGTH) + (MAX_NEW_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * 1) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + 2 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + GAS_LENGTH; +global PUBLIC_ACCUMULATED_DATA_LENGTH = (MAX_NEW_NOTE_HASHES_PER_TX * NOTE_HASH_LENGTH) + (MAX_NEW_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * 1) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + GAS_LENGTH; global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + 1 + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + AZTEC_ADDRESS_LENGTH; global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index c27429ffbf2..ba88b2d5c7a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -143,8 +143,6 @@ impl FixtureBuilder { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes, encrypted_logs_hashes: self.encrypted_logs_hashes, unencrypted_logs_hashes: self.unencrypted_logs_hashes, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, private_call_stack: self.private_call_stack, public_call_stack: self.public_call_stack }; @@ -159,8 +157,6 @@ impl FixtureBuilder { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage, encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, public_data_update_requests: self.public_data_update_requests.storage, public_call_stack: self.public_call_stack.storage, gas_used: self.gas_used diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index edcab97af36..12f692a03fe 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -48,9 +48,6 @@ struct PrivateCircuitPublicInputsBuilder { encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, - encrypted_log_preimages_length: Field, - unencrypted_log_preimages_length: Field, - historical_header: Header, chain_id: Field, @@ -156,13 +153,11 @@ impl PrivateCircuitPublicInputsBuilder { pub fn add_encrypted_log(&mut self, hash: Field, preimages_length: Field) { let side_effect = LogHash { value: hash, counter: self.next_counter(), length: preimages_length }; self.encrypted_logs_hashes.push(side_effect); - self.encrypted_log_preimages_length += preimages_length; } pub fn add_unencrypted_log(&mut self, hash: Field, preimages_length: Field) { let side_effect = LogHash { value: hash, counter: self.next_counter(), length: preimages_length }; self.unencrypted_logs_hashes.push(side_effect); - self.unencrypted_log_preimages_length += preimages_length; } pub fn generate_call_request(self, hash: Field, is_delegate_call: bool) -> CallRequest { @@ -220,8 +215,6 @@ impl PrivateCircuitPublicInputsBuilder { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage, encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, historical_header: self.historical_header, tx_context: self.build_tx_context() } @@ -256,8 +249,6 @@ impl Empty for PrivateCircuitPublicInputsBuilder { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - encrypted_log_preimages_length: 0, - unencrypted_log_preimages_length: 0, historical_header: Header::empty(), chain_id: 0, version: 0, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr index 9f66f8cf62e..633d260d468 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr @@ -147,7 +147,6 @@ impl PublicCallDataBuilder { // Counter set as 0 for testing, like note read requests let side_effect = LogHash { value: hash, counter: 0, length: preimages_length }; self.public_inputs.unencrypted_logs_hashes.push(side_effect); - self.public_inputs.unencrypted_log_preimages_length += preimages_length; } pub fn finish(self) -> PublicCallData { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr index 0aba746f283..b48eed18826 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr @@ -33,7 +33,6 @@ struct PublicCircuitPublicInputsBuilder { start_side_effect_counter: u32, end_side_effect_counter: u32, unencrypted_logs_hashes: BoundedVec, - unencrypted_log_preimages_length: Field, historical_header: Header, global_variables: GlobalVariables, prover_address: AztecAddress, @@ -66,7 +65,6 @@ impl PublicCircuitPublicInputsBuilder { start_side_effect_counter: self.start_side_effect_counter, end_side_effect_counter: self.end_side_effect_counter, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, historical_header: self.historical_header, global_variables: self.global_variables, prover_address: self.prover_address, @@ -95,7 +93,6 @@ impl Empty for PublicCircuitPublicInputsBuilder { start_side_effect_counter: 0 as u32, end_side_effect_counter: 0 as u32, unencrypted_logs_hashes: BoundedVec::new(), - unencrypted_log_preimages_length: 0, historical_header: Header::empty(), global_variables: GlobalVariables::empty(), prover_address: AztecAddress::zero(), diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts index 3b0af9d8bf7..6d14c835a6a 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts @@ -30,6 +30,14 @@ function shouldBehaveLikeFunctionL2Logs( expect(recovered.getSerializedLength()).toEqual(buffer.length); }); + + it('getKernelLength returns the correct length', () => { + const l2Logs = FunctionL2Logs.random(3); + + const expectedLength = l2Logs.logs.map(l => l.length).reduce((a, b) => a + b + 4, 0); + + expect(l2Logs.getKernelLength()).toEqual(expectedLength); + }); }); } diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.ts index dd8650132d5..dd3d8201797 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.ts @@ -37,6 +37,16 @@ export abstract class FunctionL2Logs acc + log.length + 4, 0) + 4; } + /** + * Get the total length of all chargable data (raw log data + 4 for each log) + * TODO: Rename this? getChargableLength? getDALength? + * @returns Total length of data. + */ + public getKernelLength(): number { + // Adding 4 to each log's length to account for the size stored in the serialized buffer + return this.logs.reduce((acc, log) => acc + log.length + 4, 0); + } + /** * Calculates hash of serialized logs. * @returns Buffer containing 248 bits of information of sha256 hash. diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts index 6be5194aa49..da9520bd4d0 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts @@ -28,6 +28,14 @@ function shouldBehaveLikeTxL2Logs(TxL2Logs: typeof EncryptedTxL2Logs | typeof Un expect(recovered.getSerializedLength()).toEqual(buffer.length); }); + + it('getKernelLength returns the correct length', () => { + const l2Logs = TxL2Logs.random(4, 2); + + const expectedLength = l2Logs.functionLogs.map(l => l.getKernelLength()).reduce((a, b) => a + b, 0); + + expect(l2Logs.getKernelLength()).toEqual(expectedLength); + }); }); } diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts index 86ad70a046b..f4c76498b79 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts @@ -40,6 +40,15 @@ export abstract class TxL2Logs { return this.functionLogs.reduce((acc, logs) => acc + logs.getSerializedLength(), 0) + 4; } + /** + * Get the total length of all chargable data (raw log data + 4 for each log) + * TODO: Rename this? getChargableLength? getDALength? + * @returns Total length of data. + */ + public getKernelLength(): number { + return this.functionLogs.reduce((acc, logs) => acc + logs.getKernelLength(), 0); + } + /** Gets the total number of logs. */ public getTotalLogCount() { return this.functionLogs.reduce((acc, logs) => acc + logs.logs.length, 0); diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 4fad2f35652..fd587ed18d1 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -181,6 +181,8 @@ export function toTxEffect(tx: ProcessedTx): TxEffect { tx.data.end.publicDataUpdateRequests .map(t => new PublicDataWrite(t.leafSlot, t.newValue)) .filter(h => !h.isEmpty()), + tx.data.end.encryptedLogPreimagesLength, + tx.data.end.unencryptedLogPreimagesLength, tx.noteEncryptedLogs || EncryptedTxL2Logs.empty(), tx.encryptedLogs || EncryptedTxL2Logs.empty(), tx.unencryptedLogs || UnencryptedTxL2Logs.empty(), @@ -189,15 +191,49 @@ export function toTxEffect(tx: ProcessedTx): TxEffect { function validateProcessedTxLogs(tx: ProcessedTx): void { const unencryptedLogs = tx.unencryptedLogs || UnencryptedTxL2Logs.empty(); - const kernelUnencryptedLogsHash = tx.data.end.unencryptedLogsHash; - const referenceHash = Fr.fromBuffer(unencryptedLogs.hash()); - if (!referenceHash.equals(kernelUnencryptedLogsHash)) { + let kernelHash = tx.data.end.unencryptedLogsHash; + let referenceHash = Fr.fromBuffer(unencryptedLogs.hash()); + if (!referenceHash.equals(kernelHash)) { throw new Error( - `Unencrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelUnencryptedLogsHash.toString()}. + `Unencrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelHash.toString()}. Processed: ${JSON.stringify(unencryptedLogs.toJSON())} Kernel Length: ${tx.data.end.unencryptedLogPreimagesLength}`, ); } + const encryptedLogs = tx.encryptedLogs || EncryptedTxL2Logs.empty(); + kernelHash = tx.data.end.encryptedLogsHash; + referenceHash = Fr.fromBuffer(encryptedLogs.hash()); + if (!referenceHash.equals(kernelHash)) { + throw new Error( + `Encrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelHash.toString()}. + Processed: ${JSON.stringify(encryptedLogs.toJSON())}`, + ); + } + const noteEncryptedLogs = tx.noteEncryptedLogs || EncryptedTxL2Logs.empty(); + kernelHash = tx.data.end.noteEncryptedLogsHash; + referenceHash = Fr.fromBuffer(noteEncryptedLogs.hash(0)); + if (!referenceHash.equals(kernelHash)) { + throw new Error( + `Note encrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelHash.toString()}. + Processed: ${JSON.stringify(noteEncryptedLogs.toJSON())}`, + ); + } + let referenceLength = new Fr(encryptedLogs.getKernelLength() + noteEncryptedLogs.getKernelLength()); + let kernelLength = tx.data.end.encryptedLogPreimagesLength; + if (!referenceLength.equals(kernelLength)) { + throw new Error( + `Encrypted logs length mismatch. Expected ${referenceLength.toString()}, got ${kernelLength.toString()}. + Processed: ${JSON.stringify(encryptedLogs.toJSON())}`, + ); + } + referenceLength = new Fr(unencryptedLogs.getKernelLength()); + kernelLength = tx.data.end.unencryptedLogPreimagesLength; + if (!referenceLength.equals(kernelLength)) { + throw new Error( + `Unencrypted logs length mismatch. Expected ${referenceLength.toString()}, got ${kernelLength.toString()}. + Processed: ${JSON.stringify(encryptedLogs.toJSON())}`, + ); + } } export function validateProcessedTx(tx: ProcessedTx): void { diff --git a/yarn-project/circuit-types/src/tx_effect.test.ts b/yarn-project/circuit-types/src/tx_effect.test.ts index 82876e870aa..3766ba5e259 100644 --- a/yarn-project/circuit-types/src/tx_effect.test.ts +++ b/yarn-project/circuit-types/src/tx_effect.test.ts @@ -10,6 +10,6 @@ describe('TxEffect', () => { it('hash of empty tx effect matches snapshot', () => { const txEffectHash = TxEffect.empty().hash().toString('hex'); // If you change this you have to change the hardcoded value in TxsDecoder.sol! - expect(txEffectHash).toMatchInlineSnapshot(`"00543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7"`); + expect(txEffectHash).toMatchInlineSnapshot(`"009f12fb98ebbf4e5deef4cf51ade63094a795b891880217958b226707c95f43"`); }); }); diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index 422727c5062..dabaf722f53 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -41,8 +41,10 @@ export class TxEffect { */ public publicDataWrites: PublicDataWrite[], /** - * The logs of the txEffect + * The logs and logs lengths of the txEffect */ + public encryptedLogsLength: Fr, + public unencryptedLogsLength: Fr, public noteEncryptedLogs: EncryptedTxL2Logs, public encryptedLogs: EncryptedTxL2Logs, public unencryptedLogs: UnencryptedTxL2Logs, @@ -96,6 +98,8 @@ export class TxEffect { serializeArrayOfBufferableToVector(this.nullifiers, 1), serializeArrayOfBufferableToVector(this.l2ToL1Msgs, 1), serializeArrayOfBufferableToVector(this.publicDataWrites, 1), + this.encryptedLogsLength, + this.unencryptedLogsLength, this.noteEncryptedLogs, this.encryptedLogs, this.unencryptedLogs, @@ -117,6 +121,8 @@ export class TxEffect { reader.readVectorUint8Prefix(Fr), reader.readVectorUint8Prefix(Fr), reader.readVectorUint8Prefix(PublicDataWrite), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), reader.readObject(EncryptedTxL2Logs), reader.readObject(EncryptedTxL2Logs), reader.readObject(UnencryptedTxL2Logs), @@ -159,6 +165,8 @@ export class TxEffect { nullifiersBuffer, l2ToL1MsgsBuffer, publicDataWritesBuffer, + this.encryptedLogsLength.toBuffer(), + this.unencryptedLogsLength.toBuffer(), noteEncryptedLogsHashKernel0, encryptedLogsHashKernel0, unencryptedLogsHashKernel0, @@ -173,6 +181,11 @@ export class TxEffect { numEncryptedLogsPerCall = 2, numUnencryptedLogsPerCall = 1, ): TxEffect { + const encryptedLogs = [ + EncryptedTxL2Logs.random(numPrivateCallsPerTx, numEncryptedLogsPerCall), + EncryptedTxL2Logs.random(numPrivateCallsPerTx, numEncryptedLogsPerCall), + ]; + const unencryptedLogs = UnencryptedTxL2Logs.random(numPublicCallsPerTx, numUnencryptedLogsPerCall); return new TxEffect( RevertCode.random(), Fr.random(), @@ -180,9 +193,11 @@ export class TxEffect { makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.random), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.random), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite.random), - EncryptedTxL2Logs.random(numPrivateCallsPerTx, numEncryptedLogsPerCall), - EncryptedTxL2Logs.random(numPrivateCallsPerTx, numEncryptedLogsPerCall), - UnencryptedTxL2Logs.random(numPublicCallsPerTx, numUnencryptedLogsPerCall), + new Fr(encryptedLogs[0].getKernelLength() + encryptedLogs[1].getKernelLength()), + new Fr(unencryptedLogs.getKernelLength()), + encryptedLogs[0], + encryptedLogs[1], + unencryptedLogs, ); } @@ -194,6 +209,8 @@ export class TxEffect { [], [], [], + Fr.ZERO, + Fr.ZERO, EncryptedTxL2Logs.empty(), EncryptedTxL2Logs.empty(), UnencryptedTxL2Logs.empty(), @@ -221,6 +238,8 @@ export class TxEffect { nullifiers: [${this.nullifiers.map(h => h.toString()).join(', ')}], l2ToL1Msgs: [${this.l2ToL1Msgs.map(h => h.toString()).join(', ')}], publicDataWrites: [${this.publicDataWrites.map(h => h.toString()).join(', ')}], + encryptedLogsLength: ${this.encryptedLogsLength}, + unencryptedLogsLength: ${this.unencryptedLogsLength}, noteEncryptedLogs: ${JSON.stringify(this.noteEncryptedLogs.toJSON())}, encryptedLogs: ${JSON.stringify(this.encryptedLogs.toJSON())}, unencryptedLogs: ${JSON.stringify(this.unencryptedLogs.toJSON())} diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 630f632bc1f..3be95e96e9a 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -136,7 +136,6 @@ export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL + LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL + LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL + - 2 + HEADER_LENGTH + TX_CONTEXT_LENGTH; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = @@ -152,7 +151,6 @@ export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL + 2 + LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL + - 1 + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + @@ -190,7 +188,6 @@ export const PRIVATE_ACCUMULATED_DATA_LENGTH = NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX + LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX + LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX + - 2 + CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX + CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX; export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = @@ -207,7 +204,6 @@ export const PUBLIC_ACCUMULATED_DATA_LENGTH = NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX + MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH + MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH + - 2 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH + GAS_LENGTH; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap index 1e2c25066fc..be2f85234d3 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x11e550264f1840bab424389aa41ed8a5735c0aa8f94e41bd259caab964ff93dc>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x1eaa8a277851ba8de6f7630ec75a2324e03a00a6ee99f24dd834faa422bdee4f>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x17b804ce2f015fe4761c3f524103213bdc3033a2b226f5bf33637b0e7650b8ff>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0cb30e5fa0e822ff93dc0bc3752c4b277e4629dfd8c31651aca53541873a5505>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index e53a63c1e44..dbe26205c72 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x067b9bd773ae49145e07b395da4f156fb35972e77bd4c40ed980ea8c9b90dd64>`; +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x0e8b75e4ecf8bed8e361ff2702a1c200d1f4d4394c8f06dc9003eee571982c6c>`; -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x024619cfa41bf4ca35cec15ee5c7b90183f44711737bea9aef56c40602765dbb>`; +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x16aaaeeda5082bca41b5488bb064a3384f43c61b6f4f6f14d6ad3c3e1eb71fcc>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index ff438f9222d..20348f214d3 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x2b7f8b68d96d0011ecc576459899e9451fbd880568ccc7a071d9cf04e59abb65"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x2bb94c518916df51853784f16991e7691eddd452831ee1197cd29cdfb492d7b8"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x11998b1d33b8ba1c8fa7a6c2f5bc76b31bbaa80400554465c335ba31559ac1f9"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x1fe90f27924bcd761257c1b4570f5937b6dabcb4b6047ff668a770dea8e13533"`; -exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x2e7cef26b4ef88a036f6f2bc5bd5d7457b7c2851c7357f1e6f79be9fdde4cf77>`; +exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x13e55a4c1fb75d2a348ab0abe47aba86992a0cebf5fe2b24243af0246d27d2b5>`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x025cc2b4f4105c6f39113d8544224901fbc23fde4d4c958d6c41907078b678bb>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x0e54342ea9a248adda86b676c762fab4ed8e64f91c28da0f577162870685e5ab>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap index f7eeb88b15c..49eff22d05d 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x1e4351db0c9aa20836e7009bc3e6a4555c92622c5e9cb3b49e2ec0fbbf59d0bd>`; +exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x153e47f63e4ae88293bad9aed2802315e4bb3bd2a57f108a27e78e4887490291>`; -exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x07eb8710b05470576d027ed77139ac6755324fb1a67da6c7669e837c4eab7dc2>`; +exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x10283cd87782fa6cc9f63e2766b6d5aed3350edf1e082a98ad7dd83b0cd171f0>`; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts index 0c83610688a..8582079e98d 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts @@ -1,5 +1,4 @@ import { makeTuple } from '@aztec/foundation/array'; -import { Fr } from '@aztec/foundation/fields'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { @@ -51,14 +50,6 @@ export class PrivateAccumulatedData { * Note: Truncated to 31 bytes to fit in Fr. */ public unencryptedLogsHashes: Tuple, - /** - * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations - */ - public encryptedLogPreimagesLength: Fr, - /** - * Total accumulated length of the unencrypted log preimages emitted in all the previous kernel iterations - */ - public unencryptedLogPreimagesLength: Fr, /** * Current private call stack. * TODO(#3417): Given this field must empty, should we just remove it? @@ -78,8 +69,6 @@ export class PrivateAccumulatedData { this.noteEncryptedLogsHashes, this.encryptedLogsHashes, this.unencryptedLogsHashes, - this.encryptedLogPreimagesLength, - this.unencryptedLogPreimagesLength, this.privateCallStack, this.publicCallStack, ); @@ -103,8 +92,6 @@ export class PrivateAccumulatedData { reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash), reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, LogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, LogHash), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), ); @@ -127,8 +114,6 @@ export class PrivateAccumulatedData { makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash.empty), makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, LogHash.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, LogHash.empty), - Fr.zero(), - Fr.zero(), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), ); diff --git a/yarn-project/circuits.js/src/structs/kernel/public_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/public_accumulated_data.ts index 3843fe50efc..902f8259746 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_accumulated_data.ts @@ -51,14 +51,6 @@ export class PublicAccumulatedData { * Note: Truncated to 31 bytes to fit in Fr. */ public unencryptedLogsHashes: Tuple, - /** - * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations - */ - public encryptedLogPreimagesLength: Fr, - /** - * Total accumulated length of the unencrypted log preimages emitted in all the previous kernel iterations - */ - public unencryptedLogPreimagesLength: Fr, /** * All the public data update requests made in this transaction. */ @@ -80,8 +72,6 @@ export class PublicAccumulatedData { this.noteEncryptedLogsHashes, this.encryptedLogsHashes, this.unencryptedLogsHashes, - this.encryptedLogPreimagesLength, - this.unencryptedLogPreimagesLength, this.publicDataUpdateRequests, this.publicCallStack, this.gasUsed, @@ -100,8 +90,6 @@ export class PublicAccumulatedData { this.noteEncryptedLogsHashes.every(x => x.isEmpty()) && this.encryptedLogsHashes.every(x => x.isEmpty()) && this.unencryptedLogsHashes.every(x => x.isEmpty()) && - this.encryptedLogPreimagesLength.isZero() && - this.unencryptedLogPreimagesLength.isZero() && this.publicDataUpdateRequests.every(x => x.isEmpty()) && this.publicCallStack.every(x => x.isEmpty()) && this.gasUsed.isEmpty() @@ -135,8 +123,6 @@ export class PublicAccumulatedData { .filter(x => !x.isEmpty()) .map(h => inspect(h)) .join(', ')}], - encryptedLogPreimagesLength: ${this.encryptedLogPreimagesLength} - unencryptedLogPreimagesLength: ${this.unencryptedLogPreimagesLength} publicDataUpdateRequests: [${this.publicDataUpdateRequests .filter(x => !x.isEmpty()) .map(h => inspect(h)) @@ -163,8 +149,6 @@ export class PublicAccumulatedData { reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash), reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, LogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, LogHash), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readObject(Gas), @@ -188,8 +172,6 @@ export class PublicAccumulatedData { makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash.empty), makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, LogHash.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, LogHash.empty), - Fr.zero(), - Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), Gas.empty(), diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index 7eae5eedb78..32197024ef7 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -129,16 +129,6 @@ export class PrivateCircuitPublicInputs { * Note: Truncated to 31 bytes to fit in Fr. */ public unencryptedLogsHashes: Tuple, - /** - * Length of the encrypted log preimages emitted in this function call. - * Note: Here so that the gas cost of this request can be measured by circuits, without actually needing to feed - * in the variable-length data. - */ - public encryptedLogPreimagesLength: Fr, - /** - * Length of the unencrypted log preimages emitted in this function call. - */ - public unencryptedLogPreimagesLength: Fr, /** * Header of a block whose state is used during private execution (not the block the transaction is included in). */ @@ -190,8 +180,6 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, NoteLogHash), reader.readArray(MAX_ENCRYPTED_LOGS_PER_CALL, LogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_CALL, LogHash), - reader.readObject(Fr), - reader.readObject(Fr), reader.readObject(Header), reader.readObject(TxContext), ); @@ -220,8 +208,6 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, NoteLogHash), reader.readArray(MAX_ENCRYPTED_LOGS_PER_CALL, LogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_CALL, LogHash), - reader.readField(), - reader.readField(), reader.readObject(Header), reader.readObject(TxContext), ); @@ -253,8 +239,6 @@ export class PrivateCircuitPublicInputs { makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, NoteLogHash.empty), makeTuple(MAX_ENCRYPTED_LOGS_PER_CALL, LogHash.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_CALL, LogHash.empty), - Fr.ZERO, - Fr.ZERO, Header.empty(), TxContext.empty(), ); @@ -281,8 +265,6 @@ export class PrivateCircuitPublicInputs { isEmptyArray(this.noteEncryptedLogsHashes) && isEmptyArray(this.encryptedLogsHashes) && isEmptyArray(this.unencryptedLogsHashes) && - this.encryptedLogPreimagesLength.isZero() && - this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && this.txContext.isEmpty() ); @@ -315,8 +297,6 @@ export class PrivateCircuitPublicInputs { fields.noteEncryptedLogsHashes, fields.encryptedLogsHashes, fields.unencryptedLogsHashes, - fields.encryptedLogPreimagesLength, - fields.unencryptedLogPreimagesLength, fields.historicalHeader, fields.txContext, ] as const; diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index 0674dc53b56..f1dd73f0b7c 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -107,10 +107,6 @@ export class PublicCircuitPublicInputs { * Note: Truncated to 31 bytes to fit in Fr. */ public unencryptedLogsHashes: Tuple, - /** - * Length of the unencrypted log preimages emitted in this function call. - */ - public unencryptedLogPreimagesLength: Fr, /** * Header of a block whose state is used during public execution. Set by sequencer to be a header of a block * previous to the one in which the tx is included. @@ -167,7 +163,6 @@ export class PublicCircuitPublicInputs { Fr.ZERO, Fr.ZERO, makeTuple(MAX_UNENCRYPTED_LOGS_PER_CALL, LogHash.empty), - Fr.ZERO, Header.empty(), GlobalVariables.empty(), AztecAddress.ZERO, @@ -195,7 +190,6 @@ export class PublicCircuitPublicInputs { this.startSideEffectCounter.isZero() && this.endSideEffectCounter.isZero() && isEmptyArray(this.unencryptedLogsHashes) && - this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && this.globalVariables.isEmpty() && this.proverAddress.isZero() && @@ -227,7 +221,6 @@ export class PublicCircuitPublicInputs { fields.startSideEffectCounter, fields.endSideEffectCounter, fields.unencryptedLogsHashes, - fields.unencryptedLogPreimagesLength, fields.historicalHeader, fields.globalVariables, fields.proverAddress, @@ -278,7 +271,6 @@ export class PublicCircuitPublicInputs { reader.readObject(Fr), reader.readObject(Fr), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_CALL, LogHash), - reader.readObject(Fr), reader.readObject(Header), reader.readObject(GlobalVariables), reader.readObject(AztecAddress), @@ -307,7 +299,6 @@ export class PublicCircuitPublicInputs { reader.readField(), reader.readField(), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_CALL, LogHash), - reader.readField(), Header.fromFields(reader), GlobalVariables.fromFields(reader), AztecAddress.fromFields(reader), diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 49ccb6738b4..7eb335efb0b 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -339,8 +339,6 @@ export function makePublicAccumulatedData(seed = 1, full = false): PublicAccumul tupleGenerator(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, makeNoteLogHash, seed + 0x700, NoteLogHash.empty), // note encrypted logs hashes tupleGenerator(MAX_ENCRYPTED_LOGS_PER_TX, makeLogHash, seed + 0x800, LogHash.empty), // encrypted logs hashes tupleGenerator(MAX_UNENCRYPTED_LOGS_PER_TX, makeLogHash, seed + 0x900, LogHash.empty), // unencrypted logs hashes - fr(seed + 0xa00), // encrypted_log_preimages_length - fr(seed + 0xb00), // unencrypted_log_preimages_length tupleGenerator( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, @@ -417,7 +415,6 @@ export function makePublicCircuitPublicInputs( fr(seed + 0xa00), fr(seed + 0xa01), tupleGenerator(MAX_UNENCRYPTED_LOGS_PER_CALL, makeLogHash, seed + 0x901, LogHash.empty), - fr(seed + 0x902), makeHeader(seed + 0xa00, undefined), makeGlobalVariables(seed + 0xa01), makeAztecAddress(seed + 0xb01), @@ -797,8 +794,6 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn noteEncryptedLogsHashes: makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, makeNoteLogHash, seed + 0x875), encryptedLogsHashes: makeTuple(MAX_ENCRYPTED_LOGS_PER_CALL, makeLogHash, seed + 0x900), unencryptedLogsHashes: makeTuple(MAX_UNENCRYPTED_LOGS_PER_CALL, makeLogHash, seed + 0xa00), - encryptedLogPreimagesLength: fr(seed + 0xb00), - unencryptedLogPreimagesLength: fr(seed + 0xc00), historicalHeader: makeHeader(seed + 0xd00, undefined), txContext: makeTxContext(seed + 0x1400), isFeePayer: false, diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 750d1909db5..b2ccda0887f 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -798,8 +798,6 @@ export function mapPrivateCircuitPublicInputsToNoir( note_encrypted_logs_hashes: mapTuple(privateCircuitPublicInputs.noteEncryptedLogsHashes, mapNoteLogHashToNoir), encrypted_logs_hashes: mapTuple(privateCircuitPublicInputs.encryptedLogsHashes, mapLogHashToNoir), unencrypted_logs_hashes: mapTuple(privateCircuitPublicInputs.unencryptedLogsHashes, mapLogHashToNoir), - encrypted_log_preimages_length: mapFieldToNoir(privateCircuitPublicInputs.encryptedLogPreimagesLength), - unencrypted_log_preimages_length: mapFieldToNoir(privateCircuitPublicInputs.unencryptedLogPreimagesLength), historical_header: mapHeaderToNoir(privateCircuitPublicInputs.historicalHeader), tx_context: mapTxContextToNoir(privateCircuitPublicInputs.txContext), min_revertible_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.minRevertibleSideEffectCounter), @@ -1092,8 +1090,6 @@ export function mapPrivateAccumulatedDataFromNoir( ), mapTupleFromNoir(privateAccumulatedData.encrypted_logs_hashes, MAX_ENCRYPTED_LOGS_PER_TX, mapLogHashFromNoir), mapTupleFromNoir(privateAccumulatedData.unencrypted_logs_hashes, MAX_UNENCRYPTED_LOGS_PER_TX, mapLogHashFromNoir), - mapFieldFromNoir(privateAccumulatedData.encrypted_log_preimages_length), - mapFieldFromNoir(privateAccumulatedData.unencrypted_log_preimages_length), mapTupleFromNoir( privateAccumulatedData.private_call_stack, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, @@ -1115,8 +1111,6 @@ export function mapPrivateAccumulatedDataToNoir(data: PrivateAccumulatedData): P note_encrypted_logs_hashes: mapTuple(data.noteEncryptedLogsHashes, mapNoteLogHashToNoir), encrypted_logs_hashes: mapTuple(data.encryptedLogsHashes, mapLogHashToNoir), unencrypted_logs_hashes: mapTuple(data.unencryptedLogsHashes, mapLogHashToNoir), - encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), - unencrypted_log_preimages_length: mapFieldToNoir(data.unencryptedLogPreimagesLength), private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), }; @@ -1136,8 +1130,6 @@ export function mapPublicAccumulatedDataFromNoir( ), mapTupleFromNoir(publicAccumulatedData.encrypted_logs_hashes, MAX_ENCRYPTED_LOGS_PER_TX, mapLogHashFromNoir), mapTupleFromNoir(publicAccumulatedData.unencrypted_logs_hashes, MAX_UNENCRYPTED_LOGS_PER_TX, mapLogHashFromNoir), - mapFieldFromNoir(publicAccumulatedData.encrypted_log_preimages_length), - mapFieldFromNoir(publicAccumulatedData.unencrypted_log_preimages_length), mapTupleFromNoir( publicAccumulatedData.public_data_update_requests, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -1162,8 +1154,6 @@ export function mapPublicAccumulatedDataToNoir( note_encrypted_logs_hashes: mapTuple(publicAccumulatedData.noteEncryptedLogsHashes, mapNoteLogHashToNoir), encrypted_logs_hashes: mapTuple(publicAccumulatedData.encryptedLogsHashes, mapLogHashToNoir), unencrypted_logs_hashes: mapTuple(publicAccumulatedData.unencryptedLogsHashes, mapLogHashToNoir), - encrypted_log_preimages_length: mapFieldToNoir(publicAccumulatedData.encryptedLogPreimagesLength), - unencrypted_log_preimages_length: mapFieldToNoir(publicAccumulatedData.unencryptedLogPreimagesLength), public_data_update_requests: mapTuple( publicAccumulatedData.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir, @@ -1681,7 +1671,6 @@ export function mapPublicCircuitPublicInputsToNoir( start_side_effect_counter: mapFieldToNoir(publicInputs.startSideEffectCounter), end_side_effect_counter: mapFieldToNoir(publicInputs.endSideEffectCounter), unencrypted_logs_hashes: mapTuple(publicInputs.unencryptedLogsHashes, mapLogHashToNoir), - unencrypted_log_preimages_length: mapFieldToNoir(publicInputs.unencryptedLogPreimagesLength), historical_header: mapHeaderToNoir(publicInputs.historicalHeader), global_variables: mapGlobalVariablesToNoir(publicInputs.globalVariables), prover_address: mapAztecAddressToNoir(publicInputs.proverAddress), diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 3017e1a7eaf..9645c9f4032 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -66,7 +66,6 @@ type PartialPublicExecutionResult = { contractStorageUpdateRequests: ContractStorageUpdateRequest[]; unencryptedLogsHashes: LogHash[]; unencryptedLogs: UnencryptedL2Log[]; - unencryptedLogPreimagesLength: Fr; allUnencryptedLogs: UnencryptedL2Log[]; nestedExecutions: PublicExecutionResult[]; }; @@ -119,7 +118,6 @@ export class AvmPersistableStateManager { contractStorageUpdateRequests: [], unencryptedLogsHashes: [], unencryptedLogs: [], - unencryptedLogPreimagesLength: Fr.ZERO, allUnencryptedLogs: [], nestedExecutions: [], }; @@ -312,13 +310,6 @@ export class AvmPersistableStateManager { this.transitionalExecutionResult.unencryptedLogsHashes.push( new LogHash(logHash, this.trace.accessCounter, new Fr(ulog.length)), ); - // Duplicates computation performed in public_context.nr::emit_unencrypted_log - // 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4). - // Note that ulog.length includes all the above bytes apart from processed log len - // Processed log len is added to replicate conversion to function_l2_logs at the end of exec. - this.transitionalExecutionResult.unencryptedLogPreimagesLength = new Fr(ulog.length + 4).add( - this.transitionalExecutionResult.unencryptedLogPreimagesLength, - ); // TODO(6206): likely need to track this here and not just in the transitional logic. // TODO(6205): why are logs pushed here but logs hashes are traced? diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 6b5e75207ec..9fec9c9f9a7 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -435,8 +435,8 @@ export class ClientExecutionContext extends ViewDataOracle { childExecutionResult.callStackItem.publicInputs.newNoteHashes.some(item => !item.isEmpty()) || childExecutionResult.callStackItem.publicInputs.newNullifiers.some(item => !item.isEmpty()) || childExecutionResult.callStackItem.publicInputs.newL2ToL1Msgs.some(item => !item.isEmpty()) || - !childExecutionResult.callStackItem.publicInputs.encryptedLogPreimagesLength.equals(Fr.ZERO) || - !childExecutionResult.callStackItem.publicInputs.unencryptedLogPreimagesLength.equals(Fr.ZERO) + childExecutionResult.callStackItem.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) || + childExecutionResult.callStackItem.publicInputs.unencryptedLogsHashes.some(item => !item.isEmpty()) ) { throw new Error(`Static call cannot create new notes, emit L2->L1 messages or generate logs`); } diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 7750808fd5d..1e1f9db16ff 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -169,8 +169,7 @@ describe('Private Execution test suite', () => { const getEncryptedNoteSerializedLength = (result: ExecutionResult) => { const fnLogs = new EncryptedFunctionL2Logs(result.noteEncryptedLogs.map(l => l.log)); - // We take 4 to avoid counting the extra 4 bytes used to store len for L1 - return fnLogs.getSerializedLength() - 4; + return fnLogs.getKernelLength(); }; beforeAll(() => { @@ -248,10 +247,7 @@ describe('Private Execution test suite', () => { const [unencryptedLog] = newUnencryptedLogs; expect(unencryptedLog.value).toEqual(Fr.fromBuffer(functionLogs.logs[0].hash())); - // We take 4 to avoid counting the extra 4 bytes used to store len for L1 - expect(result.callStackItem.publicInputs.unencryptedLogPreimagesLength).toEqual( - new Fr(functionLogs.getSerializedLength() - 4), - ); + expect(unencryptedLog.length).toEqual(new Fr(functionLogs.getKernelLength())); // Test that the log payload (ie ignoring address, selector, and header) matches what we emitted expect(functionLogs.logs[0].data.subarray(-32).toString('hex')).toEqual(owner.toBuffer().toString('hex')); }); @@ -268,10 +264,7 @@ describe('Private Execution test suite', () => { const [unencryptedLog] = newUnencryptedLogs; expect(unencryptedLog.value).toEqual(Fr.fromBuffer(functionLogs.logs[0].hash())); - // We take 4 to avoid counting the extra 4 bytes used to store len for L1 - expect(result.callStackItem.publicInputs.unencryptedLogPreimagesLength).toEqual( - new Fr(functionLogs.getSerializedLength() - 4), - ); + expect(unencryptedLog.length).toEqual(new Fr(functionLogs.getKernelLength())); // Test that the log payload (ie ignoring address, selector, and header) matches what we emitted const expected = Buffer.concat(args[0].map(arg => arg.toBuffer())).toString('hex'); expect(functionLogs.logs[0].data.subarray(-32 * 5).toString('hex')).toEqual(expected); @@ -348,9 +341,7 @@ describe('Private Execution test suite', () => { const [encryptedLog] = newEncryptedLogs; expect(encryptedLog.noteHashCounter).toEqual(newNoteHashes[0].counter); expect(encryptedLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); - expect(result.callStackItem.publicInputs.encryptedLogPreimagesLength).toEqual( - new Fr(getEncryptedNoteSerializedLength(result)), - ); + expect(encryptedLog.length).toEqual(new Fr(getEncryptedNoteSerializedLength(result))); }); it('should run the create_note function', async () => { @@ -380,9 +371,7 @@ describe('Private Execution test suite', () => { const [encryptedLog] = newEncryptedLogs; expect(encryptedLog.noteHashCounter).toEqual(newNoteHashes[0].counter); expect(encryptedLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); - expect(result.callStackItem.publicInputs.encryptedLogPreimagesLength).toEqual( - new Fr(getEncryptedNoteSerializedLength(result)), - ); + expect(encryptedLog.length).toEqual(new Fr(getEncryptedNoteSerializedLength(result))); }); it('should run the destroy_and_create function', async () => { @@ -442,7 +431,7 @@ describe('Private Execution test suite', () => { expect(encryptedChangeLog.noteHashCounter).toEqual(changeNoteHash.counter); expect(encryptedRecipientLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[1].log.hash())); expect(encryptedRecipientLog.noteHashCounter).toEqual(recipientNoteHash.counter); - expect(result.callStackItem.publicInputs.encryptedLogPreimagesLength).toEqual( + expect(encryptedChangeLog.length.add(encryptedRecipientLog.length)).toEqual( new Fr(getEncryptedNoteSerializedLength(result)), ); @@ -487,7 +476,7 @@ describe('Private Execution test suite', () => { expect(encryptedChangeLog.noteHashCounter).toEqual(result.callStackItem.publicInputs.newNoteHashes[0].counter); expect(encryptedRecipientLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[1].log.hash())); expect(encryptedRecipientLog.noteHashCounter).toEqual(result.callStackItem.publicInputs.newNoteHashes[1].counter); - expect(result.callStackItem.publicInputs.encryptedLogPreimagesLength).toEqual( + expect(encryptedChangeLog.length.add(encryptedRecipientLog.length)).toEqual( new Fr(getEncryptedNoteSerializedLength(result)), ); }); diff --git a/yarn-project/simulator/src/mocks/fixtures.ts b/yarn-project/simulator/src/mocks/fixtures.ts index 1ff924ed85c..da4763a3ca0 100644 --- a/yarn-project/simulator/src/mocks/fixtures.ts +++ b/yarn-project/simulator/src/mocks/fixtures.ts @@ -116,7 +116,6 @@ export class PublicExecutionResultBuilder { contractStorageReads: [], unencryptedLogsHashes: [], unencryptedLogs: UnencryptedFunctionL2Logs.empty(), - unencryptedLogPreimagesLength: new Fr(4n), // empty logs have len 4 allUnencryptedLogs: UnencryptedFunctionL2Logs.empty(), startSideEffectCounter: Fr.ZERO, endSideEffectCounter: Fr.ZERO, diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index 3da3ffa306e..f9c0dd25aff 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -452,7 +452,6 @@ export abstract class AbstractPhaseManager { ), publicCallStackHashes, unencryptedLogsHashes: padArrayEnd(result.unencryptedLogsHashes, LogHash.empty(), MAX_UNENCRYPTED_LOGS_PER_CALL), - unencryptedLogPreimagesLength: result.unencryptedLogPreimagesLength, historicalHeader: this.historicalHeader, globalVariables: this.globalVariables, startGasLeft: Gas.from(result.startGasLeft), diff --git a/yarn-project/simulator/src/public/execution.ts b/yarn-project/simulator/src/public/execution.ts index 7f5a1303568..ff63cd0138b 100644 --- a/yarn-project/simulator/src/public/execution.ts +++ b/yarn-project/simulator/src/public/execution.ts @@ -54,10 +54,6 @@ export interface PublicExecutionResult { * Note: These are preimages to `unencryptedLogsHashes`. */ unencryptedLogs: UnencryptedFunctionL2Logs; - /** - * Length of the unencrypted log preimages emitted in this function call. - */ - unencryptedLogPreimagesLength: Fr; /** * Unencrypted logs emitted during this call AND any nested calls. * Useful for maintaining correct ordering in ts. diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 9157508a9fb..cd6b8a0ef80 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -191,7 +191,6 @@ async function executePublicFunctionAcvm( nestedExecutions: [], unencryptedLogsHashes: [], unencryptedLogs: UnencryptedFunctionL2Logs.empty(), - unencryptedLogPreimagesLength: Fr.ZERO, allUnencryptedLogs: UnencryptedFunctionL2Logs.empty(), reverted, revertReason, @@ -216,7 +215,6 @@ async function executePublicFunctionAcvm( startSideEffectCounter, endSideEffectCounter, unencryptedLogsHashes: unencryptedLogsHashesPadded, - unencryptedLogPreimagesLength, } = PublicCircuitPublicInputs.fromFields(returnWitness); const returnValues = await context.unpackReturns(returnsHash); @@ -263,7 +261,6 @@ async function executePublicFunctionAcvm( nestedExecutions, unencryptedLogsHashes, unencryptedLogs, - unencryptedLogPreimagesLength, allUnencryptedLogs, reverted: false, revertReason: undefined, diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 9b17a5908bf..fb3d199d30c 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -338,9 +338,8 @@ describe('ACIR public execution simulator', () => { expect(Fr.fromBuffer(childExecutionResult.unencryptedLogs.logs[0].hash())).toEqual( childExecutionResult.unencryptedLogsHashes[0].value, ); - // We take 4 to avoid counting the extra 4 bytes used to store len for L1 - expect(childExecutionResult.unencryptedLogPreimagesLength).toEqual( - new Fr(childExecutionResult.unencryptedLogs.getSerializedLength() - 4), + expect(childExecutionResult.unencryptedLogsHashes[0].length).toEqual( + new Fr(childExecutionResult.unencryptedLogs.getKernelLength()), ); expect(result.returnValues[0]).toEqual(new Fr(newValue)); }, 20_000); From b3b7376161f353a273bf26d42e435667b41cc5e2 Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Fri, 17 May 2024 11:36:04 -0400 Subject: [PATCH 02/37] refactor: share decider with ultra_prover (#5467) Call the decider prover in ultra_prover to avoid duplication of sumcheck/zeromorph rounds. Also removes the HonkProof& return types, which is unsafe. --- .../ultra_bench/ultra_honk_rounds.bench.cpp | 10 +++- .../barretenberg/client_ivc/client_ivc.hpp | 2 +- .../src/barretenberg/eccvm/eccvm_prover.cpp | 4 +- .../src/barretenberg/eccvm/eccvm_prover.hpp | 4 +- .../protogalaxy/protogalaxy.test.cpp | 2 +- .../protogalaxy_recursive_verifier.test.cpp | 2 +- .../goblin_translator_prover.cpp | 4 +- .../goblin_translator_prover.hpp | 4 +- .../decider_prover.cpp | 6 +- .../decider_prover.hpp | 4 +- .../ultra_honk/merge_verifier.cpp | 2 +- .../barretenberg/ultra_honk/ultra_prover.cpp | 56 ++++--------------- .../barretenberg/ultra_honk/ultra_prover.hpp | 12 +--- .../barretenberg/vm/generated/avm_prover.cpp | 4 +- .../barretenberg/vm/generated/avm_prover.hpp | 4 +- 15 files changed, 43 insertions(+), 77 deletions(-) rename barretenberg/cpp/src/barretenberg/{protogalaxy => ultra_honk}/decider_prover.cpp (91%) rename barretenberg/cpp/src/barretenberg/{protogalaxy => ultra_honk}/decider_prover.hpp (96%) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp index 79b53abb683..f113305191c 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp @@ -3,6 +3,7 @@ #include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/decider_prover.hpp" #include "barretenberg/ultra_honk/oink_prover.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" @@ -53,10 +54,13 @@ BB_PROFILE static void test_round_inner(State& state, GoblinUltraProver& prover, time_if_index(GRAND_PRODUCT_COMPUTATION, [&] { oink_prover.execute_grand_product_computation_round(); }); time_if_index(GENERATE_ALPHAS, [&] { prover.instance->alphas = oink_prover.generate_alphas_round(); }); // we need to get the relation_parameters and prover_polynomials from the oink_prover - prover.instance->proving_key = std::move(oink_prover.proving_key); prover.instance->relation_parameters = oink_prover.relation_parameters; - time_if_index(RELATION_CHECK, [&] { prover.execute_relation_check_rounds(); }); - time_if_index(ZEROMORPH, [&] { prover.execute_zeromorph_rounds(); }); + + prover.generate_gate_challenges(); + + DeciderProver_ decider_prover(prover.instance, prover.transcript); + time_if_index(RELATION_CHECK, [&] { decider_prover.execute_relation_check_rounds(); }); + time_if_index(ZEROMORPH, [&] { decider_prover.execute_zeromorph_rounds(); }); } BB_PROFILE static void test_round(State& state, size_t index) noexcept { diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 54c6a7991ff..eafc0f72aef 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -2,11 +2,11 @@ #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" -#include "barretenberg/protogalaxy/decider_prover.hpp" #include "barretenberg/protogalaxy/decider_verifier.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" #include "barretenberg/sumcheck/instance/instances.hpp" +#include "barretenberg/ultra_honk/decider_prover.hpp" namespace bb { diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index ea860e1e4c7..538963c3f29 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -184,13 +184,13 @@ void ECCVMProver::execute_transcript_consistency_univariate_opening_round() translation_batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); } -HonkProof& ECCVMProver::export_proof() +HonkProof ECCVMProver::export_proof() { proof = transcript->export_proof(); return proof; } -HonkProof& ECCVMProver::construct_proof() +HonkProof ECCVMProver::construct_proof() { BB_OP_COUNT_TIME_NAME("ECCVMProver::construct_proof"); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index a4f99d8cde0..24c6349d20e 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -37,8 +37,8 @@ class ECCVMProver { BB_PROFILE void execute_zeromorph_rounds(); BB_PROFILE void execute_transcript_consistency_univariate_opening_round(); - HonkProof& export_proof(); - HonkProof& construct_proof(); + HonkProof export_proof(); + HonkProof construct_proof(); std::shared_ptr transcript; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp index 3148c54cd40..f925de29c27 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp @@ -1,10 +1,10 @@ #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/polynomials/pow.hpp" -#include "barretenberg/protogalaxy/decider_prover.hpp" #include "barretenberg/protogalaxy/decider_verifier.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" #include "barretenberg/stdlib_circuit_builders/mock_circuits.hpp" +#include "barretenberg/ultra_honk/decider_prover.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp index 4d18d9f59d5..673d7234df9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp @@ -1,7 +1,6 @@ #include "barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.hpp" #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" -#include "barretenberg/protogalaxy/decider_prover.hpp" #include "barretenberg/protogalaxy/decider_verifier.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" @@ -11,6 +10,7 @@ #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib_circuit_builders/ultra_recursive_flavor.hpp" #include "barretenberg/sumcheck/instance/instances.hpp" +#include "barretenberg/ultra_honk/decider_prover.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp index 9fe6babcf77..abf534b0247 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp @@ -185,13 +185,13 @@ void GoblinTranslatorProver::execute_zeromorph_rounds() key->polynomials.get_concatenation_groups()); } -HonkProof& GoblinTranslatorProver::export_proof() +HonkProof GoblinTranslatorProver::export_proof() { proof = transcript->export_proof(); return proof; } -HonkProof& GoblinTranslatorProver::construct_proof() +HonkProof GoblinTranslatorProver::construct_proof() { BB_OP_COUNT_TIME_NAME("GoblinTranslatorProver::construct_proof"); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp index 077632dfc04..8dedc08ae41 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp @@ -37,8 +37,8 @@ class GoblinTranslatorProver { BB_PROFILE void execute_grand_product_computation_round(); BB_PROFILE void execute_relation_check_rounds(); BB_PROFILE void execute_zeromorph_rounds(); - HonkProof& export_proof(); - HonkProof& construct_proof(); + HonkProof export_proof(); + HonkProof construct_proof(); std::shared_ptr transcript = std::make_shared(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp similarity index 91% rename from barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp rename to barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp index 7c17c906600..75d90707ee4 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.cpp @@ -17,7 +17,7 @@ DeciderProver_::DeciderProver_(const std::shared_ptr& inst, const std::shared_ptr& transcript) : accumulator(std::move(inst)) , transcript(transcript) - , commitment_key(inst->proving_key.commitment_key) + , commitment_key(accumulator->proving_key.commitment_key) {} /** @@ -49,13 +49,13 @@ template void DeciderProver_::execute_zeromorph_r transcript); } -template HonkProof& DeciderProver_::export_proof() +template HonkProof DeciderProver_::export_proof() { proof = transcript->proof_data; return proof; } -template HonkProof& DeciderProver_::construct_proof() +template HonkProof DeciderProver_::construct_proof() { BB_OP_COUNT_TIME_NAME("Decider::construct_proof"); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.hpp similarity index 96% rename from barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp rename to barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.hpp index 977605f5a7d..3df1166b635 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_prover.hpp @@ -30,8 +30,8 @@ template class DeciderProver_ { BB_PROFILE void execute_relation_check_rounds(); BB_PROFILE void execute_zeromorph_rounds(); - HonkProof& export_proof(); - HonkProof& construct_proof(); + HonkProof export_proof(); + HonkProof construct_proof(); std::shared_ptr accumulator; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 18e30a1cdaf..72cadbe963c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -17,7 +17,7 @@ MergeVerifier_::MergeVerifier_() * Schwartz-Zippel check. Evaluations are checked via batched KZG. * * @tparam Flavor - * @return HonkProof& + * @return bool */ template bool MergeVerifier_::verify_proof(const HonkProof& proof) { diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index 7030f194cb4..fb7bdbc768d 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -1,7 +1,7 @@ #include "ultra_prover.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" +#include "barretenberg/ultra_honk/decider_prover.hpp" #include "barretenberg/ultra_honk/oink_prover.hpp" - namespace bb { /** @@ -32,64 +32,32 @@ UltraProver_::UltraProver_(Builder& circuit) , commitment_key(instance->proving_key.commitment_key) {} -/** - * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. - * - */ -template void UltraProver_::execute_relation_check_rounds() +template HonkProof UltraProver_::export_proof() { - using Sumcheck = SumcheckProver; - auto circuit_size = instance->proving_key.circuit_size; - auto sumcheck = Sumcheck(circuit_size, transcript); - - std::vector gate_challenges(numeric::get_msb(circuit_size)); + proof = transcript->proof_data; + return proof; +} +template void UltraProver_::generate_gate_challenges() +{ + std::vector gate_challenges(numeric::get_msb(instance->proving_key.circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } instance->gate_challenges = gate_challenges; - sumcheck_output = sumcheck.prove(instance); } -/** - * @brief Execute the ZeroMorph protocol to prove the multilinear evaluations produced by Sumcheck - * @details See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. - * - * */ -template void UltraProver_::execute_zeromorph_rounds() -{ - ZeroMorph::prove(instance->proving_key.polynomials.get_unshifted(), - instance->proving_key.polynomials.get_to_be_shifted(), - sumcheck_output.claimed_evaluations.get_unshifted(), - sumcheck_output.claimed_evaluations.get_shifted(), - sumcheck_output.challenge, - commitment_key, - transcript); -} - -template HonkProof& UltraProver_::export_proof() -{ - proof = transcript->proof_data; - return proof; -} - -template HonkProof& UltraProver_::construct_proof() +template HonkProof UltraProver_::construct_proof() { OinkProver oink_prover(instance->proving_key, transcript); auto [proving_key, relation_params, alphas] = oink_prover.prove(); instance->proving_key = std::move(proving_key); - instance->relation_parameters = std::move(relation_params); instance->alphas = alphas; - // Fiat-Shamir: alpha - // Run sumcheck subprotocol. - execute_relation_check_rounds(); - - // Fiat-Shamir: rho, y, x, z - // Execute Zeromorph multilinear PCS - execute_zeromorph_rounds(); + generate_gate_challenges(); - return export_proof(); + DeciderProver_ decider_prover(instance, transcript); + return decider_prover.construct_proof(); } template class UltraProver_; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp index 279890e614b..d0b5641081b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp @@ -43,16 +43,10 @@ template class UltraProver_ { explicit UltraProver_(Builder&); - BB_PROFILE void execute_preamble_round(); - BB_PROFILE void execute_wire_commitments_round(); - BB_PROFILE void execute_sorted_list_accumulator_round(); - BB_PROFILE void execute_log_derivative_inverse_round(); - BB_PROFILE void execute_grand_product_computation_round(); - BB_PROFILE void execute_relation_check_rounds(); - BB_PROFILE void execute_zeromorph_rounds(); + BB_PROFILE void generate_gate_challenges(); - HonkProof& export_proof(); - HonkProof& construct_proof(); + HonkProof export_proof(); + HonkProof construct_proof(); private: HonkProof proof; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp index a88fac34e33..51be0ce1ac2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp @@ -750,13 +750,13 @@ void AvmProver::execute_zeromorph_rounds() transcript); } -HonkProof& AvmProver::export_proof() +HonkProof AvmProver::export_proof() { proof = transcript->proof_data; return proof; } -HonkProof& AvmProver::construct_proof() +HonkProof AvmProver::construct_proof() { // Add circuit size public input size and public inputs to transcript. execute_preamble_round(); diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp index 47e2603a9ca..74d504446a3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp @@ -32,8 +32,8 @@ class AvmProver { void execute_relation_check_rounds(); void execute_zeromorph_rounds(); - HonkProof& export_proof(); - HonkProof& construct_proof(); + HonkProof export_proof(); + HonkProof construct_proof(); std::shared_ptr transcript = std::make_shared(); From 237952e9fe5ea46585580c168421b6cdcdbf64e5 Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 17 May 2024 12:03:00 -0400 Subject: [PATCH 03/37] fix: arm ci (#6480) --- .github/workflows/ci-arm.yml | 52 +++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index 1b1f5234ddb..dc5ec576342 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -8,42 +8,52 @@ concurrency: # force parallelism in master, cancelling in branches (only relevant to workflow_dispatch) group: ci-${{ github.ref_name == 'master' && github.run_id || github.ref_name }} cancel-in-progress: true +env: + DOCKERHUB_PASSWORD: "${{ secrets.DOCKERHUB_PASSWORD }}" + RUN_ID: ${{ github.run_id }} + RUN_ATTEMPT: ${{ github.run_attempt }} + USERNAME: ${{ github.event.pull_request.user.login || github.actor }} + GITHUB_TOKEN: ${{ github.token }} + GH_SELF_HOSTED_RUNNER_TOKEN: ${{ secrets.GH_SELF_HOSTED_RUNNER_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + BUILD_INSTANCE_SSH_KEY: ${{ secrets.BUILD_INSTANCE_SSH_KEY }} + GIT_COMMIT: ${{ github.sha }} + # kludge until we move away from runners + WAIT_FOR_RUNNERS: false jobs: - setup: - uses: ./.github/workflows/setup-runner.yml - with: - username: master - runner_type: builder-arm - secrets: inherit - build: - needs: setup - runs-on: master-arm + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { ref: "${{ github.event.pull_request.head.sha }}" } - - uses: ./.github/ci-setup-action - with: - concurrency_key: build-master-arm - # prepare images locally, tagged by commit hash - name: "Build E2E Image" timeout-minutes: 40 - run: earthly-ci ./yarn-project+export-e2e-test-images + uses: ./.github/ensure-builder + with: + runner_type: builder-x86 + run: | + set -eux + git submodule update --init --recursive --recommend-shallow + echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u aztecprotocolci --password-stdin + scripts/earthly-ci ./yarn-project+export-e2e-test-images # all the end-to-end integration tests for aztec e2e: needs: build - runs-on: master-arm + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { ref: "${{ github.event.pull_request.head.sha }}" } - - uses: ./.github/ci-setup-action - with: - concurrency_key: e2e-master-arm-e2e-tests - - name: Test - working-directory: ./yarn-project/end-to-end/ + - name: "Test" timeout-minutes: 15 - run: earthly-ci -P --no-output +uniswap-trade-on-l1-from-l2 + uses: ./.github/ensure-builder + with: + runner_type: builder-x86 + run: | + set -eux + echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u aztecprotocolci --password-stdin + scripts/earthly-ci -P --no-output ./yarn-project/end-to-end/+uniswap-trade-on-l1-from-l2 notify: needs: [e2e] From 3a4d82857326ceb099cbd2af307cc6836027dfd1 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 17 May 2024 18:03:23 +0200 Subject: [PATCH 04/37] fix: quick fix of #6405 by removing context from value note utils (#6509) Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- .../aztec-nr/value-note/src/utils.nr | 35 ++++++------------- .../benchmarking_contract/src/main.nr | 4 +-- .../stateful_test_contract/src/main.nr | 12 +++---- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 80392c24b2f..4c4ba85021c 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -12,14 +12,10 @@ pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteG // Creates a new note for the recipient. // Inserts it to the recipient's set of notes. -pub fn increment( - mut context: PrivateContext, - balance: PrivateSet, - amount: Field, - recipient: AztecAddress -) { - let recipient_npk_m_hash = get_npk_m_hash(&mut context, recipient); - let recipient_ivpk_m = get_ivpk_m(&mut context, recipient); +pub fn increment(balance: PrivateSet, amount: Field, recipient: AztecAddress) { + let context = balance.context.private.unwrap(); + let recipient_npk_m_hash = get_npk_m_hash(context, recipient); + let recipient_ivpk_m = get_ivpk_m(context, recipient); let mut note = ValueNote::new(amount, recipient_npk_m_hash); // Insert the new note to the owner's set of notes and emit the log if value is non-zero. @@ -30,13 +26,8 @@ pub fn increment( // Remove those notes. // If the value of the removed notes exceeds the requested `amount`, create a new note containing the excess value, so that exactly `amount` is removed. // Fail if the sum of the selected notes is less than the amount. -pub fn decrement( - mut context: PrivateContext, - balance: PrivateSet, - amount: Field, - owner: AztecAddress -) { - let sum = decrement_by_at_most(context, balance, amount, owner); +pub fn decrement(balance: PrivateSet, amount: Field, owner: AztecAddress) { + let sum = decrement_by_at_most(balance, amount, owner); assert(sum == amount, "Balance too low"); } @@ -49,7 +40,6 @@ pub fn decrement( // // It returns the decremented amount, which should be less than or equal to max_amount. pub fn decrement_by_at_most( - mut context: PrivateContext, balance: PrivateSet, max_amount: Field, owner: AztecAddress @@ -60,7 +50,7 @@ pub fn decrement_by_at_most( let mut decremented = 0; for i in 0..opt_notes.len() { if opt_notes[i].is_some() { - decremented += destroy_note(context, balance, owner, opt_notes[i].unwrap_unchecked()); + decremented += destroy_note(balance, owner, opt_notes[i].unwrap_unchecked()); } } @@ -70,22 +60,17 @@ pub fn decrement_by_at_most( change_value = decremented - max_amount; decremented -= change_value; } - increment(context, balance, change_value, owner); + increment(balance, change_value, owner); decremented } // Removes the note from the owner's set of notes. // Returns the value of the destroyed note. -pub fn destroy_note( - mut context: PrivateContext, - balance: PrivateSet, - owner: AztecAddress, - note: ValueNote -) -> Field { +pub fn destroy_note(balance: PrivateSet, owner: AztecAddress, note: ValueNote) -> Field { // Ensure the note is actually owned by the owner (to prevent user from generating a valid proof while // spending someone else's notes). - let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let owner_npk_m_hash = get_npk_m_hash(balance.context.private.unwrap(), owner); // TODO (#6312): This will break with key rotation. Fix this. Will not be able to pass this after rotating keys. assert(note.npk_m_hash.eq(owner_npk_m_hash)); diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index 1a81cef4ff6..a8b9f34d36b 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -18,7 +18,7 @@ contract Benchmarking { // Creates a new value note for the target owner. Use this method to seed an initial set of notes. #[aztec(private)] fn create_note(owner: AztecAddress, value: Field) { - increment(context, storage.notes.at(owner), value, owner); + increment(storage.notes.at(owner), value, owner); } // Deletes a note at a specific index in the set and creates a new one with the same value. @@ -33,7 +33,7 @@ contract Benchmarking { let notes = owner_notes.get_notes(getter_options.set_limit(1).set_offset(index)); let note = notes[0].unwrap_unchecked(); owner_notes.remove(note); - increment(context, owner_notes, note.value, owner); + increment(owner_notes, note.value, owner); } // Reads and writes to public storage and enqueues a call to another public function. diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index db8c9965eb2..2c3b7e682f6 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -37,7 +37,7 @@ contract StatefulTest { fn create_note(owner: AztecAddress, value: Field) { if (value != 0) { let loc = storage.notes.at(owner); - increment(context, loc, value, owner); + increment(loc, value, owner); } } @@ -47,7 +47,7 @@ contract StatefulTest { if (value != 0) { let loc = storage.notes.at(owner); // TODO (#6312): This will break with key rotation. Fix this. Will not be able to spend / increment any notes after rotating key. - increment(context, loc, value, owner); + increment(loc, value, owner); } } @@ -57,10 +57,10 @@ contract StatefulTest { let sender = context.msg_sender(); let sender_notes = storage.notes.at(sender); - decrement(context, sender_notes, amount, sender); + decrement(sender_notes, amount, sender); let recipient_notes = storage.notes.at(recipient); - increment(context, recipient_notes, amount, recipient); + increment(recipient_notes, amount, recipient); } #[aztec(private)] @@ -69,10 +69,10 @@ contract StatefulTest { let sender = context.msg_sender(); let sender_notes = storage.notes.at(sender); - decrement(context, sender_notes, amount, sender); + decrement(sender_notes, amount, sender); let recipient_notes = storage.notes.at(recipient); - increment(context, recipient_notes, amount, recipient); + increment(recipient_notes, amount, recipient); } #[aztec(public)] From e298c766d17029a9dbfce694b48327c5e76dfddb Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Fri, 17 May 2024 17:30:08 +0100 Subject: [PATCH 05/37] chore: remove acvmInfo from bb.js CLI (#6507) This is now unused (equivalent code was removed from `bb` binary) --- barretenberg/ts/src/info.ts | 24 ------------------------ barretenberg/ts/src/main.ts | 21 --------------------- 2 files changed, 45 deletions(-) delete mode 100644 barretenberg/ts/src/info.ts diff --git a/barretenberg/ts/src/info.ts b/barretenberg/ts/src/info.ts deleted file mode 100644 index f5ad9980591..00000000000 --- a/barretenberg/ts/src/info.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* eslint-disable camelcase */ -export const acvmInfoJson = { - language: { - name: 'PLONK-CSAT', - width: 3, - }, - opcodes_supported: ['arithmetic', 'directive', 'brillig', 'memory_init', 'memory_op'], - black_box_functions_supported: [ - 'and', - 'xor', - 'range', - 'aes128_encrypt', - 'sha256', - 'blake2s', - 'keccak256', - 'schnorr_verify', - 'pedersen', - 'pedersen_hash', - 'ecdsa_secp256k1', - 'ecdsa_secp256r1', - 'multi_scalar_mul', - 'recursive_aggregation', - ], -}; diff --git a/barretenberg/ts/src/main.ts b/barretenberg/ts/src/main.ts index 5e864f7867d..8e07dceb8c0 100755 --- a/barretenberg/ts/src/main.ts +++ b/barretenberg/ts/src/main.ts @@ -4,7 +4,6 @@ import createDebug from 'debug'; import { readFileSync, writeFileSync } from 'fs'; import { gunzipSync } from 'zlib'; import { Command } from 'commander'; -import { acvmInfoJson } from './info.js'; import { Timer, writeBenchmark } from './benchmark/index.js'; import path from 'path'; import { GrumpkinCrs } from './crs/node/index.js'; @@ -233,17 +232,6 @@ export async function gateCount(bytecodePath: string) { } } -export function acvmInfo(outputPath: string) { - const stringifiedJson = JSON.stringify(acvmInfoJson, null, 2); - if (outputPath === '-') { - process.stdout.write(stringifiedJson); - debug(`info written to stdout`); - } else { - writeFileSync(outputPath, stringifiedJson); - debug(`info written to: ${outputPath}`); - } -} - export async function verify(proofPath: string, vkPath: string) { const { api, acirComposer } = await initLite(); try { @@ -598,15 +586,6 @@ program await vkAsFields(vkPath, outputPath); }); -program - .command('info') - .description('Return ACVM related metadata about the backend') - .requiredOption('-o, --output-path ', 'Specify the path to write the JSON information to') - .action(({ outputPath }) => { - handleGlobalOptions(); - acvmInfo(outputPath); - }); - program .command('prove_ultra_honk') .description('Generate a proof and write it to a file.') From 5c733d1fc9152317a89731793896487a5c72cc30 Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 17 May 2024 13:18:28 -0400 Subject: [PATCH 06/37] hotfix: workaround ARM issue --- .github/workflows/ci-arm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index dc5ec576342..2828c3d3289 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -1,7 +1,7 @@ name: CI (ARM) on: push: - branches: [master] + branches: [disabled] workflow_dispatch: inputs: {} concurrency: From 26f2197b01331577bb499234050cc33a71c47f05 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Fri, 17 May 2024 13:51:31 -0400 Subject: [PATCH 07/37] feat: Sync from noir (#6500) Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE feat: do not return databus returndata, keep it private. (https://github.com/noir-lang/noir/pull/5023) fix: Fixed several vulnerabilities in U128, added some tests (https://github.com/noir-lang/noir/pull/5024) fix: Fix no predicates for brillig with intermediate functions (https://github.com/noir-lang/noir/pull/5015) chore: add script to print lines of code (https://github.com/noir-lang/noir/pull/4991) END_COMMIT_OVERRIDE Co-authored-by: TomAFrench --- .noir-sync-commit | 2 +- noir/noir-repo/.tokeignore | 12 + .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 21 +- .../noirc_evaluator/src/ssa/opt/inlining.rs | 3 +- noir/noir-repo/noir_stdlib/src/uint128.nr | 252 ++++++++++++++++-- noir/noir-repo/scripts/count_loc.sh | 33 +++ .../security/insectarium/noir_stdlib.md | 61 +++++ .../no_predicates_brillig/src/main.nr | 4 + noir/noir-repo/tooling/noirc_abi/src/lib.rs | 10 +- 9 files changed, 376 insertions(+), 22 deletions(-) create mode 100644 noir/noir-repo/.tokeignore create mode 100755 noir/noir-repo/scripts/count_loc.sh create mode 100644 noir/noir-repo/security/insectarium/noir_stdlib.md diff --git a/.noir-sync-commit b/.noir-sync-commit index e7c73939ac6..bec736647ac 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -b541e793e20fa3c991e0328ec2ff7926bdcdfd45 +a5b7df12faf9d71ff24f8c5cde5e78da44558caf diff --git a/noir/noir-repo/.tokeignore b/noir/noir-repo/.tokeignore new file mode 100644 index 00000000000..55f24e41dbd --- /dev/null +++ b/noir/noir-repo/.tokeignore @@ -0,0 +1,12 @@ +docs +scripts + +# aztec_macros is explicitly considered OOS for Noir audit +aztec_macros + +# config files +*.toml +*.md +*.json +*.txt +*.config.mjs diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 0de0c28be75..117804b370a 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -1741,13 +1741,16 @@ impl<'a> Context<'a> { // will expand the array if there is one. let return_acir_vars = self.flatten_value_list(return_values, dfg)?; let mut warnings = Vec::new(); - for acir_var in return_acir_vars { + for (acir_var, is_databus) in return_acir_vars { if self.acir_context.is_constant(&acir_var) { warnings.push(SsaReport::Warning(InternalWarning::ReturnConstant { call_stack: call_stack.clone(), })); } - self.acir_context.return_var(acir_var)?; + if !is_databus { + // We do not return value for the data bus. + self.acir_context.return_var(acir_var)?; + } } Ok(warnings) } @@ -2671,12 +2674,22 @@ impl<'a> Context<'a> { &mut self, arguments: &[ValueId], dfg: &DataFlowGraph, - ) -> Result, InternalError> { + ) -> Result, InternalError> { let mut acir_vars = Vec::with_capacity(arguments.len()); for value_id in arguments { + let is_databus = if let Some(return_databus) = self.data_bus.return_data { + dfg[*value_id] == dfg[return_databus] + } else { + false + }; let value = self.convert_value(*value_id, dfg); acir_vars.append( - &mut self.acir_context.flatten(value)?.iter().map(|(var, _)| *var).collect(), + &mut self + .acir_context + .flatten(value)? + .iter() + .map(|(var, _)| (*var, is_databus)) + .collect(), ); } Ok(acir_vars) diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index 77b9e545e03..73dc3888184 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -393,10 +393,11 @@ impl<'function> PerFunctionContext<'function> { let function = &ssa.functions[&func_id]; // If we have not already finished the flattening pass, functions marked // to not have predicates should be marked as entry points unless we are inlining into brillig. + let entry_point = &ssa.functions[&self.context.entry_point]; let no_predicates_is_entry_point = self.context.no_predicates_is_entry_point && function.is_no_predicates() - && !matches!(self.source_function.runtime(), RuntimeType::Brillig); + && !matches!(entry_point.runtime(), RuntimeType::Brillig); if function.runtime().is_entry_point() || no_predicates_is_entry_point { self.push_instruction(*id); } else { diff --git a/noir/noir-repo/noir_stdlib/src/uint128.nr b/noir/noir-repo/noir_stdlib/src/uint128.nr index 9c61fc801f3..0332c8ac865 100644 --- a/noir/noir-repo/noir_stdlib/src/uint128.nr +++ b/noir/noir-repo/noir_stdlib/src/uint128.nr @@ -1,8 +1,9 @@ use crate::ops::{Add, Sub, Mul, Div, Rem, Not, BitOr, BitAnd, BitXor, Shl, Shr}; use crate::cmp::{Eq, Ord, Ordering}; +use crate::println; global pow64 : Field = 18446744073709551616; //2^64; - +global pow63 : Field = 9223372036854775808; // 2^63; struct U128 { lo: Field, hi: Field, @@ -20,6 +21,13 @@ impl U128 { U128::from_u64s_le(lo, hi) } + pub fn zero() -> U128 { + U128 { lo: 0, hi: 0 } + } + + pub fn one() -> U128 { + U128 { lo: 1, hi: 0 } + } pub fn from_le_bytes(bytes: [u8; 16]) -> U128 { let mut lo = 0; let mut base = 1; @@ -87,27 +95,44 @@ impl U128 { U128 { lo: lo as Field, hi: hi as Field } } + unconstrained fn uconstrained_check_is_upper_ascii(ascii: u8) -> bool { + ((ascii >= 65) & (ascii <= 90)) // Between 'A' and 'Z' + } + fn decode_ascii(ascii: u8) -> Field { if ascii < 58 { ascii - 48 - } else if ascii < 71 { - ascii - 55 } else { + let ascii = ascii + 32 * (U128::uconstrained_check_is_upper_ascii(ascii) as u8); + assert(ascii >= 97); // enforce >= 'a' + assert(ascii <= 102); // enforce <= 'f' ascii - 87 } as Field } + // TODO: Replace with a faster version. + // A circuit that uses this function can be slow to compute + // (we're doing up to 127 calls to compute the quotient) unconstrained fn unconstrained_div(self: Self, b: U128) -> (U128, U128) { - if self < b { - (U128::from_u64s_le(0, 0), self) + if b == U128::zero() { + // Return 0,0 to avoid eternal loop + (U128::zero(), U128::zero()) + } else if self < b { + (U128::zero(), self) + } else if self == b { + (U128::one(), U128::zero()) } else { - //TODO check if this can overflow? - let (q,r) = self.unconstrained_div(b * U128::from_u64s_le(2, 0)); + let (q,r) = if b.hi as u64 >= pow63 as u64 { + // The result of multiplication by 2 would overflow + (U128::zero(), self) + } else { + self.unconstrained_div(b * U128::from_u64s_le(2, 0)) + }; let q_mul_2 = q * U128::from_u64s_le(2, 0); if r < b { (q_mul_2, r) } else { - (q_mul_2 + U128::from_u64s_le(1, 0), r - b) + (q_mul_2 + U128::one(), r - b) } } } @@ -129,11 +154,7 @@ impl U128 { let low = self.lo * b.lo; let lo = low as u64 as Field; let carry = (low - lo) / pow64; - let high = if crate::field::modulus_num_bits() as u32 > 196 { - (self.lo + self.hi) * (b.lo + b.hi) - low + carry - } else { - self.lo * b.hi + self.hi * b.lo + carry - }; + let high = self.lo * b.hi + self.hi * b.lo + carry; let hi = high as u64 as Field; U128 { lo, hi } } @@ -294,8 +315,8 @@ impl Shr for U128 { } } -mod test { - use crate::uint128::{U128, pow64}; +mod tests { + use crate::uint128::{U128, pow64, pow63}; #[test] fn test_not() { @@ -309,4 +330,205 @@ mod test { let not_not_num = not_num.not(); assert_eq(num, not_not_num); } + + #[test] + fn test_construction() { + // Check little-endian u64 is inversed with big-endian u64 construction + let a = U128::from_u64s_le(2, 1); + let b = U128::from_u64s_be(1, 2); + assert_eq(a, b); + // Check byte construction is equivalent + let c = U128::from_le_bytes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let d = U128::from_u64s_le(0x0706050403020100, 0x0f0e0d0c0b0a0908); + assert_eq(c, d); + } + + #[test] + fn test_byte_decomposition() { + let a = U128::from_u64s_le(0x0706050403020100, 0x0f0e0d0c0b0a0908); + // Get big-endian and little-endian byte decompostions + let le_bytes_a= a.to_le_bytes(); + let be_bytes_a= a.to_be_bytes(); + + // Check equivalence + for i in 0..16 { + assert_eq(le_bytes_a[i], be_bytes_a[15 - i]); + } + // Reconstruct U128 from byte decomposition + let b= U128::from_le_bytes(le_bytes_a); + // Check that it's the same element + assert_eq(a, b); + } + + #[test] + fn test_hex_constuction() { + let a = U128::from_u64s_le(0x1, 0x2); + let b = U128::from_hex("0x20000000000000001"); + assert_eq(a, b); + + let c= U128::from_hex("0xffffffffffffffffffffffffffffffff"); + let d= U128::from_u64s_le(0xffffffffffffffff, 0xffffffffffffffff); + assert_eq(c, d); + + let e= U128::from_hex("0x00000000000000000000000000000000"); + let f= U128::from_u64s_le(0, 0); + assert_eq(e, f); + } + + // Ascii decode tests + + #[test] + fn test_ascii_decode_correct_range() { + // '0'..'9' range + for i in 0..10 { + let decoded= U128::decode_ascii(48 + i); + assert_eq(decoded, i as Field); + } + // 'A'..'F' range + for i in 0..6 { + let decoded = U128::decode_ascii(65 + i); + assert_eq(decoded, (i + 10) as Field); + } + // 'a'..'f' range + for i in 0..6 { + let decoded = U128::decode_ascii(97 + i); + assert_eq(decoded, (i + 10) as Field); + } + } + + #[test(should_fail)] + fn test_ascii_decode_range_less_than_48_fails_0() { + crate::println(U128::decode_ascii(0)); + } + + #[test(should_fail)] + fn test_ascii_decode_range_less_than_48_fails_1() { + crate::println(U128::decode_ascii(47)); + } + + #[test(should_fail)] + fn test_ascii_decode_range_58_64_fails_0() { + let _ = U128::decode_ascii(58); + } + + #[test(should_fail)] + fn test_ascii_decode_range_58_64_fails_1() { + let _ = U128::decode_ascii(64); + } + + #[test(should_fail)] + fn test_ascii_decode_range_71_96_fails_0() { + let _ = U128::decode_ascii(71); + } + + #[test(should_fail)] + fn test_ascii_decode_range_71_96_fails_1() { + let _ = U128::decode_ascii(96); + } + + #[test(should_fail)] + fn test_ascii_decode_range_greater_than_102_fails() { + let _ = U128::decode_ascii(103); + } + + #[test(should_fail)] + fn test_ascii_decode_regression() { + // This code will actually fail because of ascii_decode, + // but in the past it was possible to create a value > (1<<128) + let a = U128::from_hex("0x~fffffffffffffffffffffffffffffff"); + let b:Field= a.to_integer(); + let c= b.to_le_bytes(17); + assert(c[16] != 0); + } + + #[test] + fn test_unconstrained_div() { + // Test the potential overflow case + let a= U128::from_u64s_le(0x0, 0xffffffffffffffff); + let b= U128::from_u64s_le(0x0, 0xfffffffffffffffe); + let c= U128::one(); + let d= U128::from_u64s_le(0x0, 0x1); + let (q,r) = a.unconstrained_div(b); + assert_eq(q, c); + assert_eq(r, d); + + let a = U128::from_u64s_le(2, 0); + let b = U128::one(); + // Check the case where a is a multiple of b + let (c,d ) = a.unconstrained_div(b); + assert_eq((c, d), (a, U128::zero())); + + // Check where b is a multiple of a + let (c,d) = b.unconstrained_div(a); + assert_eq((c, d), (U128::zero(), b)); + + // Dividing by zero returns 0,0 + let a = U128::from_u64s_le(0x1, 0x0); + let b = U128::zero(); + let (c,d)= a.unconstrained_div(b); + assert_eq((c, d), (U128::zero(), U128::zero())); + + // Dividing 1<<127 by 1<<127 (special case) + let a = U128::from_u64s_le(0x0, pow63 as u64); + let b = U128::from_u64s_le(0x0, pow63 as u64); + let (c,d )= a.unconstrained_div(b); + assert_eq((c, d), (U128::one(), U128::zero())); + } + + #[test] + fn integer_conversions() { + // Maximum + let start:Field = 0xffffffffffffffffffffffffffffffff; + let a = U128::from_integer(start); + let end = a.to_integer(); + assert_eq(start, end); + + // Minimum + let start:Field = 0x0; + let a = U128::from_integer(start); + let end = a.to_integer(); + assert_eq(start, end); + + // Low limb + let start:Field = 0xffffffffffffffff; + let a = U128::from_integer(start); + let end = a.to_integer(); + assert_eq(start, end); + + // High limb + let start:Field = 0xffffffffffffffff0000000000000000; + let a = U128::from_integer(start); + let end = a.to_integer(); + assert_eq(start, end); + } + #[test] + fn test_wrapping_mul() { + // 1*0==0 + assert_eq(U128::zero(), U128::zero().wrapping_mul(U128::one())); + + // 0*1==0 + assert_eq(U128::zero(), U128::one().wrapping_mul(U128::zero())); + + // 1*1==1 + assert_eq(U128::one(), U128::one().wrapping_mul(U128::one())); + + // 0 * ( 1 << 64 ) == 0 + assert_eq(U128::zero(), U128::zero().wrapping_mul(U128::from_u64s_le(0, 1))); + + // ( 1 << 64 ) * 0 == 0 + assert_eq(U128::zero(), U128::from_u64s_le(0, 1).wrapping_mul(U128::zero())); + + // 1 * ( 1 << 64 ) == 1 << 64 + assert_eq(U128::from_u64s_le(0, 1), U128::from_u64s_le(0, 1).wrapping_mul(U128::one())); + + // ( 1 << 64 ) * 1 == 1 << 64 + assert_eq(U128::from_u64s_le(0, 1), U128::one().wrapping_mul(U128::from_u64s_le(0, 1))); + + // ( 1 << 64 ) * ( 1 << 64 ) == 1 << 64 + assert_eq(U128::zero(), U128::from_u64s_le(0, 1).wrapping_mul(U128::from_u64s_le(0, 1))); + // -1 * -1 == 1 + assert_eq( + U128::one(), U128::from_u64s_le(0xffffffffffffffff, 0xffffffffffffffff).wrapping_mul(U128::from_u64s_le(0xffffffffffffffff, 0xffffffffffffffff)) + ); + } } diff --git a/noir/noir-repo/scripts/count_loc.sh b/noir/noir-repo/scripts/count_loc.sh new file mode 100755 index 00000000000..91565aa6c4a --- /dev/null +++ b/noir/noir-repo/scripts/count_loc.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -eu + +# Run relative to repo root +cd $(dirname "$0")/../ + +if ! command -v "tokei" >/dev/null 2>&1; then + echo "Error: tokei is required but not installed." >&2 + echo "Error: Run \`cargo install --git https://github.com/TomAFrench/tokei --branch tf/add-noir-support tokei\`" >&2 + + exit 1 +fi + +echo "" +echo "Total:" + +tokei ./ --sort code + +echo "" +echo "ACIR/ACVM:" +tokei ./acvm-repo --sort code + +echo "" +echo "Compiler:" +tokei ./compiler --sort code + +echo "" +echo "Tooling:" +tokei ./tooling --sort code + +echo "" +echo "Standard Library:" +tokei ./noir_stdlib --sort code diff --git a/noir/noir-repo/security/insectarium/noir_stdlib.md b/noir/noir-repo/security/insectarium/noir_stdlib.md new file mode 100644 index 00000000000..5ec4eb5f6cd --- /dev/null +++ b/noir/noir-repo/security/insectarium/noir_stdlib.md @@ -0,0 +1,61 @@ +# Bugs found in Noir stdlib + +## U128 + +### decode_ascii +Old **decode_ascii** function didn't check that the values of individual bytes in the string were just in the range of [0-9a-f-A-F]. +```rust +fn decode_ascii(ascii: u8) -> Field { + if ascii < 58 { + ascii - 48 + } else if ascii < 71 { + ascii - 55 + } else { + ascii - 87 + } as Field +} +``` +Since the function used the assumption that decode_ascii returns values in range [0,15] to construct **lo** and **hi** it was possible to overflow these 64-bit limbs. + +### unconstrained_div +```rust + unconstrained fn unconstrained_div(self: Self, b: U128) -> (U128, U128) { + if self < b { + (U128::from_u64s_le(0, 0), self) + } else { + //TODO check if this can overflow? + let (q,r) = self.unconstrained_div(b * U128::from_u64s_le(2, 0)); + let q_mul_2 = q * U128::from_u64s_le(2, 0); + if r < b { + (q_mul_2, r) + } else { + (q_mul_2 + U128::from_u64s_le(1, 0), r - b) + } + } + } +``` +There were 2 issues in unconstrained_div: +1) Attempting to divide by zero resulted in an infinite loop, because there was no check. +2) $a >= 2^{127}$ cause the function to multiply b to such power of 2 that the result would be more than $2^{128}$ and lead to assertion failure even though it was a legitimate input + +N.B. initial fix by Rumata888 also had an edgecase missing for when a==b and b >= (1<<127). + +### wrapping_mul +```rust +fn wrapping_mul(self: Self, b: U128) -> U128 { + let low = self.lo * b.lo; + let lo = low as u64 as Field; + let carry = (low - lo) / pow64; + let high = if crate::field::modulus_num_bits() as u32 > 196 { + (self.lo + self.hi) * (b.lo + b.hi) - low + carry // Bug + } else { + self.lo * b.hi + self.hi * b.lo + carry + }; + let hi = high as u64 as Field; + U128 { lo, hi } + } +``` +Wrapping mul had the code copied from regular mul barring the assertion that the product of high limbs is zero. Because that check was removed, the optimized path for moduli > 196 bits was incorrect, since it included their product (as at least one of them was supposed to be zero originally, but not for wrapping multiplication) + + + diff --git a/noir/noir-repo/test_programs/execution_success/no_predicates_brillig/src/main.nr b/noir/noir-repo/test_programs/execution_success/no_predicates_brillig/src/main.nr index 1d088473aa7..65e2e5d61fe 100644 --- a/noir/noir-repo/test_programs/execution_success/no_predicates_brillig/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/no_predicates_brillig/src/main.nr @@ -1,4 +1,8 @@ unconstrained fn main(x: u32, y: pub u32) { + intermediate_function(x, y); +} + +fn intermediate_function(x: u32, y: u32) { basic_checks(x, y); } diff --git a/noir/noir-repo/tooling/noirc_abi/src/lib.rs b/noir/noir-repo/tooling/noirc_abi/src/lib.rs index 7e89a102a98..7a1d1787ca5 100644 --- a/noir/noir-repo/tooling/noirc_abi/src/lib.rs +++ b/noir/noir-repo/tooling/noirc_abi/src/lib.rs @@ -471,7 +471,15 @@ impl Abi { .copied() }) { - Some(decode_value(&mut return_witness_values.into_iter(), &return_type.abi_type)?) + // We do not return value for the data bus. + if return_type.visibility == AbiVisibility::DataBus { + None + } else { + Some(decode_value( + &mut return_witness_values.into_iter(), + &return_type.abi_type, + )?) + } } else { // Unlike for the circuit inputs, we tolerate not being able to find the witness values for the return value. // This is because the user may be decoding a partial witness map for which is hasn't been calculated yet. From 75d81c5fccf52d270239261bab79dd1fde41c19a Mon Sep 17 00:00:00 2001 From: guipublic <47281315+guipublic@users.noreply.github.com> Date: Fri, 17 May 2024 20:18:41 +0200 Subject: [PATCH 08/37] feat!: add is_infinite to curve addition opcode (#6384) Resolves https://github.com/noir-lang/noir/issues/4978 Since elliptic curve addition in barretenberg is already handling the point at infinity, I simply expose it in the ACIR opcode. --- .../acir_format/acir_to_constraint_buf.hpp | 12 +- .../dsl/acir_format/ec_operations.cpp | 13 ++- .../dsl/acir_format/ec_operations.hpp | 6 +- .../dsl/acir_format/ec_operations.test.cpp | 91 +++++++++++++++ .../dsl/acir_format/multi_scalar_mul.cpp | 12 +- .../dsl/acir_format/multi_scalar_mul.hpp | 3 +- .../dsl/acir_format/serde/acir.hpp | 44 ++++---- .../aztec/src/keys/point_to_symmetric_key.nr | 7 +- .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 36 +++--- .../opcodes/black_box_function_call.rs | 22 ++-- .../acir/tests/test_program_serialization.rs | 25 +++-- .../src/pwg/blackbox/embedded_curve_ops.rs | 41 ++++--- .../acvm-repo/acvm/src/pwg/blackbox/mod.rs | 12 +- .../acvm_js/test/shared/multi_scalar_mul.ts | 21 ++-- .../src/curve_specific_solver.rs | 18 ++- .../src/embedded_curve_ops.rs | 104 +++++++++++------- .../bn254_blackbox_solver/src/lib.rs | 16 ++- .../acvm-repo/brillig/src/black_box.rs | 2 + .../acvm-repo/brillig_vm/src/black_box.rs | 57 ++++++++-- .../brillig/brillig_gen/brillig_black_box.rs | 4 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 11 +- .../src/brillig/brillig_ir/debug_show.rs | 4 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 17 ++- .../noir_stdlib/src/embedded_curve_ops.nr | 40 +++++-- .../intrinsic_die/src/main.nr | 4 +- .../brillig_embedded_curve/src/main.nr | 10 +- .../embedded_curve_ops/src/main.nr | 10 +- .../embedded_curve_ops/Nargo.toml | 7 ++ .../embedded_curve_ops/src/main.nr | 37 +++++++ noir/noir-repo/tooling/lsp/src/solver.rs | 19 +++- 30 files changed, 494 insertions(+), 211 deletions(-) create mode 100644 noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/Nargo.toml create mode 100644 noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/src/main.nr diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index 3e77b60d689..d51797034dc 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -342,15 +342,19 @@ void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, Aci .scalars = map(arg.scalars, [](auto& e) { return e.witness.value; }), .out_point_x = arg.outputs[0].value, .out_point_y = arg.outputs[1].value, + .out_point_is_infinite = arg.outputs[2].value, }); } else if constexpr (std::is_same_v) { af.ec_add_constraints.push_back(EcAdd{ - .input1_x = arg.input1_x.witness.value, - .input1_y = arg.input1_y.witness.value, - .input2_x = arg.input2_x.witness.value, - .input2_y = arg.input2_y.witness.value, + .input1_x = arg.input1[0].witness.value, + .input1_y = arg.input1[1].witness.value, + .input1_infinite = arg.input1[2].witness.value, + .input2_x = arg.input2[0].witness.value, + .input2_y = arg.input2[1].witness.value, + .input2_infinite = arg.input2[2].witness.value, .result_x = arg.outputs[0].value, .result_y = arg.outputs[1].value, + .result_infinite = arg.outputs[2].value, }); } else if constexpr (std::is_same_v) { af.keccak_constraints.push_back(KeccakConstraint{ diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp index 15494fa871a..4894537b659 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.cpp @@ -13,30 +13,35 @@ void create_ec_add_constraint(Builder& builder, const EcAdd& input, bool has_val // Input to cycle_group points using cycle_group_ct = bb::stdlib::cycle_group; using field_ct = bb::stdlib::field_t; + using bool_ct = bb::stdlib::bool_t; auto x1 = field_ct::from_witness_index(&builder, input.input1_x); auto y1 = field_ct::from_witness_index(&builder, input.input1_y); auto x2 = field_ct::from_witness_index(&builder, input.input2_x); auto y2 = field_ct::from_witness_index(&builder, input.input2_y); + auto infinite1 = bool_ct(field_ct::from_witness_index(&builder, input.input1_infinite)); + auto infinite2 = bool_ct(field_ct::from_witness_index(&builder, input.input2_infinite)); if (!has_valid_witness_assignments) { auto g1 = grumpkin::g1::affine_one; // We need to have correct values representing points on the curve builder.variables[input.input1_x] = g1.x; builder.variables[input.input1_y] = g1.y; + builder.variables[input.input1_infinite] = fr(0); builder.variables[input.input2_x] = g1.x; builder.variables[input.input2_y] = g1.y; + builder.variables[input.input2_infinite] = fr(0); } - - cycle_group_ct input1_point(x1, y1, false); - cycle_group_ct input2_point(x2, y2, false); - + cycle_group_ct input1_point(x1, y1, infinite1); + cycle_group_ct input2_point(x2, y2, infinite2); // Addition cycle_group_ct result = input1_point + input2_point; auto x_normalized = result.x.normalize(); auto y_normalized = result.y.normalize(); + auto infinite = result.is_point_at_infinity().normalize(); builder.assert_equal(x_normalized.witness_index, input.result_x); builder.assert_equal(y_normalized.witness_index, input.result_y); + builder.assert_equal(infinite.witness_index, input.result_infinite); } template void create_ec_add_constraint(UltraCircuitBuilder& builder, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.hpp index de28743d16a..5c16505bc90 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.hpp @@ -8,13 +8,17 @@ namespace acir_format { struct EcAdd { uint32_t input1_x; uint32_t input1_y; + uint32_t input1_infinite; uint32_t input2_x; uint32_t input2_y; + uint32_t input2_infinite; uint32_t result_x; uint32_t result_y; + uint32_t result_infinite; // for serialization, update with any new fields - MSGPACK_FIELDS(input1_x, input1_y, input2_x, input2_y, result_x, result_y); + MSGPACK_FIELDS( + input1_x, input1_y, input1_infinite, input2_x, input2_y, input2_infinite, result_x, result_y, result_infinite); friend bool operator==(EcAdd const& lhs, EcAdd const& rhs) = default; }; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index 65be4aaae55..59333ddc0d4 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -30,13 +30,18 @@ size_t generate_ec_add_constraint(EcAdd& ec_add_constraint, WitnessVector& witne witness_values.push_back(g1.y); witness_values.push_back(result.x.get_value()); witness_values.push_back(result.y.get_value()); + witness_values.push_back(fr(0)); + witness_values.push_back(fr(0)); ec_add_constraint = EcAdd{ .input1_x = 1, .input1_y = 2, + .input1_infinite = 7, .input2_x = 3, .input2_y = 4, + .input2_infinite = 7, .result_x = 5, .result_y = 6, + .result_infinite = 8, }; return witness_values.size(); } @@ -85,6 +90,92 @@ TEST_F(EcOperations, TestECOperations) auto prover = composer.create_prover(builder); auto proof = prover.construct_proof(); + + EXPECT_TRUE(CircuitChecker::check(builder)); + auto verifier = composer.create_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST_F(EcOperations, TestECMultiScalarMul) +{ + MultiScalarMul msm_constrain; + + WitnessVector witness_values; + witness_values.emplace_back(fr(0)); + + witness_values = { + // dummy + fr(0), + // g1: x,y,infinite + fr(1), + fr("0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"), + fr(0), + // low, high scalars + fr(1), + fr(0), + // result + fr("0x06ce1b0827aafa85ddeb49cdaa36306d19a74caa311e13d46d8bc688cdbffffe"), + fr("0x1c122f81a3a14964909ede0ba2a6855fc93faf6fa1a788bf467be7e7a43f80ac"), + fr(0), + }; + msm_constrain = MultiScalarMul{ + .points = { 1, 2, 3, 1, 2, 3 }, + .scalars = { 4, 5, 4, 5 }, + .out_point_x = 6, + .out_point_y = 7, + .out_point_is_infinite = 0, + }; + auto res_x = fr("0x06ce1b0827aafa85ddeb49cdaa36306d19a74caa311e13d46d8bc688cdbffffe"); + auto assert_equal = poly_triple{ + .a = 6, + .b = 0, + .c = 0, + .q_m = 0, + .q_l = fr::neg_one(), + .q_r = 0, + .q_o = 0, + .q_c = res_x, + }; + + size_t num_variables = witness_values.size(); + AcirFormat constraint_system{ + .varnum = static_cast(num_variables + 1), + .recursive = false, + .num_acir_opcodes = 1, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .aes128_constraints = {}, + .sha256_constraints = {}, + .sha256_compression = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .poseidon2_constraints = {}, + .multi_scalar_mul_constraints = { msm_constrain }, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .poly_triple_constraints = { assert_equal }, + .quad_constraints = {}, + .block_constraints = {}, + }; + + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values); + + auto composer = Composer(); + auto prover = composer.create_prover(builder); + + auto proof = prover.construct_proof(); + EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier = composer.create_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp index 83354d97c76..83d7395bafa 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.cpp @@ -12,19 +12,20 @@ template void create_multi_scalar_mul_constraint(Builder& bui using cycle_group_ct = bb::stdlib::cycle_group; using cycle_scalar_ct = typename bb::stdlib::cycle_group::cycle_scalar; using field_ct = bb::stdlib::field_t; + using bool_ct = bb::stdlib::bool_t; std::vector points; std::vector scalars; - for (size_t i = 0; i < input.points.size(); i += 2) { + for (size_t i = 0; i < input.points.size(); i += 3) { // Instantiate the input point/variable base as `cycle_group_ct` auto point_x = field_ct::from_witness_index(&builder, input.points[i]); auto point_y = field_ct::from_witness_index(&builder, input.points[i + 1]); - cycle_group_ct input_point(point_x, point_y, false); - + auto infinite = bool_ct(field_ct::from_witness_index(&builder, input.points[i + 2])); + cycle_group_ct input_point(point_x, point_y, infinite); // Reconstruct the scalar from the low and high limbs - field_ct scalar_low_as_field = field_ct::from_witness_index(&builder, input.scalars[i]); - field_ct scalar_high_as_field = field_ct::from_witness_index(&builder, input.scalars[i + 1]); + field_ct scalar_low_as_field = field_ct::from_witness_index(&builder, input.scalars[2 * (i / 3)]); + field_ct scalar_high_as_field = field_ct::from_witness_index(&builder, input.scalars[2 * (i / 3) + 1]); cycle_scalar_ct scalar(scalar_low_as_field, scalar_high_as_field); // Add the point and scalar to the vectors @@ -38,6 +39,7 @@ template void create_multi_scalar_mul_constraint(Builder& bui // Add the constraints builder.assert_equal(output_point.x.get_witness_index(), input.out_point_x); builder.assert_equal(output_point.y.get_witness_index(), input.out_point_y); + builder.assert_equal(output_point.is_point_at_infinity().witness_index, input.out_point_is_infinite); } template void create_multi_scalar_mul_constraint(UltraCircuitBuilder& builder, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.hpp index 12b070076f9..57c143226d3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/multi_scalar_mul.hpp @@ -10,9 +10,10 @@ struct MultiScalarMul { std::vector scalars; uint32_t out_point_x; uint32_t out_point_y; + uint32_t out_point_is_infinite; // for serialization, update with any new fields - MSGPACK_FIELDS(points, scalars, out_point_x, out_point_y); + MSGPACK_FIELDS(points, scalars, out_point_x, out_point_y, out_point_is_infinite); friend bool operator==(MultiScalarMul const& lhs, MultiScalarMul const& rhs) = default; }; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 683e4c62407..2c8ad3cc5f8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -149,7 +149,7 @@ struct BlackBoxFuncCall { struct MultiScalarMul { std::vector points; std::vector scalars; - std::array outputs; + std::array outputs; friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); std::vector bincodeSerialize() const; @@ -157,11 +157,9 @@ struct BlackBoxFuncCall { }; struct EmbeddedCurveAdd { - Program::FunctionInput input1_x; - Program::FunctionInput input1_y; - Program::FunctionInput input2_x; - Program::FunctionInput input2_y; - std::array outputs; + std::array input1; + std::array input2; + std::array outputs; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; @@ -807,8 +805,10 @@ struct BlackBoxOp { struct EmbeddedCurveAdd { Program::MemoryAddress input1_x; Program::MemoryAddress input1_y; + Program::MemoryAddress input1_infinite; Program::MemoryAddress input2_x; Program::MemoryAddress input2_y; + Program::MemoryAddress input2_infinite; Program::HeapArray result; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); @@ -3194,16 +3194,10 @@ namespace Program { inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd& lhs, const BlackBoxFuncCall::EmbeddedCurveAdd& rhs) { - if (!(lhs.input1_x == rhs.input1_x)) { + if (!(lhs.input1 == rhs.input1)) { return false; } - if (!(lhs.input1_y == rhs.input1_y)) { - return false; - } - if (!(lhs.input2_x == rhs.input2_x)) { - return false; - } - if (!(lhs.input2_y == rhs.input2_y)) { + if (!(lhs.input2 == rhs.input2)) { return false; } if (!(lhs.outputs == rhs.outputs)) { @@ -3237,10 +3231,8 @@ template void serde::Serializable::serialize( const Program::BlackBoxFuncCall::EmbeddedCurveAdd& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.input1_x, serializer); - serde::Serializable::serialize(obj.input1_y, serializer); - serde::Serializable::serialize(obj.input2_x, serializer); - serde::Serializable::serialize(obj.input2_y, serializer); + serde::Serializable::serialize(obj.input1, serializer); + serde::Serializable::serialize(obj.input2, serializer); serde::Serializable::serialize(obj.outputs, serializer); } @@ -3250,10 +3242,8 @@ Program::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable< Program::BlackBoxFuncCall::EmbeddedCurveAdd>::deserialize(Deserializer& deserializer) { Program::BlackBoxFuncCall::EmbeddedCurveAdd obj; - obj.input1_x = serde::Deserializable::deserialize(deserializer); - obj.input1_y = serde::Deserializable::deserialize(deserializer); - obj.input2_x = serde::Deserializable::deserialize(deserializer); - obj.input2_y = serde::Deserializable::deserialize(deserializer); + obj.input1 = serde::Deserializable::deserialize(deserializer); + obj.input2 = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4638,12 +4628,18 @@ inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd& lhs, const BlackBoxOp if (!(lhs.input1_y == rhs.input1_y)) { return false; } + if (!(lhs.input1_infinite == rhs.input1_infinite)) { + return false; + } if (!(lhs.input2_x == rhs.input2_x)) { return false; } if (!(lhs.input2_y == rhs.input2_y)) { return false; } + if (!(lhs.input2_infinite == rhs.input2_infinite)) { + return false; + } if (!(lhs.result == rhs.result)) { return false; } @@ -4676,8 +4672,10 @@ void serde::Serializable::serialize( { serde::Serializable::serialize(obj.input1_x, serializer); serde::Serializable::serialize(obj.input1_y, serializer); + serde::Serializable::serialize(obj.input1_infinite, serializer); serde::Serializable::serialize(obj.input2_x, serializer); serde::Serializable::serialize(obj.input2_y, serializer); + serde::Serializable::serialize(obj.input2_infinite, serializer); serde::Serializable::serialize(obj.result, serializer); } @@ -4689,8 +4687,10 @@ Program::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize(deserializer); obj.input1_y = serde::Deserializable::deserialize(deserializer); + obj.input1_infinite = serde::Deserializable::deserialize(deserializer); obj.input2_x = serde::Deserializable::deserialize(deserializer); obj.input2_y = serde::Deserializable::deserialize(deserializer); + obj.input2_infinite = serde::Deserializable::deserialize(deserializer); obj.result = serde::Deserializable::deserialize(deserializer); return obj; } diff --git a/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr b/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr index e2f0edfcd70..934306e32ab 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr @@ -2,12 +2,15 @@ use dep::protocol_types::{ constants::GENERATOR_INDEX__SYMMETRIC_KEY, grumpkin_private_key::GrumpkinPrivateKey, grumpkin_point::GrumpkinPoint, utils::arr_copy_slice }; -use dep::std::{hash::sha256, embedded_curve_ops::multi_scalar_mul}; +use dep::std::{hash::sha256, embedded_curve_ops::{EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul}}; // TODO(#5726): This function is called deriveAESSecret in TS. I don't like point_to_symmetric_key name much since // point is not the only input of the function. Unify naming with TS once we have a better name. pub fn point_to_symmetric_key(secret: GrumpkinPrivateKey, point: GrumpkinPoint) -> [u8; 32] { - let shared_secret_fields = multi_scalar_mul([point.x, point.y], [secret.low, secret.high]); + let shared_secret_fields = multi_scalar_mul( + [EmbeddedCurvePoint { x: point.x, y: point.y, is_infinite: false }], + [EmbeddedCurveScalar { lo: secret.low, hi: secret.high }] + ); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/6061): make the func return Point struct directly let shared_secret = GrumpkinPoint::new(shared_secret_fields[0], shared_secret_fields[1]); let mut shared_secret_bytes_with_separator = [0 as u8; 65]; diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 222a7da6399..47e184a6332 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -149,7 +149,7 @@ namespace Program { struct MultiScalarMul { std::vector points; std::vector scalars; - std::array outputs; + std::array outputs; friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); std::vector bincodeSerialize() const; @@ -157,11 +157,9 @@ namespace Program { }; struct EmbeddedCurveAdd { - Program::FunctionInput input1_x; - Program::FunctionInput input1_y; - Program::FunctionInput input2_x; - Program::FunctionInput input2_y; - std::array outputs; + std::array input1; + std::array input2; + std::array outputs; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; @@ -782,8 +780,10 @@ namespace Program { struct EmbeddedCurveAdd { Program::MemoryAddress input1_x; Program::MemoryAddress input1_y; + Program::MemoryAddress input1_infinite; Program::MemoryAddress input2_x; Program::MemoryAddress input2_y; + Program::MemoryAddress input2_infinite; Program::HeapArray result; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); @@ -2800,10 +2800,8 @@ Program::BlackBoxFuncCall::MultiScalarMul serde::Deserializable template void serde::Serializable::serialize(const Program::BlackBoxFuncCall::EmbeddedCurveAdd &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.input1_x, serializer); - serde::Serializable::serialize(obj.input1_y, serializer); - serde::Serializable::serialize(obj.input2_x, serializer); - serde::Serializable::serialize(obj.input2_y, serializer); + serde::Serializable::serialize(obj.input1, serializer); + serde::Serializable::serialize(obj.input2, serializer); serde::Serializable::serialize(obj.outputs, serializer); } @@ -2839,10 +2835,8 @@ template <> template Program::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { Program::BlackBoxFuncCall::EmbeddedCurveAdd obj; - obj.input1_x = serde::Deserializable::deserialize(deserializer); - obj.input1_y = serde::Deserializable::deserialize(deserializer); - obj.input2_x = serde::Deserializable::deserialize(deserializer); - obj.input2_y = serde::Deserializable::deserialize(deserializer); + obj.input1 = serde::Deserializable::deserialize(deserializer); + obj.input2 = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } @@ -3909,8 +3903,10 @@ namespace Program { inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd &lhs, const BlackBoxOp::EmbeddedCurveAdd &rhs) { if (!(lhs.input1_x == rhs.input1_x)) { return false; } if (!(lhs.input1_y == rhs.input1_y)) { return false; } + if (!(lhs.input1_infinite == rhs.input1_infinite)) { return false; } if (!(lhs.input2_x == rhs.input2_x)) { return false; } if (!(lhs.input2_y == rhs.input2_y)) { return false; } + if (!(lhs.input2_infinite == rhs.input2_infinite)) { return false; } if (!(lhs.result == rhs.result)) { return false; } return true; } @@ -3937,8 +3933,10 @@ template void serde::Serializable::serialize(const Program::BlackBoxOp::EmbeddedCurveAdd &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input1_x, serializer); serde::Serializable::serialize(obj.input1_y, serializer); + serde::Serializable::serialize(obj.input1_infinite, serializer); serde::Serializable::serialize(obj.input2_x, serializer); serde::Serializable::serialize(obj.input2_y, serializer); + serde::Serializable::serialize(obj.input2_infinite, serializer); serde::Serializable::serialize(obj.result, serializer); } @@ -3948,8 +3946,10 @@ Program::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize(deserializer); obj.input1_y = serde::Deserializable::deserialize(deserializer); + obj.input1_infinite = serde::Deserializable::deserialize(deserializer); obj.input2_x = serde::Deserializable::deserialize(deserializer); obj.input2_y = serde::Deserializable::deserialize(deserializer); + obj.input2_infinite = serde::Deserializable::deserialize(deserializer); obj.result = serde::Deserializable::deserialize(deserializer); return obj; } diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 115a33c1c9d..b0e77b15c2c 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -89,14 +89,12 @@ pub enum BlackBoxFuncCall { MultiScalarMul { points: Vec, scalars: Vec, - outputs: (Witness, Witness), + outputs: (Witness, Witness, Witness), }, EmbeddedCurveAdd { - input1_x: FunctionInput, - input1_y: FunctionInput, - input2_x: FunctionInput, - input2_y: FunctionInput, - outputs: (Witness, Witness), + input1: Box<[FunctionInput; 3]>, + input2: Box<[FunctionInput; 3]>, + outputs: (Witness, Witness, Witness), }, Keccak256 { inputs: Vec, @@ -245,9 +243,9 @@ impl BlackBoxFuncCall { inputs.extend(scalars.iter().copied()); inputs } - BlackBoxFuncCall::EmbeddedCurveAdd { - input1_x, input1_y, input2_x, input2_y, .. - } => vec![*input1_x, *input1_y, *input2_x, *input2_y], + BlackBoxFuncCall::EmbeddedCurveAdd { input1, input2, .. } => { + vec![input1[0], input1[1], input2[0], input2[1]] + } BlackBoxFuncCall::RANGE { input } => vec![*input], BlackBoxFuncCall::SchnorrVerify { public_key_x, @@ -343,9 +341,11 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } | BlackBoxFuncCall::PedersenHash { output, .. } | BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } => vec![*output], + BlackBoxFuncCall::PedersenCommitment { outputs, .. } => vec![outputs.0, outputs.1], BlackBoxFuncCall::MultiScalarMul { outputs, .. } - | BlackBoxFuncCall::PedersenCommitment { outputs, .. } - | BlackBoxFuncCall::EmbeddedCurveAdd { outputs, .. } => vec![outputs.0, outputs.1], + | BlackBoxFuncCall::EmbeddedCurveAdd { outputs, .. } => { + vec![outputs.0, outputs.1, outputs.2] + } BlackBoxFuncCall::RANGE { .. } | BlackBoxFuncCall::RecursiveAggregation { .. } | BlackBoxFuncCall::BigIntFromLeBytes { .. } diff --git a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs index ecc1a26e3a4..19e4beb6158 100644 --- a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs +++ b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs @@ -63,19 +63,26 @@ fn multi_scalar_mul_circuit() { points: vec![ FunctionInput { witness: Witness(1), num_bits: 128 }, FunctionInput { witness: Witness(2), num_bits: 128 }, + FunctionInput { witness: Witness(3), num_bits: 1 }, ], scalars: vec![ - FunctionInput { witness: Witness(3), num_bits: 128 }, FunctionInput { witness: Witness(4), num_bits: 128 }, + FunctionInput { witness: Witness(5), num_bits: 128 }, ], - outputs: (Witness(5), Witness(6)), + outputs: (Witness(6), Witness(7), Witness(8)), }); let circuit = Circuit { - current_witness_index: 7, + current_witness_index: 9, opcodes: vec![multi_scalar_mul], - private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3), Witness(4)]), - return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(5), Witness(6)])), + private_parameters: BTreeSet::from([ + Witness(1), + Witness(2), + Witness(3), + Witness(4), + Witness(5), + ]), + return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(6), Witness(7), Witness(8)])), ..Circuit::default() }; let program = Program { functions: vec![circuit], unconstrained_functions: vec![] }; @@ -83,10 +90,10 @@ fn multi_scalar_mul_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 186, 244, 104, 159, - 30, 45, 218, 136, 141, 33, 40, 186, 93, 76, 208, 57, 31, 93, 96, 136, 47, 250, 146, 188, - 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, 38, 63, 180, 243, 97, 3, 125, 173, - 118, 131, 153, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 141, 219, 10, 0, 32, 8, 67, 243, 214, 5, 250, 232, + 62, 189, 69, 123, 176, 132, 195, 116, 50, 149, 114, 107, 0, 97, 127, 116, 2, 75, 243, 2, + 74, 53, 122, 202, 189, 211, 15, 106, 5, 13, 116, 238, 35, 221, 81, 230, 61, 249, 37, 253, + 250, 179, 79, 109, 218, 22, 67, 227, 173, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs index ee35385fa81..0b52ae295a2 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/embedded_curve_ops.rs @@ -11,7 +11,7 @@ pub(super) fn multi_scalar_mul( initial_witness: &mut WitnessMap, points: &[FunctionInput], scalars: &[FunctionInput], - outputs: (Witness, Witness), + outputs: (Witness, Witness, Witness), ) -> Result<(), OpcodeResolutionError> { let points: Result, _> = points.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); @@ -19,35 +19,44 @@ pub(super) fn multi_scalar_mul( let scalars: Result, _> = scalars.iter().map(|input| witness_to_value(initial_witness, input.witness)).collect(); - let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); - + let mut scalars_lo = Vec::new(); + let mut scalars_hi = Vec::new(); + for (i, scalar) in scalars?.into_iter().enumerate() { + if i % 2 == 0 { + scalars_lo.push(*scalar); + } else { + scalars_hi.push(*scalar); + } + } // Call the backend's multi-scalar multiplication function - let (res_x, res_y) = backend.multi_scalar_mul(&points, &scalars)?; + let (res_x, res_y, is_infinite) = + backend.multi_scalar_mul(&points, &scalars_lo, &scalars_hi)?; // Insert the resulting point into the witness map insert_value(&outputs.0, res_x, initial_witness)?; insert_value(&outputs.1, res_y, initial_witness)?; - + insert_value(&outputs.2, is_infinite, initial_witness)?; Ok(()) } pub(super) fn embedded_curve_add( backend: &impl BlackBoxFunctionSolver, initial_witness: &mut WitnessMap, - input1_x: FunctionInput, - input1_y: FunctionInput, - input2_x: FunctionInput, - input2_y: FunctionInput, - outputs: (Witness, Witness), + input1: [FunctionInput; 3], + input2: [FunctionInput; 3], + outputs: (Witness, Witness, Witness), ) -> Result<(), OpcodeResolutionError> { - let input1_x = witness_to_value(initial_witness, input1_x.witness)?; - let input1_y = witness_to_value(initial_witness, input1_y.witness)?; - let input2_x = witness_to_value(initial_witness, input2_x.witness)?; - let input2_y = witness_to_value(initial_witness, input2_y.witness)?; - let (res_x, res_y) = backend.ec_add(input1_x, input1_y, input2_x, input2_y)?; + let input1_x = witness_to_value(initial_witness, input1[0].witness)?; + let input1_y = witness_to_value(initial_witness, input1[1].witness)?; + let input1_infinite = witness_to_value(initial_witness, input1[2].witness)?; + let input2_x = witness_to_value(initial_witness, input2[0].witness)?; + let input2_y = witness_to_value(initial_witness, input2[1].witness)?; + let input2_infinite = witness_to_value(initial_witness, input2[2].witness)?; + let (res_x, res_y, res_infinite) = + backend.ec_add(input1_x, input1_y, input1_infinite, input2_x, input2_y, input2_infinite)?; insert_value(&outputs.0, res_x, initial_witness)?; insert_value(&outputs.1, res_y, initial_witness)?; - + insert_value(&outputs.2, res_infinite, initial_witness)?; Ok(()) } diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs index a74f44b79dc..99ed09a52e4 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -164,16 +164,8 @@ pub(crate) fn solve( BlackBoxFuncCall::MultiScalarMul { points, scalars, outputs } => { multi_scalar_mul(backend, initial_witness, points, scalars, *outputs) } - BlackBoxFuncCall::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, outputs } => { - embedded_curve_add( - backend, - initial_witness, - *input1_x, - *input1_y, - *input2_x, - *input2_y, - *outputs, - ) + BlackBoxFuncCall::EmbeddedCurveAdd { input1, input2, outputs } => { + embedded_curve_add(backend, initial_witness, **input1, **input2, *outputs) } // Recursive aggregation will be entirely handled by the backend and is not solved by the ACVM BlackBoxFuncCall::RecursiveAggregation { .. } => Ok(()), diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts index 8ee0a067a3a..5401da76974 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts @@ -1,21 +1,24 @@ // See `multi_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 76, 65, 14, 0, 32, 8, 82, 179, 186, 244, 104, 159, 30, 45, 218, 136, 141, 33, - 40, 186, 93, 76, 208, 57, 31, 93, 96, 136, 47, 250, 146, 188, 209, 39, 181, 131, 131, 187, 148, 110, 240, 246, 101, - 38, 63, 180, 243, 97, 3, 125, 173, 118, 131, 153, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 141, 219, 10, 0, 32, 8, 67, 243, 214, 5, 250, 232, 62, 189, 69, 123, 176, 132, + 195, 116, 50, 149, 114, 107, 0, 97, 127, 116, 2, 75, 243, 2, 74, 53, 122, 202, 189, 211, 15, 106, 5, 13, 116, 238, 35, + 221, 81, 230, 61, 249, 37, 253, 250, 179, 79, 109, 218, 22, 67, 227, 173, 0, 0, 0, ]); export const initialWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], [2, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], - [3, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [4, '0x0000000000000000000000000000000000000000000000000000000000000000'], + [3, '0x0000000000000000000000000000000000000000000000000000000000000000'], + [4, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [5, '0x0000000000000000000000000000000000000000000000000000000000000000'], ]); export const expectedWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], [2, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], - [3, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [4, '0x0000000000000000000000000000000000000000000000000000000000000000'], - [5, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [6, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], + [3, '0x0000000000000000000000000000000000000000000000000000000000000000'], + [4, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [5, '0x0000000000000000000000000000000000000000000000000000000000000000'], + [6, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [7, '0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c'], + [8, '0x0000000000000000000000000000000000000000000000000000000000000000'], ]); diff --git a/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs b/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs index 3403b0fe232..73f64d3d9d1 100644 --- a/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs +++ b/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs @@ -27,15 +27,18 @@ pub trait BlackBoxFunctionSolver { fn multi_scalar_mul( &self, points: &[FieldElement], - scalars: &[FieldElement], - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError>; + scalars_lo: &[FieldElement], + scalars_hi: &[FieldElement], + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError>; fn ec_add( &self, input1_x: &FieldElement, input1_y: &FieldElement, + input1_infinite: &FieldElement, input2_x: &FieldElement, input2_y: &FieldElement, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError>; + input2_infinite: &FieldElement, + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError>; fn poseidon2_permutation( &self, _inputs: &[FieldElement], @@ -81,17 +84,20 @@ impl BlackBoxFunctionSolver for StubbedBlackBoxSolver { fn multi_scalar_mul( &self, _points: &[FieldElement], - _scalars: &[FieldElement], - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + _scalars_lo: &[FieldElement], + _scalars_hi: &[FieldElement], + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { Err(Self::fail(BlackBoxFunc::MultiScalarMul)) } fn ec_add( &self, _input1_x: &FieldElement, _input1_y: &FieldElement, + _input1_infinite: &FieldElement, _input2_x: &FieldElement, _input2_y: &FieldElement, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + _input2_infinite: &FieldElement, + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { Err(Self::fail(BlackBoxFunc::EmbeddedCurveAdd)) } fn poseidon2_permutation( diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs index 3f6d2ac86c1..901eb9d5a0f 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/embedded_curve_ops.rs @@ -10,9 +10,11 @@ use crate::BlackBoxResolutionError; /// Performs multi scalar multiplication of points with scalars. pub fn multi_scalar_mul( points: &[FieldElement], - scalars: &[FieldElement], -) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - if points.len() != scalars.len() { + scalars_lo: &[FieldElement], + scalars_hi: &[FieldElement], +) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { + if points.len() != 3 * scalars_lo.len() || scalars_lo.len() != scalars_hi.len() { + dbg!(&points.len(), &scalars_lo.len(), &scalars_hi.len()); return Err(BlackBoxResolutionError::Failed( BlackBoxFunc::MultiScalarMul, "Points and scalars must have the same length".to_string(), @@ -21,21 +23,22 @@ pub fn multi_scalar_mul( let mut output_point = grumpkin::SWAffine::zero(); - for i in (0..points.len()).step_by(2) { - let point = create_point(points[i], points[i + 1]) - .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::MultiScalarMul, e))?; + for i in (0..points.len()).step_by(3) { + let point = + create_point(points[i], points[i + 1], points[i + 2] == FieldElement::from(1_u128)) + .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::MultiScalarMul, e))?; - let scalar_low: u128 = scalars[i].try_into_u128().ok_or_else(|| { + let scalar_low: u128 = scalars_lo[i / 3].try_into_u128().ok_or_else(|| { BlackBoxResolutionError::Failed( BlackBoxFunc::MultiScalarMul, - format!("Limb {} is not less than 2^128", scalars[i].to_hex()), + format!("Limb {} is not less than 2^128", scalars_lo[i].to_hex()), ) })?; - let scalar_high: u128 = scalars[i + 1].try_into_u128().ok_or_else(|| { + let scalar_high: u128 = scalars_hi[i / 3].try_into_u128().ok_or_else(|| { BlackBoxResolutionError::Failed( BlackBoxFunc::MultiScalarMul, - format!("Limb {} is not less than 2^128", scalars[i + 1].to_hex()), + format!("Limb {} is not less than 2^128", scalars_hi[i].to_hex()), ) })?; @@ -59,25 +62,33 @@ pub fn multi_scalar_mul( } if let Some((out_x, out_y)) = output_point.xy() { - Ok((FieldElement::from_repr(*out_x), FieldElement::from_repr(*out_y))) + Ok(( + FieldElement::from_repr(*out_x), + FieldElement::from_repr(*out_y), + FieldElement::from(output_point.is_zero() as u128), + )) } else { - Ok((FieldElement::zero(), FieldElement::zero())) + Ok((FieldElement::from(0_u128), FieldElement::from(0_u128), FieldElement::from(1_u128))) } } pub fn embedded_curve_add( - input1_x: FieldElement, - input1_y: FieldElement, - input2_x: FieldElement, - input2_y: FieldElement, -) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - let point1 = create_point(input1_x, input1_y) + input1: [FieldElement; 3], + input2: [FieldElement; 3], +) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { + let point1 = create_point(input1[0], input1[1], input1[2] == FieldElement::one()) .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::EmbeddedCurveAdd, e))?; - let point2 = create_point(input2_x, input2_y) + let point2 = create_point(input2[0], input2[1], input2[2] == FieldElement::one()) .map_err(|e| BlackBoxResolutionError::Failed(BlackBoxFunc::EmbeddedCurveAdd, e))?; let res = grumpkin::SWAffine::from(point1 + point2); if let Some((res_x, res_y)) = res.xy() { - Ok((FieldElement::from_repr(*res_x), FieldElement::from_repr(*res_y))) + Ok(( + FieldElement::from_repr(*res_x), + FieldElement::from_repr(*res_y), + FieldElement::from(res.is_zero() as u128), + )) + } else if res.is_zero() { + Ok((FieldElement::from(0_u128), FieldElement::from(0_u128), FieldElement::from(1_u128))) } else { Err(BlackBoxResolutionError::Failed( BlackBoxFunc::EmbeddedCurveAdd, @@ -86,7 +97,14 @@ pub fn embedded_curve_add( } } -fn create_point(x: FieldElement, y: FieldElement) -> Result { +fn create_point( + x: FieldElement, + y: FieldElement, + is_infinite: bool, +) -> Result { + if is_infinite { + return Ok(grumpkin::SWAffine::zero()); + } let point = grumpkin::SWAffine::new_unchecked(x.into_repr(), y.into_repr()); if !point.is_on_curve() { return Err(format!("Point ({}, {}) is not on curve", x.to_hex(), y.to_hex())); @@ -103,11 +121,11 @@ mod tests { use super::*; - fn get_generator() -> [FieldElement; 2] { + fn get_generator() -> [FieldElement; 3] { let generator = grumpkin::SWAffine::generator(); let generator_x = FieldElement::from_repr(*generator.x().unwrap()); let generator_y = FieldElement::from_repr(*generator.y().unwrap()); - [generator_x, generator_y] + [generator_x, generator_y, FieldElement::zero()] } #[test] @@ -115,7 +133,7 @@ mod tests { // We check that multiplying 1 by generator results in the generator let generator = get_generator(); - let res = multi_scalar_mul(&generator, &[FieldElement::one(), FieldElement::zero()])?; + let res = multi_scalar_mul(&generator, &[FieldElement::one()], &[FieldElement::zero()])?; assert_eq!(generator[0], res.0); assert_eq!(generator[1], res.1); @@ -125,9 +143,10 @@ mod tests { #[test] fn low_high_smoke_test() -> Result<(), BlackBoxResolutionError> { let points = get_generator(); - let scalars = [FieldElement::one(), FieldElement::from(2u128)]; + let scalars_lo = [FieldElement::one()]; + let scalars_hi = [FieldElement::from(2u128)]; - let res = multi_scalar_mul(&points, &scalars)?; + let res = multi_scalar_mul(&points, &scalars_lo, &scalars_hi)?; let x = "0702ab9c7038eeecc179b4f209991bcb68c7cb05bf4c532d804ccac36199c9a9"; let y = "23f10e9e43a3ae8d75d24154e796aae12ae7af546716e8f81a2564f1b5814130"; @@ -148,10 +167,10 @@ mod tests { "Limb 0000000000000000000000000000000100000000000000000000000000000000 is not less than 2^128".into(), )); - let res = multi_scalar_mul(&points, &[FieldElement::one(), invalid_limb]); + let res = multi_scalar_mul(&points, &[FieldElement::one()], &[invalid_limb]); assert_eq!(res, expected_error); - let res = multi_scalar_mul(&points, &[invalid_limb, FieldElement::one()]); + let res = multi_scalar_mul(&points, &[invalid_limb], &[FieldElement::one()]); assert_eq!(res, expected_error); } @@ -162,7 +181,7 @@ mod tests { let low = FieldElement::from_be_bytes_reduce(&x[16..32]); let high = FieldElement::from_be_bytes_reduce(&x[0..16]); - let res = multi_scalar_mul(&get_generator(), &[low, high]); + let res = multi_scalar_mul(&get_generator(), &[low], &[high]); assert_eq!( res, @@ -181,8 +200,9 @@ mod tests { let valid_scalar_high = FieldElement::zero(); let res = multi_scalar_mul( - &[invalid_point_x, invalid_point_y], - &[valid_scalar_low, valid_scalar_high], + &[invalid_point_x, invalid_point_y, FieldElement::zero()], + &[valid_scalar_low], + &[valid_scalar_high], ); assert_eq!( @@ -197,9 +217,10 @@ mod tests { #[test] fn throws_on_args_length_mismatch() { let points = get_generator(); - let scalars = [FieldElement::from(2u128)]; + let scalars_lo = [FieldElement::from(2u128)]; + let scalars_hi = []; - let res = multi_scalar_mul(&points, &scalars); + let res = multi_scalar_mul(&points, &scalars_lo, &scalars_hi); assert_eq!( res, @@ -215,7 +236,10 @@ mod tests { let x = FieldElement::from(1u128); let y = FieldElement::from(2u128); - let res = embedded_curve_add(x, y, x, y); + let res = embedded_curve_add( + [x, y, FieldElement::from(0u128)], + [x, y, FieldElement::from(0u128)], + ); assert_eq!( res, @@ -229,10 +253,14 @@ mod tests { #[test] fn output_of_msm_matches_add() -> Result<(), BlackBoxResolutionError> { let points = get_generator(); - let scalars = [FieldElement::from(2u128), FieldElement::zero()]; - - let msm_res = multi_scalar_mul(&points, &scalars)?; - let add_res = embedded_curve_add(points[0], points[1], points[0], points[1])?; + let scalars_lo = [FieldElement::from(2u128)]; + let scalars_hi = [FieldElement::zero()]; + + let msm_res = multi_scalar_mul(&points, &scalars_lo, &scalars_hi)?; + let add_res = embedded_curve_add( + [points[0], points[1], FieldElement::from(0u128)], + [points[0], points[1], FieldElement::from(0u128)], + )?; assert_eq!(msm_res.0, add_res.0); assert_eq!(msm_res.1, add_res.1); diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs index 4cb51b59755..a85ddcd894e 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs @@ -92,19 +92,25 @@ impl BlackBoxFunctionSolver for Bn254BlackBoxSolver { fn multi_scalar_mul( &self, points: &[FieldElement], - scalars: &[FieldElement], - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - multi_scalar_mul(points, scalars) + scalars_lo: &[FieldElement], + scalars_hi: &[FieldElement], + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { + multi_scalar_mul(points, scalars_lo, scalars_hi) } fn ec_add( &self, input1_x: &FieldElement, input1_y: &FieldElement, + input1_infinite: &FieldElement, input2_x: &FieldElement, input2_y: &FieldElement, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - embedded_curve_add(*input1_x, *input1_y, *input2_x, *input2_y) + input2_infinite: &FieldElement, + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { + embedded_curve_add( + [*input1_x, *input1_y, *input1_infinite], + [*input2_x, *input2_y, *input2_infinite], + ) } fn poseidon2_permutation( diff --git a/noir/noir-repo/acvm-repo/brillig/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs index 9a66b428dc3..3887092a8c2 100644 --- a/noir/noir-repo/acvm-repo/brillig/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs @@ -83,8 +83,10 @@ pub enum BlackBoxOp { EmbeddedCurveAdd { input1_x: MemoryAddress, input1_y: MemoryAddress, + input1_infinite: MemoryAddress, input2_x: MemoryAddress, input2_y: MemoryAddress, + input2_infinite: MemoryAddress, result: HeapArray, }, BigIntAdd { diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs index d6ecd25f454..ebaa6976283 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs @@ -157,22 +157,63 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::MultiScalarMul { points, scalars, outputs: result } => { - let points: Vec = - read_heap_vector(memory, points).iter().map(|x| x.try_into().unwrap()).collect(); + let points: Vec = read_heap_vector(memory, points) + .iter() + .enumerate() + .map(|(i, x)| { + if i % 3 == 2 { + let is_infinite: bool = x.try_into().unwrap(); + FieldElement::from(is_infinite as u128) + } else { + x.try_into().unwrap() + } + }) + .collect(); let scalars: Vec = read_heap_vector(memory, scalars).iter().map(|x| x.try_into().unwrap()).collect(); - - let (x, y) = solver.multi_scalar_mul(&points, &scalars)?; - memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); + let mut scalars_lo = Vec::with_capacity(scalars.len() / 2); + let mut scalars_hi = Vec::with_capacity(scalars.len() / 2); + for (i, scalar) in scalars.iter().enumerate() { + if i % 2 == 0 { + scalars_lo.push(*scalar); + } else { + scalars_hi.push(*scalar); + } + } + let (x, y, is_infinite) = solver.multi_scalar_mul(&points, &scalars_lo, &scalars_hi)?; + memory.write_slice( + memory.read_ref(result.pointer), + &[x.into(), y.into(), is_infinite.into()], + ); Ok(()) } - BlackBoxOp::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, result } => { + BlackBoxOp::EmbeddedCurveAdd { + input1_x, + input1_y, + input2_x, + input2_y, + result, + input1_infinite, + input2_infinite, + } => { let input1_x = memory.read(*input1_x).try_into().unwrap(); let input1_y = memory.read(*input1_y).try_into().unwrap(); + let input1_infinite: bool = memory.read(*input1_infinite).try_into().unwrap(); let input2_x = memory.read(*input2_x).try_into().unwrap(); let input2_y = memory.read(*input2_y).try_into().unwrap(); - let (x, y) = solver.ec_add(&input1_x, &input1_y, &input2_x, &input2_y)?; - memory.write_slice(memory.read_ref(result.pointer), &[x.into(), y.into()]); + let input2_infinite: bool = memory.read(*input2_infinite).try_into().unwrap(); + let (x, y, infinite) = solver.ec_add( + &input1_x, + &input1_y, + &input1_infinite.into(), + &input2_x, + &input2_y, + &input2_infinite.into(), + )?; + memory.write_slice( + memory.read_ref(result.pointer), + &[x.into(), y.into(), infinite.into()], + ); Ok(()) } BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index d587abc9463..f56c5daf315 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -207,15 +207,17 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::EmbeddedCurveAdd => { if let ( - [BrilligVariable::SingleAddr(input1_x), BrilligVariable::SingleAddr(input1_y), BrilligVariable::SingleAddr(input2_x), BrilligVariable::SingleAddr(input2_y)], + [BrilligVariable::SingleAddr(input1_x), BrilligVariable::SingleAddr(input1_y), BrilligVariable::SingleAddr(input1_infinite), BrilligVariable::SingleAddr(input2_x), BrilligVariable::SingleAddr(input2_y), BrilligVariable::SingleAddr(input2_infinite)], [BrilligVariable::BrilligArray(result_array)], ) = (function_arguments, function_results) { brillig_context.black_box_op_instruction(BlackBoxOp::EmbeddedCurveAdd { input1_x: input1_x.address, input1_y: input1_y.address, + input1_infinite: input1_infinite.address, input2_x: input2_x.address, input2_y: input2_y.address, + input2_infinite: input2_infinite.address, result: result_array.to_heap_array(), }); } else { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index fadcdb22c15..2bd57dc9486 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -170,18 +170,21 @@ pub(crate) mod tests { fn multi_scalar_mul( &self, _points: &[FieldElement], - _scalars: &[FieldElement], - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Ok((4_u128.into(), 5_u128.into())) + _scalars_lo: &[FieldElement], + _scalars_hi: &[FieldElement], + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { + Ok((4_u128.into(), 5_u128.into(), 0_u128.into())) } fn ec_add( &self, _input1_x: &FieldElement, _input1_y: &FieldElement, + _input1_infinite: &FieldElement, _input2_x: &FieldElement, _input2_y: &FieldElement, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { + _input2_infinite: &FieldElement, + ) -> Result<(FieldElement, FieldElement, FieldElement), BlackBoxResolutionError> { panic!("Path not trodden by this test") } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index f02f6059e7c..def91f82bfd 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -334,7 +334,9 @@ impl DebugShow { outputs ); } - BlackBoxOp::EmbeddedCurveAdd { input1_x, input1_y, input2_x, input2_y, result } => { + BlackBoxOp::EmbeddedCurveAdd { + input1_x, input1_y, input2_x, input2_y, result, .. + } => { debug_println!( self.enable_debug_trace, " EMBEDDED_CURVE_ADD ({} {}) ({} {}) -> {}", diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index c1249ae41c8..d23f4abe5f5 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -293,14 +293,13 @@ impl GeneratedAcir { BlackBoxFunc::MultiScalarMul => BlackBoxFuncCall::MultiScalarMul { points: inputs[0].clone(), scalars: inputs[1].clone(), - outputs: (outputs[0], outputs[1]), + outputs: (outputs[0], outputs[1], outputs[2]), }, + BlackBoxFunc::EmbeddedCurveAdd => BlackBoxFuncCall::EmbeddedCurveAdd { - input1_x: inputs[0][0], - input1_y: inputs[1][0], - input2_x: inputs[2][0], - input2_y: inputs[3][0], - outputs: (outputs[0], outputs[1]), + input1: Box::new([inputs[0][0], inputs[1][0], inputs[2][0]]), + input2: Box::new([inputs[3][0], inputs[4][0], inputs[5][0]]), + outputs: (outputs[0], outputs[1], outputs[2]), }, BlackBoxFunc::Keccak256 => { let var_message_size = match inputs.to_vec().pop() { @@ -684,8 +683,8 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // Recursive aggregation has a variable number of inputs BlackBoxFunc::RecursiveAggregation => None, - // Addition over the embedded curve: input are coordinates (x1,y1) and (x2,y2) of the Grumpkin points - BlackBoxFunc::EmbeddedCurveAdd => Some(4), + // Addition over the embedded curve: input are coordinates (x1,y1,infinite1) and (x2,y2,infinite2) of the Grumpkin points + BlackBoxFunc::EmbeddedCurveAdd => Some(6), // Big integer operations take in 0 inputs. They use constants for their inputs. BlackBoxFunc::BigIntAdd @@ -735,7 +734,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Output of operations over the embedded curve // will be 2 field elements representing the point. - BlackBoxFunc::MultiScalarMul | BlackBoxFunc::EmbeddedCurveAdd => Some(2), + BlackBoxFunc::MultiScalarMul | BlackBoxFunc::EmbeddedCurveAdd => Some(3), // Big integer operations return a big integer BlackBoxFunc::BigIntAdd diff --git a/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr b/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr index 21d658db615..2aec90e0a55 100644 --- a/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr +++ b/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr @@ -1,15 +1,20 @@ use crate::ops::arith::{Add, Sub, Neg}; - +use crate::cmp::Eq; // TODO(https://github.com/noir-lang/noir/issues/4931) struct EmbeddedCurvePoint { x: Field, y: Field, + is_infinite: bool } impl EmbeddedCurvePoint { fn double(self) -> EmbeddedCurvePoint { embedded_curve_add(self, self) } + + fn point_at_infinity() -> EmbeddedCurvePoint { + EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true } + } } impl Add for EmbeddedCurvePoint { @@ -28,11 +33,24 @@ impl Neg for EmbeddedCurvePoint { fn neg(self) -> EmbeddedCurvePoint { EmbeddedCurvePoint { x: self.x, - y: -self.y + y: -self.y, + is_infinite: self.is_infinite } } } +impl Eq for EmbeddedCurvePoint { + fn eq(self: Self, b: EmbeddedCurvePoint) -> bool { + (self.is_infinite & b.is_infinite) | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y)) + } +} + +// Scalar represented as low and high limbs +struct EmbeddedCurveScalar { + lo: Field, + hi: Field, +} + // Computes a multi scalar multiplication over the embedded curve. // For bn254, We have Grumpkin and Baby JubJub. // For bls12-381, we have JubJub and Bandersnatch. @@ -42,9 +60,9 @@ impl Neg for EmbeddedCurvePoint { #[foreign(multi_scalar_mul)] // docs:start:multi_scalar_mul pub fn multi_scalar_mul( - points: [Field; N], // points represented as x and y coordinates [x1, y1, x2, y2, ...] - scalars: [Field; N] // scalars represented as low and high limbs [low1, high1, low2, high2, ...] -) -> [Field; 2] + points: [EmbeddedCurvePoint; N], + scalars: [EmbeddedCurveScalar; N] +) -> [Field; 3] // docs:end:multi_scalar_mul {} @@ -52,12 +70,12 @@ pub fn multi_scalar_mul( pub fn fixed_base_scalar_mul( scalar_low: Field, scalar_high: Field -) -> [Field; 2] +) -> [Field; 3] // docs:end:fixed_base_scalar_mul { - let g1_x = 1; - let g1_y = 17631683881184975370165255887551781615748388533673675138860; - multi_scalar_mul([g1_x, g1_y], [scalar_low, scalar_high]) + let g1 = EmbeddedCurvePoint { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; + let scalar = EmbeddedCurveScalar { lo: scalar_low, hi: scalar_high }; + multi_scalar_mul([g1], [scalar]) } // This is a hack as returning an `EmbeddedCurvePoint` from a foreign function in brillig returns a [BrilligVariable::SingleAddr; 2] rather than BrilligVariable::BrilligArray @@ -72,8 +90,8 @@ fn embedded_curve_add( let point_array = embedded_curve_add_array_return(point1, point2); let x = point_array[0]; let y = point_array[1]; - EmbeddedCurvePoint { x, y } + EmbeddedCurvePoint { x, y, is_infinite: point_array[2] == 1 } } #[foreign(embedded_curve_add)] -fn embedded_curve_add_array_return(_point1: EmbeddedCurvePoint, _point2: EmbeddedCurvePoint) -> [Field; 2] {} +fn embedded_curve_add_array_return(_point1: EmbeddedCurvePoint, _point2: EmbeddedCurvePoint) -> [Field; 3] {} diff --git a/noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/src/main.nr index 9ce17f72c0d..a6c6d3df9a1 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/src/main.nr @@ -4,5 +4,7 @@ fn main(x: Field) { let hash = std::hash::pedersen_commitment([x]); let g1_x = 0x0000000000000000000000000000000000000000000000000000000000000001; let g1_y = 0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c; - let _p1 = std::embedded_curve_ops::multi_scalar_mul([g1_x, g1_y], [x, 0]); + let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: g1_x, y: g1_y, is_infinite: false }; + let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: x, hi: 0 }; + let _p1 = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]); } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr index 8a1a7f08975..89a699448dc 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr @@ -2,22 +2,22 @@ use dep::std; unconstrained fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let g1_y = 17631683881184975370165255887551781615748388533673675138860; - let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y }; - + let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y, is_infinite: false }; + let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 }; // Test that multi_scalar_mul correctly derives the public key - let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y], [priv_key, 0]); + let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]); assert(res[0] == pub_x); assert(res[1] == pub_y); // Test that double function calling embedded_curve_add works as expected - let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y }; + let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false }; let res = pub_point.double(); let double = g1.add(g1); assert(double.x == res.x); // Test calling multi_scalar_mul with multiple points and scalars - let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y, g1.x, g1.y], [priv_key, 0, priv_key, 0]); + let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]); // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice assert(double.x == res[0]); diff --git a/noir/noir-repo/test_programs/execution_success/embedded_curve_ops/src/main.nr b/noir/noir-repo/test_programs/execution_success/embedded_curve_ops/src/main.nr index 3cb27d8c181..46f919e947a 100644 --- a/noir/noir-repo/test_programs/execution_success/embedded_curve_ops/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/embedded_curve_ops/src/main.nr @@ -2,22 +2,22 @@ use dep::std; fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let g1_y = 17631683881184975370165255887551781615748388533673675138860; - let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y }; - + let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y, is_infinite: false }; + let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 }; // Test that multi_scalar_mul correctly derives the public key - let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y], [priv_key, 0]); + let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]); assert(res[0] == pub_x); assert(res[1] == pub_y); // Test that double function calling embedded_curve_add works as expected - let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y }; + let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false }; let res = pub_point.double(); let double = g1.add(g1); assert(double.x == res.x); // Test calling multi_scalar_mul with multiple points and scalars - let res = std::embedded_curve_ops::multi_scalar_mul([g1.x, g1.y, g1.x, g1.y], [priv_key, 0, priv_key, 0]); + let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]); // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice assert(double.x == res[0]); diff --git a/noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/Nargo.toml new file mode 100644 index 00000000000..65e6efea538 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "embedded_curve_ops" +type = "bin" +authors = [""] +compiler_version = ">=0.23.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/src/main.nr new file mode 100644 index 00000000000..9e3c5d87874 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_success/embedded_curve_ops/src/main.nr @@ -0,0 +1,37 @@ +use dep::std::embedded_curve_ops::{EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul}; + +#[test] + + fn test_infinite_point() { + let zero = EmbeddedCurvePoint::point_at_infinity(); + let zero = EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }; + let g1 = EmbeddedCurvePoint { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; + let g2 = g1 + g1; + + let s1 = EmbeddedCurveScalar { lo: 1, hi: 0 }; + let a = multi_scalar_mul([g1], [s1]); + assert(a[2] == 0); + assert(g1 + zero == g1); + assert(g1 - g1 == zero); + assert(g1 - zero == g1); + assert(zero + zero == zero); + assert( + multi_scalar_mul([g1], [s1]) + == [1, 17631683881184975370165255887551781615748388533673675138860, 0] + ); + assert(multi_scalar_mul([g1, g1], [s1, s1]) == [g2.x, g2.y, 0]); + assert( + multi_scalar_mul( + [g1, zero], + [EmbeddedCurveScalar { lo: 2, hi: 0 }, EmbeddedCurveScalar { lo: 42, hi: 25 }] + ) + == [g2.x, g2.y, 0] + ); + assert( + multi_scalar_mul( + [g1, g1, zero], + [s1, s1, EmbeddedCurveScalar { lo: 42, hi: 25 }] + ) + == [g2.x, g2.y, 0] + ); +} diff --git a/noir/noir-repo/tooling/lsp/src/solver.rs b/noir/noir-repo/tooling/lsp/src/solver.rs index 249406effaf..87327b01e36 100644 --- a/noir/noir-repo/tooling/lsp/src/solver.rs +++ b/noir/noir-repo/tooling/lsp/src/solver.rs @@ -27,9 +27,13 @@ impl BlackBoxFunctionSolver for WrapperSolver { fn multi_scalar_mul( &self, points: &[acvm::FieldElement], - scalars: &[acvm::FieldElement], - ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { - self.0.multi_scalar_mul(points, scalars) + scalars_lo: &[acvm::FieldElement], + scalars_hi: &[acvm::FieldElement], + ) -> Result< + (acvm::FieldElement, acvm::FieldElement, acvm::FieldElement), + acvm::BlackBoxResolutionError, + > { + self.0.multi_scalar_mul(points, scalars_lo, scalars_hi) } fn pedersen_hash( @@ -44,10 +48,15 @@ impl BlackBoxFunctionSolver for WrapperSolver { &self, input1_x: &acvm::FieldElement, input1_y: &acvm::FieldElement, + input1_infinite: &acvm::FieldElement, input2_x: &acvm::FieldElement, input2_y: &acvm::FieldElement, - ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { - self.0.ec_add(input1_x, input1_y, input2_x, input2_y) + input2_infinite: &acvm::FieldElement, + ) -> Result< + (acvm::FieldElement, acvm::FieldElement, acvm::FieldElement), + acvm::BlackBoxResolutionError, + > { + self.0.ec_add(input1_x, input1_y, input1_infinite, input2_x, input2_y, input2_infinite) } fn poseidon2_permutation( From 002b4aa556041aa1a12f0fd09bb5ad0b07f04daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 17 May 2024 15:26:25 -0300 Subject: [PATCH 09/37] chore: fix poor performance and long compile times in value_note.derement() (#6523) https://github.com/AztecProtocol/aztec-packages/pull/6405 added a very complicated call (`get_npk_m_hash`) to `destroy_note`, not realizing that `destroy_note` is called in a loop by `decrement`. The loop unrolling caused multiple calls to this function, even though they all had the same arguments, ultimately resulting in humongous RAM usage during compilation (over 40GB just for this contract) and very compilation times (from 30s to multiple minutes). This PR fixes this simply inlining the code for `destroy_note` and fetching the key once at the beginning. It does worry me slightly however that such a large performance hit was not noticed - this likely affected test times as well. --- noir-projects/aztec-nr/value-note/src/utils.nr | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 4c4ba85021c..466cf660d3f 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -47,10 +47,23 @@ pub fn decrement_by_at_most( let options = create_note_getter_options_for_decreasing_balance(max_amount); let opt_notes = balance.get_notes(options); + let owner_npk_m_hash = get_npk_m_hash(balance.context.private.unwrap(), owner); + let mut decremented = 0; for i in 0..opt_notes.len() { if opt_notes[i].is_some() { - decremented += destroy_note(balance, owner, opt_notes[i].unwrap_unchecked()); + let note = opt_notes[i].unwrap_unchecked(); + + // This is similar to destroy_note, except we only compute the owner_npk_m_hash once instead of doing it in + // each loop iteration. + + // Ensure the note is actually owned by the owner (to prevent user from generating a valid proof while + // spending someone else's notes). + // TODO (#6312): This will break with key rotation. Fix this. Will not be able to pass this after rotating keys. + assert(note.npk_m_hash.eq(owner_npk_m_hash)); + decremented += note.value; + + balance.remove(note); } } From c75fbd44c4b564e703ed9e33e948368eadc0867a Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 17 May 2024 17:12:53 -0400 Subject: [PATCH 10/37] chore(ci): only run circleci on master (#6525) We should be catching errors in old CI, and we were hitting spot instance interruptions that seemingly the best advice was 'ignore them'. Probably time for this --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 534fe6bec59..361d11a9a72 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -483,6 +483,9 @@ workflows: # # Used to generate a dynamic 'system' workflow # # This is rewritten to 'system' on the real workflow (otherwise this is ignored by circleci) # equal: [NEVER, << pipeline.parameters.workflow >>] + when: + and: + - equal: [ master, << pipeline.git.branch >> ] jobs: # Noir - noir-x86_64: *defaults From f360b3fd30b9dd1e80e5f1a3d42c325c0f54f8ed Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Fri, 17 May 2024 14:17:14 -0700 Subject: [PATCH 11/37] feat: improved ClientIvc (#6429) The goal is to make `ClientIvc` more flexible and user friendly, primarily through making recursive folding verification an internal component to the class. E.g. given an arbitrary collection of circuits in container `circuits`, I can now simply do this: ```cpp ClientIvc ivc; for (auto circuit : circuits) { ivc.accumulate(circuit); } proof = ivc.prove(); ``` where `proof`, if verified, establishes knowledge of a witness satisfying all 10 circuits. Previously this was not the case unless the required recursive folding verifiers were baked into the circuits being accumulated (as was the case with the kernel). Now, `accumulate` automatically appends a recursive folding verifier to each circuit (beginning with the third call to accumulate since prior to that no fold proof exists). Note that this is already how we were handling the recursive merge verification. This has the advantage of removing details of the IVC scheme from the kernel itself, generalizing ClientIvc for use on an arbitrary set of circuits, and improving the interface in all cases. As expected, the benchmark does not change in any substantial way. (To the extent it does change, its because the gate counts in the circuits have changed slightly due to this new structure). ``` -------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... -------------------------------------------------------------------------------- ClientIVCBench/Full/6 17908 ms 12848 ms 1 ``` --- .../client_ivc_bench/client_ivc.bench.cpp | 146 +++++----- .../barretenberg/client_ivc/client_ivc.cpp | 133 +++++---- .../barretenberg/client_ivc/client_ivc.hpp | 32 +-- .../client_ivc/client_ivc.test.cpp | 253 +++++++++++------- .../client_ivc/mock_kernel_pinning.test.cpp | 43 +-- .../src/barretenberg/goblin/mock_circuits.hpp | 63 ++--- .../protogalaxy/folding_result.hpp | 2 +- .../protogalaxy/protogalaxy_prover.cpp | 2 +- .../protogalaxy_recursive_verifier.test.cpp | 10 +- 9 files changed, 342 insertions(+), 342 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp index ded7acc08f1..80d3e326144 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp @@ -20,7 +20,6 @@ namespace { class ClientIVCBench : public benchmark::Fixture { public: using Builder = GoblinUltraCircuitBuilder; - using VerifierFoldData = GoblinMockCircuits::VerifierFoldData; // Number of function circuits to accumulate(based on Zacs target numbers) static constexpr size_t NUM_ITERATIONS_MEDIUM_COMPLEXITY = 6; @@ -31,6 +30,36 @@ class ClientIVCBench : public benchmark::Fixture { bb::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); } + /** + * @brief Compute verification key for each circuit in the IVC based on the number of desired function circuits + * @details Assumes the following circuit ordering: one initial function circuit followed by pairs of {function, + * kernel} until the desired number of function circuits has been reached. + * + * @param ivc + * @param num_function_circuits + */ + static auto precompute_verification_keys(ClientIVC& ivc, const size_t num_function_circuits) + { + // Populate the set of mock function and kernel circuits to be accumulated in the IVC + std::vector circuits; + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + circuits.emplace_back(function_circuit); + + for (size_t idx = 1; idx < num_function_circuits; ++idx) { + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + circuits.emplace_back(function_circuit); + + Builder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); + circuits.emplace_back(kernel_circuit); + } + + // Compute and return the verfication keys corresponding to this set of circuits + return ivc.precompute_folding_verification_keys(circuits); + } + /** * @brief Perform a specified number of function circuit accumulation rounds * @details Each round "accumulates" a mock function circuit and a mock kernel circuit. Each round thus consists of @@ -40,9 +69,13 @@ class ClientIVCBench : public benchmark::Fixture { * we set the size of the function circuit to be 2^17. The first one should be 2^19 but we can't currently support * folding circuits of unequal size. * + * @param NUM_CIRCUITS Number of function circuits to accumulate */ - static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) + static void perform_ivc_accumulation_rounds(size_t NUM_CIRCUITS, ClientIVC& ivc, auto& precomputed_vks) { + size_t TOTAL_NUM_CIRCUITS = NUM_CIRCUITS * 2 - 1; // need one less kernel than number of function circuits + ASSERT(precomputed_vks.size() == TOTAL_NUM_CIRCUITS); // ensure presence of a precomputed VK for each circuit + const size_t size_hint = 1 << 17; // Size hint for reserving wires/selector vector memory in builders std::vector initial_function_circuits(2); @@ -57,31 +90,21 @@ class ClientIVCBench : public benchmark::Fixture { // Prepend queue to the first circuit initial_function_circuits[0].op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Initialize ivc - ivc.initialize(initial_function_circuits[0]); + ivc.accumulate(initial_function_circuits[0], precomputed_vks[0]); // Retrieve the queue std::swap(*ivc.goblin.op_queue, *initial_function_circuits[0].op_queue); // Prepend queue to the second circuit initial_function_circuits[1].op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Accumulate another function circuit - auto function_fold_proof = ivc.accumulate(initial_function_circuits[1]); + ivc.accumulate(initial_function_circuits[1], precomputed_vks[1]); // Retrieve the queue std::swap(*ivc.goblin.op_queue, *initial_function_circuits[1].op_queue); - VerifierFoldData function_fold_output = { function_fold_proof, ivc.vks.func_vk }; // Free memory initial_function_circuits.clear(); - auto NUM_CIRCUITS = static_cast(state.range(0)); - // Subtract two to account for the "initialization" round above i.e. we have already folded two function - // circuits - NUM_CIRCUITS -= 2; - - // The accumulator for kernel uses the function accumulation verification key - auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); - - VerifierFoldData kernel_fold_output; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + for (size_t circuit_idx = 2; circuit_idx < TOTAL_NUM_CIRCUITS - 1; circuit_idx += 2) { Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; Builder function_circuit{ size_hint }; // Construct function and kernel circuits in parallel @@ -90,18 +113,7 @@ class ClientIVCBench : public benchmark::Fixture { parallel_for(2, [&](size_t workload_idx) { // workload index is 0 for kernel and 1 for function if (workload_idx == 0) { - if (circuit_idx == 0) { - - // Create the first folding kernel which only verifies the accumulation of a - // function circuit - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); - } else { - // Create kernel circuit containing the recursive folding verification of a function circuit - // and a kernel circuit - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); - } + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); } else { GoblinMockCircuits::construct_mock_function_circuit(function_circuit); } @@ -110,48 +122,25 @@ class ClientIVCBench : public benchmark::Fixture { // No need to prepend queue, it's the same after last swap // Accumulate kernel circuit - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - - // First iteration and the following ones differ - if (circuit_idx == 0) { - kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; - } else { - kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; - } + ivc.accumulate(kernel_circuit, precomputed_vks[circuit_idx]); // Prepend queue to function circuit function_circuit.op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Accumulate function circuit - auto function_fold_proof = ivc.accumulate(function_circuit); - function_fold_output = { function_fold_proof, ivc.vks.func_vk }; + ivc.accumulate(function_circuit, precomputed_vks[circuit_idx + 1]); // Retrieve queue std::swap(*ivc.goblin.op_queue, *function_circuit.op_queue); } - // If we haven't entered the cycle, the kernel proof accumulates just function proofs - if (NUM_CIRCUITS == 0) { - // Create and accumulate the first folding kernel which only verifies the accumulation of a function circuit - Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; - auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); - { - BB_OP_COUNT_TIME_NAME("construct_circuits"); - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); - } - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; - } else { - Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; - { - BB_OP_COUNT_TIME_NAME("construct_circuits"); - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); - } - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; + // Final kernel + Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; + { + BB_OP_COUNT_TIME_NAME("construct_circuits"); + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); } + ivc.accumulate(kernel_circuit, precomputed_vks.back()); } }; @@ -162,11 +151,14 @@ class ClientIVCBench : public benchmark::Fixture { BENCHMARK_DEFINE_F(ClientIVCBench, Full)(benchmark::State& state) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct IVC scheme proof (fold, decider, merge, eccvm, translator) ivc.prove(); @@ -181,11 +173,14 @@ BENCHMARK_DEFINE_F(ClientIVCBench, FullStructured)(benchmark::State& state) { ClientIVC ivc; ivc.structured_flag = true; - ivc.precompute_folding_verification_keys(); + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct IVC scheme proof (fold, decider, merge, eccvm, translator) ivc.prove(); @@ -199,11 +194,14 @@ BENCHMARK_DEFINE_F(ClientIVCBench, FullStructured)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Accumulate)(benchmark::State& state) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + // Perform a specified number of iterations of function/kernel accumulation for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); } } @@ -214,8 +212,12 @@ BENCHMARK_DEFINE_F(ClientIVCBench, Accumulate)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Decide)(benchmark::State& state) { ClientIVC ivc; + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct eccvm proof, measure only translator proof construction for (auto _ : state) { @@ -232,8 +234,11 @@ BENCHMARK_DEFINE_F(ClientIVCBench, ECCVM)(benchmark::State& state) { ClientIVC ivc; + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct and measure eccvm only for (auto _ : state) { @@ -249,10 +254,15 @@ BENCHMARK_DEFINE_F(ClientIVCBench, ECCVM)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Translator)(benchmark::State& state) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); + BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct eccvm proof, measure only translator proof construction ivc.goblin.prove_eccvm(); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 758a313658b..71b2ef0f9dd 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -2,32 +2,48 @@ namespace bb { -/** - * @brief Initialize the IVC with a first circuit - * @details Initializes the accumulator and performs the initial goblin merge - * - * @param circuit - */ -void ClientIVC::initialize(ClientCircuit& circuit) -{ - goblin.merge(circuit); // Construct new merge proof - prover_fold_output.accumulator = std::make_shared(circuit, structured_flag); -} - /** * @brief Accumulate a circuit into the IVC scheme - * @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof + * @details If this is the first circuit being accumulated, initialize the prover and verifier accumulators. Otherwise, + * fold the instance for the provided circuit into the accumulator. If a previous fold proof exists, a recursive folding + * verification is appended to the provided circuit prior to its accumulation. Similarly, if a merge proof exists, a + * recursive merge verifier is appended. * * @param circuit Circuit to be accumulated/folded - * @return FoldProof + * @param precomputed_vk Optional precomputed VK (otherwise will be computed herein) */ -ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) +void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr& precomputed_vk) { - goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof + // If a previous fold proof exists, add a recursive folding verification to the circuit + if (!fold_output.proof.empty()) { + BB_OP_COUNT_TIME_NAME("construct_circuits"); + FoldingRecursiveVerifier verifier{ &circuit, verifier_accumulator, { instance_vk } }; + auto verifier_accum = verifier.verify_folding_proof(fold_output.proof); + verifier_accumulator = std::make_shared(verifier_accum->get_value()); + } + + // Construct a merge proof (and add a recursive merge verifier to the circuit if a previous merge proof exists) + goblin.merge(circuit); + + // Construct the prover instance for circuit prover_instance = std::make_shared(circuit, structured_flag); - FoldingProver folding_prover({ prover_fold_output.accumulator, prover_instance }); - prover_fold_output = folding_prover.fold_instances(); - return prover_fold_output.folding_data; + + // Set the instance verification key from precomputed if available, else compute it + if (precomputed_vk) { + instance_vk = precomputed_vk; + } else { + instance_vk = std::make_shared(prover_instance->proving_key); + } + + // If the IVC is uninitialized, simply initialize the prover and verifier accumulator instances + if (!initialized) { + fold_output.accumulator = prover_instance; + verifier_accumulator = std::make_shared(instance_vk); + initialized = true; + } else { // Otherwise, fold the new instance into the accumulator + FoldingProver folding_prover({ fold_output.accumulator, prover_instance }); + fold_output = folding_prover.fold_instances(); + } } /** @@ -37,7 +53,7 @@ ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) */ ClientIVC::Proof ClientIVC::prove() { - return { prover_fold_output.folding_data, decider_prove(), goblin.prove() }; + return { fold_output.proof, decider_prove(), goblin.prove() }; } /** @@ -46,7 +62,7 @@ ClientIVC::Proof ClientIVC::prove() * @param proof * @return bool */ -bool ClientIVC::verify(Proof& proof, const std::vector& verifier_instances) +bool ClientIVC::verify(Proof& proof, const std::vector>& verifier_instances) { // Goblin verification (merge, eccvm, translator) bool goblin_verified = goblin.verify(proof.goblin_proof); @@ -67,63 +83,38 @@ bool ClientIVC::verify(Proof& proof, const std::vector& ver */ HonkProof ClientIVC::decider_prove() const { - GoblinUltraDeciderProver decider_prover(prover_fold_output.accumulator); + GoblinUltraDeciderProver decider_prover(fold_output.accumulator); return decider_prover.construct_proof(); } /** - * @brief Precompute the array of verification keys by simulating folding. There will be 4 different verification keys: - * initial function verification key (without recursive merge verifier), subsequent function verification key (with - * recursive merge verifier), initial kernel verification key (with recursive merge verifier appended, no previous - * kernel to fold), "full" kernel verification key( two recursive folding verifiers and merge verifier). + * @brief Given a set of circuits, compute the verification keys that will be required by the IVC scheme + * @details The verification keys computed here are in general not the same as the verification keys for the + * raw input circuits because recursive verifier circuits (merge and/or folding) may be appended to the incoming + * circuits as part accumulation. + * @note This method exists for convenience and is not not meant to be used in practice for IVC. Given a set of + * circuits, it could be run once and for all to compute then save the required VKs. It also provides a convenient + * (albeit innefficient) way of separating out the cost of computing VKs from a benchmark. * - * TODO(https://github.com/AztecProtocol/barretenberg/issues/904): This function should ultimately be moved outside of - * this class since it's used only for testing and benchmarking purposes and it requires us to clear state afterwards. - * (e.g. in the Goblin object) + * @param circuits A copy of the circuits to be accumulated (passing by reference would alter the original circuits) + * @return std::vector> */ -void ClientIVC::precompute_folding_verification_keys() +std::vector> ClientIVC::precompute_folding_verification_keys( + std::vector circuits) { - using VerifierInstance = VerifierInstance_; - using VerificationKey = Flavor::VerificationKey; - - ClientCircuit initial_function_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); - - // Initialise both the first prover and verifier accumulator from the inital function circuit - initialize(initial_function_circuit); - vks.first_func_vk = std::make_shared(prover_fold_output.accumulator->proving_key); - auto initial_verifier_acc = std::make_shared(vks.first_func_vk); - - // Accumulate the next function circuit - ClientCircuit function_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(function_circuit); - auto function_fold_proof = accumulate(function_circuit); - - // Create its verification key (we have called accumulate so it includes the recursive merge verifier) - vks.func_vk = std::make_shared(prover_instance->proving_key); - - // Create the initial kernel iteration and precompute its verification key - ClientCircuit kernel_circuit{ goblin.op_queue }; - auto kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, { function_fold_proof, vks.func_vk }, {}, initial_verifier_acc); - auto kernel_fold_proof = accumulate(kernel_circuit); - vks.first_kernel_vk = std::make_shared(prover_instance->proving_key); - - // Create another mock function circuit to run the full kernel - function_circuit = ClientCircuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(function_circuit); - function_fold_proof = accumulate(function_circuit); - - // Create the full kernel circuit and compute verification key - kernel_circuit = GoblinUltraCircuitBuilder{ goblin.op_queue }; - kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, { function_fold_proof, vks.func_vk }, { kernel_fold_proof, vks.first_kernel_vk }, kernel_acc); - kernel_fold_proof = accumulate(kernel_circuit); - - vks.kernel_vk = std::make_shared(prover_instance->proving_key); - - // Clean the Goblin state (reinitialise op_queue with mocking and clear merge proofs) - goblin = Goblin(); + std::vector> vkeys; + + for (auto& circuit : circuits) { + accumulate(circuit); + vkeys.emplace_back(instance_vk); + } + + // Reset the scheme so it can be reused for actual accumulation, maintaining the structured trace flag as is + bool structured = structured_flag; + *this = ClientIVC(); + this->structured_flag = structured; + + return vkeys; } } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index eafc0f72aef..d44b02f6740 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -23,8 +23,6 @@ class ClientIVC { using VerificationKey = Flavor::VerificationKey; using FF = Flavor::FF; using FoldProof = std::vector; - using ProverAccumulator = std::shared_ptr>; - using VerifierAccumulator = std::shared_ptr>; using ProverInstance = ProverInstance_; using VerifierInstance = VerifierInstance_; using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra @@ -35,6 +33,11 @@ class ClientIVC { using VerifierInstances = VerifierInstances_; using FoldingVerifier = ProtoGalaxyVerifier_; + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = bb::stdlib::recursion::honk::RecursiveVerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + // A full proof for the IVC scheme struct Proof { FoldProof folding_proof; // final fold proof @@ -57,13 +60,6 @@ class ClientIVC { } }; - struct PrecomputedVerificationKeys { - std::shared_ptr first_func_vk; - std::shared_ptr func_vk; - std::shared_ptr first_kernel_vk; - std::shared_ptr kernel_vk; - }; - private: using ProverFoldOutput = FoldingResult; // Note: We need to save the last instance that was folded in order to compute its verification key, this will not @@ -71,28 +67,28 @@ class ClientIVC { public: Goblin goblin; - ProverFoldOutput prover_fold_output; - ProverAccumulator prover_accumulator; - PrecomputedVerificationKeys vks; + ProverFoldOutput fold_output; + std::shared_ptr prover_accumulator; + std::shared_ptr verifier_accumulator; // Note: We need to save the last instance that was folded in order to compute its verification key, this will not // be needed in the real IVC as they are provided as inputs std::shared_ptr prover_instance; + std::shared_ptr instance_vk; // A flag indicating whether or not to construct a structured trace in the ProverInstance bool structured_flag = false; - void initialize(ClientCircuit& circuit); + // A flag indicating whether the IVC has been initialized with an initial instance + bool initialized = false; - FoldProof accumulate(ClientCircuit& circuit); + void accumulate(ClientCircuit& circuit, const std::shared_ptr& precomputed_vk = nullptr); Proof prove(); - bool verify(Proof& proof, const std::vector& verifier_instances); + bool verify(Proof& proof, const std::vector>& verifier_instances); HonkProof decider_prove() const; - void decider_prove_and_verify(const VerifierAccumulator&) const; - - void precompute_folding_verification_keys(); + std::vector> precompute_folding_verification_keys(std::vector); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 0dd189112b8..6a1676c4883 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -17,18 +17,11 @@ class ClientIVCTests : public ::testing::Test { using Flavor = ClientIVC::Flavor; using FF = typename Flavor::FF; + using VerificationKey = Flavor::VerificationKey; using Builder = ClientIVC::ClientCircuit; - using ProverAccumulator = ClientIVC::ProverAccumulator; - using VerifierAccumulator = ClientIVC::VerifierAccumulator; + using ProverInstance = ClientIVC::ProverInstance; using VerifierInstance = ClientIVC::VerifierInstance; using FoldProof = ClientIVC::FoldProof; - using VerifierFoldData = GoblinMockCircuits::VerifierFoldData; - using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; - using RecursiveVerifierAccumulator = std::shared_ptr; - using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; - using FoldingRecursiveVerifier = - bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; using DeciderProver = ClientIVC::DeciderProver; using DeciderVerifier = ClientIVC::DeciderVerifier; using ProverInstances = ProverInstances_; @@ -36,6 +29,20 @@ class ClientIVCTests : public ::testing::Test { using VerifierInstances = VerifierInstances_; using FoldingVerifier = ProtoGalaxyVerifier_; + /** + * @brief Prove and verify the IVC scheme + * @details Constructs four proofs: merge, eccvm, translator, decider; Verifies these four plus the final folding + * proof constructed on the last accumulation round + * + */ + static bool prove_and_verify(ClientIVC& ivc) + { + auto proof = ivc.prove(); + + auto verifier_inst = std::make_shared(ivc.instance_vk); + return ivc.verify(proof, { ivc.verifier_accumulator, verifier_inst }); + } + /** * @brief Construct mock circuit with arithmetic gates and goblin ops * @details Currently default sized to 2^16 to match kernel. (Note: dummy op gates added to avoid non-zero @@ -55,111 +62,153 @@ class ClientIVCTests : public ::testing::Test { MockCircuits::construct_goblin_ecc_op_circuit(circuit); return circuit; } +}; - /** - * @brief Construct mock kernel consisting of two recursive folding verifiers to verify the folding of the previous - * function circuit and kernel circuit. - * - * @param builder - * @param func_accum contains the folding proof for the function circuit and the corresponsing function - * verifier instance - * @param kernel_accum contains the folding proof for the kernel circuit and the corresponding kernel verifier - * instance - * @returns the updated verifier accumulator - */ - static VerifierAccumulator construct_mock_folding_kernel(Builder& builder, - VerifierFoldData& func_accum, - VerifierFoldData& kernel_accum, - VerifierAccumulator& prev_kernel_accum) - { +/** + * @brief A simple-as-possible test demonstrating IVC for two mock circuits + * + */ +TEST_F(ClientIVCTests, Basic) +{ + ClientIVC ivc; + + // Initialize the IVC with an arbitrary circuit + Builder circuit_0 = create_mock_circuit(ivc); + ivc.accumulate(circuit_0); - FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { func_accum.inst_vk } }; - auto fctn_verifier_accum = verifier_1.verify_folding_proof(func_accum.fold_proof); - auto native_acc = std::make_shared(fctn_verifier_accum->get_value()); - FoldingRecursiveVerifier verifier_2{ &builder, native_acc, { kernel_accum.inst_vk } }; - auto kernel_verifier_accum = verifier_2.verify_folding_proof(kernel_accum.fold_proof); - return std::make_shared(kernel_verifier_accum->get_value()); + // Create another circuit and accumulate + Builder circuit_1 = create_mock_circuit(ivc); + ivc.accumulate(circuit_1); + + EXPECT_TRUE(prove_and_verify(ivc)); +}; + +/** + * @brief Check that the IVC fails to verify if an intermediate fold proof is invalid + * + */ +TEST_F(ClientIVCTests, BasicFailure) +{ + ClientIVC ivc; + + // Initialize the IVC with an arbitrary circuit + Builder circuit_0 = create_mock_circuit(ivc); + ivc.accumulate(circuit_0); + + // Create another circuit and accumulate + Builder circuit_1 = create_mock_circuit(ivc); + ivc.accumulate(circuit_1); + + // Tamper with the fold proof just created in the last accumulation step + for (auto& val : ivc.fold_output.proof) { + if (val > 0) { // tamper by finding the first non-zero value and incrementing it by 1 + val += 1; + break; + } } - /** - * @brief Perform native fold verification and run decider prover/verifier - * - */ - static VerifierAccumulator update_accumulator_and_decide_native( - const ProverAccumulator& prover_accumulator, - const FoldProof& fold_proof, - const VerifierAccumulator& prev_verifier_accumulator, - const std::shared_ptr& verifier_inst_vk) - { - // Verify fold proof - auto new_verifier_inst = std::make_shared(verifier_inst_vk); - FoldingVerifier folding_verifier({ prev_verifier_accumulator, new_verifier_inst }); - auto verifier_accumulator = folding_verifier.verify_folding_proof(fold_proof); - - // Run decider - DeciderProver decider_prover(prover_accumulator); - DeciderVerifier decider_verifier(verifier_accumulator); - auto decider_proof = decider_prover.construct_proof(); - bool decision = decider_verifier.verify_proof(decider_proof); - EXPECT_TRUE(decision); - - return verifier_accumulator; + // Accumulate another circuit; this involves recursive folding verification of the bad proof + Builder circuit_2 = create_mock_circuit(ivc); + ivc.accumulate(circuit_2); + + // The bad fold proof should result in an invalid witness in the final circuit and the IVC should fail to verify + EXPECT_FALSE(prove_and_verify(ivc)); +}; + +/** + * @brief Prove and verify accumulation of an arbitrary set of circuits + * + */ +TEST_F(ClientIVCTests, BasicLarge) +{ + ClientIVC ivc; + + // Construct a set of arbitrary circuits + size_t NUM_CIRCUITS = 5; + std::vector circuits; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + circuits.emplace_back(create_mock_circuit(ivc)); + } + + // Accumulate each circuit + for (auto& circuit : circuits) { + ivc.accumulate(circuit); } + + EXPECT_TRUE(prove_and_verify(ivc)); }; /** - * @brief A full Goblin test using PG that mimicks the basic aztec client architecture + * @brief Using a structured trace allows for the accumulation of circuits of varying size * */ -// TODO fix with https://github.com/AztecProtocol/barretenberg/issues/930 -// intermittent failures, presumably due to uninitialized memory -TEST_F(ClientIVCTests, DISABLED_Full) +TEST_F(ClientIVCTests, BasicStructured) { - using VerificationKey = Flavor::VerificationKey; + ClientIVC ivc; + ivc.structured_flag = true; + + // Construct some circuits of varying size + Builder circuit_0 = create_mock_circuit(ivc, /*log2_num_gates=*/5); + Builder circuit_1 = create_mock_circuit(ivc, /*log2_num_gates=*/10); + Builder circuit_2 = create_mock_circuit(ivc, /*log2_num_gates=*/15); + + // The circuits can be accumulated as normal due to the structured trace + ivc.accumulate(circuit_0); + ivc.accumulate(circuit_1); + ivc.accumulate(circuit_2); + + EXPECT_TRUE(prove_and_verify(ivc)); +}; +/** + * @brief Prove and verify accumulation of an arbitrary set of circuits using precomputed verification keys + * + */ +TEST_F(ClientIVCTests, PrecomputedVerificationKeys) +{ ClientIVC ivc; - // Initialize IVC with function circuit - Builder function_circuit = create_mock_circuit(ivc); - ivc.initialize(function_circuit); - - auto function_vk = std::make_shared(ivc.prover_fold_output.accumulator->proving_key); - auto foo_verifier_instance = std::make_shared(function_vk); - // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) - Builder kernel_circuit = create_mock_circuit(ivc); - FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - // This will have a different verification key because we added the recursive merge verification to the circuit - auto function_vk_with_merge = std::make_shared(ivc.prover_instance->proving_key); - auto kernel_vk = function_vk_with_merge; - auto intermediary_acc = update_accumulator_and_decide_native( - ivc.prover_fold_output.accumulator, kernel_fold_proof, foo_verifier_instance, kernel_vk); - - VerifierFoldData kernel_fold_output = { kernel_fold_proof, function_vk_with_merge }; - size_t NUM_CIRCUITS = 1; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Accumulate function circuit - Builder function_circuit = create_mock_circuit(ivc); - FoldProof function_fold_proof = ivc.accumulate(function_circuit); - - intermediary_acc = update_accumulator_and_decide_native( - ivc.prover_fold_output.accumulator, function_fold_proof, intermediary_acc, function_vk_with_merge); - - VerifierFoldData function_fold_output = { function_fold_proof, function_vk_with_merge }; - // Accumulate kernel circuit - Builder kernel_circuit{ ivc.goblin.op_queue }; - foo_verifier_instance = construct_mock_folding_kernel( - kernel_circuit, kernel_fold_output, function_fold_output, foo_verifier_instance); - FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_vk = std::make_shared(ivc.prover_instance->proving_key); - - intermediary_acc = update_accumulator_and_decide_native( - ivc.prover_fold_output.accumulator, kernel_fold_proof, intermediary_acc, kernel_vk); - - VerifierFoldData kernel_fold_output = { kernel_fold_proof, kernel_vk }; + + // Construct a set of arbitrary circuits + size_t NUM_CIRCUITS = 3; + std::vector circuits; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + circuits.emplace_back(create_mock_circuit(ivc)); + } + + // Precompute the verification keys that will be needed for the IVC + auto precomputed_vkeys = ivc.precompute_folding_verification_keys(circuits); + + // Accumulate each circuit using the precomputed VKs + for (auto [circuit, precomputed_vk] : zip_view(circuits, precomputed_vkeys)) { + ivc.accumulate(circuit, precomputed_vk); + } + + EXPECT_TRUE(prove_and_verify(ivc)); +}; + +/** + * @brief Perform accumulation with a structured trace and precomputed verification keys + * + */ +TEST_F(ClientIVCTests, StructuredPrecomputedVKs) +{ + ClientIVC ivc; + ivc.structured_flag = true; + + // Construct a set of arbitrary circuits + size_t NUM_CIRCUITS = 3; + std::vector circuits; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + circuits.emplace_back(create_mock_circuit(ivc)); } - // Constuct four proofs: merge, eccvm, translator, decider - auto proof = ivc.prove(); - auto inst = std::make_shared(kernel_vk); - // Verify all four proofs - EXPECT_TRUE(ivc.verify(proof, { foo_verifier_instance, inst })); -}; \ No newline at end of file + // Precompute the (structured) verification keys that will be needed for the IVC + auto precomputed_vkeys = ivc.precompute_folding_verification_keys(circuits); + + // Accumulate each circuit + for (auto [circuit, precomputed_vk] : zip_view(circuits, precomputed_vkeys)) { + ivc.accumulate(circuit, precomputed_vk); + } + + EXPECT_TRUE(prove_and_verify(ivc)); +}; diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp index d4d06758e2f..bb11e2cc670 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp @@ -12,6 +12,9 @@ using namespace bb; * */ class MockKernelTest : public ::testing::Test { + public: + using Builder = GoblinUltraCircuitBuilder; + protected: static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); } }; @@ -19,38 +22,20 @@ class MockKernelTest : public ::testing::Test { TEST_F(MockKernelTest, PinFoldingKernelSizes) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); - // Accumulate three circuits to generate two folding proofs for input to folding kernel - GoblinUltraCircuitBuilder circuit_1{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_1); - ivc.initialize(circuit_1); - auto kernel_acc = std::make_shared(ivc.vks.first_func_vk); - kernel_acc->verification_key = ivc.vks.first_func_vk; - EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); - GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_2); - auto func_fold_proof = ivc.accumulate(circuit_2); - EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); + // Construct two function circuits and a kernel circuit + Builder circuit_1{ ivc.goblin.op_queue }; + Builder circuit_2{ ivc.goblin.op_queue }; + Builder kernel_circuit{ ivc.goblin.op_queue }; - // Construct kernel circuit - GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; - kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, { func_fold_proof, ivc.vks.func_vk }, {}, kernel_acc); + GoblinMockCircuits::construct_mock_function_circuit(circuit_1); + GoblinMockCircuits::construct_mock_function_circuit(circuit_2); + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); + // Accumulate all three; The kernel will contain a single recursive folding verifier + ivc.accumulate(circuit_1); + ivc.accumulate(circuit_2); + ivc.accumulate(kernel_circuit); - GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_3); - func_fold_proof = ivc.accumulate(circuit_3); EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); - - kernel_circuit = GoblinUltraCircuitBuilder{ ivc.goblin.op_queue }; - kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, - { kernel_fold_proof, ivc.vks.first_kernel_vk }, - { func_fold_proof, ivc.vks.func_vk }, - kernel_acc); - auto instance = std::make_shared(kernel_circuit); - EXPECT_EQ(instance->proving_key.log_circuit_size, 17); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 46586ff58da..a3234dbc984 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -41,15 +41,6 @@ class GoblinMockCircuits { std::shared_ptr verification_key; }; - /** - * @brief Information required by the verifier to verify a folding round besides the previous accumulator. - */ - struct VerifierFoldData { - std::vector fold_proof; // folding proof - std::shared_ptr - inst_vk; // Verification key of the instance to be folded (note: this would be a vector if k > 1 ) - }; - /** * @brief Populate a builder with some arbitrary but nontrivial constraints * @details Although the details of the circuit constructed here are arbitrary, the intent is to mock something a @@ -64,12 +55,16 @@ class GoblinMockCircuits { // Determine number of times to execute the below operations that constitute the mock circuit logic. Note that // the circuit size does not scale linearly with number of iterations due to e.g. amortization of lookup costs const size_t NUM_ITERATIONS_LARGE = 12; // results in circuit size 2^19 (502238 gates) - const size_t NUM_ITERATIONS_MEDIUM = 3; // results in circuit size 2^17 (124843 gates) - const size_t NUM_ITERATIONS = large ? NUM_ITERATIONS_LARGE : NUM_ITERATIONS_MEDIUM; - stdlib::generate_sha256_test_circuit(builder, NUM_ITERATIONS); // min gates: ~39k - stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS); // min gates: ~41k - stdlib::generate_merkle_membership_test_circuit(builder, NUM_ITERATIONS); // min gates: ~29k + if (large) { + stdlib::generate_sha256_test_circuit(builder, NUM_ITERATIONS_LARGE); + stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS_LARGE); + stdlib::generate_merkle_membership_test_circuit(builder, NUM_ITERATIONS_LARGE); + } else { // Results in circuit size 2^17 when accumulated via ClientIvc + stdlib::generate_sha256_test_circuit(builder, 5); + stdlib::generate_ecdsa_verification_test_circuit(builder, 2); + stdlib::generate_merkle_membership_test_circuit(builder, 10); + } // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): We require goblin ops to be added to the // function circuit because we cannot support zero commtiments. While the builder handles this at @@ -177,50 +172,24 @@ class GoblinMockCircuits { } /** - * @brief Construct a mock kernel circuit based on folding - * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive - * folding verification of a function circuit folding proof, and (3) recursive folding verification of a previous - * kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of - * the kernel to 2^17. + * @brief Construct a mock kernel circuit + * @details Construct an arbitrary circuit meant to represent the aztec private function execution kernel. Recursive + * folding verification is handled internally by ClientIvc, not in the kernel. * * @param builder * @param function_fold_proof * @param kernel_fold_proof */ - static std::shared_ptr construct_mock_folding_kernel( - GoblinUltraBuilder& builder, - const VerifierFoldData& func, - const VerifierFoldData& kernel, - std::shared_ptr& prev_kernel_accum) + static void construct_mock_folding_kernel(GoblinUltraBuilder& builder) { - using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstances = - bb::stdlib::recursion::honk::RecursiveVerifierInstances_; - using FoldingRecursiveVerifier = - bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; - // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make - // the kernel "full" within the dyadic size 2^17 (130914 gates) - const size_t NUM_MERKLE_CHECKS = 25; - const size_t NUM_ECDSA_VERIFICATIONS = 1; + // the kernel "full" within the dyadic size 2^17 + const size_t NUM_MERKLE_CHECKS = 20; + const size_t NUM_ECDSA_VERIFICATIONS = 2; const size_t NUM_SHA_HASHES = 1; stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS); stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ECDSA_VERIFICATIONS); stdlib::generate_sha256_test_circuit(builder, NUM_SHA_HASHES); - - // Initial kernel iteration does not have a previous kernel to fold - if (kernel.fold_proof.empty()) { - FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { func.inst_vk } }; - auto fctn_verifier_accum = verifier_1.verify_folding_proof(func.fold_proof); - return std::make_shared(fctn_verifier_accum->get_value()); - } - - FoldingRecursiveVerifier verifier_2{ &builder, prev_kernel_accum, { kernel.inst_vk } }; - auto kernel_verifier_accum = verifier_2.verify_folding_proof(kernel.fold_proof); - auto native_acc = std::make_shared(kernel_verifier_accum->get_value()); - FoldingRecursiveVerifier verifier_1{ &builder, native_acc, { func.inst_vk } }; - auto fctn_verifier_accum = verifier_1.verify_folding_proof(func.fold_proof); - return std::make_shared(fctn_verifier_accum->get_value()); } /** diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp index 4bf3eb88fff..61d6fdf3dd3 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp @@ -13,6 +13,6 @@ template struct FoldingResult { public: std::shared_ptr> accumulator; // TODO(https://github.com/AztecProtocol/barretenberg/issues/656): turn folding data into a struct - std::vector folding_data; + std::vector proof; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index 6d67ab10576..e003418a524 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -192,7 +192,7 @@ template void ProtoGalaxyProver_::accum FF combiner_challenge = transcript->template get_challenge("combiner_quotient_challenge"); std::shared_ptr next_accumulator = compute_next_accumulator(instances, state.combiner_quotient, combiner_challenge, state.compressed_perturbator); - state.result.folding_data = transcript->proof_data; + state.result.proof = transcript->proof_data; state.result.accumulator = next_accumulator; }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp index 673d7234df9..786d75545fc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp @@ -195,14 +195,14 @@ template class ProtoGalaxyRecursiveTests : public tes OuterBuilder folding_circuit; auto verifier = FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); - verifier.verify_folding_proof(folding_proof.folding_data); + verifier.verify_folding_proof(folding_proof.proof); info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates); EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err(); // Perform native folding verification and ensure it returns the same result (either true or false) as // calling check_circuit on the recursive folding verifier InnerFoldingVerifier native_folding_verifier({ verifier_instance_1, verifier_instance_2 }); - native_folding_verifier.verify_folding_proof(folding_proof.folding_data); + native_folding_verifier.verify_folding_proof(folding_proof.proof); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -259,7 +259,7 @@ template class ProtoGalaxyRecursiveTests : public tes OuterBuilder folding_circuit; auto verifier = FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); - auto recursive_verifier_accumulator = verifier.verify_folding_proof(folding_proof.folding_data); + auto recursive_verifier_accumulator = verifier.verify_folding_proof(folding_proof.proof); auto native_verifier_acc = std::make_shared(recursive_verifier_accumulator->get_value()); info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates); @@ -269,7 +269,7 @@ template class ProtoGalaxyRecursiveTests : public tes // Perform native folding verification and ensure it returns the same result (either true or false) as // calling check_circuit on the recursive folding verifier InnerFoldingVerifier native_folding_verifier({ verifier_instance_1, verifier_instance_2 }); - auto verifier_accumulator = native_folding_verifier.verify_folding_proof(folding_proof.folding_data); + auto verifier_accumulator = native_folding_verifier.verify_folding_proof(folding_proof.proof); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -359,7 +359,7 @@ template class ProtoGalaxyRecursiveTests : public tes FoldingRecursiveVerifier verifier{ &folding_circuit, verifier_accumulator, { verifier_inst->verification_key } }; - auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.folding_data); + auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.proof); // Validate that the target sum between prover and verifier is now different EXPECT_FALSE(folding_proof.accumulator->target_sum == recursive_verifier_acc->target_sum.get_value()); }; From af9fea4bbafe1a41b09d9351a34a896db2c8ab7d Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Fri, 17 May 2024 18:39:32 -0400 Subject: [PATCH 12/37] feat: laying out a new recursion constraint for honk (#6489) Create new recursion constraint for honk, which is the same as the plonk recursion constraint, but with a default aggregation object. The default aggregation object work was moved from https://github.com/AztecProtocol/aztec-packages/pull/6087. This PR is mostly for setup for https://github.com/AztecProtocol/barretenberg/issues/933. --- barretenberg/acir_tests/reset_acir_tests.sh | 7 + .../dsl/acir_format/acir_format.cpp | 137 ++++++- .../dsl/acir_format/acir_format.hpp | 15 +- .../dsl/acir_format/acir_format.test.cpp | 6 + .../acir_format/bigint_constraint.test.cpp | 5 + .../dsl/acir_format/block_constraint.test.cpp | 1 + .../dsl/acir_format/ec_operations.test.cpp | 2 + .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 3 + .../dsl/acir_format/ecdsa_secp256r1.test.cpp | 4 + .../acir_format/honk_recursion_constraint.cpp | 370 ++++++++++++++++++ .../acir_format/honk_recursion_constraint.hpp | 76 ++++ .../honk_recursion_constraint.test.cpp | 365 +++++++++++++++++ .../acir_format/poseidon2_constraint.test.cpp | 1 + .../acir_format/recursion_constraint.test.cpp | 39 +- .../acir_format/sha256_constraint.test.cpp | 1 + .../stdlib/primitives/bigfield/bigfield.hpp | 16 +- 16 files changed, 1011 insertions(+), 37 deletions(-) create mode 100644 barretenberg/acir_tests/reset_acir_tests.sh create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp diff --git a/barretenberg/acir_tests/reset_acir_tests.sh b/barretenberg/acir_tests/reset_acir_tests.sh new file mode 100644 index 00000000000..e83bea9189e --- /dev/null +++ b/barretenberg/acir_tests/reset_acir_tests.sh @@ -0,0 +1,7 @@ +cd ~/aztec-packages/noir/noir-repo +cargo clean +noirup -p . +cd test_programs && ./rebuild.sh + +cd ~/aztec-packages/barretenberg/acir_tests +rm -rf acir_tests diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index f74228a115f..3dc7fc15e6c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -10,7 +10,10 @@ template class DSLBigInts; template class DSLBigInts; template -void build_constraints(Builder& builder, AcirFormat const& constraint_system, bool has_valid_witness_assignments) +void build_constraints(Builder& builder, + AcirFormat const& constraint_system, + bool has_valid_witness_assignments, + bool honk_recursion) { // Add arithmetic gates for (const auto& constraint : constraint_system.poly_triple_constraints) { @@ -118,6 +121,7 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo create_bigint_to_le_bytes_constraint(builder, constraint, dsl_bigints); } + // RecursionConstraint // TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet // dealing with proper recursion if constexpr (IsGoblinUltraBuilder) { @@ -161,7 +165,7 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo auto error_string = format( "Public inputs are always stripped from proofs unless we have a recursive proof.\n" "Thus, public inputs attached to a proof must match the recursive aggregation object in size " - "which is {}\n", + "which is ", RecursionConstraint::AGGREGATION_OBJECT_SIZE); throw_or_abort(error_string); } @@ -206,6 +210,121 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo builder.set_recursive_proof(proof_output_witness_indices); } } + + // HonkRecursionConstraint + // TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet + // dealing with proper recursion + if constexpr (IsGoblinUltraBuilder) { + if (!constraint_system.honk_recursion_constraints.empty()) { + info("WARNING: this circuit contains honk_recursion_constraints!"); + } + } else { + // These are set and modified whenever we encounter a recursion opcode + // + // These should not be set by the caller + // TODO(maxim): Check if this is always the case. ie I won't receive a proof that will set the first + // TODO(maxim): input_aggregation_object to be non-zero. + // TODO(maxim): if not, we can add input_aggregation_object to the proof too for all recursive proofs + // TODO(maxim): This might be the case for proof trees where the proofs are created on different machines + std::array current_aggregation_object = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + // Get the size of proof with no public inputs prepended to it + // This is used while processing recursion constraints to determine whether + // the proof we are verifying contains a recursive proof itself + auto proof_size_no_pub_inputs = recursion_honk_proof_size_without_public_inputs(); + + // Add recursion constraints + for (auto constraint : constraint_system.honk_recursion_constraints) { + // A proof passed into the constraint should be stripped of its public inputs, except in the case where a + // proof contains an aggregation object itself. We refer to this as the `nested_aggregation_object`. The + // verifier circuit requires that the indices to a nested proof aggregation state are a circuit constant. + // The user tells us they how they want these constants set by keeping the nested aggregation object + // attached to the proof as public inputs. As this is the only object that can prepended to the proof if the + // proof is above the expected size (with public inputs stripped) + std::array nested_aggregation_object = {}; + // If the proof has public inputs attached to it, we should handle setting the nested aggregation object + // The public inputs attached to a proof should match the aggregation object in size + if (constraint.proof.size() - proof_size_no_pub_inputs != + HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE) { + auto error_string = format( + "Public inputs are always stripped from proofs unless we have a recursive proof.\n" + "Thus, public inputs attached to a proof must match the recursive aggregation object in size " + "which is ", + HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE); + throw_or_abort(error_string); + } + for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + // Set the nested aggregation object indices to the current size of the public inputs + // This way we know that the nested aggregation object indices will always be the last + // indices of the public inputs + nested_aggregation_object[i] = static_cast(constraint.public_inputs.size()); + // Attach the nested aggregation object to the end of the public inputs to fill in + // the slot where the nested aggregation object index will point into + constraint.public_inputs.emplace_back(constraint.proof[i]); + } + // Remove the aggregation object so that they can be handled as normal public inputs + // in they way taht the recursion constraint expects + constraint.proof.erase(constraint.proof.begin(), + constraint.proof.begin() + + static_cast(HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE)); + current_aggregation_object = create_honk_recursion_constraints(builder, + constraint, + current_aggregation_object, + nested_aggregation_object, + has_valid_witness_assignments); + } + + // Now that the circuit has been completely built, we add the output aggregation as public + // inputs. + if (!constraint_system.honk_recursion_constraints.empty()) { + + // First add the output aggregation object as public inputs + // Set the indices as public inputs because they are no longer being + // created in ACIR + for (const auto& idx : current_aggregation_object) { + builder.set_public_input(idx); + } + + // Make sure the verification key records the public input indices of the + // final recursion output. + std::vector proof_output_witness_indices(current_aggregation_object.begin(), + current_aggregation_object.end()); + builder.set_recursive_proof(proof_output_witness_indices); + } else if (honk_recursion && + builder.is_recursive_circuit) { // Set a default aggregation object if we don't have one. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted from + // a valid proof. This is a workaround because we can't represent the point at infinity in biggroup yet. + fq x0("0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf"); + fq y0("0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4"); + + fq x1("0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38"); + fq y1("0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f"); + std::vector aggregation_object_fq_values = { x0, y0, x1, y1 }; + size_t agg_obj_indices_idx = 0; + for (fq val : aggregation_object_fq_values) { + const uint256_t x = val; + std::array val_limbs = { + x.slice(0, fq_ct::NUM_LIMB_BITS), + x.slice(fq_ct::NUM_LIMB_BITS, fq_ct::NUM_LIMB_BITS * 2), + x.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 3), + x.slice(fq_ct::NUM_LIMB_BITS * 3, bb::stdlib::field_conversion::TOTAL_BITS) + }; + for (size_t i = 0; i < fq_ct::NUM_LIMBS; ++i) { + uint32_t idx = builder.add_variable(val_limbs[i]); + builder.set_public_input(idx); + current_aggregation_object[agg_obj_indices_idx] = idx; + agg_obj_indices_idx++; + } + } + // Make sure the verification key records the public input indices of the + // final recursion output. + std::vector proof_output_witness_indices(current_aggregation_object.begin(), + current_aggregation_object.end()); + builder.set_recursive_proof(proof_output_witness_indices); + } + } } /** @@ -218,14 +337,17 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo * @return Builder */ template <> -UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, size_t size_hint, WitnessVector const& witness) +UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, + size_t size_hint, + WitnessVector const& witness, + bool honk_recursion) { Builder builder{ size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, constraint_system.recursive }; bool has_valid_witness_assignments = !witness.empty(); - build_constraints(builder, constraint_system, has_valid_witness_assignments); + build_constraints(builder, constraint_system, has_valid_witness_assignments, honk_recursion); builder.finalize_circuit(); @@ -244,7 +366,8 @@ UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, size_t s template <> GoblinUltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, [[maybe_unused]] size_t size_hint, - WitnessVector const& witness) + WitnessVector const& witness, + bool honk_recursion) { // Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue auto op_queue = std::make_shared(); // instantiate empty op_queue @@ -253,13 +376,13 @@ GoblinUltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, // Populate constraints in the builder via the data in constraint_system bool has_valid_witness_assignments = !witness.empty(); - acir_format::build_constraints(builder, constraint_system, has_valid_witness_assignments); + acir_format::build_constraints(builder, constraint_system, has_valid_witness_assignments, honk_recursion); builder.finalize_circuit(); return builder; }; -template void build_constraints(GoblinUltraCircuitBuilder&, AcirFormat const&, bool); +template void build_constraints(GoblinUltraCircuitBuilder&, AcirFormat const&, bool, bool); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 9add17a1451..35d4d1fe6c1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -9,6 +9,7 @@ #include "ec_operations.hpp" #include "ecdsa_secp256k1.hpp" #include "ecdsa_secp256r1.hpp" +#include "honk_recursion_constraint.hpp" #include "keccak_constraint.hpp" #include "logic_constraint.hpp" #include "multi_scalar_mul.hpp" @@ -54,6 +55,7 @@ struct AcirFormat { std::vector multi_scalar_mul_constraints; std::vector ec_add_constraints; std::vector recursion_constraints; + std::vector honk_recursion_constraints; std::vector bigint_from_le_bytes_constraints; std::vector bigint_to_le_bytes_constraints; std::vector bigint_operations; @@ -89,6 +91,7 @@ struct AcirFormat { multi_scalar_mul_constraints, ec_add_constraints, recursion_constraints, + honk_recursion_constraints, poly_triple_constraints, block_constraints, bigint_from_le_bytes_constraints, @@ -102,9 +105,17 @@ using WitnessVector = std::vector>; using WitnessVectorStack = std::vector>; template -Builder create_circuit(const AcirFormat& constraint_system, size_t size_hint = 0, WitnessVector const& witness = {}); +Builder create_circuit(const AcirFormat& constraint_system, + size_t size_hint = 0, + WitnessVector const& witness = {}, + bool honk_recursion = false); template -void build_constraints(Builder& builder, AcirFormat const& constraint_system, bool has_valid_witness_assignments); +void build_constraints(Builder& builder, + AcirFormat const& constraint_system, + bool has_valid_witness_assignments, + bool honk_recursion = false); // honk_recursion means we will honk to recursively verify this + // circuit. This distinction is needed to not add the default + // aggregation object when we're not using the honk RV. } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 038db2a28f9..cf6df51ea90 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -52,6 +52,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -170,6 +171,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -240,6 +242,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -337,6 +340,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -453,6 +457,7 @@ TEST_F(AcirFormatTests, TestVarKeccak) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -502,6 +507,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 1cc86262bd1..923d496fd8d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -189,6 +189,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -259,6 +260,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = { from_le_bytes_constraint_bigint1 }, .bigint_to_le_bytes_constraints = { result2_to_le_bytes }, .bigint_operations = { add_constraint }, @@ -314,6 +316,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -373,6 +376,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -453,6 +457,7 @@ TEST_F(BigIntTests, TestBigIntDIV) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = { from_le_bytes_constraint_bigint1, from_le_bytes_constraint_bigint2 }, .bigint_to_le_bytes_constraints = { result3_to_le_bytes }, .bigint_operations = { div_constraint }, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 5d649d8feb3..eb377b5b532 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -131,6 +131,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index 59333ddc0d4..1cd34c076f8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -76,6 +76,7 @@ TEST_F(EcOperations, TestECOperations) .multi_scalar_mul_constraints = {}, .ec_add_constraints = { ec_add_constraint }, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -161,6 +162,7 @@ TEST_F(EcOperations, TestECMultiScalarMul) .multi_scalar_mul_constraints = { msm_constrain }, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 61782002c85..90a5546068d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -111,6 +111,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -162,6 +163,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -208,6 +210,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index de1d0931d8c..257bcf4a2e2 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -145,6 +145,7 @@ TEST(ECDSASecp256r1, test_hardcoded) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -198,6 +199,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -249,6 +251,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -295,6 +298,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp new file mode 100644 index 00000000000..fb46384ce01 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp @@ -0,0 +1,370 @@ +#include "honk_recursion_constraint.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/plonk/transcript/transcript_wrappers.hpp" +#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" +#include "recursion_constraint.hpp" + +namespace acir_format { + +using namespace bb::plonk; + +/** + * @brief Add constraints required to recursively verify an UltraPlonk proof + * + * @param builder + * @param input + * @tparam has_valid_witness_assignment. Do we have witnesses or are we just generating keys? + * @tparam inner_proof_contains_recursive_proof. Do we expect the inner proof to also have performed recursive + * verification? We need to know this at circuit-compile time. + * + * @note We currently only support HonkRecursionConstraint where inner_proof_contains_recursive_proof = false. + * We would either need a separate ACIR opcode where inner_proof_contains_recursive_proof = true, + * or we need non-witness data to be provided as metadata in the ACIR opcode + */ +std::array create_honk_recursion_constraints( + Builder& builder, + const HonkRecursionConstraint& input, + std::array input_aggregation_object, + std::array nested_aggregation_object, + bool has_valid_witness_assignments) +{ + const auto& nested_aggregation_indices = nested_aggregation_object; + const bool inner_proof_contains_recursive_proof = true; + + // If we do not have a witness, we must ensure that our dummy witness will not trigger + // on-curve errors and inverting-zero errors + { + // get a fake key/proof that satisfies on-curve + inversion-zero checks + const std::vector dummy_key = export_dummy_honk_key_in_recursion_format( + PolynomialManifest(Builder::CIRCUIT_TYPE), inner_proof_contains_recursive_proof); + const auto manifest = Composer::create_manifest(input.public_inputs.size()); + std::vector dummy_proof = + export_dummy_honk_transcript_in_recursion_format(manifest, inner_proof_contains_recursive_proof); + + for (size_t i = 0; i < input.public_inputs.size(); ++i) { + const auto public_input_idx = input.public_inputs[i]; + // if we do NOT have a witness assignment (i.e. are just building the proving/verification keys), + // we add our dummy public input values as Builder variables. + // if we DO have a valid witness assignment, we use the real witness assignment + bb::fr dummy_field = + has_valid_witness_assignments ? builder.get_variable(public_input_idx) : dummy_proof[i]; + // Create a copy constraint between our dummy field and the witness index provided by + // HonkRecursionConstraint. This will make the HonkRecursionConstraint idx equal to `dummy_field`. In the + // case of a valid witness assignment, this does nothing (as dummy_field = real value) In the case of no + // valid witness assignment, this makes sure that the HonkRecursionConstraint witness indices will not + // trigger basic errors (check inputs are on-curve, check we are not inverting 0) + // + // Failing to do these copy constraints on public inputs will trigger these basic errors + // in the case of a nested proof, as an aggregation object is expected to be two G1 points even + // in the case of no valid witness assignments. + builder.assert_equal(builder.add_variable(dummy_field), public_input_idx); + } + // Remove the public inputs from the dummy proof + // The proof supplied to the recursion constraint will already be stripped of public inputs + // while the barretenberg API works with public inputs prepended to the proof. + dummy_proof.erase(dummy_proof.begin(), + dummy_proof.begin() + static_cast(input.public_inputs.size())); + for (size_t i = 0; i < input.proof.size(); ++i) { + const auto proof_field_idx = input.proof[i]; + bb::fr dummy_field = has_valid_witness_assignments ? builder.get_variable(proof_field_idx) : dummy_proof[i]; + builder.assert_equal(builder.add_variable(dummy_field), proof_field_idx); + } + for (size_t i = 0; i < input.key.size(); ++i) { + const auto key_field_idx = input.key[i]; + bb::fr dummy_field = has_valid_witness_assignments ? builder.get_variable(key_field_idx) : dummy_key[i]; + builder.assert_equal(builder.add_variable(dummy_field), key_field_idx); + } + } + + // Construct an in-circuit representation of the verification key. + // For now, the v-key is a circuit constant and is fixed for the circuit. + // (We may need a separate recursion opcode for this to vary, or add more config witnesses to this opcode) + const auto& aggregation_input = input_aggregation_object; + aggregation_state_ct previous_aggregation; + + // If we have previously recursively verified proofs, `inner_aggregation_object_nonzero = true` + // For now this is a complile-time constant i.e. whether this is true/false is fixed for the circuit! + bool inner_aggregation_indices_all_zero = true; + for (const auto& idx : aggregation_input) { + inner_aggregation_indices_all_zero &= (idx == 0); + } + + if (!inner_aggregation_indices_all_zero) { + std::array aggregation_elements; + for (size_t i = 0; i < 4; ++i) { + aggregation_elements[i] = + bn254::BaseField(field_ct::from_witness_index(&builder, aggregation_input[4 * i]), + field_ct::from_witness_index(&builder, aggregation_input[4 * i + 1]), + field_ct::from_witness_index(&builder, aggregation_input[4 * i + 2]), + field_ct::from_witness_index(&builder, aggregation_input[4 * i + 3])); + aggregation_elements[i].assert_is_in_field(); + } + // If we have a previous aggregation object, assign it to `previous_aggregation` so that it is included + // in stdlib::recursion::verify_proof + previous_aggregation.P0 = bn254::Group(aggregation_elements[0], aggregation_elements[1]); + previous_aggregation.P1 = bn254::Group(aggregation_elements[2], aggregation_elements[3]); + previous_aggregation.has_data = true; + } else { + previous_aggregation.has_data = false; + } + + transcript::Manifest manifest = Composer::create_manifest(input.public_inputs.size()); + + std::vector key_fields; + key_fields.reserve(input.key.size()); + for (const auto& idx : input.key) { + auto field = field_ct::from_witness_index(&builder, idx); + key_fields.emplace_back(field); + } + + std::vector proof_fields; + // Prepend the public inputs to the proof fields because this is how the + // core barretenberg library processes proofs (with the public inputs first and not separated) + proof_fields.reserve(input.proof.size() + input.public_inputs.size()); + for (const auto& idx : input.public_inputs) { + auto field = field_ct::from_witness_index(&builder, idx); + proof_fields.emplace_back(field); + } + for (const auto& idx : input.proof) { + auto field = field_ct::from_witness_index(&builder, idx); + proof_fields.emplace_back(field); + } + + // recursively verify the proof + std::shared_ptr vkey = verification_key_ct::from_field_elements( + &builder, key_fields, inner_proof_contains_recursive_proof, nested_aggregation_indices); + vkey->program_width = noir_recursive_settings::program_width; + + Transcript_ct transcript(&builder, manifest, proof_fields, input.public_inputs.size()); + aggregation_state_ct result = bb::stdlib::recursion::verify_proof_( + &builder, vkey, transcript, previous_aggregation); + + // Assign correct witness value to the verification key hash + vkey->hash().assert_equal(field_ct::from_witness_index(&builder, input.key_hash)); + + ASSERT(result.public_inputs.size() == input.public_inputs.size()); + + // Assign the `public_input` field to the public input of the inner proof + for (size_t i = 0; i < input.public_inputs.size(); ++i) { + result.public_inputs[i].assert_equal(field_ct::from_witness_index(&builder, input.public_inputs[i])); + } + + // We want to return an array, so just copy the vector into the array + ASSERT(result.proof_witness_indices.size() == HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE); + std::array resulting_output_aggregation_object; + std::copy(result.proof_witness_indices.begin(), + result.proof_witness_indices.begin() + HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE, + resulting_output_aggregation_object.begin()); + + return resulting_output_aggregation_object; +} + +/** + * @brief When recursively verifying proofs, we represent the verification key using field elements. + * This method exports the key formatted in the manner our recursive verifier expects. + * NOTE: only used by the dsl at the moment. Might be cleaner to make this a dsl function? + * + * @return std::vector + */ +std::vector export_honk_key_in_recursion_format(std::shared_ptr const& vkey) +{ + std::vector output; + output.emplace_back(vkey->domain.root); + output.emplace_back(vkey->domain.domain); + output.emplace_back(vkey->domain.generator); + output.emplace_back(vkey->circuit_size); + output.emplace_back(vkey->num_public_inputs); + output.emplace_back(vkey->contains_recursive_proof); + for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + if (vkey->recursive_proof_public_input_indices.size() > i) { + output.emplace_back(vkey->recursive_proof_public_input_indices[i]); + } else { + output.emplace_back(0); + ASSERT(vkey->contains_recursive_proof == false); + } + } + for (const auto& descriptor : vkey->polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + const auto element = vkey->commitments.at(std::string(descriptor.commitment_label)); + auto g1_as_fields = export_g1_affine_element_as_fields(element); + output.emplace_back(g1_as_fields.x_lo); + output.emplace_back(g1_as_fields.x_hi); + output.emplace_back(g1_as_fields.y_lo); + output.emplace_back(g1_as_fields.y_hi); + } + } + + verification_key_data vkey_data{ + .circuit_type = static_cast(vkey->circuit_type), + .circuit_size = static_cast(vkey->circuit_size), + .num_public_inputs = static_cast(vkey->num_public_inputs), + .commitments = vkey->commitments, + .contains_recursive_proof = vkey->contains_recursive_proof, + .recursive_proof_public_input_indices = vkey->recursive_proof_public_input_indices, + }; + output.emplace_back(vkey_data.hash_native(0)); // key_hash + return output; +} + +/** + * @brief When recursively verifying proofs, we represent the verification key using field elements. + * This method exports the key formatted in the manner our recursive verifier expects. + * A dummy key is used when building a circuit without a valid witness assignment. + * We want the transcript to contain valid G1 points to prevent on-curve errors being thrown. + * We want a non-zero circuit size as this element will be inverted by the circuit + * and we do not want an "inverting 0" error thrown + * + * @return std::vector + */ +std::vector export_dummy_honk_key_in_recursion_format(const PolynomialManifest& polynomial_manifest, + const bool contains_recursive_proof) +{ + std::vector output; + output.emplace_back(1); // domain.domain (will be inverted) + output.emplace_back(1); // domain.root (will be inverted) + output.emplace_back(1); // domain.generator (will be inverted) + + output.emplace_back(1); // circuit size + output.emplace_back(1); // num public inputs + + output.emplace_back(contains_recursive_proof); // contains_recursive_proof + for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + output.emplace_back(0); // recursive_proof_public_input_indices + } + + for (const auto& descriptor : polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + // the std::biggroup class creates unsatisfiable constraints when identical points are added/subtracted. + // (when verifying zk proofs this is acceptable as we make sure verification key points are not identical. + // And prover points should contain randomness for an honest Prover). + // This check can also trigger a runtime error due to causing 0 to be inverted. + // When creating dummy verification key points we must be mindful of the above and make sure that each + // transcript point is unique. + auto scalar = bb::fr::random_element(); + const auto element = bb::g1::affine_element(bb::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(element); + output.emplace_back(g1_as_fields.x_lo); + output.emplace_back(g1_as_fields.x_hi); + output.emplace_back(g1_as_fields.y_lo); + output.emplace_back(g1_as_fields.y_hi); + } + } + + output.emplace_back(0); // key_hash + + return output; +} + +/** + * @brief Returns transcript represented as a vector of bb::fr. + * Used to represent recursive proofs (i.e. proof represented as circuit-native field elements) + * + * @return std::vector + */ +std::vector export_honk_transcript_in_recursion_format(const transcript::StandardTranscript& transcript) +{ + std::vector fields; + const auto num_rounds = transcript.get_manifest().get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (const auto& manifest_element : transcript.get_manifest().get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + fields.emplace_back(transcript.get_field_element(manifest_element.name)); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + const auto group_element = transcript.get_group_element(manifest_element.name); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } else { + ASSERT(manifest_element.name == "public_inputs"); + const auto public_inputs_vector = transcript.get_field_element_vector(manifest_element.name); + for (const auto& ele : public_inputs_vector) { + fields.emplace_back(ele); + } + } + } + } + } + return fields; +} + +/** + * @brief Get a dummy fake proof for recursion. All elliptic curve group elements are still valid points to prevent + * errors being thrown. + * + * @param manifest + * @return std::vector + */ +std::vector export_dummy_honk_transcript_in_recursion_format(const transcript::Manifest& manifest, + const bool contains_recursive_proof) +{ + std::vector fields; + const auto num_rounds = manifest.get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (const auto& manifest_element : manifest.get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + // auto scalar = bb::fr::random_element(); + fields.emplace_back(0); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + // the std::biggroup class creates unsatisfiable constraints when identical points are + // added/subtracted. + // (when verifying zk proofs this is acceptable as we make sure verification key points are not + // identical. And prover points should contain randomness for an honest Prover). This check can + // also trigger a runtime error due to causing 0 to be inverted. When creating dummy proof + // points we must be mindful of the above and make sure that each point is unique. + auto scalar = bb::fr::random_element(); + const auto group_element = bb::g1::affine_element(bb::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } else { + ASSERT(manifest_element.name == "public_inputs"); + const size_t num_public_inputs = manifest_element.num_bytes / 32; + // If we have a recursive proofs the public inputs must describe an aggregation object that + // is composed of two valid G1 points on the curve. Without this conditional we will get a + // runtime error that we are attempting to invert 0. + if (contains_recursive_proof) { + // When setting up the ACIR we emplace back the nested aggregation object + // fetched from the proof onto the public inputs. Thus, we can expect the + // nested aggregation object to always be at the end of the public inputs. + for (size_t k = 0; k < num_public_inputs - HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; + ++k) { + fields.emplace_back(0); + } + for (size_t k = 0; k < HonkRecursionConstraint::NUM_AGGREGATION_ELEMENTS; ++k) { + auto scalar = bb::fr::random_element(); + const auto group_element = bb::g1::affine_element(bb::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } + } else { + for (size_t j = 0; j < num_public_inputs; ++j) { + // auto scalar = bb::fr::random_element(); + fields.emplace_back(0); + } + } + } + } + } + } + return fields; +} + +size_t recursion_honk_proof_size_without_public_inputs() +{ + const auto manifest = Composer::create_manifest(0); + auto dummy_transcript = export_dummy_honk_transcript_in_recursion_format(manifest, false); + return dummy_transcript.size(); +} + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp new file mode 100644 index 00000000000..8696e9ef073 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp @@ -0,0 +1,76 @@ +#pragma once +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include + +namespace acir_format { + +using namespace bb::plonk; + +/** + * @brief HonkRecursionConstraint struct contains information required to recursively verify a proof! + * + * @details The recursive verifier algorithm produces an 'aggregation object' representing 2 G1 points, expressed as 16 + * witness values. The smart contract Verifier must be aware of this aggregation object in order to complete the full + * recursive verification. If the circuit verifies more than 1 proof, the recursion algorithm will update a pre-existing + * aggregation object (`input_aggregation_object`). + * + * @details We currently require that the inner circuit being verified only has a single public input. If more are + * required, the outer circuit can hash them down to 1 input. + * + * @param verification_key_data The inner circuit vkey. Is converted into circuit witness values (internal to the + * backend) + * @param proof The plonk proof. Is converted into circuit witness values (internal to the backend) + * @param is_aggregation_object_nonzero A flag to tell us whether the circuit has already recursively verified proofs + * (and therefore an aggregation object is present) + * @param public_input The index of the single public input + * @param input_aggregation_object Witness indices of pre-existing aggregation object (if it exists) + * @param output_aggregation_object Witness indices of the aggregation object produced by recursive verification + * @param nested_aggregation_object Public input indices of an aggregation object inside the proof. + * + * @note If input_aggregation_object witness indices are all zero, we interpret this to mean that the inner proof does + * NOT contain a previously recursively verified proof + * @note nested_aggregation_object is used for cases where the proof being verified contains an aggregation object in + * its public inputs! If this is the case, we record the public input locations in `nested_aggregation_object`. If the + * inner proof is of a circuit that does not have a nested aggregation object, these values are all zero. + * + * To outline the interaction between the input_aggergation_object and the nested_aggregation_object take the following + * example: If we have a circuit that verifies 2 proofs A and B, the recursion constraint for B will have an + * input_aggregation_object that points to the aggregation output produced by verifying A. If circuit B also verifies a + * proof, in the above example the recursion constraint for verifying B will have a nested object that describes the + * aggregation object in B’s public inputs as well as an input aggregation object that points to the object produced by + * the previous recursion constraint in the circuit (the one that verifies A) + * + */ +struct HonkRecursionConstraint { + // An aggregation state is represented by two G1 affine elements. Each G1 point has + // two field element coordinates (x, y). Thus, four field elements + static constexpr size_t NUM_AGGREGATION_ELEMENTS = 4; + // Four limbs are used when simulating a non-native field using the bigfield class + static constexpr size_t AGGREGATION_OBJECT_SIZE = + NUM_AGGREGATION_ELEMENTS * NUM_QUOTIENT_PARTS; // 16 field elements + std::vector key; + std::vector proof; + std::vector public_inputs; + uint32_t key_hash; + + friend bool operator==(HonkRecursionConstraint const& lhs, HonkRecursionConstraint const& rhs) = default; +}; + +std::array create_honk_recursion_constraints( + Builder& builder, + const HonkRecursionConstraint& input, + std::array input_aggregation_object, + std::array nested_aggregation_object, + bool has_valid_witness_assignments = false); + +std::vector export_honk_key_in_recursion_format(std::shared_ptr const& vkey); +std::vector export_dummy_honk_key_in_recursion_format(const PolynomialManifest& polynomial_manifest, + bool contains_recursive_proof = 0); + +std::vector export_honk_transcript_in_recursion_format(const transcript::StandardTranscript& transcript); +std::vector export_dummy_honk_transcript_in_recursion_format(const transcript::Manifest& manifest, + const bool contains_recursive_proof); +size_t recursion_honk_proof_size_without_public_inputs(); + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp new file mode 100644 index 00000000000..7ac1fc58eb0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp @@ -0,0 +1,365 @@ +#include "honk_recursion_constraint.hpp" +#include "acir_format.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" + +#include +#include + +using namespace acir_format; +using namespace bb::plonk; + +class AcirHonkRecursionConstraint : public ::testing::Test { + public: + Builder create_inner_circuit() + { + /** + * constraints produced by Noir program: + * fn main(x : u32, y : pub u32) { + * let z = x ^ y; + * + * constrain z != 10; + * } + **/ + RangeConstraint range_a{ + .witness = 0, + .num_bits = 32, + }; + RangeConstraint range_b{ + .witness = 1, + .num_bits = 32, + }; + + LogicConstraint logic_constraint{ + .a = 0, + .b = 1, + .result = 2, + .num_bits = 32, + .is_xor_gate = 1, + }; + poly_triple expr_a{ + .a = 2, + .b = 3, + .c = 0, + .q_m = 0, + .q_l = 1, + .q_r = -1, + .q_o = 0, + .q_c = -10, + }; + poly_triple expr_b{ + .a = 3, + .b = 4, + .c = 5, + .q_m = 1, + .q_l = 0, + .q_r = 0, + .q_o = -1, + .q_c = 0, + }; + poly_triple expr_c{ + .a = 3, + .b = 5, + .c = 3, + .q_m = 1, + .q_l = 0, + .q_r = 0, + .q_o = -1, + .q_c = 0, + + }; + poly_triple expr_d{ + .a = 5, + .b = 0, + .c = 0, + .q_m = 0, + .q_l = -1, + .q_r = 0, + .q_o = 0, + .q_c = 1, + }; + + AcirFormat constraint_system{ .varnum = 6, + .recursive = true, + .num_acir_opcodes = 7, + .public_inputs = { 1, 2 }, + .logic_constraints = { logic_constraint }, + .range_constraints = { range_a, range_b }, + .aes128_constraints = {}, + .sha256_constraints = {}, + .sha256_compression = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .poseidon2_constraints = {}, + .multi_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .honk_recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .poly_triple_constraints = { expr_a, expr_b, expr_c, expr_d }, + .quad_constraints = {}, + .block_constraints = {} }; + + uint256_t inverse_of_five = fr(5).invert(); + WitnessVector witness{ + 5, 10, 15, 5, inverse_of_five, 1, + }; + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk recursion*/ true); + + return builder; + } + + /** + * @brief Create a circuit that recursively verifies one or more inner circuits + * + * @param inner_circuits + * @return Composer + */ + Builder create_outer_circuit(std::vector& inner_circuits) + { + std::vector honk_recursion_constraints; + + size_t witness_offset = 0; + std::vector> witness; + + for (auto& inner_circuit : inner_circuits) { + + auto inner_composer = Composer(); + auto inner_prover = inner_composer.create_prover(inner_circuit); + auto inner_proof = inner_prover.construct_proof(); + auto inner_verifier = inner_composer.create_verifier(inner_circuit); + + const size_t num_inner_public_inputs = inner_circuit.get_public_inputs().size(); + transcript::StandardTranscript transcript(inner_proof.proof_data, + Composer::create_manifest(num_inner_public_inputs), + transcript::HashType::PedersenBlake3s, + 16); + + std::vector proof_witnesses = export_honk_transcript_in_recursion_format(transcript); + // - Save the public inputs so that we can set their values. + // - Then truncate them from the proof because the ACIR API expects proofs without public inputs + std::vector inner_public_input_values( + proof_witnesses.begin(), + proof_witnesses.begin() + static_cast(num_inner_public_inputs - + RecursionConstraint::AGGREGATION_OBJECT_SIZE)); + + // We want to make sure that we do not remove the nested aggregation object. + proof_witnesses.erase(proof_witnesses.begin(), + proof_witnesses.begin() + + static_cast(num_inner_public_inputs - + RecursionConstraint::AGGREGATION_OBJECT_SIZE)); + + std::vector key_witnesses = export_honk_key_in_recursion_format(inner_verifier.key); + bb::fr key_hash = key_witnesses.back(); + key_witnesses.pop_back(); + + const uint32_t key_hash_start_idx = static_cast(witness_offset); + const uint32_t public_input_start_idx = key_hash_start_idx + 1; + const uint32_t proof_indices_start_idx = static_cast( + public_input_start_idx + num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE); + const uint32_t key_indices_start_idx = + static_cast(proof_indices_start_idx + proof_witnesses.size()); + + std::vector proof_indices; + std::vector key_indices; + std::vector inner_public_inputs; + for (size_t i = 0; i < proof_witnesses.size(); ++i) { + proof_indices.emplace_back(static_cast(i + proof_indices_start_idx)); + } + const size_t key_size = key_witnesses.size(); + for (size_t i = 0; i < key_size; ++i) { + key_indices.emplace_back(static_cast(i + key_indices_start_idx)); + } + // We keep the nested aggregation object attached to the proof, + // thus we do not explicitly have to keep the public inputs while setting up the initial recursion + // constraint. They will later be attached as public inputs when creating the circuit. + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); + } + + HonkRecursionConstraint honk_recursion_constraint{ + .key = key_indices, + .proof = proof_indices, + .public_inputs = inner_public_inputs, + .key_hash = key_hash_start_idx, + }; + honk_recursion_constraints.push_back(honk_recursion_constraint); + + witness.emplace_back(key_hash); + for (size_t i = 0; i < proof_indices_start_idx - public_input_start_idx; ++i) { + witness.emplace_back(0); + } + for (const auto& wit : proof_witnesses) { + witness.emplace_back(wit); + } + + for (const auto& wit : key_witnesses) { + witness.emplace_back(wit); + } + + // Set the values for the inner public inputs + // TODO(maxim): check this is wrong I think + // Note: this is confusing, but we minus one here due to the fact that the + // witness values have not taken into account that zero is taken up by the zero_idx + // + // We once again have to check whether we have a nested proof, because if we do have one + // then we could get a segmentation fault as `inner_public_inputs` was never filled with values. + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + witness[inner_public_inputs[i]] = inner_public_input_values[i]; + } + + witness_offset = key_indices_start_idx + key_witnesses.size(); + } + + AcirFormat constraint_system{ .varnum = static_cast(witness.size()), + .recursive = false, + .num_acir_opcodes = static_cast(honk_recursion_constraints.size()), + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .aes128_constraints = {}, + .sha256_constraints = {}, + .sha256_compression = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .poseidon2_constraints = {}, + .multi_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .honk_recursion_constraints = honk_recursion_constraints, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .poly_triple_constraints = {}, + .quad_constraints = {}, + .block_constraints = {} }; + + auto outer_circuit = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk recursion*/ true); + + return outer_circuit; + } + + protected: + static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } +}; + +TEST_F(AcirHonkRecursionConstraint, TestBasicDoubleHonkRecursionConstraints) +{ + std::vector layer_1_circuits; + layer_1_circuits.push_back(create_inner_circuit()); + + layer_1_circuits.push_back(create_inner_circuit()); + + auto layer_2_circuit = create_outer_circuit(layer_1_circuits); + + info("circuit gates = ", layer_2_circuit.get_num_gates()); + + auto layer_2_composer = Composer(); + auto prover = layer_2_composer.create_ultra_with_keccak_prover(layer_2_circuit); + info("prover gates = ", prover.circuit_size); + auto proof = prover.construct_proof(); + auto verifier = layer_2_composer.create_ultra_with_keccak_verifier(layer_2_circuit); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST_F(AcirHonkRecursionConstraint, TestOneOuterRecursiveCircuit) +{ + /** + * We want to test the following: + * 1. circuit that verifies a proof of another circuit + * 2. the above, but the inner circuit contains a recursive proof output that we have to aggregate + * 3. the above, but the outer circuit verifies 2 proofs, the aggregation outputs from the 2 proofs (+ the recursive + * proof output from 2) are aggregated together + * + * A = basic circuit + * B = circuit that verifies proof of A + * C = circuit that verifies proof of B and a proof of A + * + * Layer 1 = proof of A + * Layer 2 = verifies proof of A and proof of B + * Layer 3 = verifies proof of C + * + * Attempt at a visual graphic + * =========================== + * + * C + * ^ + * | + * | - B + * ^ ^ + * | | + * | -A + * | + * - A + * + * =========================== + * + * Final aggregation object contains aggregated proofs for 2 instances of A and 1 instance of B + */ + std::vector layer_1_circuits; + layer_1_circuits.push_back(create_inner_circuit()); + info("created first inner circuit"); + + std::vector layer_2_circuits; + layer_2_circuits.push_back(create_inner_circuit()); + info("created second inner circuit"); + + layer_2_circuits.push_back(create_outer_circuit(layer_1_circuits)); + info("created first outer circuit"); + + auto layer_3_circuit = create_outer_circuit(layer_2_circuits); + info("created second outer circuit"); + info("number of gates in layer 3 = ", layer_3_circuit.get_num_gates()); + + auto layer_3_composer = Composer(); + auto prover = layer_3_composer.create_ultra_with_keccak_prover(layer_3_circuit); + info("prover gates = ", prover.circuit_size); + auto proof = prover.construct_proof(); + auto verifier = layer_3_composer.create_ultra_with_keccak_verifier(layer_3_circuit); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST_F(AcirHonkRecursionConstraint, TestFullRecursiveComposition) +{ + std::vector layer_b_1_circuits; + layer_b_1_circuits.push_back(create_inner_circuit()); + info("created first inner circuit"); + + std::vector layer_b_2_circuits; + layer_b_2_circuits.push_back(create_inner_circuit()); + info("created second inner circuit"); + + std::vector layer_2_circuits; + layer_2_circuits.push_back(create_outer_circuit(layer_b_1_circuits)); + info("created first outer circuit"); + + layer_2_circuits.push_back(create_outer_circuit(layer_b_2_circuits)); + info("created second outer circuit"); + + auto layer_3_circuit = create_outer_circuit(layer_2_circuits); + info("created third outer circuit"); + info("number of gates in layer 3 circuit = ", layer_3_circuit.get_num_gates()); + + auto layer_3_composer = Composer(); + auto prover = layer_3_composer.create_ultra_with_keccak_prover(layer_3_circuit); + info("prover gates = ", prover.circuit_size); + auto proof = prover.construct_proof(); + auto verifier = layer_3_composer.create_ultra_with_keccak_verifier(layer_3_circuit); + EXPECT_EQ(verifier.verify_proof(proof), true); +} diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp index 4922c63cd69..71e2cc2160f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp @@ -51,6 +51,7 @@ TEST_F(Poseidon2Tests, TestPoseidon2Permutation) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index b837f94ba2a..65e049fe0ca 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -103,6 +103,7 @@ Builder create_inner_circuit() .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -130,13 +131,9 @@ Builder create_outer_circuit(std::vector& inner_circuits) std::vector recursion_constraints; size_t witness_offset = 0; - std::array output_aggregation_object; std::vector> witness; - size_t circuit_idx = 0; for (auto& inner_circuit : inner_circuits) { - const bool has_input_aggregation_object = circuit_idx > 0; - auto inner_composer = Composer(); auto inner_prover = inner_composer.create_prover(inner_circuit); auto inner_proof = inner_prover.construct_proof(); @@ -162,33 +159,25 @@ Builder create_outer_circuit(std::vector& inner_circuits) if (!has_nested_proof) { proof_witnesses.erase(proof_witnesses.begin(), proof_witnesses.begin() + static_cast(num_inner_public_inputs)); + } else { + proof_witnesses.erase(proof_witnesses.begin(), + proof_witnesses.begin() + + static_cast(num_inner_public_inputs - + RecursionConstraint::AGGREGATION_OBJECT_SIZE)); } const std::vector key_witnesses = export_key_in_recursion_format(inner_verifier.key); const uint32_t key_hash_start_idx = static_cast(witness_offset); const uint32_t public_input_start_idx = key_hash_start_idx + 1; - const uint32_t output_aggregation_object_start_idx = - static_cast(public_input_start_idx + num_inner_public_inputs + (has_nested_proof ? 16 : 0)); - const uint32_t proof_indices_start_idx = output_aggregation_object_start_idx + 16; + const uint32_t proof_indices_start_idx = + static_cast(public_input_start_idx + num_inner_public_inputs - + (has_nested_proof ? RecursionConstraint::AGGREGATION_OBJECT_SIZE : 0)); const uint32_t key_indices_start_idx = static_cast(proof_indices_start_idx + proof_witnesses.size()); std::vector proof_indices; std::vector key_indices; std::vector inner_public_inputs; - std::array input_aggregation_object = {}; - std::array nested_aggregation_object = {}; - if (has_input_aggregation_object) { - input_aggregation_object = output_aggregation_object; - } - for (size_t i = 0; i < 16; ++i) { - output_aggregation_object[i] = (static_cast(i + output_aggregation_object_start_idx)); - } - if (has_nested_proof) { - for (size_t i = 0; i < 16; ++i) { - nested_aggregation_object[i] = inner_circuit.recursive_proof_public_input_indices[i]; - } - } for (size_t i = 0; i < proof_witnesses.size(); ++i) { proof_indices.emplace_back(static_cast(i + proof_indices_start_idx)); } @@ -203,6 +192,10 @@ Builder create_outer_circuit(std::vector& inner_circuits) for (size_t i = 0; i < num_inner_public_inputs; ++i) { inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); } + } else { + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); + } } RecursionConstraint recursion_constraint{ @@ -234,10 +227,13 @@ Builder create_outer_circuit(std::vector& inner_circuits) for (size_t i = 0; i < num_inner_public_inputs; ++i) { witness[inner_public_inputs[i]] = inner_public_input_values[i]; } + } else { + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + witness[inner_public_inputs[i]] = inner_public_input_values[i]; + } } witness_offset = key_indices_start_idx + key_witnesses.size(); - circuit_idx++; } AcirFormat constraint_system{ .varnum = static_cast(witness.size()), @@ -262,6 +258,7 @@ Builder create_outer_circuit(std::vector& inner_circuits) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = recursion_constraints, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp index 5af032bedd1..82fda6f8d81 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp @@ -53,6 +53,7 @@ TEST_F(Sha256Tests, TestSha256Compression) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp index 2fc3572cec3..e015988c5c3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp @@ -48,6 +48,11 @@ template class bigfield { field_t element; uint256_t maximum_value; }; + static constexpr size_t NUM_LIMBS = 4; + + Builder* context; + mutable Limb binary_basis_limbs[NUM_LIMBS]; + mutable field_t prime_basis_limb; bigfield(const field_t& low_bits, const field_t& high_bits, @@ -121,11 +126,11 @@ template class bigfield { static constexpr uint256_t DEFAULT_MAXIMUM_LIMB = (uint256_t(1) << NUM_LIMB_BITS) - uint256_t(1); static constexpr uint256_t DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB = (uint256_t(1) << NUM_LAST_LIMB_BITS) - uint256_t(1); - static constexpr uint64_t LOG2_BINARY_MODULUS = NUM_LIMB_BITS * 4; + static constexpr uint64_t LOG2_BINARY_MODULUS = NUM_LIMB_BITS * NUM_LIMBS; static constexpr bool is_composite = true; // false only when fr is native static constexpr uint256_t prime_basis_maximum_limb = - uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); + uint256_t(modulus_u512.slice(NUM_LIMB_BITS * (NUM_LIMBS - 1), NUM_LIMB_BITS* NUM_LIMBS)); static constexpr Basis prime_basis{ uint512_t(bb::fr::modulus), bb::fr::modulus.get_msb() + 1 }; static constexpr Basis binary_basis{ uint512_t(1) << LOG2_BINARY_MODULUS, LOG2_BINARY_MODULUS }; static constexpr Basis target_basis{ modulus_u512, modulus_u512.get_msb() + 1 }; @@ -136,13 +141,13 @@ template class bigfield { static constexpr bb::fr shift_right_2 = bb::fr(1) / shift_2; static constexpr bb::fr negative_prime_modulus_mod_binary_basis = -bb::fr(uint256_t(modulus_u512)); static constexpr uint512_t negative_prime_modulus = binary_basis.modulus - target_basis.modulus; - static constexpr uint256_t neg_modulus_limbs_u256[4]{ + static constexpr uint256_t neg_modulus_limbs_u256[NUM_LIMBS]{ uint256_t(negative_prime_modulus.slice(0, NUM_LIMB_BITS).lo), uint256_t(negative_prime_modulus.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo), uint256_t(negative_prime_modulus.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo), uint256_t(negative_prime_modulus.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo), }; - static constexpr bb::fr neg_modulus_limbs[4]{ + static constexpr bb::fr neg_modulus_limbs[NUM_LIMBS]{ bb::fr(negative_prime_modulus.slice(0, NUM_LIMB_BITS).lo), bb::fr(negative_prime_modulus.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo), bb::fr(negative_prime_modulus.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo), @@ -428,9 +433,6 @@ template class bigfield { static constexpr uint256_t get_maximum_unreduced_limb_value() { return uint256_t(1) << MAX_UNREDUCED_LIMB_SIZE; } static_assert(MAX_UNREDUCED_LIMB_SIZE < (NUM_LIMB_BITS * 2)); - Builder* context; - mutable Limb binary_basis_limbs[4]; - mutable field_t prime_basis_limb; private: static std::pair compute_quotient_remainder_values(const bigfield& a, From d1095f60bbd05d35748dc9b0188ad0c5f87390f5 Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 17 May 2024 22:06:16 -0400 Subject: [PATCH 13/37] fix(ci): ARM (#6521) Accidentally had it still targeting personal x86 --- .github/workflows/ci-arm.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index 2828c3d3289..6ddc01acf9a 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -1,7 +1,9 @@ name: CI (ARM) on: push: - branches: [disabled] + branches: + - master + - '*/*arm-build' workflow_dispatch: inputs: {} concurrency: @@ -12,7 +14,7 @@ env: DOCKERHUB_PASSWORD: "${{ secrets.DOCKERHUB_PASSWORD }}" RUN_ID: ${{ github.run_id }} RUN_ATTEMPT: ${{ github.run_attempt }} - USERNAME: ${{ github.event.pull_request.user.login || github.actor }} + USERNAME: master GITHUB_TOKEN: ${{ github.token }} GH_SELF_HOSTED_RUNNER_TOKEN: ${{ secrets.GH_SELF_HOSTED_RUNNER_TOKEN }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -31,7 +33,7 @@ jobs: timeout-minutes: 40 uses: ./.github/ensure-builder with: - runner_type: builder-x86 + runner_type: builder-arm run: | set -eux git submodule update --init --recursive --recommend-shallow @@ -46,11 +48,12 @@ jobs: - uses: actions/checkout@v4 with: { ref: "${{ github.event.pull_request.head.sha }}" } - name: "Test" - timeout-minutes: 15 + timeout-minutes: 25 uses: ./.github/ensure-builder with: - runner_type: builder-x86 + runner_type: builder-arm run: | + sudo shutdown -P 25 # hack until core part of the scripts set -eux echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u aztecprotocolci --password-stdin scripts/earthly-ci -P --no-output ./yarn-project/end-to-end/+uniswap-trade-on-l1-from-l2 From 90ad7b21736dde8428de19612e1a075ce233ea18 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 18 May 2024 02:12:33 +0000 Subject: [PATCH 14/37] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "89a3cfe088" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "89a3cfe088" git-subrepo: version: "0.4.6" origin: "???" commit: "???" [skip ci] --- barretenberg/.gitrepo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 99d7eb63fb1..19b56482828 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = af5ae45393b9dba4c77626c5f9591d53897ae6f2 - parent = 1fa59637a0829208d382d1dded36df33f4d61582 + commit = 89a3cfe088ed6be4e6dbe66870000d3ddc369daf + parent = d1095f60bbd05d35748dc9b0188ad0c5f87390f5 method = merge cmdver = 0.4.6 From 9f04bfea51a0c4fe980bbbcde5867089e8f5d8a5 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 18 May 2024 02:13:01 +0000 Subject: [PATCH 15/37] chore: replace relative paths to noir-protocol-circuits --- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- noir-projects/aztec-nr/tests/Nargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 7a1f1af5863..834682e92cf 100644 --- a/noir-projects/aztec-nr/aztec/Nargo.toml +++ b/noir-projects/aztec-nr/aztec/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.18.0" type = "lib" [dependencies] -protocol_types = { path = "../../noir-protocol-circuits/crates/types" } +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } diff --git a/noir-projects/aztec-nr/tests/Nargo.toml b/noir-projects/aztec-nr/tests/Nargo.toml index 13404b37324..312114ad930 100644 --- a/noir-projects/aztec-nr/tests/Nargo.toml +++ b/noir-projects/aztec-nr/tests/Nargo.toml @@ -6,4 +6,4 @@ type = "lib" [dependencies] aztec = { path = "../aztec" } -protocol_types = { path = "../../noir-protocol-circuits/crates/types" } +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } From 79afaa4b3cc2e35cb8b0c49d3ca85f34434d766e Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 18 May 2024 02:13:01 +0000 Subject: [PATCH 16/37] git_subrepo.sh: Fix parent in .gitrepo file. [skip ci] --- noir-projects/aztec-nr/.gitrepo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 543deac1913..3d3a19ef2f1 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = 5a57900bc92e9fa056db8a689d5622e86a15211b method = merge cmdver = 0.4.6 - parent = 3809e3d58a55d189de14f2c002bb1e0c985cb111 + parent = 8f75b8460048dfadf0097aaf323c047be9e88966 From 2202e8d170b26950c83be6e3952f44cb4eb58533 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 18 May 2024 02:13:04 +0000 Subject: [PATCH 17/37] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "440a187b5" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "440a187b5" git-subrepo: version: "0.4.6" origin: "???" commit: "???" [skip ci] --- noir-projects/aztec-nr/.gitrepo | 4 ++-- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- noir-projects/aztec-nr/tests/Nargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 3d3a19ef2f1..7ab6c0eb1c9 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = 5a57900bc92e9fa056db8a689d5622e86a15211b + commit = 440a187b5bb985f3da4ff563d6c4943c88556fa7 method = merge cmdver = 0.4.6 - parent = 8f75b8460048dfadf0097aaf323c047be9e88966 + parent = 18bb55229dd973f6a93a4314f7519d45d3b21b1b diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 834682e92cf..7a1f1af5863 100644 --- a/noir-projects/aztec-nr/aztec/Nargo.toml +++ b/noir-projects/aztec-nr/aztec/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.18.0" type = "lib" [dependencies] -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } diff --git a/noir-projects/aztec-nr/tests/Nargo.toml b/noir-projects/aztec-nr/tests/Nargo.toml index 312114ad930..13404b37324 100644 --- a/noir-projects/aztec-nr/tests/Nargo.toml +++ b/noir-projects/aztec-nr/tests/Nargo.toml @@ -6,4 +6,4 @@ type = "lib" [dependencies] aztec = { path = "../aztec" } -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } From e5cc9dccb6c36159ad90068d41786c8715af66da Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Sat, 18 May 2024 22:27:44 +0100 Subject: [PATCH 18/37] feat: Update the encrypted note log format (#6411) Fixes #5901. Uses the new format to match the keys and logs spec. The current implementation here is still using a typescript implementation to encrypt the data, mainly using the new flow. The intention is that #6408 and #1139 can be addresses separately and than we can just replace the import to use the constrained version instead of the oracle at that point. Note, that the outgoing logs are currently less than meaningful, as some of the infrastructure is not yet in place to handle those nicely, see #6410 for more on that. What was called the encrypted_log_payload in #6348 have been moved into the l1_payload, to better integrate with the rest of the setup. --- l1-contracts/test/fixtures/empty_block_0.json | 10 +- l1-contracts/test/fixtures/empty_block_1.json | 14 +- l1-contracts/test/fixtures/mixed_block_0.json | 10 +- l1-contracts/test/fixtures/mixed_block_1.json | 14 +- .../aztec-nr/address-note/src/address_note.nr | 2 +- .../aztec/src/context/private_context.nr | 69 +++--- noir-projects/aztec-nr/aztec/src/hash.nr | 56 ----- .../aztec-nr/aztec/src/oracle/logs.nr | 46 ++-- .../aztec-nr/aztec/src/oracle/logs_traits.nr | 52 ++--- .../aztec-nr/value-note/src/value_note.nr | 2 +- .../src/subscription_note.nr | 2 +- .../src/types/card_note.nr | 2 +- .../src/ecdsa_public_key_note.nr | 4 +- .../src/public_key_note.nr | 2 +- .../src/types/token_note.nr | 2 +- .../token_contract/src/types/token_note.nr | 2 +- .../src/logs/encrypted_log_payload.test.ts | 42 ---- .../src/logs/encrypted_log_payload.ts | 209 ------------------ yarn-project/circuit-types/src/logs/index.ts | 6 +- .../l1_note_payload/encrypt_buffer.test.ts | 3 +- .../logs/l1_note_payload/encrypt_buffer.ts | 24 +- .../encrypted_log_header.test.ts | 0 .../encrypted_log_header.ts | 2 +- .../encrypted_log_incoming_body.test.ts | 2 +- .../encrypted_log_incoming_body.ts | 3 +- .../encrypted_log_outgoing_body.test.ts | 0 .../encrypted_log_outgoing_body.ts | 0 .../logs/l1_note_payload/encryption_utils.ts | 24 ++ .../l1_note_payload/l1_note_payload.test.ts | 49 ++-- .../logs/l1_note_payload/l1_note_payload.ts | 167 ++++++++++++-- .../logs/l1_note_payload/tagged_note.test.ts | 54 +++-- .../src/logs/l1_note_payload/tagged_note.ts | 77 ++++--- .../src/benchmarks/bench_tx_size_fees.test.ts | 12 +- .../end-to-end/src/e2e_block_building.test.ts | 2 +- .../src/orchestrator/orchestrator.ts | 1 + .../src/note_processor/note_processor.test.ts | 12 +- .../pxe/src/note_processor/note_processor.ts | 3 +- .../simulator/src/acvm/oracle/oracle.ts | 36 +-- .../simulator/src/acvm/oracle/typed_oracle.ts | 15 +- .../src/client/client_execution_context.ts | 81 +++---- 40 files changed, 505 insertions(+), 608 deletions(-) delete mode 100644 yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts delete mode 100644 yarn-project/circuit-types/src/logs/encrypted_log_payload.ts rename yarn-project/circuit-types/src/logs/{ => l1_note_payload}/encrypted_log_header.test.ts (100%) rename yarn-project/circuit-types/src/logs/{ => l1_note_payload}/encrypted_log_header.ts (96%) rename yarn-project/circuit-types/src/logs/{ => l1_note_payload}/encrypted_log_incoming_body.test.ts (97%) rename yarn-project/circuit-types/src/logs/{ => l1_note_payload}/encrypted_log_incoming_body.ts (97%) rename yarn-project/circuit-types/src/logs/{ => l1_note_payload}/encrypted_log_outgoing_body.test.ts (100%) rename yarn-project/circuit-types/src/logs/{ => l1_note_payload}/encrypted_log_outgoing_body.ts (100%) create mode 100644 yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index aacfd5c955c..91216c12952 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x12a6236f076e51298ca7c5c4d0c9898239c5f829e1f2673a18a922d5ee50a4fd", + "archive": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3", "body": "0x00000000", "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { @@ -23,8 +23,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xf98794b6b717c6c7d6806a8ebb8cb1327144f0c7", - "feeRecipient": "0x1eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a4", + "coinbase": "0xbe70f89d75a00bd140342ebc63beb517cf9735bc", + "feeRecipient": "0x08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b172", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -55,8 +55,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000f98794b6b717c6c7d6806a8ebb8cb1327144f0c71eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x0081ff51b8e6caf79d8d0616b407a5cf7c3d939bf568a94100d6e7b5dbaf2cff", + "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000be70f89d75a00bd140342ebc63beb517cf9735bc08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b17200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00e9c95b88dbc49351e6a0a9b660918147d3c69410df4fba105c047a4f253a47", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index c2c09d34ff9..0596ade5a0a 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x19d445841fdaa62cfa9752aae068322e538729535b9fc4e195fd4e7b010f2e91", + "archive": "0x18c171439670152671eb523cdf11eb61a45c27b7685ad86a7229fbe635e9ea18", "body": "0x00000000", "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { @@ -21,10 +21,10 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1715940661, + "timestamp": 1716042415, "version": 1, - "coinbase": "0xf98794b6b717c6c7d6806a8ebb8cb1327144f0c7", - "feeRecipient": "0x1eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a4", + "coinbase": "0xbe70f89d75a00bd140342ebc63beb517cf9735bc", + "feeRecipient": "0x08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b172", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -32,7 +32,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x12a6236f076e51298ca7c5c4d0c9898239c5f829e1f2673a18a922d5ee50a4fd" + "root": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3" }, "stateReference": { "l1ToL2MessageTree": { @@ -55,8 +55,8 @@ } } }, - "header": "0x12a6236f076e51298ca7c5c4d0c9898239c5f829e1f2673a18a922d5ee50a4fd000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000066472d35f98794b6b717c6c7d6806a8ebb8cb1327144f0c71eece2f228c0b199fee7bb461e152e69a6ddd096573bd8ea45a7df0e105439a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x008568ca7fc6464f9cb6588e7215e14e0eb49c96dd210a849a0d3369d185c261", + "header": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006648baafbe70f89d75a00bd140342ebc63beb517cf9735bc08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b17200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x0033d4785f37dafeeb7e50eeef42002f0af7d1d62913119754b81cfe7ebc5217", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index b2d7765f5a4..48f9c97bf8f 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,7 +34,7 @@ ] }, "block": { - "archive": "0x1da7e3994972b8e4d8f2dffeb084976254aebcca1a429e576eea74eae6ae20c4", + "archive": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e0200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341200000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f000000000000000000000000000000000000000000000000000000000000056900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be0200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c12000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f000000000000000000000000000000000000000000000000000000000000062900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x0048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab", "decodedHeader": { @@ -49,8 +49,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x5e42ecbaebd6cd5f6dd356f51c0fa991be9d3084", - "feeRecipient": "0x1387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf269112", + "coinbase": "0xe19d288dac593449f143689ea3563e9d960e0ae6", + "feeRecipient": "0x20f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -81,8 +81,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf0000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000005e42ecbaebd6cd5f6dd356f51c0fa991be9d30841387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf26911200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00ef2466dabd158a72ec68683a56286b12b50ecf9aca3c0849414a7fa63f7a17", + "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf0000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000e19d288dac593449f143689ea3563e9d960e0ae620f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x004af29de40359d7c79637dce0ef57c561cb5ff283602607c6f644cb019fa526", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 5bc3fb47126..2fe88df3c70 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,7 +34,7 @@ ] }, "block": { - "archive": "0x250babc63de7989f6407cfa75b31762bbecdb77b1a2d6f3a8ad2ccfd348e60c6", + "archive": "0x1d882133187105c8d7ed6177b59d8c5462ce1a562537ccec510d9879caf10c7c", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e0200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f000000000000000000000000000000000000000000000000000000000000066900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be0200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481200000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c12000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501200000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f000000000000000000000000000000000000000000000000000000000000072900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x00f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b1", "decodedHeader": { @@ -47,10 +47,10 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1715940580, + "timestamp": 1716042373, "version": 1, - "coinbase": "0x5e42ecbaebd6cd5f6dd356f51c0fa991be9d3084", - "feeRecipient": "0x1387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf269112", + "coinbase": "0xe19d288dac593449f143689ea3563e9d960e0ae6", + "feeRecipient": "0x20f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -58,7 +58,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x1da7e3994972b8e4d8f2dffeb084976254aebcca1a429e576eea74eae6ae20c4" + "root": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e" }, "stateReference": { "l1ToL2MessageTree": { @@ -81,8 +81,8 @@ } } }, - "header": "0x1da7e3994972b8e4d8f2dffeb084976254aebcca1a429e576eea74eae6ae20c400000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000066472ce45e42ecbaebd6cd5f6dd356f51c0fa991be9d30841387d4ee7f411ec349f1a71cc34b181667b0fd77ced57b529a06f2ddbf26911200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00481dfc48bdb367e200298beada39daf0837e3d33e81257e92e65d48a5e0a81", + "header": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e00000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006648ba85e19d288dac593449f143689ea3563e9d960e0ae620f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x007402eac386598833154a72f24a89eb5152eec68dfd43c12dd847da5a99289b", "numTxs": 4 } } \ No newline at end of file diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index 3d33ecb4a52..df33796ed35 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -44,7 +44,7 @@ impl NoteInterface for AddressNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { // docs:start:encrypted - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 869000fac77..9722d8aecbf 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -1,12 +1,13 @@ use crate::{ context::{inputs::PrivateContextInputs, interface::ContextInterface}, messaging::process_l1_to_l2_message, - hash::{hash_args_array, ArgsHasher, compute_encrypted_log_hash, compute_unencrypted_log_hash}, + hash::{hash_args_array, ArgsHasher, compute_unencrypted_log_hash}, note::{note_interface::NoteInterface, utils::compute_note_hash_for_insertion}, oracle::{ nullifier_keys::get_nullifier_key_validation_request, arguments, returns, call_private_function::call_private_function_internal, header::get_header_at, - logs::emit_encrypted_log, logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog}, + logs::{emit_encrypted_log, emit_encrypted_note_log, compute_encrypted_log}, + logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog}, enqueue_public_function_call::{ enqueue_public_function_call_internal, set_public_teardown_function_call_internal, parse_public_call_stack_item_from_oracle @@ -14,6 +15,7 @@ use crate::{ } }; use dep::protocol_types::{ + hash::sha256_to_field, abis::{ function_selector::FunctionSelector, max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequest, @@ -281,42 +283,34 @@ impl PrivateContext { let side_effect = LogHash { value: log_hash, counter, length: len }; self.unencrypted_logs_hashes.push(side_effect); } - // TODO(1139): Convert to generic input once we encrypt inside the circuit - pub fn emit_encrypted_log( + + pub fn encrypt_and_emit_log( &mut self, contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, ivpk_m: GrumpkinPoint, preimage: [Field; N] - ) where [Field; N]: LensForEncryptedLog { - // TODO(1139): perform encryption in the circuit - // The oracle call should come last, but we require the encrypted value for now + ) where [Field; N]: LensForEncryptedLog { + // We are currently just encrypting it EXACTLY the same way as if it was a note. let counter = self.next_counter(); - let encrypted_log: [Field; M] = emit_encrypted_log( - contract_address, - storage_slot, - note_type_id, - ivpk_m, - preimage, - counter - ); - // = 32*all fields + bytes for encryption (112) + processed log len (4) - let len = 112 + 32 * (N + 3) + 4; - let log_hash = compute_encrypted_log_hash(encrypted_log); + let encrypted_log: [u8; M] = compute_encrypted_log(contract_address, storage_slot, note_type_id, ivpk_m, preimage); + emit_encrypted_log(encrypted_log, counter); + let len = 32 + 32 + 64 + 48 + 48 + 176 + 64 + (preimage.len() as Field * 32) + 16 + 4; + let log_hash = sha256_to_field(encrypted_log); let side_effect = LogHash { value: log_hash, counter, length: len }; self.encrypted_logs_hashes.push(side_effect); } - pub fn emit_note_encrypted_log( + pub fn encrypt_and_emit_note( &mut self, contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, - encryption_pub_key: GrumpkinPoint, + ivpk_m: GrumpkinPoint, note: Note - ) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { - let note_hash = compute_note_hash_for_insertion(note); + ) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { + let note_hash: Field = compute_note_hash_for_insertion(note); let note_exists_index = find_index( self.new_note_hashes.storage, |n: NoteHash| n.value == note_hash @@ -327,19 +321,24 @@ impl PrivateContext { let note_hash_counter = self.new_note_hashes.storage[note_exists_index].counter; let preimage = note.serialize_content(); let counter = self.next_counter(); - // TODO(1139): perform encryption in the circuit - // The oracle call should come last, but we require the encrypted value for now - let encrypted_log: [Field; M] = emit_encrypted_log( - contract_address, - storage_slot, - note_type_id, - encryption_pub_key, - preimage, - counter - ); - // = 32*all fields + bytes for encryption (112) + processed log len (4) - let len = 112 + 32 * (preimage.len() as Field + 3) + 4; - let log_hash = compute_encrypted_log_hash(encrypted_log); + + // TODO(#1139 | #6408): perform encryption in the circuit + let encrypted_log: [u8; M] = compute_encrypted_log(contract_address, storage_slot, note_type_id, ivpk_m, preimage); + emit_encrypted_note_log(note_hash, encrypted_log, counter); + + // Current unoptimized size of the encrypted log + // incoming_tag (32 bytes) + // outgoing_tag (32 bytes) + // eph_pk (64 bytes) + // incoming_header (48 bytes) + // outgoing_header (48 bytes) + // outgoing_body (176 bytes) + // incoming_body_fixed (64 bytes) + // incoming_body_variable (N * 32 bytes + 16 bytes padding) + // len of processed log (4 bytes) + let len = 32 + 32 + 64 + 48 + 48 + 176 + 64 + (preimage.len() as Field * 32) + 16 + 4; + + let log_hash = sha256_to_field(encrypted_log); let side_effect = NoteLogHash { value: log_hash, counter, length: len, note_hash_counter }; self.note_encrypted_logs_hashes.push(side_effect); } diff --git a/noir-projects/aztec-nr/aztec/src/hash.nr b/noir-projects/aztec-nr/aztec/src/hash.nr index f0abd4912e1..322db82b966 100644 --- a/noir-projects/aztec-nr/aztec/src/hash.nr +++ b/noir-projects/aztec-nr/aztec/src/hash.nr @@ -12,24 +12,6 @@ pub fn compute_secret_hash(secret: Field) -> Field { pedersen_hash([secret], GENERATOR_INDEX__SECRET_HASH) } -pub fn compute_encrypted_log_hash(encrypted_log: [Field; M]) -> Field where [Field; N]: LensForEncryptedLog { - let mut bytes = [0; L]; - // Note that bytes.append(encrypted_log[i].to_be_bytes(31)) results in bound error - for i in 0..M - 1 { - let to_add = encrypted_log[i].to_be_bytes(31); - for j in 0..31 { - bytes[i*31 + j] = to_add[j]; - } - } - // can't assign as L - not in scope error for: L-31*(M-1) - let num_bytes = bytes.len() as u32 - 31 * (M - 1); - let to_add_final = encrypted_log[M - 1].to_be_bytes(num_bytes); - for j in 0..num_bytes { - bytes[(M-1)*31 + j] = to_add_final[j]; - } - sha256_to_field(bytes) -} - pub fn compute_unencrypted_log_hash( contract_address: AztecAddress, event_selector: Field, @@ -167,44 +149,6 @@ fn compute_var_args_hash() { assert(hash == 0x05a1023fef839ac88731f49ae983e172c1b600a3c8f3393ad0ac25d819ac0f0f); } -#[test] -fn compute_enc_log_hash_304() { - let input = [ - 0x0000000000000000000000000000000000000000000000000000000000000000, - 0x0021a0d4aa9989656b592187cf6da1965df53ab2ff2277421e663465cf20d3e9, - 0x00c3969cc350f3474f8187a33ac1317181961f5f94043b07ce888d85a5d20cb5, - 0x0058198041ed1547b056955b5141a5a8a1551b0c8d094255ec9daaf3604d9348, - 0x00247ad96df2e4d984cf795ed7316234743a681f824a45c46253de8bfde48850, - 0x007fc251f4ce44f4e9aba3dbf6567228be28fac85660156f2825ddb0b0577457, - 0x009315851323c6bc2aaa42e23fe5f3be97208f2d8167eafdfc5742d94f2f4dd4, - 0x00b938289e563b0fe01982cd9b8d9e33e3069046768ad01c0fb05e429e7b7909, - 0x00fbcc257a3211f705b471eee763b0f43876a2b2178fab6d2b09bd2b7e086584, - 0x000000000000008c3289b5793b7448f4d45ecde039d004b6f037cad10b5c2336 - ]; - let hash = compute_encrypted_log_hash(input); - assert(hash == 0x001e3c013994947fe28957a876bf1b2c3a69ac69cc92909efd4f2ae9b972f893); -} - -#[test] -fn compute_enc_log_hash_368() { - let input = [ - 0x0000000000000000000000000000000000000000000000000000000000000000, - 0x002190697d2a50e229a7a077e0951073f7d51e46679f10466153c308b63b1ea9, - 0x00543e346facc6799b94514c9d461bcc836c04b083b13c2e4544a39130473c1e, - 0x000df76d59526f8f953bcc7d9f77cdaefd36435931f0d7348f794bc275b42ded, - 0x00a6d390ee1723af7f7ac1ae4fc81a266b2370fe07040a36d06dbe242e02413e, - 0x00acbce15b6af1fbe94bd0f7b70f11768265dff77bfe63398f2a053efdfdf26d, - 0x00b8b131b9f42c689beb095ba4f4a836d4d15c9068d0422e9add6ca82b786329, - 0x00661a6a654b38f0f97d404ef5553e0efea9ed670561ae86685b31bbb2824fac, - 0x00113a6b58edfaec0065b365f66ba8d8aa68254b8690035e8d671a17a843f0a1, - 0x0023f2d2eae8c4449bac8f268a3e62a3faace1fe1401f0efdc8b0ccfbc8fb271, - 0x00cf6603f8c61993dd2f662c719671c61727a2f4e925fb988b23d31feccd77d9, - 0x0000000000a402a84b7294671799c38dd805f6a827a3a12633fdf91a57debe1f - ]; - let hash = compute_encrypted_log_hash(input); - assert(hash == 0x00a0d651ac0cbc01b72430fa6a05d91738595af6e0229347b4c9968223387aeb); -} - #[test] fn compute_unenc_log_hash_array() { let contract_address = AztecAddress::from_field(0x233a3e0df23b2b15b324194cb4a151f26c0b7333250781d34cc269d85dc334c6); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index a1d933915ee..148b12a79b5 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -1,32 +1,40 @@ use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; -// TODO(1139): Should take encrypted data. -// Currently returns encrypted data to be hashed -// = 112 + 32 * (N + 3) bytes = N + 7 fields +// = 480 + 32 * N bytes +#[oracle(emitEncryptedNoteLog)] +fn emit_encrypted_note_log_oracle(_note_hash: Field, _encrypted_note: [u8; M], _counter: u32) {} + +unconstrained pub fn emit_encrypted_note_log( + note_hash: Field, + encrypted_note: [u8; M], + counter: u32 +) { + emit_encrypted_note_log_oracle(note_hash, encrypted_note, counter) +} + #[oracle(emitEncryptedLog)] -fn emit_encrypted_log_oracle( +fn emit_encrypted_log_oracle(_encrypted_note: [u8; M], _counter: u32) {} + +unconstrained pub fn emit_encrypted_log(encrypted_note: [u8; M], counter: u32) { + emit_encrypted_log_oracle(encrypted_note, counter) +} + +// = 480 + 32 * N bytes +#[oracle(computeEncryptedLog)] +fn compute_encrypted_log_oracle( _contract_address: AztecAddress, _storage_slot: Field, _note_type_id: Field, _encryption_pub_key: GrumpkinPoint, - _preimage: [Field; N], - _counter: u32 -) -> [Field; M] {} + _preimage: [Field; N] +) -> [u8; M] {} -unconstrained pub fn emit_encrypted_log( +unconstrained pub fn compute_encrypted_log( contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, ivpk_m: GrumpkinPoint, - preimage: [Field; N], - counter: u32 -) -> [Field; M] { - emit_encrypted_log_oracle( - contract_address, - storage_slot, - note_type_id, - ivpk_m, - preimage, - counter - ) + preimage: [Field; N] +) -> [u8; M] { + compute_encrypted_log_oracle(contract_address, storage_slot, note_type_id, ivpk_m, preimage) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr index 267979da364..c6632f5a4d3 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr @@ -1,8 +1,7 @@ use dep::protocol_types::address::AztecAddress; -// TODO: this is awful but since we can't have a fn that maps [Field; N] -> [Field; N+7] -// (where N is encrypted log preimage size and N+7 is encryption output size) -// and can't return slices from oracles, this at least compiles and runs +// TODO: this is awful but since we can't have a fn that maps [Field; N] -> [u8; 480 + N * 32] +// (where N is the note pre-image size and 480 + N * 32 is the encryption output size) // The fns for LensForEncryptedLog are never used, it's just to tell the compiler what the lens are // The to_bytes fn for ToBytesForUnencryptedLog is used to allow us to hash some generic T @@ -10,37 +9,38 @@ use dep::protocol_types::address::AztecAddress; // I could have omitted N from the trait, but wanted to keep it strictly for field arrs // TODO(1139): Once we enc inside the circuit, we will no longer need the oracle to return // anything, so we can remove this trait -trait LensForEncryptedLog { +trait LensForEncryptedLog { // N = note preimage input in fields - // M = encryption output len in fields (= N + 7 = N + 3 fields for addr, slot, type + 3.5 fields for AES data) - // L = encryption output len in bytes (= 32*M - 16) - fn output_fields(self: [Field; N]) -> [Field; M]; - fn output_bytes(self: [Field; N]) -> [u8; L]; + // M = encryption output len in bytes (= 480 + N * 32) + fn output_fields(self: [Field; N]) -> [Field; N]; + fn output_bytes(self: [Field; N]) -> [u8; M]; } -impl LensForEncryptedLog<1, 8, 240> for [Field; 1] { - fn output_fields(self) -> [Field; 8] {[self[0]; 8]} - fn output_bytes(self) -> [u8; 240] {[self[0] as u8; 240]} +impl LensForEncryptedLog<1, 512> for [Field; 1] { + fn output_fields(self) -> [Field; 1] {[self[0]; 1]} + fn output_bytes(self) -> [u8; 512] {[self[0] as u8; 512]} } -impl LensForEncryptedLog<2, 9, 272> for [Field; 2] { - fn output_fields(self) -> [Field; 9] {[self[0]; 9]} - fn output_bytes(self) -> [u8; 272] {[self[0] as u8; 272]} +impl LensForEncryptedLog<2, 544> for [Field; 2] { + fn output_fields(self) -> [Field; 2] {[self[0]; 2]} + fn output_bytes(self) -> [u8; 544] {[self[0] as u8; 544]} } -impl LensForEncryptedLog<3, 10, 304> for [Field; 3] { - fn output_fields(self) -> [Field; 10] {[self[0]; 10]} - fn output_bytes(self) -> [u8; 304] {[self[0] as u8; 304]} +impl LensForEncryptedLog<3, 576> for [Field; 3] { + fn output_fields(self) -> [Field; 3] {[self[0]; 3]} + fn output_bytes(self) -> [u8; 576] {[self[0] as u8; 576]} } -impl LensForEncryptedLog<4, 11, 336> for [Field; 4] { - fn output_fields(self) -> [Field; 11] {[self[0]; 11]} - fn output_bytes(self) -> [u8; 336] {[self[0] as u8; 336]} +impl LensForEncryptedLog<4, 608> for [Field; 4] { + fn output_fields(self) -> [Field; 4] {[self[0]; 4]} + fn output_bytes(self) -> [u8; 608] {[self[0] as u8; 608]} + } -impl LensForEncryptedLog<5, 12, 368> for [Field; 5] { - fn output_fields(self) -> [Field; 12] {[self[0]; 12]} - fn output_bytes(self) -> [u8; 368] {[self[0] as u8; 368]} +impl LensForEncryptedLog<5, 640> for [Field; 5] { + fn output_fields(self) -> [Field; 5] {[self[0]; 5]} + fn output_bytes(self) -> [u8; 640] {[self[0] as u8; 640]} } -impl LensForEncryptedLog<6, 13, 400> for [Field; 6] { - fn output_fields(self) -> [Field; 13] {[self[0]; 13]} - fn output_bytes(self) -> [u8; 400] {[self[0] as u8; 400]} +impl LensForEncryptedLog<6, 672> for [Field; 6] { + fn output_fields(self) -> [Field; 6] {[self[0]; 6]} + fn output_bytes(self) -> [u8; 672] {[self[0] as u8; 672]} + } // This trait defines the length of the inputs in bytes to diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 06c01fcbaa4..7e057b8912e 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -47,7 +47,7 @@ impl NoteInterface for ValueNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index e8e2dd2f2e5..7de5917b11d 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -40,7 +40,7 @@ impl NoteInterface for SubscriptionNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 2c3100cbc60..5efd1e93879 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -51,7 +51,7 @@ impl NoteInterface for CardNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index fa1b79f879d..f716dc5a5f8 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -24,7 +24,7 @@ impl NoteInterface for EcdsaPublicKeyNote { // [1] = x[31] // [2] = y[0..31] // [3] = y[31] - // [4] = owner + // [4] = npk_m_hash fn serialize_content(self) -> [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] { let mut x: Field = 0; let mut y: Field = 0; @@ -86,7 +86,7 @@ impl NoteInterface for EcdsaPublicKeyNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 3b675374f11..df6e72b61b3 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -39,7 +39,7 @@ impl NoteInterface for PublicKeyNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 721dc23ad24..204023a21ab 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -51,7 +51,7 @@ impl NoteInterface for TokenNote { // We only bother inserting the note if non-empty to save funds on gas. // TODO: (#5901) This will be changed a lot, as it should use the updated encrypted log format if !(self.amount == U128::from_integer(0)) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 721dc23ad24..204023a21ab 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -51,7 +51,7 @@ impl NoteInterface for TokenNote { // We only bother inserting the note if non-empty to save funds on gas. // TODO: (#5901) This will be changed a lot, as it should use the updated encrypted log format if !(self.amount == U128::from_integer(0)) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts b/yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts deleted file mode 100644 index bb62424faf0..00000000000 --- a/yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { AztecAddress, GrumpkinScalar } from '@aztec/circuits.js'; -import { Grumpkin } from '@aztec/circuits.js/barretenberg'; - -import { EncryptedLogPayload } from './encrypted_log_payload.js'; -import { L1NotePayload } from './l1_note_payload/l1_note_payload.js'; - -describe('encrypt and decrypt a full log', () => { - let grumpkin: Grumpkin; - - let ovsk: GrumpkinScalar; - let ivsk: GrumpkinScalar; - - let payload: EncryptedLogPayload; - let encrypted: Buffer; - - beforeAll(() => { - grumpkin = new Grumpkin(); - - ovsk = GrumpkinScalar.random(); - ivsk = GrumpkinScalar.random(); - - const ephSk = GrumpkinScalar.random(); - - const recipientAddress = AztecAddress.random(); - const ivpk = grumpkin.mul(Grumpkin.generator, ivsk); - - payload = EncryptedLogPayload.fromL1NotePayload(L1NotePayload.random()); - encrypted = payload.encrypt(ephSk, recipientAddress, ivpk, ovsk); - }); - - it('decrypt a log as incoming', () => { - const recreated = EncryptedLogPayload.decryptAsIncoming(encrypted, ivsk); - - expect(recreated.toBuffer()).toEqual(payload.toBuffer()); - }); - - it('decrypt a log as outgoing', () => { - const recreated = EncryptedLogPayload.decryptAsOutgoing(encrypted, ovsk); - - expect(recreated.toBuffer()).toEqual(payload.toBuffer()); - }); -}); diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_payload.ts b/yarn-project/circuit-types/src/logs/encrypted_log_payload.ts deleted file mode 100644 index 6ef1cc82add..00000000000 --- a/yarn-project/circuit-types/src/logs/encrypted_log_payload.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { - AztecAddress, - Fr, - type GrumpkinPrivateKey, - Point, - type PublicKey, - computeIvpkApp, - computeIvskApp, - computeOvskApp, - derivePublicKeyFromSecretKey, -} from '@aztec/circuits.js'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -import { EncryptedLogHeader } from './encrypted_log_header.js'; -import { EncryptedLogIncomingBody } from './encrypted_log_incoming_body.js'; -import { EncryptedLogOutgoingBody } from './encrypted_log_outgoing_body.js'; -import { type L1NotePayload } from './l1_note_payload/l1_note_payload.js'; -import { Note } from './l1_note_payload/note.js'; - -// A placeholder tag until we have a proper tag system in place. -const PLACEHOLDER_TAG = new Fr(33); - -// Both the incoming and the outgoing header are 48 bytes. -// 32 bytes for the address, and 16 bytes padding to follow PKCS#7 -const HEADER_SIZE = 48; - -// The outgoing body is constant size of 176 bytes. -// 160 bytes for the secret key, address, and public key, and 16 bytes padding to follow PKCS#7 -const OUTGOING_BODY_SIZE = 176; - -export class EncryptedLogPayload { - constructor( - /** - * A note as emitted from Noir contract. Can be used along with private key to compute nullifier. - */ - public note: Note, - /** - * Address of the contract this tx is interacting with. - */ - public contractAddress: AztecAddress, - /** - * Storage slot of the underlying note. - */ - public storageSlot: Fr, - /** - * Type identifier for the underlying note, required to determine how to compute its hash and nullifier. - */ - public noteTypeId: Fr, - ) {} - - toBuffer() { - return serializeToBuffer([this.note, this.contractAddress, this.storageSlot, this.noteTypeId]); - } - - static fromBuffer(buffer: Buffer | BufferReader): EncryptedLogPayload { - const reader = BufferReader.asReader(buffer); - return new EncryptedLogPayload( - reader.readObject(Note), - reader.readObject(AztecAddress), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - ); - } - - static fromL1NotePayload(l1NotePayload: L1NotePayload) { - return new EncryptedLogPayload( - l1NotePayload.note, - l1NotePayload.contractAddress, - l1NotePayload.storageSlot, - l1NotePayload.noteTypeId, - ); - } - - /** - * Encrypts a note payload for a given recipient and sender. - * Creates an incoming log the the recipient using the recipient's ivsk, and - * an outgoing log for the sender using the sender's ovsk. - * - * @param ephSk - An ephemeral secret key used for the encryption - * @param recipient - The recipient address, retrievable by the sender for his logs - * @param ivpk - The incoming viewing public key of the recipient - * @param ovsk - The outgoing viewing secret key of the sender - * @returns A buffer containing the encrypted log payload - */ - public encrypt(ephSk: GrumpkinPrivateKey, recipient: AztecAddress, ivpk: PublicKey, ovsk: GrumpkinPrivateKey) { - const ephPk = derivePublicKeyFromSecretKey(ephSk); - const ovpk = derivePublicKeyFromSecretKey(ovsk); - - const header = new EncryptedLogHeader(this.contractAddress); - - const incomingHeaderCiphertext = header.computeCiphertext(ephSk, ivpk); - const outgoingHeaderCiphertext = header.computeCiphertext(ephSk, ovpk); - - const ivpkApp = computeIvpkApp(ivpk, this.contractAddress); - - const incomingBodyCiphertext = new EncryptedLogIncomingBody( - this.storageSlot, - this.noteTypeId, - this.note, - ).computeCiphertext(ephSk, ivpkApp); - - const ovskApp = computeOvskApp(ovsk, this.contractAddress); - - const outgoingBodyCiphertext = new EncryptedLogOutgoingBody(ephSk, recipient, ivpkApp).computeCiphertext( - ovskApp, - ephPk, - ); - - return Buffer.concat([ - PLACEHOLDER_TAG.toBuffer(), - PLACEHOLDER_TAG.toBuffer(), - ephPk.toBuffer(), - incomingHeaderCiphertext, - outgoingHeaderCiphertext, - outgoingBodyCiphertext, - incomingBodyCiphertext, - ]); - } - - /** - * Decrypts a ciphertext as an incoming log. - * - * This is executable by the recipient of the note, and uses the ivsk to decrypt the payload. - * The outgoing parts of the log are ignored entirely. - * - * Produces the same output as `decryptAsOutgoing`. - * - * @param ciphertext - The ciphertext for the log - * @param ivsk - The incoming viewing secret key, used to decrypt the logs - * @returns The decrypted log payload - */ - public static decryptAsIncoming(ciphertext: Buffer | bigint[], ivsk: GrumpkinPrivateKey) { - const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); - const reader = BufferReader.asReader(input); - - // We don't use the tags as part of the decryption here, we just gotta read to skip them. - reader.readObject(Fr); // incoming tag - reader.readObject(Fr); // outgoing tag - - const ephPk = reader.readObject(Point); - - const incomingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ivsk, ephPk); - - // Skipping the outgoing header and body - reader.readBytes(HEADER_SIZE); - reader.readBytes(OUTGOING_BODY_SIZE); - - // The incoming can be of variable size, so we read until the end - const incomingBodySlice = reader.readToEnd(); - - const ivskApp = computeIvskApp(ivsk, incomingHeader.address); - const incomingBody = EncryptedLogIncomingBody.fromCiphertext(incomingBodySlice, ivskApp, ephPk); - - return new EncryptedLogPayload( - incomingBody.note, - incomingHeader.address, - incomingBody.storageSlot, - incomingBody.noteTypeId, - ); - } - - /** - * Decrypts a ciphertext as an outgoing log. - * - * This is executable by the sender of the note, and uses the ovsk to decrypt the payload. - * The outgoing parts are decrypted to retrieve information that allows the sender to - * decrypt the incoming log, and learn about the note contents. - * - * Produces the same output as `decryptAsIncoming`. - * - * @param ciphertext - The ciphertext for the log - * @param ovsk - The outgoing viewing secret key, used to decrypt the logs - * @returns The decrypted log payload - */ - public static decryptAsOutgoing(ciphertext: Buffer | bigint[], ovsk: GrumpkinPrivateKey) { - const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); - const reader = BufferReader.asReader(input); - - // We don't use the tags as part of the decryption here, we just gotta read to skip them. - reader.readObject(Fr); // incoming tag - reader.readObject(Fr); // outgoing tag - - const ephPk = reader.readObject(Point); - - // Skip the incoming header - reader.readBytes(HEADER_SIZE); - - const outgoingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ovsk, ephPk); - - const ovskApp = computeOvskApp(ovsk, outgoingHeader.address); - const outgoingBody = EncryptedLogOutgoingBody.fromCiphertext(reader.readBytes(OUTGOING_BODY_SIZE), ovskApp, ephPk); - - // The incoming can be of variable size, so we read until the end - const incomingBodySlice = reader.readToEnd(); - - const incomingBody = EncryptedLogIncomingBody.fromCiphertext( - incomingBodySlice, - outgoingBody.ephSk, - outgoingBody.recipientIvpkApp, - ); - - return new EncryptedLogPayload( - incomingBody.note, - outgoingHeader.address, - incomingBody.storageSlot, - incomingBody.noteTypeId, - ); - } -} diff --git a/yarn-project/circuit-types/src/logs/index.ts b/yarn-project/circuit-types/src/logs/index.ts index 0e4b8200391..6b4a4199c28 100644 --- a/yarn-project/circuit-types/src/logs/index.ts +++ b/yarn-project/circuit-types/src/logs/index.ts @@ -10,6 +10,6 @@ export * from './l1_note_payload/index.js'; export * from './tx_l2_logs.js'; export * from './unencrypted_l2_log.js'; export * from './extended_unencrypted_l2_log.js'; -export * from './encrypted_log_header.js'; -export * from './encrypted_log_incoming_body.js'; -export * from './encrypted_log_outgoing_body.js'; +export * from './l1_note_payload/encrypted_log_header.js'; +export * from './l1_note_payload/encrypted_log_incoming_body.js'; +export * from './l1_note_payload/encrypted_log_outgoing_body.js'; diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts index d8a0c4b9998..3db91fe87a0 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts @@ -3,7 +3,8 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { randomBytes } from '@aztec/foundation/crypto'; import { updateInlineTestData } from '@aztec/foundation/testing'; -import { decryptBuffer, deriveAESSecret, encryptBuffer } from './encrypt_buffer.js'; +import { decryptBuffer, encryptBuffer } from './encrypt_buffer.js'; +import { deriveAESSecret } from './encryption_utils.js'; describe('encrypt buffer', () => { let grumpkin: Grumpkin; diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts index 28262ff3ba6..dd8e954a7af 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts @@ -1,30 +1,10 @@ -import { GeneratorIndex, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; +import { type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { sha256 } from '@aztec/foundation/crypto'; import { Point } from '@aztec/foundation/fields'; -import { numToUInt8 } from '@aztec/foundation/serialize'; import { createCipheriv, createDecipheriv } from 'browserify-cipher'; -/** - * Derive an AES secret key using Elliptic Curve Diffie-Hellman (ECDH) and SHA-256. - * The function takes in an ECDH public key, a private key, and a Grumpkin instance to compute - * the shared secret. The shared secret is then hashed using SHA-256 to produce the final - * AES secret key. - * - * @param secretKey - The secret key used to derive shared secret. - * @param publicKey - The public key used to derive shared secret. - * @returns A derived AES secret key. - * TODO(#5726): This function is called point_to_symmetric_key in Noir. I don't like that name much since point is not - * the only input of the function. Unify naming once we have a better name. - */ -export function deriveAESSecret(secretKey: GrumpkinPrivateKey, publicKey: PublicKey): Buffer { - const curve = new Grumpkin(); - const sharedSecret = curve.mul(publicKey, secretKey); - const secretBuffer = Buffer.concat([sharedSecret.toBuffer(), numToUInt8(GeneratorIndex.SYMMETRIC_KEY)]); - const hash = sha256(secretBuffer); - return hash; -} +import { deriveAESSecret } from './encryption_utils.js'; /** * Encrypt a given data buffer using the owner's public key and an ephemeral private key. diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_header.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.test.ts similarity index 100% rename from yarn-project/circuit-types/src/logs/encrypted_log_header.test.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.test.ts diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_header.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.ts similarity index 96% rename from yarn-project/circuit-types/src/logs/encrypted_log_header.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.ts index baef6cc264b..ac19b40cc3c 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_log_header.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.ts @@ -1,7 +1,7 @@ import { AztecAddress, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; import { Aes128 } from '@aztec/circuits.js/barretenberg'; -import { deriveAESSecret } from './l1_note_payload/encrypt_buffer.js'; +import { deriveAESSecret } from './encryption_utils.js'; /** * An encrypted log header, containing the address of the log along with utility diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.test.ts similarity index 97% rename from yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.test.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.test.ts index bb1ab2c2588..934621b508e 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.test.ts @@ -3,7 +3,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { updateInlineTestData } from '@aztec/foundation/testing'; import { EncryptedLogIncomingBody } from './encrypted_log_incoming_body.js'; -import { Note } from './l1_note_payload/note.js'; +import { Note } from './note.js'; describe('encrypt log incoming body', () => { let grumpkin: Grumpkin; diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.ts similarity index 97% rename from yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.ts index 45e1f5382bf..3001d6963de 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.ts @@ -2,7 +2,8 @@ import { Fr, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js' import { Aes128 } from '@aztec/circuits.js/barretenberg'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { Note, deriveAESSecret } from './l1_note_payload/index.js'; +import { deriveAESSecret } from './encryption_utils.js'; +import { Note } from './note.js'; export class EncryptedLogIncomingBody { constructor(public storageSlot: Fr, public noteTypeId: Fr, public note: Note) {} diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.test.ts similarity index 100% rename from yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.test.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.test.ts diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.ts similarity index 100% rename from yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.ts diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts new file mode 100644 index 00000000000..2673af92c61 --- /dev/null +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts @@ -0,0 +1,24 @@ +import { GeneratorIndex, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; +import { Grumpkin } from '@aztec/circuits.js/barretenberg'; +import { sha256 } from '@aztec/foundation/crypto'; +import { numToUInt8 } from '@aztec/foundation/serialize'; + +/** + * Derive an AES secret key using Elliptic Curve Diffie-Hellman (ECDH) and SHA-256. + * The function takes in an ECDH public key, a private key, and a Grumpkin instance to compute + * the shared secret. The shared secret is then hashed using SHA-256 to produce the final + * AES secret key. + * + * @param secretKey - The secret key used to derive shared secret. + * @param publicKey - The public key used to derive shared secret. + * @returns A derived AES secret key. + * TODO(#5726): This function is called point_to_symmetric_key in Noir. I don't like that name much since point is not + * the only input of the function. Unify naming once we have a better name. + */ +export function deriveAESSecret(secretKey: GrumpkinPrivateKey, publicKey: PublicKey): Buffer { + const curve = new Grumpkin(); + const sharedSecret = curve.mul(publicKey, secretKey); + const secretBuffer = Buffer.concat([sharedSecret.toBuffer(), numToUInt8(GeneratorIndex.SYMMETRIC_KEY)]); + const hash = sha256(secretBuffer); + return hash; +} diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts index 288e46db36d..321a8e82985 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts @@ -1,5 +1,6 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; +import { GrumpkinScalar } from '@aztec/foundation/fields'; import { L1NotePayload } from './l1_note_payload.js'; @@ -16,22 +17,36 @@ describe('L1 Note Payload', () => { expect(L1NotePayload.fromBuffer(buf)).toEqual(payload); }); - it('convert to and from encrypted buffer', () => { - const payload = L1NotePayload.random(); - const ownerPrivKey = GrumpkinScalar.random(); - const ownerPubKey = grumpkin.mul(Grumpkin.generator, ownerPrivKey); - const encrypted = payload.toEncryptedBuffer(ownerPubKey); - const decrypted = L1NotePayload.fromEncryptedBuffer(encrypted, ownerPrivKey); - expect(decrypted).not.toBeUndefined(); - expect(decrypted).toEqual(payload); - }); + describe('encrypt and decrypt a full log', () => { + let ovsk: GrumpkinScalar; + let ivsk: GrumpkinScalar; - it('return undefined if unable to decrypt the encrypted buffer', () => { - const payload = L1NotePayload.random(); - const ownerPubKey = Point.random(); - const encrypted = payload.toEncryptedBuffer(ownerPubKey); - const randomPrivKey = GrumpkinScalar.random(); - const decrypted = L1NotePayload.fromEncryptedBuffer(encrypted, randomPrivKey); - expect(decrypted).toBeUndefined(); + let payload: L1NotePayload; + let encrypted: Buffer; + + beforeAll(() => { + ovsk = GrumpkinScalar.random(); + ivsk = GrumpkinScalar.random(); + + const ephSk = GrumpkinScalar.random(); + + const recipientAddress = AztecAddress.random(); + const ivpk = grumpkin.mul(Grumpkin.generator, ivsk); + + payload = L1NotePayload.random(); + encrypted = payload.encrypt(ephSk, recipientAddress, ivpk, ovsk); + }); + + it('decrypt a log as incoming', () => { + const recreated = L1NotePayload.decryptAsIncoming(encrypted, ivsk); + + expect(recreated.toBuffer()).toEqual(payload.toBuffer()); + }); + + it('decrypt a log as outgoing', () => { + const recreated = L1NotePayload.decryptAsOutgoing(encrypted, ovsk); + + expect(recreated.toBuffer()).toEqual(payload.toBuffer()); + }); }); }); diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts index 463512782a7..285befd192d 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts @@ -1,10 +1,27 @@ -import { AztecAddress, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; -import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; +import { + AztecAddress, + type GrumpkinPrivateKey, + type PublicKey, + computeIvpkApp, + computeIvskApp, + computeOvskApp, + derivePublicKeyFromSecretKey, +} from '@aztec/circuits.js'; +import { Fr, Point } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { decryptBuffer, encryptBuffer } from './encrypt_buffer.js'; +import { EncryptedLogHeader } from './encrypted_log_header.js'; +import { EncryptedLogIncomingBody } from './encrypted_log_incoming_body.js'; +import { EncryptedLogOutgoingBody } from './encrypted_log_outgoing_body.js'; import { Note } from './note.js'; +// Both the incoming and the outgoing header are 48 bytes. +// 32 bytes for the address, and 16 bytes padding to follow PKCS#7 +const HEADER_SIZE = 48; + +// The outgoing body is constant size of 176 bytes. +// 160 bytes for the secret key, address, and public key, and 16 bytes padding to follow PKCS#7 +const OUTGOING_BODY_SIZE = 176; /** * A class which wraps note data which is pushed on L1. * @remarks This data is required to compute a nullifier/to spend a note. Along with that this class contains @@ -21,7 +38,7 @@ export class L1NotePayload { */ public contractAddress: AztecAddress, /** - * Storage slot of the contract this tx is interacting with. + * Storage slot of the underlying note. */ public storageSlot: Fr, /** @@ -54,34 +71,136 @@ export class L1NotePayload { } /** - * Encrypt the L1NotePayload object using the owner's public key and the ephemeral private key. - * @param incomingViewingPubKey - Public key of the owner of the L1NotePayload object. - * @returns The encrypted L1NotePayload object. + * Create a random L1NotePayload object (useful for testing purposes). + * @returns A random L1NotePayload object. */ - public toEncryptedBuffer(incomingViewingPubKey: PublicKey): Buffer { - const ephSecretKey: GrumpkinPrivateKey = GrumpkinScalar.random(); - return encryptBuffer(this.toBuffer(), ephSecretKey, incomingViewingPubKey); + static random() { + return new L1NotePayload(Note.random(), AztecAddress.random(), Fr.random(), Fr.random()); } /** - * Decrypts the L1NotePayload object using the owner's incoming viewing secret key. - * @param data - Encrypted L1NotePayload object. - * @param incomingViewingSecretKey - Incoming viewing secret key of the owner of the L1NotePayload object. - * @returns Instance of L1NotePayload if the decryption was successful, undefined otherwise. + * Encrypts a note payload for a given recipient and sender. + * Creates an incoming log the the recipient using the recipient's ivsk, and + * an outgoing log for the sender using the sender's ovsk. + * + * @param ephSk - An ephemeral secret key used for the encryption + * @param recipient - The recipient address, retrievable by the sender for his logs + * @param ivpk - The incoming viewing public key of the recipient + * @param ovsk - The outgoing viewing secret key of the sender + * @returns A buffer containing the encrypted log payload */ - static fromEncryptedBuffer(data: Buffer, incomingViewingSecretKey: GrumpkinPrivateKey): L1NotePayload | undefined { - const buf = decryptBuffer(data, incomingViewingSecretKey); - if (!buf) { - return; - } - return L1NotePayload.fromBuffer(buf); + public encrypt(ephSk: GrumpkinPrivateKey, recipient: AztecAddress, ivpk: PublicKey, ovsk: GrumpkinPrivateKey) { + const ephPk = derivePublicKeyFromSecretKey(ephSk); + const ovpk = derivePublicKeyFromSecretKey(ovsk); + + const header = new EncryptedLogHeader(this.contractAddress); + + const incomingHeaderCiphertext = header.computeCiphertext(ephSk, ivpk); + const outgoingHeaderCiphertext = header.computeCiphertext(ephSk, ovpk); + + const ivpkApp = computeIvpkApp(ivpk, this.contractAddress); + + const incomingBodyCiphertext = new EncryptedLogIncomingBody( + this.storageSlot, + this.noteTypeId, + this.note, + ).computeCiphertext(ephSk, ivpkApp); + + const ovskApp = computeOvskApp(ovsk, this.contractAddress); + + const outgoingBodyCiphertext = new EncryptedLogOutgoingBody(ephSk, recipient, ivpkApp).computeCiphertext( + ovskApp, + ephPk, + ); + + return Buffer.concat([ + ephPk.toBuffer(), + incomingHeaderCiphertext, + outgoingHeaderCiphertext, + outgoingBodyCiphertext, + incomingBodyCiphertext, + ]); } /** - * Create a random L1NotePayload object (useful for testing purposes). - * @returns A random L1NotePayload object. + * Decrypts a ciphertext as an incoming log. + * + * This is executable by the recipient of the note, and uses the ivsk to decrypt the payload. + * The outgoing parts of the log are ignored entirely. + * + * Produces the same output as `decryptAsOutgoing`. + * + * @param ciphertext - The ciphertext for the log + * @param ivsk - The incoming viewing secret key, used to decrypt the logs + * @returns The decrypted log payload */ - static random() { - return new L1NotePayload(Note.random(), AztecAddress.random(), Fr.random(), Fr.random()); + public static decryptAsIncoming(ciphertext: Buffer | bigint[], ivsk: GrumpkinPrivateKey) { + const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + + const ephPk = reader.readObject(Point); + + const incomingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ivsk, ephPk); + + // Skipping the outgoing header and body + reader.readBytes(HEADER_SIZE); + reader.readBytes(OUTGOING_BODY_SIZE); + + // The incoming can be of variable size, so we read until the end + const incomingBodySlice = reader.readToEnd(); + + const ivskApp = computeIvskApp(ivsk, incomingHeader.address); + const incomingBody = EncryptedLogIncomingBody.fromCiphertext(incomingBodySlice, ivskApp, ephPk); + + return new L1NotePayload( + incomingBody.note, + incomingHeader.address, + incomingBody.storageSlot, + incomingBody.noteTypeId, + ); + } + + /** + * Decrypts a ciphertext as an outgoing log. + * + * This is executable by the sender of the note, and uses the ovsk to decrypt the payload. + * The outgoing parts are decrypted to retrieve information that allows the sender to + * decrypt the incoming log, and learn about the note contents. + * + * Produces the same output as `decryptAsIncoming`. + * + * @param ciphertext - The ciphertext for the log + * @param ovsk - The outgoing viewing secret key, used to decrypt the logs + * @returns The decrypted log payload + */ + public static decryptAsOutgoing(ciphertext: Buffer | bigint[], ovsk: GrumpkinPrivateKey) { + const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + + const ephPk = reader.readObject(Point); + + // Skip the incoming header + reader.readBytes(HEADER_SIZE); + + const outgoingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ovsk, ephPk); + + const ovskApp = computeOvskApp(ovsk, outgoingHeader.address); + const outgoingBody = EncryptedLogOutgoingBody.fromCiphertext(reader.readBytes(OUTGOING_BODY_SIZE), ovskApp, ephPk); + + // The incoming can be of variable size, so we read until the end + const incomingBodySlice = reader.readToEnd(); + + const incomingBody = EncryptedLogIncomingBody.fromCiphertext( + incomingBodySlice, + outgoingBody.ephSk, + outgoingBody.recipientIvpkApp, + ); + + return new L1NotePayload( + incomingBody.note, + outgoingHeader.address, + incomingBody.storageSlot, + incomingBody.noteTypeId, + ); } } diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts index bbd171f3702..392291c794b 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts @@ -1,5 +1,6 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; +import { GrumpkinScalar } from '@aztec/foundation/fields'; import { L1NotePayload } from './l1_note_payload.js'; import { TaggedNote } from './tagged_note.js'; @@ -18,24 +19,39 @@ describe('L1 Note Payload', () => { expect(TaggedNote.fromBuffer(buf).notePayload).toEqual(taggedNote.notePayload); }); - it('convert to and from encrypted buffer', () => { - const payload = L1NotePayload.random(); - const taggedNote = new TaggedNote(payload); - const ownerPrivKey = GrumpkinScalar.random(); - const ownerPubKey = grumpkin.mul(Grumpkin.generator, ownerPrivKey); - const encrypted = taggedNote.toEncryptedBuffer(ownerPubKey); - const decrypted = TaggedNote.fromEncryptedBuffer(encrypted, ownerPrivKey); - expect(decrypted).not.toBeUndefined(); - expect(decrypted?.notePayload).toEqual(payload); - }); + describe('encrypt and decrypt a full log', () => { + let ovsk: GrumpkinScalar; + let ivsk: GrumpkinScalar; - it('return undefined if unable to decrypt the encrypted buffer', () => { - const payload = L1NotePayload.random(); - const taggedNote = new TaggedNote(payload); - const ownerPubKey = Point.random(); - const encrypted = taggedNote.toEncryptedBuffer(ownerPubKey); - const randomPrivKey = GrumpkinScalar.random(); - const decrypted = TaggedNote.fromEncryptedBuffer(encrypted, randomPrivKey); - expect(decrypted).toBeUndefined(); + let taggedNote: TaggedNote; + let encrypted: Buffer; + + beforeAll(() => { + ovsk = GrumpkinScalar.random(); + ivsk = GrumpkinScalar.random(); + + const ephSk = GrumpkinScalar.random(); + + const recipientAddress = AztecAddress.random(); + const ivpk = grumpkin.mul(Grumpkin.generator, ivsk); + + const payload = L1NotePayload.random(); + + taggedNote = new TaggedNote(payload); + + encrypted = taggedNote.encrypt(ephSk, recipientAddress, ivpk, ovsk); + }); + + it('decrypt a log as incoming', () => { + const recreated = TaggedNote.decryptAsIncoming(encrypted, ivsk); + + expect(recreated?.toBuffer()).toEqual(taggedNote.toBuffer()); + }); + + it('decrypt a log as outgoing', () => { + const recreated = TaggedNote.decryptAsOutgoing(encrypted, ovsk); + + expect(recreated?.toBuffer()).toEqual(taggedNote.toBuffer()); + }); }); }); diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts index 4e698e382eb..aa1e45a1aa1 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts @@ -1,4 +1,4 @@ -import { type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; +import { type AztecAddress, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -11,7 +11,11 @@ const PLACEHOLDER_TAG = new Fr(33); * Encrypted note payload with a tag used for retrieval by clients. */ export class TaggedNote { - constructor(public notePayload: L1NotePayload, public tag = PLACEHOLDER_TAG) {} + constructor( + public notePayload: L1NotePayload, + public incomingTag = PLACEHOLDER_TAG, + public outgoingTag = PLACEHOLDER_TAG, + ) {} /** * Deserializes the TaggedNote object from a Buffer. @@ -20,9 +24,10 @@ export class TaggedNote { */ static fromBuffer(buffer: Buffer | BufferReader): TaggedNote { const reader = BufferReader.asReader(buffer); - const tag = Fr.fromBuffer(reader); + const incomingTag = Fr.fromBuffer(reader); + const outgoingTag = Fr.fromBuffer(reader); const payload = L1NotePayload.fromBuffer(reader); - return new TaggedNote(payload, tag); + return new TaggedNote(payload, incomingTag, outgoingTag); } /** @@ -30,39 +35,53 @@ export class TaggedNote { * @returns Buffer representation of the TaggedNote object (unencrypted). */ public toBuffer(): Buffer { - return serializeToBuffer(this.tag, this.notePayload); + return serializeToBuffer(this.incomingTag, this.outgoingTag, this.notePayload); } - /** - * Encrypt the L1NotePayload object using the owner's public key and the ephemeral private key, then attach the tag. - * @param ownerPubKey - Public key of the owner of the TaggedNote object. - * @returns The encrypted TaggedNote object. - */ - public toEncryptedBuffer(ownerPubKey: PublicKey): Buffer { - const encryptedL1NotePayload = this.notePayload.toEncryptedBuffer(ownerPubKey); - return serializeToBuffer(this.tag, encryptedL1NotePayload); + static random(): TaggedNote { + return new TaggedNote(L1NotePayload.random()); } - /** - * Decrypts the L1NotePayload object using the owner's private key. - * @param data - Encrypted TaggedNote object. - * @param ownerPrivKey - Private key of the owner of the TaggedNote object. - * @returns Instance of TaggedNote if the decryption was successful, undefined otherwise. - */ - static fromEncryptedBuffer(data: Buffer, ownerPrivKey: GrumpkinPrivateKey): TaggedNote | undefined { - const reader = BufferReader.asReader(data); - const tag = Fr.fromBuffer(reader); - - const encryptedL1NotePayload = reader.readToEnd(); + public encrypt( + ephSk: GrumpkinPrivateKey, + recipient: AztecAddress, + ivpk: PublicKey, + ovsk: GrumpkinPrivateKey, + ): Buffer { + return serializeToBuffer( + this.incomingTag, + this.outgoingTag, + this.notePayload.encrypt(ephSk, recipient, ivpk, ovsk), + ); + } - const payload = L1NotePayload.fromEncryptedBuffer(encryptedL1NotePayload, ownerPrivKey); - if (!payload) { + static decryptAsIncoming(data: Buffer | bigint[], ivsk: GrumpkinPrivateKey) { + // Right now heavily abusing that we will likely fail if bad decryption + // as some field will likely end up not being in the field etc. + try { + const input = Buffer.isBuffer(data) ? data : Buffer.from(data.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + const incomingTag = Fr.fromBuffer(reader); + const outgoingTag = Fr.fromBuffer(reader); + const payload = L1NotePayload.decryptAsIncoming(reader.readToEnd(), ivsk); + return new TaggedNote(payload, incomingTag, outgoingTag); + } catch (e) { return; } - return new TaggedNote(payload, tag); } - static random(): TaggedNote { - return new TaggedNote(L1NotePayload.random()); + static decryptAsOutgoing(data: Buffer | bigint[], ovsk: GrumpkinPrivateKey) { + // Right now heavily abusing that we will likely fail if bad decryption + // as some field will likely end up not being in the field etc. + try { + const input = Buffer.isBuffer(data) ? data : Buffer.from(data.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + const incomingTag = Fr.fromBuffer(reader); + const outgoingTag = Fr.fromBuffer(reader); + const payload = L1NotePayload.decryptAsOutgoing(reader.readToEnd(), ovsk); + return new TaggedNote(payload, incomingTag, outgoingTag); + } catch (e) { + return; + } } } diff --git a/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts b/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts index a73f08a32d2..a55331b5f3b 100644 --- a/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts +++ b/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts @@ -67,28 +67,28 @@ describe('benchmarks/tx_size_fees', () => { 'native fee', () => NativeFeePaymentMethod.create(aliceWallet), // DA: - // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 616 B enc logs, 0 B unenc logs, teardown + // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 1168 B enc note logs, 0 B enc logs, 0 B unenc logs, teardown // L2: // non-rev: 0; rev: 0 - 200012416n, + 200021120n, ], [ 'public fee', () => Promise.resolve(new PublicFeePaymentMethod(token.address, fpc.address, aliceWallet)), // DA: - // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 616 B enc logs, 0 B unenc logs, teardown + // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 1168 B enc note logs, 0 B enc logs,0 B unenc logs, teardown // L2: // non-rev: 0; rev: 0 - 200012416n, + 200021120n, ], [ 'private fee', () => Promise.resolve(new PrivateFeePaymentMethod(token.address, fpc.address, aliceWallet)), // DA: - // non-rev: 3 nullifiers, overhead; rev: 2 note hashes, 616 B enc logs, 0 B unenc logs, teardown + // non-rev: 3 nullifiers, overhead; rev: 2 note hashes, 1168 B enc note logs, 0 B enc logs, 0 B unenc logs, teardown // L2: // non-rev: 0; rev: 0 - 200012928n, + 200021632n, ], ] as const)( 'sends a tx with a fee with %s payment method', diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index cbafb01600a..e923674e705 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -273,7 +273,7 @@ describe('e2e_block_building', () => { expect(rct.status).toEqual('mined'); const decryptedLogs = tx.noteEncryptedLogs .unrollLogs() - .map(l => TaggedNote.fromEncryptedBuffer(l.data, keys.masterIncomingViewingSecretKey)); + .map(l => TaggedNote.decryptAsIncoming(l.data, keys.masterIncomingViewingSecretKey)); const notevalues = decryptedLogs.map(l => l?.notePayload.note.items[0]); expect(notevalues[0]).toEqual(new Fr(10)); expect(notevalues[1]).toEqual(new Fr(11)); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index 48d144b05fd..eb7198b7607 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -425,6 +425,7 @@ export class ProvingOrchestrator { .toBuffer() .equals(tx.processedTx.encryptedLogs.hash()) ) { + // @todo This rejection messages is never seen. Never making it out to the logs provingState.reject( `Encrypted logs hash mismatch: ${ tx.baseRollupInputs.kernelData.publicInputs.end.encryptedLogsHash diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index 8c2ba5d8b01..e9c656c09d3 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -10,6 +10,7 @@ import { TaggedNote, } from '@aztec/circuit-types'; import { + AztecAddress, Fr, type GrumpkinPrivateKey, INITIAL_L2_BLOCK_NUM, @@ -18,7 +19,7 @@ import { deriveKeys, } from '@aztec/circuits.js'; import { pedersenHash } from '@aztec/foundation/crypto'; -import { Point } from '@aztec/foundation/fields'; +import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type AcirSimulator } from '@aztec/simulator'; @@ -62,7 +63,7 @@ describe('Note Processor', () => { const logs: EncryptedFunctionL2Logs[] = []; for (let noteIndex = 0; noteIndex < MAX_NEW_NOTE_HASHES_PER_TX; ++noteIndex) { const isOwner = ownedDataIndices.includes(noteIndex); - const publicKey = isOwner ? ownerMasterIncomingViewingPublicKey : Point.random(); + const ivsk = isOwner ? ownerMasterIncomingViewingPublicKey : Point.random(); const note = (isOwner && ownedNotes[usedOwnedNote]) || TaggedNote.random(); usedOwnedNote += note === ownedNotes[usedOwnedNote] ? 1 : 0; newNotes.push(note); @@ -70,7 +71,12 @@ describe('Note Processor', () => { ownedL1NotePayloads.push(note.notePayload); } // const encryptedNote = - const log = note.toEncryptedBuffer(publicKey); + //const log = note.toEncryptedBuffer(publicKey); + + const ephSk = GrumpkinScalar.random(); + const ovsk = GrumpkinScalar.random(); + const recipient = AztecAddress.random(); + const log = note.encrypt(ephSk, recipient, ivsk, ovsk); // 1 tx containing 1 function invocation containing 1 log logs.push(new EncryptedFunctionL2Logs([new EncryptedL2Log(log)])); } diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index 3eaa6b3006d..f8b4c13b571 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -130,7 +130,8 @@ export class NoteProcessor { for (const functionLogs of txFunctionLogs) { for (const log of functionLogs.logs) { this.stats.seen++; - const taggedNote = TaggedNote.fromEncryptedBuffer(log.data, secretKey); + // @todo Issue(#6410) We should also try decrypting as outgoing if this fails. + const taggedNote = TaggedNote.decryptAsIncoming(log.data, secretKey); if (taggedNote?.notePayload) { const { notePayload: payload } = taggedNote; // We have successfully decrypted the data. diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 9def84c9f12..26d8de73567 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -286,33 +286,39 @@ export class Oracle { return newValues.map(toACVMField); } - emitEncryptedLog( + emitEncryptedLog(encryptedLog: ACVMField[], [counter]: ACVMField[]): void { + // Convert each field to a number and then to a buffer (1 byte is stored in 1 field) + const processedInput = Buffer.from(encryptedLog.map(fromACVMField).map(f => f.toNumber())); + this.typedOracle.emitEncryptedLog(processedInput, +counter); + } + + emitEncryptedNoteLog([noteHash]: ACVMField[], encryptedNote: ACVMField[], [counter]: ACVMField[]): void { + // Convert each field to a number and then to a buffer (1 byte is stored in 1 field) + const processedInput = Buffer.from(encryptedNote.map(fromACVMField).map(f => f.toNumber())); + this.typedOracle.emitEncryptedNoteLog(fromACVMField(noteHash), processedInput, +counter); + } + + computeEncryptedLog( [contractAddress]: ACVMField[], [storageSlot]: ACVMField[], [noteTypeId]: ACVMField[], [publicKeyX]: ACVMField[], [publicKeyY]: ACVMField[], - log: ACVMField[], - [counter]: ACVMField[], + preimage: ACVMField[], ): ACVMField[] { const publicKey = new Point(fromACVMField(publicKeyX), fromACVMField(publicKeyY)); - const encLog = this.typedOracle.emitEncryptedLog( + const encLog = this.typedOracle.computeEncryptedLog( AztecAddress.fromString(contractAddress), Fr.fromString(storageSlot), Fr.fromString(noteTypeId), publicKey, - log.map(fromACVMField), - +counter, + preimage.map(fromACVMField), ); - // TODO(1139): We should encrypt in the circuit, but instead we inject here - // encryption output is 112 + 32 * (N + 3) bytes, for log len N - // so split into N + 7 fields (gross but avoids 300+ ACVMFields) - const encLogFields = []; - for (let i = 0; i < Math.ceil(encLog.length / 31); i++) { - encLogFields.push(toACVMField(encLog.subarray(31 * i, Math.min(31 * (i + 1), encLog.length)))); - } - - return encLogFields; + const bytes: ACVMField[] = []; + encLog.forEach(v => { + bytes.push(toACVMField(v)); + }); + return bytes; } emitUnencryptedLog( diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 4a910040384..9c39638adea 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -183,15 +183,22 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('storageWrite'); } - emitEncryptedLog( + emitEncryptedLog(_encryptedNote: Buffer, _counter: number): void { + throw new OracleMethodNotAvailableError('emitEncryptedLog'); + } + + emitEncryptedNoteLog(_noteHash: Fr, _encryptedNote: Buffer, _counter: number): void { + throw new OracleMethodNotAvailableError('emitEncryptedNoteLog'); + } + + computeEncryptedLog( _contractAddress: AztecAddress, _storageSlot: Fr, _noteTypeId: Fr, _publicKey: PublicKey, - _log: Fr[], - _counter: number, + _preimage: Fr[], ): Buffer { - throw new OracleMethodNotAvailableError('emitEncryptedLog'); + throw new OracleMethodNotAvailableError('computeEncryptedLog'); } emitUnencryptedLog(_log: UnencryptedL2Log, _counter: number): void { diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 9fec9c9f9a7..8c06e9b1b76 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -7,7 +7,6 @@ import { type NoteStatus, TaggedNote, type UnencryptedL2Log, - encryptBuffer, } from '@aztec/circuit-types'; import { CallContext, @@ -19,18 +18,11 @@ import { type TxContext, } from '@aztec/circuits.js'; import { Aes128 } from '@aztec/circuits.js/barretenberg'; -import { - computeInnerNoteHash, - computeNoteContentHash, - computePublicDataTreeLeafSlot, - computeUniqueNoteHash, - siloNoteHash, -} from '@aztec/circuits.js/hash'; +import { computePublicDataTreeLeafSlot, computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash'; import { type FunctionAbi, type FunctionArtifact, countArgumentsSize } from '@aztec/foundation/abi'; -import { type AztecAddress } from '@aztec/foundation/aztec-address'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, GrumpkinScalar, type Point } from '@aztec/foundation/fields'; import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log'; -import { serializeToBuffer } from '@aztec/foundation/serialize'; import { type NoteData, toACVMWitness } from '../acvm/index.js'; import { type PackedValuesCache } from '../common/packed_values_cache.js'; @@ -362,44 +354,53 @@ export class ClientExecutionContext extends ViewDataOracle { } /** - * Encrypt a note and emit it as a log. + * Emit encrypted data + * @param encryptedNote - The encrypted data. + * @param counter - The effects counter. + */ + public override emitEncryptedLog(encryptedData: Buffer, counter: number) { + const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedData), counter); + this.encryptedLogs.push(encryptedLog); + } + + /** + * Emit encrypted note data + * @param noteHash - The note hash. + * @param encryptedNote - The encrypted note data. + * @param counter - The effects counter. + */ + public override emitEncryptedNoteLog(noteHash: Fr, encryptedNote: Buffer, counter: number) { + const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedNote), counter); + this.noteEncryptedLogs.push(encryptedLog); + this.noteCache.addNewLog(encryptedLog, noteHash); + } + + /** + * Encrypt a note * @param contractAddress - The contract address of the note. * @param storageSlot - The storage slot the note is at. * @param noteTypeId - The type ID of the note. - * @param publicKey - The public key of the account that can decrypt the log. - * @param log - The log contents. + * @param ivpk - The master incoming viewing public key. + * @param preimage - The note preimage. */ - public override emitEncryptedLog( + public override computeEncryptedLog( contractAddress: AztecAddress, storageSlot: Fr, noteTypeId: Fr, - publicKey: Point, - log: Fr[], - counter: number, + ivpk: Point, + preimage: Fr[], ) { - // TODO(Miranda): This is a temporary solution until we encrypt logs in the circuit - // Then we require a new oracle that deals only with notes - const note = new Note(log); - const innerNoteHash = computeInnerNoteHash(storageSlot, computeNoteContentHash(log)); - const noteExists = this.noteCache.checkNoteExists(contractAddress, innerNoteHash); - if (noteExists) { - // Log linked to note - const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId); - const taggedNote = new TaggedNote(l1NotePayload); - const encryptedNote = taggedNote.toEncryptedBuffer(publicKey); - const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedNote), counter); - this.noteEncryptedLogs.push(encryptedLog); - this.noteCache.addNewLog(encryptedLog, innerNoteHash); - return encryptedNote; - } else { - // Generic non-note log - // We assume only the log and address are required - const preimage = Buffer.concat([contractAddress.toBuffer(), serializeToBuffer(log)]); - const encryptedMsg = encryptBuffer(preimage, GrumpkinScalar.random(), publicKey); - const encryptedLog = new EncryptedL2Log(encryptedMsg); - this.encryptedLogs.push(new CountedLog(encryptedLog, counter)); - return encryptedMsg; - } + const note = new Note(preimage); + const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId); + const taggedNote = new TaggedNote(l1NotePayload); + + const ephSk = GrumpkinScalar.random(); + + // @todo Issue(#6410) Right now we are completely ignoring the outgoing log. Just drawing random data. + const ovsk = GrumpkinScalar.random(); + const recipient = AztecAddress.random(); + + return taggedNote.encrypt(ephSk, recipient, ivpk, ovsk); } /** From 22ad5a5728afce5dcf32c8e6d8025691081e0de1 Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Mon, 20 May 2024 12:29:28 +0200 Subject: [PATCH 19/37] feat: View functions with static context enforcing (#6338) Closes https://github.com/AztecProtocol/aztec-packages/issues/6078 Introduces the `#[aztec(view)]` (open to different naming, @spalladino @rahul-kothari ) modifier to functions, that forces them to be executed in an static context. It also forces generation of a "static only" `CallInterface` for them, trying to spare users from making regular calls to them. ~~Need input from the AVM team (@dbanks12 @fcarreiro) on how to implement the concept in the AVMContext.~~ In order to support direct simulated calls to view functions, the simulate method has been modified to go through the account entrypoint, which has led to implementing retrieval of return values through the whole callstack instead of just taking the latest one. Also adds the ability to navigate from contract interfaces to their implementations via LSP! --------- Co-authored-by: dbanks12 --- .../barretenberg/vm/avm_trace/avm_opcode.hpp | 2 + .../vm/avm_trace/aztec_constants.hpp | 2 +- docs/docs/migration_notes.md | 48 ++- .../img/sandbox_unconstrained_function.svg | 2 +- .../src/core/libraries/ConstantsGen.sol | 2 +- .../aztec-nr/authwit/src/entrypoint/app.nr | 8 +- .../aztec-nr/authwit/src/entrypoint/fee.nr | 12 +- .../authwit/src/entrypoint/function_call.nr | 12 +- noir-projects/aztec-nr/aztec/src/context.nr | 10 +- .../aztec/src/context/call_interfaces.nr | 407 ++++++++++++++++++ .../src/context/inputs/avm_context_inputs.nr | 2 + .../aztec-nr/aztec/src/context/interface.nr | 283 +----------- .../aztec/src/context/private_context.nr | 2 +- noir-projects/noir-contracts/Nargo.toml | 2 + .../src/dapp_payload.nr | 14 +- .../app_subscription_contract/src/main.nr | 8 +- .../src/main.nr | 4 +- .../contracts/avm_test_contract/src/main.nr | 2 +- .../crowdfunding_contract/src/main.nr | 3 +- .../docs_example_contract/src/main.nr | 6 +- .../contracts/lending_contract/src/main.nr | 4 +- .../contracts/price_feed_contract/src/main.nr | 1 + .../static_child_contract/Nargo.toml | 9 + .../static_child_contract/src/main.nr | 142 ++++++ .../static_parent_contract/Nargo.toml | 9 + .../static_parent_contract/src/main.nr | 196 +++++++++ .../contracts/uniswap_contract/src/main.nr | 15 +- .../crates/types/src/abis/function_data.nr | 10 +- .../types/src/abis/private_call_stack_item.nr | 2 +- .../types/src/abis/public_call_stack_item.nr | 8 +- .../crates/types/src/constants.nr | 2 +- .../src/tests/fixtures/contract_functions.nr | 2 + .../types/src/transaction/tx_request.nr | 4 +- noir/noir-repo/aztec_macros/src/lib.rs | 11 +- .../src/transforms/contract_interface.rs | 47 +- .../aztec_macros/src/transforms/functions.rs | 33 ++ .../aztec_macros/src/utils/ast_utils.rs | 13 +- .../aztec.js/src/contract/contract.test.ts | 13 +- .../contract/contract_function_interaction.ts | 47 +- .../default_multi_call_entrypoint.ts | 2 + .../aztec.js/src/entrypoint/payload.ts | 4 + .../src/fee/native_fee_payment_method.ts | 6 +- .../src/fee/private_fee_payment_method.ts | 9 +- .../src/fee/public_fee_payment_method.ts | 6 +- .../aztec.js/src/wallet/account_wallet.ts | 3 + .../aztec.js/src/wallet/base_wallet.ts | 9 +- .../circuit-types/src/interfaces/pxe.ts | 4 +- yarn-project/circuit-types/src/mocks.ts | 4 +- .../src/tx/public_simulation_output.ts | 31 +- .../circuit-types/src/tx/simulated_tx.ts | 12 +- yarn-project/circuits.js/src/constants.gen.ts | 2 +- .../src/contract/contract_address.test.ts | 1 + .../__snapshots__/function_data.test.ts.snap | 2 +- .../private_call_stack_item.test.ts.snap | 4 +- .../public_call_stack_item.test.ts.snap | 8 +- .../__snapshots__/tx_request.test.ts.snap | 2 +- .../src/structs/function_data.test.ts | 2 +- .../circuits.js/src/structs/function_data.ts | 20 +- .../structs/public_call_stack_item.test.ts | 4 +- .../src/structs/tx_request.test.ts | 2 +- .../circuits.js/src/tests/factories.ts | 8 +- .../end-to-end/src/e2e_fees/failures.test.ts | 15 +- .../end-to-end/src/e2e_static_calls.test.ts | 180 +++++++- .../end-to-end/src/fixtures/fixtures.ts | 3 + .../entrypoints/src/account_entrypoint.ts | 3 + .../entrypoints/src/dapp_entrypoint.ts | 2 + yarn-project/foundation/src/abi/abi.ts | 4 + .../foundation/src/abi/encoder.test.ts | 8 + .../src/type_conversion.test.ts | 2 +- .../src/type_conversion.ts | 7 +- .../pxe/src/pxe_service/pxe_service.ts | 6 +- .../src/pxe_service/test/pxe_test_suite.ts | 2 +- .../src/avm/avm_execution_environment.ts | 14 +- .../src/client/client_execution_context.ts | 4 +- .../simulator/src/client/simulator.ts | 2 +- .../client/unconstrained_execution.test.ts | 2 +- yarn-project/simulator/src/common/index.ts | 1 + .../simulator/src/common/return_values.ts | 18 + yarn-project/simulator/src/mocks/fixtures.ts | 2 +- .../src/public/abstract_phase_manager.ts | 27 +- .../simulator/src/public/index.test.ts | 6 +- .../src/public/public_execution_context.ts | 2 +- .../simulator/src/public/public_processor.ts | 14 +- .../src/public/setup_phase_manager.ts | 2 +- .../src/public/tail_phase_manager.ts | 2 +- .../src/public/teardown_phase_manager.ts | 2 +- .../src/public/transitional_adaptors.ts | 6 +- .../types/src/abi/contract_artifact.ts | 3 + yarn-project/types/src/noir/index.ts | 1 + 89 files changed, 1391 insertions(+), 493 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr create mode 100644 noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml create mode 100644 noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr create mode 100644 noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml create mode 100644 noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr create mode 100644 yarn-project/simulator/src/common/return_values.ts diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp index fd655a026f3..892ec941bd3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp @@ -98,6 +98,8 @@ enum class OpCode : uint8_t { // Gadgets KECCAK, POSEIDON2, + SHA256, + PEDERSEN, // Conversions TORADIXLE, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp index caa72df3834..f5e8bf5a97e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp @@ -83,7 +83,7 @@ const size_t CONTRACT_INSTANCE_LENGTH = 5; const size_t CONTRACT_STORAGE_READ_LENGTH = 2; const size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; const size_t ETH_ADDRESS_LENGTH = 1; -const size_t FUNCTION_DATA_LENGTH = 2; +const size_t FUNCTION_DATA_LENGTH = 3; const size_t FUNCTION_LEAF_PREIMAGE_LENGTH = 5; const size_t GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; const size_t APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 209e5a0e066..f607abad860 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -6,20 +6,56 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. +## 0.X.X + +### [Aztec.nr] View functions and interface navigation + +It is now possible to explicitly state a function doesn't perform any state alterations (including storage, logs, nullifiers and/or messages from L2 to L1) with the `#[aztec(view)]` attribute, similarly to solidity's `view` function modifier. + +```diff + #[aztec(public)] ++ #[aztec(view)] + fn get_price(asset_id: Field) -> Asset { + storage.assets.at(asset_id).read() + } +``` + +View functions only generate a `StaticCallInterface` that doesn't include `.call` or `.enqueue` methods. Also, the denomination `static` has been completely removed from the interfaces, in favor of the more familiar `view` + +```diff ++ let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; +- let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; +``` + +```diff +#[aztec(private)] +fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { ++ StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); +- StaticChild::at(target_contract).pub_get_value(value).static_enqueue(&mut context); +} +``` + +Additionally, the Noir LSP will now honor "go to definitions" requests for contract interfaces (Ctrl+click), taking the user to the original function implementation. + +### [Aztec.js] Simulate changes + +* `.simulate()` now tracks closer the process performed by `.send().wait()`, specifically going through the account contract entrypoint instead of directly calling the intended function. +* `wallet.viewTx(...)` has been renamed to `wallet.simulateUnconstrained(...)` to better clarify what it does. + ## 0.41.0 ### [Aztec.nr] Keys: Token note now stores an owner master nullifying public key hash instead of an owner address i.e. -struct TokenNote \{ +```diff +struct TokenNote { amount: U128, - ```diff - - owner: AztecAddress, - + npk_m_hash: Field, - ``` +- owner: AztecAddress, ++ npk_m_hash: Field, randomness: Field, -\} +} +``` Computing the nullifier similarly changes to use this master nullifying public key hash. diff --git a/docs/static/img/sandbox_unconstrained_function.svg b/docs/static/img/sandbox_unconstrained_function.svg index 8b42518887d..948a9ac042e 100644 --- a/docs/static/img/sandbox_unconstrained_function.svg +++ b/docs/static/img/sandbox_unconstrained_function.svg @@ -1307,7 +1307,7 @@ id="path53" d="M 2.8498858,-9.2967961e-4 -0.00199662,-7.4962595 H 1.2202387 l 1.5983078,4.4532922 c 0.3760724,1.0506006 0.5954479,1.7170264 0.6581267,2.0071176 h 0.062679 c 0.039174,-0.2273688 0.1958711,-0.7213079 0.4700905,-1.473977 0.2663846,-0.7683497 0.8618326,-2.430494 1.786344,-4.9864328 h 1.222235 L 4.1661393,-9.2967961e-4 Z m 6.5107536,0 H 8.2010828 V -7.4962595 H 9.3606394 Z M 8.1070647,-9.5033771 c 0,-0.2665703 0.062679,-0.4547376 0.1880362,-0.5645019 0.1410272,-0.125445 0.3133937,-0.188167 0.5014299,-0.188167 0.1645317,0 0.3133937,0.06272 0.4387512,0.188167 0.1410271,0.1097643 0.2193755,0.2979316 0.2193755,0.5645019 0,0.2508897 -0.078348,0.439057 -0.2193755,0.5645018 -0.1253575,0.1254449 -0.2742195,0.1881673 -0.4387512,0.1881673 -0.1880362,0 -0.3604027,-0.062722 -0.5014299,-0.1881673 C 8.1697435,-9.0643201 8.1070647,-9.2524874 8.1070647,-9.5033771 Z m 6.8006423,9.62789227 c -1.112547,0 -1.990049,-0.32929273 -2.632506,-1.0035588 C 11.648413,-1.5454694 11.33502,-2.4784655 11.33502,-3.6701916 c 0,-1.2074067 0.289889,-2.1717639 0.877502,-2.8852315 0.603283,-0.7056273 1.410271,-1.0662813 2.413131,-1.0662813 0.940181,0 1.676656,0.3136122 2.225095,0.9408364 0.540604,0.6115437 0.814824,1.4112546 0.814824,2.4148134 v 0.7213079 h -5.139656 c 0.01567,0.8781139 0.235045,1.55238 0.658126,2.0071176 0.415247,0.4625779 1.010695,0.68994668 1.786344,0.68994668 0.791319,0 1.582638,-0.16464638 2.381792,-0.50177938 v 1.00355878 C 16.952601,-0.17341635 16.576529,-0.0636521 16.223961,-9.2967961e-4 15.863558,0.07747335 15.424807,0.12451517 14.907707,0.12451517 Z M 14.625653,-6.680868 c -0.611117,0 -1.089043,0.2038479 -1.441611,0.5958631 -0.360402,0.3998554 -0.564108,0.9408363 -0.626787,1.630783 h 3.917421 c 0,-0.7056273 -0.172367,-1.2544485 -0.50143,-1.630783 C 15.659852,-6.4770201 15.205431,-6.680868 14.625653,-6.680868 Z M 25.743294,-9.2967961e-4 24.364362,-4.3914995 c -0.08618,-0.2665703 -0.250715,-0.8781139 -0.50143,-1.8189503 h -0.03134 c -0.188036,0.7997109 -0.360402,1.4034143 -0.501429,1.8189503 L 21.919891,-9.2967961e-4 H 20.603638 L 18.566579,-7.4962595 h 1.190896 c 0.477925,1.8816728 0.846163,3.3164482 1.096877,4.2964861 0.250715,0.9878782 0.391743,1.654304 0.438752,2.0071176 h 0.06268 c 0.03918,-0.2665703 0.109688,-0.6037033 0.219376,-1.0035588 0.125357,-0.415536 0.22721,-0.7526691 0.313394,-1.0035588 l 1.378932,-4.2964861 h 1.222235 l 1.347593,4.2964861 c 0.250715,0.799711 0.415247,1.4582964 0.50143,1.9757564 h 0.06268 c 0.01567,-0.1646463 0.07051,-0.415536 0.156696,-0.7526691 0.07835,-0.3292927 0.548439,-2.171764 1.410272,-5.5195734 h 1.190896 L 27.09089,-9.2967961e-4 Z m 8.007208,0 H 32.590946 V -8.9702365 h -3.165277 v -1.0035588 h 7.490109 v 1.0035588 H 33.750502 Z M 40.049715,-3.8269976 37.448548,-7.4962595 h 1.284914 l 1.97438,2.8852316 1.97438,-2.8852316 h 1.284914 l -2.601167,3.6692619 2.726525,3.82606792039 H 42.807579 L 40.707842,-3.0429673 38.608104,-9.2967961e-4 H 37.32319 Z m 4.896776,0 c 0,-1.2074067 0.172367,-2.3364104 0.53277,-3.387011 0.352567,-1.0427603 0.861832,-1.9600758 1.535629,-2.7597867 h 1.096877 c -0.650291,0.8781139 -1.143887,1.8424712 -1.47295,2.8852316 -0.336898,1.0506006 -0.50143,2.1247221 -0.50143,3.2302049 0,1.113323 0.164532,2.1874445 0.50143,3.23020487 0.329063,1.01923941 0.822659,1.97575643 1.47295,2.85387033 H 47.01489 C 46.341093,1.4495264 45.831828,0.54789154 45.479261,-0.47134787 45.118858,-1.5141082 44.946491,-2.6352715 44.946491,-3.8269976 Z m 4.606887,3.10476003 c 0,-0.31361213 0.06268,-0.54098093 0.188037,-0.68994673 0.141027,-0.1646463 0.352567,-0.2508897 0.626787,-0.2508897 0.266384,0 0.477925,0.086243 0.626787,0.2508897 0.141027,0.1489658 0.219376,0.3763346 0.219376,0.68994673 0,0.29793152 -0.08618,0.52530031 -0.250715,0.68994668 -0.148862,0.14112545 -0.344733,0.21952849 -0.595448,0.21952849 -0.235045,0 -0.430916,-0.0627224 -0.595448,-0.18816727961 C 49.623892,-0.14205514 49.553378,-0.38510453 49.553378,-0.72223757 Z m 3.729385,0 c 0,-0.31361213 0.06268,-0.54098093 0.188036,-0.68994673 0.141027,-0.1646463 0.352568,-0.2508897 0.626788,-0.2508897 0.266384,0 0.477925,0.086243 0.626787,0.2508897 0.141027,0.1489658 0.219376,0.3763346 0.219376,0.68994673 0,0.29793152 -0.08618,0.52530031 -0.250715,0.68994668 -0.148862,0.14112545 -0.344733,0.21952849 -0.595448,0.21952849 -0.235046,0 -0.430917,-0.0627224 -0.595448,-0.18816727961 C 53.353277,-0.14205514 53.282763,-0.38510453 53.282763,-0.72223757 Z m 3.72155,0 c 0,-0.31361213 0.06268,-0.54098093 0.188036,-0.68994673 0.141027,-0.1646463 0.352568,-0.2508897 0.626787,-0.2508897 0.266385,0 0.477926,0.086243 0.626788,0.2508897 0.141027,0.1489658 0.219375,0.3763346 0.219375,0.68994673 0,0.29793152 -0.08618,0.52530031 -0.250715,0.68994668 -0.148862,0.14112545 -0.344733,0.21952849 -0.595448,0.21952849 -0.235045,0 -0.430916,-0.0627224 -0.595447,-0.18816727961 C 57.074827,-0.14205514 57.004313,-0.38510453 57.004313,-0.72223757 Z m 6.267873,-3.10476003 c 0,1.1917261 -0.180201,2.3128894 -0.532769,3.35564973 C 62.402519,0.54789154 61.901089,1.4495264 61.235128,2.2257164 H 60.13825 c 0.626787,-0.8624333 1.104712,-1.81111001 1.441611,-2.85387033 0.329063,-1.04276037 0.501429,-2.11688187 0.501429,-3.23020487 0,-1.1054828 -0.172366,-2.1796043 -0.501429,-3.2302049 -0.313394,-1.0427604 -0.806989,-2.0071177 -1.472951,-2.8852316 h 1.128218 c 0.665961,0.7997109 1.167391,1.7248667 1.504289,2.7911479 0.352568,1.0506006 0.532769,2.1639237 0.532769,3.3556498 z m 6.557763,3.82606792039 H 68.670392 V -7.4962595 h 1.159557 z M 68.576374,-9.5033771 c 0,-0.2665703 0.06268,-0.4547376 0.188037,-0.5645019 0.141027,-0.125445 0.313393,-0.188167 0.501429,-0.188167 0.164532,0 0.313394,0.06272 0.438752,0.188167 0.141027,0.1097643 0.219375,0.2979316 0.219375,0.5645019 0,0.2508897 -0.07835,0.439057 -0.219375,0.5645018 -0.125358,0.1254449 -0.27422,0.1881673 -0.438752,0.1881673 -0.188036,0 -0.360402,-0.062722 -0.501429,-0.1881673 -0.125358,-0.1254448 -0.188037,-0.3136121 -0.188037,-0.5645018 z m 8.492969,7.4639686 c 0,0.6899467 -0.266385,1.22308729 -0.783484,1.59942184 -0.524935,0.37633456 -1.253575,0.56450183 -2.193756,0.56450183 -1.00286,0 -1.778509,-0.15680606 -2.319113,-0.47041819 V -1.380823 c 0.352568,0.1881672 0.736475,0.337133 1.159556,0.43905694 0.415247,0.10976424 0.814824,0.15680606 1.190896,0.15680606 0.579779,0 1.0342,-0.0940836 1.347593,-0.2822509 0.329064,-0.2038479 0.50143,-0.5017794 0.50143,-0.878114 0,-0.2900912 -0.125357,-0.5409809 -0.376072,-0.7526691 -0.250715,-0.2038479 -0.752145,-0.4468973 -1.50429,-0.7213079 -0.689466,-0.2665703 -1.183061,-0.5017794 -1.47295,-0.6899466 -0.297724,-0.1881673 -0.5171,-0.4076958 -0.658127,-0.6585855 -0.148862,-0.2508897 -0.219375,-0.5409809 -0.219375,-0.878114 0,-0.6037033 0.250714,-1.0819618 0.752144,-1.4426157 0.50143,-0.3528137 1.175227,-0.5331407 2.037059,-0.5331407 0.814824,0 1.606143,0.1724867 2.381792,0.5017794 l -0.407412,0.9094752 C 75.75309,-6.5240619 75.071458,-6.680868 74.468175,-6.680868 c -0.548438,0 -0.95585,0.086243 -1.222235,0.2508897 -0.274219,0.1724867 -0.407412,0.4076958 -0.407412,0.7213079 0,0.1881673 0.03918,0.360654 0.125358,0.5017794 0.101853,0.1489658 0.266384,0.2822509 0.50143,0.4076958 0.22721,0.1254448 0.665961,0.3057718 1.316253,0.5331406 0.893172,0.337133 1.50429,0.6742661 1.817683,1.0035588 0.313394,0.3136121 0.470091,0.7213079 0.470091,1.2230873 z m 8.461629,2.16392367 c -1.089043,0 -1.935206,-0.32145243 -2.538489,-0.97219759 -0.587613,-0.66642578 -0.877502,-1.61510248 -0.877502,-2.85387038 0,-1.2544485 0.297724,-2.2109655 0.908842,-2.8852315 0.603283,-0.6899467 1.45728,-1.0349201 2.569828,-1.0349201 0.376072,0 0.736475,0.047042 1.096878,0.1254449 0.352568,0.062722 0.634622,0.1489658 0.846163,0.2508897 l -0.344733,0.9721976 c -0.250715,-0.101924 -0.53277,-0.1881673 -0.846163,-0.2508897 -0.297724,-0.062722 -0.548439,-0.094084 -0.752145,-0.094084 -1.527794,0 -2.287774,0.9721976 -2.287774,2.9165928 0,0.9251558 0.172367,1.6307831 0.532769,2.1325625 0.376073,0.4860988 0.924512,0.72130788 1.660987,0.72130788 0.626787,0 1.261409,-0.13328516 1.911701,-0.40769578 v 1.00355882 c -0.50143,0.25088970039 -1.128217,0.37633455 -1.880362,0.37633485 z M 93.82807,-9.2967961e-4 93.577355,-1.0672109 h -0.03134 c -0.376072,0.46257788 -0.752144,0.77619 -1.128217,0.94083637 -0.376072,0.16464637 -0.846163,0.2508897 -1.410271,0.2508897 -0.736475,0 -1.308419,-0.18816727 -1.723666,-0.56450183 -0.423081,-0.37633455 -0.626787,-0.91731544 -0.626787,-1.63078304 0,-1.5053382 1.198731,-2.2972088 3.604027,-2.3834522 l 1.284914,-0.031361 v -0.4704182 c 0,-0.5801824 -0.125357,-1.0113991 -0.376072,-1.2858097 -0.250715,-0.2900912 -0.658127,-0.439057 -1.222235,-0.439057 -0.626788,0 -1.339758,0.2038479 -2.131077,0.5958631 l -0.344733,-0.878114 c 0.376072,-0.2038479 0.783484,-0.3606539 1.222235,-0.4704182 0.438751,-0.1254448 0.877502,-0.1881673 1.316253,-0.1881673 0.893172,0 1.551299,0.2038479 1.974381,0.5958631 0.438751,0.3998554 0.658126,1.03492 0.658126,1.913034 V -9.2967961e-4 Z M 91.258242,-0.78496 c 0.705135,0 1.261409,-0.19600758 1.660986,-0.595863 0.391742,-0.3920152 0.595448,-0.9408364 0.595448,-1.6307831 v -0.6585855 l -1.128217,0.031361 c -0.901007,0.047042 -1.559134,0.1881673 -1.97438,0.439057 -0.399577,0.2352091 -0.595448,0.6115437 -0.595448,1.1290037 0,0.4233764 0.125357,0.7448288 0.376072,0.9721976 0.250715,0.21168816 0.603283,0.3136121 1.065539,0.3136123 z m 6.878991,0.78403032039 H 96.977676 V -10.632381 h 1.159557 z m 3.541347,0 h -1.15956 V -10.632381 h 1.15956 z M 107.22565,0.12451517 c -1.11255,0 -1.99005,-0.32929273 -2.63251,-1.0035588 -0.62678,-0.66642577 -0.94018,-1.59942187 -0.94018,-2.79114797 0,-1.2074067 0.28989,-2.1717639 0.8775,-2.8852315 0.60329,-0.7056273 1.41028,-1.0662813 2.41314,-1.0662813 0.94018,0 1.67665,0.3136122 2.22509,0.9408364 0.5406,0.6115437 0.81482,1.4112546 0.81482,2.4148134 v 0.7213079 h -5.13965 c 0.0157,0.8781139 0.23504,1.55238 0.65812,2.0071176 0.41525,0.4625779 1.0107,0.68994668 1.78635,0.68994668 0.79132,0 1.58264,-0.16464638 2.38179,-0.50177938 v 1.00355878 c -0.39958,0.17248667 -0.77565,0.28225092 -1.12822,0.34497334039 C 108.1815,0.07747335 107.74275,0.12451517 107.22565,0.12451517 Z M 106.9436,-6.680868 c -0.61112,0 -1.08905,0.2038479 -1.44162,0.5958631 -0.3604,0.3998554 -0.5641,0.9408363 -0.62678,1.630783 h 3.91742 c 0,-0.7056273 -0.17237,-1.2544485 -0.50143,-1.630783 -0.3134,-0.3920152 -0.76782,-0.5958631 -1.34759,-0.5958631 z m 10.0756,5.6763795 h -0.0627 c -0.52493,0.75266912 -1.30842,1.12900367 -2.35045,1.12900367 -0.98719,0 -1.74717,-0.32929273 -2.28777,-1.0035588 -0.54844,-0.66642577 -0.81483,-1.61510247 -0.81483,-2.85387037 0,-1.2309276 0.26639,-2.1796043 0.81483,-2.8538703 0.5406,-0.6899467 1.30058,-1.0349201 2.28777,-1.0349201 1.01853,0 1.80201,0.3684943 2.35045,1.0976425 h 0.094 l -0.0627,-0.5331406 -0.0313,-0.5331406 v -3.0420379 h 1.15956 V -9.2967961e-4 h -0.94018 z m -2.25643,0.18816729 c 0.76781,0 1.32409,-0.20384789 1.66098,-0.62722429 0.35257,-0.415536 0.53277,-1.0976424 0.53277,-2.0384788 V -3.732914 c 0,-1.0427603 -0.1802,-1.7954294 -0.53277,-2.2580073 -0.3604,-0.4547376 -0.92451,-0.6899467 -1.69232,-0.6899467 -0.6738,0 -1.18306,0.2665703 -1.53563,0.7840303 -0.3369,0.5253003 -0.50143,1.2544485 -0.50143,2.1952849 0,0.9408364 0.16453,1.6621443 0.50143,2.1639237 0.35257,0.4860988 0.8775,0.72130789 1.56697,0.72130789 z m 15.84988,-2.94795399 c 0,1.2387679 -0.31339,2.1952849 -0.94018,2.88523157 -0.61112,0.67426607 -1.45728,1.0035588 -2.53849,1.0035588 -0.67379,0 -1.26924,-0.15680606 -1.78634,-0.47041819 -0.52494,-0.31361213 -0.93235,-0.76050938 -1.22224,-1.34853218 -0.27422,-0.5801824 -0.40741,-1.2701291 -0.40741,-2.06984 0,-1.2074067 0.29773,-2.1482431 0.90884,-2.8225091 0.62679,-0.6899467 1.48079,-1.0349201 2.56983,-1.0349201 1.04204,0 1.86469,0.360654 2.47581,1.0662813 0.62679,0.6899466 0.94018,1.6229427 0.94018,2.7911479 z m -5.70376,0 c 0,0.9643573 0.18803,1.6935055 0.56411,2.1952849 0.37607,0.5017794 0.94018,0.75266909 1.69232,0.75266909 0.72864,0 1.28492,-0.25088969 1.66099,-0.75266909 0.39174,-0.5017794 0.59545,-1.2309276 0.59545,-2.1952849 0,-0.9408364 -0.20371,-1.6464637 -0.59545,-2.1325625 -0.37607,-0.5017794 -0.94018,-0.7526691 -1.69233,-0.7526691 -0.73647,0 -1.28491,0.2430494 -1.66098,0.7213079 -0.37608,0.4860988 -0.56411,1.2074067 -0.56411,2.1639237 z m 12.8178,3.76334552039 V -4.8305564 c 0,-0.6272243 -0.14886,-1.0819619 -0.43875,-1.3798934 -0.27422,-0.2900912 -0.70514,-0.439057 -1.28492,-0.439057 -0.77565,0 -1.34759,0.2116882 -1.72366,0.6272243 -0.3604,0.4233764 -0.53277,1.1211633 -0.53277,2.1012012 v 3.92015162039 h -1.15956 V -7.4962595 h 0.94018 l 0.18804,1.03492 h 0.0627 c 0.22721,-0.3763345 0.54844,-0.6585855 0.97152,-0.8467527 0.41525,-0.2038479 0.8775,-0.3136122 1.37893,-0.3136122 0.91668,0 1.59831,0.2195285 2.03706,0.6585855 0.45442,0.439057 0.68947,1.1290037 0.68947,2.06984 V -9.2967961e-4 Z M 147.26169,-0.78496 c 0.18804,0 0.37607,-0.00784 0.56411,-0.0313612 0.18804,-0.0392015 0.32906,-0.078403 0.43875,-0.12544485 v 0.87811396 c -0.10969,0.0627224204 -0.28205,0.10192394 -0.53277,0.12544485 -0.23504,0.03920151 -0.45442,0.06272242 -0.65812,0.06272242 -1.44162,0 -2.16242,-0.76050941 -2.16242,-2.28936858 v -4.4532922 h -1.06554 v -0.5331406 l 1.06554,-0.4704182 0.47009,-1.5994218 h 0.65813 v 1.7248667 h 2.19375 v 0.8781139 h -2.19375 v 4.421931 c 0,0.439057 0.10185,0.7840303 0.31339,1.0349201 0.22721,0.25088966 0.53277,0.37633451 0.90884,0.3763345 z m 7.63114,0.78403032039 V -4.8305564 c 0,-0.6272243 -0.14886,-1.0819619 -0.43875,-1.3798934 -0.27422,-0.2900912 -0.70514,-0.439057 -1.28492,-0.439057 -0.79915,0 -1.3711,0.2195285 -1.72366,0.6585855 -0.36041,0.4233764 -0.53277,1.113323 -0.53277,2.06984 v 3.92015162039 h -1.15956 V -10.632381 h 1.15956 v 3.2302051 c 0,0.3763346 -0.0235,0.6899467 -0.0627,0.9408364 h 0.0627 c 0.22721,-0.3528136 0.5406,-0.6350645 0.94018,-0.8467527 0.41525,-0.2038479 0.89317,-0.3136122 1.44161,-0.3136122 0.89317,0 1.5748,0.2195285 2.03706,0.6585855 0.45442,0.439057 0.68946,1.1290037 0.68946,2.06984 V -9.2967961e-4 Z M 161.51327,0.12451517 c -1.11255,0 -1.99005,-0.32929273 -2.63251,-1.0035588 -0.62679,-0.66642577 -0.94018,-1.59942187 -0.94018,-2.79114797 0,-1.2074067 0.28989,-2.1717639 0.8775,-2.8852315 0.60329,-0.7056273 1.41027,-1.0662813 2.41313,-1.0662813 0.94019,0 1.67666,0.3136122 2.2251,0.9408364 0.5406,0.6115437 0.81482,1.4112546 0.81482,2.4148134 v 0.7213079 h -5.13965 c 0.0157,0.8781139 0.23504,1.55238 0.65812,2.0071176 0.41525,0.4625779 1.0107,0.68994668 1.78635,0.68994668 0.79132,0 1.58264,-0.16464638 2.38179,-0.50177938 v 1.00355878 c -0.39958,0.17248667 -0.77565,0.28225092 -1.12822,0.34497334039 C 162.46912,0.07747335 162.03037,0.12451517 161.51327,0.12451517 Z M 161.23121,-6.680868 c -0.61111,0 -1.08904,0.2038479 -1.44161,0.5958631 -0.3604,0.3998554 -0.5641,0.9408363 -0.62678,1.630783 h 3.91742 c 0,-0.7056273 -0.17237,-1.2544485 -0.50143,-1.630783 -0.3134,-0.3920152 -0.76782,-0.5958631 -1.3476,-0.5958631 z m 15.12908,-0.4076957 c 0,1.0270797 -0.34473,1.81111 -1.03419,2.3520909 -0.68947,0.5488212 -1.67666,0.8153915 -2.94591,0.8153915 h -1.19089 v 3.92015162039 h -1.15956 V -9.9737953 h 2.60117 c 2.48364,0 3.72938,0.9643573 3.72938,2.8852316 z m -5.17099,2.1639236 h 1.0342 c 1.04203,0 1.79418,-0.1646463 2.25643,-0.5017794 0.45442,-0.3292927 0.68947,-0.8624333 0.68947,-1.5994218 0,-0.6429049 -0.21938,-1.1290037 -0.65813,-1.4426158 -0.43875,-0.3292927 -1.12038,-0.5017794 -2.03706,-0.5017794 h -1.28491 z m 13.91468,4.92371042039 h -1.31626 L 181.09254,-4.3914995 178.36601,-9.2967961e-4 h -1.22223 L 180.46575,-5.206891 l -3.1026,-4.7669043 h 1.28492 l 2.47581,3.9515128 2.50715,-3.9515128 h 1.25357 l -3.1026,4.7041819 z m 7.01218,0 h -5.57841 V -9.9737953 h 5.57841 v 1.0035588 h -4.41885 v 3.2302049 h 4.1368 v 1.03492 h -4.1368 v 3.6692619 h 4.41885 z M 193.98085,-0.72223757 c 0,-0.31361213 0.0627,-0.54098093 0.18804,-0.68994673 0.14103,-0.1646463 0.35257,-0.2508897 0.62679,-0.2508897 0.26638,0 0.47792,0.086243 0.62678,0.2508897 0.14103,0.1489658 0.21938,0.3763346 0.21938,0.68994673 0,0.29793152 -0.0862,0.52530031 -0.25071,0.68994668 -0.14887,0.14112545 -0.34474,0.21952849 -0.59545,0.21952849 -0.23505,0 -0.43092,-0.0627224 -0.59545,-0.18816727961 C 194.05137,-0.14205514 193.98085,-0.38510453 193.98085,-0.72223757 Z m 0,0" style="fill:#f24726;fill-opacity:1;fill-rule:nonzero;stroke:none" - aria-label=" viewTx(...) is called on the PXE." + aria-label=" simulateUnconstrained(...) is called on the PXE." transform="matrix(0.4985742,0,0,0.49822691,416.05959,194.41453)" clip-path="url(#clipPath54)" /> for FunctionCall { fn serialize(self) -> [Field; FUNCTION_CALL_SIZE] { - [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field] + [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field, self.is_static as Field] } } @@ -34,6 +35,7 @@ impl FunctionCall { bytes[i + 64] = target_address_bytes[i]; } bytes[96] = self.is_public as u8; + bytes[97] = self.is_static as u8; bytes } } diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index c7d79f2e24b..70992b0cea7 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -5,11 +5,15 @@ mod private_context; mod public_context; mod avm_context; mod interface; +mod call_interfaces; mod gas; -use interface::{ - ContextInterface, PrivateCallInterface, PublicCallInterface, PrivateVoidCallInterface, - PublicVoidCallInterface, AvmCallInterface, AvmVoidCallInterface +use interface::ContextInterface; +use call_interfaces::{ + PrivateCallInterface, PrivateStaticCallInterface, PublicCallInterface, PublicStaticCallInterface, + PrivateVoidCallInterface, PrivateStaticVoidCallInterface, PublicVoidCallInterface, + PublicStaticVoidCallInterface, AvmCallInterface, AvmStaticCallInterface, AvmVoidCallInterface, + AvmStaticVoidCallInterface }; use private_context::PrivateContext; use private_context::PackedReturns; diff --git a/noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr b/noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr new file mode 100644 index 00000000000..a04465f60bf --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr @@ -0,0 +1,407 @@ +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, traits::Deserialize}; + +use crate::context::private_context::PrivateContext; +use crate::context::public_context::PublicContext; +use crate::context::avm_context::AvmContext; +use crate::context::gas::GasOpts; +use crate::context::public_context::FunctionReturns; + +use crate::hash::hash_args; +use crate::oracle::arguments; + +struct PrivateCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateCallInterface { + pub fn call(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ); + let unpacked: T = returns.unpack_into(); + unpacked + } + + pub fn view(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.unpack_into() + } + + pub fn delegate_call(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); + returns.unpack_into() + } +} + +struct PrivateVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateVoidCallInterface { + pub fn call(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ).assert_empty(); + } + + pub fn view(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } + + pub fn delegate_call(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); + } +} + +struct PrivateStaticCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateStaticCallInterface { + pub fn view(self, context: &mut PrivateContext) -> T where T: Deserialize { + let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.unpack_into() + } +} + +struct PrivateStaticVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PrivateStaticVoidCallInterface { + pub fn view(self, context: &mut PrivateContext) { + context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } +} + +struct PublicCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PublicCallInterface { + pub fn call(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ); + returns.deserialize_into() + } + + pub fn view(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.deserialize_into() + } + + pub fn delegate_call(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); + returns.deserialize_into() + } + + pub fn enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) + } +} + +struct PublicVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field +} + +impl PublicVoidCallInterface { + pub fn call(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ).assert_empty() + } + + pub fn view(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } + + pub fn delegate_call(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); + } + + pub fn enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + self.args_hash, + false, + false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) + } +} + +struct PublicStaticCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field, +} + +impl PublicStaticCallInterface { + pub fn view(self, context: &mut PublicContext) -> T where T: Deserialize { + let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); + returns.deserialize_into() + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } +} + +struct PublicStaticVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args_hash: Field +} + +impl PublicStaticVoidCallInterface { + pub fn view(self, context: &mut PublicContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) + } +} + +struct AvmCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn call(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.deserialize_into() + } + + pub fn view(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.deserialize_into() + } + + pub fn delegate_call(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); + returns.deserialize_into() + } + + pub fn enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ true + ) + } +} + +struct AvmVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmVoidCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn call(self, context: &mut AvmContext) { + let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.assert_empty() + } + + pub fn view(self, context: &mut AvmContext) { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.assert_empty() + } + + pub fn delegate_call(self, context: &mut AvmContext) { + let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); + returns.assert_empty() + } + + pub fn enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ false + ) + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } + + pub fn delegate_enqueue(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ true + ) + } +} + +struct AvmStaticCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmStaticCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn view(self, context: &mut AvmContext) -> T where T: Deserialize { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.deserialize_into() + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } +} + +struct AvmStaticVoidCallInterface { + target_contract: AztecAddress, + selector: FunctionSelector, + args: [Field], + gas_opts: GasOpts, +} + +impl AvmStaticVoidCallInterface { + pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { + self.gas_opts = gas_opts; + self + } + + pub fn view(self, context: &mut AvmContext) { + let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); + returns.assert_empty() + } + + pub fn enqueue_view(self, context: &mut PrivateContext) { + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) + } +} diff --git a/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr b/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr index 0000b903f6d..7361af69643 100644 --- a/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr +++ b/noir-projects/aztec-nr/aztec/src/context/inputs/avm_context_inputs.nr @@ -3,6 +3,7 @@ use dep::protocol_types::traits::Empty; struct AvmContextInputs { selector: Field, args_hash: Field, + is_static_call: bool } impl Empty for AvmContextInputs { @@ -10,6 +11,7 @@ impl Empty for AvmContextInputs { AvmContextInputs { selector: 0, args_hash: 0, + is_static_call: false } } } diff --git a/noir-projects/aztec-nr/aztec/src/context/interface.nr b/noir-projects/aztec-nr/aztec/src/context/interface.nr index 0ceb66a05a8..37bf13318d0 100644 --- a/noir-projects/aztec-nr/aztec/src/context/interface.nr +++ b/noir-projects/aztec-nr/aztec/src/context/interface.nr @@ -1,9 +1,5 @@ -use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, traits::Deserialize}; +use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; -use crate::oracle::arguments; -use crate::context::private_context::PrivateContext; -use crate::context::public_context::PublicContext; -use crate::context::avm_context::AvmContext; use crate::context::gas::GasOpts; use crate::context::public_context::FunctionReturns; @@ -54,280 +50,3 @@ trait PublicContextInterface { ) -> FunctionReturns; fn nullifier_exists(self, unsiloed_nullifier: Field, address: AztecAddress) -> bool; } - -struct PrivateCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field, -} - -impl PrivateCallInterface { - pub fn call(self, context: &mut PrivateContext) -> T where T: Deserialize { - let returns = context.call_private_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ); - let unpacked: T = returns.unpack_into(); - unpacked - } - - pub fn static_call(self, context: &mut PrivateContext) -> T where T: Deserialize { - let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); - returns.unpack_into() - } - - pub fn delegate_call(self, context: &mut PrivateContext) -> T where T: Deserialize { - let returns = context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); - returns.unpack_into() - } -} - -struct PrivateVoidCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field, -} - -impl PrivateVoidCallInterface { - pub fn call(self, context: &mut PrivateContext) { - context.call_private_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ).assert_empty(); - } - - pub fn static_call(self, context: &mut PrivateContext) { - context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); - } - - pub fn delegate_call(self, context: &mut PrivateContext) { - context.call_private_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); - } -} - -struct PublicCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field, -} - -impl PublicCallInterface { - pub fn call(self, context: &mut PublicContext) -> T where T: Deserialize { - let returns = context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ); - returns.deserialize_into() - } - - pub fn static_call(self, context: &mut PublicContext) -> T where T: Deserialize { - let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false); - returns.deserialize_into() - } - - pub fn delegate_call(self, context: &mut PublicContext) -> T where T: Deserialize { - let returns = context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true); - returns.deserialize_into() - } - - pub fn enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) - } -} - -struct PublicVoidCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args_hash: Field -} - -impl PublicVoidCallInterface { - pub fn call(self, context: &mut PublicContext) { - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ).assert_empty() - } - - pub fn static_call(self, context: &mut PublicContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false).assert_empty(); - } - - pub fn delegate_call(self, context: &mut PublicContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true).assert_empty(); - } - - pub fn enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - self.args_hash, - false, - false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, true, false) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - context.call_public_function_with_packed_args(self.target_contract, self.selector, self.args_hash, false, true) - } -} - -struct AvmCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args: [Field], - gas_opts: GasOpts, -} - -impl AvmCallInterface { - pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { - self.gas_opts = gas_opts; - self - } - - pub fn call(self, context: &mut AvmContext) -> T where T: Deserialize { - let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.deserialize_into() - } - - pub fn static_call(self, context: &mut AvmContext) -> T where T: Deserialize { - let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.deserialize_into() - } - - pub fn delegate_call(self, context: &mut AvmContext) -> T where T: Deserialize { - let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); - returns.deserialize_into() - } - - pub fn enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ true, - /*delegate=*/ false - ) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ true - ) - } -} - -struct AvmVoidCallInterface { - target_contract: AztecAddress, - selector: FunctionSelector, - args: [Field], - gas_opts: GasOpts, -} - -impl AvmVoidCallInterface { - pub fn with_gas(self: &mut Self, gas_opts: GasOpts) -> &mut Self { - self.gas_opts = gas_opts; - self - } - - pub fn call(self, context: &mut AvmContext) { - let returns = context.call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.assert_empty() - } - - pub fn static_call(self, context: &mut AvmContext) { - let returns = context.static_call_public_function(self.target_contract, self.selector, self.args, self.gas_opts); - returns.assert_empty() - } - - pub fn delegate_call(self, context: &mut AvmContext) { - let returns = context.delegate_call_public_function(self.target_contract, self.selector, self.args); - returns.assert_empty() - } - - pub fn enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ false - ) - } - - pub fn static_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ true, - /*delegate=*/ false - ) - } - - pub fn delegate_enqueue(self, context: &mut PrivateContext) { - // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. - let args_hash = arguments::pack_arguments(self.args); - context.call_public_function_with_packed_args( - self.target_contract, - self.selector, - args_hash, - /*static=*/ false, - /*delegate=*/ true - ) - } -} diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 9722d8aecbf..645ea474ad2 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -440,7 +440,7 @@ impl PrivateContext { assert(args_hash == item.public_inputs.args_hash); - // Assert that the call context of the enqueued call generated by the oracle matches our request. + // Assert that the call context of the call generated by the oracle matches our request. assert(item.public_inputs.call_context.is_delegate_call == is_delegate_call); assert(item.public_inputs.call_context.is_static_call == is_static_call); diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 38a37c0083b..12fbe295874 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -41,4 +41,6 @@ members = [ "contracts/uniswap_contract", "contracts/reader_contract", "contracts/multi_call_entrypoint_contract", + "contracts/static_child_contract", + "contracts/static_parent_contract" ] diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr index 8d6e9711a4d..4b0d7e4af7b 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr @@ -3,12 +3,11 @@ use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, use dep::authwit::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; +global DAPP_MAX_CALLS: u64 = 1; // FUNCTION_CALL_SIZE * DAPP_MAX_CALLS + 1 -global DAPP_PAYLOAD_SIZE: u64 = 5; +global DAPP_PAYLOAD_SIZE: u64 = 6; // FUNCTION_CALL_SIZE_IN_BYTES * DAPP_MAX_CALLS + 32 -global DAPP_PAYLOAD_SIZE_IN_BYTES: u64 = 129; - -global DAPP_MAX_CALLS: u64 = 1; +global DAPP_PAYLOAD_SIZE_IN_BYTES: u64 = 130; // Note: If you change the following struct you have to update default_entrypoint.ts // docs:start:app-payload-struct @@ -55,7 +54,8 @@ impl DAppPayload { // Executes all private and public calls // docs:start:entrypoint-execute-calls fn execute_calls(self, context: &mut PrivateContext, target_address: AztecAddress) { - for call in self.function_calls { + for i in 0..DAPP_MAX_CALLS { + let call = self.function_calls[i]; // whitelist the calls that the user can do only go to the expected Dapp contract assert(call.target_address == target_address); if call.is_public { @@ -63,7 +63,7 @@ impl DAppPayload { call.target_address, call.function_selector, call.args_hash, - false, + call.is_static, false ); } else { @@ -71,7 +71,7 @@ impl DAppPayload { call.target_address, call.function_selector, call.args_hash, - false, + call.is_static, false ); } diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 25bcda79fc0..a232484e17d 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -56,7 +56,7 @@ contract AppSubscription { context.end_setup(); - AppSubscription::at(context.this_address()).assert_not_expired(note.expiry_block_number).static_enqueue(&mut context); + AppSubscription::at(context.this_address()).assert_not_expired(note.expiry_block_number).enqueue_view(&mut context); payload.execute_calls(&mut context, storage.target_address.read_private()); } @@ -81,12 +81,14 @@ contract AppSubscription { #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn assert_not_expired(expiry_block_number: Field) { assert((context.block_number()) as u64 < expiry_block_number as u64); } #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn assert_block_number(expiry_block_number: Field) { assert( (context.block_number() + SUBSCRIPTION_DURATION_IN_BLOCKS) as u64 @@ -111,7 +113,7 @@ contract AppSubscription { ).call(&mut context); // Assert that the given expiry_block_number < current_block_number + SUBSCRIPTION_DURATION_IN_BLOCKS. - AppSubscription::at(context.this_address()).assert_block_number(expiry_block_number).static_enqueue(&mut context); + AppSubscription::at(context.this_address()).assert_block_number(expiry_block_number).enqueue_view(&mut context); let subscriber_npk_m_hash = get_npk_m_hash(&mut context, subscriber_address); let subscriber_ivpk_m = get_ivpk_m(&mut context, subscriber_address); @@ -124,7 +126,7 @@ contract AppSubscription { } // Compiler bug workaround. You can't call an unconstrained function in another module, unless its from an - // unconstained function in your module. + // unconstrained function in your module. unconstrained fn is_initialized(subscriber_address: AztecAddress) -> pub bool { storage.subscriptions.at(subscriber_address).is_initialized() } diff --git a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr index a21791aaee4..a62fc79b5ec 100644 --- a/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_nested_calls_test_contract/src/main.nr @@ -58,13 +58,13 @@ contract AvmNestedCallsTest { // Indirectly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { - AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).static_call(&mut context) + AvmNestedCallsTest::at(context.this_address()).add_args_return(arg_a, arg_b).view(&mut context) } // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. #[aztec(public-vm)] fn nested_static_call_to_set_storage() { - AvmNestedCallsTest::at(context.this_address()).set_storage_single(20).static_call(&mut context); + AvmNestedCallsTest::at(context.this_address()).set_storage_single(20).view(&mut context); } #[aztec(public-vm)] diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 90747ecab5c..36873f06d8b 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -377,7 +377,7 @@ contract AvmTest { */ #[aztec(private)] fn enqueue_public_from_private() { - AvmTest::at(context.this_address()).set_opcode_u8().static_enqueue(&mut context); + AvmTest::at(context.this_address()).set_opcode_u8().enqueue_view(&mut context); AvmTest::at(context.this_address()).set_read_storage_single(5).enqueue(&mut context); } } diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 9eef23a50bd..88bc4a0c54b 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -60,6 +60,7 @@ contract Crowdfunding { // docs:start:deadline-header #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn _check_deadline() { // docs:end:deadline-header let deadline = storage.deadline.read(); @@ -72,7 +73,7 @@ contract Crowdfunding { #[aztec(private)] fn donate(amount: u64) { // 1) Check that the deadline has not passed - Crowdfunding::at(context.this_address())._check_deadline().static_enqueue(&mut context); + Crowdfunding::at(context.this_address())._check_deadline().enqueue_view(&mut context); // docs:end:call-check-deadline // docs:start:do-transfer diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index d2ed49d84ec..7723b789a26 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -117,7 +117,7 @@ contract DocsExample { // and returns the response. // Used to test that we can retrieve values through calls and // correctly return them in the simulation - let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_private().static_call(&mut context); + let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_private().view(&mut context); leader.points += 1; leader } @@ -128,12 +128,13 @@ contract DocsExample { // and returns the response. // Used to test that we can retrieve values through calls and // correctly return them in the simulation - let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_public().static_call(&mut context); + let mut leader = DocsExample::at(context.this_address()).get_shared_immutable_constrained_public().view(&mut context); leader.points += 1; leader } #[aztec(public)] + #[aztec(view)] fn get_shared_immutable_constrained_public() -> pub Leader { storage.shared_immutable.read_public() } @@ -145,6 +146,7 @@ contract DocsExample { } #[aztec(private)] + #[aztec(view)] fn get_shared_immutable_constrained_private() -> pub Leader { storage.shared_immutable.read_private() } diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index c640a523829..1817bc8947d 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -151,7 +151,7 @@ contract Lending { #[aztec(internal)] fn _withdraw(owner: AztecAddress, recipient: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); - let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; + let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; let coll_loc = storage.collateral.at(owner); let collateral: Field = coll_loc.read(); @@ -199,7 +199,7 @@ contract Lending { #[aztec(internal)] fn _borrow(owner: AztecAddress, to: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator().call(&mut context); - let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; + let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; // Fetch collateral and static_debt, compute health of current position let collateral = U128::from_integer(storage.collateral.at(owner).read()); diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index c4afaacf753..6aab33130b7 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -18,6 +18,7 @@ contract PriceFeed { } #[aztec(public)] + #[aztec(view)] fn get_price(asset_id: Field) -> Asset { storage.assets.at(asset_id).read() } diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml new file mode 100644 index 00000000000..6c3ec004fe8 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_child_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "static_child_contract" +type = "contract" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +value_note = { path = "../../../aztec-nr/value-note" } diff --git a/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr new file mode 100644 index 00000000000..f6f7b7e79c7 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_child_contract/src/main.nr @@ -0,0 +1,142 @@ +// A contract used along with `StaticParent` contract to test static calls. +contract StaticChild { + use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, Deserialize}; + + use dep::aztec::{ + context::{PublicContext, Context, gas::GasOpts}, + protocol_types::{abis::{call_context::CallContext}}, + note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, + keys::getters::{get_npk_m_hash, get_ivpk_m} + }; + use dep::value_note::value_note::ValueNote; + + #[aztec(storage)] + struct Storage { + current_value: PublicMutable, + a_private_value: PrivateSet, + } + + // Returns base_value + chain_id + version + block_number + timestamp statically + #[aztec(public)] + #[aztec(view)] + fn pub_get_value(base_value: Field) -> Field { + let return_value = base_value + + context.chain_id() + + context.version() + + context.block_number() + + context.timestamp() as Field; + + return_value + } + + // Sets `current_value` to `new_value` + #[aztec(public)] + fn pub_set_value(new_value: Field) -> Field { + storage.current_value.write(new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // View function that attempts to modify state. Should always fail regardless how it's called. + #[aztec(private)] + #[aztec(view)] + fn private_illegal_set_value(new_value: Field, owner: AztecAddress) -> Field { + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let owner_ivpk_m = get_ivpk_m(&mut context, owner); + let mut note = ValueNote::new(new_value, owner_npk_m_hash); + storage.a_private_value.insert(&mut note, true, owner_ivpk_m); + new_value + } + + // Modify a note + #[aztec(private)] + fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let owner_ivpk_m = get_ivpk_m(&mut context, owner); + let mut note = ValueNote::new(new_value, owner_npk_m_hash); + storage.a_private_value.insert(&mut note, true, owner_ivpk_m); + new_value + } + + // Retrieve note value statically + #[aztec(private)] + #[aztec(view)] + fn private_get_value(amount: Field, owner: AztecAddress) -> Field { + let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); + let mut options = NoteGetterOptions::new(); + options = options.select(ValueNote::properties().value, amount, Option::none()).select( + ValueNote::properties().npk_m_hash, + owner_npk_m_hash, + Option::none() + ).set_limit(1); + let notes = storage.a_private_value.get_notes(options); + notes[0].unwrap_unchecked().value + } + + // Increments `current_value` by `new_value` + #[aztec(public)] + fn pub_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // View function that attempts to modify state. Should always fail regardless how it's called. + #[aztec(public)] + #[aztec(view)] + fn pub_illegal_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // AVM + + // Returns base_value + chain_id + version + block_number + timestamp statically + #[aztec(public-vm)] + #[aztec(view)] + fn avm_get_value(base_value: Field) -> Field { + let return_value = base_value + + context.chain_id() + + context.version() + + context.block_number() + + context.timestamp() as Field; + + return_value + } + + // Sets `current_value` to `new_value` + #[aztec(public-vm)] + fn avm_set_value(new_value: Field) -> Field { + storage.current_value.write(new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // Increments `current_value` by `new_value` + #[aztec(public-vm)] + fn avm_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } + + // View function that attempts to modify state. Should always fail regardless how it's called. + #[aztec(public-vm)] + #[aztec(view)] + fn avm_illegal_inc_value(new_value: Field) -> Field { + let old_value = storage.current_value.read(); + storage.current_value.write(old_value + new_value); + context.emit_unencrypted_log(new_value); + + new_value + } +} diff --git a/noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml new file mode 100644 index 00000000000..31ad33000b7 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_parent_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "static_parent_contract" +type = "contract" +authors = [""] +compiler_version = ">=0.28.0" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +static_child_contract = { path = "../static_child_contract"} \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr new file mode 100644 index 00000000000..e03529b57d0 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/static_parent_contract/src/main.nr @@ -0,0 +1,196 @@ + +// A contract used along with `StaticChild` contract to test static calls. +contract StaticParent { + use dep::aztec::prelude::{AztecAddress, FunctionSelector, Deserialize}; + use dep::aztec::context::gas::GasOpts; + use dep::static_child_contract::StaticChild; + + // Public function to directly call another public function to the target_contract using the selector and value provided + #[aztec(public)] + fn public_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + arg: Field + ) -> Field { + context.call_public_function( + target_contract, + target_selector, + [arg].as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Private function to directly call another private function to the target_contract using the selector and args provided + #[aztec(private)] + fn private_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 2] + ) -> Field { + context.call_private_function(target_contract, target_selector, args).unpack_into() + } + + // Private function to enqueue a call to a public function of another contract, passing the target arguments provided + #[aztec(private)] + fn enqueue_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + context.call_public_function(target_contract, target_selector, args); + } + + // Private function to statically call another private function to the target_contract using the selector and values provided + #[aztec(private)] + fn private_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 2] + ) -> Field { + context.static_call_private_function(target_contract, target_selector, args).unpack_into() + } + + // Same as above but using a specific function from the interface + #[aztec(private)] + fn private_get_value_from_child( + target_contract: AztecAddress, + value: Field, + owner: AztecAddress + ) -> Field { + StaticChild::at(target_contract).private_get_value(value, owner).view(&mut context) + } + + // Private function to set a static context and verify correct propagation for nested private calls + #[aztec(private)] + fn private_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 2] + ) -> Field { + StaticParent::at(context.this_address()).private_call(target_contract, target_selector, args).view(&mut context) + } + + // Public function to statically call another public function to the target_contract using the selector and value provided + #[aztec(public)] + fn public_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + context.static_call_public_function( + target_contract, + target_selector, + args.as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Same as above but using a specific function from the interface + #[aztec(public)] + fn public_get_value_from_child(target_contract: AztecAddress, value: Field) -> Field { + StaticChild::at(target_contract).pub_get_value(value).view(&mut context) + } + + // Public function to set a static context and verify correct propagation for nested public calls + #[aztec(public)] + fn public_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).public_call(target_contract, target_selector, args[0]).view(&mut context) + } + + // Private function to enqueue a static call to a public function of another contract, passing the target arguments provided + #[aztec(private)] + fn enqueue_static_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + context.static_call_public_function(target_contract, target_selector, args); + } + + // Same as above but using a specific function from the interface + #[aztec(private)] + fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { + StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); + } + + // Private function to set a static context and verify correct propagation of nested enqueuing of public calls + #[aztec(private)] + fn enqueue_static_nested_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).public_call(target_contract, target_selector, args[0]).enqueue_view(&mut context) + } + + // AVM + + #[aztec(public-vm)] + fn avm_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + arg: Field + ) -> Field { + context.call_public_function( + target_contract, + target_selector, + [arg].as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Public function to statically call another public function to the target_contract using the selector and value provided + #[aztec(public-vm)] + fn avm_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + context.static_call_public_function( + target_contract, + target_selector, + args.as_slice(), + GasOpts::default() + ).deserialize_into() + } + + // Same as above but using a specific function from the interface + #[aztec(public-vm)] + fn avm_get_value_from_child(target_contract: AztecAddress, value: Field) -> Field { + StaticChild::at(target_contract).avm_get_value(value).view(&mut context) + } + + // Public function to set a static context and verify correct propagation for nested public calls + #[aztec(public-vm)] + fn avm_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) -> Field { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).avm_call(target_contract, target_selector, args[0]).view(&mut context) + } + + // Same as above but using a specific function from the interface + #[aztec(private)] + fn enqueue_avm_get_value_from_child(target_contract: AztecAddress, value: Field) { + StaticChild::at(target_contract).avm_get_value(value).enqueue_view(&mut context); + } + + // Private function to set a static context and verify correct propagation of nested enqueuing of public calls + #[aztec(private)] + fn enqueue_static_nested_call_to_avm_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, + args: [Field; 1] + ) { + // Call the target public function through the pub entrypoint statically + StaticParent::at(context.this_address()).avm_call(target_contract, target_selector, args[0]).enqueue_view(&mut context) + } +} diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index afacb220568..0ccd4b5a74b 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -57,7 +57,7 @@ contract Uniswap { assert_current_call_valid_authwit_public(&mut context, sender); } - let input_asset = TokenBridge::at(input_asset_bridge).get_token().static_call(&mut context); + let input_asset = TokenBridge::at(input_asset_bridge).get_token().view(&mut context); // Transfer funds to this contract Token::at(input_asset).transfer_public( @@ -71,8 +71,8 @@ contract Uniswap { Uniswap::at(context.this_address())._approve_bridge_and_exit_input_asset_to_L1(input_asset, input_asset_bridge, input_amount).call(&mut context); // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. - let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address_public().static_call(&mut context); - let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address_public().static_call(&mut context); + let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address_public().view(&mut context); + let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address_public().view(&mut context); // ensure portal exists - else funds might be lost assert( !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0" @@ -114,7 +114,7 @@ contract Uniswap { ) { // Assert that user provided token address is same as expected by token bridge. // we can't directly use `input_asset_bridge.token` because that is a public method and public can't return data to private - Uniswap::at(context.this_address())._assert_token_is_same(input_asset, input_asset_bridge).static_enqueue(&mut context); + Uniswap::at(context.this_address())._assert_token_is_same(input_asset, input_asset_bridge).enqueue_view(&mut context); // Transfer funds to this contract Token::at(input_asset).unshield( @@ -129,8 +129,8 @@ contract Uniswap { // Create swap message and send to Outbox for Uniswap Portal // this ensures the integrity of what the user originally intends to do on L1. - let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address().static_call(&mut context); - let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address().static_call(&mut context); + let input_asset_bridge_portal_address = TokenBridge::at(input_asset_bridge).get_portal_address().view(&mut context); + let output_asset_bridge_portal_address = TokenBridge::at(output_asset_bridge).get_portal_address().view(&mut context); // ensure portal exists - else funds might be lost assert( !input_asset_bridge_portal_address.is_zero(), "L1 portal address of input_asset's bridge is 0" @@ -218,9 +218,10 @@ contract Uniswap { // docs:start:assert_token_is_same #[aztec(public)] #[aztec(internal)] + #[aztec(view)] fn _assert_token_is_same(token: AztecAddress, token_bridge: AztecAddress) { assert( - token.eq(TokenBridge::at(token_bridge).get_token().static_call(&mut context)), "input_asset address is not the same as seen in the bridge contract" + token.eq(TokenBridge::at(token_bridge).get_token().view(&mut context)), "input_asset address is not the same as seen in the bridge contract" ); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr index 2a4148182ca..f123bb616a6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr @@ -7,12 +7,14 @@ use crate::{ struct FunctionData { selector : FunctionSelector, is_private : bool, + is_static : bool, } impl Eq for FunctionData { fn eq(self, other: Self) -> bool { self.selector.eq(other.selector) & - self.is_private == other.is_private + (self.is_private == other.is_private) & + (self.is_static == other.is_static) } } @@ -24,6 +26,7 @@ impl Serialize for FunctionData { [ self.selector.to_field(), self.is_private as Field, + self.is_static as Field ] } } @@ -33,6 +36,7 @@ impl Deserialize for FunctionData { Self { selector: FunctionSelector::from_field(serialized[0]), is_private: serialized[1] as bool, + is_static: serialized[2] as bool } } } @@ -48,8 +52,10 @@ impl Empty for FunctionData { FunctionData { selector: FunctionSelector::empty(), is_private: false, + is_static: false } } + } #[test] @@ -66,6 +72,6 @@ fn empty_hash() { let hash = data.hash(); // Value from function_data.test.ts "computes empty function data hash" test - let test_data_empty_hash = 0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed; + let test_data_empty_hash = 0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 18278e5b3d2..2913e535363 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -85,6 +85,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x1eaa8a277851ba8de6f7630ec75a2324e03a00a6ee99f24dd834faa422bdee4f; + let test_data_empty_hash = 0x29d77b0175116357d39252de002a2944652f87ccb4404f9346bff6d44f020f7f; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr index 7757259ed7f..f8aefb791ed 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr @@ -58,7 +58,7 @@ mod tests { #[test] fn compute_call_stack_item_request_hash() { let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false }; + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false, is_static: false }; let mut public_inputs = PublicCircuitPublicInputs::empty(); public_inputs.new_note_hashes[0] = NoteHash { @@ -69,14 +69,14 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test - let test_data_call_stack_item_request_hash = 0x1fe90f27924bcd761257c1b4570f5937b6dabcb4b6047ff668a770dea8e13533; + let test_data_call_stack_item_request_hash = 0x0230a99218df238d4a28664ee700e10a4fdfe98e4a2f5c678bce8c95d5fa04b1; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } #[test] fn compute_call_stack_item_hash() { let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false }; + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false, is_static: false }; let mut public_inputs = PublicCircuitPublicInputs::empty(); public_inputs.new_note_hashes[0] = NoteHash { @@ -87,7 +87,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test - let test_data_call_stack_item_hash = 0x2bb94c518916df51853784f16991e7691eddd452831ee1197cd29cdfb492d7b8; + let test_data_call_stack_item_hash = 0x1bda75e8d4cf46fd126d14d6e28d1dc8ff3860b49ff59edd7da8bfeee909aef3; assert_eq(call_stack_item.hash(), test_data_call_stack_item_hash); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index ef19cbe4547..7173fcc77a2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -150,7 +150,7 @@ global CONTRACT_INSTANCE_LENGTH: u64 = 5; global CONTRACT_STORAGE_READ_LENGTH: u64 = 2; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: u64 = 2; global ETH_ADDRESS_LENGTH = 1; -global FUNCTION_DATA_LENGTH: u64 = 2; +global FUNCTION_DATA_LENGTH: u64 = 3; global FUNCTION_LEAF_PREIMAGE_LENGTH: u64 = 5; global GLOBAL_VARIABLES_LENGTH: u64 = 6 + GAS_FEES_LENGTH; global APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr index 836e673b5e1..bae6a2c40b0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr @@ -14,6 +14,7 @@ global default_private_function = ContractFunction { data: FunctionData { selector: FunctionSelector { inner: 1010101 }, is_private: true, + is_static: false }, vk_hash: 0, acir_hash: 1111, @@ -33,6 +34,7 @@ global default_public_function = ContractFunction { data: FunctionData { selector: FunctionSelector { inner: 3030303 }, is_private: false, + is_static: false }, vk_hash: 0, acir_hash: 3333, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr index 5d804fa5d0a..6e261adea38 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr @@ -95,10 +95,10 @@ mod tests { origin: AztecAddress::from_field(1), args_hash: 3, tx_context: TxContext { chain_id: 0, version: 0, gas_settings }, - function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_private: true } + function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_private: true, is_static: false } }; // Value from tx_request.test.ts "compute hash" test - let test_data_tx_request_hash = 0x0d982a1c7a65919b2bcacbf5660f5b861132072a8190d97c82b1591da402f5ea; + let test_data_tx_request_hash = 0x249ca45ef4045007021de437e14bf865445f63af6ab5dcc8d78d2b3aa7c58c74; assert(tx_request.hash() == test_data_tx_request_hash); } } diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 5f0326bea5a..c3638b7760d 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -1,6 +1,7 @@ mod transforms; mod utils; +use noirc_errors::Location; use transforms::{ compute_note_hash_and_nullifier::inject_compute_note_hash_and_nullifier, contract_interface::{ @@ -66,6 +67,7 @@ fn transform( for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { if transform_module( crate_id, + &file_id, context, &mut submodule.contents, submodule.name.0.contents.as_str(), @@ -86,6 +88,7 @@ fn transform( /// Returns true if an annotated node is found, false otherwise fn transform_module( crate_id: &CrateId, + file_id: &FileId, context: &HirContext, module: &mut SortedModule, module_name: &str, @@ -134,6 +137,7 @@ fn transform_module( let mut is_initializer = false; let mut is_internal = false; let mut insert_init_check = has_initializer; + let mut is_static = false; for secondary_attribute in func.def.attributes.secondary.clone() { if is_custom_attribute(&secondary_attribute, "aztec(private)") { @@ -150,6 +154,9 @@ fn transform_module( } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { is_public_vm = true; } + if is_custom_attribute(&secondary_attribute, "aztec(view)") { + is_static = true; + } } // Apply transformations to the function based on collected attributes @@ -161,7 +168,8 @@ fn transform_module( } else { "Public" }; - stubs.push(stub_function(fn_type, func)); + let stub_src = stub_function(fn_type, func, is_static); + stubs.push((stub_src, Location { file: *file_id, span: func.name_ident().span() })); export_fn_abi(&mut module.types, func)?; transform_function( @@ -171,6 +179,7 @@ fn transform_module( is_initializer, insert_init_check, is_internal, + is_static, )?; has_transformed_module = true; } else if storage_defined && func.def.is_unconstrained { diff --git a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs index 921bad4b612..bb63357d251 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/contract_interface.rs @@ -1,4 +1,5 @@ -use noirc_frontend::ast::{NoirFunction, UnresolvedTypeData}; +use noirc_errors::Location; +use noirc_frontend::ast::{Ident, NoirFunction, UnresolvedTypeData}; use noirc_frontend::{ graph::CrateId, macros_api::{FileId, HirContext, HirExpression, HirLiteral, HirStatement}, @@ -39,7 +40,7 @@ use crate::utils::{ // } // // The selector placeholder has to be replaced with the actual function signature after type checking in the next macro pass -pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { +pub fn stub_function(aztec_visibility: &str, func: &NoirFunction, is_static_call: bool) -> String { let fn_name = func.name().to_string(); let fn_parameters = func .parameters() @@ -59,6 +60,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { let parameters = func.parameters(); let is_void = if matches!(fn_return_type.typ, UnresolvedTypeData::Unit) { "Void" } else { "" }; + let is_static = if is_static_call { "Static" } else { "" }; let return_type_hint = if is_void == "Void" { "".to_string() } else { @@ -101,18 +103,18 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { let fn_body = format!( "{} - dep::aztec::context::{}{}CallInterface {{ + dep::aztec::context::{}{}{}CallInterface {{ target_contract: self.target_contract, selector: {}, args_hash, }}", - args_hash, aztec_visibility, is_void, fn_selector, + args_hash, aztec_visibility, is_static, is_void, fn_selector, ); format!( - "pub fn {}(self, {}) -> dep::aztec::context::{}{}CallInterface{} {{ + "pub fn {}(self, {}) -> dep::aztec::context::{}{}{}CallInterface{} {{ {} }}", - fn_name, fn_parameters, aztec_visibility, is_void, return_type_hint, fn_body + fn_name, fn_parameters, aztec_visibility, is_static, is_void, return_type_hint, fn_body ) } else { let args = format!( @@ -123,19 +125,19 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { ); let fn_body = format!( "{} - dep::aztec::context::Avm{}CallInterface {{ + dep::aztec::context::Avm{}{}CallInterface {{ target_contract: self.target_contract, selector: {}, args: args_acc, gas_opts: dep::aztec::context::gas::GasOpts::default(), }}", - args, is_void, fn_selector, + args, is_static, is_void, fn_selector, ); format!( - "pub fn {}(self, {}) -> dep::aztec::context::Avm{}CallInterface{} {{ + "pub fn {}(self, {}) -> dep::aztec::context::Avm{}{}CallInterface{} {{ {} }}", - fn_name, fn_parameters, is_void, return_type_hint, fn_body + fn_name, fn_parameters, is_static, is_void, return_type_hint, fn_body ) } } @@ -146,7 +148,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction) -> String { pub fn generate_contract_interface( module: &mut SortedModule, module_name: &str, - stubs: &[String], + stubs: &[(String, Location)], ) -> Result<(), AztecMacroError> { let contract_interface = format!( " @@ -172,7 +174,7 @@ pub fn generate_contract_interface( }} ", module_name, - stubs.join("\n"), + stubs.iter().map(|(src, _)| src.to_owned()).collect::>().join("\n"), ); let (contract_interface_ast, errors) = parse_program(&contract_interface); @@ -182,8 +184,27 @@ pub fn generate_contract_interface( } let mut contract_interface_ast = contract_interface_ast.into_sorted(); + let mut impl_with_locations = contract_interface_ast.impls.pop().unwrap(); + + impl_with_locations.methods = impl_with_locations + .methods + .iter() + .enumerate() + .map(|(i, (method, orig_span))| { + if method.name() == "at" { + (method.clone(), *orig_span) + } else { + let (_, new_location) = stubs[i]; + let mut modified_method = method.clone(); + modified_method.def.name = + Ident::new(modified_method.name().to_string(), new_location.span); + (modified_method, *orig_span) + } + }) + .collect(); + module.types.push(contract_interface_ast.types.pop().unwrap()); - module.impls.push(contract_interface_ast.impls.pop().unwrap()); + module.impls.push(impl_with_locations); module.functions.push(contract_interface_ast.functions.pop().unwrap()); Ok(()) diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 487d15ceabe..45bce6a681a 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -10,6 +10,7 @@ use noirc_frontend::ast::{ use noirc_frontend::{macros_api::FieldElement, parse_program}; +use crate::utils::ast_utils::member_access; use crate::{ chained_dep, chained_path, utils::{ @@ -33,6 +34,7 @@ pub fn transform_function( is_initializer: bool, insert_init_check: bool, is_internal: bool, + is_static: bool, ) -> Result<(), AztecMacroError> { let context_name = format!("{}Context", ty); let inputs_name = format!("{}ContextInputs", ty); @@ -40,6 +42,12 @@ pub fn transform_function( let is_avm = ty == "Avm"; let is_private = ty == "Private"; + // Force a static context if the function is static + if is_static { + let is_static_check = create_static_check(func.name(), is_avm); + func.def.body.statements.insert(0, is_static_check); + } + // Add check that msg sender equals this address and flag function as internal if is_internal { let is_internal_check = create_internal_check(func.name()); @@ -275,6 +283,31 @@ fn create_mark_as_initialized(ty: &str) -> Statement { ))) } +/// Forces a static context for a function, ensuring that no state modifications are allowed +/// +/// ```noir +/// assert(context.inputs.call_context.is_static_call == true, "Function can only be called statically") +/// ``` +fn create_static_check(fname: &str, is_avm: bool) -> Statement { + let is_static_call_expr = if !is_avm { + ["inputs", "call_context", "is_static_call"] + .iter() + .fold(variable("context"), |acc, member| member_access(acc, member)) + } else { + ["inputs", "is_static_call"] + .iter() + .fold(variable("context"), |acc, member| member_access(acc, member)) + }; + make_statement(StatementKind::Constrain(ConstrainStatement( + make_eq(is_static_call_expr, expression(ExpressionKind::Literal(Literal::Bool(true)))), + Some(expression(ExpressionKind::Literal(Literal::Str(format!( + "Function {} can only be called statically", + fname + ))))), + ConstrainKind::Assert, + ))) +} + /// Creates a check for internal functions ensuring that the caller is self. /// /// ```noir diff --git a/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs b/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs index ebb4854f86e..4e05dcaf619 100644 --- a/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs +++ b/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs @@ -1,9 +1,9 @@ use noirc_errors::{Span, Spanned}; use noirc_frontend::ast::{ BinaryOpKind, CallExpression, CastExpression, Expression, ExpressionKind, FunctionReturnType, - Ident, IndexExpression, InfixExpression, Lambda, LetStatement, MethodCallExpression, - NoirTraitImpl, Path, Pattern, PrefixExpression, Statement, StatementKind, TraitImplItem, - UnaryOp, UnresolvedType, UnresolvedTypeData, + Ident, IndexExpression, InfixExpression, Lambda, LetStatement, MemberAccessExpression, + MethodCallExpression, NoirTraitImpl, Path, Pattern, PrefixExpression, Statement, StatementKind, + TraitImplItem, UnaryOp, UnresolvedType, UnresolvedTypeData, }; use noirc_frontend::token::SecondaryAttribute; @@ -125,6 +125,13 @@ pub fn make_statement(kind: StatementKind) -> Statement { Statement { span: Span::default(), kind } } +pub fn member_access(lhs: Expression, member: &str) -> Expression { + expression(ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { + lhs, + rhs: ident(member), + }))) +} + #[macro_export] macro_rules! chained_path { ( $base:expr ) => { diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index bcdac6b8dc9..c7e7db96a48 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -20,7 +20,7 @@ describe('Contract Class', () => { const mockTxRequest = { type: 'TxRequest' } as any as TxExecutionRequest; const mockTxHash = { type: 'TxHash' } as any as TxHash; const mockTxReceipt = { type: 'TxReceipt' } as any as TxReceipt; - const mockViewResultValue = 1; + const mockUnconstrainedResultValue = 1; const l1Addresses: L1ContractAddresses = { availabilityOracleAddress: EthAddress.random(), rollupAddress: EthAddress.random(), @@ -45,6 +45,7 @@ describe('Contract Class', () => { isInitializer: false, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, debugSymbols: '', parameters: [ { @@ -68,6 +69,7 @@ describe('Contract Class', () => { { name: 'baz', isInitializer: false, + isStatic: false, functionType: FunctionType.OPEN, isInternal: false, parameters: [], @@ -78,6 +80,7 @@ describe('Contract Class', () => { { name: 'qux', isInitializer: false, + isStatic: false, functionType: FunctionType.UNCONSTRAINED, isInternal: false, parameters: [ @@ -118,7 +121,7 @@ describe('Contract Class', () => { wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest); wallet.getContractInstance.mockResolvedValue(contractInstance); wallet.sendTx.mockResolvedValue(mockTxHash); - wallet.viewTx.mockResolvedValue(mockViewResultValue as any as DecodedReturn); + wallet.simulateUnconstrained.mockResolvedValue(mockUnconstrainedResultValue as any as DecodedReturn); wallet.getTxReceipt.mockResolvedValue(mockTxReceipt); wallet.getNodeInfo.mockResolvedValue(mockNodeInfo); wallet.proveTx.mockResolvedValue(mockTx); @@ -145,9 +148,9 @@ describe('Contract Class', () => { const result = await fooContract.methods.qux(123n).simulate({ from: account.address, }); - expect(wallet.viewTx).toHaveBeenCalledTimes(1); - expect(wallet.viewTx).toHaveBeenCalledWith('qux', [123n], contractAddress, account.address); - expect(result).toBe(mockViewResultValue); + expect(wallet.simulateUnconstrained).toHaveBeenCalledTimes(1); + expect(wallet.simulateUnconstrained).toHaveBeenCalledWith('qux', [123n], contractAddress, account.address); + expect(result).toBe(mockUnconstrainedResultValue); }); it('should not call create on an unconstrained function', async () => { diff --git a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts index 39344586891..6ebf682cdc1 100644 --- a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts +++ b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts @@ -1,5 +1,5 @@ -import { type FunctionCall, PackedValues, TxExecutionRequest } from '@aztec/circuit-types'; -import { type AztecAddress, FunctionData, GasSettings, TxContext } from '@aztec/circuits.js'; +import type { FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; +import { type AztecAddress, FunctionData, type GasSettings } from '@aztec/circuits.js'; import { type FunctionAbi, FunctionType, decodeReturnValues, encodeArguments } from '@aztec/foundation/abi'; import { type Wallet } from '../account/wallet.js'; @@ -70,42 +70,29 @@ export class ContractFunctionInteraction extends BaseContractInteraction { * Differs from prove in a few important ways: * 1. It returns the values of the function execution * 2. It supports `unconstrained`, `private` and `public` functions - * 3. For `private` execution it: - * 3.a SKIPS the entrypoint and starts directly at the function - * 4. For `public` execution it: - * 4.a Removes the `txRequest` value after ended simulation - * 4.b Ignores the `from` in the options * * @param options - An optional object containing additional configuration for the transaction. * @returns The result of the transaction as returned by the contract function. */ public async simulate(options: SimulateMethodOptions = {}): Promise { if (this.functionDao.functionType == FunctionType.UNCONSTRAINED) { - return this.wallet.viewTx(this.functionDao.name, this.args, this.contractAddress, options.from); + return this.wallet.simulateUnconstrained(this.functionDao.name, this.args, this.contractAddress, options?.from); } - if (this.functionDao.functionType == FunctionType.SECRET) { - const nodeInfo = await this.wallet.getNodeInfo(); - const packedArgs = PackedValues.fromValues(encodeArguments(this.functionDao, this.args)); - const gasSettings = options.gasSettings ?? GasSettings.simulation(); + const txRequest = await this.create(); + // const from = + // this.functionDao.functionType == FunctionType.SECRET ? options.from ?? this.wallet.getAddress() : undefined; - const txRequest = TxExecutionRequest.from({ - firstCallArgsHash: packedArgs.hash, - origin: this.contractAddress, - functionData: FunctionData.fromAbi(this.functionDao), - txContext: new TxContext(nodeInfo.chainId, nodeInfo.protocolVersion, gasSettings), - argsOfCalls: [packedArgs], - authWitnesses: [], - }); - const simulatedTx = await this.wallet.simulateTx(txRequest, true, options.from ?? this.wallet.getAddress()); - const flattened = simulatedTx.privateReturnValues; - return flattened ? decodeReturnValues(this.functionDao, flattened) : []; - } else { - const txRequest = await this.create(); - const simulatedTx = await this.wallet.simulateTx(txRequest, true); - this.txRequest = undefined; - const flattened = simulatedTx.publicOutput?.publicReturnValues; - return flattened ? decodeReturnValues(this.functionDao, flattened) : []; - } + const simulatedTx = await this.wallet.simulateTx(txRequest, true, options?.from); + + // As account entrypoints are private, for private functions we retrieve the return values from the first nested call + // since we're interested in the first set of values AFTER the account entrypoint + // For public functions we retrieve the first values directly from the public output. + const rawReturnValues = + this.functionDao.functionType == FunctionType.SECRET + ? simulatedTx.privateReturnValues?.nested?.[0].values + : simulatedTx.publicOutput?.publicReturnValues?.values; + + return rawReturnValues ? decodeReturnValues(this.functionDao, rawReturnValues) : []; } } diff --git a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts b/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts index 167dfac2501..bf36456c1bb 100644 --- a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts +++ b/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts @@ -39,6 +39,7 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { isInitializer: false, functionType: 'secret', isInternal: false, + isStatic: false, parameters: [ { name: 'app_payload', @@ -73,6 +74,7 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, diff --git a/yarn-project/aztec.js/src/entrypoint/payload.ts b/yarn-project/aztec.js/src/entrypoint/payload.ts index c4bfb965aaa..7c3ec2f764d 100644 --- a/yarn-project/aztec.js/src/entrypoint/payload.ts +++ b/yarn-project/aztec.js/src/entrypoint/payload.ts @@ -33,6 +33,8 @@ type EncodedFunctionCall = { target_address: Fr; /** Whether the function is public or private */ is_public: boolean; + /** Whether the function can alter state */ + is_static: boolean; }; /* eslint-enable camelcase */ @@ -54,6 +56,7 @@ export class EntrypointPayload { function_selector: call.functionData.selector.toField(), target_address: call.to.toField(), is_public: !call.functionData.isPrivate, + is_static: call.functionData.isStatic, })); /* eslint-enable camelcase */ @@ -96,6 +99,7 @@ export class EntrypointPayload { call.function_selector, call.target_address, new Fr(call.is_public), + new Fr(call.is_static), ]), this.#nonce, ]; diff --git a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts index af5a9ac3b31..92a4779c6f0 100644 --- a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts @@ -54,7 +54,11 @@ export class NativeFeePaymentMethod implements FeePaymentMethod { return Promise.resolve([ { to: this.#gasTokenAddress, - functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false), + functionData: new FunctionData( + FunctionSelector.fromSignature('pay_fee(Field)'), + /*isPrivate=*/ false, + /*isStatic=*/ false, + ), args: [gasSettings.getFeeLimit()], }, ]); diff --git a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts index f3298ed09ef..f0a96413e31 100644 --- a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts @@ -65,7 +65,11 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { this.wallet.getVersion(), { args: [this.wallet.getCompleteAddress().address, this.paymentContract, maxFee, nonce], - functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), + functionData: new FunctionData( + FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), + /*isPrivate=*/ true, + /*isStatic=*/ false, + ), to: this.asset, }, ); @@ -78,7 +82,8 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_private(Field,(Field),Field,Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [maxFee, this.asset, secretHashForRebate, nonce], }, diff --git a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts index 33b2430ebee..5b8782107df 100644 --- a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts @@ -60,7 +60,8 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), to: this.asset, }, @@ -72,7 +73,8 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [maxFee, this.asset, nonce], }, diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index 803d07010eb..e793504eb7d 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -206,6 +206,7 @@ export class AccountWallet extends BaseWallet { isInitializer: false, functionType: FunctionType.OPEN, isInternal: true, + isStatic: false, parameters: [ { name: 'message_hash', @@ -223,6 +224,7 @@ export class AccountWallet extends BaseWallet { isInitializer: false, functionType: FunctionType.SECRET, isInternal: true, + isStatic: false, parameters: [ { name: 'message_hash', @@ -240,6 +242,7 @@ export class AccountWallet extends BaseWallet { isInitializer: false, functionType: FunctionType.UNCONSTRAINED, isInternal: false, + isStatic: false, parameters: [ { name: 'myself', diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index e94c9920359..d8a87d37098 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -130,8 +130,13 @@ export abstract class BaseWallet implements Wallet { getBlock(number: number): Promise { return this.pxe.getBlock(number); } - viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress | undefined): Promise { - return this.pxe.viewTx(functionName, args, to, from); + simulateUnconstrained( + functionName: string, + args: any[], + to: AztecAddress, + from?: AztecAddress | undefined, + ): Promise { + return this.pxe.simulateUnconstrained(functionName, args, to, from); } getUnencryptedLogs(filter: LogFilter): Promise { return this.pxe.getUnencryptedLogs(filter); diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 0ad069a0ceb..784c5d7ebbf 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -232,7 +232,7 @@ export interface PXE { getBlock(number: number): Promise; /** - * Simulate the execution of a view (read-only) function on a deployed contract without actually modifying state. + * Simulate the execution of an unconstrained function on a deployed contract without actually modifying state. * This is useful to inspect contract state, for example fetching a variable value or calling a getter function. * The function takes function name and arguments as parameters, along with the contract address * and optionally the sender's address. @@ -243,7 +243,7 @@ export interface PXE { * @param from - (Optional) The msg sender to set for the call. * @returns The result of the view function call, structured based on the function ABI. */ - viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; + simulateUnconstrained(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; /** * Gets unencrypted logs based on the provided filter. diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 2e21eac53b9..0fc51c62cdb 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -27,7 +27,7 @@ import { type ContractInstanceWithAddress, SerializableContractInstance } from ' import { EncryptedL2Log } from './logs/encrypted_l2_log.js'; import { EncryptedFunctionL2Logs, EncryptedTxL2Logs, Note, UnencryptedTxL2Logs } from './logs/index.js'; import { ExtendedNote } from './notes/index.js'; -import { type ProcessReturnValues, PublicSimulationOutput, SimulatedTx, Tx, TxHash } from './tx/index.js'; +import { NestedProcessReturnValues, PublicSimulationOutput, SimulatedTx, Tx, TxHash } from './tx/index.js'; /** * Testing utility to create empty logs composed from a single empty log. @@ -145,7 +145,7 @@ export const mockTxForRollup = (seed = 1, { hasLogs = false }: { hasLogs?: boole export const mockSimulatedTx = (seed = 1, hasLogs = true) => { const tx = mockTx(seed, { hasLogs }); - const dec: ProcessReturnValues = [new Fr(1n), new Fr(2n), new Fr(3n), new Fr(4n)]; + const dec = new NestedProcessReturnValues([new Fr(1n), new Fr(2n), new Fr(3n), new Fr(4n)]); const output = new PublicSimulationOutput( tx.encryptedLogs, tx.unencryptedLogs, diff --git a/yarn-project/circuit-types/src/tx/public_simulation_output.ts b/yarn-project/circuit-types/src/tx/public_simulation_output.ts index 24443814680..d28daa3dc4b 100644 --- a/yarn-project/circuit-types/src/tx/public_simulation_output.ts +++ b/yarn-project/circuit-types/src/tx/public_simulation_output.ts @@ -8,6 +8,31 @@ import { type PublicKernelType } from './processed_tx.js'; /** Return values of simulating a circuit. */ export type ProcessReturnValues = Fr[] | undefined; +/** Return values of simulating complete callstack. */ +export class NestedProcessReturnValues { + values: ProcessReturnValues; + nested: NestedProcessReturnValues[]; + + constructor(values: ProcessReturnValues, nested?: NestedProcessReturnValues[]) { + this.values = values; + this.nested = nested ?? []; + } + + toJSON(): any { + return { + values: this.values?.map(fr => fr.toString()), + nested: this.nested.map(n => n.toJSON()), + }; + } + + static fromJSON(json: any): NestedProcessReturnValues { + return new NestedProcessReturnValues( + json.values?.map(Fr.fromString), + json.nested?.map((n: any) => NestedProcessReturnValues.fromJSON(n)), + ); + } +} + /** * Outputs of processing the public component of a transaction. */ @@ -18,7 +43,7 @@ export class PublicSimulationOutput { public revertReason: SimulationError | undefined, public constants: CombinedConstantData, public end: CombinedAccumulatedData, - public publicReturnValues: ProcessReturnValues, + public publicReturnValues: NestedProcessReturnValues, public gasUsed: Partial>, ) {} @@ -29,7 +54,7 @@ export class PublicSimulationOutput { revertReason: this.revertReason, constants: this.constants.toBuffer().toString('hex'), end: this.end.toBuffer().toString('hex'), - publicReturnValues: this.publicReturnValues?.map(fr => fr.toString()), + publicReturnValues: this.publicReturnValues?.toJSON(), gasUsed: mapValues(this.gasUsed, gas => gas?.toJSON()), }; } @@ -41,7 +66,7 @@ export class PublicSimulationOutput { json.revertReason, CombinedConstantData.fromBuffer(Buffer.from(json.constants, 'hex')), CombinedAccumulatedData.fromBuffer(Buffer.from(json.end, 'hex')), - json.publicReturnValues?.map(Fr.fromString), + NestedProcessReturnValues.fromJSON(json.publicReturnValues), mapValues(json.gasUsed, gas => (gas ? Gas.fromJSON(gas) : undefined)), ); } diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.ts b/yarn-project/circuit-types/src/tx/simulated_tx.ts index e3808a1e463..8ac2ef72a1f 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.ts @@ -1,6 +1,4 @@ -import { Fr } from '@aztec/circuits.js'; - -import { type ProcessReturnValues, PublicSimulationOutput } from './public_simulation_output.js'; +import { NestedProcessReturnValues, PublicSimulationOutput } from './public_simulation_output.js'; import { Tx } from './tx.js'; // REFACTOR: Review what we need to expose to the user when running a simulation. @@ -12,7 +10,7 @@ import { Tx } from './tx.js'; export class SimulatedTx { constructor( public tx: Tx, - public privateReturnValues?: ProcessReturnValues, + public privateReturnValues?: NestedProcessReturnValues, public publicOutput?: PublicSimulationOutput, ) {} @@ -23,7 +21,7 @@ export class SimulatedTx { public toJSON() { return { tx: this.tx.toJSON(), - privateReturnValues: this.privateReturnValues?.map(fr => fr.toString()), + privateReturnValues: this.privateReturnValues && this.privateReturnValues.toJSON(), publicOutput: this.publicOutput && this.publicOutput.toJSON(), }; } @@ -36,7 +34,9 @@ export class SimulatedTx { public static fromJSON(obj: any) { const tx = Tx.fromJSON(obj.tx); const publicOutput = obj.publicOutput ? PublicSimulationOutput.fromJSON(obj.publicOutput) : undefined; - const privateReturnValues = obj.privateReturnValues?.map(Fr.fromString); + const privateReturnValues = obj.privateReturnValues + ? NestedProcessReturnValues.fromJSON(obj.privateReturnValues) + : undefined; return new SimulatedTx(tx, privateReturnValues, publicOutput); } diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 3be95e96e9a..4a35f384538 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -94,7 +94,7 @@ export const CONTRACT_INSTANCE_LENGTH = 5; export const CONTRACT_STORAGE_READ_LENGTH = 2; export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; export const ETH_ADDRESS_LENGTH = 1; -export const FUNCTION_DATA_LENGTH = 2; +export const FUNCTION_DATA_LENGTH = 3; export const FUNCTION_LEAF_PREIMAGE_LENGTH = 5; export const GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; export const APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index e81eaebfc49..4bb4b19a1fb 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -36,6 +36,7 @@ describe('ContractAddress', () => { functionType: FunctionType.SECRET, isInitializer: false, isInternal: false, + isStatic: false, name: 'fun', parameters: [{ name: 'param1', type: { kind: 'boolean' }, visibility: ABIParameterVisibility.SECRET }], returnTypes: [], diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap index db45ccb85d2..8287356b029 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FunctionData computes empty function data hash 1`] = `Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>`; +exports[`FunctionData computes empty function data hash 1`] = `Fr<0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap index be2f85234d3..169f798b7ea 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x1eaa8a277851ba8de6f7630ec75a2324e03a00a6ee99f24dd834faa422bdee4f>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x29d77b0175116357d39252de002a2944652f87ccb4404f9346bff6d44f020f7f>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0cb30e5fa0e822ff93dc0bc3752c4b277e4629dfd8c31651aca53541873a5505>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x00c30fa28e1ab0d35bd0eaa591f469b7f9b92bc37aa5696eaf447b88ad331339>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index 20348f214d3..5cf1ed0ff49 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x2bb94c518916df51853784f16991e7691eddd452831ee1197cd29cdfb492d7b8"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x1bda75e8d4cf46fd126d14d6e28d1dc8ff3860b49ff59edd7da8bfeee909aef3"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x1fe90f27924bcd761257c1b4570f5937b6dabcb4b6047ff668a770dea8e13533"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x0230a99218df238d4a28664ee700e10a4fdfe98e4a2f5c678bce8c95d5fa04b1"`; -exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x13e55a4c1fb75d2a348ab0abe47aba86992a0cebf5fe2b24243af0246d27d2b5>`; +exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x2328377f64bffa61d6a773e688b4b217b1dca488b8f905d94effe3fbc968111c>`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x0e54342ea9a248adda86b676c762fab4ed8e64f91c28da0f577162870685e5ab>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x20506d5ffb519b1e5763fdfe3c3f84cd6292585bacd024eccca04e31b17b4cfc>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap index fbadc0a1a84..bffda2922e4 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TxRequest compute hash 1`] = `"0x0d982a1c7a65919b2bcacbf5660f5b861132072a8190d97c82b1591da402f5ea"`; +exports[`TxRequest compute hash 1`] = `"0x249ca45ef4045007021de437e14bf865445f63af6ab5dcc8d78d2b3aa7c58c74"`; diff --git a/yarn-project/circuits.js/src/structs/function_data.test.ts b/yarn-project/circuits.js/src/structs/function_data.test.ts index c39c0a030d3..58abf6a4bcc 100644 --- a/yarn-project/circuits.js/src/structs/function_data.test.ts +++ b/yarn-project/circuits.js/src/structs/function_data.test.ts @@ -9,7 +9,7 @@ describe('FunctionData', () => { beforeAll(() => { setupCustomSnapshotSerializers(expect); - functionData = new FunctionData(new FunctionSelector(123), true); + functionData = new FunctionData(new FunctionSelector(123), /*isPrivate=*/ true, /*isStatic=*/ false); }); it(`serializes to buffer and deserializes it back`, () => { diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 66be3fd069b..d33a8b2ea8d 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -13,12 +13,15 @@ export class FunctionData { public selector: FunctionSelector, /** Indicates whether the function is private or public. */ public isPrivate: boolean, + /** Indicates whether the function can alter state or not. */ + public isStatic: boolean, ) {} static fromAbi(abi: FunctionAbi | ContractFunctionDao): FunctionData { return new FunctionData( FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), abi.functionType === FunctionType.SECRET, + abi.isStatic, ); } @@ -27,11 +30,11 @@ export class FunctionData { * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.selector, this.isPrivate); + return serializeToBuffer(this.selector, this.isPrivate, this.isStatic); } toFields(): Fr[] { - const fields = [this.selector.toField(), new Fr(this.isPrivate)]; + const fields = [this.selector.toField(), new Fr(this.isPrivate), new Fr(this.isStatic)]; if (fields.length !== FUNCTION_DATA_LENGTH) { throw new Error( `Invalid number of fields for FunctionData. Expected ${FUNCTION_DATA_LENGTH}, got ${fields.length}`, @@ -56,8 +59,10 @@ export class FunctionData { public static empty(args?: { /** Indicates whether the function is private or public. */ isPrivate?: boolean; + /** Indicates whether the function can alter state or not. */ + isStatic?: boolean; }): FunctionData { - return new FunctionData(FunctionSelector.empty(), args?.isPrivate ?? false); + return new FunctionData(FunctionSelector.empty(), args?.isPrivate ?? false, args?.isStatic ?? false); } /** @@ -67,7 +72,11 @@ export class FunctionData { */ static fromBuffer(buffer: Buffer | BufferReader): FunctionData { const reader = BufferReader.asReader(buffer); - return new FunctionData(reader.readObject(FunctionSelector), reader.readBoolean()); + return new FunctionData( + reader.readObject(FunctionSelector), + /*isPrivate=*/ reader.readBoolean(), + /*isStatic=*/ reader.readBoolean(), + ); } static fromFields(fields: Fr[] | FieldReader): FunctionData { @@ -75,8 +84,9 @@ export class FunctionData { const selector = FunctionSelector.fromFields(reader); const isPrivate = reader.readBoolean(); + const isStatic = reader.readBoolean(); - return new FunctionData(selector, isPrivate); + return new FunctionData(selector, isPrivate, isStatic); } hash(): Fr { diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts index df7c6192b6b..18719981e9e 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts @@ -32,7 +32,7 @@ describe('PublicCallStackItem', () => { const callStack = PublicCallStackItem.empty(); callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false); + callStack.functionData = new FunctionData(new FunctionSelector(2), /*isPrivate=*/ false, /*isStatic=*/ false); callStack.isExecutionRequest = true; callStack.publicInputs.newNoteHashes[0] = new NoteHash(new Fr(1), 0); @@ -51,7 +51,7 @@ describe('PublicCallStackItem', () => { const callStack = PublicCallStackItem.empty(); callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false); + callStack.functionData = new FunctionData(new FunctionSelector(2), /*isPrivate=*/ false, /*isStatic=*/ false); callStack.publicInputs.newNoteHashes[0] = new NoteHash(new Fr(1), 0); const hash = callStack.hash(); diff --git a/yarn-project/circuits.js/src/structs/tx_request.test.ts b/yarn-project/circuits.js/src/structs/tx_request.test.ts index f4a44c77fc3..8a62b32b1b9 100644 --- a/yarn-project/circuits.js/src/structs/tx_request.test.ts +++ b/yarn-project/circuits.js/src/structs/tx_request.test.ts @@ -37,7 +37,7 @@ describe('TxRequest', () => { const gasSettings = new GasSettings(new Gas(2, 2), new Gas(1, 1), new GasFees(3, 3), new Fr(10)); const txRequest = TxRequest.from({ origin: AztecAddress.fromBigInt(1n), - functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), true), + functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), /*isPrivate=*/ true, /*isStatic=*/ false), argsHash: new Fr(3), txContext: new TxContext(Fr.ZERO, Fr.ZERO, gasSettings), }); diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 7eb335efb0b..7037eabcb35 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -508,7 +508,7 @@ export function makePublicCallRequest(seed = 1): PublicCallRequest { return new PublicCallRequest( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), false), + new FunctionData(makeSelector(seed + 0x1), /*isPrivate=*/ false, /*isStatic=*/ false), childCallContext, parentCallContext, makeTuple(ARGS_LENGTH, fr, seed + 0x10), @@ -637,7 +637,7 @@ export function makePublicCallStackItem(seed = 1, full = false): PublicCallStack const callStackItem = new PublicCallStackItem( makeAztecAddress(seed), // in the public kernel, function can't be a constructor or private - new FunctionData(makeSelector(seed + 0x1), false), + new FunctionData(makeSelector(seed + 0x1), /*isPrivate=*/ false, /*isStatic=*/ false), makePublicCircuitPublicInputs(seed + 0x10, undefined, full), false, ); @@ -723,7 +723,7 @@ export function makePublicKernelInputsWithTweak( export function makeTxRequest(seed = 1): TxRequest { return TxRequest.from({ origin: makeAztecAddress(seed), - functionData: new FunctionData(makeSelector(seed + 0x100), true), + functionData: new FunctionData(makeSelector(seed + 0x100), /*isPrivate=*/ true, /*isStatic=*/ false), argsHash: fr(seed + 0x200), txContext: makeTxContext(seed + 0x400), }); @@ -759,7 +759,7 @@ export function makePrivateCallData(seed = 1): PrivateCallData { export function makePrivateCallStackItem(seed = 1): PrivateCallStackItem { return new PrivateCallStackItem( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), true), + new FunctionData(makeSelector(seed + 0x1), /*isPrivate=*/ true, /*isStatic=*/ false), makePrivateCircuitPublicInputs(seed + 0x10), ); } diff --git a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts index dfde4f8662b..35405f8b8f5 100644 --- a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts @@ -229,7 +229,8 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), to: this.asset, }, @@ -243,7 +244,8 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [tooMuchFee, this.asset, nonce], }, @@ -264,7 +266,8 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), to: this.asset, }, @@ -280,7 +283,8 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - true, + /*isPrivate=*/ true, + /*isStatic=*/ false, ), args: [maxFee, this.asset, nonce], }, @@ -289,7 +293,8 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { to: this.asset, functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, + /*isPrivate=*/ false, + /*isStatic=*/ false, ), args: [this.wallet.getAddress(), this.paymentContract, new Fr(1), Fr.random()], }, diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index a1c10487adf..d74e08d5a9c 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -1,18 +1,19 @@ import { type Wallet } from '@aztec/aztec.js'; -import { ChildContract, ParentContract } from '@aztec/noir-contracts.js'; +import { StaticChildContract, StaticParentContract } from '@aztec/noir-contracts.js'; +import { STATIC_CALL_STATE_MODIFICATION_ERROR, STATIC_CONTEXT_ASSERTION_ERROR } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; describe('e2e_static_calls', () => { let wallet: Wallet; - let parentContract: ParentContract; - let childContract: ChildContract; + let parentContract: StaticParentContract; + let childContract: StaticChildContract; let teardown: () => Promise; beforeAll(async () => { ({ teardown, wallet } = await setup()); - parentContract = await ParentContract.deploy(wallet).send().deployed(); - childContract = await ChildContract.deploy(wallet).send().deployed(); + parentContract = await StaticParentContract.deploy(wallet).send().deployed(); + childContract = await StaticChildContract.deploy(wallet).send().deployed(); // We create a note in the set, such that later reads doesn't fail due to get_notes returning 0 notes await childContract.methods.private_set_value(42n, wallet.getCompleteAddress().address).send().wait(); @@ -20,8 +21,31 @@ describe('e2e_static_calls', () => { afterAll(() => teardown()); + describe('direct view calls to child', () => { + it('performs legal private static calls', async () => { + await childContract.methods.private_get_value(42n, wallet.getCompleteAddress().address).send().wait(); + }); + + it('fails when performing non-static calls to poorly written static private functions', async () => { + await expect( + childContract.methods.private_illegal_set_value(42n, wallet.getCompleteAddress().address).send().wait(), + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('performs legal public static calls', async () => { + await childContract.methods.pub_get_value(42n).send().wait(); + }); + + it('fails when performing non-static calls to poorly written static public functions', async () => { + await expect(childContract.methods.pub_illegal_inc_value(42n).send().wait()).rejects.toThrow( + STATIC_CALL_STATE_MODIFICATION_ERROR, + ); + }); + }); + describe('parent calls child', () => { it('performs legal private to private static calls', async () => { + // Using low level calls await parentContract.methods .private_static_call(childContract.address, childContract.methods.private_get_value.selector, [ 42n, @@ -29,6 +53,12 @@ describe('e2e_static_calls', () => { ]) .send() .wait(); + + // Using the contract interface + await parentContract.methods + .private_get_value_from_child(childContract.address, 42n, wallet.getCompleteAddress().address) + .send() + .wait(); }); it('performs legal (nested) private to private static calls', async () => { @@ -42,10 +72,14 @@ describe('e2e_static_calls', () => { }); it('performs legal public to public static calls', async () => { + // Using low level calls await parentContract.methods .public_static_call(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); + + // Using contract interface + await parentContract.methods.public_get_value_from_child(childContract.address, 42n).send().wait(); }); it('performs legal (nested) public to public static calls', async () => { @@ -56,10 +90,14 @@ describe('e2e_static_calls', () => { }); it('performs legal enqueued public static calls', async () => { + // Using low level calls await parentContract.methods .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); + + // Using contract interface + await parentContract.methods.enqueue_public_get_value_from_child(childContract.address, 42).send().wait(); }); it('performs legal (nested) enqueued public static calls', async () => { @@ -82,7 +120,19 @@ describe('e2e_static_calls', () => { ]) .send() .wait(), - ).rejects.toThrow('Static call cannot create new notes, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing non-static calls to poorly written private static functions', async () => { + await expect( + parentContract.methods + .private_call(childContract.address, childContract.methods.private_illegal_set_value.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CONTEXT_ASSERTION_ERROR); }); it('fails when performing illegal (nested) private to private static calls', async () => { @@ -94,7 +144,7 @@ describe('e2e_static_calls', () => { ]) .send() .wait(), - ).rejects.toThrow('Static call cannot create new notes, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal public to public static calls', async () => { @@ -103,7 +153,7 @@ describe('e2e_static_calls', () => { .public_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal (nested) public to public static calls', async () => { @@ -112,7 +162,7 @@ describe('e2e_static_calls', () => { .public_nested_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal enqueued public static calls', async () => { @@ -123,7 +173,7 @@ describe('e2e_static_calls', () => { ]) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); }); it('fails when performing illegal (nested) enqueued public static calls', async () => { @@ -136,7 +186,115 @@ describe('e2e_static_calls', () => { ) .send() .wait(), - ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing non-static enqueue calls to poorly written public static functions', async () => { + await expect( + parentContract.methods + .enqueue_call(childContract.address, childContract.methods.pub_illegal_inc_value.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CONTEXT_ASSERTION_ERROR); + }); + }); + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/5818): clean up the following tests and either remove the "public" version above or rename these to be the new public. + // There should be 1:1 correspondence between the two sets of tests. + describe('avm', () => { + describe('direct view calls to child', () => { + it('performs legal public static calls', async () => { + await childContract.methods.avm_get_value(42n).send().wait(); + }); + + it('fails when performing non-static calls to poorly written static public functions', async () => { + await expect(childContract.methods.avm_illegal_inc_value(42n).send().wait()).rejects.toThrow( + STATIC_CALL_STATE_MODIFICATION_ERROR, + ); + }); + }); + + describe('parent calls child', () => { + it('performs legal public to public static calls', async () => { + // Using low level calls + await parentContract.methods + .avm_static_call(childContract.address, childContract.methods.avm_get_value.selector, [42n]) + .send() + .wait(); + + // Using contract interface + await parentContract.methods.public_get_value_from_child(childContract.address, 42n).send().wait(); + }); + + it('performs legal enqueued public static calls', async () => { + // Using low level calls + await parentContract.methods + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.avm_get_value.selector, [ + 42n, + ]) + .send() + .wait(); + + // Using contract interface + await parentContract.methods.enqueue_avm_get_value_from_child(childContract.address, 42).send().wait(); + }); + + it('performs legal (nested) public to public static calls', async () => { + await parentContract.methods + .avm_nested_static_call(childContract.address, childContract.methods.avm_get_value.selector, [42n]) + .send() + .wait(); + }); + + it('performs legal (nested) enqueued public static calls', async () => { + await parentContract.methods + .enqueue_static_nested_call_to_avm_function( + childContract.address, + childContract.methods.avm_get_value.selector, + [42n], + ) + .send() + .wait(); + }); + + it('fails when performing illegal enqueued public static calls', async () => { + await expect( + parentContract.methods + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.avm_set_value.selector, [ + 42n, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing illegal (nested) enqueued public static calls', async () => { + await expect( + parentContract.methods + .enqueue_static_nested_call_to_avm_function( + childContract.address, + childContract.methods.avm_set_value.selector, + [42n], + ) + .send() + .wait(), + ).rejects.toThrow(STATIC_CALL_STATE_MODIFICATION_ERROR); + }); + + it('fails when performing non-static enqueue calls to poorly written public static functions', async () => { + await expect( + parentContract.methods + .enqueue_call(childContract.address, childContract.methods.avm_illegal_inc_value.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow(STATIC_CONTEXT_ASSERTION_ERROR); + }); }); }); }); diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index ec11d1ae340..25e9922b5cb 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -10,3 +10,6 @@ export const BITSIZE_TOO_BIG_ERROR = "'self.__assert_max_bit_size(bit_size)'"; export const DUPLICATE_NULLIFIER_ERROR = /dropped|duplicate nullifier|reverted/; export const NO_L1_TO_L2_MSG_ERROR = /No non-nullified L1 to L2 message found for message hash|Tried to consume nonexistent L1-to-L2 message/; +export const STATIC_CALL_STATE_MODIFICATION_ERROR = + /Static call cannot update the state, emit L2->L1 messages or generate logs.*/; +export const STATIC_CONTEXT_ASSERTION_ERROR = /Assertion failed: Function .* can only be called statically.*/; diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index b750f3232f0..87e9a8f1023 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -48,6 +48,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { isInitializer: false, functionType: 'secret', isInternal: false, + isStatic: false, parameters: [ { name: 'app_payload', @@ -82,6 +83,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, @@ -124,6 +126,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index b80307dfc3a..2aca62739c7 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -61,6 +61,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { isInitializer: false, functionType: 'secret', isInternal: false, + isStatic: false, parameters: [ { name: 'payload', @@ -95,6 +96,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { }, }, { name: 'is_public', type: { kind: 'boolean' } }, + { name: 'is_static', type: { kind: 'boolean' } }, ], }, }, diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index ff1be9bcdd7..da33e70473b 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -165,6 +165,10 @@ export interface FunctionAbi { * Whether the function is internal. */ isInternal: boolean; + /** + * Whether the function can alter state or not + */ + isStatic: boolean; /** * Function parameters. */ diff --git a/yarn-project/foundation/src/abi/encoder.test.ts b/yarn-project/foundation/src/abi/encoder.test.ts index f78e1325dfd..a38b963e9d0 100644 --- a/yarn-project/foundation/src/abi/encoder.test.ts +++ b/yarn-project/foundation/src/abi/encoder.test.ts @@ -11,6 +11,7 @@ describe('abi/encoder', () => { functionType: FunctionType.SECRET, isInternal: false, isInitializer: true, + isStatic: false, parameters: [ { name: 'owner', @@ -33,6 +34,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -57,6 +59,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -82,6 +85,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -117,6 +121,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'contract_class', @@ -148,6 +153,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', @@ -170,6 +176,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'isOwner', @@ -195,6 +202,7 @@ describe('abi/encoder', () => { isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, + isStatic: false, parameters: [ { name: 'owner', diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts index f03c01e1876..5ba1e2b0b2a 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts @@ -47,7 +47,7 @@ describe('Noir<>Circuits.js type conversion test suite', () => { expect(mapFunctionSelectorFromNoir(mapFunctionSelectorToNoir(functionSelector))).toEqual(functionSelector); }); - const functionData = new FunctionData(functionSelector, true); + const functionData = new FunctionData(functionSelector, /*isPrivate=*/ true, /*isStatic=*/ false); it('should map function data', () => { expect(mapFunctionDataFromNoir(mapFunctionDataToNoir(functionData))).toEqual(functionData); diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index b2ccda0887f..360c3f19bd3 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -406,6 +406,7 @@ export function mapFunctionDataToNoir(functionData: FunctionData): FunctionDataN return { selector: mapFunctionSelectorToNoir(functionData.selector), is_private: functionData.isPrivate, + is_static: functionData.isStatic, }; } @@ -415,7 +416,11 @@ export function mapFunctionDataToNoir(functionData: FunctionData): FunctionDataN * @returns The function data. */ export function mapFunctionDataFromNoir(functionData: FunctionDataNoir): FunctionData { - return new FunctionData(mapFunctionSelectorFromNoir(functionData.selector), functionData.is_private); + return new FunctionData( + mapFunctionSelectorFromNoir(functionData.selector), + functionData.is_private, + functionData.is_static, + ); } /** diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 91c00795841..c94dd96973a 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -45,6 +45,7 @@ import { Timer } from '@aztec/foundation/timer'; import { type AcirSimulator, type ExecutionResult, + accumulateReturnValues, collectEnqueuedPublicFunctionCalls, collectPublicTeardownFunctionCall, collectSortedEncryptedLogs, @@ -465,7 +466,7 @@ export class PXEService implements PXE { return txHash; } - public async viewTx( + public async simulateUnconstrained( functionName: string, args: any[], to: AztecAddress, @@ -681,7 +682,8 @@ export class PXEService implements PXE { enqueuedPublicFunctions, teardownPublicFunction, ); - return new SimulatedTx(tx, executionResult.returnValues); + + return new SimulatedTx(tx, accumulateReturnValues(executionResult)); } /** diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index f367253bdeb..6d7422be7b4 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -143,7 +143,7 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => ); }); - // Note: Not testing a successful run of `proveTx`, `sendTx`, `getTxReceipt` and `viewTx` here as it requires + // Note: Not testing a successful run of `proveTx`, `sendTx`, `getTxReceipt` and `simulateUnconstrained` here as it requires // a larger setup and it's sufficiently tested in the e2e tests. it('throws when getting public storage for non-existent contract', async () => { diff --git a/yarn-project/simulator/src/avm/avm_execution_environment.ts b/yarn-project/simulator/src/avm/avm_execution_environment.ts index e57f94eecda..411b9d60ff4 100644 --- a/yarn-project/simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/simulator/src/avm/avm_execution_environment.ts @@ -1,15 +1,15 @@ import { FunctionSelector, type GasSettings, type GlobalVariables, type Header } from '@aztec/circuits.js'; import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { type Fr } from '@aztec/foundation/fields'; +import { Fr } from '@aztec/foundation/fields'; export class AvmContextInputs { - static readonly SIZE = 2; + static readonly SIZE = 3; - constructor(private selector: Fr, private argsHash: Fr) {} + constructor(private selector: Fr, private argsHash: Fr, private isStaticCall: boolean) {} public toFields(): Fr[] { - return [this.selector, this.argsHash]; + return [this.selector, this.argsHash, new Fr(this.isStaticCall)]; } } @@ -41,7 +41,11 @@ export class AvmExecutionEnvironment { ) { // We encode some extra inputs (AvmContextInputs) in calldata. // This will have to go once we move away from one proof per call. - const inputs = new AvmContextInputs(temporaryFunctionSelector.toField(), computeVarArgsHash(calldata)); + const inputs = new AvmContextInputs( + temporaryFunctionSelector.toField(), + computeVarArgsHash(calldata), + isStaticCall, + ); this.calldata = [...inputs.toFields(), ...calldata]; } diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 8c06e9b1b76..148cddf078e 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -439,7 +439,7 @@ export class ClientExecutionContext extends ViewDataOracle { childExecutionResult.callStackItem.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) || childExecutionResult.callStackItem.publicInputs.unencryptedLogsHashes.some(item => !item.isEmpty()) ) { - throw new Error(`Static call cannot create new notes, emit L2->L1 messages or generate logs`); + throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`); } } @@ -450,7 +450,7 @@ export class ClientExecutionContext extends ViewDataOracle { * @param argsHash - The packed arguments to pass to the function. * @param sideEffectCounter - The side effect counter at the start of the call. * @param isStaticCall - Whether the call is a static call. - * @param isStaticCall - Whether the call is a delegate call. + * @param isDelegateCall - Whether the call is a delegate call. * @returns The execution result. */ override async callPrivateFunction( diff --git a/yarn-project/simulator/src/client/simulator.ts b/yarn-project/simulator/src/client/simulator.ts index 1c3c8490f84..90ea5d3deee 100644 --- a/yarn-project/simulator/src/client/simulator.ts +++ b/yarn-project/simulator/src/client/simulator.ts @@ -88,7 +88,7 @@ export class AcirSimulator { contractAddress, FunctionSelector.fromNameAndParameters(entryPointArtifact.name, entryPointArtifact.parameters), false, - false, + entryPointArtifact.isStatic, startSideEffectCounter, ); const context = new ClientExecutionContext( diff --git a/yarn-project/simulator/src/client/unconstrained_execution.test.ts b/yarn-project/simulator/src/client/unconstrained_execution.test.ts index 9077aa0489e..5a901e8aeda 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.test.ts @@ -63,7 +63,7 @@ describe('Unconstrained Execution test suite', () => { const execRequest: FunctionCall = { to: contractAddress, - functionData: new FunctionData(FunctionSelector.empty(), true), + functionData: new FunctionData(FunctionSelector.empty(), /*isPrivate=*/ true, /*isStatic=*/ false), args: encodeArguments(artifact, [owner]), }; diff --git a/yarn-project/simulator/src/common/index.ts b/yarn-project/simulator/src/common/index.ts index 9e61c2e99e5..b10327ec983 100644 --- a/yarn-project/simulator/src/common/index.ts +++ b/yarn-project/simulator/src/common/index.ts @@ -1,3 +1,4 @@ export * from './packed_values_cache.js'; export * from './errors.js'; export * from './side_effect_counter.js'; +export * from './return_values.js'; diff --git a/yarn-project/simulator/src/common/return_values.ts b/yarn-project/simulator/src/common/return_values.ts new file mode 100644 index 00000000000..1878c8c673d --- /dev/null +++ b/yarn-project/simulator/src/common/return_values.ts @@ -0,0 +1,18 @@ +import { NestedProcessReturnValues } from '@aztec/circuit-types'; + +import type { ExecutionResult } from '../client/execution_result.js'; +import type { PublicExecutionResult } from '../public/execution.js'; + +/** + * Recursively accummulate the return values of a call result and its nested executions, + * so they can be retrieved in order. + * @param executionResult + * @returns + */ +export function accumulateReturnValues( + executionResult: PublicExecutionResult | ExecutionResult, +): NestedProcessReturnValues { + const acc = new NestedProcessReturnValues(executionResult.returnValues); + acc.nested = executionResult.nestedExecutions.map(nestedExecution => accumulateReturnValues(nestedExecution)); + return acc; +} diff --git a/yarn-project/simulator/src/mocks/fixtures.ts b/yarn-project/simulator/src/mocks/fixtures.ts index da4763a3ca0..3b2ca84d697 100644 --- a/yarn-project/simulator/src/mocks/fixtures.ts +++ b/yarn-project/simulator/src/mocks/fixtures.ts @@ -133,7 +133,7 @@ export const makeFunctionCall = ( to = makeAztecAddress(30), selector = makeSelector(5), args = new Array(ARGS_LENGTH).fill(Fr.ZERO), -) => ({ to, functionData: new FunctionData(selector, false), args }); +) => ({ to, functionData: new FunctionData(selector, /*isPrivate=*/ false, /*isStatic=*/ false), args }); export function addKernelPublicCallStack( kernelOutput: PrivateKernelTailCircuitPublicInputs, diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index f9c0dd25aff..2d066f8345f 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -1,6 +1,6 @@ import { MerkleTreeId, - type ProcessReturnValues, + type NestedProcessReturnValues, type PublicKernelRequest, PublicKernelType, type SimulationError, @@ -57,6 +57,7 @@ import { type PublicExecution, type PublicExecutionResult, type PublicExecutor, + accumulateReturnValues, collectPublicDataReads, collectPublicDataUpdateRequests, isPublicExecutionResult, @@ -140,7 +141,7 @@ export abstract class AbstractPhaseManager { * revert reason, if any */ revertReason: SimulationError | undefined; - returnValues: ProcessReturnValues; + returnValues: NestedProcessReturnValues[]; /** Gas used during the execution this particular phase. */ gasUsed: Gas | undefined; }>; @@ -227,7 +228,7 @@ export abstract class AbstractPhaseManager { Proof, UnencryptedFunctionL2Logs[], SimulationError | undefined, - ProcessReturnValues, + NestedProcessReturnValues[], Gas, ] > { @@ -238,7 +239,7 @@ export abstract class AbstractPhaseManager { const enqueuedCalls = this.extractEnqueuedPublicCalls(tx); if (!enqueuedCalls || !enqueuedCalls.length) { - return [[], kernelOutput, kernelProof, [], undefined, undefined, Gas.empty()]; + return [[], kernelOutput, kernelProof, [], undefined, [], Gas.empty()]; } const newUnencryptedFunctionLogs: UnencryptedFunctionL2Logs[] = []; @@ -250,9 +251,10 @@ export abstract class AbstractPhaseManager { // separate public callstacks to be proven by separate public kernel sequences // and submitted separately to the base rollup? - let returns: ProcessReturnValues = undefined; let gasUsed = Gas.empty(); + const enqueuedCallResults = []; + for (const enqueuedCall of enqueuedCalls) { const executionStack: (PublicExecution | PublicExecutionResult)[] = [enqueuedCall]; @@ -334,13 +336,14 @@ export abstract class AbstractPhaseManager { }`, ); // TODO(@spalladino): Check gasUsed is correct. The AVM should take care of setting gasLeft to zero upon a revert. - return [[], kernelOutput, kernelProof, [], result.revertReason, undefined, gasUsed]; + return [[], kernelOutput, kernelProof, [], result.revertReason, [], gasUsed]; } if (!enqueuedExecutionResult) { enqueuedExecutionResult = result; - returns = result.returnValues; } + + enqueuedCallResults.push(accumulateReturnValues(enqueuedExecutionResult)); } // HACK(#1622): Manually patches the ordering of public state actions // TODO(#757): Enforce proper ordering of public state actions @@ -350,7 +353,15 @@ export abstract class AbstractPhaseManager { // TODO(#3675): This should be done in a public kernel circuit removeRedundantPublicDataWrites(kernelOutput, this.phase); - return [publicKernelInputs, kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined, returns, gasUsed]; + return [ + publicKernelInputs, + kernelOutput, + kernelProof, + newUnencryptedFunctionLogs, + undefined, + enqueuedCallResults, + gasUsed, + ]; } /** Returns all pending private and public nullifiers. */ diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index fb3d199d30c..2923b7dd0b5 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -184,7 +184,7 @@ describe('ACIR public execution simulator', () => { beforeEach(() => { transferArtifact = TokenContractArtifact.functions.find(f => f.name === 'transfer_public')!; - functionData = new FunctionData(FunctionSelector.empty(), false); + functionData = new FunctionData(FunctionSelector.empty(), /*isPrivate=*/ false, /*isStatic=*/ false); sender = AztecAddress.random(); args = encodeArguments(transferArtifact, [sender, recipient, 140n, 0n]); @@ -265,7 +265,7 @@ describe('ACIR public execution simulator', () => { parentEntryPointFn.name, parentEntryPointFn.parameters, ); - functionData = new FunctionData(parentEntryPointFnSelector, false); + functionData = new FunctionData(parentEntryPointFnSelector, /*isPrivate=*/ false, /*isStatic=*/ false); childContractAddress = AztecAddress.random(); callContext = makeCallContext(parentContractAddress); }, 10000); @@ -354,7 +354,7 @@ describe('ACIR public execution simulator', () => { beforeEach(async () => { contractAddress = AztecAddress.random(); await mockInitializationNullifierCallback(contractAddress); - functionData = new FunctionData(FunctionSelector.empty(), false); + functionData = new FunctionData(FunctionSelector.empty(), /*isPrivate=*/ false, /*isStatic=*/ false); amount = new Fr(1); params = [amount, new Fr(1)]; }); diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index e8c6fefcda8..144c00ee509 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -212,7 +212,7 @@ export class PublicExecutionContext extends TypedOracle { `Public function call: addr=${targetContractAddress} selector=${functionSelector} args=${args.join(',')}`, ); - const functionData = new FunctionData(functionSelector, /*isPrivate=*/ false); + const functionData = new FunctionData(functionSelector, /*isPrivate=*/ false, /*isStatic=*/ false); const callContext = CallContext.from({ msgSender: isDelegateCall ? this.execution.callContext.msgSender : this.execution.contractAddress, storageContractAddress: isDelegateCall ? this.execution.contractAddress : targetContractAddress, diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index 360ed52b889..e17b20f17ed 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -1,7 +1,7 @@ import { type BlockProver, type FailedTx, - type ProcessReturnValues, + NestedProcessReturnValues, type ProcessedTx, type PublicKernelRequest, type SimulationError, @@ -96,12 +96,12 @@ export class PublicProcessor { maxTransactions = txs.length, blockProver?: BlockProver, txValidator?: TxValidator, - ): Promise<[ProcessedTx[], FailedTx[], ProcessReturnValues[]]> { + ): Promise<[ProcessedTx[], FailedTx[], NestedProcessReturnValues[]]> { // The processor modifies the tx objects in place, so we need to clone them. txs = txs.map(tx => Tx.clone(tx)); const result: ProcessedTx[] = []; const failed: FailedTx[] = []; - const returns: ProcessReturnValues[] = []; + const returns: NestedProcessReturnValues[] = []; for (const tx of txs) { // only process up to the limit of the block @@ -129,7 +129,7 @@ export class PublicProcessor { await blockProver.addNewTx(processedTx); } result.push(processedTx); - returns.push(returnValues); + returns.push(returnValues?.[0] ?? new NestedProcessReturnValues([])); } catch (err: any) { const errorMessage = err instanceof Error ? err.message : 'Unknown error'; this.log.warn(`Failed to process tx ${tx.getTxHash()}: ${errorMessage}`); @@ -138,7 +138,7 @@ export class PublicProcessor { tx, error: err instanceof Error ? err : new Error(errorMessage), }); - returns.push([]); + returns.push(new NestedProcessReturnValues([])); } } @@ -154,8 +154,8 @@ export class PublicProcessor { return makeEmptyProcessedTx(this.historicalHeader.clone(), chainId, version); } - private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, ProcessReturnValues | undefined]> { - let returnValues: ProcessReturnValues = undefined; + private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> { + let returnValues: NestedProcessReturnValues[] = []; const publicRequests: PublicKernelRequest[] = []; let phase: AbstractPhaseManager | undefined = PhaseManagerFactory.phaseFromTx( tx, diff --git a/yarn-project/simulator/src/public/setup_phase_manager.ts b/yarn-project/simulator/src/public/setup_phase_manager.ts index 33581b36f5b..0573f57ca4d 100644 --- a/yarn-project/simulator/src/public/setup_phase_manager.ts +++ b/yarn-project/simulator/src/public/setup_phase_manager.ts @@ -67,7 +67,7 @@ export class SetupPhaseManager extends AbstractPhaseManager { publicKernelOutput, publicKernelProof, revertReason, - returnValues: undefined, + returnValues: [], gasUsed, }; } diff --git a/yarn-project/simulator/src/public/tail_phase_manager.ts b/yarn-project/simulator/src/public/tail_phase_manager.ts index be324885e6f..f3c40635793 100644 --- a/yarn-project/simulator/src/public/tail_phase_manager.ts +++ b/yarn-project/simulator/src/public/tail_phase_manager.ts @@ -70,7 +70,7 @@ export class TailPhaseManager extends AbstractPhaseManager { finalKernelOutput, publicKernelProof: makeEmptyProof(), revertReason: undefined, - returnValues: undefined, + returnValues: [], gasUsed: undefined, }; } diff --git a/yarn-project/simulator/src/public/teardown_phase_manager.ts b/yarn-project/simulator/src/public/teardown_phase_manager.ts index 55b1b765630..7a40812a46c 100644 --- a/yarn-project/simulator/src/public/teardown_phase_manager.ts +++ b/yarn-project/simulator/src/public/teardown_phase_manager.ts @@ -71,7 +71,7 @@ export class TeardownPhaseManager extends AbstractPhaseManager { publicKernelOutput, publicKernelProof, revertReason, - returnValues: undefined, + returnValues: [], gasUsed, }; } diff --git a/yarn-project/simulator/src/public/transitional_adaptors.ts b/yarn-project/simulator/src/public/transitional_adaptors.ts index 74e6d004788..0f2248e348c 100644 --- a/yarn-project/simulator/src/public/transitional_adaptors.ts +++ b/yarn-project/simulator/src/public/transitional_adaptors.ts @@ -65,7 +65,11 @@ export function createPublicExecution( isStaticCall: avmEnvironment.isStaticCall, sideEffectCounter: startSideEffectCounter, }); - const functionData = new FunctionData(avmEnvironment.temporaryFunctionSelector, /*isPrivate=*/ false); + const functionData = new FunctionData( + avmEnvironment.temporaryFunctionSelector, + /*isPrivate=*/ false, + /*isStatic=*/ false, + ); const execution: PublicExecution = { contractAddress: avmEnvironment.address, callContext, diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 0998899167e..9758e85650d 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -20,6 +20,7 @@ import { AZTEC_PRIVATE_ATTRIBUTE, AZTEC_PUBLIC_ATTRIBUTE, AZTEC_PUBLIC_VM_ATTRIBUTE, + AZTEC_VIEW_ATTRIBUTE, type NoirCompiledContract, } from '../noir/index.js'; import { mockVerificationKey } from './mocked_keys.js'; @@ -138,6 +139,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No } const functionType = getFunctionType(fn); const isInternal = fn.custom_attributes.includes(AZTEC_INTERNAL_ATTRIBUTE); + const isStatic = fn.custom_attributes.includes(AZTEC_VIEW_ATTRIBUTE); // If the function is not unconstrained, the first item is inputs or CallContext which we should omit let parameters = fn.abi.parameters.map(generateFunctionParameter); @@ -170,6 +172,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No name: fn.name, functionType, isInternal, + isStatic, isInitializer: fn.custom_attributes.includes(AZTEC_INITIALIZER_ATTRIBUTE), parameters, returnTypes, diff --git a/yarn-project/types/src/noir/index.ts b/yarn-project/types/src/noir/index.ts index 56a449d8ef0..f268071eae0 100644 --- a/yarn-project/types/src/noir/index.ts +++ b/yarn-project/types/src/noir/index.ts @@ -12,6 +12,7 @@ export const AZTEC_PUBLIC_ATTRIBUTE = 'aztec(public)'; export const AZTEC_PUBLIC_VM_ATTRIBUTE = 'aztec(public-vm)'; export const AZTEC_INTERNAL_ATTRIBUTE = 'aztec(internal)'; export const AZTEC_INITIALIZER_ATTRIBUTE = 'aztec(initializer)'; +export const AZTEC_VIEW_ATTRIBUTE = 'aztec(view)'; /** The witness indices of the parameters. */ type ParamWitnessIndices = { /** Start */ start: number; /** End */ end: number }; From 72931bdb8202c34042cdfb8cee2ef44b75939879 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Mon, 20 May 2024 13:52:19 +0100 Subject: [PATCH 20/37] chore: add c++ tests for generator derivation (#6528) This PR adds some tests just to give ground truth values for `hash_to_curve` and `derive_generators` which can replicated in test suites for reimplementations of this logic [elsewhere](https://github.com/noir-lang/noir/pull/4871) --- .../src/barretenberg/crypto/CMakeLists.txt | 1 + .../crypto/generators/CMakeLists.txt | 1 + .../crypto/generators/generator_data.test.cpp | 45 +++++++++++++++++++ .../crypto/pedersen_hash/pedersen.test.cpp | 11 +++++ .../ecc/groups/affine_element.test.cpp | 30 ++++++++++++- 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 barretenberg/cpp/src/barretenberg/crypto/generators/CMakeLists.txt create mode 100644 barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/crypto/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/crypto/CMakeLists.txt index 5ea623e144e..1319f7bc668 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/crypto/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(hmac) add_subdirectory(blake2s) add_subdirectory(blake3s) add_subdirectory(blake3s_full) +add_subdirectory(generators) add_subdirectory(keccak) add_subdirectory(pedersen_commitment) add_subdirectory(pedersen_hash) diff --git a/barretenberg/cpp/src/barretenberg/crypto/generators/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/crypto/generators/CMakeLists.txt new file mode 100644 index 00000000000..73215b66e35 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/crypto/generators/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(crypto_generator_data ecc) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.test.cpp new file mode 100644 index 00000000000..c3bea7555f3 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/crypto/generators/generator_data.test.cpp @@ -0,0 +1,45 @@ +#include "generator_data.hpp" +#include "barretenberg/crypto/pedersen_commitment/c_bind.hpp" +#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +#include +#include + +namespace bb::crypto { + +TEST(GeneratorContext, DeriveDefaultGenerators) +{ + auto default_generators = generator_data::make_precomputed_generators(); + std::vector expected_default_generators; + + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("083e7911d835097629f0067531fc15cafd79a89beecb39903f69572c636f4a5a")), + fr(uint256_t("1a7f5efaad7f315c25a918f30cc8d7333fccab7ad7c90f14de81bcc528f9935d")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402")), + fr(uint256_t("209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("1c44f2a5207c81c28a8321a5815ce8b1311024bbed131819bbdaf5a2ada84748")), + fr(uint256_t("03aaee36e6422a1d0191632ac6599ae9eba5ac2c17a8c920aa3caf8b89c5f8a8")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("26d8b1160c6821a30c65f6cb47124afe01c29f4338f44d4a12c9fccf22fb6fb2")), + fr(uint256_t("05c70c3b9c0d25a4c100e3a27bf3cc375f8af8cdd9498ec4089a823d7464caff")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("20ed9c6a1d27271c4498bfce0578d59db1adbeaa8734f7facc097b9b994fcf6e")), + fr(uint256_t("29cd7d370938b358c62c4a00f73a0d10aba7e5aaa04704a0713f891ebeb92371")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("0224a8abc6c8b8d50373d64cd2a1ab1567bf372b3b1f7b861d7f01257052d383")), + fr(uint256_t("2358629b90eafb299d6650a311e79914b0215eb0a790810b26da5a826726d711")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("0f106f6d46bc904a5290542490b2f238775ff3c445b2f8f704c466655f460a2a")), + fr(uint256_t("29ab84d472f1d33f42fe09c47b8f7710f01920d6155250126731e486877bcf27")) })); + expected_default_generators.emplace_back(grumpkin::g1::affine_element( + { fr(uint256_t("0298f2e42249f0519c8a8abd91567ebe016e480f219b8c19461d6a595cc33696")), + fr(uint256_t("035bec4b8520a4ece27bd5aafabee3dfe1390d7439c419a8c55aceb207aac83b")) })); + + EXPECT_EQ(default_generators.size(), expected_default_generators.size()); + for (size_t i = 0; i < default_generators.size(); ++i) { + EXPECT_EQ(default_generators[i], expected_default_generators[i]); + } +} + +} // namespace bb::crypto \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp index 0e4ade6fca1..e920357626f 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp @@ -1,5 +1,6 @@ #include "pedersen.hpp" #include "barretenberg/crypto/generators/generator_data.hpp" +#include "barretenberg/crypto/pedersen_commitment/c_bind.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include @@ -7,6 +8,16 @@ namespace bb::crypto { using bb::fr; +TEST(Pedersen, DeriveLengthGenerator) +{ + auto generator = pedersen_hash::length_generator; + std::cout << generator << std::endl; + EXPECT_EQ(generator, + grumpkin::g1::affine_element( + fr(uint256_t("0x2df8b940e5890e4e1377e05373fae69a1d754f6935e6a780b666947431f2cdcd")), + fr(uint256_t("0x2ecd88d15967bc53b885912e0d16866154acb6aac2d3f85e27ca7eefb2c19083")))); +} + TEST(Pedersen, Hash) { auto x = pedersen_hash::Fq::one(); diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp index 4c36b16c9d4..94b24d95872 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using ::testing::Each; using ::testing::ElementsAreArray; @@ -254,4 +255,31 @@ TYPED_TEST(TestAffineElement, BatchEndomoprhismByMinusOne) } else { GTEST_SKIP(); } -} \ No newline at end of file +} + +TEST(AffineElement, HashToCurve) +{ + std::vector, grumpkin::g1::affine_element>> test_vectors; + test_vectors.emplace_back(std::vector(), + grumpkin::g1::affine_element( + fr(uint256_t("24c4cb9c1206ab5470592f237f1698abe684dadf0ab4d7a132c32b2134e2c12e")), + fr(uint256_t("0668b8d61a317fb34ccad55c930b3554f1828a0e5530479ecab4defe6bbc0b2e")))); + + test_vectors.emplace_back(std::vector{ 1 }, + grumpkin::g1::affine_element( + fr(uint256_t("107f1b633c6113f3222f39f6256f0546b41a4880918c86864b06471afb410454")), + fr(uint256_t("050cd3823d0c01590b6a50adcc85d2ee4098668fd28805578aa05a423ea938c6")))); + + // "hello world" + test_vectors.emplace_back(std::vector{ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 }, + grumpkin::g1::affine_element( + fr(uint256_t("037c5c229ae495f6e8d1b4bf7723fafb2b198b51e27602feb8a4d1053d685093")), + fr(uint256_t("10cf9596c5b2515692d930efa2cf3817607e4796856a79f6af40c949b066969f")))); + + for (std::tuple, grumpkin::g1::affine_element> test_case : test_vectors) { + auto result = grumpkin::g1::affine_element::hash_to_curve(std::get<0>(test_case), 0); + auto expected_result = std::get<1>(test_case); + std::cout << result << std::endl; + EXPECT_TRUE(result == expected_result); + } +} From 07dc0726501bc78d691e1d2360dda84d1a93b9c5 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 20 May 2024 14:11:14 +0100 Subject: [PATCH 21/37] refactor: private call validation (#6510) Emitting private call requests from app circuit instead of passing them via private inputs. Added the checks for: static calls, constants. Removed the check for public call request counter ranges. --- .../vm/avm_trace/aztec_constants.hpp | 9 +- .../src/core/libraries/ConstantsGen.sol | 10 +- .../aztec/src/context/private_context.nr | 38 ++-- .../src/private_call_data_validator.nr | 186 +++++++----------- ...e_kernel_circuit_public_inputs_composer.nr | 26 ++- .../src/private_kernel_init.nr | 12 +- .../src/private_kernel_inner.nr | 4 +- .../crates/private-kernel-lib/src/tests.nr | 2 + .../private_call_data_validator_builder.nr | 18 +- .../tests/validate_against_call_request.nr | 56 +++++- .../tests/validate_against_previous_kernel.nr | 49 +++++ .../src/tests/validate_arrays.nr | 21 +- .../src/tests/validate_as_first_call.nr | 84 ++------ .../src/tests/validate_call_requests.nr | 108 +--------- .../src/tests/validate_counters.nr | 42 ++-- .../tests/validate_private_call_requests.nr | 93 +++++++++ .../rollup-lib/src/base/base_rollup_inputs.nr | 10 +- .../crates/types/src/abis.nr | 1 + .../private_accumulated_data.nr | 8 +- .../private_accumulated_data_builder.nr | 35 ++-- .../crates/types/src/abis/caller_context.nr | 17 +- .../types/src/abis/private_call_request.nr | 152 ++++++++++++++ .../types/src/abis/private_call_stack_item.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 51 ++++- .../abis/private_kernel/private_call_data.nr | 3 +- .../crates/types/src/abis/side_effect.nr | 5 + .../crates/types/src/constants.nr | 8 +- .../crates/types/src/tests/fixture_builder.nr | 24 ++- .../crates/types/src/tests/fixtures.nr | 4 + .../src/tests/private_call_data_builder.nr | 38 ++-- .../private_circuit_public_inputs_builder.nr | 45 +++-- .../crates/types/src/utils/reader.nr | 4 + yarn-project/circuits.js/src/constants.gen.ts | 8 +- .../private_call_stack_item.test.ts.snap | 4 +- ...private_circuit_public_inputs.test.ts.snap | 4 +- .../circuits.js/src/structs/call_request.ts | 65 +----- .../circuits.js/src/structs/caller_context.ts | 80 ++++++++ yarn-project/circuits.js/src/structs/index.ts | 2 + .../kernel/private_accumulated_data.ts | 8 +- .../src/structs/kernel/private_call_data.ts | 7 - ...vate_kernel_init_circuit_private_inputs.ts | 7 +- .../src/structs/private_call_request.ts | 109 ++++++++++ .../src/structs/private_call_stack_item.ts | 26 +-- .../structs/private_circuit_public_inputs.ts | 15 +- .../src/structs/public_call_request.ts | 9 +- .../src/structs/public_call_stack_item.ts | 9 +- .../circuits.js/src/tests/factories.ts | 33 +--- .../end-to-end/src/e2e_outbox.test.ts | 2 +- .../src/type_conversion.ts | 46 ++++- .../src/kernel_prover/kernel_prover.test.ts | 4 +- .../pxe/src/kernel_prover/kernel_prover.ts | 18 +- .../build_private_kernel_init_hints.ts | 19 +- .../src/client/private_execution.test.ts | 2 +- 53 files changed, 991 insertions(+), 651 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_previous_kernel.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_private_call_requests.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_request.nr create mode 100644 yarn-project/circuits.js/src/structs/caller_context.ts create mode 100644 yarn-project/circuits.js/src/structs/private_call_request.ts diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp index f5e8bf5a97e..3e66247d244 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp @@ -101,6 +101,9 @@ const size_t NOTE_HASH_LENGTH = 2; const size_t SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; const size_t NULLIFIER_LENGTH = 3; const size_t SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; +const size_t CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH + 1; +const size_t PRIVATE_CALL_REQUEST_LENGTH = 3 + CALLER_CONTEXT_LENGTH; +const size_t SCOPED_PRIVATE_CALL_REQUEST_LENGTH = PRIVATE_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; const size_t SIDE_EFFECT_LENGTH = 2; const size_t ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; const size_t STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; @@ -113,7 +116,7 @@ const size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; @@ -143,13 +146,13 @@ const size_t COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 5 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; const size_t COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; -const size_t CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; const size_t CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; const size_t PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + - (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + + (SCOPED_PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); const size_t PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 80f12f36f82..c91cdc95813 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -130,6 +130,10 @@ library Constants { uint256 internal constant SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; uint256 internal constant NULLIFIER_LENGTH = 3; uint256 internal constant SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; + uint256 internal constant CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH + 1; + uint256 internal constant PRIVATE_CALL_REQUEST_LENGTH = 3 + CALLER_CONTEXT_LENGTH; + uint256 internal constant SCOPED_PRIVATE_CALL_REQUEST_LENGTH = + PRIVATE_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; uint256 internal constant SIDE_EFFECT_LENGTH = 2; uint256 internal constant ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; uint256 internal constant STATE_REFERENCE_LENGTH = @@ -143,7 +147,8 @@ library Constants { + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) - + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) @@ -177,7 +182,6 @@ library Constants { + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; - uint256 internal constant CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; uint256 internal constant CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = ( @@ -186,7 +190,7 @@ library Constants { + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) - + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + + (SCOPED_PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 645ea474ad2..db4b82441c1 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -17,9 +17,9 @@ use crate::{ use dep::protocol_types::{ hash::sha256_to_field, abis::{ - function_selector::FunctionSelector, max_block_number::MaxBlockNumber, - nullifier_key_validation_request::NullifierKeyValidationRequest, - private_circuit_public_inputs::PrivateCircuitPublicInputs, + caller_context::CallerContext, function_selector::FunctionSelector, + max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequest, + private_call_request::PrivateCallRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, public_call_stack_item::PublicCallStackItem, read_request::ReadRequest, note_hash::NoteHash, nullifier::Nullifier, log_hash::{LogHash, NoteLogHash} }, @@ -58,7 +58,7 @@ struct PrivateContext { new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, - private_call_stack_hashes : BoundedVec, + private_call_requests : BoundedVec, public_call_stack_hashes : BoundedVec, public_teardown_function_hash: Field, new_l2_to_l1_msgs : BoundedVec, @@ -124,7 +124,7 @@ impl PrivateContext { new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), historical_header: inputs.historical_header, - private_call_stack_hashes: BoundedVec::new(), + private_call_requests: BoundedVec::new(), public_call_stack_hashes: BoundedVec::new(), public_teardown_function_hash: 0, new_l2_to_l1_msgs: BoundedVec::new(), @@ -165,7 +165,7 @@ impl PrivateContext { nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, - private_call_stack_hashes: self.private_call_stack_hashes.storage, + private_call_requests: self.private_call_requests.storage, public_call_stack_hashes: self.public_call_stack_hashes.storage, public_teardown_function_hash: self.public_teardown_function_hash, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, @@ -409,18 +409,20 @@ impl PrivateContext { is_delegate_call: bool ) -> PackedReturns { let mut is_static_call = is_static_call | self.inputs.call_context.is_static_call; + let start_side_effect_counter = self.side_effect_counter; let item = call_private_function_internal( contract_address, function_selector, args_hash, - self.side_effect_counter, + start_side_effect_counter, is_static_call, is_delegate_call ); - assert_eq(item.public_inputs.call_context.side_effect_counter, self.side_effect_counter); - assert_eq(item.public_inputs.start_side_effect_counter, self.side_effect_counter); - self.side_effect_counter = item.public_inputs.end_side_effect_counter + 1; + assert_eq(item.public_inputs.call_context.side_effect_counter, start_side_effect_counter); + assert_eq(item.public_inputs.start_side_effect_counter, start_side_effect_counter); + let end_side_effect_counter = item.public_inputs.end_side_effect_counter; + self.side_effect_counter = end_side_effect_counter + 1; // TODO (fees) figure out why this crashes the prover and enable it // we need this in order to pay fees inside child call contexts @@ -458,7 +460,15 @@ impl PrivateContext { ); } - self.private_call_stack_hashes.push(item.hash()); + let mut caller_context = CallerContext::empty(); + caller_context.is_static_call = self.inputs.call_context.is_static_call; + if is_delegate_call { + caller_context.msg_sender = self.inputs.call_context.msg_sender; + caller_context.storage_contract_address = self.inputs.call_context.storage_contract_address; + } + self.private_call_requests.push( + PrivateCallRequest { hash: item.hash(), caller_context, start_side_effect_counter, end_side_effect_counter } + ); PackedReturns::new(item.public_inputs.returns_hash) } @@ -652,10 +662,10 @@ impl Empty for PrivateContext { nullifier_key_validation_requests: BoundedVec::new(), new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), - private_call_stack_hashes : BoundedVec::new(), - public_call_stack_hashes : BoundedVec::new(), + private_call_requests: BoundedVec::new(), + public_call_stack_hashes: BoundedVec::new(), public_teardown_function_hash: 0, - new_l2_to_l1_msgs : BoundedVec::new(), + new_l2_to_l1_msgs: BoundedVec::new(), historical_header: Header::empty(), note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr index 98dcf2727f8..dece7c74d60 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr @@ -1,51 +1,30 @@ use dep::types::{ abis::{ - call_context::CallContext, call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, - private_kernel::private_call_data::PrivateCallData, side_effect::Ordered + call_context::CallContext, call_request::CallRequest, caller_context::CallerContext, + kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, + private_call_request::ScopedPrivateCallRequest, private_call_stack_item::PrivateCallStackItem, + private_circuit_public_inputs::PrivateCircuitPublicInputsArrayLengths, + private_kernel::private_call_data::PrivateCallData, side_effect::{Ordered, RangeOrdered} }, address::{AztecAddress, PartialAddress}, contract_class_id::ContractClassId, hash::{private_functions_root_from_siblings, stdlib_recursion_verification_key_compress_native_vk}, - traits::{is_empty, is_empty_array}, transaction::tx_request::TxRequest, - utils::arrays::{array_length, validate_array} + traits::is_empty, transaction::tx_request::TxRequest }; -fn validate_arrays(data: PrivateCallData) -> ArrayLengths { - let public_inputs = data.call_stack_item.public_inputs; - - // Each of the following arrays is expected to be zero-padded. - ArrayLengths { - note_hash_read_requests: validate_array(public_inputs.note_hash_read_requests), - nullifier_read_requests: validate_array(public_inputs.nullifier_read_requests), - nullifier_key_validation_requests: validate_array(public_inputs.nullifier_key_validation_requests), - new_note_hashes: validate_array(public_inputs.new_note_hashes), - new_nullifiers: validate_array(public_inputs.new_nullifiers), - new_l2_to_l1_msgs: validate_array(public_inputs.new_l2_to_l1_msgs), - private_call_stack_hashes: validate_array(public_inputs.private_call_stack_hashes), - public_call_stack_hashes: validate_array(public_inputs.public_call_stack_hashes), - note_encrypted_logs_hashes: validate_array(public_inputs.note_encrypted_logs_hashes), - encrypted_logs_hashes: validate_array(public_inputs.encrypted_logs_hashes), - unencrypted_logs_hashes: validate_array(public_inputs.unencrypted_logs_hashes) - } -} +fn validate_caller_context(caller_context: CallerContext, this_context: CallContext) { + let matching_caller_context = caller_context.msg_sender.eq(this_context.msg_sender) + & caller_context.storage_contract_address.eq(this_context.storage_contract_address); + let hidden_caller_context = caller_context.is_hidden(); + assert(matching_caller_context | hidden_caller_context, "invalid caller context"); -fn is_valid_caller(request: CallRequest, caller_address: AztecAddress, caller_context: CallContext) -> bool { - let valid_caller_context = request.caller_context.msg_sender.eq(caller_context.msg_sender) - & request.caller_context.storage_contract_address.eq(caller_context.storage_contract_address); - - request.caller_contract_address.eq(caller_address) - & (request.caller_context.is_empty() | valid_caller_context) + assert_eq(caller_context.is_static_call, this_context.is_static_call, "mismatch is_static_call flag"); } fn validate_call_request(request: CallRequest, hash: Field, caller: PrivateCallStackItem) { if hash != 0 { assert_eq(request.hash, hash, "call stack hash does not match call request hash"); - assert( - is_valid_caller( - request, - caller.contract_address, - caller.public_inputs.call_context - ), "invalid caller" - ); + assert_eq(request.caller_contract_address, caller.contract_address, "invalid caller contract address"); + validate_caller_context(request.caller_context, caller.public_inputs.call_context) } else { assert(is_empty(request), "call requests length does not match the expected length"); } @@ -72,12 +51,12 @@ fn validate_incrementing_counters_within_range( assert(prev_counter < counter_end, "counter must be smaller than the end counter of the call"); } -fn validate_incrementing_counter_ranges_within_range( +fn validate_incrementing_counter_ranges_within_range( counter_start: u32, counter_end: u32, - items: [CallRequest; N], + items: [T; N], num_items: u64 -) { +) where T: RangeOrdered { let mut prev_counter = counter_start; let mut should_check = true; for i in 0..N { @@ -85,12 +64,10 @@ fn validate_incrementing_counter_ranges_within_range( if should_check { let item = items[i]; assert( - item.start_side_effect_counter > prev_counter, "start counter must be larger than the end counter of the previous call" - ); - assert( - item.end_side_effect_counter > item.start_side_effect_counter, "nested call has incorrect counter range" + item.counter_start() > prev_counter, "start counter must be larger than the end counter of the previous call" ); - prev_counter = item.end_side_effect_counter; + assert(item.counter_end() > item.counter_start(), "nested call has incorrect counter range"); + prev_counter = item.counter_end(); } } assert( @@ -98,70 +75,35 @@ fn validate_incrementing_counter_ranges_within_range( ); } -fn validate_split_private_call_requests( +fn validate_clean_split_ranges( min_revertible_side_effect_counter: u32, - first_revertible_call_request_index: u64, - call_requests: [CallRequest; N], - num_call_requests: u64 -) { - if first_revertible_call_request_index != 0 { - let last_non_revertible_call_request_index = first_revertible_call_request_index - 1; - let call_request = call_requests[last_non_revertible_call_request_index]; - assert( - min_revertible_side_effect_counter > call_request.end_side_effect_counter, "min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call" - ); - } - if first_revertible_call_request_index != num_call_requests { - let call_request = call_requests[first_revertible_call_request_index]; - assert( - min_revertible_side_effect_counter <= call_request.start_side_effect_counter, "min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible call" - ); - } -} - -fn validate_split_public_call_requests( - min_revertible_side_effect_counter: u32, - first_revertible_call_request_index: u64, - call_requests: [CallRequest; N], - num_call_requests: u64 -) { - if first_revertible_call_request_index != 0 { - let last_non_revertible_call_request_index = first_revertible_call_request_index - 1; - let call_request = call_requests[last_non_revertible_call_request_index]; + first_revertible_item_index: u64, + items: [T; N], + num_items: u64 +) where T: RangeOrdered { + if first_revertible_item_index != 0 { + let last_non_revertible_item_index = first_revertible_item_index - 1; + let item = items[last_non_revertible_item_index]; assert( - min_revertible_side_effect_counter > call_request.counter(), "min_revertible_side_effect_counter must be greater than the counter of the last non revertible call" + min_revertible_side_effect_counter > item.counter_end(), "min_revertible_side_effect_counter must be greater than the end counter of the last non revertible item" ); } - if first_revertible_call_request_index != num_call_requests { - let call_request = call_requests[first_revertible_call_request_index]; + if first_revertible_item_index != num_items { + let item = items[first_revertible_item_index]; assert( - min_revertible_side_effect_counter <= call_request.counter(), "min_revertible_side_effect_counter must be less than or equal to the counter of the first revertible call" + min_revertible_side_effect_counter <= item.counter_start(), "min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible item" ); } } -struct ArrayLengths { - note_hash_read_requests: u64, - nullifier_read_requests: u64, - nullifier_key_validation_requests: u64, - new_note_hashes: u64, - new_nullifiers: u64, - new_l2_to_l1_msgs: u64, - private_call_stack_hashes: u64, - public_call_stack_hashes: u64, - note_encrypted_logs_hashes: u64, - encrypted_logs_hashes: u64, - unencrypted_logs_hashes: u64, -} - struct PrivateCallDataValidator { data: PrivateCallData, - array_lengths: ArrayLengths, + array_lengths: PrivateCircuitPublicInputsArrayLengths, } impl PrivateCallDataValidator { pub fn new(data: PrivateCallData) -> Self { - let array_lengths = validate_arrays(data); + let array_lengths = PrivateCircuitPublicInputsArrayLengths::new(data.call_stack_item.public_inputs); PrivateCallDataValidator { data, array_lengths } } @@ -174,11 +116,7 @@ impl PrivateCallDataValidator { self.validate_counters(); } - pub fn validate_as_first_call( - self, - first_revertible_private_call_request_index: u64, - first_revertible_public_call_request_index: u64 - ) { + pub fn validate_as_first_call(self, first_revertible_private_call_request_index: u64) { let public_inputs = self.data.call_stack_item.public_inputs; let call_context = public_inputs.call_context; assert(call_context.is_delegate_call == false, "Users cannot make a delegatecall"); @@ -187,17 +125,11 @@ impl PrivateCallDataValidator { let min_revertible_side_effect_counter = public_inputs.min_revertible_side_effect_counter; // No need to check that the min_revertible_side_effect_counter falls in the counter range of the private call. // It is valid as long as it does not fall in the middle of any nested call. - validate_split_private_call_requests( + validate_clean_split_ranges( min_revertible_side_effect_counter, first_revertible_private_call_request_index, - self.data.private_call_stack, - self.array_lengths.private_call_stack_hashes - ); - validate_split_public_call_requests( - min_revertible_side_effect_counter, - first_revertible_public_call_request_index, - self.data.public_call_stack, - self.array_lengths.public_call_stack_hashes + public_inputs.private_call_requests, + self.array_lengths.private_call_requests ); } @@ -218,18 +150,21 @@ impl PrivateCallDataValidator { ); } - pub fn validate_against_call_request(self, request: CallRequest) { + pub fn validate_against_call_request(self, scoped_call_request: ScopedPrivateCallRequest) { let call_stack_item = self.data.call_stack_item; + let caller_contract_address = scoped_call_request.contract_address; + let request = scoped_call_request.call_request; assert_eq( request.hash, call_stack_item.hash(), "calculated private_call_hash does not match provided private_call_hash at the top of the call stack" ); let call_context = call_stack_item.public_inputs.call_context; + let caller_context = request.caller_context; + let is_caller_hidden = caller_context.is_hidden(); if call_context.is_delegate_call { - let caller_context = request.caller_context; - assert(!caller_context.is_empty(), "caller context cannot be empty for delegate calls"); + assert(!is_caller_hidden, "caller context cannot be hidden for delegate calls"); assert_eq( call_context.msg_sender, caller_context.msg_sender, "call stack msg_sender does not match expected msg_sender for delegate calls" ); @@ -237,10 +172,24 @@ impl PrivateCallDataValidator { call_context.storage_contract_address, caller_context.storage_contract_address, "call stack storage address does not match expected contract address for delegate calls" ); } else { + assert(is_caller_hidden, "caller context must be hidden for non-delegate calls"); assert_eq( - call_context.msg_sender, request.caller_contract_address, "call stack msg_sender does not match caller contract address" + call_context.msg_sender, caller_contract_address, "call stack msg_sender does not match caller contract address" ); } + + if !call_context.is_static_call { + assert(caller_context.is_static_call == false, "static call cannot make non-static calls"); + } + } + + pub fn validate_against_previous_kernel(self, previous_kernel: PrivateKernelCircuitPublicInputs) { + let constants = previous_kernel.constants; + let public_inputs = self.data.call_stack_item.public_inputs; + assert_eq(public_inputs.historical_header, constants.historical_header, "mismatch historical header"); + assert_eq(public_inputs.tx_context, constants.tx_context, "mismatch tx context"); + // constants.global_variables refers to the states shared among all txs in a block. + // It should be empty when executing private functions (initialized in PrivateKernelCircuitPublicInputsComposer.new_from_tx_request()). } fn validate_contract_address(self) { @@ -313,10 +262,17 @@ impl PrivateCallDataValidator { } fn validate_private_call_requests(self) { - let call_requests = self.data.private_call_stack; - let hashes = self.data.call_stack_item.public_inputs.private_call_stack_hashes; + let call_requests = self.data.call_stack_item.public_inputs.private_call_requests; + let num_requests = self.array_lengths.private_call_requests; + let mut should_check = true; for i in 0..call_requests.len() { - validate_call_request(call_requests[i], hashes[i], self.data.call_stack_item); + should_check &= i != num_requests; + if should_check { + validate_caller_context( + call_requests[i].caller_context, + self.data.call_stack_item.public_inputs.call_context + ); + } } } @@ -388,8 +344,8 @@ impl PrivateCallDataValidator { validate_incrementing_counter_ranges_within_range( counter_start, counter_end, - self.data.private_call_stack, - self.array_lengths.private_call_stack_hashes + public_inputs.private_call_requests, + self.array_lengths.private_call_requests ); // Validate the public call requests by checking their start counters only, as their end counters are unknown. diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr index 4792132f3b1..e0dfcb2e78f 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr @@ -3,7 +3,8 @@ use dep::types::{ call_request::CallRequest, combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder}, max_block_number::MaxBlockNumber, nullifier::Nullifier, note_hash::ScopedNoteHash, - log_hash::NoteLogHash, private_circuit_public_inputs::PrivateCircuitPublicInputs + log_hash::NoteLogHash, + private_circuit_public_inputs::{PrivateCircuitPublicInputs, PrivateCircuitPublicInputsArrayLengths} }, address::AztecAddress, constants::{ @@ -16,9 +17,10 @@ use dep::types::{ struct DataSource { private_call_public_inputs: PrivateCircuitPublicInputs, + array_lengths: PrivateCircuitPublicInputsArrayLengths, + contract_address: AztecAddress, storage_contract_address: AztecAddress, note_hash_nullifier_counters: [u32; MAX_NEW_NOTE_HASHES_PER_CALL], - private_call_requests: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_requests: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], public_teardown_call_request: CallRequest, } @@ -79,17 +81,19 @@ impl PrivateKernelCircuitPublicInputsComposer { pub fn compose( &mut self, private_call_public_inputs: PrivateCircuitPublicInputs, + array_lengths: PrivateCircuitPublicInputsArrayLengths, + contract_address: AztecAddress, note_hash_nullifier_counters: [u32; MAX_NEW_NOTE_HASHES_PER_CALL], - private_call_requests: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_requests: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], public_teardown_call_request: CallRequest ) -> Self { let storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; let source = DataSource { - storage_contract_address, private_call_public_inputs, + array_lengths, + contract_address, + storage_contract_address, note_hash_nullifier_counters, - private_call_requests, public_call_requests, public_teardown_call_request }; @@ -210,11 +214,15 @@ impl PrivateKernelCircuitPublicInputsComposer { } fn propagate_private_call_requests(&mut self, source: DataSource) { - let call_requests = source.private_call_requests; + let call_requests = source.private_call_public_inputs.private_call_requests; + let num_requests = source.array_lengths.private_call_requests; + let mut proceed = true; for i in 0..call_requests.len() { - let call_request = call_requests[i]; - if !is_empty(call_request) { - self.public_inputs.end.private_call_stack.push(call_request); + proceed &= i != num_requests; + if proceed { + // Push the call requests to the stack in reverse order. + let call_request = call_requests[num_requests - i - 1]; + self.public_inputs.end.private_call_stack.push(call_request.scope(source.contract_address)); } } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 78dc5415db3..61ed5046436 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -14,7 +14,6 @@ use dep::types::{ struct PrivateKernelInitHints { note_hash_nullifier_counters: [u32; MAX_NEW_NOTE_HASHES_PER_CALL], first_revertible_private_call_request_index: u64, - first_revertible_public_call_request_index: u64 } // Initialization struct for private inputs to the private kernel @@ -31,17 +30,15 @@ impl PrivateKernelInitCircuitPrivateInputs { let privateCallDataValidator = PrivateCallDataValidator::new(self.private_call); privateCallDataValidator.validate(); - privateCallDataValidator.validate_as_first_call( - self.hints.first_revertible_private_call_request_index, - self.hints.first_revertible_public_call_request_index - ); + privateCallDataValidator.validate_as_first_call(self.hints.first_revertible_private_call_request_index); privateCallDataValidator.validate_against_tx_request(self.tx_request); let private_call_public_inputs = self.private_call.call_stack_item.public_inputs; PrivateKernelCircuitPublicInputsComposer::new_from_tx_request(self.tx_request, private_call_public_inputs).compose( private_call_public_inputs, + privateCallDataValidator.array_lengths, + self.private_call.call_stack_item.contract_address, self.hints.note_hash_nullifier_counters, - self.private_call.private_call_stack, self.private_call.public_call_stack, self.private_call.public_teardown_call_request ).finish() @@ -75,8 +72,7 @@ mod tests { let tx_request = private_call.build_tx_request(); let hints = PrivateKernelInitHints { note_hash_nullifier_counters: [0; MAX_NEW_NOTE_HASHES_PER_CALL], - first_revertible_private_call_request_index: 0, - first_revertible_public_call_request_index: 0 + first_revertible_private_call_request_index: 0 }; PrivateKernelInitInputsBuilder { tx_request, private_call, hints } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index f3d599ba6e1..e9c8e2b6071 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -37,11 +37,13 @@ impl PrivateKernelInnerCircuitPrivateInputs { let private_call_stack_size = array_length(private_call_stack); let call_request = private_call_stack[private_call_stack_size - 1]; privateCallDataValidator.validate_against_call_request(call_request); + privateCallDataValidator.validate_against_previous_kernel(self.previous_kernel.public_inputs); PrivateKernelCircuitPublicInputsComposer::new_from_previous_kernel(self.previous_kernel.public_inputs).compose( self.private_call.call_stack_item.public_inputs, + privateCallDataValidator.array_lengths, + self.private_call.call_stack_item.contract_address, self.hints.note_hash_nullifier_counters, - self.private_call.private_call_stack, self.private_call.public_call_stack, self.private_call.public_teardown_call_request ).finish() diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr index e2af8ade73b..2a9c7d34cf3 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr @@ -1,5 +1,6 @@ mod private_call_data_validator_builder; mod validate_against_call_request; +mod validate_against_previous_kernel; mod validate_against_tx_request; mod validate_arrays; mod validate_as_first_call; @@ -7,3 +8,4 @@ mod validate_call; mod validate_call_requests; mod validate_contract_address; mod validate_counters; +mod validate_private_call_requests; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr index c76216a9635..f014c86eb54 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr @@ -1,13 +1,12 @@ use crate::private_call_data_validator::PrivateCallDataValidator; use dep::types::{ - abis::call_request::CallRequest, tests::private_call_data_builder::PrivateCallDataBuilder, - transaction::tx_request::TxRequest + abis::private_call_request::ScopedPrivateCallRequest, + tests::private_call_data_builder::PrivateCallDataBuilder, transaction::tx_request::TxRequest }; struct PrivateCallDataValidatorBuilder { private_call: PrivateCallDataBuilder, first_revertible_private_call_request_index: u64, - first_revertible_public_call_request_index: u64 } impl PrivateCallDataValidatorBuilder { @@ -18,11 +17,7 @@ impl PrivateCallDataValidatorBuilder { pub fn new_with_counter(counter: u32) -> Self { let private_call = PrivateCallDataBuilder::new_with_counter(counter); - PrivateCallDataValidatorBuilder { - private_call, - first_revertible_private_call_request_index: 0, - first_revertible_public_call_request_index: 0 - } + PrivateCallDataValidatorBuilder { private_call, first_revertible_private_call_request_index: 0 } } pub fn is_delegate_call(&mut self) -> Self { @@ -42,10 +37,7 @@ impl PrivateCallDataValidatorBuilder { pub fn validate_as_first_call(self) { let private_call = self.private_call.finish(); - PrivateCallDataValidator::new(private_call).validate_as_first_call( - self.first_revertible_private_call_request_index, - self.first_revertible_public_call_request_index - ); + PrivateCallDataValidator::new(private_call).validate_as_first_call(self.first_revertible_private_call_request_index); } pub fn validate_against_tx_request(self, request: TxRequest) { @@ -53,7 +45,7 @@ impl PrivateCallDataValidatorBuilder { PrivateCallDataValidator::new(private_call).validate_against_tx_request(request); } - pub fn validate_against_call_request(self, request: CallRequest) { + pub fn validate_against_call_request(self, request: ScopedPrivateCallRequest) { let private_call = self.private_call.finish(); PrivateCallDataValidator::new(private_call).validate_against_call_request(request); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr index 87dd96f84ed..900615e058f 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr @@ -34,17 +34,17 @@ fn validate_against_call_request_mismatch_hash_fails() { let mut request = builder.private_call.build_call_request(); // Tweak the hash to be a different value. - request.hash += 1; + request.call_request.hash += 1; builder.validate_against_call_request(request); } -#[test(should_fail_with="caller context cannot be empty for delegate calls")] +#[test(should_fail_with="caller context cannot be hidden for delegate calls")] fn validate_against_call_request_empty_caller_context_for_delegate_calls_fails() { let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); let mut request = builder.private_call.build_call_request(); - request.caller_context = CallerContext::empty(); + request.call_request.caller_context = CallerContext::empty(); builder.validate_against_call_request(request); } @@ -55,7 +55,7 @@ fn validate_against_call_request_incorrect_msg_sender_for_delegate_call_fails() let mut request = builder.private_call.build_call_request(); // Tweak the msg_sender to be a different value. - request.caller_context.msg_sender.inner += 1; + request.call_request.caller_context.msg_sender.inner += 1; builder.validate_against_call_request(request); } @@ -66,7 +66,7 @@ fn validate_against_call_request_incorrect_storage_contract_address_for_delegate let mut request = builder.private_call.build_call_request(); // Tweak the storage contract address to be a different value. - request.caller_context.storage_contract_address.inner += 1; + request.call_request.caller_context.storage_contract_address.inner += 1; builder.validate_against_call_request(request); } @@ -77,7 +77,51 @@ fn validate_against_call_request_incorrect_msg_sender_for_regular_call_fails() { let mut request = builder.private_call.build_call_request(); // Tweak the caller's contract address to be a different value. - request.caller_contract_address.inner += 1; + request.contract_address.inner += 1; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="caller context must be hidden for non-delegate calls")] +fn validate_against_call_request_non_empty_caller_for_regular_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the caller's msg_sender to be non-empty. + request.call_request.caller_context.msg_sender.inner = 1234; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="caller context must be hidden for non-delegate calls")] +fn validate_against_call_request_non_empty_caller_for_static_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the caller's msg_sender to be non-empty. + request.call_request.caller_context.msg_sender.inner = 1234; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="static call cannot make non-static calls")] +fn validate_against_call_request_static_call_regular_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the caller to be making a static call. + request.call_request.caller_context.is_static_call = true; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="static call cannot make non-static calls")] +fn validate_against_call_request_static_call_delegate_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the caller to be making a static call. + request.call_request.caller_context.is_static_call = true; builder.validate_against_call_request(request); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_previous_kernel.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_previous_kernel.nr new file mode 100644 index 00000000000..837661b0b00 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_previous_kernel.nr @@ -0,0 +1,49 @@ +use crate::{ + private_call_data_validator::PrivateCallDataValidator, + tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder +}; +use dep::types::{ + abis::kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, + tests::fixture_builder::FixtureBuilder +}; + +impl PrivateCallDataValidatorBuilder { + pub fn validate_against_previous_kernel(self, previous_kernel: PrivateKernelCircuitPublicInputs) { + let private_call = self.private_call.finish(); + PrivateCallDataValidator::new(private_call).validate_against_previous_kernel(previous_kernel); + } +} + +fn make_previous_kernel() -> PrivateKernelCircuitPublicInputs { + let builder = FixtureBuilder::new(); + builder.to_private_kernel_circuit_public_inputs() +} + +#[test] +fn validate_against_previous_kernel_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let previous_kernel = make_previous_kernel(); + + builder.validate_against_previous_kernel(previous_kernel); +} + +#[test(should_fail_with="mismatch historical header")] +fn validate_against_previous_kernel_mismatch_header_version_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut previous_kernel = make_previous_kernel(); + previous_kernel.constants.historical_header.global_variables.version += 1; + + builder.validate_against_previous_kernel(previous_kernel); +} + +#[test(should_fail_with="mismatch tx context")] +fn validate_against_previous_kernel_mismatch_chain_id_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut previous_kernel = make_previous_kernel(); + previous_kernel.constants.tx_context.chain_id += 1; + + builder.validate_against_previous_kernel(previous_kernel); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr index a8c1b2f6efd..dbc5f629877 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr @@ -1,6 +1,10 @@ use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; use dep::types::{ - abis::{note_hash::NoteHash, nullifier::Nullifier, read_request::ReadRequest, log_hash::{LogHash, NoteLogHash}}, + abis::{ + caller_context::CallerContext, note_hash::NoteHash, nullifier::Nullifier, + private_call_request::PrivateCallRequest, read_request::ReadRequest, + log_hash::{LogHash, NoteLogHash} +}, address::EthAddress, grumpkin_point::GrumpkinPoint, messaging::l2_to_l1_message::L2ToL1Message }; @@ -90,10 +94,19 @@ fn validate_arrays_malformed_l2_to_l1_msgs_fails() { } #[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_private_call_stack_fails() { +fn validate_arrays_malformed_private_call_requests_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.public_inputs.private_call_stack_hashes.extend_from_array([0, 9123]); + builder.private_call.public_inputs.private_call_requests.extend_from_array( + [ + PrivateCallRequest::empty(), PrivateCallRequest { + hash: 9123, + start_side_effect_counter: 1, + end_side_effect_counter: 2, + caller_context: CallerContext::empty() + } + ] + ); builder.validate(); } @@ -136,7 +149,7 @@ fn validate_arrays_malformed_unencrypted_logs_hashes_fails() { } #[test(should_fail_with="invalid array")] -fn input_validation_malformed_arrays_note_logs() { +fn validate_arrays_malformed_note_encrypted_logs_hashes() { let mut builder = PrivateCallDataValidatorBuilder::new(); builder.private_call.public_inputs.note_encrypted_logs_hashes.extend_from_array( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr index 852de8b834b..59bdc8a6f8f 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr @@ -1,6 +1,5 @@ use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; use dep::types::constants::MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL; -use dep::types::abis::call_request::CallRequest; impl PrivateCallDataValidatorBuilder { pub fn new_first_call() -> Self { @@ -9,25 +8,16 @@ impl PrivateCallDataValidatorBuilder { pub fn split_calls(&mut self, counter: u32) { self.private_call.public_inputs.min_revertible_side_effect_counter = counter; - self.first_revertible_private_call_request_index = self.private_call.private_call_stack.len(); - self.first_revertible_public_call_request_index = self.private_call.public_call_stack.len(); + self.first_revertible_private_call_request_index = self.private_call.public_inputs.private_call_requests.len(); } pub fn add_private_call_request(&mut self, counter_start: u32, counter_end: u32) { - let index = self.private_call.private_call_stack.len(); - self.private_call.append_private_call_requests(1, false); - self.private_call.private_call_stack.storage[index].start_side_effect_counter = counter_start; - self.private_call.private_call_stack.storage[index].end_side_effect_counter = counter_end; + let index = self.private_call.public_inputs.private_call_requests.len(); + self.private_call.public_inputs.append_private_call_requests(1, false); + self.private_call.public_inputs.private_call_requests.storage[index].start_side_effect_counter = counter_start; + self.private_call.public_inputs.private_call_requests.storage[index].end_side_effect_counter = counter_end; self.private_call.public_inputs.counter_end = counter_end + 1; } - - pub fn add_public_call_request(&mut self, counter_start: u32) { - let index = self.private_call.public_call_stack.len(); - self.private_call.append_public_call_requests(1, false); - self.private_call.public_call_stack.storage[index].start_side_effect_counter = counter_start; - self.private_call.public_call_stack.storage[index].end_side_effect_counter = 0; - self.private_call.public_inputs.counter_end = counter_start + 1; - } } #[test] @@ -90,7 +80,7 @@ fn validate_as_first_call_split_private_empty_non_revertible_succeeds() { fn validate_as_first_call_split_private_full_non_revertible_succeeds() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - builder.private_call.append_private_call_requests(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, false); + builder.private_call.public_inputs.append_private_call_requests(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, false); builder.split_calls(builder.private_call.public_inputs.counter_end); builder.validate_as_first_call(); @@ -109,7 +99,7 @@ fn validate_as_first_call_split_private_calls_less_than_first_revertible_success builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call")] +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible item")] fn validate_as_first_call_split_private_calls_less_than_last_non_revertible_fails() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); @@ -122,7 +112,7 @@ fn validate_as_first_call_split_private_calls_less_than_last_non_revertible_fail builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call")] +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible item")] fn validate_as_first_call_split_private_calls_equal_last_non_revertible_fails() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); @@ -134,7 +124,7 @@ fn validate_as_first_call_split_private_calls_equal_last_non_revertible_fails() builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible call")] +#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible item")] fn validate_as_first_call_split_private_calls_greater_than_first_revertible_fails() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); @@ -159,7 +149,7 @@ fn validate_as_first_call_split_private_calls_0_succeeds() { builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call")] +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible item")] fn validate_as_first_call_split_private_calls_0_wrong_hint_fails() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); @@ -172,7 +162,7 @@ fn validate_as_first_call_split_private_calls_0_wrong_hint_fails() { builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible call")] +#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible item")] fn validate_as_first_call_split_private_calls_index_hint_greater_than_len_fails() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); @@ -184,55 +174,3 @@ fn validate_as_first_call_split_private_calls_index_hint_greater_than_len_fails( builder.validate_as_first_call(); } - -#[test] -fn validate_as_first_call_split_public_calls_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - - builder.add_public_call_request(20); - builder.add_public_call_request(30); - builder.split_calls(40); - builder.add_public_call_request(40); - - builder.validate_as_first_call(); -} - -#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the counter of the last non revertible call")] -fn validate_as_first_call_split_public_calls_less_than_last_non_revertible_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - - builder.add_public_call_request(20); - builder.add_public_call_request(30); - // Tweak the counter to be less than the end counter of the last non-revertible call. - builder.split_calls(29); - builder.add_public_call_request(40); - - builder.validate_as_first_call(); -} - -#[test] -fn validate_as_first_call_split_private_public_mix_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - - builder.add_private_call_request(20, 30); - builder.add_public_call_request(40); - builder.split_calls(50); - builder.add_public_call_request(50); - builder.add_private_call_request(60, 70); - - builder.validate_as_first_call(); -} - -#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the counter of the first revertible call")] -fn validate_as_first_call_split_private_public_mix_falls_in_revertible_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - - builder.add_private_call_request(20, 30); - builder.add_public_call_request(40); - // Tweak the counter to be greater than the start counter of the next call. - builder.split_calls(51); - builder.add_public_call_request(50); - builder.add_private_call_request(60, 70); - - builder.validate_as_first_call(); -} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr index 58fede8fb72..4534d291e7c 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr @@ -1,102 +1,6 @@ use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; use dep::types::abis::call_request::CallRequest; -/** - * validate_private_call_requests - */ - -#[test] -fn validate_private_call_requests_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - - builder.validate(); -} - -#[test] -fn validate_private_call_requests_delegate_calls_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, true); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_private_call_requests_incorrect_hash_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the hash to be a different value. - call_request.hash += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_private_call_requests_incorrect_caller_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(1, false); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the caller contract address to be a different value. - call_request.caller_contract_address.inner += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_private_call_requests_incorrect_caller_storage_contract_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(1, true); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the storage contract to be a different value. - call_request.caller_context.storage_contract_address.inner += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_private_call_requests_incorrect_caller_msg_sender_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(1, true); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the msg_sender to be a different value. - call_request.caller_context.msg_sender.inner += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="call requests length does not match the expected length")] -fn validate_private_call_requests_fewer_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - // Remove one call stack item hash. - let _ = builder.private_call.public_inputs.private_call_stack_hashes.pop(); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_private_call_requests_more_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - // Add one random call stack item hash. - builder.private_call.public_inputs.private_call_stack_hashes.push(9123); - - builder.validate(); -} - /** * validate_public_call_requests */ @@ -132,7 +36,7 @@ fn validate_public_call_requests_incorrect_hash_fails() { builder.validate(); } -#[test(should_fail_with="invalid caller")] +#[test(should_fail_with="invalid caller contract address")] fn validate_public_call_requests_incorrect_caller_address_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); @@ -145,7 +49,7 @@ fn validate_public_call_requests_incorrect_caller_address_fails() { builder.validate(); } -#[test(should_fail_with="invalid caller")] +#[test(should_fail_with="invalid caller context")] fn validate_public_call_requests_incorrect_caller_storage_contract_address_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); @@ -158,7 +62,7 @@ fn validate_public_call_requests_incorrect_caller_storage_contract_address_fails builder.validate(); } -#[test(should_fail_with="invalid caller")] +#[test(should_fail_with="invalid caller context")] fn validate_public_call_requests_incorrect_caller_msg_sender_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); @@ -226,7 +130,7 @@ fn validate_teardown_call_request_incorrect_hash_fails() { builder.validate(); } -#[test(should_fail_with="invalid caller")] +#[test(should_fail_with="invalid caller contract address")] fn validate_teardown_call_request_incorrect_caller_address_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); @@ -237,7 +141,7 @@ fn validate_teardown_call_request_incorrect_caller_address_fails() { builder.validate(); } -#[test(should_fail_with="invalid caller")] +#[test(should_fail_with="invalid caller context")] fn validate_teardown_call_request_incorrect_caller_storage_contract_address_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); @@ -248,7 +152,7 @@ fn validate_teardown_call_request_incorrect_caller_storage_contract_address_fail builder.validate(); } -#[test(should_fail_with="invalid caller")] +#[test(should_fail_with="invalid caller context")] fn validate_teardown_call_request_incorrect_caller_msg_sender_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr index d18493899b7..044441e5382 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr @@ -125,7 +125,7 @@ fn validate_counters_note_hash_counter_same_as_call_counter_end_fails() { fn validate_counters_private_call_requests_succeeds() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(2, false); + builder.private_call.public_inputs.append_private_call_requests(2, false); builder.validate(); } @@ -134,10 +134,10 @@ fn validate_counters_private_call_requests_succeeds() { fn validate_counters_private_call_requests_less_than_call_start_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, false); // Tweak the start counter of the first nested call to be LESS than the start counter of the call. let counter_start = builder.private_call.public_inputs.counter_start; - builder.private_call.private_call_stack.storage[0].start_side_effect_counter = counter_start - 1; + builder.private_call.public_inputs.private_call_requests.storage[0].start_side_effect_counter = counter_start - 1; builder.validate(); } @@ -146,10 +146,10 @@ fn validate_counters_private_call_requests_less_than_call_start_fails() { fn validate_counters_private_call_requests_equal_call_start_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, false); // Tweak the start counter of the call to EQUAL the start counter of the first nested call. let counter_start = builder.private_call.public_inputs.counter_start; - builder.private_call.private_call_stack.storage[0].start_side_effect_counter = counter_start; + builder.private_call.public_inputs.private_call_requests.storage[0].start_side_effect_counter = counter_start; builder.validate(); } @@ -158,10 +158,10 @@ fn validate_counters_private_call_requests_equal_call_start_fails() { fn validate_counters_private_call_requests_less_than_previous_end_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(2, false); + builder.private_call.public_inputs.append_private_call_requests(2, false); // Tweak the start counter of the second nested call to be LESS than the end counter of the first nested call. - let counter_end = builder.private_call.private_call_stack.get(0).end_side_effect_counter; - builder.private_call.private_call_stack.storage[1].start_side_effect_counter = counter_end - 1; + let counter_end = builder.private_call.public_inputs.private_call_requests.get(0).end_side_effect_counter; + builder.private_call.public_inputs.private_call_requests.storage[1].start_side_effect_counter = counter_end - 1; builder.validate(); } @@ -170,10 +170,10 @@ fn validate_counters_private_call_requests_less_than_previous_end_fails() { fn validate_counters_private_call_requests_same_as_previous_end_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(2, false); + builder.private_call.public_inputs.append_private_call_requests(2, false); // Tweak the start counter of the second nested call to EQUAL the end counter of the first nested call. - let counter_end = builder.private_call.private_call_stack.get(0).end_side_effect_counter; - builder.private_call.private_call_stack.storage[1].start_side_effect_counter = counter_end; + let counter_end = builder.private_call.public_inputs.private_call_requests.get(0).end_side_effect_counter; + builder.private_call.public_inputs.private_call_requests.storage[1].start_side_effect_counter = counter_end; builder.validate(); } @@ -182,10 +182,10 @@ fn validate_counters_private_call_requests_same_as_previous_end_fails() { fn validate_counters_private_call_requests_end_less_than_start_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, false); // Tweak the end counter of the first nested call to be LESS than its start counter. - let counter_start = builder.private_call.private_call_stack.get(0).start_side_effect_counter; - builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_start - 1; + let counter_start = builder.private_call.public_inputs.private_call_requests.get(0).start_side_effect_counter; + builder.private_call.public_inputs.private_call_requests.storage[0].end_side_effect_counter = counter_start - 1; builder.validate(); } @@ -194,10 +194,10 @@ fn validate_counters_private_call_requests_end_less_than_start_fails() { fn validate_counters_private_call_requests_end_equal_start_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, false); // Tweak the end counter of the first nested call to EQUAL its start counter. - let counter_start = builder.private_call.private_call_stack.get(0).start_side_effect_counter; - builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_start; + let counter_start = builder.private_call.public_inputs.private_call_requests.get(0).start_side_effect_counter; + builder.private_call.public_inputs.private_call_requests.storage[0].end_side_effect_counter = counter_start; builder.validate(); } @@ -206,10 +206,10 @@ fn validate_counters_private_call_requests_end_equal_start_fails() { fn validate_counters_private_call_requests_greater_than_call_end_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, false); // Tweak the end counter of the nested call to be GREATER than the end counter of the call. let counter_end = builder.private_call.public_inputs.counter_end; - builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_end + 1; + builder.private_call.public_inputs.private_call_requests.storage[0].end_side_effect_counter = counter_end + 1; builder.validate(); } @@ -218,10 +218,10 @@ fn validate_counters_private_call_requests_greater_than_call_end_fails() { fn validate_counters_private_call_requests_equal_call_end_fails() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, false); // Tweak the end counter of the nested call to EQUAL the end counter of the call. let counter_end = builder.private_call.public_inputs.counter_end; - builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_end; + builder.private_call.public_inputs.private_call_requests.storage[0].end_side_effect_counter = counter_end; builder.validate(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_private_call_requests.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_private_call_requests.nr new file mode 100644 index 00000000000..89f730cc504 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_private_call_requests.nr @@ -0,0 +1,93 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; + +#[test] +fn validate_private_call_requests_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_private_call_requests(1, true); + builder.private_call.public_inputs.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, true); + + builder.validate(); +} + +#[test] +fn validate_private_call_requests_from_delegate_call_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + builder.private_call.public_inputs.append_private_call_requests(1, true); + builder.private_call.public_inputs.append_private_call_requests(1, false); + builder.private_call.public_inputs.append_private_call_requests(1, true); + + builder.validate(); +} + +#[test] +fn validate_private_call_requests_from_static_call_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.append_private_call_requests(2, false); + + builder.validate(); +} + +#[test] +fn validate_private_call_requests_delegate_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_private_call_requests(2, true); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller context")] +fn validate_private_call_requests_incorrect_caller_storage_contract_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_private_call_requests(1, true); + let mut call_request = builder.private_call.public_inputs.private_call_requests.pop(); + // Tweak the storage contract to be a different value. + call_request.caller_context.storage_contract_address.inner += 1; + builder.private_call.public_inputs.private_call_requests.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller context")] +fn validate_private_call_requests_incorrect_caller_msg_sender_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_private_call_requests(1, true); + let mut call_request = builder.private_call.public_inputs.private_call_requests.pop(); + // Tweak the msg_sender to be a different value. + call_request.caller_context.msg_sender.inner += 1; + builder.private_call.public_inputs.private_call_requests.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="mismatch is_static_call flag")] +fn validate_private_call_requests_regular_call_is_static_true_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_private_call_requests(1, false); + let mut call_request = builder.private_call.public_inputs.private_call_requests.pop(); + // Tweak the is_static_call flag to be true. + call_request.caller_context.is_static_call = true; + builder.private_call.public_inputs.private_call_requests.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="mismatch is_static_call flag")] +fn validate_private_call_requests_static_call_is_static_false_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.append_private_call_requests(1, false); + let mut call_request = builder.private_call.public_inputs.private_call_requests.pop(); + // Tweak the is_static_call flag to be false. + call_request.caller_context.is_static_call = false; + builder.private_call.public_inputs.private_call_requests.push(call_request); + + builder.validate(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 704b1ac6e65..c4d9c5ad826 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -385,8 +385,8 @@ mod tests { public_data_tree_leaf::PublicDataTreeLeaf, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, tests::{ - fixture_builder::FixtureBuilder, merkle_tree_utils::{NonEmptyMerkleTree, compute_zero_hashes}, - sort::sort_high_to_low + fixtures, fixture_builder::FixtureBuilder, + merkle_tree_utils::{NonEmptyMerkleTree, compute_zero_hashes}, sort::sort_high_to_low }, utils::{field::{full_field_less_than, field_from_bytes_32_trunc, field_from_bytes}, uint256::U256}, traits::Empty @@ -500,8 +500,8 @@ mod tests { fn new() -> Self { let mut inputs = BaseRollupInputsBuilder::empty(); inputs.kernel_data = FixtureBuilder::new(); - inputs.constants.global_variables.chain_id = 1; - inputs.constants.global_variables.version = 0; + inputs.constants.global_variables.chain_id = fixtures::CHAIN_ID; + inputs.constants.global_variables.version = fixtures::VERSION; inputs.pre_existing_blocks[0] = inputs.kernel_data.historical_header.hash(); @@ -983,7 +983,7 @@ mod tests { #[test(should_fail_with = "kernel version does not match the rollup version")] unconstrained fn constants_dont_match_kernels_version() { let mut builder = BaseRollupInputsBuilder::new(); - builder.constants.global_variables.version = 3; + builder.constants.global_variables.version += 1; builder.fails(); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index 8c12f9caeb1..dca4e80ae20 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -32,6 +32,7 @@ mod private_kernel_data; mod public_kernel_data; mod call_request; +mod private_call_request; mod private_call_stack_item; mod public_call_stack_item; mod call_context; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr index 63365b9f5a8..aceda8d20cc 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr @@ -1,7 +1,7 @@ use crate::{ abis::{ call_request::CallRequest, gas::Gas, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, - log_hash::{LogHash, NoteLogHash} + private_call_request::ScopedPrivateCallRequest, log_hash::{LogHash, NoteLogHash} }, traits::{Serialize, Deserialize, Eq, Empty}, messaging::l2_to_l1_message::ScopedL2ToL1Message, utils::reader::Reader @@ -21,7 +21,7 @@ struct PrivateAccumulatedData { encrypted_logs_hashes: [LogHash; MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_TX], - private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], + private_call_stack: [ScopedPrivateCallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], } @@ -78,7 +78,7 @@ impl Deserialize for PrivateAccumulatedData { note_encrypted_logs_hashes: reader.read_struct_array(NoteLogHash::deserialize, [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX]), encrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX]), unencrypted_logs_hashes: reader.read_struct_array(LogHash::deserialize, [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX]), - private_call_stack: reader.read_struct_array(CallRequest::deserialize, [CallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX]), + private_call_stack: reader.read_struct_array(ScopedPrivateCallRequest::deserialize, [ScopedPrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX]), public_call_stack: reader.read_struct_array(CallRequest::deserialize, [CallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX]), }; reader.finish(); @@ -108,7 +108,7 @@ impl Empty for PrivateAccumulatedData { note_encrypted_logs_hashes: [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], encrypted_logs_hashes: [LogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [LogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX], - private_call_stack: [CallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], + private_call_stack: [ScopedPrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr index 73b88b3385f..01802220d5f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr @@ -8,7 +8,8 @@ use crate::{ public_accumulated_data_builder::PublicAccumulatedDataBuilder }, call_request::CallRequest, note_hash::{NoteHash, ScopedNoteHash}, nullifier::ScopedNullifier, - public_data_update_request::PublicDataUpdateRequest, log_hash::{LogHash, NoteLogHash} + private_call_request::ScopedPrivateCallRequest, public_data_update_request::PublicDataUpdateRequest, + log_hash::{LogHash, NoteLogHash} }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, @@ -32,7 +33,7 @@ struct PrivateAccumulatedDataBuilder { encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, - private_call_stack: BoundedVec, + private_call_stack: BoundedVec, public_call_stack: BoundedVec, } @@ -224,6 +225,21 @@ impl PrivateAccumulatedDataBuilder { } } +impl Empty for PrivateAccumulatedDataBuilder { + fn empty() -> Self { + PrivateAccumulatedDataBuilder { + new_note_hashes: BoundedVec::new(), + new_nullifiers: BoundedVec::new(), + new_l2_to_l1_msgs: BoundedVec::new(), + note_encrypted_logs_hashes: BoundedVec::new(), + encrypted_logs_hashes: BoundedVec::new(), + unencrypted_logs_hashes: BoundedVec::new(), + private_call_stack: BoundedVec::new(), + public_call_stack: BoundedVec::new(), + } + } +} + mod tests { use crate::{ abis::{ @@ -448,18 +464,3 @@ mod tests { ); } } - -impl Empty for PrivateAccumulatedDataBuilder { - fn empty() -> Self { - PrivateAccumulatedDataBuilder { - new_note_hashes: BoundedVec::new(), - new_nullifiers: BoundedVec::new(), - new_l2_to_l1_msgs: BoundedVec::new(), - note_encrypted_logs_hashes: BoundedVec::new(), - encrypted_logs_hashes: BoundedVec::new(), - unencrypted_logs_hashes: BoundedVec::new(), - private_call_stack: BoundedVec::new(), - public_call_stack: BoundedVec::new(), - } - } -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr index e9c7b283947..0594718a73f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr @@ -7,12 +7,14 @@ use crate::utils::reader::Reader; struct CallerContext { msg_sender: AztecAddress, storage_contract_address: AztecAddress, + is_static_call: bool, } impl Eq for CallerContext { - fn eq(self, caller_context: CallerContext) -> bool { - caller_context.msg_sender.eq(self.msg_sender) - & caller_context.storage_contract_address.eq(self.storage_contract_address) + fn eq(self, other: CallerContext) -> bool { + other.msg_sender.eq(self.msg_sender) + & other.storage_contract_address.eq(self.storage_contract_address) + & other.is_static_call == self.is_static_call } } @@ -21,12 +23,19 @@ impl Empty for CallerContext { CallerContext { msg_sender: AztecAddress::zero(), storage_contract_address: AztecAddress::zero(), + is_static_call: false, } } } impl CallerContext { pub fn is_empty(self) -> bool { + self.msg_sender.is_zero() & self.storage_contract_address.is_zero() & !self.is_static_call + } + + // Different to an empty context, a hidden context won't reveal the caller's msg_sender and storage_contract_address, + // but will still propagate the is_static_call flag. + pub fn is_hidden(self) -> bool { self.msg_sender.is_zero() & self.storage_contract_address.is_zero() } } @@ -37,6 +46,7 @@ impl Serialize for CallerContext { fields.extend_from_array(self.msg_sender.serialize()); fields.extend_from_array(self.storage_contract_address.serialize()); + fields.push(self.is_static_call as Field); assert_eq(fields.len(), CALLER_CONTEXT_LENGTH); @@ -51,6 +61,7 @@ impl Deserialize for CallerContext { let item = CallerContext { msg_sender: reader.read_struct(AztecAddress::deserialize), storage_contract_address: reader.read_struct(AztecAddress::deserialize), + is_static_call: reader.read_bool(), }; reader.finish(); item diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_request.nr new file mode 100644 index 00000000000..8638a124253 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_request.nr @@ -0,0 +1,152 @@ +use dep::std::cmp::Eq; +use crate::{ + abis::{caller_context::CallerContext, side_effect::{Ordered, RangeOrdered}}, address::AztecAddress, + constants::{PRIVATE_CALL_REQUEST_LENGTH, SCOPED_PRIVATE_CALL_REQUEST_LENGTH}, + traits::{Empty, Serialize, Deserialize}, utils::reader::Reader +}; + +struct PrivateCallRequest { + hash: Field, + caller_context: CallerContext, + start_side_effect_counter: u32, + end_side_effect_counter: u32, +} + +impl Ordered for PrivateCallRequest { + fn counter(self) -> u32 { + self.start_side_effect_counter + } +} + +impl RangeOrdered for PrivateCallRequest { + fn counter_start(self) -> u32 { + self.start_side_effect_counter + } + fn counter_end(self) -> u32 { + self.end_side_effect_counter + } +} + +impl Eq for PrivateCallRequest { + fn eq(self, other: PrivateCallRequest) -> bool { + (self.hash == other.hash) + & (self.caller_context == other.caller_context) + & (self.start_side_effect_counter == other.start_side_effect_counter) + & (self.end_side_effect_counter == other.end_side_effect_counter) + } +} + +impl Empty for PrivateCallRequest { + fn empty() -> Self { + PrivateCallRequest { + hash: 0, + caller_context: CallerContext::empty(), + start_side_effect_counter: 0, + end_side_effect_counter: 0, + } + } +} + +impl Serialize for PrivateCallRequest { + fn serialize(self) -> [Field; PRIVATE_CALL_REQUEST_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.push(self.hash); + fields.extend_from_array(self.caller_context.serialize()); + fields.push(self.start_side_effect_counter as Field); + fields.push(self.end_side_effect_counter as Field); + + assert_eq(fields.len(), PRIVATE_CALL_REQUEST_LENGTH); + + fields.storage + } +} + +impl Deserialize for PrivateCallRequest { + fn deserialize(fields: [Field; PRIVATE_CALL_REQUEST_LENGTH]) -> PrivateCallRequest { + let mut reader = Reader::new(fields); + let item = PrivateCallRequest { + hash: reader.read(), + caller_context: reader.read_struct(CallerContext::deserialize), + start_side_effect_counter: reader.read_u32(), + end_side_effect_counter: reader.read_u32(), + }; + reader.finish(); + item + } +} + +impl PrivateCallRequest { + pub fn scope(self, contract_address: AztecAddress) -> ScopedPrivateCallRequest { + ScopedPrivateCallRequest { call_request: self, contract_address } + } +} + +struct ScopedPrivateCallRequest { + call_request: PrivateCallRequest, + contract_address: AztecAddress, +} + +impl Ordered for ScopedPrivateCallRequest { + fn counter(self) -> u32 { + self.call_request.counter_start() + } +} + +impl RangeOrdered for ScopedPrivateCallRequest { + fn counter_start(self) -> u32 { + self.call_request.counter_start() + } + fn counter_end(self) -> u32 { + self.call_request.counter_end() + } +} + +impl Eq for ScopedPrivateCallRequest { + fn eq(self, other: ScopedPrivateCallRequest) -> bool { + (self.call_request == other.call_request) + & (self.contract_address == other.contract_address) + } +} + +impl Empty for ScopedPrivateCallRequest { + fn empty() -> Self { + ScopedPrivateCallRequest { + call_request: PrivateCallRequest::empty(), + contract_address: AztecAddress::zero(), + } + } +} + +impl Serialize for ScopedPrivateCallRequest { + fn serialize(self) -> [Field; SCOPED_PRIVATE_CALL_REQUEST_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.call_request.serialize()); + fields.extend_from_array(self.contract_address.serialize()); + + assert_eq(fields.len(), SCOPED_PRIVATE_CALL_REQUEST_LENGTH); + + fields.storage + } +} + +impl Deserialize for ScopedPrivateCallRequest { + fn deserialize(fields: [Field; SCOPED_PRIVATE_CALL_REQUEST_LENGTH]) -> ScopedPrivateCallRequest { + let mut reader = Reader::new(fields); + let item = ScopedPrivateCallRequest { + call_request: reader.read_struct(PrivateCallRequest::deserialize), + contract_address: reader.read_struct(AztecAddress::deserialize), + }; + reader.finish(); + item + } +} + +#[test] +fn serialization_of_empty() { + let item = ScopedPrivateCallRequest::empty(); + let serialized = item.serialize(); + let deserialized = ScopedPrivateCallRequest::deserialize(serialized); + assert(item.eq(deserialized)); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 2913e535363..4dd411afa74 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -85,6 +85,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x29d77b0175116357d39252de002a2944652f87ccb4404f9346bff6d44f020f7f; + let test_data_empty_hash = 0x10d9feff1d02db424becc3399f496be13d0586ea5a62c85de302ea88a1f345c5; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 9fa97c8695c..4cced8097ea 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -2,7 +2,8 @@ use crate::{ abis::{ call_context::CallContext, max_block_number::MaxBlockNumber, gas_settings::GasSettings, nullifier_key_validation_request::NullifierKeyValidationRequest, note_hash::NoteHash, - nullifier::Nullifier, read_request::ReadRequest, log_hash::{LogHash, NoteLogHash} + nullifier::Nullifier, private_call_request::PrivateCallRequest, read_request::ReadRequest, + log_hash::{LogHash, NoteLogHash} }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, @@ -14,9 +15,41 @@ use crate::{ }, header::Header, hash::pedersen_hash, messaging::l2_to_l1_message::L2ToL1Message, traits::{Deserialize, Hash, Serialize, Empty}, utils::reader::Reader, - transaction::tx_context::TxContext + transaction::tx_context::TxContext, utils::arrays::validate_array }; +struct PrivateCircuitPublicInputsArrayLengths { + note_hash_read_requests: u64, + nullifier_read_requests: u64, + nullifier_key_validation_requests: u64, + new_note_hashes: u64, + new_nullifiers: u64, + new_l2_to_l1_msgs: u64, + private_call_requests: u64, + public_call_stack_hashes: u64, + note_encrypted_logs_hashes: u64, + encrypted_logs_hashes: u64, + unencrypted_logs_hashes: u64, +} + +impl PrivateCircuitPublicInputsArrayLengths { + pub fn new(public_inputs: PrivateCircuitPublicInputs) -> Self { + PrivateCircuitPublicInputsArrayLengths { + note_hash_read_requests: validate_array(public_inputs.note_hash_read_requests), + nullifier_read_requests: validate_array(public_inputs.nullifier_read_requests), + nullifier_key_validation_requests: validate_array(public_inputs.nullifier_key_validation_requests), + new_note_hashes: validate_array(public_inputs.new_note_hashes), + new_nullifiers: validate_array(public_inputs.new_nullifiers), + new_l2_to_l1_msgs: validate_array(public_inputs.new_l2_to_l1_msgs), + private_call_requests: validate_array(public_inputs.private_call_requests), + public_call_stack_hashes: validate_array(public_inputs.public_call_stack_hashes), + note_encrypted_logs_hashes: validate_array(public_inputs.note_encrypted_logs_hashes), + encrypted_logs_hashes: validate_array(public_inputs.encrypted_logs_hashes), + unencrypted_logs_hashes: validate_array(public_inputs.unencrypted_logs_hashes) + } + } +} + struct PrivateCircuitPublicInputs { call_context: CallContext, @@ -34,7 +67,7 @@ struct PrivateCircuitPublicInputs { new_note_hashes: [NoteHash; MAX_NEW_NOTE_HASHES_PER_CALL], new_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_CALL], - private_call_stack_hashes: [Field; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], + private_call_requests: [PrivateCallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_stack_hashes: [Field; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], public_teardown_function_hash: Field, new_l2_to_l1_msgs: [L2ToL1Message; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], @@ -67,7 +100,7 @@ impl Eq for PrivateCircuitPublicInputs { (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & (self.new_note_hashes == other.new_note_hashes) & (self.new_nullifiers == other.new_nullifiers) & - (self.private_call_stack_hashes == other.private_call_stack_hashes) & + (self.private_call_requests == other.private_call_requests) & (self.public_call_stack_hashes == other.public_call_stack_hashes) & (self.new_l2_to_l1_msgs == other.new_l2_to_l1_msgs) & (self.start_side_effect_counter == other.start_side_effect_counter) & @@ -107,7 +140,9 @@ impl Serialize for PrivateCircuitPublicInp for i in 0..self.new_nullifiers.len() { fields.extend_from_array(self.new_nullifiers[i].serialize()); } - fields.extend_from_array(self.private_call_stack_hashes); + for i in 0..self.private_call_requests.len() { + fields.extend_from_array(self.private_call_requests[i].serialize()); + } fields.extend_from_array(self.public_call_stack_hashes); fields.push(self.public_teardown_function_hash); for i in 0..self.new_l2_to_l1_msgs.len() { @@ -149,7 +184,7 @@ impl Deserialize for PrivateCircuitPublicI nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), new_note_hashes: reader.read_struct_array(NoteHash::deserialize, [NoteHash::empty(); MAX_NEW_NOTE_HASHES_PER_CALL]), new_nullifiers: reader.read_struct_array(Nullifier::deserialize, [Nullifier::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), - private_call_stack_hashes: reader.read_array([0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), + private_call_requests: reader.read_struct_array(PrivateCallRequest::deserialize, [PrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), public_call_stack_hashes: reader.read_array([0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL]), public_teardown_function_hash: reader.read(), new_l2_to_l1_msgs: reader.read_struct_array(L2ToL1Message::deserialize, [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), @@ -187,7 +222,7 @@ impl Empty for PrivateCircuitPublicInputs { nullifier_key_validation_requests: [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], new_note_hashes: [NoteHash::empty(); MAX_NEW_NOTE_HASHES_PER_CALL], new_nullifiers: [Nullifier::empty(); MAX_NEW_NULLIFIERS_PER_CALL], - private_call_stack_hashes: [0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], + private_call_requests: [PrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_stack_hashes: [0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], public_teardown_function_hash: 0, new_l2_to_l1_msgs: [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL], @@ -215,6 +250,6 @@ fn empty_hash() { let inputs = PrivateCircuitPublicInputs::empty(); let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x0e8b75e4ecf8bed8e361ff2702a1c200d1f4d4394c8f06dc9003eee571982c6c; + let test_data_empty_hash = 0x24ea8c67b7902c1bdc827592303786ea3df7ada25a95e8682ed26b9b36fe2f9e; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr index 56224018099..db120790ac0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr @@ -5,13 +5,12 @@ use crate::abis::{ call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, private_circuit_public_inputs::PrivateCircuitPublicInputs }; -use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, FUNCTION_TREE_HEIGHT}; +use crate::constants::{MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, FUNCTION_TREE_HEIGHT}; use crate::merkle_tree::membership::MembershipWitness; struct PrivateCallData { call_stack_item: PrivateCallStackItem, - private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], public_teardown_call_request: CallRequest, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr index 1f402b623b4..b4e9a8b5947 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr @@ -9,6 +9,11 @@ trait Ordered { fn counter(self) -> u32; } +trait RangeOrdered { + fn counter_start(self) -> u32; + fn counter_end(self) -> u32; +} + trait OrderedValue where T: Eq { fn value(self) -> T; fn counter(self) -> u32; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 7173fcc77a2..97d586ba020 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -168,13 +168,16 @@ global NOTE_HASH_LENGTH = 2; global SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; global NULLIFIER_LENGTH = 3; global SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; +global CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH + 1; +global PRIVATE_CALL_REQUEST_LENGTH = 3 + CALLER_CONTEXT_LENGTH; +global SCOPED_PRIVATE_CALL_REQUEST_LENGTH = PRIVATE_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; global SIDE_EFFECT_LENGTH = 2; global ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; global STATE_REFERENCE_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u64 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; global HEADER_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH; -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; global PUBLIC_CONTEXT_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + GAS_LENGTH + 2; @@ -187,9 +190,8 @@ global PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; global COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 5 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; global COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; -global CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; global CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; -global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); +global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + (SCOPED_PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; global PUBLIC_ACCUMULATED_DATA_LENGTH = (MAX_NEW_NOTE_HASHES_PER_TX * NOTE_HASH_LENGTH) + (MAX_NEW_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * 1) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + GAS_LENGTH; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index ba88b2d5c7a..ea2db5f580a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -9,6 +9,7 @@ use crate::{ private_kernel_data::PrivateKernelData, note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, nullifier_key_validation_request::{ScopedNullifierKeyValidationRequest, NullifierKeyValidationRequest}, + private_call_request::{PrivateCallRequest, ScopedPrivateCallRequest}, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::{ReadRequest, ScopedReadRequest}, log_hash::{LogHash, NoteLogHash}, validation_requests::{ValidationRequests, ValidationRequestsBuilder} @@ -54,7 +55,7 @@ struct FixtureBuilder { encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, public_data_update_requests: BoundedVec, - private_call_stack: BoundedVec, + private_call_requests: BoundedVec, public_call_stack: BoundedVec, gas_used: Gas, non_revertible_gas_used: Gas, @@ -84,7 +85,7 @@ struct FixtureBuilder { impl FixtureBuilder { pub fn new() -> Self { - let tx_context = TxContext { chain_id: 1, version: 0, gas_settings: GasSettings::empty() }; + let tx_context = TxContext { chain_id: fixtures::CHAIN_ID, version: fixtures::VERSION, gas_settings: GasSettings::empty() }; FixtureBuilder { contract_address: fixtures::contracts::parent_contract.address, @@ -104,7 +105,7 @@ impl FixtureBuilder { encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, public_data_update_requests: BoundedVec::new(), - private_call_stack: BoundedVec::new(), + private_call_requests: BoundedVec::new(), public_call_stack: BoundedVec::new(), max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: BoundedVec::new(), @@ -143,7 +144,7 @@ impl FixtureBuilder { note_encrypted_logs_hashes: self.note_encrypted_logs_hashes, encrypted_logs_hashes: self.encrypted_logs_hashes, unencrypted_logs_hashes: self.unencrypted_logs_hashes, - private_call_stack: self.private_call_stack, + private_call_stack: self.private_call_requests, public_call_stack: self.public_call_stack }; public_inputs.finish() @@ -446,8 +447,17 @@ impl FixtureBuilder { } pub fn push_private_call_request(&mut self, hash: Field, is_delegate_call: bool) { - let call_stack_item = self.generate_call_request(hash, is_delegate_call); - self.private_call_stack.push(call_stack_item); + let mut caller_context = CallerContext::empty(); + if is_delegate_call { + caller_context.msg_sender = fixtures::MSG_SENDER; + caller_context.storage_contract_address = self.contract_address; + } + let start_counter = self.next_counter(); + let end_counter = start_counter + 10; + self.counter = end_counter; + self.private_call_requests.push( + PrivateCallRequest { hash, caller_context, start_side_effect_counter: start_counter, end_side_effect_counter: end_counter }.scope(self.contract_address) + ); } pub fn push_public_call_request(&mut self, hash: Field, is_delegate_call: bool) { @@ -532,7 +542,7 @@ impl Empty for FixtureBuilder { encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, public_data_update_requests: BoundedVec::new(), - private_call_stack: BoundedVec::new(), + private_call_requests: BoundedVec::new(), public_call_stack: BoundedVec::new(), max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr index e4e95339cda..d30e18d7056 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr @@ -6,3 +6,7 @@ use crate::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; global MSG_SENDER = AztecAddress { inner: 27 }; global PUBLIC_KEY = GrumpkinPoint { x: 123456789, y: 123456789 }; + +global CHAIN_ID = 1; + +global VERSION = 3; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index c3d29483cca..afbf7f07b7d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -2,7 +2,9 @@ use crate::{ abis::{ gas_settings::GasSettings, call_request::{CallerContext, CallRequest}, private_call_stack_item::PrivateCallStackItem, function_data::FunctionData, - max_block_number::MaxBlockNumber, private_circuit_public_inputs::PrivateCircuitPublicInputs, + max_block_number::MaxBlockNumber, + private_call_request::{PrivateCallRequest, ScopedPrivateCallRequest}, + private_circuit_public_inputs::PrivateCircuitPublicInputs, private_kernel::private_call_data::PrivateCallData, log_hash::LogHash }, merkle_tree::membership::MembershipWitness, @@ -20,7 +22,6 @@ struct PrivateCallDataBuilder { is_execution_request: bool, function_data: FunctionData, // The rest of the values of PrivateCallData. - private_call_stack: BoundedVec, public_call_stack: BoundedVec, public_teardown_call_request: CallRequest, proof: RecursiveProof, @@ -51,7 +52,6 @@ impl PrivateCallDataBuilder { public_inputs, is_execution_request: false, function_data, - private_call_stack: BoundedVec::new(), public_call_stack: BoundedVec::new(), public_teardown_call_request: CallRequest::empty(), proof: RecursiveProof::empty(), @@ -86,36 +86,21 @@ impl PrivateCallDataBuilder { } } - pub fn build_call_request(self) -> CallRequest { + pub fn build_call_request(self) -> ScopedPrivateCallRequest { let hash = self.build_call_stack_item().hash(); let is_delegate_call = self.public_inputs.call_context.is_delegate_call; - let caller_context = if is_delegate_call { - CallerContext { - msg_sender: fixtures::MSG_SENDER, - storage_contract_address: self.public_inputs.call_context.storage_contract_address - } - } else { - CallerContext::empty() + let mut caller_context = CallerContext::empty(); + caller_context.is_static_call = self.public_inputs.call_context.is_static_call; + if is_delegate_call { + caller_context.msg_sender = fixtures::MSG_SENDER; + caller_context.storage_contract_address = self.public_inputs.call_context.storage_contract_address; }; - CallRequest { + PrivateCallRequest { hash, - caller_contract_address: self.public_inputs.call_context.msg_sender, caller_context, start_side_effect_counter: self.public_inputs.counter_start, end_side_effect_counter: self.public_inputs.counter_end - } - } - - pub fn append_private_call_requests(&mut self, num_requests: u64, is_delegate_call: bool) { - let hash_offset = 7070 + self.private_call_stack.len(); - for i in 0..self.private_call_stack.max_len() { - if i < num_requests { - let hash = (hash_offset + i) as Field; - let request = self.public_inputs.generate_call_request(hash, is_delegate_call); - self.private_call_stack.push(request); - self.public_inputs.add_private_call_request(hash); - } - } + }.scope(self.public_inputs.call_context.msg_sender) } pub fn append_public_call_requests(&mut self, num_requests: u64, is_delegate_call: bool) { @@ -151,7 +136,6 @@ impl PrivateCallDataBuilder { pub fn finish(self) -> PrivateCallData { PrivateCallData { call_stack_item: self.build_call_stack_item(), - private_call_stack: self.private_call_stack.storage, public_call_stack: self.public_call_stack.storage, public_teardown_call_request: self.public_teardown_call_request, proof: self.proof, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 12f692a03fe..6976b98d761 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -3,8 +3,8 @@ use crate::{ call_context::CallContext, call_request::CallRequest, caller_context::CallerContext, gas_settings::GasSettings, gas::Gas, max_block_number::MaxBlockNumber, note_hash::NoteHash, nullifier::Nullifier, nullifier_key_validation_request::NullifierKeyValidationRequest, - private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, - log_hash::{LogHash, NoteLogHash} + private_call_request::PrivateCallRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, + read_request::ReadRequest, log_hash::{LogHash, NoteLogHash} }, address::{AztecAddress, compute_initialization_hash}, header::Header, messaging::l2_to_l1_message::L2ToL1Message, tests::fixtures, transaction::tx_context::TxContext @@ -39,7 +39,7 @@ struct PrivateCircuitPublicInputsBuilder { new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, - private_call_stack_hashes: BoundedVec, + private_call_requests: BoundedVec, public_call_stack_hashes: BoundedVec, public_teardown_function_hash: Field, new_l2_to_l1_msgs: BoundedVec, @@ -83,9 +83,9 @@ impl PrivateCircuitPublicInputsBuilder { side_effect_counter: counter }; - public_inputs.chain_id = 0; - public_inputs.version = 1; - public_inputs.gas_settings = GasSettings::default(); + public_inputs.chain_id = fixtures::CHAIN_ID; + public_inputs.version = fixtures::VERSION; + public_inputs.gas_settings = GasSettings::empty(); public_inputs.counter_start = counter; public_inputs.counter_end = counter + 1; @@ -175,10 +175,31 @@ impl PrivateCircuitPublicInputsBuilder { } } - pub fn add_private_call_request(&mut self, hash: Field) { - let _ = self.next_counter(); // Increment for creating the call. - self.private_call_stack_hashes.push(hash); - let _ = self.next_counter(); // Increment for ending the call. + pub fn add_private_call_request(&mut self, hash: Field, is_delegate_call: bool) { + let mut caller_context = CallerContext::empty(); + caller_context.is_static_call = self.call_context.is_static_call; + if is_delegate_call { + caller_context.msg_sender = self.call_context.msg_sender; + caller_context.storage_contract_address = self.call_context.storage_contract_address; + } + self.private_call_requests.push( + PrivateCallRequest { + hash, + caller_context, + start_side_effect_counter: self.next_counter(), + end_side_effect_counter: self.next_counter() + } + ); + } + + pub fn append_private_call_requests(&mut self, num_requests: u64, is_delegate_call: bool) { + let hash_offset = 7070 + self.private_call_requests.len(); + for i in 0..self.private_call_requests.max_len() { + if i < num_requests { + let hash = (hash_offset + i) as Field; + self.add_private_call_request(hash, is_delegate_call); + } + } } pub fn add_public_call_request(&mut self, hash: Field) { @@ -206,7 +227,7 @@ impl PrivateCircuitPublicInputsBuilder { nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, - private_call_stack_hashes: self.private_call_stack_hashes.storage, + private_call_requests: self.private_call_requests.storage, public_call_stack_hashes: self.public_call_stack_hashes.storage, public_teardown_function_hash: self.public_teardown_function_hash, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, @@ -242,7 +263,7 @@ impl Empty for PrivateCircuitPublicInputsBuilder { nullifier_key_validation_requests: BoundedVec::new(), new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), - private_call_stack_hashes: BoundedVec::new(), + private_call_requests: BoundedVec::new(), public_call_stack_hashes: BoundedVec::new(), public_teardown_function_hash: 0, new_l2_to_l1_msgs: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr index 4f1b5ab95a1..7320e430475 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr @@ -18,6 +18,10 @@ impl Reader { self.read() as u32 } + pub fn read_bool(&mut self) -> bool { + self.read() as bool + } + pub fn read_array(&mut self, mut result: [Field; K]) -> [Field; K] { for i in 0..K { result[i] = self.data[self.offset + i]; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 4a35f384538..c1306b20c4a 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -112,6 +112,9 @@ export const NOTE_HASH_LENGTH = 2; export const SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; export const NULLIFIER_LENGTH = 3; export const SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; +export const CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH + 1; +export const PRIVATE_CALL_REQUEST_LENGTH = 3 + CALLER_CONTEXT_LENGTH; +export const SCOPED_PRIVATE_CALL_REQUEST_LENGTH = PRIVATE_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; export const SIDE_EFFECT_LENGTH = 2; export const ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; export const STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; @@ -128,7 +131,7 @@ export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL + NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL + NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL + - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + + PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL + @@ -179,7 +182,6 @@ export const COMBINED_ACCUMULATED_DATA_LENGTH = MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH + GAS_LENGTH; export const COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; -export const CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; export const CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; export const PRIVATE_ACCUMULATED_DATA_LENGTH = SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX + @@ -188,7 +190,7 @@ export const PRIVATE_ACCUMULATED_DATA_LENGTH = NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX + LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX + LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX + - CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX + + SCOPED_PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX + CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX; export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap index 169f798b7ea..368859ee031 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x29d77b0175116357d39252de002a2944652f87ccb4404f9346bff6d44f020f7f>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x10d9feff1d02db424becc3399f496be13d0586ea5a62c85de302ea88a1f345c5>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x00c30fa28e1ab0d35bd0eaa591f469b7f9b92bc37aa5696eaf447b88ad331339>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x1426b15f965c906a750c82da93ebc07dc4401670539baf658adaaf3177f6d260>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index dbe26205c72..1193874ffdc 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x0e8b75e4ecf8bed8e361ff2702a1c200d1f4d4394c8f06dc9003eee571982c6c>`; +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x24ea8c67b7902c1bdc827592303786ea3df7ada25a95e8682ed26b9b36fe2f9e>`; -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x16aaaeeda5082bca41b5488bb064a3384f43c61b6f4f6f14d6ad3c3e1eb71fcc>`; +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x0a365dc5815493927b46c010f3388958a3a5373f6098fbaafa70aa61d6a92ca2>`; diff --git a/yarn-project/circuits.js/src/structs/call_request.ts b/yarn-project/circuits.js/src/structs/call_request.ts index 89fef28fcb7..518b846cc58 100644 --- a/yarn-project/circuits.js/src/structs/call_request.ts +++ b/yarn-project/circuits.js/src/structs/call_request.ts @@ -1,72 +1,9 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { type FieldsOf } from '@aztec/foundation/types'; -/** - * Caller context. - */ -export class CallerContext { - constructor( - /** - * Address of the caller contract. - */ - public msgSender: AztecAddress, - /** - * Storage contract address of the caller contract. - */ - public storageContractAddress: AztecAddress, - ) {} - - /** - * Returns a new instance of CallerContext with zero values. - * @returns A new instance of CallerContext with zero values. - */ - public static empty(): CallerContext { - return new CallerContext(AztecAddress.ZERO, AztecAddress.ZERO); - } - - isEmpty() { - return this.msgSender.isZero() && this.storageContractAddress.isZero(); - } - - static from(fields: FieldsOf): CallerContext { - return new CallerContext(...CallerContext.getFields(fields)); - } - - static getFields(fields: FieldsOf) { - return [fields.msgSender, fields.storageContractAddress] as const; - } - - /** - * Serialize this as a buffer. - * @returns The buffer. - */ - toBuffer() { - return serializeToBuffer(...CallerContext.getFields(this)); - } - - /** - * Deserialize this from a buffer. - * @param buffer - The bufferable type from which to deserialize. - * @returns The deserialized instance of PublicCallRequest. - */ - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new CallerContext(new AztecAddress(reader.readBytes(32)), new AztecAddress(reader.readBytes(32))); - } - - equals(callerContext: CallerContext) { - return ( - callerContext.msgSender.equals(this.msgSender) && - callerContext.storageContractAddress.equals(this.storageContractAddress) - ); - } -} +import { CallerContext } from './caller_context.js'; -/** - * Call request. - */ export class CallRequest { constructor( /** diff --git a/yarn-project/circuits.js/src/structs/caller_context.ts b/yarn-project/circuits.js/src/structs/caller_context.ts new file mode 100644 index 00000000000..7edceebc5a2 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/caller_context.ts @@ -0,0 +1,80 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { type Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { type FieldsOf } from '@aztec/foundation/types'; + +export class CallerContext { + constructor( + /** + * Message sender of the caller contract. + */ + public msgSender: AztecAddress, + /** + * Storage contract address of the caller contract. + */ + public storageContractAddress: AztecAddress, + /** + * Whether the caller was modifying state. + */ + public isStaticCall: boolean, + ) {} + + toFields(): Fr[] { + return serializeToFields([this.msgSender, this.storageContractAddress, this.isStaticCall]); + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new CallerContext(reader.readObject(AztecAddress), reader.readObject(AztecAddress), reader.readBoolean()); + } + + /** + * Returns a new instance of CallerContext with zero values. + * @returns A new instance of CallerContext with zero values. + */ + public static empty(): CallerContext { + return new CallerContext(AztecAddress.ZERO, AztecAddress.ZERO, false); + } + + isEmpty() { + return this.msgSender.isZero() && this.storageContractAddress.isZero() && !this.isStaticCall; + } + + static from(fields: FieldsOf): CallerContext { + return new CallerContext(...CallerContext.getFields(fields)); + } + + static getFields(fields: FieldsOf) { + return [fields.msgSender, fields.storageContractAddress, fields.isStaticCall] as const; + } + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer(...CallerContext.getFields(this)); + } + + /** + * Deserialize this from a buffer. + * @param buffer - The bufferable type from which to deserialize. + * @returns The deserialized instance of PublicCallRequest. + */ + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new CallerContext( + new AztecAddress(reader.readBytes(32)), + new AztecAddress(reader.readBytes(32)), + reader.readBoolean(), + ); + } + + equals(callerContext: CallerContext) { + return ( + callerContext.msgSender.equals(this.msgSender) && + callerContext.storageContractAddress.equals(this.storageContractAddress) && + callerContext.isStaticCall === this.isStaticCall + ); + } +} diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 8be49f1d142..e4e2b2b4194 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -2,6 +2,7 @@ export * from '@aztec/foundation/eth-address'; export * from './aggregation_object.js'; export * from './call_context.js'; export * from './call_request.js'; +export * from './caller_context.js'; export * from './complete_address.js'; export * from './content_commitment.js'; export * from './context/private_context_inputs.js'; @@ -46,6 +47,7 @@ export * from './parity/parity_public_inputs.js'; export * from './parity/root_parity_input.js'; export * from './parity/root_parity_inputs.js'; export * from './partial_state_reference.js'; +export * from './private_call_request.js'; export * from './private_call_stack_item.js'; export * from './private_circuit_public_inputs.js'; export * from './proof.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts index 8582079e98d..f7de543fb76 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts @@ -16,6 +16,7 @@ import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; import { LogHash, NoteLogHash } from '../log_hash.js'; import { ScopedNoteHash } from '../note_hash.js'; import { ScopedNullifier } from '../nullifier.js'; +import { ScopedPrivateCallRequest } from '../private_call_request.js'; /** * Specific accumulated data structure for the final ordering private kernel circuit. It is included @@ -52,9 +53,8 @@ export class PrivateAccumulatedData { public unencryptedLogsHashes: Tuple, /** * Current private call stack. - * TODO(#3417): Given this field must empty, should we just remove it? */ - public privateCallStack: Tuple, + public privateCallStack: Tuple, /** * Current public call stack. */ @@ -92,7 +92,7 @@ export class PrivateAccumulatedData { reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash), reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, LogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, LogHash), - reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), + reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, ScopedPrivateCallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), ); } @@ -114,7 +114,7 @@ export class PrivateAccumulatedData { makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash.empty), makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, LogHash.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, LogHash.empty), - makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), + makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, ScopedPrivateCallRequest.empty), makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), ); } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts index 0500563e16d..c00d927fb5b 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts @@ -4,7 +4,6 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { FUNCTION_TREE_HEIGHT, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, RECURSIVE_PROOF_LENGTH, } from '../../constants.gen.js'; @@ -23,10 +22,6 @@ export class PrivateCallData { * The call stack item currently being processed. */ public callStackItem: PrivateCallStackItem, - /** - * Other private call stack items to be processed. - */ - public privateCallStack: Tuple, /** * Other public call stack items to be processed. */ @@ -77,7 +72,6 @@ export class PrivateCallData { static getFields(fields: FieldsOf) { return [ fields.callStackItem, - fields.privateCallStack, fields.publicCallStack, fields.publicTeardownCallRequest, fields.proof, @@ -112,7 +106,6 @@ export class PrivateCallData { const reader = BufferReader.asReader(buffer); return new PrivateCallData( reader.readObject(PrivateCallStackItem), - reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, CallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, CallRequest), reader.readObject(CallRequest), RecursiveProof.fromBuffer(reader, RECURSIVE_PROOF_LENGTH), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts index 7262cc7b1b5..b2b83ece100 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts @@ -8,7 +8,6 @@ export class PrivateKernelInitHints { constructor( public noteHashNullifierCounters: Tuple, public firstRevertiblePrivateCallRequestIndex: number, - public firstRevertiblePublicCallRequestIndex: number, ) {} toBuffer() { @@ -17,11 +16,7 @@ export class PrivateKernelInitHints { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new PrivateKernelInitHints( - reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_CALL), - reader.readNumber(), - reader.readNumber(), - ); + return new PrivateKernelInitHints(reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_CALL), reader.readNumber()); } } diff --git a/yarn-project/circuits.js/src/structs/private_call_request.ts b/yarn-project/circuits.js/src/structs/private_call_request.ts new file mode 100644 index 00000000000..2363165925c --- /dev/null +++ b/yarn-project/circuits.js/src/structs/private_call_request.ts @@ -0,0 +1,109 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; + +import { CallerContext } from './caller_context.js'; + +export class PrivateCallRequest { + constructor( + /** + * The call stack item hash of the call. + */ + public hash: Fr, + /** + * The call context of the contract making the call. + */ + public callerContext: CallerContext, + /** + * The start counter of the call. + */ + public startSideEffectCounter: number, + /** + * The end counter of the call. + */ + public endSideEffectCounter: number, + ) {} + + toFields(): Fr[] { + return serializeToFields([this.hash, this.callerContext, this.startSideEffectCounter, this.endSideEffectCounter]); + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new PrivateCallRequest( + reader.readField(), + reader.readObject(CallerContext), + reader.readU32(), + reader.readU32(), + ); + } + + toBuffer() { + return serializeToBuffer(this.hash, this.callerContext, this.startSideEffectCounter, this.endSideEffectCounter); + } + + public static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PrivateCallRequest( + Fr.fromBuffer(reader), + reader.readObject(CallerContext), + reader.readNumber(), + reader.readNumber(), + ); + } + + isEmpty() { + return ( + this.hash.isZero() && + this.callerContext.isEmpty() && + this.startSideEffectCounter === 0 && + this.endSideEffectCounter === 0 + ); + } + + public static empty() { + return new PrivateCallRequest(Fr.ZERO, CallerContext.empty(), 0, 0); + } + + equals(callRequest: PrivateCallRequest) { + return ( + callRequest.hash.equals(this.hash) && + callRequest.callerContext.equals(this.callerContext) && + callRequest.startSideEffectCounter === this.startSideEffectCounter && + callRequest.endSideEffectCounter === this.endSideEffectCounter + ); + } + + toString() { + return `PrivateCallRequest(hash: ${this.hash}, callerContext: ${this.callerContext}, startSideEffectCounter: ${this.startSideEffectCounter}, endSideEffectCounter: ${this.endSideEffectCounter})`; + } +} + +export class ScopedPrivateCallRequest { + constructor(public callRequest: PrivateCallRequest, public contractAddress: AztecAddress) {} + + toBuffer() { + return serializeToBuffer(this.callRequest, this.contractAddress); + } + + public static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ScopedPrivateCallRequest(reader.readObject(PrivateCallRequest), reader.readObject(AztecAddress)); + } + + isEmpty() { + return this.callRequest.isEmpty() && this.contractAddress.isZero(); + } + + public static empty() { + return new ScopedPrivateCallRequest(PrivateCallRequest.empty(), AztecAddress.ZERO); + } + + equals(callRequest: ScopedPrivateCallRequest) { + return callRequest.callRequest.equals(this.callRequest) && callRequest.contractAddress.equals(this.contractAddress); + } + + toString() { + return `ScopedPrivateCallRequest(callRequest: ${this.callRequest}, contractAddress: ${this.contractAddress})`; + } +} diff --git a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts index 23f9060c372..bfce7897770 100644 --- a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts +++ b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts @@ -1,12 +1,10 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; -import { Fr } from '@aztec/foundation/fields'; +import { type Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; import { GeneratorIndex, PRIVATE_CALL_STACK_ITEM_LENGTH } from '../constants.gen.js'; -import { type CallContext } from './call_context.js'; -import { CallRequest, CallerContext } from './call_request.js'; import { FunctionData } from './function_data.js'; import { PrivateCircuitPublicInputs } from './private_circuit_public_inputs.js'; @@ -93,26 +91,4 @@ export class PrivateCallStackItem { public hash(): Fr { return pedersenHash(this.toFields(), GeneratorIndex.CALL_STACK_ITEM); } - - /** - * Creates a new CallRequest with values of the calling contract. - * @returns A CallRequest instance with the contract address, caller context, and the hash of the call stack item. - */ - public toCallRequest(parentCallContext: CallContext) { - if (this.isEmpty()) { - return CallRequest.empty(); - } - - const currentCallContext = this.publicInputs.callContext; - const callerContext = currentCallContext.isDelegateCall - ? new CallerContext(parentCallContext.msgSender, parentCallContext.storageContractAddress) - : CallerContext.empty(); - return new CallRequest( - this.hash(), - parentCallContext.storageContractAddress, - callerContext, - new Fr(this.publicInputs.callContext.sideEffectCounter), - this.publicInputs.endSideEffectCounter, - ); - } } diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index 32197024ef7..4f59fd5d599 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -35,6 +35,7 @@ import { MaxBlockNumber } from './max_block_number.js'; import { NoteHash } from './note_hash.js'; import { Nullifier } from './nullifier.js'; import { NullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; +import { PrivateCallRequest } from './private_call_request.js'; import { ReadRequest } from './read_request.js'; import { TxContext } from './tx_context.js'; @@ -91,9 +92,9 @@ export class PrivateCircuitPublicInputs { */ public newNullifiers: Tuple, /** - * Private call stack at the current kernel iteration. + * Private call requests made within the current kernel iteration. */ - public privateCallStackHashes: Tuple, + public privateCallRequests: Tuple, /** * Public call stack at the current kernel iteration. */ @@ -171,7 +172,7 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, NoteHash), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, Nullifier), - reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, Fr), + reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PrivateCallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, Fr), reader.readObject(Fr), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), @@ -199,7 +200,7 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, NoteHash), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, Nullifier), - reader.readFieldArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL), + reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PrivateCallRequest), reader.readFieldArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL), reader.readField(), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), @@ -230,7 +231,7 @@ export class PrivateCircuitPublicInputs { makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, NoteHash.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, Nullifier.empty), - makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, Fr.zero), + makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PrivateCallRequest.empty), makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, Fr.zero), Fr.ZERO, makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), @@ -258,7 +259,7 @@ export class PrivateCircuitPublicInputs { isEmptyArray(this.nullifierKeyValidationRequests) && isEmptyArray(this.newNoteHashes) && isEmptyArray(this.newNullifiers) && - isZeroArray(this.privateCallStackHashes) && + isEmptyArray(this.privateCallRequests) && isZeroArray(this.publicCallStackHashes) && this.publicTeardownFunctionHash.isZero() && isEmptyArray(this.newL2ToL1Msgs) && @@ -288,7 +289,7 @@ export class PrivateCircuitPublicInputs { fields.nullifierKeyValidationRequests, fields.newNoteHashes, fields.newNullifiers, - fields.privateCallStackHashes, + fields.privateCallRequests, fields.publicCallStackHashes, fields.publicTeardownFunctionHash, fields.newL2ToL1Msgs, diff --git a/yarn-project/circuits.js/src/structs/public_call_request.ts b/yarn-project/circuits.js/src/structs/public_call_request.ts index f371a91b1d2..752adfc7672 100644 --- a/yarn-project/circuits.js/src/structs/public_call_request.ts +++ b/yarn-project/circuits.js/src/structs/public_call_request.ts @@ -7,7 +7,8 @@ import { inspect } from 'util'; import { computeVarArgsHash } from '../hash/hash.js'; import { CallContext } from './call_context.js'; -import { CallRequest, CallerContext } from './call_request.js'; +import { CallRequest } from './call_request.js'; +import { CallerContext } from './caller_context.js'; import { FunctionData } from './function_data.js'; import { PublicCallStackItem } from './public_call_stack_item.js'; import { PublicCircuitPublicInputs } from './public_circuit_public_inputs.js'; @@ -116,7 +117,11 @@ export class PublicCallRequest { toCallRequest() { const item = this.toPublicCallStackItem(); const callerContext = this.callContext.isDelegateCall - ? new CallerContext(this.parentCallContext.msgSender, this.parentCallContext.storageContractAddress) + ? new CallerContext( + this.parentCallContext.msgSender, + this.parentCallContext.storageContractAddress, + this.parentCallContext.isStaticCall, + ) : CallerContext.empty(); return new CallRequest( item.hash(), diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.ts index 0d53df6b95c..3223909d287 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.ts @@ -6,7 +6,8 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { GeneratorIndex } from '../constants.gen.js'; import { type CallContext } from './call_context.js'; -import { CallRequest, CallerContext } from './call_request.js'; +import { CallRequest } from './call_request.js'; +import { CallerContext } from './caller_context.js'; import { FunctionData } from './function_data.js'; import { PublicCircuitPublicInputs } from './public_circuit_public_inputs.js'; @@ -113,7 +114,11 @@ export class PublicCallStackItem { const currentCallContext = this.publicInputs.callContext; const callerContext = currentCallContext.isDelegateCall - ? new CallerContext(parentCallContext.msgSender, parentCallContext.storageContractAddress) + ? new CallerContext( + parentCallContext.msgSender, + parentCallContext.storageContractAddress, + parentCallContext.isStaticCall, + ) : CallerContext.empty(); // todo: populate side effect counters correctly return new CallRequest(this.hash(), parentCallContext.storageContractAddress, callerContext, Fr.ZERO, Fr.ZERO); diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 7037eabcb35..47664f24fd3 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -27,7 +27,6 @@ import { ConstantRollupData, ContractStorageRead, ContractStorageUpdateRequest, - FUNCTION_TREE_HEIGHT, Fq, Fr, FunctionData, @@ -91,7 +90,7 @@ import { PartialStateReference, Point, PreviousRollupData, - PrivateCallData, + PrivateCallRequest, PrivateCallStackItem, PrivateCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, @@ -616,7 +615,7 @@ export function makeProof(seed = 1) { * @returns A call stack item. */ export function makeCallerContext(seed = 1): CallerContext { - return new CallerContext(makeAztecAddress(seed), makeAztecAddress(seed + 0x1)); + return new CallerContext(makeAztecAddress(seed), makeAztecAddress(seed + 0x1), false); } /** @@ -628,6 +627,10 @@ export function makeCallRequest(seed = 1): CallRequest { return new CallRequest(fr(seed), makeAztecAddress(seed + 0x1), makeCallerContext(seed + 0x2), fr(0), fr(0)); } +function makePrivateCallRequest(seed = 1): PrivateCallRequest { + return new PrivateCallRequest(fr(seed), makeCallerContext(seed + 0x2), seed + 0x10, seed + 0x11); +} + /** * Makes arbitrary public call stack item. * @param seed - The seed to use for generating the public call stack item. @@ -729,28 +732,6 @@ export function makeTxRequest(seed = 1): TxRequest { }); } -/** - * Makes arbitrary private call data. - * @param seed - The seed to use for generating the private call data. - * @returns A private call data. - */ -export function makePrivateCallData(seed = 1): PrivateCallData { - return PrivateCallData.from({ - callStackItem: makePrivateCallStackItem(seed), - privateCallStack: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, makeCallRequest, seed + 0x10), - publicCallStack: makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, makeCallRequest, seed + 0x20), - publicTeardownCallRequest: makeCallRequest(seed + 0x30), - proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH, seed + 0x50), - vk: makeVerificationKeyAsFields(), - contractClassArtifactHash: fr(seed + 0x70), - contractClassPublicBytecodeCommitment: fr(seed + 0x71), - publicKeysHash: fr(seed + 0x72), - saltedInitializationHash: fr(seed + 0x73), - functionLeafMembershipWitness: makeMembershipWitness(FUNCTION_TREE_HEIGHT, seed + 0x30), - acirHash: fr(seed + 0x60), - }); -} - /** * Makes arbitrary private call stack item. * @param seed - The seed to use for generating the private call stack item. @@ -785,7 +766,7 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn ), newNoteHashes: makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, makeNoteHash, seed + 0x400), newNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, makeNullifier, seed + 0x500), - privateCallStackHashes: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, fr, seed + 0x600), + privateCallRequests: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, makePrivateCallRequest, seed + 0x600), publicCallStackHashes: makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, fr, seed + 0x700), publicTeardownFunctionHash: fr(seed + 0x800), newL2ToL1Msgs: makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x800), diff --git a/yarn-project/end-to-end/src/e2e_outbox.test.ts b/yarn-project/end-to-end/src/e2e_outbox.test.ts index 4a8d8ede821..1438588f500 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -58,7 +58,7 @@ describe('E2E Outbox Tests', () => { const l2ToL1Messages = block?.body.txEffects.flatMap(txEffect => txEffect.l2ToL1Msgs); expect(l2ToL1Messages?.map(l2ToL1Message => l2ToL1Message.toString())).toStrictEqual( - [makeL2ToL1Message(recipient2, content2), makeL2ToL1Message(recipient1, content1)].map(expectedL2ToL1Message => + [makeL2ToL1Message(recipient1, content1), makeL2ToL1Message(recipient2, content2)].map(expectedL2ToL1Message => expectedL2ToL1Message.toString(), ), ); diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 360c3f19bd3..2f6ef2aa908 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -70,6 +70,7 @@ import { type PreviousRollupData, PrivateAccumulatedData, type PrivateCallData, + PrivateCallRequest, type PrivateCallStackItem, type PrivateCircuitPublicInputs, PrivateKernelCircuitPublicInputs, @@ -112,6 +113,7 @@ import { ScopedNoteHash, ScopedNullifier, ScopedNullifierKeyValidationRequest, + ScopedPrivateCallRequest, ScopedReadRequest, type SettledReadHint, type StateDiffHints, @@ -177,6 +179,7 @@ import type { PreviousRollupData as PreviousRollupDataNoir, PrivateAccumulatedData as PrivateAccumulatedDataNoir, PrivateCallData as PrivateCallDataNoir, + PrivateCallRequest as PrivateCallRequestNoir, PrivateCallStackItem as PrivateCallStackItemNoir, PrivateCircuitPublicInputs as PrivateCircuitPublicInputsNoir, PrivateKernelCircuitPublicInputs as PrivateKernelCircuitPublicInputsNoir, @@ -216,6 +219,7 @@ import type { ScopedNoteHash as ScopedNoteHashNoir, ScopedNullifierKeyValidationRequest as ScopedNullifierKeyValidationRequestNoir, ScopedNullifier as ScopedNullifierNoir, + ScopedPrivateCallRequest as ScopedPrivateCallRequestNoir, ScopedReadRequest as ScopedReadRequestNoir, StateDiffHints as StateDiffHintsNoir, StateReference as StateReferenceNoir, @@ -496,6 +500,7 @@ export function mapCallerContextFromNoir(callerContext: CallerContextNoir): Call return new CallerContext( mapAztecAddressFromNoir(callerContext.msg_sender), mapAztecAddressFromNoir(callerContext.storage_contract_address), + callerContext.is_static_call, ); } @@ -508,6 +513,39 @@ export function mapCallerContextToNoir(callerContext: CallerContext): CallerCont return { msg_sender: mapAztecAddressToNoir(callerContext.msgSender), storage_contract_address: mapAztecAddressToNoir(callerContext.storageContractAddress), + is_static_call: callerContext.isStaticCall, + }; +} + +function mapPrivateCallRequestFromNoir(callRequest: PrivateCallRequestNoir) { + return new PrivateCallRequest( + mapFieldFromNoir(callRequest.hash), + mapCallerContextFromNoir(callRequest.caller_context), + mapNumberFromNoir(callRequest.start_side_effect_counter), + mapNumberFromNoir(callRequest.end_side_effect_counter), + ); +} + +function mapPrivateCallRequestToNoir(callRequest: PrivateCallRequest): PrivateCallRequestNoir { + return { + hash: mapFieldToNoir(callRequest.hash), + caller_context: mapCallerContextToNoir(callRequest.callerContext), + start_side_effect_counter: mapNumberToNoir(callRequest.startSideEffectCounter), + end_side_effect_counter: mapNumberToNoir(callRequest.endSideEffectCounter), + }; +} + +function mapScopedPrivateCallRequestFromNoir(callRequest: ScopedPrivateCallRequestNoir) { + return new ScopedPrivateCallRequest( + mapPrivateCallRequestFromNoir(callRequest.call_request), + mapAztecAddressFromNoir(callRequest.contract_address), + ); +} + +function mapScopedPrivateCallRequestToNoir(callRequest: ScopedPrivateCallRequest): ScopedPrivateCallRequestNoir { + return { + call_request: mapPrivateCallRequestToNoir(callRequest.callRequest), + contract_address: mapAztecAddressToNoir(callRequest.contractAddress), }; } @@ -794,7 +832,7 @@ export function mapPrivateCircuitPublicInputsToNoir( ), new_note_hashes: mapTuple(privateCircuitPublicInputs.newNoteHashes, mapNoteHashToNoir), new_nullifiers: mapTuple(privateCircuitPublicInputs.newNullifiers, mapNullifierToNoir), - private_call_stack_hashes: mapTuple(privateCircuitPublicInputs.privateCallStackHashes, mapFieldToNoir), + private_call_requests: mapTuple(privateCircuitPublicInputs.privateCallRequests, mapPrivateCallRequestToNoir), public_call_stack_hashes: mapTuple(privateCircuitPublicInputs.publicCallStackHashes, mapFieldToNoir), public_teardown_function_hash: mapFieldToNoir(privateCircuitPublicInputs.publicTeardownFunctionHash), new_l2_to_l1_msgs: mapTuple(privateCircuitPublicInputs.newL2ToL1Msgs, mapL2ToL1MessageToNoir), @@ -831,7 +869,6 @@ export function mapPrivateCallStackItemToNoir(privateCallStackItem: PrivateCallS export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): PrivateCallDataNoir { return { call_stack_item: mapPrivateCallStackItemToNoir(privateCallData.callStackItem), - private_call_stack: mapTuple(privateCallData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(privateCallData.publicCallStack, mapCallRequestToNoir), public_teardown_call_request: mapCallRequestToNoir(privateCallData.publicTeardownCallRequest), proof: mapRecursiveProofToNoir(privateCallData.proof), @@ -1098,7 +1135,7 @@ export function mapPrivateAccumulatedDataFromNoir( mapTupleFromNoir( privateAccumulatedData.private_call_stack, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - mapCallRequestFromNoir, + mapScopedPrivateCallRequestFromNoir, ), mapTupleFromNoir( privateAccumulatedData.public_call_stack, @@ -1116,7 +1153,7 @@ export function mapPrivateAccumulatedDataToNoir(data: PrivateAccumulatedData): P note_encrypted_logs_hashes: mapTuple(data.noteEncryptedLogsHashes, mapNoteLogHashToNoir), encrypted_logs_hashes: mapTuple(data.encryptedLogsHashes, mapLogHashToNoir), unencrypted_logs_hashes: mapTuple(data.unencryptedLogsHashes, mapLogHashToNoir), - private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), + private_call_stack: mapTuple(data.privateCallStack, mapScopedPrivateCallRequestToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), }; } @@ -1431,7 +1468,6 @@ function mapPrivateKernelInitHintsToNoir(inputs: PrivateKernelInitHints): Privat return { note_hash_nullifier_counters: mapTuple(inputs.noteHashNullifierCounters, mapNumberToNoir), first_revertible_private_call_request_index: mapNumberToNoir(inputs.firstRevertiblePrivateCallRequestIndex), - first_revertible_public_call_request_index: mapNumberToNoir(inputs.firstRevertiblePublicCallRequestIndex), }; } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index efbfafffe61..e96547fbbd7 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -186,7 +186,7 @@ describe('Kernel Prover', () => { }; const executionResult = createExecutionResult('a'); await prove(executionResult); - expectExecution(['a', 'd', 'b', 'c']); + expectExecution(['a', 'b', 'c', 'd']); } { @@ -197,7 +197,7 @@ describe('Kernel Prover', () => { }; const executionResult = createExecutionResult('k'); await prove(executionResult); - expectExecution(['k', 'o', 'r', 'p', 'n', 'm', 'q']); + expectExecution(['k', 'm', 'q', 'o', 'n', 'p', 'r']); } }); }); diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index b9c74e48f36..6a88d0a2791 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -2,7 +2,6 @@ import { type KernelProofOutput, type ProofCreator } from '@aztec/circuit-types' import { CallRequest, Fr, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, NESTED_RECURSIVE_PROOF_LENGTH, PrivateCallData, @@ -74,11 +73,8 @@ export class KernelProver { while (executionStack.length) { const currentExecution = executionStack.pop()!; - executionStack.push(...currentExecution.nestedExecutions); + executionStack.push(...[...currentExecution.nestedExecutions].reverse()); - const privateCallRequests = currentExecution.nestedExecutions.map(result => - result.callStackItem.toCallRequest(currentExecution.callStackItem.publicInputs.callContext), - ); const publicCallRequests = currentExecution.enqueuedPublicFunctionCalls.map(result => result.toCallRequest()); const publicTeardownCallRequest = currentExecution.publicTeardownFunctionCall.isEmpty() ? CallRequest.empty() @@ -97,7 +93,6 @@ export class KernelProver { const privateCallData = await this.createPrivateCallData( currentExecution, - privateCallRequests, publicCallRequests, publicTeardownCallRequest, proofOutput.proof, @@ -108,8 +103,7 @@ export class KernelProver { const hints = buildPrivateKernelInitHints( currentExecution.callStackItem.publicInputs, noteHashNullifierCounterMap, - privateCallRequests, - publicCallRequests, + currentExecution.callStackItem.publicInputs.privateCallRequests, ); const proofInput = new PrivateKernelInitCircuitPrivateInputs(txRequest, privateCallData, hints); pushTestData('private-kernel-inputs-init', proofInput); @@ -180,7 +174,6 @@ export class KernelProver { private async createPrivateCallData( { callStackItem }: ExecutionResult, - privateCallRequests: CallRequest[], publicCallRequests: CallRequest[], publicTeardownCallRequest: CallRequest, proof: RecursiveProof, @@ -188,12 +181,6 @@ export class KernelProver { ) { const { contractAddress, functionData } = callStackItem; - // Pad with empty items to reach max/const length expected by circuit. - const privateCallStack = padArrayEnd( - privateCallRequests, - CallRequest.empty(), - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - ); const publicCallStack = padArrayEnd(publicCallRequests, CallRequest.empty(), MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL); const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness( @@ -212,7 +199,6 @@ export class KernelProver { return PrivateCallData.from({ callStackItem, - privateCallStack, publicCallStack, publicTeardownCallRequest, proof, diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts index fb6a95f5fd9..b81c952d023 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts @@ -1,6 +1,6 @@ import { - type CallRequest, type MAX_NEW_NOTE_HASHES_PER_CALL, + type PrivateCallRequest, type PrivateCircuitPublicInputs, PrivateKernelInitHints, countAccumulatedItems, @@ -10,30 +10,19 @@ import { type Tuple } from '@aztec/foundation/serialize'; export function buildPrivateKernelInitHints( publicInputs: PrivateCircuitPublicInputs, noteHashNullifierCounterMap: Map, - privateCallRequests: CallRequest[], - publicCallRequests: CallRequest[], + privateCallRequests: PrivateCallRequest[], ) { const nullifierCounters = publicInputs.newNoteHashes.map( n => noteHashNullifierCounterMap.get(n.counter) ?? 0, ) as Tuple; - const minRevertibleCounter = publicInputs.minRevertibleSideEffectCounter; + const minRevertibleCounter = publicInputs.minRevertibleSideEffectCounter.toNumber(); let firstRevertiblePrivateCallRequestIndex = privateCallRequests.findIndex( r => r.startSideEffectCounter >= minRevertibleCounter, ); if (firstRevertiblePrivateCallRequestIndex === -1) { firstRevertiblePrivateCallRequestIndex = countAccumulatedItems(privateCallRequests); } - let firstRevertiblePublicCallRequestIndex = publicCallRequests.findIndex( - r => r.startSideEffectCounter >= minRevertibleCounter, - ); - if (firstRevertiblePublicCallRequestIndex === -1) { - firstRevertiblePublicCallRequestIndex = countAccumulatedItems(publicCallRequests); - } - return new PrivateKernelInitHints( - nullifierCounters, - firstRevertiblePrivateCallRequestIndex, - firstRevertiblePublicCallRequestIndex, - ); + return new PrivateKernelInitHints(nullifierCounters, firstRevertiblePrivateCallRequestIndex); } diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 1e1f9db16ff..cf817342fc4 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -516,7 +516,7 @@ describe('Private Execution test suite', () => { // check that Aztec.nr calculated the call stack item hash like cpp does const expectedCallStackItemHash = result.nestedExecutions[0].callStackItem.hash(); - expect(result.callStackItem.publicInputs.privateCallStackHashes[0]).toEqual(expectedCallStackItemHash); + expect(result.callStackItem.publicInputs.privateCallRequests[0].hash).toEqual(expectedCallStackItemHash); }); }); From bf441da243405744caa9d5422e1b8a2676efba8b Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Mon, 20 May 2024 12:22:44 -0400 Subject: [PATCH 22/37] feat: sum transaction fees and pay on l1 (#6522) Add `totalFees` to block header. Update the spec. Note: we could have had the L1 rollup contract iterate over all the tx_effects and pay out that way. Doing it ourselves in the circuit feels cheaper though, and maybe safer for a world where: 1. tx_effects are spread over multiple l1 blocks 2. tx_effects are published as blobs so we wouldn't have direct access to math over them on l1. --- barretenberg/cpp/pil/avm/constants.pil | 22 +++++----- .../relations/generated/avm/avm_main.hpp | 16 +++---- .../vm/avm_trace/aztec_constants.hpp | 7 +-- .../gas-and-fees/kernel-tracking.md | 5 ++- .../published-gas-and-fee-data.md | 4 ++ .../gas-and-fees/specifying-gas-fee-info.md | 6 +++ .../rollup-circuits/base-rollup.md | 1 + .../protocol-specs/rollup-circuits/index.md | 1 + .../rollup-circuits/root-rollup.md | 1 + docs/docs/protocol-specs/state/archive.md | 1 + docs/docs/protocol-specs/state/index.md | 1 + l1-contracts/src/core/Rollup.sol | 6 +-- .../src/core/libraries/ConstantsGen.sol | 5 ++- l1-contracts/src/core/libraries/HeaderLib.sol | 7 ++- l1-contracts/test/fixtures/empty_block_0.json | 12 ++--- l1-contracts/test/fixtures/empty_block_1.json | 14 +++--- l1-contracts/test/fixtures/mixed_block_0.json | 12 ++--- l1-contracts/test/fixtures/mixed_block_1.json | 14 +++--- .../base_or_merge_rollup_public_inputs.nr | 8 +++- .../rollup-lib/src/base/base_rollup_inputs.nr | 7 ++- .../crates/rollup-lib/src/components.nr | 7 +++ .../src/merge/merge_rollup_inputs.nr | 5 ++- .../rollup-lib/src/root/root_rollup_inputs.nr | 5 ++- .../types/src/abis/private_call_stack_item.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 2 +- .../types/src/abis/public_call_stack_item.nr | 4 +- .../src/abis/public_circuit_public_inputs.nr | 2 +- .../crates/types/src/constants.nr | 7 ++- .../crates/types/src/header.nr | 12 ++++- .../src/l2_block_code_to_purge.ts | 2 + yarn-project/circuits.js/src/constants.gen.ts | 9 +++- .../structs/__snapshots__/header.test.ts.snap | 4 +- .../private_call_stack_item.test.ts.snap | 4 +- ...private_circuit_public_inputs.test.ts.snap | 4 +- .../public_call_stack_item.test.ts.snap | 8 ++-- .../public_circuit_public_inputs.test.ts.snap | 4 +- .../circuits.js/src/structs/header.ts | 44 ++++++++++++------- .../base_or_merge_rollup_public_inputs.ts | 8 ++++ .../circuits.js/src/tests/factories.ts | 2 + yarn-project/end-to-end/Earthfile | 3 ++ .../src/e2e_fees/private_payments.test.ts | 14 +++--- .../ethereum/src/deploy_l1_contracts.ts | 3 +- .../src/type_conversion.ts | 4 ++ .../src/client/private_execution.test.ts | 2 + .../src/world-state-db/merkle_trees.ts | 8 +++- 45 files changed, 210 insertions(+), 109 deletions(-) diff --git a/barretenberg/cpp/pil/avm/constants.pil b/barretenberg/cpp/pil/avm/constants.pil index d5985545280..d34e739d4b6 100644 --- a/barretenberg/cpp/pil/avm/constants.pil +++ b/barretenberg/cpp/pil/avm/constants.pil @@ -8,22 +8,22 @@ namespace constants(256); pol PORTAL_SELECTOR = 2; // NOTE: constant expression evaluation does not seem to be supported yet in pil - // pol START_GLOBAL_VARIABLES = CALL_CONTEXT_LENGTH + HEADER_LENGTH = 6 + 22 = 28 + // pol START_GLOBAL_VARIABLES = CALL_CONTEXT_LENGTH + HEADER_LENGTH = 6 + 23 = 29 // Global Variables - pol CHAIN_ID_SELECTOR = 28; - pol VERSION_SELECTOR = 29; - pol BLOCK_NUMBER_SELECTOR = 30; - pol TIMESTAMP_SELECTOR = 31; - pol COINBASE_SELECTOR = 32; + pol CHAIN_ID_SELECTOR = 29; + pol VERSION_SELECTOR = 30; + pol BLOCK_NUMBER_SELECTOR = 31; + pol TIMESTAMP_SELECTOR = 32; + pol COINBASE_SELECTOR = 33; - pol END_GLOBAL_VARIABLES = 28 + 8; // We only use the first 5 of 8 global variables for now + pol END_GLOBAL_VARIABLES = 29 + 8; // We only use the first 5 of 8 global variables for now - pol START_SIDE_EFFECT_COUNTER = 36; + pol START_SIDE_EFFECT_COUNTER = 37; // Gas - pol FEE_PER_DA_GAS_SELECTOR = 37; - pol FEE_PER_L2_GAS_SELECTOR = 38; + pol FEE_PER_DA_GAS_SELECTOR = 38; + pol FEE_PER_L2_GAS_SELECTOR = 39; - pol TRANSACTION_FEE_SELECTOR = 39; + pol TRANSACTION_FEE_SELECTOR = 40; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index 724f3dedbf7..c8a874ed04f 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -915,7 +915,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(83); - auto tmp = (avm_main_sel_op_fee_per_da_gas * (avm_kernel_kernel_sel - FF(37))); + auto tmp = (avm_main_sel_op_fee_per_da_gas * (avm_kernel_kernel_sel - FF(38))); tmp *= scaling_factor; std::get<83>(evals) += tmp; } @@ -923,7 +923,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(84); - auto tmp = (avm_main_sel_op_fee_per_l2_gas * (avm_kernel_kernel_sel - FF(38))); + auto tmp = (avm_main_sel_op_fee_per_l2_gas * (avm_kernel_kernel_sel - FF(39))); tmp *= scaling_factor; std::get<84>(evals) += tmp; } @@ -931,7 +931,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(85); - auto tmp = (avm_main_sel_op_transaction_fee * (avm_kernel_kernel_sel - FF(39))); + auto tmp = (avm_main_sel_op_transaction_fee * (avm_kernel_kernel_sel - FF(40))); tmp *= scaling_factor; std::get<85>(evals) += tmp; } @@ -939,7 +939,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(86); - auto tmp = (avm_main_sel_op_chain_id * (avm_kernel_kernel_sel - FF(28))); + auto tmp = (avm_main_sel_op_chain_id * (avm_kernel_kernel_sel - FF(29))); tmp *= scaling_factor; std::get<86>(evals) += tmp; } @@ -947,7 +947,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(87); - auto tmp = (avm_main_sel_op_version * (avm_kernel_kernel_sel - FF(29))); + auto tmp = (avm_main_sel_op_version * (avm_kernel_kernel_sel - FF(30))); tmp *= scaling_factor; std::get<87>(evals) += tmp; } @@ -955,7 +955,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(88); - auto tmp = (avm_main_sel_op_block_number * (avm_kernel_kernel_sel - FF(30))); + auto tmp = (avm_main_sel_op_block_number * (avm_kernel_kernel_sel - FF(31))); tmp *= scaling_factor; std::get<88>(evals) += tmp; } @@ -963,7 +963,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(89); - auto tmp = (avm_main_sel_op_coinbase * (avm_kernel_kernel_sel - FF(32))); + auto tmp = (avm_main_sel_op_coinbase * (avm_kernel_kernel_sel - FF(33))); tmp *= scaling_factor; std::get<89>(evals) += tmp; } @@ -971,7 +971,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(90); - auto tmp = (avm_main_sel_op_timestamp * (avm_kernel_kernel_sel - FF(31))); + auto tmp = (avm_main_sel_op_timestamp * (avm_kernel_kernel_sel - FF(32))); tmp *= scaling_factor; std::get<90>(evals) += tmp; } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp index 3e66247d244..9c188e7c883 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp @@ -109,8 +109,9 @@ const size_t ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; const size_t STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; const size_t TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; const size_t TX_REQUEST_LENGTH = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; -const size_t HEADER_LENGTH = - APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH; +const size_t TOTAL_FEES_LENGTH = 1; +const size_t HEADER_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; const size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + @@ -172,7 +173,7 @@ const size_t KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LE PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; const size_t CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 4 + GLOBAL_VARIABLES_LENGTH; const size_t BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = - CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 4; + CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; const size_t ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; const size_t GET_NOTES_ORACLE_RETURN_LENGTH = 674; const size_t NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md b/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md index 646e7023275..39c17faab89 100644 --- a/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md +++ b/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md @@ -78,6 +78,7 @@ CombinedConstantData --> TxContext class Header { +GlobalVariables global_variables + +Fr total_fees } Header --> GlobalVariables @@ -538,10 +539,12 @@ The interplay between these two `revert_code`s is as follows: | 1 | 1 | 3 | | 2 or 3 | (any) | (unchanged) | -## Base Rollup Kernel Circuit +## Rollup Kernel Circuits The base rollup kernel circuit takes in a `KernelData`, which contains a `KernelCircuitPublicInputs`, which it uses to compute the `transaction_fee`. Additionally, it verifies that the max fees per gas specified by the user are greater than the current block's fees per gas. It also verifies the `constant_data.global_variables.gas_fees` are correct. After the public data writes specific to this transaction have been processed, and a new tree root is produced, the kernel circuit injects an additional public data write based upon that root which deducts the transaction fee from the `fee_payer`'s balance. + +The calculated trasaction fee is set as output on the base rollup as `accumulated_fees`. Each subsequent merge rollup circuit sums this value from both of its inputs. The root rollup circuit then uses this value to set the `total_fees` in the `Header`. \ No newline at end of file diff --git a/docs/docs/protocol-specs/gas-and-fees/published-gas-and-fee-data.md b/docs/docs/protocol-specs/gas-and-fees/published-gas-and-fee-data.md index fbdc0899b49..3c69c036214 100644 --- a/docs/docs/protocol-specs/gas-and-fees/published-gas-and-fee-data.md +++ b/docs/docs/protocol-specs/gas-and-fees/published-gas-and-fee-data.md @@ -12,6 +12,10 @@ The block header contains a `GlobalVariables`, which contains a `GasFees` object - `feePerDaGas`: The fee in [FPA](./fee-payment-asset.md) per unit of DA gas consumed for transactions in the block. - `feePerL2Gas`: The fee in FPA per unit of L2 gas consumed for transactions in the block. +`GlobalVariables` also includes a `coinbase` field, which is the L1 address that receives the fees. + +The block header also contains a `totalFees` field, which is the total fees collected in the block in FPA. + ## Updating the `GasFees` Object Presently, the `feePerDaGas` and `feePerL2Gas` are fixed at `1` FPA per unit of DA gas and L2 gas consumed, respectively. diff --git a/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md b/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md index 55db5a1bba3..30a8a97d83d 100644 --- a/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md +++ b/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md @@ -78,10 +78,12 @@ These are held in the L2 blocks `Header` classDiagram class Header { +GlobalVariables globalVariables + +Fr totalFees } class GlobalVariables { +GasFees gasFees + +EthAddress coinbase } class GasFees { @@ -97,6 +99,10 @@ A transaction cannot be executed if the `maxFeesPerGas` is less than the `feePer The `feePerGas` is presently held constant at `1` for both dimensions, but may be updated in future protocol versions. +`totalFees` is the total fees collected in the block in FPA. + +`coinbase` is the L1 address that receives the fees. + ## Transaction Fee The transaction fee is calculated as: diff --git a/docs/docs/protocol-specs/rollup-circuits/base-rollup.md b/docs/docs/protocol-specs/rollup-circuits/base-rollup.md index d9a4d3d8b49..35e9688e648 100644 --- a/docs/docs/protocol-specs/rollup-circuits/base-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/base-rollup.md @@ -56,6 +56,7 @@ class Header { content_commitment: ContentCommitment state: StateReference global_variables: GlobalVariables + total_fees: Fr } Header *.. Body : txs_hash Header *-- ContentCommitment: content_commitment diff --git a/docs/docs/protocol-specs/rollup-circuits/index.md b/docs/docs/protocol-specs/rollup-circuits/index.md index 85445b1864d..db2f62e3d46 100644 --- a/docs/docs/protocol-specs/rollup-circuits/index.md +++ b/docs/docs/protocol-specs/rollup-circuits/index.md @@ -188,6 +188,7 @@ class Header { content_commitment: ContentCommitment state: StateReference global_variables: GlobalVariables + total_fees: Fr } Header *.. Body : txs_hash Header *-- ContentCommitment: content_commitment diff --git a/docs/docs/protocol-specs/rollup-circuits/root-rollup.md b/docs/docs/protocol-specs/rollup-circuits/root-rollup.md index a9abf3d1e48..2c6c9cce732 100644 --- a/docs/docs/protocol-specs/rollup-circuits/root-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/root-rollup.md @@ -56,6 +56,7 @@ class Header { content_commitment: ContentCommitment state: StateReference global_variables: GlobalVariables + total_fees: Fr } Header *.. Body : txs_hash Header *-- ContentCommitment: content_commitment diff --git a/docs/docs/protocol-specs/state/archive.md b/docs/docs/protocol-specs/state/archive.md index 6a7bd5c816d..459cea3b924 100644 --- a/docs/docs/protocol-specs/state/archive.md +++ b/docs/docs/protocol-specs/state/archive.md @@ -77,6 +77,7 @@ class Header { body_hash: Fr[2] state: StateReference global_variables: GlobalVariables + total_fees: Fr } Header *.. Body : body_hash Header *-- StateReference : state diff --git a/docs/docs/protocol-specs/state/index.md b/docs/docs/protocol-specs/state/index.md index 928b7b664d0..ed7b34837c8 100644 --- a/docs/docs/protocol-specs/state/index.md +++ b/docs/docs/protocol-specs/state/index.md @@ -122,6 +122,7 @@ class Header { content_commitment: ContentCommitment state: StateReference global_variables: GlobalVariables + total_fees: Fr } Header *.. Body : txs_hash Header *-- ContentCommitment: content_commitment diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 5c23833bb40..3547145d491 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -95,9 +95,9 @@ contract Rollup is IRollup { header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeHeight ); - // pay the coinbase 1 gas token if it is not empty - if (header.globalVariables.coinbase != address(0)) { - GAS_TOKEN.transfer(address(header.globalVariables.coinbase), 1); + // pay the coinbase 1 gas token if it is not empty and header.totalFees is not zero + if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) { + GAS_TOKEN.transfer(address(header.globalVariables.coinbase), header.totalFees); } emit L2BlockProcessed(header.globalVariables.blockNumber); diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index c91cdc95813..cd657af88c3 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -140,8 +140,9 @@ library Constants { APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; uint256 internal constant TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; uint256 internal constant TX_REQUEST_LENGTH = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; + uint256 internal constant TOTAL_FEES_LENGTH = 1; uint256 internal constant HEADER_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH - + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH; + + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) @@ -211,7 +212,7 @@ library Constants { uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 4 + GLOBAL_VARIABLES_LENGTH; uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = CONSTANT_ROLLUP_DATA_LENGTH - + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 4; + + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; uint256 internal constant ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; diff --git a/l1-contracts/src/core/libraries/HeaderLib.sol b/l1-contracts/src/core/libraries/HeaderLib.sol index 5ba700dab20..98c8f86f9db 100644 --- a/l1-contracts/src/core/libraries/HeaderLib.sol +++ b/l1-contracts/src/core/libraries/HeaderLib.sol @@ -52,6 +52,7 @@ import {Hash} from "./Hash.sol"; * | 0x0208 | 0x20 | gasFees.feePerL2Gas * | | | } * | | | } + * | 0x0228 | 0x20 | total_fees * | --- | --- | --- */ library HeaderLib { @@ -100,9 +101,10 @@ library HeaderLib { ContentCommitment contentCommitment; StateReference stateReference; GlobalVariables globalVariables; + uint256 totalFees; } - uint256 private constant HEADER_LENGTH = 0x228; // Header byte length + uint256 private constant HEADER_LENGTH = 0x248; // Header byte length /** * @notice Validates the header @@ -190,6 +192,9 @@ library HeaderLib { header.globalVariables.gasFees.feePerDaGas = uint256(bytes32(_header[0x01e8:0x0208])); header.globalVariables.gasFees.feePerL2Gas = uint256(bytes32(_header[0x0208:0x0228])); + // Reading totalFees + header.totalFees = uint256(bytes32(_header[0x0228:0x0248])); + return header; } } diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 91216c12952..7f48b82ca22 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3", + "archive": "0x1457164d01299b0097706a5b0e8735720280e2937d369b2bee07ba987fd6846e", "body": "0x00000000", "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { @@ -23,8 +23,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xbe70f89d75a00bd140342ebc63beb517cf9735bc", - "feeRecipient": "0x08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b172", + "coinbase": "0x13def1c0178621c029040272730bb660031f3d51", + "feeRecipient": "0x2193c536a292e81634f7f77e7c9f3fdc7a197d396bfda81fdc0112e0b2bc9bb6", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -32,7 +32,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 1, - "root": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf" + "root": "0x05b0b6df52f1d47d0406318558052c89a174fbc9d615def82b3cc9ccc1937db8" }, "stateReference": { "l1ToL2MessageTree": { @@ -55,8 +55,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000be70f89d75a00bd140342ebc63beb517cf9735bc08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b17200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00e9c95b88dbc49351e6a0a9b660918147d3c69410df4fba105c047a4f253a47", + "header": "0x05b0b6df52f1d47d0406318558052c89a174fbc9d615def82b3cc9ccc1937db8000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000013def1c0178621c029040272730bb660031f3d512193c536a292e81634f7f77e7c9f3fdc7a197d396bfda81fdc0112e0b2bc9bb6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x004fa9f8a995305c2569a378b91e45d14f9a6b7d9ba0ca19e0ac0e4ea79123fb", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index 0596ade5a0a..abb28e4f88c 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x18c171439670152671eb523cdf11eb61a45c27b7685ad86a7229fbe635e9ea18", + "archive": "0x13dbf07432d89b646aa5d30d729f8c5c6db55c5e2227607b1a590f03274017f8", "body": "0x00000000", "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { @@ -21,10 +21,10 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1716042415, + "timestamp": 1716117514, "version": 1, - "coinbase": "0xbe70f89d75a00bd140342ebc63beb517cf9735bc", - "feeRecipient": "0x08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b172", + "coinbase": "0x13def1c0178621c029040272730bb660031f3d51", + "feeRecipient": "0x2193c536a292e81634f7f77e7c9f3fdc7a197d396bfda81fdc0112e0b2bc9bb6", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -32,7 +32,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3" + "root": "0x1457164d01299b0097706a5b0e8735720280e2937d369b2bee07ba987fd6846e" }, "stateReference": { "l1ToL2MessageTree": { @@ -55,8 +55,8 @@ } } }, - "header": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006648baafbe70f89d75a00bd140342ebc63beb517cf9735bc08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b17200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x0033d4785f37dafeeb7e50eeef42002f0af7d1d62913119754b81cfe7ebc5217", + "header": "0x1457164d01299b0097706a5b0e8735720280e2937d369b2bee07ba987fd6846e000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006649e00a13def1c0178621c029040272730bb660031f3d512193c536a292e81634f7f77e7c9f3fdc7a197d396bfda81fdc0112e0b2bc9bb6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00ee8816b0f0a192b5c65e2c700c540cda3d2f15fbdae9fca27fad25803246e1", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index 48f9c97bf8f..8debde3bcda 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,7 +34,7 @@ ] }, "block": { - "archive": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e", + "archive": "0x2bd2a10421e106d5085b29f6f8f171e6e530d1dbdb3c6c60077a9ebb5dea018e", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e0200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341200000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f000000000000000000000000000000000000000000000000000000000000056900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be0200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c12000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f000000000000000000000000000000000000000000000000000000000000062900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x0048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab", "decodedHeader": { @@ -49,8 +49,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xe19d288dac593449f143689ea3563e9d960e0ae6", - "feeRecipient": "0x20f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a", + "coinbase": "0x875190e01385d780fbd026d02d217d0f5a4de1d1", + "feeRecipient": "0x202bf1f10d1ffc84364a6b81e74c88521c5c05c38cce24e92f165b40114e8072", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -58,7 +58,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 1, - "root": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf" + "root": "0x05b0b6df52f1d47d0406318558052c89a174fbc9d615def82b3cc9ccc1937db8" }, "stateReference": { "l1ToL2MessageTree": { @@ -81,8 +81,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf0000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000e19d288dac593449f143689ea3563e9d960e0ae620f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x004af29de40359d7c79637dce0ef57c561cb5ff283602607c6f644cb019fa526", + "header": "0x05b0b6df52f1d47d0406318558052c89a174fbc9d615def82b3cc9ccc1937db80000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000875190e01385d780fbd026d02d217d0f5a4de1d1202bf1f10d1ffc84364a6b81e74c88521c5c05c38cce24e92f165b40114e8072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00db7c55237b3744896e798313ce7eff51dec6c0a19aece3d4e1ebbe7c1687ce", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 2fe88df3c70..8686757eb17 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,7 +34,7 @@ ] }, "block": { - "archive": "0x1d882133187105c8d7ed6177b59d8c5462ce1a562537ccec510d9879caf10c7c", + "archive": "0x25c90a9ef8a62e81e0783ab943849a1b09a3b3f3b44188fdc0fdf77505b2d84b", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e0200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f000000000000000000000000000000000000000000000000000000000000066900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be0200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481200000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c12000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501200000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f000000000000000000000000000000000000000000000000000000000000072900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x00f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b1", "decodedHeader": { @@ -47,10 +47,10 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1716042373, + "timestamp": 1716117478, "version": 1, - "coinbase": "0xe19d288dac593449f143689ea3563e9d960e0ae6", - "feeRecipient": "0x20f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a", + "coinbase": "0x875190e01385d780fbd026d02d217d0f5a4de1d1", + "feeRecipient": "0x202bf1f10d1ffc84364a6b81e74c88521c5c05c38cce24e92f165b40114e8072", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -58,7 +58,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e" + "root": "0x2bd2a10421e106d5085b29f6f8f171e6e530d1dbdb3c6c60077a9ebb5dea018e" }, "stateReference": { "l1ToL2MessageTree": { @@ -81,8 +81,8 @@ } } }, - "header": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e00000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006648ba85e19d288dac593449f143689ea3563e9d960e0ae620f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x007402eac386598833154a72f24a89eb5152eec68dfd43c12dd847da5a99289b", + "header": "0x2bd2a10421e106d5085b29f6f8f171e6e530d1dbdb3c6c60077a9ebb5dea018e00000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006649dfe6875190e01385d780fbd026d02d217d0f5a4de1d1202bf1f10d1ffc84364a6b81e74c88521c5c05c38cce24e92f165b40114e8072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x009aa987ea9196196678d17add8eb6d439406d60201b2f52a38d74528d0f3313", "numTxs": 4 } } \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index 33f6ac78e45..53e36d0e6de 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -28,6 +28,8 @@ struct BaseOrMergeRollupPublicInputs { // We hash public inputs to make them constant-sized (to then be unpacked on-chain) txs_effects_hash : Field, out_hash : Field, + + accumulated_fees: Field } impl Empty for BaseOrMergeRollupPublicInputs { @@ -41,6 +43,7 @@ impl Empty for BaseOrMergeRollupPublicInputs { end: PartialStateReference::empty(), txs_effects_hash : 0, out_hash : 0, + accumulated_fees: 0 } } } @@ -53,7 +56,8 @@ impl Eq for BaseOrMergeRollupPublicInputs { (self.start.eq(other.start)) & (self.end.eq(other.end)) & (self.txs_effects_hash == other.txs_effects_hash) & - (self.out_hash == other.out_hash) + (self.out_hash == other.out_hash) & + (self.accumulated_fees == other.accumulated_fees) } } @@ -68,6 +72,7 @@ impl Serialize for BaseOrMergeRollupPublicIn fields.extend_from_array(self.end.serialize()); fields.push(self.txs_effects_hash as Field); fields.push(self.out_hash as Field); + fields.push(self.accumulated_fees as Field); assert_eq(fields.len(), BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH); @@ -87,6 +92,7 @@ impl Deserialize for BaseOrMergeRollupPublic end: reader.read_struct(PartialStateReference::deserialize), txs_effects_hash: reader.read(), out_hash: reader.read(), + accumulated_fees: reader.read() }; reader.finish(); diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index c4d9c5ad826..451b9e07d6a 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -103,11 +103,13 @@ impl BaseRollupInputs { // Validate public public data reads and public data update requests, and update public data tree let end_public_data_tree_snapshot = self.validate_and_process_public_state(); + let transaction_fee = self.kernel_data.public_inputs.compute_transaction_fee(); + // Calculate the tx effects hash of the transaction let tx_effects_hash = compute_tx_effects_hash( self.kernel_data.public_inputs.end, self.kernel_data.public_inputs.revert_code, - self.kernel_data.public_inputs.compute_transaction_fee() + transaction_fee ); let out_hash = compute_kernel_out_hash(self.kernel_data.public_inputs.end); @@ -128,7 +130,8 @@ impl BaseRollupInputs { public_data_tree: end_public_data_tree_snapshot }, txs_effects_hash: tx_effects_hash, - out_hash + out_hash, + accumulated_fees: transaction_fee } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 9a4e8b9715f..8d1dc584a1e 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -79,6 +79,13 @@ pub fn assert_prev_rollups_follow_on_from_each_other( ); } +pub fn accumulate_fees( + left: BaseOrMergeRollupPublicInputs, + right: BaseOrMergeRollupPublicInputs +) -> Field { + left.accumulated_fees + right.accumulated_fees +} + /** * @brief From two previous rollup data, compute a single out hash * diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr index ed8f852cdd8..be09b46068d 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr @@ -37,6 +37,8 @@ impl MergeRollupInputs { let txs_effects_hash = components::compute_txs_effects_hash(self.previous_rollup_data); let out_hash = components::compute_out_hash(self.previous_rollup_data); + let accumulated_fees = components::accumulate_fees(left, right); + let public_inputs = BaseOrMergeRollupPublicInputs { rollup_type: MERGE_ROLLUP_TYPE, height_in_block_tree: current_height + 1, @@ -45,7 +47,8 @@ impl MergeRollupInputs { start: left.start, end: right.end, txs_effects_hash, - out_hash + out_hash, + accumulated_fees }; public_inputs diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr index 795e9507008..27febbe40b9 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr @@ -65,11 +65,14 @@ impl RootRollupInputs { out_hash: components::compute_out_hash(self.previous_rollup_data) }; + let total_fees = components::accumulate_fees(left, right); + let header = Header { last_archive: left.constants.last_archive, content_commitment, state, - global_variables: left.constants.global_variables + global_variables: left.constants.global_variables, + total_fees }; // Build the block hash for this by hashing the header and then insert the new leaf to archive tree. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 4dd411afa74..ae8f9ac9cbd 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -85,6 +85,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x10d9feff1d02db424becc3399f496be13d0586ea5a62c85de302ea88a1f345c5; + let test_data_empty_hash = 0x000a14ed4120f2ca2accd5c2df2725a5df0f0b47284b4637ce1ab130993b4275; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 4cced8097ea..4f26052d44a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -250,6 +250,6 @@ fn empty_hash() { let inputs = PrivateCircuitPublicInputs::empty(); let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x24ea8c67b7902c1bdc827592303786ea3df7ada25a95e8682ed26b9b36fe2f9e; + let test_data_empty_hash = 0x2ce8fd4d6f4f4edbe281f96b095b60f8516980e8582f0393151baab50f413307; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr index f8aefb791ed..4b63fa7b82f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr @@ -69,7 +69,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test - let test_data_call_stack_item_request_hash = 0x0230a99218df238d4a28664ee700e10a4fdfe98e4a2f5c678bce8c95d5fa04b1; + let test_data_call_stack_item_request_hash = 0x22f08643eefc9bf59f16b025bb942a8635d2d7df183514bd2fd12dc79745beb5; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } @@ -87,7 +87,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test - let test_data_call_stack_item_hash = 0x1bda75e8d4cf46fd126d14d6e28d1dc8ff3860b49ff59edd7da8bfeee909aef3; + let test_data_call_stack_item_hash = 0x2dcb7f5edd8b3268a64870512e0df631ddbd7cfcf1f836d46c3d1694220f5a42; assert_eq(call_stack_item.hash(), test_data_call_stack_item_hash); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr index 62c49177b17..157171f2648 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr @@ -188,6 +188,6 @@ fn empty_hash() { let hash = inputs.hash(); // Value from public_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x153e47f63e4ae88293bad9aed2802315e4bb3bd2a57f108a27e78e4887490291; + let test_data_empty_hash = 0x1e4351db0c9aa20836e7009bc3e6a4555c92622c5e9cb3b49e2ec0fbbf59d0bd; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 97d586ba020..2c2703974af 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -176,7 +176,8 @@ global ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; global STATE_REFERENCE_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u64 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; -global HEADER_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH; +global TOTAL_FEES_LENGTH = 1; +global HEADER_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; @@ -200,7 +201,9 @@ global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = VALIDATION_REQUESTS_LENGTH + global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; global CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 4 + GLOBAL_VARIABLES_LENGTH; -global BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 4; + +// + 5 for rollup_type, height_in_block_tree, txs_effects_hash, out_hash, accumulated_fees +global BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; global ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH: u64 = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; global GET_NOTES_ORACLE_RETURN_LENGTH: u64 = 674; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/header.nr b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr index bb962762f3e..ed8010e006c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/header.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr @@ -14,6 +14,7 @@ struct Header { content_commitment: ContentCommitment, state: StateReference, global_variables: GlobalVariables, + total_fees: Field } // docs:end:header @@ -22,7 +23,8 @@ impl Eq for Header { self.last_archive.eq(other.last_archive) & self.content_commitment.eq(other.content_commitment) & self.state.eq(other.state) & - self.global_variables.eq(other.global_variables) + self.global_variables.eq(other.global_variables) & + self.total_fees.eq(other.total_fees) } } @@ -34,6 +36,7 @@ impl Serialize for Header { fields.extend_from_array(self.content_commitment.serialize()); fields.extend_from_array(self.state.serialize()); fields.extend_from_array(self.global_variables.serialize()); + fields.push(self.total_fees); fields.storage } @@ -53,12 +56,16 @@ impl Deserialize for Header { offset = offset + STATE_REFERENCE_LENGTH; let global_variables_fields = arr_copy_slice(serialized, [0; GLOBAL_VARIABLES_LENGTH], offset); + offset = offset + GLOBAL_VARIABLES_LENGTH; + + let total_fees = serialized[offset]; Header { last_archive: AppendOnlyTreeSnapshot::deserialize(last_archive_fields), content_commitment: ContentCommitment::deserialize(content_commitment_fields), state: StateReference::deserialize(state_fields), global_variables: GlobalVariables::deserialize(global_variables_fields), + total_fees } } } @@ -70,6 +77,7 @@ impl Empty for Header { content_commitment: ContentCommitment::empty(), state: StateReference::empty(), global_variables: GlobalVariables::empty(), + total_fees: 0 } } } @@ -100,6 +108,6 @@ fn empty_hash_is_zero() { let hash = header.hash(); // Value from new_contract_data.test.ts "computes empty hash" test - let test_data_empty_hash = 0x2b2525fb1ae91c903827b8055b9ffaf8444ddf4c2b4dce4a79a3cba426bfbd73; + let test_data_empty_hash = 0x124e8c40a6eca2e3ad10c04050b01a3fad00df3cea47b13592c7571b6914c7a7; assert_eq(hash, test_data_empty_hash); } diff --git a/yarn-project/circuit-types/src/l2_block_code_to_purge.ts b/yarn-project/circuit-types/src/l2_block_code_to_purge.ts index 20fdece0cf4..7b83a34c253 100644 --- a/yarn-project/circuit-types/src/l2_block_code_to_purge.ts +++ b/yarn-project/circuit-types/src/l2_block_code_to_purge.ts @@ -11,6 +11,7 @@ import { PartialStateReference, StateReference, } from '@aztec/circuits.js'; +import { fr } from '@aztec/circuits.js/testing'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; /** @@ -27,6 +28,7 @@ export function makeHeader( makeContentCommitment(seed + 0x200, txsEffectsHash, inHash), makeStateReference(seed + 0x600), makeGlobalVariables((seed += 0x700), blockNumber), + fr(seed + 0x800), ); } diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index c1306b20c4a..ca2a8f9deb5 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -120,8 +120,13 @@ export const ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; export const STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; export const TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; export const TX_REQUEST_LENGTH = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; +export const TOTAL_FEES_LENGTH = 1; export const HEADER_LENGTH = - APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH; + APPEND_ONLY_TREE_SNAPSHOT_LENGTH + + CONTENT_COMMITMENT_LENGTH + + STATE_REFERENCE_LENGTH + + GLOBAL_VARIABLES_LENGTH + + TOTAL_FEES_LENGTH; export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 4 + @@ -226,7 +231,7 @@ export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = AZTEC_ADDRESS_LENGTH; export const CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 4 + GLOBAL_VARIABLES_LENGTH; export const BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = - CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 4; + CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; export const ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; export const NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap index 5c166a45c4d..c0fa762d9d1 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Header computes empty hash 1`] = `Fr<0x2b2525fb1ae91c903827b8055b9ffaf8444ddf4c2b4dce4a79a3cba426bfbd73>`; +exports[`Header computes empty hash 1`] = `Fr<0x124e8c40a6eca2e3ad10c04050b01a3fad00df3cea47b13592c7571b6914c7a7>`; -exports[`Header computes hash 1`] = `Fr<0x256e19fe5b99a73cce35b5ab67652155919c75aea90b39c2c5b612a8a59cdf15>`; +exports[`Header computes hash 1`] = `Fr<0x0f5e5544c7316a87ca170004ece6dbb81d44908c1602d5aa0355da9acc5a860a>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap index 368859ee031..03795b9b849 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x10d9feff1d02db424becc3399f496be13d0586ea5a62c85de302ea88a1f345c5>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x000a14ed4120f2ca2accd5c2df2725a5df0f0b47284b4637ce1ab130993b4275>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x1426b15f965c906a750c82da93ebc07dc4401670539baf658adaaf3177f6d260>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x068d19438d3d8c62c31d9a2698171613193b61111cc572c812c312a2d2e93cea>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index 1193874ffdc..1043873fce9 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x24ea8c67b7902c1bdc827592303786ea3df7ada25a95e8682ed26b9b36fe2f9e>`; +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x2ce8fd4d6f4f4edbe281f96b095b60f8516980e8582f0393151baab50f413307>`; -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x0a365dc5815493927b46c010f3388958a3a5373f6098fbaafa70aa61d6a92ca2>`; +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x0b73302ce70e48029f50873c8bee37e0914eef716a7c153cc438fef5cb25e64a>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index 5cf1ed0ff49..a8793d9c82e 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x1bda75e8d4cf46fd126d14d6e28d1dc8ff3860b49ff59edd7da8bfeee909aef3"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x2dcb7f5edd8b3268a64870512e0df631ddbd7cfcf1f836d46c3d1694220f5a42"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x0230a99218df238d4a28664ee700e10a4fdfe98e4a2f5c678bce8c95d5fa04b1"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x22f08643eefc9bf59f16b025bb942a8635d2d7df183514bd2fd12dc79745beb5"`; -exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x2328377f64bffa61d6a773e688b4b217b1dca488b8f905d94effe3fbc968111c>`; +exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x143088c82c9c2ee67c8a608a3692c6aa65f3825db9305e7af13277ddcb78ee41>`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x20506d5ffb519b1e5763fdfe3c3f84cd6292585bacd024eccca04e31b17b4cfc>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x035771f894adb10988cd2ee8754f7d06825b530e488fc4354420c9c6ea5cba77>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap index 49eff22d05d..e666e2b7cbf 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x153e47f63e4ae88293bad9aed2802315e4bb3bd2a57f108a27e78e4887490291>`; +exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x1e4351db0c9aa20836e7009bc3e6a4555c92622c5e9cb3b49e2ec0fbbf59d0bd>`; -exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x10283cd87782fa6cc9f63e2766b6d5aed3350edf1e082a98ad7dd83b0cd171f0>`; +exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x099d3f1f21b3405cf1dffefd8dd045f4a628ecdd2a717ac7a41e4cc3d41ff79b>`; diff --git a/yarn-project/circuits.js/src/structs/header.ts b/yarn-project/circuits.js/src/structs/header.ts index a6639e0f529..e642d97b105 100644 --- a/yarn-project/circuits.js/src/structs/header.ts +++ b/yarn-project/circuits.js/src/structs/header.ts @@ -1,6 +1,7 @@ import { pedersenHash } from '@aztec/foundation/crypto'; -import { type Fr } from '@aztec/foundation/fields'; -import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { type FieldsOf } from '@aztec/foundation/types'; import { GeneratorIndex, HEADER_LENGTH } from '../constants.gen.js'; import { ContentCommitment } from './content_commitment.js'; @@ -19,21 +20,27 @@ export class Header { public state: StateReference, /** Global variables of an L2 block. */ public globalVariables: GlobalVariables, + /** Total fees in the block, computed by the root rollup circuit */ + public totalFees: Fr, ) {} - toBuffer() { + static getFields(fields: FieldsOf
) { // Note: The order here must match the order in the HeaderLib solidity library. - return serializeToBuffer(this.lastArchive, this.contentCommitment, this.state, this.globalVariables); + return [ + fields.lastArchive, + fields.contentCommitment, + fields.state, + fields.globalVariables, + fields.totalFees, + ] as const; + } + + toBuffer() { + return serializeToBuffer(...Header.getFields(this)); } toFields(): Fr[] { - // Note: The order here must match the order in header.nr - const fields = [ - ...this.lastArchive.toFields(), - ...this.contentCommitment.toFields(), - ...this.state.toFields(), - ...this.globalVariables.toFields(), - ]; + const fields = serializeToFields(...Header.getFields(this)); if (fields.length !== HEADER_LENGTH) { throw new Error(`Invalid number of fields for Header. Expected ${HEADER_LENGTH}, got ${fields.length}`); } @@ -52,18 +59,20 @@ export class Header { reader.readObject(ContentCommitment), reader.readObject(StateReference), reader.readObject(GlobalVariables), + reader.readObject(Fr), ); } static fromFields(fields: Fr[] | FieldReader): Header { const reader = FieldReader.asReader(fields); - const lastArchive = new AppendOnlyTreeSnapshot(reader.readField(), Number(reader.readField().toBigInt())); - const contentCommitment = ContentCommitment.fromFields(reader); - const state = StateReference.fromFields(reader); - const globalVariables = GlobalVariables.fromFields(reader); - - return new Header(lastArchive, contentCommitment, state, globalVariables); + return new Header( + AppendOnlyTreeSnapshot.fromFields(reader), + ContentCommitment.fromFields(reader), + StateReference.fromFields(reader), + GlobalVariables.fromFields(reader), + reader.readField(), + ); } static empty(): Header { @@ -72,6 +81,7 @@ export class Header { ContentCommitment.empty(), StateReference.empty(), GlobalVariables.empty(), + Fr.ZERO, ); } diff --git a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts index 7fbb6e2f833..b4835919053 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts @@ -47,6 +47,11 @@ export class BaseOrMergeRollupPublicInputs { * Note: Truncated to 31 bytes to fit in Fr. */ public outHash: Fr, + + /** + * The summed `transaction_fee` of the constituent transactions. + */ + public accumulatedFees: Fr, ) {} /** @@ -67,6 +72,7 @@ export class BaseOrMergeRollupPublicInputs { //TODO check Fr.fromBuffer(reader), Fr.fromBuffer(reader), + Fr.fromBuffer(reader), ); } @@ -86,6 +92,8 @@ export class BaseOrMergeRollupPublicInputs { this.txsEffectsHash, this.outHash, + + this.accumulatedFees, ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 47664f24fd3..e5c0bf8f8da 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -900,6 +900,7 @@ export function makeBaseOrMergeRollupPublicInputs( makePartialStateReference(seed + 0x400), fr(seed + 0x901), fr(seed + 0x902), + fr(seed + 0x903), ); } @@ -1011,6 +1012,7 @@ export function makeHeader( makeContentCommitment(seed + 0x200, txsEffectsHash), makeStateReference(seed + 0x600), makeGlobalVariables((seed += 0x700), blockNumber), + fr(seed + 0x800), ); } diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index 571ad75dc41..f3e80c9d51e 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -127,6 +127,9 @@ e2e-pending-note-hashes-contract: e2e-private-voting-contract: DO +E2E_TEST --test=./src/e2e_private_voting_contract.test.ts +e2e-private-payments: + DO +E2E_TEST --test=./src/e2e_fees/private_payments.test.ts + e2e-public-cross-chain-messaging: DO +E2E_TEST --test=./src/e2e_public_cross_chain_messaging diff --git a/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts index ebca3276713..c470e16e4e7 100644 --- a/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts @@ -118,27 +118,27 @@ describe('e2e_fees private_payment', () => { const tx = await interaction.send().wait(); - await expect(t.getCoinbaseBalance()).resolves.toEqual(InitialSequencerL1Gas + 1n); - /** * at present the user is paying DA gas for: * 3 nullifiers = 3 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE = 3 * 32 * 16 = 1536 DA gas * 2 note hashes = 2 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE = 2 * 32 * 16 = 1024 DA gas - * 964 bytes of logs = 964 * DA_GAS_PER_BYTE = 964 * 16 = 15424 DA gas + * 1160 bytes of logs = 1160 * DA_GAS_PER_BYTE = 1160 * 16 = 5568 DA gas * tx overhead of 512 DA gas - * for a total of 18496 DA gas. + * for a total of 21632 DA gas. * * The default teardown gas allocation at present is * 100_000_000 for both DA and L2 gas. * - * That produces a grand total of 200018496n. + * That produces a grand total of 200021632n. * * This will change because: * 1. Gas use during public execution is not currently incorporated - * 2. We are presently squashing notes/nullifiers across non/revertible during private exeuction, + * 2. We are presently squashing notes/nullifiers across non/revertible during private execution, * but we shouldn't. */ - expect(tx.transactionFee).toEqual(200018496n); + + expect(tx.transactionFee).toEqual(200021632n); + await expect(t.getCoinbaseBalance()).resolves.toEqual(InitialSequencerL1Gas + tx.transactionFee!); const [feeAmount, refundAmount] = getFeeAndRefund(tx); await expectMapping( diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index a79a001ad8e..9944b69adfb 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -230,7 +230,8 @@ export const deployL1Contracts = async ( abi: contractsToDeploy.gasToken.contractAbi, client: walletClient, }); - await gasToken.write.mint([rollupAddress.toString(), 100000000000000000000n], {} as any); + const receipt = await gasToken.write.mint([rollupAddress.toString(), 100000000000000000000n], {} as any); + await publicClient.waitForTransactionReceipt({ hash: receipt }); logger.info(`Funded rollup contract with gas tokens`); const l1Contracts: L1ContractAddresses = { diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 2f6ef2aa908..2ea5a3eb06c 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1754,6 +1754,7 @@ export function mapBaseOrMergeRollupPublicInputsToNoir( end: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.end), txs_effects_hash: mapFieldToNoir(baseOrMergeRollupPublicInputs.txsEffectsHash), out_hash: mapFieldToNoir(baseOrMergeRollupPublicInputs.outHash), + accumulated_fees: mapFieldToNoir(baseOrMergeRollupPublicInputs.accumulatedFees), }; } @@ -1801,6 +1802,7 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), mapFieldFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash), mapFieldFromNoir(baseOrMergeRollupPublicInputs.out_hash), + mapFieldFromNoir(baseOrMergeRollupPublicInputs.accumulated_fees), ); } @@ -1941,6 +1943,7 @@ export function mapHeaderToNoir(header: Header): HeaderNoir { content_commitment: mapContentCommitmentToNoir(header.contentCommitment), state: mapStateReferenceToNoir(header.state), global_variables: mapGlobalVariablesToNoir(header.globalVariables), + total_fees: mapFieldToNoir(header.totalFees), }; } @@ -1955,6 +1958,7 @@ export function mapHeaderFromNoir(header: HeaderNoir): Header { mapContentCommitmentFromNoir(header.content_commitment), mapStateReferenceFromNoir(header.state), mapGlobalVariablesFromNoir(header.global_variables), + mapFieldFromNoir(header.total_fees), ); } diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index cf817342fc4..a3136d2530f 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -154,6 +154,7 @@ describe('Private Execution test suite', () => { ), ), header.globalVariables, + header.totalFees, ); } else { header = new Header( @@ -161,6 +162,7 @@ describe('Private Execution test suite', () => { header.contentCommitment, new StateReference(newSnap, header.state.partial), header.globalVariables, + header.totalFees, ); } diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index b74b887094a..8b28dfa859c 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -180,7 +180,13 @@ export class MerkleTrees implements MerkleTreeDb { public async buildInitialHeader(includeUncommitted: boolean): Promise
{ const state = await this.getStateReference(includeUncommitted); - return new Header(AppendOnlyTreeSnapshot.zero(), ContentCommitment.empty(), state, GlobalVariables.empty()); + return new Header( + AppendOnlyTreeSnapshot.zero(), + ContentCommitment.empty(), + state, + GlobalVariables.empty(), + Fr.ZERO, + ); } /** From 2a5d975a09dcdd5adfcb8fc14af711ad3c40c022 Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Mon, 20 May 2024 12:25:32 -0400 Subject: [PATCH 23/37] chore: anvil kill wrapper now supports mac (#6520) Also remove errant workspace settings. Should we remove it from source control? --- .vscode/settings.json | 2 +- .../end-to-end/scripts/anvil_kill_wrapper.sh | 42 ++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ebb2f31ee3a..9e68654eef9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -166,5 +166,5 @@ "**/l1-contracts/lib/**": true, "**/barretenberg/cpp/build*/**": true }, - "cmake.sourceDirectory": "/mnt/user-data/adam/aztec-packages/barretenberg/acir_tests/headless-test/node_modules/bare-fs" + "cmake.sourceDirectory": "${workspaceFolder}/barretenberg/cpp" } diff --git a/yarn-project/end-to-end/scripts/anvil_kill_wrapper.sh b/yarn-project/end-to-end/scripts/anvil_kill_wrapper.sh index 8eec17e179f..f03ae0e1abb 100755 --- a/yarn-project/end-to-end/scripts/anvil_kill_wrapper.sh +++ b/yarn-project/end-to-end/scripts/anvil_kill_wrapper.sh @@ -1,7 +1,39 @@ #!/bin/bash -# Find the parent of this script. -PARENT_PID=$(awk '{print $4}' /proc/$$/stat) +# Function to get the PPID in macOS +get_ppid_macos() { + ps -j $$ | awk 'NR==2 {print $3}' +} + +# Function to get the PPID in Linux +get_ppid_linux() { + awk '{print $4}' /proc/$$/stat +} + +# Function to check if a process is alive in macOS +is_process_alive_macos() { + ps -p $1 > /dev/null 2>&1 +} + +# Function to check if a process is alive in Linux +is_process_alive_linux() { + [ -d /proc/$1 ] +} + + +# Determine the operating system and call the appropriate function +if [[ "$OSTYPE" == "darwin"* ]]; then + PARENT_PID=$(get_ppid_macos) + check_process_alive() { is_process_alive_macos $1; } +elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + PARENT_PID=$(get_ppid_linux) + check_process_alive() { is_process_alive_linux $1; } +else + echo "Unsupported OS" + exit 1 +fi + +# echo "Parent PID: $PARENT_PID" # Start anvil in the background. anvil $@ & @@ -14,6 +46,6 @@ cleanup() { trap cleanup EXIT # Continuously check if the parent process is still alive. -while [ -d /proc/$PARENT_PID ]; do - sleep 1 -done \ No newline at end of file +while check_process_alive $PARENT_PID; do + sleep 1 +done From c3b573e82e3fdc1feca6ce861951d2dd93e4f9b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Mon, 20 May 2024 18:17:10 +0100 Subject: [PATCH 24/37] chore(docs): restructure improvs (#6502) In line with the latest restructure, here are some QoL things we pointed out to be iterated: - [x] Added back api docs to their rightful place - [x] Removed nested structure to make links smaller - [x] Refactored all the links to reflect the above ## To do in a later PR: - [ ] Rewrite URLs to be relative --- docs/.gitignore | 5 +- docs/docs/.gitignore | 1 - docs/docs/{aztec/aztec/index.md => aztec.md} | 4 +- docs/docs/aztec/_category_.json | 4 +- docs/docs/aztec/aztec/_category_.json | 6 -- .../{aztec => }/concepts/_category_.json | 0 .../{aztec => }/concepts/accounts/authwit.md | 8 +- .../{aztec => }/concepts/accounts/index.md | 4 +- .../{aztec => }/concepts/accounts/keys.md | 8 +- .../{aztec => }/concepts/circuits/index.md | 8 +- .../circuits/kernels/private_kernel.md | 4 +- .../circuits/kernels/public_kernel.md | 2 +- .../circuits/rollup_circuits/index.md | 2 +- docs/docs/aztec/{aztec => }/concepts/index.md | 19 +++-- .../concepts/nodes_clients/_category_.json | 0 .../concepts/nodes_clients/sequencer/index.md | 2 +- .../sequencer/sequencer_selection.md | 0 .../concepts/pxe/acir_simulator.md | 4 +- .../aztec/{aztec => }/concepts/pxe/index.md | 6 +- .../smart_contracts/communication/index.md | 2 +- .../communication/public_private_calls.md | 4 +- .../smart_contracts/contract_creation.md | 2 +- .../smart_contracts/contract_structure.md | 4 +- .../smart_contracts/functions/context.md | 4 +- .../smart_contracts/functions/index.md | 10 +-- .../functions/inner_workings.md | 16 ++-- .../functions/public_private_unconstrained.md | 0 .../smart_contracts/functions/visibility.md | 4 +- .../concepts/smart_contracts/index.md | 2 +- .../concepts/smart_contracts/oracles/index.md | 6 +- .../{aztec => }/concepts/state_model/index.md | 2 +- .../concepts/state_model/public_vm.md | 0 .../{aztec => }/concepts/storage/index.md | 8 +- .../concepts/storage/trees/index.md | 6 +- .../storage/trees/indexed_merkle_tree.mdx | 0 .../{aztec => }/concepts/transactions.md | 6 +- .../concepts/wallets/_category_.json | 0 .../concepts/wallets/architecture.md | 2 +- .../{aztec => }/concepts/wallets/index.md | 16 ++-- .../docs/aztec/{aztec => }/core_components.md | 16 ++-- .../aztec/{aztec => }/glossary/call_types.md | 2 +- docs/docs/aztec/{aztec => }/glossary/index.md | 0 .../aztec/{aztec => }/how_to_participate.md | 0 docs/docs/aztec/{aztec => }/limitations.md | 20 ++--- .../aztec/{aztec => }/roadmap/_category_.json | 0 .../roadmap/cryptography_roadmap.md | 0 .../roadmap/engineering_roadmap.md | 2 +- .../roadmap/features_initial_ldt.md | 0 docs/docs/aztec/{aztec => }/roadmap/index.md | 0 .../index.md => getting_started.md} | 6 +- docs/docs/getting_started/_category_.json | 6 -- .../aztecjs-getting-started.md | 12 +-- .../aztecnr-getting-started.md | 10 +-- .../getting_started/_category_.json | 4 - docs/docs/guides/_category_.json | 6 -- docs/docs/guides/guides/_category_.json | 6 -- .../writing_contracts/portals/index.md | 7 -- .../{guides => }/js_apps/_category_.json | 0 .../js_apps/call_view_function.md | 0 .../{guides => }/js_apps/create_account.md | 0 .../{guides => }/js_apps/deploy_contract.md | 4 +- .../{guides => }/js_apps/send_transaction.md | 0 .../{guides => }/js_apps/test_contracts.md | 16 ++-- .../{guides => }/local_env/_category_.json | 0 .../local_env/creating_schnorr_accounts.md | 6 +- .../run_more_than_one_pxe_sandbox.md | 2 +- .../local_env/versions-updating.md | 2 +- .../smart_contracts/_category_.json | 0 .../how_to_compile_contract.md | 12 +-- .../smart_contracts/how_to_deploy_contract.md | 10 +-- .../writing_contracts/_category_.json | 0 .../writing_contracts/call_functions.md | 4 +- .../common_patterns/_category_.json | 0 .../common_patterns/authwit.md | 8 +- .../common_patterns/index.md | 12 +-- .../writing_contracts/how_to_emit_event.md | 4 +- .../writing_contracts/how_to_pop_capsules.md | 0 .../writing_contracts/how_to_prove_history.md | 8 +- .../writing_contracts/index.md | 7 ++ .../writing_contracts/initializers.md | 2 +- .../writing_contracts/portals/_category_.json | 0 .../portals/communicate_with_portal.md | 6 +- .../writing_contracts/portals/index.md | 5 ++ .../writing_contracts/storage/_category_.json | 0 .../writing_contracts/storage/index.md | 4 +- .../writing_contracts/storage/notes.md | 14 ++-- .../storage/storage_slots.md | 2 +- docs/docs/index.mdx | 6 +- .../cryptography/hashing/hashing.md | 6 +- .../state/tree-implementations.md | 2 +- .../common_errors/_category_.json | 0 .../common_errors/aztecnr-errors.md | 8 +- .../common_errors/sandbox-errors.md | 14 ++-- .../reference/{reference => }/debugging.md | 0 .../{reference => }/privacy_considerations.md | 2 +- docs/docs/reference/reference/_category_.json | 6 -- .../sandbox_reference/_category_.json | 0 .../sandbox_reference/cheat_codes.md | 2 +- .../sandbox_reference/index.md | 4 +- .../sandbox_reference/sandbox-reference.md | 60 +++++++++++++- .../smart_contract_reference/_category_.json | 0 .../smart_contract_reference/dependencies.md | 4 +- .../smart_contract_reference/globals.md | 0 .../history_lib_reference.md | 2 +- .../smart_contract_reference/index.md | 0 .../portals/_category_.json | 0 .../portals/data_structures.md | 0 .../smart_contract_reference/portals/inbox.md | 0 .../portals/outbox.md | 0 .../portals/registry.md | 0 .../storage/_category_.json | 0 .../smart_contract_reference/storage/index.md | 16 ++-- .../storage/private_state.md | 14 ++-- .../storage/public_state.md | 6 +- .../storage/shared_state.md | 0 docs/docs/tutorials/_category_.json | 2 +- .../contract_tutorials/_category_.json | 0 .../advanced/_category_.json | 0 .../advanced/token_bridge/_category_.json | 0 .../token_bridge/depositing_to_aztec.md | 0 .../advanced/token_bridge/index.md | 2 +- .../advanced/token_bridge/minting_on_aztec.md | 2 +- .../advanced/token_bridge/setup.md | 2 +- .../token_bridge/typescript_glue_code.md | 0 .../token_bridge/withdrawing_to_l1.md | 4 +- .../crowdfunding_contract.md | 4 +- .../private_voting_contract.md | 16 ++-- .../contract_tutorials/token_contract.md | 14 ++-- .../simple_dapp/contract_deployment.md | 4 +- .../simple_dapp/contract_interaction.md | 6 +- .../{tutorials => }/simple_dapp/index.md | 6 +- .../simple_dapp/project_setup.md | 0 .../simple_dapp/pxe_service.md | 2 +- .../{tutorials => }/simple_dapp/testing.md | 10 +-- docs/docs/tutorials/tutorials/_category_.json | 6 -- .../write_accounts_contract.md | 12 +-- docs/docs/{aztec/index.mdx => vision.mdx} | 2 +- docs/docusaurus.config.js | 27 +++++-- docs/package.json | 7 +- docs/scripts/build.sh | 14 +++- docs/scripts/clean.sh | 5 ++ docs/scripts/move_processed.sh | 4 + docs/sidebars.js | 79 +++++-------------- .../Disclaimers/_wip_disclaimer.mdx | 2 +- .../preprocess/generate_aztecnr_reference.js | 25 +----- 145 files changed, 396 insertions(+), 419 deletions(-) delete mode 100644 docs/docs/.gitignore rename docs/docs/{aztec/aztec/index.md => aztec.md} (94%) delete mode 100644 docs/docs/aztec/aztec/_category_.json rename docs/docs/aztec/{aztec => }/concepts/_category_.json (100%) rename docs/docs/aztec/{aztec => }/concepts/accounts/authwit.md (94%) rename docs/docs/aztec/{aztec => }/concepts/accounts/index.md (98%) rename docs/docs/aztec/{aztec => }/concepts/accounts/keys.md (94%) rename docs/docs/aztec/{aztec => }/concepts/circuits/index.md (92%) rename docs/docs/aztec/{aztec => }/concepts/circuits/kernels/private_kernel.md (92%) rename docs/docs/aztec/{aztec => }/concepts/circuits/kernels/public_kernel.md (80%) rename docs/docs/aztec/{aztec => }/concepts/circuits/rollup_circuits/index.md (95%) rename docs/docs/aztec/{aztec => }/concepts/index.md (59%) rename docs/docs/aztec/{aztec => }/concepts/nodes_clients/_category_.json (100%) rename docs/docs/aztec/{aztec => }/concepts/nodes_clients/sequencer/index.md (97%) rename docs/docs/aztec/{aztec => }/concepts/nodes_clients/sequencer/sequencer_selection.md (100%) rename docs/docs/aztec/{aztec => }/concepts/pxe/acir_simulator.md (88%) rename docs/docs/aztec/{aztec => }/concepts/pxe/index.md (93%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/communication/index.md (78%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/communication/public_private_calls.md (93%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/contract_creation.md (82%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/contract_structure.md (65%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/functions/context.md (94%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/functions/index.md (72%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/functions/inner_workings.md (74%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/functions/public_private_unconstrained.md (100%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/functions/visibility.md (91%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/index.md (94%) rename docs/docs/aztec/{aztec => }/concepts/smart_contracts/oracles/index.md (94%) rename docs/docs/aztec/{aztec => }/concepts/state_model/index.md (97%) rename docs/docs/aztec/{aztec => }/concepts/state_model/public_vm.md (100%) rename docs/docs/aztec/{aztec => }/concepts/storage/index.md (77%) rename docs/docs/aztec/{aztec => }/concepts/storage/trees/index.md (96%) rename docs/docs/aztec/{aztec => }/concepts/storage/trees/indexed_merkle_tree.mdx (100%) rename docs/docs/aztec/{aztec => }/concepts/transactions.md (91%) rename docs/docs/aztec/{aztec => }/concepts/wallets/_category_.json (100%) rename docs/docs/aztec/{aztec => }/concepts/wallets/architecture.md (80%) rename docs/docs/aztec/{aztec => }/concepts/wallets/index.md (70%) rename docs/docs/aztec/{aztec => }/core_components.md (73%) rename docs/docs/aztec/{aztec => }/glossary/call_types.md (99%) rename docs/docs/aztec/{aztec => }/glossary/index.md (100%) rename docs/docs/aztec/{aztec => }/how_to_participate.md (100%) rename docs/docs/aztec/{aztec => }/limitations.md (89%) rename docs/docs/aztec/{aztec => }/roadmap/_category_.json (100%) rename docs/docs/aztec/{aztec => }/roadmap/cryptography_roadmap.md (100%) rename docs/docs/aztec/{aztec => }/roadmap/engineering_roadmap.md (99%) rename docs/docs/aztec/{aztec => }/roadmap/features_initial_ldt.md (100%) rename docs/docs/aztec/{aztec => }/roadmap/index.md (100%) rename docs/docs/{getting_started/getting_started/index.md => getting_started.md} (89%) delete mode 100644 docs/docs/getting_started/_category_.json rename docs/docs/getting_started/{getting_started => }/aztecjs-getting-started.md (96%) rename docs/docs/getting_started/{getting_started => }/aztecnr-getting-started.md (95%) delete mode 100644 docs/docs/getting_started/getting_started/_category_.json delete mode 100644 docs/docs/guides/_category_.json delete mode 100644 docs/docs/guides/guides/_category_.json delete mode 100644 docs/docs/guides/guides/smart_contracts/writing_contracts/portals/index.md rename docs/docs/guides/{guides => }/js_apps/_category_.json (100%) rename docs/docs/guides/{guides => }/js_apps/call_view_function.md (100%) rename docs/docs/guides/{guides => }/js_apps/create_account.md (100%) rename docs/docs/guides/{guides => }/js_apps/deploy_contract.md (80%) rename docs/docs/guides/{guides => }/js_apps/send_transaction.md (100%) rename docs/docs/guides/{guides => }/js_apps/test_contracts.md (86%) rename docs/docs/guides/{guides => }/local_env/_category_.json (100%) rename docs/docs/guides/{guides => }/local_env/creating_schnorr_accounts.md (93%) rename docs/docs/guides/{guides => }/local_env/run_more_than_one_pxe_sandbox.md (97%) rename docs/docs/guides/{guides => }/local_env/versions-updating.md (98%) rename docs/docs/guides/{guides => }/smart_contracts/_category_.json (100%) rename docs/docs/guides/{guides => }/smart_contracts/how_to_compile_contract.md (91%) rename docs/docs/guides/{guides => }/smart_contracts/how_to_deploy_contract.md (84%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/_category_.json (100%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/call_functions.md (65%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/common_patterns/_category_.json (100%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/common_patterns/authwit.md (96%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/common_patterns/index.md (93%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/how_to_emit_event.md (92%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/how_to_pop_capsules.md (100%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/how_to_prove_history.md (91%) create mode 100644 docs/docs/guides/smart_contracts/writing_contracts/index.md rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/initializers.md (94%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/portals/_category_.json (100%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/portals/communicate_with_portal.md (97%) create mode 100644 docs/docs/guides/smart_contracts/writing_contracts/portals/index.md rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/storage/_category_.json (100%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/storage/index.md (75%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/storage/notes.md (92%) rename docs/docs/guides/{guides => }/smart_contracts/writing_contracts/storage/storage_slots.md (89%) rename docs/docs/reference/{reference => }/common_errors/_category_.json (100%) rename docs/docs/reference/{reference => }/common_errors/aztecnr-errors.md (92%) rename docs/docs/reference/{reference => }/common_errors/sandbox-errors.md (89%) rename docs/docs/reference/{reference => }/debugging.md (100%) rename docs/docs/reference/{reference => }/privacy_considerations.md (98%) delete mode 100644 docs/docs/reference/reference/_category_.json rename docs/docs/reference/{reference => }/sandbox_reference/_category_.json (100%) rename docs/docs/reference/{reference => }/sandbox_reference/cheat_codes.md (99%) rename docs/docs/reference/{reference => }/sandbox_reference/index.md (93%) rename docs/docs/reference/{reference => }/sandbox_reference/sandbox-reference.md (82%) rename docs/docs/reference/{reference => }/smart_contract_reference/_category_.json (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/dependencies.md (92%) rename docs/docs/reference/{reference => }/smart_contract_reference/globals.md (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/history_lib_reference.md (98%) rename docs/docs/reference/{reference => }/smart_contract_reference/index.md (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/portals/_category_.json (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/portals/data_structures.md (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/portals/inbox.md (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/portals/outbox.md (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/portals/registry.md (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/storage/_category_.json (100%) rename docs/docs/reference/{reference => }/smart_contract_reference/storage/index.md (81%) rename docs/docs/reference/{reference => }/smart_contract_reference/storage/private_state.md (96%) rename docs/docs/reference/{reference => }/smart_contract_reference/storage/public_state.md (89%) rename docs/docs/reference/{reference => }/smart_contract_reference/storage/shared_state.md (100%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/_category_.json (100%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/_category_.json (100%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/_category_.json (100%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/depositing_to_aztec.md (100%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/index.md (97%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/minting_on_aztec.md (98%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/setup.md (99%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/typescript_glue_code.md (100%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md (91%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/crowdfunding_contract.md (96%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/private_voting_contract.md (82%) rename docs/docs/tutorials/{tutorials => }/contract_tutorials/token_contract.md (96%) rename docs/docs/tutorials/{tutorials => }/simple_dapp/contract_deployment.md (94%) rename docs/docs/tutorials/{tutorials => }/simple_dapp/contract_interaction.md (91%) rename docs/docs/tutorials/{tutorials => }/simple_dapp/index.md (87%) rename docs/docs/tutorials/{tutorials => }/simple_dapp/project_setup.md (100%) rename docs/docs/tutorials/{tutorials => }/simple_dapp/pxe_service.md (92%) rename docs/docs/tutorials/{tutorials => }/simple_dapp/testing.md (79%) delete mode 100644 docs/docs/tutorials/tutorials/_category_.json rename docs/docs/tutorials/{tutorials => }/write_accounts_contract.md (83%) rename docs/docs/{aztec/index.mdx => vision.mdx} (96%) create mode 100755 docs/scripts/clean.sh create mode 100755 docs/scripts/move_processed.sh diff --git a/docs/.gitignore b/docs/.gitignore index 54162e3dbc6..07d9321798d 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -22,6 +22,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -docs/reference/reference/smart_contract_reference/aztec-nr - -/src/preprocess/AztecnrReferenceAutogenStructure.json +docs/reference/aztecjs +docs/reference/smart_contract_reference/aztec-nr diff --git a/docs/docs/.gitignore b/docs/docs/.gitignore deleted file mode 100644 index 6fa7731468d..00000000000 --- a/docs/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/apis diff --git a/docs/docs/aztec/aztec/index.md b/docs/docs/aztec.md similarity index 94% rename from docs/docs/aztec/aztec/index.md rename to docs/docs/aztec.md index d679f1955e0..dec4840f9de 100644 --- a/docs/docs/aztec/aztec/index.md +++ b/docs/docs/aztec.md @@ -3,7 +3,7 @@ title: Aztec sidebar_position: 0 --- -import Disclaimer from "../../../src/components/Disclaimers/\_wip_disclaimer.mdx"; +import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; import ReactPlayer from "react-player/youtube"; Aztec is an L2 that brings programmable privacy to Ethereum. @@ -52,7 +52,7 @@ Contributors to Aztec uphold many of the values of the Ethereum community -- bui Noir is a domain specific programming language for writing zero-knowledge circuits. On Aztec a smart contract is a collection of circuits that developers write using Noir. -You can find more information and resources for learning about Noir smart contracts on [this page](/aztec/aztec/concepts/smart_contracts/index.md). +You can find more information and resources for learning about Noir smart contracts on [this page](/aztec/concepts/smart_contracts/index.md). ## Cryptography diff --git a/docs/docs/aztec/_category_.json b/docs/docs/aztec/_category_.json index 5313372a176..336394a563a 100644 --- a/docs/docs/aztec/_category_.json +++ b/docs/docs/aztec/_category_.json @@ -1,6 +1,6 @@ { + "label": "Aztec", "position": 0, "collapsible": true, - "collapsed": true, - "label": "Aztec" + "collapsed": true } diff --git a/docs/docs/aztec/aztec/_category_.json b/docs/docs/aztec/aztec/_category_.json deleted file mode 100644 index 336394a563a..00000000000 --- a/docs/docs/aztec/aztec/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "label": "Aztec", - "position": 0, - "collapsible": true, - "collapsed": true -} diff --git a/docs/docs/aztec/aztec/concepts/_category_.json b/docs/docs/aztec/concepts/_category_.json similarity index 100% rename from docs/docs/aztec/aztec/concepts/_category_.json rename to docs/docs/aztec/concepts/_category_.json diff --git a/docs/docs/aztec/aztec/concepts/accounts/authwit.md b/docs/docs/aztec/concepts/accounts/authwit.md similarity index 94% rename from docs/docs/aztec/aztec/concepts/accounts/authwit.md rename to docs/docs/aztec/concepts/accounts/authwit.md index 5b4388b5ef7..f4ad3ea825c 100644 --- a/docs/docs/aztec/aztec/concepts/accounts/authwit.md +++ b/docs/docs/aztec/concepts/accounts/authwit.md @@ -54,9 +54,9 @@ All of these issues have been discussed in the community for a while, and there Adopting ERC20 for Aztec is not as simple as it might seem because of private state. -If you recall from the [Hybrid State model](/aztec/aztec/concepts/state_model/index.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going. +If you recall from the [Hybrid State model](/aztec/concepts/state_model/index.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going. -If we were to implement the `approve` with an allowance in private, you might know the allowance, but unless you also know about the individual notes that make up the user's balances, it would be of no use to you! It is private after all. To spend the user's funds you would need to know the decryption key, see [keys for more](/aztec/aztec/concepts/accounts/keys.md). +If we were to implement the `approve` with an allowance in private, you might know the allowance, but unless you also know about the individual notes that make up the user's balances, it would be of no use to you! It is private after all. To spend the user's funds you would need to know the decryption key, see [keys for more](/aztec/concepts/accounts/keys.md). While this might sound limiting in what we can actually do, the main use of approvals have been for simplifying contract interactions that the user is doing. In the case of private transactions, this is executed on the user device, so it is not a blocker that the user need to tell the executor a secret - the user is the executor! ### So what can we do? @@ -178,7 +178,7 @@ For the transfer, this could be done simply by appending a nonce to the argument action = H(defi, token, transfer_selector, H(alice_account, defi, 1000, nonce)); ``` -Beware that the account contract will be unable to emit the nullifier since it is checked with a static call, so the calling contract must do it. This is similar to nonces in ERC20 tokens today. We provide a small library that handles this which we will see in the [developer documentation](guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md). +Beware that the account contract will be unable to emit the nullifier since it is checked with a static call, so the calling contract must do it. This is similar to nonces in ERC20 tokens today. We provide a small library that handles this which we will see in the [developer documentation](guides/smart_contracts/writing_contracts/common_patterns/authwit.md). ### Differences to approval @@ -192,4 +192,4 @@ We don't need to limit ourselves to the `transfer` function, we can use the same ### Next Steps -Check out the [developer documentation](guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md) to see how to implement this in your own contracts. +Check out the [developer documentation](guides/smart_contracts/writing_contracts/common_patterns/authwit.md) to see how to implement this in your own contracts. diff --git a/docs/docs/aztec/aztec/concepts/accounts/index.md b/docs/docs/aztec/concepts/accounts/index.md similarity index 98% rename from docs/docs/aztec/aztec/concepts/accounts/index.md rename to docs/docs/aztec/concepts/accounts/index.md index e9add04a564..5d396c9fd92 100644 --- a/docs/docs/aztec/aztec/concepts/accounts/index.md +++ b/docs/docs/aztec/concepts/accounts/index.md @@ -71,7 +71,7 @@ def entryPoint(payload): enqueueCall(to, data, value, gasLimit); ``` -Read more about how to write an account contract [here](/tutorials/tutorials/write_accounts_contract.md). +Read more about how to write an account contract [here](/tutorials/write_accounts_contract.md). ### Account contracts and wallets @@ -134,7 +134,7 @@ These two patterns combined allow an account contract to answer whether an actio Aztec requires users to define [encryption and nullifying keys](./keys.md) that are needed for receiving and spending private notes. Unlike transaction signing, encryption and nullifying is enshrined at the protocol. This means that there is a single scheme used for encryption and nullifying. These keys are derived from a master public key. This master public key, in turn, is used when deterministically deriving the account's address. -A side effect of committing to a master public key as part of the address is that _this key cannot be rotated_. While an account contract implementation could include methods for rotating the signing key, this is unfortunately not possible for encryption and nullifying keys (note that rotating nullifying keys also creates other challenges such as preventing double spends). We are exploring usage of [`SharedMutable`](/reference/reference/smart_contract_reference/storage/shared_state.md#sharedmutable) to enable rotating these keys. +A side effect of committing to a master public key as part of the address is that _this key cannot be rotated_. While an account contract implementation could include methods for rotating the signing key, this is unfortunately not possible for encryption and nullifying keys (note that rotating nullifying keys also creates other challenges such as preventing double spends). We are exploring usage of [`SharedMutable`](/reference/smart_contract_reference/storage/shared_state.md#sharedmutable) to enable rotating these keys. NOTE: While we entertained the idea of abstracting note encryption, where account contracts would define an `encrypt` method that would use a user-defined scheme, there are two main reasons we decided against this. First is that this entailed that, in order to receive funds, a user had to first deploy their account contract, which is a major UX issue. Second, users could define malicious `encrypt` methods that failed in certain circumstances, breaking application flows that required them to receive a private note. While this issue already exists in Ethereum when transferring ETH (see the [king of the hill](https://coinsbench.com/27-king-ethernaut-da5021cd4aa6)), its impact is made worse in Aztec since any execution failure in a private function makes the entire transaction unprovable (ie it is not possible to catch errors in calls to other private functions), and furthermore because encryption is required for any private state (not just for transferring ETH). Nevertheless, both of these problems are solvable. Initialization can be worked around by embedding a commitment to the bytecode in the address and removing the need for actually deploying contracts before interacting with them, and the king of the hill issue can be mitigated by introducing a full private VM that allows catching reverts. As such, we may be able to abstract encryption in the future as well. diff --git a/docs/docs/aztec/aztec/concepts/accounts/keys.md b/docs/docs/aztec/concepts/accounts/keys.md similarity index 94% rename from docs/docs/aztec/aztec/concepts/accounts/keys.md rename to docs/docs/aztec/concepts/accounts/keys.md index a0cc247d1b4..dd9caace655 100644 --- a/docs/docs/aztec/aztec/concepts/accounts/keys.md +++ b/docs/docs/aztec/concepts/accounts/keys.md @@ -20,7 +20,7 @@ Instead it's up to the account contract developer to implement it. ::: ## Public keys retrieval -The keys can either be retrieved from a key registry contract or from the [Private eXecution Environment (PXE)](/aztec/aztec/concepts/pxe/index.md). +The keys can either be retrieved from a key registry contract or from the [Private eXecution Environment (PXE)](/aztec/concepts/pxe/index.md). :::note The key registry is a canonical contract used to store user public keys. @@ -40,7 +40,7 @@ Below are some ways how we could instantiate it after getting the information in #include_code instantiate-complete-address /yarn-project/circuits.js/src/structs/complete_address.test.ts rust -Then to register the recipient's [complete address](#complete-address) in PXE we would call `registerRecipient` PXE endpoint using [Aztec.js](/aztec/aztec/core_components.md#aztecjs): +Then to register the recipient's [complete address](#complete-address) in PXE we would call `registerRecipient` PXE endpoint using [Aztec.js](/aztec/core_components.md#aztecjs): #include_code register-recipient /yarn-project/aztec.js/src/wallet/create_recipient.ts rust @@ -116,7 +116,7 @@ This is a snippet of our Schnorr Account contract implementation, which uses Sch #include_code entrypoint /noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust -Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](/tutorials/tutorials/write_accounts_contract.md) for a full example of how to manage authentication. +Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](/tutorials/write_accounts_contract.md) for a full example of how to manage authentication. Furthermore, and since signatures are fully abstracted, how the key is stored in the contract is abstracted as well and left to the developer of the account contract. In the following section we describe a few ways how an account contract could be architected to store signing keys. @@ -133,7 +133,7 @@ Similar to using a private note, but using an immutable private note removes the #### Using shared state -A compromise between the two solutions above is to use [shared state](/reference/reference/smart_contract_reference/storage/shared_state.md). This would not generate additional nullifiers and commitments for each transaction while allowing the user to rotate their key. However, this causes every transaction to now have a time-to-live determined by the frequency of the mutable shared state, as well as imposing restrictions on how fast keys can be rotated due to minimum delays. +A compromise between the two solutions above is to use [shared state](/reference/smart_contract_reference/storage/shared_state.md). This would not generate additional nullifiers and commitments for each transaction while allowing the user to rotate their key. However, this causes every transaction to now have a time-to-live determined by the frequency of the mutable shared state, as well as imposing restrictions on how fast keys can be rotated due to minimum delays. #### Reusing some of the in-protocol keys diff --git a/docs/docs/aztec/aztec/concepts/circuits/index.md b/docs/docs/aztec/concepts/circuits/index.md similarity index 92% rename from docs/docs/aztec/aztec/concepts/circuits/index.md rename to docs/docs/aztec/concepts/circuits/index.md index 108a6555a3c..e05e10c8937 100644 --- a/docs/docs/aztec/aztec/concepts/circuits/index.md +++ b/docs/docs/aztec/concepts/circuits/index.md @@ -52,7 +52,7 @@ In other words, since neither the EVM nor other rollups have rules for how to pr What kind of extra rules / checks does a rollup need, to enforce notions of private states and private functions? Stuff like: -- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [trees](/aztec/aztec/concepts/storage/trees/index.md)). +- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [trees](/aztec/concepts/storage/trees/index.md)). - "Hide which function was just executed, by wrapping it in a zk-snark" - "Hide all functions which were executed as part of this tx's stack trace, by wrapping the whole tx in a zk-snark" @@ -62,12 +62,12 @@ So what kinds of core protocol circuits does Aztec have? ### Kernel Circuits -- [Private Kernel Circuit](/aztec/aztec/concepts/circuits/kernels/private_kernel) -- [Public Kernel Circuit](/aztec/aztec/concepts/circuits/kernels/public_kernel) +- [Private Kernel Circuit](/aztec/concepts/circuits/kernels/private_kernel) +- [Public Kernel Circuit](/aztec/concepts/circuits/kernels/public_kernel) ### Rollup Circuits -- [Rollup Circuits](/aztec/aztec/concepts/circuits/rollup_circuits) +- [Rollup Circuits](/aztec/concepts/circuits/rollup_circuits) #### Squisher Circuits diff --git a/docs/docs/aztec/aztec/concepts/circuits/kernels/private_kernel.md b/docs/docs/aztec/concepts/circuits/kernels/private_kernel.md similarity index 92% rename from docs/docs/aztec/aztec/concepts/circuits/kernels/private_kernel.md rename to docs/docs/aztec/concepts/circuits/kernels/private_kernel.md index 29850ae496c..3b9f66bc016 100644 --- a/docs/docs/aztec/aztec/concepts/circuits/kernels/private_kernel.md +++ b/docs/docs/aztec/concepts/circuits/kernels/private_kernel.md @@ -16,10 +16,10 @@ This circuit is executed by the user, on their own device. This is to ensure pri - public call stacks: hashes representing calls to other public functions; - events; - all data accumulated by all previous private kernel circuit recursions of this tx; -- Hides which private function has been executed, by performing a zero-knowledge proof of membership against the [contract tree](/aztec/aztec/concepts/storage/trees/index.md#contract-tree). +- Hides which private function has been executed, by performing a zero-knowledge proof of membership against the [contract tree](/aztec/concepts/storage/trees/index.md#contract-tree). - Ensures the entire stack trace of private functions (for a particular tx) adheres to function execution rules. - Verifies a previous 'Private Kernel Proof', recursively, when verifying transactions which are composed of many private function calls. -- Optionally can [deploy](/aztec/aztec/concepts/smart_contracts/contract_creation.md) a new private contract. +- Optionally can [deploy](/aztec/concepts/smart_contracts/contract_creation.md) a new private contract. > Note: **This is the only core protocol circuit which actually needs to be "zk" (zero-knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function). > This is a really interesting point. Most so-called "zk-Rollups" do not make use of this "zero-knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero-knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup". diff --git a/docs/docs/aztec/aztec/concepts/circuits/kernels/public_kernel.md b/docs/docs/aztec/concepts/circuits/kernels/public_kernel.md similarity index 80% rename from docs/docs/aztec/aztec/concepts/circuits/kernels/public_kernel.md rename to docs/docs/aztec/concepts/circuits/kernels/public_kernel.md index 90a331cab77..ba078f1cb81 100644 --- a/docs/docs/aztec/aztec/concepts/circuits/kernels/public_kernel.md +++ b/docs/docs/aztec/concepts/circuits/kernels/public_kernel.md @@ -2,7 +2,7 @@ title: Public Kernel Circuit --- -This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](/aztec/aztec/concepts/storage/trees/index.md#public-state-tree) at any time. A Sequencer might choose to delegate proof generation to the Prover pool. +This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](/aztec/concepts/storage/trees/index.md#public-state-tree) at any time. A Sequencer might choose to delegate proof generation to the Prover pool. - Exposes (forwards) the following data to the next recursive circuit: - all data accumulated by all previous private kernel circuit recursions of this tx; diff --git a/docs/docs/aztec/aztec/concepts/circuits/rollup_circuits/index.md b/docs/docs/aztec/concepts/circuits/rollup_circuits/index.md similarity index 95% rename from docs/docs/aztec/aztec/concepts/circuits/rollup_circuits/index.md rename to docs/docs/aztec/concepts/circuits/rollup_circuits/index.md index cec6a6ce30c..7190f858400 100644 --- a/docs/docs/aztec/aztec/concepts/circuits/rollup_circuits/index.md +++ b/docs/docs/aztec/concepts/circuits/rollup_circuits/index.md @@ -23,7 +23,7 @@ For both transactions, it: - Performs public state read membership checks. - Updates the public data tree in line with the requested state transitions. -- Checks that the nullifiers haven't previously been inserted into the [indexed nullifier tree](/aztec/aztec/concepts/storage/trees/indexed_merkle_tree.mdx#primer-on-nullifier-trees). +- Checks that the nullifiers haven't previously been inserted into the [indexed nullifier tree](/aztec/concepts/storage/trees/indexed_merkle_tree.mdx#primer-on-nullifier-trees). - Batch-inserts new nullifiers into the nullifier tree. - Batch-inserts new note hashes into the note hash tree - Batch-inserts any new contract deployments into the contract tree. diff --git a/docs/docs/aztec/aztec/concepts/index.md b/docs/docs/aztec/concepts/index.md similarity index 59% rename from docs/docs/aztec/aztec/concepts/index.md rename to docs/docs/aztec/concepts/index.md index dd91d9b5243..88bbd6efa57 100644 --- a/docs/docs/aztec/aztec/concepts/index.md +++ b/docs/docs/aztec/concepts/index.md @@ -25,11 +25,11 @@ The PXE is unaware of the Public VM. And the Public VM is unaware of the PXE. Th ### Private and public state -Private state works with UTXOs, or what we call notes. To keep things private, everything is stored in an [append-only UTXO tree](/aztec/aztec/concepts/storage/trees/index.md#note-hash-tree), and a nullifier is created when notes are invalidated. Nullifiers are then stored in their own [nullifier tree](/aztec/aztec/concepts/storage/trees/indexed_merkle_tree.mdx#primer-on-nullifier-trees). +Private state works with UTXOs, or what we call notes. To keep things private, everything is stored in an [append-only UTXO tree](/aztec/concepts/storage/trees/index.md#note-hash-tree), and a nullifier is created when notes are invalidated. Nullifiers are then stored in their own [nullifier tree](/aztec/concepts/storage/trees/indexed_merkle_tree.mdx#primer-on-nullifier-trees). -Public state works similarly to other chains like Ethereum, behaving like a public ledger. Public data is stored in a [public data tree](/aztec/aztec/concepts/storage/trees/index.md#public-state-tree). +Public state works similarly to other chains like Ethereum, behaving like a public ledger. Public data is stored in a [public data tree](/aztec/concepts/storage/trees/index.md#public-state-tree). -Aztec [smart contract](/aztec/aztec/concepts/smart_contracts/index.md) developers should keep in mind that different types are used when manipulating private or public state. Working with private state is creating commitments and nullifiers to state, whereas working with public state is directly updating state. +Aztec [smart contract](/aztec/concepts/smart_contracts/index.md) developers should keep in mind that different types are used when manipulating private or public state. Working with private state is creating commitments and nullifiers to state, whereas working with public state is directly updating state. ## Accounts @@ -37,11 +37,11 @@ Every account in Aztec is a smart contract (account abstraction). This allows im Developers can write their own account contract to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed. -Learn more about account contracts [here](/aztec/aztec/concepts/index.md). +Learn more about account contracts [here](/aztec/concepts/index.md). ## Smart contracts -Developers can write [smart contracts](/aztec/aztec/concepts/smart_contracts/index.md) that manipulate both public and private state. They are written in a framework on top of Noir, the zero-knowledge domain-specific language developed specifically for Aztec. Outside of Aztec, Noir is used for writing circuits that can be verified on EVM chains. +Developers can write [smart contracts](/aztec/concepts/smart_contracts/index.md) that manipulate both public and private state. They are written in a framework on top of Noir, the zero-knowledge domain-specific language developed specifically for Aztec. Outside of Aztec, Noir is used for writing circuits that can be verified on EVM chains. Noir has its own doc site that you can find [here](https://noir-lang.org). @@ -52,14 +52,13 @@ Aztec allows private communications with Ethereum - ie no-one knows where the tr This is achieved through portals - these are smart contracts deployed on an EVM that are related to the Ethereum smart contract you want to interact with. Learn more about portals [here](/protocol-specs/l1-smart-contracts/index.md). - ## Circuits Aztec operates on three types of circuits: -- [Private kernel circuits](/aztec/aztec/concepts/circuits/kernels/private_kernel.md), which are executed by the user on their own device and prove correct execution of a function -- [Public kernel circuits](./circuits/kernels/public_kernel.md), which are executed by the [sequencer](/aztec/aztec/concepts/nodes_clients/sequencer) and ensure the stack trace of transactions adheres to function execution rules -- [Rollup circuits](/aztec/aztec/concepts/circuits), which bundle all of the Aztec transactions into a proof that can be efficiently verified on Ethereum +- [Private kernel circuits](/aztec/concepts/circuits/kernels/private_kernel.md), which are executed by the user on their own device and prove correct execution of a function +- [Public kernel circuits](./circuits/kernels/public_kernel.md), which are executed by the [sequencer](/aztec/concepts/nodes_clients/sequencer) and ensure the stack trace of transactions adheres to function execution rules +- [Rollup circuits](/aztec/concepts/circuits), which bundle all of the Aztec transactions into a proof that can be efficiently verified on Ethereum ## What's next? @@ -71,4 +70,4 @@ Explore the Concepts for a deeper understanding into the components that make up ### Start coding -Follow the [developer getting started guide](/getting_started/getting_started). +Follow the [developer getting started guide](/getting_started). diff --git a/docs/docs/aztec/aztec/concepts/nodes_clients/_category_.json b/docs/docs/aztec/concepts/nodes_clients/_category_.json similarity index 100% rename from docs/docs/aztec/aztec/concepts/nodes_clients/_category_.json rename to docs/docs/aztec/concepts/nodes_clients/_category_.json diff --git a/docs/docs/aztec/aztec/concepts/nodes_clients/sequencer/index.md b/docs/docs/aztec/concepts/nodes_clients/sequencer/index.md similarity index 97% rename from docs/docs/aztec/aztec/concepts/nodes_clients/sequencer/index.md rename to docs/docs/aztec/concepts/nodes_clients/sequencer/index.md index 35cded457bd..afaf726f022 100644 --- a/docs/docs/aztec/aztec/concepts/nodes_clients/sequencer/index.md +++ b/docs/docs/aztec/concepts/nodes_clients/sequencer/index.md @@ -40,4 +40,4 @@ You can view the current implementation on Github [here](https://github.com/Azte ## Further Reading -- [Sequencer Selection](/aztec/aztec/concepts/nodes_clients/sequencer/sequencer_selection.md) +- [Sequencer Selection](/aztec/concepts/nodes_clients/sequencer/sequencer_selection.md) diff --git a/docs/docs/aztec/aztec/concepts/nodes_clients/sequencer/sequencer_selection.md b/docs/docs/aztec/concepts/nodes_clients/sequencer/sequencer_selection.md similarity index 100% rename from docs/docs/aztec/aztec/concepts/nodes_clients/sequencer/sequencer_selection.md rename to docs/docs/aztec/concepts/nodes_clients/sequencer/sequencer_selection.md diff --git a/docs/docs/aztec/aztec/concepts/pxe/acir_simulator.md b/docs/docs/aztec/concepts/pxe/acir_simulator.md similarity index 88% rename from docs/docs/aztec/aztec/concepts/pxe/acir_simulator.md rename to docs/docs/aztec/concepts/pxe/acir_simulator.md index 9fc4039b9c3..5ee55027368 100644 --- a/docs/docs/aztec/aztec/concepts/pxe/acir_simulator.md +++ b/docs/docs/aztec/concepts/pxe/acir_simulator.md @@ -14,13 +14,13 @@ It simulates three types of functions: Private functions are simulated and proved client-side, and verified client-side in the private kernel circuit. -They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](/aztec/aztec/concepts/smart_contracts/oracles/index.md). +They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](/aztec/concepts/smart_contracts/oracles/index.md). Private functions can call other private functions and can request to call a public function. The public function execution will be performed by the sequencer asynchronously, so private functions don't have direct access to the return values of public functions. ### Public Functions -Public functions are simulated and proved on the [sequencer](/aztec/aztec/concepts/nodes_clients/sequencer) side, and verified by the [public kernel circuit](../circuits/kernels/public_kernel.md). +Public functions are simulated and proved on the [sequencer](/aztec/concepts/nodes_clients/sequencer) side, and verified by the [public kernel circuit](../circuits/kernels/public_kernel.md). They are run with the assistance of an oracle that provides any value read from the public state tree. diff --git a/docs/docs/aztec/aztec/concepts/pxe/index.md b/docs/docs/aztec/concepts/pxe/index.md similarity index 93% rename from docs/docs/aztec/aztec/concepts/pxe/index.md rename to docs/docs/aztec/concepts/pxe/index.md index 9ae9f319451..3185229b7b2 100644 --- a/docs/docs/aztec/aztec/concepts/pxe/index.md +++ b/docs/docs/aztec/concepts/pxe/index.md @@ -63,9 +63,9 @@ The keystore is a secure storage for private and public keys. ## Oracles -Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [functions section](/aztec/aztec/concepts/smart_contracts/oracles/index.md). +Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [functions section](/aztec/concepts/smart_contracts/oracles/index.md). ## For developers To learn how to develop on top of the PXE, refer to these guides: -* [Run more than one PXE on your local machine](/aztec/aztec/concepts/pxe/index.md) -* [Use in-built oracles including oracles for arbitrary data](guides/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md) +* [Run more than one PXE on your local machine](/aztec/concepts/pxe/index.md) +* [Use in-built oracles including oracles for arbitrary data](guides/smart_contracts/writing_contracts/how_to_pop_capsules.md) diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/communication/index.md b/docs/docs/aztec/concepts/smart_contracts/communication/index.md similarity index 78% rename from docs/docs/aztec/aztec/concepts/smart_contracts/communication/index.md rename to docs/docs/aztec/concepts/smart_contracts/communication/index.md index 4172cdea96d..2a6b7a8edf5 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/communication/index.md +++ b/docs/docs/aztec/concepts/smart_contracts/communication/index.md @@ -9,4 +9,4 @@ See [Private \<--\> Public execution](./public_private_calls.md) for information ## Cross-chain communication -Read the protocol specification about Cross-chain communication between Aztec and Ethereum [here](../../../../../protocol-specs/l1-smart-contracts/index.md). +Read the protocol specification about Cross-chain communication between Aztec and Ethereum [here](/protocol-specs/l1-smart-contracts/index.md). diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md b/docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md similarity index 93% rename from docs/docs/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md rename to docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md index 04e32af8c91..09f2449bec0 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md +++ b/docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md @@ -4,7 +4,7 @@ title: Private <> Public Communication import Image from "@theme/IdealImage"; -import Disclaimer from "../../../../../../src/components/Disclaimers/\_wip_disclaimer.mdx"; +import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; @@ -84,6 +84,6 @@ Many applications rely on some form of access control to function well. USDC hav Access control like this cannot easily be enforced in the private domain, as reading is also nullifying (to ensure data is up to date). However, as it is possible to read historical public state, one can combine private and public functions to get the desired effect. -This concept is known as [shared state](/reference/reference/smart_contract_reference/storage/shared_state.md), and relies on using delays when changing public data so that it can also be read in private with currentness guarantees. Since values cannot be immediately modified but instead require delays to elapse, it is possible to privately prove that an application is using the current value _as long as the transaction gets included before some time in the future_, which would be the earliest the value could possibly change. +This concept is known as [shared state](/reference/smart_contract_reference/storage/shared_state.md), and relies on using delays when changing public data so that it can also be read in private with currentness guarantees. Since values cannot be immediately modified but instead require delays to elapse, it is possible to privately prove that an application is using the current value _as long as the transaction gets included before some time in the future_, which would be the earliest the value could possibly change. If the public state is only changed infrequently, and it is acceptable to have delays when doing so, then shared state is a good solution to this problem. diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/contract_creation.md b/docs/docs/aztec/concepts/smart_contracts/contract_creation.md similarity index 82% rename from docs/docs/aztec/aztec/concepts/smart_contracts/contract_creation.md rename to docs/docs/aztec/concepts/smart_contracts/contract_creation.md index f6944dbd053..1400657f8cd 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/contract_creation.md +++ b/docs/docs/aztec/concepts/smart_contracts/contract_creation.md @@ -6,4 +6,4 @@ The latest information about contract deployment has moved to the protocol speci ## Further reading -To see how to deploy a contract in practice, check out the [dapp development tutorial](/tutorials/tutorials/simple_dapp). +To see how to deploy a contract in practice, check out the [dapp development tutorial](/tutorials/simple_dapp). diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/contract_structure.md b/docs/docs/aztec/concepts/smart_contracts/contract_structure.md similarity index 65% rename from docs/docs/aztec/aztec/concepts/smart_contracts/contract_structure.md rename to docs/docs/aztec/concepts/smart_contracts/contract_structure.md index f8e024d740d..ac8a21048a5 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/contract_structure.md +++ b/docs/docs/aztec/concepts/smart_contracts/contract_structure.md @@ -2,7 +2,7 @@ title: Structure of a contract --- -A contract is a collection of persistent [state variables](/aztec/aztec/concepts/storage/index.md), and [functions](/aztec/aztec/concepts/smart_contracts/functions) which may manipulate these variables. Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called. +A contract is a collection of persistent [state variables](/aztec/concepts/storage/index.md), and [functions](/aztec/concepts/smart_contracts/functions) which may manipulate these variables. Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called. # Contract @@ -35,4 +35,4 @@ Here's a common layout for a basic Aztec.nr Contract project: ``` - See the vanilla Noir docs for [more info on packages](https://noir-lang.org/docs/noir/modules_packages_crates/crates_and_packages). -- You can review the structure of a complete contract in the token contract tutorial [here](/tutorials/tutorials/contract_tutorials/token_contract.md). +- You can review the structure of a complete contract in the token contract tutorial [here](/tutorials/contract_tutorials/token_contract.md). diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/context.md b/docs/docs/aztec/concepts/smart_contracts/functions/context.md similarity index 94% rename from docs/docs/aztec/aztec/concepts/smart_contracts/functions/context.md rename to docs/docs/aztec/concepts/smart_contracts/functions/context.md index a2d44f40d80..5bd2f4526b3 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/context.md +++ b/docs/docs/aztec/concepts/smart_contracts/functions/context.md @@ -4,7 +4,7 @@ title: Understanding Function Context ## What is the context -The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](/aztec/aztec/concepts/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. +The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](/aztec/concepts/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. Behind the scenes, Aztec.nr will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. @@ -18,7 +18,7 @@ On this page, you'll learn ## Two contexts, one API -The `Aztec` blockchain contains two environments [public and private](/aztec/aztec/concepts/state_model/index.md). +The `Aztec` blockchain contains two environments [public and private](/aztec/concepts/state_model/index.md). - Private, for private transactions taking place on user's devices. - Public, for public transactions taking place on the network's sequencers. diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/index.md b/docs/docs/aztec/concepts/smart_contracts/functions/index.md similarity index 72% rename from docs/docs/aztec/aztec/concepts/smart_contracts/functions/index.md rename to docs/docs/aztec/concepts/smart_contracts/functions/index.md index cb3021e0c71..0593873c757 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/index.md +++ b/docs/docs/aztec/concepts/smart_contracts/functions/index.md @@ -2,9 +2,9 @@ title: Defining Functions --- -Functions serve as the building blocks of smart contracts. Functions can be either **public**, ie they are publicly available for anyone to see and can directly interact with public state, or **private**, meaning they are executed completely client-side in the [PXE](/aztec/aztec/concepts/pxe/index.md). Read more about how private functions work [here](./inner_workings.md#private-functions). +Functions serve as the building blocks of smart contracts. Functions can be either **public**, ie they are publicly available for anyone to see and can directly interact with public state, or **private**, meaning they are executed completely client-side in the [PXE](/aztec/concepts/pxe/index.md). Read more about how private functions work [here](./inner_workings.md#private-functions). -For a more practical guide of using multiple types of functions, follow the [token tutorial](/tutorials/tutorials/contract_tutorials/token_contract.md). +For a more practical guide of using multiple types of functions, follow the [token tutorial](/tutorials/contract_tutorials/token_contract.md). Currently, any function is "mutable" in the sense that it might alter state. However, we also support support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). @@ -22,7 +22,7 @@ Explore this section to learn: - [How function visibility works in Aztec](./visibility.md) - [Public, private, and unconstrained functions](./public_private_unconstrained.md), and how to write them -- How to write an [initializer function](/guides/guides/smart_contracts/writing_contracts/initializers.md) -- [Calling functions from within the same smart contract and from different contracts](/guides/guides/smart_contracts/writing_contracts/call_functions.md), including calling private functions from private functions, public from public, and even private from public -- [Oracles](/aztec/aztec/concepts/smart_contracts/oracles/index.md) and how Aztec smart contracts might use them +- How to write an [initializer function](/guides/smart_contracts/writing_contracts/initializers.md) +- [Calling functions from within the same smart contract and from different contracts](/guides/smart_contracts/writing_contracts/call_functions.md), including calling private functions from private functions, public from public, and even private from public +- [Oracles](/aztec/concepts/smart_contracts/oracles/index.md) and how Aztec smart contracts might use them - [How functions work under the hood](./inner_workings.md) diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/inner_workings.md b/docs/docs/aztec/concepts/smart_contracts/functions/inner_workings.md similarity index 74% rename from docs/docs/aztec/aztec/concepts/smart_contracts/functions/inner_workings.md rename to docs/docs/aztec/concepts/smart_contracts/functions/inner_workings.md index eb0a4b5599c..2e6f412ee1b 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/inner_workings.md +++ b/docs/docs/aztec/concepts/smart_contracts/functions/inner_workings.md @@ -10,7 +10,7 @@ To get a more practical understanding about functions, read [the rest of this se Aztec.nr uses an attribute system to annotate a function's type. Annotating a function with the `#[aztec(private)]` attribute tells the framework that this is a private function that will be executed on a users device. The compiler will create a circuit to define this function. -`#aztec(private)` is just syntactic sugar. At compile time, the Aztec.nr framework inserts code that allows the function to interact with the [kernel](/aztec/aztec/concepts/circuits/kernels/private_kernel.md). +`#aztec(private)` is just syntactic sugar. At compile time, the Aztec.nr framework inserts code that allows the function to interact with the [kernel](/aztec/concepts/circuits/kernels/private_kernel.md). To help illustrate how this interacts with the internals of Aztec and its kernel circuits, we can take an example private function, and explore what it looks like after Aztec.nr's macro expansion. @@ -24,12 +24,12 @@ To help illustrate how this interacts with the internals of Aztec and its kernel #### The expansion broken down? -Viewing the expanded Aztec contract uncovers a lot about how Aztec contracts interact with the [kernel](/aztec/aztec/concepts/circuits/kernels/private_kernel.md). To aid with developing intuition, we will break down each inserted line. +Viewing the expanded Aztec contract uncovers a lot about how Aztec contracts interact with the [kernel](/aztec/concepts/circuits/kernels/private_kernel.md). To aid with developing intuition, we will break down each inserted line. **Receiving context from the kernel.** #include_code context-example-inputs /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust -Private function calls are able to interact with each other through orchestration from within the [kernel circuit](/aztec/aztec/concepts/circuits/kernels/private_kernel.md). The kernel circuit forwards information to each contract function (recall each contract function is a circuit). This information then becomes part of the private context. +Private function calls are able to interact with each other through orchestration from within the [kernel circuit](/aztec/concepts/circuits/kernels/private_kernel.md). The kernel circuit forwards information to each contract function (recall each contract function is a circuit). This information then becomes part of the private context. For example, within each private function we can access some global variables. To access them we can call on the `context`, e.g. `context.chain_id()`. The value of the chain ID comes from the values passed into the circuit from the kernel. The kernel checks that all of the values passed to each circuit in a function call are the same. @@ -54,7 +54,7 @@ Inside the kernel circuits, the inputs to functions are reduced to a single valu **Creating the function's context.** #include_code context-example-context /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust -Each Aztec function has access to a [context](/aztec/aztec/concepts/smart_contracts/functions/context) object. This object, although labelled a global variable, is created locally on a users' device. It is initialized from the inputs provided by the kernel, and a hash of the function's inputs. +Each Aztec function has access to a [context](/aztec/concepts/smart_contracts/functions/context) object. This object, although labelled a global variable, is created locally on a users' device. It is initialized from the inputs provided by the kernel, and a hash of the function's inputs. #include_code context-example-context-return /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust @@ -64,7 +64,7 @@ We achieve this by pushing return values to the execution context, which we then **Making the contract's storage available** #include_code storage-example-context /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust -When a [`Storage` struct](/guides/guides/smart_contracts/writing_contracts/storage) is declared within a contract, the `storage` keyword is made available. As shown in the macro expansion above, this calls the init function on the storage struct with the current function's context. +When a [`Storage` struct](/guides/smart_contracts/writing_contracts/storage) is declared within a contract, the `storage` keyword is made available. As shown in the macro expansion above, this calls the init function on the storage struct with the current function's context. Any state variables declared in the `Storage` struct can now be accessed as normal struct members. @@ -75,14 +75,14 @@ This function takes the application context, and converts it into the `PrivateCi ## Unconstrained functions -Defining a function as `unconstrained` tells Aztec to simulate it completely client-side in the [ACIR simulator](/aztec/aztec/concepts/pxe/acir_simulator.md) without generating proofs. They are useful for extracting information from a user through an [oracle](../oracles). +Defining a function as `unconstrained` tells Aztec to simulate it completely client-side in the [ACIR simulator](/aztec/concepts/pxe/acir_simulator.md) without generating proofs. They are useful for extracting information from a user through an [oracle](../oracles). When an unconstrained function is called, it prompts the ACIR simulator to 1. generate the execution environment 2. execute the function within this environment -To generate the environment, the simulator gets the blockheader from the [PXE database](/aztec/aztec/concepts/pxe/index.md#database) and passes it along with the contract address to `ViewDataOracle`. This creates a context that simulates the state of the blockchain at a specific block, allowing the unconstrained function to access and interact with blockchain data as it would appear in that block, but without affecting the actual blockchain state. +To generate the environment, the simulator gets the blockheader from the [PXE database](/aztec/concepts/pxe/index.md#database) and passes it along with the contract address to `ViewDataOracle`. This creates a context that simulates the state of the blockchain at a specific block, allowing the unconstrained function to access and interact with blockchain data as it would appear in that block, but without affecting the actual blockchain state. Once the execution environment is created, `execute_unconstrained_function` is invoked: @@ -93,4 +93,4 @@ This: 1. Prepares the ACIR for execution 2. Converts `args` into a format suitable for the ACVM (Abstract Circuit Virtual Machine), creating an initial witness (witness = set of inputs required to compute the function). `args` might be an oracle to request a user's balance 3. Executes the function in the ACVM, which involves running the ACIR with the initial witness and the context. If requesting a user's balance, this would query the balance from the PXE database -4. Extracts the return values from the `partialWitness` and decodes them based on the artifact to get the final function output. The [artifact](/aztec/aztec/concepts/smart_contracts/contract_structure.md) is the compiled output of the contract, and has information like the function signature, parameter types, and return types +4. Extracts the return values from the `partialWitness` and decodes them based on the artifact to get the final function output. The [artifact](/aztec/concepts/smart_contracts/contract_structure.md) is the compiled output of the contract, and has information like the function signature, parameter types, and return types diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/public_private_unconstrained.md b/docs/docs/aztec/concepts/smart_contracts/functions/public_private_unconstrained.md similarity index 100% rename from docs/docs/aztec/aztec/concepts/smart_contracts/functions/public_private_unconstrained.md rename to docs/docs/aztec/concepts/smart_contracts/functions/public_private_unconstrained.md diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/visibility.md b/docs/docs/aztec/concepts/smart_contracts/functions/visibility.md similarity index 91% rename from docs/docs/aztec/aztec/concepts/smart_contracts/functions/visibility.md rename to docs/docs/aztec/concepts/smart_contracts/functions/visibility.md index 2db0a5a4805..ef5e9002ac3 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/functions/visibility.md +++ b/docs/docs/aztec/concepts/smart_contracts/functions/visibility.md @@ -4,7 +4,7 @@ title: Visibility In Aztec there are multiple different types of visibility that can be applied to functions. Namely we have `data visibility` and `function visibility`. This page explains these types of visibility. -For a practical guide of using multiple types of data and function visibility,follow the [token tutorial](/tutorials/tutorials/contract_tutorials/token_contract.md). +For a practical guide of using multiple types of data and function visibility,follow the [token tutorial](/tutorials/contract_tutorials/token_contract.md). ### Data Visibility @@ -19,7 +19,7 @@ By default, all functions are callable from other contracts, similarly to the So A good place to use `internal` is when you want a private function to be able to alter public state. As mentioned above, private functions cannot do this directly. They are able to call public functions and by making these internal we can ensure that this state manipulating function is only callable from our private function. :::danger -Note that non-internal functions could be used directly as an entry-point, which currently means that the `msg_sender` would be `0`, so for now, using address `0` as a burn address is not recommended. You can learn more about this in the [Accounts concept page](/aztec/aztec/concepts/index.md#entrypoint-restrictions). +Note that non-internal functions could be used directly as an entry-point, which currently means that the `msg_sender` would be `0`, so for now, using address `0` as a burn address is not recommended. You can learn more about this in the [Accounts concept page](/aztec/concepts/index.md#entrypoint-restrictions). ::: To understand how visibility works under the hood, check out the [Inner Workings page](./inner_workings.md). diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/index.md b/docs/docs/aztec/concepts/smart_contracts/index.md similarity index 94% rename from docs/docs/aztec/aztec/concepts/smart_contracts/index.md rename to docs/docs/aztec/concepts/smart_contracts/index.md index 2eea1b9e17f..6237dc5051a 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/index.md +++ b/docs/docs/aztec/concepts/smart_contracts/index.md @@ -24,4 +24,4 @@ There are no plans for EVM compatibility or to support Solidity in Aztec. The pr ## Further reading -Read more about writing Aztec contracts [here](/aztec/aztec/concepts/smart_contracts/index.md). +Read more about writing Aztec contracts [here](/aztec/concepts/smart_contracts/index.md). diff --git a/docs/docs/aztec/aztec/concepts/smart_contracts/oracles/index.md b/docs/docs/aztec/concepts/smart_contracts/oracles/index.md similarity index 94% rename from docs/docs/aztec/aztec/concepts/smart_contracts/oracles/index.md rename to docs/docs/aztec/concepts/smart_contracts/oracles/index.md index 9f0c252cb91..51760f0b59c 100644 --- a/docs/docs/aztec/aztec/concepts/smart_contracts/oracles/index.md +++ b/docs/docs/aztec/concepts/smart_contracts/oracles/index.md @@ -4,7 +4,7 @@ title: Oracle Functions This page goes over what oracles are in Aztec and how they work. -Looking for a hands-on guide? You can learn how to use oracles in a smart contract [here](/guides/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). +Looking for a hands-on guide? You can learn how to use oracles in a smart contract [here](/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). An oracle is something that allows us to get data from the outside world into our contracts. The most widely-known types of oracles in blockchain systems are probably Chainlink price feeds, which allow us to get the price of an asset in USD taking non-blockchain data into account. @@ -22,7 +22,7 @@ Oracles introduce **non-determinism** into a circuit, and thus are `unconstraine ## Inbuilt oracles -- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/debug_log.nr) - Provides a couple of debug functions that can be used to log information to the console. Read more about debugging [here](/reference/reference/debugging.md#logging-in-aztecnr). +- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/debug_log.nr) - Provides a couple of debug functions that can be used to log information to the console. Read more about debugging [here](/reference/debugging.md#logging-in-aztecnr). - [`auth_witness`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth_witness.nr) - Provides a way to fetch the authentication witness for a given address. This is useful when building account contracts to support approve-like functionality. - [`get_l1_to_l2_message`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr) - Useful for application that receive messages from L1 to be consumed on L2, such as token bridges or other cross-chain applications. - [`notes`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/notes.nr) - Provides a lot of functions related to notes, such as fetches notes from storage etc, used behind the scenes for value notes and other pre-build note implementations. @@ -30,4 +30,4 @@ Oracles introduce **non-determinism** into a circuit, and thus are `unconstraine Find a full list [on GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/aztec-nr/aztec/src/oracle). -Please note that it is **not** possible to write a custom oracle for your dapp. Oracles are implemented in the PXE, so all users of your dapp would have to use a PXE service with your custom oracle included. If you want to inject some arbitrary data that does not have a dedicated oracle, you can use [popCapsule](/guides/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). +Please note that it is **not** possible to write a custom oracle for your dapp. Oracles are implemented in the PXE, so all users of your dapp would have to use a PXE service with your custom oracle included. If you want to inject some arbitrary data that does not have a dedicated oracle, you can use [popCapsule](/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). diff --git a/docs/docs/aztec/aztec/concepts/state_model/index.md b/docs/docs/aztec/concepts/state_model/index.md similarity index 97% rename from docs/docs/aztec/aztec/concepts/state_model/index.md rename to docs/docs/aztec/concepts/state_model/index.md index 593ca47e718..3a393f32076 100644 --- a/docs/docs/aztec/aztec/concepts/state_model/index.md +++ b/docs/docs/aztec/concepts/state_model/index.md @@ -44,4 +44,4 @@ This is achieved with two main features: ## Further reading -Read more about how to leverage the Aztec state model in Aztec contracts [here](/aztec/aztec/concepts/storage/index.md). +Read more about how to leverage the Aztec state model in Aztec contracts [here](/aztec/concepts/storage/index.md). diff --git a/docs/docs/aztec/aztec/concepts/state_model/public_vm.md b/docs/docs/aztec/concepts/state_model/public_vm.md similarity index 100% rename from docs/docs/aztec/aztec/concepts/state_model/public_vm.md rename to docs/docs/aztec/concepts/state_model/public_vm.md diff --git a/docs/docs/aztec/aztec/concepts/storage/index.md b/docs/docs/aztec/concepts/storage/index.md similarity index 77% rename from docs/docs/aztec/aztec/concepts/storage/index.md rename to docs/docs/aztec/concepts/storage/index.md index 7e121117ca5..643e24857e8 100644 --- a/docs/docs/aztec/aztec/concepts/storage/index.md +++ b/docs/docs/aztec/concepts/storage/index.md @@ -12,7 +12,7 @@ It also means that we need to be careful about how we allocate storage to ensure ## Public State Slots -As mentioned in [State Model](/aztec/aztec/concepts/state_model/index.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address. +As mentioned in [State Model](/aztec/concepts/state_model/index.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address. The mental model is that we have a key-value store, where the siloed slot is the key, and the value is the data stored in that slot. You can think of the `real_storage_slot` identifying its position in the tree, and the `logical_storage_slot` identifying the position in the contract storage. @@ -20,14 +20,14 @@ The mental model is that we have a key-value store, where the siloed slot is the real_storage_slot = H(contract_address, logical_storage_slot) ``` -The siloing is performed by the [Kernel circuits](/aztec/aztec/concepts/circuits). +The siloing is performed by the [Kernel circuits](/aztec/concepts/circuits). For structs and arrays, we are logically using a similar storage slot computation to ethereum, e.g., as a struct with 3 fields would be stored in 3 consecutive slots. However, because the "actual" storage slot is computed as a hash of the contract address and the logical storage slot, the actual storage slot is not consecutive. ## Private State Slots - Slots aren't real -Private storage is a different beast. As you might remember from [Hybrid State Model](/aztec/aztec/concepts/state_model/index.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree where each leaf is a commitment. Being append-only, means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that lookups at a specific storage slot would leak information in the context of private state. If you could look up a specific address balance just by looking at the storage slot, even if encrypted you would be able to see it changing! That is not good privacy. +Private storage is a different beast. As you might remember from [Hybrid State Model](/aztec/concepts/state_model/index.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree where each leaf is a commitment. Being append-only, means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that lookups at a specific storage slot would leak information in the context of private state. If you could look up a specific address balance just by looking at the storage slot, even if encrypted you would be able to see it changing! That is not good privacy. Following this, the storage slot as we know it doesn't really exist. The leaves of the note hashes tree are just commitments to content (think of it as a hash of its content). @@ -62,4 +62,4 @@ By doing this address-siloing at the kernel circuit we *force* the inserted comm To ensure that nullifiers don't collide across contracts we also force this contract siloing at the kernel level. ::: -For an example of this see [developer documentation storage slots](/aztec/aztec/concepts/storage/index.md). +For an example of this see [developer documentation storage slots](/aztec/concepts/storage/index.md). diff --git a/docs/docs/aztec/aztec/concepts/storage/trees/index.md b/docs/docs/aztec/concepts/storage/trees/index.md similarity index 96% rename from docs/docs/aztec/aztec/concepts/storage/trees/index.md rename to docs/docs/aztec/concepts/storage/trees/index.md index 56a508aaa10..1def5386a27 100644 --- a/docs/docs/aztec/aztec/concepts/storage/trees/index.md +++ b/docs/docs/aztec/concepts/storage/trees/index.md @@ -130,7 +130,7 @@ nullifier = hash(note_hash, owner_secret_key); This has the property that it's inextricably linked to the Note it is nullifying, and it can only be derived by the owner of the `owner_public_key` contained within the Note. Ensuring that the secret key corresponds to the public key would be implemented in the Aztec contract. -A smart contract that generates this nullifier and submits it to the network will only be allowed to submit it once; a second submission will be rejected by the base [Rollup Circuit](/aztec/aztec/concepts/circuits) (which performs Merkle non-membership checks against the Nullifier Tree). This prevents a Note from being 'deleted' twice. +A smart contract that generates this nullifier and submits it to the network will only be allowed to submit it once; a second submission will be rejected by the base [Rollup Circuit](/aztec/concepts/circuits) (which performs Merkle non-membership checks against the Nullifier Tree). This prevents a Note from being 'deleted' twice. :::note @@ -169,7 +169,7 @@ This tree's data can only be read/written by the Sequencer, since only they can ## Contract Tree -The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the [Kernel Circuits](/aztec/aztec/concepts/circuits) to validate that a function belongs to a specific contract. +The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the [Kernel Circuits](/aztec/concepts/circuits) to validate that a function belongs to a specific contract. @@ -209,7 +209,7 @@ HistoricalAccessTree --- Header ``` -It can also be used to find information about notes, public state, and contracts that were included in a certain block using [inclusion and non-inclusion proofs](/guides/guides/smart_contracts/writing_contracts/how_to_prove_history.md). +It can also be used to find information about notes, public state, and contracts that were included in a certain block using [inclusion and non-inclusion proofs](/guides/smart_contracts/writing_contracts/how_to_prove_history.md). ## Trees of valid Kernel/Rollup circuit Verification Keys diff --git a/docs/docs/aztec/aztec/concepts/storage/trees/indexed_merkle_tree.mdx b/docs/docs/aztec/concepts/storage/trees/indexed_merkle_tree.mdx similarity index 100% rename from docs/docs/aztec/aztec/concepts/storage/trees/indexed_merkle_tree.mdx rename to docs/docs/aztec/concepts/storage/trees/indexed_merkle_tree.mdx diff --git a/docs/docs/aztec/aztec/concepts/transactions.md b/docs/docs/aztec/concepts/transactions.md similarity index 91% rename from docs/docs/aztec/aztec/concepts/transactions.md rename to docs/docs/aztec/concepts/transactions.md index fd2c0d2f468..898de71c4a8 100644 --- a/docs/docs/aztec/aztec/concepts/transactions.md +++ b/docs/docs/aztec/concepts/transactions.md @@ -30,9 +30,9 @@ _The transaction has not been broadcasted to the sequencer network yet. For now, _The transaction has still not been broadcasted to the sequencer network yet and continues to live solely within the context of the PXE._ -3. **The PXE proves correct execution** – At this point, the PXE proves correct execution (via zero-knowledge proofs) of the authorization and of the private transfer method. Once the proofs have been generated, the PXE sends the proofs and required inputs (inputs are new note commitments, stored in the [note hash tree](/aztec/aztec/concepts/storage/trees/index.md#note-hash-tree) and nullifiers stored in the [nullifiers tree](/aztec/aztec/concepts/storage/trees/index.md#nullifier-tree)) to the sequencer. Nullifiers are data that invalidate old commitments, ensuring that commitments can only be used once. +3. **The PXE proves correct execution** – At this point, the PXE proves correct execution (via zero-knowledge proofs) of the authorization and of the private transfer method. Once the proofs have been generated, the PXE sends the proofs and required inputs (inputs are new note commitments, stored in the [note hash tree](/aztec/concepts/storage/trees/index.md#note-hash-tree) and nullifiers stored in the [nullifiers tree](/aztec/concepts/storage/trees/index.md#nullifier-tree)) to the sequencer. Nullifiers are data that invalidate old commitments, ensuring that commitments can only be used once. -_The sequencer has received the transaction proof and can begin to process the transaction - verifying proofs and applying updates to the relevant [data trees](/aztec/aztec/concepts/storage/trees/index.md) - alongside other public and private transactions._ +_The sequencer has received the transaction proof and can begin to process the transaction - verifying proofs and applying updates to the relevant [data trees](/aztec/concepts/storage/trees/index.md) - alongside other public and private transactions._ 4. **The sequencer has the necessary information to act** – the randomly-selected sequencer (based on the Fernet sequencer selection protocol) validates the transaction proofs along with required inputs (e.g. the note commitments and nullifiers) for this private transfer. The sequencer also executes public functions and requests proofs of public execution from a prover network. The sequencer updates the corresponding data trees and does the same for other private transactions. When the sequencer receives proofs from the prover network, the proofs will be bundled into a final rollup proof. @@ -48,7 +48,7 @@ Transactions on Aztec start with a call from Aztec.js or the Aztec CLI, which cr See [this diagram](https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg) for a more detailed overview of the transaction execution process. It highlights 3 different types of transaction execution: contract deployments, private transactions and public transactions. -See the page on [contract communication](/aztec/aztec/concepts/smart_contracts/communication/index.md) for more context on transaction execution. +See the page on [contract communication](/aztec/concepts/smart_contracts/communication/index.md) for more context on transaction execution. ### Enabling Transaction Semantics: The Aztec Kernel diff --git a/docs/docs/aztec/aztec/concepts/wallets/_category_.json b/docs/docs/aztec/concepts/wallets/_category_.json similarity index 100% rename from docs/docs/aztec/aztec/concepts/wallets/_category_.json rename to docs/docs/aztec/concepts/wallets/_category_.json diff --git a/docs/docs/aztec/aztec/concepts/wallets/architecture.md b/docs/docs/aztec/concepts/wallets/architecture.md similarity index 80% rename from docs/docs/aztec/aztec/concepts/wallets/architecture.md rename to docs/docs/aztec/concepts/wallets/architecture.md index f79dd176e4c..b62febe1947 100644 --- a/docs/docs/aztec/aztec/concepts/wallets/architecture.md +++ b/docs/docs/aztec/concepts/wallets/architecture.md @@ -10,7 +10,7 @@ Architecture-wise, a wallet is an instance of an **Private Execution Environment The PXE also communicates with an **Aztec Node** for retrieving public information or broadcasting transactions. Note that the PXE requires a local database for keeping private state, and is also expected to be continuously syncing new blocks for trial-decryption of user notes. -Additionally, a wallet must be able to handle one or more [account contract implementations](/aztec/aztec/concepts/index.md#account-contracts-and-wallets). When a user creates a new account, the account is represented on-chain by an account contract. The wallet is responsible for deploying and interacting with this contract. A wallet may support multiple flavours of accounts, such as an account that uses ECDSA signatures, or one that relies on WebAuthn, or one that requires multi-factor authentication. For a user, the choice of what account implementation to use is then determined by the wallet they interact with. +Additionally, a wallet must be able to handle one or more [account contract implementations](/aztec/concepts/index.md#account-contracts-and-wallets). When a user creates a new account, the account is represented on-chain by an account contract. The wallet is responsible for deploying and interacting with this contract. A wallet may support multiple flavours of accounts, such as an account that uses ECDSA signatures, or one that relies on WebAuthn, or one that requires multi-factor authentication. For a user, the choice of what account implementation to use is then determined by the wallet they interact with. In code, this translates to a wallet implementing an **AccountInterface** interface that defines [how to create an _execution request_ out of an array of _function calls_](./index.md#transaction-lifecycle) for the specific implementation of an account contract and [how to generate an _auth witness_](./index.md#authorizing-actions) for authorizing actions on behalf of the user. Think of this interface as the Javascript counterpart of an account contract, or the piece of code that knows how to format a transaction and authenticate an action based on the rules defined by the user's account contract implementation. diff --git a/docs/docs/aztec/aztec/concepts/wallets/index.md b/docs/docs/aztec/concepts/wallets/index.md similarity index 70% rename from docs/docs/aztec/aztec/concepts/wallets/index.md rename to docs/docs/aztec/concepts/wallets/index.md index 18540be83db..b47f11bab17 100644 --- a/docs/docs/aztec/aztec/concepts/wallets/index.md +++ b/docs/docs/aztec/concepts/wallets/index.md @@ -4,7 +4,7 @@ title: Wallets In this page we will cover the main responsibilities of a wallet in the Aztec network. -Refer to [_writing an account contract_](/tutorials/tutorials/write_accounts_contract.md) for a tutorial on how to write a contract to back a user's account. +Refer to [_writing an account contract_](/tutorials/write_accounts_contract.md) for a tutorial on how to write a contract to back a user's account. Go to [\_wallet architecture](./architecture.md) for an overview of its architecture and a reference on the interface a wallet must implement. @@ -16,17 +16,17 @@ In addition to these usual responsibilities, wallets in Aztec also need to track ## Account setup -The first step for any wallet is to let the user set up their [accounts](/aztec/aztec/concepts/index.md). An account in Aztec is represented on-chain by its corresponding account contract that the user must deploy to begin interacting with the network. This account contract dictates how transactions are authenticated and executed. +The first step for any wallet is to let the user set up their [accounts](/aztec/concepts/index.md). An account in Aztec is represented on-chain by its corresponding account contract that the user must deploy to begin interacting with the network. This account contract dictates how transactions are authenticated and executed. -A wallet must support at least one specific [account contract implementation](/tutorials/tutorials/write_accounts_contract.md), which means being able to deploy such a contract, as well as interacting with it when sending transactions. Code-wise, this requires [implementing the `AccountContract` interface](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/account_contract/index.ts). +A wallet must support at least one specific [account contract implementation](/tutorials/write_accounts_contract.md), which means being able to deploy such a contract, as well as interacting with it when sending transactions. Code-wise, this requires [implementing the `AccountContract` interface](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/account_contract/index.ts). -Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](/aztec/aztec/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin. +Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](/aztec/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin. ## Transaction lifecycle Every transaction in Aztec is broadcast to the network as a zero-knowledge proof of correct execution, in order to preserve privacy. This means that transaction proofs are generated on the wallet and not on a remote node. This is one of the biggest differences with regard to EVM chain wallets. -A wallet is responsible for **creating** an [_execution request_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/tx_execution_request.ts) out of one or more [_function calls_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/function_call.ts) requested by a dapp. For example, a dapp may request a wallet to "invoke the `transfer` function on the contract at `0x1234` with the following arguments", in response to a user action. The wallet [turns that into an execution request](/aztec/aztec/concepts/index.md#execution-requests) with the signed instructions to execute that function call from the user's account contract. In an [ECDSA-based account](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr), for instance, this is an execution request that encodes the function call in the _entrypoint payload_, and includes its ECDSA signature with the account's signing private key. +A wallet is responsible for **creating** an [_execution request_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/tx_execution_request.ts) out of one or more [_function calls_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/function_call.ts) requested by a dapp. For example, a dapp may request a wallet to "invoke the `transfer` function on the contract at `0x1234` with the following arguments", in response to a user action. The wallet [turns that into an execution request](/aztec/concepts/index.md#execution-requests) with the signed instructions to execute that function call from the user's account contract. In an [ECDSA-based account](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr), for instance, this is an execution request that encodes the function call in the _entrypoint payload_, and includes its ECDSA signature with the account's signing private key. Once the _execution request_ is created, the wallet is responsible for **simulating** and **proving** the execution of its private functions. The simulation yields an execution trace, which can be used to provide the user with a list of side effects of the private execution of the transaction. During this simulation, the wallet is responsible of providing data to the virtual machine, such as private notes, encryption keys, or nullifier secrets. This execution trace is fed into the prover, which returns a zero-knowledge proof that guarantees correct execution and hides all private information. The output of this process is a [_transaction_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/tx/tx.ts) object. @@ -42,13 +42,13 @@ There are no proofs generated as of the Sandbox release. This will be included i ## Authorizing actions -Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](/aztec/aztec/concepts/index.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else. +Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](/aztec/concepts/index.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else. Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWit` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation. ## Key management -As in EVM-based chains, wallets are expected to manage user keys, or provide an interface to hardware wallets or alternative key stores. Keep in mind that in Aztec each account requires [two sets of keys](/aztec/aztec/concepts/accounts/keys.md): privacy keys and authentication keys. Privacy keys are mandated by the protocol and used for encryption and nullification, whereas authentication keys are dependent on the account contract implementation rolled out by the wallet. Should the account contract support it, wallets must provide the user with the means to rotate or recover their authentication keys. +As in EVM-based chains, wallets are expected to manage user keys, or provide an interface to hardware wallets or alternative key stores. Keep in mind that in Aztec each account requires [two sets of keys](/aztec/concepts/accounts/keys.md): privacy keys and authentication keys. Privacy keys are mandated by the protocol and used for encryption and nullification, whereas authentication keys are dependent on the account contract implementation rolled out by the wallet. Should the account contract support it, wallets must provide the user with the means to rotate or recover their authentication keys. :::info Due to limitations in the current architecture, privacy keys need to be available in the wallet software itself and cannot be punted to an external keystore. This restriction may be lifted in a future release. @@ -56,7 +56,7 @@ Due to limitations in the current architecture, privacy keys need to be availabl ## Recipient encryption keys -Wallets are also expected to manage the public encryption keys of any recipients of local transactions. When creating an encrypted note for a recipient given their address, the wallet needs to provide their [complete address](/aztec/aztec/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys). Recipients broadcast their complete addresses when deploying their account contracts, and wallets collect this information and save it in a local registry for easy access when needed. +Wallets are also expected to manage the public encryption keys of any recipients of local transactions. When creating an encrypted note for a recipient given their address, the wallet needs to provide their [complete address](/aztec/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys). Recipients broadcast their complete addresses when deploying their account contracts, and wallets collect this information and save it in a local registry for easy access when needed. Note that, in order to interact with a recipient who has not yet deployed their account contract (and thus not broadcasted their complete address), it must also be possible to manually add an entry to a wallet's local registry of complete addresses. diff --git a/docs/docs/aztec/aztec/core_components.md b/docs/docs/aztec/core_components.md similarity index 73% rename from docs/docs/aztec/aztec/core_components.md rename to docs/docs/aztec/core_components.md index acaa0857820..b5619300187 100644 --- a/docs/docs/aztec/aztec/core_components.md +++ b/docs/docs/aztec/core_components.md @@ -35,13 +35,13 @@ An overview of the Aztec network architecture will help contextualize the concep ### Aztec.js -A user of the Aztec network will interact with the network through Aztec.js. Aztec.js is a library that provides APIs for managing accounts and interacting with smart contracts (including account contracts) on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](/aztec/aztec/concepts/pxe) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. +A user of the Aztec network will interact with the network through Aztec.js. Aztec.js is a library that provides APIs for managing accounts and interacting with smart contracts (including account contracts) on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](/aztec/concepts/pxe) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. ### Private Execution Environment -The PXE provides a secure environment for the execution of sensitive operations, ensuring private information and decrypted data are not accessible to unauthorized applications. It hides the details of the [state model](/aztec/aztec/concepts/state_model/index.md) from end users, but the state model is important for Aztec developers to understand as it has implications for [private/public execution](/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md) and [L1/L2 communication](../../protocol-specs/l1-smart-contracts/index.md). The PXE also includes the [ACIR Simulator](/aztec/aztec/concepts/pxe/acir_simulator.md) for private executions and the KeyStore for secure key management. +The PXE provides a secure environment for the execution of sensitive operations, ensuring private information and decrypted data are not accessible to unauthorized applications. It hides the details of the [state model](/aztec/concepts/state_model/index.md) from end users, but the state model is important for Aztec developers to understand as it has implications for [private/public execution](/aztec/concepts/smart_contracts/communication/public_private_calls.md) and [L1/L2 communication](/protocol-specs/l1-smart-contracts/index.md). The PXE also includes the [ACIR Simulator](/aztec/concepts/pxe/acir_simulator.md) for private executions and the KeyStore for secure key management. -Procedurally, the PXE sends results of private function execution and requests for public function executions to the [sequencer](/aztec/aztec/concepts/nodes_clients/sequencer), which will update the state of the rollup. +Procedurally, the PXE sends results of private function execution and requests for public function executions to the [sequencer](/aztec/concepts/nodes_clients/sequencer), which will update the state of the rollup. ### Sequencer @@ -49,8 +49,8 @@ The sequencer aggregates transactions into a block, generates proofs of the stat ## Further Reading -- [The state model](/aztec/aztec/concepts/state_model) -- [Accounts](/aztec/aztec/concepts) -- [Aztec Smart Contracts](/aztec/aztec/concepts/smart_contracts) -- [Transactions](/aztec/aztec/concepts/transactions) -- [Communication between network components](/aztec/aztec/concepts/smart_contracts/communication) +- [The state model](/aztec/concepts/state_model) +- [Accounts](/aztec/concepts) +- [Aztec Smart Contracts](/aztec/concepts/smart_contracts) +- [Transactions](/aztec/concepts/transactions) +- [Communication between network components](/aztec/concepts/smart_contracts/communication) diff --git a/docs/docs/aztec/aztec/glossary/call_types.md b/docs/docs/aztec/glossary/call_types.md similarity index 99% rename from docs/docs/aztec/aztec/glossary/call_types.md rename to docs/docs/aztec/glossary/call_types.md index ba700ae846d..0ecb95dbd6c 100644 --- a/docs/docs/aztec/aztec/glossary/call_types.md +++ b/docs/docs/aztec/glossary/call_types.md @@ -121,7 +121,7 @@ A common pattern is to enqueue public calls to check some validity condition on #include_code deadline /noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr rust :::warning -Calling public functions privately leaks some privacy! The caller of the function and all arguments will be revelead, so exercise care when mixing the private and public domains. To learn about alternative ways to access public state privately, look into [Shared State](/reference/reference/smart_contract_reference/storage/shared_state.md). +Calling public functions privately leaks some privacy! The caller of the function and all arguments will be revelead, so exercise care when mixing the private and public domains. To learn about alternative ways to access public state privately, look into [Shared State](/reference/smart_contract_reference/storage/shared_state.md). ::: ### Public Execution diff --git a/docs/docs/aztec/aztec/glossary/index.md b/docs/docs/aztec/glossary/index.md similarity index 100% rename from docs/docs/aztec/aztec/glossary/index.md rename to docs/docs/aztec/glossary/index.md diff --git a/docs/docs/aztec/aztec/how_to_participate.md b/docs/docs/aztec/how_to_participate.md similarity index 100% rename from docs/docs/aztec/aztec/how_to_participate.md rename to docs/docs/aztec/how_to_participate.md diff --git a/docs/docs/aztec/aztec/limitations.md b/docs/docs/aztec/limitations.md similarity index 89% rename from docs/docs/aztec/aztec/limitations.md rename to docs/docs/aztec/limitations.md index 5ca4703a923..6c48a29e7e5 100644 --- a/docs/docs/aztec/aztec/limitations.md +++ b/docs/docs/aztec/limitations.md @@ -30,11 +30,11 @@ Help shape and define: - It is a testing environment, it is insecure, unaudited and does not generate any proofs, its only for testing purposes; - Constructors can not call nor alter public state - - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [initializer functions](/guides/guides/smart_contracts/writing_contracts/initializers.md). + - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [initializer functions](/guides/smart_contracts/writing_contracts/initializers.md). - Beware that what you think of as a `view` could alter state ATM! Notably the account could alter state or re-enter whenever the account contract's `is_valid` function is called. - `msg_sender` is currently leaking when doing private -> public calls - - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](/aztec/aztec/concepts/smart_contracts/functions/context). -- The initial `msg_sender` is 0, which can be problematic for some contracts, see [function visibility](/aztec/aztec/concepts/smart_contracts/functions/visibility.md). + - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](/aztec/concepts/smart_contracts/functions/context). +- The initial `msg_sender` is 0, which can be problematic for some contracts, see [function visibility](/aztec/concepts/smart_contracts/functions/visibility.md). - Unencrypted logs don't link to the contract that emitted it, so essentially just a `debug_log`` that you can match values against. - A note that is created and nullified in the same transaction will still emit an encrypted log. - A limited amount of new note hashes, nullifiers and calls that are supported by a transaction, see [circuit limitations](#circuit-limitations). @@ -53,7 +53,7 @@ That's right, the Sandbox doesn't actually generate or verify any zk-SNARKs yet! The main goal of the Sandbox is to enable developers to experiment with building apps, and hopefully to provide feedback. We want the developer experience to be as fast as possible, much like how Ethereum developers use Ganache or Anvil to get super-fast block times, instead of the slow-but-realistic 12-second block times that they'll encounter in production. A fast Sandbox enables fast testing, which enables developers to iterate quickly. -That's not to say a super-fast proving system isn't being worked on [as we speak](/aztec/aztec/roadmap/cryptography_roadmap.md). +That's not to say a super-fast proving system isn't being worked on [as we speak](/aztec/roadmap/cryptography_roadmap.md). #### What are the consequences? @@ -172,11 +172,11 @@ This will be patched in the near future, but unfortunately, app developers might ### New Privacy Standards are required -There are many [patterns](/reference/reference/privacy_considerations.md) which can leak privacy, even on Aztec. Standards haven't been developed yet, to encourage best practices when designing private smart contracts. +There are many [patterns](/reference/privacy_considerations.md) which can leak privacy, even on Aztec. Standards haven't been developed yet, to encourage best practices when designing private smart contracts. #### What are the consequences? -For example, until community standards are developed to reduce the uniqueness of ['Tx Fingerprints'](/reference/reference/privacy_considerations.md#function-fingerprints-and-tx-fingerprints) app developers might accidentally forfeit some function privacy. +For example, until community standards are developed to reduce the uniqueness of ['Tx Fingerprints'](/reference/privacy_considerations.md#function-fingerprints-and-tx-fingerprints) app developers might accidentally forfeit some function privacy. ## Circuit limitations @@ -192,7 +192,7 @@ Here are the current constants: #### What are the consequences? -When you write an Aztec.nr [function](/aztec/aztec/concepts/smart_contracts/functions), there will be upper bounds on the following: +When you write an Aztec.nr [function](/aztec/concepts/smart_contracts/functions), there will be upper bounds on the following: - The number of public state reads and writes; - The number of note reads and nullifications; @@ -208,13 +208,13 @@ Not only are there limits on a _per function_ basis, there are also limits on a **In particular, these _per-transaction_ limits will limit transaction call stack depths** in the Sandbox. That means if a function call results in a cascade of nested function calls, and each of those function calls outputs lots of state reads and writes, or logs (etc.), then all of that accumulated output data might exceed the per-transaction limits that we currently have. This would cause such transactions to fail. -There are plans to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](/aztec/aztec/concepts/circuits), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. +There are plans to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](/aztec/concepts/circuits), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. > **In the mean time**, if you encounter a per-transaction limit when testing, and you're feeling adventurous, you could 'hack' the Sandbox to increase the limits. See here (TODO: link) for a guide. **However**, the limits cannot be increased indefinitely. So although we do anticipate that we'll be able to increase them a little bit, don't go mad and provide yourself with 1 million state transitions per transaction. That would be as unrealistic as artificially increasing Ethereum gas limits to 1 trillion. ### Circuits Processing Order Differs from Execution Order -Each function call is represented by a circuit with a dedicated zero-knowledge proof of its execution. The [private kernel circuit](/aztec/aztec/concepts/circuits/kernels/private_kernel.md) is in charge of stitching all these proofs together to produce a zero-knowledge proof that the whole execution of all function calls within a transaction is correct. In doing so, the processing order differs from the execution order. Firstly, the private kernel has to handle one function call in its entirety at a time because a zk proof cannot be verified partially. This property alone makes it impossible for the ordering of kernel circuit validation to match the order in which the functions of the transaction were executed. Secondly, the private kernel processes function calls in a stack-based order, i.e., after having processed a function call, it processes all direct child function calls in an order which is the reverse of the execution order. +Each function call is represented by a circuit with a dedicated zero-knowledge proof of its execution. The [private kernel circuit](/aztec/concepts/circuits/kernels/private_kernel.md) is in charge of stitching all these proofs together to produce a zero-knowledge proof that the whole execution of all function calls within a transaction is correct. In doing so, the processing order differs from the execution order. Firstly, the private kernel has to handle one function call in its entirety at a time because a zk proof cannot be verified partially. This property alone makes it impossible for the ordering of kernel circuit validation to match the order in which the functions of the transaction were executed. Secondly, the private kernel processes function calls in a stack-based order, i.e., after having processed a function call, it processes all direct child function calls in an order which is the reverse of the execution order. Note that there is no plan to change this in the future. @@ -242,7 +242,7 @@ Transaction output elements such as notes in encrypted logs, note hashes (commit ### Chopped Transient Notes are still Emitted in Logs -A note which is created and nullified during the very same transaction is called transient. Such a note is chopped by the [private kernel circuit](/aztec/aztec/concepts/circuits/kernels/private_kernel.md) and is never stored in any persistent data tree. +A note which is created and nullified during the very same transaction is called transient. Such a note is chopped by the [private kernel circuit](/aztec/concepts/circuits/kernels/private_kernel.md) and is never stored in any persistent data tree. For the time being, such chopped notes are still emitted through encrypted logs (which is the communication channel to transmit notes). When a log containing a chopped note is processed, a warning will be logged about a decrypted note which does not exist in data tree. We [improved](https://github.com/AztecProtocol/aztec-packages/issues/1603) error logging to help identify such an occurrence. However, this might be a source of confusion. This issue is tracked in ticket [#1641](https://github.com/AztecProtocol/aztec-packages/issues/1641). diff --git a/docs/docs/aztec/aztec/roadmap/_category_.json b/docs/docs/aztec/roadmap/_category_.json similarity index 100% rename from docs/docs/aztec/aztec/roadmap/_category_.json rename to docs/docs/aztec/roadmap/_category_.json diff --git a/docs/docs/aztec/aztec/roadmap/cryptography_roadmap.md b/docs/docs/aztec/roadmap/cryptography_roadmap.md similarity index 100% rename from docs/docs/aztec/aztec/roadmap/cryptography_roadmap.md rename to docs/docs/aztec/roadmap/cryptography_roadmap.md diff --git a/docs/docs/aztec/aztec/roadmap/engineering_roadmap.md b/docs/docs/aztec/roadmap/engineering_roadmap.md similarity index 99% rename from docs/docs/aztec/aztec/roadmap/engineering_roadmap.md rename to docs/docs/aztec/roadmap/engineering_roadmap.md index 6f510af56e6..02be93a9875 100644 --- a/docs/docs/aztec/aztec/roadmap/engineering_roadmap.md +++ b/docs/docs/aztec/roadmap/engineering_roadmap.md @@ -124,7 +124,7 @@ CI takes up a significant amount of time. It gets its own section here, so we re ## Shared Mutable State -We _need_ a way to read mutable public data from a private function. We are moving away from the old Slow Updates Tree in favor of [Shared Mutable](/reference/reference/smart_contract_reference/storage/shared_state.md). +We _need_ a way to read mutable public data from a private function. We are moving away from the old Slow Updates Tree in favor of [Shared Mutable](/reference/smart_contract_reference/storage/shared_state.md). ## Contract classes and instances? diff --git a/docs/docs/aztec/aztec/roadmap/features_initial_ldt.md b/docs/docs/aztec/roadmap/features_initial_ldt.md similarity index 100% rename from docs/docs/aztec/aztec/roadmap/features_initial_ldt.md rename to docs/docs/aztec/roadmap/features_initial_ldt.md diff --git a/docs/docs/aztec/aztec/roadmap/index.md b/docs/docs/aztec/roadmap/index.md similarity index 100% rename from docs/docs/aztec/aztec/roadmap/index.md rename to docs/docs/aztec/roadmap/index.md diff --git a/docs/docs/getting_started/getting_started/index.md b/docs/docs/getting_started.md similarity index 89% rename from docs/docs/getting_started/getting_started/index.md rename to docs/docs/getting_started.md index 18c358b4cf2..163fa2588a5 100644 --- a/docs/docs/getting_started/getting_started/index.md +++ b/docs/docs/getting_started.md @@ -16,7 +16,7 @@ This creates a codespace with a prebuilt image containing one of the "Aztec Boxe The above method uses Aztec boxes to install the sandbox and clone the repo. You can use it too to get started on your own machine and use your own IDE. -You can also [install the sandbox manually](/reference/reference/sandbox_reference). +You can also [install the sandbox manually](/reference/sandbox_reference). ### Prerequisites @@ -37,8 +37,8 @@ You can run `npx create-aztec-app sandbox -h` to start, stop, update and output ## What's next? -To deploy a smart contract to your sandbox and interact with it using Aztec.js, go to the [next page](aztecjs-getting-started.md). +To deploy a smart contract to your sandbox and interact with it using Aztec.js, go to the [next page](getting_started/aztecjs-getting-started.md). -To skip this and write your first smart contract, go to the [Aztec.nr getting started page](aztecnr-getting-started.md). +To skip this and write your first smart contract, go to the [Aztec.nr getting started page](getting_started/aztecnr-getting-started.md). diff --git a/docs/docs/getting_started/_category_.json b/docs/docs/getting_started/_category_.json deleted file mode 100644 index 52193ac82d5..00000000000 --- a/docs/docs/getting_started/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "position": 1, - "collapsible": true, - "collapsed": true, - "label": "Getting Started" -} diff --git a/docs/docs/getting_started/getting_started/aztecjs-getting-started.md b/docs/docs/getting_started/aztecjs-getting-started.md similarity index 96% rename from docs/docs/getting_started/getting_started/aztecjs-getting-started.md rename to docs/docs/getting_started/aztecjs-getting-started.md index b292cce92fc..88cf9c2210f 100644 --- a/docs/docs/getting_started/getting_started/aztecjs-getting-started.md +++ b/docs/docs/getting_started/aztecjs-getting-started.md @@ -7,11 +7,11 @@ import Image from "@theme/IdealImage"; In this guide, we will retrieving the Sandbox and deploy a pre-written contract to it using Aztec.js. -This guide assumes you have followed the [quickstart](./index.md). +This guide assumes you have followed the [quickstart](../getting_started.md). ## Prerequisites -- A running [Aztec sandbox](./index.md) +- A running [Aztec sandbox](../getting_started.md) ## Set up the project @@ -146,9 +146,9 @@ The sandbox is preloaded with multiple accounts so you don't have to sit and cre #include_code load_accounts /yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts typescript -An explanation on accounts on Aztec can be found [here](/aztec/aztec/concepts/index.md). +An explanation on accounts on Aztec can be found [here](/aztec/concepts/index.md). -If you want more accounts, you can find instructions in the [Account creation section](/guides/guides/local_env/creating_schnorr_accounts). +If you want more accounts, you can find instructions in the [Account creation section](/guides/local_env/creating_schnorr_accounts). ## Deploy a contract @@ -256,7 +256,7 @@ Now lets transfer some funds from Alice to Bob by calling the `transfer` functio 1. The sender. 2. The recipient. 3. The quantity of tokens to be transferred. -4. The nonce for the [authentication witness](/aztec/aztec/concepts/index.md#authorizing-actions), or 0 if msg.sender equal sender. +4. The nonce for the [authentication witness](/aztec/concepts/index.md#authorizing-actions), or 0 if msg.sender equal sender. Here is the Typescript code to call the `transfer` function, add this to your `index.ts` at the bottom of the `main` function: @@ -353,7 +353,7 @@ Our complete output should now be something like: token Bob's balance 10543 +43ms ``` -That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [here](/aztec/aztec/concepts/transactions). +That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [here](/aztec/concepts/transactions). ## Next Steps diff --git a/docs/docs/getting_started/getting_started/aztecnr-getting-started.md b/docs/docs/getting_started/aztecnr-getting-started.md similarity index 95% rename from docs/docs/getting_started/getting_started/aztecnr-getting-started.md rename to docs/docs/getting_started/aztecnr-getting-started.md index 1e331c443f5..8e2abeff7b7 100644 --- a/docs/docs/getting_started/getting_started/aztecnr-getting-started.md +++ b/docs/docs/getting_started/aztecnr-getting-started.md @@ -5,11 +5,11 @@ sidebar_position: 2 In this guide, we will create our first Aztec.nr smart contract. We will build a simple private counter. This contract will get you started with the basic setup and syntax of Aztec.nr, but doesn't showcase the awesome stuff Aztec is capable of. -If you already have some experience with Noir and want to build a cooler contract that utilizes both private and public state, you might want to check out the [token contract tutorial instead](/tutorials/tutorials/contract_tutorials/token_contract.md). +If you already have some experience with Noir and want to build a cooler contract that utilizes both private and public state, you might want to check out the [token contract tutorial instead](/tutorials/contract_tutorials/token_contract.md). ## Prerequisites -- You have followed the [quickstart](./index.md) +- You have followed the [quickstart](../getting_started.md) - Running Aztec Sandbox ## Set up a project @@ -116,7 +116,7 @@ Let’s create a constructor method to run on deployment that assigns an initial This function accesses the counts from storage. Then it assigns the passed initial counter to the `owner`'s counter privately using `at().add()`. -We have annotated this and other functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](/aztec/aztec/concepts/smart_contracts/functions). +We have annotated this and other functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](/aztec/concepts/smart_contracts/functions). ## Incrementing our counter @@ -181,7 +181,7 @@ Update the `Noir: Nargo Path` field to point to your desired `aztec-nargo` execu The next recommmended steps are follow the tutorials in order. They will teach you more about contracts, Aztec.js, and how Aztec works in general. -To follow the series of tutorials, start with the private voting contract [here](/tutorials/tutorials/contract_tutorials/private_voting_contract.md). +To follow the series of tutorials, start with the private voting contract [here](/tutorials/contract_tutorials/private_voting_contract.md). -Alternatively, you can read about the high level architecture on the [Core Components page](/aztec/aztec/concepts/state_model/index.md) and [the lifecycle of a transaction](/aztec/aztec/concepts/transactions). +Alternatively, you can read about the high level architecture on the [Core Components page](/aztec/concepts/state_model/index.md) and [the lifecycle of a transaction](/aztec/concepts/transactions). diff --git a/docs/docs/getting_started/getting_started/_category_.json b/docs/docs/getting_started/getting_started/_category_.json deleted file mode 100644 index f2c55c6f9e1..00000000000 --- a/docs/docs/getting_started/getting_started/_category_.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "label": "Getting Started", - "position": 1 -} diff --git a/docs/docs/guides/_category_.json b/docs/docs/guides/_category_.json deleted file mode 100644 index 5dc68949682..00000000000 --- a/docs/docs/guides/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "position": 2, - "collapsible": true, - "collapsed": true, - "label": "Guides" -} diff --git a/docs/docs/guides/guides/_category_.json b/docs/docs/guides/guides/_category_.json deleted file mode 100644 index a8fa84718fc..00000000000 --- a/docs/docs/guides/guides/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "position": 0, - "collapsible": true, - "collapsed": true, - "label": "Guides" -} diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/portals/index.md b/docs/docs/guides/guides/smart_contracts/writing_contracts/portals/index.md deleted file mode 100644 index f861c47664a..00000000000 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/portals/index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Portals ---- - -A portal is a point of contact between L1 and a contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. - -As outlined in [Communication](../../../../../protocol-specs/l1-smart-contracts/index.md), an Aztec L2 contract does not have to be linked to a portal contract, but can specify an intended portal in storage. Note, that a portal doesn't actually need to be a contract, it could be any address on L1. diff --git a/docs/docs/guides/guides/js_apps/_category_.json b/docs/docs/guides/js_apps/_category_.json similarity index 100% rename from docs/docs/guides/guides/js_apps/_category_.json rename to docs/docs/guides/js_apps/_category_.json diff --git a/docs/docs/guides/guides/js_apps/call_view_function.md b/docs/docs/guides/js_apps/call_view_function.md similarity index 100% rename from docs/docs/guides/guides/js_apps/call_view_function.md rename to docs/docs/guides/js_apps/call_view_function.md diff --git a/docs/docs/guides/guides/js_apps/create_account.md b/docs/docs/guides/js_apps/create_account.md similarity index 100% rename from docs/docs/guides/guides/js_apps/create_account.md rename to docs/docs/guides/js_apps/create_account.md diff --git a/docs/docs/guides/guides/js_apps/deploy_contract.md b/docs/docs/guides/js_apps/deploy_contract.md similarity index 80% rename from docs/docs/guides/guides/js_apps/deploy_contract.md rename to docs/docs/guides/js_apps/deploy_contract.md index 90e4ddd9f83..1a511366185 100644 --- a/docs/docs/guides/guides/js_apps/deploy_contract.md +++ b/docs/docs/guides/js_apps/deploy_contract.md @@ -10,11 +10,11 @@ You should have a wallet to act as the deployer, and a contract artifact ready t You can learn how to create wallets from [this guide](./create_account.md). -You can read about contract artifacts [here](/aztec/aztec/concepts/smart_contracts/contract_structure.md). +You can read about contract artifacts [here](/aztec/concepts/smart_contracts/contract_structure.md). ## Import the contract artifact -In this guide we are using a Token contract artifact. This comes from the [token contract tutorial](/tutorials/tutorials/contract_tutorials/token_contract.md). +In this guide we are using a Token contract artifact. This comes from the [token contract tutorial](/tutorials/contract_tutorials/token_contract.md). #include_code import_token_contract yarn-project/end-to-end/src/composed/docs_examples.test.ts typescript diff --git a/docs/docs/guides/guides/js_apps/send_transaction.md b/docs/docs/guides/js_apps/send_transaction.md similarity index 100% rename from docs/docs/guides/guides/js_apps/send_transaction.md rename to docs/docs/guides/js_apps/send_transaction.md diff --git a/docs/docs/guides/guides/js_apps/test_contracts.md b/docs/docs/guides/js_apps/test_contracts.md similarity index 86% rename from docs/docs/guides/guides/js_apps/test_contracts.md rename to docs/docs/guides/js_apps/test_contracts.md index 14e5b8854b9..53a7272335a 100644 --- a/docs/docs/guides/guides/js_apps/test_contracts.md +++ b/docs/docs/guides/js_apps/test_contracts.md @@ -8,7 +8,7 @@ We will be using typescript to write our tests, and rely on the [`aztec.js`](htt ## A simple example -Let's start with a simple example for a test using the [Sandbox](/reference/reference/sandbox_reference/index.md). We will create two accounts and deploy a token contract in a setup step, and then issue a transfer from one user to another. +Let's start with a simple example for a test using the [Sandbox](/reference/sandbox_reference/index.md). We will create two accounts and deploy a token contract in a setup step, and then issue a transfer from one user to another. #include_code sandbox-example /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript @@ -17,7 +17,7 @@ This test sets up the environment by creating a client to the Private Execution Once we have this setup, the test itself is simple. We check the balance of the `recipient` user to ensure it has no tokens, send and await a deployment transaction, and then check the balance again to ensure it was increased. Note that all numeric values are represented as [native bigints](https://developer.mozilla.org/en-US/docs/Web/JavaScript//reference/Global_Objects/BigInt) to avoid loss of precision. :::info -We are using the `Token` contract's typescript interface. Follow the [typescript interface section](/guides/guides/smart_contracts/how_to_compile_contract.md#typescript-interfaces) to get type-safe methods for deploying and interacting with the token contract. +We are using the `Token` contract's typescript interface. Follow the [typescript interface section](/guides/smart_contracts/how_to_compile_contract.md#typescript-interfaces) to get type-safe methods for deploying and interacting with the token contract. ::: To run the test, first make sure the Sandbox is running on port 8080, and then [run your tests using jest](https://jestjs.io/docs/getting-started#running-from-command-line). Your test should pass, and you should see the following output in the Sandbox logs, where each chunk corresponds to a transaction. Note how this test run has a total of four transactions: two for deploying the account contracts for the `owner` and `recipient`, another for deploying the token contract, and a last one for actually executing the transfer. @@ -92,7 +92,7 @@ If a note doesn't appear when you expect it to, check the visible notes returned If the note appears in the visible notes and it contains the expected values there is probably an issue with how you fetch the notes. Check that the note getter (or note viewer) parameters are set correctly. If the note doesn't appear, ensure that you have emitted the corresponding encrypted log (usually by passing in a `broadcast = true` param to the `create_note` function). You can also check the Sandbox logs to see if the `emitEncryptedLog` was emitted. Run `export DEBUG="aztec:\*" before spinning up sandbox to see all the logs. -For debugging and logging in Aztec contracts, see [this page](/reference/reference/debugging.md). +For debugging and logging in Aztec contracts, see [this page](/reference/debugging.md). ## Assertions @@ -142,13 +142,13 @@ WARN Error processing tx 06dc87c4d64462916ea58426ffcfaf20017880b353c9ec3e0f0ee5f We can check private or public state directly rather than going through view-only methods, as we did in the initial example by calling `token.methods.balance().simulate()`. Bear in mind that directly accessing contract storage will break any kind of encapsulation. -To query storage directly, you'll need to know the slot you want to access. This can be checked in the [contract's `Storage` definition](/aztec/aztec/concepts/storage/index.md) directly for most data types. However, when it comes to mapping types, as in most EVM languages, we'll need to calculate the slot for a given key. To do this, we'll use the [`CheatCodes`](/reference/reference/sandbox_reference/cheat_codes.md) utility class: +To query storage directly, you'll need to know the slot you want to access. This can be checked in the [contract's `Storage` definition](/aztec/concepts/storage/index.md) directly for most data types. However, when it comes to mapping types, as in most EVM languages, we'll need to calculate the slot for a given key. To do this, we'll use the [`CheatCodes`](/reference/sandbox_reference/cheat_codes.md) utility class: #include_code calc-slot /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript #### Querying private state -Private state in the Aztec Network is represented via sets of [private notes](/aztec/aztec/concepts/state_model/index.md#private-state). In our token contract example, the balance of a user is represented as a set of unspent value notes, each with their own corresponding numeric value. +Private state in the Aztec Network is represented via sets of [private notes](/aztec/concepts/state_model/index.md#private-state). In our token contract example, the balance of a user is represented as a set of unspent value notes, each with their own corresponding numeric value. #include_code value-note-def noir-projects/aztec-nr/value-note/src/value_note.nr rust @@ -158,13 +158,13 @@ We can query the Private eXecution Environment (PXE) for all notes encrypted for #### Querying public state -[Public state](/aztec/aztec/concepts/state_model/index.md#public-state) behaves as a key-value store, much like in the EVM. This scenario is much more straightforward, in that we can directly query the target slot and get the result back as a buffer. Note that we use the [`TokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/token_contract/src/main.nr) in this example, which defines a mapping of public balances on slot 6. +[Public state](/aztec/concepts/state_model/index.md#public-state) behaves as a key-value store, much like in the EVM. This scenario is much more straightforward, in that we can directly query the target slot and get the result back as a buffer. Note that we use the [`TokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-contracts/contracts/token_contract/src/main.nr) in this example, which defines a mapping of public balances on slot 6. #include_code public-storage /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript ### Logs -Last but not least, we can check the logs of [events](/guides/guides/smart_contracts/writing_contracts/how_to_emit_event) emitted by our contracts. Contracts in Aztec can emit both [encrypted](/guides/guides/smart_contracts/writing_contracts/how_to_emit_event.md#encrypted-events) and [unencrypted](/guides/guides/smart_contracts/writing_contracts/how_to_emit_event.md#unencrypted-events) events. +Last but not least, we can check the logs of [events](/guides/smart_contracts/writing_contracts/how_to_emit_event) emitted by our contracts. Contracts in Aztec can emit both [encrypted](/guides/smart_contracts/writing_contracts/how_to_emit_event.md#encrypted-events) and [unencrypted](/guides/smart_contracts/writing_contracts/how_to_emit_event.md#unencrypted-events) events. :::info At the time of this writing, only unencrypted events can be queried directly. Encrypted events are always assumed to be encrypted notes. @@ -178,7 +178,7 @@ We can query the PXE for the unencrypted logs emitted in the block where our tra ## Cheats -The [`CheatCodes`](/reference/reference/sandbox_reference/cheat_codes.md) class, which we used for [calculating the storage slot above](#state), also includes a set of cheat methods for modifying the chain state that can be handy for testing. +The [`CheatCodes`](/reference/sandbox_reference/cheat_codes.md) class, which we used for [calculating the storage slot above](#state), also includes a set of cheat methods for modifying the chain state that can be handy for testing. ### Set next block timestamp diff --git a/docs/docs/guides/guides/local_env/_category_.json b/docs/docs/guides/local_env/_category_.json similarity index 100% rename from docs/docs/guides/guides/local_env/_category_.json rename to docs/docs/guides/local_env/_category_.json diff --git a/docs/docs/guides/guides/local_env/creating_schnorr_accounts.md b/docs/docs/guides/local_env/creating_schnorr_accounts.md similarity index 93% rename from docs/docs/guides/guides/local_env/creating_schnorr_accounts.md rename to docs/docs/guides/local_env/creating_schnorr_accounts.md index 0649378a77a..51eb3e24a84 100644 --- a/docs/docs/guides/guides/local_env/creating_schnorr_accounts.md +++ b/docs/docs/guides/local_env/creating_schnorr_accounts.md @@ -7,14 +7,14 @@ sidebar_position: 1 This section shows how to create schnorr account wallets on the Aztec Sandbox. -An in-depth explaining about accounts on aztec can be found [here](/aztec/aztec/concepts/index.md). But creating an account on the Sandbox does 2 things: +An in-depth explaining about accounts on aztec can be found [here](/aztec/concepts/index.md). But creating an account on the Sandbox does 2 things: 1. Deploys an account contract -- representing you -- allowing you to perform actions on the network (deploy contracts, call functions etc). 2. Adds your encryption keys to the Private eXecution Environment (PXE) allowing it to decrypt and manage your private state. ## Pre-requisites -Have a running Sandbox and a repository that interacts with it as explained [here](/getting_started/getting_started). +Have a running Sandbox and a repository that interacts with it as explained [here](/getting_started). Let's assume you have a file `src/index.ts` from the example used in the Sandbox page. @@ -61,4 +61,4 @@ Once this has completed, the L2 block is retrieved and pulled down to the PXE so ## Next Steps -Check out our section on [Writing your own Account Contract](/tutorials/tutorials/write_accounts_contract.md) leveraging our account abstraction +Check out our section on [Writing your own Account Contract](/tutorials/write_accounts_contract.md) leveraging our account abstraction diff --git a/docs/docs/guides/guides/local_env/run_more_than_one_pxe_sandbox.md b/docs/docs/guides/local_env/run_more_than_one_pxe_sandbox.md similarity index 97% rename from docs/docs/guides/guides/local_env/run_more_than_one_pxe_sandbox.md rename to docs/docs/guides/local_env/run_more_than_one_pxe_sandbox.md index 398a0fd6112..9081163c703 100644 --- a/docs/docs/guides/guides/local_env/run_more_than_one_pxe_sandbox.md +++ b/docs/docs/guides/local_env/run_more_than_one_pxe_sandbox.md @@ -39,6 +39,6 @@ You should see something like this: Aztec Server listening on port 8080 ``` -You can learn more about custom commands in the [sandbox reference](/reference/reference/sandbox_reference/index.md). +You can learn more about custom commands in the [sandbox reference](/reference/sandbox_reference/index.md). diff --git a/docs/docs/guides/guides/local_env/versions-updating.md b/docs/docs/guides/local_env/versions-updating.md similarity index 98% rename from docs/docs/guides/guides/local_env/versions-updating.md rename to docs/docs/guides/local_env/versions-updating.md index 0a133ee1359..cb322f82c43 100644 --- a/docs/docs/guides/guides/local_env/versions-updating.md +++ b/docs/docs/guides/local_env/versions-updating.md @@ -81,7 +81,7 @@ cd your/aztec/project aztec-builder update . --contract src/contract1 --contract src/contract2 ``` -The sandbox must be running for the update command to work. Make sure it is [installed and running](/reference/reference/sandbox_reference/index.md). +The sandbox must be running for the update command to work. Make sure it is [installed and running](/reference/sandbox_reference/index.md). Follow [updating Aztec.nr packages](#updating-aztecnr-packages) and [updating JavaScript packages](#updating-aztecjs-packages) guides. diff --git a/docs/docs/guides/guides/smart_contracts/_category_.json b/docs/docs/guides/smart_contracts/_category_.json similarity index 100% rename from docs/docs/guides/guides/smart_contracts/_category_.json rename to docs/docs/guides/smart_contracts/_category_.json diff --git a/docs/docs/guides/guides/smart_contracts/how_to_compile_contract.md b/docs/docs/guides/smart_contracts/how_to_compile_contract.md similarity index 91% rename from docs/docs/guides/guides/smart_contracts/how_to_compile_contract.md rename to docs/docs/guides/smart_contracts/how_to_compile_contract.md index ddf8cc86833..944e2dea6ed 100644 --- a/docs/docs/guides/guides/smart_contracts/how_to_compile_contract.md +++ b/docs/docs/guides/smart_contracts/how_to_compile_contract.md @@ -3,9 +3,9 @@ title: How to Compile a Contract sidebar_position: 3 --- -import Disclaimer from "../../../../src/components/Disclaimers/\_wip_disclaimer.mdx"; +import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; -Once you have written a contract in Aztec.nr, you will need to compile it into an [artifact](/aztec/aztec/concepts/smart_contracts/contract_structure.md) in order to use it. +Once you have written a contract in Aztec.nr, you will need to compile it into an [artifact](/aztec/concepts/smart_contracts/contract_structure.md) in order to use it. In this guide we will cover how to do so, both using the `aztec-nargo` command and programmatically. @@ -21,7 +21,7 @@ Run the `aztec-nargo compile` command within your contract project folder (the o aztec-nargo compile ``` -This will output a JSON [artifact](/aztec/aztec/concepts/smart_contracts/contract_structure.md) for each contract in the project to a `target` folder containing the Noir ABI artifacts. +This will output a JSON [artifact](/aztec/concepts/smart_contracts/contract_structure.md) for each contract in the project to a `target` folder containing the Noir ABI artifacts. :::note This command looks for `Nargo.toml` files by ascending up the parent directories, and will compile the top-most Nargo.toml file it finds. @@ -222,11 +222,11 @@ export class TokenContract extends ContractBase { } ``` -Read more about interacting with contracts using `aztec.js` [here](/getting_started/getting_started/aztecjs-getting-started.md). +Read more about interacting with contracts using `aztec.js` [here](/getting_started/aztecjs-getting-started.md). ### Aztec.nr interfaces -An Aztec.nr contract can [call a function](/guides/guides/smart_contracts/writing_contracts/call_functions.md) in another contract via `context.call_private_function` or `context.call_public_function`. However, this requires manually assembling the function selector and manually serializing the arguments, which is not type-safe. +An Aztec.nr contract can [call a function](/guides/smart_contracts/writing_contracts/call_functions.md) in another contract via `context.call_private_function` or `context.call_public_function`. However, this requires manually assembling the function selector and manually serializing the arguments, which is not type-safe. To make this easier, the compiler automatically generates interface structs that expose a convenience method for each function listed in a given contract artifact. These structs are intended to be used from another contract project that calls into the current one. @@ -260,7 +260,7 @@ contract FPC { } ``` -Read more about how to use the Aztec.nr interfaces [here](/aztec/aztec/concepts/smart_contracts/functions). +Read more about how to use the Aztec.nr interfaces [here](/aztec/concepts/smart_contracts/functions). :::info At the moment, the compiler generates these interfaces from already compiled ABIs, and not from source code. This means that you should not import a generated interface from within the same project as its source contract, or you risk circular references. diff --git a/docs/docs/guides/guides/smart_contracts/how_to_deploy_contract.md b/docs/docs/guides/smart_contracts/how_to_deploy_contract.md similarity index 84% rename from docs/docs/guides/guides/smart_contracts/how_to_deploy_contract.md rename to docs/docs/guides/smart_contracts/how_to_deploy_contract.md index 5811c261265..f9c2f851814 100644 --- a/docs/docs/guides/guides/smart_contracts/how_to_deploy_contract.md +++ b/docs/docs/guides/smart_contracts/how_to_deploy_contract.md @@ -5,13 +5,13 @@ sidebar_position: 4 # Deploying contracts -Once you have [compiled](/guides/guides/smart_contracts/how_to_compile_contract) your contracts you can proceed to deploying them using aztec.js which is a Typescript client to interact with the sandbox. +Once you have [compiled](/guides/smart_contracts/how_to_compile_contract) your contracts you can proceed to deploying them using aztec.js which is a Typescript client to interact with the sandbox. ## Prerequisites -- `aztec-nargo` installed (go to [Sandbox and CLI section](/reference/reference/sandbox_reference) for installation instructions) -- contract artifacts ready (go to [How to Compile Contract](/guides/guides/smart_contracts/how_to_compile_contract) for instructions on how to compile contracts) -- Aztec Sandbox running (go to [Sandbox section](/getting_started/getting_started) for instructions on how to install and run the sandbox) +- `aztec-nargo` installed (go to [Sandbox and CLI section](/reference/sandbox_reference) for installation instructions) +- contract artifacts ready (go to [How to Compile Contract](/guides/smart_contracts/how_to_compile_contract) for instructions on how to compile contracts) +- Aztec Sandbox running (go to [Sandbox section](/getting_started) for instructions on how to install and run the sandbox) ## Deploy @@ -29,7 +29,7 @@ Generate the typescript class: aztec-builder ./aztec-nargo/output/target/path -o src/artifacts ``` -This would create a typescript file like `Example.ts` in `./src/artifacts`. Read more on the [compiling page](/guides/guides/smart_contracts/how_to_compile_contract). +This would create a typescript file like `Example.ts` in `./src/artifacts`. Read more on the [compiling page](/guides/smart_contracts/how_to_compile_contract). Now you can import it to easily deploy and interact with the contract. diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/_category_.json b/docs/docs/guides/smart_contracts/writing_contracts/_category_.json similarity index 100% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/_category_.json rename to docs/docs/guides/smart_contracts/writing_contracts/_category_.json diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/call_functions.md b/docs/docs/guides/smart_contracts/writing_contracts/call_functions.md similarity index 65% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/call_functions.md rename to docs/docs/guides/smart_contracts/writing_contracts/call_functions.md index dcf5c8d2dd4..c026447e3dd 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/call_functions.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/call_functions.md @@ -4,7 +4,7 @@ sidebar_position: 2 --- -A contract is a collection of persistent [state variables](/aztec/aztec/concepts/storage/index.md), and [functions](/aztec/aztec/concepts/smart_contracts/functions) which may manipulate these variables. Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called. +A contract is a collection of persistent [state variables](/aztec/concepts/storage/index.md), and [functions](/aztec/concepts/smart_contracts/functions) which may manipulate these variables. Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called. ### Contract @@ -37,4 +37,4 @@ Here's a common layout for a basic Aztec.nr Contract project: ``` - See the vanilla Noir docs for [more info on packages](https://noir-lang.org/docs/noir/modules_packages_crates/crates_and_packages). -- You can review the structure of a complete contract in the token contract tutorial [here](/tutorials/tutorials/contract_tutorials/token_contract.md). +- You can review the structure of a complete contract in the token contract tutorial [here](/tutorials/contract_tutorials/token_contract.md). diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/_category_.json b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/_category_.json similarity index 100% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/_category_.json rename to docs/docs/guides/smart_contracts/writing_contracts/common_patterns/_category_.json diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/authwit.md similarity index 96% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md rename to docs/docs/guides/smart_contracts/writing_contracts/common_patterns/authwit.md index 6840366384b..9a31c6de1a5 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/authwit.md @@ -5,13 +5,13 @@ description: Developer Documentation to use Authentication Witness for authentic ## Prerequisite reading -- [Authwit](guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md) +- [Authwit](guides/smart_contracts/writing_contracts/common_patterns/authwit.md) ## Introduction Authentication Witness is a scheme for authentication actions on Aztec, so users can allow third-parties (eg protocols or other users) to execute an action on their behalf. -How it works logically is explained in the [concepts](guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md) but we will do a short recap here. +How it works logically is explained in the [concepts](guides/smart_contracts/writing_contracts/common_patterns/authwit.md) but we will do a short recap here. An authentication witness is defined for a specific action, such as allowing a Defi protocol to transfer funds on behalf of the user. An action is here something that could be explained as `A is allowed to perform X operation on behalf of B` and we define it as a hash computed as such: @@ -82,7 +82,7 @@ Both return the value `0xabf64ad4` (`IS_VALID` selector) for a successful authen As part of [Aztec.nr](https://aztec.nr), we are providing a library that can be used to implement authentication witness for your contracts. -This library also provides a basis for account implementations such that these can more easily implement authentication witness. For more on the wallets, see [writing an account contract](/tutorials/tutorials/write_accounts_contract.md). +This library also provides a basis for account implementations such that these can more easily implement authentication witness. For more on the wallets, see [writing an account contract](/tutorials/write_accounts_contract.md). For our purposes here (not building a wallet), the most important part of the library is the `auth` utility which exposes a couple of helper methods for computing the action hash, retrieving witnesses, validating them and emitting the nullifier. @@ -163,7 +163,7 @@ With private functions covered, how can we use this in a public function? Well, Authenticating an action in the public domain is quite similar to the private domain, with the difference that we are executing a function on the account contract to add the witness, if you recall, this is because we don't have access to the oracle in the public domain. -In the snippet below, this is done as a separate contract call, but can also be done as part of a batch as mentioned in the [Accounts concepts](guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md#what-about-public). +In the snippet below, this is done as a separate contract call, but can also be done as part of a batch as mentioned in the [Accounts concepts](guides/smart_contracts/writing_contracts/common_patterns/authwit.md#what-about-public). #include_code authwit_public_transfer_example /yarn-project/end-to-end/src/e2e_token_contract/transfer_public.test.ts typescript diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md similarity index 93% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md rename to docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md index a09038acc4c..70490891197 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/common_patterns/index.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/index.md @@ -40,7 +40,7 @@ Note - you could also create a note and send it to the user. The problem is ther You can't read public storage in private domain. But nevertheless reading public storage is desirable. There are two ways to achieve the desired effect: -1. For public values that change infrequently, you can use [shared state](/reference/reference/smart_contract_reference/storage/shared_state.md). +1. For public values that change infrequently, you can use [shared state](/reference/smart_contract_reference/storage/shared_state.md). 1. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.: @@ -82,13 +82,13 @@ Let's say you have some storage in public and want to move them into the private So you have to create a custom note in the public domain that is not encrypted by some owner - we call such notes a "TransparentNote" since it is created in public, anyone can see the amount and the note is not encrypted by some owner. -This pattern is discussed in detail in [writing a token contract section in the shield() method](/tutorials/tutorials/contract_tutorials/token_contract.md#redeem_shield). +This pattern is discussed in detail in [writing a token contract section in the shield() method](/tutorials/contract_tutorials/token_contract.md#redeem_shield). ### Discovering my notes -When you send someone a note, the note hash gets added to the [note hash tree](/aztec/aztec/concepts/storage/trees/index.md#note-hash-tree). To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes: +When you send someone a note, the note hash gets added to the [note hash tree](/aztec/concepts/storage/trees/index.md#note-hash-tree). To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes: -1. When sending someone a note, use `emit_encrypted_log` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](/guides/guides/smart_contracts/writing_contracts/how_to_emit_event) +1. When sending someone a note, use `emit_encrypted_log` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](/guides/smart_contracts/writing_contracts/how_to_emit_event) 2. Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`emit_encrypted_log` shouldn't be called in the public domain because everything is public), like in the previous section where we created a TransparentNote in public. #include_code pxe_add_note yarn-project/end-to-end/src/e2e_cheat_codes.test.ts typescript @@ -115,7 +115,7 @@ Hence, it's necessary to add a "randomness" field to your note to prevent such a ### L1 -- L2 interactions -Refer to [Token Portal tutorial on bridging tokens between L1 and L2](/tutorials/tutorials/contract_tutorials/advanced/token_bridge). This example shows how to: +Refer to [Token Portal tutorial on bridging tokens between L1 and L2](/tutorials/contract_tutorials/advanced/token_bridge). This example shows how to: 1. L1 -> L2 message flow 2. L2 -> L1 message flow @@ -151,6 +151,6 @@ PS: when calling from private to public, `msg_sender` is the contract address wh In the [Prevent the same user flow from happening twice using nullifier](#prevent-the-same-user-flow-from-happening-twice-using-nullifiers), we recommended using nullifiers. But what you put in the nullifier is also as important. -E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](/aztec/aztec/concepts/accounts/keys.md#nullifier-secrets). E.g.: +E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](/aztec/concepts/accounts/keys.md#nullifier-secrets). E.g.: #include_code nullifier /noir-projects/aztec-nr/value-note/src/value_note.nr rust diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_emit_event.md b/docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md similarity index 92% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_emit_event.md rename to docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md index 913497e3249..bd8f362bc8c 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_emit_event.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md @@ -25,7 +25,7 @@ Bellow are some ways how we could instantiate it after getting the information i #include_code instantiate-complete-address /yarn-project/circuits.js/src/structs/complete_address.test.ts rust -Then to register the recipient's [complete address](/aztec/aztec/concepts/accounts/keys.md#complete-address) in PXE we would call `registerRecipient` PXE endpoint using [Aztec.js](/aztec/aztec/core_components.md#aztecjs): +Then to register the recipient's [complete address](/aztec/concepts/accounts/keys.md#complete-address) in PXE we would call `registerRecipient` PXE endpoint using [Aztec.js](/aztec/core_components.md#aztecjs): #include_code register-recipient /yarn-project/aztec.js/src/wallet/create_recipient.ts rust @@ -60,7 +60,7 @@ They can be emitted by both public and private functions. :::danger - Emitting unencrypted events from private function is a significant privacy leak and it should be considered by the developer whether it is acceptable. -- Unencrypted events are currently **NOT** linked to the contract emitting them, so it is practically a [`debug_log`](/aztec/aztec/concepts/smart_contracts/oracles/index.md#a-few-useful-inbuilt-oracles). +- Unencrypted events are currently **NOT** linked to the contract emitting them, so it is practically a [`debug_log`](/aztec/concepts/smart_contracts/oracles/index.md#a-few-useful-inbuilt-oracles). ::: diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md b/docs/docs/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md similarity index 100% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md rename to docs/docs/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_prove_history.md b/docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md similarity index 91% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_prove_history.md rename to docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md index 0cd59d451f1..c6fbd2c2e16 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/how_to_prove_history.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md @@ -3,9 +3,9 @@ title: Using the Archive Tree sidebar_position: 4 --- -The Aztec Protocol uses an append-only Merkle tree to store hashes of the headers of all previous blocks in the chain as its leaves. This is known as an archive tree. You can learn more about how it works in the [concepts section](/aztec/aztec/concepts/storage/trees/index.md#archive-tree). +The Aztec Protocol uses an append-only Merkle tree to store hashes of the headers of all previous blocks in the chain as its leaves. This is known as an archive tree. You can learn more about how it works in the [concepts section](/aztec/concepts/storage/trees/index.md#archive-tree). -View the History lib reference [here](/reference/reference/smart_contract_reference/history_lib_reference.md). +View the History lib reference [here](/reference/smart_contract_reference/history_lib_reference.md). # History library @@ -30,7 +30,7 @@ Using this library, you can check that specific notes or nullifiers were part of - Prove a note was included in a specified block - Create a nullifier and prove it was not included in a specified block -For a more extensive reference, go to [the reference page](/reference/reference/smart_contract_reference/history_lib_reference.md). +For a more extensive reference, go to [the reference page](/reference/smart_contract_reference/history_lib_reference.md). ## 1. Import the `history` library from `aztec` @@ -98,4 +98,4 @@ You can also prove that a nullifier was not included in a specified block by usi ## Prove contract inclusion, public value inclusion, and use current state in lookups -To see what else you can do with the `history` library, check out the [reference](/reference/reference/smart_contract_reference/history_lib_reference.md). +To see what else you can do with the `history` library, check out the [reference](/reference/smart_contract_reference/history_lib_reference.md). diff --git a/docs/docs/guides/smart_contracts/writing_contracts/index.md b/docs/docs/guides/smart_contracts/writing_contracts/index.md new file mode 100644 index 00000000000..2c857ff0af3 --- /dev/null +++ b/docs/docs/guides/smart_contracts/writing_contracts/index.md @@ -0,0 +1,7 @@ +--- +title: Portals +--- + +A portal is a point of contact between L1 and a contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. + +As outlined in [Communication](/protocol-specs/l1-smart-contracts/index.md), an Aztec L2 contract does not have to be linked to a portal contract, but can specify an intended portal in storage. Note, that a portal doesn't actually need to be a contract, it could be any address on L1. diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/initializers.md b/docs/docs/guides/smart_contracts/writing_contracts/initializers.md similarity index 94% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/initializers.md rename to docs/docs/guides/smart_contracts/writing_contracts/initializers.md index 7c15e051fd1..3c0194132e2 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/initializers.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/initializers.md @@ -27,4 +27,4 @@ Initializers are commonly used to set an admin, such as this example: Here, the initializer is calling a public function. It can also call a private function. Learn more about calling functions from functions [here](./call_functions.md). -To see constructors in action, check out the [Aztec.nr getting started guide](/getting_started/getting_started/aztecnr-getting-started.md). +To see constructors in action, check out the [Aztec.nr getting started guide](/getting_started/aztecnr-getting-started.md). diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/portals/_category_.json b/docs/docs/guides/smart_contracts/writing_contracts/portals/_category_.json similarity index 100% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/portals/_category_.json rename to docs/docs/guides/smart_contracts/writing_contracts/portals/_category_.json diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md b/docs/docs/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md similarity index 97% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md rename to docs/docs/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md index 31ef4735f7c..027b1740b82 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md @@ -2,9 +2,9 @@ title: Communicating with L1 --- -Is this your first time hearing the word `Portal`? Check out the [concepts section](../../../../../protocol-specs/l1-smart-contracts/index.md). +Is this your first time hearing the word `Portal`? Check out the [concepts section](../../../../protocol-specs/l1-smart-contracts/index.md). -Follow the [token bridge tutorial](/tutorials/tutorials/contract_tutorials/advanced/token_bridge) for hands-on experience writing and deploying a Portal contract. +Follow the [token bridge tutorial](/tutorials/contract_tutorials/advanced/token_bridge) for hands-on experience writing and deploying a Portal contract. ## Passing data to the rollup @@ -42,7 +42,7 @@ Note that while the `secret` and the `content` are both hashed, they are actuall ### Token bridge example -Computing the `content` must currently be done manually, as we are still adding a number of bytes utilities. A good example exists within the [Token bridge example](../../../../../tutorials/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md#consume-the-l1-message). +Computing the `content` must currently be done manually, as we are still adding a number of bytes utilities. A good example exists within the [Token bridge example](/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md#consume-the-l1-message). #include_code claim_public /noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr rust diff --git a/docs/docs/guides/smart_contracts/writing_contracts/portals/index.md b/docs/docs/guides/smart_contracts/writing_contracts/portals/index.md new file mode 100644 index 00000000000..ddf0bfeb784 --- /dev/null +++ b/docs/docs/guides/smart_contracts/writing_contracts/portals/index.md @@ -0,0 +1,5 @@ +--- +title: Portals +--- + +A portal is a point of contact between L1 and a contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. Note, that a portal doesn't actually need to be a contract, it could be any address on L1. diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/_category_.json b/docs/docs/guides/smart_contracts/writing_contracts/storage/_category_.json similarity index 100% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/storage/_category_.json rename to docs/docs/guides/smart_contracts/writing_contracts/storage/_category_.json diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md b/docs/docs/guides/smart_contracts/writing_contracts/storage/index.md similarity index 75% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md rename to docs/docs/guides/smart_contracts/writing_contracts/storage/index.md index f6cc58cac40..7198612356d 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/index.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/storage/index.md @@ -4,9 +4,9 @@ title: Defining Storage On this page, you will learn how to define storage in your smart contract. -To learn more about how storage works in Aztec, read [the concepts](/guides/guides/smart_contracts/writing_contracts/storage/storage_slots). +To learn more about how storage works in Aztec, read [the concepts](/guides/smart_contracts/writing_contracts/storage/storage_slots). -[See the storage reference](/aztec/aztec/concepts/storage/index.md). +[See the storage reference](/aztec/concepts/storage/index.md). ```rust #[aztec(storage)] diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/notes.md b/docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md similarity index 92% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/storage/notes.md rename to docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md index da2a8e82fe6..41f93939383 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/notes.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md @@ -19,7 +19,7 @@ This page will focus on how private variables are implemented with Notes and sto #### Side-note about execution Under the hood, the Aztec protocol handles some important details around public and private function calls. Calls between them are asynchronous due to different execution contexts (local execution vs. node execution). -A detailed explanation of the transaction lifecycle can be found [here](/aztec/aztec/concepts/transactions.md#simple-example-of-the-private-transaction-lifecycle). +A detailed explanation of the transaction lifecycle can be found [here](/aztec/concepts/transactions.md#simple-example-of-the-private-transaction-lifecycle). ## Private state variables in Aztec State variables in an Aztec contract are defined inside a struct specifically named `Storage`, and must satisfy the [Note Interface](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/aztec-nr/aztec/src/note/note_interface.nr) and contain a [Note header](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/aztec-nr/aztec/src/note/note_header.nr). @@ -29,7 +29,7 @@ The Note header struct contains the contract address which the value is effectiv A couple of things to unpack here: #### Storage "slot" -Storage slots are more literal for public storage, a place where a value is stored. For private storage, a storage slot is logical (more [here](/aztec/aztec/concepts/storage/index.md#private-state-slots---slots-arent-real)). +Storage slots are more literal for public storage, a place where a value is stored. For private storage, a storage slot is logical (more [here](/aztec/concepts/storage/index.md#private-state-slots---slots-arent-real)). #### Silos The address of the contract is included in a Note's data to ensure that different contracts don't arrive at the same hash with an identical variable. This is handled in the protocol's execution. @@ -69,9 +69,9 @@ To update a value, its previous note hash(es) are nullified. The new note value ## Supplementary components Some optional background resources on notes can be found here: -- [High level network architecture](/aztec/aztec/core_components.md#high-level-network-architecture), specifically the Private Execution Environment -- [Transaction lifecycle (simple diagram)](/aztec/aztec/concepts/transactions.md#simple-example-of-the-private-transaction-lifecycle) -- [Public and Private state](/aztec/aztec/concepts/state_model) +- [High level network architecture](/aztec/core_components.md#high-level-network-architecture), specifically the Private Execution Environment +- [Transaction lifecycle (simple diagram)](/aztec/concepts/transactions.md#simple-example-of-the-private-transaction-lifecycle) +- [Public and Private state](/aztec/concepts/state_model) Notes touch several core components of the protocol, but we will focus on a the essentials first. @@ -126,10 +126,10 @@ Notice how the `add` function shows the simplicity of appending a new note to al ----- ### Apply -Try the [Token tutorial](/tutorials/tutorials/contract_tutorials/token_contract.md) to see what notes can achieve. In this section you will also find other tutorials using notes in different ways. +Try the [Token tutorial](/tutorials/contract_tutorials/token_contract.md) to see what notes can achieve. In this section you will also find other tutorials using notes in different ways. ### Further reading -- [Storage Trees](/aztec/aztec/concepts/storage/trees) +- [Storage Trees](/aztec/concepts/storage/trees) - [Proof of prior notes](../how_to_prove_history.md) - public/private reading of public/private proof of state (public or private) If you're curious about any of the following related topics, search the documentation for... diff --git a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/storage_slots.md b/docs/docs/guides/smart_contracts/writing_contracts/storage/storage_slots.md similarity index 89% rename from docs/docs/guides/guides/smart_contracts/writing_contracts/storage/storage_slots.md rename to docs/docs/guides/smart_contracts/writing_contracts/storage/storage_slots.md index ef53ad1b77d..32881114bd5 100644 --- a/docs/docs/guides/guides/smart_contracts/writing_contracts/storage/storage_slots.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/storage/storage_slots.md @@ -2,7 +2,7 @@ title: Storage slots --- -From the description of storage slots [in the Concepts](/guides/guides/smart_contracts/writing_contracts/storage/storage_slots) you will get an idea around the logic of storage slots. In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against. +From the description of storage slots [in the Concepts](/guides/smart_contracts/writing_contracts/storage/storage_slots) you will get an idea around the logic of storage slots. In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against. For the case of the example, we will look at what is inserted into the note hashes tree when adding a note in the Token contract. Specifically, we are looking at the last part of the `transfer` function: diff --git a/docs/docs/index.mdx b/docs/docs/index.mdx index 1957686f36e..db92b85619e 100644 --- a/docs/docs/index.mdx +++ b/docs/docs/index.mdx @@ -36,11 +36,11 @@ Aztec is: ### Learn 📚 -Start on the [Technical Overview page](/aztec/aztec/core_components) to read about how Aztec works. +Start on the [Technical Overview page](/aztec/core_components) to read about how Aztec works. ### Build 🧑‍💻 -Go to the [Getting Started section](/getting_started/getting_started) of the developer docs to get your hands dirty and start developing on Aztec. +Go to the [Getting Started section](/getting_started) of the developer docs to get your hands dirty and start developing on Aztec. #### Go deeper 🔬 @@ -48,4 +48,4 @@ Check out the [Awesome Aztec repo](https://github.com/AztecProtocol/awesome-azte Clone the [Aztec Starter repo](https://github.com/AztecProtocol/aztec-starter) to get a minimal project set up with Sandbox (local developer network), a simple contract and a test suite. -Jump into one of the [tutorials](/tutorials/tutorials/contract_tutorials/private_voting_contract.md) to learn how to build more complex applications on Aztec. +Jump into one of the [tutorials](/tutorials/contract_tutorials/private_voting_contract.md) to learn how to build more complex applications on Aztec. diff --git a/docs/docs/protocol-specs/cryptography/hashing/hashing.md b/docs/docs/protocol-specs/cryptography/hashing/hashing.md index 80a3bed1129..f1773cb63fd 100644 --- a/docs/docs/protocol-specs/cryptography/hashing/hashing.md +++ b/docs/docs/protocol-specs/cryptography/hashing/hashing.md @@ -14,7 +14,7 @@ To minimize the potential for collisions between distinct hashing contexts, all In the case of using Poseidon2 for hashing (which is the case for most hashing in the Aztec protocol), the string is converted from a big-endian byte representation into a `Field` element, and passed as a first argument into the hash. In the case of using non-algebraic hash functions (such as sha256), the string is converted from a big-endian byte representation into bits, and passed as the first bits into the hash. These details are conveyed more clearly as pseudocode in the relevant sections of the spec. -For some hashes there is further domain-separation. For example, [Merkle tree hashing](/aztec/aztec/concepts/storage/trees/index.md#layers) of the tree. +For some hashes there is further domain-separation. For example, [Merkle tree hashing](/aztec/concepts/storage/trees/index.md#layers) of the tree. ### Pseudo-randomness @@ -24,6 +24,6 @@ Pseudo-randomness is required in cases such as: - Fiat-Shamir challenge generation. - Expanding a random seed to generate additional randomness. - - See the derivation of [master secret keys](/aztec/aztec/concepts/accounts/keys.md#master-keys). + - See the derivation of [master secret keys](/aztec/concepts/accounts/keys.md#master-keys). - Deriving a nullifier, and siloing a nullifier. - - See [deriving a nullifier](/aztec/aztec/concepts/accounts/keys.md#deriving-a-nullifier-within-an-app-contract). + - See [deriving a nullifier](/aztec/concepts/accounts/keys.md#deriving-a-nullifier-within-an-app-contract). diff --git a/docs/docs/protocol-specs/state/tree-implementations.md b/docs/docs/protocol-specs/state/tree-implementations.md index 03f3657e95d..ec15a26fe1b 100644 --- a/docs/docs/protocol-specs/state/tree-implementations.md +++ b/docs/docs/protocol-specs/state/tree-implementations.md @@ -14,7 +14,7 @@ Indexed Merkle trees, introduced [here](https://eprint.iacr.org/2021/1263.pdf), With an Indexed Merkle tree, proving non-membership of a value `x` then requires a membership proof of the node with value lower than `x` and a next-highest value greater than `x`. The cost of this proof is proportional to the height of the tree, which can be set according to the expected number of elements to be stored in the tree. For comparison, a non-membership proof in a sparse tree requires a tree with height proportional to the size of the elements, so when working with 256-bit elements, 256 hashes are required for a proof. -Refer to [this page](/aztec/aztec/concepts/storage/trees/indexed_merkle_tree) for more details on how insertions, updates, and membership proofs are executed on an Indexed Merkle tree. +Refer to [this page](/aztec/concepts/storage/trees/indexed_merkle_tree) for more details on how insertions, updates, and membership proofs are executed on an Indexed Merkle tree. diff --git a/docs/docs/reference/reference/common_errors/_category_.json b/docs/docs/reference/common_errors/_category_.json similarity index 100% rename from docs/docs/reference/reference/common_errors/_category_.json rename to docs/docs/reference/common_errors/_category_.json diff --git a/docs/docs/reference/reference/common_errors/aztecnr-errors.md b/docs/docs/reference/common_errors/aztecnr-errors.md similarity index 92% rename from docs/docs/reference/reference/common_errors/aztecnr-errors.md rename to docs/docs/reference/common_errors/aztecnr-errors.md index dc0a9bf6510..71028ba9429 100644 --- a/docs/docs/reference/reference/common_errors/aztecnr-errors.md +++ b/docs/docs/reference/common_errors/aztecnr-errors.md @@ -12,11 +12,11 @@ All smart contracts written in Aztec.nr need the `aztec` dependency. In your `Na aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/aztec" } ``` -You can learn more about dependencies and their paths [here](/reference/reference/smart_contract_reference/dependencies.md). +You can learn more about dependencies and their paths [here](/reference/smart_contract_reference/dependencies.md). #### `backend has encountered an error` -This is likely due to a version mismatch or bad install of barretenberg. Try [reinstalling nargo](guides/guides/local_env/versions-updating.md#updating) or uninstalling barretenberg: +This is likely due to a version mismatch or bad install of barretenberg. Try [reinstalling nargo](guides/local_env/versions-updating.md#updating) or uninstalling barretenberg: ```bash nargo backend uninstall acvm-backend-barretenberg @@ -26,7 +26,7 @@ It will then reinstall when you compile. #### `Oracle callback {} not found` & `Oracle callback pedersenHash not found` -This can occasionally happen when there are breaking releases. Make sure that your dependencies in `Nargo.toml` are [updated to the latest release](/reference/reference/smart_contract_reference/dependencies.md). +This can occasionally happen when there are breaking releases. Make sure that your dependencies in `Nargo.toml` are [updated to the latest release](/reference/smart_contract_reference/dependencies.md). #### `error: Failed constraint: 'Public state writes only supported in public functions` @@ -47,7 +47,7 @@ This error occurs when you are trying to interact with a smart contract via an P To execute a transaction, the PXE needs to know the complete address of a contract and contract artifacts. -To address the error, add the contract to the PXE by calling [`pxe.addContracts(...)`](/aztec/aztec/concepts/pxe/index.md#addcontracts). +To address the error, add the contract to the PXE by calling [`pxe.addContracts(...)`](/aztec/concepts/pxe/index.md#addcontracts). #### `Simulation error: No public key registered for address 0x0. Register it by calling pxe.registerRecipient(...) or pxe.registerAccount(...)` diff --git a/docs/docs/reference/reference/common_errors/sandbox-errors.md b/docs/docs/reference/common_errors/sandbox-errors.md similarity index 89% rename from docs/docs/reference/reference/common_errors/sandbox-errors.md rename to docs/docs/reference/common_errors/sandbox-errors.md index 873b5de2db2..3ab918c7ac9 100644 --- a/docs/docs/reference/reference/common_errors/sandbox-errors.md +++ b/docs/docs/reference/common_errors/sandbox-errors.md @@ -2,7 +2,7 @@ title: Aztec Sandbox Errors --- -import Disclaimer from '../../../../src/components/Disclaimers/\_wip_disclaimer.mdx'; +import Disclaimer from '@site/src/components/Disclaimers/\_wip_disclaimer.mdx'; @@ -14,7 +14,7 @@ This section contains a list of errors you may encounter when using Aztec Sandbo ### Kernel Circuits -We have several versions of public and private kernels as explained in [our circuits section](/aztec/aztec/concepts/circuits). Certain things are only possible in certain versions of the circuits. So always ensure that the right version is being used for proof generation. For example, there is a specific version of the public kernel that only works if the previous kernel iteration was a private kernel. Similarly there is one that only works if the previous kernel was public. +We have several versions of public and private kernels as explained in [our circuits section](/aztec/concepts/circuits). Certain things are only possible in certain versions of the circuits. So always ensure that the right version is being used for proof generation. For example, there is a specific version of the public kernel that only works if the previous kernel iteration was a private kernel. Similarly there is one that only works if the previous kernel was public. Remember that for each function call (i.e. each item in the call stack), there is a new kernel iteration that gets run. @@ -87,7 +87,7 @@ Calling a private Aztec.nr function in a public kernel is not allowed. #### 3005 - PUBLIC_KERNEL\_\_NON_EMPTY_PRIVATE_CALL_STACK -Public functions are executed after all the private functions are (see [private-public execution](/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md)). As such, private call stack must be empty when executing in the public kernel. +Public functions are executed after all the private functions are (see [private-public execution](/aztec/concepts/smart_contracts/communication/public_private_calls.md)). As such, private call stack must be empty when executing in the public kernel. #### 3011 - PUBLIC_KERNEL\_\_CALCULATED_PRIVATE_CALL_HASH_AND_PROVIDED_PRIVATE_CALL_HASH_MISMATCH @@ -131,7 +131,7 @@ For static calls, no new note hashes or nullifiers can be added to the state. ### Rollup circuit errors -These are errors that occur when kernel proofs (transaction proofs) are sent to the rollup circuits to create an L2 block. See [rollup circuits](/aztec/aztec/concepts/circuits) for more information. +These are errors that occur when kernel proofs (transaction proofs) are sent to the rollup circuits to create an L2 block. See [rollup circuits](/aztec/concepts/circuits) for more information. #### 4007 - BASE\_\_INVALID_CHAIN_ID @@ -141,7 +141,7 @@ The L1 chain ID you used in your proof generation (for your private transaction) Same as [section 4007](#4007---base__invalid_chain_id) except the `version` refers to the version of the Aztec L2 instance. -Some scary bugs like `4003 - BASE__INVALID_NULLIFIER_SUBTREE` and `4004 - BASE__INVALID_NULLIFIER_RANGE` which are to do malformed nullifier trees (see [Indexed Merkle Trees](/aztec/aztec/concepts/storage/trees/indexed_merkle_tree)) etc may seem unrelated at a glance, but at a closer look may be because of some bug in an application's Aztec.nr code. Same is true for certain instances of `7008 - MEMBERSHIP_CHECK_FAILED`. +Some scary bugs like `4003 - BASE__INVALID_NULLIFIER_SUBTREE` and `4004 - BASE__INVALID_NULLIFIER_RANGE` which are to do malformed nullifier trees (see [Indexed Merkle Trees](/aztec/concepts/storage/trees/indexed_merkle_tree)) etc may seem unrelated at a glance, but at a closer look may be because of some bug in an application's Aztec.nr code. Same is true for certain instances of `7008 - MEMBERSHIP_CHECK_FAILED`. ### Generic circuit errors @@ -172,7 +172,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit - using invalid historical L1 to L2 message data tree state - inserting a subtree into the greater tree - we make a smaller merkle tree of all the new note hashes/nullifiers etc that were created in a transaction or in a rollup and add it to the bigger state tree. Before inserting, we do a merkle membership check to ensure that the index to insert at is indeed an empty subtree (otherwise we would be overwriting state). This can happen when `next_available_leaf_index` in the state tree's snapshot is wrong (it is fetched by the sequencer from the archiver). The error message should reveal which tree is causing this issue - - nullifier tree related errors - The nullifier tree uses an [Indexed Merkle Tree](/aztec/aztec/concepts/storage/trees/indexed_merkle_tree). It requires additional data from the archiver to know which is the nullifier in the tree that is just below the current nullifier before it can perform batch insertion. If the low nullifier is wrong, or the nullifier is in incorrect range, you may receive this error. + - nullifier tree related errors - The nullifier tree uses an [Indexed Merkle Tree](/aztec/concepts/storage/trees/indexed_merkle_tree). It requires additional data from the archiver to know which is the nullifier in the tree that is just below the current nullifier before it can perform batch insertion. If the low nullifier is wrong, or the nullifier is in incorrect range, you may receive this error. --- @@ -190,7 +190,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit - "\$\{treeName\} tree next available leaf index mismatch" - validating a tree's root is not enough. It also checks that the `next_available_leaf_index` is as expected. This is the next index we can insert new values into. Note that for the public data tree, this test is skipped since as it is a sparse tree unlike the others. -- "Public call stack size exceeded" - In Aztec, the sequencer executes all enqueued public functions in a transaction (to prevent race conditions - see [private-public execution](/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md)). This error says there are too many public functions requested. +- "Public call stack size exceeded" - In Aztec, the sequencer executes all enqueued public functions in a transaction (to prevent race conditions - see [private-public execution](/aztec/concepts/smart_contracts/communication/public_private_calls.md)). This error says there are too many public functions requested. - "Array size exceeds target length" - happens if you add more items than allowed by the constants set due to our circuit limitations (eg sending too many L2 to L1 messages or creating a function that exceeds the call stack length or returns more values than what Aztec.nr functions allow) diff --git a/docs/docs/reference/reference/debugging.md b/docs/docs/reference/debugging.md similarity index 100% rename from docs/docs/reference/reference/debugging.md rename to docs/docs/reference/debugging.md diff --git a/docs/docs/reference/reference/privacy_considerations.md b/docs/docs/reference/privacy_considerations.md similarity index 98% rename from docs/docs/reference/reference/privacy_considerations.md rename to docs/docs/reference/privacy_considerations.md index 0b0af36def6..7198d90df1d 100644 --- a/docs/docs/reference/reference/privacy_considerations.md +++ b/docs/docs/reference/privacy_considerations.md @@ -52,7 +52,7 @@ Any time a private function makes a call to a public function, information is le ### Crossing the public -> private boundary -If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. See [here](/reference/reference/smart_contract_reference/portals/inbox.md) for more details. +If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. See [here](/reference/smart_contract_reference/portals/inbox.md) for more details. ### Timing of transactions diff --git a/docs/docs/reference/reference/_category_.json b/docs/docs/reference/reference/_category_.json deleted file mode 100644 index 31e9f9521da..00000000000 --- a/docs/docs/reference/reference/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "label": "Reference", - "position": 4, - "collapsible": true, - "collapsed": true -} diff --git a/docs/docs/reference/reference/sandbox_reference/_category_.json b/docs/docs/reference/sandbox_reference/_category_.json similarity index 100% rename from docs/docs/reference/reference/sandbox_reference/_category_.json rename to docs/docs/reference/sandbox_reference/_category_.json diff --git a/docs/docs/reference/reference/sandbox_reference/cheat_codes.md b/docs/docs/reference/sandbox_reference/cheat_codes.md similarity index 99% rename from docs/docs/reference/reference/sandbox_reference/cheat_codes.md rename to docs/docs/reference/sandbox_reference/cheat_codes.md index 2817c900f27..493690c7466 100644 --- a/docs/docs/reference/reference/sandbox_reference/cheat_codes.md +++ b/docs/docs/reference/sandbox_reference/cheat_codes.md @@ -1,7 +1,7 @@ --- title: Cheat Codes --- -import Disclaimer from "../../../../src/components/Disclaimers/\_wip_disclaimer.mdx"; +import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; ## Introduction diff --git a/docs/docs/reference/reference/sandbox_reference/index.md b/docs/docs/reference/sandbox_reference/index.md similarity index 93% rename from docs/docs/reference/reference/sandbox_reference/index.md rename to docs/docs/reference/sandbox_reference/index.md index 68e12b66849..c0a12814740 100644 --- a/docs/docs/reference/reference/sandbox_reference/index.md +++ b/docs/docs/reference/sandbox_reference/index.md @@ -10,7 +10,7 @@ Aztec's Layer 2 network is a fully programmable combined private/public ZK rollu - Aztec Node - Aggregates all of the 'backend' services necessary for the building and publishing of rollups. This package is currently in development and much of the functionality is mocked. - [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/pxe) - Normally residing with the end client, this decrypts and stores a client's private state, executes simulations and submits transactions to the Aztec Node. -- [Aztec.js](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js) - Aztec's client library for interacting with the PXE (think Ethers.js). See the getting started guide [here](/getting_started/getting_started/aztecjs-getting-started.md). +- [Aztec.js](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js) - Aztec's client library for interacting with the PXE (think Ethers.js). See the getting started guide [here](/getting_started/aztecjs-getting-started.md). All of this is included in the Sandbox, with the exception of Aztec.js which you can use to interact with it. @@ -34,4 +34,4 @@ The current sandbox does not generate or verify proofs, but provides a working e ## Command line tools -Aztec-nargo and aztec-builder are command-line tool allowing you to compile smart contracts. See the [compiling contracts](/guides/guides/smart_contracts/how_to_compile_contract) page for more information. +Aztec-nargo and aztec-builder are command-line tool allowing you to compile smart contracts. See the [compiling contracts](/guides/smart_contracts/how_to_compile_contract) page for more information. diff --git a/docs/docs/reference/reference/sandbox_reference/sandbox-reference.md b/docs/docs/reference/sandbox_reference/sandbox-reference.md similarity index 82% rename from docs/docs/reference/reference/sandbox_reference/sandbox-reference.md rename to docs/docs/reference/sandbox_reference/sandbox-reference.md index 52c31cd9d3a..c02d4a7988c 100644 --- a/docs/docs/reference/reference/sandbox_reference/sandbox-reference.md +++ b/docs/docs/reference/sandbox_reference/sandbox-reference.md @@ -4,13 +4,65 @@ title: Sandbox Reference :::tip -For a quick start, follow the [guide](/getting_started/getting_started) to install the sandbox. +For a quick start, follow the [guide](/getting_started.md) to install the sandbox. ::: ## Manual Install -You can manually install the sandbox via the underlying script used in the [Aztec Boxes](getting_started/getting_started/index.md#run-the-npx-script). + +You can manually install the sandbox via the underlying script used in the [Aztec Boxes](/getting_started.md#run-the-npx-script). + +### Prerequisites + +- Node.js >= v18 (recommend installing with [nvm](https://github.com/nvm-sh/nvm)) +- Docker (visit [this page of the Docker docs](https://docs.docker.com/get-docker/) on how to install it) + +### Install the sandbox + +To install the latest Sandbox version, run: + +```bash +bash -i <(curl -s install.aztec.network) +``` + +This will install the following tools: + +- **aztec** - launches various infrastructure subsystems (sequencer, prover, pxe, etc). +- **aztec-nargo** - aztec's build of nargo, the noir compiler toolchain. +- **aztec-sandbox** - a wrapper around docker-compose that launches services needed for sandbox testing. +- **aztec-up** - a tool to upgrade the aztec toolchain to the latest, or specific versions. +- **aztec-builder** - A useful tool for projects to generate ABIs and update their dependencies. + +Once these have been installed, to start the sandbox, run: + +```bash +aztec-sandbox +``` + +### Have fun! + +**Congratulations, you have just installed and run the Aztec Sandbox!** + +```bash + /\ | | + / \ ___| |_ ___ ___ + / /\ \ |_ / __/ _ \/ __| + / ____ \ / /| || __/ (__ + /_/___ \_\/___|\__\___|\___| + +``` + +In the terminal, you will see some logs: +1. Sandbox version +2. Contract addresses of rollup contracts +3. PXE (private execution environment) setup logs +4. Initial accounts that are shipped with the sandbox and can be used in tests + + +## Manual Install + +You can manually install the sandbox via the underlying script used in the [Aztec Boxes](getting_started.md#run-the-npx-script). ### Prerequisites @@ -67,7 +119,7 @@ If you wish to run components of the Aztec network stack separately, you can use aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] --prover [proverOptions] ----p2p-bootstrap [p2pOptions] ``` -Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node.Eg if you want to run a PXE separately to a node, you can [read this guide](/aztec/aztec/concepts/pxe/index.md)/ +Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node.Eg if you want to run a PXE separately to a node, you can [read this guide](/aztec/concepts/pxe/index.md)/ ## Environment Variables @@ -165,7 +217,7 @@ To help with testing, the sandbox is shipped with a set of cheatcodes. Cheatcodes allow you to change the time of the Aztec block, load certain state or more easily manipulate Ethereum instead of having to write dedicated RPC calls to anvil or hardhat. -You can find the cheat code reference [here](/reference/reference/sandbox_reference/cheat_codes.md). +You can find the cheat code reference [here](/reference/sandbox_reference/cheat_codes.md). ## Contracts diff --git a/docs/docs/reference/reference/smart_contract_reference/_category_.json b/docs/docs/reference/smart_contract_reference/_category_.json similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/_category_.json rename to docs/docs/reference/smart_contract_reference/_category_.json diff --git a/docs/docs/reference/reference/smart_contract_reference/dependencies.md b/docs/docs/reference/smart_contract_reference/dependencies.md similarity index 92% rename from docs/docs/reference/reference/smart_contract_reference/dependencies.md rename to docs/docs/reference/smart_contract_reference/dependencies.md index 6b8f9510cab..39ca07ee85c 100644 --- a/docs/docs/reference/reference/smart_contract_reference/dependencies.md +++ b/docs/docs/reference/smart_contract_reference/dependencies.md @@ -19,7 +19,7 @@ This is the core Aztec library that is required for every Aztec.nr smart contrac authwit = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/authwit"} ``` -This allows you to use authentication witnesses in your contract. Find more about its usage [here](guides/guides/smart_contracts/writing_contracts/common_patterns/authwit.md). +This allows you to use authentication witnesses in your contract. Find more about its usage [here](guides/smart_contracts/writing_contracts/common_patterns/authwit.md). ## Address note @@ -51,4 +51,4 @@ This library contains types that are used in the Aztec protocol. Find it on [Git value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/value-note" } ``` -This is a library for a note that stores one arbitrary value. You can see an example of how it might be used in the [token contract tutorial](/tutorials/tutorials/contract_tutorials/token_contract.md). +This is a library for a note that stores one arbitrary value. You can see an example of how it might be used in the [token contract tutorial](/tutorials/contract_tutorials/token_contract.md). diff --git a/docs/docs/reference/reference/smart_contract_reference/globals.md b/docs/docs/reference/smart_contract_reference/globals.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/globals.md rename to docs/docs/reference/smart_contract_reference/globals.md diff --git a/docs/docs/reference/reference/smart_contract_reference/history_lib_reference.md b/docs/docs/reference/smart_contract_reference/history_lib_reference.md similarity index 98% rename from docs/docs/reference/reference/smart_contract_reference/history_lib_reference.md rename to docs/docs/reference/smart_contract_reference/history_lib_reference.md index 86563bb7074..64f41b03086 100644 --- a/docs/docs/reference/reference/smart_contract_reference/history_lib_reference.md +++ b/docs/docs/reference/smart_contract_reference/history_lib_reference.md @@ -21,7 +21,7 @@ Note inclusion proves that a note existed (its hash was included in a note hash ## prove_note_commitment_inclusion -A **commitment**, also referred to as a **note hash** is a public acknowledgment of the existence of a note without revealing the content of the note. You can learn more about how to compress a note to a note hash [here](/aztec/aztec/concepts/storage/trees/index.md#example-note). +A **commitment**, also referred to as a **note hash** is a public acknowledgment of the existence of a note without revealing the content of the note. You can learn more about how to compress a note to a note hash [here](/aztec/concepts/storage/trees/index.md#example-note). `prove_note_commitment_inclusion` takes 2 parameters: diff --git a/docs/docs/reference/reference/smart_contract_reference/index.md b/docs/docs/reference/smart_contract_reference/index.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/index.md rename to docs/docs/reference/smart_contract_reference/index.md diff --git a/docs/docs/reference/reference/smart_contract_reference/portals/_category_.json b/docs/docs/reference/smart_contract_reference/portals/_category_.json similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/portals/_category_.json rename to docs/docs/reference/smart_contract_reference/portals/_category_.json diff --git a/docs/docs/reference/reference/smart_contract_reference/portals/data_structures.md b/docs/docs/reference/smart_contract_reference/portals/data_structures.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/portals/data_structures.md rename to docs/docs/reference/smart_contract_reference/portals/data_structures.md diff --git a/docs/docs/reference/reference/smart_contract_reference/portals/inbox.md b/docs/docs/reference/smart_contract_reference/portals/inbox.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/portals/inbox.md rename to docs/docs/reference/smart_contract_reference/portals/inbox.md diff --git a/docs/docs/reference/reference/smart_contract_reference/portals/outbox.md b/docs/docs/reference/smart_contract_reference/portals/outbox.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/portals/outbox.md rename to docs/docs/reference/smart_contract_reference/portals/outbox.md diff --git a/docs/docs/reference/reference/smart_contract_reference/portals/registry.md b/docs/docs/reference/smart_contract_reference/portals/registry.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/portals/registry.md rename to docs/docs/reference/smart_contract_reference/portals/registry.md diff --git a/docs/docs/reference/reference/smart_contract_reference/storage/_category_.json b/docs/docs/reference/smart_contract_reference/storage/_category_.json similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/storage/_category_.json rename to docs/docs/reference/smart_contract_reference/storage/_category_.json diff --git a/docs/docs/reference/reference/smart_contract_reference/storage/index.md b/docs/docs/reference/smart_contract_reference/storage/index.md similarity index 81% rename from docs/docs/reference/reference/smart_contract_reference/storage/index.md rename to docs/docs/reference/smart_contract_reference/storage/index.md index 267b71f8b08..8e8cfb0472d 100644 --- a/docs/docs/reference/reference/smart_contract_reference/storage/index.md +++ b/docs/docs/reference/smart_contract_reference/storage/index.md @@ -4,8 +4,8 @@ title: Storage Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its hybrid, privacy-first architecture, the management of this storage is more complex than other blockchains like Ethereum. -To learn how to define a storage struct, read [this guide](/guides/guides/smart_contracts/writing_contracts/storage). -To learn more about storage slots, read [this explainer](/guides/guides/smart_contracts/writing_contracts/storage/storage_slots). +To learn how to define a storage struct, read [this guide](/guides/smart_contracts/writing_contracts/storage). +To learn more about storage slots, read [this explainer](/guides/smart_contracts/writing_contracts/storage/storage_slots). You control this storage in Aztec using a struct annotated with `#[aztec(storage)]`. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. @@ -26,7 +26,7 @@ On this and the following pages in this section, you’ll learn: Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data or note viewing key with). -Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (/aztec/aztec/concepts/state_model/index.md) and [private/public execution](/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md)) for more background. +Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (/aztec/aztec/concepts/state_model/index.md) and [private/public execution](/aztec/concepts/smart_contracts/communication/public_private_calls.md)) for more background. ## Storage struct @@ -46,7 +46,7 @@ A `map` is a state variable that "maps" a key to a value. It can be used with pr In Aztec.nr, keys are always `Field`s, or types that can be serialized as Fields, and values can be any type - even other maps. `Field`s are finite field elements, but you can think of them as integers. ::: -It includes a [`Context`](/aztec/aztec/concepts/smart_contracts/functions/context) to specify the private or public domain, a `storage_slot` to specify where in storage the map is stored, and a `start_var_constructor` which tells the map how it should operate on the underlying type. This includes how to serialize and deserialize the type, as well as how commitments and nullifiers are computed for the type if it's private. +It includes a [`Context`](/aztec/concepts/smart_contracts/functions/context) to specify the private or public domain, a `storage_slot` to specify where in storage the map is stored, and a `start_var_constructor` which tells the map how it should operate on the underlying type. This includes how to serialize and deserialize the type, as well as how commitments and nullifiers are computed for the type if it's private. You can view the implementation in the Aztec.nr library [here](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/aztec-nr). @@ -54,7 +54,7 @@ You can have multiple `map`s in your contract that each have a different underly ### `new` -When declaring the storage for a map, we use the `Map::new()` constructor. As seen below, this takes the `storage_slot` and the `start_var_constructor` along with the [`Context`](/aztec/aztec/concepts/smart_contracts/functions/context). +When declaring the storage for a map, we use the `Map::new()` constructor. As seen below, this takes the `storage_slot` and the `start_var_constructor` along with the [`Context`](/aztec/concepts/smart_contracts/functions/context). We will see examples of map constructors for public and private variables in later sections. @@ -94,6 +94,6 @@ require(minters[msg.sender], "caller is not minter"); ## Concepts mentioned -- [State Model](/aztec/aztec/concepts/state_model/index.md) -- [Public-private execution](/aztec/aztec/concepts/smart_contracts/communication/public_private_calls.md) -- [Function Contexts](/aztec/aztec/concepts/smart_contracts/functions/context) +- [State Model](/aztec/concepts/state_model/index.md) +- [Public-private execution](/aztec/concepts/smart_contracts/communication/public_private_calls.md) +- [Function Contexts](/aztec/concepts/smart_contracts/functions/context) diff --git a/docs/docs/reference/reference/smart_contract_reference/storage/private_state.md b/docs/docs/reference/smart_contract_reference/storage/private_state.md similarity index 96% rename from docs/docs/reference/reference/smart_contract_reference/storage/private_state.md rename to docs/docs/reference/smart_contract_reference/storage/private_state.md index f1c3619899d..bed799ff641 100644 --- a/docs/docs/reference/reference/smart_contract_reference/storage/private_state.md +++ b/docs/docs/reference/smart_contract_reference/storage/private_state.md @@ -4,15 +4,15 @@ title: Private State On this page we will look at how to manage private state in Aztec contracts. We will look at how to declare private state, how to read and write to it, and how to use it in your contracts. -For a higher level overview of the state model in Aztec, see the [hybrid state model](/aztec/aztec/concepts/state_model/index.md) page. +For a higher level overview of the state model in Aztec, see the [hybrid state model](/aztec/concepts/state_model/index.md) page. ## Overview In contrast to public state, private state is persistent state that is **not** visible to the whole world. Depending on the logic of the smart contract, a private state variable's current value will only be known to one entity, or a closed group of entities. -The value of a private state variable can either be shared via an [encrypted log](/guides/guides/smart_contracts/writing_contracts/how_to_emit_event#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. +The value of a private state variable can either be shared via an [encrypted log](/guides/smart_contracts/writing_contracts/how_to_emit_event#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. -Aztec private state follows a [utxo](https://en.wikipedia.org/wiki/Unspent_transaction_output)-based model. That is, a private state's current value is represented as one or many [notes](/aztec/aztec/concepts/storage/trees/index.md). +Aztec private state follows a [utxo](https://en.wikipedia.org/wiki/Unspent_transaction_output)-based model. That is, a private state's current value is represented as one or many [notes](/aztec/concepts/storage/trees/index.md). To greatly simplify the experience of writing private state, Aztec.nr provides three different types of private state variable: @@ -184,7 +184,7 @@ Functionally similar to `get_note`, but executed unconstrained and can be used b You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/set.nr). -And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](/guides/guides/smart_contracts/writing_contracts/call_functions.md). +And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](/guides/smart_contracts/writing_contracts/call_functions.md). #include_code storage-set-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust @@ -200,13 +200,13 @@ We can initialize the set as follows: Allows us to modify the storage by inserting a note into the `PrivateSet`. -A hash of the note will be generated, and inserted into the note hash tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an [encrypted log](/guides/guides/smart_contracts/writing_contracts/how_to_emit_event#encrypted-events), or offchain via web2, or completely offline. +A hash of the note will be generated, and inserted into the note hash tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an [encrypted log](/guides/smart_contracts/writing_contracts/how_to_emit_event#encrypted-events), or offchain via web2, or completely offline. #include_code insert /noir-projects/aztec-nr/easy-private-state/src/easy_private_uint.nr rust ### `insert_from_public` -The `insert_from_public` allow public function to insert notes into private storage. This is very useful when we want to support private function calls that have been initiated in public, such as shielding in the [example token contract](/tutorials/tutorials/contract_tutorials/token_contract.md#shield). +The `insert_from_public` allow public function to insert notes into private storage. This is very useful when we want to support private function calls that have been initiated in public, such as shielding in the [example token contract](/tutorials/contract_tutorials/token_contract.md#shield). The usage is similar to using the `insert` method with the difference that this one is called in public functions. @@ -248,7 +248,7 @@ This function requires a `NoteViewerOptions`. The `NoteViewerOptions` is essenti ## `NoteGetterOptions` -`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a [data oracle](/aztec/aztec/concepts/smart_contracts/oracles/index.md). Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. +`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a [data oracle](/aztec/concepts/smart_contracts/oracles/index.md). Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr). diff --git a/docs/docs/reference/reference/smart_contract_reference/storage/public_state.md b/docs/docs/reference/smart_contract_reference/storage/public_state.md similarity index 89% rename from docs/docs/reference/reference/smart_contract_reference/storage/public_state.md rename to docs/docs/reference/smart_contract_reference/storage/public_state.md index 3b04b61747a..f30e256659d 100644 --- a/docs/docs/reference/reference/smart_contract_reference/storage/public_state.md +++ b/docs/docs/reference/smart_contract_reference/storage/public_state.md @@ -4,7 +4,7 @@ title: Public State On this page we will look at how to manage public state in Aztec contracts. We will look at how to declare public state, how to read and write to it, and how to use it in your contracts. -For a higher level overview of the state model in Aztec, see the [state model](/aztec/aztec/concepts/state_model/index.md) page. +For a higher level overview of the state model in Aztec, see the [state model](/aztec/concepts/state_model/index.md) page. ## `PublicMutable` @@ -13,7 +13,7 @@ The `PublicMutable` (formerly known as `PublicState`) struct is generic over the #include_code serialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust #include_code deserialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust -The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out _where_ in storage the variable is located. Notice that while we don't have the exact same [state model](/aztec/aztec/concepts/state_model/index.md) as EVM chains it will look similar from the contract developers point of view. +The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out _where_ in storage the variable is located. Notice that while we don't have the exact same [state model](/aztec/concepts/state_model/index.md) as EVM chains it will look similar from the contract developers point of view. You can find the details of `PublicMutable` in the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr). @@ -25,7 +25,7 @@ An example using a larger struct can be found in the [lending example](https://g ### `new` -When declaring the storage for `T` as a persistent public storage variable, we use the `PublicMutable::new()` constructor. As seen below, this takes the `storage_slot` and the `serialization_methods` as arguments along with the [`Context`](/aztec/aztec/concepts/smart_contracts/functions/context), which in this case is used to share interface with other structures. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr). +When declaring the storage for `T` as a persistent public storage variable, we use the `PublicMutable::new()` constructor. As seen below, this takes the `storage_slot` and the `serialization_methods` as arguments along with the [`Context`](/aztec/concepts/smart_contracts/functions/context), which in this case is used to share interface with other structures. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr). #### Single value example diff --git a/docs/docs/reference/reference/smart_contract_reference/storage/shared_state.md b/docs/docs/reference/smart_contract_reference/storage/shared_state.md similarity index 100% rename from docs/docs/reference/reference/smart_contract_reference/storage/shared_state.md rename to docs/docs/reference/smart_contract_reference/storage/shared_state.md diff --git a/docs/docs/tutorials/_category_.json b/docs/docs/tutorials/_category_.json index 1285823106e..02c7361fd8a 100644 --- a/docs/docs/tutorials/_category_.json +++ b/docs/docs/tutorials/_category_.json @@ -1,6 +1,6 @@ { "label": "Tutorials", - "position": 2, + "position": 1, "collapsible": true, "collapsed": true } diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/_category_.json b/docs/docs/tutorials/contract_tutorials/_category_.json similarity index 100% rename from docs/docs/tutorials/tutorials/contract_tutorials/_category_.json rename to docs/docs/tutorials/contract_tutorials/_category_.json diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/_category_.json b/docs/docs/tutorials/contract_tutorials/advanced/_category_.json similarity index 100% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/_category_.json rename to docs/docs/tutorials/contract_tutorials/advanced/_category_.json diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/_category_.json b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/_category_.json similarity index 100% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/_category_.json rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/_category_.json diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/depositing_to_aztec.md b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/depositing_to_aztec.md similarity index 100% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/depositing_to_aztec.md rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/depositing_to_aztec.md diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/index.md b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/index.md similarity index 97% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/index.md rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/index.md index 7d3880595a2..3331911f850 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/index.md +++ b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/index.md @@ -43,7 +43,7 @@ The goal for this tutorial is to create functionality such that a token can be b This is just a reference implementation for educational purposes only. It has not been through an in-depth security audit. -Let’s assume a token exists on Ethereum and Aztec (see a [guide on writing a token contract on Aztec here](/tutorials/tutorials/contract_tutorials/token_contract)). +Let’s assume a token exists on Ethereum and Aztec (see a [guide on writing a token contract on Aztec here](/tutorials/contract_tutorials/token_contract)). We will build: diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md similarity index 98% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md index 0aef8d37fef..f3b6aadd52d 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md +++ b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/minting_on_aztec.md @@ -47,6 +47,6 @@ If the content hashes were constructed similarly for `mint_private` and `mint_pu While we mint the tokens on L2, we _still don’t actually mint them to a certain address_. Instead we continue to pass the `secret_hash_for_redeeming_minted_notes` like we did on L1. This means that a user could reveal their secret for L2 message consumption for anyone to mint tokens on L2 but they can redeem these notes at a later time. **This enables a paradigm where an app can manage user’s secrets for L2 message consumption on their behalf**. **The app or any external party can also mint tokens on the user’s behalf should they be comfortable with leaking the secret for L2 Message consumption.** This doesn’t leak any new information to the app because their smart contract on L1 knew that a user wanted to move some amount of tokens to L2. The app still doesn’t know which address on L2 the user wants these notes to be in, but they can mint tokens nevertheless on their behalf. -To mint tokens privately, `claim_private` calls an internal function `_call_mint_on_token()` which then calls [token.mint_private()](/tutorials/tutorials/contract_tutorials/token_contract.md#redeem_shield). +To mint tokens privately, `claim_private` calls an internal function `_call_mint_on_token()` which then calls [token.mint_private()](/tutorials/contract_tutorials/token_contract.md#redeem_shield). In the next step we will see how we can cancel a message. diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/setup.md b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/setup.md similarity index 99% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/setup.md rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/setup.md index 1c214be6efb..78fe396dc07 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/setup.md +++ b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/setup.md @@ -18,7 +18,7 @@ We recommend going through this setup to fully understand where things live. - [node v18+](https://github.com/tj/n) - [docker](https://docs.docker.com/) - [Aztec sandbox](https://docs.aztec.network/developers/getting_started/sandbox) - you should have this running before starting the tutorial -- [Aztec CLI](/getting_started/getting_started) +- [Aztec CLI](/getting_started) ```bash /bin/sh -c "$(curl -fsSL 'https://sandbox.aztec.network')" diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/typescript_glue_code.md b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/typescript_glue_code.md similarity index 100% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/typescript_glue_code.md rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/typescript_glue_code.md diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md similarity index 91% rename from docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md rename to docs/docs/tutorials/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md index bf4034a6ca9..3c5c8b4008e 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md +++ b/docs/docs/tutorials/contract_tutorials/advanced/token_bridge/withdrawing_to_l1.md @@ -17,9 +17,9 @@ For this to work we import the `get_withdraw_content_hash` helper function from The `exit_to_l1_public` function enables anyone to withdraw their L2 tokens back to L1 publicly. This is done by burning tokens on L2 and then creating an L2->L1 message. 1. Like with our deposit function, we need to create the L2 to L1 message. The content is the _amount_ to burn, the recipient address, and who can execute the withdraw on the L1 portal on behalf of the user. It can be `0x0` for anyone, or a specified address. -2. `context.message_portal()` passes this content to the [kernel circuit](/aztec/aztec/concepts/circuits/kernels/public_kernel.md) which creates the proof for the transaction. The kernel circuit then adds the sender (the L2 address of the bridge + version of aztec) and the recipient (the portal to the L2 address + the chain ID of L1) under the hood, to create the message which gets added as part of the transaction data published by the sequencer and is stored in the outbox for consumption. +2. `context.message_portal()` passes this content to the [kernel circuit](/aztec/concepts/circuits/kernels/public_kernel.md) which creates the proof for the transaction. The kernel circuit then adds the sender (the L2 address of the bridge + version of aztec) and the recipient (the portal to the L2 address + the chain ID of L1) under the hood, to create the message which gets added as part of the transaction data published by the sequencer and is stored in the outbox for consumption. 3. The `context.message_portal()` takes the recipient and content as input, and will insert a message into the outbox. We set the recipient to be the portal address read from storage of the contract. -4. Finally, you also burn the tokens on L2! Note that it burning is done at the end to follow the check effects interaction pattern. Note that the caller has to first approve the bridge contract to burn tokens on its behalf. Refer to [burn_public function on the token contract](/tutorials/tutorials/contract_tutorials/token_contract.md#authorizing-token-spends). +4. Finally, you also burn the tokens on L2! Note that it burning is done at the end to follow the check effects interaction pattern. Note that the caller has to first approve the bridge contract to burn tokens on its behalf. Refer to [burn_public function on the token contract](/tutorials/contract_tutorials/token_contract.md#authorizing-token-spends). - We burn the tokens from the `msg_sender()`. Otherwise, a malicious user could burn someone else’s tokens and mint tokens on L1 to themselves. One could add another approval flow on the bridge but that might make it complex for other applications to call the bridge. ## Withdrawing Privately diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/crowdfunding_contract.md b/docs/docs/tutorials/contract_tutorials/crowdfunding_contract.md similarity index 96% rename from docs/docs/tutorials/tutorials/contract_tutorials/crowdfunding_contract.md rename to docs/docs/tutorials/contract_tutorials/crowdfunding_contract.md index 1e7edbaff58..7147853ac5b 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/crowdfunding_contract.md +++ b/docs/docs/tutorials/contract_tutorials/crowdfunding_contract.md @@ -76,7 +76,7 @@ Replace the example functions with an initializer that takes the required campai } ``` -More about initializers [here](/guides/guides/smart_contracts/writing_contracts/initializers.md). +More about initializers [here](/guides/smart_contracts/writing_contracts/initializers.md). #### Dependencies @@ -184,7 +184,7 @@ token = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_ With the dependency already `use`d at the start of the contract, the token contract can be called to make the transfer from msg sender to this contract. :::note -The user must have authorised this action (concept [here](/aztec/aztec/concepts/accounts#authorizing-actions)), example use of `createAuthWit` in 'full donor flow' test [here](../../../../../yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts). +The user must have authorised this action (concept [here](/aztec/concepts/accounts#authorizing-actions)), example use of `createAuthWit` in 'full donor flow' test [here](../../../../yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts). ::: #### Creating and storing a private receipt note diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/private_voting_contract.md b/docs/docs/tutorials/contract_tutorials/private_voting_contract.md similarity index 82% rename from docs/docs/tutorials/tutorials/contract_tutorials/private_voting_contract.md rename to docs/docs/tutorials/contract_tutorials/private_voting_contract.md index 10a211912d7..5815d037c26 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/private_voting_contract.md +++ b/docs/docs/tutorials/contract_tutorials/private_voting_contract.md @@ -21,7 +21,7 @@ To keep things simple, we won't create ballots or allow for delegate voting. ## Prerequisites -- You have followed the [quickstart](/getting_started/getting_started) to install `aztec-nargo` and `aztec-sandbox`. +- You have followed the [quickstart](/getting_started) to install `aztec-nargo` and `aztec-sandbox`. - Running Aztec Sandbox ## Set up a project @@ -110,9 +110,9 @@ Create a private function called `cast_vote`: #include_code cast_vote noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -In this function, we do not create a nullifier with the address directly. This would leak privacy as it would be easy to reverse-engineer. We must add some randomness or some form of secret, like [nullifier secrets](/aztec/aztec/concepts/accounts/keys.md#nullifier-secrets). +In this function, we do not create a nullifier with the address directly. This would leak privacy as it would be easy to reverse-engineer. We must add some randomness or some form of secret, like [nullifier secrets](/aztec/concepts/accounts/keys.md#nullifier-secrets). -To do this, we make an [oracle call](/aztec/aztec/concepts/smart_contracts/oracles/index.md) to fetch the caller's secret key, hash it to create a nullifier, and push the nullifier to Aztec. The `secret.high` and `secret.low` values here refer to how we divide a large [Grumpkin scalar](https://github.com/AztecProtocol/aztec-packages/blob/7fb35874eae3f2cad5cb922282a619206573592c/noir/noir_stdlib/src/grumpkin_scalar.nr) value into its higher and lower parts. This allows for faster cryptographic computations so our hash can still be secure but is calculated faster. +To do this, we make an [oracle call](/aztec/concepts/smart_contracts/oracles/index.md) to fetch the caller's secret key, hash it to create a nullifier, and push the nullifier to Aztec. The `secret.high` and `secret.low` values here refer to how we divide a large [Grumpkin scalar](https://github.com/AztecProtocol/aztec-packages/blob/7fb35874eae3f2cad5cb922282a619206573592c/noir/noir_stdlib/src/grumpkin_scalar.nr) value into its higher and lower parts. This allows for faster cryptographic computations so our hash can still be secure but is calculated faster. After pushing the nullifier, we update the `tally` to reflect this vote. As we know from before, a private function cannot update public state directly, so we are calling a public function. @@ -132,7 +132,7 @@ We will create a function that anyone can call that will return the number of vo #include_code get_vote noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -We set it as `unconstrained` and do not annotate it because it is only reading from state. You can read more about unconstrained functions [here](/aztec/aztec/concepts/pxe/acir_simulator.md#unconstrained-functions). +We set it as `unconstrained` and do not annotate it because it is only reading from state. You can read more about unconstrained functions [here](/aztec/concepts/pxe/acir_simulator.md#unconstrained-functions). ## Allowing an admin to end a voting period @@ -154,18 +154,18 @@ aztec-nargo compile This will create a new directory called `target` and a JSON artifact inside it. -Once it is compiled you can [deploy](/reference/reference/sandbox_reference/index.md). +Once it is compiled you can [deploy](/reference/sandbox_reference/index.md). ```bash aztec-builder target -o src/artifacts ``` -Once it is compiled you can [deploy](/guides/guides/smart_contracts/how_to_deploy_contract.md) it to the sandbox. This is out of scope for this tutorial but you can learn how to do this in the [Aztec.js getting-started guide](/getting_started/getting_started/aztecjs-getting-started.md). +Once it is compiled you can [deploy](/guides/smart_contracts/how_to_deploy_contract.md) it to the sandbox. This is out of scope for this tutorial but you can learn how to do this in the [Aztec.js getting-started guide](/getting_started/aztecjs-getting-started.md). ## Next steps Now you have learned the foundations of Aztec smart contracts, you can start to play around with some more advanced features. Some ideas: - Add some more features into this contract, like the admin can distribute votes, people can delegate their votes, or voteIds can have more data like names, descriptions, etc -- Create a frontend for this contract using [Aztec.js](/getting_started/getting_started/aztecjs-getting-started.md). -- Go to the [next tutorial](/tutorials/tutorials/contract_tutorials/token_contract.md) and learn how to write a token contract +- Create a frontend for this contract using [Aztec.js](/getting_started/aztecjs-getting-started.md). +- Go to the [next tutorial](/tutorials/contract_tutorials/token_contract.md) and learn how to write a token contract diff --git a/docs/docs/tutorials/tutorials/contract_tutorials/token_contract.md b/docs/docs/tutorials/contract_tutorials/token_contract.md similarity index 96% rename from docs/docs/tutorials/tutorials/contract_tutorials/token_contract.md rename to docs/docs/tutorials/contract_tutorials/token_contract.md index 18b32e3db9d..cac8dc0a4d1 100644 --- a/docs/docs/tutorials/tutorials/contract_tutorials/token_contract.md +++ b/docs/docs/tutorials/contract_tutorials/token_contract.md @@ -21,7 +21,7 @@ We are going to start with a blank project and fill in the token contract source ## Requirements -You will need to have `aztec-nargo` installed in order to compile Aztec.nr contracts. See the [sandbox reference](/reference/reference/sandbox_reference/index.md) for installation instructions. +You will need to have `aztec-nargo` installed in order to compile Aztec.nr contracts. See the [sandbox reference](/reference/sandbox_reference/index.md) for installation instructions. You should also install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) for VS Code. @@ -151,7 +151,7 @@ These are functions that have transparent logic, will execute in a publicly veri ### Private functions -These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data [commitments](https://en.wikipedia.org/wiki/Commitment_scheme) and [nullifiers](/aztec/aztec/concepts/storage/trees/index.md#nullifier-tree), so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. +These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data [commitments](https://en.wikipedia.org/wiki/Commitment_scheme) and [nullifiers](/aztec/concepts/storage/trees/index.md#nullifier-tree), so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. - `redeem_shield` enables accounts to claim tokens that have been made private via `mint_private` or `shield` by providing the secret - `unshield` enables an account to send tokens from their private balance to any other account's public balance @@ -209,7 +209,7 @@ We are importing: - `compute_secret_hash` that will help with the shielding and unshielding, allowing someone to claim a token from private to public - Types for storing note types -For more detail on execution contexts, see [Contract Communication](/aztec/aztec/concepts/smart_contracts/communication). +For more detail on execution contexts, see [Contract Communication](/aztec/concepts/smart_contracts/communication). ### Types files @@ -219,7 +219,7 @@ The main thing to note from this types folder is the `TransparentNote` definitio ### Note on private state -Private state in Aztec is all [UTXOs](/aztec/aztec/concepts/storage/index.md) to learn more about public and private state in Aztec. +Private state in Aztec is all [UTXOs](/aztec/concepts/storage/index.md) to learn more about public and private state in Aztec. ## Contract Storage @@ -238,7 +238,7 @@ Reading through the storage variables: - `pending_shields` is a `PrivateSet` of `TransparentNote`s stored in private state. What is stored publicly is a set of commitments to `TransparentNote`s. - `public_balances` is a mapping of Aztec addresses in public state and represents the publicly viewable balances of accounts. -You can read more about it [here](/aztec/aztec/concepts/storage/index.md). +You can read more about it [here](/aztec/concepts/storage/index.md). ## Functions @@ -423,7 +423,7 @@ A getter function for checking the public balance of the provided Aztec account. ## Compiling -Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](/reference/reference/sandbox_reference/index.md) for instructions on setting it up. +Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](/reference/sandbox_reference/index.md) for instructions on setting it up. Run the following command in the directory where your `Nargo.toml` file is located: @@ -447,6 +447,6 @@ https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn ### Token Bridge Contract -The [token bridge tutorial](/tutorials/tutorials/contract_tutorials/advanced/token_bridge) is a great follow up to this one. +The [token bridge tutorial](/tutorials/contract_tutorials/advanced/token_bridge) is a great follow up to this one. It builds on the Token contract described here and goes into more detail about Aztec contract composability and Ethereum (L1) and Aztec (L2) cross-chain messaging. diff --git a/docs/docs/tutorials/tutorials/simple_dapp/contract_deployment.md b/docs/docs/tutorials/simple_dapp/contract_deployment.md similarity index 94% rename from docs/docs/tutorials/tutorials/simple_dapp/contract_deployment.md rename to docs/docs/tutorials/simple_dapp/contract_deployment.md index b3e157f88d7..a6981fbd58d 100644 --- a/docs/docs/tutorials/tutorials/simple_dapp/contract_deployment.md +++ b/docs/docs/tutorials/simple_dapp/contract_deployment.md @@ -3,7 +3,7 @@ To add contracts to your application, we'll start by creating a new `aztec-nargo` project. We'll then compile the contracts, and write a simple script to deploy them to our Sandbox. :::info -Follow the instructions [here](/reference/reference/sandbox_reference/index.md) to install `aztec-nargo` if you haven't done so already. +Follow the instructions [here](/reference/sandbox_reference/index.md) to install `aztec-nargo` if you haven't done so already. ::: ## Initialize Aztec project @@ -34,7 +34,7 @@ The `Token` contract also requires some helper files. You can view the files [he ## Compile your contract -We'll now use `aztec-nargo` to [compile](/reference/reference/sandbox_reference/index.md#installation). +We'll now use `aztec-nargo` to [compile](/reference/sandbox_reference/index.md#installation). Now run the following from your contract folder (containing Nargo.toml): diff --git a/docs/docs/tutorials/tutorials/simple_dapp/contract_interaction.md b/docs/docs/tutorials/simple_dapp/contract_interaction.md similarity index 91% rename from docs/docs/tutorials/tutorials/simple_dapp/contract_interaction.md rename to docs/docs/tutorials/simple_dapp/contract_interaction.md index 253801457e0..c263b64ddf6 100644 --- a/docs/docs/tutorials/tutorials/simple_dapp/contract_interaction.md +++ b/docs/docs/tutorials/simple_dapp/contract_interaction.md @@ -9,7 +9,7 @@ Let's start by showing our user's private balance for the token across their acc #include_code balance_of_private noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust :::info -Note that this function will only return a valid response for accounts registered in the Private eXecution Environment (PXE), since it requires access to the [user's private state](/aztec/aztec/concepts/wallets/index.md#private-state). In other words, you cannot query the private balance of another user for the token contract. +Note that this function will only return a valid response for accounts registered in the Private eXecution Environment (PXE), since it requires access to the [user's private state](/aztec/concepts/wallets/index.md#private-state). In other words, you cannot query the private balance of another user for the token contract. ::: To do this, let's first initialize a new `Contract` instance using `aztec.js` that represents our deployed token contracts. Create a new `src/contracts.mjs` file with the imports for our artifacts and other dependencies: @@ -93,12 +93,12 @@ At the time of this writing, there are no events emitted when new private notes ## Working with public state -While [private and public state](/aztec/aztec/concepts/state_model/index.md) are fundamentally different, the API for working with private and public functions and state from `aztec.js` is equivalent. To query the balance in public tokens for our user accounts, we can just call the `balance_of_public` view function in the contract: +While [private and public state](/aztec/concepts/state_model/index.md) are fundamentally different, the API for working with private and public functions and state from `aztec.js` is equivalent. To query the balance in public tokens for our user accounts, we can just call the `balance_of_public` view function in the contract: #include_code showPublicBalances yarn-project/end-to-end/src/sample-dapp/index.mjs javascript :::info -Since this we are working with pubic balances, we can now query the balance for any address, not just those registered in our local PXE. We can also send funds to addresses for which we don't know their [public encryption key](/aztec/aztec/concepts/accounts/keys.md#encryption-keys). +Since this we are working with pubic balances, we can now query the balance for any address, not just those registered in our local PXE. We can also send funds to addresses for which we don't know their [public encryption key](/aztec/concepts/accounts/keys.md#encryption-keys). ::: Here, since the token contract does not mint any initial funds upon deployment, the balances for all of our user's accounts will be zero. diff --git a/docs/docs/tutorials/tutorials/simple_dapp/index.md b/docs/docs/tutorials/simple_dapp/index.md similarity index 87% rename from docs/docs/tutorials/tutorials/simple_dapp/index.md rename to docs/docs/tutorials/simple_dapp/index.md index 7254d2e242d..34a7c6dd6be 100644 --- a/docs/docs/tutorials/tutorials/simple_dapp/index.md +++ b/docs/docs/tutorials/simple_dapp/index.md @@ -4,7 +4,7 @@ title: Dapp Tutorial In this tutorial we'll go through the steps for building a simple application that interacts with the Aztec Sandbox. We'll be building a console application using Javascript and NodeJS, but you may reuse the same concepts here for a web-based app. All Aztec libraries are written in Typescript and fully typed, so you can use Typescript instead of Javascript to make the most out of its type checker. -This tutorial will focus on environment setup, including creating accounts and deployments, as well as interacting with your contracts. It will not cover [how to write contracts in Noir](/aztec/aztec/concepts/smart_contracts/index.md). +This tutorial will focus on environment setup, including creating accounts and deployments, as well as interacting with your contracts. It will not cover [how to write contracts in Noir](/aztec/concepts/smart_contracts/index.md). The full code for this tutorial is [available on the `aztec-packages` repository](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/end-to-end/src/sample-dapp). @@ -12,8 +12,8 @@ The full code for this tutorial is [available on the `aztec-packages` repository - Linux or OSX environment - [NodeJS](https://nodejs.org/) 18 or higher -- [Aztec Sandbox](/getting_started/getting_started) -- [Aztec CLI](/reference/reference/sandbox_reference) +- [Aztec Sandbox](/getting_started) +- [Aztec CLI](/reference/sandbox_reference) ## Prerequisites diff --git a/docs/docs/tutorials/tutorials/simple_dapp/project_setup.md b/docs/docs/tutorials/simple_dapp/project_setup.md similarity index 100% rename from docs/docs/tutorials/tutorials/simple_dapp/project_setup.md rename to docs/docs/tutorials/simple_dapp/project_setup.md diff --git a/docs/docs/tutorials/tutorials/simple_dapp/pxe_service.md b/docs/docs/tutorials/simple_dapp/pxe_service.md similarity index 92% rename from docs/docs/tutorials/tutorials/simple_dapp/pxe_service.md rename to docs/docs/tutorials/simple_dapp/pxe_service.md index 8832d8e9c7d..f4f3c51c158 100644 --- a/docs/docs/tutorials/tutorials/simple_dapp/pxe_service.md +++ b/docs/docs/tutorials/simple_dapp/pxe_service.md @@ -4,7 +4,7 @@ PXE is a component of the Aztec Protocol that provides a private execution envir As an app developer, the [PXE](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/pxe) interface provides you with access to the user's accounts and their private state, as well as a connection to the network for accessing public global state. -During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](/reference/reference/sandbox_reference/index.md), which runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. +During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](/reference/sandbox_reference/index.md), which runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. The Sandbox also includes a set of pre-initialized accounts that you can use from your app. In this section, we'll connect to the Sandbox from our project. diff --git a/docs/docs/tutorials/tutorials/simple_dapp/testing.md b/docs/docs/tutorials/simple_dapp/testing.md similarity index 79% rename from docs/docs/tutorials/tutorials/simple_dapp/testing.md rename to docs/docs/tutorials/simple_dapp/testing.md index c9907bd0dd0..1160977b085 100644 --- a/docs/docs/tutorials/tutorials/simple_dapp/testing.md +++ b/docs/docs/tutorials/simple_dapp/testing.md @@ -4,7 +4,7 @@ title: Testing To wrap up this tutorial, we'll set up a simple automated test for our dapp contracts. We will be using [jest](https://jestjs.io/), but any nodejs test runner works fine. -Here we'll only test the happy path for a `transfer` on our private token contract, but in a real application you should be testing both happy and unhappy paths, as well as both your contracts and application logic. Refer to the full [testing guide](/tutorials/tutorials/simple_dapp/testing.md) for more info on testing and assertions. +Here we'll only test the happy path for a `transfer` on our private token contract, but in a real application you should be testing both happy and unhappy paths, as well as both your contracts and application logic. ## Dependencies @@ -14,7 +14,7 @@ Start by installing our test runner, in this case jest: yarn add -D jest ``` -We'll need to [install and run the Sandbox](/reference/reference/sandbox_reference/index.md#installation). +We'll need to [install and run the Sandbox](/reference/sandbox_reference/index.md#installation). ## Test setup @@ -46,7 +46,7 @@ Let's set up our test suite. We'll make sure the Sandbox is running, create two #include_code setup yarn-project/end-to-end/src/sample-dapp/index.test.mjs javascript :::tip -Instead of creating new accounts in our test suite, we can use the ones already initialized by the Sandbox upon startup. This can provide a speed boost to your tests setup. However, bear in mind that you may accidentally introduce an interdependency across test suites by reusing the same accounts. Read more [here](/tutorials/tutorials/simple_dapp/testing.md#using-sandbox-initial-accounts). +Instead of creating new accounts in our test suite, we can use the ones already initialized by the Sandbox upon startup. This can provide a speed boost to your tests setup. However, bear in mind that you may accidentally introduce an interdependency across test suites by reusing the same accounts. ::: ## Writing our test @@ -55,7 +55,7 @@ Now that we have a working test environment, we can write our first test for exe #include_code test yarn-project/end-to-end/src/sample-dapp/index.test.mjs javascript -In this example, we assert that the `recipient`'s balance is increased by the amount transferred. We could also test that the `owner`'s funds are decremented by the same amount, or that a transaction that attempts to send more funds than those available would fail. Check out the [testing guide](/tutorials/tutorials/simple_dapp/testing.md) for more ideas. +In this example, we assert that the `recipient`'s balance is increased by the amount transferred. We could also test that the `owner`'s funds are decremented by the same amount, or that a transaction that attempts to send more funds than those available would fail. ## Running our tests @@ -67,4 +67,4 @@ yarn node --experimental-vm-modules $(yarn bin jest) --testRegex '.*\.test\.mjs$ ## Next steps -Now that you have finished the tutorial, you can learn more about [writing contracts with Noir](/aztec/aztec/concepts/smart_contracts/index.md) or read about the [fundamental concepts behind Aztec Network](/aztec/aztec/core_components). +Now that you have finished the tutorial, you can learn more about [writing contracts with Noir](/aztec/concepts/smart_contracts/index.md) or read about the [fundamental concepts behind Aztec Network](/aztec/core_components). diff --git a/docs/docs/tutorials/tutorials/_category_.json b/docs/docs/tutorials/tutorials/_category_.json deleted file mode 100644 index 02c7361fd8a..00000000000 --- a/docs/docs/tutorials/tutorials/_category_.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "label": "Tutorials", - "position": 1, - "collapsible": true, - "collapsed": true -} diff --git a/docs/docs/tutorials/tutorials/write_accounts_contract.md b/docs/docs/tutorials/write_accounts_contract.md similarity index 83% rename from docs/docs/tutorials/tutorials/write_accounts_contract.md rename to docs/docs/tutorials/write_accounts_contract.md index bee114a9c58..fca19b89b0d 100644 --- a/docs/docs/tutorials/tutorials/write_accounts_contract.md +++ b/docs/docs/tutorials/write_accounts_contract.md @@ -13,15 +13,15 @@ You will learn: - Typescript glue code to format and authenticate transactions - Deploying and testing the account contract -Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of [account abstraction](/aztec/aztec/concepts/index.md#what-is-account-abstraction) in the Aztec network. +Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of [account abstraction](/aztec/concepts/index.md#what-is-account-abstraction) in the Aztec network. -It is highly recommended that you understand how an [account](/aztec/aztec/concepts/index.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](/aztec/aztec/concepts/accounts/keys.md). You will also need to know how to write a contract in Noir, as well as some basic [Typescript](https://www.typescriptlang.org/). +It is highly recommended that you understand how an [account](/aztec/concepts/index.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](/aztec/concepts/accounts/keys.md). You will also need to know how to write a contract in Noir, as well as some basic [Typescript](https://www.typescriptlang.org/). For this tutorial, we will write an account contract that uses Schnorr signatures for authenticating transaction requests. Every time a transaction payload is passed to this account contract's `entrypoint` function, the account contract requires a valid Schnorr signature, whose signed message matches the transaction payload, and whose signer matches the account contract owner's public key. If the signature fails, the transaction will fail. -For the sake of simplicity, we will hardcode the signing public key into the contract, but you could store it [in a private note](/aztec/aztec/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](/aztec/aztec/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](/aztec/aztec/concepts/accounts/keys.md#using-a-separate-keystore), to mention a few examples. +For the sake of simplicity, we will hardcode the signing public key into the contract, but you could store it [in a private note](/aztec/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](/aztec/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](/aztec/concepts/accounts/keys.md#using-a-separate-keystore), to mention a few examples. ## Contract @@ -29,7 +29,7 @@ Let's start with the account contract itself in Aztec.nr. Create a new Aztec.nr #include_code contract noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr rust -The important part of this contract is the `entrypoint` function, which will be the first function executed in any transaction originated from this account. This function has two main responsibilities: authenticating the transaction and executing calls. It receives a `payload` with the list of function calls to execute, and requests a corresponding [authentication witness](/aztec/aztec/concepts/accounts/authwit.md) from an oracle to validate it. Authentication witnesses are used for authorizing actions for an account, whether it is just checking a signature, like in this case, or granting authorization for another account to act on an accounts behalf (e.g. token approvals). You will find this logic implemented in the `AccountActions` module, which use the `AppPayload` and `FeePayload` structs: +The important part of this contract is the `entrypoint` function, which will be the first function executed in any transaction originated from this account. This function has two main responsibilities: authenticating the transaction and executing calls. It receives a `payload` with the list of function calls to execute, and requests a corresponding [authentication witness](/aztec/concepts/accounts/authwit.md) from an oracle to validate it. Authentication witnesses are used for authorizing actions for an account, whether it is just checking a signature, like in this case, or granting authorization for another account to act on an accounts behalf (e.g. token approvals). You will find this logic implemented in the `AccountActions` module, which use the `AppPayload` and `FeePayload` structs: #include_code entrypoint noir-projects/aztec-nr/authwit/src/account.nr rust @@ -83,11 +83,11 @@ More signing schemes are available in case you want to experiment with other typ Let's try creating a new account backed by our account contract, and interact with a simple token contract to test it works. -To create and deploy the account, we will use the `AccountManager` class, which takes an instance of an Private Execution Environment (PXE), a [privacy private key](/aztec/aztec/concepts/accounts/keys.md#privacy-keys), and an instance of our `AccountContract` class: +To create and deploy the account, we will use the `AccountManager` class, which takes an instance of an Private Execution Environment (PXE), a [privacy private key](/aztec/concepts/accounts/keys.md#privacy-keys), and an instance of our `AccountContract` class: #include_code account-contract-deploy yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript -Note that we get a [`Wallet` instance](/aztec/aztec/concepts/index.md#account-contracts-and-wallets) out of the account, which we can use for initializing the token contract class after deployment, so any transactions sent to it are sent from our wallet. We can then send a transaction to it and check its effects: +Note that we get a [`Wallet` instance](/aztec/concepts/index.md#account-contracts-and-wallets) out of the account, which we can use for initializing the token contract class after deployment, so any transactions sent to it are sent from our wallet. We can then send a transaction to it and check its effects: #include_code account-contract-works yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript diff --git a/docs/docs/aztec/index.mdx b/docs/docs/vision.mdx similarity index 96% rename from docs/docs/aztec/index.mdx rename to docs/docs/vision.mdx index 5381c307ecb..498522810f5 100644 --- a/docs/docs/aztec/index.mdx +++ b/docs/docs/vision.mdx @@ -3,7 +3,7 @@ title: Vision sidebar_position: 1 --- -import Disclaimer from "../../src/components/Disclaimers/_wip_disclaimer.mdx"; +import Disclaimer from "@site/src/components/Disclaimers/_wip_disclaimer.mdx"; ## The world's encrypted ledger diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 5b5b5fe9190..16c6fbacd7c 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -126,33 +126,40 @@ const config = { [ "docusaurus-plugin-typedoc", { - id: "apis/pxe", + id: "aztecjs/pxe", entryPoints: ["../yarn-project/circuit-types/src/interfaces/pxe.ts"], tsconfig: "../yarn-project/circuit-types/tsconfig.json", entryPointStrategy: "expand", - out: "apis/pxe", + out: "reference/aztecjs/pxe", + readme: "none", + sidebar: { + categoryLabel: "Private Execution Environment (PXE)", + }, disableSources: true, - frontmatter: { sidebar_label: "Private Execution Environment (PXE)" }, }, ], [ "docusaurus-plugin-typedoc", { - id: "apis/aztec-js", + id: "aztecjs/aztec-js", entryPoints: [ "../yarn-project/aztec.js/src/contract/index.ts", "../yarn-project/aztec.js/src/account/index.ts", ], tsconfig: "../yarn-project/aztec.js/tsconfig.json", entryPointStrategy: "resolve", - out: "apis/aztec-js", + out: "reference/aztecjs/aztec-js", + readme: "none", + sidebar: { + categoryLabel: "Aztec.js", + }, disableSources: true, }, ], [ "docusaurus-plugin-typedoc", { - id: "apis/accounts", + id: "aztecjs/accounts", entryPoints: [ "../yarn-project/accounts/src/defaults/index.ts", "../yarn-project/accounts/src/ecdsa/index.ts", @@ -162,7 +169,11 @@ const config = { ], tsconfig: "../yarn-project/accounts/tsconfig.json", entryPointStrategy: "resolve", - out: "apis/accounts", + out: "reference/aztecjs/accounts", + readme: "none", + sidebar: { + categoryLabel: "Accounts", + }, disableSources: true, }, ], @@ -231,7 +242,7 @@ const config = { }, { label: "Developer Quickstart", - to: "/getting_started/getting_started", + to: "/getting_started", }, { label: "Aztec.nr", diff --git a/docs/package.json b/docs/package.json index 390cff4d4a5..ce1043aaaef 100644 --- a/docs/package.json +++ b/docs/package.json @@ -8,14 +8,11 @@ "dev:local": "ENV=dev yarn docs", "build": "./scripts/build.sh", "swizzle": "docusaurus swizzle", - "clear": "rm -rf 'processed-docs' 'processed-docs-cache' docs/apis && docusaurus clear && rm 'src/preprocess/AztecnrReferenceAutogenStructure.json' && rm -rf 'docs/developers/references/aztec-nr'", + "clean": "./scripts/clean.sh", "serve": "docusaurus serve", "preprocess": "yarn node -r dotenv/config ./src/preprocess/index.js && node src/preprocess/generate_aztecnr_reference.js", "preprocess:dev": "nodemon --config nodemon.json ./src/preprocess/index.js && nodemon --config nodemon.json src/preprocess/generate_aztecnr_reference.js ", - "typedoc": "rm -rf docs/apis && docusaurus generate-typedoc && cp -a docs/apis processed-docs/", - "typedoc:dev": "nodemon -w ../yarn-project -e '*.js,*.ts,*.nr,*.md' --exec \"rm -rf docs/apis && yarn docusaurus generate-typedoc && cp -a docs/apis processed-docs/\"", - "write-translations": "docusaurus write-translations", - "write-heading-ids": "docusaurus write-heading-ids" + "typedoc": "docusaurus generate-typedoc" }, "dependencies": { "@docusaurus/core": "^3.0.1", diff --git a/docs/scripts/build.sh b/docs/scripts/build.sh index ead793d4968..d884bcdf3d5 100755 --- a/docs/scripts/build.sh +++ b/docs/scripts/build.sh @@ -45,10 +45,16 @@ if [ -n "$NETLIFY" ]; then yarn fi +# Clean +echo Cleaning... +yarn clean + # Now build the docsite echo Building docsite... -echo "Generating Aztec.nr reference docs..." -node ./src/preprocess/generate_aztecnr_reference.js -echo "Generated Aztec.nr reference docs" +echo "Processing..." +yarn preprocess +yarn typedoc +sh scripts/move_processed.sh -yarn preprocess && yarn typedoc && yarn docusaurus build +echo "Building..." +yarn docusaurus build diff --git a/docs/scripts/clean.sh b/docs/scripts/clean.sh new file mode 100755 index 00000000000..da22dfd276e --- /dev/null +++ b/docs/scripts/clean.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +rm -rf 'processed-docs' 'processed-docs-cache' +rm -rf docs/reference/aztecjs 'docs/reference/smart_contract_reference/aztec-nr' + +docusaurus clear diff --git a/docs/scripts/move_processed.sh b/docs/scripts/move_processed.sh new file mode 100755 index 00000000000..8a29b13a16e --- /dev/null +++ b/docs/scripts/move_processed.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +echo "label: \"AztecJS\"" > ./docs/reference/aztecjs/_category_.yml +mv ./docs/reference/aztecjs ./processed-docs/reference/aztecjs +mv ./docs/reference/smart_contract_reference/aztec-nr ./processed-docs/reference/smart_contract_reference/aztec-nr diff --git a/docs/sidebars.js b/docs/sidebars.js index e8adcdc8704..1b84e84f303 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -1,82 +1,45 @@ -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ - // @ts-check const fs = require("fs"); const path = require("path"); -// Load the structured documentation paths -const docsStructurePath = path.join( - __dirname, - "/src/preprocess/AztecnrReferenceAutogenStructure.json" -); -const docsStructure = JSON.parse(fs.readFileSync(docsStructurePath, "utf8")); - -// Function to recursively build sidebar items from the structured documentation -function buildSidebarItemsFromStructure(structure, basePath = "") { - const items = []; - for (const key in structure) { - if (key === "_docs") { - // Base case: add the docs - structure[key].forEach((doc) => { - items.push(`${basePath}/${doc}`); - }); - } else { - // Recursive case: process a subdirectory - const subItems = buildSidebarItemsFromStructure( - structure[key], - `${basePath}/${key}` - ); - items.push({ - type: "category", - label: key.charAt(0).toUpperCase() + key.slice(1), // Capitalize the label - items: subItems, - }); - } - } - return items; -} - -// Build sidebar for AztecNR documentation -const aztecNRSidebar = buildSidebarItemsFromStructure( - docsStructure.AztecNR, - "developers/contracts/references/aztec-nr" -); /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ export default { sidebar: [ { - type: "autogenerated", - dirName: "aztec", + type: "category", + label: "Aztec", + link: { type: "doc", id: "aztec" }, + items: [{ type: "autogenerated", dirName: "aztec" }], + }, + { + type: "doc", + id: "vision", }, { type: "html", value: '', }, { - type: "autogenerated", - dirName: "getting_started", + type: "category", + label: "Getting Started", + link: { type: "doc", id: "getting_started" }, + items: [{ type: "autogenerated", dirName: "getting_started" }], }, { - type: "autogenerated", - dirName: "tutorials", + type: "category", + label: "Tutorials", + items: [{ type: "autogenerated", dirName: "tutorials" }], }, { - type: "autogenerated", - dirName: "guides", + type: "category", + label: "Guides", + items: [{ type: "autogenerated", dirName: "guides" }], }, { - type: "autogenerated", - dirName: "reference", + type: "category", + label: "Reference", + items: [{ type: "autogenerated", dirName: "reference" }], }, { type: "html", diff --git a/docs/src/components/Disclaimers/_wip_disclaimer.mdx b/docs/src/components/Disclaimers/_wip_disclaimer.mdx index 8d1d33f4405..597f226dc5f 100644 --- a/docs/src/components/Disclaimers/_wip_disclaimer.mdx +++ b/docs/src/components/Disclaimers/_wip_disclaimer.mdx @@ -5,7 +5,7 @@ :::caution Disclaimer We are building Aztec as transparently as we can. The documents published here are living documents. The protocol, sandbox, language, and tools are all subject to change over time. -Please see [here](/aztec/aztec/limitations) for details of known Aztec protocol and Aztec Sandbox limitations. +Please see [here](/aztec/limitations) for details of known Aztec protocol and Aztec Sandbox limitations. If you would like to help us build Aztec: diff --git a/docs/src/preprocess/generate_aztecnr_reference.js b/docs/src/preprocess/generate_aztecnr_reference.js index c2a54ec731b..b0902590663 100644 --- a/docs/src/preprocess/generate_aztecnr_reference.js +++ b/docs/src/preprocess/generate_aztecnr_reference.js @@ -317,36 +317,13 @@ function processFiles(baseDir, outputBaseDir) { fs.mkdirSync(path.dirname(outputFilePath), { recursive: true }); fs.writeFileSync(outputFilePath, markdown); - - // Adjusted to populate docStructure for JSON - const docPathForJson = adjustedPath.replace(/\\/g, "/").replace(".md", ""); - const parts = docPathForJson.split("/"); - let current = docStructure; - - for (let i = 0; i < parts.length - 1; i++) { - current[parts[i]] = current[parts[i]] || {}; - current = current[parts[i]]; - } - - current._docs = current._docs || []; - current._docs.push(parts[parts.length - 1]); }); - - // Write structured documentation paths to JSON - const outputPath = path.join( - __dirname, - "AztecnrReferenceAutogenStructure.json" - ); - fs.writeFileSync( - outputPath, - JSON.stringify({ AztecNR: docStructure }, null, 2) - ); } let baseDir = path.resolve(__dirname, "../../../noir-projects/aztec-nr"); let outputBaseDir = path.resolve( __dirname, - "../../docs/reference/reference/smart_contract_reference/aztec-nr" + "../../docs/reference/smart_contract_reference/aztec-nr" ); console.log(outputBaseDir); processFiles(baseDir, outputBaseDir); From 2453ba8f2ba193df829ec2d4937d8ae3770373d3 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Mon, 20 May 2024 21:22:00 +0100 Subject: [PATCH 25/37] feat(docs): Key rotation / owner -> nullifier key docs (#6538) Closes https://github.com/AztecProtocol/dev-rel/issues/279 --- .../aztecnr-getting-started.md | 4 +- docs/docs/guides/js_apps/rotate_keys.md | 41 +++++++++++++++++++ docs/docs/guides/js_apps/test_contracts.md | 2 +- .../common_patterns/key_rotation.md | 27 ++++++++++++ .../writing_contracts/how_to_emit_event.md | 2 +- .../writing_contracts/how_to_prove_history.md | 2 +- .../writing_contracts/storage/notes.md | 2 +- docs/docs/migration_notes.md | 12 ++++++ .../storage/private_state.md | 4 +- .../private_voting_contract.md | 6 ++- .../contract_tutorials/token_contract.md | 10 ++--- .../end-to-end/src/e2e_key_rotation.test.ts | 16 ++++++-- 12 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 docs/docs/guides/js_apps/rotate_keys.md create mode 100644 docs/docs/guides/smart_contracts/writing_contracts/common_patterns/key_rotation.md diff --git a/docs/docs/getting_started/aztecnr-getting-started.md b/docs/docs/getting_started/aztecnr-getting-started.md index 8e2abeff7b7..6caa2634c64 100644 --- a/docs/docs/getting_started/aztecnr-getting-started.md +++ b/docs/docs/getting_started/aztecnr-getting-started.md @@ -92,7 +92,7 @@ Map is a private state variable that functions like a dictionary, relating Field `value_note` -Notes are fundamental to how Aztec manages privacy. A note is a privacy-preserving representation of an amount of tokens associated with an address, while encrypting the amount and owner. In this contract, we are using the `value_note` library. This is a type of note interface for storing a single Field, eg a balance - or, in our case, a counter. +Notes are fundamental to how Aztec manages privacy. A note is a privacy-preserving representation of an amount of tokens associated with a nullifier key (that can be owned by an owner), while encrypting the amount. In this contract, we are using the `value_note` library. This is a type of note interface for storing a single Field, eg a balance - or, in our case, a counter. We are also using `balance_utils` from this import, a useful library that allows us to utilize value notes as if they are simple balances. @@ -128,7 +128,7 @@ The `increment` function works very similarly to the `constructor`, but instead ## Prevent double spending -Because our counters are private, the network can't directly verify if a note was spent or not, which could lead to double-spending. To solve this, we use a nullifier - a unique identifier generated from each spent note and its owner. Although this isn't really an issue in this simple smart contract, Aztec injects a special function called `compute_note_hash_and_nullifier` to determine these values for any given note produced by this contract. +Because our counters are private, the network can't directly verify if a note was spent or not, which could lead to double-spending. To solve this, we use a nullifier - a unique identifier generated from each spent note and its nullifier key. Although this isn't really an issue in this simple smart contract, Aztec injects a special function called `compute_note_hash_and_nullifier` to determine these values for any given note produced by this contract. ## Getting a counter diff --git a/docs/docs/guides/js_apps/rotate_keys.md b/docs/docs/guides/js_apps/rotate_keys.md new file mode 100644 index 00000000000..3fca7522ac3 --- /dev/null +++ b/docs/docs/guides/js_apps/rotate_keys.md @@ -0,0 +1,41 @@ +--- +title: How to Rotate Nullifier Keys +--- + +This guide explains how to rotate nullifer secret and public keys using Aztec.js. To learn more about key rotation, read the [concepts section](../../aztec/concepts/accounts/keys.md#key-rotation). + +## Prerequisites + +You should have a wallet whose keys you want to rotate. You can learn how to create wallets from [this guide](./create_account.md). + +You should also have a PXE initialized. + +## Relevant imports + +You will need to import these from Aztec.js: + +#include_code imports yarn-project/end-to-end/src/e2e_key_rotation.test.ts typescript + +## Create nullifier secret and public key + +`newNskM` = new master nullifier secret key + +`newNpkM` = new master nullifier public key (type `PublicKey`) + +#include_code create_keys yarn-project/end-to-end/src/e2e_key_rotation.test.ts typescript + +## Rotate nullifier secret and public key + +Call `rotateMasterNullifierKey` on the PXE to rotate the secret key. + +#include_code rotateMasterNullifierKey yarn-project/end-to-end/src/e2e_key_rotation.test.ts typescript + +## Rotate public key + +Connect to the key registry contract with your wallet. + +#include_code keyRegistryWithB yarn-project/end-to-end/src/e2e_key_rotation.test.ts typescript + +Then `rotate_npk_m` on the key registry contract to rotate the public key: + +#include_code rotate_npk_m yarn-project/end-to-end/src/e2e_key_rotation.test.ts typescript diff --git a/docs/docs/guides/js_apps/test_contracts.md b/docs/docs/guides/js_apps/test_contracts.md index 53a7272335a..c2ef8cf6c0b 100644 --- a/docs/docs/guides/js_apps/test_contracts.md +++ b/docs/docs/guides/js_apps/test_contracts.md @@ -152,7 +152,7 @@ Private state in the Aztec Network is represented via sets of [private notes](/a #include_code value-note-def noir-projects/aztec-nr/value-note/src/value_note.nr rust -We can query the Private eXecution Environment (PXE) for all notes encrypted for a given user in a contract slot. For this example, we'll get all notes encrypted for the `owner` user that are stored on the token contract address and on the slot we calculated earlier. To calculate the actual balance, we extract the `value` of each note, which is the first element, and sum them up. +We can query the Private eXecution Environment (PXE) for all notes encrypted to a given owner in a contract slot. For this example, we'll get all notes encrypted for the `owner` user that are stored on the token contract address and on the slot we calculated earlier. To calculate the actual balance, we extract the `value` of each note, which is the first element, and sum them up. #include_code private-storage /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript diff --git a/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/key_rotation.md b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/key_rotation.md new file mode 100644 index 00000000000..9fb6fdca481 --- /dev/null +++ b/docs/docs/guides/smart_contracts/writing_contracts/common_patterns/key_rotation.md @@ -0,0 +1,27 @@ +--- +title: Key Rotation +--- + +## Prerequisite reading + +- [Keys](../../../../aztec/concepts/accounts/keys.md) + +## Introduction + +It is possible for users to rotate their keys, which can be helpful if some of their keys are leaked. + +Because of this, notes are associated with their `nullifier key` rather than any sort of 'owner' address. + +It is still possible to nullify the notes with the old nullifier key even after the key rotation. + +## Things to consider + +- 'Owner' is arbitrary - as long as you know the nullifier secret, you can nullify a note +- Consider how key rotation can affect account contracts, eg you can add additional security checks for who or how the key rotation is called + +## Glossary + +- `npk_m_hash`: master nullifying public key hash +- `nsk_app`: app nullifying secret key - the app-specific NSK (learn more about app-scoped keys [here](../../../../aztec/concepts/accounts/keys.md#scoped-keys)) +- `nsk_hash`: nullifying secret key hash +- `ivpk_m`: incoming view public key (master) (learn more about IVPKs [here](../../../../aztec/concepts/accounts/keys.md#keys)) \ No newline at end of file diff --git a/docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md b/docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md index bd8f362bc8c..4e734d4b8c1 100644 --- a/docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/how_to_emit_event.md @@ -21,7 +21,7 @@ Encrypted events can only be emitted by private functions and are encrypted usin For this reason it is necessary to register a recipient in the Private Execution Environment (PXE) before encrypting the events for them. First we need to get a hold of recipient's [complete address](#complete-address). -Bellow are some ways how we could instantiate it after getting the information in a string form from a recipient: +Below are some ways how we could instantiate it after getting the information in a string form from a recipient: #include_code instantiate-complete-address /yarn-project/circuits.js/src/structs/complete_address.test.ts rust diff --git a/docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md b/docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md index c6fbd2c2e16..619cd33a8a0 100644 --- a/docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/how_to_prove_history.md @@ -20,7 +20,7 @@ The history library allows you to prove any of the following at a given block he Using this library, you can check that specific notes or nullifiers were part of Aztec network state at specific blocks. This can be useful for things such as: - Verifying a minimum timestamp from a private context -- Checking eligibility based on historical events (e.g. for an airdrop by proving that you owned a note) +- Checking eligibility based on historical events (e.g. for an airdrop by proving that you knew the nullifier key for a note) - Verifying historic ownership / relinquishing of assets - Proving existence of a value in public data tree at a given contract slot - Proving that a contract was deployed in a given block with some parameters diff --git a/docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md b/docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md index 41f93939383..097ca2e12a3 100644 --- a/docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md +++ b/docs/docs/guides/smart_contracts/writing_contracts/storage/notes.md @@ -106,7 +106,7 @@ As a convenience, the outer [note/utils.nr](https://github.com/AztecProtocol/azt Serialization/deserialization of content is used to convert between the Note's variables and a generic array of Field elements. The Field type is understood and used by lower level crypographic libraries. This is analogous to the encoding/decoding between variables and bytes in solidity. -For example in ValueNote, the `serialize_content` function simply returns: the value, owner address (as a field) and the note randomness; as an array of Field elements. +For example in ValueNote, the `serialize_content` function simply returns: the value, nullifying public key hash (as a field) and the note randomness; as an array of Field elements. ### Value as a sum of Notes We recall that multiple notes are associated with a "slot" (or ID), and so the value of a numerical note (like ValueNote) is the sum of each note's value. diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index f607abad860..ee69840c376 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -57,8 +57,20 @@ struct TokenNote { } ``` +Creating a token note and adding it to storage now looks like this: + +```diff +- let mut note = ValueNote::new(new_value, owner); +- storage.a_private_value.insert(&mut note, true); ++ let owner_npk_m_hash = get_npk_m_hash(&mut context, owner); ++ let owner_ivpk_m = get_ivpk_m(&mut context, owner); ++ let mut note = ValueNote::new(new_value, owner_npk_m_hash); ++ storage.a_private_value.insert(&mut note, true, owner_ivpk_m); +``` + Computing the nullifier similarly changes to use this master nullifying public key hash. + ## 0.40.0 ### [Aztec.nr] Debug logging diff --git a/docs/docs/reference/smart_contract_reference/storage/private_state.md b/docs/docs/reference/smart_contract_reference/storage/private_state.md index bed799ff641..256543f3493 100644 --- a/docs/docs/reference/smart_contract_reference/storage/private_state.md +++ b/docs/docs/reference/smart_contract_reference/storage/private_state.md @@ -326,9 +326,9 @@ The first value of `.select` and `.sort` is the index of a field in a note type. #include_code state_vars-CardNote /noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust -The indices are: 0 for `points`, 1 for `secret`, and 2 for `owner`. +The indices are: 0 for `points`, 1 for `randomness`, and 2 for `npk_m_hash`. -In the example, `.select(2, account_address, Option::none())` matches the 2nd field of `CardNote`, which is `owner`, and returns the cards whose `owner` field equals `account_address`, equality is the comparator used because because including no comparator (the third argument) defaults to using the equality comparator. The current possible values of Comparator are specified in the Note Getter Options implementation linked above. +In the example, `.select(2, account_address, Option::none())` matches the 2nd field of `CardNote`, which is `npk_m_hash`, and returns the cards whose `npk_m_hash` field equals `account_npk_m_hash`, equality is the comparator used because because including no comparator (the third argument) defaults to using the equality comparator. The current possible values of Comparator are specified in the Note Getter Options implementation linked above. `.sort(0, SortOrder.DESC)` sorts the 0th field of `CardNote`, which is `points`, in descending order. diff --git a/docs/docs/tutorials/contract_tutorials/private_voting_contract.md b/docs/docs/tutorials/contract_tutorials/private_voting_contract.md index 5815d037c26..70709f44de4 100644 --- a/docs/docs/tutorials/contract_tutorials/private_voting_contract.md +++ b/docs/docs/tutorials/contract_tutorials/private_voting_contract.md @@ -44,7 +44,7 @@ Your file structure should look something like this: The file `main.nr` will soon turn into our smart contract! -We will need the Aztec library to create this contract. In your `Nargo.toml` you should see `[dependencies]` - paste this bellow it. +We will need the Aztec library to create this contract. In your `Nargo.toml` you should see `[dependencies]` - paste this below it. ```toml [dependencies] @@ -126,6 +126,10 @@ The first thing we do here is assert that the vote has not ended. The code after the assertion will only run if the assertion is true. In this snippet, we read the current vote tally at the voteId, add 1 to it, and write this new number to the voteId. The `Field` element allows us to use `+` to add to an integer. +:::danger +Note that due to [key rotation](../../aztec/concepts/accounts/keys.md#key-rotation), it would be possible for a user to rotate their nullifier secret key and be able to vote again. Refer to [common patterns](../../guides/smart_contracts/writing_contracts/common_patterns/key_rotation.md) for more information +::: + ## Getting the number of votes We will create a function that anyone can call that will return the number of votes at a given vote Id. Paste this in your contract: diff --git a/docs/docs/tutorials/contract_tutorials/token_contract.md b/docs/docs/tutorials/contract_tutorials/token_contract.md index cac8dc0a4d1..3df7b7a7db4 100644 --- a/docs/docs/tutorials/contract_tutorials/token_contract.md +++ b/docs/docs/tutorials/contract_tutorials/token_contract.md @@ -215,7 +215,7 @@ For more detail on execution contexts, see [Contract Communication](/aztec/conce We are also importing types from a `types.nr` file, which imports types from the `types` folder. You can view them [here](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src). -The main thing to note from this types folder is the `TransparentNote` definition. This defines how the contract moves value from the public domain into the private domain. It is similar to the `value_note` that we imported, but with some modifications namely, instead of a defined `owner`, it allows anyone that can produce the pre-image to the stored `secret_hash` to spend the note. +The main thing to note from this types folder is the `TransparentNote` definition. This defines how the contract moves value from the public domain into the private domain. It is similar to the `value_note` that we imported, but with some modifications namely, instead of a defined nullifier key, it allows anyone that can produce the pre-image to the stored `secret_hash` to spend the note. ### Note on private state @@ -233,7 +233,7 @@ Reading through the storage variables: - `admin` an Aztec address stored in public state. - `minters` is a mapping of Aztec addresses in public state. This will store whether an account is an approved minter on the contract. -- `balances` is a mapping of private balances. Private balances are stored in a `PrivateSet` of `ValueNote`s. The balance is the sum of all of an account's `ValueNote`s. +- `balances` is a mapping of private balances. Private balances are stored in a `PrivateSet` of `TokenNote`s. The balance is the sum of all of an account's `TokenNote`s. - `total_supply` is an unsigned integer (max 128 bit value) stored in public state and represents the total number of tokens minted. - `pending_shields` is a `PrivateSet` of `TransparentNote`s stored in private state. What is stored publicly is a set of commitments to `TransparentNote`s. - `public_balances` is a mapping of Aztec addresses in public state and represents the publicly viewable balances of accounts. @@ -337,7 +337,7 @@ Storage is referenced as `storage.variable`. #### `redeem_shield` -This private function enables an account to move tokens from a `TransparentNote` in the `pending_shields` mapping to any Aztec account as a `ValueNote` in private `balances`. +This private function enables an account to move tokens from a `TransparentNote` in the `pending_shields` mapping to a `TokenNote` in private `balances`. The `TokenNote` will be associated with a nullifier key, so any account that knows this key can spend this note. Going through the function logic, first the `secret_hash` is generated from the given secret. This ensures that only the entity possessing the secret can use it to redeem the note. Following this, a `TransparentNote` is retrieved from the set, using the provided amount and secret. The note is subsequently removed from the set, allowing it to be redeemed only once. The recipient's private balance is then increased using the `increment` helper function from the `value_note` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/value-note/src/utils.nr). @@ -347,7 +347,7 @@ The function returns `1` to indicate successful execution. #### `unshield` -This private function enables un-shielding of private `ValueNote`s stored in `balances` to any Aztec account's `public_balance`. +This private function enables un-shielding of private `TokenNote`s stored in `balances` to any Aztec account's `public_balance`. After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_valid_message_for` is modified to work specifically in the private context. After the authorization check, the sender's private balance is decreased using the `decrement` helper function for the `value_note` library. Then it stages a public function call on this contract ([`_increase_public_balance`](#_increase_public_balance)) to be executed in the [public execution phase](#execution-contexts) of transaction execution. `_increase_public_balance` is marked as an `internal` function, so can only be called by this token contract. @@ -411,7 +411,7 @@ A getter function for checking the token `total_supply`. #### `balance_of_private` -A getter function for checking the private balance of the provided Aztec account. Note that the [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/pxe) must have access to the `owner`s decryption keys in order to decrypt their notes. +A getter function for checking the private balance of the provided Aztec account. Note that the [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/pxe) must have `ivsk_app` ([app-specific secret key](../../aztec/concepts/accounts/keys.md#scoped-keys)) in order to decrypt the notes. #include_code balance_of_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust diff --git a/yarn-project/end-to-end/src/e2e_key_rotation.test.ts b/yarn-project/end-to-end/src/e2e_key_rotation.test.ts index 06ec9e71473..ba7aad8612c 100644 --- a/yarn-project/end-to-end/src/e2e_key_rotation.test.ts +++ b/yarn-project/end-to-end/src/e2e_key_rotation.test.ts @@ -13,8 +13,11 @@ import { computeSecretHash, retryUntil, } from '@aztec/aztec.js'; +// docs:start:imports import { type PublicKey, derivePublicKeyFromSecretKey } from '@aztec/circuits.js'; -import { KeyRegistryContract, TestContract, TokenContract } from '@aztec/noir-contracts.js'; +import { KeyRegistryContract } from '@aztec/noir-contracts.js'; +// docs:end:imports +import { TestContract, TokenContract } from '@aztec/noir-contracts.js'; import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry'; import { jest } from '@jest/globals'; @@ -56,10 +59,10 @@ describe('e2e_key_rotation', () => { } = await setup(1)); ({ pxe: pxeB, teardown: teardownB } = await setupPXEService(aztecNode, {}, undefined, true)); - + // docs:start:keyRegistryWithB [walletB] = await createAccounts(pxeB, 1); keyRegistryWithB = await KeyRegistryContract.at(getCanonicalKeyRegistryAddress(), walletB); - + // docs:end:keyRegistryWithB // We deploy test and token contracts testContract = await TestContract.deploy(walletA).send().deployed(); const tokenInstance = await deployTokenContract(initialBalance, walletA.getAddress(), pxeA); @@ -174,11 +177,16 @@ describe('e2e_key_rotation', () => { // 3. Rotates B key let newNpkM: PublicKey; { + // docs:start:create_keys const newNskM = Fq.random(); newNpkM = derivePublicKeyFromSecretKey(newNskM); + // docs:end:create_keys + // docs:start:rotateMasterNullifierKey await pxeB.rotateMasterNullifierKey(walletB.getAddress(), newNskM); - + // docs:end:rotateMasterNullifierKey + // docs:start:rotate_npk_m await keyRegistryWithB.methods.rotate_npk_m(walletB.getAddress(), newNpkM, 0).send().wait(); + // docs:end:rotate_npk_m await crossDelay(); } From 21dc72aaf29ada2c1a12682d3763370c76eff524 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 20 May 2024 18:31:27 -0300 Subject: [PATCH 26/37] chore: Copy subset of constants to cpp (#6544) Copying all aztec constants to cpp-land caused unnecessary rebuilds of barretenberg, since only a handful of constants are actually used. This adds a list of what constants are actually used in cpp that are used as a filter. --- .../vm/avm_trace/aztec_constants.hpp | 174 ------------------ .../circuits.js/src/scripts/constants.in.ts | 18 +- 2 files changed, 17 insertions(+), 175 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp index 9c188e7c883..980fcfd48e6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp @@ -2,190 +2,16 @@ #pragma once #include -const size_t ARGS_LENGTH = 16; -const size_t MAX_NEW_NOTE_HASHES_PER_CALL = 16; -const size_t MAX_NEW_NULLIFIERS_PER_CALL = 16; -const size_t MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL = 4; -const size_t MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL = 16; -const size_t MAX_NEW_L2_TO_L1_MSGS_PER_CALL = 2; -const size_t MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; -const size_t MAX_PUBLIC_DATA_READS_PER_CALL = 16; -const size_t MAX_NOTE_HASH_READ_REQUESTS_PER_CALL = 32; -const size_t MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 32; -const size_t MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL = 32; -const size_t MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 16; -const size_t MAX_NOTE_ENCRYPTED_LOGS_PER_CALL = 16; -const size_t MAX_ENCRYPTED_LOGS_PER_CALL = 4; -const size_t MAX_UNENCRYPTED_LOGS_PER_CALL = 4; -const size_t MAX_NEW_NOTE_HASHES_PER_TX = 64; -const size_t MAX_NEW_NULLIFIERS_PER_TX = 64; -const size_t MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX = 8; -const size_t MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX = 32; -const size_t MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 32; -const size_t MAX_PUBLIC_DATA_READS_PER_TX = 32; -const size_t MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; -const size_t MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; -const size_t MAX_NULLIFIER_READ_REQUESTS_PER_TX = 128; -const size_t MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX = 128; -const size_t MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 64; -const size_t MAX_NOTE_ENCRYPTED_LOGS_PER_TX = 64; -const size_t MAX_ENCRYPTED_LOGS_PER_TX = 8; -const size_t MAX_UNENCRYPTED_LOGS_PER_TX = 8; -const size_t NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; -const size_t NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; -const size_t MAX_PUBLIC_DATA_HINTS = 64; -const size_t NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; -const size_t VK_TREE_HEIGHT = 3; -const size_t FUNCTION_TREE_HEIGHT = 5; -const size_t NOTE_HASH_TREE_HEIGHT = 32; -const size_t PUBLIC_DATA_TREE_HEIGHT = 40; -const size_t NULLIFIER_TREE_HEIGHT = 20; -const size_t L1_TO_L2_MSG_TREE_HEIGHT = 16; -const size_t ROLLUP_VK_TREE_HEIGHT = 8; -const size_t ARTIFACT_FUNCTION_TREE_MAX_HEIGHT = 5; -const size_t NULLIFIER_TREE_ID = 0; -const size_t NOTE_HASH_TREE_ID = 1; -const size_t PUBLIC_DATA_TREE_ID = 2; -const size_t L1_TO_L2_MESSAGE_TREE_ID = 3; -const size_t ARCHIVE_TREE_ID = 4; -const size_t NOTE_HASH_SUBTREE_HEIGHT = 6; -const size_t NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH = 26; -const size_t NULLIFIER_SUBTREE_HEIGHT = 6; -const size_t PUBLIC_DATA_SUBTREE_HEIGHT = 5; -const size_t ARCHIVE_HEIGHT = 16; -const size_t NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH = 14; -const size_t PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH = 35; -const size_t L1_TO_L2_MSG_SUBTREE_HEIGHT = 4; -const size_t L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH = 12; -const size_t FUNCTION_SELECTOR_NUM_BYTES = 4; -const size_t ARGS_HASH_CHUNK_LENGTH = 64; -const size_t ARGS_HASH_CHUNK_COUNT = 64; -const size_t MAX_ARGS_LENGTH = ARGS_HASH_CHUNK_COUNT * ARGS_HASH_CHUNK_LENGTH; -const size_t INITIAL_L2_BLOCK_NUM = 1; -const size_t BLOB_SIZE_IN_BYTES = 31 * 4096; -const size_t MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; -const size_t MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; -const size_t MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; -const size_t REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 19; -const size_t REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 12; -const size_t DEFAULT_MAX_FEE_PER_GAS = 10; -const size_t DEFAULT_INCLUSION_FEE = 0; -const size_t DA_BYTES_PER_FIELD = 32; -const size_t DA_GAS_PER_BYTE = 16; -const size_t FIXED_DA_GAS = 512; -const size_t AZTEC_ADDRESS_LENGTH = 1; const size_t GAS_FEES_LENGTH = 2; const size_t GAS_LENGTH = 2; -const size_t GAS_SETTINGS_LENGTH = GAS_LENGTH * 2 + GAS_FEES_LENGTH + /* inclusion_fee */ 1; const size_t CALL_CONTEXT_LENGTH = 6; const size_t CONTENT_COMMITMENT_LENGTH = 4; -const size_t CONTRACT_INSTANCE_LENGTH = 5; -const size_t CONTRACT_STORAGE_READ_LENGTH = 2; -const size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; -const size_t ETH_ADDRESS_LENGTH = 1; -const size_t FUNCTION_DATA_LENGTH = 3; -const size_t FUNCTION_LEAF_PREIMAGE_LENGTH = 5; const size_t GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; const size_t APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; -const size_t L1_TO_L2_MESSAGE_LENGTH = 6; -const size_t L2_TO_L1_MESSAGE_LENGTH = 3; -const size_t SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; -const size_t MAX_BLOCK_NUMBER_LENGTH = 2; -const size_t NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; -const size_t SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; const size_t PARTIAL_STATE_REFERENCE_LENGTH = 6; -const size_t READ_REQUEST_LENGTH = 2; -const size_t LOG_HASH_LENGTH = 3; -const size_t NOTE_LOG_HASH_LENGTH = 4; -const size_t NOTE_HASH_LENGTH = 2; -const size_t SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; -const size_t NULLIFIER_LENGTH = 3; -const size_t SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; -const size_t CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH + 1; -const size_t PRIVATE_CALL_REQUEST_LENGTH = 3 + CALLER_CONTEXT_LENGTH; -const size_t SCOPED_PRIVATE_CALL_REQUEST_LENGTH = PRIVATE_CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; -const size_t SIDE_EFFECT_LENGTH = 2; -const size_t ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; const size_t STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; -const size_t TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; -const size_t TX_REQUEST_LENGTH = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; const size_t TOTAL_FEES_LENGTH = 1; const size_t HEADER_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; -const size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = - CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + - (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + - (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + - (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + - (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + - (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + - (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + - (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; -const size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = - CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + - (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + - (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + - (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + - (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + - (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + - HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + - /* transaction_fee */ 1; -const size_t PRIVATE_CALL_STACK_ITEM_LENGTH = - AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; const size_t PUBLIC_CONTEXT_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + GAS_LENGTH + 2; -const size_t SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; -const size_t PUBLIC_DATA_READ_LENGTH = 2; -const size_t VALIDATION_REQUESTS_LENGTH = - ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + - (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + - (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + - (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + - (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); -const size_t PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; -const size_t COMBINED_ACCUMULATED_DATA_LENGTH = - MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 5 + - (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; -const size_t COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; -const size_t CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; -const size_t PRIVATE_ACCUMULATED_DATA_LENGTH = - (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + - (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + - (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + - (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + - (SCOPED_PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + - (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); -const size_t PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = - 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + - CALL_REQUEST_LENGTH + AZTEC_ADDRESS_LENGTH; -const size_t PUBLIC_ACCUMULATED_DATA_LENGTH = - (MAX_NEW_NOTE_HASHES_PER_TX * NOTE_HASH_LENGTH) + (MAX_NEW_NULLIFIERS_PER_TX * NULLIFIER_LENGTH) + - (MAX_NEW_L2_TO_L1_MSGS_PER_TX * 1) + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) + - (MAX_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + - (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + - (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + GAS_LENGTH; -const size_t PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = - VALIDATION_REQUESTS_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + PUBLIC_ACCUMULATED_DATA_LENGTH + - COMBINED_CONSTANT_DATA_LENGTH + 1 + (MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX * CALL_REQUEST_LENGTH) + - AZTEC_ADDRESS_LENGTH; -const size_t KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + - COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + - PARTIAL_STATE_REFERENCE_LENGTH + 1 + AZTEC_ADDRESS_LENGTH; -const size_t CONSTANT_ROLLUP_DATA_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + 4 + GLOBAL_VARIABLES_LENGTH; -const size_t BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = - CONSTANT_ROLLUP_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH + 5; -const size_t ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; -const size_t GET_NOTES_ORACLE_RETURN_LENGTH = 674; -const size_t NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; -const size_t NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; -const size_t PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 2048; -const size_t CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP = 32; -const size_t CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP = 64; -const size_t CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED = 52; -const size_t L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP = 64; -const size_t LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 64; -const size_t NUM_MSGS_PER_BASE_PARITY = 4; -const size_t NUM_BASE_PARITY_PER_ROOT_PARITY = 4; -const size_t RECURSIVE_PROOF_LENGTH = 93; -const size_t NESTED_RECURSIVE_PROOF_LENGTH = 109; -const size_t VERIFICATION_KEY_LENGTH_IN_FIELDS = 114; diff --git a/yarn-project/circuits.js/src/scripts/constants.in.ts b/yarn-project/circuits.js/src/scripts/constants.in.ts index e5f969e228b..ad8c57f95ec 100644 --- a/yarn-project/circuits.js/src/scripts/constants.in.ts +++ b/yarn-project/circuits.js/src/scripts/constants.in.ts @@ -7,6 +7,22 @@ const TS_CONSTANTS_FILE = '../constants.gen.ts'; const CPP_AZTEC_CONSTANTS_FILE = '../../../../barretenberg/cpp/src/barretenberg/vm/avm_trace/aztec_constants.hpp'; const SOLIDITY_CONSTANTS_FILE = '../../../../l1-contracts/src/core/libraries/ConstantsGen.sol'; +// Whitelist of constants that will be copied to aztec_constants.hpp. +// We don't copy everything as just a handful are needed, and updating them breaks the cache and triggers expensive bb builds. +const CPP_CONSTANTS = [ + 'TOTAL_FEES_LENGTH', + 'GAS_FEES_LENGTH', + 'GAS_LENGTH', + 'CONTENT_COMMITMENT_LENGTH', + 'GLOBAL_VARIABLES_LENGTH', + 'APPEND_ONLY_TREE_SNAPSHOT_LENGTH', + 'PARTIAL_STATE_REFERENCE_LENGTH', + 'STATE_REFERENCE_LENGTH', + 'HEADER_LENGTH', + 'CALL_CONTEXT_LENGTH', + 'PUBLIC_CONTEXT_INPUTS_LENGTH', +]; + /** * Parsed content. */ @@ -46,7 +62,7 @@ function processConstantsCpp(constants: { [key: string]: string }): string { const code: string[] = []; Object.entries(constants).forEach(([key, value]) => { // We exclude large numbers - if (!(value.startsWith('0x') || value.includes('0_0'))) { + if (CPP_CONSTANTS.includes(key) && !(value.startsWith('0x') || value.includes('0_0'))) { code.push(`const size_t ${key} = ${value};`); } }); From 8e8d2ddd5eefed4f5ca7248b882dfc3d8287d1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Mon, 20 May 2024 23:33:00 +0200 Subject: [PATCH 27/37] feat: Adding autogenerated variants for the reset circuit (#6508) This PR adds: - Autogeneration of kernel reset variants by declaring them in a json file - Updating of the nargo workspace so the new variants get compiled - Autogeneration from the same JSON of the circuits.js typings for the variants, and validation of the sizes - Updates across code to support multiple variants for the reset. However, if you add variants in the json descriptor, you'll still have to manually update `noir-protocol-circuits-types/index.ts` to add imports for the jsons of the variants (however typescript will cry in the places that you need to modify, thanks to the circuits.js autogeneration) - Updates the kernel prover to choose the appropiate variant for the hints size and trims the hints --- noir-projects/Dockerfile | 3 +- .../noir-protocol-circuits/.gitignore | 2 + .../{Nargo.toml => Nargo.template.toml} | 0 .../noir-protocol-circuits/bootstrap.sh | 3 + .../src/private_kernel_reset.nr | 21 +-- .../src/private_kernel_tail.nr | 32 +---- .../src/private_kernel_tail_to_public.nr | 14 +- .../src/main.nr | 16 ++- .../crates/private-kernel-reset/src/main.nr | 16 ++- .../src/public_kernel_tail.nr | 4 +- .../src/note_hash_read_request_reset.nr | 6 +- .../src/nullifier_read_request_reset.nr | 6 +- .../private_validation_request_processor.nr | 48 ++----- .../public_validation_request_processor.nr | 6 +- .../crates/reset-kernel-lib/src/reset.nr | 1 + .../src/reset/nullifier_key.nr | 66 +++++++++ .../note_hash_read_request_hints_builder.nr | 2 +- .../nullifier_read_request_hints_builder.nr | 2 +- noir-projects/noir-protocol-circuits/index.js | 82 ++++++++++++ .../noir-protocol-circuits/package.json | 8 ++ .../reset_variants.json | 35 +++++ .../noir-protocol-circuits/yarn.lock | 8 ++ yarn-project/.gitignore | 1 + .../src/prover/bb_native_proof_creator.ts | 9 +- yarn-project/bb-prover/src/stats.ts | 10 +- .../src/interfaces/proof_creator.ts | 4 +- yarn-project/circuit-types/src/stats/stats.ts | 5 +- yarn-project/circuits.js/package.json | 3 +- ...build_note_hash_read_request_hints.test.ts | 23 +++- .../build_note_hash_read_request_hints.ts | 6 +- ...build_nullifier_read_request_hints.test.ts | 21 ++- .../build_nullifier_read_request_hints.ts | 12 +- .../src/scripts/generate_reset_variants.ts | 125 ++++++++++++++++++ yarn-project/circuits.js/src/structs/index.ts | 1 + ...ate_kernel_reset_circuit_private_inputs.ts | 122 ++++++++++++++--- ...blic_kernel_tail_circuit_private_inputs.ts | 13 +- .../src/structs/read_request_hints/index.ts | 1 + .../note_hash_read_request_hints.ts | 40 +++--- .../read_request_hints/nullifier_key_hint.ts | 20 +++ .../nullifier_read_request_hints.ts | 36 +++-- .../read_request_hints/read_request_hints.ts | 14 ++ .../circuits.js/src/tests/factories.ts | 2 +- .../noir-protocol-circuits-types/src/index.ts | 90 ++++++++----- .../src/scripts/generate_ts_from_abi.ts | 12 +- .../src/type_conversion.ts | 86 ++++++++++-- .../pxe/src/kernel_prover/kernel_prover.ts | 16 +-- .../build_private_kernel_reset_hints.ts | 112 +++++++++++++--- .../private_inputs_builders/index.ts | 2 +- .../kernel_prover/test/test_circuit_prover.ts | 8 +- .../simulator/src/public/hints_builder.ts | 14 +- 50 files changed, 918 insertions(+), 271 deletions(-) rename noir-projects/noir-protocol-circuits/{Nargo.toml => Nargo.template.toml} (100%) create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr create mode 100644 noir-projects/noir-protocol-circuits/index.js create mode 100644 noir-projects/noir-protocol-circuits/package.json create mode 100644 noir-projects/noir-protocol-circuits/reset_variants.json create mode 100644 noir-projects/noir-protocol-circuits/yarn.lock create mode 100644 yarn-project/circuits.js/src/scripts/generate_reset_variants.ts create mode 100644 yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts diff --git a/noir-projects/Dockerfile b/noir-projects/Dockerfile index 574738e2a1b..ab4c6270e97 100644 --- a/noir-projects/Dockerfile +++ b/noir-projects/Dockerfile @@ -2,7 +2,8 @@ FROM aztecprotocol/noir as noir FROM aztecprotocol/avm-transpiler as transpiler FROM ubuntu:lunar AS builder -RUN apt-get update && apt-get install -y parallel +RUN apt-get update && apt-get install -y parallel nodejs npm +RUN npm install --global yarn # Copy in nargo COPY --from=noir /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo ENV PATH="/usr/src/noir/noir-repo/target/release:${PATH}" diff --git a/noir-projects/noir-protocol-circuits/.gitignore b/noir-projects/noir-protocol-circuits/.gitignore index b8a74c10108..9ff1b82cda5 100644 --- a/noir-projects/noir-protocol-circuits/.gitignore +++ b/noir-projects/noir-protocol-circuits/.gitignore @@ -1,3 +1,5 @@ Prover.toml Verifier.toml target +crates/autogenerated +Nargo.toml \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/Nargo.toml b/noir-projects/noir-protocol-circuits/Nargo.template.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/Nargo.toml rename to noir-projects/noir-protocol-circuits/Nargo.template.toml diff --git a/noir-projects/noir-protocol-circuits/bootstrap.sh b/noir-projects/noir-protocol-circuits/bootstrap.sh index e647f07b80f..735ac9e1982 100755 --- a/noir-projects/noir-protocol-circuits/bootstrap.sh +++ b/noir-projects/noir-protocol-circuits/bootstrap.sh @@ -15,6 +15,9 @@ if [ -n "$CMD" ]; then fi fi +yarn +node ./index.js + echo "Compiling protocol circuits..." NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} $NARGO compile --silence-warnings \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr index db96da72dbb..d43ae5e907d 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr @@ -1,7 +1,7 @@ use crate::private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer; use dep::reset_kernel_lib::{ NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor, - verify_squashed_transient_note_hashes_and_nullifiers + verify_squashed_transient_note_hashes_and_nullifiers, reset::nullifier_key::NullifierKeyHint }; use dep::types::{ abis::{ @@ -25,22 +25,22 @@ struct PrivateKernelResetOutputs { note_encrypted_log_hashes: [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], } -struct PrivateKernelResetHints { +struct PrivateKernelResetHints { transient_nullifier_indexes_for_note_hashes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], transient_note_hash_indexes_for_nullifiers: [u64; MAX_NEW_NULLIFIERS_PER_TX], transient_note_hash_indexes_for_logs: [u64; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - note_hash_read_request_hints: NoteHashReadRequestHints, - nullifier_read_request_hints: NullifierReadRequestHints, - master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + note_hash_read_request_hints: NoteHashReadRequestHints, + nullifier_read_request_hints: NullifierReadRequestHints, + master_nullifier_secret_keys: [NullifierKeyHint; NLL_KEYS], } -struct PrivateKernelResetCircuitPrivateInputs { +struct PrivateKernelResetCircuitPrivateInputs { previous_kernel: PrivateKernelData, outputs: PrivateKernelResetOutputs, - hints: PrivateKernelResetHints, + hints: PrivateKernelResetHints, } -impl PrivateKernelResetCircuitPrivateInputs { +impl PrivateKernelResetCircuitPrivateInputs { pub fn execute(self) -> PrivateKernelCircuitPublicInputs { let mut previous_public_inputs = self.previous_kernel.public_inputs; @@ -86,7 +86,8 @@ mod tests { nullifier_read_request_hints_builder::NullifierReadRequestHintsBuilder, squash_transient_data::{squash_transient_note_hashes, squash_transient_nullifiers, squash_transient_logs} }, - reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus} + reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus}, + reset::nullifier_key::NullifierKeyHint }; use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, @@ -178,7 +179,7 @@ mod tests { transient_note_hash_indexes_for_logs: self.transient_note_hash_indexes_for_logs, note_hash_read_request_hints: self.note_hash_read_request_hints_builder.to_hints(), nullifier_read_request_hints: self.nullifier_read_request_hints_builder.to_hints(), - master_nullifier_secret_keys: [GrumpkinPrivateKey::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX] + master_nullifier_secret_keys: [NullifierKeyHint::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX] }; let kernel = PrivateKernelResetCircuitPrivateInputs { previous_kernel: self.previous_kernel.to_private_kernel_data(), outputs, hints }; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 3c887b05361..b35cb1e6d86 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -92,11 +92,6 @@ mod tests { // TODO: Reduce the duplicated code/tests for PrivateKernelTailInputs and PrivateKernelTailToPublicInputs. struct PrivateKernelTailInputsBuilder { previous_kernel: FixtureBuilder, - transient_nullifier_indexes_for_note_hashes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u64; MAX_NEW_NULLIFIERS_PER_TX], - transient_note_hash_indexes_for_logs: [u64; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, } impl PrivateKernelTailInputsBuilder { @@ -106,14 +101,7 @@ mod tests { previous_kernel.append_new_nullifiers(1); - PrivateKernelTailInputsBuilder { - previous_kernel, - transient_nullifier_indexes_for_note_hashes: [MAX_NEW_NULLIFIERS_PER_TX; MAX_NEW_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [MAX_NEW_NOTE_HASHES_PER_TX; MAX_NEW_NULLIFIERS_PER_TX], - transient_note_hash_indexes_for_logs: [MAX_NEW_NOTE_HASHES_PER_TX; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder::new(MAX_NOTE_HASH_READ_REQUESTS_PER_TX), - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX) - } + PrivateKernelTailInputsBuilder { previous_kernel } } // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed @@ -177,24 +165,6 @@ mod tests { let sorted_unencrypted_log_hashes = sorted.sorted_array; let sorted_unencrypted_log_hashes_indexes = sorted.sorted_index_hints; - let mut sorted_transient_nullifier_indexes_for_note_hashes = [MAX_NEW_NULLIFIERS_PER_TX; MAX_NEW_NOTE_HASHES_PER_TX]; - for i in 0..self.transient_nullifier_indexes_for_note_hashes.len() { - let old_index = self.transient_nullifier_indexes_for_note_hashes[i]; - if old_index != MAX_NEW_NULLIFIERS_PER_TX { - let new_note_hash_index = sorted_new_note_hashes_indexes[i]; - sorted_transient_nullifier_indexes_for_note_hashes[new_note_hash_index] = sorted_new_nullifiers_indexes[old_index]; - } - } - - let mut sorted_transient_note_hash_indexes_for_nullifiers = [MAX_NEW_NOTE_HASHES_PER_TX; MAX_NEW_NULLIFIERS_PER_TX]; - for i in 0..self.transient_note_hash_indexes_for_nullifiers.len() { - let old_index = self.transient_note_hash_indexes_for_nullifiers[i]; - if old_index != MAX_NEW_NOTE_HASHES_PER_TX { - let new_nullifier_index = sorted_new_nullifiers_indexes[i]; - sorted_transient_note_hash_indexes_for_nullifiers[new_nullifier_index] = sorted_new_note_hashes_indexes[old_index]; - } - } - let hints = PrivateKernelTailHints { sorted_new_note_hashes, sorted_new_note_hashes_indexes, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index a50185244a1..8e8993d4bb2 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -89,11 +89,6 @@ mod tests { // TODO: Reduce the duplicated code/tests for PrivateKernelTailToPublicInputs and PrivateKernelTailInputs. struct PrivateKernelTailToPublicInputsBuilder { previous_kernel: FixtureBuilder, - transient_nullifier_indexes_for_note_hashes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u64; MAX_NEW_NULLIFIERS_PER_TX], - transient_note_hash_indexes_for_logs: [u64; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, } impl PrivateKernelTailToPublicInputsBuilder { @@ -103,14 +98,7 @@ mod tests { previous_kernel.append_new_nullifiers(1); previous_kernel.push_public_call_request(1, false); - PrivateKernelTailToPublicInputsBuilder { - previous_kernel, - transient_nullifier_indexes_for_note_hashes: [MAX_NEW_NULLIFIERS_PER_TX; MAX_NEW_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [MAX_NEW_NOTE_HASHES_PER_TX; MAX_NEW_NULLIFIERS_PER_TX], - transient_note_hash_indexes_for_logs: [MAX_NEW_NOTE_HASHES_PER_TX; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder::new(MAX_NOTE_HASH_READ_REQUESTS_PER_TX), - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX) - } + PrivateKernelTailToPublicInputsBuilder { previous_kernel } } // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr index 36b736b9ea7..2d4947cfcef 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr @@ -1,6 +1,18 @@ use dep::private_kernel_lib::PrivateKernelResetCircuitPrivateInputs; -use dep::types::PrivateKernelCircuitPublicInputs; +use dep::types::{ + PrivateKernelCircuitPublicInputs, + constants::{ + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX +} +}; + +global NOTE_HASH_PENDING_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; // 128 +global NOTE_HASH_SETTLED_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; +global NULLIFIER_PENDING_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; // 8 +global NULLIFIER_SETTLED_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; +global NULLIFIER_KEYS = MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX; // 4 -unconstrained fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +unconstrained fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr index fddb8407810..d39fcc38ecf 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr @@ -1,7 +1,19 @@ use dep::private_kernel_lib::PrivateKernelResetCircuitPrivateInputs; -use dep::types::PrivateKernelCircuitPublicInputs; +use dep::types::{ + PrivateKernelCircuitPublicInputs, + constants::{ + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX +} +}; + +global NOTE_HASH_PENDING_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; // 128 +global NOTE_HASH_SETTLED_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; +global NULLIFIER_PENDING_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; // 8 +global NULLIFIER_SETTLED_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; +global NULLIFIER_KEYS = MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX; // 4 #[recursive] -fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 632555d5307..a7c0da2114f 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -8,14 +8,14 @@ use dep::types::{ accumulated_data::CombinedAccumulatedData, kernel_circuit_public_inputs::KernelCircuitPublicInputs, public_kernel_data::PublicKernelData }, - constants::MAX_PUBLIC_DATA_HINTS, + constants::{MAX_PUBLIC_DATA_HINTS, MAX_NULLIFIER_READ_REQUESTS_PER_TX}, merkle_tree::{conditionally_assert_check_membership, MembershipWitness}, partial_state_reference::PartialStateReference, utils::{arrays::array_length} }; struct PublicKernelTailCircuitPrivateInputs { previous_kernel: PublicKernelData, - nullifier_read_request_hints: NullifierReadRequestHints, + nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, public_data_hints: [PublicDataHint; MAX_PUBLIC_DATA_HINTS], public_data_read_request_hints: PublicDataReadRequestHints, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr index cb105f6543c..073cdfd825d 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr @@ -36,10 +36,10 @@ impl SettledReadHint for NoteHashSe } } -struct NoteHashReadRequestHints { +struct NoteHashReadRequestHints { read_request_statuses: [ReadRequestStatus; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - pending_read_hints: [PendingReadHint; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - settled_read_hints: [NoteHashSettledReadHint; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], + pending_read_hints: [PendingReadHint; PENDING], + settled_read_hints: [NoteHashSettledReadHint; SETTLED], } mod tests { diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr index e7363f828c4..48f81f127e6 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr @@ -36,10 +36,10 @@ impl SettledReadHint for Nullifier } } -struct NullifierReadRequestHints { +struct NullifierReadRequestHints { read_request_statuses: [ReadRequestStatus; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - pending_read_hints: [PendingReadHint; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - settled_read_hints: [NullifierSettledReadHint; MAX_NULLIFIER_READ_REQUESTS_PER_TX], + pending_read_hints: [PendingReadHint; PENDING], + settled_read_hints: [NullifierSettledReadHint; SETTLED], } mod tests { diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr index d8516c91ae2..877112c0dd1 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr @@ -1,6 +1,7 @@ use crate::{ note_hash_read_request_reset::NoteHashReadRequestHints, - nullifier_read_request_reset::NullifierReadRequestHints, reset::read_request::reset_read_requests + nullifier_read_request_reset::NullifierReadRequestHints, reset::read_request::reset_read_requests, + reset::nullifier_key::{NullifierKeyHint, reset_nullifier_keys} }; use dep::types::{ abis::{ @@ -16,18 +17,18 @@ use dep::types::{ utils::arrays::filter_array_to_bounded_vec }; -struct PrivateValidationRequestProcessor { +struct PrivateValidationRequestProcessor { validation_requests: ValidationRequests, - note_hash_read_request_hints: NoteHashReadRequestHints, + note_hash_read_request_hints: NoteHashReadRequestHints, pending_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], note_hash_tree_root: Field, - nullifier_read_request_hints: NullifierReadRequestHints, + nullifier_read_request_hints: NullifierReadRequestHints, pending_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], nullifier_tree_root: Field, - master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + master_nullifier_secret_keys: [NullifierKeyHint; NLL_KEYS], } -impl PrivateValidationRequestProcessor { +impl PrivateValidationRequestProcessor { pub fn validate(self) -> ValidationRequests { let remaining_note_hash_read_requests = self.validate_note_hash_read_requests(); let remaining_nullifier_read_requests = self.validate_nullifier_read_requests(); @@ -66,36 +67,9 @@ impl PrivateValidationRequestProcessor { } fn validate_nullifier_keys(self) -> BoundedVec { - let mut should_propagate = [false; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX]; - let requests = self.validation_requests.nullifier_key_validation_requests; - for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { - let request = requests[i].request; - if !is_empty(request) { - let contract_address = requests[i].contract_address; - let master_nullifier_secret_key = self.master_nullifier_secret_keys[i]; - if !is_empty(master_nullifier_secret_key) { - // First we check that derived public key matches master nullifier public key from request - let master_nullifier_public_key = master_nullifier_secret_key.derive_public_key(); - assert( - master_nullifier_public_key.eq(request.master_nullifier_public_key), "Failed to derive matching master nullifier public key from the secret key." - ); - - // Then we check that siloing the master secret key with the contract address gives the app nullifier secret key - - let app_nullifier_secret_key = poseidon2_hash( - [ - master_nullifier_secret_key.high, master_nullifier_secret_key.low, contract_address.to_field(), GENERATOR_INDEX__NSK_M - ] - ); - assert( - app_nullifier_secret_key.eq(request.app_nullifier_secret_key), "Failed to derive matching app nullifier secret key from the secret key." - ); - } else { - should_propagate[i] = true; - } - } - } - - filter_array_to_bounded_vec(requests, should_propagate) + reset_nullifier_keys( + self.validation_requests.nullifier_key_validation_requests, + self.master_nullifier_secret_keys + ) } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr index a25b760e1d4..787a8ebc630 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr @@ -12,7 +12,7 @@ use dep::types::{ kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, nullifier::Nullifier, public_data_update_request::PublicDataUpdateRequest, validation_requests::ValidationRequests }, - constants::{MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX}, + constants::{MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX}, hash::silo_nullifier, traits::is_empty, utils::arrays::{array_merge, array_to_bounded_vec, assert_sorted_array} }; @@ -21,7 +21,7 @@ struct PublicValidationRequestProcessor { validation_requests: ValidationRequests, pending_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], pending_public_data_writes: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - nullifier_read_request_hints: NullifierReadRequestHints, + nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, nullifier_tree_root: Field, public_data_read_request_hints: PublicDataReadRequestHints, @@ -31,7 +31,7 @@ struct PublicValidationRequestProcessor { impl PublicValidationRequestProcessor { pub fn new( public_inputs: PublicKernelCircuitPublicInputs, - nullifier_read_request_hints: NullifierReadRequestHints, + nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, nullifier_tree_root: Field, public_data_read_request_hints: PublicDataReadRequestHints, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr index 92b72993869..740cbc359fb 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr @@ -2,3 +2,4 @@ mod mutable_data_read_request; mod non_existent_read_request; mod read_request; mod transient_data; +mod nullifier_key; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr new file mode 100644 index 00000000000..91207ddb717 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr @@ -0,0 +1,66 @@ +use crate::{nullifier_read_request_reset::NullifierReadRequestHints}; +use dep::types::{ + traits::{Empty, is_empty}, + abis::{nullifier_key_validation_request::ScopedNullifierKeyValidationRequest}, + constants::{MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GENERATOR_INDEX__NSK_M}, + grumpkin_private_key::GrumpkinPrivateKey, hash::poseidon2_hash, + utils::arrays::filter_array_to_bounded_vec +}; + +struct NullifierKeyHint { + private_key: GrumpkinPrivateKey, + request_index: u64, +} + +impl Empty for NullifierKeyHint { + fn empty() -> Self { + NullifierKeyHint { + private_key: GrumpkinPrivateKey::empty(), + request_index: 0, + } + } +} + +impl Eq for NullifierKeyHint { + fn eq(self, other: Self) -> bool { + self.private_key.eq(other.private_key) & self.request_index.eq(other.request_index) + } + +} + +pub fn reset_nullifier_keys( + nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + key_hints: [NullifierKeyHint; N] +) -> BoundedVec { + let mut should_propagate = nullifier_key_validation_requests.map(|req| !is_empty(req)); + for i in 0..N { + let hint = key_hints[i]; + if !is_empty(hint) { + let scoped_request = nullifier_key_validation_requests[hint.request_index]; + let contract_address = scoped_request.contract_address; + let request = scoped_request.request; + let master_nullifier_secret_key = hint.private_key; + + // First we check that derived public key matches master nullifier public key from request + let master_nullifier_public_key = master_nullifier_secret_key.derive_public_key(); + assert( + master_nullifier_public_key.eq(request.master_nullifier_public_key), "Failed to derive matching master nullifier public key from the secret key." + ); + + // Then we check that siloing the master secret key with the contract address gives the app nullifier secret key + + let app_nullifier_secret_key = poseidon2_hash( + [ + master_nullifier_secret_key.high, master_nullifier_secret_key.low, contract_address.to_field(), GENERATOR_INDEX__NSK_M + ] + ); + assert( + app_nullifier_secret_key.eq(request.app_nullifier_secret_key), "Failed to derive matching app nullifier secret key from the secret key." + ); + + should_propagate[hint.request_index] = false; + } + } + + filter_array_to_bounded_vec(nullifier_key_validation_requests, should_propagate) +} diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr index 4153aff1344..72862ea7ff6 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr @@ -22,7 +22,7 @@ impl NoteHashReadRequestHintsBuilder { } } - pub fn to_hints(self) -> NoteHashReadRequestHints { + pub fn to_hints(self) -> NoteHashReadRequestHints { NoteHashReadRequestHints { read_request_statuses: self.read_request_statuses, pending_read_hints: self.pending_read_hints.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr index d9640b2ee09..46142a29a38 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr @@ -22,7 +22,7 @@ impl NullifierReadRequestHintsBuilder { } } - pub fn to_hints(self) -> NullifierReadRequestHints { + pub fn to_hints(self) -> NullifierReadRequestHints { NullifierReadRequestHints { read_request_statuses: self.read_request_statuses, pending_read_hints: self.pending_read_hints.storage, diff --git a/noir-projects/noir-protocol-circuits/index.js b/noir-projects/noir-protocol-circuits/index.js new file mode 100644 index 00000000000..a57793eae85 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/index.js @@ -0,0 +1,82 @@ +const TOML = require("@iarna/toml"); +const fs = require("fs"); +const path = require("path"); + +const nargoTomlTemplate = TOML.parse( + fs.readFileSync("./Nargo.template.toml", "utf8") +); +const autogeneratedCircuitsPath = path.join(__dirname, "crates/autogenerated"); + +if (fs.existsSync(autogeneratedCircuitsPath)) { + fs.rmSync(autogeneratedCircuitsPath, { recursive: true }); +} +fs.mkdirSync(autogeneratedCircuitsPath); + +function generateResetVariants() { + const resetVariants = require("./reset_variants.json"); + + generateVariants("private-kernel-reset", resetVariants); + generateVariants("private-kernel-reset-simulated", resetVariants); +} + +function generateVariants(originalFolder, variantsArray) { + const originalCrateFolder = path.join(__dirname, "crates", originalFolder); + const originalNargoToml = TOML.parse( + fs.readFileSync(path.join(originalCrateFolder, "Nargo.toml"), "utf8") + ); + const originalName = originalNargoToml.package.name; + + for ({ tag, replacements } of variantsArray) { + const variantFolder = `${originalFolder}-${tag}`; + const variantNargoToml = structuredClone(originalNargoToml); + for ([depName, depDescriptor] of Object.entries( + variantNargoToml.dependencies + )) { + if (depDescriptor.path) { + depDescriptor.path = "../" + depDescriptor.path; + } + } + variantNargoToml.package.name = `${originalName}_${tag}`; + + let mainDotNoirCode = fs.readFileSync( + path.join(originalCrateFolder, "src/main.nr"), + "utf8" + ); + + for ([variableName, variableValue] of Object.entries(replacements)) { + mainDotNoirCode = mainDotNoirCode.replace( + new RegExp(`^global\\s+${variableName}\\s=\\s.*;.*$`, "m"), + `global ${variableName} = ${variableValue};` + ); + } + + fs.mkdirSync(path.join(autogeneratedCircuitsPath, variantFolder, "src"), { + recursive: true, + }); + + fs.writeFileSync( + path.join(autogeneratedCircuitsPath, variantFolder, "src/main.nr"), + mainDotNoirCode + ); + + fs.writeFileSync( + path.join(autogeneratedCircuitsPath, variantFolder, "Nargo.toml"), + TOML.stringify(variantNargoToml) + ); + } +} + +generateResetVariants(); + +for (entry of fs.readdirSync(autogeneratedCircuitsPath)) { + nargoTomlTemplate.workspace.members.push( + path.relative(__dirname, path.join(autogeneratedCircuitsPath, entry)) + ); +} + +fs.writeFileSync( + "./Nargo.toml", + `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n${TOML.stringify( + nargoTomlTemplate + )}` +); diff --git a/noir-projects/noir-protocol-circuits/package.json b/noir-projects/noir-protocol-circuits/package.json new file mode 100644 index 00000000000..5e0598e8ce7 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/package.json @@ -0,0 +1,8 @@ +{ + "name": "noir-protocol-circuits-generator", + "version": "0.0.0", + "main": "index.js", + "dependencies": { + "@iarna/toml": "^2.2.5" + } +} \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/reset_variants.json b/noir-projects/noir-protocol-circuits/reset_variants.json new file mode 100644 index 00000000000..d241396dece --- /dev/null +++ b/noir-projects/noir-protocol-circuits/reset_variants.json @@ -0,0 +1,35 @@ +[ + { + "tag": "big", + "priority": 98, + "replacements": { + "NOTE_HASH_PENDING_AMOUNT": 64, + "NOTE_HASH_SETTLED_AMOUNT": 64, + "NULLIFIER_PENDING_AMOUNT": 64, + "NULLIFIER_SETTLED_AMOUNT": 64, + "NULLIFIER_KEYS": 4 + } + }, + { + "tag": "medium", + "priority": 99, + "replacements": { + "NOTE_HASH_PENDING_AMOUNT": 32, + "NOTE_HASH_SETTLED_AMOUNT": 32, + "NULLIFIER_PENDING_AMOUNT": 32, + "NULLIFIER_SETTLED_AMOUNT": 32, + "NULLIFIER_KEYS": 4 + } + }, + { + "tag": "small", + "priority": 100, + "replacements": { + "NOTE_HASH_PENDING_AMOUNT": 16, + "NOTE_HASH_SETTLED_AMOUNT": 16, + "NULLIFIER_PENDING_AMOUNT": 16, + "NULLIFIER_SETTLED_AMOUNT": 16, + "NULLIFIER_KEYS": 2 + } + } +] \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/yarn.lock b/noir-projects/noir-protocol-circuits/yarn.lock new file mode 100644 index 00000000000..f411a21e2d6 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@iarna/toml@^2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" + integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== diff --git a/yarn-project/.gitignore b/yarn-project/.gitignore index 7c86855f16a..e92d481c252 100644 --- a/yarn-project/.gitignore +++ b/yarn-project/.gitignore @@ -18,6 +18,7 @@ aztec-node/data* aztec-js/src/account_contract/artifacts aztec/log circuits.js/fixtures/*.json +circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs_variants.ts docs/dist end-to-end/addresses.json end-to-end/log diff --git a/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts b/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts index 5e76f59f489..5b904dd4a68 100644 --- a/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts +++ b/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts @@ -7,7 +7,7 @@ import { type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, - type PrivateKernelResetCircuitPrivateInputs, + type PrivateKernelResetCircuitPrivateInputsVariants, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, Proof, @@ -24,6 +24,7 @@ import { Timer } from '@aztec/foundation/timer'; import { ClientCircuitArtifacts, type ClientProtocolArtifact, + PrivateResetTagToArtifactName, convertPrivateKernelInitInputsToWitnessMap, convertPrivateKernelInitOutputsFromWitnessMap, convertPrivateKernelInnerInputsToWitnessMap, @@ -110,13 +111,13 @@ export class BBNativeProofCreator implements ProofCreator { } public async createProofReset( - inputs: PrivateKernelResetCircuitPrivateInputs, + inputs: PrivateKernelResetCircuitPrivateInputsVariants, ): Promise> { return await this.createSafeProof( inputs, - 'PrivateKernelResetArtifact', + PrivateResetTagToArtifactName[inputs.sizeTag], convertPrivateKernelResetInputsToWitnessMap, - convertPrivateKernelResetOutputsFromWitnessMap, + output => convertPrivateKernelResetOutputsFromWitnessMap(output, inputs.sizeTag), ); } diff --git a/yarn-project/bb-prover/src/stats.ts b/yarn-project/bb-prover/src/stats.ts index 9627d0db8f9..ad52f26d869 100644 --- a/yarn-project/bb-prover/src/stats.ts +++ b/yarn-project/bb-prover/src/stats.ts @@ -47,8 +47,14 @@ export function mapProtocolArtifactNameToCircuitName( return 'private-kernel-tail'; case 'PrivateKernelTailToPublicArtifact': return 'private-kernel-tail-to-public'; - case 'PrivateKernelResetArtifact': - return 'private-kernel-reset'; + case 'PrivateKernelResetFullArtifact': + return 'private-kernel-reset-full'; + case 'PrivateKernelResetBigArtifact': + return 'private-kernel-reset-big'; + case 'PrivateKernelResetMediumArtifact': + return 'private-kernel-reset-medium'; + case 'PrivateKernelResetSmallArtifact': + return 'private-kernel-reset-small'; default: throw new Error(`Unknown circuit type: ${artifact}`); } diff --git a/yarn-project/circuit-types/src/interfaces/proof_creator.ts b/yarn-project/circuit-types/src/interfaces/proof_creator.ts index 7a3ef4042dc..82c57b993c2 100644 --- a/yarn-project/circuit-types/src/interfaces/proof_creator.ts +++ b/yarn-project/circuit-types/src/interfaces/proof_creator.ts @@ -4,7 +4,7 @@ import { type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, - type PrivateKernelResetCircuitPrivateInputs, + type PrivateKernelResetCircuitPrivateInputsVariants, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, type RECURSIVE_PROOF_LENGTH, @@ -85,7 +85,7 @@ export interface ProofCreator { * @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof. */ createProofReset( - privateKernelInputsReset: PrivateKernelResetCircuitPrivateInputs, + privateKernelInputsReset: PrivateKernelResetCircuitPrivateInputsVariants, ): Promise>; /** diff --git a/yarn-project/circuit-types/src/stats/stats.ts b/yarn-project/circuit-types/src/stats/stats.ts index 750735d8cef..09843ab2b03 100644 --- a/yarn-project/circuit-types/src/stats/stats.ts +++ b/yarn-project/circuit-types/src/stats/stats.ts @@ -56,7 +56,10 @@ export type CircuitName = | 'root-rollup' | 'private-kernel-init' | 'private-kernel-inner' - | 'private-kernel-reset' + | 'private-kernel-reset-full' + | 'private-kernel-reset-big' + | 'private-kernel-reset-medium' + | 'private-kernel-reset-small' | 'private-kernel-tail' | 'private-kernel-tail-to-public' | 'app-circuit' diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index 92b5928fc87..84f9e873016 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -30,7 +30,8 @@ }, "scripts": { "build": "yarn clean && yarn generate && tsc -b", - "generate": "./scripts/copy-contracts.sh", + "generate": "./scripts/copy-contracts.sh && yarn generate:reset-variants", + "generate:reset-variants": "node --no-warnings --loader ts-node/esm src/scripts/generate_reset_variants.ts && prettier -w src/structs/kernel/private_kernel_reset_circuit_private_inputs_variants.ts", "build:dev": "tsc -b --watch", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", diff --git a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts index 831c6d70a82..d56371e9f13 100644 --- a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts @@ -30,7 +30,10 @@ describe('buildNoteHashReadRequestHints', () => { let noteHashReadRequests: Tuple; let noteHashes: Tuple; let noteHashLeafIndexMap: Map = new Map(); - let expectedHints: NoteHashReadRequestHints; + let expectedHints: NoteHashReadRequestHints< + typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX + >; let numReadRequests = 0; let numPendingReads = 0; let numSettledReads = 0; @@ -64,14 +67,26 @@ describe('buildNoteHashReadRequestHints', () => { numSettledReads++; }; - const buildHints = () => - buildNoteHashReadRequestHints(oracle, noteHashReadRequests, noteHashes, noteHashLeafIndexMap); + const buildHints = async () => + ( + await buildNoteHashReadRequestHints( + oracle, + noteHashReadRequests, + noteHashes, + noteHashLeafIndexMap, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + ) + ).hints; beforeEach(() => { noteHashReadRequests = makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ScopedReadRequest.empty); noteHashes = makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, i => makeNoteHash(innerNoteHash(i))); noteHashLeafIndexMap = new Map(); - expectedHints = NoteHashReadRequestHintsBuilder.empty(); + expectedHints = NoteHashReadRequestHintsBuilder.empty( + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + ); numReadRequests = 0; numPendingReads = 0; numSettledReads = 0; diff --git a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts index 7fdfda24591..0c09f523b4c 100644 --- a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts @@ -22,15 +22,17 @@ function isValidNoteHashReadRequest(readRequest: ScopedReadRequest, noteHash: Sc ); } -export async function buildNoteHashReadRequestHints( +export async function buildNoteHashReadRequestHints( oracle: { getNoteHashMembershipWitness(leafIndex: bigint): Promise>; }, noteHashReadRequests: Tuple, noteHashes: Tuple, noteHashLeafIndexMap: Map, + sizePending: PENDING, + sizeSettled: SETTLED, ) { - const builder = new NoteHashReadRequestHintsBuilder(); + const builder = new NoteHashReadRequestHintsBuilder(sizePending, sizeSettled); const numReadRequests = countAccumulatedItems(noteHashReadRequests); diff --git a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts index bec3d9d5a8b..776f2324455 100644 --- a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts @@ -26,7 +26,10 @@ describe('buildNullifierReadRequestHints', () => { }; let nullifierReadRequests: Tuple; let nullifiers: Tuple; - let expectedHints: NullifierReadRequestHints; + let expectedHints: NullifierReadRequestHints< + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX + >; let numReadRequests = 0; let numPendingReads = 0; let numSettledReads = 0; @@ -69,12 +72,24 @@ describe('buildNullifierReadRequestHints', () => { numSettledReads++; }; - const buildHints = () => buildNullifierReadRequestHints(oracle, nullifierReadRequests, nullifiers); + const buildHints = async () => + ( + await buildNullifierReadRequestHints( + oracle, + nullifierReadRequests, + nullifiers, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + ) + ).hints; beforeEach(() => { nullifierReadRequests = makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest.empty); nullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => makeNullifier(innerNullifier(i))); - expectedHints = NullifierReadRequestHintsBuilder.empty(); + expectedHints = NullifierReadRequestHintsBuilder.empty( + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + ); numReadRequests = 0; numPendingReads = 0; numSettledReads = 0; diff --git a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts index 9a1cbb38ae8..a10401c80ef 100644 --- a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts @@ -25,15 +25,17 @@ interface NullifierMembershipWitnessWithPreimage { leafPreimage: IndexedTreeLeafPreimage; } -export async function buildNullifierReadRequestHints( +export async function buildNullifierReadRequestHints( oracle: { getNullifierMembershipWitness(nullifier: Fr): Promise; }, nullifierReadRequests: Tuple, nullifiers: Tuple, + sizePending: PENDING, + sizeSettled: SETTLED, siloed = false, ) { - const builder = new NullifierReadRequestHintsBuilder(); + const builder = new NullifierReadRequestHintsBuilder(sizePending, sizeSettled); const numReadRequests = countAccumulatedItems(nullifierReadRequests); @@ -69,12 +71,14 @@ export async function buildNullifierReadRequestHints( return builder.toHints(); } -export function buildSiloedNullifierReadRequestHints( +export function buildSiloedNullifierReadRequestHints( oracle: { getNullifierMembershipWitness(nullifier: Fr): Promise; }, nullifierReadRequests: Tuple, nullifiers: Tuple, + sizePending: PENDING, + sizeSettled: SETTLED, ) { // Nullifiers outputted from public kernels are already siloed while read requests are not. // Siloing the read request values and set the contract addresses to zero to find the matching nullifier contexts. @@ -90,5 +94,5 @@ export function buildSiloedNullifierReadRequestHints( new Nullifier(n.value, n.counter, n.noteHash).scope(AztecAddress.ZERO), ) as Tuple; - return buildNullifierReadRequestHints(oracle, siloedReadRequests, scopedNullifiers, true); + return buildNullifierReadRequestHints(oracle, siloedReadRequests, scopedNullifiers, sizePending, sizeSettled, true); } diff --git a/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts b/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts new file mode 100644 index 00000000000..90380d66b08 --- /dev/null +++ b/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts @@ -0,0 +1,125 @@ +import fs from 'fs'; +import path from 'path'; + +import { + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, +} from '../constants.gen.js'; + +interface ResetVariant { + tag: string; + priority: number; + replacements: { + NOTE_HASH_PENDING_AMOUNT: number; + NOTE_HASH_SETTLED_AMOUNT: number; + NULLIFIER_PENDING_AMOUNT: number; + NULLIFIER_SETTLED_AMOUNT: number; + NULLIFIER_KEYS: number; + }; +} + +const prelude = ` +// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +import { + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, +} from '../../constants.gen.js'; +import type { PrivateKernelResetCircuitPrivateInputs } from './private_kernel_reset_circuit_private_inputs.js'; +`; + +function buildPrivateResetVariantsObject(variants: ResetVariant[]): string { + let output = 'export const PRIVATE_RESET_VARIANTS = {'; + + for (const variant of variants) { + output += ` + ${variant.tag}: { + NOTE_HASH_PENDING_AMOUNT: ${variant.replacements.NOTE_HASH_PENDING_AMOUNT}, + NOTE_HASH_SETTLED_AMOUNT: ${variant.replacements.NOTE_HASH_SETTLED_AMOUNT}, + NULLIFIER_PENDING_AMOUNT: ${variant.replacements.NULLIFIER_PENDING_AMOUNT}, + NULLIFIER_SETTLED_AMOUNT: ${variant.replacements.NULLIFIER_SETTLED_AMOUNT}, + NULLIFIER_KEYS: ${variant.replacements.NULLIFIER_KEYS}, + },`; + } + + output += ` + full: { + NOTE_HASH_PENDING_AMOUNT: MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + NOTE_HASH_SETTLED_AMOUNT: MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + NULLIFIER_PENDING_AMOUNT: MAX_NULLIFIER_READ_REQUESTS_PER_TX, + NULLIFIER_SETTLED_AMOUNT: MAX_NULLIFIER_READ_REQUESTS_PER_TX, + NULLIFIER_KEYS: MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + }, + } as const;\n`; + return output; +} + +function buildPrivateResetVariantsType(variants: ResetVariant[]): string { + let output = 'export type PrivateKernelResetCircuitPrivateInputsVariants =\n'; + + for (const variant of variants) { + output += ` + | PrivateKernelResetCircuitPrivateInputs< + ${variant.replacements.NOTE_HASH_PENDING_AMOUNT}, + ${variant.replacements.NOTE_HASH_SETTLED_AMOUNT}, + ${variant.replacements.NULLIFIER_PENDING_AMOUNT}, + ${variant.replacements.NULLIFIER_SETTLED_AMOUNT}, + ${variant.replacements.NULLIFIER_KEYS}, + '${variant.tag}' + > + `; + } + + output += ` + | PrivateKernelResetCircuitPrivateInputs< + typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + 'full' + >;`; + return output; +} + +function validateVariants(variants: ResetVariant[]) { + for (const variant of variants) { + if (variant.replacements.NOTE_HASH_PENDING_AMOUNT > MAX_NOTE_HASH_READ_REQUESTS_PER_TX) { + throw new Error(`NOTE_HASH_PENDING_AMOUNT must be less than ${MAX_NOTE_HASH_READ_REQUESTS_PER_TX}`); + } + if (variant.replacements.NOTE_HASH_SETTLED_AMOUNT > MAX_NOTE_HASH_READ_REQUESTS_PER_TX) { + throw new Error(`NOTE_HASH_SETTLED_AMOUNT must be less than ${MAX_NOTE_HASH_READ_REQUESTS_PER_TX}`); + } + if (variant.replacements.NULLIFIER_PENDING_AMOUNT > MAX_NULLIFIER_READ_REQUESTS_PER_TX) { + throw new Error(`NULLIFIER_PENDING_AMOUNT must be less than ${MAX_NULLIFIER_READ_REQUESTS_PER_TX}`); + } + if (variant.replacements.NULLIFIER_SETTLED_AMOUNT > MAX_NULLIFIER_READ_REQUESTS_PER_TX) { + throw new Error(`NULLIFIER_SETTLED_AMOUNT must be less than ${MAX_NULLIFIER_READ_REQUESTS_PER_TX}`); + } + if (variant.replacements.NULLIFIER_KEYS > MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) { + throw new Error(`NULLIFIER_KEYS must be less than ${MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX}`); + } + } +} + +const resetVariants: ResetVariant[] = JSON.parse( + fs.readFileSync(path.resolve('../../noir-projects/noir-protocol-circuits/reset_variants.json'), 'utf8'), +); + +// Sort them by decreasing priority so that the bigger circuits are tried later +resetVariants.sort((a, b) => b.priority - a.priority); + +validateVariants(resetVariants); + +fs.writeFileSync( + path.resolve('./src/structs/kernel/private_kernel_reset_circuit_private_inputs_variants.ts'), + ` +${prelude} + +${buildPrivateResetVariantsObject(resetVariants)} + +export type PrivateKernelResetTags = keyof typeof PRIVATE_RESET_VARIANTS; + +${buildPrivateResetVariantsType(resetVariants)}`, +); diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index e4e2b2b4194..9d763fe68ff 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -25,6 +25,7 @@ export * from './kernel/private_kernel_circuit_public_inputs.js'; export * from './kernel/private_kernel_data.js'; export * from './kernel/private_kernel_inner_circuit_private_inputs.js'; export * from './kernel/private_kernel_reset_circuit_private_inputs.js'; +export * from './kernel/private_kernel_reset_circuit_private_inputs_variants.js'; export * from './kernel/private_kernel_tail_circuit_private_inputs.js'; export * from './kernel/private_kernel_tail_circuit_public_inputs.js'; export * from './kernel/public_call_data.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts index 980af10d329..4c15cca12fa 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts @@ -1,19 +1,17 @@ -import { GrumpkinScalar } from '@aztec/foundation/fields'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, } from '../../constants.gen.js'; -import { type GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; import { countAccumulatedItems } from '../../utils/index.js'; import { NoteLogHash } from '../log_hash.js'; import { ScopedNoteHash } from '../note_hash.js'; import { ScopedNullifier } from '../nullifier.js'; import { type NoteHashReadRequestHints, + NullifierKeyHint, type NullifierReadRequestHints, noteHashReadRequestHintsFromBuffer, nullifierReadRequestHintsFromBuffer, @@ -41,7 +39,13 @@ export class PrivateKernelResetOutputs { } } -export class PrivateKernelResetHints { +export class PrivateKernelResetHints< + NH_RR_PENDING extends number, + NH_RR_SETTLED extends number, + NLL_RR_PENDING extends number, + NLL_RR_SETTLED extends number, + NLL_KEYS extends number, +> { constructor( /** * Contains hints for the transient note hashes to locate corresponding nullifiers. @@ -58,16 +62,16 @@ export class PrivateKernelResetHints { /** * Contains hints for the transient read requests to localize corresponding commitments. */ - public noteHashReadRequestHints: NoteHashReadRequestHints, + public noteHashReadRequestHints: NoteHashReadRequestHints, /** * Contains hints for the nullifier read requests to locate corresponding pending or settled nullifiers. */ - public nullifierReadRequestHints: NullifierReadRequestHints, + public nullifierReadRequestHints: NullifierReadRequestHints, /** * The master nullifier secret keys for the nullifier key validation requests. */ - public masterNullifierSecretKeys: Tuple, + public masterNullifierSecretKeys: Tuple, ) {} toBuffer() { @@ -81,20 +85,67 @@ export class PrivateKernelResetHints { ); } + trimToSizes< + NEW_NH_RR_PENDING extends number, + NEW_NH_RR_SETTLED extends number, + NEW_NLL_RR_PENDING extends number, + NEW_NLL_RR_SETTLED extends number, + NEW_NLL_KEYS extends number, + >( + numNoteHashReadRequestPending: NEW_NH_RR_PENDING, + numNoteHashReadRequestSettled: NEW_NH_RR_SETTLED, + numNullifierReadRequestPending: NEW_NLL_RR_PENDING, + numNullifierReadRequestSettled: NEW_NLL_RR_SETTLED, + numNullifierKeys: NEW_NLL_KEYS, + ): PrivateKernelResetHints< + NEW_NH_RR_PENDING, + NEW_NH_RR_SETTLED, + NEW_NLL_RR_PENDING, + NEW_NLL_RR_SETTLED, + NEW_NLL_KEYS + > { + return new PrivateKernelResetHints( + this.transientNullifierIndexesForNoteHashes, + this.transientNoteHashIndexesForNullifiers, + this.transientNoteHashIndexesForLogs, + this.noteHashReadRequestHints.trimToSizes(numNoteHashReadRequestPending, numNoteHashReadRequestSettled), + this.nullifierReadRequestHints.trimToSizes(numNullifierReadRequestPending, numNullifierReadRequestSettled), + this.masterNullifierSecretKeys.slice(0, numNullifierKeys) as Tuple, + ); + } /** * Deserializes from a buffer or reader. * @param buffer - Buffer or reader to read from. * @returns The deserialized instance. */ - static fromBuffer(buffer: Buffer | BufferReader) { + static fromBuffer< + NH_RR_PENDING extends number, + NH_RR_SETTLED extends number, + NLL_RR_PENDING extends number, + NLL_RR_SETTLED extends number, + NLL_KEYS extends number, + >( + buffer: Buffer | BufferReader, + numNoteHashReadRequestPending: NH_RR_PENDING, + numNoteHashReadRequestSettled: NH_RR_SETTLED, + numNullifierReadRequestPending: NLL_RR_PENDING, + numNullifierReadRequestSettled: NLL_RR_SETTLED, + numNullifierKeys: NLL_KEYS, + ): PrivateKernelResetHints { const reader = BufferReader.asReader(buffer); return new PrivateKernelResetHints( reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_TX), reader.readNumbers(MAX_NEW_NULLIFIERS_PER_TX), reader.readNumbers(MAX_NOTE_ENCRYPTED_LOGS_PER_TX), - reader.readObject({ fromBuffer: noteHashReadRequestHintsFromBuffer }), - reader.readObject({ fromBuffer: nullifierReadRequestHintsFromBuffer }), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar), + reader.readObject({ + fromBuffer: buf => + noteHashReadRequestHintsFromBuffer(buf, numNoteHashReadRequestPending, numNoteHashReadRequestSettled), + }), + reader.readObject({ + fromBuffer: buf => + nullifierReadRequestHintsFromBuffer(buf, numNullifierReadRequestPending, numNullifierReadRequestSettled), + }), + reader.readArray(numNullifierKeys, NullifierKeyHint), ); } } @@ -102,14 +153,22 @@ export class PrivateKernelResetHints { /** * Input to the private kernel circuit - reset call. */ -export class PrivateKernelResetCircuitPrivateInputs { +export class PrivateKernelResetCircuitPrivateInputs< + NH_RR_PENDING extends number, + NH_RR_SETTLED extends number, + NLL_RR_PENDING extends number, + NLL_RR_SETTLED extends number, + NLL_KEYS extends number, + TAG extends string, +> { constructor( /** * The previous kernel data */ public previousKernel: PrivateKernelData, public outputs: PrivateKernelResetOutputs, - public hints: PrivateKernelResetHints, + public hints: PrivateKernelResetHints, + public sizeTag: TAG, ) {} isForPublic() { @@ -129,12 +188,45 @@ export class PrivateKernelResetCircuitPrivateInputs { * @param buffer - Buffer or reader to read from. * @returns The deserialized instance. */ - static fromBuffer(buffer: Buffer | BufferReader): PrivateKernelResetCircuitPrivateInputs { + static fromBuffer< + NH_RR_PENDING extends number, + NH_RR_SETTLED extends number, + NLL_RR_PENDING extends number, + NLL_RR_SETTLED extends number, + NLL_KEYS extends number, + TAG extends string, + >( + buffer: Buffer | BufferReader, + numNoteHashReadRequestPending: NH_RR_PENDING, + numNoteHashReadRequestSettled: NH_RR_SETTLED, + numNullifierReadRequestPending: NLL_RR_PENDING, + numNullifierReadRequestSettled: NLL_RR_SETTLED, + numNullifierKeys: NLL_KEYS, + sizeTag: TAG, + ): PrivateKernelResetCircuitPrivateInputs< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + NLL_KEYS, + TAG + > { const reader = BufferReader.asReader(buffer); return new PrivateKernelResetCircuitPrivateInputs( reader.readObject(PrivateKernelData), reader.readObject(PrivateKernelResetOutputs), - reader.readObject(PrivateKernelResetHints), + reader.readObject({ + fromBuffer: buf => + PrivateKernelResetHints.fromBuffer( + buf, + numNoteHashReadRequestPending, + numNoteHashReadRequestSettled, + numNullifierReadRequestPending, + numNullifierReadRequestSettled, + numNullifierKeys, + ), + }), + sizeTag, ); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts index 14943e0e59b..c6f22d4b536 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts @@ -1,6 +1,6 @@ import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; -import { MAX_PUBLIC_DATA_HINTS } from '../../constants.gen.js'; +import { MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_HINTS } from '../../constants.gen.js'; import { type NullifierNonExistentReadRequestHints, nullifierNonExistentReadRequestHintsFromBuffer, @@ -20,7 +20,10 @@ export class PublicKernelTailCircuitPrivateInputs { /** * Contains hints for the nullifier read requests to locate corresponding pending or settled nullifiers. */ - public readonly nullifierReadRequestHints: NullifierReadRequestHints, + public readonly nullifierReadRequestHints: NullifierReadRequestHints< + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX + >, /** * Contains hints for the nullifier non existent read requests. */ @@ -53,7 +56,11 @@ export class PublicKernelTailCircuitPrivateInputs { const reader = BufferReader.asReader(buffer); return new PublicKernelTailCircuitPrivateInputs( reader.readObject(PublicKernelData), - nullifierReadRequestHintsFromBuffer(reader), + nullifierReadRequestHintsFromBuffer( + reader, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + ), nullifierNonExistentReadRequestHintsFromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_HINTS, PublicDataHint), reader.readObject(PublicDataReadRequestHints), diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/index.ts b/yarn-project/circuits.js/src/structs/read_request_hints/index.ts index b0b5692505e..c140118984c 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints/index.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints/index.ts @@ -1,3 +1,4 @@ export * from './note_hash_read_request_hints.js'; export * from './nullifier_read_request_hints.js'; export * from './read_request_hints.js'; +export * from './nullifier_key_hint.js'; diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/note_hash_read_request_hints.ts b/yarn-project/circuits.js/src/structs/read_request_hints/note_hash_read_request_hints.ts index edc7f672219..55ae64a2ae2 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints/note_hash_read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints/note_hash_read_request_hints.ts @@ -14,42 +14,46 @@ import { type NoteHashLeafValue = Fr; -export type NoteHashReadRequestHints = ReadRequestResetHints< - typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, +export type NoteHashReadRequestHints = ReadRequestResetHints< typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + PENDING, + SETTLED, typeof NOTE_HASH_TREE_HEIGHT, NoteHashLeafValue >; -export function noteHashReadRequestHintsFromBuffer(buffer: Buffer | BufferReader): NoteHashReadRequestHints { +export function noteHashReadRequestHintsFromBuffer( + buffer: Buffer | BufferReader, + numPending: PENDING, + numSettled: SETTLED, +): NoteHashReadRequestHints { return ReadRequestResetHints.fromBuffer( buffer, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + numPending, + numSettled, NOTE_HASH_TREE_HEIGHT, Fr, ); } -export class NoteHashReadRequestHintsBuilder { - private hints: NoteHashReadRequestHints; - private numPendingReadHints = 0; - private numSettledReadHints = 0; +export class NoteHashReadRequestHintsBuilder { + private hints: NoteHashReadRequestHints; + public numPendingReadHints = 0; + public numSettledReadHints = 0; - constructor() { + constructor(numPending: PENDING, numSettled: SETTLED) { this.hints = new ReadRequestResetHints( makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ReadRequestStatus.nada), - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, () => PendingReadHint.nada(MAX_NOTE_HASH_READ_REQUESTS_PER_TX)), - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, () => + makeTuple(numPending, () => PendingReadHint.nada(MAX_NOTE_HASH_READ_REQUESTS_PER_TX)), + makeTuple(numSettled, () => SettledReadHint.nada(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, NOTE_HASH_TREE_HEIGHT, Fr.zero), ), ); } - static empty() { - return new NoteHashReadRequestHintsBuilder().toHints(); + static empty(numPending: PENDING, numSettled: SETTLED) { + return new NoteHashReadRequestHintsBuilder(numPending, numSettled).toHints().hints; } addPendingReadRequest(readRequestIndex: number, noteHashIndex: number) { @@ -79,6 +83,10 @@ export class NoteHashReadRequestHintsBuilder { } toHints() { - return this.hints; + return { + numPendingReadHints: this.numPendingReadHints, + numSettledReadHints: this.numSettledReadHints, + hints: this.hints, + }; } } diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts b/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts new file mode 100644 index 00000000000..cb9d55f81e4 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts @@ -0,0 +1,20 @@ +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; + +export class NullifierKeyHint { + constructor(public privateKey: GrumpkinPrivateKey, public requestIndex: number) {} + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new NullifierKeyHint(reader.readObject(GrumpkinPrivateKey), reader.readNumber()); + } + + toBuffer() { + return serializeToBuffer(this.privateKey, this.requestIndex); + } + + static empty() { + return new NullifierKeyHint(GrumpkinPrivateKey.zero(), 0); + } +} diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_read_request_hints.ts b/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_read_request_hints.ts index abccc72c816..0f78e722470 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_read_request_hints.ts @@ -13,42 +13,46 @@ import { SettledReadHint, } from './read_request_hints.js'; -export type NullifierReadRequestHints = ReadRequestResetHints< - typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, - typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, +export type NullifierReadRequestHints = ReadRequestResetHints< typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + PENDING, + SETTLED, typeof NULLIFIER_TREE_HEIGHT, TreeLeafPreimage >; -export function nullifierReadRequestHintsFromBuffer(buffer: Buffer | BufferReader): NullifierReadRequestHints { +export function nullifierReadRequestHintsFromBuffer( + buffer: Buffer | BufferReader, + numPendingReads: PENDING, + numSettledReads: SETTLED, +): NullifierReadRequestHints { return ReadRequestResetHints.fromBuffer( buffer, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, + numPendingReads, + numSettledReads, NULLIFIER_TREE_HEIGHT, NullifierLeafPreimage, ); } -export class NullifierReadRequestHintsBuilder { - private hints: NullifierReadRequestHints; +export class NullifierReadRequestHintsBuilder { + private hints: NullifierReadRequestHints; private numPendingReadHints = 0; private numSettledReadHints = 0; - constructor() { + constructor(numPending: PENDING, numSettled: SETTLED) { this.hints = new ReadRequestResetHints( makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestStatus.nada), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, () => PendingReadHint.nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX)), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, () => + makeTuple(numPending, () => PendingReadHint.nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX)), + makeTuple(numSettled, () => SettledReadHint.nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, NullifierLeafPreimage.empty), ), ); } - static empty() { - return new NullifierReadRequestHintsBuilder().toHints(); + static empty(numPending: PENDING, numSettled: SETTLED) { + return new NullifierReadRequestHintsBuilder(numPending, numSettled).toHints().hints; } addPendingReadRequest(readRequestIndex: number, nullifierIndex: number) { @@ -78,6 +82,10 @@ export class NullifierReadRequestHintsBuilder { } toHints() { - return this.hints; + return { + numPendingReadHints: this.numPendingReadHints, + numSettledReadHints: this.numSettledReadHints, + hints: this.hints, + }; } } diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/read_request_hints.ts b/yarn-project/circuits.js/src/structs/read_request_hints/read_request_hints.ts index ba3d0b02d94..8c2b81c6165 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints/read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints/read_request_hints.ts @@ -105,6 +105,20 @@ export class ReadRequestResetHints< public settledReadHints: Tuple, NUM_SETTLED_READS>, ) {} + trimToSizes( + numPendingReads: NEW_NUM_PENDING_READS, + numSettledReads: NEW_NUM_SETTLED_READS, + ): ReadRequestResetHints { + return new ReadRequestResetHints( + this.readRequestStatuses, + this.pendingReadHints.slice(0, numPendingReads) as Tuple, + this.settledReadHints.slice(0, numSettledReads) as Tuple< + SettledReadHint, + NEW_NUM_SETTLED_READS + >, + ); + } + /** * Deserializes from a buffer or reader. * @param buffer - Buffer or reader to read from. diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index e5c0bf8f8da..b287c870912 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -681,7 +681,7 @@ export function makePublicKernelCircuitPrivateInputs(seed = 1): PublicKernelCirc export function makePublicKernelTailCircuitPrivateInputs(seed = 1): PublicKernelTailCircuitPrivateInputs { return new PublicKernelTailCircuitPrivateInputs( makePublicKernelData(seed), - NullifierReadRequestHintsBuilder.empty(), + NullifierReadRequestHintsBuilder.empty(MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX), NullifierNonExistentReadRequestHintsBuilder.empty(), makeTuple(MAX_PUBLIC_DATA_HINTS, PublicDataHint.empty, seed + 0x100), PublicDataReadRequestHintsBuilder.empty(), diff --git a/yarn-project/noir-protocol-circuits-types/src/index.ts b/yarn-project/noir-protocol-circuits-types/src/index.ts index 48be3f815e4..a9168a22063 100644 --- a/yarn-project/noir-protocol-circuits-types/src/index.ts +++ b/yarn-project/noir-protocol-circuits-types/src/index.ts @@ -9,7 +9,8 @@ import { type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, - type PrivateKernelResetCircuitPrivateInputs, + type PrivateKernelResetCircuitPrivateInputsVariants, + type PrivateKernelResetTags, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, type PublicKernelCircuitPrivateInputs, @@ -23,7 +24,7 @@ import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log' import { type NoirCompiledCircuit } from '@aztec/types/noir'; import { type ForeignCallInput, type ForeignCallOutput } from '@noir-lang/acvm_js'; -import { type CompiledCircuit } from '@noir-lang/noir_js'; +import { type CompiledCircuit, type InputMap, Noir } from '@noir-lang/noir_js'; import { type Abi, abiDecode, abiEncode } from '@noir-lang/noirc_abi'; import { type WitnessMap } from '@noir-lang/types'; import { strict as assert } from 'assert'; @@ -35,7 +36,13 @@ import PrivateKernelInitSimulatedJson from './target/private_kernel_init_simulat import PrivateKernelInnerJson from './target/private_kernel_inner.json' assert { type: 'json' }; import PrivateKernelInnerSimulatedJson from './target/private_kernel_inner_simulated.json' assert { type: 'json' }; import PrivateKernelResetJson from './target/private_kernel_reset.json' assert { type: 'json' }; +import PrivateKernelResetBigJson from './target/private_kernel_reset_big.json' assert { type: 'json' }; +import PrivateKernelResetMediumJson from './target/private_kernel_reset_medium.json' assert { type: 'json' }; import PrivateKernelResetSimulatedJson from './target/private_kernel_reset_simulated.json' assert { type: 'json' }; +import PrivateKernelResetBigSimulatedJson from './target/private_kernel_reset_simulated_big.json' assert { type: 'json' }; +import PrivateKernelResetMediumSimulatedJson from './target/private_kernel_reset_simulated_medium.json' assert { type: 'json' }; +import PrivateKernelResetSmallSimulatedJson from './target/private_kernel_reset_simulated_small.json' assert { type: 'json' }; +import PrivateKernelResetSmallJson from './target/private_kernel_reset_small.json' assert { type: 'json' }; import PrivateKernelTailJson from './target/private_kernel_tail.json' assert { type: 'json' }; import PrivateKernelTailSimulatedJson from './target/private_kernel_tail_simulated.json' assert { type: 'json' }; import PrivateKernelTailToPublicJson from './target/private_kernel_tail_to_public.json' assert { type: 'json' }; @@ -84,7 +91,6 @@ import { type PrivateKernelTailReturnType as TailReturnType, PrivateKernelInit as executePrivateKernelInitWithACVM, PrivateKernelInner as executePrivateKernelInnerWithACVM, - PrivateKernelReset as executePrivateKernelResetWithACVM, PrivateKernelTailToPublic as executePrivateKernelTailToPublicWithACVM, PrivateKernelTail as executePrivateKernelTailWithACVM, } from './types/index.js'; @@ -142,6 +148,19 @@ export const MergeRollupArtifact = MergeRollupJson as NoirCompiledCircuit; export const RootRollupArtifact = RootRollupJson as NoirCompiledCircuit; +export type PrivateResetArtifacts = + | 'PrivateKernelResetFullArtifact' + | 'PrivateKernelResetBigArtifact' + | 'PrivateKernelResetMediumArtifact' + | 'PrivateKernelResetSmallArtifact'; + +export const PrivateResetTagToArtifactName: Record = { + full: 'PrivateKernelResetFullArtifact', + big: 'PrivateKernelResetBigArtifact', + medium: 'PrivateKernelResetMediumArtifact', + small: 'PrivateKernelResetSmallArtifact', +}; + export type ServerProtocolArtifact = | 'PublicKernelSetupArtifact' | 'PublicKernelAppLogicArtifact' @@ -156,9 +175,9 @@ export type ServerProtocolArtifact = export type ClientProtocolArtifact = | 'PrivateKernelInitArtifact' | 'PrivateKernelInnerArtifact' - | 'PrivateKernelResetArtifact' | 'PrivateKernelTailArtifact' - | 'PrivateKernelTailToPublicArtifact'; + | 'PrivateKernelTailToPublicArtifact' + | PrivateResetArtifacts; export type ProtocolArtifact = ServerProtocolArtifact | ClientProtocolArtifact; @@ -177,26 +196,17 @@ export const ServerCircuitArtifacts: Record = { PrivateKernelInitArtifact: PrivateKernelInitArtifact, PrivateKernelInnerArtifact: PrivateKernelInnerArtifact, - PrivateKernelResetArtifact: PrivateKernelResetArtifact, + PrivateKernelResetFullArtifact: PrivateKernelResetArtifact, + PrivateKernelResetBigArtifact: PrivateKernelResetBigJson as NoirCompiledCircuit, + PrivateKernelResetMediumArtifact: PrivateKernelResetMediumJson as NoirCompiledCircuit, + PrivateKernelResetSmallArtifact: PrivateKernelResetSmallJson as NoirCompiledCircuit, PrivateKernelTailArtifact: PrivateKernelTailArtifact, PrivateKernelTailToPublicArtifact: PrivateKernelTailToPublicArtifact, }; export const ProtocolCircuitArtifacts: Record = { - PrivateKernelInitArtifact: PrivateKernelInitArtifact, - PrivateKernelInnerArtifact: PrivateKernelInnerArtifact, - PrivateKernelResetArtifact: PrivateKernelResetArtifact, - PrivateKernelTailArtifact: PrivateKernelTailArtifact, - PrivateKernelTailToPublicArtifact: PrivateKernelTailToPublicArtifact, - PublicKernelSetupArtifact: PublicKernelSetupArtifact, - PublicKernelAppLogicArtifact: PublicKernelAppLogicArtifact, - PublicKernelTeardownArtifact: PublicKernelTeardownArtifact, - PublicKernelTailArtifact: PublicKernelTailArtifact, - BaseParityArtifact: BaseParityArtifact, - RootParityArtifact: RootParityArtifact, - BaseRollupArtifact: BaseRollupArtifact, - MergeRollupArtifact: MergeRollupArtifact, - RootRollupArtifact: RootRollupArtifact, + ...ClientCircuitArtifacts, + ...ServerCircuitArtifacts, }; /** @@ -233,21 +243,29 @@ export async function executeInner( return mapPrivateKernelCircuitPublicInputsFromNoir(returnType); } +const ResetSimulatedArtifacts: Record = { + PrivateKernelResetFullArtifact: PrivateKernelResetSimulatedJson as CompiledCircuit, + PrivateKernelResetBigArtifact: PrivateKernelResetBigSimulatedJson as CompiledCircuit, + PrivateKernelResetMediumArtifact: PrivateKernelResetMediumSimulatedJson as CompiledCircuit, + PrivateKernelResetSmallArtifact: PrivateKernelResetSmallSimulatedJson as CompiledCircuit, +}; + /** * Executes the inner private kernel. * @param privateKernelResetCircuitPrivateInputs - The private inputs to the reset private kernel. * @returns The public inputs. */ export async function executeReset( - privateKernelResetCircuitPrivateInputs: PrivateKernelResetCircuitPrivateInputs, + privateKernelResetCircuitPrivateInputs: PrivateKernelResetCircuitPrivateInputsVariants, ): Promise { - const returnType = await executePrivateKernelResetWithACVM( - mapPrivateKernelResetCircuitPrivateInputsToNoir(privateKernelResetCircuitPrivateInputs), - PrivateKernelResetSimulatedJson as CompiledCircuit, - foreignCallHandler, - ); - - return mapPrivateKernelCircuitPublicInputsFromNoir(returnType); + const artifact = + ResetSimulatedArtifacts[PrivateResetTagToArtifactName[privateKernelResetCircuitPrivateInputs.sizeTag]]; + const program = new Noir(artifact); + const args: InputMap = { + input: mapPrivateKernelResetCircuitPrivateInputsToNoir(privateKernelResetCircuitPrivateInputs as any), + }; + const { returnValue } = await program.execute(args, foreignCallHandler); + return mapPrivateKernelCircuitPublicInputsFromNoir(returnValue as any); } /** @@ -316,10 +334,12 @@ export function convertPrivateKernelInnerInputsToWitnessMap( * @returns The witness map */ export function convertPrivateKernelResetInputsToWitnessMap( - privateKernelResetCircuitPrivateInputs: PrivateKernelResetCircuitPrivateInputs, + privateKernelResetCircuitPrivateInputs: PrivateKernelResetCircuitPrivateInputsVariants, ): WitnessMap { - const mapped = mapPrivateKernelResetCircuitPrivateInputsToNoir(privateKernelResetCircuitPrivateInputs); - const initialWitnessMap = abiEncode(PrivateKernelResetArtifact.abi as Abi, { input: mapped as any }); + const mapped = mapPrivateKernelResetCircuitPrivateInputsToNoir(privateKernelResetCircuitPrivateInputs as any); + const artifact = + ClientCircuitArtifacts[PrivateResetTagToArtifactName[privateKernelResetCircuitPrivateInputs.sizeTag]]; + const initialWitnessMap = abiEncode(artifact.abi as Abi, { input: mapped as any }); return initialWitnessMap; } @@ -384,9 +404,13 @@ export function convertPrivateKernelInnerOutputsFromWitnessMap(outputs: WitnessM * @param outputs - The private kernel outputs as a witness map. * @returns The public inputs. */ -export function convertPrivateKernelResetOutputsFromWitnessMap(outputs: WitnessMap): PrivateKernelCircuitPublicInputs { +export function convertPrivateKernelResetOutputsFromWitnessMap( + outputs: WitnessMap, + sizeTag: PrivateKernelResetTags, +): PrivateKernelCircuitPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PrivateKernelResetArtifact.abi as Abi, outputs); + const artifact = ClientCircuitArtifacts[PrivateResetTagToArtifactName[sizeTag]]; + const decodedInputs: DecodedInputs = abiDecode(artifact.abi as Abi, outputs); // Cast the inputs as the return type const returnType = decodedInputs.return_value as ResetReturnType; diff --git a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts index 51581bd197d..e759fb55253 100644 --- a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts +++ b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts @@ -7,12 +7,14 @@ import fs from 'fs/promises'; const log = createConsoleLogger('aztec:noir-contracts'); +const resetCircuit = 'private_kernel_reset'; + const circuits = [ 'parity_base', 'parity_root', 'private_kernel_init', 'private_kernel_inner', - 'private_kernel_reset', + resetCircuit, 'private_kernel_tail', 'private_kernel_tail_to_public', 'public_kernel_setup', @@ -25,6 +27,14 @@ const circuits = [ ]; const main = async () => { + const resetVariants = JSON.parse( + await fs.readFile('../../noir-projects/noir-protocol-circuits/reset_variants.json', 'utf8'), + ); + + for (const variant of resetVariants) { + circuits.push(`${resetCircuit}_${variant.tag}`); + } + try { await fs.access('./src/types/'); } catch (error) { diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 2ea5a3eb06c..e7b3f99a30f 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -165,6 +165,7 @@ import type { NoteHashReadRequestHints as NoteHashReadRequestHintsNoir, NoteHashSettledReadHint as NoteHashSettledReadHintNoir, NoteLogHash as NoteLogHashNoir, + NullifierKeyHint as NullifierKeyHintNoir, NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, NullifierLeafPreimage as NullifierLeafPreimageNoir, Nullifier as NullifierNoir, @@ -306,6 +307,21 @@ export function mapGrumpkinPrivateKeyToNoir(privateKey: GrumpkinPrivateKey): Gru }; } +/** + * Maps a NullifierKeyHint to noir. + * @param hint - The nullifier key hint. + * @returns The nullifier key hint mapped to noir types. + */ +export function mapNullifierKeyHintToNoir(hint: { + privateKey: GrumpkinPrivateKey; + requestIndex: number; +}): NullifierKeyHintNoir { + return { + private_key: mapGrumpkinPrivateKeyToNoir(hint.privateKey), + request_index: mapNumberToNoir(hint.requestIndex), + }; +} + /** * Maps a noir GrumpkinPrivateKey to a GrumpkinPrivateKey. * @param privateKey - The noir GrumpkinPrivateKey. @@ -1016,19 +1032,36 @@ function mapNullifierSettledReadHintToNoir( }; } -function mapNoteHashReadRequestHintsToNoir(hints: NoteHashReadRequestHints): NoteHashReadRequestHintsNoir { +function mapNoteHashReadRequestHintsToNoir( + hints: NoteHashReadRequestHints, +): NoteHashReadRequestHintsNoir { return { read_request_statuses: mapTuple(hints.readRequestStatuses, mapReadRequestStatusToNoir), - pending_read_hints: mapTuple(hints.pendingReadHints, mapPendingReadHintToNoir), - settled_read_hints: mapTuple(hints.settledReadHints, mapNoteHashSettledReadHintToNoir), + pending_read_hints: hints.pendingReadHints.map(mapPendingReadHintToNoir) as FixedLengthArray< + PendingReadHintNoir, + PENDING + >, + settled_read_hints: hints.settledReadHints.map(mapNoteHashSettledReadHintToNoir) as FixedLengthArray< + NoteHashSettledReadHintNoir, + SETTLED + >, }; } -function mapNullifierReadRequestHintsToNoir(hints: NullifierReadRequestHints): NullifierReadRequestHintsNoir { +function mapNullifierReadRequestHintsToNoir( + hints: NullifierReadRequestHints, +): NullifierReadRequestHintsNoir { return { read_request_statuses: mapTuple(hints.readRequestStatuses, mapReadRequestStatusToNoir), - pending_read_hints: mapTuple(hints.pendingReadHints, mapPendingReadHintToNoir), - settled_read_hints: mapTuple(hints.settledReadHints, mapNullifierSettledReadHintToNoir), + pending_read_hints: hints.pendingReadHints.map(mapPendingReadHintToNoir) as FixedLengthArray< + PendingReadHintNoir, + PENDING + >, + settled_read_hints: hints.settledReadHints.map(settledHint => + mapNullifierSettledReadHintToNoir( + settledHint as SettledReadHint, + ), + ) as FixedLengthArray, }; } @@ -1520,7 +1553,15 @@ function mapPrivateKernelTailHintsToNoir(inputs: PrivateKernelTailHints): Privat }; } -function mapPrivateKernelResetHintsToNoir(inputs: PrivateKernelResetHints): PrivateKernelResetHintsNoir { +function mapPrivateKernelResetHintsToNoir< + NH_RR_PENDING extends number, + NH_RR_SETTLED extends number, + NLL_RR_PENDING extends number, + NLL_RR_SETTLED extends number, + NLL_KEYS extends number, +>( + inputs: PrivateKernelResetHints, +): PrivateKernelResetHintsNoir { return { transient_nullifier_indexes_for_note_hashes: mapTuple( inputs.transientNullifierIndexesForNoteHashes, @@ -1530,13 +1571,30 @@ function mapPrivateKernelResetHintsToNoir(inputs: PrivateKernelResetHints): Priv transient_note_hash_indexes_for_logs: mapTuple(inputs.transientNoteHashIndexesForLogs, mapNumberToNoir), note_hash_read_request_hints: mapNoteHashReadRequestHintsToNoir(inputs.noteHashReadRequestHints), nullifier_read_request_hints: mapNullifierReadRequestHintsToNoir(inputs.nullifierReadRequestHints), - master_nullifier_secret_keys: mapTuple(inputs.masterNullifierSecretKeys, mapGrumpkinPrivateKeyToNoir), - }; -} - -export function mapPrivateKernelResetCircuitPrivateInputsToNoir( - inputs: PrivateKernelResetCircuitPrivateInputs, -): PrivateKernelResetCircuitPrivateInputsNoir { + master_nullifier_secret_keys: inputs.masterNullifierSecretKeys.map(mapNullifierKeyHintToNoir) as FixedLengthArray< + NullifierKeyHintNoir, + NLL_KEYS + >, + }; +} + +export function mapPrivateKernelResetCircuitPrivateInputsToNoir< + NH_RR_PENDING extends number, + NH_RR_SETTLED extends number, + NLL_RR_PENDING extends number, + NLL_RR_SETTLED extends number, + NLL_KEYS extends number, + TAG extends string, +>( + inputs: PrivateKernelResetCircuitPrivateInputs< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + NLL_KEYS, + TAG + >, +): PrivateKernelResetCircuitPrivateInputsNoir { return { previous_kernel: mapPrivateKernelDataToNoir(inputs.previousKernel), outputs: mapPrivateKernelResetOutputsToNoir(inputs.outputs), diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 6a88d0a2791..88431b4c145 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -9,7 +9,6 @@ import { PrivateKernelData, PrivateKernelInitCircuitPrivateInputs, PrivateKernelInnerCircuitPrivateInputs, - PrivateKernelResetCircuitPrivateInputs, PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, type RECURSIVE_PROOF_LENGTH, @@ -28,8 +27,7 @@ import { type ExecutionResult, collectNoteHashLeafIndexMap, collectNullifiedNote import { buildPrivateKernelInitHints, buildPrivateKernelInnerHints, - buildPrivateKernelResetHints, - buildPrivateKernelResetOutputs, + buildPrivateKernelResetInputs, buildPrivateKernelTailHints, } from './private_inputs_builders/index.js'; import { type ProvingDataOracle } from './proving_data_oracle.js'; @@ -137,18 +135,8 @@ export class KernelProver { assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); - const expectedOutputs = buildPrivateKernelResetOutputs( - output.publicInputs.end.newNoteHashes, - output.publicInputs.end.newNullifiers, - output.publicInputs.end.noteEncryptedLogsHashes, - ); - output = await this.proofCreator.createProofReset( - new PrivateKernelResetCircuitPrivateInputs( - previousKernelData, - expectedOutputs, - await buildPrivateKernelResetHints(output.publicInputs, noteHashLeafIndexMap, this.oracle), - ), + await buildPrivateKernelResetInputs(previousKernelData, noteHashLeafIndexMap, this.oracle), ); previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey); diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts index 1449ceec2ac..6eef626d510 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts @@ -1,14 +1,18 @@ import { type Fr, - GrumpkinScalar, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - type MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MembershipWitness, NULLIFIER_TREE_HEIGHT, - type PrivateKernelCircuitPublicInputs, + NullifierKeyHint, + PRIVATE_RESET_VARIANTS, + type PrivateKernelData, + PrivateKernelResetCircuitPrivateInputs, + type PrivateKernelResetCircuitPrivateInputsVariants, PrivateKernelResetHints, type ScopedNullifier, type ScopedNullifierKeyValidationRequest, @@ -21,11 +25,14 @@ import { makeTuple } from '@aztec/foundation/array'; import { type Tuple } from '@aztec/foundation/serialize'; import { type ProvingDataOracle } from '../proving_data_oracle.js'; +import { buildPrivateKernelResetOutputs } from './build_private_kernel_reset_outputs.js'; -function getNullifierReadRequestHints( +function getNullifierReadRequestHints( nullifierReadRequests: Tuple, nullifiers: Tuple, oracle: ProvingDataOracle, + sizePending: PENDING, + sizeSettled: SETTLED, ) { const getNullifierMembershipWitness = async (nullifier: Fr) => { const res = await oracle.getNullifierMembershipWitness(nullifier); @@ -44,7 +51,13 @@ function getNullifierReadRequestHints( }; }; - return buildNullifierReadRequestHints({ getNullifierMembershipWitness }, nullifierReadRequests, nullifiers); + return buildNullifierReadRequestHints( + { getNullifierMembershipWitness }, + nullifierReadRequests, + nullifiers, + sizePending, + sizeSettled, + ); } async function getMasterNullifierSecretKeys( @@ -54,36 +67,59 @@ async function getMasterNullifierSecretKeys( >, oracle: ProvingDataOracle, ) { - const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar.zero); + const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyHint.empty); + + let keyIndex = 0; for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) { const request = nullifierKeyValidationRequests[i].request; if (request.isEmpty()) { break; } - keys[i] = await oracle.getMasterNullifierSecretKey(request.masterNullifierPublicKey); + keys[keyIndex] = new NullifierKeyHint( + await oracle.getMasterNullifierSecretKey(request.masterNullifierPublicKey), + i, + ); + keyIndex++; } - return keys; + return { + keysCount: keyIndex, + keys, + }; } -export async function buildPrivateKernelResetHints( - publicInputs: PrivateKernelCircuitPublicInputs, +export async function buildPrivateKernelResetInputs( + previousKernelData: PrivateKernelData, noteHashLeafIndexMap: Map, oracle: ProvingDataOracle, ) { - const noteHashReadRequestHints = await buildNoteHashReadRequestHints( + const publicInputs = previousKernelData.publicInputs; + // Use max sizes, they will be trimmed down later. + const { + numPendingReadHints: noteHashPendingReadHints, + numSettledReadHints: noteHashSettledReadHints, + hints: noteHashReadRequestHints, + } = await buildNoteHashReadRequestHints( oracle, publicInputs.validationRequests.noteHashReadRequests, publicInputs.end.newNoteHashes, noteHashLeafIndexMap, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ); - const nullifierReadRequestHints = await getNullifierReadRequestHints( + const { + numPendingReadHints: nullifierPendingReadHints, + numSettledReadHints: nullifierSettledReadHints, + hints: nullifierReadRequestHints, + } = await getNullifierReadRequestHints( publicInputs.validationRequests.nullifierReadRequests, publicInputs.end.newNullifiers, oracle, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, ); - const masterNullifierSecretKeys = await getMasterNullifierSecretKeys( + const { keysCount: nullifierKeysCount, keys: masterNullifierSecretKeys } = await getMasterNullifierSecretKeys( publicInputs.validationRequests.nullifierKeyValidationRequests, oracle, ); @@ -101,12 +137,48 @@ export async function buildPrivateKernelResetHints( MAX_NOTE_ENCRYPTED_LOGS_PER_TX, ); - return new PrivateKernelResetHints( - transientNullifierIndexesForNoteHashes, - transientNoteHashIndexesForNullifiers, - transientNoteHashIndexesForLogs, - noteHashReadRequestHints, - nullifierReadRequestHints, - masterNullifierSecretKeys, + const expectedOutputs = buildPrivateKernelResetOutputs( + previousKernelData.publicInputs.end.newNoteHashes, + previousKernelData.publicInputs.end.newNullifiers, + previousKernelData.publicInputs.end.noteEncryptedLogsHashes, ); + + let privateInputs; + + for (const [sizeTag, hintSizes] of Object.entries(PRIVATE_RESET_VARIANTS)) { + if ( + hintSizes.NOTE_HASH_PENDING_AMOUNT >= noteHashPendingReadHints && + hintSizes.NOTE_HASH_SETTLED_AMOUNT >= noteHashSettledReadHints && + hintSizes.NULLIFIER_PENDING_AMOUNT >= nullifierPendingReadHints && + hintSizes.NULLIFIER_SETTLED_AMOUNT >= nullifierSettledReadHints && + hintSizes.NULLIFIER_KEYS >= nullifierKeysCount + ) { + privateInputs = new PrivateKernelResetCircuitPrivateInputs( + previousKernelData, + expectedOutputs, + new PrivateKernelResetHints( + transientNullifierIndexesForNoteHashes, + transientNoteHashIndexesForNullifiers, + transientNoteHashIndexesForLogs, + noteHashReadRequestHints, + nullifierReadRequestHints, + masterNullifierSecretKeys, + ).trimToSizes( + hintSizes.NOTE_HASH_PENDING_AMOUNT, + hintSizes.NOTE_HASH_SETTLED_AMOUNT, + hintSizes.NULLIFIER_PENDING_AMOUNT, + hintSizes.NULLIFIER_SETTLED_AMOUNT, + hintSizes.NULLIFIER_KEYS, + ), + sizeTag, + ); + break; + } + } + + if (!privateInputs) { + throw new Error('No private inputs found for the given hint sizes.'); + } + + return privateInputs as PrivateKernelResetCircuitPrivateInputsVariants; } diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts index de292d85327..07dee2ce561 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts @@ -1,5 +1,5 @@ export { buildPrivateKernelInitHints } from './build_private_kernel_init_hints.js'; export { buildPrivateKernelInnerHints } from './build_private_kernel_inner_hints.js'; export { buildPrivateKernelTailHints } from './build_private_kernel_tail_hints.js'; -export { buildPrivateKernelResetHints } from './build_private_kernel_reset_hints.js'; +export { buildPrivateKernelResetInputs } from './build_private_kernel_reset_hints.js'; export { buildPrivateKernelResetOutputs } from './build_private_kernel_reset_outputs.js'; diff --git a/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts b/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts index ff919257d4b..97ca1c230fc 100644 --- a/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts @@ -1,12 +1,12 @@ import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '@aztec/circuit-types'; -import { type CircuitSimulationStats } from '@aztec/circuit-types/stats'; +import type { CircuitName, CircuitSimulationStats } from '@aztec/circuit-types/stats'; import { NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, - type PrivateKernelResetCircuitPrivateInputs, + type PrivateKernelResetCircuitPrivateInputsVariants, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, RECURSIVE_PROOF_LENGTH, @@ -67,12 +67,12 @@ export class TestProofCreator implements ProofCreator { } public async createProofReset( - privateInputs: PrivateKernelResetCircuitPrivateInputs, + privateInputs: PrivateKernelResetCircuitPrivateInputsVariants, ): Promise> { const [duration, result] = await elapsed(() => executeReset(privateInputs)); this.log.debug(`Simulated private kernel reset`, { eventName: 'circuit-simulation', - circuitName: 'private-kernel-reset', + circuitName: ('private-kernel-reset-' + privateInputs.sizeTag) as CircuitName, duration, inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, diff --git a/yarn-project/simulator/src/public/hints_builder.ts b/yarn-project/simulator/src/public/hints_builder.ts index 0d83cd44db4..a7cf24f1726 100644 --- a/yarn-project/simulator/src/public/hints_builder.ts +++ b/yarn-project/simulator/src/public/hints_builder.ts @@ -3,7 +3,7 @@ import { type Fr, type MAX_NEW_NULLIFIERS_PER_TX, type MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, - type MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, type MAX_PUBLIC_DATA_HINTS, type MAX_PUBLIC_DATA_READS_PER_TX, type MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -27,11 +27,19 @@ import { type IndexedTreeId, type MerkleTreeOperations } from '@aztec/world-stat export class HintsBuilder { constructor(private db: MerkleTreeOperations) {} - getNullifierReadRequestHints( + async getNullifierReadRequestHints( nullifierReadRequests: Tuple, pendingNullifiers: Tuple, ) { - return buildSiloedNullifierReadRequestHints(this, nullifierReadRequests, pendingNullifiers); + return ( + await buildSiloedNullifierReadRequestHints( + this, + nullifierReadRequests, + pendingNullifiers, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + ) + ).hints; } getNullifierNonExistentReadRequestHints( From a7f72ef8a76e2c683a8a8704628c5c29a05497fe Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 21 May 2024 02:12:37 +0000 Subject: [PATCH 28/37] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "8f6e476fce" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "8f6e476fce" git-subrepo: version: "0.4.6" origin: "???" commit: "???" [skip ci] --- barretenberg/.gitrepo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 19b56482828..5b78e344806 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 89a3cfe088ed6be4e6dbe66870000d3ddc369daf - parent = d1095f60bbd05d35748dc9b0188ad0c5f87390f5 + commit = 8f6e476fcebf06b18771d1802035e8b1dcbd102f + parent = 8e8d2ddd5eefed4f5ca7248b882dfc3d8287d1bb method = merge cmdver = 0.4.6 From 94ab87786b2b83af40033e93b8fe1edb68b5e4f9 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 21 May 2024 02:13:09 +0000 Subject: [PATCH 29/37] chore: replace relative paths to noir-protocol-circuits --- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- noir-projects/aztec-nr/tests/Nargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 7a1f1af5863..834682e92cf 100644 --- a/noir-projects/aztec-nr/aztec/Nargo.toml +++ b/noir-projects/aztec-nr/aztec/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.18.0" type = "lib" [dependencies] -protocol_types = { path = "../../noir-protocol-circuits/crates/types" } +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } diff --git a/noir-projects/aztec-nr/tests/Nargo.toml b/noir-projects/aztec-nr/tests/Nargo.toml index 13404b37324..312114ad930 100644 --- a/noir-projects/aztec-nr/tests/Nargo.toml +++ b/noir-projects/aztec-nr/tests/Nargo.toml @@ -6,4 +6,4 @@ type = "lib" [dependencies] aztec = { path = "../aztec" } -protocol_types = { path = "../../noir-protocol-circuits/crates/types" } +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } From 9c24c5a707abea3f25cba631b62d2da992f042c7 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 21 May 2024 02:13:09 +0000 Subject: [PATCH 30/37] git_subrepo.sh: Fix parent in .gitrepo file. [skip ci] --- noir-projects/aztec-nr/.gitrepo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 7ab6c0eb1c9..9f2d49d4a61 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = 440a187b5bb985f3da4ff563d6c4943c88556fa7 method = merge cmdver = 0.4.6 - parent = 18bb55229dd973f6a93a4314f7519d45d3b21b1b + parent = 79afaa4b3cc2e35cb8b0c49d3ca85f34434d766e From 2870acd117e25a24f864c0172d25eacad12fa834 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 21 May 2024 02:13:12 +0000 Subject: [PATCH 31/37] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "5b4345f50" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "5b4345f50" git-subrepo: version: "0.4.6" origin: "???" commit: "???" [skip ci] --- noir-projects/aztec-nr/.gitrepo | 4 ++-- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- noir-projects/aztec-nr/tests/Nargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 9f2d49d4a61..b6cfeed9c80 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = 440a187b5bb985f3da4ff563d6c4943c88556fa7 + commit = 5b4345f5038605a558a41764947b6a1c2b97e71e method = merge cmdver = 0.4.6 - parent = 79afaa4b3cc2e35cb8b0c49d3ca85f34434d766e + parent = 75d85cb330ba7750e8a3849d4515b6df32af39ae diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 834682e92cf..7a1f1af5863 100644 --- a/noir-projects/aztec-nr/aztec/Nargo.toml +++ b/noir-projects/aztec-nr/aztec/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.18.0" type = "lib" [dependencies] -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } diff --git a/noir-projects/aztec-nr/tests/Nargo.toml b/noir-projects/aztec-nr/tests/Nargo.toml index 312114ad930..13404b37324 100644 --- a/noir-projects/aztec-nr/tests/Nargo.toml +++ b/noir-projects/aztec-nr/tests/Nargo.toml @@ -6,4 +6,4 @@ type = "lib" [dependencies] aztec = { path = "../aztec" } -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.40.1", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } From 89bc350575076c8a6a7d25a6f687884b76803aa8 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Tue, 21 May 2024 10:55:08 +0100 Subject: [PATCH 32/37] chore: fix migration notes (#6551) --- docs/docs/migration_notes.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index ee69840c376..2bdfb23618c 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -6,7 +6,7 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. -## 0.X.X +## 0.41.0 ### [Aztec.nr] View functions and interface navigation @@ -23,15 +23,15 @@ It is now possible to explicitly state a function doesn't perform any state alte View functions only generate a `StaticCallInterface` that doesn't include `.call` or `.enqueue` methods. Also, the denomination `static` has been completely removed from the interfaces, in favor of the more familiar `view` ```diff -+ let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; - let price = PriceFeed::at(asset.oracle).get_price(0).static_call(&mut context).price; ++ let price = PriceFeed::at(asset.oracle).get_price(0).view(&mut context).price; ``` ```diff #[aztec(private)] fn enqueue_public_get_value_from_child(target_contract: AztecAddress, value: Field) { -+ StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); - StaticChild::at(target_contract).pub_get_value(value).static_enqueue(&mut context); ++ StaticChild::at(target_contract).pub_get_value(value).enqueue_view(&mut context); } ``` @@ -42,8 +42,6 @@ Additionally, the Noir LSP will now honor "go to definitions" requests for contr * `.simulate()` now tracks closer the process performed by `.send().wait()`, specifically going through the account contract entrypoint instead of directly calling the intended function. * `wallet.viewTx(...)` has been renamed to `wallet.simulateUnconstrained(...)` to better clarify what it does. -## 0.41.0 - ### [Aztec.nr] Keys: Token note now stores an owner master nullifying public key hash instead of an owner address i.e. From 948ec383b30c4f467b6da6591fa518ce793fc54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Tue, 21 May 2024 12:05:44 +0200 Subject: [PATCH 33/37] feat: generic key validation request (#6474) --- .../circuits/private-function.md | 2 +- .../circuits/private-kernel-initial.mdx | 16 +- .../circuits/private-kernel-inner.mdx | 10 +- .../circuits/private-kernel-reset.md | 9 +- .../circuits/private-kernel-tail.md | 2 +- docs/docs/protocol-specs/constants.md | 4 +- .../src/core/libraries/ConstantsGen.sol | 13 +- .../aztec-nr/address-note/src/address_note.nr | 2 +- .../aztec/src/context/private_context.nr | 58 +-- noir-projects/aztec-nr/aztec/src/keys.nr | 1 + .../aztec-nr/aztec/src/keys/constants.nr | 19 + .../aztec-nr/aztec/src/keys/getters.nr | 13 +- .../aztec-nr/aztec/src/keys/public_keys.nr | 12 +- noir-projects/aztec-nr/aztec/src/oracle.nr | 2 +- .../src/oracle/key_validation_request.nr | 17 + .../aztec/src/oracle/nullifier_keys.nr | 21 -- .../aztec-nr/value-note/src/value_note.nr | 2 +- .../src/subscription_note.nr | 2 +- .../src/types/card_note.nr | 2 +- .../src/ecdsa_public_key_note.nr | 2 +- .../src/public_key_note.nr | 2 +- .../contracts/test_contract/src/main.nr | 5 + .../src/types/token_note.nr | 2 +- .../token_contract/src/types/token_note.nr | 2 +- .../kernel_circuit_public_inputs_composer.nr | 2 +- ...e_kernel_circuit_public_inputs_composer.nr | 14 +- .../src/private_kernel_init.nr | 12 +- .../src/private_kernel_reset.nr | 30 +- .../src/private_kernel_tail.nr | 12 +- .../src/private_kernel_tail_to_public.nr | 14 +- .../src/tests/validate_arrays.nr | 27 +- .../src/main.nr | 4 +- .../crates/private-kernel-reset/src/main.nr | 4 +- .../private_validation_request_processor.nr | 25 +- .../crates/reset-kernel-lib/src/reset.nr | 2 +- .../src/reset/key_validation_hint.nr | 62 ++++ .../src/reset/nullifier_key.nr | 66 ---- .../crates/types/src/abis.nr | 2 +- .../types/src/abis/key_validation_request.nr | 101 +++++ .../abis/nullifier_key_validation_request.nr | 101 ----- .../src/abis/private_circuit_public_inputs.nr | 30 +- .../validation_requests.nr | 17 +- .../validation_requests_builder.nr | 11 +- .../crates/types/src/constants.nr | 14 +- .../crates/types/src/tests/fixture_builder.nr | 27 +- .../private_circuit_public_inputs_builder.nr | 16 +- .../circuit-types/src/keys/key_store.ts | 53 ++- yarn-project/circuits.js/src/constants.gen.ts | 12 +- ...x.test.ts.snap => derivation.test.ts.snap} | 0 .../{index.test.ts => derivation.test.ts} | 2 +- .../circuits.js/src/keys/derivation.ts | 102 ++++++ yarn-project/circuits.js/src/keys/index.ts | 94 +---- .../circuits.js/src/keys/key_types.ts | 5 + yarn-project/circuits.js/src/keys/utils.ts | 8 + .../src/scripts/generate_reset_variants.ts | 12 +- yarn-project/circuits.js/src/structs/index.ts | 2 +- ...ate_kernel_reset_circuit_private_inputs.ts | 46 ++- .../src/structs/key_validation_request.ts | 92 +++++ .../nullifier_key_validation_request.ts | 101 ----- .../structs/private_circuit_public_inputs.ts | 21 +- .../src/structs/read_request_hints/index.ts | 2 +- .../read_request_hints/key_validation_hint.ts | 31 ++ .../read_request_hints/nullifier_key_hint.ts | 20 - .../src/structs/validation_requests.ts | 19 +- .../circuits.js/src/tests/factories.ts | 30 +- yarn-project/end-to-end/Earthfile | 3 + .../end-to-end/src/e2e_key_registry.test.ts | 67 +--- yarn-project/end-to-end/src/e2e_keys.test.ts | 128 +++++++ .../key-store/src/test_key_store.test.ts | 56 ++- yarn-project/key-store/src/test_key_store.ts | 345 ++++++++---------- .../src/type_conversion.ts | 116 +++--- yarn-project/pxe/src/kernel_oracle/index.ts | 6 +- .../build_private_kernel_reset_hints.ts | 37 +- .../src/kernel_prover/proving_data_oracle.ts | 12 +- .../pxe/src/simulator_oracle/index.ts | 9 +- .../simulator/src/acvm/oracle/oracle.ts | 12 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 13 +- .../simulator/src/client/db_oracle.ts | 12 +- .../src/client/private_execution.test.ts | 37 +- .../simulator/src/client/simulator.test.ts | 9 +- .../simulator/src/client/view_data_oracle.ts | 14 +- 81 files changed, 1218 insertions(+), 1123 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/keys/constants.nr create mode 100644 noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr delete mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/key_validation_request.nr delete mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr rename yarn-project/circuits.js/src/keys/__snapshots__/{index.test.ts.snap => derivation.test.ts.snap} (100%) rename yarn-project/circuits.js/src/keys/{index.test.ts => derivation.test.ts} (97%) create mode 100644 yarn-project/circuits.js/src/keys/derivation.ts create mode 100644 yarn-project/circuits.js/src/keys/key_types.ts create mode 100644 yarn-project/circuits.js/src/keys/utils.ts create mode 100644 yarn-project/circuits.js/src/structs/key_validation_request.ts delete mode 100644 yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts create mode 100644 yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts delete mode 100644 yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts create mode 100644 yarn-project/end-to-end/src/e2e_keys.test.ts diff --git a/docs/docs/protocol-specs/circuits/private-function.md b/docs/docs/protocol-specs/circuits/private-function.md index 613282ef1b7..d137504d227 100644 --- a/docs/docs/protocol-specs/circuits/private-function.md +++ b/docs/docs/protocol-specs/circuits/private-function.md @@ -51,7 +51,7 @@ The public inputs of _every_ private function _must_ adhere to the following ABI | `encrypted_note_preimage_hashes` | [[`EncryptedNotePreimageHash`](#encryptednotepreimagehash); [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Hashes of the encrypted note preimages emitted in this function call. | | `note_hash_read_requests` | [[`ReadRequest`](#readrequest); [`MAX_NOTE_HASH_READ_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to prove the note hashes being read exist. | | `nullifier_read_requests` | [[`ReadRequest`](#readrequest); [`MAX_NULLIFIER_READ_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to prove the nullifiers being read exist. | -| `nullifier_key_validation_requests` | [[`ParentSecretKeyValidationRequest`](#parentsecretkeyvalidationrequest); [`MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to validate nullifier keys used in this function call. | +| `key_validation_requests` | [[`ParentSecretKeyValidationRequest`](#parentsecretkeyvalidationrequest); [`MAX_KEY_VALIDATION_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to validate keys used in this function call. | | `public_call_requests` | [[`PublicCallRequest`](#publiccallrequest); [`MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL`](../constants.md#circuit-constants)] | Requests to call public functions. | | `private_call_requests` | [[`PrivateCallRequest`](#privatecallrequest); [`MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL`](../constants.md#circuit-constants)] | Requests to call Private functions. | | `counter_start` | `u32` | Counter at which the function call was initiated. | diff --git a/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx b/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx index 843f516772e..a7e2fde94a5 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx +++ b/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx @@ -221,7 +221,7 @@ This circuit verifies that the values in [`private_inputs`](#private-inputs)[`.p - `value`, `contract_address`, `counter` - `nullifier_read_requests` - `value`, `contract_address`, `counter` -- `nullifier_key_validation_request_contexts` +- `key_validation_request_contexts` - `parent_public_key`, `hardened_child_secret_key` - `unencrypted_log_hash_contexts` - `hash`, `length`, `counter` @@ -254,7 +254,7 @@ This circuit verifies that the values in [`private_inputs`](#private-inputs)[`.p - `note_hash_contexts` - `nullifier_contexts` - `l2_to_l1_message_contexts` - - `nullifier_key_validation_request_contexts` + - `key_validation_request_contexts` - `unencrypted_log_hash_contexts` - `encrypted_log_hash_contexts` - `encrypted_note_preimage_hash_contexts` @@ -452,7 +452,7 @@ class PrivateFunctionPublicInputs { l2_to_l1_messages: List~field~ note_hash_read_requests: List~ReadRequest~ nullifier_read_requests: List~ReadRequest~ - nullifier_key_validation_requests: List~ParentSecretKeyValidationRequest~ + key_validation_requests: List~ParentSecretKeyValidationRequest~ unencrypted_log_hashes: List~UnencryptedLogHash~ encrypted_log_hashes: List~EncryptedLogHash~ encrypted_note_preimage_hashes: List~EncryptedNotePreimageHash~ @@ -470,7 +470,7 @@ PrivateFunctionPublicInputs *-- NoteHash: note_hashes PrivateFunctionPublicInputs *-- Nullifier: nullifiers PrivateFunctionPublicInputs *-- ReadRequest: note_hash_read_requests PrivateFunctionPublicInputs *-- ReadRequest: nullifier_read_requests -PrivateFunctionPublicInputs *-- ParentSecretKeyValidationRequest: nullifier_key_validation_requests +PrivateFunctionPublicInputs *-- ParentSecretKeyValidationRequest: key_validation_requests PrivateFunctionPublicInputs *-- UnencryptedLogHash: unencrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedLogHash: encrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedNotePreimageHash: encrypted_note_preimage_hashes @@ -529,7 +529,7 @@ class ParentSecretKeyValidationRequest { parent_public_key: GrumpkinPoint hardened_child_secret_key: fq } -ParentSecretKeyValidationRequest ..> ParentSecretKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts +ParentSecretKeyValidationRequest ..> ParentSecretKeyValidationRequestContext: key_validation_requests\n->key_validation_request_contexts class UnencryptedLogHash { hash: field @@ -661,7 +661,7 @@ class TransientAccumulatedData { note_hash_contexts: List~NoteHashContext~ nullifier_contexts: List~NullifierContext~ l2_to_l1_message_contexts: List~L2ToL1MessageContext~ - nullifier_key_validation_request_contexts: List~ParentSecretKeyValidationRequestContext~ + key_validation_request_contexts: List~ParentSecretKeyValidationRequestContext~ unencrypted_log_hash_contexts: List~UnencryptedLogHashContext~ encrypted_log_hash_contexts: List~EncryptedLogHashContext~ encrypted_note_preimage_hash_contexts: List~EncryptedNotePreimageHashContext~ @@ -675,7 +675,7 @@ NullifierContext --* TransientAccumulatedData: nullifier_contexts L2ToL1MessageContext --* TransientAccumulatedData: l2_to_l1_message_contexts ReadRequest --* TransientAccumulatedData: note_hash_read_requests ReadRequest --* TransientAccumulatedData: nullifier_read_requests -ParentSecretKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts +ParentSecretKeyValidationRequestContext --* TransientAccumulatedData: key_validation_request_contexts UnencryptedLogHashContext --* TransientAccumulatedData: unencrypted_log_hash_contexts EncryptedLogHashContext --* TransientAccumulatedData: encrypted_log_hash_contexts EncryptedNotePreimageHashContext --* TransientAccumulatedData: encrypted_note_preimage_hash_contexts @@ -776,7 +776,7 @@ Would it be accurate to describe this as `AccumulatedTransientSideEffects`, perh | `encrypted_note_preimage_hash_contexts` | [[`EncryptedNotePreimageHashContext`](#encryptednotepreimagehash); [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hashes of the encrypted note preimages with extra data aiding verification. | | `note_hash_read_requests` | [[`ReadRequest`](./private-function#readrequest); [`MAX_NOTE_HASH_READ_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to prove the note hashes being read exist. | | `nullifier_read_requests` | [[`ReadRequest`](./private-function#readrequest); [`MAX_NULLIFIER_READ_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to prove the nullifiers being read exist. | -| `nullifier_key_validation_request_contexts` | [[`ParentSecretKeyValidationRequestContext`](#parentsecretkeyvalidationrequestcontext); [`MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to validate nullifier keys. | +| `key_validation_request_contexts` | [[`ParentSecretKeyValidationRequestContext`](#parentsecretkeyvalidationrequestcontext); [`MAX_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to validate nullifier keys. | | `public_call_request_contexts` | [[`PublicCallRequestContext`](./public-kernel-tail.md#publiccallrequestcontext); [`MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX`](../constants.md#circuit-constants)] | Requests to call publics functions. | | `private_call_request_stack` | [[`PrivateCallRequestContext`](#privatecallrequestcontext); [`MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX`](../constants.md#circuit-constants)] | Requests to call private functions. Pushed to the stack in reverse order so that they will be executed in chronological order. | diff --git a/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx b/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx index 7041d3a6999..78d97022a67 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx +++ b/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx @@ -251,7 +251,7 @@ class PrivateFunctionPublicInputs { encrypted_note_preimage_hashes: List~EncryptedNotePreimageHash~ note_hash_read_requests: List~ReadRequest~ nullifier_read_requests: List~ReadRequest~ - nullifier_key_validation_requests: List~ParentSecretKeyValidationRequest~ + key_validation_requests: List~ParentSecretKeyValidationRequest~ public_call_requests: List~PublicCallRequest~ private_call_requests: List~PrivateCallRequest~ counter_start: u32 @@ -266,7 +266,7 @@ PrivateFunctionPublicInputs *-- NoteHash: note_hashes PrivateFunctionPublicInputs *-- Nullifier: nullifiers PrivateFunctionPublicInputs *-- ReadRequest: note_hash_read_requests PrivateFunctionPublicInputs *-- ReadRequest: nullifier_read_requests -PrivateFunctionPublicInputs *-- ParentSecretKeyValidationRequest: nullifier_key_validation_requests +PrivateFunctionPublicInputs *-- ParentSecretKeyValidationRequest: key_validation_requests PrivateFunctionPublicInputs *-- UnencryptedLogHash: unencrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedLogHash: encrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedNotePreimageHash: encrypted_note_preimage_hashes @@ -338,7 +338,7 @@ class ParentSecretKeyValidationRequest { parent_public_key: GrumpkinPoint hardened_child_secret_key: fq } -ParentSecretKeyValidationRequest ..> ParentSecretKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts +ParentSecretKeyValidationRequest ..> ParentSecretKeyValidationRequestContext: key_validation_requests\n->key_validation_request_contexts class UnencryptedLogHash { hash: field @@ -475,7 +475,7 @@ class TransientAccumulatedData { encrypted_note_preimage_hash_contexts: List~EncryptedNotePreimageHashContext~ note_hash_read_requests: List~ReadRequest~ nullifier_read_requests: List~ReadRequest~ - nullifier_key_validation_request_contexts: List~ParentSecretKeyValidationRequestContext~ + key_validation_request_contexts: List~ParentSecretKeyValidationRequestContext~ public_call_request_contexts: List~PublicCallRequestContext~ private_call_request_stack: List~PrivateCallRequestContext~ } @@ -484,7 +484,7 @@ NullifierContext --* TransientAccumulatedData: nullifier_contexts L2ToL1MessageContext --* TransientAccumulatedData: l2_to_l1_message_contexts ReadRequest --* TransientAccumulatedData: note_hash_read_requests ReadRequest --* TransientAccumulatedData: nullifier_read_requests -ParentSecretKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts +ParentSecretKeyValidationRequestContext --* TransientAccumulatedData: key_validation_request_contexts UnencryptedLogHashContext --* TransientAccumulatedData: unencrypted_log_hash_contexts EncryptedLogHashContext --* TransientAccumulatedData: encrypted_log_hash_contexts EncryptedNotePreimageHashContext --* TransientAccumulatedData: encrypted_note_preimage_hash_contexts diff --git a/docs/docs/protocol-specs/circuits/private-kernel-reset.md b/docs/docs/protocol-specs/circuits/private-kernel-reset.md index 0b0dd79141b..01b374e88b9 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-reset.md +++ b/docs/docs/protocol-specs/circuits/private-kernel-reset.md @@ -83,11 +83,11 @@ This reset circuit validates the correct derivation of secret keys used in priva Initialize `requests_kept` to `0`. -For each `request` at index `i` in `nullifier_key_validation_request_contexts`, locate the `master_secret_key` at `master_secret_keys[i]`, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through `private_inputs`. +For each `request` at index `i` in `key_validation_request_contexts`, locate the `master_secret_key` at `master_secret_keys[i]` and the relevant `app_secret_key` generator at `app_secret_keys_generators[i]`, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through `private_inputs`. 1. If `master_secret_key == 0`, ensure the request remain within the `public_inputs`.: - - `public_inputs.transient_accumulated_data.nullifier_key_validation_request_contexts[requests_kept] == request` + - `public_inputs.transient_accumulated_data.key_validation_request_contexts[requests_kept] == request` - Increase `requests_kept` by 1: `requests_kept += 1` 2. Else: @@ -199,7 +199,7 @@ All arrays in the `transient_accumulated_data` in the [`public_inputs`](#public- 1. [Read request reset circuit](#note-hash-read-request-reset-private-kernel-circuit) (for note hashes): `note_hash_read_requests` 2. [Read request reset circuit](#nullifier-read-request-reset-private-kernel-circuit) (for nullifiers): `nullifier_read_requests` -3. [Parent secret key validation request reset circuit](#nullifier-key-validation-request-reset-private-kernel-circuit) (for nullifier keys): `nullifier_key_validation_request_contexts` +3. [Parent secret key validation request reset circuit](#nullifier-key-validation-request-reset-private-kernel-circuit) (for nullifier keys): `key_validation_request_contexts` 4. [Transient note reset circuit](#transient-note-reset-private-kernel-circuit): `note_hash_contexts` and `nullifier_contexts` #### Verifying other data. @@ -236,7 +236,8 @@ The format aligns with the [`PreviousKernel`](./private-kernel-inner#previousker | Field | Type | Description | | -------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------- | -| `master_secret_keys` | [`field`; [`MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Master secret keys for the secret keys. | +| `master_secret_keys` | [`field`; [`MAX_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Master secret to try to derive app secret keys and pub keys from. | +| `app_secret_keys_generators` | [`field`; [`MAX_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | App secret key generators to assist with ^. | ### _Hints_ for [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit) diff --git a/docs/docs/protocol-specs/circuits/private-kernel-tail.md b/docs/docs/protocol-specs/circuits/private-kernel-tail.md index 1c66ca85802..dc842b8994a 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-tail.md +++ b/docs/docs/protocol-specs/circuits/private-kernel-tail.md @@ -30,7 +30,7 @@ It checks the data within [`private_inputs`](#private-inputs)[`.previous_kernel` - `note_hash_read_requests` - `nullifier_read_requests` - - `nullifier_key_validation_request_contexts` + - `key_validation_request_contexts` - The `nullifier_counter` associated with each note hash in `note_hash_contexts`. - The `note_hash_counter` associated with each nullifier in `nullifier_contexts`. diff --git a/docs/docs/protocol-specs/constants.md b/docs/docs/protocol-specs/constants.md index 969a98ffae4..2be04c2b645 100644 --- a/docs/docs/protocol-specs/constants.md +++ b/docs/docs/protocol-specs/constants.md @@ -52,7 +52,7 @@ The statically-sized nature the kernel & rollup circuits will restrict the quant | `MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_CALL` | 128 | | `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` | 128 | | `MAX_NULLIFIER_READ_REQUESTS_PER_CALL` | 128 | -| `MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL` | 1 | TODO: we shouldn't need this, given the reset circuit. | +| `MAX_KEY_VALIDATION_REQUESTS_PER_CALL | 16 | TODO: we shouldn't need this, given the reset circuit. | | `MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL` | 32 | | `MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL` | 32 | @@ -71,7 +71,7 @@ The statically-sized nature the kernel & rollup circuits will restrict the quant | `MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX` | 128 | | `MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX` | 4 | | `MAX_NOTE_HASH_READ_REQUESTS_PER_TX` | 128 | TODO: we shouldn't need this, given the reset circuit. | -| `MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX` | 4 | TODO: we shouldn't need this, given the reset circuit. | +| `MAX_KEY_VALIDATION_REQUESTS_PER_TX` | 64 | TODO: we shouldn't need this, given the reset circuit. | | `MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX` | 32 | | `MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX` | 32 | diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index cd657af88c3..72293011b05 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -25,7 +25,7 @@ library Constants { uint256 internal constant MAX_NOTE_HASH_READ_REQUESTS_PER_CALL = 32; uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 32; uint256 internal constant MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL = 32; - uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 16; + uint256 internal constant MAX_KEY_VALIDATION_REQUESTS_PER_CALL = 16; uint256 internal constant MAX_NOTE_ENCRYPTED_LOGS_PER_CALL = 16; uint256 internal constant MAX_ENCRYPTED_LOGS_PER_CALL = 4; uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_CALL = 4; @@ -39,7 +39,7 @@ library Constants { uint256 internal constant MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_TX = 128; uint256 internal constant MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX = 128; - uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 64; + uint256 internal constant MAX_KEY_VALIDATION_REQUESTS_PER_TX = 64; uint256 internal constant MAX_NOTE_ENCRYPTED_LOGS_PER_TX = 64; uint256 internal constant MAX_ENCRYPTED_LOGS_PER_TX = 8; uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_TX = 8; @@ -119,9 +119,8 @@ library Constants { uint256 internal constant L2_TO_L1_MESSAGE_LENGTH = 3; uint256 internal constant SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; uint256 internal constant MAX_BLOCK_NUMBER_LENGTH = 2; - uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; - uint256 internal constant SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = - NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; + uint256 internal constant KEY_VALIDATION_REQUEST_LENGTH = 3; + uint256 internal constant SCOPED_KEY_VALIDATION_REQUEST_LENGTH = KEY_VALIDATION_REQUEST_LENGTH + 1; uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 6; uint256 internal constant READ_REQUEST_LENGTH = 2; uint256 internal constant LOG_HASH_LENGTH = 3; @@ -146,7 +145,7 @@ library Constants { uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) - + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + + (KEY_VALIDATION_REQUEST_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) @@ -175,7 +174,7 @@ library Constants { + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) - + (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + + (SCOPED_KEY_VALIDATION_REQUEST_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); uint256 internal constant PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index df33796ed35..e2a243fdf10 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -4,7 +4,7 @@ use dep::aztec::{ grumpkin_point::GrumpkinPoint, hash::poseidon2_hash }, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::unsafe_rand::unsafe_rand, oracle::nullifier_keys::get_nsk_app, context::PrivateContext + oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; global ADDRESS_NOTE_LEN: Field = 3; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index db4b82441c1..26199d2f93e 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -2,9 +2,10 @@ use crate::{ context::{inputs::PrivateContextInputs, interface::ContextInterface}, messaging::process_l1_to_l2_message, hash::{hash_args_array, ArgsHasher, compute_unencrypted_log_hash}, + keys::constants::{NULLIFIER_INDEX, OUTGOING_INDEX, NUM_KEY_TYPES, sk_generators}, note::{note_interface::NoteInterface, utils::compute_note_hash_for_insertion}, oracle::{ - nullifier_keys::get_nullifier_key_validation_request, arguments, returns, + key_validation_request::get_key_validation_request, arguments, returns, call_private_function::call_private_function_internal, header::get_header_at, logs::{emit_encrypted_log, emit_encrypted_note_log, compute_encrypted_log}, logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog}, @@ -18,7 +19,7 @@ use dep::protocol_types::{ hash::sha256_to_field, abis::{ caller_context::CallerContext, function_selector::FunctionSelector, - max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequest, + max_block_number::MaxBlockNumber, key_validation_request::KeyValidationRequest, private_call_request::PrivateCallRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, public_call_stack_item::PublicCallStackItem, read_request::ReadRequest, note_hash::NoteHash, nullifier::Nullifier, log_hash::{LogHash, NoteLogHash} @@ -28,8 +29,8 @@ use dep::protocol_types::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_CALL, - MAX_UNENCRYPTED_LOGS_PER_CALL, MAX_NOTE_ENCRYPTED_LOGS_PER_CALL + MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL, + MAX_NOTE_ENCRYPTED_LOGS_PER_CALL }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, grumpkin_private_key::GrumpkinPrivateKey, grumpkin_point::GrumpkinPoint, header::Header, @@ -53,7 +54,8 @@ struct PrivateContext { note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, + key_validation_requests: BoundedVec, + app_secret_keys_generators: BoundedVec, new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -71,7 +73,10 @@ struct PrivateContext { encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, - last_nullifier_key_validation_request: Option, + // Contains the last key validation request for each key type. This is used to cache the last request and avoid + // fetching the same request multiple times. + // The index of the array corresponds to the key type (0 nullifier, 1 incoming, 2 outgoing, 3 tagging). + last_key_validation_requests: [Option; NUM_KEY_TYPES], } impl ContextInterface for PrivateContext { @@ -120,7 +125,8 @@ impl PrivateContext { max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), - nullifier_key_validation_requests: BoundedVec::new(), + key_validation_requests: BoundedVec::new(), + app_secret_keys_generators: BoundedVec::new(), new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), historical_header: inputs.historical_header, @@ -131,7 +137,7 @@ impl PrivateContext { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - last_nullifier_key_validation_request: Option::none() + last_key_validation_requests: [Option::none(); NUM_KEY_TYPES] } } @@ -162,7 +168,7 @@ impl PrivateContext { max_block_number: self.max_block_number, note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, + key_validation_requests: self.key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, private_call_requests: self.private_call_requests.storage, @@ -204,21 +210,30 @@ impl PrivateContext { } pub fn request_nsk_app(&mut self, npk_m_hash: Field) -> Field { - let cached_request = self.last_nullifier_key_validation_request.unwrap_or(NullifierKeyValidationRequest::empty()); + self.request_sk_app(npk_m_hash, NULLIFIER_INDEX) + } + + pub fn request_ovsk_app(&mut self, ovpk_m_hash: Field) -> Field { + self.request_sk_app(ovpk_m_hash, OUTGOING_INDEX) + } + + fn request_sk_app(&mut self, pk_m_hash: Field, key_index: Field) -> Field { + let cached_request = self.last_key_validation_requests[key_index].unwrap_or(KeyValidationRequest::empty()); - if cached_request.master_nullifier_public_key.hash() == npk_m_hash { + if cached_request.pk_m.hash() == pk_m_hash { // We get a match so the cached request is the latest one - cached_request.app_nullifier_secret_key + cached_request.sk_app } else { // We didn't get a match meaning the cached result is stale. We fetch new values from oracle and instruct // protocol circuits to validate them by storing the validation request in context. - let request = get_nullifier_key_validation_request(npk_m_hash); - // We constrain that the npk_m_hash matches the one in the request (otherwise we could get an arbitrary - // valid key request and not the one corresponding to npk_m_hash). - assert(request.master_nullifier_public_key.hash() == npk_m_hash); - self.nullifier_key_validation_requests.push(request); - self.last_nullifier_key_validation_request = Option::some(request); - request.app_nullifier_secret_key + let request = get_key_validation_request(pk_m_hash, key_index); + // We constrain that the pk_m_hash matches the one in the request (otherwise we could get an arbitrary + // valid key request and not the one corresponding to pk_m_hash). + assert(request.pk_m.hash() == pk_m_hash); + self.key_validation_requests.push(request); + self.app_secret_keys_generators.push(sk_generators[key_index]); + self.last_key_validation_requests[key_index] = Option::some(request); + request.sk_app } } @@ -659,7 +674,8 @@ impl Empty for PrivateContext { max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), - nullifier_key_validation_requests: BoundedVec::new(), + key_validation_requests: BoundedVec::new(), + app_secret_keys_generators: BoundedVec::new(), new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), private_call_requests: BoundedVec::new(), @@ -670,7 +686,7 @@ impl Empty for PrivateContext { note_encrypted_logs_hashes: BoundedVec::new(), encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), - last_nullifier_key_validation_request: Option::none(), + last_key_validation_requests: [Option::none(); NUM_KEY_TYPES] } } } diff --git a/noir-projects/aztec-nr/aztec/src/keys.nr b/noir-projects/aztec-nr/aztec/src/keys.nr index f47c5eea375..2470a1bafeb 100644 --- a/noir-projects/aztec-nr/aztec/src/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/keys.nr @@ -1,3 +1,4 @@ +mod constants; mod getters; mod point_to_symmetric_key; mod public_keys; diff --git a/noir-projects/aztec-nr/aztec/src/keys/constants.nr b/noir-projects/aztec-nr/aztec/src/keys/constants.nr new file mode 100644 index 00000000000..24444f576bf --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/keys/constants.nr @@ -0,0 +1,19 @@ +use dep::protocol_types::constants::{GENERATOR_INDEX__NSK_M, GENERATOR_INDEX__IVSK_M, GENERATOR_INDEX__OVSK_M, GENERATOR_INDEX__TSK_M}; + +// Note: In fetch_key_from_registry we expect that the shared mutable slot is index * 2 + 1 for the x coordinate and +// index * 2 + 2 for the y coordinate. For example, the npk_m x coordinates will be stored in a map at storage slot +// 0 * 2 + 1 = 1, and the npk_m y coordinates at 2 * 2 + 2 = 6. If this changes the function will need to be +// refactored. +global NULLIFIER_INDEX = 0; +global INCOMING_INDEX = 1; +global OUTGOING_INDEX = 2; +global TAGGING_INDEX = 3; + +global NUM_KEY_TYPES = 4; + +global sk_generators = [ + GENERATOR_INDEX__NSK_M, + GENERATOR_INDEX__IVSK_M, + GENERATOR_INDEX__OVSK_M, + GENERATOR_INDEX__TSK_M +]; diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters.nr b/noir-projects/aztec-nr/aztec/src/keys/getters.nr index c0b2feffc12..d085c309d7c 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/getters.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/getters.nr @@ -1,10 +1,11 @@ use dep::protocol_types::{ - abis::nullifier_key_validation_request::NullifierKeyValidationRequest, address::AztecAddress, + abis::key_validation_request::KeyValidationRequest, address::AztecAddress, constants::CANONICAL_KEY_REGISTRY_ADDRESS, grumpkin_point::GrumpkinPoint }; use crate::{ - context::PrivateContext, oracle::{keys::get_public_keys_and_partial_address}, - keys::public_keys::{PublicKeys, NULLIFIER_INDEX, INCOMING_INDEX}, + context::PrivateContext, + oracle::{keys::get_public_keys_and_partial_address, key_validation_request::get_key_validation_request}, + keys::{public_keys::PublicKeys, constants::{NULLIFIER_INDEX, INCOMING_INDEX}}, state_vars::{ map::derive_storage_slot_in_map, shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter @@ -89,3 +90,9 @@ fn fetch_and_constrain_keys(address: AztecAddress) -> PublicKeys { public_keys } + +// A helper function since requesting nsk_app is very common +// TODO(#6543) +pub fn get_nsk_app(npk_m_hash: Field) -> Field { + get_key_validation_request(npk_m_hash, NULLIFIER_INDEX).sk_app +} diff --git a/noir-projects/aztec-nr/aztec/src/keys/public_keys.nr b/noir-projects/aztec-nr/aztec/src/keys/public_keys.nr index ffdff5aa001..e6c82b833d0 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/public_keys.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/public_keys.nr @@ -2,15 +2,7 @@ use dep::protocol_types::{ address::PublicKeysHash, constants::GENERATOR_INDEX__PUBLIC_KEYS_HASH, hash::poseidon2_hash, grumpkin_point::GrumpkinPoint, traits::{Deserialize, Serialize} }; - -// Note: In fetch_key_from_registry we expect that the shared mutable slot is index * 2 + 1 for the x coordinate and -// index * 2 + 2 for the y coordinate. For example, the npk_m x coordinates will be stored in a map at storage slot -// 0 * 2 + 1 = 1, and the npk_m y coordinates at 2 * 2 + 2 = 6. If this changes the function will need to be -// refactored. -global NULLIFIER_INDEX = 0; -global INCOMING_INDEX = 1; -global OUTGOING_INDEX = 2; -global TAGGING_INDEX = 3; +use crate::keys::constants::{NUM_KEY_TYPES, NULLIFIER_INDEX, INCOMING_INDEX, OUTGOING_INDEX}; global PUBLIC_KEYS_LENGTH = 8; @@ -41,7 +33,7 @@ impl PublicKeys { } pub fn get_key_by_index(self, index: Field) -> GrumpkinPoint { - assert(index as u8 < 4, "Invalid key index"); + assert(index as u8 < NUM_KEY_TYPES, "Invalid key index"); if index == NULLIFIER_INDEX { self.npk_m } else if index == INCOMING_INDEX { diff --git a/noir-projects/aztec-nr/aztec/src/oracle.nr b/noir-projects/aztec-nr/aztec/src/oracle.nr index 2d3cc6dd1f9..a2b8a1198f6 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle.nr @@ -11,7 +11,7 @@ mod get_nullifier_membership_witness; mod get_public_data_witness; mod get_membership_witness; mod keys; -mod nullifier_keys; +mod key_validation_request; mod get_sibling_path; mod unsafe_rand; mod enqueue_public_function_call; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr b/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr new file mode 100644 index 00000000000..1df79eef12f --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr @@ -0,0 +1,17 @@ +use dep::protocol_types::{ + grumpkin_point::GrumpkinPoint, + abis::key_validation_request::{KeyValidationRequest, KEY_VALIDATION_REQUEST_LENGTH} +}; + +#[oracle(getKeyValidationRequest)] +fn get_key_validation_request_oracle(_pk_m_hash: Field, _key_index: Field) -> [Field; KEY_VALIDATION_REQUEST_LENGTH] {} + +unconstrained fn get_key_validation_request_internal(npk_m_hash: Field, key_index: Field) -> KeyValidationRequest { + let result = get_key_validation_request_oracle(npk_m_hash, key_index); + KeyValidationRequest::deserialize(result) +} + +pub fn get_key_validation_request(pk_m_hash: Field, key_index: Field) -> KeyValidationRequest { + get_key_validation_request_internal(pk_m_hash, key_index) +} + diff --git a/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr deleted file mode 100644 index 0eb33d7cb15..00000000000 --- a/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr +++ /dev/null @@ -1,21 +0,0 @@ -use dep::protocol_types::{grumpkin_point::GrumpkinPoint, abis::nullifier_key_validation_request::NullifierKeyValidationRequest}; - -#[oracle(getNullifierKeys)] -fn get_nullifier_key_validation_request_oracle(_npk_m_hash: Field) -> [Field; 3] {} - -unconstrained fn get_nullifier_key_validation_request_internal(npk_m_hash: Field) -> NullifierKeyValidationRequest { - let result = get_nullifier_key_validation_request_oracle(npk_m_hash); - NullifierKeyValidationRequest { - master_nullifier_public_key: GrumpkinPoint { x: result[0], y: result[1] }, - app_nullifier_secret_key: result[2] - } -} - -// We get the full struct Nullifier Keys here -pub fn get_nullifier_key_validation_request(npk_m_hash: Field) -> NullifierKeyValidationRequest { - get_nullifier_key_validation_request_internal(npk_m_hash) -} - -pub fn get_nsk_app(npk_m_hash: Field) -> Field { - get_nullifier_key_validation_request_internal(npk_m_hash).app_nullifier_secret_key -} diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 7e057b8912e..bdc4fcc33b6 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -5,7 +5,7 @@ use dep::aztec::{ constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash }, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::unsafe_rand::unsafe_rand, oracle::nullifier_keys::get_nsk_app, context::PrivateContext + oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext }; global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 7de5917b11d..e1c40e40f45 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -2,7 +2,7 @@ use dep::aztec::prelude::{AztecAddress, PrivateContext, NoteHeader, NoteInterfac use dep::aztec::{ keys::getters::get_ivpk_m, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, - note::utils::compute_note_hash_for_consumption, oracle::nullifier_keys::get_nsk_app + note::utils::compute_note_hash_for_consumption, keys::getters::get_nsk_app }; global SUBSCRIPTION_NOTE_LEN: Field = 3; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 5efd1e93879..8664cbad9bb 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,7 +1,7 @@ use dep::aztec::prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContext}; use dep::aztec::{ keys::getters::get_ivpk_m, note::{utils::compute_note_hash_for_consumption}, - oracle::nullifier_keys::get_nsk_app, + keys::getters::get_nsk_app, protocol_types::{ traits::Empty, grumpkin_point::GrumpkinPoint, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index f716dc5a5f8..30121822ee7 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -2,7 +2,7 @@ use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteInterf use dep::aztec::{ keys::getters::get_ivpk_m, note::utils::compute_note_hash_for_consumption, - oracle::nullifier_keys::get_nsk_app, + keys::getters::get_nsk_app, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash} }; diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index df6e72b61b3..a24b9a1fe8a 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,6 +1,6 @@ use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}; use dep::aztec::{ - note::utils::compute_note_hash_for_consumption, oracle::nullifier_keys::get_nsk_app, + note::utils::compute_note_hash_for_consumption, keys::getters::get_nsk_app, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash} }; diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 03c7f86ccb7..95467448503 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -50,6 +50,11 @@ contract Test { example_set: PrivateSet, } + #[aztec(private)] + fn get_ovsk_app(ovpk_m_hash: Field) -> Field { + context.request_ovsk_app(ovpk_m_hash) + } + #[aztec(private)] fn get_master_incoming_viewing_public_key(address: AztecAddress) -> [Field; 2] { let pub_key = get_ivpk_m(&mut context, address); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 204023a21ab..ec62873e67b 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, note::utils::compute_note_hash_for_consumption, oracle::unsafe_rand::unsafe_rand, - oracle::nullifier_keys::get_nsk_app + keys::getters::get_nsk_app }; trait OwnedNote { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 204023a21ab..ec62873e67b 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, note::utils::compute_note_hash_for_consumption, oracle::unsafe_rand::unsafe_rand, - oracle::nullifier_keys::get_nsk_app + keys::getters::get_nsk_app }; trait OwnedNote { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr index da0ce3470db..16f812eb38b 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr @@ -257,7 +257,7 @@ impl KernelCircuitPublicInputsComposer { ); assert_eq( - array_length(self.previous_kernel.public_inputs.validation_requests.nullifier_key_validation_requests), 0, "Non empty nullifier key validation requests" + array_length(self.previous_kernel.public_inputs.validation_requests.key_validation_requests), 0, "Non empty key validation requests" ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr index e0dfcb2e78f..878dedef4da 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr @@ -62,7 +62,7 @@ impl PrivateKernelCircuitPublicInputsComposer { public_inputs.validation_requests.max_block_number = start.for_rollup.max_block_number; public_inputs.validation_requests.note_hash_read_requests = array_to_bounded_vec(start.note_hash_read_requests); public_inputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); - public_inputs.validation_requests.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); + public_inputs.validation_requests.key_validation_requests = array_to_bounded_vec(start.key_validation_requests); let start = previous_kernel_public_inputs.end; public_inputs.end.new_note_hashes = array_to_bounded_vec(start.new_note_hashes); @@ -101,7 +101,7 @@ impl PrivateKernelCircuitPublicInputsComposer { self.propagate_max_block_number(source); self.propagate_note_hash_read_requests(source); self.propagate_nullifier_read_requests(source); - self.propagate_nullifier_key_validation_requests(source); + self.propagate_key_validation_requests(source); self.propagate_note_hashes(source); self.propagate_nullifiers(source); self.propagate_l2_to_l1_messages(source); @@ -143,12 +143,12 @@ impl PrivateKernelCircuitPublicInputsComposer { } } - fn propagate_nullifier_key_validation_requests(&mut self, source: DataSource) { - let nullifier_key_validation_requests = source.private_call_public_inputs.nullifier_key_validation_requests; - for i in 0..nullifier_key_validation_requests.len() { - let request = nullifier_key_validation_requests[i]; + fn propagate_key_validation_requests(&mut self, source: DataSource) { + let key_validation_requests = source.private_call_public_inputs.key_validation_requests; + for i in 0..key_validation_requests.len() { + let request = key_validation_requests[i]; if !is_empty(request) { - self.public_inputs.validation_requests.nullifier_key_validation_requests.push(request.scope(source.storage_contract_address)); + self.public_inputs.validation_requests.key_validation_requests.push(request.scope(source.storage_contract_address)); } } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 61ed5046436..e0dde7101af 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -50,7 +50,7 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, note_hash::NoteHash, - nullifier_key_validation_request::NullifierKeyValidationRequest, + key_validation_request::KeyValidationRequest, private_kernel::private_call_data::PrivateCallData, read_request::ReadRequest, nullifier::Nullifier, log_hash::{LogHash, NoteLogHash} }, @@ -197,17 +197,17 @@ mod tests { } #[test] - fn propagate_nullifier_key_validation_requests() { + fn propagate_key_validation_requests() { let mut builder = PrivateKernelInitInputsBuilder::new(); - let request_0 = NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: 1, y: 2 }, app_nullifier_secret_key: 3 }; - builder.private_call.public_inputs.nullifier_key_validation_requests.push(request_0); + let request_0 = KeyValidationRequest { pk_m: GrumpkinPoint { x: 1, y: 2 }, sk_app: 3 }; + builder.private_call.public_inputs.key_validation_requests.push(request_0); let public_inputs = builder.execute(); - assert_eq(array_length(public_inputs.validation_requests.nullifier_key_validation_requests), 1); + assert_eq(array_length(public_inputs.validation_requests.key_validation_requests), 1); - let request = public_inputs.validation_requests.nullifier_key_validation_requests[0]; + let request = public_inputs.validation_requests.key_validation_requests[0]; assert_eq(request.request, request_0); assert_eq( request.contract_address, builder.private_call.public_inputs.call_context.storage_contract_address diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr index d43ae5e907d..5aa62789ee5 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr @@ -1,7 +1,7 @@ use crate::private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer; use dep::reset_kernel_lib::{ NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor, - verify_squashed_transient_note_hashes_and_nullifiers, reset::nullifier_key::NullifierKeyHint + verify_squashed_transient_note_hashes_and_nullifiers, reset::key_validation_hint::KeyValidationHint }; use dep::types::{ abis::{ @@ -11,8 +11,8 @@ use dep::types::{ }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, + MAX_NOTE_ENCRYPTED_LOGS_PER_TX }, grumpkin_private_key::GrumpkinPrivateKey, utils::arrays::array_length, traits::is_empty, PrivateKernelCircuitPublicInputs @@ -25,22 +25,22 @@ struct PrivateKernelResetOutputs { note_encrypted_log_hashes: [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], } -struct PrivateKernelResetHints { +struct PrivateKernelResetHints { transient_nullifier_indexes_for_note_hashes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], transient_note_hash_indexes_for_nullifiers: [u64; MAX_NEW_NULLIFIERS_PER_TX], transient_note_hash_indexes_for_logs: [u64; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], note_hash_read_request_hints: NoteHashReadRequestHints, nullifier_read_request_hints: NullifierReadRequestHints, - master_nullifier_secret_keys: [NullifierKeyHint; NLL_KEYS], + key_validation_hints: [KeyValidationHint; KEY_VALIDATION_REQUESTS], } -struct PrivateKernelResetCircuitPrivateInputs { +struct PrivateKernelResetCircuitPrivateInputs { previous_kernel: PrivateKernelData, outputs: PrivateKernelResetOutputs, - hints: PrivateKernelResetHints, + hints: PrivateKernelResetHints, } -impl PrivateKernelResetCircuitPrivateInputs { +impl PrivateKernelResetCircuitPrivateInputs { pub fn execute(self) -> PrivateKernelCircuitPublicInputs { let mut previous_public_inputs = self.previous_kernel.public_inputs; @@ -55,7 +55,7 @@ impl Pri nullifier_read_request_hints: self.hints.nullifier_read_request_hints, pending_nullifiers: previous_public_inputs.end.new_nullifiers, nullifier_tree_root: previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root, - master_nullifier_secret_keys: self.hints.master_nullifier_secret_keys + key_validation_hints: self.hints.key_validation_hints, }.validate(); verify_squashed_transient_note_hashes_and_nullifiers( @@ -87,11 +87,11 @@ mod tests { squash_transient_data::{squash_transient_note_hashes, squash_transient_nullifiers, squash_transient_logs} }, reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus}, - reset::nullifier_key::NullifierKeyHint + reset::key_validation_hint::KeyValidationHint }; use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, DA_BYTES_PER_FIELD }; @@ -179,7 +179,7 @@ mod tests { transient_note_hash_indexes_for_logs: self.transient_note_hash_indexes_for_logs, note_hash_read_request_hints: self.note_hash_read_request_hints_builder.to_hints(), nullifier_read_request_hints: self.nullifier_read_request_hints_builder.to_hints(), - master_nullifier_secret_keys: [NullifierKeyHint::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX] + key_validation_hints: [KeyValidationHint::empty(); MAX_KEY_VALIDATION_REQUESTS_PER_TX] }; let kernel = PrivateKernelResetCircuitPrivateInputs { previous_kernel: self.previous_kernel.to_private_kernel_data(), outputs, hints }; @@ -300,15 +300,15 @@ mod tests { let remaining_nullifier_rr_index = builder.previous_kernel.add_read_request_for_pending_nullifier(1); let nullifier_rr = builder.previous_kernel.nullifier_read_requests.storage[remaining_nullifier_rr_index]; - let nk_validation_index = builder.previous_kernel.add_request_for_nullifier_key_validation(GrumpkinPoint::new(1, 2), 27); - let nk_validation = builder.previous_kernel.nullifier_key_validation_requests.storage[nk_validation_index]; + let key_validation_index = builder.previous_kernel.add_request_for_key_validation(GrumpkinPoint::new(1, 2), 27); + let key_validation = builder.previous_kernel.key_validation_requests.storage[key_validation_index]; // Check that they have been propagated to the next kernel let result = builder.execute(); assert_eq(result.validation_requests.note_hash_read_requests[0], note_hash_rr); assert_eq(result.validation_requests.nullifier_read_requests[0], nullifier_rr); - assert_eq(result.validation_requests.nullifier_key_validation_requests[0], nk_validation); + assert_eq(result.validation_requests.key_validation_requests[0], key_validation); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index b35cb1e6d86..ffd088d8464 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -7,8 +7,8 @@ use dep::types::{ }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, + MAX_NOTE_ENCRYPTED_LOGS_PER_TX }, grumpkin_private_key::GrumpkinPrivateKey, utils::arrays::array_length, traits::is_empty }; @@ -72,7 +72,7 @@ mod tests { }; use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE }; @@ -331,10 +331,10 @@ mod tests { builder.failed(); } - #[test(should_fail_with="Non empty nullifier key validation requests")] - unconstrained fn non_empty_nullifier_key_validations() { + #[test(should_fail_with="Non empty key validation requests")] + unconstrained fn non_empty_key_validations() { let mut builder = PrivateKernelTailInputsBuilder::new(); - let _void = builder.previous_kernel.add_request_for_nullifier_key_validation(GrumpkinPoint::new(1, 2), 27); + let _void = builder.previous_kernel.add_request_for_key_validation(GrumpkinPoint::new(1, 2), 27); builder.failed(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index 8e8993d4bb2..cc688c36dec 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -7,8 +7,8 @@ use dep::types::{ }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, + MAX_NOTE_ENCRYPTED_LOGS_PER_TX }, grumpkin_private_key::GrumpkinPrivateKey, utils::arrays::array_length, traits::is_empty }; @@ -71,8 +71,8 @@ mod tests { }; use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, MAX_NOTE_ENCRYPTED_LOGS_PER_TX + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, DA_BYTES_PER_FIELD, + DA_GAS_PER_BYTE, MAX_NOTE_ENCRYPTED_LOGS_PER_TX }; use dep::types::{ abis::{ @@ -374,10 +374,10 @@ mod tests { builder.failed(); } - #[test(should_fail_with="Non empty nullifier key validation requests")] - unconstrained fn non_empty_nullifier_key_validations() { + #[test(should_fail_with="Non empty key validation requests")] + unconstrained fn non_empty_key_validations() { let mut builder = PrivateKernelTailToPublicInputsBuilder::new(); - let _void = builder.previous_kernel.add_request_for_nullifier_key_validation(GrumpkinPoint::new(1, 2), 27); + let _void = builder.previous_kernel.add_request_for_key_validation(GrumpkinPoint::new(1, 2), 27); builder.failed(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr index dbc5f629877..0d5cd45d2c7 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr @@ -1,8 +1,8 @@ use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; use dep::types::{ abis::{ - caller_context::CallerContext, note_hash::NoteHash, nullifier::Nullifier, - private_call_request::PrivateCallRequest, read_request::ReadRequest, + key_validation_request::KeyValidationRequest, caller_context::CallerContext, note_hash::NoteHash, + nullifier::Nullifier, private_call_request::PrivateCallRequest, read_request::ReadRequest, log_hash::{LogHash, NoteLogHash} }, address::EthAddress, grumpkin_point::GrumpkinPoint, messaging::l2_to_l1_message::L2ToL1Message @@ -36,20 +36,19 @@ fn validate_arrays_malformed_nullifier_read_requests_fails() { builder.validate(); } -// Enable this test if MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is greater than 1. -// #[test(should_fail_with="invalid array")] -// fn validate_arrays_malformed_nullifier_key_validation_requests_fails() { -// let mut builder = PrivateCallDataValidatorBuilder::new(); +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_key_validation_requests_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); -// builder.private_call.public_inputs.nullifier_key_validation_requests.extend_from_array( -// [ -// NullifierKeyValidationRequest::empty(), -// NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: 12, y: 34 }, app_nullifier_secret_key: 5 } -// ] -// ); + builder.private_call.public_inputs.key_validation_requests.extend_from_array( + [ + KeyValidationRequest::empty(), + KeyValidationRequest { pk_m: GrumpkinPoint { x: 12, y: 34 }, sk_app: 5 } + ] + ); -// builder.validate(); -// } + builder.validate(); +} #[test(should_fail_with="invalid array")] fn validate_arrays_malformed_note_hashes_fails() { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr index 2d4947cfcef..507705d905f 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr @@ -3,7 +3,7 @@ use dep::types::{ PrivateKernelCircuitPublicInputs, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + MAX_KEY_VALIDATION_REQUESTS_PER_TX } }; @@ -11,7 +11,7 @@ global NOTE_HASH_PENDING_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; // 128 global NOTE_HASH_SETTLED_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; global NULLIFIER_PENDING_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; // 8 global NULLIFIER_SETTLED_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; -global NULLIFIER_KEYS = MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX; // 4 +global NULLIFIER_KEYS = MAX_KEY_VALIDATION_REQUESTS_PER_TX; // 4 unconstrained fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.execute() diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr index d39fcc38ecf..a8757a84662 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr @@ -3,7 +3,7 @@ use dep::types::{ PrivateKernelCircuitPublicInputs, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + MAX_KEY_VALIDATION_REQUESTS_PER_TX } }; @@ -11,7 +11,7 @@ global NOTE_HASH_PENDING_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; // 128 global NOTE_HASH_SETTLED_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; global NULLIFIER_PENDING_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; // 8 global NULLIFIER_SETTLED_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; -global NULLIFIER_KEYS = MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX; // 4 +global NULLIFIER_KEYS = MAX_KEY_VALIDATION_REQUESTS_PER_TX; // 4 #[recursive] fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr index 877112c0dd1..dbafe5b01ba 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr @@ -1,23 +1,22 @@ use crate::{ note_hash_read_request_reset::NoteHashReadRequestHints, nullifier_read_request_reset::NullifierReadRequestHints, reset::read_request::reset_read_requests, - reset::nullifier_key::{NullifierKeyHint, reset_nullifier_keys} + reset::key_validation_hint::{KeyValidationHint, reset_key_validation_requests} }; use dep::types::{ abis::{ note_hash::ScopedNoteHash, nullifier::ScopedNullifier, validation_requests::ValidationRequests, - read_request::ScopedReadRequest, - nullifier_key_validation_request::ScopedNullifierKeyValidationRequest + read_request::ScopedReadRequest, key_validation_request::ScopedKeyValidationRequest }, constants::{ - MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, GENERATOR_INDEX__NSK_M, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX }, grumpkin_private_key::GrumpkinPrivateKey, hash::poseidon2_hash, traits::is_empty, utils::arrays::filter_array_to_bounded_vec }; -struct PrivateValidationRequestProcessor { +struct PrivateValidationRequestProcessor { validation_requests: ValidationRequests, note_hash_read_request_hints: NoteHashReadRequestHints, pending_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], @@ -25,14 +24,14 @@ struct PrivateValidationRequestProcessor, pending_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], nullifier_tree_root: Field, - master_nullifier_secret_keys: [NullifierKeyHint; NLL_KEYS], + key_validation_hints: [KeyValidationHint; KEY_VALIDATION_REQUESTS], } -impl PrivateValidationRequestProcessor { +impl PrivateValidationRequestProcessor { pub fn validate(self) -> ValidationRequests { let remaining_note_hash_read_requests = self.validate_note_hash_read_requests(); let remaining_nullifier_read_requests = self.validate_nullifier_read_requests(); - let remaining_nullifier_key_validation_requests = self.validate_nullifier_keys(); + let remaining_key_validation_requests = self.validate_keys(); ValidationRequests { for_rollup: self.validation_requests.for_rollup, @@ -40,7 +39,7 @@ impl Pri public_data_reads: self.validation_requests.public_data_reads, note_hash_read_requests: remaining_note_hash_read_requests.storage, nullifier_read_requests: remaining_nullifier_read_requests.storage, - nullifier_key_validation_requests: remaining_nullifier_key_validation_requests.storage + key_validation_requests: remaining_key_validation_requests.storage } } @@ -66,10 +65,10 @@ impl Pri ) } - fn validate_nullifier_keys(self) -> BoundedVec { - reset_nullifier_keys( - self.validation_requests.nullifier_key_validation_requests, - self.master_nullifier_secret_keys + fn validate_keys(self) -> BoundedVec { + reset_key_validation_requests( + self.validation_requests.key_validation_requests, + self.key_validation_hints ) } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr index 740cbc359fb..283e01ab190 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr @@ -2,4 +2,4 @@ mod mutable_data_read_request; mod non_existent_read_request; mod read_request; mod transient_data; -mod nullifier_key; +mod key_validation_hint; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr new file mode 100644 index 00000000000..d902e36ee1b --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr @@ -0,0 +1,62 @@ +use dep::types::{ + traits::{Empty, is_empty}, abis::{key_validation_request::ScopedKeyValidationRequest}, + constants::MAX_KEY_VALIDATION_REQUESTS_PER_TX, grumpkin_private_key::GrumpkinPrivateKey, + hash::poseidon2_hash, utils::arrays::filter_array_to_bounded_vec +}; + +struct KeyValidationHint { + sk_m: GrumpkinPrivateKey, + sk_app_generator_index: Field, + request_index: u64, +} + +impl Empty for KeyValidationHint { + fn empty() -> Self { + KeyValidationHint { + sk_m: GrumpkinPrivateKey::empty(), + sk_app_generator_index: 0, + request_index: 0, + } + } +} + +impl Eq for KeyValidationHint { + fn eq(self, other: Self) -> bool { + self.sk_m.eq(other.sk_m) & self.request_index.eq(other.request_index) + } + +} + +pub fn reset_key_validation_requests( + key_validation_requests: [ScopedKeyValidationRequest; MAX_KEY_VALIDATION_REQUESTS_PER_TX], + key_validation_hints: [KeyValidationHint; N] +) -> BoundedVec { + let mut should_propagate = key_validation_requests.map(|req| !is_empty(req)); + for i in 0..N { + let hint = key_validation_hints[i]; + if !is_empty(hint) { + let scoped_request = key_validation_requests[hint.request_index]; + let contract_address = scoped_request.contract_address; + let request = scoped_request.request; + let sk_m = hint.sk_m; + let sk_app_generator_index = hint.sk_app_generator_index; + + // First we check that derived public key matches master public key from request + let pk_m = sk_m.derive_public_key(); + assert( + pk_m.eq(request.pk_m), "Failed to derive matching master public key from the secret key." + ); + + // Then we check that siloing the master secret key with the contract address gives the app secret key + + let sk_app = poseidon2_hash([sk_m.high, sk_m.low, contract_address.to_field(), sk_app_generator_index]); + assert( + sk_app.eq(request.sk_app), "Failed to derive matching app secret key from the secret key." + ); + + should_propagate[hint.request_index] = false; + } + } + + filter_array_to_bounded_vec(key_validation_requests, should_propagate) +} diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr deleted file mode 100644 index 91207ddb717..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/nullifier_key.nr +++ /dev/null @@ -1,66 +0,0 @@ -use crate::{nullifier_read_request_reset::NullifierReadRequestHints}; -use dep::types::{ - traits::{Empty, is_empty}, - abis::{nullifier_key_validation_request::ScopedNullifierKeyValidationRequest}, - constants::{MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GENERATOR_INDEX__NSK_M}, - grumpkin_private_key::GrumpkinPrivateKey, hash::poseidon2_hash, - utils::arrays::filter_array_to_bounded_vec -}; - -struct NullifierKeyHint { - private_key: GrumpkinPrivateKey, - request_index: u64, -} - -impl Empty for NullifierKeyHint { - fn empty() -> Self { - NullifierKeyHint { - private_key: GrumpkinPrivateKey::empty(), - request_index: 0, - } - } -} - -impl Eq for NullifierKeyHint { - fn eq(self, other: Self) -> bool { - self.private_key.eq(other.private_key) & self.request_index.eq(other.request_index) - } - -} - -pub fn reset_nullifier_keys( - nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], - key_hints: [NullifierKeyHint; N] -) -> BoundedVec { - let mut should_propagate = nullifier_key_validation_requests.map(|req| !is_empty(req)); - for i in 0..N { - let hint = key_hints[i]; - if !is_empty(hint) { - let scoped_request = nullifier_key_validation_requests[hint.request_index]; - let contract_address = scoped_request.contract_address; - let request = scoped_request.request; - let master_nullifier_secret_key = hint.private_key; - - // First we check that derived public key matches master nullifier public key from request - let master_nullifier_public_key = master_nullifier_secret_key.derive_public_key(); - assert( - master_nullifier_public_key.eq(request.master_nullifier_public_key), "Failed to derive matching master nullifier public key from the secret key." - ); - - // Then we check that siloing the master secret key with the contract address gives the app nullifier secret key - - let app_nullifier_secret_key = poseidon2_hash( - [ - master_nullifier_secret_key.high, master_nullifier_secret_key.low, contract_address.to_field(), GENERATOR_INDEX__NSK_M - ] - ); - assert( - app_nullifier_secret_key.eq(request.app_nullifier_secret_key), "Failed to derive matching app nullifier secret key from the secret key." - ); - - should_propagate[hint.request_index] = false; - } - } - - filter_array_to_bounded_vec(nullifier_key_validation_requests, should_propagate) -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index dca4e80ae20..3b0e0938572 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -16,7 +16,7 @@ mod read_request; mod log_hash; mod note_hash; mod nullifier; -mod nullifier_key_validation_request; +mod key_validation_request; mod public_data_read; mod public_data_update_request; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/key_validation_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/key_validation_request.nr new file mode 100644 index 00000000000..4bf6ade35d2 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/key_validation_request.nr @@ -0,0 +1,101 @@ +use dep::std::cmp::Eq; +use crate::{ + address::AztecAddress, + constants::{SCOPED_KEY_VALIDATION_REQUEST_LENGTH, KEY_VALIDATION_REQUEST_LENGTH}, + traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, + utils::{arrays::array_concat, reader::Reader} +}; + +struct KeyValidationRequest { + pk_m: GrumpkinPoint, + sk_app: Field, // not a grumpkin scalar because it's output of poseidon2 +} + +impl Eq for KeyValidationRequest { + fn eq(self, request: KeyValidationRequest) -> bool { + (request.pk_m.eq(self.pk_m)) + & (request.sk_app.eq(self.sk_app)) + } +} + +impl Empty for KeyValidationRequest { + fn empty() -> Self { + KeyValidationRequest { + pk_m: GrumpkinPoint::zero(), + sk_app: 0, + } + } +} + +impl Serialize for KeyValidationRequest { + fn serialize(self) -> [Field; KEY_VALIDATION_REQUEST_LENGTH] { + [ + self.pk_m.x, + self.pk_m.y, + self.sk_app, + ] + } +} + +impl Deserialize for KeyValidationRequest { + fn deserialize(fields: [Field; KEY_VALIDATION_REQUEST_LENGTH]) -> Self { + Self { + pk_m: GrumpkinPoint::new(fields[0], fields[1]), + sk_app: fields[2], + } + } +} + +impl KeyValidationRequest { + pub fn scope(self, contract_address: AztecAddress) -> ScopedKeyValidationRequest { + ScopedKeyValidationRequest { request: self, contract_address } + } +} + +struct ScopedKeyValidationRequest { + request: KeyValidationRequest, + contract_address: AztecAddress, +} + +impl Eq for ScopedKeyValidationRequest { + fn eq(self, other: ScopedKeyValidationRequest) -> bool { + (self.request.eq(other.request)) + & (self.contract_address.eq(other.contract_address)) + } +} + +impl Empty for ScopedKeyValidationRequest { + fn empty() -> Self { + ScopedKeyValidationRequest { + request: KeyValidationRequest::empty(), + contract_address: AztecAddress::zero(), + } + } +} + +impl Serialize for ScopedKeyValidationRequest { + fn serialize(self) -> [Field; SCOPED_KEY_VALIDATION_REQUEST_LENGTH] { + array_concat(self.request.serialize(), [self.contract_address.to_field()]) + } +} + +impl Deserialize for ScopedKeyValidationRequest { + fn deserialize(fields: [Field; SCOPED_KEY_VALIDATION_REQUEST_LENGTH]) -> Self { + let mut reader = Reader::new(fields); + let res = Self { + request: reader.read_struct(KeyValidationRequest::deserialize), + contract_address: reader.read_struct(AztecAddress::deserialize), + }; + reader.finish(); + res + } +} + +#[test] +fn serialization_of_empty() { + let item = ScopedKeyValidationRequest::empty(); + let serialized = item.serialize(); + let deserialized = ScopedKeyValidationRequest::deserialize(serialized); + assert(item.eq(deserialized)); +} + diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr deleted file mode 100644 index 0424f6a3d7e..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr +++ /dev/null @@ -1,101 +0,0 @@ -use dep::std::cmp::Eq; -use crate::{ - address::AztecAddress, - constants::{SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, - traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, - utils::{arrays::array_concat, reader::Reader} -}; - -struct NullifierKeyValidationRequest { - master_nullifier_public_key: GrumpkinPoint, - app_nullifier_secret_key: Field, // not a grumpkin scalar because it's output of poseidon2 -} - -impl Eq for NullifierKeyValidationRequest { - fn eq(self, request: NullifierKeyValidationRequest) -> bool { - (request.master_nullifier_public_key.eq(self.master_nullifier_public_key)) - & (request.app_nullifier_secret_key.eq(self.app_nullifier_secret_key)) - } -} - -impl Empty for NullifierKeyValidationRequest { - fn empty() -> Self { - NullifierKeyValidationRequest { - master_nullifier_public_key: GrumpkinPoint::zero(), - app_nullifier_secret_key: 0, - } - } -} - -impl Serialize for NullifierKeyValidationRequest { - fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH] { - [ - self.master_nullifier_public_key.x, - self.master_nullifier_public_key.y, - self.app_nullifier_secret_key, - ] - } -} - -impl Deserialize for NullifierKeyValidationRequest { - fn deserialize(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH]) -> Self { - Self { - master_nullifier_public_key: GrumpkinPoint::new(fields[0], fields[1]), - app_nullifier_secret_key: fields[2], - } - } -} - -impl NullifierKeyValidationRequest { - pub fn scope(self, contract_address: AztecAddress) -> ScopedNullifierKeyValidationRequest { - ScopedNullifierKeyValidationRequest { request: self, contract_address } - } -} - -struct ScopedNullifierKeyValidationRequest { - request: NullifierKeyValidationRequest, - contract_address: AztecAddress, -} - -impl Eq for ScopedNullifierKeyValidationRequest { - fn eq(self, other: ScopedNullifierKeyValidationRequest) -> bool { - (self.request.eq(other.request)) - & (self.contract_address.eq(other.contract_address)) - } -} - -impl Empty for ScopedNullifierKeyValidationRequest { - fn empty() -> Self { - ScopedNullifierKeyValidationRequest { - request: NullifierKeyValidationRequest::empty(), - contract_address: AztecAddress::zero(), - } - } -} - -impl Serialize for ScopedNullifierKeyValidationRequest { - fn serialize(self) -> [Field; SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH] { - array_concat(self.request.serialize(), [self.contract_address.to_field()]) - } -} - -impl Deserialize for ScopedNullifierKeyValidationRequest { - fn deserialize(fields: [Field; SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH]) -> Self { - let mut reader = Reader::new(fields); - let res = Self { - request: reader.read_struct(NullifierKeyValidationRequest::deserialize), - contract_address: reader.read_struct(AztecAddress::deserialize), - }; - reader.finish(); - res - } -} - -#[test] -fn serialization_of_empty() { - let item = ScopedNullifierKeyValidationRequest::empty(); - let serialized = item.serialize(); - let deserialized = ScopedNullifierKeyValidationRequest::deserialize(serialized); - assert(item.eq(deserialized)); -} - diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 4f26052d44a..f9819b856b9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -1,17 +1,17 @@ use crate::{ abis::{ call_context::CallContext, max_block_number::MaxBlockNumber, gas_settings::GasSettings, - nullifier_key_validation_request::NullifierKeyValidationRequest, note_hash::NoteHash, - nullifier::Nullifier, private_call_request::PrivateCallRequest, read_request::ReadRequest, + key_validation_request::KeyValidationRequest, note_hash::NoteHash, nullifier::Nullifier, + private_call_request::PrivateCallRequest, read_request::ReadRequest, log_hash::{LogHash, NoteLogHash} }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS, - MAX_ENCRYPTED_LOGS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL, MAX_NOTE_ENCRYPTED_LOGS_PER_CALL + MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, + GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS, MAX_ENCRYPTED_LOGS_PER_CALL, + MAX_UNENCRYPTED_LOGS_PER_CALL, MAX_NOTE_ENCRYPTED_LOGS_PER_CALL }, header::Header, hash::pedersen_hash, messaging::l2_to_l1_message::L2ToL1Message, traits::{Deserialize, Hash, Serialize, Empty}, utils::reader::Reader, @@ -21,7 +21,7 @@ use crate::{ struct PrivateCircuitPublicInputsArrayLengths { note_hash_read_requests: u64, nullifier_read_requests: u64, - nullifier_key_validation_requests: u64, + key_validation_requests: u64, new_note_hashes: u64, new_nullifiers: u64, new_l2_to_l1_msgs: u64, @@ -37,7 +37,7 @@ impl PrivateCircuitPublicInputsArrayLengths { PrivateCircuitPublicInputsArrayLengths { note_hash_read_requests: validate_array(public_inputs.note_hash_read_requests), nullifier_read_requests: validate_array(public_inputs.nullifier_read_requests), - nullifier_key_validation_requests: validate_array(public_inputs.nullifier_key_validation_requests), + key_validation_requests: validate_array(public_inputs.key_validation_requests), new_note_hashes: validate_array(public_inputs.new_note_hashes), new_nullifiers: validate_array(public_inputs.new_nullifiers), new_l2_to_l1_msgs: validate_array(public_inputs.new_l2_to_l1_msgs), @@ -63,7 +63,7 @@ struct PrivateCircuitPublicInputs { note_hash_read_requests: [ReadRequest; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], nullifier_read_requests: [ReadRequest; MAX_NULLIFIER_READ_REQUESTS_PER_CALL], - nullifier_key_validation_requests: [NullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], + key_validation_requests: [KeyValidationRequest; MAX_KEY_VALIDATION_REQUESTS_PER_CALL], new_note_hashes: [NoteHash; MAX_NEW_NOTE_HASHES_PER_CALL], new_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_CALL], @@ -97,7 +97,7 @@ impl Eq for PrivateCircuitPublicInputs { (self.max_block_number == other.max_block_number) & (self.note_hash_read_requests == other.note_hash_read_requests) & (self.nullifier_read_requests == other.nullifier_read_requests) & - (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & + (self.key_validation_requests == other.key_validation_requests) & (self.new_note_hashes == other.new_note_hashes) & (self.new_nullifiers == other.new_nullifiers) & (self.private_call_requests == other.private_call_requests) & @@ -131,8 +131,8 @@ impl Serialize for PrivateCircuitPublicInp for i in 0..self.nullifier_read_requests.len() { fields.extend_from_array(self.nullifier_read_requests[i].serialize()); } - for i in 0..self.nullifier_key_validation_requests.len() { - fields.extend_from_array(self.nullifier_key_validation_requests[i].serialize()); + for i in 0..self.key_validation_requests.len() { + fields.extend_from_array(self.key_validation_requests[i].serialize()); } for i in 0..self.new_note_hashes.len() { fields.extend_from_array(self.new_note_hashes[i].serialize()); @@ -181,7 +181,7 @@ impl Deserialize for PrivateCircuitPublicI max_block_number: reader.read_struct(MaxBlockNumber::deserialize), note_hash_read_requests: reader.read_struct_array(ReadRequest::deserialize, [ReadRequest::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]), nullifier_read_requests: reader.read_struct_array(ReadRequest::deserialize, [ReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_CALL]), - nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), + key_validation_requests: reader.read_struct_array(KeyValidationRequest::deserialize, [KeyValidationRequest::empty(); MAX_KEY_VALIDATION_REQUESTS_PER_CALL]), new_note_hashes: reader.read_struct_array(NoteHash::deserialize, [NoteHash::empty(); MAX_NEW_NOTE_HASHES_PER_CALL]), new_nullifiers: reader.read_struct_array(Nullifier::deserialize, [Nullifier::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), private_call_requests: reader.read_struct_array(PrivateCallRequest::deserialize, [PrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), @@ -219,7 +219,7 @@ impl Empty for PrivateCircuitPublicInputs { max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: [ReadRequest::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], nullifier_read_requests: [ReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_CALL], - nullifier_key_validation_requests: [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], + key_validation_requests: [KeyValidationRequest::empty(); MAX_KEY_VALIDATION_REQUESTS_PER_CALL], new_note_hashes: [NoteHash::empty(); MAX_NEW_NOTE_HASHES_PER_CALL], new_nullifiers: [Nullifier::empty(); MAX_NEW_NULLIFIERS_PER_CALL], private_call_requests: [PrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr index 2cc7fabdb0c..31bcf1f6ec8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -1,13 +1,12 @@ use crate::{ abis::{ - max_block_number::MaxBlockNumber, - nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, + max_block_number::MaxBlockNumber, key_validation_request::ScopedKeyValidationRequest, public_data_read::PublicDataRead, read_request::ScopedReadRequest, validation_requests::rollup_validation_requests::RollupValidationRequests }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, VALIDATION_REQUESTS_LENGTH }, traits::{Serialize, Deserialize, Empty}, utils::reader::Reader @@ -19,7 +18,7 @@ struct ValidationRequests { note_hash_read_requests: [ScopedReadRequest; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_read_requests: [ScopedReadRequest; MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_non_existent_read_requests: [ScopedReadRequest; MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], - nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + key_validation_requests: [ScopedKeyValidationRequest; MAX_KEY_VALIDATION_REQUESTS_PER_TX], public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], } @@ -41,8 +40,8 @@ impl Serialize for ValidationRequests { fields.extend_from_array(self.nullifier_non_existent_read_requests[i].serialize()); } - for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { - fields.extend_from_array(self.nullifier_key_validation_requests[i].serialize()); + for i in 0..MAX_KEY_VALIDATION_REQUESTS_PER_TX { + fields.extend_from_array(self.key_validation_requests[i].serialize()); } for i in 0..MAX_PUBLIC_DATA_READS_PER_TX { @@ -64,7 +63,7 @@ impl Deserialize for ValidationRequests { note_hash_read_requests: reader.read_struct_array(ScopedReadRequest::deserialize, [ScopedReadRequest::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_TX]), nullifier_read_requests: reader.read_struct_array(ScopedReadRequest::deserialize, [ScopedReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_TX]), nullifier_non_existent_read_requests: reader.read_struct_array(ScopedReadRequest::deserialize, [ScopedReadRequest::empty(); MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX]), - nullifier_key_validation_requests: reader.read_struct_array(ScopedNullifierKeyValidationRequest::deserialize, [ScopedNullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX]), + key_validation_requests: reader.read_struct_array(ScopedKeyValidationRequest::deserialize, [ScopedKeyValidationRequest::empty(); MAX_KEY_VALIDATION_REQUESTS_PER_TX]), public_data_reads: reader.read_struct_array(PublicDataRead::deserialize, [PublicDataRead::empty(); MAX_PUBLIC_DATA_READS_PER_TX]), }; @@ -81,7 +80,7 @@ impl Empty for ValidationRequests { note_hash_read_requests: [ScopedReadRequest::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_read_requests: [ScopedReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_non_existent_read_requests: [ScopedReadRequest::empty(); MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], - nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + key_validation_requests: [ScopedKeyValidationRequest::empty(); MAX_KEY_VALIDATION_REQUESTS_PER_TX], public_data_reads: [PublicDataRead::empty(); MAX_PUBLIC_DATA_READS_PER_TX], } } @@ -93,7 +92,7 @@ impl Eq for ValidationRequests { (self.note_hash_read_requests == other.note_hash_read_requests) & (self.nullifier_read_requests == other.nullifier_read_requests) & (self.nullifier_non_existent_read_requests == other.nullifier_non_existent_read_requests) & - (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & + (self.key_validation_requests == other.key_validation_requests) & (self.public_data_reads == other.public_data_reads) } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr index 6fe9d71310a..b271d6e7d27 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr @@ -1,14 +1,13 @@ use crate::{ abis::{ - max_block_number::MaxBlockNumber, - nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, + max_block_number::MaxBlockNumber, key_validation_request::ScopedKeyValidationRequest, public_data_read::PublicDataRead, read_request::ScopedReadRequest, validation_requests::validation_requests::ValidationRequests, validation_requests::rollup_validation_requests::RollupValidationRequests }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX }, traits::Empty @@ -19,7 +18,7 @@ struct ValidationRequestsBuilder { note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_non_existent_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, + key_validation_requests: BoundedVec, public_data_reads: BoundedVec, } @@ -30,7 +29,7 @@ impl ValidationRequestsBuilder { note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, + key_validation_requests: self.key_validation_requests.storage, public_data_reads: self.public_data_reads.storage } } @@ -47,7 +46,7 @@ impl Empty for ValidationRequestsBuilder { note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), nullifier_non_existent_read_requests: BoundedVec::new(), - nullifier_key_validation_requests: BoundedVec::new(), + key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 2c2703974af..72b4fe23927 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -32,7 +32,7 @@ global MAX_PUBLIC_DATA_READS_PER_CALL: u64 = 16; global MAX_NOTE_HASH_READ_REQUESTS_PER_CALL: u64 = 32; global MAX_NULLIFIER_READ_REQUESTS_PER_CALL: u64 = 32; global MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL: u64 = 32; -global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL: u64 = 16; +global MAX_KEY_VALIDATION_REQUESTS_PER_CALL: u64 = 16; global MAX_NOTE_ENCRYPTED_LOGS_PER_CALL: u64 = 16; global MAX_ENCRYPTED_LOGS_PER_CALL: u64 = 4; // If modifying, update DEPLOYER_CONTRACT_ADDRESS. global MAX_UNENCRYPTED_LOGS_PER_CALL: u64 = 4; // If modifying, update DEPLOYER_CONTRACT_ADDRESS. @@ -48,7 +48,9 @@ global MAX_NEW_L2_TO_L1_MSGS_PER_TX: u64 = 2; global MAX_NOTE_HASH_READ_REQUESTS_PER_TX: u64 = 128; global MAX_NULLIFIER_READ_REQUESTS_PER_TX: u64 = 128; global MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX: u64 = 128; -global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX: u64 = 64; +// TODO: for large multisends we might run out of key validation requests here but not dealing with this now as +// databus will hopefully make the issue go away. +global MAX_KEY_VALIDATION_REQUESTS_PER_TX: u64 = 64; global MAX_NOTE_ENCRYPTED_LOGS_PER_TX: u64 = 64; global MAX_ENCRYPTED_LOGS_PER_TX: u64 = 8; global MAX_UNENCRYPTED_LOGS_PER_TX: u64 = 8; @@ -158,8 +160,8 @@ global L1_TO_L2_MESSAGE_LENGTH: u64 = 6; global L2_TO_L1_MESSAGE_LENGTH: u64 = 3; global SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; global MAX_BLOCK_NUMBER_LENGTH: u64 = 2; // 1 for the option flag, 1 for the value -global NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; -global SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; +global KEY_VALIDATION_REQUEST_LENGTH = 3; +global SCOPED_KEY_VALIDATION_REQUEST_LENGTH = KEY_VALIDATION_REQUEST_LENGTH + 1; global PARTIAL_STATE_REFERENCE_LENGTH: u64 = 6; global READ_REQUEST_LENGTH = 2; global LOG_HASH_LENGTH = 3; @@ -178,14 +180,14 @@ global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u64 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; global TOTAL_FEES_LENGTH = 1; global HEADER_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + CONTENT_COMMITMENT_LENGTH + STATE_REFERENCE_LENGTH + GLOBAL_VARIABLES_LENGTH + TOTAL_FEES_LENGTH; -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 4 + MAX_BLOCK_NUMBER_LENGTH + (READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (KEY_VALIDATION_REQUEST_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_CALL) + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + 1 + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; global PUBLIC_CONTEXT_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + GAS_LENGTH + 2; global SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; global PUBLIC_DATA_READ_LENGTH = 2; -global VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); +global VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (SCOPED_KEY_VALIDATION_REQUEST_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); global PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; global COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 5 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index ea2db5f580a..c80959c409b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -8,7 +8,7 @@ use crate::{ kernel_data::KernelData, public_kernel_data::PublicKernelData, max_block_number::MaxBlockNumber, private_kernel_data::PrivateKernelData, note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, - nullifier_key_validation_request::{ScopedNullifierKeyValidationRequest, NullifierKeyValidationRequest}, + key_validation_request::{ScopedKeyValidationRequest, KeyValidationRequest}, private_call_request::{PrivateCallRequest, ScopedPrivateCallRequest}, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::{ReadRequest, ScopedReadRequest}, log_hash::{LogHash, NoteLogHash}, @@ -20,9 +20,8 @@ use crate::{ MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - VK_TREE_HEIGHT, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, VK_TREE_HEIGHT, + MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX }, hash::silo_nullifier, header::Header, messaging::l2_to_l1_message::{L2ToL1Message, ScopedL2ToL1Message}, @@ -65,7 +64,7 @@ struct FixtureBuilder { note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_non_existent_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, + key_validation_requests: BoundedVec, public_data_reads: BoundedVec, // Proof. @@ -111,7 +110,7 @@ impl FixtureBuilder { note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), nullifier_non_existent_read_requests: BoundedVec::new(), - nullifier_key_validation_requests: BoundedVec::new(), + key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), proof: NestedRecursiveProof::empty(), vk: VerificationKey::empty(), @@ -185,7 +184,7 @@ impl FixtureBuilder { note_hash_read_requests: self.note_hash_read_requests, nullifier_read_requests: self.nullifier_read_requests, nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests, - nullifier_key_validation_requests: self.nullifier_key_validation_requests, + key_validation_requests: self.key_validation_requests, public_data_reads: self.public_data_reads }; validation_requests.finish() @@ -412,14 +411,10 @@ impl FixtureBuilder { new_read_request_index } - pub fn add_request_for_nullifier_key_validation( - &mut self, - master_nullifier_public_key: GrumpkinPoint, - app_nullifier_secret_key: Field - ) -> u64 { - let new_request_index = self.nullifier_key_validation_requests.len(); - let request = NullifierKeyValidationRequest { master_nullifier_public_key, app_nullifier_secret_key }; - self.nullifier_key_validation_requests.push(request.scope(self.storage_contract_address)); + pub fn add_request_for_key_validation(&mut self, pk_m: GrumpkinPoint, sk_app: Field) -> u64 { + let new_request_index = self.key_validation_requests.len(); + let request = KeyValidationRequest { pk_m, sk_app }; + self.key_validation_requests.push(request.scope(self.storage_contract_address)); new_request_index } @@ -548,7 +543,7 @@ impl Empty for FixtureBuilder { note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), nullifier_non_existent_read_requests: BoundedVec::new(), - nullifier_key_validation_requests: BoundedVec::new(), + key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), proof: NestedRecursiveProof::empty(), vk: VerificationKey::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 6976b98d761..be489e0894b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -2,7 +2,7 @@ use crate::{ abis::{ call_context::CallContext, call_request::CallRequest, caller_context::CallerContext, gas_settings::GasSettings, gas::Gas, max_block_number::MaxBlockNumber, note_hash::NoteHash, - nullifier::Nullifier, nullifier_key_validation_request::NullifierKeyValidationRequest, + nullifier::Nullifier, key_validation_request::KeyValidationRequest, private_call_request::PrivateCallRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, log_hash::{LogHash, NoteLogHash} }, @@ -12,10 +12,10 @@ use crate::{ use crate::{ constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_CALL, - MAX_UNENCRYPTED_LOGS_PER_CALL, MAX_NOTE_ENCRYPTED_LOGS_PER_CALL + MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL, + MAX_NOTE_ENCRYPTED_LOGS_PER_CALL }, traits::Empty }; @@ -34,7 +34,7 @@ struct PrivateCircuitPublicInputsBuilder { note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, + key_validation_requests: BoundedVec, new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -224,7 +224,7 @@ impl PrivateCircuitPublicInputsBuilder { max_block_number: self.max_block_number, note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, + key_validation_requests: self.key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, private_call_requests: self.private_call_requests.storage, @@ -260,7 +260,7 @@ impl Empty for PrivateCircuitPublicInputsBuilder { max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), - nullifier_key_validation_requests: BoundedVec::new(), + key_validation_requests: BoundedVec::new(), new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), private_call_requests: BoundedVec::new(), diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts index 1dbeeb7831c..62b5874c55b 100644 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ b/yarn-project/circuit-types/src/keys/key_store.ts @@ -4,6 +4,8 @@ import { type Fq, type Fr, type GrumpkinPrivateKey, + type KeyGenerator, + type KeyValidationRequest, type PartialAddress, type PublicKey, } from '@aztec/circuits.js'; @@ -32,14 +34,6 @@ export interface KeyStore { */ getAccounts(): Promise; - /** - * Gets the master nullifier public key for a given master nullifier public key hash. - * @throws If the account corresponding to the master nullifier public key hash does not exist in the key store. - * @param npkMHash - The master nullifier public key hash. - * @returns The master nullifier public key for the account. - */ - getMasterNullifierPublicKey(npkMHash: Fr): Promise; - /** * Gets the master incoming viewing public key for a given account. * @throws If the account does not exist in the key store. @@ -64,15 +58,6 @@ export interface KeyStore { */ getMasterTaggingPublicKey(account: AztecAddress): Promise; - /** - * Derives and returns the application nullifier secret key for a given master nullifier public key hash. - * @throws If the account corresponding to the master nullifier public key hash does not exist in the key store. - * @param npkMHash - The master nullifier public key hash. - * @param app - The application address to retrieve the nullifier secret key for. - * @returns A Promise that resolves to the application nullifier secret key. - */ - getAppNullifierSecretKey(npkMHash: Fr, app: AztecAddress): Promise; - /** * Retrieves application incoming viewing secret key. * @throws If the account does not exist in the key store. @@ -92,14 +77,13 @@ export interface KeyStore { getAppOutgoingViewingSecretKey(account: AztecAddress, app: AztecAddress): Promise; /** - * Retrieves the master nullifier secret key (nsk_m) corresponding to the specified master nullifier public key - * (Npk_m). + * Retrieves the sk_m for the pk_m and a generator index of the key type. * @throws If the provided public key is not associated with any of the registered accounts. - * @param masterNullifierPublicKey - The master nullifier public key to get secret key for. - * @returns A Promise that resolves to the master nullifier secret key. - * @dev Used when feeding the master nullifier secret key to the kernel circuit for nullifier keys verification. + * @param masterPublicKey - The master public key to get secret key for. + * @returns A Promise that resolves to sk_m. + * @dev Used when feeding the sk_m to the kernel circuit for keys verification. */ - getMasterNullifierSecretKeyForPublicKey(masterNullifierPublicKey: PublicKey): Promise; + getMasterSecretKeyAndAppKeyGenerator(masterPublicKey: PublicKey): Promise<[GrumpkinPrivateKey, KeyGenerator]>; /** * Retrieves the master incoming viewing secret key (ivsk_m) corresponding to the specified master incoming viewing @@ -112,12 +96,25 @@ export interface KeyStore { getMasterIncomingViewingSecretKeyForPublicKey(masterIncomingViewingPublicKey: PublicKey): Promise; /** - * Retrieves public keys hash of the account - * @throws If the provided account address is not associated with any of the registered accounts. - * @param account - The account address to get public keys hash for. - * @returns A Promise that resolves to the public keys hash. + * Gets the key validation request for a given master public key hash and contract address. + * @throws If the account corresponding to the master public key hash does not exist in the key store. + * @param pkMHash - The master public key hash. + * @param contractAddress - The contract address to silo the secret key in the the key validation request with. + * @returns The key validation request. */ - getPublicKeysHash(account: AztecAddress): Promise; + getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise; + /** + * Rotates the master nullifier key for the specified account. + * + * @dev This function updates the secret and public keys associated with the account. + * It appends a new secret key to the existing secret keys, derives the + * corresponding public key, and updates the stored keys accordingly. + * + * @param account - The account address for which the master nullifier key is being rotated. + * @param newSecretKey - (Optional) A new secret key of type Fq. If not provided, a random key is generated. + * @throws If the account does not have existing nullifier secret keys or public keys. + * @returns A Promise that resolves when the key rotation is complete. + */ rotateMasterNullifierKey(account: AztecAddress, secretKey: Fq): Promise; } diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index ca2a8f9deb5..33264c6e445 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -11,7 +11,7 @@ export const MAX_PUBLIC_DATA_READS_PER_CALL = 16; export const MAX_NOTE_HASH_READ_REQUESTS_PER_CALL = 32; export const MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 32; export const MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL = 32; -export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 16; +export const MAX_KEY_VALIDATION_REQUESTS_PER_CALL = 16; export const MAX_NOTE_ENCRYPTED_LOGS_PER_CALL = 16; export const MAX_ENCRYPTED_LOGS_PER_CALL = 4; export const MAX_UNENCRYPTED_LOGS_PER_CALL = 4; @@ -25,7 +25,7 @@ export const MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; export const MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; export const MAX_NULLIFIER_READ_REQUESTS_PER_TX = 128; export const MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX = 128; -export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 64; +export const MAX_KEY_VALIDATION_REQUESTS_PER_TX = 64; export const MAX_NOTE_ENCRYPTED_LOGS_PER_TX = 64; export const MAX_ENCRYPTED_LOGS_PER_TX = 8; export const MAX_UNENCRYPTED_LOGS_PER_TX = 8; @@ -102,8 +102,8 @@ export const L1_TO_L2_MESSAGE_LENGTH = 6; export const L2_TO_L1_MESSAGE_LENGTH = 3; export const SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; export const MAX_BLOCK_NUMBER_LENGTH = 2; -export const NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; -export const SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; +export const KEY_VALIDATION_REQUEST_LENGTH = 3; +export const SCOPED_KEY_VALIDATION_REQUEST_LENGTH = KEY_VALIDATION_REQUEST_LENGTH + 1; export const PARTIAL_STATE_REFERENCE_LENGTH = 6; export const READ_REQUEST_LENGTH = 2; export const LOG_HASH_LENGTH = 3; @@ -133,7 +133,7 @@ export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH + READ_REQUEST_LENGTH * MAX_NOTE_HASH_READ_REQUESTS_PER_CALL + READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL + - NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL + + KEY_VALIDATION_REQUEST_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_CALL + NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL + NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL + PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + @@ -176,7 +176,7 @@ export const VALIDATION_REQUESTS_LENGTH = SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX + SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX + SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX + - SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + + SCOPED_KEY_VALIDATION_REQUEST_LENGTH * MAX_KEY_VALIDATION_REQUESTS_PER_TX + PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX; export const PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; export const COMBINED_ACCUMULATED_DATA_LENGTH = diff --git a/yarn-project/circuits.js/src/keys/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/keys/__snapshots__/derivation.test.ts.snap similarity index 100% rename from yarn-project/circuits.js/src/keys/__snapshots__/index.test.ts.snap rename to yarn-project/circuits.js/src/keys/__snapshots__/derivation.test.ts.snap diff --git a/yarn-project/circuits.js/src/keys/index.test.ts b/yarn-project/circuits.js/src/keys/derivation.test.ts similarity index 97% rename from yarn-project/circuits.js/src/keys/index.test.ts rename to yarn-project/circuits.js/src/keys/derivation.test.ts index de6d68d1610..f41aa0c0d3f 100644 --- a/yarn-project/circuits.js/src/keys/index.test.ts +++ b/yarn-project/circuits.js/src/keys/derivation.test.ts @@ -2,7 +2,7 @@ import { Fr, Point } from '@aztec/foundation/fields'; import { updateInlineTestData } from '@aztec/foundation/testing'; import { PublicKeys } from '../types/public_keys.js'; -import { computeAddress } from './index.js'; +import { computeAddress } from './derivation.js'; describe('🔑', () => { it('computing public keys hash matches Noir', () => { diff --git a/yarn-project/circuits.js/src/keys/derivation.ts b/yarn-project/circuits.js/src/keys/derivation.ts new file mode 100644 index 00000000000..e6d008c132c --- /dev/null +++ b/yarn-project/circuits.js/src/keys/derivation.ts @@ -0,0 +1,102 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { poseidon2Hash, sha512ToGrumpkinScalar } from '@aztec/foundation/crypto'; +import { Fq, type Fr, type GrumpkinScalar } from '@aztec/foundation/fields'; + +import { Grumpkin } from '../barretenberg/crypto/grumpkin/index.js'; +import { GeneratorIndex } from '../constants.gen.js'; +import { GrumpkinPrivateKey } from '../types/grumpkin_private_key.js'; +import { type PublicKey } from '../types/public_key.js'; +import { PublicKeys } from '../types/public_keys.js'; +import { type KeyPrefix } from './key_types.js'; +import { getKeyGenerator } from './utils.js'; + +const curve = new Grumpkin(); + +export function computeAppNullifierSecretKey(masterNullifierSecretKey: GrumpkinPrivateKey, app: AztecAddress): Fr { + return poseidon2Hash([masterNullifierSecretKey.high, masterNullifierSecretKey.low, app, GeneratorIndex.NSK_M]); +} + +export function computeAppSecretKey(skM: GrumpkinPrivateKey, app: AztecAddress, keyPrefix: KeyPrefix): Fr { + const generator = getKeyGenerator(keyPrefix); + return poseidon2Hash([skM.high, skM.low, app, generator]); +} + +export function computeIvpkApp(ivpk: PublicKey, address: AztecAddress) { + const I = Fq.fromBuffer(poseidon2Hash([address.toField(), ivpk.x, ivpk.y, GeneratorIndex.IVSK_M]).toBuffer()); + return curve.add(curve.mul(Grumpkin.generator, I), ivpk); +} + +export function computeIvskApp(ivsk: GrumpkinPrivateKey, address: AztecAddress) { + const ivpk = curve.mul(Grumpkin.generator, ivsk); + const I = Fq.fromBuffer(poseidon2Hash([address.toField(), ivpk.x, ivpk.y, GeneratorIndex.IVSK_M]).toBuffer()); + return new Fq((I.toBigInt() + ivsk.toBigInt()) % Fq.MODULUS); +} + +export function computeOvskApp(ovsk: GrumpkinPrivateKey, address: AztecAddress) { + return GrumpkinPrivateKey.fromBuffer( + poseidon2Hash([address.toField(), ovsk.high, ovsk.low, GeneratorIndex.OVSK_M]).toBuffer(), + ); +} + +export function deriveMasterNullifierSecretKey(secretKey: Fr): GrumpkinScalar { + return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.NSK_M]); +} + +export function deriveMasterIncomingViewingSecretKey(secretKey: Fr): GrumpkinScalar { + return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.IVSK_M]); +} + +export function deriveMasterOutgoingViewingSecretKey(secretKey: Fr): GrumpkinScalar { + return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.OVSK_M]); +} + +export function deriveSigningKey(secretKey: Fr): GrumpkinScalar { + // TODO(#5837): come up with a standard signing key derivation scheme instead of using ivsk_m as signing keys here + return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.IVSK_M]); +} + +export function computeAddress(publicKeysHash: Fr, partialAddress: Fr) { + const addressFr = poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]); + return AztecAddress.fromField(addressFr); +} + +export function derivePublicKeyFromSecretKey(secretKey: Fq) { + const curve = new Grumpkin(); + return curve.mul(curve.generator(), secretKey); +} + +/** + * Computes secret and public keys and public keys hash from a secret key. + * @param secretKey - The secret key to derive keys from. + * @returns The derived keys. + */ +export function deriveKeys(secretKey: Fr) { + // First we derive master secret keys - we use sha512 here because this derivation will never take place + // in a circuit + const masterNullifierSecretKey = deriveMasterNullifierSecretKey(secretKey); + const masterIncomingViewingSecretKey = deriveMasterIncomingViewingSecretKey(secretKey); + const masterOutgoingViewingSecretKey = deriveMasterOutgoingViewingSecretKey(secretKey); + const masterTaggingSecretKey = sha512ToGrumpkinScalar([secretKey, GeneratorIndex.TSK_M]); + + // Then we derive master public keys + const masterNullifierPublicKey = derivePublicKeyFromSecretKey(masterNullifierSecretKey); + const masterIncomingViewingPublicKey = derivePublicKeyFromSecretKey(masterIncomingViewingSecretKey); + const masterOutgoingViewingPublicKey = derivePublicKeyFromSecretKey(masterOutgoingViewingSecretKey); + const masterTaggingPublicKey = derivePublicKeyFromSecretKey(masterTaggingSecretKey); + + // We hash the public keys to get the public keys hash + const publicKeys = new PublicKeys( + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ); + + return { + masterNullifierSecretKey, + masterIncomingViewingSecretKey, + masterOutgoingViewingSecretKey, + masterTaggingSecretKey, + publicKeys, + }; +} diff --git a/yarn-project/circuits.js/src/keys/index.ts b/yarn-project/circuits.js/src/keys/index.ts index 2dc73210e08..0befa5d93fa 100644 --- a/yarn-project/circuits.js/src/keys/index.ts +++ b/yarn-project/circuits.js/src/keys/index.ts @@ -1,91 +1,3 @@ -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { poseidon2Hash, sha512ToGrumpkinScalar } from '@aztec/foundation/crypto'; -import { Fq, type Fr, type GrumpkinScalar } from '@aztec/foundation/fields'; - -import { Grumpkin } from '../barretenberg/crypto/grumpkin/index.js'; -import { GeneratorIndex } from '../constants.gen.js'; -import { GrumpkinPrivateKey } from '../types/grumpkin_private_key.js'; -import { type PublicKey } from '../types/public_key.js'; -import { PublicKeys } from '../types/public_keys.js'; - -const curve = new Grumpkin(); - -export function computeAppNullifierSecretKey(masterNullifierSecretKey: GrumpkinPrivateKey, app: AztecAddress): Fr { - return poseidon2Hash([masterNullifierSecretKey.high, masterNullifierSecretKey.low, app, GeneratorIndex.NSK_M]); -} - -export function computeIvpkApp(ivpk: PublicKey, address: AztecAddress) { - const I = Fq.fromBuffer(poseidon2Hash([address.toField(), ivpk.x, ivpk.y, GeneratorIndex.IVSK_M]).toBuffer()); - return curve.add(curve.mul(Grumpkin.generator, I), ivpk); -} - -export function computeIvskApp(ivsk: GrumpkinPrivateKey, address: AztecAddress) { - const ivpk = curve.mul(Grumpkin.generator, ivsk); - const I = Fq.fromBuffer(poseidon2Hash([address.toField(), ivpk.x, ivpk.y, GeneratorIndex.IVSK_M]).toBuffer()); - return new Fq((I.toBigInt() + ivsk.toBigInt()) % Fq.MODULUS); -} - -export function computeOvskApp(ovsk: GrumpkinPrivateKey, address: AztecAddress) { - return GrumpkinPrivateKey.fromBuffer( - poseidon2Hash([address.toField(), ovsk.high, ovsk.low, GeneratorIndex.OVSK_M]).toBuffer(), - ); -} - -export function deriveMasterNullifierSecretKey(secretKey: Fr): GrumpkinScalar { - return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.NSK_M]); -} - -export function deriveMasterIncomingViewingSecretKey(secretKey: Fr): GrumpkinScalar { - return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.IVSK_M]); -} - -export function deriveSigningKey(secretKey: Fr): GrumpkinScalar { - // TODO(#5837): come up with a standard signing key derivation scheme instead of using ivsk_m as signing keys here - return sha512ToGrumpkinScalar([secretKey, GeneratorIndex.IVSK_M]); -} - -export function computeAddress(publicKeysHash: Fr, partialAddress: Fr) { - const addressFr = poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]); - return AztecAddress.fromField(addressFr); -} - -export function derivePublicKeyFromSecretKey(secretKey: Fq) { - const curve = new Grumpkin(); - return curve.mul(curve.generator(), secretKey); -} - -/** - * Computes secret and public keys and public keys hash from a secret key. - * @param secretKey - The secret key to derive keys from. - * @returns The derived keys. - */ -export function deriveKeys(secretKey: Fr) { - // First we derive master secret keys - we use sha512 here because this derivation will never take place - // in a circuit - const masterNullifierSecretKey = deriveMasterNullifierSecretKey(secretKey); - const masterIncomingViewingSecretKey = deriveMasterIncomingViewingSecretKey(secretKey); - const masterOutgoingViewingSecretKey = sha512ToGrumpkinScalar([secretKey, GeneratorIndex.OVSK_M]); - const masterTaggingSecretKey = sha512ToGrumpkinScalar([secretKey, GeneratorIndex.TSK_M]); - - // Then we derive master public keys - const masterNullifierPublicKey = derivePublicKeyFromSecretKey(masterNullifierSecretKey); - const masterIncomingViewingPublicKey = derivePublicKeyFromSecretKey(masterIncomingViewingSecretKey); - const masterOutgoingViewingPublicKey = derivePublicKeyFromSecretKey(masterOutgoingViewingSecretKey); - const masterTaggingPublicKey = derivePublicKeyFromSecretKey(masterTaggingSecretKey); - - // We hash the public keys to get the public keys hash - const publicKeys = new PublicKeys( - masterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, - ); - - return { - masterNullifierSecretKey, - masterIncomingViewingSecretKey, - masterOutgoingViewingSecretKey, - masterTaggingSecretKey, - publicKeys, - }; -} +export * from './derivation.js'; +export * from './key_types.js'; +export * from './utils.js'; diff --git a/yarn-project/circuits.js/src/keys/key_types.ts b/yarn-project/circuits.js/src/keys/key_types.ts new file mode 100644 index 00000000000..3ccc908c14d --- /dev/null +++ b/yarn-project/circuits.js/src/keys/key_types.ts @@ -0,0 +1,5 @@ +import { type GeneratorIndex } from '../constants.gen.js'; + +export type KeyGenerator = GeneratorIndex.NSK_M | GeneratorIndex.IVSK_M | GeneratorIndex.OVSK_M | GeneratorIndex.TSK_M; +export type KeyPrefix = 'n' | 'iv' | 'ov' | 't'; +export const KEY_PREFIXES: KeyPrefix[] = ['n', 'iv', 'ov', 't']; diff --git a/yarn-project/circuits.js/src/keys/utils.ts b/yarn-project/circuits.js/src/keys/utils.ts new file mode 100644 index 00000000000..c7c9657917d --- /dev/null +++ b/yarn-project/circuits.js/src/keys/utils.ts @@ -0,0 +1,8 @@ +import { GeneratorIndex } from '../constants.gen.js'; +import { type KeyGenerator, type KeyPrefix } from './key_types.js'; + +export function getKeyGenerator(prefix: KeyPrefix): KeyGenerator { + // We get enum key by capitalizing key prefix and concatenating it with 'SK_M' + const enumKey = `${prefix.toUpperCase()}SK_M`; + return GeneratorIndex[enumKey as keyof typeof GeneratorIndex] as KeyGenerator; +} diff --git a/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts b/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts index 90380d66b08..0de55dd2b8b 100644 --- a/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts +++ b/yarn-project/circuits.js/src/scripts/generate_reset_variants.ts @@ -2,8 +2,8 @@ import fs from 'fs'; import path from 'path'; import { + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, } from '../constants.gen.js'; @@ -23,7 +23,7 @@ const prelude = ` // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. import { MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, } from '../../constants.gen.js'; import type { PrivateKernelResetCircuitPrivateInputs } from './private_kernel_reset_circuit_private_inputs.js'; @@ -49,7 +49,7 @@ function buildPrivateResetVariantsObject(variants: ResetVariant[]): string { NOTE_HASH_SETTLED_AMOUNT: MAX_NOTE_HASH_READ_REQUESTS_PER_TX, NULLIFIER_PENDING_AMOUNT: MAX_NULLIFIER_READ_REQUESTS_PER_TX, NULLIFIER_SETTLED_AMOUNT: MAX_NULLIFIER_READ_REQUESTS_PER_TX, - NULLIFIER_KEYS: MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + NULLIFIER_KEYS: MAX_KEY_VALIDATION_REQUESTS_PER_TX, }, } as const;\n`; return output; @@ -77,7 +77,7 @@ function buildPrivateResetVariantsType(variants: ResetVariant[]): string { typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, - typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX, 'full' >;`; return output; @@ -97,8 +97,8 @@ function validateVariants(variants: ResetVariant[]) { if (variant.replacements.NULLIFIER_SETTLED_AMOUNT > MAX_NULLIFIER_READ_REQUESTS_PER_TX) { throw new Error(`NULLIFIER_SETTLED_AMOUNT must be less than ${MAX_NULLIFIER_READ_REQUESTS_PER_TX}`); } - if (variant.replacements.NULLIFIER_KEYS > MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) { - throw new Error(`NULLIFIER_KEYS must be less than ${MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX}`); + if (variant.replacements.NULLIFIER_KEYS > MAX_KEY_VALIDATION_REQUESTS_PER_TX) { + throw new Error(`NULLIFIER_KEYS must be less than ${MAX_KEY_VALIDATION_REQUESTS_PER_TX}`); } } } diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 9d763fe68ff..3603206f712 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -42,7 +42,7 @@ export * from './membership_witness.js'; export * from './non_existent_read_request_hints.js'; export * from './note_hash.js'; export * from './nullifier.js'; -export * from './nullifier_key_validation_request.js'; +export * from './key_validation_request.js'; export * from './parity/base_parity_inputs.js'; export * from './parity/parity_public_inputs.js'; export * from './parity/root_parity_input.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts index 4c15cca12fa..a35c33f9730 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts @@ -10,8 +10,8 @@ import { NoteLogHash } from '../log_hash.js'; import { ScopedNoteHash } from '../note_hash.js'; import { ScopedNullifier } from '../nullifier.js'; import { + KeyValidationHint, type NoteHashReadRequestHints, - NullifierKeyHint, type NullifierReadRequestHints, noteHashReadRequestHintsFromBuffer, nullifierReadRequestHintsFromBuffer, @@ -44,7 +44,7 @@ export class PrivateKernelResetHints< NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, - NLL_KEYS extends number, + KEY_VALIDATION_REQUESTS extends number, > { constructor( /** @@ -67,11 +67,10 @@ export class PrivateKernelResetHints< * Contains hints for the nullifier read requests to locate corresponding pending or settled nullifiers. */ public nullifierReadRequestHints: NullifierReadRequestHints, - /** - * The master nullifier secret keys for the nullifier key validation requests. + * Contains hints for key validation request. */ - public masterNullifierSecretKeys: Tuple, + public keyValidationHints: Tuple, ) {} toBuffer() { @@ -81,7 +80,7 @@ export class PrivateKernelResetHints< this.transientNoteHashIndexesForLogs, this.noteHashReadRequestHints, this.nullifierReadRequestHints, - this.masterNullifierSecretKeys, + this.keyValidationHints, ); } @@ -90,19 +89,19 @@ export class PrivateKernelResetHints< NEW_NH_RR_SETTLED extends number, NEW_NLL_RR_PENDING extends number, NEW_NLL_RR_SETTLED extends number, - NEW_NLL_KEYS extends number, + NEW_KEY_VALIDATION_REQUESTS extends number, >( numNoteHashReadRequestPending: NEW_NH_RR_PENDING, numNoteHashReadRequestSettled: NEW_NH_RR_SETTLED, numNullifierReadRequestPending: NEW_NLL_RR_PENDING, numNullifierReadRequestSettled: NEW_NLL_RR_SETTLED, - numNullifierKeys: NEW_NLL_KEYS, + numKeyValidationRequests: NEW_KEY_VALIDATION_REQUESTS, ): PrivateKernelResetHints< NEW_NH_RR_PENDING, NEW_NH_RR_SETTLED, NEW_NLL_RR_PENDING, NEW_NLL_RR_SETTLED, - NEW_NLL_KEYS + NEW_KEY_VALIDATION_REQUESTS > { return new PrivateKernelResetHints( this.transientNullifierIndexesForNoteHashes, @@ -110,7 +109,10 @@ export class PrivateKernelResetHints< this.transientNoteHashIndexesForLogs, this.noteHashReadRequestHints.trimToSizes(numNoteHashReadRequestPending, numNoteHashReadRequestSettled), this.nullifierReadRequestHints.trimToSizes(numNullifierReadRequestPending, numNullifierReadRequestSettled), - this.masterNullifierSecretKeys.slice(0, numNullifierKeys) as Tuple, + this.keyValidationHints.slice(0, numKeyValidationRequests) as Tuple< + KeyValidationHint, + NEW_KEY_VALIDATION_REQUESTS + >, ); } /** @@ -123,15 +125,15 @@ export class PrivateKernelResetHints< NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, - NLL_KEYS extends number, + KEY_VALIDATION_REQUESTS extends number, >( buffer: Buffer | BufferReader, numNoteHashReadRequestPending: NH_RR_PENDING, numNoteHashReadRequestSettled: NH_RR_SETTLED, numNullifierReadRequestPending: NLL_RR_PENDING, numNullifierReadRequestSettled: NLL_RR_SETTLED, - numNullifierKeys: NLL_KEYS, - ): PrivateKernelResetHints { + numNullifierKeys: KEY_VALIDATION_REQUESTS, + ): PrivateKernelResetHints { const reader = BufferReader.asReader(buffer); return new PrivateKernelResetHints( reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_TX), @@ -145,7 +147,7 @@ export class PrivateKernelResetHints< fromBuffer: buf => nullifierReadRequestHintsFromBuffer(buf, numNullifierReadRequestPending, numNullifierReadRequestSettled), }), - reader.readArray(numNullifierKeys, NullifierKeyHint), + reader.readArray(numNullifierKeys, KeyValidationHint), ); } } @@ -158,7 +160,7 @@ export class PrivateKernelResetCircuitPrivateInputs< NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, - NLL_KEYS extends number, + KEY_VALIDATION_REQUESTS extends number, TAG extends string, > { constructor( @@ -167,7 +169,13 @@ export class PrivateKernelResetCircuitPrivateInputs< */ public previousKernel: PrivateKernelData, public outputs: PrivateKernelResetOutputs, - public hints: PrivateKernelResetHints, + public hints: PrivateKernelResetHints< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + KEY_VALIDATION_REQUESTS + >, public sizeTag: TAG, ) {} @@ -193,7 +201,7 @@ export class PrivateKernelResetCircuitPrivateInputs< NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, - NLL_KEYS extends number, + KEY_VALIDATION_REQUESTS extends number, TAG extends string, >( buffer: Buffer | BufferReader, @@ -201,14 +209,14 @@ export class PrivateKernelResetCircuitPrivateInputs< numNoteHashReadRequestSettled: NH_RR_SETTLED, numNullifierReadRequestPending: NLL_RR_PENDING, numNullifierReadRequestSettled: NLL_RR_SETTLED, - numNullifierKeys: NLL_KEYS, + numNullifierKeys: KEY_VALIDATION_REQUESTS, sizeTag: TAG, ): PrivateKernelResetCircuitPrivateInputs< NH_RR_PENDING, NH_RR_SETTLED, NLL_RR_PENDING, NLL_RR_SETTLED, - NLL_KEYS, + KEY_VALIDATION_REQUESTS, TAG > { const reader = BufferReader.asReader(buffer); diff --git a/yarn-project/circuits.js/src/structs/key_validation_request.ts b/yarn-project/circuits.js/src/structs/key_validation_request.ts new file mode 100644 index 00000000000..b76d7e1cf7f --- /dev/null +++ b/yarn-project/circuits.js/src/structs/key_validation_request.ts @@ -0,0 +1,92 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr, Point } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { KEY_VALIDATION_REQUEST_LENGTH, SCOPED_KEY_VALIDATION_REQUEST_LENGTH } from '../constants.gen.js'; + +/** + * Request for validating keys used in the app. + */ +export class KeyValidationRequest { + constructor( + /** + * Master public key (pk_m) corresponding to the same underlying secret as app secret key bellow. + */ + public readonly masterPublicKey: Point, + /** + * App-siloed secret key (sk_app) corresponding to the same underlying secret as master public key above. + */ + public readonly appSecretKey: Fr, + ) {} + + toBuffer() { + return serializeToBuffer(this.masterPublicKey, this.appSecretKey); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new KeyValidationRequest(Point.fromBuffer(reader), Fr.fromBuffer(reader)); + } + + toFields(): Fr[] { + const fields = [this.masterPublicKey.toFields(), this.appSecretKey].flat(); + if (fields.length !== KEY_VALIDATION_REQUEST_LENGTH) { + throw new Error( + `Invalid number of fields for KeyValidationRequest. Expected ${KEY_VALIDATION_REQUEST_LENGTH}, got ${fields.length}`, + ); + } + return fields; + } + + static fromFields(fields: Fr[] | FieldReader): KeyValidationRequest { + const reader = FieldReader.asReader(fields); + return new KeyValidationRequest(Point.fromFields(reader), reader.readField()); + } + + isEmpty() { + return this.masterPublicKey.isZero() && this.appSecretKey.isZero(); + } + + static empty() { + return new KeyValidationRequest(Point.ZERO, Fr.ZERO); + } +} + +/** + * Request for validating keys used in the app. + */ +export class ScopedKeyValidationRequest { + constructor(public readonly request: KeyValidationRequest, public readonly contractAddress: AztecAddress) {} + + toBuffer() { + return serializeToBuffer(this.request, this.contractAddress); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ScopedKeyValidationRequest(KeyValidationRequest.fromBuffer(reader), AztecAddress.fromBuffer(reader)); + } + + toFields(): Fr[] { + const fields = [...this.request.toFields(), this.contractAddress]; + if (fields.length !== SCOPED_KEY_VALIDATION_REQUEST_LENGTH) { + throw new Error( + `Invalid number of fields for ScopedKeyValidationRequest. Expected ${SCOPED_KEY_VALIDATION_REQUEST_LENGTH}, got ${fields.length}`, + ); + } + return fields; + } + + static fromFields(fields: Fr[] | FieldReader): ScopedKeyValidationRequest { + const reader = FieldReader.asReader(fields); + return new ScopedKeyValidationRequest(KeyValidationRequest.fromFields(reader), AztecAddress.fromFields(reader)); + } + + isEmpty() { + return this.request.isEmpty() && this.contractAddress.isZero(); + } + + static empty() { + return new ScopedKeyValidationRequest(KeyValidationRequest.empty(), AztecAddress.ZERO); + } +} diff --git a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts deleted file mode 100644 index 2d1fa9813b5..00000000000 --- a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { Fr, Point } from '@aztec/foundation/fields'; -import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -import { - NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, - SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, -} from '../constants.gen.js'; - -/** - * Request for validating a nullifier key pair used in the app. - */ -export class NullifierKeyValidationRequest { - constructor( - /** - * Public key of the nullifier key (Npk_m). - */ - public readonly masterNullifierPublicKey: Point, - /** - * App-siloed nullifier secret key (nsk_app*). - */ - public readonly appNullifierSecretKey: Fr, - ) {} - - toBuffer() { - return serializeToBuffer(this.masterNullifierPublicKey, this.appNullifierSecretKey); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new NullifierKeyValidationRequest(Point.fromBuffer(reader), Fr.fromBuffer(reader)); - } - - toFields(): Fr[] { - const fields = [this.masterNullifierPublicKey.toFields(), this.appNullifierSecretKey].flat(); - if (fields.length !== NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH) { - throw new Error( - `Invalid number of fields for NullifierKeyValidationRequest. Expected ${NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, got ${fields.length}`, - ); - } - return fields; - } - - static fromFields(fields: Fr[] | FieldReader): NullifierKeyValidationRequest { - const reader = FieldReader.asReader(fields); - return new NullifierKeyValidationRequest(Point.fromFields(reader), reader.readField()); - } - - isEmpty() { - return this.masterNullifierPublicKey.isZero() && this.appNullifierSecretKey.isZero(); - } - - static empty() { - return new NullifierKeyValidationRequest(Point.ZERO, Fr.ZERO); - } -} - -/** - * Request for validating a nullifier key pair used in the app. - */ -export class ScopedNullifierKeyValidationRequest { - constructor(public readonly request: NullifierKeyValidationRequest, public readonly contractAddress: AztecAddress) {} - - toBuffer() { - return serializeToBuffer(this.request, this.contractAddress); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new ScopedNullifierKeyValidationRequest( - NullifierKeyValidationRequest.fromBuffer(reader), - AztecAddress.fromBuffer(reader), - ); - } - - toFields(): Fr[] { - const fields = [...this.request.toFields(), this.contractAddress]; - if (fields.length !== SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH) { - throw new Error( - `Invalid number of fields for ScopedNullifierKeyValidationRequest. Expected ${SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, got ${fields.length}`, - ); - } - return fields; - } - - static fromFields(fields: Fr[] | FieldReader): ScopedNullifierKeyValidationRequest { - const reader = FieldReader.asReader(fields); - return new ScopedNullifierKeyValidationRequest( - NullifierKeyValidationRequest.fromFields(reader), - AztecAddress.fromFields(reader), - ); - } - - isEmpty() { - return this.request.isEmpty() && this.contractAddress.isZero(); - } - - static empty() { - return new ScopedNullifierKeyValidationRequest(NullifierKeyValidationRequest.empty(), AztecAddress.ZERO); - } -} diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index 4f59fd5d599..1495944a878 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -14,12 +14,12 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { GeneratorIndex, MAX_ENCRYPTED_LOGS_PER_CALL, + MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, @@ -29,12 +29,12 @@ import { import { Header } from '../structs/header.js'; import { isEmptyArray } from '../utils/index.js'; import { CallContext } from './call_context.js'; +import { KeyValidationRequest } from './key_validation_request.js'; import { L2ToL1Message } from './l2_to_l1_message.js'; import { LogHash, NoteLogHash } from './log_hash.js'; import { MaxBlockNumber } from './max_block_number.js'; import { NoteHash } from './note_hash.js'; import { Nullifier } from './nullifier.js'; -import { NullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; import { PrivateCallRequest } from './private_call_request.js'; import { ReadRequest } from './read_request.js'; import { TxContext } from './tx_context.js'; @@ -77,12 +77,9 @@ export class PrivateCircuitPublicInputs { */ public nullifierReadRequests: Tuple, /** - * Nullifier key validation requests created by the corresponding function call. + * Key validation requests created by the corresponding function call. */ - public nullifierKeyValidationRequests: Tuple< - NullifierKeyValidationRequest, - typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL - >, + public keyValidationRequests: Tuple, /** * New note hashes created by the corresponding function call. */ @@ -169,7 +166,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(MaxBlockNumber), reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), + reader.readArray(MAX_KEY_VALIDATION_REQUESTS_PER_CALL, KeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, NoteHash), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, Nullifier), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PrivateCallRequest), @@ -197,7 +194,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(MaxBlockNumber), reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), + reader.readArray(MAX_KEY_VALIDATION_REQUESTS_PER_CALL, KeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, NoteHash), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, Nullifier), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PrivateCallRequest), @@ -228,7 +225,7 @@ export class PrivateCircuitPublicInputs { MaxBlockNumber.empty(), makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, ReadRequest.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest.empty), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), + makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_CALL, KeyValidationRequest.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, NoteHash.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, Nullifier.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PrivateCallRequest.empty), @@ -256,7 +253,7 @@ export class PrivateCircuitPublicInputs { this.maxBlockNumber.isEmpty() && isEmptyArray(this.noteHashReadRequests) && isEmptyArray(this.nullifierReadRequests) && - isEmptyArray(this.nullifierKeyValidationRequests) && + isEmptyArray(this.keyValidationRequests) && isEmptyArray(this.newNoteHashes) && isEmptyArray(this.newNullifiers) && isEmptyArray(this.privateCallRequests) && @@ -286,7 +283,7 @@ export class PrivateCircuitPublicInputs { fields.maxBlockNumber, fields.noteHashReadRequests, fields.nullifierReadRequests, - fields.nullifierKeyValidationRequests, + fields.keyValidationRequests, fields.newNoteHashes, fields.newNullifiers, fields.privateCallRequests, diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/index.ts b/yarn-project/circuits.js/src/structs/read_request_hints/index.ts index c140118984c..6f64a279458 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints/index.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints/index.ts @@ -1,4 +1,4 @@ export * from './note_hash_read_request_hints.js'; export * from './nullifier_read_request_hints.js'; export * from './read_request_hints.js'; -export * from './nullifier_key_hint.js'; +export * from './key_validation_hint.js'; diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts b/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts new file mode 100644 index 00000000000..92656cf2b6c --- /dev/null +++ b/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts @@ -0,0 +1,31 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; + +export class KeyValidationHint { + constructor( + /** Master secret key used to derive sk_app and pk_m. */ + public skM: GrumpkinPrivateKey, + /** + * Generator index used to generate sk_app. + * Note: Ideally KeyGenerator type would be used here but then we would have incompatibility with the empty method. + */ + public skAppGeneratorIndex: Fr, + /** Index of the request in the array of hints. */ + public requestIndex: number, + ) {} + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new KeyValidationHint(reader.readObject(GrumpkinPrivateKey), reader.readObject(Fr), reader.readNumber()); + } + + toBuffer() { + return serializeToBuffer(this.skM, this.skAppGeneratorIndex, this.requestIndex); + } + + static empty() { + return new KeyValidationHint(GrumpkinPrivateKey.zero(), Fr.ZERO, 0); + } +} diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts b/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts deleted file mode 100644 index cb9d55f81e4..00000000000 --- a/yarn-project/circuits.js/src/structs/read_request_hints/nullifier_key_hint.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -import { GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; - -export class NullifierKeyHint { - constructor(public privateKey: GrumpkinPrivateKey, public requestIndex: number) {} - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new NullifierKeyHint(reader.readObject(GrumpkinPrivateKey), reader.readNumber()); - } - - toBuffer() { - return serializeToBuffer(this.privateKey, this.requestIndex); - } - - static empty() { - return new NullifierKeyHint(GrumpkinPrivateKey.zero(), 0); - } -} diff --git a/yarn-project/circuits.js/src/structs/validation_requests.ts b/yarn-project/circuits.js/src/structs/validation_requests.ts index 6d33a5b5865..23b99426104 100644 --- a/yarn-project/circuits.js/src/structs/validation_requests.ts +++ b/yarn-project/circuits.js/src/structs/validation_requests.ts @@ -4,13 +4,13 @@ import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/s import { inspect } from 'util'; import { + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, } from '../constants.gen.js'; -import { ScopedNullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; +import { ScopedKeyValidationRequest } from './key_validation_request.js'; import { PublicDataRead } from './public_data_read_request.js'; import { ScopedReadRequest } from './read_request.js'; import { RollupValidationRequests } from './rollup_validation_requests.js'; @@ -41,12 +41,9 @@ export class ValidationRequests { typeof MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX >, /** - * All the nullifier key validation requests made in this transaction. + * All the key validation requests made in this transaction. */ - public nullifierKeyValidationRequests: Tuple< - ScopedNullifierKeyValidationRequest, - typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX - >, + public keyValidationRequests: Tuple, /** * All the public data reads made in this transaction. */ @@ -59,7 +56,7 @@ export class ValidationRequests { this.noteHashReadRequests, this.nullifierReadRequests, this.nullifierNonExistentReadRequests, - this.nullifierKeyValidationRequests, + this.keyValidationRequests, this.publicDataReads, ); } @@ -80,7 +77,7 @@ export class ValidationRequests { reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ScopedReadRequest), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest), reader.readArray(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ScopedReadRequest), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, ScopedNullifierKeyValidationRequest), + reader.readArray(MAX_KEY_VALIDATION_REQUESTS_PER_TX, ScopedKeyValidationRequest), reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead), ); } @@ -100,7 +97,7 @@ export class ValidationRequests { makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ScopedReadRequest.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest.empty), makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ScopedReadRequest.empty), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, ScopedNullifierKeyValidationRequest.empty), + makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_TX, ScopedKeyValidationRequest.empty), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } @@ -120,7 +117,7 @@ export class ValidationRequests { .filter(x => !x.isEmpty()) .map(h => inspect(h)) .join(', ')}], - nullifierKeyValidationRequests: [${this.nullifierKeyValidationRequests + keyValidationRequests: [${this.keyValidationRequests .filter(x => !x.isEmpty()) .map(h => inspect(h)) .join(', ')}], diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index b287c870912..336963a8fee 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -34,11 +34,14 @@ import { G1AffineElement, type GrumpkinPrivateKey, GrumpkinScalar, + KeyValidationRequest, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, L2ToL1Message, LogHash, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_TX, + MAX_KEY_VALIDATION_REQUESTS_PER_CALL, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NOTE_HASHES_PER_CALL, @@ -49,8 +52,6 @@ import { MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, @@ -78,7 +79,6 @@ import { NoteHash, NoteLogHash, Nullifier, - NullifierKeyValidationRequest, NullifierLeafPreimage, NullifierNonExistentReadRequestHintsBuilder, NullifierReadRequestHintsBuilder, @@ -119,7 +119,7 @@ import { RootParityInputs, RootRollupInputs, RootRollupPublicInputs, - ScopedNullifierKeyValidationRequest, + ScopedKeyValidationRequest, ScopedReadRequest, StateDiffHints, StateReference, @@ -209,16 +209,16 @@ function makeScopedReadRequest(n: number): ScopedReadRequest { } /** - * Creates arbitrary NullifierKeyValidationRequest from the given seed. - * @param seed - The seed to use for generating the NullifierKeyValidationRequest. - * @returns A NullifierKeyValidationRequest. + * Creates arbitrary KeyValidationRequest from the given seed. + * @param seed - The seed to use for generating the KeyValidationRequest. + * @returns A KeyValidationRequest. */ -function makeNullifierKeyValidationRequest(seed: number): NullifierKeyValidationRequest { - return new NullifierKeyValidationRequest(makePoint(seed), fr(seed + 2)); +function makeKeyValidationRequests(seed: number): KeyValidationRequest { + return new KeyValidationRequest(makePoint(seed), fr(seed + 2)); } -function makeScopedNullifierKeyValidationRequest(seed: number): ScopedNullifierKeyValidationRequest { - return new ScopedNullifierKeyValidationRequest(makeNullifierKeyValidationRequest(seed), makeAztecAddress(seed + 4)); +function makeScopedKeyValidationRequests(seed: number): ScopedKeyValidationRequest { + return new ScopedKeyValidationRequest(makeKeyValidationRequests(seed), makeAztecAddress(seed + 4)); } /** @@ -279,7 +279,7 @@ export function makeValidationRequests(seed = 1) { makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, makeScopedReadRequest, seed + 0x80), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeScopedReadRequest, seed + 0x90), makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, makeScopedReadRequest, seed + 0x95), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, makeScopedNullifierKeyValidationRequest, seed + 0x100), + makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_TX, makeScopedKeyValidationRequests, seed + 0x100), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); } @@ -759,11 +759,7 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn minRevertibleSideEffectCounter: fr(0), noteHashReadRequests: makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, makeReadRequest, seed + 0x300), nullifierReadRequests: makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, makeReadRequest, seed + 0x310), - nullifierKeyValidationRequests: makeTuple( - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - makeNullifierKeyValidationRequest, - seed + 0x320, - ), + keyValidationRequests: makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_CALL, makeKeyValidationRequests, seed + 0x320), newNoteHashes: makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, makeNoteHash, seed + 0x400), newNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, makeNullifier, seed + 0x500), privateCallRequests: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, makePrivateCallRequest, seed + 0x600), diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index f3e80c9d51e..e7a65e3e0a7 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -94,6 +94,9 @@ e2e-escrow-contract: e2e-key-registry: DO +E2E_TEST --test=./src/e2e_key_registry.test.ts +e2e-keys: + DO +E2E_TEST --test=./src/e2e_keys.test.ts + e2e-lending-contract: DO +E2E_TEST --test=./src/e2e_lending_contract.test.ts diff --git a/yarn-project/end-to-end/src/e2e_key_registry.test.ts b/yarn-project/end-to-end/src/e2e_key_registry.test.ts index 8f482b6c075..5a21e4d70bb 100644 --- a/yarn-project/end-to-end/src/e2e_key_registry.test.ts +++ b/yarn-project/end-to-end/src/e2e_key_registry.test.ts @@ -1,16 +1,5 @@ -import { createAccounts } from '@aztec/accounts/testing'; -import { type AccountWallet, AztecAddress, type AztecNode, Fr, type L2Block, type PXE } from '@aztec/aztec.js'; -import { - CompleteAddress, - GeneratorIndex, - INITIAL_L2_BLOCK_NUM, - Point, - PublicKeys, - computeAppNullifierSecretKey, - deriveMasterNullifierSecretKey, -} from '@aztec/circuits.js'; -import { siloNullifier } from '@aztec/circuits.js/hash'; -import { poseidon2Hash } from '@aztec/foundation/crypto'; +import { type AccountWallet, AztecAddress, Fr, type PXE } from '@aztec/aztec.js'; +import { CompleteAddress, Point, PublicKeys } from '@aztec/circuits.js'; import { KeyRegistryContract, TestContract } from '@aztec/noir-contracts.js'; import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry'; @@ -26,7 +15,6 @@ describe('Key Registry', () => { let keyRegistry: KeyRegistryContract; let pxe: PXE; - let aztecNode: AztecNode; let testContract: TestContract; jest.setTimeout(TIMEOUT); @@ -37,7 +25,7 @@ describe('Key Registry', () => { const account = CompleteAddress.random(); beforeAll(async () => { - ({ aztecNode, teardown, pxe, wallets } = await setup(2)); + ({ teardown, pxe, wallets } = await setup(2)); keyRegistry = await KeyRegistryContract.at(getCanonicalKeyRegistryAddress(), wallets[0]); testContract = await TestContract.deploy(wallets[0]).send().deployed(); @@ -226,53 +214,4 @@ describe('Key Registry', () => { .wait(); }); }); - - describe('using nsk_app to detect nullification', () => { - // This test checks that it possible to detect that a note has been nullified just by using nsk_app. Note that this - // only works for non-transient note as transient notes never emit a note hash which makes it impossible to brute - // force their nullifier. This makes this scheme a bit useless in practice. - it('nsk_app and contract address are enough to detect note nullification', async () => { - const secret = Fr.random(); - const [account] = await createAccounts(pxe, 1, [secret]); - - const masterNullifierSecretKey = deriveMasterNullifierSecretKey(secret); - const nskApp = computeAppNullifierSecretKey(masterNullifierSecretKey, testContract.address); - - const noteValue = 5; - const noteOwner = account.getAddress(); - const noteStorageSlot = 12; - - await testContract.methods.call_create_note(noteValue, noteOwner, noteStorageSlot).send().wait(); - - expect(await getNumNullifiedNotes(nskApp, testContract.address)).toEqual(0); - - await testContract.methods.call_destroy_note(noteStorageSlot).send().wait(); - - expect(await getNumNullifiedNotes(nskApp, testContract.address)).toEqual(1); - }); - - const getNumNullifiedNotes = async (nskApp: Fr, contractAddress: AztecAddress) => { - // 1. Get all the note hashes - const blocks = await aztecNode.getBlocks(INITIAL_L2_BLOCK_NUM, 1000); - const noteHashes = blocks.flatMap((block: L2Block) => - block.body.txEffects.flatMap(txEffect => txEffect.noteHashes), - ); - // 2. Get all the seen nullifiers - const nullifiers = blocks.flatMap((block: L2Block) => - block.body.txEffects.flatMap(txEffect => txEffect.nullifiers), - ); - // 3. Derive all the possible nullifiers using nskApp - const derivedNullifiers = noteHashes.map(noteHash => { - const innerNullifier = poseidon2Hash([noteHash, nskApp, GeneratorIndex.NOTE_NULLIFIER]); - return siloNullifier(contractAddress, innerNullifier); - }); - // 4. Count the number of derived nullifiers that are in the nullifiers array - return derivedNullifiers.reduce((count, derived) => { - if (nullifiers.some(nullifier => nullifier.equals(derived))) { - count++; - } - return count; - }, 0); - }; - }); }); diff --git a/yarn-project/end-to-end/src/e2e_keys.test.ts b/yarn-project/end-to-end/src/e2e_keys.test.ts new file mode 100644 index 00000000000..41ae31de443 --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_keys.test.ts @@ -0,0 +1,128 @@ +import { createAccounts } from '@aztec/accounts/testing'; +import { + type AccountWallet, + type AztecAddress, + type AztecNode, + Fr, + type L2Block, + type PXE, + type Wallet, +} from '@aztec/aztec.js'; +import { + GeneratorIndex, + INITIAL_L2_BLOCK_NUM, + computeAppNullifierSecretKey, + computeAppSecretKey, + deriveMasterNullifierSecretKey, + deriveMasterOutgoingViewingSecretKey, + derivePublicKeyFromSecretKey, +} from '@aztec/circuits.js'; +import { siloNullifier } from '@aztec/circuits.js/hash'; +import { poseidon2Hash } from '@aztec/foundation/crypto'; +import { TestContract } from '@aztec/noir-contracts.js'; + +import { jest } from '@jest/globals'; + +import { setup } from './fixtures/utils.js'; + +const TIMEOUT = 120_000; + +describe('Key Registry', () => { + jest.setTimeout(TIMEOUT); + + let aztecNode: AztecNode; + let pxe: PXE; + let teardown: () => Promise; + + let testContract: TestContract; + + const secret = Fr.random(); + let account: AccountWallet; + + beforeAll(async () => { + let wallet: Wallet; + ({ aztecNode, pxe, teardown, wallet } = await setup(2)); + testContract = await TestContract.deploy(wallet).send().deployed(); + + [account] = await createAccounts(pxe, 1, [secret]); + }); + + afterAll(() => teardown()); + + describe('using nsk_app to detect nullification', () => { + // This test checks that it possible to detect that a note has been nullified just by using nsk_app. Note that + // this only works for non-transient notes as transient ones never emit a note hash which makes it impossible + // to brute force their nullifier. + // This might seem to make the scheme useless in practice. This could not be the case because if you have + // a note of funds, when you create the transient you are nullifying that note. So even if I cannot see when you + // nullified the transient ones, I can see that you nullified the first. + // + // E.g.: Say you have a note A, which is 10 $, you nullify it (I can see) and create B and C, that you then spend. + // I cannot see B and C, but I saw A, so I knew that you did something with those funds. + // + // There are some examples where the action is fully hidden though. One of those examples is shielding where you + // instantly consume the note after creating it. In this case, the nullifier is never emitted and hence the action + // is impossible to detect with this scheme. + // Another example is a withdraw is withdrawing from DeFi and then immediately spending the funds. In this case, + // we would need nsk_app and the contract address of the DeFi contract to detect the nullification of the initial + // note. + it('nsk_app and contract address are enough to detect note nullification', async () => { + const masterNullifierSecretKey = deriveMasterNullifierSecretKey(secret); + const nskApp = computeAppNullifierSecretKey(masterNullifierSecretKey, testContract.address); + + const noteValue = 5; + const noteOwner = account.getAddress(); + const noteStorageSlot = 12; + + await testContract.methods.call_create_note(noteValue, noteOwner, noteStorageSlot).send().wait(); + + expect(await getNumNullifiedNotes(nskApp, testContract.address)).toEqual(0); + + await testContract.methods.call_destroy_note(noteStorageSlot).send().wait(); + + expect(await getNumNullifiedNotes(nskApp, testContract.address)).toEqual(1); + }); + + const getNumNullifiedNotes = async (nskApp: Fr, contractAddress: AztecAddress) => { + // 1. Get all the note hashes + const blocks = await aztecNode.getBlocks(INITIAL_L2_BLOCK_NUM, 1000); + const noteHashes = blocks.flatMap((block: L2Block) => + block.body.txEffects.flatMap(txEffect => txEffect.noteHashes), + ); + // 2. Get all the seen nullifiers + const nullifiers = blocks.flatMap((block: L2Block) => + block.body.txEffects.flatMap(txEffect => txEffect.nullifiers), + ); + // 3. Derive all the possible nullifiers using nskApp + const derivedNullifiers = noteHashes.map(noteHash => { + const innerNullifier = poseidon2Hash([noteHash, nskApp, GeneratorIndex.NOTE_NULLIFIER]); + return siloNullifier(contractAddress, innerNullifier); + }); + // 4. Count the number of derived nullifiers that are in the nullifiers array + return derivedNullifiers.reduce((count, derived) => { + if (nullifiers.some(nullifier => nullifier.equals(derived))) { + count++; + } + return count; + }, 0); + }; + }); + + describe('ovsk_app', () => { + it('gets ovsk_app', async () => { + // Derive the ovpk_m_hash from the account secret + const ovskM = deriveMasterOutgoingViewingSecretKey(secret); + const ovpkMHash = derivePublicKeyFromSecretKey(ovskM).hash(); + + // Compute the expected ovsk_app + const expectedOvskApp = computeAppSecretKey(ovskM, testContract.address, 'ov'); + + // Get the ovsk_app via the test contract + const ovskAppBigInt = await testContract.methods.get_ovsk_app(ovpkMHash).simulate(); + const ovskApp = new Fr(ovskAppBigInt); + + // Check that the ovsk_app is as expected + expect(ovskApp).toEqual(expectedOvskApp); + }); + }); +}); diff --git a/yarn-project/key-store/src/test_key_store.test.ts b/yarn-project/key-store/src/test_key_store.test.ts index 1dde6a3f02b..436b71771e5 100644 --- a/yarn-project/key-store/src/test_key_store.test.ts +++ b/yarn-project/key-store/src/test_key_store.test.ts @@ -2,6 +2,7 @@ import { AztecAddress, Fq, Fr, + GeneratorIndex, computeAppNullifierSecretKey, deriveKeys, derivePublicKeyFromSecretKey, @@ -27,7 +28,10 @@ describe('TestKeyStore', () => { `"0x1a8a9a1d91cbb353d8df4f1bbfd0283f7fc63766f671edd9443a1270a7b2a954"`, ); - const masterNullifierPublicKey = await keyStore.getMasterNullifierPublicKey(computedMasterNullifierPublicKeyHash); + const { masterPublicKey: masterNullifierPublicKey } = await keyStore.getKeyValidationRequest( + computedMasterNullifierPublicKeyHash, + AztecAddress.random(), // Address is random because we are not interested in the app secret key here + ); expect(masterNullifierPublicKey.toString()).toMatchInlineSnapshot( `"0x2ef5d15dd65d29546680ab72846fb071f41cb9f2a0212215e6c560e29df4ff650ce764818364b376be92dc2f49577fe440e64a16012584f7c4ee94f7edbc323a"`, ); @@ -47,21 +51,15 @@ describe('TestKeyStore', () => { `"0x076429010fdebfa522b053267f654a4c5daf18589915d96f7e5001d63ea2033f27f915f254560c84450aa38e93c3162be52492d05b316e75f542e3b302117360"`, ); - const publicKeysHash = await keyStore.getPublicKeysHash(accountAddress); - expect(publicKeysHash.toString()).toMatchInlineSnapshot( - `"0x1ba15945655812587b5c16a6a8125193c901c2c31a4ac4edaed202726c0d4c89"`, - ); - // Arbitrary app contract address const appAddress = AztecAddress.fromBigInt(624n); - const appNullifierSecretKey = await keyStore.getAppNullifierSecretKey( - computedMasterNullifierPublicKeyHash, - appAddress, - ); + const { masterPublicKey: obtainedMasterNullifierPublicKey, appSecretKey: appNullifierSecretKey } = + await keyStore.getKeyValidationRequest(computedMasterNullifierPublicKeyHash, appAddress); expect(appNullifierSecretKey.toString()).toMatchInlineSnapshot( `"0x230a44dfe7cfec7a735c89f7289c5cb5d2c3dc0bf5d3505917fd2476f67873a8"`, ); + expect(obtainedMasterNullifierPublicKey).toEqual(masterNullifierPublicKey); const appIncomingViewingSecretKey = await keyStore.getAppIncomingViewingSecretKey(accountAddress, appAddress); expect(appIncomingViewingSecretKey.toString()).toMatchInlineSnapshot( @@ -80,10 +78,22 @@ describe('TestKeyStore', () => { ); // Manages to find master nullifer secret key for pub key - const masterNullifierSecretKey = await keyStore.getMasterNullifierSecretKeyForPublicKey(masterNullifierPublicKey); + const [masterNullifierSecretKey, generator] = await keyStore.getMasterSecretKeyAndAppKeyGenerator( + masterNullifierPublicKey, + ); expect(masterNullifierSecretKey.toString()).toMatchInlineSnapshot( `"0x0fde74d5e504c73b58aad420dd72590fc6004571411e7f77c45378714195a52b"`, ); + expect(generator).toBe(GeneratorIndex.NSK_M); + + // Manages to find master incoming viewing secret key for pub key + const [masterIncomingViewingSecretKey, generatorIncoming] = await keyStore.getMasterSecretKeyAndAppKeyGenerator( + masterIncomingViewingPublicKey, + ); + expect(masterIncomingViewingSecretKey.toString()).toMatchInlineSnapshot( + `"0x1f1f43082427fed511393bbabf8a471eb87af09f0e95bb740dc33e1ced1a54c1"`, + ); + expect(generatorIncoming).toBe(GeneratorIndex.IVSK_M); }); it('nullifier key rotation tests', async () => { @@ -118,35 +128,41 @@ describe('TestKeyStore', () => { await keyStore.rotateMasterNullifierKey(accountAddress, newMasterNullifierSecretKeys[2]); // We make sure we can get master nullifier public keys with master nullifier public key hashes - expect(await keyStore.getMasterNullifierPublicKey(newComputedMasterNullifierPublicKeyHashes[2])).toEqual( - newDerivedMasterNullifierPublicKeys[2], + const { masterPublicKey: masterNullifierPublicKey2 } = await keyStore.getKeyValidationRequest( + newComputedMasterNullifierPublicKeyHashes[2], + AztecAddress.random(), // Address is random because we are not interested in the app secret key here ); - expect(await keyStore.getMasterNullifierPublicKey(newComputedMasterNullifierPublicKeyHashes[1])).toEqual( - newDerivedMasterNullifierPublicKeys[1], + expect(masterNullifierPublicKey2).toEqual(newDerivedMasterNullifierPublicKeys[2]); + const { masterPublicKey: masterNullifierPublicKey1 } = await keyStore.getKeyValidationRequest( + newComputedMasterNullifierPublicKeyHashes[1], + AztecAddress.random(), // Address is random because we are not interested in the app secret key here ); - expect(await keyStore.getMasterNullifierPublicKey(newComputedMasterNullifierPublicKeyHashes[0])).toEqual( - newDerivedMasterNullifierPublicKeys[0], + expect(masterNullifierPublicKey1).toEqual(newDerivedMasterNullifierPublicKeys[1]); + const { masterPublicKey: masterNullifierPublicKey0 } = await keyStore.getKeyValidationRequest( + newComputedMasterNullifierPublicKeyHashes[0], + AztecAddress.random(), // Address is random because we are not interested in the app secret key here ); + expect(masterNullifierPublicKey0).toEqual(newDerivedMasterNullifierPublicKeys[0]); // Arbitrary app contract address const appAddress = AztecAddress.fromBigInt(624n); // We make sure we can get app nullifier secret keys with master nullifier public key hashes - const appNullifierSecretKey0 = await keyStore.getAppNullifierSecretKey( + const { appSecretKey: appNullifierSecretKey0 } = await keyStore.getKeyValidationRequest( newComputedMasterNullifierPublicKeyHashes[0], appAddress, ); expect(appNullifierSecretKey0.toString()).toMatchInlineSnapshot( `"0x296e42f1039b62290372d608fcab55b00a3f96c1c8aa347b2a830639c5a12757"`, ); - const appNullifierSecretKey1 = await keyStore.getAppNullifierSecretKey( + const { appSecretKey: appNullifierSecretKey1 } = await keyStore.getKeyValidationRequest( newComputedMasterNullifierPublicKeyHashes[1], appAddress, ); expect(appNullifierSecretKey1.toString()).toMatchInlineSnapshot( `"0x019f2a705b68683f1d86da639a543411fa779af41896c3920d0c2d5226c686dd"`, ); - const appNullifierSecretKey2 = await keyStore.getAppNullifierSecretKey( + const { appSecretKey: appNullifierSecretKey2 } = await keyStore.getKeyValidationRequest( newComputedMasterNullifierPublicKeyHashes[2], appAddress, ); diff --git a/yarn-project/key-store/src/test_key_store.ts b/yarn-project/key-store/src/test_key_store.ts index 6e5416be404..9877e8181cd 100644 --- a/yarn-project/key-store/src/test_key_store.ts +++ b/yarn-project/key-store/src/test_key_store.ts @@ -7,14 +7,20 @@ import { GeneratorIndex, type GrumpkinPrivateKey, GrumpkinScalar, + KEY_PREFIXES, + type KeyGenerator, + type KeyPrefix, + KeyValidationRequest, type PartialAddress, Point, computeAddress, - computeAppNullifierSecretKey, + computeAppSecretKey, deriveKeys, derivePublicKeyFromSecretKey, + getKeyGenerator, } from '@aztec/circuits.js'; import { poseidon2Hash } from '@aztec/foundation/crypto'; +import { type Bufferable, serializeToBuffer } from '@aztec/foundation/serialize'; import { type AztecKVStore, type AztecMap } from '@aztec/kv-store'; /** @@ -54,31 +60,34 @@ export class TestKeyStore implements KeyStore { } = deriveKeys(sk); const publicKeysHash = publicKeys.hash(); - const accountAddress = computeAddress(publicKeysHash, partialAddress); - - // We save the keys to db associated with the account address - await this.#keys.set(`${accountAddress.toString()}-public_keys_hash`, publicKeysHash.toBuffer()); - - // Naming of keys is as follows ${from}-${to}_m - await this.#keys.set(`${accountAddress.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer()); - // The key of the following is different from the others because the buffer can store multiple keys - await this.#keys.set(`${accountAddress.toString()}-ns_keys_m`, masterNullifierSecretKey.toBuffer()); - - await this.#keys.set(`${accountAddress.toString()}-np_keys_m`, publicKeys.masterNullifierPublicKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer()); - - // We store a npk_m_hash-account_address map to make address easy to obtain with the hash later on + const account = computeAddress(publicKeysHash, partialAddress); + + // Naming of keys is as follows ${account}-${n/iv/ov/t}${sk/pk}_m + await this.#keys.set(`${account.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer()); + await this.#keys.set(`${account.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer()); + await this.#keys.set(`${account.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer()); + await this.#keys.set(`${account.toString()}-nsk_m`, masterNullifierSecretKey.toBuffer()); + + await this.#keys.set(`${account.toString()}-npk_m`, publicKeys.masterNullifierPublicKey.toBuffer()); + await this.#keys.set(`${account.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer()); + await this.#keys.set(`${account.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer()); + await this.#keys.set(`${account.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer()); + + // We store pk_m_hash under `account-{n/iv/ov/t}pk_m_hash` key to be able to obtain address and key prefix + // using the #getKeyPrefixAndAccount function later on + await this.#keys.set(`${account.toString()}-npk_m_hash`, publicKeys.masterNullifierPublicKey.hash().toBuffer()); + await this.#keys.set( + `${account.toString()}-ivpk_m_hash`, + publicKeys.masterIncomingViewingPublicKey.hash().toBuffer(), + ); await this.#keys.set( - `${publicKeys.masterNullifierPublicKey.hash().toString()}-npk_m_hash`, - accountAddress.toBuffer(), + `${account.toString()}-ovpk_m_hash`, + publicKeys.masterOutgoingViewingPublicKey.hash().toBuffer(), ); + await this.#keys.set(`${account.toString()}-tpk_m_hash`, publicKeys.masterTaggingPublicKey.hash().toBuffer()); // At last, we return the newly derived account address - return Promise.resolve(new CompleteAddress(accountAddress, publicKeys, partialAddress)); + return Promise.resolve(new CompleteAddress(account, publicKeys, partialAddress)); } /** @@ -93,43 +102,72 @@ export class TestKeyStore implements KeyStore { } /** - * Gets the master nullifier public key for a given master nullifier public key hash. - * @throws If the account corresponding to the master nullifier public key hash does not exist in the key store. - * @param npkMHash - The master nullifier public key hash. - * @returns The master nullifier public key for the account. + * Gets the key validation request for a given master public key hash and contract address. + * @throws If the account corresponding to the master public key hash does not exist in the key store. + * @param pkMHash - The master public key hash. + * @param contractAddress - The contract address to silo the secret key in the the key validation request with. + * @returns The key validation request. */ - public getMasterNullifierPublicKey(npkMHash: Fr): Promise { - // Get the address for npk_m_hash - const accountAddressBuffer = this.#keys.get(`${npkMHash.toString()}-npk_m_hash`); - if (!accountAddressBuffer) { - throw new Error(`Could no find address for master nullifier public key hash ${npkMHash}.`); + public getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise { + const [keyPrefix, account] = this.#getKeyPrefixAndAccount(pkMHash); + + // Now we find the master public key for the account + // Since each public keys buffer contains multiple public keys, we need to find the one that matches the hash. + // Then we store the index of the key in the buffer to be able to quickly obtain the corresponding secret key. + let pkM: PublicKey | undefined; + let keyIndexInBuffer = 0; + { + const pkMsBuffer = this.#keys.get(`${account.toString()}-${keyPrefix}pk_m`); + if (!pkMsBuffer) { + throw new Error( + `Could not find ${keyPrefix}pk_m for account ${account.toString()} whose address was successfully obtained with ${keyPrefix}pk_m_hash ${pkMHash.toString()}.`, + ); + } + + // Now we iterate over the public keys in the buffer to find the one that matches the hash + const numKeys = pkMsBuffer.byteLength / Point.SIZE_IN_BYTES; + for (; keyIndexInBuffer < numKeys; keyIndexInBuffer++) { + const foundPkM = Point.fromBuffer( + pkMsBuffer.subarray(keyIndexInBuffer * Point.SIZE_IN_BYTES, (keyIndexInBuffer + 1) * Point.SIZE_IN_BYTES), + ); + if (foundPkM.hash().equals(pkMHash)) { + pkM = foundPkM; + break; + } + } + + if (!pkM) { + throw new Error(`Could not find ${keyPrefix}pkM for ${keyPrefix}pk_m_hash ${pkMHash.toString()}.`); + } } - const accountAddress = AztecAddress.fromBuffer(accountAddressBuffer); - // Get the master nullifier public keys buffer for the account - const masterNullifierPublicKeysBuffer = this.#keys.get(`${accountAddress.toString()}-np_keys_m`); - if (!masterNullifierPublicKeysBuffer) { - throw new Error( - `Could not find master nullifier public key for account ${accountAddress.toString()} whose address was successfully obtained with npk_m_hash ${npkMHash.toString()}.`, + // Now we find the secret key for the public key + let skM: GrumpkinPrivateKey | undefined; + { + const skMsBuffer = this.#keys.get(`${account.toString()}-${keyPrefix}sk_m`); + if (!skMsBuffer) { + throw new Error( + `Could not find ${keyPrefix}sk_m for account ${account.toString()} whose address was successfully obtained with ${keyPrefix}pk_m_hash ${pkMHash.toString()}.`, + ); + } + + skM = GrumpkinScalar.fromBuffer( + skMsBuffer.subarray( + keyIndexInBuffer * GrumpkinScalar.SIZE_IN_BYTES, + (keyIndexInBuffer + 1) * GrumpkinScalar.SIZE_IN_BYTES, + ), ); } - // We check that the buffer's length is a multiple of Point.SIZE_IN_BYTES - if (masterNullifierPublicKeysBuffer.byteLength % Point.SIZE_IN_BYTES !== 0) { - throw new Error("Master nullifier public key buffer's length is not a multiple of Point.SIZE_IN_BYTES."); + // We sanity check that it's possible to derive the public key from the secret key + if (!derivePublicKeyFromSecretKey(skM).equals(pkM)) { + throw new Error(`Could not derive ${keyPrefix}pkM from ${keyPrefix}skM.`); } - // Now we iterate over the public keys in the buffer to find the one that matches the hash - const numKeys = masterNullifierPublicKeysBuffer.byteLength / Point.SIZE_IN_BYTES; - for (let i = 0; i < numKeys; i++) { - const masterNullifierPublicKey = Point.fromBuffer( - masterNullifierPublicKeysBuffer.subarray(i * Point.SIZE_IN_BYTES, (i + 1) * Point.SIZE_IN_BYTES), - ); - if (masterNullifierPublicKey.hash().equals(npkMHash)) { - return Promise.resolve(masterNullifierPublicKey); - } - } - throw new Error(`Could not find master nullifier public key for npk_m_hash ${npkMHash.toString()}.`); + // At last we silo the secret key and return the key validation request + const skApp = computeAppSecretKey(skM, contractAddress, keyPrefix!); + + return Promise.resolve(new KeyValidationRequest(pkM, skApp)); } /** @@ -180,50 +218,6 @@ export class TestKeyStore implements KeyStore { return Promise.resolve(Point.fromBuffer(masterTaggingPublicKeyBuffer)); } - /** - * Derives and returns the application nullifier secret key for a given master nullifier public key hash. - * @throws If the account corresponding to the master nullifier public key hash does not exist in the key store. - * @param npkMHash - The master nullifier public key hash. - * @param app - The application address to retrieve the nullifier secret key for. - * @returns A Promise that resolves to the application nullifier secret key. - */ - public getAppNullifierSecretKey(npkMHash: Fr, app: AztecAddress): Promise { - // First we get the account address for npk_m_hash - const accountAddressBuffer = this.#keys.get(`${npkMHash.toString()}-npk_m_hash`); - if (!accountAddressBuffer) { - throw new Error(`Could no find address for master nullifier public key hash ${npkMHash}.`); - } - - // Now we get the master nullifier secret keys for the account - const masterNullifierSecretKeysBuffer = this.#keys.get( - `${AztecAddress.fromBuffer(accountAddressBuffer).toString()}-ns_keys_m`, - ); - if (!masterNullifierSecretKeysBuffer) { - throw new Error( - `Could not find master nullifier secret keys for account ${AztecAddress.fromBuffer( - accountAddressBuffer, - ).toString()}`, - ); - } - - // Now we iterate over all the secret keys to find the one that matches the hash - const numKeys = masterNullifierSecretKeysBuffer.byteLength / GrumpkinScalar.SIZE_IN_BYTES; - for (let i = 0; i < numKeys; i++) { - const secretKey = GrumpkinScalar.fromBuffer( - masterNullifierSecretKeysBuffer.subarray( - i * GrumpkinScalar.SIZE_IN_BYTES, - (i + 1) * GrumpkinScalar.SIZE_IN_BYTES, - ), - ); - const publicKey = derivePublicKeyFromSecretKey(secretKey); - if (publicKey.hash().equals(npkMHash)) { - return Promise.resolve(computeAppNullifierSecretKey(secretKey, app)); - } - } - - throw new Error(`Could not find master nullifier secret key for npk_m_hash ${npkMHash.toString()}.`); - } - /** * Retrieves application incoming viewing secret key. * @throws If the account does not exist in the key store. @@ -277,68 +271,44 @@ export class TestKeyStore implements KeyStore { } /** - * Retrieves the master nullifier secret key (nsk_m) corresponding to the specified master nullifier public key - * (Npk_m). + * Retrieves the sk_m for the pk_m and a generator index of the key type. * @throws If the provided public key is not associated with any of the registered accounts. - * @param masterNullifierPublicKey - The master nullifier public key to get secret key for. - * @returns A Promise that resolves to the master nullifier secret key. - * @dev Used when feeding the master nullifier secret key to the kernel circuit for nullifier keys verification. + * @param pkM - The master public key to get secret key for. + * @returns A Promise that resolves to sk_m. + * @dev Used when feeding the sk_m to the kernel circuit for keys verification. */ - public getMasterNullifierSecretKeyForPublicKey(masterNullifierPublicKey: PublicKey): Promise { - // We get the account address associated with the master nullifier public key hash - const accountAddressBuffer = this.#keys.get(`${masterNullifierPublicKey.hash().toString()}-npk_m_hash`); - if (!accountAddressBuffer) { - throw new Error( - `Could not find account address for master nullifier public key ${masterNullifierPublicKey.toString()}`, - ); - } - const accountAddress = AztecAddress.fromBuffer(accountAddressBuffer); - - // We fetch the public keys and find this specific public key's position in the buffer - const masterNullifierPublicKeysBuffer = this.#keys.get(`${accountAddress.toString()}-np_keys_m`); - if (!masterNullifierPublicKeysBuffer) { - throw new Error(`Could not find master nullifier public keys for account ${accountAddress.toString()}`); - } - - // We check that the buffer's length is a multiple of Point.SIZE_IN_BYTES - if (masterNullifierPublicKeysBuffer.byteLength % Point.SIZE_IN_BYTES !== 0) { - throw new Error("Master nullifier public key buffer's length is not a multiple of Point.SIZE_IN_BYTES."); - } - - // Now we iterate over the public keys in the buffer to find the one that matches the hash - const numKeys = masterNullifierPublicKeysBuffer.byteLength / Point.SIZE_IN_BYTES; - let keyIndex = -1; - for (let i = 0; i < numKeys; i++) { - const publicKey = Point.fromBuffer( - masterNullifierPublicKeysBuffer.subarray(i * Point.SIZE_IN_BYTES, (i + 1) * Point.SIZE_IN_BYTES), - ); - if (publicKey.equals(masterNullifierPublicKey)) { - keyIndex = i; - break; + public getMasterSecretKeyAndAppKeyGenerator(pkM: PublicKey): Promise<[GrumpkinPrivateKey, KeyGenerator]> { + const [keyPrefix, account] = this.#getKeyPrefixAndAccount(pkM); + + // We get the secret keys buffer and iterate over the values in the buffer to find the one that matches pkM + let sk: GrumpkinScalar | undefined; + { + const secretKeysBuffer = this.#keys.get(`${account.toString()}-${keyPrefix}sk_m`); + if (!secretKeysBuffer) { + throw new Error( + `Could not find ${keyPrefix}sk_m for ${keyPrefix}pk_m ${pkM.toString()}. This should not happen.`, + ); } - } - // Now we fetch the secret keys buffer and extract the secret key at the same index - const masterNullifierSecretKeysBuffer = this.#keys.get(`${accountAddress.toString()}-ns_keys_m`); - if (!masterNullifierSecretKeysBuffer) { - throw new Error(`Could not find master nullifier secret keys for account ${accountAddress.toString()}`); - } - - // We extract the secret key from the buffer - const secretKeyBuffer = masterNullifierSecretKeysBuffer.subarray( - keyIndex * GrumpkinScalar.SIZE_IN_BYTES, - (keyIndex + 1) * GrumpkinScalar.SIZE_IN_BYTES, - ); - const secretKey = GrumpkinScalar.fromBuffer(secretKeyBuffer); + const numKeys = secretKeysBuffer.byteLength / GrumpkinScalar.SIZE_IN_BYTES; + for (let i = 0; i < numKeys; i++) { + const foundSk = GrumpkinScalar.fromBuffer( + secretKeysBuffer.subarray(i * GrumpkinScalar.SIZE_IN_BYTES, (i + 1) * GrumpkinScalar.SIZE_IN_BYTES), + ); + if (derivePublicKeyFromSecretKey(foundSk).equals(pkM)) { + sk = foundSk; + break; + } + } - // We sanity check that it's possible to derive the public key from the secret key - if (!derivePublicKeyFromSecretKey(secretKey).equals(masterNullifierPublicKey)) { - throw new Error( - `Could not find master nullifier secret key for public key ${masterNullifierPublicKey.toString()}`, - ); + if (!sk) { + throw new Error(`Could not find ${keyPrefix}skM for ${keyPrefix}pkM ${pkM.toString()} in secret keys buffer.`); + } } - return Promise.resolve(secretKey); + // Now we determine the key type and return generator accordingly + const generator = getKeyGenerator(keyPrefix); + return Promise.resolve([sk, generator]); } /** @@ -356,11 +326,11 @@ export class TestKeyStore implements KeyStore { for (const [key, value] of this.#keys.entries()) { if (value.equals(masterIncomingViewingPublicKey.toBuffer())) { // We extract the account address from the map key - const accountAddress = key.split('-')[0]; + const account = key.split('-')[0]; // We fetch the secret key and return it - const masterIncomingViewingSecretKeyBuffer = this.#keys.get(`${accountAddress.toString()}-ivsk_m`); + const masterIncomingViewingSecretKeyBuffer = this.#keys.get(`${account.toString()}-ivsk_m`); if (!masterIncomingViewingSecretKeyBuffer) { - throw new Error(`Could not find master incoming viewing secret key for account ${accountAddress.toString()}`); + throw new Error(`Could not find master incoming viewing secret key for account ${account.toString()}`); } return Promise.resolve(GrumpkinScalar.fromBuffer(masterIncomingViewingSecretKeyBuffer)); } @@ -371,22 +341,6 @@ export class TestKeyStore implements KeyStore { ); } - /** - * Retrieves public keys hash of the account - * @throws If the provided account address is not associated with any of the registered accounts. - * @param account - The account address to get public keys hash for. - * @returns A Promise that resolves to the public keys hash. - */ - public async getPublicKeysHash(account: AztecAddress): Promise { - const publicKeysHashBuffer = this.#keys.get(`${account.toString()}-public_keys_hash`); - if (!publicKeysHashBuffer) { - throw new Error( - `Account ${account.toString()} does not exist. Registered accounts: ${await this.getAccounts()}.`, - ); - } - return Promise.resolve(Fr.fromBuffer(publicKeysHashBuffer)); - } - /** * Rotates the master nullifier key for the specified account. * @@ -400,28 +354,47 @@ export class TestKeyStore implements KeyStore { * @returns A Promise that resolves when the key rotation is complete. */ public async rotateMasterNullifierKey(account: AztecAddress, newSecretKey: Fq = Fq.random()) { - // We append the secret key to the original secret key - const secretKeysBuffer = this.#keys.get(`${account.toString()}-ns_keys_m`); - if (!secretKeysBuffer) { - throw new Error(`Could not find nullifier secret keys for account ${account.toString()}`); - } - - // We append the new secret key to the buffer of secret keys - const newSecretKeysBuffer = Buffer.concat([secretKeysBuffer, newSecretKey.toBuffer()]); - await this.#keys.set(`${account.toString()}-ns_keys_m`, newSecretKeysBuffer); + // We append the secret key to the array of secret keys + await this.#appendValue(`${account.toString()}-nsk_m`, newSecretKey); // Now we derive the public key from the new secret key and append it to the buffer of original public keys const newPublicKey = derivePublicKeyFromSecretKey(newSecretKey); - const publicKeysBuffer = this.#keys.get(`${account.toString()}-np_keys_m`); - if (!publicKeysBuffer) { - throw new Error(`Could not find nullifier public keys for account ${account.toString()}`); + await this.#appendValue(`${account.toString()}-npk_m`, newPublicKey); + + // At last we store npk_m_hash under `account-npk_m_hash` key to be able to obtain address and key prefix + // using the #getKeyPrefixAndAccount function later on + await this.#appendValue(`${account.toString()}-npk_m_hash`, newPublicKey.hash()); + } + + /** + * Gets the key prefix and account address for a given value. + * @returns A tuple containing the key prefix and account address. + * @dev Note that this is quite inefficient but it should not matter because there should never be too many keys + * in the key store. + */ + #getKeyPrefixAndAccount(value: Bufferable): [KeyPrefix, AztecAddress] { + const valueBuffer = serializeToBuffer(value); + for (const [key, val] of this.#keys.entries()) { + // `val` can contain multiple values due to key rotation so we check if the value is in the buffer instead + // of just calling `.equals(...)` + if (val.includes(valueBuffer)) { + for (const prefix of KEY_PREFIXES) { + if (key.includes(`-${prefix}`)) { + const account = AztecAddress.fromString(key.split('-')[0]); + return [prefix, account]; + } + } + } } + throw new Error(`Could not find key prefix.`); + } - // We append the new public key to the buffer of public keys - const newPublicKeysBuffer = Buffer.concat([publicKeysBuffer, newPublicKey.toBuffer()]); - await this.#keys.set(`${account.toString()}-np_keys_m`, newPublicKeysBuffer); + async #appendValue(key: string, value: Bufferable) { + const currentValue = this.#keys.get(key); + if (!currentValue) { + throw new Error(`Could not find current value for key ${key}`); + } - // We store a npk_m_hash-account_address map to make address easy to obtain with the hash later on - await this.#keys.set(`${newPublicKey.hash().toString()}-npk_m_hash`, account.toBuffer()); + await this.#keys.set(key, serializeToBuffer([currentValue, value])); } } diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index e7b3f99a30f..e9461fbcb8f 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -27,16 +27,18 @@ import { Header, KernelCircuitPublicInputs, type KernelData, + type KeyValidationHint, + KeyValidationRequest, L2ToL1Message, type LeafDataReadHint, LogHash, MAX_ENCRYPTED_LOGS_PER_TX, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, @@ -56,7 +58,6 @@ import { type NoteHashReadRequestHints, NoteLogHash, Nullifier, - NullifierKeyValidationRequest, type NullifierLeafPreimage, type NullifierNonExistentReadRequestHints, type NullifierReadRequestHints, @@ -109,10 +110,10 @@ import { type RootParityInputs, type RootRollupInputs, RootRollupPublicInputs, + ScopedKeyValidationRequest, ScopedL2ToL1Message, ScopedNoteHash, ScopedNullifier, - ScopedNullifierKeyValidationRequest, ScopedPrivateCallRequest, ScopedReadRequest, type SettledReadHint, @@ -150,6 +151,8 @@ import type { Header as HeaderNoir, KernelCircuitPublicInputs as KernelCircuitPublicInputsNoir, KernelData as KernelDataNoir, + KeyValidationHint as KeyValidationHintNoir, + KeyValidationRequest as KeyValidationRequestsNoir, L2ToL1Message as L2ToL1MessageNoir, LeafDataReadHint as LeafDataReadHintNoir, LogHash as LogHashNoir, @@ -165,8 +168,6 @@ import type { NoteHashReadRequestHints as NoteHashReadRequestHintsNoir, NoteHashSettledReadHint as NoteHashSettledReadHintNoir, NoteLogHash as NoteLogHashNoir, - NullifierKeyHint as NullifierKeyHintNoir, - NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, NullifierLeafPreimage as NullifierLeafPreimageNoir, Nullifier as NullifierNoir, NullifierNonExistentReadRequestHints as NullifierNonExistentReadRequestHintsNoir, @@ -216,9 +217,9 @@ import type { RootRollupInputs as RootRollupInputsNoir, RootRollupParityInput as RootRollupParityInputNoir, RootRollupPublicInputs as RootRollupPublicInputsNoir, + ScopedKeyValidationRequest as ScopedKeyValidationRequestsNoir, ScopedL2ToL1Message as ScopedL2ToL1MessageNoir, ScopedNoteHash as ScopedNoteHashNoir, - ScopedNullifierKeyValidationRequest as ScopedNullifierKeyValidationRequestNoir, ScopedNullifier as ScopedNullifierNoir, ScopedPrivateCallRequest as ScopedPrivateCallRequestNoir, ScopedReadRequest as ScopedReadRequestNoir, @@ -308,16 +309,14 @@ export function mapGrumpkinPrivateKeyToNoir(privateKey: GrumpkinPrivateKey): Gru } /** - * Maps a NullifierKeyHint to noir. - * @param hint - The nullifier key hint. - * @returns The nullifier key hint mapped to noir types. + * Maps a KeyValidationHint to noir. + * @param hint - The key validation hint. + * @returns The key validation hint mapped to noir types. */ -export function mapNullifierKeyHintToNoir(hint: { - privateKey: GrumpkinPrivateKey; - requestIndex: number; -}): NullifierKeyHintNoir { +export function mapKeyValidationHintToNoir(hint: KeyValidationHint): KeyValidationHintNoir { return { - private_key: mapGrumpkinPrivateKeyToNoir(hint.privateKey), + sk_m: mapGrumpkinPrivateKeyToNoir(hint.skM), + sk_app_generator_index: mapFieldToNoir(new Fr(hint.skAppGeneratorIndex)), request_index: mapNumberToNoir(hint.requestIndex), }; } @@ -747,47 +746,36 @@ export function mapScopedReadRequestFromNoir(scoped: ScopedReadRequestNoir): Sco } /** - * Maps a NullifierKeyValidationRequest to a noir NullifierKeyValidationRequest. - * @param request - The NullifierKeyValidationRequest. - * @returns The noir NullifierKeyValidationRequest. + * Maps a KeyValidationRequest to a noir KeyValidationRequest. + * @param request - The KeyValidationRequest. + * @returns The noir KeyValidationRequest. */ -export function mapNullifierKeyValidationRequestToNoir( - request: NullifierKeyValidationRequest, -): NullifierKeyValidationRequestNoir { +export function mapKeyValidationRequestsToNoir(request: KeyValidationRequest): KeyValidationRequestsNoir { return { - master_nullifier_public_key: mapPointToNoir(request.masterNullifierPublicKey), - app_nullifier_secret_key: mapFieldToNoir(request.appNullifierSecretKey), + pk_m: mapPointToNoir(request.masterPublicKey), + sk_app: mapFieldToNoir(request.appSecretKey), }; } /** - * Maps a noir NullifierKeyValidationRequest to NullifierKeyValidationRequest. - * @param request - The noir NullifierKeyValidationRequest. - * @returns The TS NullifierKeyValidationRequest. + * Maps a noir KeyValidationRequest to KeyValidationRequest. + * @param request - The noir KeyValidationRequest. + * @returns The TS KeyValidationRequest. */ -export function mapNullifierKeyValidationRequestFromNoir( - request: NullifierKeyValidationRequestNoir, -): NullifierKeyValidationRequest { - return new NullifierKeyValidationRequest( - mapPointFromNoir(request.master_nullifier_public_key), - mapFieldFromNoir(request.app_nullifier_secret_key), - ); +export function mapKeyValidationRequestsFromNoir(request: KeyValidationRequestsNoir): KeyValidationRequest { + return new KeyValidationRequest(mapPointFromNoir(request.pk_m), mapFieldFromNoir(request.sk_app)); } -function mapScopedNullifierKeyValidationRequestToNoir( - request: ScopedNullifierKeyValidationRequest, -): ScopedNullifierKeyValidationRequestNoir { +function mapScopedKeyValidationRequestsToNoir(request: ScopedKeyValidationRequest): ScopedKeyValidationRequestsNoir { return { - request: mapNullifierKeyValidationRequestToNoir(request.request), + request: mapKeyValidationRequestsToNoir(request.request), contract_address: mapAztecAddressToNoir(request.contractAddress), }; } -function mapScopedNullifierKeyValidationRequestFromNoir( - request: ScopedNullifierKeyValidationRequestNoir, -): ScopedNullifierKeyValidationRequest { - return new ScopedNullifierKeyValidationRequest( - mapNullifierKeyValidationRequestFromNoir(request.request), +function mapScopedKeyValidationRequestsFromNoir(request: ScopedKeyValidationRequestsNoir): ScopedKeyValidationRequest { + return new ScopedKeyValidationRequest( + mapKeyValidationRequestsFromNoir(request.request), mapAztecAddressFromNoir(request.contract_address), ); } @@ -842,10 +830,7 @@ export function mapPrivateCircuitPublicInputsToNoir( returns_hash: mapFieldToNoir(privateCircuitPublicInputs.returnsHash), note_hash_read_requests: mapTuple(privateCircuitPublicInputs.noteHashReadRequests, mapReadRequestToNoir), nullifier_read_requests: mapTuple(privateCircuitPublicInputs.nullifierReadRequests, mapReadRequestToNoir), - nullifier_key_validation_requests: mapTuple( - privateCircuitPublicInputs.nullifierKeyValidationRequests, - mapNullifierKeyValidationRequestToNoir, - ), + key_validation_requests: mapTuple(privateCircuitPublicInputs.keyValidationRequests, mapKeyValidationRequestsToNoir), new_note_hashes: mapTuple(privateCircuitPublicInputs.newNoteHashes, mapNoteHashToNoir), new_nullifiers: mapTuple(privateCircuitPublicInputs.newNullifiers, mapNullifierToNoir), private_call_requests: mapTuple(privateCircuitPublicInputs.privateCallRequests, mapPrivateCallRequestToNoir), @@ -1112,10 +1097,7 @@ function mapValidationRequestsToNoir(requests: ValidationRequests): ValidationRe requests.nullifierNonExistentReadRequests, mapScopedReadRequestToNoir, ), - nullifier_key_validation_requests: mapTuple( - requests.nullifierKeyValidationRequests, - mapScopedNullifierKeyValidationRequestToNoir, - ), + key_validation_requests: mapTuple(requests.keyValidationRequests, mapScopedKeyValidationRequestsToNoir), public_data_reads: mapTuple(requests.publicDataReads, mapPublicDataReadToNoir), }; } @@ -1139,9 +1121,9 @@ function mapValidationRequestsFromNoir(requests: ValidationRequestsNoir): Valida mapScopedReadRequestFromNoir, ), mapTupleFromNoir( - requests.nullifier_key_validation_requests, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - mapScopedNullifierKeyValidationRequestFromNoir, + requests.key_validation_requests, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, + mapScopedKeyValidationRequestsFromNoir, ), mapTupleFromNoir(requests.public_data_reads, MAX_PUBLIC_DATA_READS_PER_TX, mapPublicDataReadFromNoir), ); @@ -1558,10 +1540,16 @@ function mapPrivateKernelResetHintsToNoir< NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, - NLL_KEYS extends number, + KEY_VALIDATION_REQUESTS extends number, >( - inputs: PrivateKernelResetHints, -): PrivateKernelResetHintsNoir { + inputs: PrivateKernelResetHints< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + KEY_VALIDATION_REQUESTS + >, +): PrivateKernelResetHintsNoir { return { transient_nullifier_indexes_for_note_hashes: mapTuple( inputs.transientNullifierIndexesForNoteHashes, @@ -1571,9 +1559,9 @@ function mapPrivateKernelResetHintsToNoir< transient_note_hash_indexes_for_logs: mapTuple(inputs.transientNoteHashIndexesForLogs, mapNumberToNoir), note_hash_read_request_hints: mapNoteHashReadRequestHintsToNoir(inputs.noteHashReadRequestHints), nullifier_read_request_hints: mapNullifierReadRequestHintsToNoir(inputs.nullifierReadRequestHints), - master_nullifier_secret_keys: inputs.masterNullifierSecretKeys.map(mapNullifierKeyHintToNoir) as FixedLengthArray< - NullifierKeyHintNoir, - NLL_KEYS + key_validation_hints: inputs.keyValidationHints.map(mapKeyValidationHintToNoir) as FixedLengthArray< + KeyValidationHintNoir, + KEY_VALIDATION_REQUESTS >, }; } @@ -1583,7 +1571,7 @@ export function mapPrivateKernelResetCircuitPrivateInputsToNoir< NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, - NLL_KEYS extends number, + KEY_VALIDATION_REQUESTS extends number, TAG extends string, >( inputs: PrivateKernelResetCircuitPrivateInputs< @@ -1591,10 +1579,16 @@ export function mapPrivateKernelResetCircuitPrivateInputsToNoir< NH_RR_SETTLED, NLL_RR_PENDING, NLL_RR_SETTLED, - NLL_KEYS, + KEY_VALIDATION_REQUESTS, TAG >, -): PrivateKernelResetCircuitPrivateInputsNoir { +): PrivateKernelResetCircuitPrivateInputsNoir< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + KEY_VALIDATION_REQUESTS +> { return { previous_kernel: mapPrivateKernelDataToNoir(inputs.previousKernel), outputs: mapPrivateKernelResetOutputsToNoir(inputs.outputs), diff --git a/yarn-project/pxe/src/kernel_oracle/index.ts b/yarn-project/pxe/src/kernel_oracle/index.ts index 26728bd6be2..3a3d1010997 100644 --- a/yarn-project/pxe/src/kernel_oracle/index.ts +++ b/yarn-project/pxe/src/kernel_oracle/index.ts @@ -3,6 +3,8 @@ import { type AztecAddress, type Fr, type FunctionSelector, + type GrumpkinPrivateKey, + type KeyGenerator, MembershipWitness, type NOTE_HASH_TREE_HEIGHT, type Point, @@ -67,8 +69,8 @@ export class KernelOracle implements ProvingDataOracle { return header.state.partial.noteHashTree.root; } - public getMasterNullifierSecretKey(nullifierPublicKey: Point) { - return this.keyStore.getMasterNullifierSecretKeyForPublicKey(nullifierPublicKey); + public getMasterSecretKeyAndAppKeyGenerator(masterPublicKey: Point): Promise<[GrumpkinPrivateKey, KeyGenerator]> { + return this.keyStore.getMasterSecretKeyAndAppKeyGenerator(masterPublicKey); } public async getFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise { diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts index 6eef626d510..f77d2055bc6 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_reset_hints.ts @@ -1,21 +1,21 @@ import { - type Fr, + Fr, + KeyValidationHint, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MembershipWitness, NULLIFIER_TREE_HEIGHT, - NullifierKeyHint, PRIVATE_RESET_VARIANTS, type PrivateKernelData, PrivateKernelResetCircuitPrivateInputs, type PrivateKernelResetCircuitPrivateInputsVariants, PrivateKernelResetHints, + type ScopedKeyValidationRequest, type ScopedNullifier, - type ScopedNullifierKeyValidationRequest, type ScopedReadRequest, buildNoteHashReadRequestHints, buildNullifierReadRequestHints, @@ -60,30 +60,25 @@ function getNullifierReadRequestHints, +async function getMasterSecretKeysAndAppKeyGenerators( + keyValidationRequests: Tuple, oracle: ProvingDataOracle, ) { - const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyHint.empty); + const keysHints = makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_TX, KeyValidationHint.empty); let keyIndex = 0; - for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) { - const request = nullifierKeyValidationRequests[i].request; + for (let i = 0; i < keyValidationRequests.length; ++i) { + const request = keyValidationRequests[i].request; if (request.isEmpty()) { break; } - keys[keyIndex] = new NullifierKeyHint( - await oracle.getMasterNullifierSecretKey(request.masterNullifierPublicKey), - i, - ); + const [secretKeys, appKeyGenerator] = await oracle.getMasterSecretKeyAndAppKeyGenerator(request.masterPublicKey); + keysHints[keyIndex] = new KeyValidationHint(secretKeys, new Fr(appKeyGenerator), i); keyIndex++; } return { keysCount: keyIndex, - keys, + keysHints, }; } @@ -119,8 +114,8 @@ export async function buildPrivateKernelResetInputs( MAX_NULLIFIER_READ_REQUESTS_PER_TX, ); - const { keysCount: nullifierKeysCount, keys: masterNullifierSecretKeys } = await getMasterNullifierSecretKeys( - publicInputs.validationRequests.nullifierKeyValidationRequests, + const { keysCount, keysHints } = await getMasterSecretKeysAndAppKeyGenerators( + publicInputs.validationRequests.keyValidationRequests, oracle, ); @@ -151,7 +146,7 @@ export async function buildPrivateKernelResetInputs( hintSizes.NOTE_HASH_SETTLED_AMOUNT >= noteHashSettledReadHints && hintSizes.NULLIFIER_PENDING_AMOUNT >= nullifierPendingReadHints && hintSizes.NULLIFIER_SETTLED_AMOUNT >= nullifierSettledReadHints && - hintSizes.NULLIFIER_KEYS >= nullifierKeysCount + hintSizes.NULLIFIER_KEYS >= keysCount ) { privateInputs = new PrivateKernelResetCircuitPrivateInputs( previousKernelData, @@ -162,7 +157,7 @@ export async function buildPrivateKernelResetInputs( transientNoteHashIndexesForLogs, noteHashReadRequestHints, nullifierReadRequestHints, - masterNullifierSecretKeys, + keysHints, ).trimToSizes( hintSizes.NOTE_HASH_PENDING_AMOUNT, hintSizes.NOTE_HASH_SETTLED_AMOUNT, diff --git a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts index f1dc0b39dda..9a0df980702 100644 --- a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts +++ b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts @@ -4,6 +4,7 @@ import { type Fr, type FunctionSelector, type GrumpkinPrivateKey, + type KeyGenerator, type MembershipWitness, type NOTE_HASH_TREE_HEIGHT, type Point, @@ -70,12 +71,13 @@ export interface ProvingDataOracle { getNoteHashTreeRoot(): Promise; /** - * Get the master secret key of the nullifier public key. - * - * @param nullifierPublicKey - The nullifier public key. - * @returns the master nullifier secret key. + * Retrieves the sk_m for the pk_m and a generator index of the key type. + * @throws If the provided public key is not associated with any of the registered accounts. + * @param masterPublicKey - The master public key to get secret key for. + * @returns A Promise that resolves to sk_m and the corresponding app key generator. + * @dev Used when feeding the sk_m to the kernel circuit for keys verification. */ - getMasterNullifierSecretKey(nullifierPublicKey: Point): Promise; + getMasterSecretKeyAndAppKeyGenerator(masterPublicKey: Point): Promise<[GrumpkinPrivateKey, KeyGenerator]>; getFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise; } diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 0aafc050919..8e81ce7974a 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -14,12 +14,13 @@ import { type Fr, type FunctionSelector, type Header, + type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, } from '@aztec/circuits.js'; import { computeL1ToL2MessageNullifier } from '@aztec/circuits.js/hash'; import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; -import { type DBOracle, MessageLoadOracleInputs, type NullifierKeys } from '@aztec/simulator'; +import { type DBOracle, MessageLoadOracleInputs } from '@aztec/simulator'; import { type ContractInstance } from '@aztec/types/contracts'; import { type ContractDataOracle } from '../contract_data_oracle/index.js'; @@ -37,10 +38,8 @@ export class SimulatorOracle implements DBOracle { private log = createDebugLogger('aztec:pxe:simulator_oracle'), ) {} - async getNullifierKeys(npkMHash: Fr, contractAddress: AztecAddress): Promise { - const masterNullifierPublicKey = await this.keyStore.getMasterNullifierPublicKey(npkMHash); - const appNullifierSecretKey = await this.keyStore.getAppNullifierSecretKey(npkMHash, contractAddress); - return { masterNullifierPublicKey, appNullifierSecretKey }; + getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise { + return this.keyStore.getKeyValidationRequest(pkMHash, contractAddress); } async getCompleteAddress(account: AztecAddress): Promise { diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 26d8de73567..8ff5628a12a 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -40,16 +40,12 @@ export class Oracle { return unpacked.map(toACVMField); } - async getNullifierKeys([masterNullifierPublicKeyHash]: ACVMField[]): Promise { - const { masterNullifierPublicKey, appNullifierSecretKey } = await this.typedOracle.getNullifierKeys( - fromACVMField(masterNullifierPublicKeyHash), + async getKeyValidationRequest([masterPublicKeyHash]: ACVMField[]): Promise { + const { masterPublicKey, appSecretKey } = await this.typedOracle.getKeyValidationRequest( + fromACVMField(masterPublicKeyHash), ); - return [ - toACVMField(masterNullifierPublicKey.x), - toACVMField(masterNullifierPublicKey.y), - toACVMField(appNullifierSecretKey), - ]; + return [toACVMField(masterPublicKey.x), toACVMField(masterPublicKey.y), toACVMField(appSecretKey)]; } async getContractInstance([address]: ACVMField[]) { diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 9c39638adea..3ad314f41a4 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -11,6 +11,7 @@ import { } from '@aztec/circuit-types'; import { type Header, + type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, type PrivateCallStackItem, type PublicCallRequest, @@ -20,14 +21,6 @@ import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; -/** Nullifier keys which both correspond to the same master nullifier secret key. */ -export interface NullifierKeys { - /** Master nullifier public key. */ - masterNullifierPublicKey: PublicKey; - /** App nullifier secret key. */ - appNullifierSecretKey: Fr; -} - /** * Information about a note needed during execution. */ @@ -89,8 +82,8 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('unpackReturns'); } - getNullifierKeys(_npkMHash: Fr): Promise { - throw new OracleMethodNotAvailableError('getNullifierKeys'); + getKeyValidationRequest(_pkMHash: Fr): Promise { + throw new OracleMethodNotAvailableError('getKeyValidationRequest'); } getContractInstance(_address: AztecAddress): Promise { diff --git a/yarn-project/simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts index f36616c2303..35b18deab2a 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -5,13 +5,13 @@ import { type NullifierMembershipWitness, type PublicDataWitness, } from '@aztec/circuit-types'; -import { type CompleteAddress, type Header } from '@aztec/circuits.js'; +import { type CompleteAddress, type Header, type KeyValidationRequest } from '@aztec/circuits.js'; import { type FunctionArtifact, type FunctionSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { type Fr } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; -import { type NoteData, type NullifierKeys } from '../acvm/index.js'; +import { type NoteData } from '../acvm/index.js'; import { type CommitmentsDB } from '../public/db.js'; /** @@ -66,12 +66,12 @@ export interface DBOracle extends CommitmentsDB { popCapsule(): Promise; /** - * Retrieve nullifier keys associated with a specific master nullifier public key and app address. - * @param npkMHash - The master nullifier public key hash. + * Retrieve keys associated with a specific master public key and app address. + * @param pkMHash - The master public key hash. * @returns A Promise that resolves to nullifier keys. - * @throws If the nullifier keys are not registered in the key store. + * @throws If the keys are not registered in the key store. */ - getNullifierKeys(npkMHash: Fr, contractAddress: AztecAddress): Promise; + getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise; /** * Retrieves a set of notes stored in the database for a given contract address and storage slot. diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index a3136d2530f..6a22436e8ab 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -17,6 +17,7 @@ import { GeneratorIndex, type GrumpkinPrivateKey, Header, + KeyValidationRequest, L1_TO_L2_MSG_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, @@ -192,21 +193,27 @@ describe('Private Execution test suite', () => { beforeEach(async () => { trees = {}; oracle = mock(); - oracle.getNullifierKeys.mockImplementation((masterNullifierPublicKeyHash: Fr, contractAddress: AztecAddress) => { - if (masterNullifierPublicKeyHash.equals(ownerCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { - return Promise.resolve({ - masterNullifierPublicKey: ownerCompleteAddress.publicKeys.masterNullifierPublicKey, - appNullifierSecretKey: computeAppNullifierSecretKey(ownerMasterNullifierSecretKey, contractAddress), - }); - } - if (masterNullifierPublicKeyHash.equals(recipientCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { - return Promise.resolve({ - masterNullifierPublicKey: recipientCompleteAddress.publicKeys.masterNullifierPublicKey, - appNullifierSecretKey: computeAppNullifierSecretKey(recipientMasterNullifierSecretKey, contractAddress), - }); - } - throw new Error(`Unknown master nullifier public key hash: ${masterNullifierPublicKeyHash}`); - }); + oracle.getKeyValidationRequest.mockImplementation( + (masterNullifierPublicKeyHash: Fr, contractAddress: AztecAddress) => { + if (masterNullifierPublicKeyHash.equals(ownerCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { + return Promise.resolve( + new KeyValidationRequest( + ownerCompleteAddress.publicKeys.masterNullifierPublicKey, + computeAppNullifierSecretKey(ownerMasterNullifierSecretKey, contractAddress), + ), + ); + } + if (masterNullifierPublicKeyHash.equals(recipientCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { + return Promise.resolve( + new KeyValidationRequest( + recipientCompleteAddress.publicKeys.masterNullifierPublicKey, + computeAppNullifierSecretKey(recipientMasterNullifierSecretKey, contractAddress), + ), + ); + } + throw new Error(`Unknown master nullifier public key hash: ${masterNullifierPublicKeyHash}`); + }, + ); // We call insertLeaves here with no leaves to populate empty public data tree root --> this is necessary to be // able to get ivpk_m during execution diff --git a/yarn-project/simulator/src/client/simulator.test.ts b/yarn-project/simulator/src/client/simulator.test.ts index f4cdbd7c97b..63c468804b2 100644 --- a/yarn-project/simulator/src/client/simulator.test.ts +++ b/yarn-project/simulator/src/client/simulator.test.ts @@ -1,5 +1,5 @@ import { type AztecNode, CompleteAddress, Note } from '@aztec/circuit-types'; -import { GeneratorIndex, computeAppNullifierSecretKey, deriveKeys } from '@aztec/circuits.js'; +import { GeneratorIndex, KeyValidationRequest, computeAppNullifierSecretKey, deriveKeys } from '@aztec/circuits.js'; import { computeInnerNoteHash, computeNoteContentHash, @@ -42,10 +42,9 @@ describe('Simulator', () => { oracle = mock(); node = mock(); - oracle.getNullifierKeys.mockResolvedValue({ - masterNullifierPublicKey: ownerMasterNullifierPublicKey, - appNullifierSecretKey, - }); + oracle.getKeyValidationRequest.mockResolvedValue( + new KeyValidationRequest(ownerMasterNullifierPublicKey, appNullifierSecretKey), + ); oracle.getCompleteAddress.mockResolvedValue(ownerCompleteAddress); simulator = new AcirSimulator(oracle, node); diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 68479c6266b..47a75f4ad2c 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -7,14 +7,14 @@ import { type NullifierMembershipWitness, type PublicDataWitness, } from '@aztec/circuit-types'; -import { type Header } from '@aztec/circuits.js'; +import { type Header, type KeyValidationRequest } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log'; import { type ContractInstance } from '@aztec/types/contracts'; -import { type NoteData, type NullifierKeys, TypedOracle } from '../acvm/index.js'; +import { type NoteData, TypedOracle } from '../acvm/index.js'; import { type DBOracle } from './db_oracle.js'; import { pickNotes } from './pick_notes.js'; @@ -35,13 +35,13 @@ export class ViewDataOracle extends TypedOracle { } /** - * Retrieve nullifier keys associated with a specific master nullifier public key and app address. - * @param npkMHash - The master nullifier public key hash. + * Retrieve keys associated with a specific master public key and app address. + * @param pkMHash - The master public key hash. * @returns A Promise that resolves to nullifier keys. - * @throws If the nullifier keys are not registered in the key store. + * @throws If the keys are not registered in the key store. */ - public override getNullifierKeys(npkMHash: Fr): Promise { - return this.db.getNullifierKeys(npkMHash, this.contractAddress); + public override getKeyValidationRequest(pkMHash: Fr): Promise { + return this.db.getKeyValidationRequest(pkMHash, this.contractAddress); } /** From ebf6fc2313c82b97d9ccd8c36caee42fb7a1c901 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 21 May 2024 11:08:00 +0100 Subject: [PATCH 34/37] feat: run benchmarks for ACIR proving (#6155) Resolves #6060 --------- Co-authored-by: PhilWindle Co-authored-by: ludamad Co-authored-by: Santiago Palladino --- .github/workflows/ci.yml | 70 ++++++++++++++----- Earthfile | 2 +- barretenberg/acir_tests/bench_acir_tests.sh | 12 +++- .../cpp/src/barretenberg/common/benchmark.hpp | 2 +- noir/Earthfile | 37 ++++++++++ .../circuit-types/src/stats/metrics.ts | 7 ++ yarn-project/circuit-types/src/stats/stats.ts | 13 ++++ yarn-project/scripts/Earthfile | 3 +- .../scripts/src/benchmarks/aggregate.ts | 10 +++ .../scripts/src/benchmarks/markdown.ts | 6 ++ 10 files changed, 137 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 184848f54f4..6b4db3a4d53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,8 +153,39 @@ jobs: --no-output \ +${{ matrix.test }} + acir-bench: + runs-on: ubuntu-latest + needs: setup + steps: + - uses: actions/checkout@v4 + with: { ref: "${{ env.GIT_COMMIT }}" } + - uses: ./.github/ci-setup-action + - name: Setup and Test + uses: ./.github/ensure-tester-with-images + timeout-minutes: 40 + with: + runner_type: 16core-tester-x86 + builder_type: builder-x86 + # these are copied to the tester and expected by the earthly command below + # if they fail to copy, it will try to build them on the tester and fail + builder_images_to_copy: aztecprotocol/barretenberg-acir-benches:${{ env.GIT_COMMIT }} + # command to produce the images in case they don't exist + builder_command: cd noir && ../scripts/earthly-ci +export-bench-acir-bb + run: | + set -eux + cd ./noir/ + export FORCE_COLOR=1 + export EARTHLY_BUILD_ARGS="${{ env.EARTHLY_BUILD_ARGS }}" + ../scripts/earthly-ci -P \ + --secret AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }} \ + --secret AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }} \ + --no-output \ + +bench-publish-acir-bb + bench-summary: - needs: bench-e2e + needs: + - acir-bench + - bench-e2e runs-on: ${{ inputs.username || github.actor }}-x86 steps: - uses: actions/checkout@v4 @@ -181,24 +212,6 @@ jobs: working-directory: ./yarn-project/scripts run: earthly-ci -P --secret AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }} --secret AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }} --secret AZTEC_BOT_COMMENTER_GITHUB_TOKEN=${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} +bench-comment - noir-format: - needs: setup - runs-on: ${{ github.event.pull_request.user.login || github.actor }}-x86 - steps: - - uses: actions/checkout@v4 - with: { ref: "${{ env.GIT_COMMIT }}" } - - uses: ./.github/ci-setup-action - with: - concurrency_key: noir-format-x86 - - name: "Format Noir" - working-directory: ./noir/ - timeout-minutes: 40 - run: earthly-ci --no-output ./+format - - name: "Format noir-projects" - working-directory: ./noir-projects/ - timeout-minutes: 40 - run: earthly-ci --no-output ./+format - # barretenberg (prover) native and AVM (public VM) tests # only ran on x86 for resource reasons (memory intensive) bb-native-tests: @@ -232,6 +245,24 @@ jobs: timeout-minutes: 40 run: earthly-ci --no-output ./+test + noir-format: + needs: setup + runs-on: ${{ github.event.pull_request.user.login || github.actor }}-x86 + steps: + - uses: actions/checkout@v4 + with: { ref: "${{ env.GIT_COMMIT }}" } + - uses: ./.github/ci-setup-action + with: + concurrency_key: noir-format-x86 + - name: "Format Noir" + working-directory: ./noir/ + timeout-minutes: 40 + run: earthly-ci --no-output ./+format + - name: "Format noir-projects" + working-directory: ./noir-projects/ + timeout-minutes: 40 + run: earthly-ci --no-output ./+format + noir-test: needs: setup runs-on: ${{ github.event.pull_request.user.login || github.actor }}-x86 @@ -468,6 +499,7 @@ jobs: - setup - e2e - bb-native-tests + - acir-bench - bb-bench - yarn-project-formatting - yarn-project-test diff --git a/Earthfile b/Earthfile index 155a0df3082..2c3da388fc7 100644 --- a/Earthfile +++ b/Earthfile @@ -60,4 +60,4 @@ base-log-uploader: unzip awscliv2.zip && \ ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update && \ rm -rf aws awscliv2.zip - COPY +scripts/scripts /usr/src/scripts \ No newline at end of file + COPY +scripts/scripts /usr/src/scripts diff --git a/barretenberg/acir_tests/bench_acir_tests.sh b/barretenberg/acir_tests/bench_acir_tests.sh index a41b261d1cc..8cdc19a7c8f 100755 --- a/barretenberg/acir_tests/bench_acir_tests.sh +++ b/barretenberg/acir_tests/bench_acir_tests.sh @@ -1,8 +1,14 @@ #!/usr/bin/env bash +cd "$(dirname "$0")" + TEST_NAMES=("$@") THREADS=(1 4 16 32 64) -BENCHMARKS=$(mktemp) +BENCHMARKS=$LOG_FILE + +if [[ -z "${LOG_FILE}" ]]; then + BENCHMARKS=$(mktemp) +fi if [ "${#TEST_NAMES[@]}" -eq 0 ]; then TEST_NAMES=(sha256 ecdsa_secp256k1 ecdsa_secp256r1 schnorr double_verify_proof) @@ -64,4 +70,6 @@ function genthreadheaders(t, len, res) { } ' -rm $BENCHMARKS \ No newline at end of file +if [[ -z "${LOG_FILE}" ]]; then + rm $BENCHMARKS +fi diff --git a/barretenberg/cpp/src/barretenberg/common/benchmark.hpp b/barretenberg/cpp/src/barretenberg/common/benchmark.hpp index 98715635c92..ad966dc3833 100644 --- a/barretenberg/cpp/src/barretenberg/common/benchmark.hpp +++ b/barretenberg/cpp/src/barretenberg/common/benchmark.hpp @@ -94,7 +94,7 @@ template void write_benchmark(const std::string& } std::ostringstream oss; oss << "{\"timestamp\": \"" << getCurrentTimestamp() << "\", " - << "\"name\": \"" << name << "\", " + << "\"eventName\": \"" << name << "\", " << "\"type\": \"" << TypeTraits::type << "\", " << "\"value\": " << value << ", " << "\"threads\": " << env_hardware_concurrency(); diff --git a/noir/Earthfile b/noir/Earthfile index 9337b11452a..88d87214d66 100644 --- a/noir/Earthfile +++ b/noir/Earthfile @@ -216,6 +216,43 @@ build-acir-tests: RUN ./rebuild.sh true SAVE ARTIFACT /usr/src/noir-repo/test_programs/acir_artifacts/* +barretenberg-acir-benches-bb: + FROM ubuntu:noble + RUN apt update && \ + apt install -y curl git jq unzip + COPY ../barretenberg/cpp/+preset-clang-assert/bin/bb /usr/src/barretenberg/cpp/build/bin/bb + COPY ../barretenberg/+acir-tests/ /usr/src/barretenberg/acir_tests + COPY +build-acir-tests/ /usr/src/acir_artifacts + + ENV TEST_SRC=/usr/src/acir_artifacts + + WORKDIR /usr/src/barretenberg/acir_tests + +export-bench-acir-bb: + ARG EARTHLY_GIT_HASH + FROM +barretenberg-acir-benches-bb + SAVE IMAGE aztecprotocol/barretenberg-acir-benches:$EARTHLY_GIT_HASH + +bench-publish-acir-bb: + ARG PULL_REQUEST + ARG BRANCH + ARG COMMIT_HASH + LOCALLY + + # Let docker compose know about the pushed tags above + ENV AZTEC_DOCKER_TAG=$(git rev-parse HEAD) + # Optimize to not cause serial behavior if image already exists + IF ! docker image ls --format '{{.Repository}}:{{.Tag}}' | grep "aztecprotocol/barretenberg-acir-benches:$AZTEC_DOCKER_TAG" + WAIT + BUILD +export-bench-acir-bb + END + END + + RUN mkdir -p ./log + RUN docker run -v "$(pwd)/log":/log -e LOG_FILE=/log/bench-acir.jsonl --rm aztecprotocol/barretenberg-acir-benches:$AZTEC_DOCKER_TAG ./bench_acir_tests.sh sha256 + + DO ../+UPLOAD_LOGS --PULL_REQUEST=$PULL_REQUEST --BRANCH=$BRANCH --COMMIT_HASH=$COMMIT_HASH + barretenberg-acir-tests-bb: FROM ../build-images/+build diff --git a/yarn-project/circuit-types/src/stats/metrics.ts b/yarn-project/circuit-types/src/stats/metrics.ts index 41fbc543064..97e97abedfe 100644 --- a/yarn-project/circuit-types/src/stats/metrics.ts +++ b/yarn-project/circuit-types/src/stats/metrics.ts @@ -2,6 +2,7 @@ import { type StatsEventName } from './stats.js'; /** How a metric is grouped in benchmarks: by block size, by length of chain processed, or by circuit name. */ export type MetricGroupBy = + | 'threads' | 'block-size' | 'chain-length' | 'protocol-circuit-name' @@ -25,6 +26,12 @@ export interface Metric { /** Metric definitions to track from benchmarks. */ export const Metrics = [ + { + name: 'proof_construction_time_sha256', + groupBy: 'threads', + description: 'Time needed to generate a proof of an ACIR program.', + events: ['proof_construction_time'], + }, { name: 'l1_rollup_calldata_size_in_bytes', groupBy: 'block-size', diff --git a/yarn-project/circuit-types/src/stats/stats.ts b/yarn-project/circuit-types/src/stats/stats.ts index 09843ab2b03..8d956321455 100644 --- a/yarn-project/circuit-types/src/stats/stats.ts +++ b/yarn-project/circuit-types/src/stats/stats.ts @@ -1,3 +1,15 @@ +/** Stats associated with an ACIR proof generation.*/ +export type ProofConstructed = { + /** Name of the event for metrics purposes */ + eventName: 'proof_construction_time'; + /** Name of the program being proven */ + acir_test: string; + /** Number of threads used for proving */ + threads: number; + /** Time spent proving */ + value: number; +}; + /** Stats associated with an L2 block. */ export type L2BlockStats = { /** Number of txs in the L2 block. */ @@ -255,6 +267,7 @@ export type TxAddedToPoolStats = { /** Stats emitted in structured logs with an `eventName` for tracking. */ export type Stats = + | ProofConstructed | L1PublishStats | NodeSyncedChainHistoryStats | CircuitSimulationStats diff --git a/yarn-project/scripts/Earthfile b/yarn-project/scripts/Earthfile index 98f856d6fac..5f26109d9ad 100644 --- a/yarn-project/scripts/Earthfile +++ b/yarn-project/scripts/Earthfile @@ -65,5 +65,4 @@ bench-comment: RUN --secret AZTEC_BOT_COMMENTER_GITHUB_TOKEN \ [ -f $BENCH_FOLDER/benchmark.json ] \ && (cd /usr/src/yarn-project/scripts && AZTEC_BOT_COMMENTER_GITHUB_TOKEN=$AZTEC_BOT_COMMENTER_GITHUB_TOKEN yarn bench-comment) \ - || echo "No benchmark file found in $BENCH_FOLDER" - + || echo "No benchmark file found in $BENCH_FOLDER" \ No newline at end of file diff --git a/yarn-project/scripts/src/benchmarks/aggregate.ts b/yarn-project/scripts/src/benchmarks/aggregate.ts index 4d2a35f559f..caa95c22010 100644 --- a/yarn-project/scripts/src/benchmarks/aggregate.ts +++ b/yarn-project/scripts/src/benchmarks/aggregate.ts @@ -24,6 +24,7 @@ import { type MetricName, type NodeSyncedChainHistoryStats, type NoteProcessorCaughtUpStats, + type ProofConstructed, type Stats, type TreeInsertionStats, type TxAddedToPoolStats, @@ -66,6 +67,13 @@ function append( results[metric]![bucket].push(numeric); } +/** Processes an entry with event name 'acir-proof-generated' and updates results */ +function processAcirProofGenerated(entry: ProofConstructed, results: BenchmarkCollectedResults) { + if (entry.acir_test === 'sha256') { + append(results, `proof_construction_time_sha256`, entry.threads, entry.value); + } +} + /** Processes an entry with event name 'rollup-published-to-l1' and updates results */ function processRollupPublished(entry: L1PublishStats, results: BenchmarkCollectedResults) { const bucket = entry.txCount; @@ -240,6 +248,8 @@ function processTreeInsertion(entry: TreeInsertionStats, results: BenchmarkColle /** Processes a parsed entry from a log-file and updates results */ function processEntry(entry: Stats, results: BenchmarkCollectedResults, fileName: string) { switch (entry.eventName) { + case 'proof_construction_time': + return processAcirProofGenerated(entry, results); case 'rollup-published-to-l1': return processRollupPublished(entry, results); case 'l2-block-handled': diff --git a/yarn-project/scripts/src/benchmarks/markdown.ts b/yarn-project/scripts/src/benchmarks/markdown.ts index 5730067f7c5..537cdc5f487 100644 --- a/yarn-project/scripts/src/benchmarks/markdown.ts +++ b/yarn-project/scripts/src/benchmarks/markdown.ts @@ -183,6 +183,7 @@ export function getMarkdown(prNumber: number) { const benchmark = JSON.parse(fs.readFileSync(inputFile, 'utf-8')); const baseBenchmark = getBaseBenchmark(); + const metricsByThreads = Metrics.filter(m => m.groupBy === 'threads').map(m => m.name); const metricsByBlockSize = Metrics.filter(m => m.groupBy === 'block-size').map(m => m.name); const metricsByChainLength = Metrics.filter(m => m.groupBy === 'chain-length').map(m => m.name); const kernelCircuitMetrics = Metrics.filter(m => m.groupBy === 'protocol-circuit-name').map(m => m.name); @@ -218,6 +219,11 @@ All benchmarks are run on txs on the \`Benchmarking\` contract on the repository ${prSourceDataText} ${baseCommitText} +### Proof generation + +Each column represents the number of threads used in proof generation. +${getTableContent(pick(benchmark, metricsByThreads), baseBenchmark, 'threads')} + ### L2 block published to L1 Each column represents the number of txs on an L2 block published to L1. From f9c74c4195739ea10af77dfc307d2c32ee13dfd8 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Tue, 21 May 2024 13:08:10 +0200 Subject: [PATCH 35/37] refactor: purge secret and open keywords (#6501) Resolves #5538 --- .../communication/public_private_calls.md | 2 +- .../reference/smart_contract_reference/index.md | 8 ++++---- .../contracts/import_test_contract/src/main.nr | 8 ++++---- .../aztec.js/src/contract/contract.test.ts | 4 ++-- .../contract/contract_function_interaction.ts | 4 ++-- .../entrypoint/default_multi_call_entrypoint.ts | 2 +- .../aztec.js/src/wallet/account_wallet.ts | 4 ++-- .../src/fixtures/test_contract/Nargo.toml | 8 -------- .../src/fixtures/test_contract/src/main.nr | 11 ----------- yarn-project/builder/src/fixtures/test_lib.zip | Bin 1198 -> 0 bytes .../builder/src/fixtures/test_lib/Nargo.toml | 7 ------- .../builder/src/fixtures/test_lib/src/lib.nr | 1 - .../builder/src/fixtures/test_lib/src/module.nr | 1 - .../src/fixtures/test_lib/src/module/foo.nr | 3 --- .../circuits.js/src/contract/artifact_hash.ts | 2 +- .../src/contract/contract_address.test.ts | 2 +- .../src/contract/contract_class.test.ts | 4 ++-- .../circuits.js/src/contract/contract_class.ts | 4 ++-- .../private_function_membership_proof.test.ts | 2 +- .../private_function_membership_proof.ts | 4 ++-- .../circuits.js/src/structs/function_data.ts | 2 +- .../src/e2e_nested_contract/importer.test.ts | 12 ++++++------ .../entrypoints/src/account_entrypoint.ts | 2 +- yarn-project/entrypoints/src/dapp_entrypoint.ts | 2 +- yarn-project/foundation/src/abi/abi.test.ts | 4 ++-- yarn-project/foundation/src/abi/abi.ts | 6 +++--- yarn-project/foundation/src/abi/encoder.test.ts | 16 ++++++++-------- yarn-project/simulator/src/client/simulator.ts | 4 ++-- yarn-project/types/src/abi/contract_artifact.ts | 6 +++--- 29 files changed, 52 insertions(+), 83 deletions(-) delete mode 100644 yarn-project/builder/src/fixtures/test_contract/Nargo.toml delete mode 100644 yarn-project/builder/src/fixtures/test_contract/src/main.nr delete mode 100644 yarn-project/builder/src/fixtures/test_lib.zip delete mode 100644 yarn-project/builder/src/fixtures/test_lib/Nargo.toml delete mode 100644 yarn-project/builder/src/fixtures/test_lib/src/lib.nr delete mode 100644 yarn-project/builder/src/fixtures/test_lib/src/module.nr delete mode 100644 yarn-project/builder/src/fixtures/test_lib/src/module/foo.nr diff --git a/docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md b/docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md index 09f2449bec0..1dfd3c1a218 100644 --- a/docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md +++ b/docs/docs/aztec/concepts/smart_contracts/communication/public_private_calls.md @@ -60,7 +60,7 @@ To summarize: - _Public_ functions altering public state (updatable storage) must be executed at the current "head" of the chain, which only the sequencer can ensure, so these must be executed separately to the _private_ functions. - _Private_ and _public_ functions within an Aztec transaction are therefore ordered such that first _private_ functions are executed, and then _public_. -A more comprehensive overview of the interplay between private and public functions and their ability to manipulate data is presented below. It is worth noting that all data reads performed by private functions are historical in nature, and that private functions are not capable of modifying public storage. Conversely, public functions have the capacity to manipulate private storage (e.g., inserting new note hashes, potentially as part of transferring funds from the public domain to the secret domain). +A more comprehensive overview of the interplay between private and public functions and their ability to manipulate data is presented below. It is worth noting that all data reads performed by private functions are historical in nature, and that private functions are not capable of modifying public storage. Conversely, public functions have the capacity to manipulate private storage (e.g., inserting new note hashes, potentially as part of transferring funds from the public domain to the private domain). diff --git a/docs/docs/reference/smart_contract_reference/index.md b/docs/docs/reference/smart_contract_reference/index.md index 38cf6204067..8c47f55d714 100644 --- a/docs/docs/reference/smart_contract_reference/index.md +++ b/docs/docs/reference/smart_contract_reference/index.md @@ -15,7 +15,7 @@ The structure of a contract artifact is as follows: "functions": [ { "name": "constructor", - "functionType": "secret", + "functionType": "private", "isInternal": false, "parameters": [], "returnTypes": [], @@ -24,7 +24,7 @@ The structure of a contract artifact is as follows: }, { "name": "on_card_played", - "functionType": "open", + "functionType": "public", "isInternal": true, "parameters": [ { @@ -75,8 +75,8 @@ A simple string that matches the name that the contract developer used for this #### `function.functionType` The function type can have one of the following values: -- Secret: The function is ran and proved locally by the clients, and its bytecode not published to the network. -- Open: The function is ran and proved by the sequencer, and its bytecode is published to the network. +- Private: The function is ran and proved locally by the clients, and its bytecode not published to the network. +- Public: The function is ran and proved by the sequencer, and its bytecode is published to the network. - Unconstrained: The function is ran locally by the clients to generate digested information useful for the user. It's not meant to be transacted against. #### `function.isInternal` diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index bd11a2ac560..d8dd2776a3a 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -41,18 +41,18 @@ contract ImportTest { } // Calls the emit_nullifier_public on the Test contract at the target address - // Used for testing calling an open function + // Used for testing calling a public function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] - fn call_open_fn(target: AztecAddress) { + fn call_public_fn(target: AztecAddress) { Test::at(target).emit_nullifier_public(1).enqueue(&mut context); } // Calls the emit_nullifier_public on the Test contract at the target address - // Used for testing calling an open function from another open function + // Used for testing calling a public function from another public function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(public)] - fn pub_call_open_fn(target: AztecAddress) { + fn pub_call_public_fn(target: AztecAddress) { Test::at(target).emit_nullifier_public(1).call(&mut context); } } diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index c7e7db96a48..56855fd9f98 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -43,7 +43,7 @@ describe('Contract Class', () => { { name: 'bar', isInitializer: false, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, debugSymbols: '', @@ -70,7 +70,7 @@ describe('Contract Class', () => { name: 'baz', isInitializer: false, isStatic: false, - functionType: FunctionType.OPEN, + functionType: FunctionType.PUBLIC, isInternal: false, parameters: [], returnTypes: [], diff --git a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts index 6ebf682cdc1..dd8c84951fc 100644 --- a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts +++ b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts @@ -81,7 +81,7 @@ export class ContractFunctionInteraction extends BaseContractInteraction { const txRequest = await this.create(); // const from = - // this.functionDao.functionType == FunctionType.SECRET ? options.from ?? this.wallet.getAddress() : undefined; + // this.functionDao.functionType == FunctionType.PRIVATE ? options.from ?? this.wallet.getAddress() : undefined; const simulatedTx = await this.wallet.simulateTx(txRequest, true, options?.from); @@ -89,7 +89,7 @@ export class ContractFunctionInteraction extends BaseContractInteraction { // since we're interested in the first set of values AFTER the account entrypoint // For public functions we retrieve the first values directly from the public output. const rawReturnValues = - this.functionDao.functionType == FunctionType.SECRET + this.functionDao.functionType == FunctionType.PRIVATE ? simulatedTx.privateReturnValues?.nested?.[0].values : simulatedTx.publicOutput?.publicReturnValues?.values; diff --git a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts b/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts index bf36456c1bb..8d5e7e6cd3f 100644 --- a/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts +++ b/yarn-project/aztec.js/src/entrypoint/default_multi_call_entrypoint.ts @@ -37,7 +37,7 @@ export class DefaultMultiCallEntrypoint implements EntrypointInterface { return { name: 'entrypoint', isInitializer: false, - functionType: 'secret', + functionType: 'private', isInternal: false, isStatic: false, parameters: [ diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index e793504eb7d..21210c9167d 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -204,7 +204,7 @@ export class AccountWallet extends BaseWallet { return { name: 'approve_public_authwit', isInitializer: false, - functionType: FunctionType.OPEN, + functionType: FunctionType.PUBLIC, isInternal: true, isStatic: false, parameters: [ @@ -222,7 +222,7 @@ export class AccountWallet extends BaseWallet { return { name: 'cancel_authwit', isInitializer: false, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: true, isStatic: false, parameters: [ diff --git a/yarn-project/builder/src/fixtures/test_contract/Nargo.toml b/yarn-project/builder/src/fixtures/test_contract/Nargo.toml deleted file mode 100644 index 44ea20e01ba..00000000000 --- a/yarn-project/builder/src/fixtures/test_contract/Nargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "test" -authors = [""] -compiler_version = ">=0.18.0" -type = "contract" - -[dependencies] -test = { path = "../test_lib" } diff --git a/yarn-project/builder/src/fixtures/test_contract/src/main.nr b/yarn-project/builder/src/fixtures/test_contract/src/main.nr deleted file mode 100644 index 95824d09f4b..00000000000 --- a/yarn-project/builder/src/fixtures/test_contract/src/main.nr +++ /dev/null @@ -1,11 +0,0 @@ -contract TestContract { - use dep::test::module::foo; - - fn constructor(param: Field, pub_param: pub Field) -> pub [Field; 2] { - [foo::bar(param), param + pub_param] - } - - open fn openFunction() -> pub Field { - 42 - } -} diff --git a/yarn-project/builder/src/fixtures/test_lib.zip b/yarn-project/builder/src/fixtures/test_lib.zip deleted file mode 100644 index e5004ee2eceff5ec1ed39df5b9e4955e03770b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1198 zcmWIWW@Zs#U|`^2uyu0_XPcmG9tz~e1FNVo`d&UP*p#PG|@x z1GCvF`BY05gVfRrZU#n{uu=vFFd=(7nyW!U!0qAp$ksDVi^MK?xg2`4ylu}yu`Rz( zT|fM@WZSzf);zA#3(}7AZmo=*`Q~b0$gArnn-!-!iS=)~qY)bP=YHXg8Mh`|zv=kW z*0V#=%F$Fm0O&$4pnDj=E(9~61TV4+i;I%=;ckn%qmS-3RAX*m;(N>uGzNrGJPI-f z=wZFQBDi5#Jer%Iq5#CDIjPpD=AP`cBT-WjvRhxG8wpEK#2Jj5 zgpdt(1cn7X5I}B4N>Id^4GKmW5Me+Lhnd*T1|}+eCL^K_HAx}6`Z*4hVF?VE`K)Xp Rm$Ct&G!p|uEf6y>008bOBar|A diff --git a/yarn-project/builder/src/fixtures/test_lib/Nargo.toml b/yarn-project/builder/src/fixtures/test_lib/Nargo.toml deleted file mode 100644 index fe1288f4a6e..00000000000 --- a/yarn-project/builder/src/fixtures/test_lib/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "testlib" -authors = [""] -compiler_version = ">=0.18.0" -type = "lib" - -[dependencies] \ No newline at end of file diff --git a/yarn-project/builder/src/fixtures/test_lib/src/lib.nr b/yarn-project/builder/src/fixtures/test_lib/src/lib.nr deleted file mode 100644 index 144bcec0532..00000000000 --- a/yarn-project/builder/src/fixtures/test_lib/src/lib.nr +++ /dev/null @@ -1 +0,0 @@ -mod module; diff --git a/yarn-project/builder/src/fixtures/test_lib/src/module.nr b/yarn-project/builder/src/fixtures/test_lib/src/module.nr deleted file mode 100644 index f4ad3bff5c9..00000000000 --- a/yarn-project/builder/src/fixtures/test_lib/src/module.nr +++ /dev/null @@ -1 +0,0 @@ -mod foo; diff --git a/yarn-project/builder/src/fixtures/test_lib/src/module/foo.nr b/yarn-project/builder/src/fixtures/test_lib/src/module/foo.nr deleted file mode 100644 index 0376cd4cb87..00000000000 --- a/yarn-project/builder/src/fixtures/test_lib/src/module/foo.nr +++ /dev/null @@ -1,3 +0,0 @@ -pub fn bar(param: Field) -> Field { - dep::std::hash::pedersen_hash([param]) -} diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.ts b/yarn-project/circuits.js/src/contract/artifact_hash.ts index f4e594854dc..c56af781335 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.ts @@ -52,7 +52,7 @@ export function computeArtifactHash( } export function computeArtifactHashPreimage(artifact: ContractArtifact) { - const privateFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.SECRET); + const privateFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.PRIVATE); const unconstrainedFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.UNCONSTRAINED); const metadataHash = computeArtifactMetadataHash(artifact); return { privateFunctionRoot, unconstrainedFunctionRoot, metadataHash }; diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index 4bb4b19a1fb..9f424a3d665 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -33,7 +33,7 @@ describe('ContractAddress', () => { it('computeInitializationHash', () => { const mockInitFn: FunctionAbi = { - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInitializer: false, isInternal: false, isStatic: false, diff --git a/yarn-project/circuits.js/src/contract/contract_class.test.ts b/yarn-project/circuits.js/src/contract/contract_class.test.ts index 5e1fe283358..13540a34d3e 100644 --- a/yarn-project/circuits.js/src/contract/contract_class.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_class.test.ts @@ -20,10 +20,10 @@ describe('ContractClass', () => { // Check function selectors match const publicFunctionSelectors = artifact.functions - .filter(fn => fn.functionType === FunctionType.OPEN) + .filter(fn => fn.functionType === FunctionType.PUBLIC) .map(fn => FunctionSelector.fromNameAndParameters(fn)); const privateFunctionSelectors = artifact.functions - .filter(fn => fn.functionType === FunctionType.SECRET) + .filter(fn => fn.functionType === FunctionType.PRIVATE) .map(fn => FunctionSelector.fromNameAndParameters(fn)); expect(new Set(contractClass.publicFunctions.map(fn => fn.selector))).toEqual(new Set(publicFunctionSelectors)); diff --git a/yarn-project/circuits.js/src/contract/contract_class.ts b/yarn-project/circuits.js/src/contract/contract_class.ts index b4834dc8673..4efe593ed7e 100644 --- a/yarn-project/circuits.js/src/contract/contract_class.ts +++ b/yarn-project/circuits.js/src/contract/contract_class.ts @@ -18,7 +18,7 @@ export function getContractClassFromArtifact( ): ContractClassWithId & ContractClassIdPreimage { const artifactHash = 'artifactHash' in artifact ? artifact.artifactHash : computeArtifactHash(artifact); const publicFunctions: ContractClass['publicFunctions'] = artifact.functions - .filter(f => f.functionType === FunctionType.OPEN) + .filter(f => f.functionType === FunctionType.PUBLIC) .map(f => ({ selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), bytecode: f.bytecode, @@ -28,7 +28,7 @@ export function getContractClassFromArtifact( const packedBytecode = packBytecode(publicFunctions); const privateFunctions: ContractClass['privateFunctions'] = artifact.functions - .filter(f => f.functionType === FunctionType.SECRET) + .filter(f => f.functionType === FunctionType.PRIVATE) .map(getContractClassPrivateFunctionFromArtifact) .sort(cmpFunctionArtifacts); diff --git a/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts b/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts index 6909cd68c30..958af440bf9 100644 --- a/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts +++ b/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts @@ -20,7 +20,7 @@ describe('private_function_membership_proof', () => { beforeAll(() => { artifact = getBenchmarkContractArtifact(); contractClass = getContractClassFromArtifact(artifact); - privateFunction = artifact.functions.findLast(fn => fn.functionType === FunctionType.SECRET)!; + privateFunction = artifact.functions.findLast(fn => fn.functionType === FunctionType.PRIVATE)!; vkHash = computeVerificationKeyHash(privateFunction.verificationKey!); selector = FunctionSelector.fromNameAndParameters(privateFunction); }); diff --git a/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts b/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts index 2857b463c24..d2c628bea65 100644 --- a/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts +++ b/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts @@ -32,7 +32,7 @@ export function createPrivateFunctionMembershipProof( // Locate private function definition and artifact const privateFunctions = artifact.functions - .filter(fn => fn.functionType === FunctionType.SECRET) + .filter(fn => fn.functionType === FunctionType.PRIVATE) .map(getContractClassPrivateFunctionFromArtifact); const privateFunction = privateFunctions.find(fn => fn.selector.equals(selector)); const privateFunctionArtifact = artifact.functions.find(fn => selector.equals(fn)); @@ -54,7 +54,7 @@ export function createPrivateFunctionMembershipProof( // And the "artifact tree" captures function bytecode and metadata, and is used by the pxe to check that its executing the code it's supposed to be executing, but it never goes into circuits. const functionMetadataHash = computeFunctionMetadataHash(privateFunctionArtifact); const functionArtifactHash = computeFunctionArtifactHash({ ...privateFunctionArtifact, functionMetadataHash }); - const artifactTree = computeArtifactFunctionTree(artifact, FunctionType.SECRET)!; + const artifactTree = computeArtifactFunctionTree(artifact, FunctionType.PRIVATE)!; const artifactTreeLeafIndex = artifactTree.getIndex(functionArtifactHash.toBuffer()); const artifactTreeSiblingPath = artifactTree.getSiblingPath(artifactTreeLeafIndex).map(Fr.fromBuffer); diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index d33a8b2ea8d..38fb1faa53d 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -20,7 +20,7 @@ export class FunctionData { static fromAbi(abi: FunctionAbi | ContractFunctionDao): FunctionData { return new FunctionData( FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), - abi.functionType === FunctionType.SECRET, + abi.functionType === FunctionType.PRIVATE, abi.isStatic, ); } diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts index f74f92dcde8..e11ce439df9 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts @@ -33,13 +33,13 @@ describe('e2e_nested_contract manual', () => { await importerContract.methods.call_no_args(testContract.address).send().wait(); }); - it('calls an open function', async () => { - logger.info(`Calling openfn on importer contract`); - await importerContract.methods.call_open_fn(testContract.address).send().wait(); + it('calls a public function', async () => { + logger.info(`Calling public_fn on importer contract`); + await importerContract.methods.call_public_fn(testContract.address).send().wait(); }); - it('calls an open function from an open function', async () => { - logger.info(`Calling pub openfn on importer contract`); - await importerContract.methods.pub_call_open_fn(testContract.address).send().wait(); + it('calls a public function from a public function', async () => { + logger.info(`Calling pub_public_fn on importer contract`); + await importerContract.methods.pub_call_public_fn(testContract.address).send().wait(); }); }); diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index 87e9a8f1023..a7a9450f36f 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -46,7 +46,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { return { name: 'entrypoint', isInitializer: false, - functionType: 'secret', + functionType: 'private', isInternal: false, isStatic: false, parameters: [ diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 2aca62739c7..5f7572da58e 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -59,7 +59,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { return { name: 'entrypoint', isInitializer: false, - functionType: 'secret', + functionType: 'private', isInternal: false, isStatic: false, parameters: [ diff --git a/yarn-project/foundation/src/abi/abi.test.ts b/yarn-project/foundation/src/abi/abi.test.ts index b7b1334e432..69e04c80d6d 100644 --- a/yarn-project/foundation/src/abi/abi.test.ts +++ b/yarn-project/foundation/src/abi/abi.test.ts @@ -46,8 +46,8 @@ describe('abi', () => { it('prefers functions based on type', () => { const contract = { functions: [ - { name: 'foo', isInitializer: true, functionType: FunctionType.OPEN }, - { name: 'bar', isInitializer: true, functionType: FunctionType.SECRET }, + { name: 'foo', isInitializer: true, functionType: FunctionType.PUBLIC }, + { name: 'bar', isInitializer: true, functionType: FunctionType.PRIVATE }, ], } as ContractArtifact; expect(getDefaultInitializer(contract)?.name).toEqual('bar'); diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index da33e70473b..200e7b0088c 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -144,8 +144,8 @@ export interface StructType extends BasicType<'struct'> { * Aztec.nr function types. */ export enum FunctionType { - SECRET = 'secret', - OPEN = 'open', + PRIVATE = 'private', + PUBLIC = 'public', UNCONSTRAINED = 'unconstrained', } @@ -404,7 +404,7 @@ export function getDefaultInitializer(contractArtifact: ContractArtifact): Funct ? initializers.find(f => f.name === 'constructor') ?? initializers.find(f => f.name === 'initializer') ?? initializers.find(f => f.parameters?.length === 0) ?? - initializers.find(f => f.functionType === FunctionType.SECRET) ?? + initializers.find(f => f.functionType === FunctionType.PRIVATE) ?? initializers[0] : initializers[0]; } diff --git a/yarn-project/foundation/src/abi/encoder.test.ts b/yarn-project/foundation/src/abi/encoder.test.ts index a38b963e9d0..82c2d569ac7 100644 --- a/yarn-project/foundation/src/abi/encoder.test.ts +++ b/yarn-project/foundation/src/abi/encoder.test.ts @@ -8,7 +8,7 @@ describe('abi/encoder', () => { it('serializes fields as fields', () => { const abi: FunctionAbi = { name: 'constructor', - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isInitializer: true, isStatic: false, @@ -32,7 +32,7 @@ describe('abi/encoder', () => { const abi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ @@ -57,7 +57,7 @@ describe('abi/encoder', () => { const abi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ @@ -83,7 +83,7 @@ describe('abi/encoder', () => { const abi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ @@ -119,7 +119,7 @@ describe('abi/encoder', () => { const abi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ @@ -151,7 +151,7 @@ describe('abi/encoder', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ @@ -174,7 +174,7 @@ describe('abi/encoder', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ @@ -200,7 +200,7 @@ describe('abi/encoder', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', isInitializer: true, - functionType: FunctionType.SECRET, + functionType: FunctionType.PRIVATE, isInternal: false, isStatic: false, parameters: [ diff --git a/yarn-project/simulator/src/client/simulator.ts b/yarn-project/simulator/src/client/simulator.ts index 90ea5d3deee..55c4a0e1153 100644 --- a/yarn-project/simulator/src/client/simulator.ts +++ b/yarn-project/simulator/src/client/simulator.ts @@ -68,8 +68,8 @@ export class AcirSimulator { contractAddress: AztecAddress, msgSender = AztecAddress.ZERO, ): Promise { - if (entryPointArtifact.functionType !== FunctionType.SECRET) { - throw new Error(`Cannot run ${entryPointArtifact.functionType} function as secret`); + if (entryPointArtifact.functionType !== FunctionType.PRIVATE) { + throw new Error(`Cannot run ${entryPointArtifact.functionType} function as private`); } if (request.origin !== contractAddress) { diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 9758e85650d..8ca72aa68a7 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -184,17 +184,17 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No function getFunctionType(fn: NoirCompiledContractFunction): FunctionType { if (fn.custom_attributes.includes(AZTEC_PRIVATE_ATTRIBUTE)) { - return FunctionType.SECRET; + return FunctionType.PRIVATE; } else if ( fn.custom_attributes.includes(AZTEC_PUBLIC_ATTRIBUTE) || fn.custom_attributes.includes(AZTEC_PUBLIC_VM_ATTRIBUTE) ) { - return FunctionType.OPEN; + return FunctionType.PUBLIC; } else if (fn.is_unconstrained) { return FunctionType.UNCONSTRAINED; } else { // Default to a private function (see simple_macro_example_expanded for an example of this behavior) - return FunctionType.SECRET; + return FunctionType.PRIVATE; } } From 8bbbbb645e7f12b535b1dc683b5ab5aea0b73e5b Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Tue, 21 May 2024 07:26:32 -0400 Subject: [PATCH 36/37] feat: Sync from noir (#6555) Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE feat: add native rust implementations of pedersen functions (https://github.com/noir-lang/noir/pull/4871) chore: add benchmarks for pedersen and schnorr verification (https://github.com/noir-lang/noir/pull/5056) END_COMMIT_OVERRIDE --------- Co-authored-by: Tom French --- .noir-sync-commit | 2 +- noir/noir-repo/Cargo.lock | 1 + .../bn254_blackbox_solver/Cargo.toml | 1 + .../benches/criterion.rs | 53 ++++- .../src/generator/generators.rs | 184 ++++++++++++++++++ .../src/generator/hash_to_curve.rs | 135 +++++++++++++ .../src/generator/mod.rs | 8 + .../bn254_blackbox_solver/src/lib.rs | 24 ++- .../src/pedersen/commitment.rs | 76 ++++++++ .../src/pedersen/hash.rs | 68 +++++++ .../bn254_blackbox_solver/src/pedersen/mod.rs | 2 + .../src/wasm/barretenberg_structures.rs | 25 --- .../bn254_blackbox_solver/src/wasm/mod.rs | 20 -- .../src/wasm/pedersen.rs | 73 ------- noir/noir-repo/cspell.json | 1 + .../noir_stdlib/src/embedded_curve_ops.nr | 1 + 16 files changed, 544 insertions(+), 130 deletions(-) create mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/generators.rs create mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs create mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/mod.rs create mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/commitment.rs create mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/hash.rs create mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/mod.rs delete mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs delete mode 100644 noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs diff --git a/.noir-sync-commit b/.noir-sync-commit index bec736647ac..4195c98aff3 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -a5b7df12faf9d71ff24f8c5cde5e78da44558caf +fb039f74df23aea39bc0593a5d538d82b4efadf0 diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index 63a40ee1320..707ca33c9d3 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -586,6 +586,7 @@ dependencies = [ "acvm_blackbox_solver", "ark-ec", "ark-ff", + "ark-std", "cfg-if 1.0.0", "criterion", "getrandom 0.2.10", diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/Cargo.toml b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/Cargo.toml index 3a6c9b1d55b..b261be65735 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/Cargo.toml +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/Cargo.toml @@ -40,6 +40,7 @@ getrandom.workspace = true wasmer = "4.2.6" [dev-dependencies] +ark-std = { version = "^0.4.0", default-features = false } criterion = "0.5.0" pprof = { version = "0.12", features = [ "flamegraph", diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/benches/criterion.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/benches/criterion.rs index eb529ed2c11..a8fa7d8aae4 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/benches/criterion.rs +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/benches/criterion.rs @@ -2,7 +2,8 @@ use criterion::{criterion_group, criterion_main, Criterion}; use std::{hint::black_box, time::Duration}; use acir::FieldElement; -use bn254_blackbox_solver::poseidon2_permutation; +use acvm_blackbox_solver::BlackBoxFunctionSolver; +use bn254_blackbox_solver::{poseidon2_permutation, Bn254BlackBoxSolver}; use pprof::criterion::{Output, PProfProfiler}; @@ -12,10 +13,58 @@ fn bench_poseidon2(c: &mut Criterion) { c.bench_function("poseidon2", |b| b.iter(|| poseidon2_permutation(black_box(&inputs), 4))); } +fn bench_pedersen_commitment(c: &mut Criterion) { + let inputs = [FieldElement::one(); 2]; + let solver = Bn254BlackBoxSolver::new(); + + c.bench_function("pedersen_commitment", |b| { + b.iter(|| solver.pedersen_commitment(black_box(&inputs), 0)) + }); +} + +fn bench_pedersen_hash(c: &mut Criterion) { + let inputs = [FieldElement::one(); 2]; + let solver = Bn254BlackBoxSolver::new(); + + c.bench_function("pedersen_hash", |b| b.iter(|| solver.pedersen_hash(black_box(&inputs), 0))); +} + +fn bench_schnorr_verify(c: &mut Criterion) { + let solver = Bn254BlackBoxSolver::new(); + + let pub_key_x = FieldElement::from_hex( + "0x04b260954662e97f00cab9adb773a259097f7a274b83b113532bce27fa3fb96a", + ) + .unwrap(); + let pub_key_y = FieldElement::from_hex( + "0x2fd51571db6c08666b0edfbfbc57d432068bccd0110a39b166ab243da0037197", + ) + .unwrap(); + let sig_bytes: [u8; 64] = [ + 1, 13, 119, 112, 212, 39, 233, 41, 84, 235, 255, 93, 245, 172, 186, 83, 157, 253, 76, 77, + 33, 128, 178, 15, 214, 67, 105, 107, 177, 234, 77, 48, 27, 237, 155, 84, 39, 84, 247, 27, + 22, 8, 176, 230, 24, 115, 145, 220, 254, 122, 135, 179, 171, 4, 214, 202, 64, 199, 19, 84, + 239, 138, 124, 12, + ]; + + let message: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + c.bench_function("schnorr_verify", |b| { + b.iter(|| { + solver.schnorr_verify( + black_box(&pub_key_x), + black_box(&pub_key_y), + black_box(&sig_bytes), + black_box(message), + ) + }) + }); +} + criterion_group!( name = benches; config = Criterion::default().sample_size(40).measurement_time(Duration::from_secs(20)).with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = bench_poseidon2 + targets = bench_poseidon2, bench_pedersen_commitment, bench_pedersen_hash, bench_schnorr_verify ); criterion_main!(benches); diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/generators.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/generators.rs new file mode 100644 index 00000000000..f89d582d167 --- /dev/null +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/generators.rs @@ -0,0 +1,184 @@ +// Adapted from https://github.com/laudiacay/barustenberg/blob/df6bc6f095fe7f288bf6a12e7317fd8eb33d68ae/barustenberg/src/ecc/groups/affine_element.rshttps://github.com/laudiacay/barustenberg/blob/df6bc6f095fe7f288bf6a12e7317fd8eb33d68ae/barustenberg/src/ecc/groups/group.rs +//! +//! Code is used under the MIT license + +use std::sync::OnceLock; + +use ark_ec::short_weierstrass::Affine; + +use acvm_blackbox_solver::blake3; +use grumpkin::GrumpkinParameters; + +use super::hash_to_curve::hash_to_curve; + +pub(crate) const DEFAULT_DOMAIN_SEPARATOR: &[u8] = "DEFAULT_DOMAIN_SEPARATOR".as_bytes(); +const NUM_DEFAULT_GENERATORS: usize = 8; + +fn default_generators() -> &'static [Affine; NUM_DEFAULT_GENERATORS] { + static INSTANCE: OnceLock<[Affine; NUM_DEFAULT_GENERATORS]> = + OnceLock::new(); + INSTANCE.get_or_init(|| { + _derive_generators(DEFAULT_DOMAIN_SEPARATOR, NUM_DEFAULT_GENERATORS as u32, 0) + .try_into() + .expect("Should generate `NUM_DEFAULT_GENERATORS`") + }) +} + +/// Derives generator points via [hash-to-curve][hash_to_curve]. +/// +/// # ALGORITHM DESCRIPTION +/// +/// 1. Each generator has an associated "generator index" described by its location in the vector +/// 2. a 64-byte preimage buffer is generated with the following structure: +/// - bytes 0-31: BLAKE3 hash of domain_separator +/// - bytes 32-63: generator index in big-endian form +/// 3. The [hash-to-curve algorithm][hash_to_curve] is used to hash the above into a curve point. +/// +/// NOTE: The domain separator is included to ensure that it is possible to derive independent sets of +/// index-addressable generators. +/// +/// [hash_to_curve]: super::hash_to_curve::hash_to_curve +pub(crate) fn derive_generators( + domain_separator_bytes: &[u8], + num_generators: u32, + starting_index: u32, +) -> Vec> { + // We cache a small number of the default generators so we can reuse them without needing to repeatedly recalculate them. + if domain_separator_bytes == DEFAULT_DOMAIN_SEPARATOR + && starting_index + num_generators <= NUM_DEFAULT_GENERATORS as u32 + { + let start_index = starting_index as usize; + let end_index = (starting_index + num_generators) as usize; + default_generators()[start_index..end_index].to_vec() + } else { + _derive_generators(domain_separator_bytes, num_generators, starting_index) + } +} + +fn _derive_generators( + domain_separator_bytes: &[u8], + num_generators: u32, + starting_index: u32, +) -> Vec> { + let mut generator_preimage = [0u8; 64]; + let domain_hash = blake3(domain_separator_bytes).expect("hash should succeed"); + //1st 32 bytes are blake3 domain_hash + generator_preimage[..32].copy_from_slice(&domain_hash); + + // Convert generator index in big-endian form + let mut res = Vec::with_capacity(num_generators as usize); + for i in starting_index..(starting_index + num_generators) { + let generator_be_bytes: [u8; 4] = i.to_be_bytes(); + generator_preimage[32] = generator_be_bytes[0]; + generator_preimage[33] = generator_be_bytes[1]; + generator_preimage[34] = generator_be_bytes[2]; + generator_preimage[35] = generator_be_bytes[3]; + let generator = hash_to_curve(&generator_preimage, 0); + res.push(generator); + } + res +} + +#[cfg(test)] +mod test { + + use ark_ec::AffineRepr; + use ark_ff::{BigInteger, PrimeField}; + + use super::*; + + #[test] + fn test_derive_generators() { + let res = derive_generators("test domain".as_bytes(), 128, 0); + + let is_unique = |y: Affine, j: usize| -> bool { + for (i, res) in res.iter().enumerate() { + if i != j && *res == y { + return false; + } + } + true + }; + + for (i, res) in res.iter().enumerate() { + assert!(is_unique(*res, i)); + assert!(res.is_on_curve()); + } + } + + #[test] + fn derive_length_generator() { + let domain_separator = "pedersen_hash_length"; + let length_generator = derive_generators(domain_separator.as_bytes(), 1, 0)[0]; + + let expected_generator = ( + "2df8b940e5890e4e1377e05373fae69a1d754f6935e6a780b666947431f2cdcd", + "2ecd88d15967bc53b885912e0d16866154acb6aac2d3f85e27ca7eefb2c19083", + ); + assert_eq!( + hex::encode(length_generator.x().unwrap().into_bigint().to_bytes_be()), + expected_generator.0, + "Failed on x component" + ); + assert_eq!( + hex::encode(length_generator.y().unwrap().into_bigint().to_bytes_be()), + expected_generator.1, + "Failed on y component" + ); + } + + #[test] + fn derives_default_generators() { + const DEFAULT_GENERATORS: &[[&str; 2]] = &[ + [ + "083e7911d835097629f0067531fc15cafd79a89beecb39903f69572c636f4a5a", + "1a7f5efaad7f315c25a918f30cc8d7333fccab7ad7c90f14de81bcc528f9935d", + ], + [ + "054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402", + "209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126", + ], + [ + "1c44f2a5207c81c28a8321a5815ce8b1311024bbed131819bbdaf5a2ada84748", + "03aaee36e6422a1d0191632ac6599ae9eba5ac2c17a8c920aa3caf8b89c5f8a8", + ], + [ + "26d8b1160c6821a30c65f6cb47124afe01c29f4338f44d4a12c9fccf22fb6fb2", + "05c70c3b9c0d25a4c100e3a27bf3cc375f8af8cdd9498ec4089a823d7464caff", + ], + [ + "20ed9c6a1d27271c4498bfce0578d59db1adbeaa8734f7facc097b9b994fcf6e", + "29cd7d370938b358c62c4a00f73a0d10aba7e5aaa04704a0713f891ebeb92371", + ], + [ + "0224a8abc6c8b8d50373d64cd2a1ab1567bf372b3b1f7b861d7f01257052d383", + "2358629b90eafb299d6650a311e79914b0215eb0a790810b26da5a826726d711", + ], + [ + "0f106f6d46bc904a5290542490b2f238775ff3c445b2f8f704c466655f460a2a", + "29ab84d472f1d33f42fe09c47b8f7710f01920d6155250126731e486877bcf27", + ], + [ + "0298f2e42249f0519c8a8abd91567ebe016e480f219b8c19461d6a595cc33696", + "035bec4b8520a4ece27bd5aafabee3dfe1390d7439c419a8c55aceb207aac83b", + ], + ]; + + let generated_generators = + derive_generators(DEFAULT_DOMAIN_SEPARATOR, DEFAULT_GENERATORS.len() as u32, 0); + for (i, (generator, expected_generator)) in + generated_generators.iter().zip(DEFAULT_GENERATORS).enumerate() + { + assert_eq!( + hex::encode(generator.x().unwrap().into_bigint().to_bytes_be()), + expected_generator[0], + "Failed on x component of generator {i}" + ); + assert_eq!( + hex::encode(generator.y().unwrap().into_bigint().to_bytes_be()), + expected_generator[1], + "Failed on y component of generator {i}" + ); + } + } +} diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs new file mode 100644 index 00000000000..c0197883442 --- /dev/null +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/hash_to_curve.rs @@ -0,0 +1,135 @@ +// Adapted from https://github.com/laudiacay/barustenberg/blob/df6bc6f095fe7f288bf6a12e7317fd8eb33d68ae/barustenberg/src/ecc/groups/affine_element.rs +//! +//! Code is used under the MIT license + +use acvm_blackbox_solver::blake3; + +use ark_ec::{short_weierstrass::Affine, AffineRepr, CurveConfig}; +use ark_ff::Field; +use ark_ff::{BigInteger, PrimeField}; +use grumpkin::GrumpkinParameters; + +/// Hash a seed buffer into a point +/// +/// # ALGORITHM DESCRIPTION +/// +/// 1. Initialize unsigned integer `attempt_count = 0` +/// 2. Copy seed into a buffer whose size is 2 bytes greater than `seed` (initialized to `0`) +/// 3. Interpret `attempt_count` as a byte and write into buffer at `[buffer.size() - 2]` +/// 4. Compute Blake3 hash of buffer +/// 5. Set the end byte of the buffer to `1` +/// 6. Compute Blake3 hash of buffer +/// 7. Interpret the two hash outputs as the high / low 256 bits of a 512-bit integer (big-endian) +/// 8. Derive x-coordinate of point by reducing the 512-bit integer modulo the curve's field modulus (Fq) +/// 9. Compute `y^2` from the curve formula `y^2 = x^3 + ax + b` (`a`, `b` are curve params. for BN254, `a = 0`, `b = 3`) +/// 10. IF `y^2` IS NOT A QUADRATIC RESIDUE: +/// +/// a. increment `attempt_count` by 1 and go to step 2 +/// +/// 11. IF `y^2` IS A QUADRATIC RESIDUE: +/// +/// a. derive y coordinate via `y = sqrt(y)` +/// +/// b. Interpret most significant bit of 512-bit integer as a 'parity' bit +/// +/// c. If parity bit is set AND `y`'s most significant bit is not set, invert `y` +/// +/// d. If parity bit is not set AND `y`'s most significant bit is set, invert `y` +/// +/// e. return (x, y) +/// +/// N.B. steps c. and e. are because the `sqrt()` algorithm can return 2 values, +/// we need to a way to canonically distinguish between these 2 values and select a "preferred" one +pub(crate) fn hash_to_curve(seed: &[u8], attempt_count: u8) -> Affine { + let seed_size = seed.len(); + // expand by 2 bytes to cover incremental hash attempts + let mut target_seed = seed.to_vec(); + target_seed.extend_from_slice(&[0u8; 2]); + + target_seed[seed_size] = attempt_count; + target_seed[seed_size + 1] = 0; + let hash_hi = blake3(&target_seed).expect("hash should succeed"); + target_seed[seed_size + 1] = 1; + let hash_lo = blake3(&target_seed).expect("hash should succeed"); + + let mut hash = hash_hi.to_vec(); + hash.extend_from_slice(&hash_lo); + + // Here we reduce the 512 bit number modulo the base field modulus to calculate `x` + let x = <::BaseField as Field>::BasePrimeField::from_be_bytes_mod_order(&hash); + let x = ::BaseField::from_base_prime_field(x); + + if let Some(point) = Affine::::get_point_from_x_unchecked(x, false) { + let parity_bit = hash_hi[0] > 127; + let y_bit_set = point.y().unwrap().into_bigint().get_bit(0); + if (parity_bit && !y_bit_set) || (!parity_bit && y_bit_set) { + -point + } else { + point + } + } else { + hash_to_curve(seed, attempt_count + 1) + } +} + +#[cfg(test)] +mod test { + + use ark_ec::AffineRepr; + use ark_ff::{BigInteger, PrimeField}; + + use super::hash_to_curve; + + #[test] + fn smoke_test() { + let test_cases: [(&[u8], u8, (&str, &str)); 4] = [ + ( + &[], + 0, + ( + "24c4cb9c1206ab5470592f237f1698abe684dadf0ab4d7a132c32b2134e2c12e", + "0668b8d61a317fb34ccad55c930b3554f1828a0e5530479ecab4defe6bbc0b2e", + ), + ), + ( + &[], + 1, + ( + "24c4cb9c1206ab5470592f237f1698abe684dadf0ab4d7a132c32b2134e2c12e", + "0668b8d61a317fb34ccad55c930b3554f1828a0e5530479ecab4defe6bbc0b2e", + ), + ), + ( + &[1], + 0, + ( + "107f1b633c6113f3222f39f6256f0546b41a4880918c86864b06471afb410454", + "050cd3823d0c01590b6a50adcc85d2ee4098668fd28805578aa05a423ea938c6", + ), + ), + ( + &[0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64], + 0, + ( + "037c5c229ae495f6e8d1b4bf7723fafb2b198b51e27602feb8a4d1053d685093", + "10cf9596c5b2515692d930efa2cf3817607e4796856a79f6af40c949b066969f", + ), + ), + ]; + + for (seed, attempt_count, expected_point) in test_cases { + let point = hash_to_curve(seed, attempt_count); + assert!(point.is_on_curve()); + assert_eq!( + hex::encode(point.x().unwrap().into_bigint().to_bytes_be()), + expected_point.0, + "Failed on x component with seed {seed:?}, attempt_count {attempt_count}" + ); + assert_eq!( + hex::encode(point.y().unwrap().into_bigint().to_bytes_be()), + expected_point.1, + "Failed on y component with seed {seed:?}, attempt_count {attempt_count}" + ); + } + } +} diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/mod.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/mod.rs new file mode 100644 index 00000000000..0f62642516a --- /dev/null +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/generator/mod.rs @@ -0,0 +1,8 @@ +//! This module is adapted from the [Barustenberg][barustenberg] Rust implementation of the Barretenberg library. +//! +//! Code is used under the MIT license +//! +//! [barustenberg]: https://github.com/laudiacay/barustenberg/blob/df6bc6f095fe7f288bf6a12e7317fd8eb33d68ae/ + +pub(crate) mod generators; +mod hash_to_curve; diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs index a85ddcd894e..2fc609f4d38 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs @@ -6,14 +6,17 @@ use acir::{BlackBoxFunc, FieldElement}; use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; mod embedded_curve_ops; +mod generator; +mod pedersen; mod poseidon2; mod wasm; +use ark_ec::AffineRepr; pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; pub use poseidon2::poseidon2_permutation; use wasm::Barretenberg; -use self::wasm::{Pedersen, SchnorrSig}; +use self::wasm::SchnorrSig; pub struct Bn254BlackBoxSolver { blackbox_vendor: Barretenberg, @@ -72,10 +75,13 @@ impl BlackBoxFunctionSolver for Bn254BlackBoxSolver { inputs: &[FieldElement], domain_separator: u32, ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - #[allow(deprecated)] - self.blackbox_vendor.encrypt(inputs.to_vec(), domain_separator).map_err(|err| { - BlackBoxResolutionError::Failed(BlackBoxFunc::PedersenCommitment, err.to_string()) - }) + let inputs: Vec = inputs.iter().map(|input| input.into_repr()).collect(); + let result = pedersen::commitment::commit_native_with_index(&inputs, domain_separator); + let res_x = + FieldElement::from_repr(*result.x().expect("should not commit to point at infinity")); + let res_y = + FieldElement::from_repr(*result.y().expect("should not commit to point at infinity")); + Ok((res_x, res_y)) } fn pedersen_hash( @@ -83,10 +89,10 @@ impl BlackBoxFunctionSolver for Bn254BlackBoxSolver { inputs: &[FieldElement], domain_separator: u32, ) -> Result { - #[allow(deprecated)] - self.blackbox_vendor.hash(inputs.to_vec(), domain_separator).map_err(|err| { - BlackBoxResolutionError::Failed(BlackBoxFunc::PedersenCommitment, err.to_string()) - }) + let inputs: Vec = inputs.iter().map(|input| input.into_repr()).collect(); + let result = pedersen::hash::hash_with_index(&inputs, domain_separator); + let result = FieldElement::from_repr(result); + Ok(result) } fn multi_scalar_mul( diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/commitment.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/commitment.rs new file mode 100644 index 00000000000..6769150508a --- /dev/null +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/commitment.rs @@ -0,0 +1,76 @@ +// Taken from: https://github.com/laudiacay/barustenberg/blob/df6bc6f095fe7f288bf6a12e7317fd8eb33d68ae/barustenberg/src/crypto/pedersen/pederson.rs + +use ark_ec::{short_weierstrass::Affine, AffineRepr, CurveGroup}; +use ark_ff::{MontConfig, PrimeField}; +use grumpkin::{Fq, FqConfig, Fr, FrConfig, GrumpkinParameters}; + +use crate::generator::generators::{derive_generators, DEFAULT_DOMAIN_SEPARATOR}; + +/// Given a vector of fields, generate a pedersen commitment using the indexed generators. +pub(crate) fn commit_native_with_index( + inputs: &[Fq], + starting_index: u32, +) -> Affine { + let generators = + derive_generators(DEFAULT_DOMAIN_SEPARATOR, inputs.len() as u32, starting_index); + + // As |F_r| > |F_q|, we can safely convert any `F_q` into an `F_r` uniquely. + assert!(FrConfig::MODULUS > FqConfig::MODULUS); + + inputs.iter().enumerate().fold(Affine::zero(), |mut acc, (i, input)| { + acc = (acc + (generators[i] * Fr::from_bigint(input.into_bigint()).unwrap()).into_affine()) + .into_affine(); + acc + }) +} + +#[cfg(test)] +mod test { + + use acir::FieldElement; + use ark_ec::short_weierstrass::Affine; + use ark_std::{One, Zero}; + use grumpkin::Fq; + + use crate::pedersen::commitment::commit_native_with_index; + + #[test] + fn commitment() { + // https://github.com/AztecProtocol/aztec-packages/blob/72931bdb8202c34042cdfb8cee2ef44b75939879/barretenberg/cpp/src/barretenberg/crypto/pedersen_commitment/pedersen.test.cpp#L10-L18 + let res = commit_native_with_index(&[Fq::one(), Fq::one()], 0); + let expected = Affine::new( + FieldElement::from_hex( + "0x2f7a8f9a6c96926682205fb73ee43215bf13523c19d7afe36f12760266cdfe15", + ) + .unwrap() + .into_repr(), + FieldElement::from_hex( + "0x01916b316adbbf0e10e39b18c1d24b33ec84b46daddf72f43878bcc92b6057e6", + ) + .unwrap() + .into_repr(), + ); + + assert_eq!(res, expected); + } + + #[test] + fn commitment_with_zero() { + // https://github.com/AztecProtocol/aztec-packages/blob/72931bdb8202c34042cdfb8cee2ef44b75939879/barretenberg/cpp/src/barretenberg/crypto/pedersen_commitment/pedersen.test.cpp#L20-L29 + let res = commit_native_with_index(&[Fq::zero(), Fq::one()], 0); + let expected = Affine::new( + FieldElement::from_hex( + "0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402", + ) + .unwrap() + .into_repr(), + FieldElement::from_hex( + "0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126", + ) + .unwrap() + .into_repr(), + ); + + assert_eq!(res, expected); + } +} diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/hash.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/hash.rs new file mode 100644 index 00000000000..28bf354edc9 --- /dev/null +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/hash.rs @@ -0,0 +1,68 @@ +// Taken from: https://github.com/laudiacay/barustenberg/blob/df6bc6f095fe7f288bf6a12e7317fd8eb33d68ae/barustenberg/src/crypto/pedersen/pederson_hash.rs + +use std::sync::OnceLock; + +use ark_ec::{short_weierstrass::Affine, CurveConfig, CurveGroup}; +use grumpkin::GrumpkinParameters; + +use crate::generator::generators::derive_generators; + +use super::commitment::commit_native_with_index; + +/// Given a vector of fields, generate a pedersen hash using the indexed generators. +pub(crate) fn hash_with_index( + inputs: &[grumpkin::Fq], + starting_index: u32, +) -> ::BaseField { + let length_as_scalar: ::ScalarField = + (inputs.len() as u64).into(); + let length_prefix = *length_generator() * length_as_scalar; + let result = length_prefix + commit_native_with_index(inputs, starting_index); + result.into_affine().x +} + +fn length_generator() -> &'static Affine { + static INSTANCE: OnceLock> = OnceLock::new(); + INSTANCE.get_or_init(|| derive_generators("pedersen_hash_length".as_bytes(), 1, 0)[0]) +} + +#[cfg(test)] +pub(crate) mod test { + + use super::*; + + use acir::FieldElement; + use ark_std::One; + use grumpkin::Fq; + + //reference: https://github.com/AztecProtocol/barretenberg/blob/master/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp + #[test] + fn hash_one() { + // https://github.com/AztecProtocol/aztec-packages/blob/72931bdb8202c34042cdfb8cee2ef44b75939879/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp#L21-L26 + let res = hash_with_index(&[Fq::one(), Fq::one()], 0); + + assert_eq!( + res, + FieldElement::from_hex( + "0x07ebfbf4df29888c6cd6dca13d4bb9d1a923013ddbbcbdc3378ab8845463297b", + ) + .unwrap() + .into_repr(), + ); + } + + #[test] + fn test_hash_with_index() { + // https://github.com/AztecProtocol/aztec-packages/blob/72931bdb8202c34042cdfb8cee2ef44b75939879/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.test.cpp#L28-L33 + let res = hash_with_index(&[Fq::one(), Fq::one()], 5); + + assert_eq!( + res, + FieldElement::from_hex( + "0x1c446df60816b897cda124524e6b03f36df0cec333fad87617aab70d7861daa6", + ) + .unwrap() + .into_repr(), + ); + } +} diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/mod.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/mod.rs new file mode 100644 index 00000000000..c3c4ed56450 --- /dev/null +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/pedersen/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod commitment; +pub(crate) mod hash; diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs deleted file mode 100644 index 302ffa8af9b..00000000000 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs +++ /dev/null @@ -1,25 +0,0 @@ -use acir::FieldElement; - -#[derive(Debug, Default)] -pub(crate) struct Assignments(Vec); - -impl Assignments { - pub(crate) fn to_bytes(&self) -> Vec { - let mut buffer = Vec::new(); - - let witness_len = self.0.len() as u32; - buffer.extend_from_slice(&witness_len.to_be_bytes()); - - for assignment in self.0.iter() { - buffer.extend_from_slice(&assignment.to_be_bytes()); - } - - buffer - } -} - -impl From> for Assignments { - fn from(w: Vec) -> Assignments { - Assignments(w) - } -} diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs index f4f6f56aa99..e0a5c4c9069 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs @@ -4,13 +4,8 @@ //! //! As [`acvm`] includes rust implementations for these opcodes, this module can be removed. -mod barretenberg_structures; -mod pedersen; mod schnorr; -use barretenberg_structures::Assignments; - -pub(crate) use pedersen::Pedersen; pub(crate) use schnorr::SchnorrSig; /// The number of bytes necessary to store a `FieldElement`. @@ -208,10 +203,6 @@ impl Barretenberg { buf } - pub(crate) fn call(&self, name: &str, param: &WASMValue) -> Result { - self.call_multiple(name, vec![param]) - } - pub(crate) fn call_multiple( &self, name: &str, @@ -236,17 +227,6 @@ impl Barretenberg { Ok(WASMValue(option_value)) } - - /// Creates a pointer and allocates the bytes that the pointer references to, to the heap - pub(crate) fn allocate(&self, bytes: &[u8]) -> Result { - let ptr: i32 = self.call("bbmalloc", &bytes.len().into())?.try_into()?; - - let i32_bytes = ptr.to_be_bytes(); - let u32_bytes = u32::from_be_bytes(i32_bytes); - - self.transfer_to_heap(bytes, u32_bytes as usize); - Ok(ptr.into()) - } } fn init_memory_and_state() -> (Memory, Store, Imports) { diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs deleted file mode 100644 index c816e5b4d1b..00000000000 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs +++ /dev/null @@ -1,73 +0,0 @@ -use acir::FieldElement; - -use super::{Assignments, Barretenberg, Error, FIELD_BYTES}; - -pub(crate) trait Pedersen { - fn encrypt( - &self, - inputs: Vec, - hash_index: u32, - ) -> Result<(FieldElement, FieldElement), Error>; - - fn hash(&self, inputs: Vec, hash_index: u32) -> Result; -} - -impl Pedersen for Barretenberg { - fn encrypt( - &self, - inputs: Vec, - hash_index: u32, - ) -> Result<(FieldElement, FieldElement), Error> { - let input_buf = Assignments::from(inputs).to_bytes(); - let input_ptr = self.allocate(&input_buf)?; - let result_ptr: usize = 0; - - self.call_multiple( - "pedersen_plookup_commit_with_hash_index", - vec![&input_ptr, &result_ptr.into(), &hash_index.into()], - )?; - - let result_bytes: [u8; 2 * FIELD_BYTES] = self.read_memory(result_ptr); - let (point_x_bytes, point_y_bytes) = result_bytes.split_at(FIELD_BYTES); - - let point_x = FieldElement::from_be_bytes_reduce(point_x_bytes); - let point_y = FieldElement::from_be_bytes_reduce(point_y_bytes); - - Ok((point_x, point_y)) - } - - fn hash(&self, inputs: Vec, hash_index: u32) -> Result { - let input_buf = Assignments::from(inputs).to_bytes(); - let input_ptr = self.allocate(&input_buf)?; - let result_ptr: usize = 0; - - self.call_multiple( - "pedersen_plookup_compress_with_hash_index", - vec![&input_ptr, &result_ptr.into(), &hash_index.into()], - )?; - - let result_bytes: [u8; FIELD_BYTES] = self.read_memory(result_ptr); - - let hash = FieldElement::from_be_bytes_reduce(&result_bytes); - - Ok(hash) - } -} - -#[test] -fn pedersen_hash_to_point() -> Result<(), Error> { - let barretenberg = Barretenberg::new(); - let (x, y) = barretenberg.encrypt(vec![FieldElement::one(), FieldElement::one()], 1)?; - let expected_x = FieldElement::from_hex( - "0x12afb43195f5c621d1d2cabb5f629707095c5307fd4185a663d4e80bb083e878", - ) - .unwrap(); - let expected_y = FieldElement::from_hex( - "0x25793f5b5e62beb92fd18a66050293a9fd554a2ff13bceba0339cae1a038d7c1", - ) - .unwrap(); - - assert_eq!(expected_x.to_hex(), x.to_hex()); - assert_eq!(expected_y.to_hex(), y.to_hex()); - Ok(()) -} diff --git a/noir/noir-repo/cspell.json b/noir/noir-repo/cspell.json index 5fc9ad9d1b1..64f56d05b27 100644 --- a/noir/noir-repo/cspell.json +++ b/noir/noir-repo/cspell.json @@ -18,6 +18,7 @@ "Backpropagation", "barebones", "barretenberg", + "barustenberg", "bincode", "bindgen", "bitand", diff --git a/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr b/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr index 2aec90e0a55..cd8c421e136 100644 --- a/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr +++ b/noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr @@ -1,5 +1,6 @@ use crate::ops::arith::{Add, Sub, Neg}; use crate::cmp::Eq; + // TODO(https://github.com/noir-lang/noir/issues/4931) struct EmbeddedCurvePoint { x: Field, From 23e0518fc46eb7308f93e65df7080278c2d732cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Tue, 21 May 2024 13:56:14 +0200 Subject: [PATCH 37/37] refactor: nuking `KeyStore` and `KeyPair` interfaces (#6553) --- yarn-project/circuit-types/src/index.ts | 1 - yarn-project/circuit-types/src/keys/index.ts | 2 - .../circuit-types/src/keys/key_pair.ts | 20 --- .../circuit-types/src/keys/key_store.ts | 120 ------------------ yarn-project/key-store/src/index.ts | 2 +- ...st_key_store.test.ts => key_store.test.ts} | 8 +- .../src/{test_key_store.ts => key_store.ts} | 7 +- yarn-project/pxe/src/kernel_oracle/index.ts | 3 +- .../src/note_processor/note_processor.test.ts | 2 +- .../pxe/src/note_processor/note_processor.ts | 2 +- .../pxe/src/pxe_service/create_pxe_service.ts | 8 +- .../pxe/src/pxe_service/pxe_service.ts | 2 +- .../src/pxe_service/test/pxe_service.test.ts | 8 +- yarn-project/pxe/src/simulator/index.ts | 3 +- .../pxe/src/simulator_oracle/index.ts | 2 +- .../pxe/src/synchronizer/synchronizer.test.ts | 4 +- .../pxe/src/synchronizer/synchronizer.ts | 10 +- 17 files changed, 27 insertions(+), 177 deletions(-) delete mode 100644 yarn-project/circuit-types/src/keys/index.ts delete mode 100644 yarn-project/circuit-types/src/keys/key_pair.ts delete mode 100644 yarn-project/circuit-types/src/keys/key_store.ts rename yarn-project/key-store/src/{test_key_store.test.ts => key_store.test.ts} (97%) rename yarn-project/key-store/src/{test_key_store.ts => key_store.ts} (97%) diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index 67763d4d6d3..7a0b84d677c 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -1,5 +1,4 @@ export * from './function_call.js'; -export * from './keys/index.js'; export * from './notes/index.js'; export * from './messaging/index.js'; export * from './l2_block.js'; diff --git a/yarn-project/circuit-types/src/keys/index.ts b/yarn-project/circuit-types/src/keys/index.ts deleted file mode 100644 index f137b0d567a..00000000000 --- a/yarn-project/circuit-types/src/keys/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './key_pair.js'; -export * from './key_store.js'; diff --git a/yarn-project/circuit-types/src/keys/key_pair.ts b/yarn-project/circuit-types/src/keys/key_pair.ts deleted file mode 100644 index 2f4c0c1e3d3..00000000000 --- a/yarn-project/circuit-types/src/keys/key_pair.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; - -/** - * Represents a cryptographic public-private key pair. - * Provides functionality to generate, access, and sign messages using the key pair. - */ -export interface KeyPair { - /** - * Retrieve the public key from the KeyPair instance. - * The returned public key is a PublicKey object which represents a point on an elliptic curve. - * @returns The public key as an elliptic curve point. - */ - getPublicKey(): PublicKey; - /** - * Retrieves the private key of the KeyPair instance. - * The function returns a Promise that resolves to a Buffer containing the private key. - * @returns A Promise that resolves to a Buffer containing the private key. - */ - getPrivateKey(): GrumpkinPrivateKey; -} diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts deleted file mode 100644 index 62b5874c55b..00000000000 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { - type AztecAddress, - type CompleteAddress, - type Fq, - type Fr, - type GrumpkinPrivateKey, - type KeyGenerator, - type KeyValidationRequest, - type PartialAddress, - type PublicKey, -} from '@aztec/circuits.js'; - -/** - * Represents a secure storage for managing keys. - */ -export interface KeyStore { - /** - * Creates a new account from a randomly generated secret key. - * @returns A promise that resolves to the newly created account's CompleteAddress. - */ - createAccount(): Promise; - - /** - * Adds an account to the key store from the provided secret key. - * @param sk - The secret key of the account. - * @param partialAddress - The partial address of the account. - * @returns The account's complete address. - */ - addAccount(sk: Fr, partialAddress: PartialAddress): Promise; - - /** - * Retrieves addresses of accounts stored in the key store. - * @returns A Promise that resolves to an array of account addresses. - */ - getAccounts(): Promise; - - /** - * Gets the master incoming viewing public key for a given account. - * @throws If the account does not exist in the key store. - * @param account - The account address for which to retrieve the master incoming viewing public key. - * @returns The master incoming viewing public key for the account. - */ - getMasterIncomingViewingPublicKey(account: AztecAddress): Promise; - - /** - * Retrieves the master outgoing viewing key. - * @throws If the account does not exist in the key store. - * @param account - The account to retrieve the master outgoing viewing key for. - * @returns A Promise that resolves to the master outgoing viewing key. - */ - getMasterOutgoingViewingPublicKey(account: AztecAddress): Promise; - - /** - * Retrieves the master tagging key. - * @throws If the account does not exist in the key store. - * @param account - The account to retrieve the master tagging key for. - * @returns A Promise that resolves to the master tagging key. - */ - getMasterTaggingPublicKey(account: AztecAddress): Promise; - - /** - * Retrieves application incoming viewing secret key. - * @throws If the account does not exist in the key store. - * @param account - The account to retrieve the application incoming viewing secret key for. - * @param app - The application address to retrieve the incoming viewing secret key for. - * @returns A Promise that resolves to the application incoming viewing secret key. - */ - getAppIncomingViewingSecretKey(account: AztecAddress, app: AztecAddress): Promise; - - /** - * Retrieves application outgoing viewing secret key. - * @throws If the account does not exist in the key store. - * @param account - The account to retrieve the application outgoing viewing secret key for. - * @param app - The application address to retrieve the outgoing viewing secret key for. - * @returns A Promise that resolves to the application outgoing viewing secret key. - */ - getAppOutgoingViewingSecretKey(account: AztecAddress, app: AztecAddress): Promise; - - /** - * Retrieves the sk_m for the pk_m and a generator index of the key type. - * @throws If the provided public key is not associated with any of the registered accounts. - * @param masterPublicKey - The master public key to get secret key for. - * @returns A Promise that resolves to sk_m. - * @dev Used when feeding the sk_m to the kernel circuit for keys verification. - */ - getMasterSecretKeyAndAppKeyGenerator(masterPublicKey: PublicKey): Promise<[GrumpkinPrivateKey, KeyGenerator]>; - - /** - * Retrieves the master incoming viewing secret key (ivsk_m) corresponding to the specified master incoming viewing - * public key (Ivpk_m). - * @throws If the provided public key is not associated with any of the registered accounts. - * @param masterIncomingViewingPublicKey - The master nullifier public key to get secret key for. - * @returns A Promise that resolves to the master nullifier secret key. - * @dev Used when feeding the master nullifier secret key to the kernel circuit for nullifier keys verification. - */ - getMasterIncomingViewingSecretKeyForPublicKey(masterIncomingViewingPublicKey: PublicKey): Promise; - - /** - * Gets the key validation request for a given master public key hash and contract address. - * @throws If the account corresponding to the master public key hash does not exist in the key store. - * @param pkMHash - The master public key hash. - * @param contractAddress - The contract address to silo the secret key in the the key validation request with. - * @returns The key validation request. - */ - getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise; - - /** - * Rotates the master nullifier key for the specified account. - * - * @dev This function updates the secret and public keys associated with the account. - * It appends a new secret key to the existing secret keys, derives the - * corresponding public key, and updates the stored keys accordingly. - * - * @param account - The account address for which the master nullifier key is being rotated. - * @param newSecretKey - (Optional) A new secret key of type Fq. If not provided, a random key is generated. - * @throws If the account does not have existing nullifier secret keys or public keys. - * @returns A Promise that resolves when the key rotation is complete. - */ - rotateMasterNullifierKey(account: AztecAddress, secretKey: Fq): Promise; -} diff --git a/yarn-project/key-store/src/index.ts b/yarn-project/key-store/src/index.ts index e4ae5ce271c..7969b66bac4 100644 --- a/yarn-project/key-store/src/index.ts +++ b/yarn-project/key-store/src/index.ts @@ -1 +1 @@ -export * from './test_key_store.js'; +export * from './key_store.js'; diff --git a/yarn-project/key-store/src/test_key_store.test.ts b/yarn-project/key-store/src/key_store.test.ts similarity index 97% rename from yarn-project/key-store/src/test_key_store.test.ts rename to yarn-project/key-store/src/key_store.test.ts index 436b71771e5..319b6142f16 100644 --- a/yarn-project/key-store/src/test_key_store.test.ts +++ b/yarn-project/key-store/src/key_store.test.ts @@ -9,11 +9,11 @@ import { } from '@aztec/circuits.js'; import { openTmpStore } from '@aztec/kv-store/utils'; -import { TestKeyStore } from './test_key_store.js'; +import { KeyStore } from './key_store.js'; -describe('TestKeyStore', () => { +describe('KeyStore', () => { it('Adds account and returns keys', async () => { - const keyStore = new TestKeyStore(openTmpStore()); + const keyStore = new KeyStore(openTmpStore()); // Arbitrary fixed values const sk = new Fr(8923n); @@ -97,7 +97,7 @@ describe('TestKeyStore', () => { }); it('nullifier key rotation tests', async () => { - const keyStore = new TestKeyStore(openTmpStore()); + const keyStore = new KeyStore(openTmpStore()); // Arbitrary fixed values const sk = new Fr(8923n); diff --git a/yarn-project/key-store/src/test_key_store.ts b/yarn-project/key-store/src/key_store.ts similarity index 97% rename from yarn-project/key-store/src/test_key_store.ts rename to yarn-project/key-store/src/key_store.ts index 9877e8181cd..76aac6d9280 100644 --- a/yarn-project/key-store/src/test_key_store.ts +++ b/yarn-project/key-store/src/key_store.ts @@ -1,4 +1,4 @@ -import { type KeyStore, type PublicKey } from '@aztec/circuit-types'; +import { type PublicKey } from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, @@ -24,10 +24,9 @@ import { type Bufferable, serializeToBuffer } from '@aztec/foundation/serialize' import { type AztecKVStore, type AztecMap } from '@aztec/kv-store'; /** - * TestKeyStore is an implementation of the KeyStore interface, used for managing key pairs in a testing environment. - * It should be utilized in testing scenarios where secure key management is not required, and ease-of-use is prioritized. + * Used for managing keys. Can hold keys of multiple accounts and allows for key rotation. */ -export class TestKeyStore implements KeyStore { +export class KeyStore { #keys: AztecMap; constructor(database: AztecKVStore) { diff --git a/yarn-project/pxe/src/kernel_oracle/index.ts b/yarn-project/pxe/src/kernel_oracle/index.ts index 3a3d1010997..7fd428b2c65 100644 --- a/yarn-project/pxe/src/kernel_oracle/index.ts +++ b/yarn-project/pxe/src/kernel_oracle/index.ts @@ -1,4 +1,4 @@ -import { type AztecNode, type KeyStore } from '@aztec/circuit-types'; +import { type AztecNode } from '@aztec/circuit-types'; import { type AztecAddress, type Fr, @@ -13,6 +13,7 @@ import { } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { type Tuple } from '@aztec/foundation/serialize'; +import { type KeyStore } from '@aztec/key-store'; import { type ContractDataOracle } from '../contract_data_oracle/index.js'; import { type ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js'; diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index e9c656c09d3..e0cb2339294 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -4,7 +4,6 @@ import { EncryptedL2BlockL2Logs, EncryptedL2Log, EncryptedTxL2Logs, - type KeyStore, type L1NotePayload, L2Block, TaggedNote, @@ -20,6 +19,7 @@ import { } from '@aztec/circuits.js'; import { pedersenHash } from '@aztec/foundation/crypto'; import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; +import { type KeyStore } from '@aztec/key-store'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type AcirSimulator } from '@aztec/simulator'; diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index f8b4c13b571..8f8fffeada1 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -1,7 +1,6 @@ import { type AztecNode, type EncryptedL2BlockL2Logs, - type KeyStore, L1NotePayload, type L2Block, TaggedNote, @@ -11,6 +10,7 @@ import { INITIAL_L2_BLOCK_NUM, MAX_NEW_NOTE_HASHES_PER_TX, type PublicKey } from import { type Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; +import { type KeyStore } from '@aztec/key-store'; import { ContractNotFoundError } from '@aztec/simulator'; import { DeferredNoteDao } from '../database/deferred_note_dao.js'; diff --git a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts index 2a33dd3dd66..41aaea2589a 100644 --- a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts @@ -2,7 +2,7 @@ import { BBNativeProofCreator } from '@aztec/bb-prover'; import { type AztecNode, type ProofCreator } from '@aztec/circuit-types'; import { randomBytes } from '@aztec/foundation/crypto'; import { createDebugLogger } from '@aztec/foundation/log'; -import { TestKeyStore } from '@aztec/key-store'; +import { KeyStore } from '@aztec/key-store'; import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; import { initStoreForRollup } from '@aztec/kv-store/utils'; import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer'; @@ -20,7 +20,7 @@ import { PXEService } from './pxe_service.js'; /** * Create and start an PXEService instance with the given AztecNode. - * If no keyStore or database is provided, it will use TestKeyStore and MemoryDB as default values. + * If no keyStore or database is provided, it will use KeyStore and MemoryDB as default values. * Returns a Promise that resolves to the started PXEService instance. * * @param aztecNode - The AztecNode instance to be used by the server. @@ -42,9 +42,7 @@ export async function createPXEService( const keyStorePath = config.dataDirectory ? join(config.dataDirectory, 'pxe_key_store') : undefined; const l1Contracts = await aztecNode.getL1ContractAddresses(); - const keyStore = new TestKeyStore( - await initStoreForRollup(AztecLmdbStore.open(keyStorePath), l1Contracts.rollupAddress), - ); + const keyStore = new KeyStore(await initStoreForRollup(AztecLmdbStore.open(keyStorePath), l1Contracts.rollupAddress)); const db = new KVPxeDatabase(await initStoreForRollup(AztecLmdbStore.open(pxeDbPath), l1Contracts.rollupAddress)); // (@PhilWindle) Temporary validation until WASM is implemented diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index c94dd96973a..e7139f5c86a 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -5,7 +5,6 @@ import { ExtendedNote, type FunctionCall, type GetUnencryptedLogsResponse, - type KeyStore, type L2Block, type LogFilter, MerkleTreeId, @@ -42,6 +41,7 @@ import { Fq, Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; +import { type KeyStore } from '@aztec/key-store'; import { type AcirSimulator, type ExecutionResult, diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index ba00fbefa1f..3728d8683d3 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -2,7 +2,7 @@ import { type AztecNode, type PXE, TxEffect, mockTx } from '@aztec/circuit-types import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { type L1ContractAddresses } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { TestKeyStore } from '@aztec/key-store'; +import { KeyStore } from '@aztec/key-store'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type MockProxy, mock } from 'jest-mock-extended'; @@ -16,7 +16,7 @@ import { pxeTestSuite } from './pxe_test_suite.js'; function createPXEService(): Promise { const kvStore = openTmpStore(); - const keyStore = new TestKeyStore(kvStore); + const keyStore = new KeyStore(kvStore); const node = mock(); const db = new KVPxeDatabase(kvStore); const config: PXEServiceConfig = { l2BlockPollingIntervalMS: 100, l2StartingBlock: INITIAL_L2_BLOCK_NUM }; @@ -42,14 +42,14 @@ function createPXEService(): Promise { pxeTestSuite('PXEService', createPXEService); describe('PXEService', () => { - let keyStore: TestKeyStore; + let keyStore: KeyStore; let node: MockProxy; let db: PxeDatabase; let config: PXEServiceConfig; beforeEach(() => { const kvStore = openTmpStore(); - keyStore = new TestKeyStore(kvStore); + keyStore = new KeyStore(kvStore); node = mock(); db = new KVPxeDatabase(kvStore); config = { l2BlockPollingIntervalMS: 100, l2StartingBlock: INITIAL_L2_BLOCK_NUM, proverEnabled: false }; diff --git a/yarn-project/pxe/src/simulator/index.ts b/yarn-project/pxe/src/simulator/index.ts index e1a4c898578..0a4dc3abf73 100644 --- a/yarn-project/pxe/src/simulator/index.ts +++ b/yarn-project/pxe/src/simulator/index.ts @@ -1,4 +1,5 @@ -import { type AztecNode, type KeyStore } from '@aztec/circuit-types'; +import { type AztecNode } from '@aztec/circuit-types'; +import { type KeyStore } from '@aztec/key-store'; import { AcirSimulator } from '@aztec/simulator'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 8e81ce7974a..738af3673eb 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -1,6 +1,5 @@ import { type AztecNode, - type KeyStore, type L2Block, MerkleTreeId, type NoteStatus, @@ -20,6 +19,7 @@ import { import { computeL1ToL2MessageNullifier } from '@aztec/circuits.js/hash'; import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; +import { type KeyStore } from '@aztec/key-store'; import { type DBOracle, MessageLoadOracleInputs } from '@aztec/simulator'; import { type ContractInstance } from '@aztec/types/contracts'; diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index 01b1fedb289..36c0590a51e 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -3,7 +3,7 @@ import { Fr, type Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { makeHeader } from '@aztec/circuits.js/testing'; import { randomInt } from '@aztec/foundation/crypto'; import { SerialQueue } from '@aztec/foundation/fifo'; -import { TestKeyStore } from '@aztec/key-store'; +import { KeyStore } from '@aztec/key-store'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type MockProxy, mock } from 'jest-mock-extended'; @@ -126,7 +126,7 @@ describe('Synchronizer', () => { expect(await synchronizer.isGlobalStateSynchronized()).toBe(true); // Manually adding account to database so that we can call synchronizer.isAccountStateSynchronized - const keyStore = new TestKeyStore(openTmpStore()); + const keyStore = new KeyStore(openTmpStore()); const addAddress = async (startingBlockNum: number) => { const secretKey = Fr.random(); const partialAddress = Fr.random(); diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index f85a7cf3a7d..8c5bd7588d9 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -1,16 +1,10 @@ -import { - type AztecNode, - type KeyStore, - type L2Block, - L2BlockL2Logs, - MerkleTreeId, - type TxHash, -} from '@aztec/circuit-types'; +import { type AztecNode, type L2Block, L2BlockL2Logs, MerkleTreeId, type TxHash } from '@aztec/circuit-types'; import { type NoteProcessorCaughtUpStats } from '@aztec/circuit-types/stats'; import { type AztecAddress, type Fr, INITIAL_L2_BLOCK_NUM, type PublicKey } from '@aztec/circuits.js'; import { type SerialQueue } from '@aztec/foundation/fifo'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; +import { type KeyStore } from '@aztec/key-store'; import { type DeferredNoteDao } from '../database/deferred_note_dao.js'; import { type PxeDatabase } from '../database/index.js';