@crisp-e3/sdk 0.17.0 → 0.18.0-insecure.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.
@@ -0,0 +1,49 @@
1
+ import { CompiledCircuit } from '@noir-lang/noir_js';
2
+
3
+ /** BFV parameter sets the circuits can be compiled against. */
4
+ type CircuitPreset = 'insecure-512' | 'secure-8192';
5
+ /**
6
+ * The circuits whose ABI is shaped by the BFV degree, and which therefore exist once per preset.
7
+ *
8
+ * The aggregation circuits — `crisp_fold`, `crisp_onchain_fold` and `user_data_encryption` — are
9
+ * deliberately absent. Their parameters are proof and verification-key shaped (410/115 fields), not
10
+ * polynomial shaped, so one compiled artifact serves both presets; the fold circuits assert
11
+ * `chain_key_hash` against the insecure *or* the secure constant for exactly that reason. They ship
12
+ * in the main entry point, which is why `verifyProof` works without a preset loaded.
13
+ */
14
+ type CircuitBundle = {
15
+ readonly preset: CircuitPreset;
16
+ readonly crisp: CompiledCircuit;
17
+ readonly crispOnchain: CompiledCircuit;
18
+ readonly userDataEncryptionCt0: CompiledCircuit;
19
+ readonly userDataEncryptionCt1: CompiledCircuit;
20
+ };
21
+ /**
22
+ * Install the preset-bound circuits used by `generateProof`.
23
+ *
24
+ * The bundle is not bundled into the main entry point, because the secure-8192 artifacts are more
25
+ * than an order of magnitude larger than the insecure-512 ones and no consumer needs both. Load the
26
+ * one you want from its subpath and register it once at start-up:
27
+ *
28
+ * ```ts
29
+ * import { setCircuits } from '@crisp-e3/sdk'
30
+ * import { loadCircuits } from '@crisp-e3/sdk/insecure-512'
31
+ *
32
+ * setCircuits(await loadCircuits())
33
+ * ```
34
+ */
35
+ declare const setCircuits: (bundle: CircuitBundle) => void;
36
+ /** The registered bundle, or `null` when none has been installed yet. */
37
+ declare const getRegisteredCircuits: () => CircuitBundle | null;
38
+ /** The preset currently installed, or `null` when none has been installed yet. */
39
+ declare const registeredPreset: () => CircuitPreset | null;
40
+ /**
41
+ * The registered bundle, throwing a directed error when nothing has been installed.
42
+ *
43
+ * Proving cannot fall back to a default preset: a ballot proved against the wrong parameters fails
44
+ * on chain rather than locally, so guessing here would move the failure somewhere much harder to
45
+ * read.
46
+ */
47
+ declare const requireCircuits: () => CircuitBundle;
48
+
49
+ export { type CircuitBundle as C, type CircuitPreset as a, requireCircuits as b, getRegisteredCircuits as g, registeredPreset as r, setCircuits as s };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ export { C as CircuitBundle, a as CircuitPreset, g as getRegisteredCircuits, r as registeredPreset, b as requireCircuits, s as setCircuits } from './circuits-BWegRaZy.js';
1
2
  import { LeanIMTMerkleProof, LeanIMT } from '@zk-kit/lean-imt';
2
3
  import { Hex } from 'viem';
4
+ import '@noir-lang/noir_js';
3
5
 
4
6
  /**
5
7
  * Get the merkle tree data from the CRISP server
@@ -94,6 +96,14 @@ type ProofData = {
94
96
  publicInputs: string[];
95
97
  proof: Uint8Array;
96
98
  encryptedVote: Uint8Array;
99
+ /**
100
+ * The tree index of the entry this input extends, plus one; zero when it extends nothing.
101
+ *
102
+ * `CRISPProgram` reads the parent's commitment from this and hands it to the circuit as
103
+ * `prev_ct_commitment`, and the Secure Process walks each slot's chain by it. Offset by one so
104
+ * that zero means "no parent", which is what index 0 would otherwise be ambiguous with.
105
+ */
106
+ parentIndexPlusOne: number;
97
107
  };
98
108
  /**
99
109
  * Which circuit a ballot is built for.
@@ -103,14 +113,34 @@ type ProofData = {
103
113
  * reads from the token, and matches `CensusMode.ONCHAIN`.
104
114
  */
105
115
  type CensusVariant = 'merkle' | 'onchain';
