@unlink-xyz/core 0.1.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 (185) hide show
  1. package/dist/account/zkAccount.d.ts +38 -0
  2. package/dist/account/zkAccount.d.ts.map +1 -0
  3. package/dist/account/zkAccount.js +128 -0
  4. package/dist/clients/broadcaster.d.ts +33 -0
  5. package/dist/clients/broadcaster.d.ts.map +1 -0
  6. package/dist/clients/broadcaster.js +23 -0
  7. package/dist/clients/http.d.ts +23 -0
  8. package/dist/clients/http.d.ts.map +1 -0
  9. package/dist/clients/http.js +57 -0
  10. package/dist/clients/indexer.d.ts +44 -0
  11. package/dist/clients/indexer.d.ts.map +1 -0
  12. package/dist/clients/indexer.js +67 -0
  13. package/dist/config.d.ts +12 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +29 -0
  16. package/dist/core.d.ts +10 -0
  17. package/dist/core.d.ts.map +1 -0
  18. package/dist/core.js +12 -0
  19. package/dist/errors.d.ts +10 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +18 -0
  22. package/dist/index.d.ts +18 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +16 -0
  25. package/dist/key-derivation/babyjubjub.d.ts +9 -0
  26. package/dist/key-derivation/babyjubjub.d.ts.map +1 -0
  27. package/dist/key-derivation/babyjubjub.js +9 -0
  28. package/dist/key-derivation/bech32.d.ts +22 -0
  29. package/dist/key-derivation/bech32.d.ts.map +1 -0
  30. package/dist/key-derivation/bech32.js +86 -0
  31. package/dist/key-derivation/bip32.d.ts +17 -0
  32. package/dist/key-derivation/bip32.d.ts.map +1 -0
  33. package/dist/key-derivation/bip32.js +41 -0
  34. package/dist/key-derivation/bip39.d.ts +22 -0
  35. package/dist/key-derivation/bip39.d.ts.map +1 -0
  36. package/dist/key-derivation/bip39.js +56 -0
  37. package/dist/key-derivation/bytes.d.ts +19 -0
  38. package/dist/key-derivation/bytes.d.ts.map +1 -0
  39. package/dist/key-derivation/bytes.js +92 -0
  40. package/dist/key-derivation/hash.d.ts +3 -0
  41. package/dist/key-derivation/hash.d.ts.map +1 -0
  42. package/dist/key-derivation/hash.js +10 -0
  43. package/dist/key-derivation/index.d.ts +8 -0
  44. package/dist/key-derivation/index.d.ts.map +1 -0
  45. package/dist/key-derivation/index.js +7 -0
  46. package/dist/key-derivation/wallet-node.d.ts +45 -0
  47. package/dist/key-derivation/wallet-node.d.ts.map +1 -0
  48. package/dist/key-derivation/wallet-node.js +109 -0
  49. package/dist/keys.d.ts +22 -0
  50. package/dist/keys.d.ts.map +1 -0
  51. package/dist/keys.js +41 -0
  52. package/dist/prover/config.d.ts +60 -0
  53. package/dist/prover/config.d.ts.map +1 -0
  54. package/dist/prover/config.js +80 -0
  55. package/dist/prover/index.d.ts +2 -0
  56. package/dist/prover/index.d.ts.map +1 -0
  57. package/dist/prover/index.js +1 -0
  58. package/dist/prover/prover.d.ts +59 -0
  59. package/dist/prover/prover.d.ts.map +1 -0
  60. package/dist/prover/prover.js +274 -0
  61. package/dist/prover/registry.d.ts +39 -0
  62. package/dist/prover/registry.d.ts.map +1 -0
  63. package/dist/prover/registry.js +57 -0
  64. package/dist/schema.d.ts +4 -0
  65. package/dist/schema.d.ts.map +1 -0
  66. package/dist/schema.js +14 -0
  67. package/dist/state/ciphertext-store.d.ts +12 -0
  68. package/dist/state/ciphertext-store.d.ts.map +1 -0
  69. package/dist/state/ciphertext-store.js +25 -0
  70. package/dist/state/index.d.ts +3 -0
  71. package/dist/state/index.d.ts.map +1 -0
  72. package/dist/state/index.js +2 -0
  73. package/dist/state/leaf-store.d.ts +17 -0
  74. package/dist/state/leaf-store.d.ts.map +1 -0
  75. package/dist/state/leaf-store.js +35 -0
  76. package/dist/state/merkle/hydrator.d.ts +27 -0
  77. package/dist/state/merkle/hydrator.d.ts.map +1 -0
  78. package/dist/state/merkle/hydrator.js +36 -0
  79. package/dist/state/merkle/index.d.ts +3 -0
  80. package/dist/state/merkle/index.d.ts.map +1 -0
  81. package/dist/state/merkle/index.js +2 -0
  82. package/dist/state/merkle/merkle-tree.d.ts +34 -0
  83. package/dist/state/merkle/merkle-tree.d.ts.map +1 -0
  84. package/dist/state/merkle/merkle-tree.js +104 -0
  85. package/dist/state/merkle-tree.d.ts +34 -0
  86. package/dist/state/merkle-tree.d.ts.map +1 -0
  87. package/dist/state/merkle-tree.js +104 -0
  88. package/dist/state/note-store.d.ts +37 -0
  89. package/dist/state/note-store.d.ts.map +1 -0
  90. package/dist/state/note-store.js +133 -0
  91. package/dist/state/nullifier-store.d.ts +13 -0
  92. package/dist/state/nullifier-store.d.ts.map +1 -0
  93. package/dist/state/nullifier-store.js +21 -0
  94. package/dist/state/records.d.ts +57 -0
  95. package/dist/state/records.d.ts.map +1 -0
  96. package/dist/state/records.js +1 -0
  97. package/dist/state/root-store.d.ts +13 -0
  98. package/dist/state/root-store.d.ts.map +1 -0
  99. package/dist/state/root-store.js +30 -0
  100. package/dist/state/store/ciphertext-store.d.ts +12 -0
  101. package/dist/state/store/ciphertext-store.d.ts.map +1 -0
  102. package/dist/state/store/ciphertext-store.js +25 -0
  103. package/dist/state/store/index.d.ts +10 -0
  104. package/dist/state/store/index.d.ts.map +1 -0
  105. package/dist/state/store/index.js +8 -0
  106. package/dist/state/store/job-store.d.ts +12 -0
  107. package/dist/state/store/job-store.d.ts.map +1 -0
  108. package/dist/state/store/job-store.js +118 -0
  109. package/dist/state/store/jobs.d.ts +50 -0
  110. package/dist/state/store/jobs.d.ts.map +1 -0
  111. package/dist/state/store/jobs.js +1 -0
  112. package/dist/state/store/leaf-store.d.ts +17 -0
  113. package/dist/state/store/leaf-store.d.ts.map +1 -0
  114. package/dist/state/store/leaf-store.js +35 -0
  115. package/dist/state/store/note-store.d.ts +38 -0
  116. package/dist/state/store/note-store.d.ts.map +1 -0
  117. package/dist/state/store/note-store.js +142 -0
  118. package/dist/state/store/nullifier-store.d.ts +17 -0
  119. package/dist/state/store/nullifier-store.d.ts.map +1 -0
  120. package/dist/state/store/nullifier-store.js +30 -0
  121. package/dist/state/store/records.d.ts +57 -0
  122. package/dist/state/store/records.d.ts.map +1 -0
  123. package/dist/state/store/records.js +1 -0
  124. package/dist/state/store/root-store.d.ts +13 -0
  125. package/dist/state/store/root-store.d.ts.map +1 -0
  126. package/dist/state/store/root-store.js +30 -0
  127. package/dist/state/store/store.d.ts +34 -0
  128. package/dist/state/store/store.d.ts.map +1 -0
  129. package/dist/state/store/store.js +22 -0
  130. package/dist/state/store.d.ts +26 -0
  131. package/dist/state/store.d.ts.map +1 -0
  132. package/dist/state/store.js +19 -0
  133. package/dist/storage/index.d.ts +4 -0
  134. package/dist/storage/index.d.ts.map +1 -0
  135. package/dist/storage/index.js +2 -0
  136. package/dist/storage/indexeddb.d.ts +27 -0
  137. package/dist/storage/indexeddb.d.ts.map +1 -0
  138. package/dist/storage/indexeddb.js +205 -0
  139. package/dist/storage/memory.d.ts +25 -0
  140. package/dist/storage/memory.d.ts.map +1 -0
  141. package/dist/storage/memory.js +87 -0
  142. package/dist/transactions/deposit.d.ts +18 -0
  143. package/dist/transactions/deposit.d.ts.map +1 -0
  144. package/dist/transactions/deposit.js +173 -0
  145. package/dist/transactions/index.d.ts +7 -0
  146. package/dist/transactions/index.d.ts.map +1 -0
  147. package/dist/transactions/index.js +4 -0
  148. package/dist/transactions/note-sync.d.ts +46 -0
  149. package/dist/transactions/note-sync.d.ts.map +1 -0
  150. package/dist/transactions/note-sync.js +320 -0
  151. package/dist/transactions/reconcile.d.ts +22 -0
  152. package/dist/transactions/reconcile.d.ts.map +1 -0
  153. package/dist/transactions/reconcile.js +39 -0
  154. package/dist/transactions/transact.d.ts +34 -0
  155. package/dist/transactions/transact.d.ts.map +1 -0
  156. package/dist/transactions/transact.js +561 -0
  157. package/dist/transactions/types.d.ts +114 -0
  158. package/dist/transactions/types.d.ts.map +1 -0
  159. package/dist/transactions/types.js +1 -0
  160. package/dist/tsconfig.tsbuildinfo +1 -0
  161. package/dist/types.d.ts +27 -0
  162. package/dist/types.d.ts.map +1 -0
  163. package/dist/types.js +1 -0
  164. package/dist/utils/async.d.ts +10 -0
  165. package/dist/utils/async.d.ts.map +1 -0
  166. package/dist/utils/async.js +13 -0
  167. package/dist/utils/bigint.d.ts +9 -0
  168. package/dist/utils/bigint.d.ts.map +1 -0
  169. package/dist/utils/bigint.js +29 -0
  170. package/dist/utils/crypto.d.ts +12 -0
  171. package/dist/utils/crypto.d.ts.map +1 -0
  172. package/dist/utils/crypto.js +39 -0
  173. package/dist/utils/json-codec.d.ts +9 -0
  174. package/dist/utils/json-codec.d.ts.map +1 -0
  175. package/dist/utils/json-codec.js +25 -0
  176. package/dist/utils/polling.d.ts +7 -0
  177. package/dist/utils/polling.d.ts.map +1 -0
  178. package/dist/utils/polling.js +6 -0
  179. package/dist/utils/signature.d.ts +9 -0
  180. package/dist/utils/signature.d.ts.map +1 -0
  181. package/dist/utils/signature.js +12 -0
  182. package/dist/utils/validators.d.ts +30 -0
  183. package/dist/utils/validators.d.ts.map +1 -0
  184. package/dist/utils/validators.js +70 -0
  185. package/package.json +52 -0
