@aztec/stdlib 0.0.1-commit.2b2662070 → 0.0.1-commit.2c0ee1788

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.
Files changed (178) hide show
  1. package/dest/abi/encoder.d.ts +1 -1
  2. package/dest/abi/encoder.d.ts.map +1 -1
  3. package/dest/abi/encoder.js +32 -6
  4. package/dest/avm/avm.d.ts +300 -300
  5. package/dest/block/attestation_info.d.ts +3 -2
  6. package/dest/block/attestation_info.d.ts.map +1 -1
  7. package/dest/block/attestation_info.js +7 -5
  8. package/dest/block/block_data.d.ts +290 -1
  9. package/dest/block/block_data.d.ts.map +1 -1
  10. package/dest/block/block_data.js +14 -0
  11. package/dest/block/block_parameter.d.ts +30 -3
  12. package/dest/block/block_parameter.d.ts.map +1 -1
  13. package/dest/block/block_parameter.js +36 -2
  14. package/dest/block/l2_block_source.d.ts +39 -4
  15. package/dest/block/l2_block_source.d.ts.map +1 -1
  16. package/dest/block/proposal/attestations_and_signers.d.ts +13 -6
  17. package/dest/block/proposal/attestations_and_signers.d.ts.map +1 -1
  18. package/dest/block/proposal/attestations_and_signers.js +26 -18
  19. package/dest/checkpoint/checkpoint_data.d.ts +7 -1
  20. package/dest/checkpoint/checkpoint_data.d.ts.map +1 -1
  21. package/dest/checkpoint/checkpoint_data.js +2 -0
  22. package/dest/config/chain-config.d.ts +2 -2
  23. package/dest/config/chain-config.d.ts.map +1 -1
  24. package/dest/config/chain-config.js +2 -2
  25. package/dest/config/sequencer-config.d.ts +5 -3
  26. package/dest/config/sequencer-config.d.ts.map +1 -1
  27. package/dest/config/sequencer-config.js +13 -6
  28. package/dest/contract/contract_address.d.ts +1 -1
  29. package/dest/contract/contract_address.js +2 -2
  30. package/dest/contract/private_function.d.ts +1 -1
  31. package/dest/contract/private_function.d.ts.map +1 -1
  32. package/dest/contract/private_function.js +2 -4
  33. package/dest/gas/gas_fees.d.ts +5 -1
  34. package/dest/gas/gas_fees.d.ts.map +1 -1
  35. package/dest/ha-signing/config.d.ts +6 -6
  36. package/dest/ha-signing/config.d.ts.map +1 -1
  37. package/dest/ha-signing/config.js +4 -3
  38. package/dest/ha-signing/local_config.d.ts +1 -1
  39. package/dest/ha-signing/local_config.d.ts.map +1 -1
  40. package/dest/ha-signing/local_config.js +2 -2
  41. package/dest/hash/hash.d.ts +16 -1
  42. package/dest/hash/hash.d.ts.map +1 -1
  43. package/dest/hash/hash.js +32 -0
  44. package/dest/interfaces/archiver.d.ts +11 -1
  45. package/dest/interfaces/archiver.d.ts.map +1 -1
  46. package/dest/interfaces/archiver.js +10 -4
  47. package/dest/interfaces/aztec-node-admin.d.ts +19 -4
  48. package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
  49. package/dest/interfaces/aztec-node-admin.js +2 -1
  50. package/dest/interfaces/aztec-node.d.ts +45 -55
  51. package/dest/interfaces/aztec-node.d.ts.map +1 -1
  52. package/dest/interfaces/aztec-node.js +18 -16
  53. package/dest/interfaces/block_response.d.ts +156 -0
  54. package/dest/interfaces/block_response.d.ts.map +1 -0
  55. package/dest/interfaces/block_response.js +24 -0
  56. package/dest/interfaces/chain_tips.d.ts +304 -0
  57. package/dest/interfaces/chain_tips.d.ts.map +1 -0
  58. package/dest/interfaces/chain_tips.js +11 -0
  59. package/dest/interfaces/checkpoint_parameter.d.ts +27 -0
  60. package/dest/interfaces/checkpoint_parameter.d.ts.map +1 -0
  61. package/dest/interfaces/checkpoint_parameter.js +20 -0
  62. package/dest/interfaces/checkpoint_response.d.ts +312 -0
  63. package/dest/interfaces/checkpoint_response.d.ts.map +1 -0
  64. package/dest/interfaces/checkpoint_response.js +26 -0
  65. package/dest/interfaces/client.d.ts +6 -1
  66. package/dest/interfaces/client.d.ts.map +1 -1
  67. package/dest/interfaces/client.js +5 -0
  68. package/dest/interfaces/configs.d.ts +12 -2
  69. package/dest/interfaces/configs.d.ts.map +1 -1
  70. package/dest/interfaces/configs.js +3 -1
  71. package/dest/interfaces/l1_publish_info.d.ts +43 -0
  72. package/dest/interfaces/l1_publish_info.d.ts.map +1 -0
  73. package/dest/interfaces/l1_publish_info.js +26 -0
  74. package/dest/interfaces/proving-job.d.ts +166 -166
  75. package/dest/interfaces/server.d.ts +6 -1
  76. package/dest/interfaces/server.d.ts.map +1 -1
  77. package/dest/interfaces/server.js +5 -0
  78. package/dest/interfaces/validator.d.ts +20 -8
  79. package/dest/interfaces/validator.d.ts.map +1 -1
  80. package/dest/interfaces/validator.js +2 -0
  81. package/dest/p2p/block_proposal.d.ts +19 -9
  82. package/dest/p2p/block_proposal.d.ts.map +1 -1
  83. package/dest/p2p/block_proposal.js +42 -32
  84. package/dest/p2p/checkpoint_attestation.d.ts +7 -3
  85. package/dest/p2p/checkpoint_attestation.d.ts.map +1 -1
  86. package/dest/p2p/checkpoint_attestation.js +15 -17
  87. package/dest/p2p/checkpoint_proposal.d.ts +15 -7
  88. package/dest/p2p/checkpoint_proposal.d.ts.map +1 -1
  89. package/dest/p2p/checkpoint_proposal.js +31 -29
  90. package/dest/p2p/consensus_payload.d.ts +18 -7
  91. package/dest/p2p/consensus_payload.d.ts.map +1 -1
  92. package/dest/p2p/consensus_payload.js +31 -19
  93. package/dest/p2p/signature_utils.d.ts +28 -19
  94. package/dest/p2p/signature_utils.d.ts.map +1 -1
  95. package/dest/p2p/signature_utils.js +118 -21
  96. package/dest/p2p/signed_txs.d.ts +15 -13
  97. package/dest/p2p/signed_txs.d.ts.map +1 -1
  98. package/dest/p2p/signed_txs.js +26 -24
  99. package/dest/parity/parity_base_private_inputs.d.ts +7 -3
  100. package/dest/parity/parity_base_private_inputs.d.ts.map +1 -1
  101. package/dest/parity/parity_base_private_inputs.js +7 -5
  102. package/dest/parity/parity_public_inputs.d.ts +7 -3
  103. package/dest/parity/parity_public_inputs.d.ts.map +1 -1
  104. package/dest/parity/parity_public_inputs.js +6 -3
  105. package/dest/rollup/block_headers_hash.d.ts +1 -1
  106. package/dest/rollup/block_headers_hash.d.ts.map +1 -1
  107. package/dest/rollup/block_headers_hash.js +8 -2
  108. package/dest/tests/factories.d.ts +2 -7
  109. package/dest/tests/factories.d.ts.map +1 -1
  110. package/dest/tests/factories.js +8 -18
  111. package/dest/tests/mocks.d.ts +7 -1
  112. package/dest/tests/mocks.d.ts.map +1 -1
  113. package/dest/tests/mocks.js +28 -14
  114. package/dest/timetable/index.d.ts +1 -1
  115. package/dest/timetable/index.d.ts.map +1 -1
  116. package/dest/timetable/index.js +25 -11
  117. package/dest/trees/nullifier_leaf.d.ts +2 -1
  118. package/dest/trees/nullifier_leaf.d.ts.map +1 -1
  119. package/dest/trees/nullifier_leaf.js +3 -0
  120. package/dest/tx/profiling.js +4 -4
  121. package/dest/types/shared.d.ts +1 -10
  122. package/dest/types/shared.d.ts.map +1 -1
  123. package/dest/types/shared.js +0 -9
  124. package/dest/vks/verification_key.d.ts +2 -137
  125. package/dest/vks/verification_key.d.ts.map +1 -1
  126. package/dest/vks/verification_key.js +5 -126
  127. package/dest/world-state/world_state_revision.d.ts +8 -1
  128. package/dest/world-state/world_state_revision.d.ts.map +1 -1
  129. package/dest/world-state/world_state_revision.js +7 -1
  130. package/package.json +8 -8
  131. package/src/abi/encoder.ts +42 -6
  132. package/src/block/attestation_info.ts +11 -11
  133. package/src/block/block_data.ts +17 -0
  134. package/src/block/block_parameter.ts +35 -2
  135. package/src/block/l2_block_source.ts +43 -3
  136. package/src/block/proposal/attestations_and_signers.ts +32 -17
  137. package/src/checkpoint/checkpoint_data.ts +4 -0
  138. package/src/config/chain-config.ts +2 -3
  139. package/src/config/sequencer-config.ts +25 -7
  140. package/src/contract/contract_address.ts +2 -2
  141. package/src/contract/private_function.ts +3 -1
  142. package/src/gas/gas_fees.ts +5 -0
  143. package/src/ha-signing/config.ts +5 -2
  144. package/src/ha-signing/local_config.ts +2 -2
  145. package/src/hash/hash.ts +27 -0
  146. package/src/interfaces/archiver.ts +21 -3
  147. package/src/interfaces/aztec-node-admin.ts +3 -1
  148. package/src/interfaces/aztec-node.ts +105 -95
  149. package/src/interfaces/block_response.ts +79 -0
  150. package/src/interfaces/chain_tips.ts +24 -0
  151. package/src/interfaces/checkpoint_parameter.ts +22 -0
  152. package/src/interfaces/checkpoint_response.ts +84 -0
  153. package/src/interfaces/client.ts +5 -0
  154. package/src/interfaces/configs.ts +8 -1
  155. package/src/interfaces/l1_publish_info.ts +40 -0
  156. package/src/interfaces/server.ts +5 -0
  157. package/src/interfaces/validator.ts +7 -1
  158. package/src/p2p/block_proposal.ts +84 -28
  159. package/src/p2p/checkpoint_attestation.ts +15 -20
  160. package/src/p2p/checkpoint_proposal.ts +69 -37
  161. package/src/p2p/consensus_payload.ts +50 -28
  162. package/src/p2p/signature_utils.ts +110 -25
  163. package/src/p2p/signed_txs.ts +46 -28
  164. package/src/parity/parity_base_private_inputs.ts +10 -4
  165. package/src/parity/parity_public_inputs.ts +9 -2
  166. package/src/rollup/block_headers_hash.ts +11 -2
  167. package/src/tests/factories.ts +14 -20
  168. package/src/tests/mocks.ts +46 -26
  169. package/src/timetable/index.ts +26 -11
  170. package/src/trees/nullifier_leaf.ts +4 -0
  171. package/src/tx/profiling.ts +4 -4
  172. package/src/types/shared.ts +0 -10
  173. package/src/vks/verification_key.ts +5 -184
  174. package/src/world-state/world_state_revision.ts +9 -1
  175. package/dest/abi/mocked_keys.d.ts +0 -2
  176. package/dest/abi/mocked_keys.d.ts.map +0 -1
  177. package/dest/abi/mocked_keys.js +0 -1
  178. package/src/abi/mocked_keys.ts +0 -2