116
+ /**
117
+ * The two halves of a slot head, which only mean anything together.
118
+ *
119
+ * Modelled as a pair rather than two optional fields: a ciphertext without its index would be
120
+ * proven against one entry and published against another, and the mismatch only surfaces as a
121
+ * rejected proof.
122
+ */
123
+ type SlotHeadInputs = {
124
+ /**
125
+ * The ciphertext currently in the slot: the end of its chain of usable entries, not simply
126
+ * the newest one published. An entry whose bytes do not reproduce its commitment is never
127
+ * selected by the Secure Process and is never a valid parent, so building on it would have
128
+ * this input dropped from the tally.
129
+ */
130
+ previousCiphertext: Uint8Array;
131
+ /** The tree index of `previousCiphertext`, which this input names as its parent. */
132
+ previousIndex: number;
133
+ } | {
134
+ previousCiphertext?: undefined;
135
+ previousIndex?: undefined;
136
+ };
106
137
  type PrepareBallotInputsBase = {
107
- previousCiphertext?: Uint8Array;
108
138
  publicKey: Uint8Array;
109
139
  slotAddress: string;
110
140
  isMaskVote: boolean;
111
141
  numOptions: number;
112
142
  vote: Vote;
113
- };
143
+ } & SlotHeadInputs;
114
144
  /**
115
145
  * Everything needed to encrypt a ballot, before the voter has signed anything.
116
146
  */
@@ -130,8 +160,21 @@ type PrepareBallotInputs = (PrepareBallotInputsBase & {
130
160
  */
131
161
  type PreparedBallot = {
132
162
  circuitInputs: any;
163
+ /**
164
+ * The ciphertext to publish, which is the ballot itself for a vote or a re-vote, and the slot's
165
+ * ciphertext plus the zero ballot for a mask over an occupied slot.
166
+ */
133
167
  encryptedVote: Uint8Array;
168
+ /**
169
+ * The commitment to `encryptedVote`: what the circuit returns, what the E3 program stores, and
170
+ * what `CRISPProgram.ballotDigest` takes as its `ciphertextCommitment` argument.
171
+ *
172
+ * Since the digest is itself a circuit input, a caller has to know this value before proving,
173
+ * which is why the wasm exports it rather than leaving it to be read off the finished proof.
174
+ */
134
175
  ctCommitment: `0x${string}`;
176
+ /** The value {@link ProofData.parentIndexPlusOne} carries through to `encodeSolidityProof`. */
177
+ parentIndexPlusOne: number;
135
178
  censusMode: CensusVariant;
136
179
  };
137
180
  /**
@@ -144,11 +187,23 @@ type DistributiveOmit<T, K extends keyof never> = T extends unknown ? Omit<T, K>
144
187
  /**
145
188
  * A {@link PrepareBallotInputs} plus the round it belongs to.
146
189
  *
147
- * The SDK resolves `previousCiphertext` from the server, so callers do not pass it.
190
+ * The SDK resolves the slot head from the server, so callers pass neither part of it.
148
191
  */
149
192
  type PrepareBallotRequest = {
150
193
  e3Id: bigint;
151
- } & DistributiveOmit<PrepareBallotInputs, 'previousCiphertext'>;
194
+ } & DistributiveOmit<PrepareBallotInputs, 'previousCiphertext' | 'previousIndex'>;
195
+ /**
196
+ * The end of a slot's chain of usable entries: what a new input extends.
197
+ *
198
+ * Not simply the newest entry published to the slot. An entry whose bytes do not reproduce its
199
+ * commitment is never selected by the Secure Process and is never a valid parent, so the server
200
+ * resolves the chain and answers with the entry that actually holds the slot.
201
+ */
202
+ type SlotHead = {
203
+ ciphertext: Uint8Array;
204
+ /** The tree index of that entry. */
205
+ index: number;
206
+ };
152
207
  /**
153
208
  * Type representing the current round returned by the CRISP server (`rounds/current`)
154
209
  */
@@ -277,6 +332,22 @@ declare const getRoundTokenDetails: (serverUrl: string, e3Id: bigint) => Promise
277
332
  * @returns The on chain round data
278
333
  */
279
334
  declare const getOnChainRoundData: (programAddress: string, e3Id: bigint, chainId: number) => Promise<OnChainRoundData>;
335
+ /**
336
+ * Get the voting power a slot may spend in a `CensusMode.ONCHAIN` round, in ballot units.
337
+ *
338
+ * Read from the CRISP program rather than derived here. The contract scales raw token power by a
339
+ * per-round divisor before handing it to the circuit as public input 4, and it is the same
340
+ * contract that verifies the proof — so recomputing the value client-side would mean re-deriving
341
+ * the round's snapshot, its divisor and the rounding, and any drift surfaces only as an opaque
342
+ * verifier failure.
343
+ *
344
+ * @param programAddress - The CRISP program address
345
+ * @param e3Id - The e3Id of the round
346
+ * @param slot - The slot address the ballot is written to
347
+ * @param chainId - The chain the program is deployed on
348
+ * @returns The spendable voting power in ballot units, or 0 for a round that is not ONCHAIN
349
+ */
350
+ declare const getOnchainVotingPower: (programAddress: string, e3Id: bigint, slot: string, chainId: number) => Promise<bigint>;
280
351
  /**
281
352
  * Get the previous ciphertext for a slot from the CRISP server.
282
353
  * Returns undefined when the slot is empty (404).
@@ -284,9 +355,10 @@ declare const getOnChainRoundData: (programAddress: string, e3Id: bigint, chainI
284
355
  * @param serverUrl - The base URL of the CRISP server
285
356
  * @param e3Id - The e3Id of the round
286
357
  * @param address - The address of the slot
287
- * @returns The previous ciphertext for the slot, or undefined if the slot is empty
358
+ * @returns The end of the slot's chain of usable entries and its tree index, or undefined when the
359
+ * slot holds nothing usable. The index is what a new input names as its parent.
288
360
  */
289
- declare const getPreviousCiphertext: (serverUrl: string, e3Id: bigint, address: string) => Promise<Uint8Array | undefined>;
361
+ declare const getPreviousCiphertext: (serverUrl: string, e3Id: bigint, address: string) => Promise<SlotHead | undefined>;
290
362
 
291
363
  /**
292
364
  * Get the current (most recent) round, optionally filtered by requester addresses.
@@ -561,7 +633,7 @@ declare const verifyProof: (proof: ProofData, censusMode?: CensusVariant) => Pro
561
633
  * @param proof The proof data.
562
634
  * @returns The encoded proof data as a hex string.
563
635
  */
564
- declare const encodeSolidityProof: ({ publicInputs, proof, encryptedVote }: ProofData) => Hex;
636
+ declare const encodeSolidityProof: ({ publicInputs, proof, encryptedVote, parentIndexPlusOne }: ProofData) => Hex;
565
637
 
566
638
  /**
567
639
  * A class representing the CRISP SDK.
@@ -700,9 +772,9 @@ declare class CrispSDK {
700
772
  * Get the previous ciphertext input for a slot address in a given round.
701
773
  * @param e3Id - The e3Id of the round
702
774
  * @param address - The address of the slot
703
- * @returns The previous ciphertext, or undefined if the slot is empty
775
+ * @returns The slot head and its tree index, or undefined if the slot holds nothing usable
704
776
  */
705
- getPreviousCiphertext(e3Id: bigint, address: string): Promise<Uint8Array | undefined>;
777
+ getPreviousCiphertext(e3Id: bigint, address: string): Promise<SlotHead | undefined>;
706
778
  }