@@ -0,0 +1,86 @@
1
+ import { bech32m } from "@scure/base";
2
+ import { ByteLength, ByteUtils } from "./bytes.js";
3
+ export const ADDRESS_VERSION = 1;
4
+ export const ADDRESS_LENGTH_LIMIT = 127;
5
+ export const ALL_CHAINS_NETWORK_ID = "ffffffffffffffff";
6
+ const PREFIX = "0zk";
7
+ const XOR_SALT = new TextEncoder().encode("unlink");
8
+ /**
9
+ * XOR the network identifier with a static salt to keep addresses compact and avoid
10
+ * exposing raw chain IDs directly (mirrors the reference implementation).
11
+ */
12
+ const xorNetworkID = (networkID) => {
13
+ const bytes = ByteUtils.hexStringToBytes(networkID);
14
+ const result = new Uint8Array(bytes.length);
15
+ const saltLength = XOR_SALT.length;
16
+ for (let i = 0; i < bytes.length; i += 1) {
17
+ const byte = bytes[i] ?? 0;
18
+ let saltByte = 0;
19
+ if (saltLength > 0) {
20
+ const saltIndex = i % saltLength;
21
+ saltByte = XOR_SALT[saltIndex] ?? 0;
22
+ }
23
+ result[i] = byte ^ saltByte;
24
+ }
25
+ return ByteUtils.bytesToHex(result);
26
+ };
27
+ const chainToNetworkID = (chain) => {
28
+ if (!chain)
29
+ return ALL_CHAINS_NETWORK_ID;
30
+ const { type, id } = chain;
31
+ const typeHex = (type & 0xff).toString(16).padStart(2, "0");
32
+ const idHex = BigInt(id).toString(16).padStart(14, "0");
33
+ return `${typeHex}${idHex}`;
34
+ };
35
+ const networkIDToChain = (networkID) => {
36
+ if (networkID === ALL_CHAINS_NETWORK_ID) {
37
+ return undefined;
38
+ }
39
+ const type = parseInt(networkID.slice(0, 2), 16);
40
+ const id = parseInt(networkID.slice(2), 16);
41
+ return { type, id };
42
+ };
43
+ /**
44
+ * Encode address metadata into a Bech32m string with the 0zk prefix.
45
+ */
46
+ export const encodeAddress = (addressData) => {
47
+ const versionHex = (addressData.version ?? ADDRESS_VERSION)
48
+ .toString(16)
49
+ .padStart(2, "0");
50
+ const masterPublicKey = ByteUtils.nToHex(addressData.masterPublicKey, ByteLength.UINT_256, false);
51
+ const viewingPublicKey = ByteUtils.formatToByteLength(addressData.viewingPublicKey, ByteLength.UINT_256);
52
+ const networkID = xorNetworkID(chainToNetworkID(addressData.chain));
53
+ const payloadHex = `${versionHex}${masterPublicKey}${networkID}${viewingPublicKey}`;
54
+ const payload = ByteUtils.hexStringToBytes(payloadHex);
55
+ return bech32m.encode(PREFIX, bech32m.toWords(payload), ADDRESS_LENGTH_LIMIT);
56
+ };
57
+ /**
58
+ * Decode and validate a Bech32m address, returning the structured payload.
59
+ */
60
+ export const decodeAddress = (address) => {
61
+ if (!address) {
62
+ throw new Error("No address to decode");
63
+ }
64
+ const decoded = bech32m.decode(address, ADDRESS_LENGTH_LIMIT);
65
+ if (decoded.prefix !== PREFIX) {
66
+ throw new Error("Invalid address prefix");
67
+ }
68
+ const payloadHex = ByteUtils.hexlify(bech32m.fromWords(decoded.words));
69
+ if (payloadHex.length !== 2 + 64 + 16 + 64) {
70
+ throw new Error("Incorrect address payload length");
71
+ }
72
+ const version = parseInt(payloadHex.slice(0, 2), 16);
73
+ if (version !== ADDRESS_VERSION) {
74
+ throw new Error("Incorrect address version");
75
+ }
76
+ const masterPublicKey = ByteUtils.hexToBigInt(payloadHex.slice(2, 66));
77
+ const networkID = xorNetworkID(payloadHex.slice(66, 82));
78
+ const viewingPublicKey = ByteUtils.hexStringToBytes(payloadHex.slice(82, 146));
79
+ const chain = networkIDToChain(networkID);
80
+ return {
81
+ version,
82
+ masterPublicKey,
83
+ viewingPublicKey,
84
+ chain,
85
+ };
86
+ };
@@ -0,0 +1,17 @@
1
+ export type KeyNode = {
2
+ chainKey: string;
3
+ chainCode: string;
4
+ };
5
+ /**
6
+ * Parse a derivation path into hardened segment indexes.
7
+ */
8
+ export declare const getPathSegments: (path: string) => number[];
9
+ /**
10
+ * Perform hardened child derivation using the BabyJubJub curve seed.
11
+ */
12
+ export declare const childKeyDerivationHardened: (node: KeyNode, index: number, offset?: number) => KeyNode;
13
+ /**
14
+ * Create the root BIP-32 node from a BIP-39 seed.
15
+ */
16
+ export declare const getMasterKeyFromSeed: (seed: string) => KeyNode;
17
+ //# sourceMappingURL=bip32.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bip32.d.ts","sourceRoot":"","sources":["../../key-derivation/bip32.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AASF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAAM,EASpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACrC,MAAM,OAAO,EACb,OAAO,MAAM,EACb,SAAQ,MAAmB,KAC1B,OAOF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,OAKnD,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { ByteUtils, fromUTF8String } from "./bytes.js";
2
+ import { sha512HMAC } from "./hash.js";
3
+ const CURVE_SEED = fromUTF8String("babyjubjub seed");
4
+ // Validates derivation paths of the form m/... with hardened segments.
5
+ const PATH_REGEX = /^m(\/[0-9]+')+$/;
6
+ const isValidPath = (path) => {
7
+ return PATH_REGEX.test(path);
8
+ };
9
+ /**
10
+ * Parse a derivation path into hardened segment indexes.
11
+ */
12
+ export const getPathSegments = (path) => {
13
+ if (!isValidPath(path)) {
14
+ throw new Error("Invalid derivation path");
15
+ }
16
+ return path
17
+ .split("/")
18
+ .slice(1)
19
+ .map((segment) => segment.replace("'", ""))
20
+ .map((segment) => parseInt(segment, 10));
21
+ };
22
+ /**
23
+ * Perform hardened child derivation using the BabyJubJub curve seed.
24
+ */
25
+ export const childKeyDerivationHardened = (node, index, offset = 0x80000000) => {
26
+ const indexFormatted = ByteUtils.padToLength(index + offset, 4);
27
+ const preImage = `00${node.chainKey}${indexFormatted}`;
28
+ const I = sha512HMAC(node.chainCode, preImage);
29
+ const chainKey = I.slice(0, 64);
30
+ const chainCode = I.slice(64);
31
+ return { chainKey, chainCode };
32
+ };
33
+ /**
34
+ * Create the root BIP-32 node from a BIP-39 seed.
35
+ */
36
+ export const getMasterKeyFromSeed = (seed) => {
37
+ const I = sha512HMAC(CURVE_SEED, seed);
38
+ const chainKey = I.slice(0, 64);
39
+ const chainCode = I.slice(64);
40
+ return { chainKey, chainCode };
41
+ };
@@ -0,0 +1,22 @@
1
+ export declare class Mnemonic {
2
+ /**
3
+ * Generate a BIP-39 mnemonic using the English wordlist.
4
+ */
5
+ static generate(strength?: 128 | 192 | 256): string;
6
+ /**
7
+ * Validate a mnemonic against the English wordlist checksum.
8
+ */
9
+ static validate(mnemonic: string): boolean;
10
+ /**
11
+ * Convert a mnemonic to a hex-encoded BIP-39 seed. Optional password supported.
12
+ */
13
+ static toSeed(mnemonic: string, password?: string): string;
14
+ static toEntropy(mnemonic: string): string;
15
+ static fromEntropy(entropyHex: string): string;
16
+ /**
17
+ * Convenience helper: derive a 0x private key for non-0zk flows.
18
+ */
19
+ static to0xPrivateKey(mnemonic: string, derivationIndex?: number): string;
20
+ static to0xAddress(mnemonic: string, derivationIndex?: number): string;
21
+ }
22
+ //# sourceMappingURL=bip39.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bip39.d.ts","sourceRoot":"","sources":["../../key-derivation/bip39.ts"],"names":[],"mappings":"AAqBA,qBAAa,QAAQ;IACnB;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAE,GAAG,GAAG,GAAG,GAAG,GAAS,GAAG,MAAM;IAIxD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI1C;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,MAAM;IAK9D,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK1C,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAK9C;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM;IAWzE,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM;CAOvE"}
@@ -0,0 +1,56 @@
1
+ import { entropyToMnemonic, generateMnemonic, mnemonicToEntropy, mnemonicToSeedSync, validateMnemonic, } from "@scure/bip39";
2
+ import { wordlist } from "@scure/bip39/wordlists/english.js";
3
+ import { HDKey } from "ethereum-cryptography/hdkey";
4
+ import { Mnemonic as EthersMnemonic, HDNodeWallet } from "ethers";
5
+ import { ByteUtils } from "./bytes.js";
6
+ /**
7
+ * Standard ETH derivation path helper for convenience utilities below.
8
+ * Not used for 0zk accounts but kept for backwards compatibility.
9
+ */
10
+ const derivationPath = (index = 0) => {
11
+ return `m/44'/60'/0'/0/${index}`;
12
+ };
13
+ export class Mnemonic {
14
+ /**
15
+ * Generate a BIP-39 mnemonic using the English wordlist.
16
+ */
17
+ static generate(strength = 128) {
18
+ return generateMnemonic(wordlist, strength);
19
+ }
20
+ /**
21
+ * Validate a mnemonic against the English wordlist checksum.
22
+ */
23
+ static validate(mnemonic) {
24
+ return validateMnemonic(mnemonic, wordlist);
25
+ }
26
+ /**
27
+ * Convert a mnemonic to a hex-encoded BIP-39 seed. Optional password supported.
28
+ */
29
+ static toSeed(mnemonic, password = "") {
30
+ const seed = mnemonicToSeedSync(mnemonic, password);
31
+ return ByteUtils.bytesToHex(seed);
32
+ }
33
+ static toEntropy(mnemonic) {
34
+ const entropy = mnemonicToEntropy(mnemonic, wordlist);
35
+ return ByteUtils.bytesToHex(entropy);
36
+ }
37
+ static fromEntropy(entropyHex) {
38
+ const entropy = ByteUtils.hexStringToBytes(entropyHex);
39
+ return entropyToMnemonic(entropy, wordlist);
40
+ }
41
+ /**
42
+ * Convenience helper: derive a 0x private key for non-0zk flows.
43
+ */
44
+ static to0xPrivateKey(mnemonic, derivationIndex) {
45
+ const seed = mnemonicToSeedSync(mnemonic);
46
+ const node = HDKey.fromMasterSeed(Buffer.from(seed)).derive(derivationPath(derivationIndex));
47
+ if (!node.privateKey) {
48
+ throw new Error("Failed to derive private key");
49
+ }
50
+ return ByteUtils.bytesToHex(node.privateKey);
51
+ }
52
+ static to0xAddress(mnemonic, derivationIndex) {
53
+ const wallet = HDNodeWallet.fromMnemonic(EthersMnemonic.fromPhrase(mnemonic), derivationPath(derivationIndex));
54
+ return wallet.address;
55
+ }
56
+ }
@@ -0,0 +1,19 @@
1
+ export declare enum ByteLength {
2
+ UINT_256 = 32,
3
+ UINT_512 = 64
4
+ }
5
+ export type BytesData = string | number | bigint | Uint8Array | ArrayLike<number>;
6
+ export declare class ByteUtils {
7
+ static prefix0x(value: string): string;
8
+ static strip0x(value: string): string;
9
+ static hexlify(data: BytesData): string;
10
+ static bytesToHex(bytes: Uint8Array): string;
11
+ static hexStringToBytes(hex: string): Uint8Array;
12
+ static arrayify(data: BytesData): Uint8Array;
13
+ static hexToBigInt(hex: string): bigint;
14
+ static padToLength(data: BytesData, length: number, side?: "left" | "right"): string;
15
+ static formatToByteLength(data: BytesData, length: ByteLength): string;
16
+ static nToHex(value: bigint, length: ByteLength, prefix?: boolean): string;
17
+ }
18
+ export declare function fromUTF8String(value: string): string;
19
+ //# sourceMappingURL=bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../../key-derivation/bytes.ts"],"names":[],"mappings":"AAAA,oBAAY,UAAU;IACpB,QAAQ,KAAK;IACb,QAAQ,KAAK;CACd;AAED,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,MAAM,GACN,UAAU,GACV,SAAS,CAAC,MAAM,CAAC,CAAC;AAkBtB,qBAAa,SAAS;IACpB,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAItC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIrC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM;IAavC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM;IAQ5C,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;IAUhD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,UAAU;IAa5C,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIvC,MAAM,CAAC,WAAW,CAChB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAM,GAAG,OAAgB,GAC9B,MAAM;IAWT,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM;IAQtE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,UAAQ,GAAG,MAAM;CAIzE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD"}
@@ -0,0 +1,92 @@
1
+ export var ByteLength;
2
+ (function (ByteLength) {
3
+ ByteLength[ByteLength["UINT_256"] = 32] = "UINT_256";
4
+ ByteLength[ByteLength["UINT_512"] = 64] = "UINT_512";
5
+ })(ByteLength || (ByteLength = {}));
6
+ const HEX_REGEX = /^[0-9a-f]*$/i;
7
+ const isPrefixed = (value) => value.startsWith("0x");
8
+ const assertEvenLength = (hex) => {
9
+ if (hex.length % 2 !== 0) {
10
+ throw new Error("Hex string must have an even length");
11
+ }
12
+ };
13
+ const assertHex = (hex) => {
14
+ if (!HEX_REGEX.test(hex)) {
15
+ throw new Error("Invalid hex string");
16
+ }
17
+ };
18
+ export class ByteUtils {
19
+ static prefix0x(value) {
20
+ return isPrefixed(value) ? value : `0x${value}`;
21
+ }
22
+ static strip0x(value) {
23
+ return isPrefixed(value) ? value.slice(2) : value;
24
+ }
25
+ static hexlify(data) {
26
+ if (typeof data === "string") {
27
+ return ByteUtils.strip0x(data).toLowerCase();
28
+ }
29
+ if (typeof data === "number" || typeof data === "bigint") {
30
+ if (data < 0)
31
+ throw new Error("Cannot hexlify negative values");
32
+ const hex = data.toString(16);
33
+ return hex.length % 2 === 0 ? hex : `0${hex}`;
34
+ }
35
+ const view = data instanceof Uint8Array ? data : Uint8Array.from(data);
36
+ return ByteUtils.bytesToHex(view);
37
+ }
38
+ static bytesToHex(bytes) {
39
+ let hex = "";
40
+ for (const byte of bytes) {
41
+ hex += byte.toString(16).padStart(2, "0");
42
+ }
43
+ return hex;
44
+ }
45
+ static hexStringToBytes(hex) {
46
+ const normalized = ByteUtils.strip0x(hex).toLowerCase();
47
+ assertEvenLength(normalized);
48
+ assertHex(normalized);
49
+ const byteLength = normalized.length / 2;
50
+ return Uint8Array.from({ length: byteLength }, (_, index) => parseInt(normalized.slice(index * 2, index * 2 + 2), 16));
51
+ }
52
+ static arrayify(data) {
53
+ if (data instanceof Uint8Array) {
54
+ return new Uint8Array(data);
55
+ }
56
+ if (typeof data === "string") {
57
+ return ByteUtils.hexStringToBytes(data);
58
+ }
59
+ if (typeof data === "number" || typeof data === "bigint") {
60
+ return ByteUtils.hexStringToBytes(ByteUtils.hexlify(data));
61
+ }
62
+ return Uint8Array.from(data);
63
+ }
64
+ static hexToBigInt(hex) {
65
+ return BigInt(`0x${ByteUtils.strip0x(hex)}`);
66
+ }
67
+ static padToLength(data, length, side = "left") {
68
+ const hex = ByteUtils.hexlify(data);
69
+ const targetLength = length * 2;
70
+ if (hex.length > targetLength) {
71
+ throw new Error("Cannot pad data that exceeds target length");
72
+ }
73
+ return side === "left"
74
+ ? hex.padStart(targetLength, "0")
75
+ : hex.padEnd(targetLength, "0");
76
+ }
77
+ static formatToByteLength(data, length) {
78
+ const hex = ByteUtils.hexlify(data);
79
+ if (hex.length > length * 2) {
80
+ return hex.slice(0, length * 2);
81
+ }
82
+ return hex.padStart(length * 2, "0");
83
+ }
84
+ static nToHex(value, length, prefix = false) {
85
+ const hex = value.toString(16).padStart(length * 2, "0");
86
+ return prefix ? `0x${hex}` : hex;
87
+ }
88
+ }
89
+ export function fromUTF8String(value) {
90
+ const encoder = new TextEncoder();
91
+ return ByteUtils.hexlify(encoder.encode(value));
92
+ }
@@ -0,0 +1,3 @@
1
+ import { BytesData } from "./bytes.js";
2
+ export declare function sha512HMAC(key: BytesData, data: BytesData): string;
3
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../key-derivation/hash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AAMlD,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAGlE"}
@@ -0,0 +1,10 @@
1
+ import { hmac } from "@noble/hashes/hmac";
2
+ import { sha512 } from "@noble/hashes/sha2";
3
+ import { ByteUtils } from "./bytes.js";
4
+ const toBytes = (data) => {
5
+ return ByteUtils.arrayify(data);
6
+ };
7
+ export function sha512HMAC(key, data) {
8
+ const mac = hmac(sha512, toBytes(key), toBytes(data));
9
+ return ByteUtils.bytesToHex(mac);
10
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./babyjubjub.js";
2
+ export * from "./bip32.js";
3
+ export * from "./bip39.js";
4
+ export * from "./bech32.js";
5
+ export * from "./bytes.js";
6
+ export * from "./hash.js";
7
+ export * from "./wallet-node.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../key-derivation/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from "./babyjubjub.js";
2
+ export * from "./bip32.js";
3
+ export * from "./bip39.js";
4
+ export * from "./bech32.js";
5
+ export * from "./bytes.js";
6
+ export * from "./hash.js";
7
+ export * from "./wallet-node.js";
@@ -0,0 +1,45 @@
1
+ import { KeyNode } from "./bip32.js";
2
+ export type SpendingPublicKey = [bigint, bigint];
3
+ export type SpendingKeyPair = {
4
+ privateKey: Uint8Array;
5
+ pubkey: SpendingPublicKey;
6
+ };
7
+ export type ViewingKeyPair = {
8
+ privateKey: Uint8Array;
9
+ pubkey: Uint8Array;
10
+ };
11
+ export type WalletNodes = {
12
+ spending: WalletNode;
13
+ viewing: WalletNode;
14
+ };
15
+ export declare const deriveNodes: (mnemonic: string, index?: number) => WalletNodes;
16
+ export declare const deriveNodesFromSeed: (seed: Uint8Array, index?: number) => WalletNodes;
17
+ export declare class WalletNode {
18
+ private readonly chainKey;
19
+ private readonly chainCode;
20
+ constructor(node: KeyNode);
21
+ static fromMnemonic(mnemonic: string): WalletNode;
22
+ /**
23
+ * Convenience constructor for callers that already hold a seed or mnemonic-derived hex.
24
+ */
25
+ static fromSeed(seed: Uint8Array | string): WalletNode;
26
+ /**
27
+ * Traverse a derivation path, returning the resulting hardened node.
28
+ */
29
+ derive(path: string): WalletNode;
30
+ /**
31
+ * Derive the BabyJubJub spending key pair (private scalar + affine point).
32
+ */
33
+ getSpendingKeyPair(): SpendingKeyPair;
34
+ static getMasterPublicKey(spendingPublicKey: SpendingPublicKey, nullifyingKey: bigint): bigint;
35
+ static getNullifyingKey(viewingPrivateKey: Uint8Array): bigint;
36
+ /**
37
+ * Derive the Ed25519 viewing key pair for encrypted note retrieval.
38
+ */
39
+ getViewingKeyPair(): Promise<ViewingKeyPair>;
40
+ /**
41
+ * Compute the Poseidon-based nullifying key used in note nullifier generation.
42
+ */
43
+ getNullifyingKey(): Promise<bigint>;
44
+ }
45
+ //# sourceMappingURL=wallet-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-node.d.ts","sourceRoot":"","sources":["../../key-derivation/wallet-node.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,OAAO,EACR,MAAM,YAAY,CAAC;AASpB,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACjD,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAgB5E,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAExE,eAAO,MAAM,WAAW,GACtB,UAAU,MAAM,EAChB,QAAO,MAAU,KAChB,WAOF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,MAAM,UAAU,EAChB,QAAO,MAAU,KAChB,WAOF,CAAC;AAEF,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,IAAI,EAAE,OAAO;IAKzB,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU;IAKjD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU;IAQtD;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAUhC;;OAEG;IACH,kBAAkB,IAAI,eAAe;IASrC,MAAM,CAAC,kBAAkB,CACvB,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,MAAM,GACpB,MAAM;IAIT,MAAM,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,UAAU,GAAG,MAAM;IAW9D;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC;IASlD;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;CAI1C"}
@@ -0,0 +1,109 @@
1
+ import { Buffer } from "buffer";
2
+ import { getPublicKey, hashes } from "@noble/ed25519";
3
+ import { sha512 } from "@noble/hashes/sha2";
4
+ import { eddsa, poseidon } from "@railgun-community/circomlibjs";
5
+ import { childKeyDerivationHardened, getMasterKeyFromSeed, getPathSegments, } from "./bip32.js";
6
+ import { Mnemonic } from "./bip39.js";
7
+ import { ByteUtils } from "./bytes.js";
8
+ hashes.sha512 = sha512;
9
+ hashes.sha512Async = async (message) => sha512(message);
10
+ const HARDENED_OFFSET = 0x80000000;
11
+ /**
12
+ * Hardened base paths for spending/viewing keys. The final path becomes
13
+ * m/.../{index}' for each account slot.
14
+ */
15
+ const DERIVATION_PATH_PREFIXES = {
16
+ SPENDING: "m/44'/1984'/0'/0'/",
17
+ VIEWING: "m/420'/1984'/0'/0'/",
18
+ };
19
+ const derivePathsForIndex = (index = 0) => ({
20
+ spending: `${DERIVATION_PATH_PREFIXES.SPENDING}${index}'`,
21
+ viewing: `${DERIVATION_PATH_PREFIXES.VIEWING}${index}'`,
22
+ });
23
+ export const deriveNodes = (mnemonic, index = 0) => {
24
+ const paths = derivePathsForIndex(index);
25
+ const root = WalletNode.fromMnemonic(mnemonic);
26
+ return {
27
+ spending: root.derive(paths.spending),
28
+ viewing: root.derive(paths.viewing),
29
+ };
30
+ };
31
+ export const deriveNodesFromSeed = (seed, index = 0) => {
32
+ const paths = derivePathsForIndex(index);
33
+ const root = WalletNode.fromSeed(seed);
34
+ return {
35
+ spending: root.derive(paths.spending),
36
+ viewing: root.derive(paths.viewing),
37
+ };
38
+ };
39
+ export class WalletNode {
40
+ chainKey;
41
+ chainCode;
42
+ constructor(node) {
43
+ this.chainKey = node.chainKey;
44
+ this.chainCode = node.chainCode;
45
+ }
46
+ static fromMnemonic(mnemonic) {
47
+ const seedHex = Mnemonic.toSeed(mnemonic);
48
+ return new WalletNode(getMasterKeyFromSeed(seedHex));
49
+ }
50
+ /**
51
+ * Convenience constructor for callers that already hold a seed or mnemonic-derived hex.
52
+ */
53
+ static fromSeed(seed) {
54
+ const seedHex = typeof seed === "string"
55
+ ? ByteUtils.hexlify(seed)
56
+ : ByteUtils.bytesToHex(seed);
57
+ return new WalletNode(getMasterKeyFromSeed(seedHex));
58
+ }
59
+ /**
60
+ * Traverse a derivation path, returning the resulting hardened node.
61
+ */
62
+ derive(path) {
63
+ const segments = getPathSegments(path);
64
+ const derived = segments.reduce((parent, segment) => childKeyDerivationHardened(parent, segment, HARDENED_OFFSET), { chainKey: this.chainKey, chainCode: this.chainCode });
65
+ return new WalletNode(derived);
66
+ }
67
+ /**
68
+ * Derive the BabyJubJub spending key pair (private scalar + affine point).
69
+ */
70
+ getSpendingKeyPair() {
71
+ const privateKey = ByteUtils.hexStringToBytes(this.chainKey);
72
+ if (privateKey.length !== 32) {
73
+ throw new Error("Spending private key must be 32 bytes");
74
+ }
75
+ const pubkey = eddsa.prv2pub(Buffer.from(privateKey));
76
+ return { privateKey, pubkey };
77
+ }
78
+ static getMasterPublicKey(spendingPublicKey, nullifyingKey) {
79
+ return poseidon([...spendingPublicKey, nullifyingKey]);
80
+ }
81
+ static getNullifyingKey(viewingPrivateKey) {
82
+ if (!(viewingPrivateKey instanceof Uint8Array)) {
83
+ throw new Error("Viewing private key must be a Uint8Array");
84
+ }
85
+ if (viewingPrivateKey.length !== 32) {
86
+ throw new Error("Viewing private key must be 32 bytes");
87
+ }
88
+ const privateKeyHex = ByteUtils.bytesToHex(viewingPrivateKey);
89
+ return poseidon([ByteUtils.hexToBigInt(privateKeyHex)]);
90
+ }
91
+ /**
92
+ * Derive the Ed25519 viewing key pair for encrypted note retrieval.
93
+ */
94
+ async getViewingKeyPair() {
95
+ const privateKey = ByteUtils.hexStringToBytes(this.chainKey);
96
+ if (privateKey.length !== 32) {
97
+ throw new Error("Viewing private key must be 32 bytes");
98
+ }
99
+ const pubkey = await getPublicKey(privateKey);
100
+ return { privateKey, pubkey };
101
+ }
102
+ /**
103
+ * Compute the Poseidon-based nullifying key used in note nullifier generation.
104
+ */
105
+ async getNullifyingKey() {
106
+ const { privateKey } = await this.getViewingKeyPair();
107
+ return WalletNode.getNullifyingKey(privateKey);
108
+ }
109
+ }
package/dist/keys.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ export declare const RESERVED_PREFIXES: readonly ["meta:", "notes:", "leaves:", "roots:", "nullifiers:", "ciphertexts:", "jobs:", "proof_cache:", "cfg:", "idx:", "locks:"];
2
+ /** Canonical builders for storage key namespaces used across core */
3
+ export declare const keys: {
4
+ note: (c: number, i: number) => string;
5
+ leaf: (c: number, i: number) => string;
6
+ ciphertext: (c: number, i: number) => string;
7
+ /** Track note indices that remain unspent for a given master public key (mpk acts as the account identifier). */
8
+ unspent: (c: number, mpk: string, i: number) => string;
9
+ unspentPrefix: (c: number, mpk: string) => string;
10
+ nullifierObs: (c: number, n: string) => string;
11
+ nullToIndex: (c: number, n: string) => string;
12
+ nullifier: (c: number, n: string) => string;
13
+ root: (c: number, value: string) => string;
14
+ latestRoot: (c: number) => string;
15
+ rootCursor: (c: number) => string;
16
+ cursor: (c: number) => string;
17
+ aggregate: (c: number, a: string) => string;
18
+ job: (relayId: string) => string;
19
+ };
20
+ export declare const MAX_KEY_LEN = 512;
21
+ export declare function validateKey(key: string): void;
22
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../keys.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,qIAYpB,CAAC;AAEX,qEAAqE;AACrE,eAAO,MAAM,IAAI;cACL,MAAM,KAAK,MAAM;cACjB,MAAM,KAAK,MAAM;oBACX,MAAM,KAAK,MAAM;IACjC,iHAAiH;iBACpG,MAAM,OAAO,MAAM,KAAK,MAAM;uBAExB,MAAM,OAAO,MAAM;sBACpB,MAAM,KAAK,MAAM;qBAClB,MAAM,KAAK,MAAM;mBACnB,MAAM,KAAK,MAAM;cACtB,MAAM,SAAS,MAAM;oBACf,MAAM;oBACN,MAAM;gBACV,MAAM;mBACH,MAAM,KAAK,MAAM;mBACjB,MAAM;CACtB,CAAC;AAEF,eAAO,MAAM,WAAW,MAAM,CAAC;AAE/B,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,QAQtC"}
package/dist/keys.js ADDED
@@ -0,0 +1,41 @@
1
+ import { KeyValidationError } from "./errors.js";
2
+ export const RESERVED_PREFIXES = [
3
+ "meta:",
4
+ "notes:",
5
+ "leaves:",
6
+ "roots:",
7
+ "nullifiers:",
8
+ "ciphertexts:",
9
+ "jobs:",
10
+ "proof_cache:",
11
+ "cfg:",
12
+ "idx:",
13
+ "locks:",
14
+ ];
15
+ /** Canonical builders for storage key namespaces used across core */
16
+ export const keys = {
17
+ note: (c, i) => `notes:${c}:${i}`,
18
+ leaf: (c, i) => `leaves:${c}:${i}`,
19
+ ciphertext: (c, i) => `ciphertexts:${c}:${i}`,
20
+ /** Track note indices that remain unspent for a given master public key (mpk acts as the account identifier). */
21
+ unspent: (c, mpk, i) => `idx:notes:unspent:${c}:${mpk}:${i}`,
22
+ unspentPrefix: (c, mpk) => `idx:notes:unspent:${c}:${mpk}:`,
23
+ nullifierObs: (c, n) => `nullifiers:${c}:${n}`,
24
+ nullToIndex: (c, n) => `idx:nullifier:${c}:${n}`,
25
+ nullifier: (c, n) => `nullifiers:${c}:${n}`,
26
+ root: (c, value) => `roots:${c}:${value}`,
27
+ latestRoot: (c) => `roots:latest:${c}`,
28
+ rootCursor: (c) => `meta:roots:cursor:${c}`,
29
+ cursor: (c) => `meta:sync:cursors:${c}`,
30
+ aggregate: (c, a) => `idx:notes:agg:${c}:${a}`,
31
+ job: (relayId) => `jobs:${relayId}`,
32
+ };
33
+ export const MAX_KEY_LEN = 512;
34
+ export function validateKey(key) {
35
+ if (!key)
36
+ throw new KeyValidationError("key must not be empty");
37
+ if (key.length > MAX_KEY_LEN)
38
+ throw new KeyValidationError(`key exceeds ${MAX_KEY_LEN}`);
39
+ if (!RESERVED_PREFIXES.some((p) => key.startsWith(p)))
40
+ throw new KeyValidationError("key must start with a reserved namespace prefix");
41
+ }