@aztec-labs/stdlib 6.0.0-nightly.20260922 → 6.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/block/proposal/committee_attestation.d.ts +1 -1
- package/dest/block/proposal/committee_attestation.d.ts.map +1 -1
- package/dest/block/proposal/committee_attestation.js +5 -9
- package/dest/block/test/l2_tips_store_test_suite.d.ts +1 -1
- package/dest/block/test/l2_tips_store_test_suite.d.ts.map +1 -1
- package/dest/block/test/l2_tips_store_test_suite.js +2 -2
- package/dest/block/validate_block_result.d.ts +2 -2
- package/dest/block/validate_block_result.d.ts.map +1 -1
- package/dest/block/validate_block_result.js +1 -4
- package/dest/checkpoint/checkpoint_data.d.ts +9 -1
- package/dest/checkpoint/checkpoint_data.d.ts.map +1 -1
- package/dest/checkpoint/checkpoint_data.js +3 -0
- package/dest/checkpoint/published_checkpoint.d.ts +22 -3
- package/dest/checkpoint/published_checkpoint.d.ts.map +1 -1
- package/dest/checkpoint/published_checkpoint.js +23 -5
- package/dest/hash/hash.d.ts +2 -2
- package/dest/hash/hash.d.ts.map +1 -1
- package/dest/hash/hash.js +2 -2
- package/dest/interfaces/proving-job.d.ts +70 -70
- package/dest/kernel/private_circuit_public_inputs.d.ts +11 -7
- package/dest/kernel/private_circuit_public_inputs.d.ts.map +1 -1
- package/dest/kernel/private_circuit_public_inputs.js +10 -8
- package/dest/kernel/private_context_inputs.d.ts +3 -3
- package/dest/kernel/private_context_inputs.d.ts.map +1 -1
- package/dest/kernel/private_context_inputs.js +4 -4
- package/dest/tests/factories.js +1 -1
- package/dest/tx/private_tx_constant_data.d.ts +9 -9
- package/dest/tx/private_tx_constant_data.d.ts.map +1 -1
- package/dest/tx/private_tx_constant_data.js +8 -8
- package/dest/tx/tx_request.d.ts +24 -4
- package/dest/tx/tx_request.d.ts.map +1 -1
- package/dest/tx/tx_request.js +25 -4
- package/package.json +8 -8
- package/src/block/proposal/committee_attestation.ts +5 -5
- package/src/block/test/l2_tips_store_test_suite.ts +7 -1
- package/src/block/validate_block_result.ts +4 -7
- package/src/checkpoint/checkpoint_data.ts +11 -0
- package/src/checkpoint/published_checkpoint.ts +26 -1
- package/src/hash/hash.ts +2 -2
- package/src/kernel/private_circuit_public_inputs.ts +8 -6
- package/src/kernel/private_context_inputs.ts +2 -2
- package/src/tests/factories.ts +1 -1
- package/src/tx/private_tx_constant_data.ts +6 -6
- package/src/tx/tx_request.ts +27 -5
package/dest/tx/tx_request.d.ts
CHANGED
|
@@ -16,7 +16,12 @@ export declare class TxRequest {
|
|
|
16
16
|
txContext: TxContext;
|
|
17
17
|
/** Function data representing the function to call. */
|
|
18
18
|
functionData: FunctionData;
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* A fresh random field drawn by the wallet, acting as the tx request's nonce. With `origin`, `chainId` and `version`
|
|
21
|
+
* it is the whole preimage of the protocol nullifier, so it keeps that nullifier unpredictable and unique. The kernel
|
|
22
|
+
* cannot check that it is random; draw it fresh for every transaction, since two requests with the same origin and
|
|
23
|
+
* salt are mutually exclusive.
|
|
24
|
+
*/
|
|
20
25
|
salt: Fr;
|
|
21
26
|
constructor(
|
|
22
27
|
/** Sender. */
|
|
@@ -27,7 +32,12 @@ export declare class TxRequest {
|
|
|
27
32
|
txContext: TxContext,
|
|
28
33
|
/** Function data representing the function to call. */
|
|
29
34
|
functionData: FunctionData,
|
|
30
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* A fresh random field drawn by the wallet, acting as the tx request's nonce. With `origin`, `chainId` and `version`
|
|
37
|
+
* it is the whole preimage of the protocol nullifier, so it keeps that nullifier unpredictable and unique. The kernel
|
|
38
|
+
* cannot check that it is random; draw it fresh for every transaction, since two requests with the same origin and
|
|
39
|
+
* salt are mutually exclusive.
|
|
40
|
+
*/
|
|
31
41
|
salt: Fr);
|
|
32
42
|
static getFields(fields: FieldsOf<TxRequest>): readonly [AztecAddress, Fr, TxContext, FunctionData, Fr];
|
|
33
43
|
static from(fields: FieldsOf<TxRequest>): TxRequest;
|
|
@@ -36,6 +46,17 @@ export declare class TxRequest {
|
|
|
36
46
|
* @returns The buffer.
|
|
37
47
|
*/
|
|
38
48
|
toBuffer(): Buffer<ArrayBufferLike>;
|
|
49
|
+
/**
|
|
50
|
+
* The unsiloed value of the protocol nullifier: the transaction's nonce commitment.
|
|
51
|
+
* The preimage is only `origin`, `chainId`, `version` and `salt`. Gas settings and the first call's arguments are
|
|
52
|
+
* left out so that a fee bump or a cancellation that reuses the salt produces the same nullifier.
|
|
53
|
+
*/
|
|
54
|
+
computeProtocolNullifierValue(): Promise<Fr>;
|
|
55
|
+
/**
|
|
56
|
+
* The protocol nullifier as inserted into the nullifier tree, and as every private call receives it in
|
|
57
|
+
* `PrivateCircuitPublicInputs.protocolNullifier`: the value above siloed under `NULL_MSG_SENDER`.
|
|
58
|
+
*/
|
|
59
|
+
computeProtocolNullifier(): Promise<Fr>;
|
|
39
60
|
toFields(): Fr[];
|
|
40
61
|
/**
|
|
41
62
|
* Deserializes from a buffer or reader, corresponding to a write in cpp.
|
|
@@ -43,8 +64,7 @@ export declare class TxRequest {
|
|
|
43
64
|
* @returns The deserialized TxRequest object.
|
|
44
65
|
*/
|
|
45
66
|
static fromBuffer(buffer: Buffer | BufferReader): TxRequest;
|
|
46
|
-
hash(): Promise<Fr>;
|
|
47
67
|
static empty(): TxRequest;
|
|
48
68
|
isEmpty(): boolean;
|
|
49
69
|
}
|
|
50
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhfcmVxdWVzdC5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3R4L3R4X3JlcXVlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ3pELE9BQU8sRUFBRSxZQUFZLEVBQXdDLE1BQU0sa0NBQWtDLENBQUM7QUFDdEcsT0FBTyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFN0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRXpELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFNUM7O0dBRUc7QUFDSCxxQkFBYSxTQUFTO0lBR2xCLGNBQWM7SUFDUCxNQUFNLEVBQUUsWUFBWTtJQUMzQiwyQ0FBMkM7SUFDcEMsUUFBUSxFQUFFLEVBQUU7SUFDbkIsMkJBQTJCO0lBQ3BCLFNBQVMsRUFBRSxTQUFTO0lBQzNCLHVEQUF1RDtJQUNoRCxZQUFZLEVBQUUsWUFBWTtJQUNqQzs7Ozs7T0FLRztJQUNJLElBQUksRUFBRSxFQUFFO0lBZmpCO0lBQ0UsY0FBYztJQUNQLE1BQU0sRUFBRSxZQUFZO0lBQzNCLDJDQUEyQztJQUNwQyxRQUFRLEVBQUUsRUFBRTtJQUNuQiwyQkFBMkI7SUFDcEIsU0FBUyxFQUFFLFNBQVM7SUFDM0IsdURBQXVEO0lBQ2hELFlBQVksRUFBRSxZQUFZO0lBQ2pDOzs7OztPQUtHO0lBQ0ksSUFBSSxFQUFFLEVBQUUsRUFDYjtJQUdKLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxTQUFTLENBQUMsNERBRTNDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLFNBQVMsQ0FBQyxHQUFHLFNBQVMsQ0FFbEQ7SUFFRDs7O09BR0c7SUFDSCxRQUFRLDRCQUVQO0lBRUQ7Ozs7T0FJRztJQUNILDZCQUE2QixJQUFJLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FLM0M7SUFFRDs7O09BR0c7SUFDRyx3QkFBd0IsSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDLENBRTVDO0lBRUQsUUFBUSxJQUFJLEVBQUUsRUFBRSxDQU1mO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sR0FBRyxZQUFZLEdBQUcsU0FBUyxDQVMxRDtJQUVELE1BQU0sQ0FBQyxLQUFLLGNBRVg7SUFFRCxPQUFPLFlBUU47Q0FDRiJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tx_request.d.ts","sourceRoot":"","sources":["../../src/tx/tx_request.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,qCAAqC,CAAC;AACzD,OAAO,EAAE,YAAY,EAAwC,MAAM,kCAAkC,CAAC;AACtG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"tx_request.d.ts","sourceRoot":"","sources":["../../src/tx/tx_request.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,qCAAqC,CAAC;AACzD,OAAO,EAAE,YAAY,EAAwC,MAAM,kCAAkC,CAAC;AACtG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,qBAAa,SAAS;IAGlB,cAAc;IACP,MAAM,EAAE,YAAY;IAC3B,2CAA2C;IACpC,QAAQ,EAAE,EAAE;IACnB,2BAA2B;IACpB,SAAS,EAAE,SAAS;IAC3B,uDAAuD;IAChD,YAAY,EAAE,YAAY;IACjC;;;;;OAKG;IACI,IAAI,EAAE,EAAE;IAfjB;IACE,cAAc;IACP,MAAM,EAAE,YAAY;IAC3B,2CAA2C;IACpC,QAAQ,EAAE,EAAE;IACnB,2BAA2B;IACpB,SAAS,EAAE,SAAS;IAC3B,uDAAuD;IAChD,YAAY,EAAE,YAAY;IACjC;;;;;OAKG;IACI,IAAI,EAAE,EAAE,EACb;IAGJ,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,4DAE3C;IAED,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,SAAS,CAElD;IAED;;;OAGG;IACH,QAAQ,4BAEP;IAED;;;;OAIG;IACH,6BAA6B,IAAI,OAAO,CAAC,EAAE,CAAC,CAK3C;IAED;;;OAGG;IACG,wBAAwB,IAAI,OAAO,CAAC,EAAE,CAAC,CAE5C;IAED,QAAQ,IAAI,EAAE,EAAE,CAMf;IAED;;;;OAIG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAS1D;IAED,MAAM,CAAC,KAAK,cAEX;IAED,OAAO,YAQN;CACF"}
|
package/dest/tx/tx_request.js
CHANGED
|
@@ -3,6 +3,7 @@ import { poseidon2HashWithSeparator } from '@aztec-labs/foundation/crypto/poseid
|
|
|
3
3
|
import { Fr } from '@aztec-labs/foundation/curves/bn254';
|
|
4
4
|
import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec-labs/foundation/serialize';
|
|
5
5
|
import { AztecAddress } from '../aztec-address/index.js';
|
|
6
|
+
import { computeProtocolNullifier } from '../hash/hash.js';
|
|
6
7
|
import { FunctionData } from './function_data.js';
|
|
7
8
|
import { TxContext } from './tx_context.js';
|
|
8
9
|
/**
|
|
@@ -14,7 +15,12 @@ import { TxContext } from './tx_context.js';
|
|
|
14
15
|
functionData;
|
|
15
16
|
salt;
|
|
16
17
|
// docs:start:constructor
|
|
17
|
-
constructor(/** Sender. */ origin, /** Pedersen hash of function arguments. */ argsHash, /** Transaction context. */ txContext, /** Function data representing the function to call. */ functionData, /**
|
|
18
|
+
constructor(/** Sender. */ origin, /** Pedersen hash of function arguments. */ argsHash, /** Transaction context. */ txContext, /** Function data representing the function to call. */ functionData, /**
|
|
19
|
+
* A fresh random field drawn by the wallet, acting as the tx request's nonce. With `origin`, `chainId` and `version`
|
|
20
|
+
* it is the whole preimage of the protocol nullifier, so it keeps that nullifier unpredictable and unique. The kernel
|
|
21
|
+
* cannot check that it is random; draw it fresh for every transaction, since two requests with the same origin and
|
|
22
|
+
* salt are mutually exclusive.
|
|
23
|
+
*/ salt){
|
|
18
24
|
this.origin = origin;
|
|
19
25
|
this.argsHash = argsHash;
|
|
20
26
|
this.txContext = txContext;
|
|
@@ -42,6 +48,24 @@ import { TxContext } from './tx_context.js';
|
|
|
42
48
|
...TxRequest.getFields(this)
|
|
43
49
|
]);
|
|
44
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* The unsiloed value of the protocol nullifier: the transaction's nonce commitment.
|
|
53
|
+
* The preimage is only `origin`, `chainId`, `version` and `salt`. Gas settings and the first call's arguments are
|
|
54
|
+
* left out so that a fee bump or a cancellation that reuses the salt produces the same nullifier.
|
|
55
|
+
*/ computeProtocolNullifierValue() {
|
|
56
|
+
return poseidon2HashWithSeparator([
|
|
57
|
+
this.origin.toField(),
|
|
58
|
+
this.txContext.chainId,
|
|
59
|
+
this.txContext.version,
|
|
60
|
+
this.salt
|
|
61
|
+
], DomainSeparator.PROTOCOL_NULLIFIER);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The protocol nullifier as inserted into the nullifier tree, and as every private call receives it in
|
|
65
|
+
* `PrivateCircuitPublicInputs.protocolNullifier`: the value above siloed under `NULL_MSG_SENDER`.
|
|
66
|
+
*/ async computeProtocolNullifier() {
|
|
67
|
+
return computeProtocolNullifier(await this.computeProtocolNullifierValue());
|
|
68
|
+
}
|
|
45
69
|
toFields() {
|
|
46
70
|
const fields = serializeToFields(...TxRequest.getFields(this));
|
|
47
71
|
if (fields.length !== TX_REQUEST_LENGTH) {
|
|
@@ -57,9 +81,6 @@ import { TxContext } from './tx_context.js';
|
|
|
57
81
|
const reader = BufferReader.asReader(buffer);
|
|
58
82
|
return new TxRequest(reader.readObject(AztecAddress), Fr.fromBuffer(reader), reader.readObject(TxContext), reader.readObject(FunctionData), Fr.fromBuffer(reader));
|
|
59
83
|
}
|
|
60
|
-
hash() {
|
|
61
|
-
return poseidon2HashWithSeparator(this.toFields(), DomainSeparator.TX_REQUEST);
|
|
62
|
-
}
|
|
63
84
|
static empty() {
|
|
64
85
|
return new TxRequest(AztecAddress.ZERO, Fr.zero(), TxContext.empty(), FunctionData.empty(), Fr.zero());
|
|
65
86
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec-labs/stdlib",
|
|
3
|
-
"version": "6.0.0-
|
|
3
|
+
"version": "6.0.0-rc.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"inherits": [
|
|
6
6
|
"../package.common.json",
|
|
@@ -92,12 +92,12 @@
|
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
94
|
"@aws-sdk/client-s3": "^3.892.0",
|
|
95
|
-
"@aztec-foundation/bb.js": "6.0.0-
|
|
96
|
-
"@aztec-foundation/noir-noirc_abi": "6.0.0-
|
|
97
|
-
"@aztec-labs/blob-lib": "6.0.0-
|
|
98
|
-
"@aztec-labs/constants": "6.0.0-
|
|
99
|
-
"@aztec-labs/ethereum": "6.0.0-
|
|
100
|
-
"@aztec-labs/foundation": "6.0.0-
|
|
95
|
+
"@aztec-foundation/bb.js": "6.0.0-rc.1",
|
|
96
|
+
"@aztec-foundation/noir-noirc_abi": "6.0.0-rc.1",
|
|
97
|
+
"@aztec-labs/blob-lib": "6.0.0-rc.1",
|
|
98
|
+
"@aztec-labs/constants": "6.0.0-rc.1",
|
|
99
|
+
"@aztec-labs/ethereum": "6.0.0-rc.1",
|
|
100
|
+
"@aztec-labs/foundation": "6.0.0-rc.1",
|
|
101
101
|
"@google-cloud/storage": "^7.15.0",
|
|
102
102
|
"axios": "^1.15.1",
|
|
103
103
|
"json-stringify-deterministic": "1.0.12",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"msgpackr": "^1.11.2",
|
|
109
109
|
"pako": "^2.1.0",
|
|
110
110
|
"tslib": "^2.4.0",
|
|
111
|
-
"viem": "npm:@aztec/viem@2.38.
|
|
111
|
+
"viem": "npm:@aztec/viem@2.38.3",
|
|
112
112
|
"zod": "~4.4.3"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ViemCommitteeAttestation, ViemCommitteeAttestations } from '@aztec-labs/ethereum/contracts';
|
|
2
|
+
import { Buffer32 } from '@aztec-labs/foundation/buffer';
|
|
2
3
|
import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
3
4
|
import { Signature } from '@aztec-labs/foundation/eth-signature';
|
|
4
5
|
import { BufferReader, serializeToBuffer } from '@aztec-labs/foundation/serialize';
|
|
@@ -76,10 +77,10 @@ export class CommitteeAttestation {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
const v = dataBuffer[dataIndex];
|
|
79
|
-
const r =
|
|
80
|
-
const s =
|
|
80
|
+
const r = Buffer32.fromBuffer(dataBuffer.subarray(dataIndex + 1, dataIndex + 33));
|
|
81
|
+
const s = Buffer32.fromBuffer(dataBuffer.subarray(dataIndex + 33, dataIndex + 65));
|
|
81
82
|
|
|
82
|
-
const signature = Signature
|
|
83
|
+
const signature = new Signature(r, s, v);
|
|
83
84
|
|
|
84
85
|
// For signed attestations, we use a zero address as the address is recovered from the signature
|
|
85
86
|
attestations.push(new CommitteeAttestation(EthAddress.ZERO, signature));
|
|
@@ -90,8 +91,7 @@ export class CommitteeAttestation {
|
|
|
90
91
|
throw new Error(`Insufficient data for address at position ${i}`);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
const
|
|
94
|
-
const address = EthAddress.fromString(`0x${addressBytes.toString('hex')}`);
|
|
94
|
+
const address = EthAddress.fromBuffer(dataBuffer.subarray(dataIndex, dataIndex + 20));
|
|
95
95
|
|
|
96
96
|
// For address-only attestations, use empty signature
|
|
97
97
|
attestations.push(new CommitteeAttestation(address, Signature.empty()));
|
|
@@ -3,6 +3,7 @@ import { times } from '@aztec-labs/foundation/collection';
|
|
|
3
3
|
import { Fr } from '@aztec-labs/foundation/curves/bn254';
|
|
4
4
|
import {
|
|
5
5
|
type CheckpointId,
|
|
6
|
+
CommitteeAttestationsAndSigners,
|
|
6
7
|
GENESIS_CHECKPOINT_HEADER_HASH,
|
|
7
8
|
L2Block,
|
|
8
9
|
type L2BlockId,
|
|
@@ -91,7 +92,12 @@ export function testL2TipsStore(makeTipsStore: () => Promise<L2TipsStore>) {
|
|
|
91
92
|
blockToCheckpoint.set(block.number, checkpointNumber);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
return new PublishedCheckpoint(
|
|
95
|
+
return new PublishedCheckpoint(
|
|
96
|
+
checkpoint,
|
|
97
|
+
L1PublishedData.random(),
|
|
98
|
+
[],
|
|
99
|
+
CommitteeAttestationsAndSigners.packAttestations([]),
|
|
100
|
+
);
|
|
95
101
|
};
|
|
96
102
|
|
|
97
103
|
/** Creates a thin chain-checkpointed event carrying the block + checkpoint ids of the checkpoint's last block. */
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type ViemCommitteeAttestations,
|
|
3
|
+
ViemCommitteeAttestationsSchema,
|
|
4
|
+
} from '@aztec-labs/ethereum/contracts/committee-attestations';
|
|
2
5
|
import { EpochNumber, EpochNumberSchema } from '@aztec-labs/foundation/branded-types';
|
|
3
6
|
import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
4
7
|
import { type ZodFor, schemas } from '@aztec-labs/foundation/schemas';
|
|
@@ -71,12 +74,6 @@ export type ValidateCheckpointNegativeResult =
|
|
|
71
74
|
/** Result type for validating checkpoint attestations */
|
|
72
75
|
export type ValidateCheckpointResult = { valid: true } | ValidateCheckpointNegativeResult;
|
|
73
76
|
|
|
74
|
-
/** Zod schema for the raw packed `CommitteeAttestations` viem tuple (two 0x-prefixed hex strings). */
|
|
75
|
-
const ViemCommitteeAttestationsSchema: ZodFor<ViemCommitteeAttestations> = z.object({
|
|
76
|
-
signatureIndices: schemas.HexStringWith0x,
|
|
77
|
-
signaturesOrAddresses: schemas.HexStringWith0x,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
77
|
export const ValidateCheckpointResultSchema: ZodFor<ValidateCheckpointResult> = z.union([
|
|
81
78
|
z.object({ valid: z.literal(true) }),
|
|
82
79
|
z.object({
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ViemCommitteeAttestations,
|
|
3
|
+
ViemCommitteeAttestationsSchema,
|
|
4
|
+
} from '@aztec-labs/ethereum/contracts/committee-attestations';
|
|
1
5
|
import {
|
|
2
6
|
BlockNumber,
|
|
3
7
|
BlockNumberSchema,
|
|
@@ -24,6 +28,11 @@ export type CommonCheckpointData = {
|
|
|
24
28
|
/** Data stored with checkpoint data after publishing on l1 */
|
|
25
29
|
export type L1EnrichedCheckpointData = {
|
|
26
30
|
attestations: CommitteeAttestation[];
|
|
31
|
+
/**
|
|
32
|
+
* The packed `CommitteeAttestations` tuple exactly as posted to L1. {@link attestations} is what this tuple
|
|
33
|
+
* decodes to; only the tuple reproduces the `attestationsHash` the rollup stored at propose time.
|
|
34
|
+
*/
|
|
35
|
+
verbatimAttestations: ViemCommitteeAttestations;
|
|
27
36
|
l1: L1PublishedData;
|
|
28
37
|
};
|
|
29
38
|
|
|
@@ -86,6 +95,7 @@ export const CheckpointDataSchema = z
|
|
|
86
95
|
blockCount: schemas.Integer,
|
|
87
96
|
feeAssetPriceModifier: schemas.BigInt,
|
|
88
97
|
attestations: z.array(CommitteeAttestation.schema),
|
|
98
|
+
verbatimAttestations: ViemCommitteeAttestationsSchema,
|
|
89
99
|
l1: L1PublishedData.schema,
|
|
90
100
|
})
|
|
91
101
|
.transform(
|
|
@@ -98,6 +108,7 @@ export const CheckpointDataSchema = z
|
|
|
98
108
|
blockCount: obj.blockCount,
|
|
99
109
|
feeAssetPriceModifier: obj.feeAssetPriceModifier,
|
|
100
110
|
attestations: obj.attestations,
|
|
111
|
+
verbatimAttestations: obj.verbatimAttestations,
|
|
101
112
|
l1: obj.l1,
|
|
102
113
|
}),
|
|
103
114
|
);
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
// Ignoring import issue to fix portable inferred type issue in zod schema
|
|
2
|
+
import {
|
|
3
|
+
type ViemCommitteeAttestations,
|
|
4
|
+
ViemCommitteeAttestationsSchema,
|
|
5
|
+
} from '@aztec-labs/ethereum/contracts/committee-attestations';
|
|
2
6
|
import { Buffer32 } from '@aztec-labs/foundation/buffer';
|
|
3
7
|
import { randomBigInt } from '@aztec-labs/foundation/crypto/random';
|
|
4
8
|
import { schemas } from '@aztec-labs/foundation/schemas';
|
|
5
9
|
import { BufferReader, serializeToBuffer } from '@aztec-labs/foundation/serialize';
|
|
10
|
+
import { bufferToHex, hexToBuffer } from '@aztec-labs/foundation/string';
|
|
6
11
|
import type { FieldsOf } from '@aztec-labs/foundation/types';
|
|
7
12
|
import { z } from 'zod';
|
|
8
13
|
|
|
@@ -60,6 +65,14 @@ export class PublishedCheckpoint {
|
|
|
60
65
|
public l1: L1PublishedData,
|
|
61
66
|
/** The attestations for the last block in the checkpoint. */
|
|
62
67
|
public attestations: CommitteeAttestation[],
|
|
68
|
+
/**
|
|
69
|
+
* The packed `CommitteeAttestations` tuple exactly as it appeared in the propose calldata. The rollup
|
|
70
|
+
* stores `keccak256(abi.encode(tuple))` and re-checks it when an epoch proof or an invalidation is
|
|
71
|
+
* submitted, so the tuple can only be reproduced from these bytes: repacking the decoded
|
|
72
|
+
* {@link attestations} zeroes bitmap bits past the committee size and canonicalizes recovery bytes,
|
|
73
|
+
* neither of which any decoder reads but both of which the stored hash covers.
|
|
74
|
+
*/
|
|
75
|
+
public verbatimAttestations: ViemCommitteeAttestations,
|
|
63
76
|
) {}
|
|
64
77
|
|
|
65
78
|
static get schema() {
|
|
@@ -68,12 +81,13 @@ export class PublishedCheckpoint {
|
|
|
68
81
|
checkpoint: Checkpoint.schema,
|
|
69
82
|
l1: L1PublishedData.schema,
|
|
70
83
|
attestations: z.array(CommitteeAttestation.schema),
|
|
84
|
+
verbatimAttestations: ViemCommitteeAttestationsSchema,
|
|
71
85
|
})
|
|
72
86
|
.transform(obj => PublishedCheckpoint.from(obj));
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
static getFields(fields: FieldsOf<PublishedCheckpoint>) {
|
|
76
|
-
return [fields.checkpoint, fields.l1, fields.attestations] as const;
|
|
90
|
+
return [fields.checkpoint, fields.l1, fields.attestations, fields.verbatimAttestations] as const;
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
static from(fields: FieldsOf<PublishedCheckpoint>) {
|
|
@@ -87,14 +101,21 @@ export class PublishedCheckpoint {
|
|
|
87
101
|
const l1BlockHash = reader.readString(MAX_BLOCK_HASH_STRING_LENGTH);
|
|
88
102
|
const l1Timestamp = reader.readBigInt();
|
|
89
103
|
const attestations = reader.readVector(CommitteeAttestation, MAX_COMMITTEE_SIZE);
|
|
104
|
+
const verbatimAttestations: ViemCommitteeAttestations = {
|
|
105
|
+
signatureIndices: bufferToHex(reader.readBuffer()),
|
|
106
|
+
signaturesOrAddresses: bufferToHex(reader.readBuffer()),
|
|
107
|
+
};
|
|
90
108
|
return new PublishedCheckpoint(
|
|
91
109
|
checkpoint,
|
|
92
110
|
new L1PublishedData(l1BlockNumber, l1Timestamp, l1BlockHash),
|
|
93
111
|
attestations,
|
|
112
|
+
verbatimAttestations,
|
|
94
113
|
);
|
|
95
114
|
}
|
|
96
115
|
|
|
97
116
|
public toBuffer(): Buffer {
|
|
117
|
+
const signatureIndices = hexToBuffer(this.verbatimAttestations.signatureIndices);
|
|
118
|
+
const signaturesOrAddresses = hexToBuffer(this.verbatimAttestations.signaturesOrAddresses);
|
|
98
119
|
return serializeToBuffer(
|
|
99
120
|
this.checkpoint,
|
|
100
121
|
this.l1.blockNumber,
|
|
@@ -102,6 +123,10 @@ export class PublishedCheckpoint {
|
|
|
102
123
|
this.l1.timestamp,
|
|
103
124
|
this.attestations.length,
|
|
104
125
|
this.attestations,
|
|
126
|
+
signatureIndices.length,
|
|
127
|
+
signatureIndices,
|
|
128
|
+
signaturesOrAddresses.length,
|
|
129
|
+
signaturesOrAddresses,
|
|
105
130
|
);
|
|
106
131
|
}
|
|
107
132
|
}
|
package/src/hash/hash.ts
CHANGED
|
@@ -109,8 +109,8 @@ export async function computeSiloedPublicInitializationNullifier(contract: Aztec
|
|
|
109
109
|
*
|
|
110
110
|
* @dev Must match the implementation in noir-protocol-circuits/crates/types/src/hash.nr > compute_protocol_nullifier
|
|
111
111
|
*/
|
|
112
|
-
export function computeProtocolNullifier(
|
|
113
|
-
return siloNullifier(AztecAddress.NULL_MSG_SENDER,
|
|
112
|
+
export function computeProtocolNullifier(protocolNullifierValue: Fr): Promise<Fr> {
|
|
113
|
+
return siloNullifier(AztecAddress.NULL_MSG_SENDER, protocolNullifierValue);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/** Domain-separates a raw log tag with the given domain separator. */
|
|
@@ -145,10 +145,12 @@ export class PrivateCircuitPublicInputs {
|
|
|
145
145
|
*/
|
|
146
146
|
public contractClassLogsHashes: ClaimedLengthArray<CountedLogHash, typeof MAX_CONTRACT_CLASS_LOGS_PER_CALL>,
|
|
147
147
|
/**
|
|
148
|
-
* The
|
|
149
|
-
*
|
|
148
|
+
* The transaction's siloed protocol nullifier: the value the init kernel inserts at index 0 of the transaction's
|
|
149
|
+
* nullifiers, identical on every private call. The init kernel asserts the first call's value equals the one
|
|
150
|
+
* derived from the tx request, binding this proof to that request; every later kernel asserts each nested call's
|
|
151
|
+
* value equals the transaction constant.
|
|
150
152
|
*/
|
|
151
|
-
public
|
|
153
|
+
public protocolNullifier: Fr,
|
|
152
154
|
) {}
|
|
153
155
|
|
|
154
156
|
/**
|
|
@@ -287,7 +289,7 @@ export class PrivateCircuitPublicInputs {
|
|
|
287
289
|
this.l2ToL1Msgs.isEmpty() &&
|
|
288
290
|
this.privateLogs.isEmpty() &&
|
|
289
291
|
this.contractClassLogsHashes.isEmpty() &&
|
|
290
|
-
this.
|
|
292
|
+
this.protocolNullifier.isZero()
|
|
291
293
|
);
|
|
292
294
|
}
|
|
293
295
|
|
|
@@ -321,7 +323,7 @@ export class PrivateCircuitPublicInputs {
|
|
|
321
323
|
fields.l2ToL1Msgs,
|
|
322
324
|
fields.privateLogs,
|
|
323
325
|
fields.contractClassLogsHashes,
|
|
324
|
-
fields.
|
|
326
|
+
fields.protocolNullifier,
|
|
325
327
|
] as const;
|
|
326
328
|
}
|
|
327
329
|
|
|
@@ -356,7 +358,7 @@ export class PrivateCircuitPublicInputs {
|
|
|
356
358
|
this.l2ToL1Msgs,
|
|
357
359
|
this.privateLogs,
|
|
358
360
|
this.contractClassLogsHashes,
|
|
359
|
-
this.
|
|
361
|
+
this.protocolNullifier,
|
|
360
362
|
]);
|
|
361
363
|
}
|
|
362
364
|
|
|
@@ -11,7 +11,7 @@ export class PrivateContextInputs {
|
|
|
11
11
|
public anchorBlockHeader: BlockHeader,
|
|
12
12
|
public txContext: TxContext,
|
|
13
13
|
public startSideEffectCounter: number,
|
|
14
|
-
public
|
|
14
|
+
public protocolNullifier: Fr,
|
|
15
15
|
) {}
|
|
16
16
|
|
|
17
17
|
public static empty(): PrivateContextInputs {
|
|
@@ -24,7 +24,7 @@ export class PrivateContextInputs {
|
|
|
24
24
|
this.anchorBlockHeader,
|
|
25
25
|
this.txContext,
|
|
26
26
|
this.startSideEffectCounter,
|
|
27
|
-
this.
|
|
27
|
+
this.protocolNullifier,
|
|
28
28
|
]);
|
|
29
29
|
}
|
|
30
30
|
}
|
package/src/tests/factories.ts
CHANGED
|
@@ -653,7 +653,7 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn
|
|
|
653
653
|
anchorBlockHeader: makeBlockHeader(seed + 0xd00),
|
|
654
654
|
txContext: makeTxContext(seed + 0x1400),
|
|
655
655
|
isFeePayer: false,
|
|
656
|
-
|
|
656
|
+
protocolNullifier: fr(seed + 0x1500),
|
|
657
657
|
});
|
|
658
658
|
}
|
|
659
659
|
|
|
@@ -24,13 +24,13 @@ export class PrivateTxConstantData {
|
|
|
24
24
|
*/
|
|
25
25
|
public txContext: TxContext,
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* The transaction's siloed protocol nullifier.
|
|
28
28
|
*
|
|
29
29
|
* Bound to the user's `tx_request` by the Init circuit and kept constant by every subsequent kernel so that each
|
|
30
|
-
* app circuit's `
|
|
31
|
-
*
|
|
30
|
+
* app circuit's `protocolNullifier` public input can be checked against it. Not carried into `TxConstantData`:
|
|
31
|
+
* the value is already published as the transaction's first nullifier.
|
|
32
32
|
*/
|
|
33
|
-
public
|
|
33
|
+
public protocolNullifier: Fr,
|
|
34
34
|
/**
|
|
35
35
|
* Root of the vk tree for the protocol circuits.
|
|
36
36
|
*/
|
|
@@ -49,7 +49,7 @@ export class PrivateTxConstantData {
|
|
|
49
49
|
return [
|
|
50
50
|
fields.anchorBlockHeader,
|
|
51
51
|
fields.txContext,
|
|
52
|
-
fields.
|
|
52
|
+
fields.protocolNullifier,
|
|
53
53
|
fields.vkTreeRoot,
|
|
54
54
|
fields.protocolContracts,
|
|
55
55
|
] as const;
|
|
@@ -105,7 +105,7 @@ export class PrivateTxConstantData {
|
|
|
105
105
|
return (
|
|
106
106
|
this.anchorBlockHeader.getSize() +
|
|
107
107
|
this.txContext.getSize() +
|
|
108
|
-
this.
|
|
108
|
+
this.protocolNullifier.size +
|
|
109
109
|
this.vkTreeRoot.size +
|
|
110
110
|
this.protocolContracts.getSize()
|
|
111
111
|
);
|
package/src/tx/tx_request.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec-labs/
|
|
|
5
5
|
import type { FieldsOf } from '@aztec-labs/foundation/types';
|
|
6
6
|
|
|
7
7
|
import { AztecAddress } from '../aztec-address/index.js';
|
|
8
|
+
import { computeProtocolNullifier } from '../hash/hash.js';
|
|
8
9
|
import { FunctionData } from './function_data.js';
|
|
9
10
|
import { TxContext } from './tx_context.js';
|
|
10
11
|
|
|
@@ -22,7 +23,12 @@ export class TxRequest {
|
|
|
22
23
|
public txContext: TxContext,
|
|
23
24
|
/** Function data representing the function to call. */
|
|
24
25
|
public functionData: FunctionData,
|
|
25
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* A fresh random field drawn by the wallet, acting as the tx request's nonce. With `origin`, `chainId` and `version`
|
|
28
|
+
* it is the whole preimage of the protocol nullifier, so it keeps that nullifier unpredictable and unique. The kernel
|
|
29
|
+
* cannot check that it is random; draw it fresh for every transaction, since two requests with the same origin and
|
|
30
|
+
* salt are mutually exclusive.
|
|
31
|
+
*/
|
|
26
32
|
public salt: Fr,
|
|
27
33
|
) {}
|
|
28
34
|
// docs:end:constructor
|
|
@@ -43,6 +49,26 @@ export class TxRequest {
|
|
|
43
49
|
return serializeToBuffer([...TxRequest.getFields(this)]);
|
|
44
50
|
}
|
|
45
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The unsiloed value of the protocol nullifier: the transaction's nonce commitment.
|
|
54
|
+
* The preimage is only `origin`, `chainId`, `version` and `salt`. Gas settings and the first call's arguments are
|
|
55
|
+
* left out so that a fee bump or a cancellation that reuses the salt produces the same nullifier.
|
|
56
|
+
*/
|
|
57
|
+
computeProtocolNullifierValue(): Promise<Fr> {
|
|
58
|
+
return poseidon2HashWithSeparator(
|
|
59
|
+
[this.origin.toField(), this.txContext.chainId, this.txContext.version, this.salt],
|
|
60
|
+
DomainSeparator.PROTOCOL_NULLIFIER,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The protocol nullifier as inserted into the nullifier tree, and as every private call receives it in
|
|
66
|
+
* `PrivateCircuitPublicInputs.protocolNullifier`: the value above siloed under `NULL_MSG_SENDER`.
|
|
67
|
+
*/
|
|
68
|
+
async computeProtocolNullifier(): Promise<Fr> {
|
|
69
|
+
return computeProtocolNullifier(await this.computeProtocolNullifierValue());
|
|
70
|
+
}
|
|
71
|
+
|
|
46
72
|
toFields(): Fr[] {
|
|
47
73
|
const fields = serializeToFields(...TxRequest.getFields(this));
|
|
48
74
|
if (fields.length !== TX_REQUEST_LENGTH) {
|
|
@@ -67,10 +93,6 @@ export class TxRequest {
|
|
|
67
93
|
);
|
|
68
94
|
}
|
|
69
95
|
|
|
70
|
-
hash() {
|
|
71
|
-
return poseidon2HashWithSeparator(this.toFields(), DomainSeparator.TX_REQUEST);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
96
|
static empty() {
|
|
75
97
|
return new TxRequest(AztecAddress.ZERO, Fr.zero(), TxContext.empty(), FunctionData.empty(), Fr.zero());
|
|
76
98
|
}
|