@umbra-privacy/sdk 1.0.0 → 2.0.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.
Files changed (181) hide show
  1. package/README.md +104 -25
  2. package/dist/{addresses-Brzgurv_.d.ts → addresses-B7HybtbJ.d.ts} +2 -1
  3. package/dist/{addresses-D_0YAS6B.d.cts → addresses-CTVY1oi7.d.cts} +2 -1
  4. package/dist/arcium-BXXlryfe.d.cts +20 -0
  5. package/dist/arcium-BXXlryfe.d.ts +20 -0
  6. package/dist/chunk-4RHXVBNI.js +203 -0
  7. package/dist/chunk-4RHXVBNI.js.map +1 -0
  8. package/dist/chunk-4TZVXB5G.js +324 -0
  9. package/dist/chunk-4TZVXB5G.js.map +1 -0
  10. package/dist/chunk-5GUSMQ74.cjs +549 -0
  11. package/dist/chunk-5GUSMQ74.cjs.map +1 -0
  12. package/dist/chunk-5KPQXPQM.js +36 -0
  13. package/dist/chunk-5KPQXPQM.js.map +1 -0
  14. package/dist/chunk-AXD7LXYY.cjs +405 -0
  15. package/dist/chunk-AXD7LXYY.cjs.map +1 -0
  16. package/dist/{chunk-HOEXDXRC.cjs → chunk-BL6WXLPV.cjs} +32 -360
  17. package/dist/chunk-BL6WXLPV.cjs.map +1 -0
  18. package/dist/chunk-CFFLOE7D.cjs +598 -0
  19. package/dist/chunk-CFFLOE7D.cjs.map +1 -0
  20. package/dist/{chunk-BM7N6N7E.js → chunk-CFTW5WNG.js} +3 -325
  21. package/dist/chunk-CFTW5WNG.js.map +1 -0
  22. package/dist/chunk-DD2WCK4C.js +327 -0
  23. package/dist/chunk-DD2WCK4C.js.map +1 -0
  24. package/dist/chunk-DMPMQ74B.cjs +246 -0
  25. package/dist/chunk-DMPMQ74B.cjs.map +1 -0
  26. package/dist/{chunk-2Q75CQQJ.js → chunk-EEKF4553.js} +2 -2
  27. package/dist/chunk-EEKF4553.js.map +1 -0
  28. package/dist/chunk-ENVYYEM4.cjs +113 -0
  29. package/dist/chunk-ENVYYEM4.cjs.map +1 -0
  30. package/dist/chunk-FQX6ZYGJ.js +500 -0
  31. package/dist/chunk-FQX6ZYGJ.js.map +1 -0
  32. package/dist/chunk-FSK2ICMB.cjs +39 -0
  33. package/dist/chunk-FSK2ICMB.cjs.map +1 -0
  34. package/dist/chunk-FZYWLQAF.cjs +355 -0
  35. package/dist/chunk-FZYWLQAF.cjs.map +1 -0
  36. package/dist/chunk-GP26R377.js +436 -0
  37. package/dist/chunk-GP26R377.js.map +1 -0
  38. package/dist/chunk-HA5FLM63.js +393 -0
  39. package/dist/chunk-HA5FLM63.js.map +1 -0
  40. package/dist/chunk-INJ73LXQ.js +1107 -0
  41. package/dist/chunk-INJ73LXQ.js.map +1 -0
  42. package/dist/chunk-JPDF7BIT.cjs +10892 -0
  43. package/dist/chunk-JPDF7BIT.cjs.map +1 -0
  44. package/dist/{chunk-MDFSBU5W.cjs → chunk-LTCKPTZC.cjs} +2 -351
  45. package/dist/chunk-LTCKPTZC.cjs.map +1 -0
  46. package/dist/chunk-MKNCBUFA.js +564 -0
  47. package/dist/chunk-MKNCBUFA.js.map +1 -0
  48. package/dist/chunk-NKVMSABR.cjs +207 -0
  49. package/dist/chunk-NKVMSABR.cjs.map +1 -0
  50. package/dist/chunk-OFDWNWCL.js +70 -0
  51. package/dist/chunk-OFDWNWCL.js.map +1 -0
  52. package/dist/chunk-QJAUUYZU.cjs +331 -0
  53. package/dist/chunk-QJAUUYZU.cjs.map +1 -0
  54. package/dist/chunk-RVUYPKKD.js +10750 -0
  55. package/dist/chunk-RVUYPKKD.js.map +1 -0
  56. package/dist/chunk-TLR7A64G.js +103 -0
  57. package/dist/chunk-TLR7A64G.js.map +1 -0
  58. package/dist/{chunk-MVKTV3FT.cjs → chunk-TQQZGNOI.cjs} +2 -2
  59. package/dist/chunk-TQQZGNOI.cjs.map +1 -0
  60. package/dist/chunk-UOFYS6M3.js +219 -0
  61. package/dist/chunk-UOFYS6M3.js.map +1 -0
  62. package/dist/chunk-UXMQI6B7.js +2406 -0
  63. package/dist/chunk-UXMQI6B7.js.map +1 -0
  64. package/dist/chunk-WN75ORDT.js +571 -0
  65. package/dist/chunk-WN75ORDT.js.map +1 -0
  66. package/dist/chunk-Y55PYKXH.cjs +595 -0
  67. package/dist/chunk-Y55PYKXH.cjs.map +1 -0
  68. package/dist/chunk-YEZBTYCP.cjs +77 -0
  69. package/dist/chunk-YEZBTYCP.cjs.map +1 -0
  70. package/dist/chunk-ZQOIYCGA.cjs +1126 -0
  71. package/dist/chunk-ZQOIYCGA.cjs.map +1 -0
  72. package/dist/chunk-ZY3TSHMJ.cjs +2665 -0
  73. package/dist/chunk-ZY3TSHMJ.cjs.map +1 -0
  74. package/dist/client-DkVBHMWb.d.cts +2613 -0
  75. package/dist/client-V4AF6Bz9.d.ts +2613 -0
  76. package/dist/common/pda/index.cjs +145 -0
  77. package/dist/common/pda/index.cjs.map +1 -0
  78. package/dist/common/pda/index.d.cts +1250 -0
  79. package/dist/common/pda/index.d.ts +1250 -0
  80. package/dist/common/pda/index.js +8 -0
  81. package/dist/common/pda/index.js.map +1 -0
  82. package/dist/constants/index.cjs +38 -164
  83. package/dist/constants/index.cjs.map +1 -1
  84. package/dist/constants/index.d.cts +8 -425
  85. package/dist/constants/index.d.ts +8 -425
  86. package/dist/constants/index.js +15 -124
  87. package/dist/constants/index.js.map +1 -1
  88. package/dist/crypto/index.cjs +583 -0
  89. package/dist/crypto/index.cjs.map +1 -0
  90. package/dist/crypto/index.d.cts +6731 -0
  91. package/dist/crypto/index.d.ts +6731 -0
  92. package/dist/crypto/index.js +14 -0
  93. package/dist/crypto/index.js.map +1 -0
  94. package/dist/{cryptography-BTGC72u-.d.ts → cryptography-BFSJcvi6.d.ts} +3 -2465
  95. package/dist/{cryptography-BTGC72u-.d.cts → cryptography-D6tPDh-Y.d.cts} +3 -2465
  96. package/dist/errors/index.cjs +64 -54
  97. package/dist/errors/index.d.cts +7 -797
  98. package/dist/errors/index.d.ts +7 -797
  99. package/dist/errors/index.js +3 -1
  100. package/dist/errors-B9EoPeWV.d.cts +593 -0
  101. package/dist/errors-B9EoPeWV.d.ts +593 -0
  102. package/dist/errors-DAIrstEL.d.cts +300 -0
  103. package/dist/errors-DPNMfyh0.d.ts +300 -0
  104. package/dist/index-BG0yjL7C.d.cts +6006 -0
  105. package/dist/index-ByynoyBO.d.ts +6006 -0
  106. package/dist/index.cjs +5126 -16118
  107. package/dist/index.cjs.map +1 -1
  108. package/dist/index.d.cts +1031 -7685
  109. package/dist/index.d.ts +1031 -7685
  110. package/dist/index.js +3219 -14905
  111. package/dist/index.js.map +1 -1
  112. package/dist/interfaces/index.d.cts +14 -6
  113. package/dist/interfaces/index.d.ts +14 -6
  114. package/dist/interfaces-43cReBcS.d.cts +3346 -0
  115. package/dist/interfaces-B8xKNl_6.d.ts +997 -0
  116. package/dist/interfaces-D2NO6kDD.d.cts +997 -0
  117. package/dist/interfaces-z_xYJlgV.d.ts +3346 -0
  118. package/dist/math/index.cjs +115 -0
  119. package/dist/math/index.cjs.map +1 -0
  120. package/dist/math/index.d.cts +1327 -0
  121. package/dist/math/index.d.ts +1327 -0
  122. package/dist/math/index.js +10 -0
  123. package/dist/math/index.js.map +1 -0
  124. package/dist/networks-RMd3abPE.d.ts +44 -0
  125. package/dist/networks-yAoO8peQ.d.cts +44 -0
  126. package/dist/relayer-NRRMSMNB.js +4 -0
  127. package/dist/relayer-NRRMSMNB.js.map +1 -0
  128. package/dist/relayer-RJHEIXJG.cjs +21 -0
  129. package/dist/relayer-RJHEIXJG.cjs.map +1 -0
  130. package/dist/solana/index.cjs +56 -0
  131. package/dist/solana/index.cjs.map +1 -0
  132. package/dist/solana/index.d.cts +105 -0
  133. package/dist/solana/index.d.ts +105 -0
  134. package/dist/solana/index.js +7 -0
  135. package/dist/solana/index.js.map +1 -0
  136. package/dist/{index-CLj_zWSD.d.ts → temporal-BbRaEPoO.d.ts} +1 -1
  137. package/dist/{index-CX6_pIRS.d.cts → temporal-oUj7iCaq.d.cts} +1 -1
  138. package/dist/transaction-forwarder-5mAMTjw6.d.ts +1155 -0
  139. package/dist/transaction-forwarder-C6gMUG7a.d.cts +1155 -0
  140. package/dist/types/index.cjs +232 -231
  141. package/dist/types/index.d.cts +15 -1485
  142. package/dist/types/index.d.ts +15 -1485
  143. package/dist/types/index.js +2 -1
  144. package/dist/types-BohhvPth.d.cts +87 -0
  145. package/dist/types-CW0oTT0j.d.ts +87 -0
  146. package/dist/types-C_V_CaKK.d.cts +2468 -0
  147. package/dist/types-C_V_CaKK.d.ts +2468 -0
  148. package/dist/types-Ca7frykr.d.ts +793 -0
  149. package/dist/types-CuKeoI19.d.cts +1296 -0
  150. package/dist/types-CxfTIpN9.d.ts +1052 -0
  151. package/dist/{types-n-sHFcgr.d.ts → types-D1jDUjfN.d.ts} +2 -2
  152. package/dist/types-DKEDUlH9.d.ts +1296 -0
  153. package/dist/types-EKuIfxTz.d.cts +1052 -0
  154. package/dist/{types-BBuELtY8.d.cts → types-IMGYmlv-.d.cts} +2 -2
  155. package/dist/types-PwNLi_2k.d.cts +793 -0
  156. package/dist/utils/index.cjs +823 -525
  157. package/dist/utils/index.d.cts +1711 -4021
  158. package/dist/utils/index.d.ts +1711 -4021
  159. package/dist/utils/index.js +9 -3
  160. package/dist/{versions-D9PqsEvj.d.cts → versions-BRlR36EA.d.cts} +1 -0
  161. package/dist/{versions-D9PqsEvj.d.ts → versions-BRlR36EA.d.ts} +1 -0
  162. package/package.json +79 -18
  163. package/dist/chunk-2Q75CQQJ.js.map +0 -1
  164. package/dist/chunk-BM7N6N7E.js.map +0 -1
  165. package/dist/chunk-GXKSUB2U.cjs +0 -4416
  166. package/dist/chunk-GXKSUB2U.cjs.map +0 -1
  167. package/dist/chunk-HOEXDXRC.cjs.map +0 -1
  168. package/dist/chunk-MDFSBU5W.cjs.map +0 -1
  169. package/dist/chunk-MQY7HDIA.js +0 -600
  170. package/dist/chunk-MQY7HDIA.js.map +0 -1
  171. package/dist/chunk-MVKTV3FT.cjs.map +0 -1
  172. package/dist/chunk-PG2J6V6Y.js +0 -4094
  173. package/dist/chunk-PG2J6V6Y.js.map +0 -1
  174. package/dist/chunk-VEGLTTYQ.cjs +0 -621
  175. package/dist/chunk-VEGLTTYQ.cjs.map +0 -1
  176. package/dist/chunk-WVHQ46DD.js +0 -758
  177. package/dist/chunk-WVHQ46DD.js.map +0 -1
  178. package/dist/index-B9pDY73x.d.ts +0 -12933
  179. package/dist/index-D33yo0qB.d.cts +0 -12933
  180. package/dist/networks-C-orpSFW.d.ts +0 -65
  181. package/dist/networks-FxYERGD1.d.cts +0 -65
