@interfold/sdk 0.14.0 → 0.15.0

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/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { PublicClient, WalletClient, Chain, Hash, Abi, Log, Address } from 'viem';
2
- import { C as ContractAddresses, E as E3RequestParams, a as E3, F as FailureReason, b as E3Stage } from './types-Cwx_flfX.js';
3
- export { c as CommitteeSize, v as validateCommitteeSize } from './types-Cwx_flfX.js';
1
+ import { PublicClient, WalletClient, Chain, Hash, Abi, Log, Hex, Address } from 'viem';
2
+ import { C as ContractAddresses, E as E3RequestParams, a as CiphertextOutputReference, b as E3, F as FailureReason, c as E3Stage } from './types-BJe3EYvv.js';
3
+ export { d as CommitteeSize, v as validateCommitteeSize } from './types-BJe3EYvv.js';
4
4
  import { ThresholdBfvParamsPresetName, BfvParams, EncryptedValueAndPublicInputs, VerifiableEncryptionResult } from './crypto/index.js';
5
5
  export { ThresholdBfvParamsPresetNames, computeCiphertextCommitment, computePublicKeyCommitment, encryptNumber, encryptNumberAndGenInputs, encryptNumberAndGenProof, encryptVector, encryptVectorAndGenInputs, encryptVectorAndGenProof, generateProof, generatePublicKey, getThresholdBfvParamsSet } from './crypto/index.js';
6
- import { AllEventTypes, EventCallback, RandomnessProviderEventType, RandomnessProviderEventCallback } from './events/index.js';
6
+ import { AllEventTypes, EventCallback, RandomnessProviderEventType, RandomnessProviderEventCallback, CommitteePublicKeyChunkPublishedData } from './events/index.js';
7
7
  export { CiphernodeAddedData, CiphernodeRemovedData, CiphertextOutputPublishedData, CommitteeFinalizedData, CommitteePublishedData, CommitteeRandomnessRequestedData, CommitteeRequestedData, E3ActivatedData, E3RequestedData, EventFilter, EventListener, EventListenerConfig, EventListenerOptions, InterfoldEvent, InterfoldEventData, InterfoldEventType, PlaintextOutputPublishedData, RandomnessCircuitBreakerTrippedData, RandomnessFulfilledData, RandomnessProviderEvent, RegistryEventData, RegistryEventType, SDKEventEmitter } from './events/index.js';
8
8
  export { ContractClient, ContractClientConfig } from './contracts/index.js';
9
9
  import '@aztec/bb.js';
@@ -31,9 +31,9 @@ declare class InterfoldSDK {
31
31
  /**
32
32
  * Validate serialized BFV public-key bytes before using them for encryption.
33
33
  *
34
- * `CommitteePublished.publicKey` is an untrusted transport value. Consumers
35
- * must compare its semantic BFV commitment with the event's on-chain
36
- * `pkCommitment` before accepting it.
34
+ * A reassembled public key is an untrusted transport value. Consumers must
35
+ * compare its semantic BFV commitment with the on-chain `pkCommitment`
36
+ * before accepting it.
37
37
  */
38
38
  validatePublicKeyCommitment(publicKey: Uint8Array, expectedCommitment: Uint8Array): Promise<boolean>;
39
39
  encryptNumber(data: bigint, publicKey: Uint8Array): Promise<Uint8Array>;
@@ -46,7 +46,7 @@ declare class InterfoldSDK {
46
46
  requestE3(params: E3RequestParams): Promise<Hash>;
47
47
  cancelE3(e3Id: bigint): Promise<Hash>;
48
48
  getE3PublicKey(e3Id: bigint): Promise<`0x${string}`>;
49
- publishCiphertextOutput(e3Id: bigint, ciphertextOutput: `0x${string}`, ciphertextCommitment: `0x${string}`, proof: `0x${string}`, gasLimit?: bigint): Promise<Hash>;
49
+ publishCiphertextOutput(e3Id: bigint, outputReference: CiphertextOutputReference, gasLimit?: bigint): Promise<Hash>;
50
50
  getE3(e3Id: bigint): Promise<E3>;
51
51
  getE3Quote(params: E3RequestParams): Promise<bigint>;
52
52
  getFailureReason(e3Id: bigint): Promise<FailureReason>;
@@ -76,6 +76,34 @@ declare class InterfoldSDK {
76
76
  }): InterfoldSDK;
77
77
  }
