@unlink-xyz/core 0.1.3-canary.fd5dddf → 0.1.4

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 (213) hide show
  1. package/README.md +9 -0
  2. package/dist/account/account.d.ts +31 -2
  3. package/dist/account/account.d.ts.map +1 -1
  4. package/dist/account/accounts.d.ts +42 -0
  5. package/dist/account/accounts.d.ts.map +1 -0
  6. package/dist/account/seed.d.ts +45 -0
  7. package/dist/account/seed.d.ts.map +1 -0
  8. package/dist/account/serialization.d.ts +6 -0
  9. package/dist/account/serialization.d.ts.map +1 -0
  10. package/dist/browser/index.js +34424 -86406
  11. package/dist/browser/index.js.map +1 -1
  12. package/dist/browser/wallet/index.js +55942 -0
  13. package/dist/browser/wallet/index.js.map +1 -0
  14. package/dist/clients/broadcaster.d.ts +1 -0
  15. package/dist/clients/broadcaster.d.ts.map +1 -1
  16. package/dist/clients/indexer.d.ts +5 -0
  17. package/dist/clients/indexer.d.ts.map +1 -1
  18. package/dist/config.d.ts +6 -4
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/core.d.ts.map +1 -1
  21. package/dist/crypto/adapters/index.d.ts +17 -0
  22. package/dist/crypto/adapters/index.d.ts.map +1 -0
  23. package/dist/crypto/adapters/polyfills.d.ts +5 -0
  24. package/dist/crypto/adapters/polyfills.d.ts.map +1 -0
  25. package/dist/crypto/encrypt.d.ts +33 -0
  26. package/dist/crypto/encrypt.d.ts.map +1 -0
  27. package/dist/crypto/secure-memory.d.ts.map +1 -0
  28. package/dist/errors.d.ts +8 -0
  29. package/dist/errors.d.ts.map +1 -1
  30. package/dist/index.d.ts +6 -2
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +6721 -23
  33. package/dist/index.js.map +1 -0
  34. package/dist/keys/derive.d.ts +2 -2
  35. package/dist/keys/derive.d.ts.map +1 -1
  36. package/dist/keys/hex.d.ts +1 -4
  37. package/dist/keys/hex.d.ts.map +1 -1
  38. package/dist/keys/mnemonic.d.ts +0 -2
  39. package/dist/keys/mnemonic.d.ts.map +1 -1
  40. package/dist/keys.d.ts +1 -0
  41. package/dist/keys.d.ts.map +1 -1
  42. package/dist/prover/config.d.ts +54 -9
  43. package/dist/prover/config.d.ts.map +1 -1
  44. package/dist/prover/integrity.d.ts +20 -0
  45. package/dist/prover/integrity.d.ts.map +1 -0
  46. package/dist/prover/prover.d.ts +16 -31
  47. package/dist/prover/prover.d.ts.map +1 -1
  48. package/dist/state/merkle/hydrator.d.ts +21 -19
  49. package/dist/state/merkle/hydrator.d.ts.map +1 -1
  50. package/dist/state/merkle/index.d.ts +1 -1
  51. package/dist/state/merkle/index.d.ts.map +1 -1
  52. package/dist/state/store/ciphertext-store.d.ts +7 -0
  53. package/dist/state/store/ciphertext-store.d.ts.map +1 -1
  54. package/dist/state/store/index.d.ts +1 -1
  55. package/dist/state/store/index.d.ts.map +1 -1
  56. package/dist/state/store/job-store.d.ts.map +1 -1
  57. package/dist/state/store/jobs.d.ts +14 -16
  58. package/dist/state/store/jobs.d.ts.map +1 -1
  59. package/dist/state/store/leaf-store.d.ts +4 -0
  60. package/dist/state/store/leaf-store.d.ts.map +1 -1
  61. package/dist/state/store/nullifier-store.d.ts.map +1 -1
  62. package/dist/state/store/records.d.ts +8 -0
  63. package/dist/state/store/records.d.ts.map +1 -1
  64. package/dist/state/store/store.d.ts +18 -0
  65. package/dist/state/store/store.d.ts.map +1 -1
  66. package/dist/storage/indexeddb.d.ts.map +1 -1
  67. package/dist/storage/memory.d.ts.map +1 -1
  68. package/dist/transactions/adapter.d.ts +31 -0
  69. package/dist/transactions/adapter.d.ts.map +1 -0
  70. package/dist/transactions/deposit.d.ts +1 -1
  71. package/dist/transactions/deposit.d.ts.map +1 -1
  72. package/dist/transactions/index.d.ts +4 -2
  73. package/dist/transactions/index.d.ts.map +1 -1
  74. package/dist/transactions/note-sync.d.ts +3 -3
  75. package/dist/transactions/note-sync.d.ts.map +1 -1
  76. package/dist/transactions/reconcile.d.ts +1 -1
  77. package/dist/transactions/reconcile.d.ts.map +1 -1
  78. package/dist/transactions/transact.d.ts +21 -2
  79. package/dist/transactions/transact.d.ts.map +1 -1
  80. package/dist/transactions/transaction-planner.d.ts +1 -1
  81. package/dist/transactions/transaction-planner.d.ts.map +1 -1
  82. package/dist/transactions/transfer-planner.d.ts +2 -1
  83. package/dist/transactions/transfer-planner.d.ts.map +1 -1
  84. package/dist/transactions/types/deposit.d.ts +3 -3
  85. package/dist/transactions/types/deposit.d.ts.map +1 -1
  86. package/dist/transactions/types/domain.d.ts +3 -0
  87. package/dist/transactions/types/domain.d.ts.map +1 -1
  88. package/dist/transactions/types/options.d.ts +14 -5
  89. package/dist/transactions/types/options.d.ts.map +1 -1
  90. package/dist/transactions/types/planning.d.ts +2 -0
  91. package/dist/transactions/types/planning.d.ts.map +1 -1
  92. package/dist/transactions/types/state-stores.d.ts +53 -5
  93. package/dist/transactions/types/state-stores.d.ts.map +1 -1
  94. package/dist/transactions/types/transact.d.ts +10 -3
  95. package/dist/transactions/types/transact.d.ts.map +1 -1
  96. package/dist/transactions/withdrawal-planner.d.ts +1 -1
  97. package/dist/transactions/withdrawal-planner.d.ts.map +1 -1
  98. package/dist/tsconfig.tsbuildinfo +1 -1
  99. package/dist/tsup.config.d.ts +8 -0
  100. package/dist/tsup.config.d.ts.map +1 -0
  101. package/dist/types.d.ts +1 -0
  102. package/dist/types.d.ts.map +1 -1
  103. package/dist/utils/amounts.d.ts +0 -13
  104. package/dist/utils/amounts.d.ts.map +1 -1
  105. package/dist/utils/async.js +37 -34
  106. package/dist/utils/async.js.map +1 -0
  107. package/dist/utils/bigint.d.ts +0 -2
  108. package/dist/utils/bigint.d.ts.map +1 -1
  109. package/dist/utils/random.d.ts +5 -0
  110. package/dist/utils/random.d.ts.map +1 -1
  111. package/dist/utils/validators.d.ts.map +1 -1
  112. package/dist/vitest.config.d.ts.map +1 -1
  113. package/dist/wallet/adapter.d.ts +21 -0
  114. package/dist/wallet/adapter.d.ts.map +1 -0
  115. package/dist/wallet/burner/service.d.ts +32 -0
  116. package/dist/wallet/burner/service.d.ts.map +1 -0
  117. package/dist/wallet/burner/types.d.ts +47 -0
  118. package/dist/wallet/burner/types.d.ts.map +1 -0
  119. package/dist/wallet/index.d.ts +20 -0
  120. package/dist/wallet/index.d.ts.map +1 -0
  121. package/dist/wallet/index.js +6462 -0
  122. package/dist/wallet/index.js.map +1 -0
  123. package/dist/wallet/sdk.d.ts +48 -0
  124. package/dist/wallet/sdk.d.ts.map +1 -0
  125. package/dist/wallet/types.d.ts +457 -0
  126. package/dist/wallet/types.d.ts.map +1 -0
  127. package/dist/wallet/unlink-wallet.d.ts +187 -0
  128. package/dist/wallet/unlink-wallet.d.ts.map +1 -0
  129. package/package.json +16 -6
  130. package/dist/account/account.js +0 -142
  131. package/dist/circuits.json +0 -74
  132. package/dist/clients/broadcaster.js +0 -30
  133. package/dist/clients/http.js +0 -72
  134. package/dist/clients/indexer.js +0 -94
  135. package/dist/config.js +0 -36
  136. package/dist/constants.js +0 -5
  137. package/dist/core.js +0 -15
  138. package/dist/crypto-adapters/auto-init.d.ts +0 -2
  139. package/dist/crypto-adapters/auto-init.d.ts.map +0 -1
  140. package/dist/crypto-adapters/auto-init.js +0 -7
  141. package/dist/crypto-adapters/index.d.ts +0 -22
  142. package/dist/crypto-adapters/index.d.ts.map +0 -1
  143. package/dist/crypto-adapters/index.js +0 -47
  144. package/dist/crypto-adapters/polyfills.d.ts +0 -5
  145. package/dist/crypto-adapters/polyfills.d.ts.map +0 -1
  146. package/dist/crypto-adapters/polyfills.js +0 -8
  147. package/dist/errors.js +0 -36
  148. package/dist/history/index.js +0 -2
  149. package/dist/history/service.js +0 -354
  150. package/dist/history/types.js +0 -1
  151. package/dist/keys/address.js +0 -55
  152. package/dist/keys/derive.js +0 -112
  153. package/dist/keys/hex.js +0 -66
  154. package/dist/keys/index.js +0 -4
  155. package/dist/keys/mnemonic.js +0 -23
  156. package/dist/keys.js +0 -45
  157. package/dist/prover/config.js +0 -70
  158. package/dist/prover/index.js +0 -1
  159. package/dist/prover/prover.js +0 -291
  160. package/dist/prover/registry.js +0 -18
  161. package/dist/schema.js +0 -14
  162. package/dist/state/index.js +0 -2
  163. package/dist/state/merkle/hydrator.js +0 -37
  164. package/dist/state/merkle/index.js +0 -2
  165. package/dist/state/merkle/merkle-tree.js +0 -113
  166. package/dist/state/store/ciphertext-store.js +0 -37
  167. package/dist/state/store/history-store.js +0 -53
  168. package/dist/state/store/index.js +0 -9
  169. package/dist/state/store/job-store.js +0 -144
  170. package/dist/state/store/jobs.js +0 -1
  171. package/dist/state/store/leaf-store.js +0 -32
  172. package/dist/state/store/note-store.js +0 -146
  173. package/dist/state/store/nullifier-store.js +0 -60
  174. package/dist/state/store/records.js +0 -1
  175. package/dist/state/store/root-store.js +0 -26
  176. package/dist/state/store/store.js +0 -113
  177. package/dist/storage/index.js +0 -2
  178. package/dist/storage/indexeddb.js +0 -205
  179. package/dist/storage/memory.js +0 -91
  180. package/dist/transactions/deposit.js +0 -220
  181. package/dist/transactions/index.js +0 -9
  182. package/dist/transactions/note-selection.js +0 -201
  183. package/dist/transactions/note-sync.js +0 -485
  184. package/dist/transactions/reconcile.js +0 -85
  185. package/dist/transactions/transact.js +0 -450
  186. package/dist/transactions/transaction-planner.js +0 -116
  187. package/dist/transactions/transfer-planner.js +0 -85
  188. package/dist/transactions/types/deposit.js +0 -1
  189. package/dist/transactions/types/domain.js +0 -4
  190. package/dist/transactions/types/index.js +0 -17
  191. package/dist/transactions/types/options.js +0 -1
  192. package/dist/transactions/types/planning.js +0 -1
  193. package/dist/transactions/types/state-stores.js +0 -1
  194. package/dist/transactions/types/transact.js +0 -1
  195. package/dist/transactions/withdrawal-planner.js +0 -128
  196. package/dist/tsup.browser.config.js +0 -34
  197. package/dist/types.js +0 -1
  198. package/dist/utils/amounts.js +0 -89
  199. package/dist/utils/bigint.js +0 -29
  200. package/dist/utils/crypto.d.ts +0 -18
  201. package/dist/utils/crypto.d.ts.map +0 -1
  202. package/dist/utils/crypto.js +0 -45
  203. package/dist/utils/format.js +0 -33
  204. package/dist/utils/json-codec.js +0 -25
  205. package/dist/utils/notes.js +0 -14
  206. package/dist/utils/polling.js +0 -11
  207. package/dist/utils/random.js +0 -27
  208. package/dist/utils/secure-memory.d.ts.map +0 -1
  209. package/dist/utils/secure-memory.js +0 -28
  210. package/dist/utils/signature.js +0 -14
  211. package/dist/utils/validators.js +0 -96
  212. package/dist/vitest.config.js +0 -13
  213. /package/dist/{utils → crypto}/secure-memory.d.ts +0 -0
