@vocdoni/davinci-sdk 0.1.1 → 0.1.2

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.mjs CHANGED
@@ -1,7 +1,9 @@
1
1
  import axios from 'axios';
2
2
  import { ProcessRegistry__factory, OrganizationRegistry__factory } from '@vocdoni/davinci-contracts';
3
- import { groth16 } from 'snarkjs';
4
3
  import { sha256 } from 'ethers';
4
+ import * as snarkjs from 'snarkjs';
5
+ import { groth16 } from 'snarkjs';
6
+ import { buildBabyjub, buildPoseidon } from 'circomlibjs';
5
7
 
6
8
  var ElectionResultsTypeNames = /* @__PURE__ */ ((ElectionResultsTypeNames2) => {
7
9
  ElectionResultsTypeNames2["SINGLE_CHOICE_MULTIQUESTION"] = "single-choice-multiquestion";
@@ -1880,97 +1882,6 @@ class ProcessOrchestrationService {
1880
1882
  }
1881
1883
  }
1882
1884
 
1883
- class CircomProof {
1884
- constructor(opts = {}) {
1885
- // simple in-memory cache keyed by URL
1886
- this.wasmCache = /* @__PURE__ */ new Map();
1887
- this.zkeyCache = /* @__PURE__ */ new Map();
1888
- this.vkeyCache = /* @__PURE__ */ new Map();
1889
- this.wasmUrl = opts.wasmUrl;
1890
- this.zkeyUrl = opts.zkeyUrl;
1891
- this.vkeyUrl = opts.vkeyUrl;
1892
- this.wasmHash = opts.wasmHash;
1893
- this.zkeyHash = opts.zkeyHash;
1894
- this.vkeyHash = opts.vkeyHash;
1895
- }
1896
- /**
1897
- * Computes SHA-256 hash of the given data and compares it with the expected hash.
1898
- * @param data - The data to hash (string or ArrayBuffer or Uint8Array)
1899
- * @param expectedHash - The expected SHA-256 hash in hexadecimal format
1900
- * @param filename - The filename for error reporting
1901
- * @throws Error if the computed hash doesn't match the expected hash
1902
- */
1903
- verifyHash(data, expectedHash, filename) {
1904
- let bytes;
1905
- if (typeof data === "string") {
1906
- bytes = new TextEncoder().encode(data);
1907
- } else if (data instanceof ArrayBuffer) {
1908
- bytes = new Uint8Array(data);
1909
- } else {
1910
- bytes = data;
1911
- }
1912
- const computedHash = sha256(bytes).slice(2);
1913
- if (computedHash.toLowerCase() !== expectedHash.toLowerCase()) {
1914
- throw new Error(
1915
- `Hash verification failed for ${filename}. Expected: ${expectedHash.toLowerCase()}, Computed: ${computedHash.toLowerCase()}`
1916
- );
1917
- }
1918
- }
1919
- /**
1920
- * Generate a zk‐SNARK proof.
1921
- * If you didn't pass wasmUrl/zkeyUrl in the constructor you must supply them here.
1922
- */
1923
- async generate(inputs, urls = {}) {
1924
- const wasmUrl = urls.wasmUrl ?? this.wasmUrl;
1925
- const zkeyUrl = urls.zkeyUrl ?? this.zkeyUrl;
1926
- if (!wasmUrl) throw new Error("`wasmUrl` is required to generate a proof");
1927
- if (!zkeyUrl) throw new Error("`zkeyUrl` is required to generate a proof");
1928
- let wasmBin = this.wasmCache.get(wasmUrl);
1929
- if (!wasmBin) {
1930
- const r = await fetch(wasmUrl);
1931
- if (!r.ok) throw new Error(`Failed to fetch wasm at ${wasmUrl}: ${r.status}`);
1932
- const buf = await r.arrayBuffer();
1933
- wasmBin = new Uint8Array(buf);
1934
- if (this.wasmHash) {
1935
- this.verifyHash(wasmBin, this.wasmHash, "circuit.wasm");
1936
- }
1937
- this.wasmCache.set(wasmUrl, wasmBin);
1938
- }
1939
- let zkeyBin = this.zkeyCache.get(zkeyUrl);
1940
- if (!zkeyBin) {
1941
- const r = await fetch(zkeyUrl);
1942
- if (!r.ok) throw new Error(`Failed to fetch zkey at ${zkeyUrl}: ${r.status}`);
1943
- const buf = await r.arrayBuffer();
1944
- zkeyBin = new Uint8Array(buf);
1945
- if (this.zkeyHash) {
1946
- this.verifyHash(zkeyBin, this.zkeyHash, "proving_key.zkey");
1947
- }
1948
- this.zkeyCache.set(zkeyUrl, zkeyBin);
1949
- }
1950
- const { proof, publicSignals } = await groth16.fullProve(inputs, wasmBin, zkeyBin);
1951
- return {
1952
- proof,
1953
- publicSignals
1954
- };
1955
- }
1956
- async verify(proof, publicSignals, urlOverride) {
1957
- const vkeyUrl = urlOverride ?? this.vkeyUrl;
1958
- if (!vkeyUrl) throw new Error("`vkeyUrl` is required to verify a proof");
1959
- let vk = this.vkeyCache.get(vkeyUrl);
1960
- if (!vk) {
1961
- const r = await fetch(vkeyUrl);
1962
- if (!r.ok) throw new Error(`Failed to fetch vkey at ${vkeyUrl}: ${r.status}`);
1963
- const vkeyText = await r.text();
1964
- if (this.vkeyHash) {
1965
- this.verifyHash(vkeyText, this.vkeyHash, "verification_key.json");
1966
- }
1967
- vk = JSON.parse(vkeyText);
1968
- this.vkeyCache.set(vkeyUrl, vk);
1969
- }
1970
- return groth16.verify(vk, publicSignals, proof);
1971
- }
1972
- }
1973
-
1974
1885
  var VoteStatus = /* @__PURE__ */ ((VoteStatus2) => {
1975
1886
  VoteStatus2["Pending"] = "pending";
1976
1887
  VoteStatus2["Verified"] = "verified";
@@ -1982,11 +1893,15 @@ var VoteStatus = /* @__PURE__ */ ((VoteStatus2) => {
1982
1893
  })(VoteStatus || {});
1983
1894
 
1984
1895
  class VoteOrchestrationService {
1985
- constructor(apiService, getCrypto, signer, censusProviders = {}, config = {}) {
1896
+ constructor(apiService, getBallotInputGenerator, signer, censusProviders = {}, config = {}) {
1986
1897
  this.apiService = apiService;
1987
- this.getCrypto = getCrypto;
1898
+ this.getBallotInputGenerator = getBallotInputGenerator;
1988
1899
  this.signer = signer;
1989
1900
  this.censusProviders = censusProviders;
1901
+ // Cache for circuit files
1902
+ this.wasmCache = /* @__PURE__ */ new Map();
1903
+ this.zkeyCache = /* @__PURE__ */ new Map();
1904
+ this.vkeyCache = /* @__PURE__ */ new Map();
1990
1905
  this.verifyCircuitFiles = config.verifyCircuitFiles ?? true;
1991
1906
  this.verifyProof = config.verifyProof ?? true;
1992
1907
  }
@@ -2036,7 +1951,7 @@ class VoteOrchestrationService {
2036
1951
  if (process.census.censusOrigin === CensusOrigin.CSP) {
2037
1952
  voteRequest.censusProof = censusProof;
2038
1953
  }
2039
- await this.submitVoteRequest(voteRequest);
1954
+ await this.apiService.sequencer.submitVote(voteRequest);
2040
1955
  const status = await this.apiService.sequencer.getVoteStatus(config.processId, voteId);
2041
1956
  return {
2042
1957
  voteId,
@@ -2185,30 +2100,29 @@ class VoteOrchestrationService {
2185
2100
  throw new Error(`Unsupported census origin: ${censusOrigin}`);
2186
2101
  }
2187
2102
  /**
2188
- * Generate vote proof inputs using DavinciCrypto
2103
+ * Generate vote proof inputs using BallotInputGenerator
2189
2104
  */
2190
2105
  async generateVoteProofInputs(processId, voterAddress, encryptionKey, ballotMode, choices, weight, customRandomness) {
2191
- const crypto = await this.getCrypto();
2106
+ const generator = await this.getBallotInputGenerator();
2192
2107
  this.validateChoices(choices, ballotMode);
2193
- const fieldValues = choices.map((choice) => choice.toString());
2194
- const inputs = {
2195
- address: voterAddress.replace(/^0x/, ""),
2196
- processID: processId.replace(/^0x/, ""),
2197
- encryptionKey: [encryptionKey.x, encryptionKey.y],
2198
- ballotMode,
2199
- weight,
2200
- fieldValues
2201
- };
2108
+ let k;
2202
2109
  if (customRandomness) {
2203
2110
  const hexRandomness = customRandomness.startsWith("0x") ? customRandomness : "0x" + customRandomness;
2204
- const k = BigInt(hexRandomness).toString();
2205
- inputs.k = k;
2111
+ k = BigInt(hexRandomness).toString();
2206
2112
  }
2207
- const cryptoOutput = await crypto.proofInputs(inputs);
2113
+ const result = await generator.generateInputs(
2114
+ processId.replace(/^0x/, ""),
2115
+ voterAddress.replace(/^0x/, ""),
2116
+ encryptionKey,
2117
+ ballotMode,
2118
+ choices,
2119
+ weight,
2120
+ k
2121
+ );
2208
2122
  return {
2209
- voteId: cryptoOutput.voteId,
2210
- cryptoOutput,
2211
- circomInputs: cryptoOutput.circomInputs
2123
+ voteId: result.voteId,
2124
+ cryptoOutput: result,
2125
+ circomInputs: result.circomInputs
2212
2126
  };
2213
2127
  }
2214
2128
  /**
@@ -2225,29 +2139,79 @@ class VoteOrchestrationService {
2225
2139
  }
2226
2140
  }
2227
2141
  /**
2228
- * Generate zk-SNARK proof using CircomProof
2142
+ * Verify hash of downloaded file
2143
+ */
2144
+ verifyHash(data, expectedHash, filename) {
2145
+ const computedHash = sha256(data).slice(2);
2146
+ if (computedHash.toLowerCase() !== expectedHash.toLowerCase()) {
2147
+ throw new Error(
2148
+ `Hash verification failed for ${filename}. Expected: ${expectedHash.toLowerCase()}, Computed: ${computedHash.toLowerCase()}`
2149
+ );
2150
+ }
2151
+ }
2152
+ /**
2153
+ * Generate zk-SNARK proof using snarkjs directly (no CircomProof wrapper)
2229
2154
  */
2230
2155
  async generateZkProof(circomInputs) {
2231
2156
  const info = await this.apiService.sequencer.getInfo();
2232
- const circomProof = new CircomProof({
2233
- wasmUrl: info.circuitUrl,
2234
- zkeyUrl: info.provingKeyUrl,
2235
- vkeyUrl: info.verificationKeyUrl,
2236
- // Only pass hashes if verifyCircuitFiles is enabled
2237
- ...this.verifyCircuitFiles && {
2238
- wasmHash: info.circuitHash,
2239
- zkeyHash: info.provingKeyHash,
2240
- vkeyHash: info.verificationKeyHash
2157
+ let wasmBytes = this.wasmCache.get(info.circuitUrl);
2158
+ if (!wasmBytes) {
2159
+ const response = await fetch(info.circuitUrl);
2160
+ if (!response.ok) {
2161
+ throw new Error(`Failed to fetch WASM at ${info.circuitUrl}: ${response.status}`);
2241
2162
  }
2242
- });
2243
- const { proof, publicSignals } = await circomProof.generate(circomInputs);
2163
+ const buffer = await response.arrayBuffer();
2164
+ wasmBytes = new Uint8Array(buffer);
2165
+ if (this.verifyCircuitFiles) {
2166
+ this.verifyHash(wasmBytes, info.circuitHash, "circuit.wasm");
2167
+ }
2168
+ this.wasmCache.set(info.circuitUrl, wasmBytes);
2169
+ }
2170
+ let zkeyBytes = this.zkeyCache.get(info.provingKeyUrl);
2171
+ if (!zkeyBytes) {
2172
+ const response = await fetch(info.provingKeyUrl);
2173
+ if (!response.ok) {
2174
+ throw new Error(`Failed to fetch zkey at ${info.provingKeyUrl}: ${response.status}`);
2175
+ }
2176
+ const buffer = await response.arrayBuffer();
2177
+ zkeyBytes = new Uint8Array(buffer);
2178
+ if (this.verifyCircuitFiles) {
2179
+ this.verifyHash(zkeyBytes, info.provingKeyHash, "proving_key.zkey");
2180
+ }
2181
+ this.zkeyCache.set(info.provingKeyUrl, zkeyBytes);
2182
+ }
2183
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(
2184
+ circomInputs,
2185
+ wasmBytes,
2186
+ zkeyBytes
2187
+ );
2244
2188
  if (this.verifyProof) {
2245
- const isValid = await circomProof.verify(proof, publicSignals);
2189
+ let vkey = this.vkeyCache.get(info.verificationKeyUrl);
2190
+ if (!vkey) {
2191
+ const response = await fetch(info.verificationKeyUrl);
2192
+ if (!response.ok) {
2193
+ throw new Error(`Failed to fetch vkey at ${info.verificationKeyUrl}: ${response.status}`);
2194
+ }
2195
+ const vkeyText = await response.text();
2196
+ if (this.verifyCircuitFiles) {
2197
+ const vkeyBytes = new TextEncoder().encode(vkeyText);
2198
+ this.verifyHash(vkeyBytes, info.verificationKeyHash, "verification_key.json");
2199
+ }
2200
+ vkey = JSON.parse(vkeyText);
2201
+ this.vkeyCache.set(info.verificationKeyUrl, vkey);
2202
+ }
2203
+ const isValid = await snarkjs.groth16.verify(vkey, publicSignals, proof);
2246
2204
  if (!isValid) {
2247
2205
  throw new Error("Generated proof is invalid");
2248
2206
  }
2249
2207
  }
2250
- return { proof, publicSignals };
2208
+ const voteProof = {
2209
+ pi_a: proof.pi_a,
2210
+ pi_b: proof.pi_b,
2211
+ pi_c: proof.pi_c,
2212
+ protocol: proof.protocol
2213
+ };
2214
+ return { proof: voteProof, publicSignals };
2251
2215
  }
2252
2216
  hexToBytes(hex) {
2253
2217
  const clean = hex.replace(/^0x/, "");
@@ -2262,22 +2226,6 @@ class VoteOrchestrationService {
2262
2226
  async signVote(voteId) {
2263
2227
  return this.signer.signMessage(this.hexToBytes(voteId));
2264
2228
  }
2265
- /**
2266
- * Submit the vote request to the sequencer
2267
- */
2268
- async submitVoteRequest(voteRequest) {
2269
- const ballotProof = {
2270
- pi_a: voteRequest.ballotProof.pi_a,
2271
- pi_b: voteRequest.ballotProof.pi_b,
2272
- pi_c: voteRequest.ballotProof.pi_c,
2273
- protocol: voteRequest.ballotProof.protocol
2274
- };
2275
- const request = {
2276
- ...voteRequest,
2277
- ballotProof
2278
- };
2279
- await this.apiService.sequencer.submitVote(request);
2280
- }
2281
2229
  }
2282
2230
 
2283
2231
  class OrganizationRegistryService extends SmartContractService {
@@ -2376,6 +2324,97 @@ class OrganizationRegistryService extends SmartContractService {
2376
2324
  }
2377
2325
  }
2378
2326
 
2327
+ class CircomProof {
2328
+ constructor(opts = {}) {
2329
+ // simple in-memory cache keyed by URL
2330
+ this.wasmCache = /* @__PURE__ */ new Map();
2331
+ this.zkeyCache = /* @__PURE__ */ new Map();
2332
+ this.vkeyCache = /* @__PURE__ */ new Map();
2333
+ this.wasmUrl = opts.wasmUrl;
2334
+ this.zkeyUrl = opts.zkeyUrl;
2335
+ this.vkeyUrl = opts.vkeyUrl;
2336
+ this.wasmHash = opts.wasmHash;
2337
+ this.zkeyHash = opts.zkeyHash;
2338
+ this.vkeyHash = opts.vkeyHash;
2339
+ }
2340
+ /**
2341
+ * Computes SHA-256 hash of the given data and compares it with the expected hash.
2342
+ * @param data - The data to hash (string or ArrayBuffer or Uint8Array)
2343
+ * @param expectedHash - The expected SHA-256 hash in hexadecimal format
2344
+ * @param filename - The filename for error reporting
2345
+ * @throws Error if the computed hash doesn't match the expected hash
2346
+ */
2347
+ verifyHash(data, expectedHash, filename) {
2348
+ let bytes;
2349
+ if (typeof data === "string") {
2350
+ bytes = new TextEncoder().encode(data);
2351
+ } else if (data instanceof ArrayBuffer) {
2352
+ bytes = new Uint8Array(data);
2353
+ } else {
2354
+ bytes = data;
2355
+ }
2356
+ const computedHash = sha256(bytes).slice(2);
2357
+ if (computedHash.toLowerCase() !== expectedHash.toLowerCase()) {
2358
+ throw new Error(
2359
+ `Hash verification failed for ${filename}. Expected: ${expectedHash.toLowerCase()}, Computed: ${computedHash.toLowerCase()}`
2360
+ );
2361
+ }
2362
+ }
2363
+ /**
2364
+ * Generate a zk‐SNARK proof.
2365
+ * If you didn't pass wasmUrl/zkeyUrl in the constructor you must supply them here.
2366
+ */
2367
+ async generate(inputs, urls = {}) {
2368
+ const wasmUrl = urls.wasmUrl ?? this.wasmUrl;
2369
+ const zkeyUrl = urls.zkeyUrl ?? this.zkeyUrl;
2370
+ if (!wasmUrl) throw new Error("`wasmUrl` is required to generate a proof");
2371
+ if (!zkeyUrl) throw new Error("`zkeyUrl` is required to generate a proof");
2372
+ let wasmBin = this.wasmCache.get(wasmUrl);
2373
+ if (!wasmBin) {
2374
+ const r = await fetch(wasmUrl);
2375
+ if (!r.ok) throw new Error(`Failed to fetch wasm at ${wasmUrl}: ${r.status}`);
2376
+ const buf = await r.arrayBuffer();
2377
+ wasmBin = new Uint8Array(buf);
2378
+ if (this.wasmHash) {
2379
+ this.verifyHash(wasmBin, this.wasmHash, "circuit.wasm");
2380
+ }
2381
+ this.wasmCache.set(wasmUrl, wasmBin);
2382
+ }
2383
+ let zkeyBin = this.zkeyCache.get(zkeyUrl);
2384
+ if (!zkeyBin) {
2385
+ const r = await fetch(zkeyUrl);
2386
+ if (!r.ok) throw new Error(`Failed to fetch zkey at ${zkeyUrl}: ${r.status}`);
2387
+ const buf = await r.arrayBuffer();
2388
+ zkeyBin = new Uint8Array(buf);
2389
+ if (this.zkeyHash) {
2390
+ this.verifyHash(zkeyBin, this.zkeyHash, "proving_key.zkey");
2391
+ }
2392
+ this.zkeyCache.set(zkeyUrl, zkeyBin);
2393
+ }
2394
+ const { proof, publicSignals } = await groth16.fullProve(inputs, wasmBin, zkeyBin);
2395
+ return {
2396
+ proof,
2397
+ publicSignals
2398
+ };
2399
+ }
2400
+ async verify(proof, publicSignals, urlOverride) {
2401
+ const vkeyUrl = urlOverride ?? this.vkeyUrl;
2402
+ if (!vkeyUrl) throw new Error("`vkeyUrl` is required to verify a proof");
2403
+ let vk = this.vkeyCache.get(vkeyUrl);
2404
+ if (!vk) {
2405
+ const r = await fetch(vkeyUrl);
2406
+ if (!r.ok) throw new Error(`Failed to fetch vkey at ${vkeyUrl}: ${r.status}`);
2407
+ const vkeyText = await r.text();
2408
+ if (this.vkeyHash) {
2409
+ this.verifyHash(vkeyText, this.vkeyHash, "verification_key.json");
2410
+ }
2411
+ vk = JSON.parse(vkeyText);
2412
+ this.vkeyCache.set(vkeyUrl, vk);
2413
+ }
2414
+ return groth16.verify(vk, publicSignals, proof);
2415
+ }
2416
+ }
2417
+
2379
2418
  class DavinciCrypto {
2380
2419
  constructor(opts) {
2381
2420
  this.initialized = false;
@@ -2559,6 +2598,518 @@ class DavinciCrypto {
2559
2598
  }
2560
2599
  }
2561
2600
 
2601
+ class DavinciCSP {
2602
+ constructor(opts) {
2603
+ this.initialized = false;
2604
+ const { wasmExecUrl, wasmUrl, initTimeoutMs, wasmExecHash, wasmHash } = opts;
2605
+ if (!wasmExecUrl) throw new Error("`wasmExecUrl` is required");
2606
+ if (!wasmUrl) throw new Error("`wasmUrl` is required");
2607
+ this.wasmExecUrl = wasmExecUrl;
2608
+ this.wasmUrl = wasmUrl;
2609
+ this.initTimeoutMs = initTimeoutMs ?? 5e3;
2610
+ this.wasmExecHash = wasmExecHash;
2611
+ this.wasmHash = wasmHash;
2612
+ }
2613
+ static {
2614
+ // Cache for wasm files
2615
+ this.wasmExecCache = /* @__PURE__ */ new Map();
2616
+ }
2617
+ static {
2618
+ this.wasmBinaryCache = /* @__PURE__ */ new Map();
2619
+ }
2620
+ /**
2621
+ * Computes SHA-256 hash of the given data and compares it with the expected hash.
2622
+ * @param data - The data to hash (string or ArrayBuffer)
2623
+ * @param expectedHash - The expected SHA-256 hash in hexadecimal format
2624
+ * @param filename - The filename for error reporting
2625
+ * @throws Error if the computed hash doesn't match the expected hash
2626
+ */
2627
+ verifyHash(data, expectedHash, filename) {
2628
+ let bytes;
2629
+ if (typeof data === "string") {
2630
+ bytes = new TextEncoder().encode(data);
2631
+ } else {
2632
+ bytes = new Uint8Array(data);
2633
+ }
2634
+ const computedHash = sha256(bytes).slice(2);
2635
+ if (computedHash.toLowerCase() !== expectedHash.toLowerCase()) {
2636
+ throw new Error(
2637
+ `Hash verification failed for ${filename}. Expected: ${expectedHash.toLowerCase()}, Computed: ${computedHash.toLowerCase()}`
2638
+ );
2639
+ }
2640
+ }
2641
+ /**
2642
+ * Must be awaited before calling CSP functions.
2643
+ * Safe to call multiple times.
2644
+ */
2645
+ async init() {
2646
+ if (this.initialized) return;
2647
+ let shimCode = DavinciCSP.wasmExecCache.get(this.wasmExecUrl);
2648
+ if (!shimCode) {
2649
+ const shim = await fetch(this.wasmExecUrl);
2650
+ if (!shim.ok) {
2651
+ throw new Error(`Failed to fetch wasm_exec.js from ${this.wasmExecUrl}`);
2652
+ }
2653
+ shimCode = await shim.text();
2654
+ if (this.wasmExecHash) {
2655
+ this.verifyHash(shimCode, this.wasmExecHash, "wasm_exec.js");
2656
+ }
2657
+ DavinciCSP.wasmExecCache.set(this.wasmExecUrl, shimCode);
2658
+ }
2659
+ new Function(shimCode)();
2660
+ if (typeof globalThis.Go !== "function") {
2661
+ throw new Error("Global `Go` constructor not found after loading wasm_exec.js");
2662
+ }
2663
+ this.go = new globalThis.Go();
2664
+ let bytes = DavinciCSP.wasmBinaryCache.get(this.wasmUrl);
2665
+ if (!bytes) {
2666
+ const resp = await fetch(this.wasmUrl);
2667
+ if (!resp.ok) {
2668
+ throw new Error(`Failed to fetch davinci_crypto.wasm from ${this.wasmUrl}`);
2669
+ }
2670
+ bytes = await resp.arrayBuffer();
2671
+ if (this.wasmHash) {
2672
+ this.verifyHash(bytes, this.wasmHash, "davinci_crypto.wasm");
2673
+ }
2674
+ DavinciCSP.wasmBinaryCache.set(this.wasmUrl, bytes);
2675
+ }
2676
+ const { instance } = await WebAssembly.instantiate(bytes, this.go.importObject);
2677
+ this.go.run(instance).catch(() => {
2678
+ });
2679
+ const deadline = Date.now() + this.initTimeoutMs;
2680
+ while (Date.now() < deadline && !globalThis.DavinciCrypto) {
2681
+ await new Promise((r) => setTimeout(r, 50));
2682
+ }
2683
+ if (!globalThis.DavinciCrypto) {
2684
+ throw new Error("`DavinciCrypto` not initialized within timeout");
2685
+ }
2686
+ this.initialized = true;
2687
+ }
2688
+ /**
2689
+ * Generate a CSP (Credential Service Provider) signature for census proof.
2690
+ * @param censusOrigin - The census origin type (e.g., CensusOrigin.CSP)
2691
+ * @param privKey - The private key in hex format
2692
+ * @param processId - The process ID in hex format
2693
+ * @param address - The address in hex format
2694
+ * @param weight - The vote weight as a decimal string
2695
+ * @returns The CSP proof as a parsed JSON object
2696
+ * @throws if called before `await init()`, or if Go returns an error
2697
+ */
2698
+ async cspSign(censusOrigin, privKey, processId, address, weight) {
2699
+ if (!this.initialized) {
2700
+ throw new Error("DavinciCSP not initialized \u2014 call `await init()` first");
2701
+ }
2702
+ const raw = globalThis.DavinciCrypto.cspSign(censusOrigin, privKey, processId, address, weight);
2703
+ if (raw.error) {
2704
+ throw new Error(`Go/WASM cspSign error: ${raw.error}`);
2705
+ }
2706
+ if (!raw.data) {
2707
+ throw new Error("Go/WASM cspSign returned no data");
2708
+ }
2709
+ return raw.data;
2710
+ }
2711
+ /**
2712
+ * Verify a CSP (Credential Service Provider) proof.
2713
+ * @param censusOrigin - The census origin type (e.g., CensusOrigin.CSP)
2714
+ * @param root - The census root
2715
+ * @param address - The address
2716
+ * @param weight - The vote weight as a decimal string
2717
+ * @param processId - The process ID
2718
+ * @param publicKey - The public key
2719
+ * @param signature - The signature
2720
+ * @returns The verification result
2721
+ * @throws if called before `await init()`, or if Go returns an error
2722
+ */
2723
+ async cspVerify(censusOrigin, root, address, weight, processId, publicKey, signature) {
2724
+ if (!this.initialized) {
2725
+ throw new Error("DavinciCSP not initialized \u2014 call `await init()` first");
2726
+ }
2727
+ const cspProof = {
2728
+ censusOrigin,
2729
+ root,
2730
+ address,
2731
+ weight,
2732
+ processId,
2733
+ publicKey,
2734
+ signature
2735
+ };
2736
+ const raw = globalThis.DavinciCrypto.cspVerify(JSON.stringify(cspProof));
2737
+ if (raw.error) {
2738
+ throw new Error(`Go/WASM cspVerify error: ${raw.error}`);
2739
+ }
2740
+ if (!raw.data) {
2741
+ throw new Error("Go/WASM cspVerify returned no data");
2742
+ }
2743
+ return raw.data;
2744
+ }
2745
+ /**
2746
+ * Generate a CSP (Credential Service Provider) census root.
2747
+ * @param censusOrigin - The census origin type (e.g., CensusOrigin.CSP)
2748
+ * @param privKey - The private key in hex format
2749
+ * @returns The census root as a hexadecimal string
2750
+ * @throws if called before `await init()`, or if Go returns an error
2751
+ */
2752
+ async cspCensusRoot(censusOrigin, privKey) {
2753
+ if (!this.initialized) {
2754
+ throw new Error("DavinciCSP not initialized \u2014 call `await init()` first");
2755
+ }
2756
+ const raw = globalThis.DavinciCrypto.cspCensusRoot(censusOrigin, privKey);
2757
+ if (raw.error) {
2758
+ throw new Error(`Go/WASM cspCensusRoot error: ${raw.error}`);
2759
+ }
2760
+ if (!raw.data) {
2761
+ throw new Error("Go/WASM cspCensusRoot returned no data");
2762
+ }
2763
+ return raw.data.root;
2764
+ }
2765
+ }
2766
+
2767
+ function getRandomBytes(n) {
2768
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) {
2769
+ return globalThis.crypto.getRandomValues(new Uint8Array(n));
2770
+ }
2771
+ throw new Error("Crypto not available");
2772
+ }
2773
+ async function buildElGamal() {
2774
+ const babyjub = await buildBabyjub();
2775
+ const F = babyjub.F;
2776
+ function randomScalar() {
2777
+ const bytes = getRandomBytes(32);
2778
+ let bi = 0n;
2779
+ for (let i = 0; i < bytes.length; i++) {
2780
+ bi += BigInt(bytes[i]) << BigInt(8 * i);
2781
+ }
2782
+ return bi % babyjub.order;
2783
+ }
2784
+ function generateKeyPair() {
2785
+ const privKey = randomScalar();
2786
+ const pubKey = babyjub.mulPointEscalar(babyjub.Base8, privKey);
2787
+ return { privKey, pubKey };
2788
+ }
2789
+ function encrypt(msg, pubKey, k) {
2790
+ const kVal = BigInt(k);
2791
+ const mVal = BigInt(msg);
2792
+ const c1 = babyjub.mulPointEscalar(babyjub.Base8, kVal);
2793
+ const s = babyjub.mulPointEscalar(pubKey, kVal);
2794
+ const mPoint = babyjub.mulPointEscalar(babyjub.Base8, mVal);
2795
+ const c2 = babyjub.addPoint(mPoint, s);
2796
+ return { c1, c2 };
2797
+ }
2798
+ return {
2799
+ babyjub,
2800
+ F,
2801
+ encrypt,
2802
+ generateKeyPair,
2803
+ randomScalar,
2804
+ packPoint: babyjub.packPoint,
2805
+ unpackPoint: babyjub.unpackPoint
2806
+ };
2807
+ }
2808
+
2809
+ const FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
2810
+ const SCALING_FACTOR = 6360561867910373094066688120553762416144456282423235903351243436111059670888n;
2811
+ function modInverse(a, m) {
2812
+ let [old_r, r] = [a, m];
2813
+ let [old_s, s] = [1n, 0n];
2814
+ while (r !== 0n) {
2815
+ const quotient = old_r / r;
2816
+ [old_r, r] = [r, old_r - quotient * r];
2817
+ [old_s, s] = [s, old_s - quotient * s];
2818
+ }
2819
+ return (old_s % m + m) % m;
2820
+ }
2821
+ function mod(n, m) {
2822
+ return (n % m + m) % m;
2823
+ }
2824
+ function fromRTEtoTE(x, y) {
2825
+ const negF = mod(-SCALING_FACTOR, FIELD_MODULUS);
2826
+ const negFInv = modInverse(negF, FIELD_MODULUS);
2827
+ const xTE = mod(x * negFInv, FIELD_MODULUS);
2828
+ return [xTE, y];
2829
+ }
2830
+ function hexToDecimal(hex) {
2831
+ const cleanHex = hex.startsWith("0x") || hex.startsWith("0X") ? hex : "0x" + hex;
2832
+ return BigInt(cleanHex).toString();
2833
+ }
2834
+ function parseBallotMode(ballotMode) {
2835
+ return {
2836
+ numFields: ballotMode.numFields,
2837
+ uniqueValues: ballotMode.uniqueValues ? 1 : 0,
2838
+ maxValue: parseInt(ballotMode.maxValue),
2839
+ minValue: parseInt(ballotMode.minValue),
2840
+ maxValueSum: parseInt(ballotMode.maxValueSum),
2841
+ minValueSum: parseInt(ballotMode.minValueSum),
2842
+ costExponent: ballotMode.costExponent,
2843
+ costFromWeight: ballotMode.costFromWeight ? 1 : 0
2844
+ };
2845
+ }
2846
+ class BallotBuilder {
2847
+ constructor(elgamal, poseidon) {
2848
+ this.elgamal = elgamal;
2849
+ this.poseidon = poseidon;
2850
+ this.F = poseidon.F;
2851
+ }
2852
+ static async build() {
2853
+ const elgamal = await buildElGamal();
2854
+ const poseidon = await buildPoseidon();
2855
+ return new BallotBuilder(elgamal, poseidon);
2856
+ }
2857
+ randomK() {
2858
+ return this.elgamal.randomScalar().toString();
2859
+ }
2860
+ derivePoseidonChain(seedK, n) {
2861
+ let current = BigInt(seedK);
2862
+ const out = [current.toString()];
2863
+ for (let i = 0; i < n; i++) {
2864
+ const h = this.poseidon([current]);
2865
+ const hBig = BigInt(this.F.toString(h, 10));
2866
+ out.push(hBig.toString());
2867
+ current = hBig;
2868
+ }
2869
+ return out;
2870
+ }
2871
+ // Matches circuits/lib/multiposeidon.circom logic
2872
+ multiHash(inputs) {
2873
+ const nInputs = inputs.length;
2874
+ if (nInputs <= 16) {
2875
+ return this.F.toObject(this.poseidon(inputs));
2876
+ }
2877
+ const chunks = [];
2878
+ for (let i = 0; i < nInputs; i += 16) {
2879
+ chunks.push(inputs.slice(i, i + 16));
2880
+ }
2881
+ const intermediateHashes = [];
2882
+ for (const chunk of chunks) {
2883
+ intermediateHashes.push(this.F.toObject(this.poseidon(chunk)));
2884
+ }
2885
+ return this.F.toObject(this.poseidon(intermediateHashes));
2886
+ }
2887
+ encryptFields(fields, pubKey, seedK, nFields) {
2888
+ const paddedFields = [...fields];
2889
+ while (paddedFields.length < nFields) {
2890
+ paddedFields.push(0);
2891
+ }
2892
+ const ks = this.derivePoseidonChain(seedK, nFields);
2893
+ const cipherfields = [];
2894
+ for (let i = 0; i < nFields; i++) {
2895
+ const k = ks[i + 1];
2896
+ const msg = BigInt(paddedFields[i]);
2897
+ const enc = this.elgamal.encrypt(msg, pubKey, k);
2898
+ cipherfields.push([
2899
+ [this.elgamal.F.toString(enc.c1[0], 10), this.elgamal.F.toString(enc.c1[1], 10)],
2900
+ [this.elgamal.F.toString(enc.c2[0], 10), this.elgamal.F.toString(enc.c2[1], 10)]
2901
+ ]);
2902
+ }
2903
+ return { cipherfields, paddedFields };
2904
+ }
2905
+ computeVoteID(processId, address, k) {
2906
+ const h = this.poseidon([BigInt(processId), BigInt(address), BigInt(k)]);
2907
+ const hBig = BigInt(this.F.toString(h, 10));
2908
+ const mask = (1n << 160n) - 1n;
2909
+ return (hBig & mask).toString();
2910
+ }
2911
+ computeInputsHash(inputs) {
2912
+ return this.multiHash(inputs).toString();
2913
+ }
2914
+ /**
2915
+ * Creates a public key point from TE coordinates (as strings or bigints).
2916
+ * Use this when you already have coordinates in TE format.
2917
+ */
2918
+ createPubKeyFromTE(x, y) {
2919
+ return [this.elgamal.F.e(BigInt(x)), this.elgamal.F.e(BigInt(y))];
2920
+ }
2921
+ /**
2922
+ * Creates a public key point from RTE coordinates (as strings or bigints).
2923
+ * Use this when you have coordinates from a Gnark-based system (like the DAVINCI sequencer).
2924
+ * This automatically converts from RTE to TE format.
2925
+ */
2926
+ createPubKeyFromRTE(x, y) {
2927
+ const [xTE, yTE] = fromRTEtoTE(BigInt(x), BigInt(y));
2928
+ return [this.elgamal.F.e(xTE), this.elgamal.F.e(yTE)];
2929
+ }
2930
+ /**
2931
+ * Generates ballot inputs for the circuit.
2932
+ *
2933
+ * IMPORTANT: The pubKey must be in TE (Twisted Edwards) format as used by circomlibjs.
2934
+ * If you have RTE coordinates from a Gnark-based system (like DAVINCI sequencer),
2935
+ * use `createPubKeyFromRTE()` or `generateInputsFromSequencer()` instead.
2936
+ *
2937
+ * @param fields - The vote field values
2938
+ * @param weight - The voter's weight
2939
+ * @param pubKey - Public key as field elements [x, y] in TE format (use createPubKeyFromTE/RTE)
2940
+ * @param processId - Process ID as decimal string
2941
+ * @param address - Voter address as decimal string
2942
+ * @param k - Random k value for encryption
2943
+ * @param config - Ballot configuration
2944
+ * @param circuitCapacity - Number of fields the circuit supports (default: 8)
2945
+ */
2946
+ generateInputs(fields, weight, pubKey, processId, address, k, config, circuitCapacity = 8) {
2947
+ const activeFields = fields.length;
2948
+ const { cipherfields, paddedFields } = this.encryptFields(fields, pubKey, k, circuitCapacity);
2949
+ const voteId = this.computeVoteID(processId, address, k);
2950
+ const inputsList = [];
2951
+ const ffProcessID = mod(BigInt(processId), FIELD_MODULUS);
2952
+ inputsList.push(ffProcessID);
2953
+ inputsList.push(BigInt(activeFields));
2954
+ inputsList.push(BigInt(config.uniqueValues));
2955
+ inputsList.push(BigInt(config.maxValue));
2956
+ inputsList.push(BigInt(config.minValue));
2957
+ inputsList.push(BigInt(config.maxValueSum));
2958
+ inputsList.push(BigInt(config.minValueSum));
2959
+ inputsList.push(BigInt(config.costExponent));
2960
+ inputsList.push(BigInt(config.costFromWeight));
2961
+ inputsList.push(BigInt(this.elgamal.F.toString(pubKey[0], 10)));
2962
+ inputsList.push(BigInt(this.elgamal.F.toString(pubKey[1], 10)));
2963
+ inputsList.push(BigInt(address));
2964
+ inputsList.push(BigInt(voteId));
2965
+ for (const cf of cipherfields) {
2966
+ inputsList.push(BigInt(cf[0][0]));
2967
+ inputsList.push(BigInt(cf[0][1]));
2968
+ inputsList.push(BigInt(cf[1][0]));
2969
+ inputsList.push(BigInt(cf[1][1]));
2970
+ }
2971
+ inputsList.push(BigInt(weight));
2972
+ const inputsHash = this.computeInputsHash(inputsList);
2973
+ return {
2974
+ fields: paddedFields,
2975
+ weight,
2976
+ encryption_pubkey: [
2977
+ this.elgamal.F.toString(pubKey[0], 10),
2978
+ this.elgamal.F.toString(pubKey[1], 10)
2979
+ ],
2980
+ cipherfields,
2981
+ process_id: processId,
2982
+ address,
2983
+ k,
2984
+ vote_id: voteId,
2985
+ inputs_hash: inputsHash,
2986
+ // Config
2987
+ num_fields: activeFields,
2988
+ unique_values: config.uniqueValues,
2989
+ max_value: config.maxValue,
2990
+ min_value: config.minValue,
2991
+ max_value_sum: config.maxValueSum,
2992
+ min_value_sum: config.minValueSum,
2993
+ cost_exponent: config.costExponent,
2994
+ cost_from_weight: config.costFromWeight
2995
+ };
2996
+ }
2997
+ /**
2998
+ * Generates ballot inputs from sequencer data.
2999
+ * This is a convenience method that handles the RTE to TE conversion
3000
+ * for the public key automatically.
3001
+ *
3002
+ * @param sequencerData - Data from the DAVINCI sequencer
3003
+ * @param fields - The vote field values
3004
+ * @param weight - The voter's weight
3005
+ * @param k - Optional random k value (generated if not provided)
3006
+ * @param circuitCapacity - The number of fields the circuit supports (default: 8)
3007
+ */
3008
+ generateInputsFromSequencer(sequencerData, fields, weight, k, circuitCapacity = 8) {
3009
+ const processId = hexToDecimal(sequencerData.processId);
3010
+ const address = hexToDecimal(sequencerData.address);
3011
+ const [pubKeyX_TE, pubKeyY_TE] = fromRTEtoTE(
3012
+ BigInt(sequencerData.pubKeyX),
3013
+ BigInt(sequencerData.pubKeyY)
3014
+ );
3015
+ const pubKey = [this.elgamal.F.e(pubKeyX_TE), this.elgamal.F.e(pubKeyY_TE)];
3016
+ const config = parseBallotMode(sequencerData.ballotMode);
3017
+ const kValue = k ?? this.randomK();
3018
+ return this.generateInputs(fields, weight, pubKey, processId, address, kValue, config, circuitCapacity);
3019
+ }
3020
+ }
3021
+
3022
+ class BallotInputGenerator {
3023
+ constructor() {
3024
+ this.initialized = false;
3025
+ }
3026
+ /**
3027
+ * Initialize the ballot input generator
3028
+ * Must be called before generating inputs
3029
+ */
3030
+ async init() {
3031
+ if (this.initialized) return;
3032
+ this.builder = await BallotBuilder.build();
3033
+ this.initialized = true;
3034
+ }
3035
+ /**
3036
+ * Generate ballot inputs for voting
3037
+ * @param processId - Process ID (hex string without 0x)
3038
+ * @param address - Voter address (hex string without 0x)
3039
+ * @param encryptionKey - Encryption public key [x, y]
3040
+ * @param ballotMode - Ballot mode configuration
3041
+ * @param choices - Array of voter choices
3042
+ * @param weight - Voter weight
3043
+ * @param customK - Optional custom randomness (will be generated if not provided)
3044
+ * @returns Ballot inputs ready for proof generation
3045
+ */
3046
+ async generateInputs(processId, address, encryptionKey, ballotMode, choices, weight, customK) {
3047
+ if (!this.initialized || !this.builder) {
3048
+ throw new Error("BallotInputGenerator not initialized \u2014 call `await init()` first");
3049
+ }
3050
+ const ballotInputs = this.builder.generateInputsFromSequencer(
3051
+ {
3052
+ processId,
3053
+ address: "0x" + address,
3054
+ pubKeyX: encryptionKey.x,
3055
+ pubKeyY: encryptionKey.y,
3056
+ ballotMode: {
3057
+ numFields: ballotMode.numFields,
3058
+ uniqueValues: ballotMode.uniqueValues,
3059
+ maxValue: ballotMode.maxValue,
3060
+ minValue: ballotMode.minValue,
3061
+ maxValueSum: ballotMode.maxValueSum,
3062
+ minValueSum: ballotMode.minValueSum,
3063
+ costExponent: ballotMode.costExponent,
3064
+ costFromWeight: ballotMode.costFromWeight
3065
+ }
3066
+ },
3067
+ choices,
3068
+ parseInt(weight),
3069
+ customK,
3070
+ 8
3071
+ );
3072
+ const circomInputs = {
3073
+ fields: ballotInputs.fields.map((f) => f.toString()),
3074
+ num_fields: ballotInputs.num_fields.toString(),
3075
+ unique_values: ballotInputs.unique_values.toString(),
3076
+ max_value: ballotInputs.max_value.toString(),
3077
+ min_value: ballotInputs.min_value.toString(),
3078
+ max_value_sum: ballotInputs.max_value_sum.toString(),
3079
+ min_value_sum: ballotInputs.min_value_sum.toString(),
3080
+ cost_exponent: ballotInputs.cost_exponent.toString(),
3081
+ cost_from_weight: ballotInputs.cost_from_weight.toString(),
3082
+ address: ballotInputs.address,
3083
+ weight: ballotInputs.weight.toString(),
3084
+ process_id: ballotInputs.process_id,
3085
+ vote_id: ballotInputs.vote_id,
3086
+ encryption_pubkey: [
3087
+ ballotInputs.encryption_pubkey[0],
3088
+ ballotInputs.encryption_pubkey[1]
3089
+ ],
3090
+ k: ballotInputs.k,
3091
+ cipherfields: ballotInputs.cipherfields.flat(2),
3092
+ inputs_hash: ballotInputs.inputs_hash
3093
+ };
3094
+ const ciphertexts = ballotInputs.cipherfields.map((cf) => ({
3095
+ c1: [cf[0][0], cf[0][1]],
3096
+ c2: [cf[1][0], cf[1][1]]
3097
+ }));
3098
+ const output = {
3099
+ processId: "0x" + BigInt(ballotInputs.process_id).toString(16).padStart(64, "0"),
3100
+ address: "0x" + BigInt(ballotInputs.address).toString(16).padStart(40, "0"),
3101
+ ballot: {
3102
+ curveType: "bjj_iden3",
3103
+ ciphertexts
3104
+ },
3105
+ ballotInputsHash: ballotInputs.inputs_hash,
3106
+ voteId: "0x" + BigInt(ballotInputs.vote_id).toString(16).padStart(64, "0"),
3107
+ circomInputs
3108
+ };
3109
+ return output;
3110
+ }
3111
+ }
3112
+
2562
3113
  class DavinciSDK {
2563
3114
  constructor(config) {
2564
3115
  this.initialized = false;
@@ -2648,6 +3199,30 @@ class DavinciSDK {
2648
3199
  }
2649
3200
  return this.davinciCrypto;
2650
3201
  }
3202
+ /**
3203
+ * Get or initialize the DavinciCSP service for CSP cryptographic operations
3204
+ */
3205
+ async getCSP() {
3206
+ if (!this.davinciCSP) {
3207
+ const info = await this.apiService.sequencer.getInfo();
3208
+ this.davinciCSP = new DavinciCSP({
3209
+ wasmExecUrl: info.ballotProofWasmHelperExecJsUrl,
3210
+ wasmUrl: info.ballotProofWasmHelperUrl
3211
+ });
3212
+ await this.davinciCSP.init();
3213
+ }
3214
+ return this.davinciCSP;
3215
+ }
3216
+ /**
3217
+ * Get or initialize the BallotInputGenerator service for ballot input generation
3218
+ */
3219
+ async getBallotInputGenerator() {
3220
+ if (!this.ballotInputGenerator) {
3221
+ this.ballotInputGenerator = new BallotInputGenerator();
3222
+ await this.ballotInputGenerator.init();
3223
+ }
3224
+ return this.ballotInputGenerator;
3225
+ }
2651
3226
  /**
2652
3227
  * Get the process orchestration service for simplified process creation.
2653
3228
  * Requires a signer with a provider for blockchain interactions.
@@ -2674,7 +3249,7 @@ class DavinciSDK {
2674
3249
  if (!this._voteOrchestrator) {
2675
3250
  this._voteOrchestrator = new VoteOrchestrationService(
2676
3251
  this.apiService,
2677
- () => this.getCrypto(),
3252
+ () => this.getBallotInputGenerator(),
2678
3253
  this.config.signer,
2679
3254
  this.censusProviders,
2680
3255
  {
@@ -3527,5 +4102,5 @@ class DavinciSDK {
3527
4102
  }
3528
4103
  }
3529
4104
 
3530
- export { BaseService, Census, CensusNotUpdatable, CensusOrchestrator, CensusOrigin, CircomProof, ContractServiceError, CspCensus, DavinciCrypto, DavinciSDK, ElectionMetadataTemplate, ElectionResultsTypeNames, MerkleCensus, OffchainCensus, OffchainDynamicCensus, OnchainCensus, OrganizationAdministratorError, OrganizationCreateError, OrganizationDeleteError, OrganizationRegistryService, OrganizationUpdateError, ProcessCensusError, ProcessCreateError, ProcessDurationError, ProcessOrchestrationService, ProcessRegistryService, ProcessResultError, ProcessStateTransitionError, ProcessStatus, ProcessStatusError, PublishedCensus, SmartContractService, TxStatus, VocdoniApiService, VocdoniCensusService, VocdoniSequencerService, VoteOrchestrationService, VoteStatus, assertCSPCensusProof, assertMerkleCensusProof, createProcessSignatureMessage, getElectionMetadataTemplate, isCSPCensusProof, isMerkleCensusProof, signProcessCreation, validateProcessId };
4105
+ export { BallotInputGenerator, BaseService, Census, CensusNotUpdatable, CensusOrchestrator, CensusOrigin, CircomProof, ContractServiceError, CspCensus, DavinciCSP, DavinciCrypto, DavinciSDK, ElectionMetadataTemplate, ElectionResultsTypeNames, MerkleCensus, OffchainCensus, OffchainDynamicCensus, OnchainCensus, OrganizationAdministratorError, OrganizationCreateError, OrganizationDeleteError, OrganizationRegistryService, OrganizationUpdateError, ProcessCensusError, ProcessCreateError, ProcessDurationError, ProcessOrchestrationService, ProcessRegistryService, ProcessResultError, ProcessStateTransitionError, ProcessStatus, ProcessStatusError, PublishedCensus, SmartContractService, TxStatus, VocdoniApiService, VocdoniCensusService, VocdoniSequencerService, VoteOrchestrationService, VoteStatus, assertCSPCensusProof, assertMerkleCensusProof, createProcessSignatureMessage, getElectionMetadataTemplate, isCSPCensusProof, isMerkleCensusProof, signProcessCreation, validateProcessId };
3531
4106
  //# sourceMappingURL=index.mjs.map