78
78
 
79
+ declare const MAX_COMMITTEE_PUBLIC_KEY_BYTES: number;
80
+ declare const MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES: number;
81
+ interface AssembledCommitteePublicKey {
82
+ e3Id: bigint;
83
+ nodes: string[];
84
+ pkCommitment: Hex;
85
+ publicKey: Uint8Array;
86
+ }
87
+ /**
88
+ * Reassembles the deterministic public-key chunks emitted by the registry.
89
+ *
90
+ * The first candidate emitted by each publisher is the only candidate accepted
91
+ * from that publisher. This matches ciphernode and indexer recovery behavior.
92
+ */
93
+ declare class CommitteePublicKeyAssembler {
94
+ private readonly maxTrackedE3s;
95
+ private readonly selectedCandidates;
96
+ private readonly assemblies;
97
+ private readonly invalidAssemblies;
98
+ private readonly completedAssemblies;
99
+ private readonly trackedE3s;
100
+ constructor(maxTrackedE3s?: number);
101
+ add(event: CommitteePublicKeyChunkPublishedData): AssembledCommitteePublicKey | undefined;
102
+ clear(e3Id: bigint): void;
103
+ private track;
104
+ private dropE3;
105
+ }
106
+
79
107
  declare const DEFAULT_THRESHOLD_BFV_PARAMS_PRESET_NAME: ThresholdBfvParamsPresetName;
80
108
 