707
779
 
708
- export { type BroadcastVoteRequest, type BroadcastVoteResponse, type CensusVariant, CreditMode, CrispSDK, type CurrentRoundResponse, type E3StateLiteResponse, type JsonResponse, MAX_MSG_NON_ZERO_COEFFS, MAX_VOTE_OPTIONS, MERKLE_TREE_MAX_DEPTH, type NewRoundRequest, type OnChainRoundData, type PrepareBallotInputs, type PrepareBallotRequest, type PreparedBallot, type ProofData, type RoundDetails, SIGNATURE_MESSAGE, SIGNATURE_MESSAGE_HASH, type TallyResult, type TokenDetails, type TokenHolder, type Vote, type VoteResponseStatus, type VoteStatusResponse, type WebResultResponse, broadcastVote, decodeTally, decryptVote, destroyBBApi, encodeSolidityProof, encodeVote, encryptVote, finishBallotProof, finishMaskProof, generateBFVKeys, generateMerkleProof, generateMerkleTree, getAddressFromSignature, getAllRoundResults, getBalanceAt, getCurrentRound, getEligibleAddresses, getMaxVoteValue, getOnChainRoundData, getPreviousCiphertext, getRoundCiphertext, getRoundDetails, getRoundPublicKey, getRoundResult, getRoundStateLite, getRoundTokenDetails, getScaledBalance, getTokenHolderHashes, getTotalSupplyAt, getTreeData, getVoteStatus, getZeroVote, hashLeaf, prepareBallot, prepareCircuitInputs, requestNewRound, splitDigest, validateVote, verifyProof };
780
+ export { type BroadcastVoteRequest, type BroadcastVoteResponse, type CensusVariant, CreditMode, CrispSDK, type CurrentRoundResponse, type E3StateLiteResponse, type JsonResponse, MAX_MSG_NON_ZERO_COEFFS, MAX_VOTE_OPTIONS, MERKLE_TREE_MAX_DEPTH, type NewRoundRequest, type OnChainRoundData, type PrepareBallotInputs, type PrepareBallotRequest, type PreparedBallot, type ProofData, type RoundDetails, SIGNATURE_MESSAGE, SIGNATURE_MESSAGE_HASH, type SlotHead, type TallyResult, type TokenDetails, type TokenHolder, type Vote, type VoteResponseStatus, type VoteStatusResponse, type WebResultResponse, broadcastVote, decodeTally, decryptVote, destroyBBApi, encodeSolidityProof, encodeVote, encryptVote, finishBallotProof, finishMaskProof, generateBFVKeys, generateMerkleProof, generateMerkleTree, getAddressFromSignature, getAllRoundResults, getBalanceAt, getCurrentRound, getEligibleAddresses, getMaxVoteValue, getOnChainRoundData, getOnchainVotingPower, getPreviousCiphertext, getRoundCiphertext, getRoundDetails, getRoundPublicKey, getRoundResult, getRoundStateLite, getRoundTokenDetails, getScaledBalance, getTokenHolderHashes, getTotalSupplyAt, getTreeData, getVoteStatus, getZeroVote, hashLeaf, prepareBallot, prepareCircuitInputs, requestNewRound, splitDigest, validateVote, verifyProof };