@@ -10,10 +10,21 @@ import { z } from 'zod';
10
10
  import type { Checkpoint } from '../checkpoint/checkpoint.js';
11
11
  import { CheckpointHeader } from '../rollup/checkpoint_header.js';
12
12
  import type { CheckpointProposal, CheckpointProposalCore } from './checkpoint_proposal.js';
13
- import type { Signable, SignatureDomainSeparator } from './signature_utils.js';
13
+ import {
14
+ type CoordinationSignatureContext,
15
+ type CoordinationSignatureType,
16
+ EMPTY_COORDINATION_SIGNATURE_CONTEXT,
17
+ type Signable,
18
+ coordinationSignatureContextEquals,
19
+ coordinationSignatureContextSchema,
20
+ readCoordinationSignatureContext,
21
+ serializeCoordinationSignatureContext,
22
+ } from './signature_utils.js';
14
23
 
15
24
  /** Checkpoint consensus payload as signed by validators and verified on L1. */
16
25
  export class ConsensusPayload implements Signable {
26
+ readonly primaryType: CoordinationSignatureType = 'CheckpointAttestation';
27
+
17
28
  private size: number | undefined;
18
29
 
19
30
  constructor(
@@ -22,7 +33,9 @@ export class ConsensusPayload implements Signable {
22
33
  /** The archive root after the block is added */
23
34
  public readonly archive: Fr,
24
35
  /** The fee asset price modifier in basis points (from oracle) */
25
- public readonly feeAssetPriceModifier: bigint = 0n,
36
+ public readonly feeAssetPriceModifier: bigint,
37
+ /** The signing domain (chainId + rollupAddress) the signature is bound to */
38
+ public readonly signatureContext: CoordinationSignatureContext,
26
39
  ) {}
27
40
 
28
41
  static get schema() {
@@ -31,36 +44,38 @@ export class ConsensusPayload implements Signable {
31
44
  header: CheckpointHeader.schema,
32
45
  archive: schemas.Fr,
33
46
  feeAssetPriceModifier: schemas.BigInt,
47
+ signatureContext: coordinationSignatureContextSchema,
34
48
  })
35
- .transform(obj => new ConsensusPayload(obj.header, obj.archive, obj.feeAssetPriceModifier));
49
+ .transform(obj => new ConsensusPayload(obj.header, obj.archive, obj.feeAssetPriceModifier, obj.signatureContext));
36
50
  }
37
51
 
38
- static getFields(fields: FieldsOf<ConsensusPayload>) {
39
- return [fields.header, fields.archive, fields.feeAssetPriceModifier] as const;
52
+ static getFields(fields: Omit<FieldsOf<ConsensusPayload>, 'primaryType'>) {
53
+ return [fields.header, fields.archive, fields.feeAssetPriceModifier, fields.signatureContext] as const;
40
54
  }
41
55
 
42
- getPayloadToSign(domainSeparator: SignatureDomainSeparator): Buffer {
56
+ getPayloadToSign(): Buffer {
57
+ // Matches the L1 ProposePayload struct in ProposeLib.sol.
43
58
  const abi = parseAbiParameters(
44
- 'uint8, ' + //domainSeperator
45
- '(' +
59
+ '(' +
46
60
  'bytes32, ' + // archive
47
61
  '(int256), ' + // oracleInput
48
62
  'bytes32' + // headerHash
49
63
  ')',
50
64
  );
51
65
  const archiveRoot = this.archive.toString();
52
-
53
66
  const headerHash = this.header.hash().toString();
54
- const encodedData = encodeAbiParameters(abi, [
55
- domainSeparator,
56
- [archiveRoot, [this.feeAssetPriceModifier], headerHash],
57
- ] as const);
67
+ const encodedData = encodeAbiParameters(abi, [[archiveRoot, [this.feeAssetPriceModifier], headerHash]] as const);
58
68
 
59
69
  return hexToBuffer(encodedData);
60
70
  }
61
71
 
62
72
  toBuffer(): Buffer {
63
- return serializeToBuffer([this.header, this.archive, serializeSignedBigInt(this.feeAssetPriceModifier)]);
73
+ return serializeToBuffer([
74
+ this.header,
75
+ this.archive,
76
+ serializeSignedBigInt(this.feeAssetPriceModifier),
77
+ serializeCoordinationSignatureContext(this.signatureContext),
78
+ ]);
64
79
  }
65
80
 
66
81
  public equals(other: ConsensusPayload | CheckpointProposal | CheckpointProposalCore): boolean {
@@ -69,34 +84,39 @@ export class ConsensusPayload implements Signable {
69
84
  return (
70
85
  this.header.equals(otherHeader) &&
71
86
  this.archive.equals(other.archive) &&
72
- this.feeAssetPriceModifier === otherModifier
87
+ this.feeAssetPriceModifier === otherModifier &&
88
+ coordinationSignatureContextEquals(this.signatureContext, other.signatureContext)
73
89
  );
74
90
  }
75
91
 
76
92
  static fromBuffer(buf: Buffer | BufferReader): ConsensusPayload {
77
93
  const reader = BufferReader.asReader(buf);
78
- const payload = new ConsensusPayload(
79
- reader.readObject(CheckpointHeader),
80
- reader.readObject(Fr),
81
- reader.readInt256(),
82
- );
83
- return payload;
94
+ const header = reader.readObject(CheckpointHeader);
95
+ const archive = reader.readObject(Fr);
96
+ const feeAssetPriceModifier = reader.readInt256();
97
+ const signatureContext = readCoordinationSignatureContext(reader);
98
+ return new ConsensusPayload(header, archive, feeAssetPriceModifier, signatureContext);
84
99
  }
85
100
 
86
- static fromFields(fields: FieldsOf<ConsensusPayload>): ConsensusPayload {
87
- return new ConsensusPayload(fields.header, fields.archive, fields.feeAssetPriceModifier);
101
+ static fromFields(fields: Omit<FieldsOf<ConsensusPayload>, 'primaryType'>): ConsensusPayload {
102
+ return new ConsensusPayload(fields.header, fields.archive, fields.feeAssetPriceModifier, fields.signatureContext);
88
103
  }
89
104
 
90
- static fromCheckpoint(checkpoint: Checkpoint): ConsensusPayload {
91
- return new ConsensusPayload(checkpoint.header, checkpoint.archive.root, checkpoint.feeAssetPriceModifier);
105
+ static fromCheckpoint(checkpoint: Checkpoint, signatureContext: CoordinationSignatureContext): ConsensusPayload {
106
+ return new ConsensusPayload(
107
+ checkpoint.header,
108
+ checkpoint.archive.root,
109
+ checkpoint.feeAssetPriceModifier,
110
+ signatureContext,
111
+ );
92
112
  }
93
113
 
94
114
  static empty(): ConsensusPayload {
95
- return new ConsensusPayload(CheckpointHeader.empty(), Fr.ZERO, 0n);
115
+ return new ConsensusPayload(CheckpointHeader.empty(), Fr.ZERO, 0n, EMPTY_COORDINATION_SIGNATURE_CONTEXT);
96
116
  }
97
117
 
98
118
  static random(): ConsensusPayload {
99
- return new ConsensusPayload(CheckpointHeader.random(), Fr.random(), 0n);
119
+ return new ConsensusPayload(CheckpointHeader.random(), Fr.random(), 0n, EMPTY_COORDINATION_SIGNATURE_CONTEXT);
100
120
  }
101
121
 
102
122
  /**
@@ -117,10 +137,12 @@ export class ConsensusPayload implements Signable {
117
137
  header: this.header.toInspect(),
118
138
  archive: this.archive.toString(),
119
139
  feeAssetPriceModifier: this.feeAssetPriceModifier.toString(),
140
+ chainId: this.signatureContext.chainId,
141
+ rollupAddress: this.signatureContext.rollupAddress.toString(),
120
142
  };
121
143
  }
122
144
 
123
145
  toString() {
124
- return `header: ${this.header.toString()}, archive: ${this.archive.toString()}, feeAssetPriceModifier: ${this.feeAssetPriceModifier}}`;
146
+ return `header: ${this.header.toString()}, archive: ${this.archive.toString()}, feeAssetPriceModifier: ${this.feeAssetPriceModifier}, chainId: ${this.signatureContext.chainId}, rollupAddress: ${this.signatureContext.rollupAddress.toString()}`;
125
147
  }
126
148
  }
@@ -1,37 +1,122 @@
1
1
  import { Buffer32 } from '@aztec/foundation/buffer';
2
2
  import { keccak256 } from '@aztec/foundation/crypto/keccak';
3
- import { makeEthSignDigest } from '@aztec/foundation/crypto/secp256k1-signer';
3
+ import { tryRecoverAddress } from '@aztec/foundation/crypto/secp256k1-signer';
4
+ import { EthAddress } from '@aztec/foundation/eth-address';
5
+ import type { Signature } from '@aztec/foundation/eth-signature';
6
+ import { type BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
4
7
 
5
- export enum SignatureDomainSeparator {
6
- blockProposal = 0,
7
- checkpointAttestation = 1,
8
- attestationsAndSigners = 2,
9
- checkpointProposal = 3,
10
- signedTxs = 4,
11
- }
8
+ import { type TypedDataDefinition, hashTypedData } from 'viem';
9
+ import { z } from 'zod';
10
+
11
+ import type { ZodFor } from '../schemas/index.js';
12
+
13
+ export type CoordinationSignatureType =
14
+ | 'BlockProposal'
15
+ | 'CheckpointProposal'
16
+ | 'CheckpointAttestation'
17
+ | 'AttestationsAndSigners'
18
+ | 'SignedTxs';
19
+
20
+ export type CoordinationSignatureContext = {
21
+ chainId: number;
22
+ rollupAddress: EthAddress;
23
+ };
24
+
25
+ export const EMPTY_COORDINATION_SIGNATURE_CONTEXT: CoordinationSignatureContext = {
26
+ chainId: 0,
27
+ rollupAddress: EthAddress.ZERO,
28
+ };
29
+
30
+ export const coordinationSignatureContextSchema: ZodFor<CoordinationSignatureContext> = z.object({
31
+ chainId: z.number(),
32
+ rollupAddress: EthAddress.schema,
33
+ });
12
34
 
13
35
  export interface Signable {
14
- getPayloadToSign(domainSeparator: SignatureDomainSeparator): Buffer;
36
+ readonly primaryType: CoordinationSignatureType;
37
+ readonly signatureContext: CoordinationSignatureContext;
38
+ getPayloadToSign(): Buffer;
15
39
  }
16
40
 
17
- /**
18
- * Get the hashed payload for the signature of the `Signable`
19
- * @param s - The `Signable` to sign
20
- * @returns The hashed payload for the signature of the `Signable`
21
- */
22
- export function getHashedSignaturePayload(s: Signable, domainSeparator: SignatureDomainSeparator): Buffer32 {
23
- return Buffer32.fromBuffer(keccak256(s.getPayloadToSign(domainSeparator)));
41
+ export function coordinationSignatureContextEquals(
42
+ a: CoordinationSignatureContext,
43
+ b: CoordinationSignatureContext,
44
+ ): boolean {
45
+ return a.chainId === b.chainId && a.rollupAddress.equals(b.rollupAddress);
46
+ }
47
+
48
+ export function serializeCoordinationSignatureContext(ctx: CoordinationSignatureContext): Buffer {
49
+ return serializeToBuffer([ctx.chainId, ctx.rollupAddress]);
50
+ }
51
+
52
+ export function readCoordinationSignatureContext(reader: BufferReader): CoordinationSignatureContext {
53
+ const chainId = reader.readNumber();
54
+ const rollupAddress = reader.readObject(EthAddress);
55
+ return { chainId, rollupAddress };
24
56
  }
25
57
 
26
58
  /**
27
- * Get the hashed payload for the signature of the `Signable` as an Ethereum signed message EIP-712
28
- * @param s - the `Signable` to sign
29
- * @returns The hashed payload for the signature of the `Signable` as an Ethereum signed message
59
+ * Returns true if the signable carries a context matching the node's expected context.
60
+ * Use this at the P2P ingress boundary to reject foreign-chain messages cheaply before
61
+ * performing any signature recovery.
30
62
  */
31
- export function getHashedSignaturePayloadEthSignedMessage(
32
- s: Signable,
33
- domainSeparator: SignatureDomainSeparator,
34
- ): Buffer32 {
35
- const payload = getHashedSignaturePayload(s, domainSeparator);
36
- return makeEthSignDigest(payload);
63
+ export function hasValidSignatureContext(signable: Signable, expected: CoordinationSignatureContext): boolean {
64
+ return coordinationSignatureContextEquals(signable.signatureContext, expected);
65
+ }
66
+
67
+ const COORDINATION_SIGNATURE_NAME = 'Aztec Rollup';
68
+ const COORDINATION_SIGNATURE_VERSION = '1';
69
+
70
+ const EIP712_DOMAIN_FIELDS = [
71
+ { name: 'name', type: 'string' },
72
+ { name: 'version', type: 'string' },
73
+ { name: 'chainId', type: 'uint256' },
74
+ { name: 'verifyingContract', type: 'address' },
75
+ ] as const;
76
+
77
+ const COORDINATION_SIGNATURE_TYPES = {
78
+ EIP712Domain: EIP712_DOMAIN_FIELDS,
79
+ BlockProposal: [{ name: 'payloadHash', type: 'bytes32' }],
80
+ CheckpointProposal: [{ name: 'payloadHash', type: 'bytes32' }],
81
+ CheckpointAttestation: [{ name: 'payloadHash', type: 'bytes32' }],
82
+ AttestationsAndSigners: [{ name: 'payloadHash', type: 'bytes32' }],
83
+ SignedTxs: [{ name: 'payloadHash', type: 'bytes32' }],
84
+ } as const;
85
+
86
+ export function getCoordinationSignatureTypedDataForPayloadHash(
87
+ payloadHash: Buffer32,
88
+ type: CoordinationSignatureType,
89
+ context: CoordinationSignatureContext,
90
+ ): TypedDataDefinition {
91
+ return {
92
+ domain: {
93
+ name: COORDINATION_SIGNATURE_NAME,
94
+ version: COORDINATION_SIGNATURE_VERSION,
95
+ chainId: context.chainId,
96
+ verifyingContract: context.rollupAddress.toString() as `0x${string}`,
97
+ },
98
+ types: COORDINATION_SIGNATURE_TYPES,
99
+ primaryType: type,
100
+ message: {
101
+ payloadHash: payloadHash.toString() as `0x${string}`,
102
+ },
103
+ };
104
+ }
105
+
106
+ export function getCoordinationSignatureTypedData(signable: Signable): TypedDataDefinition {
107
+ const payloadHash = getHashedSignaturePayload(signable);
108
+ return getCoordinationSignatureTypedDataForPayloadHash(payloadHash, signable.primaryType, signable.signatureContext);
109
+ }
110
+
111
+ export function getHashedSignaturePayloadTypedData(signable: Signable): Buffer32 {
112
+ return Buffer32.fromString(hashTypedData(getCoordinationSignatureTypedData(signable)));
113
+ }
114
+
115
+ export function recoverCoordinationSigner(signable: Signable, signature: Signature): EthAddress | undefined {
116
+ const digest = getHashedSignaturePayloadTypedData(signable);
117
+ return tryRecoverAddress(digest, signature, { allowYParityAsV: true });
118
+ }
119
+
120
+ export function getHashedSignaturePayload(s: Signable): Buffer32 {
121
+ return Buffer32.fromBuffer(keccak256(s.getPayloadToSign()));
37
122
  }
@@ -1,15 +1,20 @@
1
- import { Buffer32 } from '@aztec/foundation/buffer';
2
- import { tryRecoverAddress } from '@aztec/foundation/crypto/secp256k1-signer';
3
1
  import type { EthAddress } from '@aztec/foundation/eth-address';
4
2
  import { Signature } from '@aztec/foundation/eth-signature';
5
3
  import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
6
4
 
5
+ import type { TypedDataDefinition } from 'viem';
6
+
7
7
  import { MAX_TXS_PER_BLOCK } from '../deserialization/index.js';
8
8
  import { Tx } from '../tx/tx.js';
9
9
  import {
10
- SignatureDomainSeparator,
11
- getHashedSignaturePayload,
12
- getHashedSignaturePayloadEthSignedMessage,
10
+ type CoordinationSignatureContext,
11
+ type CoordinationSignatureType,
12
+ EMPTY_COORDINATION_SIGNATURE_CONTEXT,
13
+ type Signable,
14
+ getCoordinationSignatureTypedData,
15
+ readCoordinationSignatureContext,
16
+ recoverCoordinationSigner,
17
+ serializeCoordinationSignatureContext,
13
18
  } from './signature_utils.js';
14
19
 
15
20
  /**
@@ -17,50 +22,56 @@ import {
17
22
  * The signature is over the transaction objects themselves, providing
18
23
  * data availability guarantees beyond just the transaction hashes.
19
24
  */
20
- export class SignedTxs {
21
- private sender: EthAddress | undefined;
25
+ export class SignedTxs implements Signable {
26
+ readonly primaryType: CoordinationSignatureType = 'SignedTxs';
27
+
28
+ private cachedSender: EthAddress | undefined | null = undefined;
22
29
 
23
30
  constructor(
24
31
  /** The transactions */
25
32
  public readonly txs: Tx[],
26
33
  /** The proposer's signature over the transactions */
27
34
  public readonly signature: Signature,
35
+ /** The signing domain (chainId + rollupAddress) the signature is bound to */
36
+ public readonly signatureContext: CoordinationSignatureContext,
28
37
  ) {}
29
38
 
30
- /**
31
- * Get the payload to sign for this signed txs.
32
- */
33
- getPayloadToSign(domainSeparator: SignatureDomainSeparator): Buffer {
34
- return serializeToBuffer([domainSeparator, this.txs.length, this.txs]);
39
+ getPayloadToSign(): Buffer {
40
+ return serializeToBuffer([this.txs.length, this.txs]);
35
41
  }
36
42
 
37
43
  /**
38
- * Lazily evaluate the sender of the signed txs; result is cached
44
+ * Lazily evaluate the sender of the signed txs; result is cached.
39
45
  * @returns The sender address, or undefined if signature recovery fails
40
46
  */
41
47
  getSender(): EthAddress | undefined {
42
- if (!this.sender) {
43
- const hashed = getHashedSignaturePayloadEthSignedMessage(this, SignatureDomainSeparator.signedTxs);
44
- this.sender = tryRecoverAddress(hashed, this.signature);
48
+ if (this.cachedSender === undefined) {
49
+ this.cachedSender = recoverCoordinationSigner(this, this.signature) ?? null;
45
50
  }
46
- return this.sender;
51
+ return this.cachedSender ?? undefined;
47
52
  }
48
53
 
49
54
  /**
50
- * Create SignedTxs from a signer function
55
+ * Create SignedTxs from a typed-data signer function
51
56
  */
52
57
  static async createFromSigner(
53
58
  txs: Tx[],
54
- payloadSigner: (payload: Buffer32) => Promise<Signature>,
59
+ signatureContext: CoordinationSignatureContext,
60
+ typedDataSigner: (typedData: TypedDataDefinition) => Promise<Signature>,
55
61
  ): Promise<SignedTxs> {
56
- const tempSignedTxs = new SignedTxs(txs, Signature.empty());
57
- const hashed = getHashedSignaturePayload(tempSignedTxs, SignatureDomainSeparator.signedTxs);
58
- const signature = await payloadSigner(hashed);
59
- return new SignedTxs(txs, signature);
62
+ const tempSignedTxs = new SignedTxs(txs, Signature.empty(), signatureContext);
63
+ const typedData = getCoordinationSignatureTypedData(tempSignedTxs);
64
+ const signature = await typedDataSigner(typedData);
65
+ return new SignedTxs(txs, signature, signatureContext);
60
66
  }
61
67
 
62
68
  toBuffer(): Buffer {
63
- return serializeToBuffer([this.txs.length, this.txs, this.signature]);
69
+ return serializeToBuffer([
70
+ this.txs.length,
71
+ this.txs,
72
+ this.signature,
73
+ serializeCoordinationSignatureContext(this.signatureContext),
74
+ ]);
64
75
  }
65
76
 
66
77
  static fromBuffer(buf: Buffer | BufferReader): SignedTxs {
@@ -71,18 +82,25 @@ export class SignedTxs {
71
82
  }
72
83
  const txs = reader.readArray(txCount, Tx);
73
84
  const signature = reader.readObject(Signature);
74
- return new SignedTxs(txs, signature);
85
+ const signatureContext = readCoordinationSignatureContext(reader);
86
+ return new SignedTxs(txs, signature, signatureContext);
75
87
  }
76
88
 
77
89
  getSize(): number {
78
- return 4 /* txs.length */ + this.txs.reduce((acc, tx) => acc + tx.getSize(), 0) + this.signature.getSize();
90
+ return (
91
+ 4 /* txs.length */ +
92
+ this.txs.reduce((acc, tx) => acc + tx.getSize(), 0) +
93
+ this.signature.getSize() +
94
+ 4 /* chainId */ +
95
+ 20 /* rollupAddress */
96
+ );
79
97
  }
80
98
 
81
99
  static empty(): SignedTxs {
82
- return new SignedTxs([], Signature.empty());
100
+ return new SignedTxs([], Signature.empty(), EMPTY_COORDINATION_SIGNATURE_CONTEXT);
83
101
  }
84
102
 
85
103
  static random(): SignedTxs {
86
- return new SignedTxs([Tx.random(), Tx.random()], Signature.random());
104
+ return new SignedTxs([Tx.random(), Tx.random()], Signature.random(), EMPTY_COORDINATION_SIGNATURE_CONTEXT);
87
105
  }
88
106
  }
@@ -10,9 +10,11 @@ export class ParityBasePrivateInputs {
10
10
  public readonly msgs: Tuple<Fr, typeof NUM_MSGS_PER_BASE_PARITY>,
11
11
  /** Root of the VK tree */
12
12
  public readonly vkTreeRoot: Fr,
13
+ /** Prover identity committed to by the circuit, for sybil protection. */
14
+ public readonly proverId: Fr,
13
15
  ) {}
14
16
 
15
- public static fromSlice(array: Fr[], index: number, vkTreeRoot: Fr): ParityBasePrivateInputs {
17
+ public static fromSlice(array: Fr[], index: number, vkTreeRoot: Fr, proverId: Fr): ParityBasePrivateInputs {
16
18
  // Can't use Tuple<Fr, typeof NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP> due to length
17
19
  if (array.length !== NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) {
18
20
  throw new Error(
@@ -22,12 +24,12 @@ export class ParityBasePrivateInputs {
22
24
  const start = index * NUM_MSGS_PER_BASE_PARITY;
23
25
  const end = start + NUM_MSGS_PER_BASE_PARITY;
24
26
  const msgs = array.slice(start, end);
25
- return new ParityBasePrivateInputs(msgs as Tuple<Fr, typeof NUM_MSGS_PER_BASE_PARITY>, vkTreeRoot);
27
+ return new ParityBasePrivateInputs(msgs as Tuple<Fr, typeof NUM_MSGS_PER_BASE_PARITY>, vkTreeRoot, proverId);
26
28
  }
27
29
 
28
30
  /** Serializes the inputs to a buffer. */
29
31
  toBuffer() {
30
- return serializeToBuffer(this.msgs, this.vkTreeRoot);
32
+ return serializeToBuffer(this.msgs, this.vkTreeRoot, this.proverId);
31
33
  }
32
34
 
33
35
  /** Serializes the inputs to a hex string. */
@@ -41,7 +43,11 @@ export class ParityBasePrivateInputs {
41
43
  */
42
44
  static fromBuffer(buffer: Buffer | BufferReader) {
43
45
  const reader = BufferReader.asReader(buffer);
44
- return new ParityBasePrivateInputs(reader.readArray(NUM_MSGS_PER_BASE_PARITY, Fr), Fr.fromBuffer(reader));
46
+ return new ParityBasePrivateInputs(
47
+ reader.readArray(NUM_MSGS_PER_BASE_PARITY, Fr),
48
+ Fr.fromBuffer(reader),
49
+ Fr.fromBuffer(reader),
50
+ );
45
51
  }
46
52
 
47
53
  /**
@@ -12,6 +12,8 @@ export class ParityPublicInputs {
12
12
  public convertedRoot: Fr,
13
13
  /** Root of the VK tree */
14
14
  public vkTreeRoot: Fr,
15
+ /** Prover identity committed to by the circuit, for sybil protection. */
16
+ public proverId: Fr,
15
17
  ) {
16
18
  if (shaRoot.toBuffer()[0] != 0) {
17
19
  throw new Error(`shaRoot buffer must be 31 bytes. Got 32 bytes`);
@@ -54,7 +56,7 @@ export class ParityPublicInputs {
54
56
  * @returns The instance fields.
55
57
  */
56
58
  static getFields(fields: FieldsOf<ParityPublicInputs>) {
57
- return [fields.shaRoot, fields.convertedRoot, fields.vkTreeRoot] as const;
59
+ return [fields.shaRoot, fields.convertedRoot, fields.vkTreeRoot, fields.proverId] as const;
58
60
  }
59
61
 
60
62
  /**
@@ -64,7 +66,12 @@ export class ParityPublicInputs {
64
66
  */
65
67
  static fromBuffer(buffer: Buffer | BufferReader) {
66
68
  const reader = BufferReader.asReader(buffer);
67
- return new ParityPublicInputs(reader.readObject(Fr), reader.readObject(Fr), Fr.fromBuffer(reader));
69
+ return new ParityPublicInputs(
70
+ reader.readObject(Fr),
71
+ reader.readObject(Fr),
72
+ Fr.fromBuffer(reader),
73
+ Fr.fromBuffer(reader),
74
+ );
68
75
  }
69
76
 
70
77
  /**
@@ -1,5 +1,7 @@
1
+ import { DomainSeparator } from '@aztec/constants';
2
+ import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
1
3
  import { Fr } from '@aztec/foundation/curves/bn254';
2
- import { computeUnbalancedPoseidonRoot } from '@aztec/foundation/trees';
4
+ import { computeUnbalancedMerkleTreeRootAsync } from '@aztec/foundation/trees';
3
5
 
4
6
  import type { BlockHeader } from '../tx/block_header.js';
5
7
 
@@ -7,6 +9,13 @@ export async function computeBlockHeadersHash(blockHeaders: BlockHeader[]): Prom
7
9
  const blockHeaderHashes = await Promise.all(blockHeaders.map(header => header.hash()));
8
10
  // Must match the implementation in merge_block_rollups.nr, with the **unbalanced** rollup structure
9
11
  // (see validate_consecutive_block_rollups.nr > assert_rollups_filled_greedily.nr).
10
- const blockHeadersHash = await computeUnbalancedPoseidonRoot(blockHeaderHashes.map(hash => hash.toBuffer()));
12
+ const blockHeadersHasher = async (left: Uint8Array, right: Uint8Array) =>
13
+ (
14
+ await poseidon2HashWithSeparator([Buffer.from(left), Buffer.from(right)], DomainSeparator.BLOCK_HEADERS_HASH)
15
+ ).toBuffer() as Buffer<ArrayBuffer>;
16
+ const blockHeadersHash = await computeUnbalancedMerkleTreeRootAsync(
17
+ blockHeaderHashes.map(hash => hash.toBuffer()),
18
+ blockHeadersHasher,
19
+ );
11
20
  return Fr.fromBuffer(blockHeadersHash);
12
21
  }
@@ -9,7 +9,6 @@ import {
9
9
  AVM_V2_PROOF_LENGTH_IN_FIELDS_PADDED,
10
10
  CHONK_PROOF_LENGTH,
11
11
  CONTRACT_CLASS_LOG_SIZE_IN_FIELDS,
12
- DomainSeparator,
13
12
  L1_TO_L2_MSG_SUBTREE_ROOT_SIBLING_PATH_LENGTH,
14
13
  MAX_CHECKPOINTS_PER_EPOCH,
15
14
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
@@ -46,7 +45,6 @@ import { type FieldsOf, makeTuple } from '@aztec/foundation/array';
46
45
  import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
47
46
  import { compact } from '@aztec/foundation/collection';
48
47
  import { Grumpkin } from '@aztec/foundation/crypto/grumpkin';
49
- import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
50
48
  import { SchnorrSignature } from '@aztec/foundation/crypto/schnorr';
51
49
  import { sha256 } from '@aztec/foundation/crypto/sha256';
52
50
  import { Fq, Fr } from '@aztec/foundation/curves/bn254';
@@ -95,6 +93,7 @@ import {
95
93
  type PrivateFunction,
96
94
  SerializableContractInstance,
97
95
  computeContractClassId,
96
+ computePartialAddress,
98
97
  computePublicBytecodeCommitment,
99
98
  } from '../contract/index.js';
100
99
  import { Gas, GasFees, GasSettings } from '../gas/index.js';
@@ -176,7 +175,7 @@ import { TxHash } from '../tx/tx_hash.js';
176
175
  import { TxRequest } from '../tx/tx_request.js';
177
176
  import { Vector } from '../types/index.js';
178
177
  import { VkData } from '../vks/index.js';
179
- import { VerificationKey, VerificationKeyAsFields, VerificationKeyData } from '../vks/verification_key.js';
178
+ import { VerificationKeyAsFields, VerificationKeyData } from '../vks/verification_key.js';
180
179
 
181
180
  /**
182
181
  * Creates an arbitrary side effect object with the given seed.
@@ -573,14 +572,6 @@ export function makeVerificationKeyAsFields(size: number): VerificationKeyAsFiel
573
572
  return VerificationKeyAsFields.makeFake(size);
574
573
  }
575
574
 
576
- /**
577
- * Creates arbitrary/mocked verification key.
578
- * @returns A verification key object
579
- */
580
- export function makeVerificationKey(): VerificationKey {
581
- return VerificationKey.makeFake();
582
- }
583
-
584
575
  /**
585
576
  * Creates an arbitrary point in a curve.
586
577
  * @param seed - Seed to generate the point values.
@@ -863,11 +854,16 @@ export function makeParityPublicInputs(seed = 0): ParityPublicInputs {
863
854
  new Fr(BigInt(seed + 0x200)),
864
855
  new Fr(BigInt(seed + 0x300)),
865
856
  new Fr(BigInt(seed + 0x400)),
857
+ new Fr(BigInt(seed + 0x500)),
866
858
  );
867
859
  }
868
860
 
869
861
  export function makeParityBasePrivateInputs(seed = 0): ParityBasePrivateInputs {
870
- return new ParityBasePrivateInputs(makeTuple(NUM_MSGS_PER_BASE_PARITY, fr, seed + 0x3000), new Fr(seed + 0x4000));
862
+ return new ParityBasePrivateInputs(
863
+ makeTuple(NUM_MSGS_PER_BASE_PARITY, fr, seed + 0x3000),
864
+ new Fr(seed + 0x4000),
865
+ new Fr(seed + 0x5000),
866
+ );
871
867
  }
872
868
 
873
869
  export function makeParityRootPrivateInputs(seed = 0) {
@@ -1253,14 +1249,12 @@ export async function makeContractInstanceFromClassId(
1253
1249
  const deployer = overrides?.deployer ?? new AztecAddress(new Fr(seed + 2));
1254
1250
  const publicKeys = overrides?.publicKeys ?? (await makePublicKeys(seed + 3));
1255
1251
 
1256
- const saltedInitializationHash = await poseidon2HashWithSeparator(
1257
- [salt, initializationHash, deployer],
1258
- DomainSeparator.PARTIAL_ADDRESS,
1259
- );
1260
- const partialAddress = await poseidon2HashWithSeparator(
1261
- [classId, saltedInitializationHash],
1262
- DomainSeparator.PARTIAL_ADDRESS,
1263
- );
1252
+ const partialAddress = await computePartialAddress({
1253
+ originalContractClassId: classId,
1254
+ salt,
1255
+ initializationHash,
1256
+ deployer,
1257
+ });
1264
1258
  const address = await computeAddress(publicKeys, partialAddress);
1265
1259
  return new SerializableContractInstance({
1266
1260
  version: 1,