@@ -1,112 +0,0 @@
1
- /**
2
- * Key derivation for Unlink wallets using SLIP-10.
3
- *
4
- * SLIP-10 is a standard for BIP-32-style HD key derivation on non-secp256k1 curves.
5
- * We use "babyjubjub seed" as the curve identifier (standard convention: "<curve> seed").
6
- *
7
- * Derivation paths (BIP-44 style):
8
- * - Spending: m/44'/1984'/0'/0'/{index}'
9
- * - Viewing: m/420'/1984'/0'/0'/{index}'
10
- *
11
- * @see https://github.com/satoshilabs/slips/blob/master/slip-0010.md
12
- */
13
- import { getPublicKey, hashes } from "@noble/ed25519";
14
- import { hmac } from "@noble/hashes/hmac.js";
15
- import { sha512 } from "@noble/hashes/sha2.js";
16
- import { deriveSpendingPublicKey, poseidon } from "../crypto-adapters/index.js";
17
- import { ValidationError } from "../errors.js";
18
- import { Hex } from "./hex.js";
19
- // Configure ed25519 to use sha512
20
- hashes.sha512 = sha512;
21
- hashes.sha512Async = async (m) => sha512(m);
22
- // SLIP-10 curve identifier (convention: "<curve> seed")
23
- const CURVE_SEED = new TextEncoder().encode("babyjubjub seed");
24
- // BIP-44 paths: m/purpose'/coin_type'/account'/change'/{index}'
25
- // 1984 = coin type for Unlink
26
- const SPENDING_PATH = [44, 1984, 0, 0]; // + index
27
- const VIEWING_PATH = [420, 1984, 0, 0]; // + index
28
- /**
29
- * SLIP-10 master key derivation from seed.
30
- * I = HMAC-SHA512(Key = curve_seed, Data = seed)
31
- * Returns left 32 bytes as key, right 32 bytes as chain code.
32
- */
33
- function deriveMasterKey(seed) {
34
- const I = hmac(sha512, CURVE_SEED, seed);
35
- return {
36
- key: I.slice(0, 32),
37
- chainCode: I.slice(32, 64),
38
- };
39
- }
40
- /**
41
- * SLIP-10 hardened child key derivation.
42
- * For hardened keys (index >= 0x80000000), we use:
43
- * I = HMAC-SHA512(Key = chainCode, Data = 0x00 || key || index)
44
- */
45
- function deriveHardenedChild(key, chainCode, index) {
46
- // Data = 0x00 || key (32 bytes) || index (4 bytes, big-endian)
47
- const data = new Uint8Array(37);
48
- data[0] = 0x00;
49
- data.set(key, 1);
50
- // Hardened index: original index + 0x80000000
51
- const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
52
- view.setUint32(33, 0x80000000 + index, false); // big-endian
53
- const I = hmac(sha512, chainCode, data);
54
- return {
55
- key: I.slice(0, 32),
56
- chainCode: I.slice(32, 64),
57
- };
58
- }
59
- /**
60
- * Derive a key by traversing a BIP-32 path (all hardened).
61
- */
62
- function deriveKeyFromPath(seed, path) {
63
- let { key, chainCode } = deriveMasterKey(seed);
64
- for (const index of path) {
65
- ({ key, chainCode } = deriveHardenedChild(key, chainCode, index));
66
- }
67
- return key;
68
- }
69
- /**
70
- * Derive spending key pair (BabyJubJub) for an account.
71
- */
72
- export function deriveSpendingKeyPair(seed, index) {
73
- const path = [...SPENDING_PATH, index];
74
- const privateKey = deriveKeyFromPath(seed, path);
75
- const pubkey = deriveSpendingPublicKey(privateKey);
76
- return { privateKey, pubkey };
77
- }
78
- /**
79
- * Derive viewing key pair (Ed25519) for an account.
80
- */
81
- export async function deriveViewingKeyPair(seed, index) {
82
- const path = [...VIEWING_PATH, index];
83
- const privateKey = deriveKeyFromPath(seed, path);
84
- const pubkey = await getPublicKey(privateKey);
85
- return { privateKey, pubkey };
86
- }
87
- /**
88
- * Compute nullifying key from viewing private key using Poseidon hash.
89
- */
90
- export function computeNullifyingKey(viewingPrivateKey) {
91
- if (viewingPrivateKey.length !== 32) {
92
- throw new ValidationError("Viewing private key must be 32 bytes");
93
- }
94
- return poseidon([Hex.toBigInt(Hex.fromBytes(viewingPrivateKey))]);
95
- }
96
- /**
97
- * Compute master public key from spending public key and nullifying key.
98
- * MPK = Poseidon(spendingPubkey[0], spendingPubkey[1], nullifyingKey)
99
- */
100
- export function computeMasterPublicKey(spendingPubkey, nullifyingKey) {
101
- return poseidon([...spendingPubkey, nullifyingKey]);
102
- }
103
- /**
104
- * Derive all account keys from a seed.
105
- */
106
- export async function deriveAccountKeys(seed, index) {
107
- const spending = deriveSpendingKeyPair(seed, index);
108
- const viewing = await deriveViewingKeyPair(seed, index);
109
- const nullifyingKey = computeNullifyingKey(viewing.privateKey);
110
- const masterPublicKey = computeMasterPublicKey(spending.pubkey, nullifyingKey);
111
- return { spending, viewing, nullifyingKey, masterPublicKey };
112
- }
package/dist/keys/hex.js DELETED
@@ -1,66 +0,0 @@
1
- import { ValidationError } from "../errors.js";
2
- export var FieldSize;
3
- (function (FieldSize) {
4
- FieldSize[FieldSize["SCALAR"] = 32] = "SCALAR";
5
- FieldSize[FieldSize["SEED"] = 64] = "SEED";
6
- })(FieldSize || (FieldSize = {}));
7
- const HEX_REGEX = /^[0-9a-f]*$/i;
8
- export class Hex {
9
- static strip(value) {
10
- return value.startsWith("0x") ? value.slice(2) : value;
11
- }
12
- static encode(data) {
13
- if (typeof data === "string")
14
- return Hex.strip(data).toLowerCase();
15
- if (typeof data === "number" || typeof data === "bigint") {
16
- if (data < 0)
17
- throw new ValidationError("Cannot hexlify negative values");
18
- const hex = data.toString(16);
19
- return hex.length % 2 === 0 ? hex : `0${hex}`;
20
- }
21
- return Hex.fromBytes(data instanceof Uint8Array ? data : Uint8Array.from(data));
22
- }
23
- static fromBytes(bytes) {
24
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
25
- }
26
- static toBytes(hex) {
27
- const h = Hex.strip(hex).toLowerCase();
28
- if (h.length % 2 !== 0)
29
- throw new ValidationError("Hex string must have an even length");
30
- if (!HEX_REGEX.test(h))
31
- throw new ValidationError("Invalid hex string");
32
- return Uint8Array.from({ length: h.length / 2 }, (_, i) => parseInt(h.slice(i * 2, i * 2 + 2), 16));
33
- }
34
- static decode(data) {
35
- if (data instanceof Uint8Array)
36
- return new Uint8Array(data);
37
- if (typeof data === "string")
38
- return Hex.toBytes(data);
39
- if (typeof data === "number" || typeof data === "bigint")
40
- return Hex.toBytes(Hex.encode(data));
41
- return Uint8Array.from(data);
42
- }
43
- static toBigInt(hex) {
44
- return BigInt(`0x${Hex.strip(hex)}`);
45
- }
46
- static pad(data, bytes, side = "left") {
47
- const hex = Hex.encode(data);
48
- const target = bytes * 2;
49
- if (hex.length > target)
50
- throw new ValidationError("Cannot pad data that exceeds target length");
51
- return side === "left"
52
- ? hex.padStart(target, "0")
53
- : hex.padEnd(target, "0");
54
- }
55
- static padToSize(data, size) {
56
- const hex = Hex.encode(data);
57
- const target = size * 2;
58
- return hex.length > target
59
- ? hex.slice(0, target)
60
- : hex.padStart(target, "0");
61
- }
62
- static fromBigInt(value, size, prefix = false) {
63
- const hex = value.toString(16).padStart(size * 2, "0");
64
- return prefix ? `0x${hex}` : hex;
65
- }
66
- }
@@ -1,4 +0,0 @@
1
- export { Mnemonic } from "./mnemonic.js";
2
- export { deriveAccountKeys, deriveSpendingKeyPair, deriveViewingKeyPair, computeNullifyingKey, computeMasterPublicKey, } from "./derive.js";
3
- export { encodeAddress, decodeAddress, } from "./address.js";
4
- export { Hex, FieldSize } from "./hex.js";
@@ -1,23 +0,0 @@
1
- import { entropyToMnemonic, generateMnemonic, mnemonicToEntropy, mnemonicToSeedSync, validateMnemonic, } from "@scure/bip39";
2
- import { wordlist } from "@scure/bip39/wordlists/english.js";
3
- import { Hex } from "./hex.js";
4
- export class Mnemonic {
5
- static generate(strength = 128) {
6
- return generateMnemonic(wordlist, strength);
7
- }
8
- static validate(mnemonic) {
9
- return validateMnemonic(mnemonic, wordlist);
10
- }
11
- static toSeed(mnemonic, password = "") {
12
- const seed = mnemonicToSeedSync(mnemonic, password);
13
- return Hex.fromBytes(seed);
14
- }
15
- static toEntropy(mnemonic) {
16
- const entropy = mnemonicToEntropy(mnemonic, wordlist);
17
- return Hex.fromBytes(entropy);
18
- }
19
- static fromEntropy(entropyHex) {
20
- const entropy = Hex.toBytes(entropyHex);
21
- return entropyToMnemonic(entropy, wordlist);
22
- }
23
- }
package/dist/keys.js DELETED
@@ -1,45 +0,0 @@
1
- import { KeyValidationError } from "./errors.js";
2
- export const RESERVED_PREFIXES = [
3
- "meta:",
4
- "history:",
5
- "notes:",
6
- "leaves:",
7
- "roots:",
8
- "nullifiers:",
9
- "ciphertexts:",
10
- "jobs:",
11
- "proof_cache:",
12
- "cfg:",
13
- "idx:",
14
- "locks:",
15
- ];
16
- /** Canonical builders for storage key namespaces used across core */
17
- export const keys = {
18
- note: (c, i) => `notes:${c}:${i}`,
19
- historyEntry: (id) => `history:${id}`,
20
- historyPrefix: (chainId, mpk) => `history:${chainId}:${mpk}:`,
21
- historyMeta: (chainId, mpk) => `history:${chainId}:${mpk}:__meta__`,
22
- leaf: (c, i) => `leaves:${c}:${i}`,
23
- ciphertext: (c, i) => `ciphertexts:${c}:${i}`,
24
- /** Track note indices that remain unspent for a given master public key (mpk acts as the account identifier). */
25
- unspent: (c, mpk, i) => `idx:notes:unspent:${c}:${mpk}:${i}`,
26
- unspentPrefix: (c, mpk) => `idx:notes:unspent:${c}:${mpk}:`,
27
- nullifierObs: (c, n) => `nullifiers:${c}:${n}`,
28
- nullToIndex: (c, n) => `idx:nullifier:${c}:${n}`,
29
- nullifier: (c, n) => `nullifiers:${c}:${n}`,
30
- root: (c, value) => `roots:${c}:${value}`,
31
- latestRoot: (c) => `roots:latest:${c}`,
32
- rootCursor: (c) => `meta:roots:cursor:${c}`,
33
- cursor: (c) => `meta:sync:cursors:${c}`,
34
- aggregate: (c, a) => `idx:notes:agg:${c}:${a}`,
35
- job: (relayId) => `jobs:${relayId}`,
36
- };
37
- export const MAX_KEY_LEN = 512;
38
- export function validateKey(key) {
39
- if (!key)
40
- throw new KeyValidationError("key must not be empty");
41
- if (key.length > MAX_KEY_LEN)
42
- throw new KeyValidationError(`key exceeds ${MAX_KEY_LEN}`);
43
- if (!RESERVED_PREFIXES.some((p) => key.startsWith(p)))
44
- throw new KeyValidationError("key must start with a reserved namespace prefix");
45
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * Configuration for the prover system
3
- * Handles artifact loading from local files or remote artifact server
4
- */
5
- /**
6
- * Artifact file types
7
- */
8
- export var ArtifactType;
9
- (function (ArtifactType) {
10
- ArtifactType["WASM"] = "joinsplit.wasm";
11
- ArtifactType["ZKEY"] = "joinsplit.zkey";
12
- ArtifactType["VKEY"] = "joinsplit.vkey.json";
13
- })(ArtifactType || (ArtifactType = {}));
14
- /**
15
- * Build artifact URL for a given circuit and artifact type
16
- * @param circuitName Full circuit name (e.g., "joinsplit_2x3_16")
17
- * @param artifactType Type of artifact to fetch
18
- * @param baseUrl Base URL of the artifact server
19
- * @returns Full URL to the artifact
20
- */
21
- export function buildArtifactUrl(circuitName, artifactType, baseUrl) {
22
- // Remove trailing slash from baseUrl
23
- const cleanBaseUrl = baseUrl.replace(/\/$/, "");
24
- return `${cleanBaseUrl}/artifacts/${circuitName}/${artifactType}`;
25
- }
26
- /**
27
- * Get relative path for local artifact loading
28
- * Used in Node.js environment when artifacts are bundled
29
- * @param circuitName Full circuit name (e.g., "joinsplit_2x3_16")
30
- * @param artifactType Type of artifact
31
- * @returns Relative path to artifact
32
- */
33
- export function getLocalArtifactPath(circuitName, artifactType) {
34
- // Return multiple candidate paths for different build scenarios
35
- return [
36
- // When compiled: dist/prover/ -> ../../artifacts/circuits/{circuit}/
37
- `../../artifacts/circuits/${circuitName}/${artifactType}`,
38
- // When in source: prover/ -> ../artifacts/circuits/{circuit}/
39
- `../artifacts/circuits/${circuitName}/${artifactType}`,
40
- ];
41
- }
42
- /**
43
- * Runtime detection utilities
44
- */
45
- export const Runtime = {
46
- /**
47
- * Check if running in browser environment
48
- */
49
- isBrowser() {
50
- return typeof window !== "undefined" && typeof document !== "undefined";
51
- },
52
- /**
53
- * Check if running in Node.js environment
54
- */
55
- isNode() {
56
- return (typeof process !== "undefined" &&
57
- process.versions != null &&
58
- process.versions.node != null);
59
- },
60
- /**
61
- * Get environment description for debugging
62
- */
63
- getEnvironment() {
64
- if (this.isBrowser())
65
- return "browser";
66
- if (this.isNode())
67
- return "node";
68
- return "unknown";
69
- },
70
- };
@@ -1 +0,0 @@
1
- export * from "./prover.js";
@@ -1,291 +0,0 @@
1
- import * as snarkjs from "snarkjs";
2
- import { ProofError } from "../errors.js";
3
- import { ArtifactType, buildArtifactUrl, getLocalArtifactPath, Runtime, } from "./config.js";
4
- import { getCircuitConfig, SUPPORTED_CIRCUITS, } from "./registry.js";
5
- // Cache for loaded artifacts to avoid reloading 18MB of files on every call
6
- // Now keyed by circuit name to support multiple circuits
7
- const artifactCache = {};
8
- /**
9
- * Select the appropriate circuit based on input/output dimensions
10
- * @param inputs Number of inputs (nullifiers)
11
- * @param outputs Number of outputs (commitments)
12
- * @returns Circuit configuration
13
- * @throws ProofError if no matching circuit is found
14
- */
15
- function selectCircuit(inputs, outputs) {
16
- const config = getCircuitConfig(inputs, outputs);
17
- if (!config) {
18
- throw new ProofError(`No circuit available for ${inputs} inputs and ${outputs} outputs. ` +
19
- `Supported circuits: ${SUPPORTED_CIRCUITS.join(", ")}`);
20
- }
21
- return config;
22
- }
23
- /**
24
- * Fetch circuit artifacts from server or local files (for tests)
25
- * @param circuitName Full circuit name (e.g., "joinsplit_2x3_16")
26
- * @param rpcUrl Base URL for fetching artifacts
27
- * @returns Artifacts object with wasm, zkey, and vkey
28
- */
29
- async function fetchCircuitArtifacts(circuitName, rpcUrl) {
30
- // Check cache first
31
- if (artifactCache[circuitName]) {
32
- return artifactCache[circuitName];
33
- }
34
- // Browser: always requires rpcUrl and fetches from server
35
- if (Runtime.isBrowser()) {
36
- if (!rpcUrl) {
37
- throw new ProofError("rpcUrl is required. Please configure it via UnlinkProvider or pass it to the SDK.");
38
- }
39
- return fetchFromServer(circuitName, rpcUrl);
40
- }
41
- // Node.js: try server first if rpcUrl provided, fall back to local files
42
- if (rpcUrl) {
43
- try {
44
- return await fetchFromServer(circuitName, rpcUrl);
45
- }
46
- catch {
47
- // Server not available, fall back to local files (useful for tests)
48
- }
49
- }
50
- // Node.js: try local files (for tests and development)
51
- try {
52
- return await fetchFromLocalFiles(circuitName);
53
- }
54
- catch {
55
- throw new ProofError("rpcUrl is required. Local artifacts not found. " +
56
- "If running tests, ensure artifacts are built with 'pnpm run zk:build'.");
57
- }
58
- }
59
- async function fetchFromServer(circuitName, rpcUrl) {
60
- const wasmUrl = buildArtifactUrl(circuitName, ArtifactType.WASM, rpcUrl);
61
- const zkeyUrl = buildArtifactUrl(circuitName, ArtifactType.ZKEY, rpcUrl);
62
- const vkeyUrl = buildArtifactUrl(circuitName, ArtifactType.VKEY, rpcUrl);
63
- const [wasmRes, zkeyRes, vkeyRes] = await Promise.all([
64
- fetch(wasmUrl),
65
- fetch(zkeyUrl),
66
- fetch(vkeyUrl),
67
- ]);
68
- if (!wasmRes.ok || !zkeyRes.ok || !vkeyRes.ok) {
69
- throw new ProofError(`Failed to fetch artifacts for ${circuitName} from ${rpcUrl}. ` +
70
- `Status: wasm=${wasmRes.status}, zkey=${zkeyRes.status}, vkey=${vkeyRes.status}`);
71
- }
72
- const wasm = new Uint8Array(await wasmRes.arrayBuffer());
73
- const zkey = new Uint8Array(await zkeyRes.arrayBuffer());
74
- const vkey = (await vkeyRes.json());
75
- const artifacts = { wasm, zkey, vkey };
76
- artifactCache[circuitName] = artifacts;
77
- return artifacts;
78
- }
79
- async function fetchFromLocalFiles(circuitName) {
80
- const wasmCandidates = getLocalArtifactPath(circuitName, ArtifactType.WASM);
81
- const zkeyCandidates = getLocalArtifactPath(circuitName, ArtifactType.ZKEY);
82
- const vkeyCandidates = getLocalArtifactPath(circuitName, ArtifactType.VKEY);
83
- let wasm;
84
- let zkey;
85
- let vkey;
86
- let wasmLoaded = false;
87
- for (const candidate of wasmCandidates) {
88
- try {
89
- wasm = await readBinaryResource(candidate);
90
- wasmLoaded = true;
91
- break;
92
- }
93
- catch {
94
- // Try next candidate
95
- }
96
- }
97
- if (!wasmLoaded) {
98
- throw new ProofError(`Could not find WASM artifact for ${circuitName}. ` +
99
- `Please run 'pnpm run build:all' in the circuits package.`);
100
- }
101
- // Load zkey
102
- let zkeyLoaded = false;
103
- for (const candidate of zkeyCandidates) {
104
- try {
105
- zkey = await readBinaryResource(candidate);
106
- zkeyLoaded = true;
107
- break;
108
- }
109
- catch {
110
- // Try next candidate
111
- }
112
- }
113
- if (!zkeyLoaded) {
114
- throw new ProofError(`Could not find zkey artifact for ${circuitName}. ` +
115
- `Please run 'pnpm run build:all' in the circuits package.`);
116
- }
117
- // Load vkey
118
- let vkeyLoaded = false;
119
- for (const candidate of vkeyCandidates) {
120
- try {
121
- const vkeyText = await readTextResource(candidate);
122
- vkey = JSON.parse(vkeyText);
123
- vkeyLoaded = true;
124
- break;
125
- }
126
- catch {
127
- // Try next candidate
128
- }
129
- }
130
- if (!vkeyLoaded) {
131
- throw new ProofError(`Could not find verification key for ${circuitName}. ` +
132
- `Please run 'pnpm run build:all' in the circuits package.`);
133
- }
134
- // Cache the artifacts for future calls
135
- // TypeScript now knows these are defined after the check above
136
- const artifacts = { wasm: wasm, zkey: zkey, vkey: vkey };
137
- artifactCache[circuitName] = artifacts;
138
- return artifacts;
139
- }
140
- async function readBinaryResource(relativePath) {
141
- const url = new URL(relativePath, import.meta.url);
142
- try {
143
- if (url.protocol === "file:") {
144
- const fs = (await import("fs")).default;
145
- const readPromise = new Promise((resolve, reject) => {
146
- fs.readFile(url.pathname, (err, data) => {
147
- if (err) {
148
- reject(err);
149
- }
150
- else {
151
- resolve(data);
152
- }
153
- });
154
- });
155
- const buf = await readPromise;
156
- return new Uint8Array(buf);
157
- }
158
- const response = await fetch(url);
159
- if (!response.ok) {
160
- throw new ProofError(`failed to fetch ${relativePath}: ${response.statusText}`);
161
- }
162
- return new Uint8Array(await response.arrayBuffer());
163
- }
164
- catch (error) {
165
- throw new ProofError(`failed to read binary resource ${relativePath}: ${error.message}`);
166
- }
167
- }
168
- async function readTextResource(relativePath) {
169
- const url = new URL(relativePath, import.meta.url);
170
- if (url.protocol === "file:") {
171
- const fs = (await import("fs")).default;
172
- const readPromise = new Promise((resolve, reject) => {
173
- fs.readFile(url.pathname, (err, data) => {
174
- if (err) {
175
- reject(err);
176
- }
177
- else {
178
- resolve(data);
179
- }
180
- });
181
- });
182
- const buf = await readPromise;
183
- return buf.toString("utf-8");
184
- }
185
- const response = await fetch(url);
186
- if (!response.ok) {
187
- throw new ProofError(`failed to fetch ${relativePath}: ${response.statusText}`);
188
- }
189
- return response.text();
190
- }
191
- export async function proveTransaction(input, options) {
192
- try {
193
- // Auto-detect circuit based on input dimensions
194
- const nInputs = input.nullifiers.length;
195
- const nOutputs = input.commitmentsOut.length;
196
- const circuit = selectCircuit(nInputs, nOutputs);
197
- // Fetch circuit artifacts (wasm and zkey)
198
- const { wasm, vkey, zkey } = await fetchCircuitArtifacts(circuit.name, options?.rpcUrl);
199
- const inputSignals = input;
200
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(inputSignals, wasm, zkey);
201
- // Additional verification step (optional)
202
- const isValid = await snarkjs.groth16.verify(vkey, publicSignals, proof);
203
- if (!isValid) {
204
- throw new ProofError("generated proof is invalid");
205
- }
206
- return {
207
- proof,
208
- publicSignals,
209
- };
210
- }
211
- catch (error) {
212
- throw new ProofError("proof generation failed: " + error.message);
213
- }
214
- }
215
- /**
216
- * Get verification key for a specific circuit configuration
217
- * @param inputs Number of inputs (nullifiers)
218
- * @param outputs Number of outputs (commitments)
219
- * @param options Configuration including rpcUrl
220
- * @returns Verification key for the circuit
221
- */
222
- export async function getVerificationKey(inputs, outputs, options) {
223
- try {
224
- const circuit = selectCircuit(inputs, outputs);
225
- const { vkey } = await fetchCircuitArtifacts(circuit.name, options?.rpcUrl);
226
- return vkey;
227
- }
228
- catch (error) {
229
- throw new ProofError("failed to load verification key: " + error.message);
230
- }
231
- }
232
- /**
233
- * Verify a proof with public signals
234
- * Auto-detects the circuit from the public signals structure
235
- * @param proof Groth16 proof
236
- * @param publicSignals Public signals array
237
- * @param options Optional configuration including rpcUrl
238
- * @returns True if proof is valid
239
- */
240
- export async function verifyProof(proof, publicSignals, options) {
241
- try {
242
- // Public signals structure: [merkleRoot, boundParamsHash, ...nullifiers, ...commitments]
243
- // We need to determine the circuit from the length
244
- // This is tricky without additional context, so we'll need to try to infer
245
- // or require explicit circuit specification
246
- // For now, extract nullifier and commitment counts from the public signals
247
- // The caller should know this information, but we can make an educated guess
248
- // based on the total length and circuit registry
249
- // Length = 2 (root + hash) + nInputs + nOutputs
250
- const totalLength = publicSignals.length;
251
- const variableCount = totalLength - 2; // Remove merkleRoot and boundParamsHash
252
- // Try to find a matching circuit
253
- let vkey = null;
254
- for (const circuitKey of SUPPORTED_CIRCUITS) {
255
- const parts = circuitKey.split("x");
256
- const config = getCircuitConfig(parseInt(parts[0]), parseInt(parts[1]));
257
- if (config && config.inputs + config.outputs === variableCount) {
258
- const artifacts = await fetchCircuitArtifacts(config.name, options?.rpcUrl);
259
- vkey = artifacts.vkey;
260
- break;
261
- }
262
- }
263
- if (!vkey) {
264
- throw new ProofError(`Could not determine circuit from ${totalLength} public signals`);
265
- }
266
- return await snarkjs.groth16.verify(vkey, publicSignals, proof);
267
- }
268
- catch (error) {
269
- throw new ProofError("proof verification failed: " + error.message);
270
- }
271
- }
272
- /**
273
- * Verify a proof with explicit circuit specification
274
- * Preferred method when you know the circuit dimensions
275
- * @param proof Groth16 proof
276
- * @param publicSignals Public signals array
277
- * @param inputs Number of inputs (nullifiers)
278
- * @param outputs Number of outputs (commitments)
279
- * @param options Optional configuration including rpcUrl
280
- * @returns True if proof is valid
281
- */
282
- export async function verifyProofWithCircuit(proof, publicSignals, inputs, outputs, options) {
283
- try {
284
- const circuit = selectCircuit(inputs, outputs);
285
- const { vkey } = await fetchCircuitArtifacts(circuit.name, options?.rpcUrl);
286
- return await snarkjs.groth16.verify(vkey, publicSignals, proof);
287
- }
288
- catch (error) {
289
- throw new ProofError("proof verification failed: " + error.message);
290
- }
291
- }
@@ -1,18 +0,0 @@
1
- import circuitsJson from "../circuits.json" with { type: "json" };
2
- // Build registry from circuits.json — keyed by "NxM" (inputs x outputs)
3
- const registry = {};
4
- for (const [name, def] of Object.entries(circuitsJson)) {
5
- const params = def.params;
6
- const inputs = params[0];
7
- const outputs = params[1];
8
- const depth = params[2];
9
- registry[`${inputs}x${outputs}`] = { name, inputs, outputs, depth };
10
- }
11
- export const CIRCUIT_REGISTRY = registry;
12
- export const SUPPORTED_CIRCUITS = Object.keys(CIRCUIT_REGISTRY);
13
- export function getCircuitConfig(inputs, outputs) {
14
- return CIRCUIT_REGISTRY[`${inputs}x${outputs}`];
15
- }
16
- export function isCircuitSupported(inputs, outputs) {
17
- return getCircuitConfig(inputs, outputs) !== undefined;
18
- }
package/dist/schema.js DELETED
@@ -1,14 +0,0 @@
1
- import { SchemaMismatchError } from "./errors.js";
2
- export const CORE_SCHEMA_VERSION = 1;
3
- export async function migrate(storage) {
4
- await storage.open();
5
- const current = await storage.getSchemaVersion();
6
- if (current === 0) {
7
- // seed structures if needed
8
- await storage.setSchemaVersion(CORE_SCHEMA_VERSION);
9
- return;
10
- }
11
- if (current !== CORE_SCHEMA_VERSION) {
12
- throw new SchemaMismatchError(current, CORE_SCHEMA_VERSION);
13
- }
14
- }
@@ -1,2 +0,0 @@
1
- export * from "./merkle/index.js";
2
- export * from "./store/index.js";