@permissionless-technologies/upp-sdk 0.3.5 → 0.4.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.
- package/dist/{asp-ZA3RGN7G.js → asp-72WUGTQE.js} +3 -3
- package/dist/asp-72WUGTQE.js.map +1 -0
- package/dist/{asp-TXSAFFD3.cjs → asp-CUE3NMBN.cjs} +14 -14
- package/dist/asp-CUE3NMBN.cjs.map +1 -0
- package/dist/{chunk-KXPZUBPI.cjs → chunk-23B5XSS4.cjs} +12 -12
- package/dist/{chunk-KXPZUBPI.cjs.map → chunk-23B5XSS4.cjs.map} +1 -1
- package/dist/{chunk-SQKBT2SH.cjs → chunk-2G22R7AJ.cjs} +18 -7
- package/dist/chunk-2G22R7AJ.cjs.map +1 -0
- package/dist/chunk-5QSSX3KR.js +64 -0
- package/dist/chunk-5QSSX3KR.js.map +1 -0
- package/dist/{chunk-P37MRZ73.js → chunk-6IEYWJVS.js} +8 -8
- package/dist/chunk-6IEYWJVS.js.map +1 -0
- package/dist/{chunk-5V5HSN6Y.js → chunk-6TFDBBAQ.js} +3 -3
- package/dist/{chunk-5V5HSN6Y.js.map → chunk-6TFDBBAQ.js.map} +1 -1
- package/dist/{chunk-ZKZV6OI3.cjs → chunk-7BNJV2ZS.cjs} +21 -21
- package/dist/{chunk-ZKZV6OI3.cjs.map → chunk-7BNJV2ZS.cjs.map} +1 -1
- package/dist/{chunk-XBNYAAMU.js → chunk-7T4CUE6E.js} +3 -3
- package/dist/{chunk-XBNYAAMU.js.map → chunk-7T4CUE6E.js.map} +1 -1
- package/dist/{chunk-OD2SDC4L.js → chunk-CEJN5ZE5.js} +3 -3
- package/dist/{chunk-OD2SDC4L.js.map → chunk-CEJN5ZE5.js.map} +1 -1
- package/dist/{chunk-2JQISXBD.js → chunk-DTEAFJG7.js} +8 -8
- package/dist/{chunk-2JQISXBD.js.map → chunk-DTEAFJG7.js.map} +1 -1
- package/dist/chunk-EHGH6TAW.js +100 -0
- package/dist/chunk-EHGH6TAW.js.map +1 -0
- package/dist/{chunk-ZU6J7KMY.js → chunk-GPF72JFR.js} +3 -3
- package/dist/{chunk-ZU6J7KMY.js.map → chunk-GPF72JFR.js.map} +1 -1
- package/dist/chunk-HEHXSV47.cjs +77 -0
- package/dist/chunk-HEHXSV47.cjs.map +1 -0
- package/dist/chunk-I5EKGD4P.cjs +113 -0
- package/dist/chunk-I5EKGD4P.cjs.map +1 -0
- package/dist/{chunk-EUP7MBAH.cjs → chunk-IIUKM5VE.cjs} +7 -7
- package/dist/{chunk-EUP7MBAH.cjs.map → chunk-IIUKM5VE.cjs.map} +1 -1
- package/dist/{chunk-PJLRCR2T.js → chunk-OBBSIPEK.js} +30 -35
- package/dist/chunk-OBBSIPEK.js.map +1 -0
- package/dist/{chunk-QSL4XPNU.cjs → chunk-Q2E432UK.cjs} +41 -46
- package/dist/chunk-Q2E432UK.cjs.map +1 -0
- package/dist/{chunk-QKI4QWLT.js → chunk-RNUG3EFC.js} +6 -6
- package/dist/{chunk-QKI4QWLT.js.map → chunk-RNUG3EFC.js.map} +1 -1
- package/dist/{chunk-3YZSIYJC.cjs → chunk-SWTNJPK5.cjs} +11 -11
- package/dist/{chunk-3YZSIYJC.cjs.map → chunk-SWTNJPK5.cjs.map} +1 -1
- package/dist/{chunk-BH24DZ5S.cjs → chunk-U3YFYMWF.cjs} +5 -5
- package/dist/{chunk-BH24DZ5S.cjs.map → chunk-U3YFYMWF.cjs.map} +1 -1
- package/dist/{chunk-3HQ7A6ZM.cjs → chunk-UFEDJJSH.cjs} +5 -5
- package/dist/{chunk-3HQ7A6ZM.cjs.map → chunk-UFEDJJSH.cjs.map} +1 -1
- package/dist/{chunk-W77GRBO4.js → chunk-UQIM2KT3.js} +3 -3
- package/dist/{chunk-W77GRBO4.js.map → chunk-UQIM2KT3.js.map} +1 -1
- package/dist/{chunk-SJDPDHSD.cjs → chunk-UTAJSERA.cjs} +4 -4
- package/dist/{chunk-SJDPDHSD.cjs.map → chunk-UTAJSERA.cjs.map} +1 -1
- package/dist/{chunk-KLGLXF6H.cjs → chunk-UYE2JASE.cjs} +2 -2
- package/dist/{chunk-KLGLXF6H.cjs.map → chunk-UYE2JASE.cjs.map} +1 -1
- package/dist/{chunk-S4B7GYLN.js → chunk-W3HLIKC2.js} +18 -8
- package/dist/chunk-W3HLIKC2.js.map +1 -0
- package/dist/{chunk-NDM5EJEV.cjs → chunk-XVIICZKW.cjs} +7 -7
- package/dist/chunk-XVIICZKW.cjs.map +1 -0
- package/dist/{chunk-OFA2DP7S.js → chunk-ZTVXII74.js} +2 -2
- package/dist/{chunk-OFA2DP7S.js.map → chunk-ZTVXII74.js.map} +1 -1
- package/dist/core/index.cjs +82 -82
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +10 -10
- package/dist/{index-B45-okum.d.cts → index-BgPdYxFS.d.cts} +18 -18
- package/dist/{index-o-Ds3YAq.d.cts → index-CL4vb3ej.d.cts} +1 -1
- package/dist/{index-BIcvNMPt.d.ts → index-CtcXgof_.d.ts} +18 -18
- package/dist/{index-DwAJBoU7.d.ts → index-D6nvfm59.d.ts} +1 -1
- package/dist/index.cjs +175 -176
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +29 -30
- package/dist/index.js.map +1 -1
- package/dist/indexer/index.cjs +6 -6
- package/dist/indexer/index.d.cts +5 -5
- package/dist/indexer/index.d.ts +5 -5
- package/dist/indexer/index.js +1 -1
- package/dist/keys/index.cjs +18 -18
- package/dist/keys/index.js +4 -4
- package/dist/merkle-DZHEOPH3.cjs +30 -0
- package/dist/{merkle-HGDC6OB4.cjs.map → merkle-DZHEOPH3.cjs.map} +1 -1
- package/dist/merkle-IF2RMWCF.js +5 -0
- package/dist/{merkle-7KS2EHRF.js.map → merkle-IF2RMWCF.js.map} +1 -1
- package/dist/poseidon-ACM7E2OH.js +7 -0
- package/dist/{poseidon-UHTJLWQM.js.map → poseidon-ACM7E2OH.js.map} +1 -1
- package/dist/poseidon-PUSGUIVZ.cjs +61 -0
- package/dist/{poseidon-WHJSZSNP.cjs.map → poseidon-PUSGUIVZ.cjs.map} +1 -1
- package/dist/proof-JME3IZTX.js +4 -0
- package/dist/{proof-C4YBP6RY.js.map → proof-JME3IZTX.js.map} +1 -1
- package/dist/proof-XR6XE5PJ.cjs +49 -0
- package/dist/{proof-5OECB3RQ.cjs.map → proof-XR6XE5PJ.cjs.map} +1 -1
- package/dist/react/index.cjs +52 -55
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +25 -28
- package/dist/react/index.js.map +1 -1
- package/dist/{transfer-BzyernBd.d.cts → transfer-D111ihqN.d.cts} +108 -56
- package/dist/{transfer-sqS6mJko.d.ts → transfer-DvIXqHCr.d.ts} +108 -56
- package/dist/transfer-MQMGSXTH.js +8 -0
- package/dist/{transfer-P4D57KJ5.js.map → transfer-MQMGSXTH.js.map} +1 -1
- package/dist/transfer-PB6D5VCW.cjs +37 -0
- package/dist/{transfer-XCVVZ7FF.cjs.map → transfer-PB6D5VCW.cjs.map} +1 -1
- package/dist/utils/index.cjs +60 -61
- package/dist/utils/index.d.cts +37 -14
- package/dist/utils/index.d.ts +37 -14
- package/dist/utils/index.js +6 -7
- package/package.json +4 -2
- package/src/contracts/interfaces/IUniversalPrivatePool.sol +10 -8
- package/src/contracts/interfaces/IVerifiers.sol +16 -52
- package/src/deployments/11155111.json +15 -12
- package/dist/asp-TXSAFFD3.cjs.map +0 -1
- package/dist/asp-ZA3RGN7G.js.map +0 -1
- package/dist/babyjubjub-2MGQVCKB.js +0 -5
- package/dist/babyjubjub-2MGQVCKB.js.map +0 -1
- package/dist/babyjubjub-MWZLJOVZ.cjs +0 -66
- package/dist/babyjubjub-MWZLJOVZ.cjs.map +0 -1
- package/dist/chunk-JWNXBALH.cjs +0 -57
- package/dist/chunk-JWNXBALH.cjs.map +0 -1
- package/dist/chunk-NDM5EJEV.cjs.map +0 -1
- package/dist/chunk-P37MRZ73.js.map +0 -1
- package/dist/chunk-PJLRCR2T.js.map +0 -1
- package/dist/chunk-PTDVGWHU.cjs +0 -10
- package/dist/chunk-PTDVGWHU.cjs.map +0 -1
- package/dist/chunk-QSL4XPNU.cjs.map +0 -1
- package/dist/chunk-S4B7GYLN.js.map +0 -1
- package/dist/chunk-SQKBT2SH.cjs.map +0 -1
- package/dist/chunk-TSF6HEVS.cjs +0 -201
- package/dist/chunk-TSF6HEVS.cjs.map +0 -1
- package/dist/chunk-UAVWYXDN.js +0 -8
- package/dist/chunk-UAVWYXDN.js.map +0 -1
- package/dist/chunk-V23OSL25.js +0 -48
- package/dist/chunk-V23OSL25.js.map +0 -1
- package/dist/chunk-YOWDERVC.js +0 -186
- package/dist/chunk-YOWDERVC.js.map +0 -1
- package/dist/merkle-7KS2EHRF.js +0 -5
- package/dist/merkle-HGDC6OB4.cjs +0 -30
- package/dist/poseidon-UHTJLWQM.js +0 -7
- package/dist/poseidon-WHJSZSNP.cjs +0 -45
- package/dist/proof-5OECB3RQ.cjs +0 -45
- package/dist/proof-C4YBP6RY.js +0 -4
- package/dist/transfer-P4D57KJ5.js +0 -8
- package/dist/transfer-XCVVZ7FF.cjs +0 -37
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { splitToM31Limbs, computeStarkOwnerHash, keccakM31 } from './chunk-
|
|
2
|
-
import { init_crypto, bytesToBigint, hexToBytes, bytesToHex } from './chunk-
|
|
3
|
-
import { init_poseidon, FIELD_PRIME } from './chunk-
|
|
1
|
+
import { splitToM31Limbs, computeStarkOwnerHash, keccakM31 } from './chunk-6TFDBBAQ.js';
|
|
2
|
+
import { init_crypto, bytesToBigint, hexToBytes, bytesToHex } from './chunk-UQIM2KT3.js';
|
|
3
|
+
import { init_poseidon, FIELD_PRIME } from './chunk-5QSSX3KR.js';
|
|
4
4
|
import { keccak256, toHex } from 'viem';
|
|
5
5
|
|
|
6
6
|
// src/keys/types.ts
|
|
@@ -13,7 +13,7 @@ var DEFAULT_KEY_DERIVATION_CONFIG = {
|
|
|
13
13
|
init_poseidon();
|
|
14
14
|
init_crypto();
|
|
15
15
|
async function deriveKeysFromSignature(signature, config = DEFAULT_KEY_DERIVATION_CONFIG) {
|
|
16
|
-
const { poseidon } = await import('./poseidon-
|
|
16
|
+
const { poseidon } = await import('./poseidon-ACM7E2OH.js');
|
|
17
17
|
const seed = keccak256(signature);
|
|
18
18
|
const spendingSecretHash = keccak256(
|
|
19
19
|
toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))
|
|
@@ -66,12 +66,12 @@ async function deriveDualKeysFromSignature(signature, config = DEFAULT_KEY_DERIV
|
|
|
66
66
|
return { snark, stark };
|
|
67
67
|
}
|
|
68
68
|
async function deriveNullifierKey(spendingSecret) {
|
|
69
|
-
const { poseidon } = await import('./poseidon-
|
|
69
|
+
const { poseidon } = await import('./poseidon-ACM7E2OH.js');
|
|
70
70
|
return await poseidon([spendingSecret, 0n]);
|
|
71
71
|
}
|
|
72
72
|
init_crypto();
|
|
73
73
|
async function derivePerNoteKey(viewingSecret, nonce) {
|
|
74
|
-
const { poseidon } = await import('./poseidon-
|
|
74
|
+
const { poseidon } = await import('./poseidon-ACM7E2OH.js');
|
|
75
75
|
const perNoteKey = await poseidon([viewingSecret, nonce]);
|
|
76
76
|
return toHex(perNoteKey, { size: 32 });
|
|
77
77
|
}
|
|
@@ -146,5 +146,5 @@ function deriveStarkPerNoteKeyFromKeys(keys, nonce) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export { DEFAULT_KEY_DERIVATION_CONFIG, deriveDualKeysFromSignature, deriveKeysFromSignature, deriveNullifierKey, derivePerNoteKey, derivePerNoteKeyFromKeys, deriveStarkKeysFromSignature, deriveStarkPerNoteKey, deriveStarkPerNoteKeyFromKeys, exportViewingKeysForAudit, getKeyDerivationMessage, getViewingKeyFromExport, validateAuditKeyExport, verifyKeysMatchSignature };
|
|
149
|
-
//# sourceMappingURL=chunk-
|
|
150
|
-
//# sourceMappingURL=chunk-
|
|
149
|
+
//# sourceMappingURL=chunk-DTEAFJG7.js.map
|
|
150
|
+
//# sourceMappingURL=chunk-DTEAFJG7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/keys/types.ts","../src/keys/derive.ts","../src/keys/viewing.ts"],"names":["toHex","keccak256"],"mappings":"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","file":"chunk-2JQISXBD.js","sourcesContent":["/**\n * Key Type Definitions for UPP SDK\n *\n * Post-quantum key structure (hash-based, no elliptic curves):\n *\n * Wallet Signature → Seed\n * ├── Spending Secret → Owner Hash = Poseidon(spendingSecret)\n * └── Viewing Secret (for note encryption, derived from seed)\n *\n * Ownership is proven via hash preimage: \"I know secret such that Poseidon(secret) == ownerHash\"\n * This replaces the previous BabyJubJub ECDLP-based ownership proof.\n */\n\nimport type { Hex, Address } from 'viem'\n\n/**\n * Master keys derived from wallet signature\n *\n * Post-quantum: uses hash-based ownership instead of BabyJubJub curve.\n * ownerHash = Poseidon(spendingSecret) replaces spendingPubKey (curve point).\n */\nexport interface MasterKeys {\n /** Spending secret - for note ownership proofs (hash preimage) */\n spendingSecret: bigint\n /** Owner hash = Poseidon(spendingSecret) - publicly committed in notes */\n ownerHash: bigint\n /** Viewing secret - for note encryption/decryption (symmetric key derivation) */\n viewingSecret: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for search tags and indexing */\n viewingHash: bigint\n}\n\n/**\n * Per-transaction viewing key (for decryption)\n *\n * Can be shared with auditors to reveal specific transactions\n * without compromising the master viewing secret.\n *\n * Post-quantum: uses hash-based key derivation instead of ECDH.\n */\nexport interface TransactionViewingKey {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The per-note nonce (used in key derivation) */\n nonce: bigint\n /** The per-note decryption key (derived from viewingSecret + nonce) */\n decryptionKey: Hex\n}\n\n/**\n * Exported viewing keys for audit\n *\n * Contains the minimum information needed for an auditor\n * to decrypt specific transactions.\n */\nexport interface AuditKeyExport {\n /** Version for forward compatibility (v4 = post-quantum hash-based) */\n version: 4\n /** Ethereum address that signed to derive keys (for identification) */\n signerAddress: Address\n /** The viewing hash (for verification) */\n viewingHash: bigint\n /** Per-transaction viewing keys */\n viewingKeys: TransactionViewingKey[]\n /** Instructions for auditor */\n instructions: string\n}\n\n/**\n * Stealth address components (simplified for hash-based system)\n * Published once, used by senders to encrypt notes\n */\nexport interface StealthAddressComponents {\n /** Owner hash = Poseidon(spendingSecret) */\n ownerHash: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for encryption */\n viewingHash: bigint\n /** Optional chain ID (for multi-chain support) */\n chainId?: number\n}\n\n/**\n * Configuration for key derivation\n */\nexport interface KeyDerivationConfig {\n /** The message to sign for key derivation */\n message: string\n /** Version number for the key derivation scheme */\n version: 1\n}\n\n/**\n * Default key derivation configuration\n */\nexport const DEFAULT_KEY_DERIVATION_CONFIG: KeyDerivationConfig = {\n message: 'UPP Stealth Key Derivation v1',\n version: 1,\n}\n\n/**\n * Result of deriving one-time keys for a transaction (hash-based)\n */\nexport interface OneTimeKeys {\n /** One-time secret (for the owner to spend the note) */\n oneTimeSecret: bigint\n /** One-time owner hash = Poseidon(oneTimeSecret) - in the commitment */\n ownerHash: bigint\n}\n\n/**\n * Serialized key format for storage\n */\nexport interface SerializedKeys {\n version: 1\n /** Hex-encoded encrypted key data */\n encryptedData: Hex\n /** Salt for key derivation (if password protected) */\n salt?: Hex\n /** Nonce for encryption */\n nonce: Hex\n}\n\n// =========================================================================\n// STARK Key Types (M31/Keccak-based, post-quantum)\n// =========================================================================\n\nimport type { M31Digest, M31Secret } from '../utils/keccak-m31.js'\n\n/** Which proving system to use */\nexport type ProvingSystem = 'snark' | 'stark'\n\n/**\n * STARK master keys derived from wallet signature.\n *\n * Uses M31 field and keccak-256 hashing — no elliptic curves.\n * ownerHash = keccak_m31(starkSecret) — 4 M31 elements.\n */\nexport interface StarkMasterKeys {\n /** 8 M31 limbs (248 bits of entropy) — for ownership proofs */\n starkSecret: M31Secret\n /** keccak_m31(starkSecret) — publicly committed in STARK notes */\n starkOwnerHash: M31Digest\n /** 8 M31 limbs — for note encryption/decryption */\n starkViewingSecret: M31Secret\n /** keccak_m31(starkViewingSecret) — for search tags and indexing */\n starkViewingHash: M31Digest\n}\n\n/**\n * Dual master keys: both SNARK (BN254/Poseidon) and STARK (M31/Keccak).\n *\n * Derived from the same wallet signature via domain-separated keccak256.\n * Breaking BJJ (quantum) does NOT compromise STARK keys (keccak preimage resistance).\n */\nexport interface DualMasterKeys {\n snark: MasterKeys\n stark: StarkMasterKeys\n}\n","/**\n * Key Derivation from Wallet Signature (Post-Quantum / Hash-Based)\n *\n * Derives keys from an Ethereum wallet signature using only hash functions.\n * No elliptic curve operations — quantum-resistant by design.\n *\n * Security Model:\n * - Keys are derived deterministically from the signature\n * - No seed phrase management required\n * - Same signature always produces same keys\n * - Ownership proven via hash preimage (Poseidon), not discrete log\n */\n\nimport { keccak256, toHex, type Hex } from 'viem'\nimport { FIELD_PRIME } from '../utils/poseidon.js'\nimport { hexToBytes, bytesToBigint } from '../utils/crypto.js'\nimport { splitToM31Limbs, computeStarkOwnerHash } from '../utils/keccak-m31.js'\nimport type { MasterKeys, StarkMasterKeys, DualMasterKeys, KeyDerivationConfig } from './types.js'\nimport { DEFAULT_KEY_DERIVATION_CONFIG } from './types.js'\n\n/**\n * Derive master keys from a wallet signature (hash-based, post-quantum)\n *\n * This replaces the previous BabyJubJub-based derivation.\n * Instead of curve points, we use Poseidon hashes for ownership proofs.\n *\n * @param signature - The wallet signature (from personal_sign or EIP-712)\n * @param config - Optional key derivation configuration\n * @returns Master keys for stealth operations\n *\n * @example\n * ```ts\n * const signature = await walletClient.signMessage({\n * message: 'UPP Stealth Key Derivation v1'\n * })\n * const keys = await deriveKeysFromSignature(signature)\n * // keys.ownerHash is Poseidon(spendingSecret) — used in note commitments\n * ```\n */\nexport async function deriveKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<MasterKeys> {\n const { poseidon } = await import('../utils/poseidon.js')\n\n // Create a seed from the signature using keccak256\n const seed = keccak256(signature)\n\n // Derive spending secret from seed\n const spendingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))\n )\n const spendingSecretRaw = bytesToBigint(hexToBytes(spendingSecretHash))\n const spendingSecret = spendingSecretRaw % FIELD_PRIME\n\n // Derive owner hash: Poseidon(spendingSecret)\n // This replaces BabyJubJub public key derivation\n const ownerHash = await poseidon([spendingSecret])\n\n // Derive viewing secret from seed\n const viewingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:viewing:v${config.version}`))\n )\n const viewingSecretRaw = bytesToBigint(hexToBytes(viewingSecretHash))\n const viewingSecret = viewingSecretRaw % FIELD_PRIME\n\n // Derive viewing hash: Poseidon(viewingSecret)\n const viewingHash = await poseidon([viewingSecret])\n\n return {\n spendingSecret,\n ownerHash,\n viewingSecret,\n viewingHash,\n }\n}\n\n/**\n * Get the message to sign for key derivation\n */\nexport function getKeyDerivationMessage(\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): string {\n return config.message\n}\n\n/**\n * Verify that keys match a given signature\n */\nexport async function verifyKeysMatchSignature(\n keys: MasterKeys,\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<boolean> {\n const derivedKeys = await deriveKeysFromSignature(signature, config)\n\n return (\n keys.spendingSecret === derivedKeys.spendingSecret &&\n keys.ownerHash === derivedKeys.ownerHash &&\n keys.viewingSecret === derivedKeys.viewingSecret &&\n keys.viewingHash === derivedKeys.viewingHash\n )\n}\n\n/**\n * Derive STARK master keys from a wallet signature (M31/Keccak, post-quantum)\n *\n * Uses domain-separated keccak256 to derive M31 secrets, then keccak_m31\n * for owner/viewing hashes. No elliptic curve operations.\n *\n * @param signature - The wallet signature (same one used for SNARK keys)\n * @param config - Optional key derivation configuration\n * @returns STARK master keys for stealth operations\n */\nexport function deriveStarkKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): StarkMasterKeys {\n const seed = keccak256(signature)\n\n // Derive STARK spending secret: 8 M31 limbs from a single keccak256\n const starkSpendingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:spending:v${config.version}`))\n )\n const starkSecret = splitToM31Limbs(starkSpendingHash)\n const starkOwnerHash = computeStarkOwnerHash(starkSecret)\n\n // Derive STARK viewing secret: 8 M31 limbs from a separate keccak256\n const starkViewingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:viewing:v${config.version}`))\n )\n const starkViewingSecret = splitToM31Limbs(starkViewingHash)\n const starkViewingHashDigest = computeStarkOwnerHash(starkViewingSecret)\n\n return {\n starkSecret,\n starkOwnerHash,\n starkViewingSecret,\n starkViewingHash: starkViewingHashDigest,\n }\n}\n\n/**\n * Derive both SNARK and STARK keys from a single wallet signature.\n *\n * Same seed, domain-separated derivation. Breaking BJJ (quantum) does NOT\n * compromise STARK keys — keccak preimage resistance provides 2^128 quantum security.\n */\nexport async function deriveDualKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<DualMasterKeys> {\n const snark = await deriveKeysFromSignature(signature, config)\n const stark = deriveStarkKeysFromSignature(signature, config)\n return { snark, stark }\n}\n\n/**\n * Derive a nullifier key from the spending secret\n *\n * nullifier = Poseidon(nullifierKey, leafIndex, commitment)\n */\nexport async function deriveNullifierKey(spendingSecret: bigint): Promise<bigint> {\n const { poseidon } = await import('../utils/poseidon.js')\n return await poseidon([spendingSecret, 0n]) // 0n = nullifier domain\n}\n","/**\n * Per-Transaction Viewing Key Derivation (Post-Quantum, Hash-Based)\n *\n * Implements hierarchical viewing keys using Poseidon hash instead of ECDH.\n *\n * Key Properties:\n * - Per-note decryption key: Poseidon(viewingSecret, nonce)\n * - AES key: keccak256(perNoteKey) for symmetric encryption\n *\n * Derivation:\n * perNoteKey = Poseidon(viewingSecret, nonce)\n * aesKey = keccak256(perNoteKey)\n *\n * SECURITY (v4):\n * Audit exports contain per-note decryption keys derived from viewingSecret + nonce.\n * This prevents master key recovery: knowing Poseidon(viewingSecret, nonce) doesn't\n * reveal viewingSecret due to the one-wayness of Poseidon.\n */\n\nimport type { Address, Hex } from 'viem'\nimport { keccak256, toHex } from 'viem'\nimport type {\n MasterKeys,\n StarkMasterKeys,\n TransactionViewingKey,\n AuditKeyExport,\n} from './types.js'\nimport { keccakM31, type M31Secret } from '../utils/keccak-m31.js'\nimport { bytesToHex } from '../utils/crypto.js'\n\n/**\n * Derive a per-note decryption key from master viewing secret and nonce\n *\n * @param viewingSecret - Master viewing secret\n * @param nonce - Unique per-note nonce\n * @returns Per-note decryption key as hex\n */\nexport async function derivePerNoteKey(\n viewingSecret: bigint,\n nonce: bigint\n): Promise<Hex> {\n const { poseidon } = await import('../utils/poseidon.js')\n const perNoteKey = await poseidon([viewingSecret, nonce])\n return toHex(perNoteKey, { size: 32 })\n}\n\n/**\n * Derive per-note key from MasterKeys convenience wrapper\n */\nexport async function derivePerNoteKeyFromKeys(\n keys: MasterKeys,\n nonce: bigint\n): Promise<Hex> {\n return derivePerNoteKey(keys.viewingSecret, nonce)\n}\n\n/**\n * Note reference for audit export\n */\nexport interface NoteReference {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The nonce used in per-note key derivation */\n nonce: bigint\n}\n\n/**\n * Export viewing keys for specific notes\n *\n * Creates an export package that can be shared with an auditor.\n * The auditor can use these keys to decrypt the specified notes,\n * but cannot derive keys for other notes.\n *\n * @param keys - Master keys\n * @param signerAddress - The Ethereum address that signed to derive keys\n * @param notes - Array of note references (leafIndex + nonce) to export\n * @returns Audit key export package\n */\nexport async function exportViewingKeysForAudit(\n keys: MasterKeys,\n signerAddress: Address,\n notes: NoteReference[]\n): Promise<AuditKeyExport> {\n const viewingKeys: TransactionViewingKey[] = []\n\n for (const note of notes) {\n // Derive the per-note decryption key\n const decryptionKey = await derivePerNoteKey(keys.viewingSecret, note.nonce)\n\n viewingKeys.push({\n leafIndex: note.leafIndex,\n nonce: note.nonce,\n decryptionKey,\n })\n }\n\n return {\n version: 4,\n signerAddress,\n viewingHash: keys.viewingHash,\n viewingKeys,\n instructions: `\nThis export contains per-note decryption keys for ${viewingKeys.length} UPP note(s).\n\nTo decrypt a note:\n1. Find the viewingKey entry for the desired leafIndex\n2. Retrieve the encrypted note from the blockchain (Shielded event at that leaf index)\n3. Derive AES key: key = keccak256(decryptionKey)\n4. Decrypt the note ciphertext with AES-GCM\n\nThese per-note keys ONLY allow decryption of the specified notes.\nThey do NOT reveal:\n- The master viewing secret (protected by Poseidon one-wayness)\n- Keys for any other notes\n- The spending secret (cannot spend funds)\n `.trim(),\n }\n}\n\n/**\n * Validate an audit key export\n */\nexport function validateAuditKeyExport(\n exportData: AuditKeyExport\n): { valid: boolean; error?: string } {\n if (exportData.version !== 4) {\n return { valid: false, error: `Unsupported version: ${exportData.version}. Expected version 4.` }\n }\n\n if (!exportData.signerAddress || !exportData.signerAddress.startsWith('0x')) {\n return { valid: false, error: 'Invalid signer address' }\n }\n\n if (exportData.viewingHash === undefined || exportData.viewingHash === null) {\n return { valid: false, error: 'Missing viewing hash' }\n }\n\n if (!Array.isArray(exportData.viewingKeys) || exportData.viewingKeys.length === 0) {\n return { valid: false, error: 'No viewing keys in export' }\n }\n\n return { valid: true }\n}\n\n/**\n * Look up a decryption key from an audit export by leaf index\n *\n * Returns the per-note decryption key for direct use in AES-GCM decryption.\n * Derive AES key: keccak256(decryptionKey)\n */\nexport function getViewingKeyFromExport(\n exportData: AuditKeyExport,\n leafIndex: number\n): Hex | null {\n const key = exportData.viewingKeys.find(k => k.leafIndex === leafIndex)\n return key ? key.decryptionKey : null\n}\n\n// =========================================================================\n// STARK Per-Note Viewing Key Derivation (Keccak-based, no elliptic curves)\n// =========================================================================\n\n/**\n * Derive a STARK per-note decryption key from viewing secret and nonce.\n *\n * Uses keccak_m31 instead of Poseidon — purely symmetric, post-quantum safe.\n * The nonce is encoded as a single M31 element appended to the viewing secret.\n *\n * perNoteDigest = keccak_m31(viewingSecret[0..8], nonce)\n * aesKey = keccak256(perNoteDigest_packed_as_16_LE_bytes)\n *\n * @param starkViewingSecret - 8 M31 limbs (the master STARK viewing secret)\n * @param nonce - Per-note nonce (M31 range)\n * @returns 32-byte AES key as hex\n */\nexport function deriveStarkPerNoteKey(\n starkViewingSecret: M31Secret,\n nonce: bigint\n): Hex {\n // keccak_m31(viewingSecret[0..8], nonce) → 4 M31 elements\n const digest = keccakM31([...starkViewingSecret, nonce])\n\n // Pack digest as 16 bytes LE for AES key derivation\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 4; i++) {\n const val = Number(digest[i]!)\n bytes[i * 4] = val & 0xff\n bytes[i * 4 + 1] = (val >> 8) & 0xff\n bytes[i * 4 + 2] = (val >> 16) & 0xff\n bytes[i * 4 + 3] = (val >> 24) & 0xff\n }\n\n // Derive 32-byte AES key via keccak256\n return keccak256(bytesToHex(bytes))\n}\n\n/**\n * Derive STARK per-note key from StarkMasterKeys convenience wrapper\n */\nexport function deriveStarkPerNoteKeyFromKeys(\n keys: StarkMasterKeys,\n nonce: bigint\n): Hex {\n return deriveStarkPerNoteKey(keys.starkViewingSecret, nonce)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keys/types.ts","../src/keys/derive.ts","../src/keys/viewing.ts"],"names":["toHex","keccak256"],"mappings":"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","file":"chunk-DTEAFJG7.js","sourcesContent":["/**\n * Key Type Definitions for UPP SDK\n *\n * Post-quantum key structure (hash-based, no elliptic curves):\n *\n * Wallet Signature → Seed\n * ├── Spending Secret → Owner Hash = Poseidon(spendingSecret)\n * └── Viewing Secret (for note encryption, derived from seed)\n *\n * Ownership is proven via hash preimage: \"I know secret such that Poseidon(secret) == ownerHash\"\n * This replaces the previous BabyJubJub ECDLP-based ownership proof.\n */\n\nimport type { Hex, Address } from 'viem'\n\n/**\n * Master keys derived from wallet signature\n *\n * Post-quantum: uses hash-based ownership instead of BabyJubJub curve.\n * ownerHash = Poseidon(spendingSecret) replaces spendingPubKey (curve point).\n */\nexport interface MasterKeys {\n /** Spending secret - for note ownership proofs (hash preimage) */\n spendingSecret: bigint\n /** Owner hash = Poseidon(spendingSecret) - publicly committed in notes */\n ownerHash: bigint\n /** Viewing secret - for note encryption/decryption (symmetric key derivation) */\n viewingSecret: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for search tags and indexing */\n viewingHash: bigint\n}\n\n/**\n * Per-transaction viewing key (for decryption)\n *\n * Can be shared with auditors to reveal specific transactions\n * without compromising the master viewing secret.\n *\n * Post-quantum: uses hash-based key derivation instead of ECDH.\n */\nexport interface TransactionViewingKey {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The per-note nonce (used in key derivation) */\n nonce: bigint\n /** The per-note decryption key (derived from viewingSecret + nonce) */\n decryptionKey: Hex\n}\n\n/**\n * Exported viewing keys for audit\n *\n * Contains the minimum information needed for an auditor\n * to decrypt specific transactions.\n */\nexport interface AuditKeyExport {\n /** Version for forward compatibility (v4 = post-quantum hash-based) */\n version: 4\n /** Ethereum address that signed to derive keys (for identification) */\n signerAddress: Address\n /** The viewing hash (for verification) */\n viewingHash: bigint\n /** Per-transaction viewing keys */\n viewingKeys: TransactionViewingKey[]\n /** Instructions for auditor */\n instructions: string\n}\n\n/**\n * Stealth address components (simplified for hash-based system)\n * Published once, used by senders to encrypt notes\n */\nexport interface StealthAddressComponents {\n /** Owner hash = Poseidon(spendingSecret) */\n ownerHash: bigint\n /** Viewing hash = Poseidon(viewingSecret) - for encryption */\n viewingHash: bigint\n /** Optional chain ID (for multi-chain support) */\n chainId?: number\n}\n\n/**\n * Configuration for key derivation\n */\nexport interface KeyDerivationConfig {\n /** The message to sign for key derivation */\n message: string\n /** Version number for the key derivation scheme */\n version: 1\n}\n\n/**\n * Default key derivation configuration\n */\nexport const DEFAULT_KEY_DERIVATION_CONFIG: KeyDerivationConfig = {\n message: 'UPP Stealth Key Derivation v1',\n version: 1,\n}\n\n/**\n * Result of deriving one-time keys for a transaction (hash-based)\n */\nexport interface OneTimeKeys {\n /** One-time secret (for the owner to spend the note) */\n oneTimeSecret: bigint\n /** One-time owner hash = Poseidon(oneTimeSecret) - in the commitment */\n ownerHash: bigint\n}\n\n/**\n * Serialized key format for storage\n */\nexport interface SerializedKeys {\n version: 1\n /** Hex-encoded encrypted key data */\n encryptedData: Hex\n /** Salt for key derivation (if password protected) */\n salt?: Hex\n /** Nonce for encryption */\n nonce: Hex\n}\n\n// =========================================================================\n// STARK Key Types (M31/Keccak-based, post-quantum)\n// =========================================================================\n\nimport type { M31Digest, M31Secret } from '../utils/keccak-m31.js'\n\n/** Which proving system to use */\nexport type ProvingSystem = 'snark' | 'stark'\n\n/**\n * STARK master keys derived from wallet signature.\n *\n * Uses M31 field and keccak-256 hashing — no elliptic curves.\n * ownerHash = keccak_m31(starkSecret) — 4 M31 elements.\n */\nexport interface StarkMasterKeys {\n /** 8 M31 limbs (248 bits of entropy) — for ownership proofs */\n starkSecret: M31Secret\n /** keccak_m31(starkSecret) — publicly committed in STARK notes */\n starkOwnerHash: M31Digest\n /** 8 M31 limbs — for note encryption/decryption */\n starkViewingSecret: M31Secret\n /** keccak_m31(starkViewingSecret) — for search tags and indexing */\n starkViewingHash: M31Digest\n}\n\n/**\n * Dual master keys: both SNARK (BN254/Poseidon) and STARK (M31/Keccak).\n *\n * Derived from the same wallet signature via domain-separated keccak256.\n * Breaking BJJ (quantum) does NOT compromise STARK keys (keccak preimage resistance).\n */\nexport interface DualMasterKeys {\n snark: MasterKeys\n stark: StarkMasterKeys\n}\n","/**\n * Key Derivation from Wallet Signature (Post-Quantum / Hash-Based)\n *\n * Derives keys from an Ethereum wallet signature using only hash functions.\n * No elliptic curve operations — quantum-resistant by design.\n *\n * Security Model:\n * - Keys are derived deterministically from the signature\n * - No seed phrase management required\n * - Same signature always produces same keys\n * - Ownership proven via hash preimage (Poseidon), not discrete log\n */\n\nimport { keccak256, toHex, type Hex } from 'viem'\nimport { FIELD_PRIME } from '../utils/poseidon.js'\nimport { hexToBytes, bytesToBigint } from '../utils/crypto.js'\nimport { splitToM31Limbs, computeStarkOwnerHash } from '../utils/keccak-m31.js'\nimport type { MasterKeys, StarkMasterKeys, DualMasterKeys, KeyDerivationConfig } from './types.js'\nimport { DEFAULT_KEY_DERIVATION_CONFIG } from './types.js'\n\n/**\n * Derive master keys from a wallet signature (hash-based, post-quantum)\n *\n * This replaces the previous BabyJubJub-based derivation.\n * Instead of curve points, we use Poseidon hashes for ownership proofs.\n *\n * @param signature - The wallet signature (from personal_sign or EIP-712)\n * @param config - Optional key derivation configuration\n * @returns Master keys for stealth operations\n *\n * @example\n * ```ts\n * const signature = await walletClient.signMessage({\n * message: 'UPP Stealth Key Derivation v1'\n * })\n * const keys = await deriveKeysFromSignature(signature)\n * // keys.ownerHash is Poseidon(spendingSecret) — used in note commitments\n * ```\n */\nexport async function deriveKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<MasterKeys> {\n const { poseidon } = await import('../utils/poseidon.js')\n\n // Create a seed from the signature using keccak256\n const seed = keccak256(signature)\n\n // Derive spending secret from seed\n const spendingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))\n )\n const spendingSecretRaw = bytesToBigint(hexToBytes(spendingSecretHash))\n const spendingSecret = spendingSecretRaw % FIELD_PRIME\n\n // Derive owner hash: Poseidon(spendingSecret)\n // This replaces BabyJubJub public key derivation\n const ownerHash = await poseidon([spendingSecret])\n\n // Derive viewing secret from seed\n const viewingSecretHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:viewing:v${config.version}`))\n )\n const viewingSecretRaw = bytesToBigint(hexToBytes(viewingSecretHash))\n const viewingSecret = viewingSecretRaw % FIELD_PRIME\n\n // Derive viewing hash: Poseidon(viewingSecret)\n const viewingHash = await poseidon([viewingSecret])\n\n return {\n spendingSecret,\n ownerHash,\n viewingSecret,\n viewingHash,\n }\n}\n\n/**\n * Get the message to sign for key derivation\n */\nexport function getKeyDerivationMessage(\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): string {\n return config.message\n}\n\n/**\n * Verify that keys match a given signature\n */\nexport async function verifyKeysMatchSignature(\n keys: MasterKeys,\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<boolean> {\n const derivedKeys = await deriveKeysFromSignature(signature, config)\n\n return (\n keys.spendingSecret === derivedKeys.spendingSecret &&\n keys.ownerHash === derivedKeys.ownerHash &&\n keys.viewingSecret === derivedKeys.viewingSecret &&\n keys.viewingHash === derivedKeys.viewingHash\n )\n}\n\n/**\n * Derive STARK master keys from a wallet signature (M31/Keccak, post-quantum)\n *\n * Uses domain-separated keccak256 to derive M31 secrets, then keccak_m31\n * for owner/viewing hashes. No elliptic curve operations.\n *\n * @param signature - The wallet signature (same one used for SNARK keys)\n * @param config - Optional key derivation configuration\n * @returns STARK master keys for stealth operations\n */\nexport function deriveStarkKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): StarkMasterKeys {\n const seed = keccak256(signature)\n\n // Derive STARK spending secret: 8 M31 limbs from a single keccak256\n const starkSpendingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:spending:v${config.version}`))\n )\n const starkSecret = splitToM31Limbs(starkSpendingHash)\n const starkOwnerHash = computeStarkOwnerHash(starkSecret)\n\n // Derive STARK viewing secret: 8 M31 limbs from a separate keccak256\n const starkViewingHash = keccak256(\n toHex(new TextEncoder().encode(`${seed}:stark:viewing:v${config.version}`))\n )\n const starkViewingSecret = splitToM31Limbs(starkViewingHash)\n const starkViewingHashDigest = computeStarkOwnerHash(starkViewingSecret)\n\n return {\n starkSecret,\n starkOwnerHash,\n starkViewingSecret,\n starkViewingHash: starkViewingHashDigest,\n }\n}\n\n/**\n * Derive both SNARK and STARK keys from a single wallet signature.\n *\n * Same seed, domain-separated derivation. Breaking BJJ (quantum) does NOT\n * compromise STARK keys — keccak preimage resistance provides 2^128 quantum security.\n */\nexport async function deriveDualKeysFromSignature(\n signature: Hex,\n config: KeyDerivationConfig = DEFAULT_KEY_DERIVATION_CONFIG\n): Promise<DualMasterKeys> {\n const snark = await deriveKeysFromSignature(signature, config)\n const stark = deriveStarkKeysFromSignature(signature, config)\n return { snark, stark }\n}\n\n/**\n * Derive a nullifier key from the spending secret\n *\n * nullifier = Poseidon(nullifierKey, leafIndex, commitment)\n */\nexport async function deriveNullifierKey(spendingSecret: bigint): Promise<bigint> {\n const { poseidon } = await import('../utils/poseidon.js')\n return await poseidon([spendingSecret, 0n]) // 0n = nullifier domain\n}\n","/**\n * Per-Transaction Viewing Key Derivation (Post-Quantum, Hash-Based)\n *\n * Implements hierarchical viewing keys using Poseidon hash instead of ECDH.\n *\n * Key Properties:\n * - Per-note decryption key: Poseidon(viewingSecret, nonce)\n * - AES key: keccak256(perNoteKey) for symmetric encryption\n *\n * Derivation:\n * perNoteKey = Poseidon(viewingSecret, nonce)\n * aesKey = keccak256(perNoteKey)\n *\n * SECURITY (v4):\n * Audit exports contain per-note decryption keys derived from viewingSecret + nonce.\n * This prevents master key recovery: knowing Poseidon(viewingSecret, nonce) doesn't\n * reveal viewingSecret due to the one-wayness of Poseidon.\n */\n\nimport type { Address, Hex } from 'viem'\nimport { keccak256, toHex } from 'viem'\nimport type {\n MasterKeys,\n StarkMasterKeys,\n TransactionViewingKey,\n AuditKeyExport,\n} from './types.js'\nimport { keccakM31, type M31Secret } from '../utils/keccak-m31.js'\nimport { bytesToHex } from '../utils/crypto.js'\n\n/**\n * Derive a per-note decryption key from master viewing secret and nonce\n *\n * @param viewingSecret - Master viewing secret\n * @param nonce - Unique per-note nonce\n * @returns Per-note decryption key as hex\n */\nexport async function derivePerNoteKey(\n viewingSecret: bigint,\n nonce: bigint\n): Promise<Hex> {\n const { poseidon } = await import('../utils/poseidon.js')\n const perNoteKey = await poseidon([viewingSecret, nonce])\n return toHex(perNoteKey, { size: 32 })\n}\n\n/**\n * Derive per-note key from MasterKeys convenience wrapper\n */\nexport async function derivePerNoteKeyFromKeys(\n keys: MasterKeys,\n nonce: bigint\n): Promise<Hex> {\n return derivePerNoteKey(keys.viewingSecret, nonce)\n}\n\n/**\n * Note reference for audit export\n */\nexport interface NoteReference {\n /** The Merkle leaf index (for locating the on-chain event) */\n leafIndex: number\n /** The nonce used in per-note key derivation */\n nonce: bigint\n}\n\n/**\n * Export viewing keys for specific notes\n *\n * Creates an export package that can be shared with an auditor.\n * The auditor can use these keys to decrypt the specified notes,\n * but cannot derive keys for other notes.\n *\n * @param keys - Master keys\n * @param signerAddress - The Ethereum address that signed to derive keys\n * @param notes - Array of note references (leafIndex + nonce) to export\n * @returns Audit key export package\n */\nexport async function exportViewingKeysForAudit(\n keys: MasterKeys,\n signerAddress: Address,\n notes: NoteReference[]\n): Promise<AuditKeyExport> {\n const viewingKeys: TransactionViewingKey[] = []\n\n for (const note of notes) {\n // Derive the per-note decryption key\n const decryptionKey = await derivePerNoteKey(keys.viewingSecret, note.nonce)\n\n viewingKeys.push({\n leafIndex: note.leafIndex,\n nonce: note.nonce,\n decryptionKey,\n })\n }\n\n return {\n version: 4,\n signerAddress,\n viewingHash: keys.viewingHash,\n viewingKeys,\n instructions: `\nThis export contains per-note decryption keys for ${viewingKeys.length} UPP note(s).\n\nTo decrypt a note:\n1. Find the viewingKey entry for the desired leafIndex\n2. Retrieve the encrypted note from the blockchain (Shielded event at that leaf index)\n3. Derive AES key: key = keccak256(decryptionKey)\n4. Decrypt the note ciphertext with AES-GCM\n\nThese per-note keys ONLY allow decryption of the specified notes.\nThey do NOT reveal:\n- The master viewing secret (protected by Poseidon one-wayness)\n- Keys for any other notes\n- The spending secret (cannot spend funds)\n `.trim(),\n }\n}\n\n/**\n * Validate an audit key export\n */\nexport function validateAuditKeyExport(\n exportData: AuditKeyExport\n): { valid: boolean; error?: string } {\n if (exportData.version !== 4) {\n return { valid: false, error: `Unsupported version: ${exportData.version}. Expected version 4.` }\n }\n\n if (!exportData.signerAddress || !exportData.signerAddress.startsWith('0x')) {\n return { valid: false, error: 'Invalid signer address' }\n }\n\n if (exportData.viewingHash === undefined || exportData.viewingHash === null) {\n return { valid: false, error: 'Missing viewing hash' }\n }\n\n if (!Array.isArray(exportData.viewingKeys) || exportData.viewingKeys.length === 0) {\n return { valid: false, error: 'No viewing keys in export' }\n }\n\n return { valid: true }\n}\n\n/**\n * Look up a decryption key from an audit export by leaf index\n *\n * Returns the per-note decryption key for direct use in AES-GCM decryption.\n * Derive AES key: keccak256(decryptionKey)\n */\nexport function getViewingKeyFromExport(\n exportData: AuditKeyExport,\n leafIndex: number\n): Hex | null {\n const key = exportData.viewingKeys.find(k => k.leafIndex === leafIndex)\n return key ? key.decryptionKey : null\n}\n\n// =========================================================================\n// STARK Per-Note Viewing Key Derivation (Keccak-based, no elliptic curves)\n// =========================================================================\n\n/**\n * Derive a STARK per-note decryption key from viewing secret and nonce.\n *\n * Uses keccak_m31 instead of Poseidon — purely symmetric, post-quantum safe.\n * The nonce is encoded as a single M31 element appended to the viewing secret.\n *\n * perNoteDigest = keccak_m31(viewingSecret[0..8], nonce)\n * aesKey = keccak256(perNoteDigest_packed_as_16_LE_bytes)\n *\n * @param starkViewingSecret - 8 M31 limbs (the master STARK viewing secret)\n * @param nonce - Per-note nonce (M31 range)\n * @returns 32-byte AES key as hex\n */\nexport function deriveStarkPerNoteKey(\n starkViewingSecret: M31Secret,\n nonce: bigint\n): Hex {\n // keccak_m31(viewingSecret[0..8], nonce) → 4 M31 elements\n const digest = keccakM31([...starkViewingSecret, nonce])\n\n // Pack digest as 16 bytes LE for AES key derivation\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 4; i++) {\n const val = Number(digest[i]!)\n bytes[i * 4] = val & 0xff\n bytes[i * 4 + 1] = (val >> 8) & 0xff\n bytes[i * 4 + 2] = (val >> 16) & 0xff\n bytes[i * 4 + 3] = (val >> 24) & 0xff\n }\n\n // Derive 32-byte AES key via keccak256\n return keccak256(bytesToHex(bytes))\n}\n\n/**\n * Derive STARK per-note key from StarkMasterKeys convenience wrapper\n */\nexport function deriveStarkPerNoteKeyFromKeys(\n keys: StarkMasterKeys,\n nonce: bigint\n): Hex {\n return deriveStarkPerNoteKey(keys.starkViewingSecret, nonce)\n}\n"]}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { init_crypto } from './chunk-UQIM2KT3.js';
|
|
2
|
+
import { init_poseidon, BABYJUBJUB_SUBORDER } from './chunk-5QSSX3KR.js';
|
|
3
|
+
|
|
4
|
+
// src/utils/index.ts
|
|
5
|
+
init_poseidon();
|
|
6
|
+
|
|
7
|
+
// src/utils/babyjubjub.ts
|
|
8
|
+
init_poseidon();
|
|
9
|
+
var babyjubInstance = null;
|
|
10
|
+
async function initBabyJub() {
|
|
11
|
+
if (babyjubInstance === null) {
|
|
12
|
+
const { buildBabyjub } = await import('circomlibjs');
|
|
13
|
+
babyjubInstance = await buildBabyjub();
|
|
14
|
+
}
|
|
15
|
+
return babyjubInstance;
|
|
16
|
+
}
|
|
17
|
+
async function getSubOrder() {
|
|
18
|
+
const babyjub = await initBabyJub();
|
|
19
|
+
return babyjub.subOrder;
|
|
20
|
+
}
|
|
21
|
+
async function getBasePoint() {
|
|
22
|
+
const babyjub = await initBabyJub();
|
|
23
|
+
return {
|
|
24
|
+
x: babyjub.F.toObject(babyjub.Base8[0]),
|
|
25
|
+
y: babyjub.F.toObject(babyjub.Base8[1])
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function isOnCurve(point) {
|
|
29
|
+
const babyjub = await initBabyJub();
|
|
30
|
+
const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)];
|
|
31
|
+
return babyjub.inCurve(internal);
|
|
32
|
+
}
|
|
33
|
+
async function mulPointScalar(point, scalar) {
|
|
34
|
+
const babyjub = await initBabyJub();
|
|
35
|
+
const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)];
|
|
36
|
+
const result = babyjub.mulPointEscalar(internal, scalar);
|
|
37
|
+
return {
|
|
38
|
+
x: babyjub.F.toObject(result[0]),
|
|
39
|
+
y: babyjub.F.toObject(result[1])
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function addPoints(p1, p2) {
|
|
43
|
+
const babyjub = await initBabyJub();
|
|
44
|
+
const internal1 = [babyjub.F.e(p1.x), babyjub.F.e(p1.y)];
|
|
45
|
+
const internal2 = [babyjub.F.e(p2.x), babyjub.F.e(p2.y)];
|
|
46
|
+
const result = babyjub.addPoint(internal1, internal2);
|
|
47
|
+
return {
|
|
48
|
+
x: babyjub.F.toObject(result[0]),
|
|
49
|
+
y: babyjub.F.toObject(result[1])
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function privateToPublic(privateKey) {
|
|
53
|
+
const babyjub = await initBabyJub();
|
|
54
|
+
const scalar = privateKey % babyjub.subOrder;
|
|
55
|
+
const result = babyjub.mulPointEscalar(babyjub.Base8, scalar);
|
|
56
|
+
return {
|
|
57
|
+
x: babyjub.F.toObject(result[0]),
|
|
58
|
+
y: babyjub.F.toObject(result[1])
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function computeSharedSecret(myPrivateKey, theirPublicKey) {
|
|
62
|
+
return mulPointScalar(theirPublicKey, myPrivateKey);
|
|
63
|
+
}
|
|
64
|
+
function packPoint(point) {
|
|
65
|
+
const ySign = point.y % 2n;
|
|
66
|
+
return point.x | ySign << 254n;
|
|
67
|
+
}
|
|
68
|
+
function pointToTuple(point) {
|
|
69
|
+
return [point.x, point.y];
|
|
70
|
+
}
|
|
71
|
+
function tupleToPoint(tuple) {
|
|
72
|
+
return { x: tuple[0], y: tuple[1] };
|
|
73
|
+
}
|
|
74
|
+
async function deriveEncryptionViewingKey(masterViewingPubKey, nonce) {
|
|
75
|
+
const { poseidonScalar: poseidonScalar2 } = await import('./poseidon-ACM7E2OH.js');
|
|
76
|
+
const babyjub = await initBabyJub();
|
|
77
|
+
const scalar = await poseidonScalar2([masterViewingPubKey.x, masterViewingPubKey.y, nonce]);
|
|
78
|
+
const offset = babyjub.mulPointEscalar(babyjub.Base8, scalar);
|
|
79
|
+
const mvkInternal = [
|
|
80
|
+
babyjub.F.e(masterViewingPubKey.x),
|
|
81
|
+
babyjub.F.e(masterViewingPubKey.y)
|
|
82
|
+
];
|
|
83
|
+
const result = babyjub.addPoint(mvkInternal, offset);
|
|
84
|
+
return {
|
|
85
|
+
x: babyjub.F.toObject(result[0]),
|
|
86
|
+
y: babyjub.F.toObject(result[1])
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async function deriveDecryptionViewingKey(masterViewingPrivKey, masterViewingPubKey, nonce) {
|
|
90
|
+
const { poseidonScalar: poseidonScalar2 } = await import('./poseidon-ACM7E2OH.js');
|
|
91
|
+
const scalar = await poseidonScalar2([masterViewingPubKey.x, masterViewingPubKey.y, nonce]);
|
|
92
|
+
return (masterViewingPrivKey + scalar) % BABYJUBJUB_SUBORDER;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/utils/index.ts
|
|
96
|
+
init_crypto();
|
|
97
|
+
|
|
98
|
+
export { addPoints, computeSharedSecret, deriveDecryptionViewingKey, deriveEncryptionViewingKey, getBasePoint, getSubOrder, isOnCurve, mulPointScalar, packPoint, pointToTuple, privateToPublic, tupleToPoint };
|
|
99
|
+
//# sourceMappingURL=chunk-EHGH6TAW.js.map
|
|
100
|
+
//# sourceMappingURL=chunk-EHGH6TAW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/index.ts","../src/utils/babyjubjub.ts"],"names":["poseidonScalar"],"mappings":"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","file":"chunk-EHGH6TAW.js","sourcesContent":["/**\n * Utility functions for UPP SDK\n */\n\n// Poseidon hash\nexport {\n poseidon,\n poseidonHash,\n poseidonScalar,\n FIELD_PRIME,\n BABYJUBJUB_SUBORDER,\n addressToField,\n fieldToAddress,\n isValidFieldElement,\n toFieldElement,\n} from './poseidon.js'\n\n// BabyJubJub curve operations\nexport {\n type Point,\n getSubOrder,\n getBasePoint,\n isOnCurve,\n mulPointScalar,\n addPoints,\n privateToPublic,\n computeSharedSecret,\n packPoint,\n pointToTuple,\n tupleToPoint,\n deriveEncryptionViewingKey,\n deriveDecryptionViewingKey,\n} from './babyjubjub.js'\n\n// Merkle tree\nexport {\n MerkleTree,\n buildMerkleTree,\n getMerkleProof,\n verifyMerkleProof,\n type MerkleProof,\n MAX_TREE_DEPTH,\n} from './merkle.js'\n\n// Crypto utilities\nexport {\n randomBytes,\n randomFieldElement,\n bytesToHex,\n hexToBytes,\n bigintToBytes,\n bytesToBigint,\n} from './crypto.js'\n\n// STARK utilities (amount scaling, witness building, Fiat-Shamir)\nexport {\n STARK_AMOUNT_SCALE,\n STARK_STATE_TREE_DEPTH,\n STARK_ASP_TREE_DEPTH,\n isStarkAligned,\n scaleAmountForStark,\n truncateToM31,\n addressToM31,\n splitSecretToM31Limbs,\n packM31Digest,\n computeWithdrawPublicInputsSeed,\n computeTransferPublicInputsSeed,\n buildStarkWithdrawWitness,\n buildStarkTransferWitness,\n type StarkWithdrawWitness,\n type StarkTransferWitness,\n} from './stark.js'\n\n// Keccak-M31 hashing (STARK)\nexport {\n keccakM31,\n keccakHashTwo,\n computeStarkOwnerHash,\n computeStarkCommitment,\n computeStarkNullifier,\n splitToM31Limbs,\n M31_P,\n DIGEST_SIZE,\n SECRET_LIMBS,\n type M31Digest,\n type M31Secret,\n} from './keccak-m31.js'\n","/**\n * BabyJubJub Elliptic Curve Utilities\n *\n * Wrapper around circomlibjs BabyJubJub implementation.\n * Used for stealth addresses, key derivation, and ECDH.\n *\n * BabyJubJub is a twisted Edwards curve embedded in BN254's scalar field,\n * making it efficient for use in zk-SNARKs.\n */\n\nimport { BABYJUBJUB_SUBORDER } from './poseidon.js'\n\n/**\n * A point on the BabyJubJub curve\n */\nexport interface Point {\n x: bigint\n y: bigint\n}\n\n/**\n * Internal BabyJubJub field type from circomlibjs\n */\ntype BabyJubJubField = {\n e: (val: bigint) => unknown\n toObject: (val: unknown) => bigint\n}\n\n/**\n * BabyJubJub instance type from circomlibjs\n */\ntype BabyJubJub = {\n F: BabyJubJubField\n Base8: [unknown, unknown]\n subOrder: bigint\n mulPointEscalar: (p: [unknown, unknown], scalar: bigint) => [unknown, unknown]\n addPoint: (p1: [unknown, unknown], p2: [unknown, unknown]) => [unknown, unknown]\n inCurve: (p: [unknown, unknown]) => boolean\n}\n\n// Lazily initialized BabyJubJub instance\nlet babyjubInstance: BabyJubJub | null = null\n\n/**\n * Initialize BabyJubJub curve (lazy loading)\n */\nasync function initBabyJub(): Promise<BabyJubJub> {\n if (babyjubInstance === null) {\n const { buildBabyjub } = await import('circomlibjs')\n babyjubInstance = await buildBabyjub() as BabyJubJub\n }\n return babyjubInstance as BabyJubJub\n}\n\n/**\n * Get the BabyJubJub subgroup order\n */\nexport async function getSubOrder(): Promise<bigint> {\n const babyjub = await initBabyJub()\n return babyjub.subOrder\n}\n\n/**\n * Get the generator point (Base8)\n */\nexport async function getBasePoint(): Promise<Point> {\n const babyjub = await initBabyJub()\n return {\n x: babyjub.F.toObject(babyjub.Base8[0]),\n y: babyjub.F.toObject(babyjub.Base8[1]),\n }\n}\n\n/**\n * Check if a point is on the curve\n */\nexport async function isOnCurve(point: Point): Promise<boolean> {\n const babyjub = await initBabyJub()\n const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)] as [unknown, unknown]\n return babyjub.inCurve(internal)\n}\n\n/**\n * Scalar multiplication: point * scalar\n *\n * @param point - Point on the curve\n * @param scalar - Scalar value (mod subOrder)\n * @returns Resulting point\n */\nexport async function mulPointScalar(point: Point, scalar: bigint): Promise<Point> {\n const babyjub = await initBabyJub()\n\n // Convert to internal format\n const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)] as [unknown, unknown]\n\n // Perform scalar multiplication\n const result = babyjub.mulPointEscalar(internal, scalar)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Point addition: p1 + p2\n */\nexport async function addPoints(p1: Point, p2: Point): Promise<Point> {\n const babyjub = await initBabyJub()\n\n // Convert to internal format\n const internal1 = [babyjub.F.e(p1.x), babyjub.F.e(p1.y)] as [unknown, unknown]\n const internal2 = [babyjub.F.e(p2.x), babyjub.F.e(p2.y)] as [unknown, unknown]\n\n // Add points\n const result = babyjub.addPoint(internal1, internal2)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Generate public key from private key\n * pubKey = privateKey * Base8\n *\n * @param privateKey - Private key scalar (must be < subOrder)\n * @returns Public key point\n */\nexport async function privateToPublic(privateKey: bigint): Promise<Point> {\n const babyjub = await initBabyJub()\n\n // Ensure private key is in valid range\n const scalar = privateKey % babyjub.subOrder\n\n // pubKey = scalar * Base8\n const result = babyjub.mulPointEscalar(babyjub.Base8, scalar)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Compute ECDH shared secret\n * sharedSecret = myPrivateKey * theirPublicKey\n *\n * @param myPrivateKey - Your private key\n * @param theirPublicKey - Their public key\n * @returns Shared secret point\n */\nexport async function computeSharedSecret(\n myPrivateKey: bigint,\n theirPublicKey: Point\n): Promise<Point> {\n return mulPointScalar(theirPublicKey, myPrivateKey)\n}\n\n/**\n * Pack a point into a single bigint (compressed form)\n * Uses the x-coordinate and a sign bit for y\n */\nexport function packPoint(point: Point): bigint {\n // Use x-coordinate with y sign bit in high position\n const ySign = point.y % 2n\n return point.x | (ySign << 254n)\n}\n\n/**\n * Convert a point to tuple format [x, y] for use with snarkjs\n */\nexport function pointToTuple(point: Point): [bigint, bigint] {\n return [point.x, point.y]\n}\n\n/**\n * Convert a tuple [x, y] to Point format\n */\nexport function tupleToPoint(tuple: [bigint, bigint]): Point {\n return { x: tuple[0], y: tuple[1] }\n}\n\n// BabyJubJub curve parameters\n// Curve: a*x² + y² = 1 + d*x²*y²\nconst BABYJUBJUB_A = 168700n\nconst BABYJUBJUB_D = 168696n\n// Field prime (BN254 scalar field)\nconst BABYJUBJUB_P = 21888242871839275222246405745257275088548364400416034343698204186575808495617n\n\n/**\n * Modular exponentiation: base^exp mod p\n */\nfunction modPow(base: bigint, exp: bigint, p: bigint): bigint {\n let result = 1n\n base = ((base % p) + p) % p\n while (exp > 0n) {\n if (exp % 2n === 1n) {\n result = (result * base) % p\n }\n exp = exp / 2n\n base = (base * base) % p\n }\n return result\n}\n\n/**\n * Modular inverse using Fermat's little theorem: a^(-1) = a^(p-2) mod p\n */\nfunction modInverse(a: bigint, p: bigint): bigint {\n return modPow(a, p - 2n, p)\n}\n\n/**\n * Tonelli-Shanks algorithm for modular square root\n * Returns sqrt(n) mod p, or null if no square root exists\n */\nfunction modSqrt(n: bigint, p: bigint): bigint | null {\n n = ((n % p) + p) % p\n if (n === 0n) return 0n\n\n // Check if n is a quadratic residue (Euler's criterion)\n if (modPow(n, (p - 1n) / 2n, p) !== 1n) {\n return null // No square root exists\n }\n\n // For p ≡ 3 (mod 4), sqrt(n) = n^((p+1)/4) mod p\n // BN254 scalar field: p ≡ 1 (mod 4), so we need Tonelli-Shanks\n\n // Factor out powers of 2 from p - 1\n let q = p - 1n\n let s = 0n\n while (q % 2n === 0n) {\n q = q / 2n\n s++\n }\n\n // Find a quadratic non-residue\n let z = 2n\n while (modPow(z, (p - 1n) / 2n, p) !== p - 1n) {\n z++\n }\n\n let m = s\n let c = modPow(z, q, p)\n let t = modPow(n, q, p)\n let r = modPow(n, (q + 1n) / 2n, p)\n\n while (true) {\n if (t === 1n) return r\n\n // Find the least i such that t^(2^i) = 1\n let i = 1n\n let temp = (t * t) % p\n while (temp !== 1n) {\n temp = (temp * temp) % p\n i++\n }\n\n // Update values\n const b = modPow(c, modPow(2n, m - i - 1n, p - 1n), p)\n m = i\n c = (b * b) % p\n t = (t * c) % p\n r = (r * b) % p\n }\n}\n\n/**\n * Reconstruct a BabyJubJub point from its x-coordinate\n *\n * BabyJubJub curve equation: a*x² + y² = 1 + d*x²*y²\n * Solving for y²: y² = (1 - a*x²) / (1 - d*x²)\n *\n * Returns the point with the smaller y value (canonical form),\n * or null if x is not on the curve.\n *\n * @param x - The x-coordinate\n * @returns Point with the given x, or null if invalid\n */\nexport async function reconstructPointFromX(x: bigint): Promise<Point | null> {\n const p = BABYJUBJUB_P\n x = ((x % p) + p) % p\n\n // Compute x²\n const x2 = (x * x) % p\n\n // Compute numerator: 1 - a*x²\n const numerator = ((1n - BABYJUBJUB_A * x2) % p + p) % p\n\n // Compute denominator: 1 - d*x²\n const denominator = ((1n - BABYJUBJUB_D * x2) % p + p) % p\n\n if (denominator === 0n) {\n return null // Division by zero\n }\n\n // Compute y² = numerator / denominator\n const y2 = (numerator * modInverse(denominator, p)) % p\n\n // Compute y = sqrt(y²)\n const y = modSqrt(y2, p)\n if (y === null) {\n return null // x is not on the curve\n }\n\n // Return the point with smaller y (canonical form)\n const yAlt = p - y\n const yCanonical = y < yAlt ? y : yAlt\n\n const point = { x, y: yCanonical }\n\n // Verify the point is actually on the curve\n if (!(await isOnCurve(point))) {\n // Try the other y\n const pointAlt = { x, y: y < yAlt ? yAlt : y }\n if (!(await isOnCurve(pointAlt))) {\n return null\n }\n return pointAlt\n }\n\n return point\n}\n\n/**\n * Reconstruct a BabyJubJub point from x-coordinate and y parity bit\n *\n * @param x - The x-coordinate\n * @param yParity - 0 for even y, 1 for odd y\n * @returns Point with matching parity, or null if invalid\n */\nexport async function reconstructPointFromXWithParity(\n x: bigint,\n yParity: 0 | 1\n): Promise<Point | null> {\n const p = BABYJUBJUB_P\n x = ((x % p) + p) % p\n\n const x2 = (x * x) % p\n const numerator = ((1n - BABYJUBJUB_A * x2) % p + p) % p\n const denominator = ((1n - BABYJUBJUB_D * x2) % p + p) % p\n\n if (denominator === 0n) return null\n\n const y2 = (numerator * modInverse(denominator, p)) % p\n const y = modSqrt(y2, p)\n if (y === null) return null\n\n // Select y based on parity\n const actualParity = Number(y % 2n)\n const finalY = actualParity === yParity ? y : p - y\n\n return { x, y: finalY }\n}\n\n/**\n * Derive a per-transaction viewing public key (EVK)\n *\n * EVK = MVK_pub + Poseidon(MVK_pub.x, MVK_pub.y, nonce) * Base8\n *\n * This allows the sender to derive a unique encryption key for each transaction\n * without knowing the recipient's private key.\n *\n * @param masterViewingPubKey - Recipient's master viewing public key\n * @param nonce - Unique per-note nonce (R.x — ephemeral public key x-coordinate)\n * @returns Per-transaction encryption viewing key\n */\nexport async function deriveEncryptionViewingKey(\n masterViewingPubKey: Point,\n nonce: bigint\n): Promise<Point> {\n // Import poseidonScalar to avoid circular dependency\n const { poseidonScalar } = await import('./poseidon.js')\n\n const babyjub = await initBabyJub()\n\n // Compute scalar: Poseidon(MVK_pub.x, MVK_pub.y, nonce) mod subOrder\n const scalar = await poseidonScalar([masterViewingPubKey.x, masterViewingPubKey.y, nonce])\n\n // Compute offset: scalar * Base8\n const offset = babyjub.mulPointEscalar(babyjub.Base8, scalar)\n\n // Convert MVK_pub to internal format\n const mvkInternal = [\n babyjub.F.e(masterViewingPubKey.x),\n babyjub.F.e(masterViewingPubKey.y),\n ] as [unknown, unknown]\n\n // EVK = MVK_pub + offset\n const result = babyjub.addPoint(mvkInternal, offset)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Derive a per-transaction viewing private key (DVK)\n *\n * DVK = MVK_priv + Poseidon(MVK_pub.x, MVK_pub.y, nonce)\n *\n * Only the owner with MVK_priv can compute this.\n * DVK can be shared with auditors to decrypt specific transactions.\n *\n * @param masterViewingPrivKey - Owner's master viewing private key\n * @param masterViewingPubKey - Owner's master viewing public key\n * @param nonce - Unique per-note nonce (R.x — ephemeral public key x-coordinate)\n * @returns Per-transaction decryption viewing key\n */\nexport async function deriveDecryptionViewingKey(\n masterViewingPrivKey: bigint,\n masterViewingPubKey: Point,\n nonce: bigint\n): Promise<bigint> {\n // Import poseidonScalar to avoid circular dependency\n const { poseidonScalar } = await import('./poseidon.js')\n\n // Compute scalar: Poseidon(MVK_pub.x, MVK_pub.y, nonce) mod subOrder\n const scalar = await poseidonScalar([masterViewingPubKey.x, masterViewingPubKey.y, nonce])\n\n // DVK = MVK_priv + scalar (mod subOrder)\n return (masterViewingPrivKey + scalar) % BABYJUBJUB_SUBORDER\n}\n\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { init_poseidon, poseidon } from './chunk-
|
|
1
|
+
import { init_poseidon, poseidon } from './chunk-5QSSX3KR.js';
|
|
2
2
|
|
|
3
3
|
// src/utils/merkle.ts
|
|
4
4
|
init_poseidon();
|
|
@@ -155,5 +155,5 @@ async function verifyMerkleProof(leaf, proof) {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
export { MAX_TREE_DEPTH, MerkleTree, buildMerkleTree, getMerkleProof, verifyMerkleProof };
|
|
158
|
-
//# sourceMappingURL=chunk-
|
|
159
|
-
//# sourceMappingURL=chunk-
|
|
158
|
+
//# sourceMappingURL=chunk-GPF72JFR.js.map
|
|
159
|
+
//# sourceMappingURL=chunk-GPF72JFR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/merkle.ts"],"names":[],"mappings":"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","file":"chunk-ZU6J7KMY.js","sourcesContent":["/**\n * Merkle Tree Utilities\n *\n * Client-side Merkle tree for computing proofs.\n * Compatible with LeanIMT on-chain implementation.\n */\n\nimport { poseidon } from './poseidon.js'\n\n/**\n * Maximum tree depth (matches contract)\n */\nexport const MAX_TREE_DEPTH = 32\n\n/**\n * Merkle proof for a leaf\n */\nexport interface MerkleProof {\n /** Path elements (siblings) */\n pathElements: bigint[]\n /** Path indices (0 = left, 1 = right) */\n pathIndices: number[]\n /** Leaf index in the tree */\n leafIndex: number\n /** Tree root */\n root: bigint\n}\n\n/**\n * LeanIMT-compatible Merkle Tree\n *\n * Features:\n * - Dynamic depth (grows as needed)\n * - Single-child optimization\n * - Async hash operations (Poseidon is async)\n */\nexport class MerkleTree {\n private leaves: bigint[] = []\n private nodes: Map<string, bigint> = new Map() // level:index -> hash\n private cachedRoot: bigint | null = null\n readonly maxDepth: number\n\n constructor(maxDepth: number = MAX_TREE_DEPTH) {\n this.maxDepth = maxDepth\n }\n\n /**\n * Insert a leaf into the tree\n */\n insert(leaf: bigint): number {\n if (leaf === 0n) {\n throw new Error('Leaf cannot be zero')\n }\n const index = this.leaves.length\n this.leaves.push(leaf)\n this.cachedRoot = null // Invalidate cached root\n this.nodes.clear() // Clear cached nodes\n return index\n }\n\n /**\n * Get the number of leaves in the tree\n */\n get size(): number {\n return this.leaves.length\n }\n\n /**\n * Get the current depth of the tree\n * LeanIMT: depth grows when 2^depth < size\n */\n get depth(): number {\n if (this.leaves.length <= 1) return 0\n return Math.ceil(Math.log2(this.leaves.length))\n }\n\n /**\n * Check if a leaf exists in the tree\n */\n has(leaf: bigint): boolean {\n return this.leaves.includes(leaf)\n }\n\n /**\n * Get the index of a leaf\n */\n indexOf(leaf: bigint): number {\n return this.leaves.indexOf(leaf)\n }\n\n /**\n * Get the current root (async because of Poseidon)\n */\n async getRoot(): Promise<bigint> {\n if (this.leaves.length === 0) {\n return 0n\n }\n if (this.cachedRoot !== null) {\n return this.cachedRoot\n }\n this.cachedRoot = await this.computeRoot()\n return this.cachedRoot\n }\n\n /**\n * Get a Merkle proof for a leaf at index\n */\n async getProof(index: number): Promise<MerkleProof> {\n if (index < 0 || index >= this.leaves.length) {\n throw new Error(`Leaf index ${index} out of bounds (size: ${this.leaves.length})`)\n }\n\n const pathElements: bigint[] = []\n const pathIndices: number[] = []\n const treeDepth = this.depth\n\n let currentIndex = index\n\n for (let level = 0; level < treeDepth; level++) {\n const siblingIndex = currentIndex ^ 1 // XOR to get sibling\n const isLeft = currentIndex % 2 === 0\n\n // Get sibling hash\n const sibling = await this.getNodeHash(level, siblingIndex)\n pathElements.push(sibling)\n pathIndices.push(isLeft ? 0 : 1)\n\n // Move to parent\n currentIndex = Math.floor(currentIndex / 2)\n }\n\n return {\n pathElements,\n pathIndices,\n leafIndex: index,\n root: await this.getRoot(),\n }\n }\n\n /**\n * Get the hash of a node at (level, index)\n * level 0 = leaves, higher levels are internal nodes\n */\n private async getNodeHash(level: number, index: number): Promise<bigint> {\n const key = `${level}:${index}`\n if (this.nodes.has(key)) {\n return this.nodes.get(key)!\n }\n\n let hash: bigint\n\n if (level === 0) {\n // Leaf level\n hash = index < this.leaves.length ? this.leaves[index]! : 0n\n } else {\n // Internal node: hash of children\n const leftChild = await this.getNodeHash(level - 1, index * 2)\n const rightChild = await this.getNodeHash(level - 1, index * 2 + 1)\n\n if (leftChild === 0n && rightChild === 0n) {\n hash = 0n\n } else if (rightChild === 0n) {\n // LeanIMT optimization: single child\n hash = leftChild\n } else {\n hash = await poseidon([leftChild, rightChild])\n }\n }\n\n this.nodes.set(key, hash)\n return hash\n }\n\n /**\n * Compute the root hash\n */\n private async computeRoot(): Promise<bigint> {\n if (this.leaves.length === 0) return 0n\n if (this.leaves.length === 1) return this.leaves[0]!\n\n const treeDepth = this.depth\n return await this.getNodeHash(treeDepth, 0)\n }\n}\n\n/**\n * Build a Merkle tree from an array of leaves\n */\nexport function buildMerkleTree(leaves: bigint[]): MerkleTree {\n const tree = new MerkleTree()\n for (const leaf of leaves) {\n tree.insert(leaf)\n }\n return tree\n}\n\n/**\n * Get a Merkle proof for a specific leaf (async)\n */\nexport async function getMerkleProof(\n leaves: bigint[],\n index: number\n): Promise<MerkleProof> {\n const tree = buildMerkleTree(leaves)\n return tree.getProof(index)\n}\n\n/**\n * Verify a Merkle proof (async)\n */\nexport async function verifyMerkleProof(\n leaf: bigint,\n proof: MerkleProof\n): Promise<boolean> {\n let current = leaf\n\n for (let i = 0; i < proof.pathElements.length; i++) {\n const sibling = proof.pathElements[i]!\n const isLeft = proof.pathIndices[i] === 0\n\n if (sibling === 0n) {\n // LeanIMT: missing sibling means we just propagate\n continue\n }\n\n if (isLeft) {\n current = await poseidon([current, sibling])\n } else {\n current = await poseidon([sibling, current])\n }\n }\n\n return current === proof.root\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/merkle.ts"],"names":[],"mappings":"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","file":"chunk-GPF72JFR.js","sourcesContent":["/**\n * Merkle Tree Utilities\n *\n * Client-side Merkle tree for computing proofs.\n * Compatible with LeanIMT on-chain implementation.\n */\n\nimport { poseidon } from './poseidon.js'\n\n/**\n * Maximum tree depth (matches contract)\n */\nexport const MAX_TREE_DEPTH = 32\n\n/**\n * Merkle proof for a leaf\n */\nexport interface MerkleProof {\n /** Path elements (siblings) */\n pathElements: bigint[]\n /** Path indices (0 = left, 1 = right) */\n pathIndices: number[]\n /** Leaf index in the tree */\n leafIndex: number\n /** Tree root */\n root: bigint\n}\n\n/**\n * LeanIMT-compatible Merkle Tree\n *\n * Features:\n * - Dynamic depth (grows as needed)\n * - Single-child optimization\n * - Async hash operations (Poseidon is async)\n */\nexport class MerkleTree {\n private leaves: bigint[] = []\n private nodes: Map<string, bigint> = new Map() // level:index -> hash\n private cachedRoot: bigint | null = null\n readonly maxDepth: number\n\n constructor(maxDepth: number = MAX_TREE_DEPTH) {\n this.maxDepth = maxDepth\n }\n\n /**\n * Insert a leaf into the tree\n */\n insert(leaf: bigint): number {\n if (leaf === 0n) {\n throw new Error('Leaf cannot be zero')\n }\n const index = this.leaves.length\n this.leaves.push(leaf)\n this.cachedRoot = null // Invalidate cached root\n this.nodes.clear() // Clear cached nodes\n return index\n }\n\n /**\n * Get the number of leaves in the tree\n */\n get size(): number {\n return this.leaves.length\n }\n\n /**\n * Get the current depth of the tree\n * LeanIMT: depth grows when 2^depth < size\n */\n get depth(): number {\n if (this.leaves.length <= 1) return 0\n return Math.ceil(Math.log2(this.leaves.length))\n }\n\n /**\n * Check if a leaf exists in the tree\n */\n has(leaf: bigint): boolean {\n return this.leaves.includes(leaf)\n }\n\n /**\n * Get the index of a leaf\n */\n indexOf(leaf: bigint): number {\n return this.leaves.indexOf(leaf)\n }\n\n /**\n * Get the current root (async because of Poseidon)\n */\n async getRoot(): Promise<bigint> {\n if (this.leaves.length === 0) {\n return 0n\n }\n if (this.cachedRoot !== null) {\n return this.cachedRoot\n }\n this.cachedRoot = await this.computeRoot()\n return this.cachedRoot\n }\n\n /**\n * Get a Merkle proof for a leaf at index\n */\n async getProof(index: number): Promise<MerkleProof> {\n if (index < 0 || index >= this.leaves.length) {\n throw new Error(`Leaf index ${index} out of bounds (size: ${this.leaves.length})`)\n }\n\n const pathElements: bigint[] = []\n const pathIndices: number[] = []\n const treeDepth = this.depth\n\n let currentIndex = index\n\n for (let level = 0; level < treeDepth; level++) {\n const siblingIndex = currentIndex ^ 1 // XOR to get sibling\n const isLeft = currentIndex % 2 === 0\n\n // Get sibling hash\n const sibling = await this.getNodeHash(level, siblingIndex)\n pathElements.push(sibling)\n pathIndices.push(isLeft ? 0 : 1)\n\n // Move to parent\n currentIndex = Math.floor(currentIndex / 2)\n }\n\n return {\n pathElements,\n pathIndices,\n leafIndex: index,\n root: await this.getRoot(),\n }\n }\n\n /**\n * Get the hash of a node at (level, index)\n * level 0 = leaves, higher levels are internal nodes\n */\n private async getNodeHash(level: number, index: number): Promise<bigint> {\n const key = `${level}:${index}`\n if (this.nodes.has(key)) {\n return this.nodes.get(key)!\n }\n\n let hash: bigint\n\n if (level === 0) {\n // Leaf level\n hash = index < this.leaves.length ? this.leaves[index]! : 0n\n } else {\n // Internal node: hash of children\n const leftChild = await this.getNodeHash(level - 1, index * 2)\n const rightChild = await this.getNodeHash(level - 1, index * 2 + 1)\n\n if (leftChild === 0n && rightChild === 0n) {\n hash = 0n\n } else if (rightChild === 0n) {\n // LeanIMT optimization: single child\n hash = leftChild\n } else {\n hash = await poseidon([leftChild, rightChild])\n }\n }\n\n this.nodes.set(key, hash)\n return hash\n }\n\n /**\n * Compute the root hash\n */\n private async computeRoot(): Promise<bigint> {\n if (this.leaves.length === 0) return 0n\n if (this.leaves.length === 1) return this.leaves[0]!\n\n const treeDepth = this.depth\n return await this.getNodeHash(treeDepth, 0)\n }\n}\n\n/**\n * Build a Merkle tree from an array of leaves\n */\nexport function buildMerkleTree(leaves: bigint[]): MerkleTree {\n const tree = new MerkleTree()\n for (const leaf of leaves) {\n tree.insert(leaf)\n }\n return tree\n}\n\n/**\n * Get a Merkle proof for a specific leaf (async)\n */\nexport async function getMerkleProof(\n leaves: bigint[],\n index: number\n): Promise<MerkleProof> {\n const tree = buildMerkleTree(leaves)\n return tree.getProof(index)\n}\n\n/**\n * Verify a Merkle proof (async)\n */\nexport async function verifyMerkleProof(\n leaf: bigint,\n proof: MerkleProof\n): Promise<boolean> {\n let current = leaf\n\n for (let i = 0; i < proof.pathElements.length; i++) {\n const sibling = proof.pathElements[i]!\n const isLeft = proof.pathIndices[i] === 0\n\n if (sibling === 0n) {\n // LeanIMT: missing sibling means we just propagate\n continue\n }\n\n if (isLeft) {\n current = await poseidon([current, sibling])\n } else {\n current = await poseidon([sibling, current])\n }\n }\n\n return current === proof.root\n}\n"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkG7VZBCD6_cjs = require('./chunk-G7VZBCD6.cjs');
|
|
4
|
+
var poseidonBls12381 = require('poseidon-bls12381');
|
|
5
|
+
|
|
6
|
+
async function poseidon(inputs) {
|
|
7
|
+
return poseidonSync(inputs);
|
|
8
|
+
}
|
|
9
|
+
function poseidonSync(inputs) {
|
|
10
|
+
const fn = POSEIDON_FNS[inputs.length];
|
|
11
|
+
if (!fn) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`Poseidon: unsupported arity ${inputs.length}. Supported: 1-6.`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return fn(inputs);
|
|
17
|
+
}
|
|
18
|
+
async function poseidonHash(inputs) {
|
|
19
|
+
const hash = poseidonSync(inputs);
|
|
20
|
+
return `0x${hash.toString(16).padStart(64, "0")}`;
|
|
21
|
+
}
|
|
22
|
+
async function poseidonScalar(inputs) {
|
|
23
|
+
const hash = poseidonSync(inputs);
|
|
24
|
+
return hash % exports.BABYJUBJUB_SUBORDER;
|
|
25
|
+
}
|
|
26
|
+
function addressToField(address) {
|
|
27
|
+
return BigInt(address);
|
|
28
|
+
}
|
|
29
|
+
function fieldToAddress(field) {
|
|
30
|
+
const masked = field & (1n << 160n) - 1n;
|
|
31
|
+
return `0x${masked.toString(16).padStart(40, "0")}`;
|
|
32
|
+
}
|
|
33
|
+
function isValidFieldElement(value) {
|
|
34
|
+
return value >= 0n && value < exports.FIELD_PRIME;
|
|
35
|
+
}
|
|
36
|
+
function toFieldElement(value) {
|
|
37
|
+
return (value % exports.FIELD_PRIME + exports.FIELD_PRIME) % exports.FIELD_PRIME;
|
|
38
|
+
}
|
|
39
|
+
function computeOwnerHash(secret) {
|
|
40
|
+
return poseidonSync([secret]);
|
|
41
|
+
}
|
|
42
|
+
function computeNoteCommitment(amount, ownerHash, blinding, origin, token) {
|
|
43
|
+
return poseidonSync([amount, ownerHash, blinding, origin, token]);
|
|
44
|
+
}
|
|
45
|
+
function computeNullifier(oneTimeSecret, leafIndex, commitment) {
|
|
46
|
+
return poseidonSync([oneTimeSecret, leafIndex, commitment]);
|
|
47
|
+
}
|
|
48
|
+
exports.FIELD_PRIME = void 0; exports.BABYJUBJUB_SUBORDER = void 0; var POSEIDON_FNS;
|
|
49
|
+
var init_poseidon = chunkG7VZBCD6_cjs.__esm({
|
|
50
|
+
"src/utils/poseidon.ts"() {
|
|
51
|
+
exports.FIELD_PRIME = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n;
|
|
52
|
+
exports.BABYJUBJUB_SUBORDER = 2736030358979909402780800718157159386076813972158567259200215660948447373041n;
|
|
53
|
+
POSEIDON_FNS = {
|
|
54
|
+
1: poseidonBls12381.poseidon1,
|
|
55
|
+
2: poseidonBls12381.poseidon2,
|
|
56
|
+
3: poseidonBls12381.poseidon3,
|
|
57
|
+
4: poseidonBls12381.poseidon4,
|
|
58
|
+
5: poseidonBls12381.poseidon5,
|
|
59
|
+
6: poseidonBls12381.poseidon6
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
exports.addressToField = addressToField;
|
|
65
|
+
exports.computeNoteCommitment = computeNoteCommitment;
|
|
66
|
+
exports.computeNullifier = computeNullifier;
|
|
67
|
+
exports.computeOwnerHash = computeOwnerHash;
|
|
68
|
+
exports.fieldToAddress = fieldToAddress;
|
|
69
|
+
exports.init_poseidon = init_poseidon;
|
|
70
|
+
exports.isValidFieldElement = isValidFieldElement;
|
|
71
|
+
exports.poseidon = poseidon;
|
|
72
|
+
exports.poseidonHash = poseidonHash;
|
|
73
|
+
exports.poseidonScalar = poseidonScalar;
|
|
74
|
+
exports.poseidonSync = poseidonSync;
|
|
75
|
+
exports.toFieldElement = toFieldElement;
|
|
76
|
+
//# sourceMappingURL=chunk-HEHXSV47.cjs.map
|
|
77
|
+
//# sourceMappingURL=chunk-HEHXSV47.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/poseidon.ts"],"names":["BABYJUBJUB_SUBORDER","FIELD_PRIME","__esm","poseidon1","poseidon2","poseidon3","poseidon4","poseidon5","poseidon6"],"mappings":";;;;;AAoEA,eAAsB,SAAS,MAAA,EAAmC;AAChE,EAAA,OAAO,aAAa,MAAM,CAAA;AAC5B;AAKO,SAAS,aAAa,MAAA,EAA0B;AACrD,EAAA,MAAM,EAAA,GAAK,YAAA,CAAa,MAAA,CAAO,MAAM,CAAA;AACrC,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,4BAAA,EAA+B,OAAO,MAAM,CAAA,iBAAA;AAAA,KAC9C;AAAA,EACF;AACA,EAAA,OAAO,GAAG,MAAM,CAAA;AAClB;AAKA,eAAsB,aAAa,MAAA,EAA0C;AAC3E,EAAA,MAAM,IAAA,GAAO,aAAa,MAAM,CAAA;AAChC,EAAA,OAAO,CAAA,EAAA,EAAK,KAAK,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,EAAA,EAAI,GAAG,CAAC,CAAA,CAAA;AACjD;AAQA,eAAsB,eAAe,MAAA,EAAmC;AACtE,EAAA,MAAM,IAAA,GAAO,aAAa,MAAM,CAAA;AAChC,EAAA,OAAO,IAAA,GAAOA,2BAAA;AAChB;AAKO,SAAS,eAAe,OAAA,EAAgC;AAC7D,EAAA,OAAO,OAAO,OAAO,CAAA;AACvB;AAKO,SAAS,eAAe,KAAA,EAA8B;AAE3D,EAAA,MAAM,MAAA,GAAS,KAAA,GAAA,CAAU,EAAA,IAAM,IAAA,IAAQ,EAAA;AACvC,EAAA,OAAO,CAAA,EAAA,EAAK,OAAO,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,EAAA,EAAI,GAAG,CAAC,CAAA,CAAA;AACnD;AAKO,SAAS,oBAAoB,KAAA,EAAwB;AAC1D,EAAA,OAAO,KAAA,IAAS,MAAM,KAAA,GAAQC,mBAAA;AAChC;AAKO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,OAAA,CAAS,KAAA,GAAQA,sBAAeA,mBAAA,IAAeA,mBAAA;AACjD;AASO,SAAS,iBAAiB,MAAA,EAAwB;AACvD,EAAA,OAAO,YAAA,CAAa,CAAC,MAAM,CAAC,CAAA;AAC9B;AASO,SAAS,qBAAA,CACd,MAAA,EACA,SAAA,EACA,QAAA,EACA,QACA,KAAA,EACQ;AACR,EAAA,OAAO,aAAa,CAAC,MAAA,EAAQ,WAAW,QAAA,EAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAClE;AAOO,SAAS,gBAAA,CACd,aAAA,EACA,SAAA,EACA,UAAA,EACQ;AACR,EAAA,OAAO,YAAA,CAAa,CAAC,aAAA,EAAe,SAAA,EAAW,UAAU,CAAC,CAAA;AAC5D;AAjJaA,8BAOAD,oCAAA,CAAA,KAGP;AAtCN,IAAA,aAAA,GAAAE,uBAAA,CAAA;AAAA,EAAA,uBAAA,GAAA;AA4BO,IAAMD,mBAAA,GAAc,mEAAA;AAOpB,IAAMD,2BAAA,GAAsB,6EAAA;AAGnC,IAAM,YAAA,GAA6D;AAAA,MACjE,CAAA,EAAGG,0BAAA;AAAA,MACH,CAAA,EAAGC,0BAAA;AAAA,MACH,CAAA,EAAGC,0BAAA;AAAA,MACH,CAAA,EAAGC,0BAAA;AAAA,MACH,CAAA,EAAGC,0BAAA;AAAA,MACH,CAAA,EAAGC;AAAA,KACL;AAAA,EAAA;AAAA,CAAA","file":"chunk-HEHXSV47.cjs","sourcesContent":["/**\n * Poseidon Hash Utilities (BLS12-381)\n *\n * Poseidon hash over the BLS12-381 scalar field (128-bit security).\n * Uses the poseidon-bls12381 package for hash computation.\n *\n * This replaces the previous circomlibjs BN254 Poseidon implementation.\n * The BLS12-381 field provides 128-bit security (vs ~100-bit for BN254),\n * meeting the NIST 128-bit minimum standard.\n */\n\nimport {\n poseidon1,\n poseidon2,\n poseidon3,\n poseidon4,\n poseidon5,\n poseidon6,\n} from 'poseidon-bls12381'\n\n/**\n * BLS12-381 scalar field prime (Fr)\n *\n * r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001\n * = 52435875175126190479447740508185965837690552500527637822603658699938581184513\n *\n * This is ~255 bits, providing 128-bit security.\n */\nexport const FIELD_PRIME = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n\n\n/**\n * @deprecated BabyJubJub is no longer used in BLS12-381 circuits.\n * Hash-based ownership (ownerHash = Poseidon(secret)) replaces curve operations.\n * Kept temporarily for backward compatibility with off-chain stealth address code.\n */\nexport const BABYJUBJUB_SUBORDER = 2736030358979909402780800718157159386076813972158567259200215660948447373041n\n\n// Arity-indexed Poseidon functions for BLS12-381\nconst POSEIDON_FNS: Record<number, (inputs: bigint[]) => bigint> = {\n 1: poseidon1,\n 2: poseidon2,\n 3: poseidon3,\n 4: poseidon4,\n 5: poseidon5,\n 6: poseidon6,\n}\n\n/**\n * Compute Poseidon hash over BLS12-381 scalar field\n *\n * Synchronous — no initialization needed (unlike circomlibjs).\n * The async signature is preserved for backward compatibility.\n *\n * @param inputs - Array of field elements to hash (1-6 elements)\n * @returns Hash as bigint in BLS12-381 scalar field\n *\n * @example\n * ```ts\n * // Note commitment (5 inputs)\n * const commitment = await poseidon([amount, ownerHash, blinding, origin, token])\n *\n * // Nullifier (3 inputs)\n * const nullifier = await poseidon([oneTimeSecret, leafIndex, commitment])\n *\n * // Owner hash (1 input)\n * const ownerHash = await poseidon([oneTimeSecret])\n * ```\n */\nexport async function poseidon(inputs: bigint[]): Promise<bigint> {\n return poseidonSync(inputs)\n}\n\n/**\n * Synchronous Poseidon hash (preferred for new code)\n */\nexport function poseidonSync(inputs: bigint[]): bigint {\n const fn = POSEIDON_FNS[inputs.length]\n if (!fn) {\n throw new Error(\n `Poseidon: unsupported arity ${inputs.length}. Supported: 1-6.`\n )\n }\n return fn(inputs)\n}\n\n/**\n * Compute Poseidon hash and return as hex string\n */\nexport async function poseidonHash(inputs: bigint[]): Promise<`0x${string}`> {\n const hash = poseidonSync(inputs)\n return `0x${hash.toString(16).padStart(64, '0')}`\n}\n\n/**\n * @deprecated BabyJubJub scalars are no longer used. Use poseidon() directly.\n *\n * Compute Poseidon hash modulo BabyJubJub suborder.\n * Kept for backward compatibility with off-chain stealth address code.\n */\nexport async function poseidonScalar(inputs: bigint[]): Promise<bigint> {\n const hash = poseidonSync(inputs)\n return hash % BABYJUBJUB_SUBORDER\n}\n\n/**\n * Convert an address to a field element\n */\nexport function addressToField(address: `0x${string}`): bigint {\n return BigInt(address)\n}\n\n/**\n * Convert a field element to an address (20 bytes)\n */\nexport function fieldToAddress(field: bigint): `0x${string}` {\n // Mask to 160 bits (20 bytes) for address\n const masked = field & ((1n << 160n) - 1n)\n return `0x${masked.toString(16).padStart(40, '0')}`\n}\n\n/**\n * Check if a value is within the BLS12-381 scalar field\n */\nexport function isValidFieldElement(value: bigint): boolean {\n return value >= 0n && value < FIELD_PRIME\n}\n\n/**\n * Reduce a value modulo BLS12-381 field prime\n */\nexport function toFieldElement(value: bigint): bigint {\n return ((value % FIELD_PRIME) + FIELD_PRIME) % FIELD_PRIME\n}\n\n/**\n * Compute owner hash from spending secret\n *\n * ownerHash = Poseidon(secret)\n *\n * This replaces BabyJubJub DerivePublicKey for circuit ownership proofs.\n */\nexport function computeOwnerHash(secret: bigint): bigint {\n return poseidonSync([secret])\n}\n\n/**\n * Compute note commitment (BLS12-381)\n *\n * commitment = Poseidon(amount, ownerHash, blinding, origin, token)\n *\n * 5-input format (replaces old 6-input format with pubkeyX/pubkeyY).\n */\nexport function computeNoteCommitment(\n amount: bigint,\n ownerHash: bigint,\n blinding: bigint,\n origin: bigint,\n token: bigint\n): bigint {\n return poseidonSync([amount, ownerHash, blinding, origin, token])\n}\n\n/**\n * Compute nullifier for a note\n *\n * nullifier = Poseidon(oneTimeSecret, leafIndex, commitment)\n */\nexport function computeNullifier(\n oneTimeSecret: bigint,\n leafIndex: bigint,\n commitment: bigint\n): bigint {\n return poseidonSync([oneTimeSecret, leafIndex, commitment])\n}\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkUFEDJJSH_cjs = require('./chunk-UFEDJJSH.cjs');
|
|
4
|
+
var chunkHEHXSV47_cjs = require('./chunk-HEHXSV47.cjs');
|
|
5
|
+
|
|
6
|
+
// src/utils/index.ts
|
|
7
|
+
chunkHEHXSV47_cjs.init_poseidon();
|
|
8
|
+
|
|
9
|
+
// src/utils/babyjubjub.ts
|
|
10
|
+
chunkHEHXSV47_cjs.init_poseidon();
|
|
11
|
+
var babyjubInstance = null;
|
|
12
|
+
async function initBabyJub() {
|
|
13
|
+
if (babyjubInstance === null) {
|
|
14
|
+
const { buildBabyjub } = await import('circomlibjs');
|
|
15
|
+
babyjubInstance = await buildBabyjub();
|
|
16
|
+
}
|
|
17
|
+
return babyjubInstance;
|
|
18
|
+
}
|
|
19
|
+
async function getSubOrder() {
|
|
20
|
+
const babyjub = await initBabyJub();
|
|
21
|
+
return babyjub.subOrder;
|
|
22
|
+
}
|
|
23
|
+
async function getBasePoint() {
|
|
24
|
+
const babyjub = await initBabyJub();
|
|
25
|
+
return {
|
|
26
|
+
x: babyjub.F.toObject(babyjub.Base8[0]),
|
|
27
|
+
y: babyjub.F.toObject(babyjub.Base8[1])
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function isOnCurve(point) {
|
|
31
|
+
const babyjub = await initBabyJub();
|
|
32
|
+
const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)];
|
|
33
|
+
return babyjub.inCurve(internal);
|
|
34
|
+
}
|
|
35
|
+
async function mulPointScalar(point, scalar) {
|
|
36
|
+
const babyjub = await initBabyJub();
|
|
37
|
+
const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)];
|
|
38
|
+
const result = babyjub.mulPointEscalar(internal, scalar);
|
|
39
|
+
return {
|
|
40
|
+
x: babyjub.F.toObject(result[0]),
|
|
41
|
+
y: babyjub.F.toObject(result[1])
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async function addPoints(p1, p2) {
|
|
45
|
+
const babyjub = await initBabyJub();
|
|
46
|
+
const internal1 = [babyjub.F.e(p1.x), babyjub.F.e(p1.y)];
|
|
47
|
+
const internal2 = [babyjub.F.e(p2.x), babyjub.F.e(p2.y)];
|
|
48
|
+
const result = babyjub.addPoint(internal1, internal2);
|
|
49
|
+
return {
|
|
50
|
+
x: babyjub.F.toObject(result[0]),
|
|
51
|
+
y: babyjub.F.toObject(result[1])
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function privateToPublic(privateKey) {
|
|
55
|
+
const babyjub = await initBabyJub();
|
|
56
|
+
const scalar = privateKey % babyjub.subOrder;
|
|
57
|
+
const result = babyjub.mulPointEscalar(babyjub.Base8, scalar);
|
|
58
|
+
return {
|
|
59
|
+
x: babyjub.F.toObject(result[0]),
|
|
60
|
+
y: babyjub.F.toObject(result[1])
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function computeSharedSecret(myPrivateKey, theirPublicKey) {
|
|
64
|
+
return mulPointScalar(theirPublicKey, myPrivateKey);
|
|
65
|
+
}
|
|
66
|
+
function packPoint(point) {
|
|
67
|
+
const ySign = point.y % 2n;
|
|
68
|
+
return point.x | ySign << 254n;
|
|
69
|
+
}
|
|
70
|
+
function pointToTuple(point) {
|
|
71
|
+
return [point.x, point.y];
|
|
72
|
+
}
|
|
73
|
+
function tupleToPoint(tuple) {
|
|
74
|
+
return { x: tuple[0], y: tuple[1] };
|
|
75
|
+
}
|
|
76
|
+
async function deriveEncryptionViewingKey(masterViewingPubKey, nonce) {
|
|
77
|
+
const { poseidonScalar: poseidonScalar2 } = await import('./poseidon-PUSGUIVZ.cjs');
|
|
78
|
+
const babyjub = await initBabyJub();
|
|
79
|
+
const scalar = await poseidonScalar2([masterViewingPubKey.x, masterViewingPubKey.y, nonce]);
|
|
80
|
+
const offset = babyjub.mulPointEscalar(babyjub.Base8, scalar);
|
|
81
|
+
const mvkInternal = [
|
|
82
|
+
babyjub.F.e(masterViewingPubKey.x),
|
|
83
|
+
babyjub.F.e(masterViewingPubKey.y)
|
|
84
|
+
];
|
|
85
|
+
const result = babyjub.addPoint(mvkInternal, offset);
|
|
86
|
+
return {
|
|
87
|
+
x: babyjub.F.toObject(result[0]),
|
|
88
|
+
y: babyjub.F.toObject(result[1])
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async function deriveDecryptionViewingKey(masterViewingPrivKey, masterViewingPubKey, nonce) {
|
|
92
|
+
const { poseidonScalar: poseidonScalar2 } = await import('./poseidon-PUSGUIVZ.cjs');
|
|
93
|
+
const scalar = await poseidonScalar2([masterViewingPubKey.x, masterViewingPubKey.y, nonce]);
|
|
94
|
+
return (masterViewingPrivKey + scalar) % chunkHEHXSV47_cjs.BABYJUBJUB_SUBORDER;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/utils/index.ts
|
|
98
|
+
chunkUFEDJJSH_cjs.init_crypto();
|
|
99
|
+
|
|
100
|
+
exports.addPoints = addPoints;
|
|
101
|
+
exports.computeSharedSecret = computeSharedSecret;
|
|
102
|
+
exports.deriveDecryptionViewingKey = deriveDecryptionViewingKey;
|
|
103
|
+
exports.deriveEncryptionViewingKey = deriveEncryptionViewingKey;
|
|
104
|
+
exports.getBasePoint = getBasePoint;
|
|
105
|
+
exports.getSubOrder = getSubOrder;
|
|
106
|
+
exports.isOnCurve = isOnCurve;
|
|
107
|
+
exports.mulPointScalar = mulPointScalar;
|
|
108
|
+
exports.packPoint = packPoint;
|
|
109
|
+
exports.pointToTuple = pointToTuple;
|
|
110
|
+
exports.privateToPublic = privateToPublic;
|
|
111
|
+
exports.tupleToPoint = tupleToPoint;
|
|
112
|
+
//# sourceMappingURL=chunk-I5EKGD4P.cjs.map
|
|
113
|
+
//# sourceMappingURL=chunk-I5EKGD4P.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/index.ts","../src/utils/babyjubjub.ts"],"names":["init_poseidon","poseidonScalar","BABYJUBJUB_SUBORDER","init_crypto"],"mappings":"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","file":"chunk-I5EKGD4P.cjs","sourcesContent":["/**\n * Utility functions for UPP SDK\n */\n\n// Poseidon hash\nexport {\n poseidon,\n poseidonHash,\n poseidonScalar,\n FIELD_PRIME,\n BABYJUBJUB_SUBORDER,\n addressToField,\n fieldToAddress,\n isValidFieldElement,\n toFieldElement,\n} from './poseidon.js'\n\n// BabyJubJub curve operations\nexport {\n type Point,\n getSubOrder,\n getBasePoint,\n isOnCurve,\n mulPointScalar,\n addPoints,\n privateToPublic,\n computeSharedSecret,\n packPoint,\n pointToTuple,\n tupleToPoint,\n deriveEncryptionViewingKey,\n deriveDecryptionViewingKey,\n} from './babyjubjub.js'\n\n// Merkle tree\nexport {\n MerkleTree,\n buildMerkleTree,\n getMerkleProof,\n verifyMerkleProof,\n type MerkleProof,\n MAX_TREE_DEPTH,\n} from './merkle.js'\n\n// Crypto utilities\nexport {\n randomBytes,\n randomFieldElement,\n bytesToHex,\n hexToBytes,\n bigintToBytes,\n bytesToBigint,\n} from './crypto.js'\n\n// STARK utilities (amount scaling, witness building, Fiat-Shamir)\nexport {\n STARK_AMOUNT_SCALE,\n STARK_STATE_TREE_DEPTH,\n STARK_ASP_TREE_DEPTH,\n isStarkAligned,\n scaleAmountForStark,\n truncateToM31,\n addressToM31,\n splitSecretToM31Limbs,\n packM31Digest,\n computeWithdrawPublicInputsSeed,\n computeTransferPublicInputsSeed,\n buildStarkWithdrawWitness,\n buildStarkTransferWitness,\n type StarkWithdrawWitness,\n type StarkTransferWitness,\n} from './stark.js'\n\n// Keccak-M31 hashing (STARK)\nexport {\n keccakM31,\n keccakHashTwo,\n computeStarkOwnerHash,\n computeStarkCommitment,\n computeStarkNullifier,\n splitToM31Limbs,\n M31_P,\n DIGEST_SIZE,\n SECRET_LIMBS,\n type M31Digest,\n type M31Secret,\n} from './keccak-m31.js'\n","/**\n * BabyJubJub Elliptic Curve Utilities\n *\n * Wrapper around circomlibjs BabyJubJub implementation.\n * Used for stealth addresses, key derivation, and ECDH.\n *\n * BabyJubJub is a twisted Edwards curve embedded in BN254's scalar field,\n * making it efficient for use in zk-SNARKs.\n */\n\nimport { BABYJUBJUB_SUBORDER } from './poseidon.js'\n\n/**\n * A point on the BabyJubJub curve\n */\nexport interface Point {\n x: bigint\n y: bigint\n}\n\n/**\n * Internal BabyJubJub field type from circomlibjs\n */\ntype BabyJubJubField = {\n e: (val: bigint) => unknown\n toObject: (val: unknown) => bigint\n}\n\n/**\n * BabyJubJub instance type from circomlibjs\n */\ntype BabyJubJub = {\n F: BabyJubJubField\n Base8: [unknown, unknown]\n subOrder: bigint\n mulPointEscalar: (p: [unknown, unknown], scalar: bigint) => [unknown, unknown]\n addPoint: (p1: [unknown, unknown], p2: [unknown, unknown]) => [unknown, unknown]\n inCurve: (p: [unknown, unknown]) => boolean\n}\n\n// Lazily initialized BabyJubJub instance\nlet babyjubInstance: BabyJubJub | null = null\n\n/**\n * Initialize BabyJubJub curve (lazy loading)\n */\nasync function initBabyJub(): Promise<BabyJubJub> {\n if (babyjubInstance === null) {\n const { buildBabyjub } = await import('circomlibjs')\n babyjubInstance = await buildBabyjub() as BabyJubJub\n }\n return babyjubInstance as BabyJubJub\n}\n\n/**\n * Get the BabyJubJub subgroup order\n */\nexport async function getSubOrder(): Promise<bigint> {\n const babyjub = await initBabyJub()\n return babyjub.subOrder\n}\n\n/**\n * Get the generator point (Base8)\n */\nexport async function getBasePoint(): Promise<Point> {\n const babyjub = await initBabyJub()\n return {\n x: babyjub.F.toObject(babyjub.Base8[0]),\n y: babyjub.F.toObject(babyjub.Base8[1]),\n }\n}\n\n/**\n * Check if a point is on the curve\n */\nexport async function isOnCurve(point: Point): Promise<boolean> {\n const babyjub = await initBabyJub()\n const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)] as [unknown, unknown]\n return babyjub.inCurve(internal)\n}\n\n/**\n * Scalar multiplication: point * scalar\n *\n * @param point - Point on the curve\n * @param scalar - Scalar value (mod subOrder)\n * @returns Resulting point\n */\nexport async function mulPointScalar(point: Point, scalar: bigint): Promise<Point> {\n const babyjub = await initBabyJub()\n\n // Convert to internal format\n const internal = [babyjub.F.e(point.x), babyjub.F.e(point.y)] as [unknown, unknown]\n\n // Perform scalar multiplication\n const result = babyjub.mulPointEscalar(internal, scalar)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Point addition: p1 + p2\n */\nexport async function addPoints(p1: Point, p2: Point): Promise<Point> {\n const babyjub = await initBabyJub()\n\n // Convert to internal format\n const internal1 = [babyjub.F.e(p1.x), babyjub.F.e(p1.y)] as [unknown, unknown]\n const internal2 = [babyjub.F.e(p2.x), babyjub.F.e(p2.y)] as [unknown, unknown]\n\n // Add points\n const result = babyjub.addPoint(internal1, internal2)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Generate public key from private key\n * pubKey = privateKey * Base8\n *\n * @param privateKey - Private key scalar (must be < subOrder)\n * @returns Public key point\n */\nexport async function privateToPublic(privateKey: bigint): Promise<Point> {\n const babyjub = await initBabyJub()\n\n // Ensure private key is in valid range\n const scalar = privateKey % babyjub.subOrder\n\n // pubKey = scalar * Base8\n const result = babyjub.mulPointEscalar(babyjub.Base8, scalar)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Compute ECDH shared secret\n * sharedSecret = myPrivateKey * theirPublicKey\n *\n * @param myPrivateKey - Your private key\n * @param theirPublicKey - Their public key\n * @returns Shared secret point\n */\nexport async function computeSharedSecret(\n myPrivateKey: bigint,\n theirPublicKey: Point\n): Promise<Point> {\n return mulPointScalar(theirPublicKey, myPrivateKey)\n}\n\n/**\n * Pack a point into a single bigint (compressed form)\n * Uses the x-coordinate and a sign bit for y\n */\nexport function packPoint(point: Point): bigint {\n // Use x-coordinate with y sign bit in high position\n const ySign = point.y % 2n\n return point.x | (ySign << 254n)\n}\n\n/**\n * Convert a point to tuple format [x, y] for use with snarkjs\n */\nexport function pointToTuple(point: Point): [bigint, bigint] {\n return [point.x, point.y]\n}\n\n/**\n * Convert a tuple [x, y] to Point format\n */\nexport function tupleToPoint(tuple: [bigint, bigint]): Point {\n return { x: tuple[0], y: tuple[1] }\n}\n\n// BabyJubJub curve parameters\n// Curve: a*x² + y² = 1 + d*x²*y²\nconst BABYJUBJUB_A = 168700n\nconst BABYJUBJUB_D = 168696n\n// Field prime (BN254 scalar field)\nconst BABYJUBJUB_P = 21888242871839275222246405745257275088548364400416034343698204186575808495617n\n\n/**\n * Modular exponentiation: base^exp mod p\n */\nfunction modPow(base: bigint, exp: bigint, p: bigint): bigint {\n let result = 1n\n base = ((base % p) + p) % p\n while (exp > 0n) {\n if (exp % 2n === 1n) {\n result = (result * base) % p\n }\n exp = exp / 2n\n base = (base * base) % p\n }\n return result\n}\n\n/**\n * Modular inverse using Fermat's little theorem: a^(-1) = a^(p-2) mod p\n */\nfunction modInverse(a: bigint, p: bigint): bigint {\n return modPow(a, p - 2n, p)\n}\n\n/**\n * Tonelli-Shanks algorithm for modular square root\n * Returns sqrt(n) mod p, or null if no square root exists\n */\nfunction modSqrt(n: bigint, p: bigint): bigint | null {\n n = ((n % p) + p) % p\n if (n === 0n) return 0n\n\n // Check if n is a quadratic residue (Euler's criterion)\n if (modPow(n, (p - 1n) / 2n, p) !== 1n) {\n return null // No square root exists\n }\n\n // For p ≡ 3 (mod 4), sqrt(n) = n^((p+1)/4) mod p\n // BN254 scalar field: p ≡ 1 (mod 4), so we need Tonelli-Shanks\n\n // Factor out powers of 2 from p - 1\n let q = p - 1n\n let s = 0n\n while (q % 2n === 0n) {\n q = q / 2n\n s++\n }\n\n // Find a quadratic non-residue\n let z = 2n\n while (modPow(z, (p - 1n) / 2n, p) !== p - 1n) {\n z++\n }\n\n let m = s\n let c = modPow(z, q, p)\n let t = modPow(n, q, p)\n let r = modPow(n, (q + 1n) / 2n, p)\n\n while (true) {\n if (t === 1n) return r\n\n // Find the least i such that t^(2^i) = 1\n let i = 1n\n let temp = (t * t) % p\n while (temp !== 1n) {\n temp = (temp * temp) % p\n i++\n }\n\n // Update values\n const b = modPow(c, modPow(2n, m - i - 1n, p - 1n), p)\n m = i\n c = (b * b) % p\n t = (t * c) % p\n r = (r * b) % p\n }\n}\n\n/**\n * Reconstruct a BabyJubJub point from its x-coordinate\n *\n * BabyJubJub curve equation: a*x² + y² = 1 + d*x²*y²\n * Solving for y²: y² = (1 - a*x²) / (1 - d*x²)\n *\n * Returns the point with the smaller y value (canonical form),\n * or null if x is not on the curve.\n *\n * @param x - The x-coordinate\n * @returns Point with the given x, or null if invalid\n */\nexport async function reconstructPointFromX(x: bigint): Promise<Point | null> {\n const p = BABYJUBJUB_P\n x = ((x % p) + p) % p\n\n // Compute x²\n const x2 = (x * x) % p\n\n // Compute numerator: 1 - a*x²\n const numerator = ((1n - BABYJUBJUB_A * x2) % p + p) % p\n\n // Compute denominator: 1 - d*x²\n const denominator = ((1n - BABYJUBJUB_D * x2) % p + p) % p\n\n if (denominator === 0n) {\n return null // Division by zero\n }\n\n // Compute y² = numerator / denominator\n const y2 = (numerator * modInverse(denominator, p)) % p\n\n // Compute y = sqrt(y²)\n const y = modSqrt(y2, p)\n if (y === null) {\n return null // x is not on the curve\n }\n\n // Return the point with smaller y (canonical form)\n const yAlt = p - y\n const yCanonical = y < yAlt ? y : yAlt\n\n const point = { x, y: yCanonical }\n\n // Verify the point is actually on the curve\n if (!(await isOnCurve(point))) {\n // Try the other y\n const pointAlt = { x, y: y < yAlt ? yAlt : y }\n if (!(await isOnCurve(pointAlt))) {\n return null\n }\n return pointAlt\n }\n\n return point\n}\n\n/**\n * Reconstruct a BabyJubJub point from x-coordinate and y parity bit\n *\n * @param x - The x-coordinate\n * @param yParity - 0 for even y, 1 for odd y\n * @returns Point with matching parity, or null if invalid\n */\nexport async function reconstructPointFromXWithParity(\n x: bigint,\n yParity: 0 | 1\n): Promise<Point | null> {\n const p = BABYJUBJUB_P\n x = ((x % p) + p) % p\n\n const x2 = (x * x) % p\n const numerator = ((1n - BABYJUBJUB_A * x2) % p + p) % p\n const denominator = ((1n - BABYJUBJUB_D * x2) % p + p) % p\n\n if (denominator === 0n) return null\n\n const y2 = (numerator * modInverse(denominator, p)) % p\n const y = modSqrt(y2, p)\n if (y === null) return null\n\n // Select y based on parity\n const actualParity = Number(y % 2n)\n const finalY = actualParity === yParity ? y : p - y\n\n return { x, y: finalY }\n}\n\n/**\n * Derive a per-transaction viewing public key (EVK)\n *\n * EVK = MVK_pub + Poseidon(MVK_pub.x, MVK_pub.y, nonce) * Base8\n *\n * This allows the sender to derive a unique encryption key for each transaction\n * without knowing the recipient's private key.\n *\n * @param masterViewingPubKey - Recipient's master viewing public key\n * @param nonce - Unique per-note nonce (R.x — ephemeral public key x-coordinate)\n * @returns Per-transaction encryption viewing key\n */\nexport async function deriveEncryptionViewingKey(\n masterViewingPubKey: Point,\n nonce: bigint\n): Promise<Point> {\n // Import poseidonScalar to avoid circular dependency\n const { poseidonScalar } = await import('./poseidon.js')\n\n const babyjub = await initBabyJub()\n\n // Compute scalar: Poseidon(MVK_pub.x, MVK_pub.y, nonce) mod subOrder\n const scalar = await poseidonScalar([masterViewingPubKey.x, masterViewingPubKey.y, nonce])\n\n // Compute offset: scalar * Base8\n const offset = babyjub.mulPointEscalar(babyjub.Base8, scalar)\n\n // Convert MVK_pub to internal format\n const mvkInternal = [\n babyjub.F.e(masterViewingPubKey.x),\n babyjub.F.e(masterViewingPubKey.y),\n ] as [unknown, unknown]\n\n // EVK = MVK_pub + offset\n const result = babyjub.addPoint(mvkInternal, offset)\n\n return {\n x: babyjub.F.toObject(result[0]),\n y: babyjub.F.toObject(result[1]),\n }\n}\n\n/**\n * Derive a per-transaction viewing private key (DVK)\n *\n * DVK = MVK_priv + Poseidon(MVK_pub.x, MVK_pub.y, nonce)\n *\n * Only the owner with MVK_priv can compute this.\n * DVK can be shared with auditors to decrypt specific transactions.\n *\n * @param masterViewingPrivKey - Owner's master viewing private key\n * @param masterViewingPubKey - Owner's master viewing public key\n * @param nonce - Unique per-note nonce (R.x — ephemeral public key x-coordinate)\n * @returns Per-transaction decryption viewing key\n */\nexport async function deriveDecryptionViewingKey(\n masterViewingPrivKey: bigint,\n masterViewingPubKey: Point,\n nonce: bigint\n): Promise<bigint> {\n // Import poseidonScalar to avoid circular dependency\n const { poseidonScalar } = await import('./poseidon.js')\n\n // Compute scalar: Poseidon(MVK_pub.x, MVK_pub.y, nonce) mod subOrder\n const scalar = await poseidonScalar([masterViewingPubKey.x, masterViewingPubKey.y, nonce])\n\n // DVK = MVK_priv + scalar (mod subOrder)\n return (masterViewingPrivKey + scalar) % BABYJUBJUB_SUBORDER\n}\n\n"]}
|