@aztec/foundation 0.0.1-commit.9117c5f5a → 0.0.1-commit.936cb2cae
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/branded-types/slot.d.ts +4 -1
- package/dest/branded-types/slot.d.ts.map +1 -1
- package/dest/branded-types/slot.js +3 -0
- package/dest/buffer/index.d.ts +2 -1
- package/dest/buffer/index.d.ts.map +1 -1
- package/dest/buffer/index.js +1 -0
- package/dest/buffer/utils.d.ts +3 -0
- package/dest/buffer/utils.d.ts.map +1 -0
- package/dest/buffer/utils.js +7 -0
- package/dest/collection/array.d.ts +3 -1
- package/dest/collection/array.d.ts.map +1 -1
- package/dest/collection/array.js +15 -0
- package/dest/collection/index.d.ts +2 -1
- package/dest/collection/index.d.ts.map +1 -1
- package/dest/collection/index.js +1 -0
- package/dest/collection/lru_set.d.ts +35 -0
- package/dest/collection/lru_set.d.ts.map +1 -0
- package/dest/collection/lru_set.js +95 -0
- package/dest/config/env_var.d.ts +2 -2
- package/dest/config/env_var.d.ts.map +1 -1
- package/dest/config/index.d.ts +1 -1
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +15 -0
- package/dest/config/network_config.d.ts +19 -1
- package/dest/config/network_config.d.ts.map +1 -1
- package/dest/config/network_config.js +4 -1
- package/dest/crypto/poseidon/index.d.ts +1 -1
- package/dest/crypto/poseidon/index.d.ts.map +1 -1
- package/dest/crypto/poseidon/index.js +40 -33
- package/dest/crypto/secp256k1-signer/utils.d.ts +12 -1
- package/dest/crypto/secp256k1-signer/utils.d.ts.map +1 -1
- package/dest/crypto/secp256k1-signer/utils.js +26 -0
- package/dest/eth-signature/eth_signature.d.ts +2 -1
- package/dest/eth-signature/eth_signature.d.ts.map +1 -1
- package/dest/eth-signature/eth_signature.js +7 -2
- package/dest/fifo/fifo_frame_reader.d.ts +41 -0
- package/dest/fifo/fifo_frame_reader.d.ts.map +1 -0
- package/dest/fifo/fifo_frame_reader.js +74 -0
- package/dest/fifo/index.d.ts +2 -0
- package/dest/fifo/index.d.ts.map +1 -0
- package/dest/fifo/index.js +1 -0
- package/dest/log/bigint-utils.d.ts +1 -1
- package/dest/log/bigint-utils.d.ts.map +1 -1
- package/dest/log/bigint-utils.js +3 -0
- package/dest/schemas/api.d.ts +2 -2
- package/dest/schemas/api.d.ts.map +1 -1
- package/dest/trees/indexed_merkle_tree_calculator.d.ts +1 -1
- package/dest/trees/indexed_merkle_tree_calculator.d.ts.map +1 -1
- package/dest/trees/indexed_merkle_tree_calculator.js +5 -1
- package/package.json +3 -2
- package/src/branded-types/slot.ts +5 -0
- package/src/buffer/index.ts +1 -0
- package/src/buffer/utils.ts +8 -0
- package/src/collection/array.ts +14 -0
- package/src/collection/index.ts +1 -0
- package/src/collection/lru_set.ts +115 -0
- package/src/config/env_var.ts +21 -5
- package/src/config/index.ts +15 -0
- package/src/config/network_config.ts +3 -0
- package/src/crypto/poseidon/index.ts +42 -34
- package/src/crypto/secp256k1-signer/utils.ts +32 -0
- package/src/eth-signature/eth_signature.ts +7 -1
- package/src/fifo/fifo_frame_reader.ts +98 -0
- package/src/fifo/index.ts +1 -0
- package/src/log/bigint-utils.ts +3 -0
- package/src/schemas/api.ts +4 -1
- package/src/trees/indexed_merkle_tree_calculator.ts +5 -1
- package/dest/crypto/serialize.d.ts +0 -51
- package/dest/crypto/serialize.d.ts.map +0 -1
- package/dest/crypto/serialize.js +0 -68
- package/src/crypto/serialize.ts +0 -85
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/** Node in a doubly-linked list used by {@link LruSet}. */
|
|
2
|
+
type LruNode<T> = {
|
|
3
|
+
value: T;
|
|
4
|
+
prev: LruNode<T> | undefined;
|
|
5
|
+
next: LruNode<T> | undefined;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A bounded set with Least Recently Used (LRU) eviction.
|
|
10
|
+
* Both {@link has} and {@link add} count as an access and refresh the entry's
|
|
11
|
+
* recency, so items that are actively checked stay in the set longest.
|
|
12
|
+
*
|
|
13
|
+
* Uses a doubly-linked list for O(1) ordering and a Map for O(1) lookup.
|
|
14
|
+
* Head = least recent, tail = most recent.
|
|
15
|
+
*/
|
|
16
|
+
export class LruSet<T> {
|
|
17
|
+
/** Map from value to its linked-list node for O(1) lookup. */
|
|
18
|
+
private readonly map = new Map<T, LruNode<T>>();
|
|
19
|
+
private head: LruNode<T> | undefined;
|
|
20
|
+
private tail: LruNode<T> | undefined;
|
|
21
|
+
|
|
22
|
+
constructor(private readonly maxSize: number) {
|
|
23
|
+
if (maxSize < 1) {
|
|
24
|
+
throw new Error('LruSet maxSize must be at least 1');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Number of entries in the set. */
|
|
29
|
+
get size(): number {
|
|
30
|
+
return this.map.size;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns true if the item is in the set.
|
|
35
|
+
* Refreshes the item's recency so it becomes the most recently used.
|
|
36
|
+
*/
|
|
37
|
+
has(item: T): boolean {
|
|
38
|
+
const node = this.map.get(item);
|
|
39
|
+
if (!node) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
this.moveToTail(node);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Adds an item to the set. If the item already exists, refreshes its recency.
|
|
48
|
+
* If the set is at capacity, evicts the least recently used item.
|
|
49
|
+
*/
|
|
50
|
+
add(item: T): void {
|
|
51
|
+
const existing = this.map.get(item);
|
|
52
|
+
if (existing) {
|
|
53
|
+
this.moveToTail(existing);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.map.size >= this.maxSize) {
|
|
58
|
+
this.evictHead();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const node: LruNode<T> = { value: item, prev: this.tail, next: undefined };
|
|
62
|
+
if (this.tail) {
|
|
63
|
+
this.tail.next = node;
|
|
64
|
+
} else {
|
|
65
|
+
this.head = node;
|
|
66
|
+
}
|
|
67
|
+
this.tail = node;
|
|
68
|
+
this.map.set(item, node);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Removes all entries from the set. */
|
|
72
|
+
clear(): void {
|
|
73
|
+
this.map.clear();
|
|
74
|
+
this.head = undefined;
|
|
75
|
+
this.tail = undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Unlinks a node from its current position and relinks it at the tail. */
|
|
79
|
+
private moveToTail(node: LruNode<T>): void {
|
|
80
|
+
if (node === this.tail) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Unlink
|
|
85
|
+
if (node.prev) {
|
|
86
|
+
node.prev.next = node.next;
|
|
87
|
+
} else {
|
|
88
|
+
this.head = node.next;
|
|
89
|
+
}
|
|
90
|
+
if (node.next) {
|
|
91
|
+
node.next.prev = node.prev;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Relink at tail
|
|
95
|
+
node.prev = this.tail;
|
|
96
|
+
node.next = undefined;
|
|
97
|
+
if (this.tail) {
|
|
98
|
+
this.tail.next = node;
|
|
99
|
+
}
|
|
100
|
+
this.tail = node;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Evicts the head (least recently used) node. */
|
|
104
|
+
private evictHead(): void {
|
|
105
|
+
const oldHead = this.head!;
|
|
106
|
+
this.map.delete(oldHead.value);
|
|
107
|
+
|
|
108
|
+
this.head = oldHead.next;
|
|
109
|
+
if (this.head) {
|
|
110
|
+
this.head.prev = undefined;
|
|
111
|
+
} else {
|
|
112
|
+
this.tail = undefined;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
package/src/config/env_var.ts
CHANGED
|
@@ -23,6 +23,8 @@ export type EnvVar =
|
|
|
23
23
|
| 'BB_WORKING_DIRECTORY'
|
|
24
24
|
| 'BB_NUM_IVC_VERIFIERS'
|
|
25
25
|
| 'BB_IVC_CONCURRENCY'
|
|
26
|
+
| 'BB_CHONK_VERIFY_MAX_BATCH'
|
|
27
|
+
| 'BB_CHONK_VERIFY_BATCH_CONCURRENCY'
|
|
26
28
|
| 'BOOTSTRAP_NODES'
|
|
27
29
|
| 'BLOB_ARCHIVE_API_URL'
|
|
28
30
|
| 'BLOB_FILE_STORE_URLS'
|
|
@@ -62,6 +64,7 @@ export type EnvVar =
|
|
|
62
64
|
| 'BLOB_SINK_MAP_SIZE_KB'
|
|
63
65
|
| 'P2P_STORE_MAP_SIZE_KB'
|
|
64
66
|
| 'PROVER_BROKER_STORE_MAP_SIZE_KB'
|
|
67
|
+
| 'SIGNING_PROTECTION_MAP_SIZE_KB'
|
|
65
68
|
| 'WS_DB_MAP_SIZE_KB'
|
|
66
69
|
| 'ARCHIVE_TREE_MAP_SIZE_KB'
|
|
67
70
|
| 'NULLIFIER_TREE_MAP_SIZE_KB'
|
|
@@ -80,6 +83,7 @@ export type EnvVar =
|
|
|
80
83
|
| 'KEY_STORE_DIRECTORY'
|
|
81
84
|
| 'L1_CHAIN_ID'
|
|
82
85
|
| 'L1_CONSENSUS_HOST_URLS'
|
|
86
|
+
| 'ETHEREUM_HTTP_TIMEOUT_MS'
|
|
83
87
|
| 'L1_CONSENSUS_HOST_API_KEYS'
|
|
84
88
|
| 'L1_CONSENSUS_HOST_API_KEY_HEADERS'
|
|
85
89
|
| 'L1_TX_FAILED_STORE'
|
|
@@ -129,6 +133,7 @@ export type EnvVar =
|
|
|
129
133
|
| 'P2P_L2_QUEUE_SIZE'
|
|
130
134
|
| 'P2P_MAX_PEERS'
|
|
131
135
|
| 'P2P_PEER_CHECK_INTERVAL_MS'
|
|
136
|
+
| 'P2P_PEER_FAILED_BAN_TIME_MS'
|
|
132
137
|
| 'P2P_PEER_PENALTY_VALUES'
|
|
133
138
|
| 'P2P_QUERY_FOR_IP'
|
|
134
139
|
| 'P2P_REQRESP_INDIVIDUAL_REQUEST_TIMEOUT_MS'
|
|
@@ -152,6 +157,7 @@ export type EnvVar =
|
|
|
152
157
|
| 'P2P_DROP_TX_CHANCE'
|
|
153
158
|
| 'P2P_TX_POOL_DELETE_TXS_AFTER_REORG'
|
|
154
159
|
| 'P2P_MIN_TX_POOL_AGE_MS'
|
|
160
|
+
| 'P2P_RPC_PRICE_BUMP_PERCENTAGE'
|
|
155
161
|
| 'DEBUG_P2P_INSTRUMENT_MESSAGES'
|
|
156
162
|
| 'PEER_ID_PRIVATE_KEY'
|
|
157
163
|
| 'PEER_ID_PRIVATE_KEY_PATH'
|
|
@@ -167,6 +173,7 @@ export type EnvVar =
|
|
|
167
173
|
| 'PROVER_BROKER_MAX_EPOCHS_TO_KEEP_RESULTS_FOR'
|
|
168
174
|
| 'PROVER_BROKER_DEBUG_REPLAY_ENABLED'
|
|
169
175
|
| 'PROVER_CANCEL_JOBS_ON_STOP'
|
|
176
|
+
| 'PROVER_ENQUEUE_CONCURRENCY'
|
|
170
177
|
| 'PROVER_COORDINATION_NODE_URLS'
|
|
171
178
|
| 'PROVER_PROOF_STORE'
|
|
172
179
|
| 'PROVER_FAILED_PROOF_STORE'
|
|
@@ -200,17 +207,22 @@ export type EnvVar =
|
|
|
200
207
|
| 'SENTINEL_ENABLED'
|
|
201
208
|
| 'SENTINEL_HISTORY_LENGTH_IN_EPOCHS'
|
|
202
209
|
| 'SENTINEL_HISTORIC_PROVEN_PERFORMANCE_LENGTH_IN_EPOCHS'
|
|
203
|
-
| '
|
|
210
|
+
| 'SEQ_ENABLE_PROPOSER_PIPELINING'
|
|
204
211
|
| 'SEQ_MAX_TX_PER_BLOCK'
|
|
212
|
+
| 'SEQ_MAX_TX_PER_CHECKPOINT'
|
|
205
213
|
| 'SEQ_MIN_TX_PER_BLOCK'
|
|
206
214
|
| 'SEQ_PUBLISH_TXS_WITH_PROPOSALS'
|
|
207
215
|
| 'SEQ_MAX_DA_BLOCK_GAS'
|
|
208
216
|
| 'SEQ_MAX_L2_BLOCK_GAS'
|
|
217
|
+
| 'SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER'
|
|
218
|
+
| 'SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET'
|
|
209
219
|
| 'SEQ_PUBLISHER_PRIVATE_KEY'
|
|
210
220
|
| 'SEQ_PUBLISHER_PRIVATE_KEYS'
|
|
211
221
|
| 'SEQ_PUBLISHER_ADDRESSES'
|
|
212
222
|
| 'SEQ_PUBLISHER_ALLOW_INVALID_STATES'
|
|
213
223
|
| 'SEQ_PUBLISHER_FORWARDER_ADDRESS'
|
|
224
|
+
| 'PUBLISHER_FUNDING_THRESHOLD'
|
|
225
|
+
| 'PUBLISHER_FUNDING_AMOUNT'
|
|
214
226
|
| 'SEQ_POLLING_INTERVAL_MS'
|
|
215
227
|
| 'SEQ_ENFORCE_TIME_TABLE'
|
|
216
228
|
| 'SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT'
|
|
@@ -247,6 +259,7 @@ export type EnvVar =
|
|
|
247
259
|
| 'TELEMETRY'
|
|
248
260
|
| 'TEST_ACCOUNTS'
|
|
249
261
|
| 'SPONSORED_FPC'
|
|
262
|
+
| 'PREFUND_ADDRESSES'
|
|
250
263
|
| 'TX_COLLECTION_FAST_NODES_TIMEOUT_BEFORE_REQ_RESP_MS'
|
|
251
264
|
| 'TX_COLLECTION_SLOW_NODES_INTERVAL_MS'
|
|
252
265
|
| 'TX_COLLECTION_SLOW_REQ_RESP_INTERVAL_MS'
|
|
@@ -276,9 +289,12 @@ export type EnvVar =
|
|
|
276
289
|
| 'TRANSACTIONS_DISABLED'
|
|
277
290
|
| 'VALIDATOR_ATTESTATIONS_POLLING_INTERVAL_MS'
|
|
278
291
|
| 'VALIDATOR_DISABLED'
|
|
292
|
+
| 'VALIDATOR_MAX_DA_BLOCK_GAS'
|
|
293
|
+
| 'VALIDATOR_MAX_L2_BLOCK_GAS'
|
|
294
|
+
| 'VALIDATOR_MAX_TX_PER_BLOCK'
|
|
295
|
+
| 'VALIDATOR_MAX_TX_PER_CHECKPOINT'
|
|
279
296
|
| 'VALIDATOR_PRIVATE_KEYS'
|
|
280
297
|
| 'VALIDATOR_PRIVATE_KEY'
|
|
281
|
-
| 'VALIDATOR_REEXECUTE'
|
|
282
298
|
| 'VALIDATOR_ADDRESSES'
|
|
283
299
|
| 'ROLLUP_VERSION'
|
|
284
300
|
| 'WS_BLOCK_CHECK_INTERVAL_MS'
|
|
@@ -340,12 +356,12 @@ export type EnvVar =
|
|
|
340
356
|
| 'K8S_POD_NAME'
|
|
341
357
|
| 'K8S_POD_UID'
|
|
342
358
|
| 'K8S_NAMESPACE_NAME'
|
|
343
|
-
| '
|
|
344
|
-
| 'AUTO_UPDATE'
|
|
345
|
-
| 'AUTO_UPDATE_URL'
|
|
359
|
+
| 'ENABLE_VERSION_CHECK'
|
|
346
360
|
| 'WEB3_SIGNER_URL'
|
|
347
361
|
| 'SKIP_ARCHIVER_INITIAL_SYNC'
|
|
348
362
|
| 'BLOB_ALLOW_EMPTY_SOURCES'
|
|
363
|
+
| 'BLOB_PREFER_FILESTORES'
|
|
364
|
+
| 'BLOB_FILE_STORE_TIMEOUT_MS'
|
|
349
365
|
| 'FISHERMAN_MODE'
|
|
350
366
|
| 'MAX_ALLOWED_ETH_CLIENT_DRIFT_SECONDS'
|
|
351
367
|
| 'LEGACY_BLS_CLI'
|
package/src/config/index.ts
CHANGED
|
@@ -177,6 +177,21 @@ export function bigintConfigHelper(defaultVal?: bigint): Pick<ConfigMapping, 'pa
|
|
|
177
177
|
if (val === '') {
|
|
178
178
|
return defaultVal;
|
|
179
179
|
}
|
|
180
|
+
// Handle scientific notation (e.g. "1e+23", "2E23") which BigInt() doesn't accept directly.
|
|
181
|
+
// We parse it losslessly using bigint arithmetic instead of going through float64.
|
|
182
|
+
if (/[eE]/.test(val)) {
|
|
183
|
+
const match = val.match(/^(-?\d+(?:\.(\d+))?)[eE]([+-]?\d+)$/);
|
|
184
|
+
if (!match) {
|
|
185
|
+
throw new Error(`Cannot convert '${val}' to a BigInt`);
|
|
186
|
+
}
|
|
187
|
+
const digits = match[1].replace('.', '');
|
|
188
|
+
const decimalPlaces = match[2]?.length ?? 0;
|
|
189
|
+
const exponent = parseInt(match[3], 10) - decimalPlaces;
|
|
190
|
+
if (exponent < 0) {
|
|
191
|
+
throw new Error(`Cannot convert '${val}' to a BigInt: result is not an integer`);
|
|
192
|
+
}
|
|
193
|
+
return BigInt(digits) * 10n ** BigInt(exponent);
|
|
194
|
+
}
|
|
180
195
|
return BigInt(val);
|
|
181
196
|
},
|
|
182
197
|
defaultValue: defaultVal,
|
|
@@ -5,10 +5,13 @@ export const NetworkConfigSchema = z
|
|
|
5
5
|
bootnodes: z.array(z.string()),
|
|
6
6
|
snapshots: z.array(z.string()),
|
|
7
7
|
blobFileStoreUrls: z.array(z.string()).optional(),
|
|
8
|
+
txCollectionFileStoreUrls: z.array(z.string()).optional(),
|
|
8
9
|
registryAddress: z.string(),
|
|
9
10
|
feeAssetHandlerAddress: z.string().optional(),
|
|
10
11
|
l1ChainId: z.number(),
|
|
11
12
|
blockDurationMs: z.number().positive().optional(),
|
|
13
|
+
txPublicSetupAllowListExtend: z.string().optional(),
|
|
14
|
+
nodeVersion: z.string().optional(),
|
|
12
15
|
})
|
|
13
16
|
.passthrough(); // Allow additional unknown fields to pass through
|
|
14
17
|
|
|
@@ -1,21 +1,35 @@
|
|
|
1
|
-
import { Barretenberg } from '@aztec/bb.js';
|
|
1
|
+
import { Barretenberg, BarretenbergSync } from '@aztec/bb.js';
|
|
2
2
|
|
|
3
3
|
import { Fr } from '../../curves/bn254/field.js';
|
|
4
4
|
import { type Fieldable, serializeToFields } from '../../serialize/serialize.js';
|
|
5
5
|
|
|
6
|
+
const IS_BROWSER = typeof self !== 'undefined';
|
|
7
|
+
|
|
8
|
+
async function poseidon2HashFields(inputFields: Fr[]): Promise<Fr> {
|
|
9
|
+
if (IS_BROWSER) {
|
|
10
|
+
await BarretenbergSync.initSingleton();
|
|
11
|
+
const api = BarretenbergSync.getSingleton();
|
|
12
|
+
const response = api.poseidon2Hash({
|
|
13
|
+
inputs: inputFields.map(i => i.toBuffer()),
|
|
14
|
+
});
|
|
15
|
+
return Fr.fromBuffer(Buffer.from(response.hash));
|
|
16
|
+
} else {
|
|
17
|
+
await Barretenberg.initSingleton();
|
|
18
|
+
const api = Barretenberg.getSingleton();
|
|
19
|
+
const response = await api.poseidon2Hash({
|
|
20
|
+
inputs: inputFields.map(i => i.toBuffer()),
|
|
21
|
+
});
|
|
22
|
+
return Fr.fromBuffer(Buffer.from(response.hash));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
6
26
|
/**
|
|
7
27
|
* Create a poseidon hash (field) from an array of input fields.
|
|
8
28
|
* @param input - The input fields to hash.
|
|
9
29
|
* @returns The poseidon hash.
|
|
10
30
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
await Barretenberg.initSingleton();
|
|
14
|
-
const api = Barretenberg.getSingleton();
|
|
15
|
-
const response = await api.poseidon2Hash({
|
|
16
|
-
inputs: inputFields.map(i => i.toBuffer()),
|
|
17
|
-
});
|
|
18
|
-
return Fr.fromBuffer(Buffer.from(response.hash));
|
|
31
|
+
export function poseidon2Hash(input: Fieldable[]): Promise<Fr> {
|
|
32
|
+
return poseidon2HashFields(serializeToFields(input));
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
/**
|
|
@@ -24,15 +38,10 @@ export async function poseidon2Hash(input: Fieldable[]): Promise<Fr> {
|
|
|
24
38
|
* @param separator - The domain separator.
|
|
25
39
|
* @returns The poseidon hash.
|
|
26
40
|
*/
|
|
27
|
-
export
|
|
41
|
+
export function poseidon2HashWithSeparator(input: Fieldable[], separator: number): Promise<Fr> {
|
|
28
42
|
const inputFields = serializeToFields(input);
|
|
29
43
|
inputFields.unshift(new Fr(separator));
|
|
30
|
-
|
|
31
|
-
const api = Barretenberg.getSingleton();
|
|
32
|
-
const response = await api.poseidon2Hash({
|
|
33
|
-
inputs: inputFields.map(i => i.toBuffer()),
|
|
34
|
-
});
|
|
35
|
-
return Fr.fromBuffer(Buffer.from(response.hash));
|
|
44
|
+
return poseidon2HashFields(inputFields);
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
/**
|
|
@@ -42,19 +51,24 @@ export async function poseidon2HashWithSeparator(input: Fieldable[], separator:
|
|
|
42
51
|
*/
|
|
43
52
|
export async function poseidon2Permutation(input: Fieldable[]): Promise<Fr[]> {
|
|
44
53
|
const inputFields = serializeToFields(input);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
if (IS_BROWSER) {
|
|
55
|
+
await BarretenbergSync.initSingleton();
|
|
56
|
+
const api = BarretenbergSync.getSingleton();
|
|
57
|
+
const response = api.poseidon2Permutation({
|
|
58
|
+
inputs: inputFields.map(i => i.toBuffer()),
|
|
59
|
+
});
|
|
60
|
+
return response.outputs.map(o => Fr.fromBuffer(Buffer.from(o)));
|
|
61
|
+
} else {
|
|
62
|
+
await Barretenberg.initSingleton();
|
|
63
|
+
const api = Barretenberg.getSingleton();
|
|
64
|
+
const response = await api.poseidon2Permutation({
|
|
65
|
+
inputs: inputFields.map(i => i.toBuffer()),
|
|
66
|
+
});
|
|
67
|
+
return response.outputs.map(o => Fr.fromBuffer(Buffer.from(o)));
|
|
68
|
+
}
|
|
55
69
|
}
|
|
56
70
|
|
|
57
|
-
export
|
|
71
|
+
export function poseidon2HashBytes(input: Buffer): Promise<Fr> {
|
|
58
72
|
const inputFields = [];
|
|
59
73
|
for (let i = 0; i < input.length; i += 31) {
|
|
60
74
|
const fieldBytes = Buffer.alloc(32, 0);
|
|
@@ -65,11 +79,5 @@ export async function poseidon2HashBytes(input: Buffer): Promise<Fr> {
|
|
|
65
79
|
inputFields.push(Fr.fromBuffer(fieldBytes));
|
|
66
80
|
}
|
|
67
81
|
|
|
68
|
-
|
|
69
|
-
const api = Barretenberg.getSingleton();
|
|
70
|
-
const response = await api.poseidon2Hash({
|
|
71
|
-
inputs: inputFields.map(i => i.toBuffer()),
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return Fr.fromBuffer(Buffer.from(response.hash));
|
|
82
|
+
return poseidon2HashFields(inputFields);
|
|
75
83
|
}
|
|
@@ -210,3 +210,35 @@ export function recoverPublicKey(hash: Buffer32, signature: Signature, opts: Rec
|
|
|
210
210
|
const publicKey = sig.recoverPublicKey(hash.buffer).toHex(false);
|
|
211
211
|
return Buffer.from(publicKey, 'hex');
|
|
212
212
|
}
|
|
213
|
+
|
|
214
|
+
/** Arbitrary hash used for testing signature recoverability. */
|
|
215
|
+
const PROBE_HASH = Buffer32.fromBuffer(keccak256(Buffer.from('signature-recoverability-probe')));
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Generates a random valid ECDSA signature that is recoverable to some address.
|
|
219
|
+
* Since Signature.random() produces real signatures via secp256k1 signing, the result is always
|
|
220
|
+
* recoverable, but we verify defensively by checking tryRecoverAddress.
|
|
221
|
+
*/
|
|
222
|
+
export function generateRecoverableSignature(): Signature {
|
|
223
|
+
for (let i = 0; i < 100; i++) {
|
|
224
|
+
const sig = Signature.random();
|
|
225
|
+
if (tryRecoverAddress(PROBE_HASH, sig) !== undefined) {
|
|
226
|
+
return sig;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
throw new Secp256k1Error('Failed to generate a recoverable signature after 100 attempts');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Generates a random signature where ECDSA address recovery fails.
|
|
234
|
+
* Uses random r/s values (not from real signing) so that r is unlikely to be a valid secp256k1 x-coordinate.
|
|
235
|
+
*/
|
|
236
|
+
export function generateUnrecoverableSignature(): Signature {
|
|
237
|
+
for (let i = 0; i < 100; i++) {
|
|
238
|
+
const sig = new Signature(Buffer32.random(), Buffer32.random(), 27);
|
|
239
|
+
if (tryRecoverAddress(PROBE_HASH, sig) === undefined) {
|
|
240
|
+
return sig;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
throw new Secp256k1Error('Failed to generate an unrecoverable signature after 100 attempts');
|
|
244
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
2
2
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
3
3
|
|
|
4
|
+
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
|
|
7
|
+
import { randomBytes } from '../crypto/random/index.js';
|
|
6
8
|
import { hasHexPrefix, hexToBuffer } from '../string/index.js';
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -77,8 +79,12 @@ export class Signature {
|
|
|
77
79
|
return new Signature(Buffer32.fromBuffer(hexToBuffer(sig.r)), Buffer32.fromBuffer(hexToBuffer(sig.s)), sig.yParity);
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
/** Generates a random valid ECDSA signature with a low s-value by signing a random message with a random key. */
|
|
80
83
|
static random(): Signature {
|
|
81
|
-
|
|
84
|
+
const privateKey = randomBytes(32);
|
|
85
|
+
const message = randomBytes(32);
|
|
86
|
+
const { r, s, recovery } = secp256k1.sign(message, privateKey);
|
|
87
|
+
return new Signature(Buffer32.fromBigInt(r), Buffer32.fromBigInt(s), recovery ? 28 : 27);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
static empty(): Signature {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import type { Readable } from 'node:stream';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Events emitted by FifoFrameReader.
|
|
7
|
+
*
|
|
8
|
+
* - `frame`: A complete frame payload (without the 4-byte length header).
|
|
9
|
+
* - `error`: An unrecoverable error (invalid frame length, stream error).
|
|
10
|
+
* - `end`: The underlying stream has ended.
|
|
11
|
+
*/
|
|
12
|
+
export interface FifoFrameReaderEvents {
|
|
13
|
+
frame: [payload: Buffer];
|
|
14
|
+
error: [error: Error];
|
|
15
|
+
end: [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Reads length-delimited frames from a readable stream (typically a named FIFO pipe).
|
|
20
|
+
*
|
|
21
|
+
* Wire format: `[4-byte big-endian payload length][payload bytes]`
|
|
22
|
+
*
|
|
23
|
+
* Emits a `frame` event for each complete frame with the raw payload buffer.
|
|
24
|
+
* Callers are responsible for deserializing the payload (e.g., via msgpack).
|
|
25
|
+
*
|
|
26
|
+
* On encountering an invalid payload length (0 or >maxPayloadSize), emits `error`
|
|
27
|
+
* and destroys the stream.
|
|
28
|
+
*/
|
|
29
|
+
export class FifoFrameReader extends EventEmitter<FifoFrameReaderEvents> {
|
|
30
|
+
private stream: Readable | null = null;
|
|
31
|
+
private pendingBuf: Buffer = Buffer.alloc(0);
|
|
32
|
+
private running = false;
|
|
33
|
+
|
|
34
|
+
constructor(private readonly maxPayloadSize = 10 * 1024 * 1024) {
|
|
35
|
+
super();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Open a FIFO at the given path and start reading frames. */
|
|
39
|
+
start(fifoPath: string, highWaterMark = 64 * 1024): void {
|
|
40
|
+
this.startFromStream(fs.createReadStream(fifoPath, { highWaterMark }));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Start reading frames from an existing readable stream. */
|
|
44
|
+
startFromStream(stream: Readable): void {
|
|
45
|
+
if (this.running) {
|
|
46
|
+
throw new Error('FifoFrameReader is already running');
|
|
47
|
+
}
|
|
48
|
+
this.running = true;
|
|
49
|
+
this.pendingBuf = Buffer.alloc(0);
|
|
50
|
+
this.stream = stream;
|
|
51
|
+
|
|
52
|
+
stream.on('data', (chunk: Buffer | string) => {
|
|
53
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
54
|
+
this.pendingBuf = this.pendingBuf.length > 0 ? Buffer.concat([this.pendingBuf, buf]) : buf;
|
|
55
|
+
this.drainFrames();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
stream.on('error', (err: Error) => {
|
|
59
|
+
if (this.running) {
|
|
60
|
+
this.emit('error', err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
stream.on('end', () => {
|
|
65
|
+
this.emit('end');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Stop reading and destroy the underlying stream. */
|
|
70
|
+
stop(): void {
|
|
71
|
+
this.running = false;
|
|
72
|
+
if (this.stream) {
|
|
73
|
+
this.stream.destroy();
|
|
74
|
+
this.stream = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Parse complete frames out of the pending buffer. */
|
|
79
|
+
private drainFrames(): void {
|
|
80
|
+
while (this.pendingBuf.length >= 4) {
|
|
81
|
+
const payloadLen = this.pendingBuf.readUInt32BE(0);
|
|
82
|
+
if (payloadLen === 0 || payloadLen > this.maxPayloadSize) {
|
|
83
|
+
this.emit('error', new Error(`Invalid payload length: ${payloadLen}`));
|
|
84
|
+
this.stop();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const frameLen = 4 + payloadLen;
|
|
89
|
+
if (this.pendingBuf.length < frameLen) {
|
|
90
|
+
break; // Wait for more data
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const payload = this.pendingBuf.subarray(4, frameLen);
|
|
94
|
+
this.pendingBuf = this.pendingBuf.subarray(frameLen);
|
|
95
|
+
this.emit('frame', Buffer.from(payload));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FifoFrameReader } from './fifo_frame_reader.js';
|
package/src/log/bigint-utils.ts
CHANGED
|
@@ -11,6 +11,9 @@ export function convertBigintsToStrings(obj: unknown): unknown {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
if (obj !== null && typeof obj === 'object') {
|
|
14
|
+
if (typeof (obj as any).toJSON === 'function') {
|
|
15
|
+
return convertBigintsToStrings((obj as any).toJSON());
|
|
16
|
+
}
|
|
14
17
|
const result: Record<string, unknown> = {};
|
|
15
18
|
for (const key in obj) {
|
|
16
19
|
result[key] = convertBigintsToStrings((obj as Record<string, unknown>)[key]);
|
package/src/schemas/api.ts
CHANGED
|
@@ -37,7 +37,10 @@ export type ApiSchema = {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
/** Return whether an API schema defines a valid function schema for a given method name. */
|
|
40
|
-
export function schemaHasMethod
|
|
40
|
+
export function schemaHasMethod<T extends ApiSchema>(
|
|
41
|
+
schema: T,
|
|
42
|
+
methodName: string,
|
|
43
|
+
): methodName is Extract<keyof T, string> {
|
|
41
44
|
return (
|
|
42
45
|
typeof methodName === 'string' &&
|
|
43
46
|
Object.hasOwn(schema, methodName) &&
|
|
@@ -40,7 +40,11 @@ export class IndexedMerkleTreeCalculator<T extends IndexedTreeLeafPreimage, N ex
|
|
|
40
40
|
}
|
|
41
41
|
const sorted = values
|
|
42
42
|
.map((v, i) => ({ value: v, index: i }))
|
|
43
|
-
.sort((a, b)
|
|
43
|
+
.sort((a, b): -1 | 0 | 1 => {
|
|
44
|
+
const aBigInt = toBigIntBE(a.value);
|
|
45
|
+
const bBigInt = toBigIntBE(b.value);
|
|
46
|
+
return aBigInt < bBigInt ? 1 : aBigInt > bBigInt ? -1 : 0;
|
|
47
|
+
});
|
|
44
48
|
const indexedLeaves = sorted.map((item, i) => ({
|
|
45
49
|
leaf: this.factory.fromBuffer(
|
|
46
50
|
Buffer.concat([
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Buffer } from 'buffer';
|
|
2
|
-
/**
|
|
3
|
-
* For serializing an array of fixed length buffers.
|
|
4
|
-
* TODO move to foundation pkg.
|
|
5
|
-
* @param arr - Array of bufffers.
|
|
6
|
-
* @returns The serialized buffers.
|
|
7
|
-
*/
|
|
8
|
-
export declare function serializeBufferArrayToVector(arr: Buffer[]): Buffer<ArrayBuffer>;
|
|
9
|
-
/**
|
|
10
|
-
* Helper function for deserializeArrayFromVector.
|
|
11
|
-
*/
|
|
12
|
-
type DeserializeFn<T> = (buf: Buffer, offset: number) => {
|
|
13
|
-
/**
|
|
14
|
-
* The deserialized type.
|
|
15
|
-
*/
|
|
16
|
-
elem: T;
|
|
17
|
-
/**
|
|
18
|
-
* How many bytes to advance by.
|
|
19
|
-
*/
|
|
20
|
-
adv: number;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* For deserializing numbers to 32-bit little-endian form.
|
|
24
|
-
* TODO move to foundation pkg.
|
|
25
|
-
* @param n - The number.
|
|
26
|
-
* @returns The endian-corrected number.
|
|
27
|
-
*/
|
|
28
|
-
export declare function deserializeArrayFromVector<T>(deserialize: DeserializeFn<T>, vector: Buffer, offset?: number): {
|
|
29
|
-
elem: T[];
|
|
30
|
-
adv: number;
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* For serializing numbers to 32 bit little-endian form.
|
|
34
|
-
* TODO move to foundation pkg.
|
|
35
|
-
* @param n - The number.
|
|
36
|
-
* @returns The endian-corrected number.
|
|
37
|
-
*/
|
|
38
|
-
export declare function numToUInt32LE(n: number, bufferSize?: number): Buffer<ArrayBuffer>;
|
|
39
|
-
/**
|
|
40
|
-
* Deserialize the 256-bit number at address `offset`.
|
|
41
|
-
* @param buf - The buffer.
|
|
42
|
-
* @param offset - The address.
|
|
43
|
-
* @returns The derserialized 256-bit field.
|
|
44
|
-
*/
|
|
45
|
-
export declare function deserializeField(buf: Buffer, offset?: number): {
|
|
46
|
-
elem: Buffer<ArrayBuffer>;
|
|
47
|
-
adv: number;
|
|
48
|
-
};
|
|
49
|
-
export declare function concatenateUint8Arrays(arrayOfUint8Arrays: Uint8Array[]): Uint8Array<ArrayBuffer>;
|
|
50
|
-
export {};
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VyaWFsaXplLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY3J5cHRvL3NlcmlhbGl6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRWhDOzs7OztHQUtHO0FBQ0gsd0JBQWdCLDRCQUE0QixDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsdUJBSXpEO0FBRUQ7O0dBRUc7QUFDSCxLQUFLLGFBQWEsQ0FBQyxDQUFDLElBQUksQ0FDdEIsR0FBRyxFQUFFLE1BQU0sRUFDWCxNQUFNLEVBQUUsTUFBTSxLQUNYO0lBQ0g7O09BRUc7SUFDSCxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ1I7O09BRUc7SUFDSCxHQUFHLEVBQUUsTUFBTSxDQUFDO0NBQ2IsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsd0JBQWdCLDBCQUEwQixDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFJOzs7RUFXdEc7QUFFRDs7Ozs7R0FLRztBQUNILHdCQUFnQixhQUFhLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxVQUFVLFNBQUksdUJBSXREO0FBRUQ7Ozs7O0dBS0c7QUFDSCx3QkFBZ0IsZ0JBQWdCLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLFNBQUk7OztFQUd2RDtBQUVELHdCQUFnQixzQkFBc0IsQ0FBQyxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsMkJBU3RFIn0=
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/crypto/serialize.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,uBAIzD;AAED;;GAEG;AACH,KAAK,aAAa,CAAC,CAAC,IAAI,CACtB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,KACX;IACH;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC;IACR;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAWtG;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,SAAI,uBAItD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAI;;;EAGvD;AAED,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,UAAU,EAAE,2BAStE"}
|