81
109
  declare class SDKError extends Error {
@@ -137,4 +165,4 @@ declare function calculateInputWindow(publicClient: PublicClient, duration?: num
137
165
  */
138
166
  declare function decodePlaintextOutput(plaintextOutput: string): number | null;
139
167
 
140
- export { AllEventTypes, BfvParams, type ComputeProviderParams, ContractAddresses, DEFAULT_COMPUTE_PROVIDER_PARAMS, DEFAULT_E3_CONFIG, DEFAULT_THRESHOLD_BFV_PARAMS_PRESET_NAME, E3, E3RequestParams, E3Stage, EncryptedValueAndPublicInputs, EventCallback, FailureReason, InterfoldSDK, RandomnessProviderEventCallback, RandomnessProviderEventType, type SDKConfig, SDKError, ThresholdBfvParamsPresetName, VerifiableEncryptionResult, calculateInputWindow, decodePlaintextOutput, encodeBfvParams, encodeComputeProviderParams, encodeCustomParams, formatBigInt, formatEventName, generateEventId, getCurrentTimestamp, isValidAddress, isValidHash, parseBigInt, parseEventData, sleep };
168
+ export { AllEventTypes, type AssembledCommitteePublicKey, BfvParams, CiphertextOutputReference, CommitteePublicKeyAssembler, CommitteePublicKeyChunkPublishedData, type ComputeProviderParams, ContractAddresses, DEFAULT_COMPUTE_PROVIDER_PARAMS, DEFAULT_E3_CONFIG, DEFAULT_THRESHOLD_BFV_PARAMS_PRESET_NAME, E3, E3RequestParams, E3Stage, EncryptedValueAndPublicInputs, EventCallback, FailureReason, InterfoldSDK, MAX_COMMITTEE_PUBLIC_KEY_BYTES, MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES, RandomnessProviderEventCallback, RandomnessProviderEventType, type SDKConfig, SDKError, ThresholdBfvParamsPresetName, VerifiableEncryptionResult, calculateInputWindow, decodePlaintextOutput, encodeBfvParams, encodeComputeProviderParams, encodeCustomParams, formatBigInt, formatEventName, generateEventId, getCurrentTimestamp, isValidAddress, isValidHash, parseBigInt, parseEventData, sleep };
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
9
9
 
10
10
  // src/contracts/contract-client.ts
11
11
  import {
12
+ encodeAbiParameters as encodeAbiParameters2,
12
13
  createPublicClient,
13
14
  createWalletClient,
14
15
  http,
@@ -333,7 +334,7 @@ var ContractClient = class _ContractClient {
333
334
  throw new SDKError(`Failed to cancel E3: ${error}`, "CANCEL_E3_FAILED");
334
335
  }
335
336
  }
336
- async publishCiphertextOutput(e3Id, ciphertextOutput, ciphertextCommitment, proof, gasLimit) {
337
+ async publishCiphertextOutput(e3Id, outputReference, gasLimit) {
337
338
  if (!this.walletClient) {
338
339
  throw new SDKError("Wallet client required for write operations", "NO_WALLET");
339
340
  }
@@ -342,11 +343,25 @@ var ContractClient = class _ContractClient {
342
343
  if (!account) {
343
344
  throw new SDKError("No account connected", "NO_ACCOUNT");
344
345
  }
346
+ const encodedOutputReference = encodeAbiParameters2(
347
+ [
348
+ {
349
+ type: "tuple",
350
+ components: [
351
+ { name: "contentHash", type: "bytes32" },
352
+ { name: "ciphertextCommitment", type: "bytes32" },
353
+ { name: "computeProof", type: "bytes" },
354
+ { name: "availabilityProof", type: "bytes" }
355
+ ]
356
+ }
357
+ ],
358
+ [outputReference]
359
+ );
345
360
  const { request } = await this.publicClient.simulateContract({
346
361
  address: this.contracts.interfold,
347
362
  abi: Interfold__factory.abi,
348
363
  functionName: "publishCiphertextOutput",
349
- args: [e3Id, ciphertextOutput, ciphertextCommitment, proof],
364
+ args: [e3Id, encodedOutputReference],
350
365
  account,
351
366
  gas: gasLimit
352
367
  });
@@ -472,6 +487,7 @@ import { CiphernodeRegistryOwnable__factory as CiphernodeRegistryOwnable__factor
472
487
  var InterfoldEventType = /* @__PURE__ */ ((InterfoldEventType2) => {
473
488
  InterfoldEventType2["E3_REQUESTED"] = "E3Requested";
474
489
  InterfoldEventType2["CIPHERTEXT_OUTPUT_PUBLISHED"] = "CiphertextOutputPublished";
490
+ InterfoldEventType2["CIPHERTEXT_OUTPUT_REFERENCE_PUBLISHED"] = "CiphertextOutputReferencePublished";
475
491
  InterfoldEventType2["PLAINTEXT_OUTPUT_PUBLISHED"] = "PlaintextOutputPublished";
476
492
  InterfoldEventType2["E3_PROGRAM_REGISTERED"] = "E3ProgramRegistered";
477
493
  InterfoldEventType2["ENCRYPTION_SCHEME_ENABLED"] = "EncryptionSchemeEnabled";
@@ -487,6 +503,7 @@ var RegistryEventType = /* @__PURE__ */ ((RegistryEventType2) => {
487
503
  RegistryEventType2["COMMITTEE_RANDOMNESS_REQUESTED"] = "CommitteeRandomnessRequested";
488
504
  RegistryEventType2["RANDOMNESS_CIRCUIT_BREAKER_TRIPPED"] = "RandomnessCircuitBreakerTripped";
489
505
  RegistryEventType2["COMMITTEE_PUBLISHED"] = "CommitteePublished";
506
+ RegistryEventType2["COMMITTEE_PUBLIC_KEY_CHUNK_PUBLISHED"] = "CommitteePublicKeyChunkPublished";
490
507
  RegistryEventType2["COMMITTEE_FINALIZED"] = "SortitionCommitteeFinalized";
491
508
  RegistryEventType2["INTERFOLD_SET"] = "InterfoldSet";
492
509
  RegistryEventType2["OWNERSHIP_TRANSFERRED"] = "OwnershipTransferred";
@@ -526,6 +543,7 @@ var EventListener = class _EventListener {
526
543
  "CommitteeRandomnessRequested" /* COMMITTEE_RANDOMNESS_REQUESTED */,
527
544
  "RandomnessCircuitBreakerTripped" /* RANDOMNESS_CIRCUIT_BREAKER_TRIPPED */,
528
545
  "CommitteePublished" /* COMMITTEE_PUBLISHED */,
546
+ "CommitteePublicKeyChunkPublished" /* COMMITTEE_PUBLIC_KEY_CHUNK_PUBLISHED */,
529
547
  "SortitionCommitteeFinalized" /* COMMITTEE_FINALIZED */,
530
548
  "InterfoldSet" /* INTERFOLD_SET */
531
549
  ]);
@@ -1133,9 +1151,9 @@ var InterfoldSDK = class _InterfoldSDK {
1133
1151
  /**
1134
1152
  * Validate serialized BFV public-key bytes before using them for encryption.
1135
1153
  *
1136
- * `CommitteePublished.publicKey` is an untrusted transport value. Consumers
1137
- * must compare its semantic BFV commitment with the event's on-chain
1138
- * `pkCommitment` before accepting it.
1154
+ * A reassembled public key is an untrusted transport value. Consumers must
1155
+ * compare its semantic BFV commitment with the on-chain `pkCommitment`
1156
+ * before accepting it.
1139
1157
  */
1140
1158
  async validatePublicKeyCommitment(publicKey, expectedCommitment) {
1141
1159
  if (expectedCommitment.length !== 32) {
@@ -1175,8 +1193,8 @@ var InterfoldSDK = class _InterfoldSDK {
1175
1193
  async getE3PublicKey(e3Id) {
1176
1194
  return this.contractClient.getE3PublicKey(e3Id);
1177
1195
  }
1178
- async publishCiphertextOutput(e3Id, ciphertextOutput, ciphertextCommitment, proof, gasLimit) {
1179
- return this.contractClient.publishCiphertextOutput(e3Id, ciphertextOutput, ciphertextCommitment, proof, gasLimit);
1196
+ async publishCiphertextOutput(e3Id, outputReference, gasLimit) {
1197
+ return this.contractClient.publishCiphertextOutput(e3Id, outputReference, gasLimit);
1180
1198
  }
1181
1199
  async getE3(e3Id) {
1182
1200
  return this.contractClient.getE3(e3Id);
@@ -1256,7 +1274,149 @@ var InterfoldSDK = class _InterfoldSDK {
1256
1274
  });
1257
1275
  }
1258
1276
  };
1277
+
1278
+ // src/committee-public-key.ts
1279
+ import { hexToBytes, isHex, keccak256 } from "viem";
1280
+ var MAX_COMMITTEE_PUBLIC_KEY_BYTES = 512 * 1024;
1281
+ var MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES = 90 * 1024;
1282
+ var DEFAULT_MAX_TRACKED_COMMITTEE_KEYS = 128;
1283
+ var CommitteePublicKeyAssembler = class {
1284
+ constructor(maxTrackedE3s = DEFAULT_MAX_TRACKED_COMMITTEE_KEYS) {
1285
+ this.maxTrackedE3s = maxTrackedE3s;
1286
+ if (!Number.isInteger(maxTrackedE3s) || maxTrackedE3s < 1) {
1287
+ throw new Error("Maximum tracked committee-key count must be a positive integer");
1288
+ }
1289
+ }
1290
+ selectedCandidates = /* @__PURE__ */ new Map();
1291
+ assemblies = /* @__PURE__ */ new Map();
1292
+ invalidAssemblies = /* @__PURE__ */ new Set();
1293
+ completedAssemblies = /* @__PURE__ */ new Set();
1294
+ trackedE3s = /* @__PURE__ */ new Map();
1295
+ add(event) {
1296
+ const e3Key = event.e3Id.toString();
1297
+ this.track(e3Key);
1298
+ const metadata = validateEvent(event);
1299
+ const publisherKey = `${e3Key}:${event.publisher.toLowerCase()}`;
1300
+ const selectedCandidate = this.selectedCandidates.get(publisherKey);
1301
+ if (selectedCandidate && selectedCandidate.toLowerCase() !== metadata.candidateHash.toLowerCase()) {
1302
+ return void 0;
1303
+ }
1304
+ this.selectedCandidates.set(publisherKey, metadata.candidateHash);
1305
+ const assemblyKey = `${publisherKey}:${metadata.candidateHash.toLowerCase()}`;
1306
+ if (this.completedAssemblies.has(assemblyKey)) return void 0;
1307
+ if (this.invalidAssemblies.has(assemblyKey)) return void 0;
1308
+ const assembly = this.assemblies.get(assemblyKey) ?? {
1309
+ nodes: [...event.nodes],
1310
+ pkCommitment: metadata.pkCommitment,
1311
+ candidateHash: metadata.candidateHash,
1312
+ totalLength: event.totalLength,
1313
+ chunks: Array.from({ length: event.chunkCount }).fill(void 0)
1314
+ };
1315
+ if (!metadataMatches(assembly, event, metadata.pkCommitment)) {
1316
+ this.assemblies.delete(assemblyKey);
1317
+ this.invalidAssemblies.add(assemblyKey);
1318
+ return void 0;
1319
+ }
1320
+ const existing = assembly.chunks[event.chunkIndex];
1321
+ if (existing && !bytesEqual(existing, metadata.chunk)) {
1322
+ this.assemblies.delete(assemblyKey);
1323
+ this.invalidAssemblies.add(assemblyKey);
1324
+ return void 0;
1325
+ }
1326
+ assembly.chunks[event.chunkIndex] = metadata.chunk;
1327
+ this.assemblies.set(assemblyKey, assembly);
1328
+ if (assembly.chunks.some((chunk) => chunk === void 0)) return void 0;
1329
+ const publicKey = new Uint8Array(assembly.totalLength);
1330
+ let offset = 0;
1331
+ for (const chunk of assembly.chunks) {
1332
+ publicKey.set(chunk, offset);
1333
+ offset += chunk.length;
1334
+ }
1335
+ if (offset !== assembly.totalLength || keccak256(publicKey).toLowerCase() !== assembly.candidateHash.toLowerCase()) {
1336
+ this.assemblies.delete(assemblyKey);
1337
+ this.invalidAssemblies.add(assemblyKey);
1338
+ return void 0;
1339
+ }
1340
+ this.completedAssemblies.add(assemblyKey);
1341
+ this.assemblies.delete(assemblyKey);
1342
+ return {
1343
+ e3Id: event.e3Id,
1344
+ nodes: assembly.nodes,
1345
+ pkCommitment: assembly.pkCommitment,
1346
+ publicKey
1347
+ };
1348
+ }
1349
+ clear(e3Id) {
1350
+ const e3Key = e3Id.toString();
1351
+ this.trackedE3s.delete(e3Key);
1352
+ this.dropE3(e3Key);
1353
+ }
1354
+ track(e3Key) {
1355
+ this.trackedE3s.delete(e3Key);
1356
+ this.trackedE3s.set(e3Key, true);
1357
+ while (this.trackedE3s.size > this.maxTrackedE3s) {
1358
+ const oldest = this.trackedE3s.keys().next().value;
1359
+ if (oldest === void 0) return;
1360
+ this.trackedE3s.delete(oldest);
1361
+ this.dropE3(oldest);
1362
+ }
1363
+ }
1364
+ dropE3(e3Key) {
1365
+ const prefix = `${e3Key}:`;
1366
+ for (const key of this.selectedCandidates.keys()) {
1367
+ if (key.startsWith(prefix)) this.selectedCandidates.delete(key);
1368
+ }
1369
+ for (const key of this.assemblies.keys()) {
1370
+ if (key.startsWith(prefix)) this.assemblies.delete(key);
1371
+ }
1372
+ for (const key of this.invalidAssemblies) {
1373
+ if (key.startsWith(prefix)) this.invalidAssemblies.delete(key);
1374
+ }
1375
+ for (const key of this.completedAssemblies) {
1376
+ if (key.startsWith(prefix)) this.completedAssemblies.delete(key);
1377
+ }
1378
+ }
1379
+ };
1380
+ function validateEvent(event) {
1381
+ if (!isBytes32(event.candidateHash) || !isBytes32(event.pkCommitment)) {
1382
+ throw new Error("Committee public-key chunk contains an invalid bytes32 value");
1383
+ }
1384
+ if (!Number.isInteger(event.totalLength) || event.totalLength <= 0 || event.totalLength > MAX_COMMITTEE_PUBLIC_KEY_BYTES) {
1385
+ throw new Error("Committee public-key total length is outside the supported range");
1386
+ }
1387
+ const expectedChunkCount = Math.ceil(event.totalLength / MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES);
1388
+ if (!Number.isInteger(event.chunkCount) || event.chunkCount !== expectedChunkCount) {
1389
+ throw new Error("Committee public-key chunk count does not match the total length");
1390
+ }
1391
+ if (!Number.isInteger(event.chunkIndex) || event.chunkIndex < 0 || event.chunkIndex >= event.chunkCount) {
1392
+ throw new Error("Committee public-key chunk index is outside the candidate range");
1393
+ }
1394
+ if (!isHex(event.chunk)) {
1395
+ throw new Error("Committee public-key chunk is not valid hex");
1396
+ }
1397
+ const chunk = hexToBytes(event.chunk);
1398
+ const remaining = event.totalLength - event.chunkIndex * MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES;
1399
+ const expectedLength = Math.min(remaining, MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES);
1400
+ if (chunk.length !== expectedLength) {
1401
+ throw new Error("Committee public-key chunk length does not match its index");
1402
+ }
1403
+ return {
1404
+ candidateHash: event.candidateHash,
1405
+ pkCommitment: event.pkCommitment,
1406
+ chunk
1407
+ };
1408
+ }
1409
+ function metadataMatches(assembly, event, pkCommitment) {
1410
+ return assembly.totalLength === event.totalLength && assembly.chunks.length === event.chunkCount && assembly.pkCommitment.toLowerCase() === pkCommitment.toLowerCase() && assembly.nodes.length === event.nodes.length && assembly.nodes.every((node, index) => node.toLowerCase() === event.nodes[index]?.toLowerCase());
1411
+ }
1412
+ function isBytes32(value) {
1413
+ return /^0x[0-9a-fA-F]{64}$/.test(value);
1414
+ }
1415
+ function bytesEqual(left, right) {
1416
+ return left.length === right.length && left.every((byte, index) => byte === right[index]);
1417
+ }
1259
1418
  export {
1419
+ CommitteePublicKeyAssembler,
1260
1420
  CommitteeSize,
1261
1421
  ContractClient,
1262
1422
  DEFAULT_COMPUTE_PROVIDER_PARAMS,
@@ -1267,6 +1427,8 @@ export {
1267
1427
  FailureReason,
1268
1428
  InterfoldEventType,
1269
1429
  InterfoldSDK,
1430
+ MAX_COMMITTEE_PUBLIC_KEY_BYTES,
1431
+ MAX_COMMITTEE_PUBLIC_KEY_CHUNK_BYTES,
1270
1432
  RandomnessProviderEventType,
1271
1433
  RegistryEventType,
1272
1434
  SDKError,