@@ -0,0 +1,3346 @@
1
+ import { C as Curve25519FieldElement, B as Bn254FieldElement, g as PoseidonHash, h as PoseidonCounter, P as PoseidonKey, i as PoseidonKeystream, j as PoseidonCiphertext, k as PoseidonPlaintext, R as RcEncryptionNonce, D as DailyViewingKey, M as MasterSeed, H as HourlyViewingKey, d as MasterViewingKey, f as MintViewingKey, l as MinuteViewingKey, e as MonthlyViewingKey, S as SecondViewingKey, Y as YearlyViewingKey, m as RcCiphertext, n as RcPlaintext, o as RcCounter, p as RcKey } from './cryptography-D6tPDh-Y.cjs';
2
+ import { Address } from '@solana/kit';
3
+ import { i as U512BeBytes, f as U256 } from './types-C_V_CaKK.cjs';
4
+ import { Y as Year, M as Month, D as Day, H as Hour, a as Minute, S as Second } from './types-IMGYmlv-.cjs';
5
+ import { C as Curve25519KeypairResult } from './types-CuKeoI19.cjs';
6
+
7
+ /**
8
+ * Fiat-Shamir Challenge Interfaces
9
+ *
10
+ * This module defines TypeScript function type interfaces and dependency injection
11
+ * interfaces for Fiat-Shamir challenge generation and related polynomial operations
12
+ * used in Umbra's zero-knowledge proof systems.
13
+ *
14
+ * ## Fiat-Shamir Heuristic — Background
15
+ *
16
+ * An interactive sigma-protocol requires a verifier who sends a uniformly random
17
+ * challenge after seeing the prover's first message. The Fiat-Shamir transform
18
+ * replaces this interactive step with a hash of the transcript, turning the proof
19
+ * into a non-interactive argument of knowledge (NIAOK) secure in the Random
20
+ * Oracle Model (ROM).
21
+ *
22
+ * For Umbra's Groth16-based claim instructions, the challenge is derived from a
23
+ * 10-element transcript that includes all public inputs (nullifiers, commitments,
24
+ * root, fee parameters, etc.) in a canonical order defined in
25
+ * `rules/fiat-shamir-and-aggregated-hash.md`. The ordering **must not change**
26
+ * because the Circom circuit and the on-chain verifier both encode the same
27
+ * ordering — a mismatch silently produces wrong proofs.
28
+ *
29
+ * ## Security Considerations
30
+ *
31
+ * - Challenge generation must be deterministic given the same transcript.
32
+ * - Outputs must be uniformly distributed over the Curve25519 prime field GF(p).
33
+ * - All arithmetic must use constant-time field operations to prevent timing side-channels.
34
+ * - The hash function used (Keccak-256) must be modelled as a random oracle; do
35
+ * not substitute weaker primitives.
36
+ *
37
+ * @packageDocumentation
38
+ * @module interfaces/cryptography/challenges
39
+ * @public
40
+ */
41
+
42
+ /**
43
+ * Function type for generating Fiat-Shamir challenges from a proof transcript.
44
+ *
45
+ * Takes a serialised transcript (an arbitrary byte array representing all public
46
+ * inputs in canonical order) and produces a uniformly distributed element of the
47
+ * Curve25519 prime field GF(p = 2^255 - 19) using Keccak-256 with rejection
48
+ * sampling.
49
+ *
50
+ * @param input - The serialised transcript byte array. Must contain all public
51
+ * proof inputs concatenated in the order mandated by the Circom circuit and
52
+ * on-chain verifier. The transcript is treated as opaque bytes; no internal
53
+ * parsing is performed.
54
+ * @returns A {@link Curve25519FieldElement} in the range [0, 2^255 - 19) derived
55
+ * deterministically from `input`.
56
+ *
57
+ * @remarks
58
+ * ## Contract
59
+ *
60
+ * Implementations of this type **must** guarantee:
61
+ * 1. **Determinism** — the same `input` always produces the same output.
62
+ * 2. **Uniform distribution** — the output is statistically indistinguishable
63
+ * from a uniformly random element of GF(p). Bias from simple modular
64
+ * reduction is not acceptable; use rejection sampling.
65
+ * 3. **No additional state** — the function must be pure (no caches or counters
66
+ * that could make two calls with the same `input` return different values).
67
+ *
68
+ * ## Algorithm (reference implementation)
69
+ *
70
+ * 1. Compute `h = Keccak256(input)` — 256-bit output.
71
+ * 2. Clear bit 255 (`h[31] &= 0x7F` in little-endian) to constrain to 255 bits.
72
+ * 3. Interpret `h` as a little-endian 256-bit unsigned integer `v`.
73
+ * 4. If `v < p`, return `v` as the challenge.
74
+ * 5. Otherwise, re-hash `h` (hash chaining) and repeat from step 2.
75
+ *
76
+ * ## Why Transcript Ordering Matters for Soundness
77
+ *
78
+ * In the ROM, the challenge is bound to the *entire* transcript. If two different
79
+ * transcripts (e.g. the same inputs in a different order) collide to the same
80
+ * challenge, an adversary could craft a proof that passes for one statement but
81
+ * was computed for another. The canonical element ordering in
82
+ * `rules/fiat-shamir-and-aggregated-hash.md` is part of the protocol definition
83
+ * and must be respected by all callers.
84
+ *
85
+ * @public
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const generateChallenge: FiatShamirChallengeGeneratorFunction =
90
+ * getFiatShamirChallengeGeneratorFunction();
91
+ *
92
+ * // Serialise public inputs in canonical order before hashing:
93
+ * const transcript = buildFiatShamirTranscript({
94
+ * merkleRoot,
95
+ * nullifiers,
96
+ * utxoCommitments,
97
+ * recipientPublicKey,
98
+ * fees,
99
+ * });
100
+ * const challenge: Curve25519FieldElement = generateChallenge(transcript);
101
+ * ```
102
+ *
103
+ * @see {@link getFiatShamirChallengeGeneratorFunction} — factory that returns the default implementation
104
+ */
105
+ type FiatShamirChallengeGeneratorFunction = (input: Uint8Array) => Curve25519FieldElement;
106
+ /**
107
+ * Function type for computing successive powers of a Fiat-Shamir challenge value.
108
+ *
109
+ * Returns an array `[c^0, c^1, c^2, ..., c^maxPower]` where `c` is the challenge
110
+ * and all arithmetic is performed in the Curve25519 prime field GF(p = 2^255 - 19).
111
+ *
112
+ * @param challenge - The base challenge value to exponentiate.
113
+ * Must be a valid {@link Curve25519FieldElement} (i.e. `0 <= challenge < p`).
114
+ * @param maxPower - The highest power to compute (inclusive). Must be a
115
+ * non-negative integer. `maxPower === 0` returns `[1n]`.
116
+ * @returns An array of length `maxPower + 1` containing
117
+ * `[1, challenge, challenge^2, ..., challenge^maxPower]` as
118
+ * {@link Curve25519FieldElement} values.
119
+ *
120
+ * @throws {Error} If `maxPower` is negative.
121
+ *
122
+ * @remarks
123
+ * ## Contract
124
+ *
125
+ * Implementations of this type **must** guarantee:
126
+ * - The returned array has exactly `maxPower + 1` elements.
127
+ * - `result[0] === 1n` always (challenge^0 = 1 by convention).
128
+ * - `result[1] === challenge` when `maxPower >= 1`.
129
+ * - All elements are valid {@link Curve25519FieldElement} values in [0, p).
130
+ * - The computation uses O(maxPower) field multiplications (no repeated squaring
131
+ * is necessary because all intermediate values are needed).
132
+ *
133
+ * ## Use in ZK Protocols
134
+ *
135
+ * Challenge powers appear in batched polynomial commitment schemes: if a verifier
136
+ * wants to check multiple polynomial evaluations simultaneously, it combines
137
+ * the checks using challenge powers as random coefficients. For example, in
138
+ * a 10-element Fiat-Shamir transcript the Groth16 circuit may need
139
+ * `[c^0, ..., c^9]` to batch-verify all input commitments in a single pairing.
140
+ *
141
+ * @public
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * const computePowers: ChallengePowersFunction = getChallengePowersFunction();
146
+ * const challenge = generateChallenge(transcript);
147
+ * const powers = computePowers(challenge, 9);
148
+ * // powers[0] === 1n
149
+ * // powers[1] === challenge
150
+ * // powers[9] === challenge^9 mod p
151
+ * ```
152
+ *
153
+ * @see {@link getChallengePowersFunction} — factory that returns the default implementation
154
+ * @see {@link FiatShamirChallengeGeneratorFunction} — produces the challenge input
155
+ */
156
+ type ChallengePowersFunction = (challenge: Curve25519FieldElement, maxPower: number) => Curve25519FieldElement[];
157
+ /**
158
+ * Function type for evaluating a univariate polynomial over the Curve25519 field.
159
+ *
160
+ * For a polynomial P(x) = c[0] + c[1]·x + c[2]·x² + ... + c[n]·x^n,
161
+ * computes `P(point)` using Horner's method. All arithmetic is performed in
162
+ * GF(p = 2^255 - 19).
163
+ *
164
+ * @param coefficients - The coefficient array `[c[0], c[1], ..., c[n]]`
165
+ * where `c[i]` is the coefficient of `x^i` (constant term first, highest
166
+ * degree last). All elements must be valid {@link Curve25519FieldElement} values.
167
+ * An empty array represents the zero polynomial and returns `0n`.
168
+ * @param point - The evaluation point, must be a valid {@link Curve25519FieldElement}.
169
+ * @returns `P(point) mod p` as a {@link Curve25519FieldElement}.
170
+ *
171
+ * @remarks
172
+ * ## Contract
173
+ *
174
+ * Implementations of this type **must** guarantee:
175
+ * - The result is a valid {@link Curve25519FieldElement} in [0, p).
176
+ * - Empty `coefficients` returns `0n`.
177
+ * - The evaluation uses Horner's method or equivalent (n multiplications and
178
+ * n additions for a degree-n polynomial), not the naïve O(n^2) approach.
179
+ *
180
+ * ## Horner's Method — Mathematical Derivation
181
+ *
182
+ * ```
183
+ * P(x) = c[0] + c[1]·x + c[2]·x² + ... + c[n]·x^n
184
+ * = c[0] + x·(c[1] + x·(c[2] + ... + x·c[n]))
185
+ * ```
186
+ *
187
+ * Starting from the innermost term `c[n]`, multiply by `x` and add `c[n-1]`,
188
+ * repeat until `c[0]` is incorporated. This requires exactly n multiplications
189
+ * and n additions regardless of the polynomial's degree — the minimum possible.
190
+ *
191
+ * ## Edge Cases
192
+ * - Empty coefficients array → returns `0n`.
193
+ * - Single coefficient `[c]` → returns `c` (constant polynomial, `point` is ignored).
194
+ *
195
+ * @public
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * const evaluate: PolynomialEvaluatorFunction = getPolynomialEvaluatorFunction();
200
+ *
201
+ * // P(x) = 1 + 2x + 3x^2
202
+ * const coefficients = [1n, 2n, 3n] as Curve25519FieldElement[];
203
+ * const point = 2n as Curve25519FieldElement;
204
+ * const value = evaluate(coefficients, point);
205
+ * // value === 1 + 2*2 + 3*4 === 17n
206
+ * ```
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * // Zero polynomial
211
+ * const zero = evaluate([], anyPoint); // === 0n
212
+ *
213
+ * // Constant polynomial
214
+ * const constant = evaluate([42n as Curve25519FieldElement], anyPoint); // === 42n
215
+ * ```
216
+ *
217
+ * @see {@link getPolynomialEvaluatorFunction} — factory that returns the default implementation
218
+ */
219
+ type PolynomialEvaluatorFunction = (coefficients: Curve25519FieldElement[], point: Curve25519FieldElement) => Curve25519FieldElement;
220
+ /**
221
+ * Function type for modular exponentiation over the Curve25519 prime field.
222
+ *
223
+ * Computes `base^exp mod p` where `p = 2^255 - 19` is the Curve25519 field prime.
224
+ * The exponent may be any non-negative `bigint`.
225
+ *
226
+ * @param base - The base value. Must be a valid {@link Curve25519FieldElement} in [0, p).
227
+ * @param exp - The exponent. May be any non-negative `bigint`; large values (e.g. the
228
+ * Rescue-XLIX inverse alpha exponent) are supported.
229
+ * @returns `base^exp mod p` as a {@link Curve25519FieldElement}.
230
+ *
231
+ * @remarks
232
+ * ## Contract
233
+ *
234
+ * Implementations of this type **must** guarantee:
235
+ * - The result is a valid {@link Curve25519FieldElement} in [0, p).
236
+ * - `base^0 === 1n` for all bases (including `0^0 = 1` by convention).
237
+ * - The algorithm runs in O(log exp) field multiplications.
238
+ *
239
+ * ## Algorithm
240
+ *
241
+ * Uses the standard binary square-and-multiply (right-to-left) method. For
242
+ * the special case where `exp === 0n`, returns `1n` immediately without entering
243
+ * the multiplication loop.
244
+ *
245
+ * ## Use Cases
246
+ *
247
+ * This function type is primarily used:
248
+ * - In the Rescue-XLIX inverse S-box: `x^(1/alpha)` requires computing the
249
+ * multiplicative inverse exponent over GF(p).
250
+ * - In pairing-based protocols where field element inversions are expressed
251
+ * as exponentiations using Fermat's little theorem: `x^(p-2)`.
252
+ *
253
+ * @public
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const modPow: ModuloPowCurve25519Function = getModuloPowCurve25519Function();
258
+ * const base = 2n as Curve25519FieldElement;
259
+ * const result = modPow(base, 10n);
260
+ * // result === 1024n
261
+ * ```
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * // Fermat's little theorem: x^(p-2) === x^(-1) mod p
266
+ * const modPow = getModuloPowCurve25519Function();
267
+ * const inverse = modPow(someElement, CURVE25519_FIELD_PRIME - 2n);
268
+ * ```
269
+ *
270
+ * @see {@link getModuloPowCurve25519Function} — factory that returns the default implementation
271
+ */
272
+ type ModuloPowCurve25519Function = (base: Curve25519FieldElement, exp: bigint) => Curve25519FieldElement;
273
+ /**
274
+ * Optional dependency injection bag for {@link getChallengePowersFunction}.
275
+ *
276
+ * Allows callers to substitute a custom modular multiplication implementation,
277
+ * primarily for unit testing (e.g. wrapping with a spy) or for environments
278
+ * that provide a native field arithmetic implementation. When fields are
279
+ * omitted, the default constant-time Curve25519 multiplication is used.
280
+ *
281
+ * @remarks
282
+ * ## Why Dependency Injection?
283
+ *
284
+ * The challenge powers function captures `modMul` in a closure. Injecting
285
+ * the function at construction time (rather than calling a global singleton
286
+ * on every multiplication) avoids global state and makes the function's
287
+ * behaviour fully deterministic for a given `modMul` implementation.
288
+ *
289
+ * @public
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * import { getChallengePowersFunction } from './challenges';
294
+ *
295
+ * // Testing: use a spy to count multiplications
296
+ * let mulCount = 0;
297
+ * const spyModMul = (a: bigint, b: bigint) => { mulCount++; return (a * b) % CURVE25519_FIELD_PRIME; };
298
+ * const powers = getChallengePowersFunction({ modMul: spyModMul })(challenge, 5);
299
+ * console.log(mulCount); // === 4 (for maxPower === 5)
300
+ * ```
301
+ */
302
+ interface ChallengePowersDeps {
303
+ /**
304
+ * Custom modular multiplication function over GF(p = 2^255 - 19).
305
+ *
306
+ * If provided, this function is used in place of the default constant-time
307
+ * Curve25519 multiplication. The function **must** return a value in [0, p)
308
+ * for any pair of inputs `(a, b)` in [0, p).
309
+ *
310
+ * @defaultValue The default constant-time implementation from `math/curve25519/field-arithmetic`.
311
+ */
312
+ readonly modMul?: (a: bigint, b: bigint) => bigint;
313
+ }
314
+ /**
315
+ * Optional dependency injection bag for {@link getPolynomialEvaluatorFunction}.
316
+ *
317
+ * Allows callers to substitute custom modular addition and/or multiplication
318
+ * implementations, primarily for unit testing or specialised environments.
319
+ * When fields are omitted, the default constant-time Curve25519 operations are used.
320
+ *
321
+ * @remarks
322
+ * ## Partial Overrides
323
+ *
324
+ * Either `modAdd` or `modMul` may be omitted independently. If only one is
325
+ * provided, the other falls back to its default implementation. This is useful
326
+ * when you want to test only one of the two arithmetic paths in isolation.
327
+ *
328
+ * ## Caching Caveat
329
+ *
330
+ * When any custom dependency is provided, the returned evaluator function is
331
+ * **not** cached (unlike the no-deps default singleton). Each call to
332
+ * `getPolynomialEvaluatorFunction` with non-empty deps creates a fresh closure.
333
+ *
334
+ * @public
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * import { getPolynomialEvaluatorFunction } from './challenges';
339
+ *
340
+ * // Testing with a modular addition spy
341
+ * let addCount = 0;
342
+ * const spyModAdd = (a: bigint, b: bigint) => { addCount++; return (a + b) % PRIME; };
343
+ * const evaluate = getPolynomialEvaluatorFunction({ modAdd: spyModAdd });
344
+ * evaluate([1n, 2n, 3n] as Curve25519FieldElement[], 4n as Curve25519FieldElement);
345
+ * console.log(addCount); // === 2 (for a degree-2 polynomial)
346
+ * ```
347
+ */
348
+ interface PolynomialEvaluatorDeps {
349
+ /**
350
+ * Custom modular addition function over GF(p = 2^255 - 19).
351
+ *
352
+ * If provided, this function is used in place of the default constant-time
353
+ * Curve25519 addition. The function **must** return a value in [0, p) for
354
+ * any pair of inputs `(a, b)` in [0, p).
355
+ *
356
+ * @defaultValue The default constant-time implementation from `math/curve25519/field-arithmetic`.
357
+ */
358
+ readonly modAdd?: (a: bigint, b: bigint) => bigint;
359
+ /**
360
+ * Custom modular multiplication function over GF(p = 2^255 - 19).
361
+ *
362
+ * If provided, this function is used in place of the default constant-time
363
+ * Curve25519 multiplication. The function **must** return a value in [0, p)
364
+ * for any pair of inputs `(a, b)` in [0, p).
365
+ *
366
+ * @defaultValue The default constant-time implementation from `math/curve25519/field-arithmetic`.
367
+ */
368
+ readonly modMul?: (a: bigint, b: bigint) => bigint;
369
+ }
370
+
371
+ /**
372
+ * Poseidon Cipher Interfaces
373
+ *
374
+ * This module defines the TypeScript interface types for Poseidon hash and cipher
375
+ * operations. Poseidon is a cryptographic hash function optimized for zero-knowledge
376
+ * proof systems, operating natively on field elements.
377
+ *
378
+ * ## Overview
379
+ *
380
+ * Poseidon is designed for efficiency in SNARK and STARK circuits. It uses
381
+ * the BN254 (alt_bn128) field, making it compatible with Ethereum precompiles
382
+ * and widely-used ZK proof systems like Groth16 and PLONK.
383
+ *
384
+ * ## Features
385
+ *
386
+ * - **Hash Function**: Collision-resistant hashing of field elements
387
+ * - **Encryption**: Symmetric encryption using Poseidon permutation
388
+ * - **Decryption**: Symmetric decryption recovering original plaintexts
389
+ * - **Keystream Generation**: Counter-mode key derivation for streaming encryption
390
+ *
391
+ * ## Interface Design: Dependency Injection
392
+ *
393
+ * Every function type in this module is defined as a `type` alias for a function
394
+ * signature rather than as a concrete implementation. This enables dependency
395
+ * injection throughout the SDK: callers declare what they need
396
+ * (e.g., `PoseidonHashFunction`) and receive an implementation via a getter
397
+ * (e.g., `getPoseidonHasher()`). Tests can substitute mock implementations, and
398
+ * the production code remains decoupled from the underlying `@noble/curves` library.
399
+ *
400
+ * ## Aggregation vs. Hashing
401
+ *
402
+ * Two distinct hash function types are provided:
403
+ * - {@link PoseidonHashFunction} — low-level, returns an unbranded `Bn254FieldElement`.
404
+ * Suitable for recursive hashing, Merkle tree construction, and any use where the
405
+ * caller manages the output type.
406
+ * - {@link PoseidonAggregatorHashFunction} — high-level aggregator, returns a branded
407
+ * {@link PoseidonHash}. Used specifically for the aggregated ZK public input (the
408
+ * 70-element Poseidon chain that collapses all UTXO fields into a single on-chain
409
+ * verifier input).
410
+ *
411
+ * @see {@link https://eprint.iacr.org/2019/458} Poseidon: A New Hash Function for Zero-Knowledge Proof Systems
412
+ * @see {@link PoseidonKey} for the user's Poseidon private key type
413
+ * @see {@link PoseidonHashFunction} for the low-level hash interface
414
+ * @see {@link PoseidonAggregatorHashFunction} for the high-level aggregator interface
415
+ *
416
+ * @packageDocumentation
417
+ * @module crypto/poseidon/interfaces
418
+ */
419
+
420
+ /**
421
+ * An asynchronous function that computes a Poseidon hash over N BN254 field elements.
422
+ *
423
+ * This is the foundational Poseidon interface in the SDK. It maps an ordered array of
424
+ * {@link Bn254FieldElement} values to a single {@link Bn254FieldElement} output using
425
+ * the Poseidon permutation with parameters tuned for the BN254 scalar field. The
426
+ * implementation is compatible with Circom's `Poseidon(N)` template.
427
+ *
428
+ * @param dataPoints - An ordered, readonly array of {@link Bn254FieldElement} values to hash.
429
+ * The implementation supports 1 to 12 elements. Input order is significant:
430
+ * `hash([a, b]) ≠ hash([b, a])`.
431
+ * @returns A `Promise` resolving to a single {@link Bn254FieldElement} — the Poseidon
432
+ * hash output. The output is always a valid BN254 field element.
433
+ *
434
+ * @remarks
435
+ * ## Poseidon Construction
436
+ *
437
+ * The Poseidon hash function uses a sponge construction with a width-`t` state
438
+ * (where `t = N + 1`) over the BN254 scalar field F_r. The permutation consists of:
439
+ * - Full rounds (applying x^5 to the entire state) at the beginning and end.
440
+ * - Partial rounds (applying x^5 only to the first element) in the middle.
441
+ *
442
+ * Round counts and MDS matrix coefficients are fixed parameters determined by
443
+ * the security analysis in the Poseidon paper (eprint 2019/458). They cannot
444
+ * be changed without breaking compatibility with existing ZK circuits.
445
+ *
446
+ * ## ZK-Friendliness
447
+ *
448
+ * Poseidon requires approximately 8N R1CS constraints per hash of N field elements,
449
+ * compared to ~25,000 for SHA-256. This makes it practical to prove hash pre-images
450
+ * inside a Groth16 proof. In Umbra, this property is essential for:
451
+ * - Proving knowledge of a UTXO's opening (amount, nullifier, blinding factor).
452
+ * - Proving membership in the indexed Merkle tree (IMT) without revealing the leaf.
453
+ * - Generating Fiat-Shamir challenges from a transcript of public values.
454
+ *
455
+ * ## Async Interface
456
+ *
457
+ * The `Promise` wrapper is used for consistency with the rest of the SDK's
458
+ * cryptographic API. The underlying computation is synchronous, but callers should
459
+ * always `await` the result.
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * import { getPoseidonHasher } from "@umbra/sdk";
464
+ *
465
+ * const hasher: PoseidonHashFunction = getPoseidonHasher();
466
+ *
467
+ * // Hash two field elements (order matters)
468
+ * const h1 = await hasher([123n, 456n]);
469
+ * const h2 = await hasher([456n, 123n]);
470
+ * // h1 !== h2 in general
471
+ *
472
+ * // Hash a single element (used as a PRF output or commitment)
473
+ * const commitment = await hasher([secretValue]);
474
+ * ```
475
+ *
476
+ * @example
477
+ * ```typescript
478
+ * // Merkle tree parent node computation
479
+ * const parent = await hasher([leftChild, rightChild]);
480
+ * ```
481
+ *
482
+ * @see {@link PoseidonAggregatorHashFunction} for the branded-output aggregation variant
483
+ * @see {@link PoseidonPrfFunction} for the PRF interface built on top of this hash
484
+ * @public
485
+ */
486
+ type PoseidonHashFunction = (dataPoints: readonly Bn254FieldElement[]) => Promise<Bn254FieldElement>;
487
+ /**
488
+ * An asynchronous function that encrypts an array of {@link PoseidonPlaintext} values
489
+ * using Poseidon counter-mode encryption.
490
+ *
491
+ * This encryptor is the write side of Umbra's confidential token account scheme.
492
+ * For each plaintext at position `i` (0-indexed), it derives an independent keystream
493
+ * via the Poseidon PRF and adds it to the plaintext modulo the BN254 field prime,
494
+ * producing the corresponding ciphertext.
495
+ *
496
+ * @param plaintexts - An ordered, readonly array of {@link PoseidonPlaintext} values to encrypt.
497
+ * Each element is encrypted independently at its array position. The array length
498
+ * determines how many counter values are consumed.
499
+ * @param key - The {@link PoseidonKey} (user's Poseidon private key, derived from the master
500
+ * seed) used as the PRF key for keystream generation. Must be kept secret.
501
+ * @returns A `Promise` resolving to an array of {@link PoseidonCiphertext} values, in the
502
+ * same order as the input plaintexts. `result[i]` is the encryption of `plaintexts[i]`.
503
+ *
504
+ * @remarks
505
+ * ## Encryption Scheme
506
+ *
507
+ * For each plaintext position `i`, the cipher operates as:
508
+ * ```
509
+ * keystream[i] = Poseidon([key, i, 2n])
510
+ * ciphertext[i] = (plaintext[i] + keystream[i]) mod BN254_FIELD_PRIME
511
+ * ```
512
+ *
513
+ * The domain separation constant `2n` in the third argument slot ensures that
514
+ * keystream generation is distinct from any other Poseidon usage in the protocol
515
+ * (e.g., commitment hashing, Fiat-Shamir challenges).
516
+ *
517
+ * ## What Is Encrypted
518
+ *
519
+ * In Umbra's confidential token account model, the encrypted fields are:
520
+ * - Token balance (as a field element representing the token amount).
521
+ * - Blinding factors associated with UTXO commitments.
522
+ *
523
+ * These ciphertexts are stored in the on-chain `EncryptedTokenAccount` state and
524
+ * can only be decrypted by the holder of the corresponding `PoseidonKey`.
525
+ *
526
+ * ## IND-CPA Security
527
+ *
528
+ * Under the PRF security assumption for Poseidon, each ciphertext is computationally
529
+ * indistinguishable from a uniformly random field element. The scheme provides
530
+ * IND-CPA security as long as the key is secret and counter values are not reused.
531
+ *
532
+ * @example
533
+ * ```typescript
534
+ * import { getPoseidonEncryptor } from "@umbra/sdk";
535
+ *
536
+ * const encryptor: PoseidonEncryptorFunction = getPoseidonEncryptor();
537
+ *
538
+ * // Encrypt a token balance and blinding factor together
539
+ * const balance: PoseidonPlaintext = ...; // amount as field element
540
+ * const blinding: PoseidonPlaintext = ...; // random blinding factor
541
+ *
542
+ * const ciphertexts = await encryptor([balance, blinding], myPoseidonKey);
543
+ * // ciphertexts[0] = encryption of balance (counter 0)
544
+ * // ciphertexts[1] = encryption of blinding (counter 1)
545
+ * ```
546
+ *
547
+ * @see {@link PoseidonDecryptorFunction} for the corresponding decryption function
548
+ * @see {@link PoseidonKeystreamGeneratorFunction} for direct keystream access
549
+ * @see {@link PoseidonKey} for the key type accepted by this function
550
+ * @public
551
+ */
552
+ type PoseidonEncryptorFunction = (plaintexts: readonly PoseidonPlaintext[], key: PoseidonKey) => Promise<PoseidonCiphertext[]>;
553
+ /**
554
+ * An asynchronous function that decrypts an array of {@link PoseidonCiphertext} values
555
+ * using Poseidon counter-mode decryption.
556
+ *
557
+ * This decryptor is the read side of Umbra's confidential token account scheme. For
558
+ * each ciphertext at position `i`, it regenerates the same keystream that was used
559
+ * during encryption and subtracts it (modulo the BN254 field prime) to recover the
560
+ * original plaintext.
561
+ *
562
+ * @param ciphertexts - An ordered, readonly array of {@link PoseidonCiphertext} values to decrypt.
563
+ * The array length determines how many counter values are consumed. `result[i]` is
564
+ * the decryption of `ciphertexts[i]`.
565
+ * @param key - The {@link PoseidonKey} that was used during encryption. Using a different
566
+ * key will produce garbage output without any error — the cipher has no authentication
567
+ * and does not detect wrong-key decryption.
568
+ * @returns A `Promise` resolving to an array of {@link PoseidonPlaintext} values, in the
569
+ * same order as the input ciphertexts.
570
+ *
571
+ * @remarks
572
+ * ## Decryption Formula
573
+ *
574
+ * For each ciphertext at position `i`:
575
+ * ```
576
+ * keystream[i] = Poseidon([key, i, 2n])
577
+ * plaintext[i] = (ciphertext[i] - keystream[i] + BN254_FIELD_PRIME) mod BN254_FIELD_PRIME
578
+ * ```
579
+ *
580
+ * The addition of `BN254_FIELD_PRIME` before the modulo ensures the result is
581
+ * non-negative even when `ciphertext[i] < keystream[i]` (subtraction would underflow
582
+ * without it).
583
+ *
584
+ * ## No Authentication
585
+ *
586
+ * This cipher provides confidentiality (IND-CPA) but NOT integrity. A wrong key
587
+ * silently produces incorrect plaintexts rather than throwing. Callers that need
588
+ * authenticated decryption must layer a MAC or use a scheme that includes a
589
+ * commitment to the ciphertext (e.g., comparing against an on-chain hash).
590
+ *
591
+ * In Umbra, ciphertext integrity is enforced externally via ZK proof verification:
592
+ * the prover must demonstrate knowledge of the plaintext that satisfies the
593
+ * circuit's constraints, which transitively checks correctness.
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * import { getPoseidonDecryptor } from "@umbra/sdk";
598
+ *
599
+ * const decryptor: PoseidonDecryptorFunction = getPoseidonDecryptor();
600
+ *
601
+ * // Recover balance and blinding factor from on-chain ciphertexts
602
+ * const [balance, blinding] = await decryptor(
603
+ * [encryptedBalance, encryptedBlinding],
604
+ * myPoseidonKey
605
+ * );
606
+ * // balance: PoseidonPlaintext — original amount
607
+ * // blinding: PoseidonPlaintext — original blinding factor
608
+ * ```
609
+ *
610
+ * @see {@link PoseidonEncryptorFunction} for the corresponding encryption function
611
+ * @see {@link PoseidonKey} for the key type accepted by this function
612
+ * @public
613
+ */
614
+ type PoseidonDecryptorFunction = (ciphertexts: readonly PoseidonCiphertext[], key: PoseidonKey) => Promise<PoseidonPlaintext[]>;
615
+ /**
616
+ * An asynchronous function that generates per-counter Poseidon keystream values.
617
+ *
618
+ * This function is the core PRF primitive underlying Umbra's stream cipher. Given a set of
619
+ * counter values and a master {@link PoseidonKey}, it returns a map from each counter to
620
+ * its corresponding {@link PoseidonKeystream} value. Callers use these keystream values
621
+ * directly to perform field-element encryption and decryption, or they can rely on the
622
+ * higher-level {@link PoseidonEncryptorFunction} and {@link PoseidonDecryptorFunction}.
623
+ *
624
+ * @param counters - A readonly array of {@link PoseidonCounter} values specifying which
625
+ * positions in the keystream to generate. Counters may be provided in any order; the
626
+ * returned `Map` is keyed by counter value for random-access lookup.
627
+ * @param key - The master {@link PoseidonKey} (user's Poseidon private key) from which all
628
+ * keystream elements are derived. This value must remain secret.
629
+ * @returns A `Promise` resolving to a `Map<PoseidonCounter, PoseidonKeystream>` where each
630
+ * entry maps a requested counter to the corresponding derived keystream.
631
+ *
632
+ * @remarks
633
+ * ## Keystream Generation Formula
634
+ *
635
+ * For each counter `c` in the input array, the keystream element is:
636
+ * ```
637
+ * keystream(c) = Poseidon([key, c, 2n])
638
+ * ```
639
+ *
640
+ * - `key`: the user's {@link PoseidonKey} — 1 field element.
641
+ * - `c`: the {@link PoseidonCounter} — 1 field element (typically a small non-negative integer).
642
+ * - `2n`: domain separation constant — distinguishes keystream PRF from other Poseidon
643
+ * usages within the Umbra protocol.
644
+ *
645
+ * Total Poseidon inputs: 3 elements → state width t = 4.
646
+ *
647
+ * ## Usage as a Stream Cipher
648
+ *
649
+ * ```
650
+ * // Encrypt position i:
651
+ * ciphertext[i] = (plaintext[i] + keystream(i)) mod BN254_FIELD_PRIME
652
+ *
653
+ * // Decrypt position i:
654
+ * plaintext[i] = (ciphertext[i] - keystream(i) + BN254_FIELD_PRIME) mod BN254_FIELD_PRIME
655
+ * ```
656
+ *
657
+ * ## Keystream Commitment
658
+ *
659
+ * In Umbra's linker encryption scheme, keystream values are also committed on-chain via
660
+ * {@link KeystreamCommitmentFunction}:
661
+ * ```
662
+ * commitment = Poseidon([keystream, blindingFactor])
663
+ * ```
664
+ * This allows a ZK proof to verify that the correct keystream was used in a specific
665
+ * encryption operation without revealing the keystream itself.
666
+ *
667
+ * ## Security
668
+ *
669
+ * - Keystream values are cryptographic secrets. They must never be stored persistently,
670
+ * logged, or transmitted outside the current computation context.
671
+ * - Counter reuse with the same key reveals the field difference between the two
672
+ * plaintexts encrypted at that position.
673
+ * - The output `Map` uses `PoseidonCounter` as its key type, so `Map.get(c)` requires
674
+ * the same branded `PoseidonCounter` value used as input.
675
+ *
676
+ * @example
677
+ * ```typescript
678
+ * import { getPoseidonKeystreamGenerator } from "@umbra/sdk";
679
+ *
680
+ * const keystreamGenerator: PoseidonKeystreamGeneratorFunction =
681
+ * getPoseidonKeystreamGenerator();
682
+ *
683
+ * // Generate keystreams for positions 0, 1, and 2
684
+ * const counters: PoseidonCounter[] = [0n, 1n, 2n].map((c) => {
685
+ * assertPoseidonCounter(c); return c;
686
+ * });
687
+ *
688
+ * const keystreamMap = await keystreamGenerator(counters, myPoseidonKey);
689
+ *
690
+ * // Access individual keystream values
691
+ * const ks0 = keystreamMap.get(counters[0])!;
692
+ * const ks1 = keystreamMap.get(counters[1])!;
693
+ *
694
+ * // Encrypt manually
695
+ * const ciphertext0 = (plaintext0 + ks0) % BN254_FIELD_PRIME;
696
+ * const ciphertext1 = (plaintext1 + ks1) % BN254_FIELD_PRIME;
697
+ * ```
698
+ *
699
+ * @see {@link PoseidonEncryptorFunction} for the higher-level encryption interface
700
+ * @see {@link PoseidonDecryptorFunction} for the higher-level decryption interface
701
+ * @see {@link KeystreamCommitmentFunction} for committing keystream values in ZK proofs
702
+ * @see {@link PoseidonCounter} for the counter (nonce) type
703
+ * @see {@link PoseidonKeystream} for the keystream output type
704
+ * @public
705
+ */
706
+ type PoseidonKeystreamGeneratorFunction = (counters: readonly PoseidonCounter[], key: PoseidonKey) => Promise<Map<PoseidonCounter, PoseidonKeystream>>;
707
+ /**
708
+ * An asynchronous function that aggregates multiple BN254 field elements into a single
709
+ * branded {@link PoseidonHash} via a sequence of Poseidon invocations.
710
+ *
711
+ * The aggregator is the high-level interface used to produce the single on-chain public
712
+ * input for the Groth16 verifier. Rather than passing all UTXO fields individually
713
+ * (which would be impractical on-chain), Umbra aggregates them into one field element
714
+ * that the ZK circuit can verify matches a committed value.
715
+ *
716
+ * @param plaintexts - A readonly array of {@link Bn254FieldElement} values representing
717
+ * the full set of UTXO fields to aggregate. In the Umbra claim protocol, this array
718
+ * contains exactly 70 elements: the Fiat-Shamir transcript concatenated with all
719
+ * per-UTXO field values (amounts, nullifiers, addresses, blinding factors). The
720
+ * order of elements must match the Circom circuit's expected ordering exactly.
721
+ * @returns A `Promise` resolving to a branded {@link PoseidonHash} — the single
722
+ * aggregated public input. This value is compared on-chain against the hash
723
+ * embedded in the Groth16 proof's public signals.
724
+ *
725
+ * @remarks
726
+ * ## Aggregation Algorithm
727
+ *
728
+ * The aggregator processes the input array in a chain: each Poseidon invocation takes
729
+ * two inputs — the running accumulator and the next element — and produces an updated
730
+ * accumulator:
731
+ * ```
732
+ * acc = plaintexts[0]
733
+ * for i in 1..N-1:
734
+ * acc = Poseidon([acc, plaintexts[i]])
735
+ * result = acc (as PoseidonHash)
736
+ * ```
737
+ *
738
+ * This is a serial (non-tree) aggregation. The result depends on the order of all
739
+ * inputs; swapping any two elements produces a completely different hash.
740
+ *
741
+ * ## Role in Umbra's ZK Protocol
742
+ *
743
+ * The 70-element aggregated public input condenses the Fiat-Shamir transcript and
744
+ * all UTXO data fields into a single on-chain verifiable value. The Groth16 prover
745
+ * produces a proof that the circuit constraints are satisfied given this exact public
746
+ * input, and the Solana program verifies both:
747
+ * 1. The Groth16 proof is valid for the given public input.
748
+ * 2. The public input matches the locally computed aggregated hash.
749
+ *
750
+ * ## Difference from `PoseidonHashFunction`
751
+ *
752
+ * While {@link PoseidonHashFunction} accepts up to 12 elements in a single call and
753
+ * returns an unbranded `Bn254FieldElement`, this function handles arbitrarily many
754
+ * elements via chaining and returns a branded `PoseidonHash`. The branded return type
755
+ * ensures aggregated hashes are not accidentally mixed with raw field elements in
756
+ * downstream code.
757
+ *
758
+ * @example
759
+ * ```typescript
760
+ * import { getPoseidonAggregator } from "@umbra/sdk";
761
+ *
762
+ * const aggregator: PoseidonAggregatorHashFunction = getPoseidonAggregator();
763
+ *
764
+ * // Build the 70-element input array (Fiat-Shamir + UTXO fields)
765
+ * const publicInputs: Bn254FieldElement[] = buildAggregatedInputArray(utxos, transcript);
766
+ * // publicInputs.length === 70
767
+ *
768
+ * const aggregatedHash = await aggregator(publicInputs);
769
+ * // aggregatedHash: PoseidonHash — single value submitted to the on-chain verifier
770
+ * ```
771
+ *
772
+ * @example
773
+ * ```typescript
774
+ * // Smaller example: aggregate three commitment values
775
+ * const data: Bn254FieldElement[] = [commitment1, commitment2, commitment3];
776
+ * const fingerprint = await aggregator(data);
777
+ * // fingerprint uniquely identifies the ordered set of commitments
778
+ * ```
779
+ *
780
+ * @see {@link PoseidonHashFunction} for the low-level, unbranded, single-call hash interface
781
+ * @see {@link PoseidonHash} for the branded output type
782
+ * @public
783
+ */
784
+ type PoseidonAggregatorHashFunction = (plaintexts: readonly Bn254FieldElement[]) => Promise<PoseidonHash>;
785
+ /**
786
+ * An asynchronous function that evaluates the Poseidon Pseudo-Random Function (PRF).
787
+ *
788
+ * A PRF is a deterministic keyed function whose outputs are computationally
789
+ * indistinguishable from random when the key (seeds) is unknown. This Poseidon-based
790
+ * PRF is the foundation for all key derivation, nullifier generation, and keystream
791
+ * computation in the Umbra SDK.
792
+ *
793
+ * @param seeds - A readonly array of 1 to 11 {@link Bn254FieldElement} values serving as
794
+ * the secret key material. In combination with the evaluation point, the total number
795
+ * of Poseidon inputs must not exceed 12 (`seeds.length + 1 ≤ 12`).
796
+ * @param evaluationPoint - A public {@link Bn254FieldElement} at which to evaluate the PRF.
797
+ * Different evaluation points yield completely different outputs from the same seeds,
798
+ * allowing a single set of seeds to derive multiple independent values (one per point).
799
+ * @returns A `Promise` resolving to a {@link Bn254FieldElement} — the PRF output.
800
+ * The output is deterministic for the same `(seeds, evaluationPoint)` pair.
801
+ *
802
+ * @remarks
803
+ * ## PRF Construction
804
+ *
805
+ * The PRF is instantiated as a Poseidon hash over all seeds followed by the evaluation
806
+ * point:
807
+ * ```
808
+ * PRF(seeds, x) = Poseidon([seeds[0], seeds[1], ..., seeds[n-1], x])
809
+ * ```
810
+ *
811
+ * The evaluation point `x` is always the last input, ensuring a clean separation
812
+ * between the key material and the index.
813
+ *
814
+ * ## Input Constraints
815
+ *
816
+ * - `seeds.length` must be at least 1 and at most 11.
817
+ * - The total `seeds.length + 1` must not exceed 12, which is the maximum arity
818
+ * supported by this Poseidon implementation (state width t = 13).
819
+ * - Violating these constraints will produce an error from the underlying hasher.
820
+ *
821
+ * ## Security Properties
822
+ *
823
+ * - **Deterministic**: Identical `(seeds, evaluationPoint)` always yields the same output.
824
+ * - **Pseudo-random**: If at least one seed is unknown to the adversary, the output
825
+ * is computationally indistinguishable from a uniformly random field element.
826
+ * - **Key-dependent**: Even a single bit difference in seeds produces an entirely
827
+ * different output (avalanche effect of Poseidon's non-linear permutation).
828
+ * - **Collision-resistant**: Inherited from Poseidon's second-preimage resistance.
829
+ *
830
+ * ## Use Cases in Umbra
831
+ *
832
+ * - **Keystream generation**: `PRF(poseidonKey, counter)` derives per-counter keystreams
833
+ * for counter-mode encryption of confidential token balances.
834
+ * - **Nullifier derivation**: `PRF(viewingKey, utxoIndex)` produces the nullifier
835
+ * that is published on-chain when a UTXO is spent, preventing double-spending.
836
+ * - **User commitment**: `PRF([masterViewingKey, poseidonKey], domainTag)` produces the
837
+ * user's on-chain commitment that binds their cryptographic identity to a single
838
+ * field element verifiable in a ZK circuit.
839
+ *
840
+ * @example
841
+ * ```typescript
842
+ * import { getPoseidonPrf } from "@umbra/sdk";
843
+ *
844
+ * const prf: PoseidonPrfFunction = getPoseidonPrf();
845
+ *
846
+ * // Derive three independent values from the same secret seed
847
+ * const secretSeed: Bn254FieldElement = myDerivedKey;
848
+ * const keystream0 = await prf([secretSeed], 0n); // at point 0
849
+ * const keystream1 = await prf([secretSeed], 1n); // at point 1
850
+ * const keystream2 = await prf([secretSeed], 2n); // at point 2
851
+ * // All three are distinct and computationally random
852
+ * ```
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * // Nullifier generation in a ZK UTXO protocol
857
+ * const prf: PoseidonPrfFunction = getPoseidonPrf();
858
+ *
859
+ * const viewingKey: Bn254FieldElement = userViewingKey;
860
+ * const utxoIndex: Bn254FieldElement = BigInt(noteIndex);
861
+ *
862
+ * // Nullifier: PRF(viewingKey, utxoIndex)
863
+ * const nullifier = await prf([viewingKey], utxoIndex);
864
+ * // nullifier uniquely identifies the spent note without revealing the viewing key
865
+ * ```
866
+ *
867
+ * @example
868
+ * ```typescript
869
+ * // Multi-seed PRF for user commitment (binds two keys)
870
+ * const userCommitment = await prf([masterViewingKey, poseidonKey], domainSeparator);
871
+ * ```
872
+ *
873
+ * @see {@link PoseidonHashFunction} for the underlying hash primitive
874
+ * @see {@link PoseidonKeystreamGeneratorFunction} for the keystream-specific wrapper
875
+ * @public
876
+ */
877
+ type PoseidonPrfFunction = (seeds: readonly Bn254FieldElement[], evaluationPoint: Bn254FieldElement) => Promise<Bn254FieldElement>;
878
+ /**
879
+ * Parameters for generating the H2 UTXO leaf as a flat Poseidon(6) hash.
880
+ *
881
+ * ```
882
+ * H2 = Poseidon([amount, nullifier, userCommitment, addrLow, addrHigh, h2BlindingFactor])
883
+ * ```
884
+ *
885
+ * The BN254 field constraint means the Solana address (32 bytes = 256 bits) must be
886
+ * split into two 128-bit halves (`finalDestinationAddressLow` and
887
+ * `finalDestinationAddressHigh`) for compatibility with Poseidon's field element inputs.
888
+ *
889
+ * Input ordering must exactly match the Circom circuit's witness assignment.
890
+ *
891
+ * @see {@link H2CircuitProvableHashFunction}
892
+ * @see {@link H2HashFunction}
893
+ * @public
894
+ */
895
+ interface H2CircuitProvableParams {
896
+ /**
897
+ * The transaction amount in the smallest token unit (after protocol fees have been deducted).
898
+ *
899
+ * @remarks
900
+ * This is the net amount that will be claimable by the UTXO recipient after protocol
901
+ * and relayer fees. Must be a valid BN254 field element. For token amounts that fit
902
+ * within 64 bits (all SPL token amounts), this is always safely within field range.
903
+ *
904
+ * The circuit constrains the amount to be non-negative and consistent with the
905
+ * encrypted balance stored in the sender's confidential token account.
906
+ */
907
+ amount: Bn254FieldElement;
908
+ /**
909
+ * The nullifier that uniquely identifies this UTXO and prevents double-spending.
910
+ *
911
+ * @remarks
912
+ * The nullifier is derived deterministically from the user's viewing key and the
913
+ * UTXO's position or index:
914
+ * ```
915
+ * nullifier = Poseidon([viewingKey, utxoIndex])
916
+ * ```
917
+ *
918
+ * When a UTXO is claimed, its nullifier is published on-chain and inserted into the
919
+ * treap nullifier set. Subsequent claim attempts for the same UTXO are rejected by
920
+ * checking for the nullifier's presence in the treap.
921
+ *
922
+ * The ZK circuit proves knowledge of the pre-image (viewing key + index) that
923
+ * produces this nullifier, without revealing the viewing key.
924
+ */
925
+ nullifier: Bn254FieldElement;
926
+ /**
927
+ * The on-chain commitment that identifies the user authorized to claim this UTXO.
928
+ *
929
+ * @remarks
930
+ * The `userCommitment` is computed as:
931
+ * ```
932
+ * userCommitment = Poseidon([masterViewingKey, poseidonKey])
933
+ * ```
934
+ *
935
+ * Two locking modes exist in the Umbra protocol:
936
+ * - **Ephemeral unlocking**: the `userCommitment` is derived from a per-UTXO ephemeral
937
+ * key, allowing claim by anyone who knows that ephemeral key.
938
+ * - **Receiver unlocking**: the `userCommitment` is the receiver's registered
939
+ * commitment, requiring the receiver's `masterViewingKey` and `poseidonKey`.
940
+ *
941
+ * The circuit proves that the claimer knows the opening of this commitment.
942
+ */
943
+ userCommitment: Bn254FieldElement;
944
+ /**
945
+ * The lower 128 bits of the final destination Solana address (bytes 0–15).
946
+ *
947
+ * @remarks
948
+ * Solana public keys are 32 bytes (256 bits). Because BN254 field elements are
949
+ * only ~254 bits, a full Solana address cannot be represented as a single field
950
+ * element without potential reduction. The address is therefore split into two
951
+ * 128-bit halves for safe inclusion as Poseidon inputs.
952
+ *
953
+ * The split is:
954
+ * ```
955
+ * finalDestinationAddressLow = address & 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFFn
956
+ * finalDestinationAddressHigh = address >> 128n
957
+ * ```
958
+ */
959
+ finalDestinationAddressLow: Bn254FieldElement;
960
+ /**
961
+ * The upper 128 bits of the final destination Solana address (bytes 16–31).
962
+ *
963
+ * @remarks
964
+ * Pair of {@link H2CircuitProvableParams.finalDestinationAddressLow}. Together, the
965
+ * two halves reconstruct the full 32-byte Solana destination address:
966
+ * ```
967
+ * address = finalDestinationAddressLow | (finalDestinationAddressHigh << 128n)
968
+ * ```
969
+ */
970
+ finalDestinationAddressHigh: Bn254FieldElement;
971
+ /**
972
+ * A uniformly random BN254 field element that provides hiding for the H2 commitment.
973
+ *
974
+ * @remarks
975
+ * Without a blinding factor, the UTXO commitment `H2` would be deterministic given
976
+ * the other public fields (amount, destination address). An observer could enumerate
977
+ * candidate amounts and precompute commitments to deanonymize transactions. The
978
+ * blinding factor makes each UTXO commitment computationally unique even for
979
+ * identical amounts and destinations.
980
+ *
981
+ * Must be generated using a CSPRNG and must remain secret until the UTXO is claimed.
982
+ */
983
+ h2BlindingFactor: Bn254FieldElement;
984
+ }
985
+ /**
986
+ * Backward-compatible alias for {@link H2CircuitProvableParams}.
987
+ *
988
+ * H2 is now computed as a flat Poseidon(6) hash — identical to the circuit-provable hash.
989
+ * This alias exists so that code referencing `H2FullParams` continues to compile.
990
+ *
991
+ * @public
992
+ */
993
+ type H2FullParams = H2CircuitProvableParams;
994
+ /**
995
+ * Computes the circuit-provable Poseidon(6) hash over the six core UTXO fields.
996
+ *
997
+ * ```
998
+ * H2 = Poseidon([amount, nullifier, userCommitment, addrLow, addrHigh, h2BlindingFactor])
999
+ * ```
1000
+ *
1001
+ * Input ordering must exactly match the Circom circuit's witness assignment.
1002
+ *
1003
+ * @see {@link H2CircuitProvableParams}
1004
+ * @public
1005
+ */
1006
+ type H2CircuitProvableHashFunction = (params: H2CircuitProvableParams) => Promise<Bn254FieldElement>;
1007
+ /**
1008
+ * Computes the complete H2 UTXO leaf commitment as a flat Poseidon(6) hash.
1009
+ *
1010
+ * ```
1011
+ * H2 = Poseidon([amount, nullifier, userCommitment, addrLow, addrHigh, h2BlindingFactor])
1012
+ * ```
1013
+ *
1014
+ * The result is the leaf inserted into the mixer's indexed Merkle tree (IMT).
1015
+ *
1016
+ * @see {@link H2CircuitProvableParams}
1017
+ * @public
1018
+ */
1019
+ type H2HashFunction = (params: H2CircuitProvableParams) => Promise<Bn254FieldElement>;
1020
+ /**
1021
+ * Bundle of H2-related hash generation functions for dependency injection.
1022
+ *
1023
+ * Obtain via `getUtxoCommitmentHashGenerator()`. Both functions share the same Poseidon instance.
1024
+ *
1025
+ * @see {@link H2CircuitProvableHashFunction}
1026
+ * @see {@link H2HashFunction}
1027
+ * @public
1028
+ */
1029
+ interface H2GeneratorFns {
1030
+ /** Computes the Poseidon(6) hash over the six core UTXO fields. */
1031
+ generateCircuitProvableHash: H2CircuitProvableHashFunction;
1032
+ /**
1033
+ * Computes the complete H2 UTXO leaf — flat Poseidon(6), identical to
1034
+ * `generateCircuitProvableHash`.
1035
+ */
1036
+ generateH2: H2HashFunction;
1037
+ }
1038
+ /**
1039
+ * An asynchronous function that generates a Poseidon commitment to a keystream value.
1040
+ *
1041
+ * Keystream commitments allow a ZK proof to verify that a specific keystream value was
1042
+ * used in a Poseidon encryption operation without revealing the keystream itself. They
1043
+ * are a core component of Umbra's linker encryption scheme, which provides
1044
+ * zero-knowledge proofs of correct encryption.
1045
+ *
1046
+ * @param keystream - The {@link Bn254FieldElement} keystream value to commit to (produced by
1047
+ * {@link PoseidonKeystreamGeneratorFunction}). This value is kept secret; only its
1048
+ * commitment is published.
1049
+ * @param blindingFactor - A uniformly random {@link Bn254FieldElement} that hides the
1050
+ * keystream in the commitment. Must be generated using a CSPRNG.
1051
+ * @returns A `Promise` resolving to a {@link Bn254FieldElement} — the keystream commitment.
1052
+ * This value is safe to publish on-chain or include in a ZK proof's public inputs.
1053
+ *
1054
+ * @remarks
1055
+ * ## Commitment Formula
1056
+ *
1057
+ * ```
1058
+ * commitment = Poseidon([keystream, blindingFactor])
1059
+ * ```
1060
+ *
1061
+ * This is a standard Poseidon-based Pedersen-style commitment: the `blindingFactor`
1062
+ * provides hiding (the commitment reveals no information about `keystream` to an
1063
+ * observer who does not know `blindingFactor`), and the collision resistance of
1064
+ * Poseidon provides binding (the committer cannot find two different `keystream`
1065
+ * values that open to the same commitment).
1066
+ *
1067
+ * ## Role in the Linker Encryption Scheme
1068
+ *
1069
+ * When a sender encrypts a value for a recipient, the keystream used in the
1070
+ * encryption is committed on-chain:
1071
+ * 1. The sender generates `keystream = Poseidon([transactionViewingKey, counter, 2n])`.
1072
+ * 2. The sender computes and publishes `commitment = Poseidon([keystream, blindingFactor])`.
1073
+ * 3. A ZK proof verifies that:
1074
+ * - The ciphertext was correctly formed using this keystream.
1075
+ * - The keystream corresponds to the published commitment.
1076
+ *
1077
+ * This binds the encryption to the commitment without revealing the keystream or
1078
+ * the transaction viewing key.
1079
+ *
1080
+ * @example
1081
+ * ```typescript
1082
+ * import { getKeystreamCommitmentGenerator } from "@umbra/sdk";
1083
+ *
1084
+ * const commitmentGenerator: KeystreamCommitmentFunction =
1085
+ * getKeystreamCommitmentGenerator();
1086
+ *
1087
+ * // Generate a keystream for counter 0
1088
+ * const keystreamMap = await keystreamGenerator([counter0], transactionViewingKey);
1089
+ * const keystream = keystreamMap.get(counter0)!;
1090
+ *
1091
+ * // Generate a random blinding factor (must use CSPRNG in production)
1092
+ * const blindingFactor: Bn254FieldElement = secureRandomFieldElement();
1093
+ *
1094
+ * // Commit to the keystream
1095
+ * const commitment = await commitmentGenerator(keystream, blindingFactor);
1096
+ * // commitment: Bn254FieldElement — safe to publish on-chain or in a ZK public input
1097
+ * ```
1098
+ *
1099
+ * @see {@link PoseidonKeystreamGeneratorFunction} for the function that produces keystreams
1100
+ * @see {@link PoseidonEncryptorFunction} for the encryption function whose keystream is committed
1101
+ * @public
1102
+ */
1103
+ type KeystreamCommitmentFunction = (keystream: Bn254FieldElement, blindingFactor: Bn254FieldElement) => Promise<Bn254FieldElement>;
1104
+
1105
+ /**
1106
+ * User Commitment Interfaces
1107
+ *
1108
+ * This module defines TypeScript function type interfaces for user commitment
1109
+ * generation used in the Umbra privacy protocol.
1110
+ *
1111
+ * ## Overview
1112
+ *
1113
+ * User commitments are cryptographic hashes that bind a user's identity to their
1114
+ * on-chain account without revealing the underlying keys. The commitment is
1115
+ * computed as a depth-2 Merkle tree root using Poseidon hashing, a hash function
1116
+ * specifically designed to be efficient inside zero-knowledge circuits.
1117
+ *
1118
+ * ## Tree Structure
1119
+ *
1120
+ * The commitment is computed as:
1121
+ * ```
1122
+ * left = Poseidon(masterViewingKey, mvkBlindingFactor)
1123
+ * right = Poseidon(poseidonPrivateKey, poseidonPrivateKeyBlindingFactor)
1124
+ * root = Poseidon(left, right)
1125
+ * ```
1126
+ *
1127
+ * ## Security Properties
1128
+ *
1129
+ * - The commitment is hiding (reveals nothing about the underlying inputs)
1130
+ * - The commitment is binding (cannot be opened to different input values)
1131
+ * - Poseidon is ZK-friendly, enabling efficient on-chain and off-circuit verification
1132
+ *
1133
+ * @packageDocumentation
1134
+ * @module interfaces/cryptography/commitment
1135
+ */
1136
+
1137
+ /**
1138
+ * Function type for generating user commitments.
1139
+ *
1140
+ * Computes a depth-2 Merkle tree root from four BN254 field elements using
1141
+ * Poseidon hashing. The four inputs are grouped into two leaf nodes:
1142
+ *
1143
+ * - The left leaf commits to the master viewing key and its blinding factor.
1144
+ * - The right leaf commits to the Poseidon private key and its blinding factor.
1145
+ * - The root is the Poseidon hash of the two leaves.
1146
+ *
1147
+ * This function type is returned by {@link getUserCommitmentGeneratorFunction}
1148
+ * and is the primary interface consumers depend on when computing commitments.
1149
+ *
1150
+ * @param masterViewingKey - The user's master viewing key, a BN254 field element
1151
+ * derived from the user's wallet signature. This key governs decryption of all
1152
+ * confidential balances belonging to the user.
1153
+ * @param mvkBlindingFactor - A random BN254 field element used to blind the
1154
+ * master viewing key inside the left leaf, ensuring the leaf hides the key
1155
+ * from observers who only see the commitment.
1156
+ * @param poseidonPrivateKey - The user's Poseidon private key, a BN254 field
1157
+ * element used within ZK proof computations. This key is distinct from the
1158
+ * master viewing key and governs UTXO claim operations.
1159
+ * @param poseidonPrivateKeyBlindingFactor - A random BN254 field element used
1160
+ * to blind the Poseidon private key inside the right leaf.
1161
+ * @returns A `Promise` resolving to a {@link Bn254FieldElement} representing
1162
+ * the Merkle root commitment. This value is stored on-chain inside the
1163
+ * `EncryptedUserAccount`.
1164
+ *
1165
+ * @remarks
1166
+ * ## On-Chain Usage
1167
+ *
1168
+ * The user commitment is stored in the `EncryptedUserAccount` and is
1169
+ * used to:
1170
+ * - Bind the user's identity to their on-chain account without revealing keys
1171
+ * - Enable on-chain verification of key ownership during claim operations
1172
+ * - Support privacy-preserving balance proofs where the circuit checks the
1173
+ * commitment opening as a precondition for spending
1174
+ *
1175
+ * ## Blinding Factor Freshness
1176
+ *
1177
+ * The blinding factors MUST be sampled freshly from a cryptographically secure
1178
+ * random source for each new commitment. Reusing blinding factors across
1179
+ * commitments may allow an adversary to correlate commitments and deduce key
1180
+ * material.
1181
+ *
1182
+ * ## Security Properties
1183
+ *
1184
+ * - Hiding: the commitment reveals nothing about its four inputs
1185
+ * - Binding: it is computationally infeasible to open the commitment to
1186
+ * different input values under the Poseidon collision-resistance assumption
1187
+ * - ZK-friendliness: Poseidon has low multiplicative complexity, making
1188
+ * commitments cheap to verify inside Groth16 circuits
1189
+ *
1190
+ * @example
1191
+ * ```typescript
1192
+ * import { getUserCommitmentGeneratorFunction } from "./index";
1193
+ *
1194
+ * const generateCommitment = getUserCommitmentGeneratorFunction();
1195
+ *
1196
+ * const commitment = await generateCommitment(
1197
+ * masterViewingKey,
1198
+ * mvkBlindingFactor,
1199
+ * poseidonPrivateKey,
1200
+ * poseidonPrivateKeyBlindingFactor,
1201
+ * );
1202
+ *
1203
+ * // Store `commitment` in the EncryptedUserAccount on-chain
1204
+ * ```
1205
+ *
1206
+ * @see {@link getUserCommitmentGeneratorFunction} for the factory that produces
1207
+ * instances of this function type
1208
+ * @see {@link UserCommitmentGeneratorDeps} for optional dependency injection
1209
+ * @public
1210
+ */
1211
+ type UserCommitmentGeneratorFunction = (masterViewingKey: Bn254FieldElement, mvkBlindingFactor: Bn254FieldElement, poseidonPrivateKey: Bn254FieldElement, poseidonPrivateKeyBlindingFactor: Bn254FieldElement) => Promise<Bn254FieldElement>;
1212
+ /**
1213
+ * Optional dependency injection bag for the user commitment generator.
1214
+ *
1215
+ * Allows callers to substitute the default Poseidon hasher with a custom
1216
+ * implementation. This is useful in two scenarios:
1217
+ *
1218
+ * - **Testing**: inject a deterministic or mock hasher to make tests
1219
+ * reproducible without relying on the default WASM-backed implementation.
1220
+ * - **Performance**: inject a pre-warmed hasher instance to avoid the
1221
+ * per-call initialisation cost of {@link getPoseidonHasher}.
1222
+ *
1223
+ * If the `hasher` field is omitted or `undefined`, the factory falls back to
1224
+ * the default singleton returned by `getPoseidonHasher()`.
1225
+ *
1226
+ * @example
1227
+ * ```typescript
1228
+ * import { getUserCommitmentGeneratorFunction } from "./index";
1229
+ * import type { UserCommitmentGeneratorDeps } from "./interfaces";
1230
+ *
1231
+ * // Inject a custom hasher for testing
1232
+ * const deps: UserCommitmentGeneratorDeps = { hasher: mockPoseidonHasher };
1233
+ * const generateCommitment = getUserCommitmentGeneratorFunction(deps);
1234
+ * ```
1235
+ *
1236
+ * @see {@link getUserCommitmentGeneratorFunction} for the factory that consumes
1237
+ * this interface
1238
+ * @see {@link PoseidonHashFunction} for the hasher contract
1239
+ * @public
1240
+ */
1241
+ interface UserCommitmentGeneratorDeps {
1242
+ /**
1243
+ * Custom Poseidon hash function to use when generating commitments.
1244
+ *
1245
+ * If not provided, the factory uses the default implementation returned by
1246
+ * `getPoseidonHasher()`. Supplying a custom hasher also causes the factory
1247
+ * to maintain a separate cache entry keyed on the hasher reference, so
1248
+ * different hasher instances produce isolated generator functions.
1249
+ *
1250
+ * @defaultValue `getPoseidonHasher()` — the default WASM-backed Poseidon
1251
+ * hasher over the BN254 scalar field
1252
+ */
1253
+ readonly hasher?: PoseidonHashFunction;
1254
+ }
1255
+
1256
+ /**
1257
+ * External Cryptography Dependency Interfaces
1258
+ *
1259
+ * This module defines interface types for external cryptographic functions
1260
+ * that are used by the SDK. These interfaces allow dependency injection
1261
+ * for testing and customization.
1262
+ *
1263
+ * @module interfaces/cryptography/external
1264
+ */
1265
+
1266
+ /**
1267
+ * KMAC256 (Keccak Message Authentication Code) function interface.
1268
+ *
1269
+ * KMAC256 is a keyed hash function based on Keccak that provides
1270
+ * both authentication and domain separation capabilities.
1271
+ *
1272
+ * @param key - The key (customization string) as bytes
1273
+ * @param message - The message to authenticate
1274
+ * @param opts - Options object with output length
1275
+ * @returns The KMAC256 output as a Uint8Array
1276
+ *
1277
+ * @remarks
1278
+ * The default implementation uses `kmac256` from `@noble/hashes/sha3-addons`.
1279
+ *
1280
+ * @example
1281
+ * ```typescript
1282
+ * import { kmac256 } from "@noble/hashes/sha3-addons";
1283
+ *
1284
+ * const myKmac: Kmac256Function = (key, message, opts) =>
1285
+ * kmac256(key, message, opts);
1286
+ * ```
1287
+ */
1288
+ type Kmac256Function = (key: Uint8Array, message: Uint8Array, options: {
1289
+ dkLen: number;
1290
+ personalization?: Uint8Array;
1291
+ }) => Uint8Array;
1292
+ /**
1293
+ * X25519 shared secret derivation function interface.
1294
+ *
1295
+ * This function computes the X25519 Diffie-Hellman shared secret from
1296
+ * a private key and a public key.
1297
+ *
1298
+ * @param privateKey - The X25519 private key (32 bytes)
1299
+ * @param publicKey - The X25519 public key of the counterparty (32 bytes)
1300
+ * @returns The shared secret as a Uint8Array (32 bytes)
1301
+ *
1302
+ * @remarks
1303
+ * The default implementation uses `x25519.getSharedSecret` from `@noble/curves/ed25519`.
1304
+ *
1305
+ * @example
1306
+ * ```typescript
1307
+ * import { x25519 } from "@noble/curves/ed25519";
1308
+ *
1309
+ * const myGetSharedSecret: X25519GetSharedSecretFunction =
1310
+ * (privateKey, publicKey) => x25519.getSharedSecret(privateKey, publicKey);
1311
+ * ```
1312
+ */
1313
+ type X25519GetSharedSecretFunction = (privateKey: Uint8Array, publicKey: Uint8Array) => Uint8Array;
1314
+ /**
1315
+ * Random nonce generator function interface.
1316
+ *
1317
+ * This function generates a cryptographically secure random nonce
1318
+ * for use in encryption operations.
1319
+ *
1320
+ * @returns A random RcEncryptionNonce (128-bit value)
1321
+ *
1322
+ * @remarks
1323
+ * The default implementation uses `generateRandomNonce` from the SDK utilities.
1324
+ *
1325
+ * @example
1326
+ * ```typescript
1327
+ * import { generateRandomNonce } from "@umbra/sdk";
1328
+ *
1329
+ * const myGenerator: RandomNonceGeneratorFunction = () => generateRandomNonce();
1330
+ * ```
1331
+ */
1332
+ type RandomNonceGeneratorFunction = () => RcEncryptionNonce;
1333
+
1334
+ /**
1335
+ * Key Generator Function Types
1336
+ *
1337
+ * This module defines function types (generator contracts) for all cryptographic
1338
+ * key generation operations in the Umbra key derivation system. Each type
1339
+ * specifies the signature that a conforming generator implementation must expose.
1340
+ *
1341
+ * @remarks
1342
+ * ## Design Philosophy
1343
+ *
1344
+ * All key generators follow a dependency-injection (DI) pattern:
1345
+ * - **Factory functions** (in `index.ts`) accept a client and optional deps and
1346
+ * return a generator function of one of the types defined here.
1347
+ * - **Generator function types** (this file) define the contract: parameter names,
1348
+ * types, and the Promise-based return value.
1349
+ *
1350
+ * This separation allows components to depend on the abstract generator type
1351
+ * without coupling to a concrete implementation, enabling easy testing via
1352
+ * mock generators and flexibility to swap cryptographic backends.
1353
+ *
1354
+ * ## Key Hierarchy and Generator Relationships
1355
+ *
1356
+ * ```
1357
+ * MasterSeed (64 bytes — root secret)
1358
+ * │
1359
+ * ├── [MasterSeedGeneratorFunction] — generates from entropy
1360
+ * ├── [EphemeralMasterSeedDeriverFunction] — generates per-offset ephemeral seed
1361
+ * │
1362
+ * ├── [MasterViewingKeyDeriverFunction] — KMAC256 → 252-bit BN254 element
1363
+ * ├── [MasterViewingKeyBlindingFactorDeriverFunction] — KMAC256 → BN254 element
1364
+ * │
1365
+ * ├── [PoseidonPrivateKeyDeriverFunction] — KMAC256 → BN254 element
1366
+ * ├── [PoseidonBlindingFactorDeriverFunction] — KMAC256 → BN254 element
1367
+ * │
1368
+ * ├── [Curve25519KeypairGeneratorFunction] — UserAccountX25519 keypair
1369
+ * ├── [MintX25519KeypairDeriverFunction] — per-(mint, offset) keypair
1370
+ * │
1371
+ * └── MVK → Poseidon hash chain → time-scoped viewing keys
1372
+ * [MintViewingKeyDeriverFunction]
1373
+ * [YearlyViewingKeyGeneratorFunction]
1374
+ * [MonthlyViewingKeyGeneratorFunction]
1375
+ * [DailyViewingKeyGeneratorFunction]
1376
+ * [HourlyViewingKeyGeneratorFunction]
1377
+ * [MinuteViewingKeyGeneratorFunction]
1378
+ * [SecondViewingKeyGeneratorFunction]
1379
+ * ```
1380
+ *
1381
+ * @packageDocumentation
1382
+ * @public
1383
+ *
1384
+ * @module interfaces/cryptography/key-generator
1385
+ */
1386
+
1387
+ /**
1388
+ * Options accepted by viewing key generator functions that use Poseidon hashing.
1389
+ *
1390
+ * @remarks
1391
+ * Viewing key derivation below the MVK level (mint, yearly, monthly, etc.) uses
1392
+ * the Poseidon hash function defined over the BN254 scalar field. This options
1393
+ * bag allows callers to inject a custom Poseidon implementation — useful for
1394
+ * testing with a mock hasher or for using a hardware-accelerated backend.
1395
+ *
1396
+ * If the `hasher` field is omitted, implementations MUST fall back to the
1397
+ * default `getPoseidonHasher()` implementation from the Poseidon module.
1398
+ *
1399
+ * @example
1400
+ * ```typescript
1401
+ * const generator = getMintViewingKeyDeriver({ client });
1402
+ * // Inject a test-double hasher for deterministic unit tests
1403
+ * const mintKey = await generator(usdcMint, { hasher: mockPoseidonHasher });
1404
+ * ```
1405
+ *
1406
+ * @see {@link MintViewingKeyDeriverFunction}
1407
+ * @see {@link YearlyViewingKeyGeneratorFunction}
1408
+ * @public
1409
+ */
1410
+ interface ViewingKeyGeneratorOptions {
1411
+ /**
1412
+ * Optional custom Poseidon hasher function.
1413
+ *
1414
+ * @remarks
1415
+ * If omitted, implementations use the default `getPoseidonHasher()`.
1416
+ * The hasher must accept an array of BN254 field elements and return
1417
+ * a single BN254 field element that is the Poseidon hash output.
1418
+ *
1419
+ * @readonly
1420
+ */
1421
+ readonly hasher?: PoseidonHashFunction;
1422
+ }
1423
+ /**
1424
+ * Generates a new master seed from high-entropy input.
1425
+ *
1426
+ * @remarks
1427
+ * The master seed is the root of the Umbra key derivation hierarchy. Implementations
1428
+ * MUST source entropy from a cryptographically secure random number generator
1429
+ * (CSPRNG) and hash it with Keccak-512 to produce the 64-byte master seed.
1430
+ *
1431
+ * Pre-conditions:
1432
+ * - The runtime environment MUST provide a CSPRNG (e.g., `crypto.getRandomValues`).
1433
+ *
1434
+ * Post-conditions:
1435
+ * - The returned `MasterSeed` is exactly 64 bytes.
1436
+ * - The seed has at least 256 bits of effective entropy.
1437
+ *
1438
+ * @returns A Promise resolving to a 64-byte MasterSeed
1439
+ *
1440
+ * @see {@link MasterSeed}
1441
+ * @public
1442
+ */
1443
+ type MasterSeedGeneratorFunction = () => Promise<MasterSeed>;
1444
+ /**
1445
+ * Generates a deterministic ephemeral master seed from a U256 offset index.
1446
+ *
1447
+ * @remarks
1448
+ * Ephemeral seeds are used to derive single-use key sub-hierarchies for forward
1449
+ * secrecy. Each offset produces an independent seed via KMAC256 keyed by the
1450
+ * long-lived master seed. This ensures:
1451
+ * - Two different offsets always produce different ephemeral seeds.
1452
+ * - The same offset always produces the same ephemeral seed (deterministic).
1453
+ * - Knowledge of an ephemeral seed does not reveal the master seed.
1454
+ *
1455
+ * ## Algorithm
1456
+ *
1457
+ * Uses the internal pseudorandom U512 generator with domain separator:
1458
+ * `"Ephemeral Seed - {offset}"` where `offset` is formatted as a decimal string.
1459
+ *
1460
+ * Pre-conditions:
1461
+ * - The client MUST have a valid master seed loaded.
1462
+ *
1463
+ * Post-conditions:
1464
+ * - The returned value is exactly 64 bytes.
1465
+ * - Distinct offsets produce computationally independent outputs.
1466
+ *
1467
+ * @param offset - A U256 value used as the derivation offset (typically a generation index)
1468
+ * @returns A Promise resolving to a 64-byte MasterSeed usable for ephemeral key derivation
1469
+ *
1470
+ * @example
1471
+ * ```typescript
1472
+ * import { EphemeralMasterSeedDeriverFunction } from "@umbra/sdk";
1473
+ *
1474
+ * const generator: EphemeralMasterSeedDeriverFunction = getGenerator(client);
1475
+ *
1476
+ * // Generate ephemeral seeds with different offsets
1477
+ * const seed0 = await generator(0n as U256);
1478
+ * const seed1 = await generator(1n as U256);
1479
+ * const seed42 = await generator(42n as U256);
1480
+ *
1481
+ * // Use ephemeral seed for single-use key derivation; discard after use
1482
+ * ```
1483
+ *
1484
+ * @see {@link MasterSeed}
1485
+ * @public
1486
+ */
1487
+ type EphemeralMasterSeedDeriverFunction = (offset: U256) => Promise<MasterSeed>;
1488
+ /**
1489
+ * Generates the master viewing key (MVK) from the client's master seed.
1490
+ *
1491
+ * @remarks
1492
+ * The master viewing key is the root of the read-only key tree. Sharing the MVK
1493
+ * allows a recipient to view ALL of the user's transactions across all tokens
1494
+ * and all time periods, without gaining any spending capability.
1495
+ *
1496
+ * ## Algorithm
1497
+ *
1498
+ * 1. Compute `KMAC256(key="Umbra Privacy - MasterViewingKey - {offset}", msg=masterSeed, dkLen=32)`
1499
+ * using the version-aware personalization string from the client.
1500
+ * 2. Interpret the 32-byte output as a big-endian unsigned integer.
1501
+ * 3. Mask to 252 bits: `value = value & (2^252 - 1)`.
1502
+ * 4. Assert `value < BN254_FIELD_PRIME`.
1503
+ *
1504
+ * The 252-bit constraint ensures compatibility with ZK circuits that perform
1505
+ * range checks on BN254 field element inputs.
1506
+ *
1507
+ * Pre-conditions:
1508
+ * - The client MUST have a valid master seed loaded.
1509
+ * - The client's offset for the master viewing key MUST be set.
1510
+ *
1511
+ * Post-conditions:
1512
+ * - The returned value is a BN254 field element strictly less than 2^252.
1513
+ *
1514
+ * @returns A Promise resolving to a MasterViewingKey (BN254 field element < 2^252)
1515
+ *
1516
+ * @example
1517
+ * ```typescript
1518
+ * import { getMasterViewingKeyDeriver } from "@umbra/sdk";
1519
+ *
1520
+ * const generator = getMasterViewingKeyDeriver({ masterSeed });
1521
+ * const mvk = await generator();
1522
+ *
1523
+ * // The MVK is constrained to 252 bits for ZK circuit compatibility
1524
+ * console.assert(mvk < 2n ** 252n);
1525
+ * ```
1526
+ *
1527
+ * @see {@link MasterViewingKey}
1528
+ * @see {@link MintViewingKeyDeriverFunction}
1529
+ * @public
1530
+ */
1531
+ type MasterViewingKeyDeriverFunction = () => Promise<MasterViewingKey>;
1532
+ /**
1533
+ * Generates a blinding factor for the master viewing key commitment.
1534
+ *
1535
+ * @remarks
1536
+ * The blinding factor is used to conceal the master viewing key in a Pedersen
1537
+ * commitment: `commitment = g^mvk * h^blindingFactor`. This allows the user to
1538
+ * prove knowledge of the MVK in a ZK proof without revealing it directly.
1539
+ *
1540
+ * ## Algorithm
1541
+ *
1542
+ * Derives a BN254 field element via KMAC256 with the domain separator
1543
+ * `"UmbraPrivacy - Master Viewing Key Blinding Factor"` keyed by the master seed.
1544
+ *
1545
+ * Pre-conditions:
1546
+ * - The client MUST have a valid master seed loaded.
1547
+ *
1548
+ * Post-conditions:
1549
+ * - Returns a uniformly distributed BN254 field element in [0, BN254_FIELD_PRIME).
1550
+ * - Deterministic: same master seed always produces the same blinding factor.
1551
+ *
1552
+ * @returns A Promise resolving to a BN254 field element for use as the blinding factor
1553
+ *
1554
+ * @example
1555
+ * ```typescript
1556
+ * const generator = getMasterViewingKeyBlindingFactorDeriver({ client });
1557
+ * const blindingFactor = await generator();
1558
+ *
1559
+ * // Use in Pedersen commitment: commitment = g^mvk * h^blindingFactor
1560
+ * ```
1561
+ *
1562
+ * @see {@link MasterViewingKey}
1563
+ * @public
1564
+ */
1565
+ type MasterViewingKeyBlindingFactorDeriverFunction = () => Promise<Bn254FieldElement>;
1566
+ /**
1567
+ * Generates the Poseidon private key for the user's master seed.
1568
+ *
1569
+ * @remarks
1570
+ * The Poseidon private key is used as the secret key input to the Poseidon
1571
+ * cipher (`PoseidonEnc`) for encrypting balances and UTXO fields. Each master
1572
+ * seed is associated with exactly one Poseidon private key.
1573
+ *
1574
+ * ## Algorithm
1575
+ *
1576
+ * Derives a BN254 field element via KMAC256 with the domain separator
1577
+ * `"PoseidonPrivateKey - {offset}"` where `offset` comes from the client's
1578
+ * `offsets.poseidonPrivateKey` field.
1579
+ *
1580
+ * ## Security Properties
1581
+ *
1582
+ * - Compromise of this key allows decryption of Poseidon-encrypted data.
1583
+ * - Different offsets produce independent Poseidon private keys.
1584
+ * - Knowledge of this key does NOT reveal the master seed or other keys.
1585
+ *
1586
+ * Pre-conditions:
1587
+ * - The client MUST have a valid master seed loaded.
1588
+ *
1589
+ * Post-conditions:
1590
+ * - Returns a uniformly distributed BN254 field element in [0, BN254_FIELD_PRIME).
1591
+ *
1592
+ * @returns A Promise resolving to a BN254 field element for use as the Poseidon private key
1593
+ *
1594
+ * @example
1595
+ * ```typescript
1596
+ * const generator = getPoseidonPrivateKeyDeriver({ client });
1597
+ * const privateKey = await generator();
1598
+ *
1599
+ * // Use as key for Poseidon encryption
1600
+ * const ciphertext = await poseidonEncrypt(plaintext, privateKey);
1601
+ * ```
1602
+ *
1603
+ * @see {@link PoseidonBlindingFactorDeriverFunction}
1604
+ * @public
1605
+ */
1606
+ type PoseidonPrivateKeyDeriverFunction = () => Promise<Bn254FieldElement>;
1607
+ /**
1608
+ * Generates the Poseidon blinding factor for the user's master seed.
1609
+ *
1610
+ * @remarks
1611
+ * Blinding factors add randomness to Poseidon-based commitments while preserving
1612
+ * the ability to prove knowledge of the committed value in a ZK circuit.
1613
+ * Each master seed is associated with exactly one Poseidon blinding factor.
1614
+ *
1615
+ * ## Algorithm
1616
+ *
1617
+ * Derives a BN254 field element via KMAC256 with the domain separator
1618
+ * `"PoseidonBlindingFactor"` keyed by the master seed.
1619
+ *
1620
+ * Pre-conditions:
1621
+ * - The client MUST have a valid master seed loaded.
1622
+ *
1623
+ * Post-conditions:
1624
+ * - Returns a uniformly distributed BN254 field element in [0, BN254_FIELD_PRIME).
1625
+ *
1626
+ * @returns A Promise resolving to a BN254 field element for use as the blinding factor
1627
+ *
1628
+ * @example
1629
+ * ```typescript
1630
+ * const generator = getPoseidonBlindingFactorDeriver({ client });
1631
+ * const blindingFactor = await generator();
1632
+ *
1633
+ * // Use in Poseidon commitment: commitment = Poseidon([value, blindingFactor])
1634
+ * const commitment = await poseidonHash([value, blindingFactor]);
1635
+ * ```
1636
+ *
1637
+ * @see {@link PoseidonPrivateKeyDeriverFunction}
1638
+ * @public
1639
+ */
1640
+ type PoseidonBlindingFactorDeriverFunction = () => Promise<Bn254FieldElement>;
1641
+ /**
1642
+ * Generates a mint-specific viewing key from the master viewing key and a mint address.
1643
+ *
1644
+ * @remarks
1645
+ * A mint viewing key grants read-only visibility into all transactions involving
1646
+ * a specific SPL token (identified by its mint address) without revealing
1647
+ * transactions of other tokens. It is the first Poseidon-hash step below the MVK.
1648
+ *
1649
+ * ## Algorithm
1650
+ *
1651
+ * ```
1652
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1653
+ * ```
1654
+ *
1655
+ * Where:
1656
+ * - `MVK` is the master viewing key (derived internally from the client's master seed)
1657
+ * - `mintAddressLow` = bytes 0–15 of the base58-decoded mint address as a little-endian U128
1658
+ * - `mintAddressHigh` = bytes 16–31 of the base58-decoded mint address as a little-endian U128
1659
+ *
1660
+ * Pre-conditions:
1661
+ * - The client MUST have a valid master seed loaded.
1662
+ * - `mint` MUST be a valid Solana address (32-byte base58-encoded string).
1663
+ *
1664
+ * Post-conditions:
1665
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1666
+ * - Deterministic: same MVK and same mint always produce the same mint viewing key.
1667
+ *
1668
+ * @param mint - The Solana SPL token mint address
1669
+ * @param options - Optional configuration, including a custom Poseidon hasher
1670
+ * @returns A Promise resolving to a MintViewingKey (BN254 field element)
1671
+ *
1672
+ * @example
1673
+ * ```typescript
1674
+ * import { getMintViewingKeyDeriver } from "@umbra/sdk";
1675
+ * import { address } from "@solana/kit";
1676
+ *
1677
+ * const generator = getMintViewingKeyDeriver({ masterViewingKey });
1678
+ * const usdcMint = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
1679
+ *
1680
+ * const mintKey = await generator(usdcMint);
1681
+ *
1682
+ * // Share with auditor for USDC-specific review only
1683
+ * shareViewingKey(auditor, mintKey);
1684
+ * ```
1685
+ *
1686
+ * @see {@link MintViewingKey}
1687
+ * @see {@link MasterViewingKey}
1688
+ * @public
1689
+ */
1690
+ type MintViewingKeyDeriverFunction = (mint: Address, options?: ViewingKeyGeneratorOptions) => Promise<MintViewingKey>;
1691
+ /**
1692
+ * Generates a yearly viewing key for a specific calendar year and token.
1693
+ *
1694
+ * @remarks
1695
+ * A yearly viewing key scopes visibility to a single calendar year for a specific
1696
+ * token mint. It is derived by extending the mint viewing key with the year value.
1697
+ *
1698
+ * ## Algorithm
1699
+ *
1700
+ * ```
1701
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1702
+ * h1 = Poseidon(h0, year) // YearlyViewingKey
1703
+ * ```
1704
+ *
1705
+ * Pre-conditions:
1706
+ * - The client MUST have a valid master seed loaded.
1707
+ * - `year` MUST be a valid bigint in the `Year` branded type range.
1708
+ *
1709
+ * Post-conditions:
1710
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1711
+ *
1712
+ * @param mint - The Solana mint address of the token
1713
+ * @param year - The calendar year (e.g., `2024n as Year`)
1714
+ * @param options - Optional configuration including custom Poseidon hasher
1715
+ * @returns A Promise resolving to a YearlyViewingKey (BN254 field element)
1716
+ *
1717
+ * @example
1718
+ * ```typescript
1719
+ * import { assertYear } from "@umbra/sdk";
1720
+ *
1721
+ * const generator = getYearlyViewingKeyDeriver({ masterViewingKey });
1722
+ *
1723
+ * const year = 2024n;
1724
+ * assertYear(year);
1725
+ * const yearlyKey = await generator(usdcMint, year);
1726
+ *
1727
+ * // Share with tax authority for 2024 USDC audit
1728
+ * shareViewingKey(taxAuthority, yearlyKey);
1729
+ * ```
1730
+ *
1731
+ * @see {@link YearlyViewingKey}
1732
+ * @see {@link MintViewingKeyDeriverFunction}
1733
+ * @public
1734
+ */
1735
+ type YearlyViewingKeyGeneratorFunction = (mint: Address, year: Year, options?: ViewingKeyGeneratorOptions) => Promise<YearlyViewingKey>;
1736
+ /**
1737
+ * Generates a monthly viewing key for a specific calendar month and token.
1738
+ *
1739
+ * @remarks
1740
+ * A monthly viewing key scopes visibility to a single calendar month (within a
1741
+ * specific year) for a specific token mint. It extends the yearly viewing key
1742
+ * with the month value.
1743
+ *
1744
+ * ## Algorithm
1745
+ *
1746
+ * ```
1747
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1748
+ * h1 = Poseidon(h0, year)
1749
+ * h2 = Poseidon(h1, month) // MonthlyViewingKey
1750
+ * ```
1751
+ *
1752
+ * Pre-conditions:
1753
+ * - The client MUST have a valid master seed loaded.
1754
+ * - `year` and `month` MUST be in their respective branded type ranges.
1755
+ * - `month` MUST be in [1, 12].
1756
+ *
1757
+ * Post-conditions:
1758
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1759
+ *
1760
+ * @param mint - The Solana mint address of the token
1761
+ * @param year - The calendar year (e.g., `2024n as Year`)
1762
+ * @param month - The calendar month, 1–12 (e.g., `6n as Month` for June)
1763
+ * @param options - Optional configuration including custom Poseidon hasher
1764
+ * @returns A Promise resolving to a MonthlyViewingKey (BN254 field element)
1765
+ *
1766
+ * @example
1767
+ * ```typescript
1768
+ * import { assertYear, assertMonth } from "@umbra/sdk";
1769
+ *
1770
+ * const generator = getMonthlyViewingKeyDeriver({ masterViewingKey });
1771
+ *
1772
+ * const year = 2024n;
1773
+ * const month = 6n;
1774
+ * assertYear(year);
1775
+ * assertMonth(month);
1776
+ * const monthlyKey = await generator(usdcMint, year, month); // June 2024
1777
+ *
1778
+ * // Share with accountant for monthly review
1779
+ * shareViewingKey(accountant, monthlyKey);
1780
+ * ```
1781
+ *
1782
+ * @see {@link MonthlyViewingKey}
1783
+ * @see {@link YearlyViewingKeyGeneratorFunction}
1784
+ * @public
1785
+ */
1786
+ type MonthlyViewingKeyGeneratorFunction = (mint: Address, year: Year, month: Month, options?: ViewingKeyGeneratorOptions) => Promise<MonthlyViewingKey>;
1787
+ /**
1788
+ * Generates a daily viewing key for a specific calendar day and token.
1789
+ *
1790
+ * @remarks
1791
+ * A daily viewing key scopes visibility to a single calendar day (within a
1792
+ * specific year and month) for a specific token mint. It extends the monthly
1793
+ * viewing key with the day value.
1794
+ *
1795
+ * ## Algorithm
1796
+ *
1797
+ * ```
1798
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1799
+ * h1 = Poseidon(h0, year)
1800
+ * h2 = Poseidon(h1, month)
1801
+ * h3 = Poseidon(h2, day) // DailyViewingKey
1802
+ * ```
1803
+ *
1804
+ * Pre-conditions:
1805
+ * - The client MUST have a valid master seed loaded.
1806
+ * - `year`, `month`, and `day` MUST be in their respective branded type ranges.
1807
+ * - `day` MUST be in [1, 31].
1808
+ *
1809
+ * Post-conditions:
1810
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1811
+ *
1812
+ * @param mint - The Solana mint address of the token
1813
+ * @param year - The calendar year (e.g., `2024n as Year`)
1814
+ * @param month - The calendar month, 1–12 (e.g., `6n as Month`)
1815
+ * @param day - The calendar day, 1–31 (e.g., `15n as Day`)
1816
+ * @param options - Optional configuration including custom Poseidon hasher
1817
+ * @returns A Promise resolving to a DailyViewingKey (BN254 field element)
1818
+ *
1819
+ * @example
1820
+ * ```typescript
1821
+ * import { assertYear, assertMonth, assertDay } from "@umbra/sdk";
1822
+ *
1823
+ * const generator = getDailyViewingKeyDeriver({ masterViewingKey });
1824
+ *
1825
+ * const year = 2024n;
1826
+ * const month = 6n;
1827
+ * const day = 15n;
1828
+ * assertYear(year);
1829
+ * assertMonth(month);
1830
+ * assertDay(day);
1831
+ * const dailyKey = await generator(usdcMint, year, month, day); // June 15, 2024
1832
+ *
1833
+ * // Share for investigating a specific date
1834
+ * shareViewingKey(investigator, dailyKey);
1835
+ * ```
1836
+ *
1837
+ * @see {@link DailyViewingKey}
1838
+ * @see {@link MonthlyViewingKeyGeneratorFunction}
1839
+ * @public
1840
+ */
1841
+ type DailyViewingKeyGeneratorFunction = (mint: Address, year: Year, month: Month, day: Day, options?: ViewingKeyGeneratorOptions) => Promise<DailyViewingKey>;
1842
+ /**
1843
+ * Generates an hourly viewing key for a specific hour and token.
1844
+ *
1845
+ * @remarks
1846
+ * An hourly viewing key scopes visibility to a single hour (within a specific
1847
+ * year, month, and day) for a specific token mint. It extends the daily viewing
1848
+ * key with the hour value (0–23).
1849
+ *
1850
+ * ## Algorithm
1851
+ *
1852
+ * ```
1853
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1854
+ * h1 = Poseidon(h0, year)
1855
+ * h2 = Poseidon(h1, month)
1856
+ * h3 = Poseidon(h2, day)
1857
+ * h4 = Poseidon(h3, hour) // HourlyViewingKey
1858
+ * ```
1859
+ *
1860
+ * Pre-conditions:
1861
+ * - The client MUST have a valid master seed loaded.
1862
+ * - All time parameters MUST be in their respective branded type ranges.
1863
+ * - `hour` MUST be in [0, 23].
1864
+ *
1865
+ * Post-conditions:
1866
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1867
+ *
1868
+ * @param mint - The Solana mint address of the token
1869
+ * @param year - The calendar year (e.g., `2024n as Year`)
1870
+ * @param month - The calendar month, 1–12
1871
+ * @param day - The calendar day, 1–31
1872
+ * @param hour - The hour of the day, 0–23 (e.g., `14n as Hour` for 2 PM UTC)
1873
+ * @param options - Optional configuration including custom Poseidon hasher
1874
+ * @returns A Promise resolving to a HourlyViewingKey (BN254 field element)
1875
+ *
1876
+ * @example
1877
+ * ```typescript
1878
+ * import { assertYear, assertMonth, assertDay, assertHour } from "@umbra/sdk";
1879
+ *
1880
+ * const generator = getHourlyViewingKeyDeriver({ masterViewingKey });
1881
+ *
1882
+ * const year = 2024n;
1883
+ * const month = 6n;
1884
+ * const day = 15n;
1885
+ * const hour = 14n;
1886
+ * assertYear(year);
1887
+ * assertMonth(month);
1888
+ * assertDay(day);
1889
+ * assertHour(hour);
1890
+ * const hourlyKey = await generator(usdcMint, year, month, day, hour); // June 15, 2024 2PM
1891
+ *
1892
+ * // Share for high-frequency trading audit within this hour
1893
+ * shareViewingKey(auditor, hourlyKey);
1894
+ * ```
1895
+ *
1896
+ * @see {@link HourlyViewingKey}
1897
+ * @see {@link DailyViewingKeyGeneratorFunction}
1898
+ * @public
1899
+ */
1900
+ type HourlyViewingKeyGeneratorFunction = (mint: Address, year: Year, month: Month, day: Day, hour: Hour, options?: ViewingKeyGeneratorOptions) => Promise<HourlyViewingKey>;
1901
+ /**
1902
+ * Generates a minute viewing key for a specific minute and token.
1903
+ *
1904
+ * @remarks
1905
+ * A minute viewing key scopes visibility to a single minute within a specific
1906
+ * hour, day, month, and year for a specific token mint. It extends the hourly
1907
+ * viewing key with the minute value (0–59).
1908
+ *
1909
+ * ## Algorithm
1910
+ *
1911
+ * ```
1912
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1913
+ * h1 = Poseidon(h0, year)
1914
+ * h2 = Poseidon(h1, month)
1915
+ * h3 = Poseidon(h2, day)
1916
+ * h4 = Poseidon(h3, hour)
1917
+ * h5 = Poseidon(h4, minute) // MinuteViewingKey
1918
+ * ```
1919
+ *
1920
+ * Pre-conditions:
1921
+ * - The client MUST have a valid master seed loaded.
1922
+ * - All time parameters MUST be in their respective branded type ranges.
1923
+ * - `minute` MUST be in [0, 59].
1924
+ *
1925
+ * Post-conditions:
1926
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1927
+ *
1928
+ * @param mint - The Solana mint address of the token
1929
+ * @param year - The calendar year (e.g., `2024n as Year`)
1930
+ * @param month - The calendar month, 1–12
1931
+ * @param day - The calendar day, 1–31
1932
+ * @param hour - The hour of the day, 0–23
1933
+ * @param minute - The minute within the hour, 0–59 (e.g., `30n as Minute`)
1934
+ * @param options - Optional configuration including custom Poseidon hasher
1935
+ * @returns A Promise resolving to a MinuteViewingKey (BN254 field element)
1936
+ *
1937
+ * @example
1938
+ * ```typescript
1939
+ * import { assertYear, assertMonth, assertDay, assertHour, assertMinute } from "@umbra/sdk";
1940
+ *
1941
+ * const generator = getMinuteViewingKeyDeriver({ masterViewingKey });
1942
+ *
1943
+ * const year = 2024n;
1944
+ * const month = 6n;
1945
+ * const day = 15n;
1946
+ * const hour = 14n;
1947
+ * const minute = 30n;
1948
+ * assertYear(year);
1949
+ * assertMonth(month);
1950
+ * assertDay(day);
1951
+ * assertHour(hour);
1952
+ * assertMinute(minute);
1953
+ * const minuteKey = await generator(usdcMint, year, month, day, hour, minute);
1954
+ *
1955
+ * // Share for precise forensic analysis of a specific minute
1956
+ * shareViewingKey(forensicAnalyst, minuteKey);
1957
+ * ```
1958
+ *
1959
+ * @see {@link MinuteViewingKey}
1960
+ * @see {@link HourlyViewingKeyGeneratorFunction}
1961
+ * @public
1962
+ */
1963
+ type MinuteViewingKeyGeneratorFunction = (mint: Address, year: Year, month: Month, day: Day, hour: Hour, minute: Minute, options?: ViewingKeyGeneratorOptions) => Promise<MinuteViewingKey>;
1964
+ /**
1965
+ * Generates a second viewing key for a specific second and token.
1966
+ *
1967
+ * @remarks
1968
+ * The second viewing key is the finest-granularity key in the Umbra viewing
1969
+ * key hierarchy, scoping visibility to a single second within a specific minute.
1970
+ * It is the leaf node of the Poseidon hash chain.
1971
+ *
1972
+ * ## Algorithm
1973
+ *
1974
+ * ```
1975
+ * h0 = Poseidon(MVK, mintAddressLow, mintAddressHigh)
1976
+ * h1 = Poseidon(h0, year)
1977
+ * h2 = Poseidon(h1, month)
1978
+ * h3 = Poseidon(h2, day)
1979
+ * h4 = Poseidon(h3, hour)
1980
+ * h5 = Poseidon(h4, minute)
1981
+ * TVK = Poseidon(h5, second) // SecondViewingKey (Terminal Viewing Key)
1982
+ * ```
1983
+ *
1984
+ * Pre-conditions:
1985
+ * - The client MUST have a valid master seed loaded.
1986
+ * - All time parameters MUST be in their respective branded type ranges.
1987
+ * - `second` MUST be in [0, 59].
1988
+ *
1989
+ * Post-conditions:
1990
+ * - Returns a BN254 field element in [0, BN254_FIELD_PRIME).
1991
+ * - No further time-scoped keys can be derived from a SecondViewingKey.
1992
+ *
1993
+ * @param mint - The Solana mint address of the token
1994
+ * @param year - The calendar year (e.g., `2024n as Year`)
1995
+ * @param month - The calendar month, 1–12
1996
+ * @param day - The calendar day, 1–31
1997
+ * @param hour - The hour of the day, 0–23
1998
+ * @param minute - The minute within the hour, 0–59
1999
+ * @param second - The second within the minute, 0–59 (e.g., `45n as Second`)
2000
+ * @param options - Optional configuration including custom Poseidon hasher
2001
+ * @returns A Promise resolving to a SecondViewingKey (BN254 field element)
2002
+ *
2003
+ * @example
2004
+ * ```typescript
2005
+ * import { assertYear, assertMonth, assertDay, assertHour, assertMinute, assertSecond } from "@umbra/sdk";
2006
+ *
2007
+ * const generator = getSecondViewingKeyDeriver({ masterViewingKey });
2008
+ *
2009
+ * const year = 2024n;
2010
+ * const month = 6n;
2011
+ * const day = 15n;
2012
+ * const hour = 14n;
2013
+ * const minute = 30n;
2014
+ * const second = 45n;
2015
+ * assertYear(year);
2016
+ * assertMonth(month);
2017
+ * assertDay(day);
2018
+ * assertHour(hour);
2019
+ * assertMinute(minute);
2020
+ * assertSecond(second);
2021
+ * const secondKey = await generator(usdcMint, year, month, day, hour, minute, second);
2022
+ *
2023
+ * // Share for investigating a specific transaction
2024
+ * shareViewingKey(investigator, secondKey);
2025
+ * ```
2026
+ *
2027
+ * @see {@link SecondViewingKey}
2028
+ * @see {@link MinuteViewingKeyGeneratorFunction}
2029
+ * @public
2030
+ */
2031
+ type SecondViewingKeyGeneratorFunction = (mint: Address, year: Year, month: Month, day: Day, hour: Hour, minute: Minute, second: Second, options?: ViewingKeyGeneratorOptions) => Promise<SecondViewingKey>;
2032
+ /**
2033
+ * Generates a complete Curve25519 keypair (Ed25519 + X25519) from the master seed.
2034
+ *
2035
+ * @remarks
2036
+ * This function derives both an Ed25519 (Edwards curve) signing keypair and
2037
+ * an X25519 (Montgomery curve) ECDH keypair from the master seed using a single
2038
+ * deterministic derivation pipeline. The two keypairs share the same Curve25519
2039
+ * foundation and are used together in token account registration.
2040
+ *
2041
+ * ## Derivation Pipeline
2042
+ *
2043
+ * 1. Derive 64 bytes via `KMAC256(key="Umbra Privacy - {domain} - {offset}", msg=masterSeed, dkLen=64)`
2044
+ * 2. **Ed25519 Keypair**:
2045
+ * - Use first 32 bytes as the Ed25519 seed
2046
+ * - Derive Ed25519 public key: `ed25519.getPublicKey(seed)`
2047
+ * 3. **X25519 Keypair**:
2048
+ * - Hash seed with SHA-512 → 64 bytes
2049
+ * - Clamp first 32 bytes per RFC 8032 §5.1.5
2050
+ * - Derive X25519 public key via birational map: `ed25519.utils.toMontgomery(ed25519Pub)`
2051
+ *
2052
+ * ## Security Properties
2053
+ *
2054
+ * - **Deterministic**: Same master seed always produces the same keypairs
2055
+ * - **Domain Separated**: Independent from all other key derivations
2056
+ * - **Forward Secure**: Different offsets produce independent keypairs
2057
+ *
2058
+ * Pre-conditions:
2059
+ * - The client MUST have a valid master seed loaded.
2060
+ *
2061
+ * Post-conditions:
2062
+ * - Returns a valid `Curve25519KeypairResult` with both Ed25519 and X25519 keypairs.
2063
+ *
2064
+ * @returns A Promise resolving to a Curve25519KeypairResult with ed25519Keypair and x25519Keypair
2065
+ *
2066
+ * @example
2067
+ * ```typescript
2068
+ * import { getUserAccountX25519KeypairDeriver } from "@umbra/sdk";
2069
+ *
2070
+ * const generator = getUserAccountX25519KeypairDeriver({ client });
2071
+ * const result = await generator();
2072
+ *
2073
+ * // Use Ed25519 for signing
2074
+ * const signature = ed25519.sign(message, result.ed25519Keypair.seed);
2075
+ *
2076
+ * // Use X25519 for key exchange
2077
+ * const sharedSecret = x25519.getSharedSecret(
2078
+ * result.x25519Keypair.privateKey,
2079
+ * peerPublicKey
2080
+ * );
2081
+ * ```
2082
+ *
2083
+ * @see {@link Curve25519KeypairResult}
2084
+ * @see {@link MintX25519KeypairDeriverFunction}
2085
+ * @public
2086
+ */
2087
+ type Curve25519KeypairGeneratorFunction = () => Promise<Curve25519KeypairResult>;
2088
+ /**
2089
+ * Generates a per-mint Curve25519 keypair (Ed25519 + X25519) for a given mint.
2090
+ *
2091
+ * @remarks
2092
+ * Used for `reencrypt_shared` operations — produces a unique keypair for each
2093
+ * mint address. The offset is taken from `client.offsets.mintX25519PrivateKey`
2094
+ * at construction time, consistent with all other key types.
2095
+ *
2096
+ * ## Algorithm
2097
+ *
2098
+ * Domain separator: `"MintX25519Keypair - {mint} - {client.offsets.mintX25519PrivateKey}"`
2099
+ *
2100
+ * Pre-conditions:
2101
+ * - The client MUST have a valid master seed loaded.
2102
+ * - `mint` MUST be a valid Solana address.
2103
+ *
2104
+ * Post-conditions:
2105
+ * - Returns a valid `Curve25519KeypairResult`.
2106
+ * - Different mints produce independent keypairs.
2107
+ * - Different `client.offsets.mintX25519PrivateKey` values produce independent keypairs.
2108
+ *
2109
+ * @param mint - The Solana SPL token mint address
2110
+ * @returns A Promise resolving to a Curve25519KeypairResult
2111
+ *
2112
+ * @example
2113
+ * ```typescript
2114
+ * const generator = getMintX25519KeypairDeriver({ client });
2115
+ * const usdcKeypair = await generator(usdcMint);
2116
+ * const solKeypair = await generator(solMint);
2117
+ * // usdcKeypair and solKeypair are independent due to different mints
2118
+ * ```
2119
+ *
2120
+ * @see {@link Curve25519KeypairGeneratorFunction}
2121
+ * @see {@link Curve25519KeypairResult}
2122
+ * @public
2123
+ */
2124
+ type MintX25519KeypairDeriverFunction = (mint: Address) => Promise<Curve25519KeypairResult>;
2125
+ /**
2126
+ * Generates a 512-bit pseudorandom value from the master seed and a domain separator.
2127
+ *
2128
+ * @remarks
2129
+ * This is the base primitive for all KMAC256-based key derivation in Umbra.
2130
+ * It produces 512 bits of pseudorandom output from the master seed using
2131
+ * a single KMAC256 call with a domain-separated key. The 512-bit output size
2132
+ * ensures negligible bias when reducing to BN254 or Curve25519 field elements.
2133
+ *
2134
+ * ## Algorithm
2135
+ *
2136
+ * 1. Construct the KMAC key string: `"Umbra Privacy - {domainSeparator}"`
2137
+ * 2. Compute `KMAC256(key, masterSeed, dkLen=64, personalization=versionString)`
2138
+ * 3. Return the 64-byte big-endian output as `U512BeBytes`
2139
+ *
2140
+ * ## Security Properties
2141
+ *
2142
+ * - **Domain Separation**: Different domain separators produce computationally
2143
+ * independent outputs, even with the same master seed.
2144
+ * - **Deterministic**: Same domain separator and master seed always produce
2145
+ * the same output.
2146
+ * - **Pseudorandom**: Output is computationally indistinguishable from random
2147
+ * under standard assumptions about KMAC256.
2148
+ *
2149
+ * Pre-conditions:
2150
+ * - The client MUST have a valid master seed loaded.
2151
+ *
2152
+ * Post-conditions:
2153
+ * - Returns exactly 64 bytes encoded as big-endian `U512BeBytes`.
2154
+ *
2155
+ * @param domainSeparator - A string that uniquely identifies the derivation context
2156
+ * @returns A Promise resolving to a 512-bit big-endian byte array (U512BeBytes)
2157
+ *
2158
+ * @example
2159
+ * ```typescript
2160
+ * import { PseudorandomU512DeriverFunction } from "@umbra/sdk";
2161
+ *
2162
+ * const generator: PseudorandomU512DeriverFunction = getGenerator(client);
2163
+ *
2164
+ * // Generate different 512-bit values using domain separation
2165
+ * const value1 = await generator("MasterViewingKey");
2166
+ * const value2 = await generator("EphemeralSeed-12345");
2167
+ *
2168
+ * // Each domain separator produces a completely independent output
2169
+ * ```
2170
+ *
2171
+ * @see {@link MasterSeedBasedFieldElementDeriverFunction}
2172
+ * @public
2173
+ */
2174
+ type PseudorandomU512DeriverFunction = (domainSeparator: string) => Promise<U512BeBytes>;
2175
+ /**
2176
+ * Derives a BN254 field element from the master seed using domain separation.
2177
+ *
2178
+ * @remarks
2179
+ * This function builds on top of `PseudorandomU512DeriverFunction` to reduce
2180
+ * the 512-bit pseudorandom output to a uniformly distributed BN254 field element.
2181
+ * The reduction uses constant-time modular arithmetic to prevent timing side-channels.
2182
+ *
2183
+ * ## Algorithm
2184
+ *
2185
+ * 1. Generate 512-bit pseudorandom value via KMAC256 with `domainSeparator`
2186
+ * 2. Reduce to BN254 field element using constant-time modular reduction:
2187
+ * `fieldElement = u512Value mod BN254_FIELD_PRIME`
2188
+ *
2189
+ * ## Security Properties
2190
+ *
2191
+ * - **Domain Separation**: Different domain separators produce independent outputs
2192
+ * - **Deterministic**: Same inputs always produce the same field element
2193
+ * - **Uniform Distribution**: Output is uniformly distributed in [0, BN254_FIELD_PRIME)
2194
+ * with bias 2^(-512 + log2(BN254_FIELD_PRIME)) ≈ 2^{-256}, which is negligible
2195
+ * - **Constant-Time**: Reduction is performed without data-dependent branches
2196
+ *
2197
+ * Pre-conditions:
2198
+ * - The client MUST have a valid master seed loaded.
2199
+ *
2200
+ * Post-conditions:
2201
+ * - Returns a bigint in [0, BN254_FIELD_PRIME).
2202
+ *
2203
+ * @param domainSeparator - A string that uniquely identifies the derivation context
2204
+ * @returns A Promise resolving to a BN254 field element in range [0, BN254_FIELD_PRIME)
2205
+ *
2206
+ * @example
2207
+ * ```typescript
2208
+ * import { getMasterSeedBasedFieldElementDeriver } from "@umbra/sdk";
2209
+ *
2210
+ * const deriver = getMasterSeedBasedFieldElementDeriver({ client });
2211
+ *
2212
+ * // Derive different keys using domain separation
2213
+ * const viewingKey = await deriver("MasterViewingKey");
2214
+ * const encryptionKey = await deriver("EncryptionKey");
2215
+ * const nullifierKey = await deriver("NullifierKey");
2216
+ *
2217
+ * // Each domain separator produces a completely independent output
2218
+ * ```
2219
+ *
2220
+ * @example
2221
+ * ```typescript
2222
+ * // Deriving time-scoped keys
2223
+ * const yearlyKey = await deriver("YearlyViewingKey-2024");
2224
+ * const monthlyKey = await deriver("MonthlyViewingKey-2024-01");
2225
+ * const dailyKey = await deriver("DailyViewingKey-2024-01-15");
2226
+ * ```
2227
+ *
2228
+ * @see {@link PseudorandomU512DeriverFunction}
2229
+ * @public
2230
+ */
2231
+ type MasterSeedBasedFieldElementDeriverFunction = (domainSeparator: string) => Promise<Bn254FieldElement>;
2232
+
2233
+ /**
2234
+ * Generates a BN254 field element blinding factor for Rescue encryption commitments.
2235
+ *
2236
+ * @remarks
2237
+ * Rescue encryption commitment blinding factors are used to commit to ciphertexts
2238
+ * and plaintexts in UTXO creation ZK proofs. The derivation binds an offset
2239
+ * (typically derived from the generation index) to ensure unique blinding factors
2240
+ * for each UTXO creation event.
2241
+ *
2242
+ * ## Algorithm
2243
+ *
2244
+ * 1. Build domain separator: `"RescueEncryptionCommitmentBlindingFactor - {totalOffset}"`
2245
+ * where `totalOffset = client.offsets.rescueCommitmentBlindingFactor + offset`
2246
+ * 2. Generate 512-bit pseudorandom value using KMAC256
2247
+ * 3. Sample BN254 field element using constant-time reduction
2248
+ *
2249
+ * Pre-conditions:
2250
+ * - The client MUST have a valid master seed loaded.
2251
+ *
2252
+ * Post-conditions:
2253
+ * - Returns a BN254 field element uniformly distributed in [0, BN254_FIELD_PRIME).
2254
+ * - Different offsets produce independent blinding factors.
2255
+ *
2256
+ * @param offset - A U256 offset for unique derivation context (e.g., generation index)
2257
+ * @returns A Promise resolving to a BN254 field element blinding factor
2258
+ *
2259
+ * @example
2260
+ * ```typescript
2261
+ * const generator = getRescueCommitmentBlindingFactorDeriver({ client });
2262
+ * const blindingFactor = await generator(0n as U256);
2263
+ * ```
2264
+ *
2265
+ * @see {@link EphemeralRescueCommitmentBlindingFactorDeriverFunction}
2266
+ * @public
2267
+ */
2268
+ type RescueCommitmentBlindingFactorDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2269
+ /**
2270
+ * Generates a Curve25519 field element random factor for polynomial commitment evaluation.
2271
+ *
2272
+ * @remarks
2273
+ * Random factors for polynomial commitments are Curve25519 field elements used
2274
+ * in Kate-style commitment evaluation to hide the committed polynomial from
2275
+ * a verifier who knows only the commitment, not the coefficients.
2276
+ *
2277
+ * ## Algorithm
2278
+ *
2279
+ * 1. Build domain separator: `"RandomFactorForPolynomialCommitment - {totalOffset}"`
2280
+ * where `totalOffset = client.offsets.randomCommitmentFactor + offset`
2281
+ * 2. Generate 512-bit pseudorandom value using KMAC256
2282
+ * 3. Sample Curve25519 field element using constant-time reduction
2283
+ *
2284
+ * Pre-conditions:
2285
+ * - The client MUST have a valid master seed loaded.
2286
+ *
2287
+ * Post-conditions:
2288
+ * - Returns a Curve25519 field element uniformly distributed in [0, curve25519_order).
2289
+ *
2290
+ * @param offset - A U256 offset for unique derivation context
2291
+ * @returns A Promise resolving to a Curve25519 field element random factor
2292
+ *
2293
+ * @example
2294
+ * ```typescript
2295
+ * const generator = getPolynomialCommitmentFactorDeriver({ client });
2296
+ * const randomFactor = await generator(0n as U256);
2297
+ * ```
2298
+ *
2299
+ * @see {@link RescueCommitmentBlindingFactorDeriverFunction}
2300
+ * @public
2301
+ */
2302
+ type PolynomialCommitmentFactorDeriverFunction = (offset: U256) => Promise<Curve25519FieldElement>;
2303
+ /**
2304
+ * Generates an ephemeral master viewing key for sender-claimable UTXOs.
2305
+ *
2306
+ * @remarks
2307
+ * Ephemeral UTXO master viewing keys are BN254 field elements used as the
2308
+ * "MVK" component of UTXOs that the sender can reclaim. Each generation index
2309
+ * produces an independent ephemeral MVK, ensuring that different UTXOs cannot
2310
+ * be linked through a shared key.
2311
+ *
2312
+ * ## Algorithm
2313
+ *
2314
+ * 1. Build domain separator: `"Umbra Privacy - Ephemeral UTXO MasterViewingKey - {offset}"`
2315
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)` with version personalization
2316
+ * 3. Sample BN254 field element and mask to 252 bits (consistent with main MVK)
2317
+ *
2318
+ * ## Security Properties
2319
+ *
2320
+ * - **Keyed Derivation**: Only the holder of the master seed can derive this value
2321
+ * - **Domain Separated**: Different offsets produce independent ephemeral MVKs
2322
+ * - **Deterministic**: Same client and offset always produce the same key
2323
+ *
2324
+ * @param offset - A U256 offset for unique derivation (typically the generation index)
2325
+ * @returns A Promise resolving to a BN254 field element for the ephemeral MVK
2326
+ *
2327
+ * @example
2328
+ * ```typescript
2329
+ * const generator = getEphemeralUtxoMasterViewingKeyDeriver({ client });
2330
+ * const ephemeralMvk = await generator(generationIndex);
2331
+ * ```
2332
+ *
2333
+ * @see {@link EphemeralUtxoMasterViewingKeyBlindingFactorDeriverFunction}
2334
+ * @public
2335
+ */
2336
+ type EphemeralUtxoMasterViewingKeyDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2337
+ /**
2338
+ * Generates a blinding factor for the ephemeral MVK commitment.
2339
+ *
2340
+ * @remarks
2341
+ * Pairs with `EphemeralUtxoMasterViewingKeyDeriverFunction` to produce the
2342
+ * blinding factor for the Pedersen commitment to the ephemeral MVK.
2343
+ *
2344
+ * ## Algorithm
2345
+ *
2346
+ * 1. Build domain separator: `"Umbra Privacy - Ephemeral UTXO MasterViewingKeyBlindingFactor - {offset}"`
2347
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)`
2348
+ * 3. Sample BN254 field element using constant-time reduction
2349
+ *
2350
+ * @param offset - A U256 offset for unique derivation context (typically the generation index)
2351
+ * @returns A Promise resolving to a BN254 field element blinding factor
2352
+ *
2353
+ * @example
2354
+ * ```typescript
2355
+ * const generator = getEphemeralUtxoMasterViewingKeyBlindingFactorDeriver({ client });
2356
+ * const ephemeralMvkBf = await generator(generationIndex);
2357
+ * ```
2358
+ *
2359
+ * @see {@link EphemeralUtxoMasterViewingKeyDeriverFunction}
2360
+ * @public
2361
+ */
2362
+ type EphemeralUtxoMasterViewingKeyBlindingFactorDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2363
+ /**
2364
+ * Generates an ephemeral Poseidon private key for sender-claimable UTXOs.
2365
+ *
2366
+ * @remarks
2367
+ * Ephemeral UTXO Poseidon private keys serve as the secret key for the
2368
+ * Poseidon cipher used to encrypt UTXO fields in sender-claimable UTXOs.
2369
+ *
2370
+ * ## Algorithm
2371
+ *
2372
+ * 1. Build domain separator: `"Umbra Privacy - Ephemeral UTXO PoseidonPrivateKey - {offset}"`
2373
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)`
2374
+ * 3. Sample BN254 field element using constant-time reduction
2375
+ *
2376
+ * @param offset - A U256 offset for unique derivation context (typically the generation index)
2377
+ * @returns A Promise resolving to a BN254 field element for the ephemeral Poseidon private key
2378
+ *
2379
+ * @example
2380
+ * ```typescript
2381
+ * const generator = getEphemeralUtxoPoseidonPrivateKeyDeriver({ client });
2382
+ * const ephemeralPk = await generator(generationIndex);
2383
+ * ```
2384
+ *
2385
+ * @see {@link EphemeralUtxoPoseidonPrivateKeyBlindingFactorDeriverFunction}
2386
+ * @public
2387
+ */
2388
+ type EphemeralUtxoPoseidonPrivateKeyDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2389
+ /**
2390
+ * Generates a blinding factor for the ephemeral Poseidon private key commitment.
2391
+ *
2392
+ * @remarks
2393
+ * Pairs with `EphemeralUtxoPoseidonPrivateKeyDeriverFunction` to produce the
2394
+ * blinding factor for the Pedersen commitment to the ephemeral Poseidon private key.
2395
+ *
2396
+ * ## Algorithm
2397
+ *
2398
+ * 1. Build domain separator: `"Umbra Privacy - Ephemeral UTXO PoseidonPrivateKeyBlindingFactor - {offset}"`
2399
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)`
2400
+ * 3. Sample BN254 field element using constant-time reduction
2401
+ *
2402
+ * @param offset - A U256 offset for unique derivation context (typically the generation index)
2403
+ * @returns A Promise resolving to a BN254 field element blinding factor
2404
+ *
2405
+ * @example
2406
+ * ```typescript
2407
+ * const generator = getEphemeralUtxoPoseidonPrivateKeyBlindingFactorDeriver({ client });
2408
+ * const ephemeralPkBf = await generator(generationIndex);
2409
+ * ```
2410
+ *
2411
+ * @see {@link EphemeralUtxoPoseidonPrivateKeyDeriverFunction}
2412
+ * @public
2413
+ */
2414
+ type EphemeralUtxoPoseidonPrivateKeyBlindingFactorDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2415
+ /**
2416
+ * Generates a nullifier for an ephemeral UTXO to prevent double-spending.
2417
+ *
2418
+ * @remarks
2419
+ * Nullifiers are BN254 field elements that uniquely identify a UTXO spend event.
2420
+ * When a UTXO is claimed, its nullifier is burned in an on-chain Indexed Merkle
2421
+ * Tree (treap); any subsequent claim with the same nullifier is rejected.
2422
+ *
2423
+ * ## Algorithm
2424
+ *
2425
+ * 1. Build domain separator: `"Umbra Privacy - Ephemeral UTXO Nullifier - {offset}"`
2426
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)`
2427
+ * 3. Sample BN254 field element using constant-time reduction
2428
+ *
2429
+ * ## Security Properties
2430
+ *
2431
+ * - **Unique per UTXO**: Each generation index produces a distinct nullifier
2432
+ * - **Keyed Derivation**: Only the master seed holder can compute the nullifier
2433
+ * - **Deterministic**: Same client and offset always produce the same nullifier
2434
+ *
2435
+ * @param offset - A U256 offset for unique derivation context (typically the generation index)
2436
+ * @returns A Promise resolving to a BN254 field element nullifier
2437
+ *
2438
+ * @example
2439
+ * ```typescript
2440
+ * const generator = getEphemeralUtxoNullifierDeriver({ client });
2441
+ * const nullifier = await generator(generationIndex);
2442
+ * // nullifier is submitted on-chain when claiming the UTXO
2443
+ * ```
2444
+ *
2445
+ * @public
2446
+ */
2447
+ type EphemeralUtxoNullifierDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2448
+ /**
2449
+ * Generates an H2 random secret (blinding factor) for ephemeral UTXO creation.
2450
+ *
2451
+ * @remarks
2452
+ * The H2 random secret is a privacy-preserving blinding factor included in the
2453
+ * H2 hash of a UTXO. It prevents the verifier from learning the other UTXO
2454
+ * fields (amount, nullifier, commitment, destination) through the H2 commitment.
2455
+ *
2456
+ * ## Algorithm
2457
+ *
2458
+ * 1. Build domain separator: `"Umbra Privacy - Ephemeral UTXO H2RandomSecret - {offset}"`
2459
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)`
2460
+ * 3. Sample BN254 field element using constant-time reduction
2461
+ *
2462
+ * ## Usage in H2 Hash
2463
+ *
2464
+ * The H2 hash is computed as:
2465
+ * ```
2466
+ * H2 = Poseidon([amount, nullifier, userCommitment, destAddrLow, destAddrHigh, h2RandomSecret])
2467
+ * ```
2468
+ *
2469
+ * @param offset - A U256 offset for unique derivation context (typically the generation index)
2470
+ * @returns A Promise resolving to a BN254 field element random secret
2471
+ *
2472
+ * @example
2473
+ * ```typescript
2474
+ * const generator = getEphemeralUtxoH2RandomSecretDeriver({ client });
2475
+ * const h2BlindingFactor = await generator(generationIndex);
2476
+ * ```
2477
+ *
2478
+ * @see {@link EphemeralUtxoNullifierDeriverFunction}
2479
+ * @public
2480
+ */
2481
+ type EphemeralUtxoH2RandomSecretDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2482
+ /**
2483
+ * Generates a blinding factor for Poseidon keystream commitments.
2484
+ *
2485
+ * @remarks
2486
+ * Poseidon keystream blinding factors are used to commit to individual keystream
2487
+ * values in Poseidon cipher operations. Binding the blinding factor to both the
2488
+ * keystream value and an offset ensures that each keystream position has a unique,
2489
+ * independently derived blinding factor.
2490
+ *
2491
+ * ## Algorithm
2492
+ *
2493
+ * 1. Build domain separator: `"Umbra Privacy - PoseidonKeystreamBlindingFactor - {offset}"`
2494
+ * 2. Concatenate `masterSeed` (64 bytes) || `keystream` (32 bytes, LE) || `offset` (32 bytes, LE)
2495
+ * 3. Compute `KMAC256(key=domainSeparator, data=concatenated, dkLen=64)`
2496
+ * 4. Sample BN254 field element using constant-time reduction
2497
+ *
2498
+ * ## Usage in Keystream Commitments
2499
+ *
2500
+ * ```
2501
+ * commitment = Poseidon([keystream, blindingFactor])
2502
+ * ```
2503
+ *
2504
+ * Pre-conditions:
2505
+ * - The client MUST have a valid master seed loaded.
2506
+ * - `keystream` MUST be a valid BN254 field element.
2507
+ *
2508
+ * Post-conditions:
2509
+ * - Different `(keystream, offset)` pairs produce independent blinding factors.
2510
+ *
2511
+ * @param keystream - The Poseidon keystream value (BN254 field element) to bind to
2512
+ * @param offset - A U256 offset for additional domain separation (e.g., keystream counter index)
2513
+ * @returns A Promise resolving to a BN254 field element blinding factor
2514
+ *
2515
+ * @example
2516
+ * ```typescript
2517
+ * const generator = getPoseidonKeystreamBlindingFactorDeriver({ client });
2518
+ *
2519
+ * // Generate blinding factors for each keystream position
2520
+ * const bf0 = await generator(keystream0, 0n as U256);
2521
+ * const bf1 = await generator(keystream1, 1n as U256);
2522
+ * const bf2 = await generator(keystream2, 2n as U256);
2523
+ * ```
2524
+ *
2525
+ * @public
2526
+ */
2527
+ type PoseidonKeystreamBlindingFactorDeriverFunction = (keystream: Bn254FieldElement, offset: U256) => Promise<Bn254FieldElement>;
2528
+ /**
2529
+ * Generates a blinding factor for ephemeral Rescue encryption commitments in UTXO creation.
2530
+ *
2531
+ * @remarks
2532
+ * Ephemeral Rescue encryption commitment blinding factors bind ciphertexts,
2533
+ * plaintexts, keys, nonce, and public key components into a zero-knowledge
2534
+ * verifiable commitment. This variant uses keyed derivation (master seed as
2535
+ * the KMAC key) rather than the offset-combined approach of the non-ephemeral variant.
2536
+ *
2537
+ * ## Algorithm
2538
+ *
2539
+ * 1. Build domain separator:
2540
+ * `"Umbra Privacy - Ephemeral RescueEncryptionCommitmentBlindingFactor - {offset}"`
2541
+ * 2. Compute `KMAC256(domainSeparator, masterSeed, dkLen=64)` with version personalization
2542
+ * 3. Sample BN254 field element using constant-time reduction
2543
+ *
2544
+ * ## Security Properties
2545
+ *
2546
+ * - **Keyed Derivation**: Uses the client's master seed as the KMAC message
2547
+ * - **Domain Separated**: Different offsets produce independent values
2548
+ * - **ZK-Friendly**: Output is a valid BN254 field element for circuit use
2549
+ *
2550
+ * @param offset - A U256 offset for unique derivation context (typically `expandedModifiedGenerationIndexU256`)
2551
+ * @returns A Promise resolving to a BN254 field element blinding factor
2552
+ *
2553
+ * @example
2554
+ * ```typescript
2555
+ * const generator = getEphemeralRescueCommitmentBlindingFactorDeriver({ client });
2556
+ * const blindingFactor = await generator(expandedModifiedGenerationIndexU256);
2557
+ * ```
2558
+ *
2559
+ * @see {@link RescueCommitmentBlindingFactorDeriverFunction}
2560
+ * @public
2561
+ */
2562
+ type EphemeralRescueCommitmentBlindingFactorDeriverFunction = (offset: U256) => Promise<Bn254FieldElement>;
2563
+
2564
+ /**
2565
+ * Rescue Cipher Interface Types
2566
+ *
2567
+ * This module defines the function type signatures for Rescue cipher operations
2568
+ * at the high-level key-exchange layer. These types abstract over the private-key
2569
+ * binding so that callers can work with pre-configured encryptors, decryptors,
2570
+ * and key generators without repeatedly supplying raw key material.
2571
+ *
2572
+ * ## Design Philosophy
2573
+ *
2574
+ * Each factory function in `./index.ts` (e.g. `getRescueEncryptorFromPrivateKey`)
2575
+ * accepts a private key once and returns a function matching one of the types
2576
+ * defined here. Callers then use the returned function repeatedly without
2577
+ * re-exposing the private key. This minimises the surface area over which raw
2578
+ * key bytes are visible in calling code.
2579
+ *
2580
+ * ## Contract for All Implementors
2581
+ *
2582
+ * Implementations of these function types **must**:
2583
+ * 1. Validate all typed inputs at the boundary (assert branded types).
2584
+ * 2. Not cache cipher instances or shared secrets internally.
2585
+ * 3. Create a fresh cipher instance on each invocation to limit how long
2586
+ * sensitive material remains in heap memory.
2587
+ * 4. Return values in the expected branded types with appropriate assertions.
2588
+ *
2589
+ * ## Nonce Security
2590
+ *
2591
+ * The Rescue cipher uses counter mode (CTR): the keystream is generated by
2592
+ * encrypting successive counter values with the derived key. The nonce
2593
+ * determines the initial counter state. **Nonce reuse with the same key is
2594
+ * catastrophic** — it allows an attacker to cancel the keystream and recover
2595
+ * the XOR (or field-sum) of the two plaintexts. Always use
2596
+ * {@link RcEncryptorFunction} (which generates random nonces) unless you have
2597
+ * a specific reason to manage nonces externally.
2598
+ *
2599
+ * @packageDocumentation
2600
+ * @module interfaces/cryptography/rescue-cipher
2601
+ * @public
2602
+ */
2603
+
2604
+ /**
2605
+ * Encryption function type with automatic nonce generation.
2606
+ *
2607
+ * A pre-configured encryptor that generates a fresh random nonce for each
2608
+ * encryption call. The nonce is returned alongside the ciphertexts because it
2609
+ * is required for decryption and must be stored by the caller.
2610
+ *
2611
+ * @param plaintext - Array of {@link RcPlaintext} field elements to encrypt.
2612
+ * Each element must be a valid Curve25519 field element (< 2^255 - 19).
2613
+ * The array may contain any number of elements; each is encrypted at a
2614
+ * successive counter position in the Rescue CTR stream.
2615
+ * @returns A promise resolving to an object containing:
2616
+ * - `ciphertexts` — one {@link RcCiphertext} per plaintext element.
2617
+ * - `nonce` — the 128-bit {@link RcEncryptionNonce} used for this encryption.
2618
+ * Store this alongside the ciphertexts; it is public and does not need
2619
+ * to be kept secret, but it must be unique per (key, nonce) pair.
2620
+ *
2621
+ * @remarks
2622
+ * ## Implementation Contract
2623
+ *
2624
+ * - A **fresh cryptographically random nonce** is generated for each call.
2625
+ * - The returned `ciphertexts` array has the same length as `plaintext`.
2626
+ * - All returned values are valid branded types (asserted before return).
2627
+ * - No cipher instance, shared secret, or nonce is retained after the
2628
+ * call completes.
2629
+ *
2630
+ * ## Nonce Properties
2631
+ *
2632
+ * Nonces generated by the default implementation are 128-bit values from
2633
+ * `generateRandomNonce()` in `../../common/arcium`. With 128-bit nonces,
2634
+ * the birthday-bound collision probability over N calls is approximately
2635
+ * N²/2^128, which is negligible for any practical N.
2636
+ *
2637
+ * @public
2638
+ *
2639
+ * @example
2640
+ * ```typescript
2641
+ * const encryptor: RcEncryptorFunction = getRescueEncryptorFromPrivateKey(
2642
+ * myPrivateKey,
2643
+ * { umbraX25519PublicKey: networkConfig.mxePubkey },
2644
+ * );
2645
+ *
2646
+ * const plaintexts: RcPlaintext[] = [balance, auxiliaryData];
2647
+ * const { ciphertexts, nonce } = await encryptor(plaintexts);
2648
+ *
2649
+ * // Both ciphertexts and nonce must be stored for later decryption:
2650
+ * await persistEncryptedBalance({ ciphertexts, nonce });
2651
+ * ```
2652
+ *
2653
+ * @see {@link RcEncryptorWithNonceFunction} — variant requiring explicit nonce
2654
+ * @see {@link getRescueEncryptorFromPrivateKey} — factory that produces this function type
2655
+ */
2656
+ type RcEncryptorFunction = (plaintext: readonly RcPlaintext[]) => Promise<{
2657
+ ciphertexts: RcCiphertext[];
2658
+ nonce: RcEncryptionNonce;
2659
+ }>;
2660
+ /**
2661
+ * Encryption function type with explicit nonce parameter.
2662
+ *
2663
+ * A pre-configured encryptor where the caller supplies the nonce on each call.
2664
+ * This variant is appropriate when nonces are managed externally (e.g. as a
2665
+ * counter maintained by the caller) or when deterministic encryption is required
2666
+ * (e.g. for generating test vectors with a fixed nonce).
2667
+ *
2668
+ * @param plaintext - Array of {@link RcPlaintext} field elements to encrypt.
2669
+ * Each element must be a valid Curve25519 field element (< 2^255 - 19).
2670
+ * @param nonce - The 128-bit nonce to use for this encryption. Must be a valid
2671
+ * {@link RcEncryptionNonce} (bigint in [0, 2^128 - 1]).
2672
+ * **CRITICAL**: This nonce MUST be unique for each encryption call with the
2673
+ * same underlying key. See the nonce security note in the module documentation.
2674
+ * @returns A promise resolving to an array of {@link RcCiphertext} values,
2675
+ * one per input plaintext element.
2676
+ *
2677
+ * @remarks
2678
+ * ## Implementation Contract
2679
+ *
2680
+ * - `nonce` is validated via {@link assertRcEncryptionNonce} before use.
2681
+ * - The returned array has the same length as `plaintext`.
2682
+ * - All returned values are valid {@link RcCiphertext} branded types.
2683
+ * - No state is retained after the call completes.
2684
+ *
2685
+ * ## When to Prefer This Over `RcEncryptorFunction`
2686
+ *
2687
+ * - When the same nonce must be used across multiple related encryption calls
2688
+ * (e.g. encrypting a batch of UTXOs that share a nonce for on-chain space
2689
+ * efficiency).
2690
+ * - When reproducing exact ciphertexts from a known (plaintext, nonce, key)
2691
+ * triple for testing or recovery purposes.
2692
+ * - When the nonce is derived from a protocol-level counter rather than random
2693
+ * sampling (e.g. the transaction sequence number).
2694
+ *
2695
+ * @public
2696
+ *
2697
+ * @example
2698
+ * ```typescript
2699
+ * const encryptor: RcEncryptorWithNonceFunction = getRescueEncryptorWithNonceFromPrivateKey(
2700
+ * myPrivateKey,
2701
+ * { umbraX25519PublicKey: networkConfig.mxePubkey },
2702
+ * );
2703
+ *
2704
+ * // Caller-managed nonce (must be unique per key):
2705
+ * const nonce = generateRandomNonce();
2706
+ * const plaintexts: RcPlaintext[] = [balance];
2707
+ * const ciphertexts = await encryptor(plaintexts, nonce);
2708
+ * ```
2709
+ *
2710
+ * @example
2711
+ * ```typescript
2712
+ * // Deterministic test encryption (NEVER reuse in production with different plaintexts):
2713
+ * const fixedNonce = 1n as RcEncryptionNonce;
2714
+ * const ciphertexts = await encryptor(plaintexts, fixedNonce);
2715
+ * ```
2716
+ *
2717
+ * @see {@link RcEncryptorFunction} — preferred variant with automatic nonce generation
2718
+ * @see {@link getRescueEncryptorWithNonceFromPrivateKey} — factory that produces this function type
2719
+ */
2720
+ type RcEncryptorWithNonceFunction = (plaintext: readonly RcPlaintext[], nonce: RcEncryptionNonce) => Promise<RcCiphertext[]>;
2721
+ /**
2722
+ * Decryption function type using a nonce.
2723
+ *
2724
+ * A pre-configured decryptor that recovers the original plaintext elements from
2725
+ * Rescue ciphertexts using the same nonce that was used during encryption.
2726
+ *
2727
+ * @param ciphertext - Array of {@link RcCiphertext} values to decrypt.
2728
+ * Must be the ciphertexts produced by a matching encryptor with the same
2729
+ * private key and public key. Each element must be a valid Curve25519 field
2730
+ * element.
2731
+ * @param nonce - The {@link RcEncryptionNonce} used during encryption.
2732
+ * Must exactly match the nonce stored alongside the ciphertexts; using a
2733
+ * different nonce will silently produce incorrect (garbage) plaintexts.
2734
+ * @returns A promise resolving to an array of {@link RcPlaintext} values,
2735
+ * one per input ciphertext element.
2736
+ *
2737
+ * @remarks
2738
+ * ## Implementation Contract
2739
+ *
2740
+ * - All `ciphertext` elements are validated via {@link assertRcCiphertext} before use.
2741
+ * - `nonce` is validated via {@link assertRcEncryptionNonce} before use.
2742
+ * - The returned array has the same length as `ciphertext`.
2743
+ * - All returned values are valid {@link RcPlaintext} branded types (asserted).
2744
+ * - No state is retained after the call completes.
2745
+ *
2746
+ * ## No Authentication
2747
+ *
2748
+ * Unlike AES-256-GCM, the Rescue cipher in CTR mode does not include an
2749
+ * authentication tag. This function will **not** detect:
2750
+ * - A wrong nonce (will silently return garbage).
2751
+ * - Tampered ciphertexts (will silently return incorrect plaintexts).
2752
+ *
2753
+ * Authentication is provided at the protocol level by the Arcium MPC computation
2754
+ * signature. For client-side usage, callers should cross-validate the decrypted
2755
+ * values against the on-chain commitments (e.g. Poseidon hash of the balance).
2756
+ *
2757
+ * @public
2758
+ *
2759
+ * @example
2760
+ * ```typescript
2761
+ * const decryptor: RcDecryptorFunction = getRescueDecryptorFromPrivateKey(
2762
+ * myPrivateKey,
2763
+ * { umbraX25519PublicKey: networkConfig.mxePubkey },
2764
+ * );
2765
+ *
2766
+ * // Load stored ciphertexts and the nonce used during encryption:
2767
+ * const { ciphertexts, nonce } = await loadEncryptedBalance(accountId);
2768
+ * const plaintexts = await decryptor(ciphertexts, nonce);
2769
+ * const [balance] = plaintexts;
2770
+ * ```
2771
+ *
2772
+ * @see {@link RcEncryptorFunction} — paired encryption function type
2773
+ * @see {@link getRescueDecryptorFromPrivateKey} — factory that produces this function type
2774
+ */
2775
+ type RcDecryptorFunction = (ciphertext: readonly RcCiphertext[], nonce: RcEncryptionNonce) => Promise<RcPlaintext[]>;
2776
+ /**
2777
+ * Key generation function type for counter-based encryption schemes.
2778
+ *
2779
+ * Generates symmetric encryption keys for specified counter positions by
2780
+ * encrypting zero-value plaintexts at those positions. The resulting keys can
2781
+ * be used as independent per-counter symmetric keys in protocols that require
2782
+ * key separation between different token account positions.
2783
+ *
2784
+ * @param counters - Array of counter values identifying the key positions to
2785
+ * generate. Each must be a valid {@link RcCounter} (non-negative Curve25519
2786
+ * field element). Duplicates are allowed; the map will contain a single entry
2787
+ * per unique counter value.
2788
+ * @param nonce - The 128-bit {@link RcEncryptionNonce} to use for the internal
2789
+ * encryption that generates the keys. Must be unique per (key, nonce) pair.
2790
+ * @returns A promise resolving to a `ReadonlyMap<RcCounter, RcKey>` mapping
2791
+ * each requested counter to its derived {@link RcKey}. Counters not present
2792
+ * in the `counters` input are not included in the map.
2793
+ *
2794
+ * @remarks
2795
+ * ## Key Generation Algorithm
2796
+ *
2797
+ * The key for counter `c` is defined as:
2798
+ * ```
2799
+ * key[c] = Rescue-CTR-Encrypt(key=sharedSecret, nonce=nonce, plaintext=0n)[c]
2800
+ * ```
2801
+ *
2802
+ * That is, a zero-value plaintext is placed at each position from 0 to
2803
+ * `max(counters)` and all positions are encrypted in a single CTR invocation.
2804
+ * Only the positions in `counters` are returned.
2805
+ *
2806
+ * ## Security Properties
2807
+ *
2808
+ * - Keys generated with the same (private key, public key, nonce) are deterministic.
2809
+ * - Keys generated at different counter positions are computationally independent
2810
+ * (due to the CTR mode keystream).
2811
+ * - The nonce must be unique per key-generation session; reusing the nonce with
2812
+ * the same key pair produces the same keys (which may be intentional for
2813
+ * deterministic recovery, but is a security risk if used with different plaintexts).
2814
+ *
2815
+ * ## Implementation Notes
2816
+ *
2817
+ * - Counter values are compared as `bigint` to avoid precision loss.
2818
+ * - The function internally allocates `max(counters) + 1` zero plaintexts, so
2819
+ * very large sparse counter sets (e.g. `[0n, 2^128]`) would be impractical.
2820
+ * Callers should use small, dense counter ranges.
2821
+ *
2822
+ * ## Use Cases
2823
+ *
2824
+ * - Pre-computing AES-equivalent stream-cipher keys for batch operations.
2825
+ * - Deriving per-UTXO keys for counter-mode encryption schemes.
2826
+ * - Key derivation for specific token account generation indices.
2827
+ *
2828
+ * @public
2829
+ *
2830
+ * @example
2831
+ * ```typescript
2832
+ * const keyGenerator: RcKeyGeneratorFunction = getRescueKeyGeneratorFromPrivateKey(
2833
+ * myPrivateKey,
2834
+ * { umbraX25519PublicKey: networkConfig.mxePubkey },
2835
+ * );
2836
+ *
2837
+ * const counters: RcCounter[] = [0n, 1n, 5n];
2838
+ * const nonce = generateRandomNonce();
2839
+ * const keysMap = await keyGenerator(counters, nonce);
2840
+ *
2841
+ * const key0 = keysMap.get(0n); // RcKey — key for counter 0
2842
+ * const key5 = keysMap.get(5n); // RcKey — key for counter 5
2843
+ * // keysMap.get(2n) === undefined — counter 2 was not requested
2844
+ * ```
2845
+ *
2846
+ * @see {@link RcEncryptorWithNonceFunction} — used internally to generate the keys
2847
+ * @see {@link getRescueKeyGeneratorFromPrivateKey} — factory that produces this function type
2848
+ */
2849
+ type RcKeyGeneratorFunction = (counters: readonly RcCounter[], nonce: RcEncryptionNonce) => Promise<ReadonlyMap<RcCounter, RcKey>>;
2850
+ /**
2851
+ * Rescue Cipher Internal Interfaces
2852
+ *
2853
+ * Type definitions and dependency injection interfaces for the Rescue-XLIX
2854
+ * cipher and Rescue-Prime hash function. All types in this module are internal
2855
+ * to the `rescue-cipher` package; consumers interact only with the public API
2856
+ * exported from `index.ts`.
2857
+ *
2858
+ * ## Design Rationale
2859
+ *
2860
+ * The interfaces in this file serve two purposes:
2861
+ *
2862
+ * - **Abstraction**: `FieldArithmetic` decouples the cipher and hash logic from
2863
+ * any specific field implementation. The default production path uses the
2864
+ * SDK's `math/curve25519/field-arithmetic` module, but tests can substitute
2865
+ * alternative implementations (e.g., slow-but-correct reference versions).
2866
+ *
2867
+ * - **Compatibility**: `RescueCipherInstance` mirrors the shape of
2868
+ * `@arcium-hq/client`'s `RescueCipher` class, allowing the SDK to drop in
2869
+ * its own implementation without breaking callers that depend on that shape.
2870
+ *
2871
+ * ## Dependency Injection
2872
+ *
2873
+ * `RescueCipherDeps` and `RescuePrimeHashDeps` follow the SDK-wide convention
2874
+ * of optional `*Deps` parameters on factory functions. Omitting them selects
2875
+ * the production defaults. Providing them bypasses module-level caches, so
2876
+ * tests can exercise the pure functional logic in isolation.
2877
+ *
2878
+ * @packageDocumentation
2879
+ * @module crypto/rescue-cipher/interfaces
2880
+ * @internal
2881
+ */
2882
+ /**
2883
+ * A stateful Rescue-XLIX cipher instance capable of encrypting and decrypting
2884
+ * vectors of field elements in CTR (counter) mode.
2885
+ *
2886
+ * @remarks
2887
+ * This interface is intentionally designed to be structurally compatible with
2888
+ * the `RescueCipher` class from `@arcium-hq/client`, enabling the SDK to serve
2889
+ * as a drop-in replacement without any upstream changes to callers.
2890
+ *
2891
+ * ## CTR Mode Overview
2892
+ *
2893
+ * Counter mode turns the Rescue-XLIX block cipher into a stream cipher:
2894
+ *
2895
+ * 1. A counter block `[nonce, blockIndex, 0, 0, 0]` is assembled for each
2896
+ * block of `BLOCK_SIZE = 5` plaintext elements.
2897
+ * 2. The Rescue permutation is applied to the counter block to produce a
2898
+ * keystream block.
2899
+ * 3. Each plaintext element is added (modulo p) to the corresponding keystream
2900
+ * element to produce ciphertext.
2901
+ *
2902
+ * Decryption is identical to encryption because field addition is its own
2903
+ * inverse: `c - k ≡ p + k - k ≡ p` when the same keystream is generated.
2904
+ *
2905
+ * ## Key Material
2906
+ *
2907
+ * The cipher instance embeds a key schedule derived from the shared secret at
2908
+ * construction time (see `createRescueCipherInstance` in `index.ts`). The key
2909
+ * schedule consists of the intermediate states produced by running the Rescue
2910
+ * permutation on the derived key, used as round keys.
2911
+ *
2912
+ * ## Security Notes
2913
+ *
2914
+ * - Nonces MUST be unique for every (key, nonce) pair. Nonce reuse under the
2915
+ * same key results in complete loss of confidentiality (two-time-pad attack).
2916
+ * - Cipher instances are not cached; each call to `getRescueCipherInstance`
2917
+ * creates a fresh instance to limit key material lifetime in memory.
2918
+ *
2919
+ * @example
2920
+ * ```typescript
2921
+ * import { getRescueCipherInstance } from "./index";
2922
+ *
2923
+ * const sharedSecret = new Uint8Array(32).fill(0xab); // from X25519 ECDH
2924
+ * const nonce = crypto.getRandomValues(new Uint8Array(16));
2925
+ *
2926
+ * const cipher = getRescueCipherInstance(sharedSecret);
2927
+ *
2928
+ * // Encrypt a vector of field elements
2929
+ * const plaintext: bigint[] = [1n, 2n, 3n, 4n, 5n];
2930
+ * const ciphertext = cipher.encrypt(plaintext, nonce);
2931
+ * // ciphertext: number[][], each inner array is 32 bytes (LE field element)
2932
+ *
2933
+ * // Decrypt back
2934
+ * const recovered = cipher.decrypt(ciphertext, nonce);
2935
+ * // recovered: bigint[] === plaintext
2936
+ * ```
2937
+ *
2938
+ * @see {@link RescueCipherDeps} — dependency injection for custom field arithmetic and KDF
2939
+ * @see `getRescueCipherInstance` in `index.ts` — factory function that returns this instance
2940
+ *
2941
+ * @internal
2942
+ */
2943
+ interface RescueCipherInstance {
2944
+ /**
2945
+ * Encrypts an array of field elements using Rescue-XLIX in CTR mode.
2946
+ *
2947
+ * @remarks
2948
+ * Plaintext elements must be valid field elements: `0 <= x < p`.
2949
+ * The nonce must be exactly `NONCE_BYTES = 16` bytes.
2950
+ *
2951
+ * The returned ciphertext is a parallel array of 32-byte little-endian
2952
+ * serialisations of the encrypted field elements. The length of the returned
2953
+ * array always equals `plaintext.length`.
2954
+ *
2955
+ * @param plaintext - Array of bigint field elements to encrypt; each must
2956
+ * satisfy `0 <= x < FIELD_PRIME`
2957
+ * @param nonce - 16-byte unique nonce; must not be reused under the same key
2958
+ * @returns Array of `number[]` where each inner array is a 32-byte
2959
+ * little-endian encoding of one ciphertext field element
2960
+ *
2961
+ * @throws `Error` if `nonce.length !== 16`
2962
+ *
2963
+ * @example
2964
+ * ```typescript
2965
+ * const nonce = crypto.getRandomValues(new Uint8Array(16));
2966
+ * const plain = [0n, 1n, 2n];
2967
+ * const cipher = getRescueCipherInstance(sharedSecret);
2968
+ * const enc = cipher.encrypt(plain, nonce);
2969
+ * // enc.length === 3, enc[0].length === 32
2970
+ * ```
2971
+ */
2972
+ encrypt: (plaintext: bigint[], nonce: Uint8Array) => number[][];
2973
+ /**
2974
+ * Decrypts an array of 32-byte ciphertext elements using Rescue-XLIX in CTR mode.
2975
+ *
2976
+ * @remarks
2977
+ * The nonce must be the same 16-byte value that was used during encryption.
2978
+ * Each element of `ciphertext` must be exactly 32 bytes (one serialised
2979
+ * field element in little-endian byte order).
2980
+ *
2981
+ * Decryption is structurally identical to encryption (CTR mode symmetry):
2982
+ * the same keystream is generated and subtracted (mod p) from each
2983
+ * ciphertext element.
2984
+ *
2985
+ * @param ciphertext - Array of `number[]`; each inner array must be exactly
2986
+ * 32 bytes representing one little-endian field element
2987
+ * @param nonce - The same 16-byte nonce used during encryption
2988
+ * @returns Array of bigint plaintext field elements
2989
+ *
2990
+ * @throws `Error` if `nonce.length !== 16`
2991
+ * @throws `Error` if any element of `ciphertext` does not have length 32
2992
+ *
2993
+ * @example
2994
+ * ```typescript
2995
+ * const plain = [10n, 20n, 30n];
2996
+ * const nonce = crypto.getRandomValues(new Uint8Array(16));
2997
+ * const enc = cipher.encrypt(plain, nonce);
2998
+ * const dec = cipher.decrypt(enc, nonce);
2999
+ * // dec deepEquals plain
3000
+ * ```
3001
+ */
3002
+ decrypt: (ciphertext: number[][], nonce: Uint8Array) => bigint[];
3003
+ }
3004
+ /**
3005
+ * Unified interface for finite field arithmetic over GF(p).
3006
+ *
3007
+ * @remarks
3008
+ * This interface abstracts all modular arithmetic needed by the Rescue-XLIX
3009
+ * permutation so that the cipher and hash implementations are independent of
3010
+ * the specific underlying library. The production default binds this to the
3011
+ * SDK's `math/curve25519/field-arithmetic` module, which targets the prime
3012
+ * `p = 2^255 - 19`.
3013
+ *
3014
+ * Implementations must enforce that all returned values are in the canonical
3015
+ * reduced range `[0, ORDER)`. In particular:
3016
+ *
3017
+ * - `create` must reduce any `bigint` into the field.
3018
+ * - `add`, `sub`, `mul`, `pow` must all return values in `[0, ORDER)`.
3019
+ * - `inv(0)` is undefined and implementations may throw or return 0.
3020
+ *
3021
+ * ## Compatibility
3022
+ *
3023
+ * The interface is intentionally aligned with the field accessor objects
3024
+ * exposed by `@noble/curves` (which uses `ORDER`, `BYTES`, `ZERO`, `ONE`,
3025
+ * `create`, `add`, `sub`, `mul`, `inv`, `pow`, `is0`), so that a `@noble`
3026
+ * field can be adapted to this interface with minimal glue code.
3027
+ *
3028
+ * @example
3029
+ * ```typescript
3030
+ * import { getFieldArithmetic } from "./index";
3031
+ *
3032
+ * const F = getFieldArithmetic();
3033
+ * const a = F.create(12345678901234567890n);
3034
+ * const b = F.create(98765432109876543210n);
3035
+ *
3036
+ * const sum = F.add(a, b); // (a + b) mod p
3037
+ * const prod = F.mul(a, b); // (a * b) mod p
3038
+ * const inv = F.inv(a); // a^(-1) mod p
3039
+ * const pow5 = F.pow(a, 5n); // a^5 mod p
3040
+ * console.log(F.is0(F.sub(a, a))); // true
3041
+ * ```
3042
+ *
3043
+ * @see {@link RescueCipherDeps} — inject a custom `FieldArithmetic` into the cipher
3044
+ * @see {@link RescuePrimeHashDeps} — inject a custom `FieldArithmetic` into the hash
3045
+ * @see `getFieldArithmetic` in `index.ts` — the default production implementation
3046
+ *
3047
+ * @internal
3048
+ */
3049
+ interface FieldArithmetic {
3050
+ /**
3051
+ * The field modulus (prime characteristic p).
3052
+ *
3053
+ * @remarks
3054
+ * For the production implementation this equals `FIELD_PRIME = 2^255 - 19`.
3055
+ * All arithmetic results are in the range `[0, ORDER)`.
3056
+ *
3057
+ * @readonly
3058
+ */
3059
+ readonly ORDER: bigint;
3060
+ /**
3061
+ * Number of bytes required to represent one field element.
3062
+ *
3063
+ * @remarks
3064
+ * For `p = 2^255 - 19`, this is 32 bytes (255 bits rounded up to the
3065
+ * nearest byte boundary).
3066
+ *
3067
+ * @readonly
3068
+ */
3069
+ readonly BYTES: number;
3070
+ /**
3071
+ * Additive identity: 0 in GF(p).
3072
+ *
3073
+ * @readonly
3074
+ */
3075
+ readonly ZERO: bigint;
3076
+ /**
3077
+ * Multiplicative identity: 1 in GF(p).
3078
+ *
3079
+ * @readonly
3080
+ */
3081
+ readonly ONE: bigint;
3082
+ /**
3083
+ * Reduces an arbitrary bigint into the canonical field range `[0, ORDER)`.
3084
+ *
3085
+ * @param value - Any bigint, possibly negative or >= ORDER
3086
+ * @returns `((value % ORDER) + ORDER) % ORDER`
3087
+ */
3088
+ create: (value: bigint) => bigint;
3089
+ /**
3090
+ * Field addition: `(a + b) mod p`.
3091
+ *
3092
+ * @param a - First operand; must be in `[0, ORDER)`
3093
+ * @param b - Second operand; must be in `[0, ORDER)`
3094
+ * @returns `(a + b) mod ORDER`, in `[0, ORDER)`
3095
+ */
3096
+ add: (a: bigint, b: bigint) => bigint;
3097
+ /**
3098
+ * Field subtraction: `(a - b) mod p`.
3099
+ *
3100
+ * @param a - Minuend; must be in `[0, ORDER)`
3101
+ * @param b - Subtrahend; must be in `[0, ORDER)`
3102
+ * @returns `(a - b + ORDER) mod ORDER`, in `[0, ORDER)`
3103
+ */
3104
+ sub: (a: bigint, b: bigint) => bigint;
3105
+ /**
3106
+ * Field multiplication: `(a * b) mod p`.
3107
+ *
3108
+ * @param a - First factor; must be in `[0, ORDER)`
3109
+ * @param b - Second factor; must be in `[0, ORDER)`
3110
+ * @returns `(a * b) mod ORDER`, in `[0, ORDER)`
3111
+ */
3112
+ mul: (a: bigint, b: bigint) => bigint;
3113
+ /**
3114
+ * Modular inverse: `a^(-1) mod p`.
3115
+ *
3116
+ * @remarks
3117
+ * Typically computed via Fermat's little theorem as `a^(p-2) mod p`,
3118
+ * which requires a full modular exponentiation. The result satisfies
3119
+ * `mul(a, inv(a)) === ONE`.
3120
+ *
3121
+ * Behaviour for `a === 0` is undefined. The production implementation may
3122
+ * return `0n` or throw.
3123
+ *
3124
+ * @param a - Operand; must be in `(0, ORDER)`
3125
+ * @returns `a^(-1) mod ORDER`, in `[0, ORDER)`
3126
+ */
3127
+ inv: (a: bigint) => bigint;
3128
+ /**
3129
+ * Modular exponentiation: `a^exponent mod p`.
3130
+ *
3131
+ * @remarks
3132
+ * Used for both the forward S-box (`x^ALPHA`) and the inverse S-box
3133
+ * (`x^ALPHA_INVERSE`). The exponent may be up to 255 bits long.
3134
+ *
3135
+ * @param a - Base; must be in `[0, ORDER)`
3136
+ * @param exponent - Non-negative exponent
3137
+ * @returns `a^exponent mod ORDER`, in `[0, ORDER)`
3138
+ */
3139
+ pow: (a: bigint, exponent: bigint) => bigint;
3140
+ /**
3141
+ * Tests whether a field element is the additive identity (zero).
3142
+ *
3143
+ * @param a - Field element to test; must be in `[0, ORDER)`
3144
+ * @returns `true` if and only if `a === 0n`
3145
+ */
3146
+ is0: (a: bigint) => boolean;
3147
+ }
3148
+ /**
3149
+ * A function that applies the Rescue-XLIX permutation to a state vector in place.
3150
+ *
3151
+ * @remarks
3152
+ * The Rescue-XLIX permutation maps a vector of `m` field elements to another
3153
+ * vector of `m` field elements. It is a bijection (invertible map) used as the
3154
+ * underlying primitive for both the cipher (in a key-dependent manner) and the
3155
+ * hash sponge (in a key-independent manner).
3156
+ *
3157
+ * The state is passed as a flat `bigint[]` and the permuted state is returned
3158
+ * as a new flat `bigint[]` of the same length. The original array is not mutated.
3159
+ *
3160
+ * In cipher mode: `m = BLOCK_SIZE = 5`, round keys are embedded in the closure.
3161
+ * In hash mode: `m = HASH_STATE_SIZE = 12`, round constants are public and fixed.
3162
+ *
3163
+ * @example
3164
+ * ```typescript
3165
+ * // Hash-mode permutation (internal usage)
3166
+ * const permute: RescuePermuteFunction = createHashPermutationFunction(fieldArithmetic);
3167
+ * const inputState = Array(12).fill(0n);
3168
+ * const outputState = permute(inputState);
3169
+ * // outputState.length === 12
3170
+ * ```
3171
+ *
3172
+ * @see `createHashPermutationFunction` in `index.ts` — hash-mode factory
3173
+ * @see `createRescueCipherInstance` in `index.ts` — cipher-mode factory (key-dependent)
3174
+ *
3175
+ * @internal
3176
+ */
3177
+ type RescuePermuteFunction = (state: bigint[]) => bigint[];
3178
+ /**
3179
+ * A function that computes the Rescue-Prime hash digest of a message.
3180
+ *
3181
+ * @remarks
3182
+ * Rescue-Prime is a sponge hash built on the Rescue-XLIX permutation. The
3183
+ * function accepts a message of arbitrary length (as field elements), applies
3184
+ * multi-rate padding, absorbs blocks of `HASH_RATE = 7` elements per
3185
+ * permutation call, then squeezes `HASH_DIGEST_LENGTH = 5` elements.
3186
+ *
3187
+ * ## Padding
3188
+ *
3189
+ * The message is padded with the "10*" scheme (a mandatory 1 bit followed by
3190
+ * zeros to the next multiple of the rate):
3191
+ * ```
3192
+ * paddedMessage = [...message, 1n, 0n, ..., 0n]
3193
+ * ```
3194
+ * where padding brings `paddedMessage.length` to a multiple of `HASH_RATE`.
3195
+ *
3196
+ * ## Output
3197
+ *
3198
+ * The digest is exactly `HASH_DIGEST_LENGTH = 5` field elements
3199
+ * (approximately 1275 bits total).
3200
+ *
3201
+ * @example
3202
+ * ```typescript
3203
+ * const hash = getRescuePrimeHashFunction();
3204
+ * const digest = hash([1n, 2n, 3n]);
3205
+ * // digest.length === 5, each element in [0, FIELD_PRIME)
3206
+ * ```
3207
+ *
3208
+ * @see `getRescuePrimeHashFunction` in `index.ts` — public factory
3209
+ * @see `createRescuePrimeHashFunction` in `index.ts` — implementation
3210
+ * @see {@link RescuePrimeHashDeps} — optional dependency injection
3211
+ *
3212
+ * @internal
3213
+ */
3214
+ type RescuePrimeHashFunction = (message: bigint[]) => bigint[];
3215
+ /**
3216
+ * A function that derives a `BLOCK_SIZE`-element cipher key from a shared secret.
3217
+ *
3218
+ * @remarks
3219
+ * The key derivation function (KDF) maps a raw 32-byte Diffie-Hellman output
3220
+ * to a vector of `BLOCK_SIZE = 5` field elements suitable for use as a
3221
+ * Rescue-XLIX cipher key.
3222
+ *
3223
+ * The default implementation (`deriveRescueCipherKey` in `index.ts`) follows
3224
+ * NIST SP 800-56C Rev 2, Section 4, Option 1, using Rescue-Prime as the
3225
+ * underlying hash:
3226
+ * ```
3227
+ * key = RescuePrimeHash([counter=1, secret_as_field_element, L=5])
3228
+ * ```
3229
+ *
3230
+ * Custom implementations provided via `RescueCipherDeps.deriveKey` must
3231
+ * return exactly `BLOCK_SIZE = 5` bigints in `[0, FIELD_PRIME)`.
3232
+ *
3233
+ * @example
3234
+ * ```typescript
3235
+ * // Custom test-only KDF that uses a fixed key
3236
+ * const fixedKey: RescueKeyDerivationFunction = (_secret) =>
3237
+ * [1n, 2n, 3n, 4n, 5n];
3238
+ *
3239
+ * const cipher = getRescueCipherInstance(sharedSecret, { deriveKey: fixedKey });
3240
+ * ```
3241
+ *
3242
+ * @see {@link RescueCipherDeps} — the deps interface that carries this function
3243
+ * @see `deriveRescueCipherKey` in `index.ts` — the default production KDF
3244
+ *
3245
+ * @internal
3246
+ */
3247
+ type RescueKeyDerivationFunction = (sharedSecret: Uint8Array) => bigint[];
3248
+ /**
3249
+ * Optional dependency injection bag for `getRescueCipherInstance`.
3250
+ *
3251
+ * @remarks
3252
+ * Both fields are optional. When omitted, the production defaults are used:
3253
+ *
3254
+ * - `getFieldArithmetic` defaults to the SDK's `math/curve25519/field-arithmetic`
3255
+ * adapter (the {@link FieldArithmetic} singleton returned by `getFieldArithmetic()`
3256
+ * in `index.ts`).
3257
+ * - `deriveKey` defaults to the Rescue-Prime-based KDF (`deriveRescueCipherKey`
3258
+ * in `index.ts`) which follows NIST SP 800-56C Rev 2 Section 4.
3259
+ *
3260
+ * Providing custom deps bypasses the module-level caches, so each
3261
+ * `getRescueCipherInstance` call with custom deps creates independent instances.
3262
+ * This is intentional to facilitate test isolation and benchmarking.
3263
+ *
3264
+ * @example
3265
+ * ```typescript
3266
+ * // Test with a trivial field (not cryptographically secure)
3267
+ * const testDeps: RescueCipherDeps = {
3268
+ * getFieldArithmetic: () => myTestFieldArithmetic,
3269
+ * deriveKey: (secret) => Array.from({ length: 5 }, (_, i) => BigInt(i)),
3270
+ * };
3271
+ *
3272
+ * const cipher = getRescueCipherInstance(sharedSecret, testDeps);
3273
+ * ```
3274
+ *
3275
+ * @see `getRescueCipherInstance` in `index.ts` — the factory that consumes this interface
3276
+ * @see {@link FieldArithmetic} — the field arithmetic interface to implement
3277
+ * @see {@link RescueKeyDerivationFunction} — the KDF function signature
3278
+ *
3279
+ * @internal
3280
+ */
3281
+ interface RescueCipherDeps {
3282
+ /**
3283
+ * Factory that returns a custom {@link FieldArithmetic} implementation.
3284
+ *
3285
+ * @remarks
3286
+ * When provided, this overrides the default SDK field arithmetic adapter.
3287
+ * The returned implementation must operate over the same prime field
3288
+ * (`p = 2^255 - 19`) as the round constants and MDS matrices.
3289
+ *
3290
+ * @defaultValue `getFieldArithmetic` from `index.ts` (SDK Curve25519 adapter)
3291
+ */
3292
+ readonly getFieldArithmetic?: () => FieldArithmetic;
3293
+ /**
3294
+ * Custom key derivation function that maps a 32-byte secret to a key vector.
3295
+ *
3296
+ * @remarks
3297
+ * When provided, this replaces the NIST SP 800-56C Rescue-Prime KDF entirely.
3298
+ * The function must return exactly `BLOCK_SIZE = 5` bigints in `[0, FIELD_PRIME)`.
3299
+ *
3300
+ * @defaultValue `deriveRescueCipherKey` from `index.ts`
3301
+ */
3302
+ readonly deriveKey?: RescueKeyDerivationFunction;
3303
+ }
3304
+ /**
3305
+ * Optional dependency injection bag for `getRescuePrimeHashFunction`.
3306
+ *
3307
+ * @remarks
3308
+ * Provides a hook to substitute a custom {@link FieldArithmetic} implementation
3309
+ * when constructing the Rescue-Prime sponge hash. This is useful for:
3310
+ *
3311
+ * - Unit testing with a small or mock field to verify the sponge logic
3312
+ * independently of the field arithmetic library.
3313
+ * - Benchmarking alternative field implementations.
3314
+ *
3315
+ * When the `getFieldArithmetic` field is omitted, the production default
3316
+ * (the SDK's `math/curve25519` adapter) is used and the result is cached
3317
+ * as a module-level singleton.
3318
+ *
3319
+ * @example
3320
+ * ```typescript
3321
+ * // Inject a custom field for testing
3322
+ * const hashFn = getRescuePrimeHashFunction({
3323
+ * getFieldArithmetic: () => myReferenceFieldImpl,
3324
+ * });
3325
+ * const digest = hashFn([1n, 2n, 3n]);
3326
+ * ```
3327
+ *
3328
+ * @see `getRescuePrimeHashFunction` in `index.ts` — the factory that consumes this interface
3329
+ * @see {@link FieldArithmetic} — the interface to implement
3330
+ *
3331
+ * @internal
3332
+ */
3333
+ interface RescuePrimeHashDeps {
3334
+ /**
3335
+ * Factory that returns a custom {@link FieldArithmetic} implementation.
3336
+ *
3337
+ * @remarks
3338
+ * When provided, this bypasses the module-level `cachedRescuePrimeHashFunction`
3339
+ * cache and creates a fresh hash function instance backed by the custom field.
3340
+ *
3341
+ * @defaultValue `getFieldArithmetic` from `index.ts` (SDK Curve25519 adapter)
3342
+ */
3343
+ readonly getFieldArithmetic?: () => FieldArithmetic;
3344
+ }
3345
+
3346
+ export type { RescuePrimeHashDeps as $, MinuteViewingKeyGeneratorFunction as A, ModuloPowCurve25519Function as B, Curve25519KeypairGeneratorFunction as C, DailyViewingKeyGeneratorFunction as D, EphemeralMasterSeedDeriverFunction as E, FiatShamirChallengeGeneratorFunction as F, MonthlyViewingKeyGeneratorFunction as G, H2CircuitProvableHashFunction as H, PolynomialEvaluatorDeps as I, PoseidonDecryptorFunction as J, KeystreamCommitmentFunction as K, PoseidonEncryptorFunction as L, MintX25519KeypairDeriverFunction as M, PoseidonHashFunction as N, PoseidonKeystreamBlindingFactorDeriverFunction as O, PoseidonPrivateKeyDeriverFunction as P, PoseidonKeystreamGeneratorFunction as Q, RescueCommitmentBlindingFactorDeriverFunction as R, PoseidonPrfFunction as S, PseudorandomU512DeriverFunction as T, UserCommitmentGeneratorFunction as U, RcDecryptorFunction as V, RcEncryptorFunction as W, RescueCipherDeps as X, RescueCipherInstance as Y, RescueKeyDerivationFunction as Z, RescuePermuteFunction as _, MasterViewingKeyDeriverFunction as a, RescuePrimeHashFunction as a0, SecondViewingKeyGeneratorFunction as a1, UserCommitmentGeneratorDeps as a2, ViewingKeyGeneratorOptions as a3, YearlyViewingKeyGeneratorFunction as a4, Kmac256Function as a5, RandomNonceGeneratorFunction as a6, X25519GetSharedSecretFunction as a7, MasterViewingKeyBlindingFactorDeriverFunction as b, PoseidonBlindingFactorDeriverFunction as c, PolynomialCommitmentFactorDeriverFunction as d, RcKeyGeneratorFunction as e, RcEncryptorWithNonceFunction as f, ChallengePowersFunction as g, PolynomialEvaluatorFunction as h, PoseidonAggregatorHashFunction as i, ChallengePowersDeps as j, EphemeralRescueCommitmentBlindingFactorDeriverFunction as k, EphemeralUtxoH2RandomSecretDeriverFunction as l, EphemeralUtxoMasterViewingKeyBlindingFactorDeriverFunction as m, EphemeralUtxoMasterViewingKeyDeriverFunction as n, EphemeralUtxoNullifierDeriverFunction as o, EphemeralUtxoPoseidonPrivateKeyBlindingFactorDeriverFunction as p, EphemeralUtxoPoseidonPrivateKeyDeriverFunction as q, FieldArithmetic as r, H2CircuitProvableParams as s, H2FullParams as t, H2GeneratorFns as u, H2HashFunction as v, HourlyViewingKeyGeneratorFunction as w, MasterSeedBasedFieldElementDeriverFunction as x, MasterSeedGeneratorFunction as y, MintViewingKeyDeriverFunction as z };