@permissionless-technologies/upp-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +194 -0
- package/dist/asp-TXSAFFD3.cjs +53 -0
- package/dist/asp-TXSAFFD3.cjs.map +1 -0
- package/dist/asp-ZA3RGN7G.js +4 -0
- package/dist/asp-ZA3RGN7G.js.map +1 -0
- package/dist/babyjubjub-2MGQVCKB.js +5 -0
- package/dist/babyjubjub-2MGQVCKB.js.map +1 -0
- package/dist/babyjubjub-MWZLJOVZ.cjs +66 -0
- package/dist/babyjubjub-MWZLJOVZ.cjs.map +1 -0
- package/dist/chunk-2JQISXBD.js +150 -0
- package/dist/chunk-2JQISXBD.js.map +1 -0
- package/dist/chunk-3HQ7A6ZM.cjs +61 -0
- package/dist/chunk-3HQ7A6ZM.cjs.map +1 -0
- package/dist/chunk-5AKBSMEQ.cjs +1008 -0
- package/dist/chunk-5AKBSMEQ.cjs.map +1 -0
- package/dist/chunk-5V5HSN6Y.js +81 -0
- package/dist/chunk-5V5HSN6Y.js.map +1 -0
- package/dist/chunk-BH24DZ5S.cjs +91 -0
- package/dist/chunk-BH24DZ5S.cjs.map +1 -0
- package/dist/chunk-C7QQOJ7T.cjs +67 -0
- package/dist/chunk-C7QQOJ7T.cjs.map +1 -0
- package/dist/chunk-ERQE57IA.cjs +404 -0
- package/dist/chunk-ERQE57IA.cjs.map +1 -0
- package/dist/chunk-EUP7MBAH.cjs +165 -0
- package/dist/chunk-EUP7MBAH.cjs.map +1 -0
- package/dist/chunk-G7VZBCD6.cjs +35 -0
- package/dist/chunk-G7VZBCD6.cjs.map +1 -0
- package/dist/chunk-GQV47S3N.cjs +10 -0
- package/dist/chunk-GQV47S3N.cjs.map +1 -0
- package/dist/chunk-GXZ3MTCQ.cjs +527 -0
- package/dist/chunk-GXZ3MTCQ.cjs.map +1 -0
- package/dist/chunk-JWNXBALH.cjs +57 -0
- package/dist/chunk-JWNXBALH.cjs.map +1 -0
- package/dist/chunk-KIKBPJXJ.cjs +348 -0
- package/dist/chunk-KIKBPJXJ.cjs.map +1 -0
- package/dist/chunk-NCW4AE7L.js +8 -0
- package/dist/chunk-NCW4AE7L.js.map +1 -0
- package/dist/chunk-NDM5EJEV.cjs +70 -0
- package/dist/chunk-NDM5EJEV.cjs.map +1 -0
- package/dist/chunk-NUIQHTSA.js +489 -0
- package/dist/chunk-NUIQHTSA.js.map +1 -0
- package/dist/chunk-OQDSHMXU.js +1002 -0
- package/dist/chunk-OQDSHMXU.js.map +1 -0
- package/dist/chunk-P37MRZ73.js +58 -0
- package/dist/chunk-P37MRZ73.js.map +1 -0
- package/dist/chunk-PWHOUQOZ.js +335 -0
- package/dist/chunk-PWHOUQOZ.js.map +1 -0
- package/dist/chunk-S4B7GYLN.js +112 -0
- package/dist/chunk-S4B7GYLN.js.map +1 -0
- package/dist/chunk-SGZZL5AC.js +59 -0
- package/dist/chunk-SGZZL5AC.js.map +1 -0
- package/dist/chunk-SQKBT2SH.cjs +122 -0
- package/dist/chunk-SQKBT2SH.cjs.map +1 -0
- package/dist/chunk-TSF6HEVS.cjs +201 -0
- package/dist/chunk-TSF6HEVS.cjs.map +1 -0
- package/dist/chunk-V23OSL25.js +48 -0
- package/dist/chunk-V23OSL25.js.map +1 -0
- package/dist/chunk-W77GRBO4.js +53 -0
- package/dist/chunk-W77GRBO4.js.map +1 -0
- package/dist/chunk-XV72HNHN.js +399 -0
- package/dist/chunk-XV72HNHN.js.map +1 -0
- package/dist/chunk-YOWDERVC.js +186 -0
- package/dist/chunk-YOWDERVC.js.map +1 -0
- package/dist/chunk-Z6ZWNWWR.js +30 -0
- package/dist/chunk-Z6ZWNWWR.js.map +1 -0
- package/dist/chunk-ZKZV6OI3.cjs +165 -0
- package/dist/chunk-ZKZV6OI3.cjs.map +1 -0
- package/dist/chunk-ZU6J7KMY.js +159 -0
- package/dist/chunk-ZU6J7KMY.js.map +1 -0
- package/dist/core/index.cjs +300 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +9 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index-BBzvvrhG.d.ts +757 -0
- package/dist/index-BGvapsJy.d.cts +2811 -0
- package/dist/index-C-jSNw6j.d.cts +757 -0
- package/dist/index-ChGaGPzP.d.ts +2811 -0
- package/dist/index.cjs +3652 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +3112 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/index.cjs +58 -0
- package/dist/indexer/index.cjs.map +1 -0
- package/dist/indexer/index.d.cts +206 -0
- package/dist/indexer/index.d.ts +206 -0
- package/dist/indexer/index.js +5 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/keccak-m31-B_AqBbRF.d.cts +70 -0
- package/dist/keccak-m31-B_AqBbRF.d.ts +70 -0
- package/dist/keys/index.cjs +68 -0
- package/dist/keys/index.cjs.map +1 -0
- package/dist/keys/index.d.cts +158 -0
- package/dist/keys/index.d.ts +158 -0
- package/dist/keys/index.js +7 -0
- package/dist/keys/index.js.map +1 -0
- package/dist/merkle-7KS2EHRF.js +5 -0
- package/dist/merkle-7KS2EHRF.js.map +1 -0
- package/dist/merkle-HGDC6OB4.cjs +30 -0
- package/dist/merkle-HGDC6OB4.cjs.map +1 -0
- package/dist/merkle-mteVOlDf.d.cts +188 -0
- package/dist/merkle-mteVOlDf.d.ts +188 -0
- package/dist/poseidon-UHTJLWQM.js +7 -0
- package/dist/poseidon-UHTJLWQM.js.map +1 -0
- package/dist/poseidon-WHJSZSNP.cjs +45 -0
- package/dist/poseidon-WHJSZSNP.cjs.map +1 -0
- package/dist/proof-5OECB3RQ.cjs +45 -0
- package/dist/proof-5OECB3RQ.cjs.map +1 -0
- package/dist/proof-C4YBP6RY.js +4 -0
- package/dist/proof-C4YBP6RY.js.map +1 -0
- package/dist/react/index.cjs +2641 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +757 -0
- package/dist/react/index.d.ts +757 -0
- package/dist/react/index.js +2598 -0
- package/dist/react/index.js.map +1 -0
- package/dist/transfer-2UDHDS7Q.cjs +37 -0
- package/dist/transfer-2UDHDS7Q.cjs.map +1 -0
- package/dist/transfer-BlmbO-Rd.d.ts +1270 -0
- package/dist/transfer-DKZuJnRM.d.cts +1270 -0
- package/dist/transfer-KTCXKHS4.js +8 -0
- package/dist/transfer-KTCXKHS4.js.map +1 -0
- package/dist/types-CJSbxv4q.d.cts +143 -0
- package/dist/types-mLybMxNR.d.ts +143 -0
- package/dist/utils/index.cjs +178 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +88 -0
- package/dist/utils/index.d.ts +88 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +119 -0
- package/src/contracts/interfaces/IASPRegistry.sol +36 -0
- package/src/contracts/interfaces/IUniversalPrivatePool.sol +260 -0
- package/src/contracts/interfaces/IVerifiers.sol +68 -0
- package/src/deployments/11155111.json +19 -0
- package/src/deployments/31337.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Universal Private Pool (UPP) SDK
|
|
2
|
+
|
|
3
|
+
Privacy-preserving token operations for any ERC20 token.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-token support**: Shield any ERC20 into a single privacy pool
|
|
8
|
+
- **Large anonymity set**: All token users share one Merkle tree
|
|
9
|
+
- **Compliance-ready**: ASP-based whitelists with ragequit protection
|
|
10
|
+
- **Modern stack**: Built on viem, not ethers.js
|
|
11
|
+
|
|
12
|
+
## Package Structure
|
|
13
|
+
|
|
14
|
+
The SDK is published as a single npm package with subpath exports:
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// Core crypto and utilities
|
|
18
|
+
import { poseidon, computeSharedSecret } from '@upp/sdk/core'
|
|
19
|
+
|
|
20
|
+
// Key derivation
|
|
21
|
+
import { deriveKeysFromSignature } from '@upp/sdk/keys'
|
|
22
|
+
|
|
23
|
+
// React hooks (requires React 18+)
|
|
24
|
+
import { UPPAccountProvider, useUPPAccount } from '@upp/sdk/react'
|
|
25
|
+
|
|
26
|
+
// Indexer for note scanning
|
|
27
|
+
import { makeRpcIndexer } from '@upp/sdk/indexer'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Why not separate packages?**
|
|
31
|
+
|
|
32
|
+
We considered splitting into `@upp/core`, `@upp/react`, etc. (like Kohaku), but chose a single package because:
|
|
33
|
+
|
|
34
|
+
1. **Same developer experience** - Subpath exports work identically to separate packages
|
|
35
|
+
2. **Tree-shaking works** - Modern bundlers only include what you import
|
|
36
|
+
3. **Simpler versioning** - No cross-package dependency management
|
|
37
|
+
4. **Prototype-appropriate** - Less operational overhead
|
|
38
|
+
|
|
39
|
+
The internal architecture maintains clean boundaries, so splitting later is straightforward if needed.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @upp/sdk viem
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { createUPPClient } from '@upp/sdk'
|
|
51
|
+
import { createPublicClient, createWalletClient, http } from 'viem'
|
|
52
|
+
import { sepolia } from 'viem/chains'
|
|
53
|
+
|
|
54
|
+
// Create viem clients
|
|
55
|
+
const publicClient = createPublicClient({
|
|
56
|
+
chain: sepolia,
|
|
57
|
+
transport: http(),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const walletClient = createWalletClient({
|
|
61
|
+
chain: sepolia,
|
|
62
|
+
transport: http(),
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Create UPP client
|
|
66
|
+
const upp = createUPPClient({
|
|
67
|
+
publicClient,
|
|
68
|
+
walletClient,
|
|
69
|
+
poolAddress: '0x...',
|
|
70
|
+
aspHubAddress: '0x...',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Shield tokens
|
|
74
|
+
const { commitment, note } = await upp.shield({
|
|
75
|
+
token: '0xUSDC...',
|
|
76
|
+
amount: 1000n * 10n ** 6n,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Transfer privately
|
|
80
|
+
await upp.transfer({
|
|
81
|
+
note: myNote,
|
|
82
|
+
recipient: recipientStealthAddress,
|
|
83
|
+
amount: 500n * 10n ** 6n,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Withdraw
|
|
87
|
+
await upp.withdraw({
|
|
88
|
+
note: myNote,
|
|
89
|
+
amount: 500n * 10n ** 6n,
|
|
90
|
+
recipient: '0xMyAddress...',
|
|
91
|
+
aspId: 1,
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Local Development
|
|
96
|
+
|
|
97
|
+
### Prerequisites
|
|
98
|
+
|
|
99
|
+
- [Foundry](https://book.getfoundry.sh/getting-started/installation) for contract compilation and deployment
|
|
100
|
+
- [Node.js](https://nodejs.org/) 18+
|
|
101
|
+
- Local Ethereum node (Anvil recommended)
|
|
102
|
+
|
|
103
|
+
### Starting a Local Node
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Start Anvil with auto-mining
|
|
107
|
+
anvil
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Deploying Contracts
|
|
111
|
+
|
|
112
|
+
The SDK includes deployment scripts and automatic address extraction:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# 1. Deploy contracts to local Anvil
|
|
116
|
+
forge script src/contracts/script/DeployUPP.s.sol:DeployUPPLocal \
|
|
117
|
+
--rpc-url http://localhost:8545 \
|
|
118
|
+
--broadcast \
|
|
119
|
+
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
|
|
120
|
+
|
|
121
|
+
# 2. Extract addresses to SDK deployment JSON
|
|
122
|
+
node scripts/extract-deployment.js 31337
|
|
123
|
+
|
|
124
|
+
# 3. Rebuild SDK to include new addresses
|
|
125
|
+
npm run build
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
After deployment, addresses are written to `src/deployments/31337.json`:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"UniversalPrivatePool": "0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6",
|
|
133
|
+
"ASPRegistryHub": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
|
|
134
|
+
"TestToken": "0x610178da211fef7d417bc0e6fed39f05609ad788",
|
|
135
|
+
"verifiers": { ... },
|
|
136
|
+
"deployBlock": 2
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Using Deployment Addresses
|
|
141
|
+
|
|
142
|
+
The SDK provides helpers to load deployment addresses:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { getDeployment, getDeploymentOrThrow } from '@upp/sdk'
|
|
146
|
+
|
|
147
|
+
// Get deployment for chain (returns null if not found)
|
|
148
|
+
const deployment = getDeployment(31337)
|
|
149
|
+
|
|
150
|
+
// Or throw if not found
|
|
151
|
+
const deployment = getDeploymentOrThrow(31337)
|
|
152
|
+
|
|
153
|
+
// Access addresses
|
|
154
|
+
const poolAddress = deployment.UniversalPrivatePool
|
|
155
|
+
const tokenAddress = deployment.TestToken // local dev
|
|
156
|
+
// or
|
|
157
|
+
const tokenAddress = deployment.USSC // production
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### TestStableToken (TST)
|
|
161
|
+
|
|
162
|
+
The local deployment includes a test ERC20 token with an ETH-to-token swap:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Mint TST by sending ETH (1 ETH = 3000 TST)
|
|
166
|
+
await walletClient.sendTransaction({
|
|
167
|
+
to: deployment.TestToken,
|
|
168
|
+
value: parseEther('1'),
|
|
169
|
+
data: encodeFunctionData({
|
|
170
|
+
abi: USSC_ABI,
|
|
171
|
+
functionName: 'mintWithEth',
|
|
172
|
+
}),
|
|
173
|
+
})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Contract ABIs
|
|
177
|
+
|
|
178
|
+
The SDK exports ABIs for all contracts:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import {
|
|
182
|
+
UNIVERSAL_PRIVATE_POOL_ABI,
|
|
183
|
+
ASP_REGISTRY_HUB_ABI,
|
|
184
|
+
USSC_ABI,
|
|
185
|
+
} from '@upp/sdk'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
See [CLAUDE.md](./CLAUDE.md) for detailed API documentation and architecture.
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkNDM5EJEV_cjs = require('./chunk-NDM5EJEV.cjs');
|
|
4
|
+
require('./chunk-G7VZBCD6.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "ASP_TREE_DEPTH", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkNDM5EJEV_cjs.ASP_TREE_DEPTH; }
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "DEMO_ASP_ID", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkNDM5EJEV_cjs.DEMO_ASP_ID; }
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(exports, "DEMO_ASP_NAME", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return chunkNDM5EJEV_cjs.DEMO_ASP_NAME; }
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports, "buildASPTree", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return chunkNDM5EJEV_cjs.buildASPTree; }
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "computeMultiOriginASPRoot", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () { return chunkNDM5EJEV_cjs.computeMultiOriginASPRoot; }
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports, "computeSingleOriginASPRoot", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () { return chunkNDM5EJEV_cjs.computeSingleOriginASPRoot; }
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(exports, "createDemoASPRoot", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () { return chunkNDM5EJEV_cjs.createDemoASPRoot; }
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "generateASPProof", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () { return chunkNDM5EJEV_cjs.generateASPProof; }
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(exports, "generateMultiOriginASPProof", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
get: function () { return chunkNDM5EJEV_cjs.generateMultiOriginASPProof; }
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(exports, "generateSingleOriginASPProof", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
get: function () { return chunkNDM5EJEV_cjs.generateSingleOriginASPProof; }
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "verifyASPProof", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function () { return chunkNDM5EJEV_cjs.verifyASPProof; }
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=asp-TXSAFFD3.cjs.map
|
|
53
|
+
//# sourceMappingURL=asp-TXSAFFD3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"asp-TXSAFFD3.cjs"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ASP_TREE_DEPTH, DEMO_ASP_ID, DEMO_ASP_NAME, buildASPTree, computeMultiOriginASPRoot, computeSingleOriginASPRoot, createDemoASPRoot, generateASPProof, generateMultiOriginASPProof, generateSingleOriginASPProof, verifyASPProof } from './chunk-P37MRZ73.js';
|
|
2
|
+
import './chunk-Z6ZWNWWR.js';
|
|
3
|
+
//# sourceMappingURL=asp-ZA3RGN7G.js.map
|
|
4
|
+
//# sourceMappingURL=asp-ZA3RGN7G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"asp-ZA3RGN7G.js"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { addPoints, computeSharedSecret, deriveDecryptionViewingKey, deriveEncryptionViewingKey, getBasePoint, getSubOrder, isOnCurve, mulPointScalar, packPoint, pointToTuple, privateToPublic, reconstructPointFromX, reconstructPointFromXWithParity, tupleToPoint } from './chunk-YOWDERVC.js';
|
|
2
|
+
import './chunk-V23OSL25.js';
|
|
3
|
+
import './chunk-Z6ZWNWWR.js';
|
|
4
|
+
//# sourceMappingURL=babyjubjub-2MGQVCKB.js.map
|
|
5
|
+
//# sourceMappingURL=babyjubjub-2MGQVCKB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"babyjubjub-2MGQVCKB.js"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkTSF6HEVS_cjs = require('./chunk-TSF6HEVS.cjs');
|
|
4
|
+
require('./chunk-JWNXBALH.cjs');
|
|
5
|
+
require('./chunk-G7VZBCD6.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "addPoints", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return chunkTSF6HEVS_cjs.addPoints; }
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(exports, "computeSharedSecret", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return chunkTSF6HEVS_cjs.computeSharedSecret; }
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(exports, "deriveDecryptionViewingKey", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return chunkTSF6HEVS_cjs.deriveDecryptionViewingKey; }
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(exports, "deriveEncryptionViewingKey", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return chunkTSF6HEVS_cjs.deriveEncryptionViewingKey; }
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(exports, "getBasePoint", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () { return chunkTSF6HEVS_cjs.getBasePoint; }
|
|
28
|
+
});
|
|
29
|
+
Object.defineProperty(exports, "getSubOrder", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () { return chunkTSF6HEVS_cjs.getSubOrder; }
|
|
32
|
+
});
|
|
33
|
+
Object.defineProperty(exports, "isOnCurve", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
get: function () { return chunkTSF6HEVS_cjs.isOnCurve; }
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(exports, "mulPointScalar", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () { return chunkTSF6HEVS_cjs.mulPointScalar; }
|
|
40
|
+
});
|
|
41
|
+
Object.defineProperty(exports, "packPoint", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
get: function () { return chunkTSF6HEVS_cjs.packPoint; }
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(exports, "pointToTuple", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function () { return chunkTSF6HEVS_cjs.pointToTuple; }
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(exports, "privateToPublic", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: function () { return chunkTSF6HEVS_cjs.privateToPublic; }
|
|
52
|
+
});
|
|
53
|
+
Object.defineProperty(exports, "reconstructPointFromX", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
get: function () { return chunkTSF6HEVS_cjs.reconstructPointFromX; }
|
|
56
|
+
});
|
|
57
|
+
Object.defineProperty(exports, "reconstructPointFromXWithParity", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: function () { return chunkTSF6HEVS_cjs.reconstructPointFromXWithParity; }
|
|
60
|
+
});
|
|
61
|
+
Object.defineProperty(exports, "tupleToPoint", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
get: function () { return chunkTSF6HEVS_cjs.tupleToPoint; }
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=babyjubjub-MWZLJOVZ.cjs.map
|
|
66
|
+
//# sourceMappingURL=babyjubjub-MWZLJOVZ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"babyjubjub-MWZLJOVZ.cjs"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { splitToM31Limbs, computeStarkOwnerHash, keccakM31 } from './chunk-5V5HSN6Y.js';
|
|
2
|
+
import { init_crypto, bytesToBigint, hexToBytes, bytesToHex } from './chunk-W77GRBO4.js';
|
|
3
|
+
import { init_poseidon, FIELD_PRIME } from './chunk-V23OSL25.js';
|
|
4
|
+
import { keccak256, toHex } from 'viem';
|
|
5
|
+
|
|
6
|
+
// src/keys/types.ts
|
|
7
|
+
var DEFAULT_KEY_DERIVATION_CONFIG = {
|
|
8
|
+
message: "UPP Stealth Key Derivation v1",
|
|
9
|
+
version: 1
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/keys/derive.ts
|
|
13
|
+
init_poseidon();
|
|
14
|
+
init_crypto();
|
|
15
|
+
async function deriveKeysFromSignature(signature, config = DEFAULT_KEY_DERIVATION_CONFIG) {
|
|
16
|
+
const { poseidon } = await import('./poseidon-UHTJLWQM.js');
|
|
17
|
+
const seed = keccak256(signature);
|
|
18
|
+
const spendingSecretHash = keccak256(
|
|
19
|
+
toHex(new TextEncoder().encode(`${seed}:spending:v${config.version}`))
|
|
20
|
+
);
|
|
21
|
+
const spendingSecretRaw = bytesToBigint(hexToBytes(spendingSecretHash));
|
|
22
|
+
const spendingSecret = spendingSecretRaw % FIELD_PRIME;
|
|
23
|
+
const ownerHash = await poseidon([spendingSecret]);
|
|
24
|
+
const viewingSecretHash = keccak256(
|
|
25
|
+
toHex(new TextEncoder().encode(`${seed}:viewing:v${config.version}`))
|
|
26
|
+
);
|
|
27
|
+
const viewingSecretRaw = bytesToBigint(hexToBytes(viewingSecretHash));
|
|
28
|
+
const viewingSecret = viewingSecretRaw % FIELD_PRIME;
|
|
29
|
+
const viewingHash = await poseidon([viewingSecret]);
|
|
30
|
+
return {
|
|
31
|
+
spendingSecret,
|
|
32
|
+
ownerHash,
|
|
33
|
+
viewingSecret,
|
|
34
|
+
viewingHash
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function getKeyDerivationMessage(config = DEFAULT_KEY_DERIVATION_CONFIG) {
|
|
38
|
+
return config.message;
|
|
39
|
+
}
|
|
40
|
+
async function verifyKeysMatchSignature(keys, signature, config = DEFAULT_KEY_DERIVATION_CONFIG) {
|
|
41
|
+
const derivedKeys = await deriveKeysFromSignature(signature, config);
|
|
42
|
+
return keys.spendingSecret === derivedKeys.spendingSecret && keys.ownerHash === derivedKeys.ownerHash && keys.viewingSecret === derivedKeys.viewingSecret && keys.viewingHash === derivedKeys.viewingHash;
|
|
43
|
+
}
|
|
44
|
+
function deriveStarkKeysFromSignature(signature, config = DEFAULT_KEY_DERIVATION_CONFIG) {
|
|
45
|
+
const seed = keccak256(signature);
|
|
46
|
+
const starkSpendingHash = keccak256(
|
|
47
|
+
toHex(new TextEncoder().encode(`${seed}:stark:spending:v${config.version}`))
|
|
48
|
+
);
|
|
49
|
+
const starkSecret = splitToM31Limbs(starkSpendingHash);
|
|
50
|
+
const starkOwnerHash = computeStarkOwnerHash(starkSecret);
|
|
51
|
+
const starkViewingHash = keccak256(
|
|
52
|
+
toHex(new TextEncoder().encode(`${seed}:stark:viewing:v${config.version}`))
|
|
53
|
+
);
|
|
54
|
+
const starkViewingSecret = splitToM31Limbs(starkViewingHash);
|
|
55
|
+
const starkViewingHashDigest = computeStarkOwnerHash(starkViewingSecret);
|
|
56
|
+
return {
|
|
57
|
+
starkSecret,
|
|
58
|
+
starkOwnerHash,
|
|
59
|
+
starkViewingSecret,
|
|
60
|
+
starkViewingHash: starkViewingHashDigest
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function deriveDualKeysFromSignature(signature, config = DEFAULT_KEY_DERIVATION_CONFIG) {
|
|
64
|
+
const snark = await deriveKeysFromSignature(signature, config);
|
|
65
|
+
const stark = deriveStarkKeysFromSignature(signature, config);
|
|
66
|
+
return { snark, stark };
|
|
67
|
+
}
|
|
68
|
+
async function deriveNullifierKey(spendingSecret) {
|
|
69
|
+
const { poseidon } = await import('./poseidon-UHTJLWQM.js');
|
|
70
|
+
return await poseidon([spendingSecret, 0n]);
|
|
71
|
+
}
|
|
72
|
+
init_crypto();
|
|
73
|
+
async function derivePerNoteKey(viewingSecret, nonce) {
|
|
74
|
+
const { poseidon } = await import('./poseidon-UHTJLWQM.js');
|
|
75
|
+
const perNoteKey = await poseidon([viewingSecret, nonce]);
|
|
76
|
+
return toHex(perNoteKey, { size: 32 });
|
|
77
|
+
}
|
|
78
|
+
async function derivePerNoteKeyFromKeys(keys, nonce) {
|
|
79
|
+
return derivePerNoteKey(keys.viewingSecret, nonce);
|
|
80
|
+
}
|
|
81
|
+
async function exportViewingKeysForAudit(keys, signerAddress, notes) {
|
|
82
|
+
const viewingKeys = [];
|
|
83
|
+
for (const note of notes) {
|
|
84
|
+
const decryptionKey = await derivePerNoteKey(keys.viewingSecret, note.nonce);
|
|
85
|
+
viewingKeys.push({
|
|
86
|
+
leafIndex: note.leafIndex,
|
|
87
|
+
nonce: note.nonce,
|
|
88
|
+
decryptionKey
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
version: 4,
|
|
93
|
+
signerAddress,
|
|
94
|
+
viewingHash: keys.viewingHash,
|
|
95
|
+
viewingKeys,
|
|
96
|
+
instructions: `
|
|
97
|
+
This export contains per-note decryption keys for ${viewingKeys.length} UPP note(s).
|
|
98
|
+
|
|
99
|
+
To decrypt a note:
|
|
100
|
+
1. Find the viewingKey entry for the desired leafIndex
|
|
101
|
+
2. Retrieve the encrypted note from the blockchain (Shielded event at that leaf index)
|
|
102
|
+
3. Derive AES key: key = keccak256(decryptionKey)
|
|
103
|
+
4. Decrypt the note ciphertext with AES-GCM
|
|
104
|
+
|
|
105
|
+
These per-note keys ONLY allow decryption of the specified notes.
|
|
106
|
+
They do NOT reveal:
|
|
107
|
+
- The master viewing secret (protected by Poseidon one-wayness)
|
|
108
|
+
- Keys for any other notes
|
|
109
|
+
- The spending secret (cannot spend funds)
|
|
110
|
+
`.trim()
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function validateAuditKeyExport(exportData) {
|
|
114
|
+
if (exportData.version !== 4) {
|
|
115
|
+
return { valid: false, error: `Unsupported version: ${exportData.version}. Expected version 4.` };
|
|
116
|
+
}
|
|
117
|
+
if (!exportData.signerAddress || !exportData.signerAddress.startsWith("0x")) {
|
|
118
|
+
return { valid: false, error: "Invalid signer address" };
|
|
119
|
+
}
|
|
120
|
+
if (exportData.viewingHash === void 0 || exportData.viewingHash === null) {
|
|
121
|
+
return { valid: false, error: "Missing viewing hash" };
|
|
122
|
+
}
|
|
123
|
+
if (!Array.isArray(exportData.viewingKeys) || exportData.viewingKeys.length === 0) {
|
|
124
|
+
return { valid: false, error: "No viewing keys in export" };
|
|
125
|
+
}
|
|
126
|
+
return { valid: true };
|
|
127
|
+
}
|
|
128
|
+
function getViewingKeyFromExport(exportData, leafIndex) {
|
|
129
|
+
const key = exportData.viewingKeys.find((k) => k.leafIndex === leafIndex);
|
|
130
|
+
return key ? key.decryptionKey : null;
|
|
131
|
+
}
|
|
132
|
+
function deriveStarkPerNoteKey(starkViewingSecret, nonce) {
|
|
133
|
+
const digest = keccakM31([...starkViewingSecret, nonce]);
|
|
134
|
+
const bytes = new Uint8Array(16);
|
|
135
|
+
for (let i = 0; i < 4; i++) {
|
|
136
|
+
const val = Number(digest[i]);
|
|
137
|
+
bytes[i * 4] = val & 255;
|
|
138
|
+
bytes[i * 4 + 1] = val >> 8 & 255;
|
|
139
|
+
bytes[i * 4 + 2] = val >> 16 & 255;
|
|
140
|
+
bytes[i * 4 + 3] = val >> 24 & 255;
|
|
141
|
+
}
|
|
142
|
+
return keccak256(bytesToHex(bytes));
|
|
143
|
+
}
|
|
144
|
+
function deriveStarkPerNoteKeyFromKeys(keys, nonce) {
|
|
145
|
+
return deriveStarkPerNoteKey(keys.starkViewingSecret, nonce);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { DEFAULT_KEY_DERIVATION_CONFIG, deriveDualKeysFromSignature, deriveKeysFromSignature, deriveNullifierKey, derivePerNoteKey, derivePerNoteKeyFromKeys, deriveStarkKeysFromSignature, deriveStarkPerNoteKey, deriveStarkPerNoteKeyFromKeys, exportViewingKeysForAudit, getKeyDerivationMessage, getViewingKeyFromExport, validateAuditKeyExport, verifyKeysMatchSignature };
|
|
149
|
+
//# sourceMappingURL=chunk-2JQISXBD.js.map
|
|
150
|
+
//# sourceMappingURL=chunk-2JQISXBD.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkJWNXBALH_cjs = require('./chunk-JWNXBALH.cjs');
|
|
4
|
+
var chunkG7VZBCD6_cjs = require('./chunk-G7VZBCD6.cjs');
|
|
5
|
+
|
|
6
|
+
// src/utils/crypto.ts
|
|
7
|
+
function randomBytes(length) {
|
|
8
|
+
const bytes = new Uint8Array(length);
|
|
9
|
+
crypto.getRandomValues(bytes);
|
|
10
|
+
return bytes;
|
|
11
|
+
}
|
|
12
|
+
function randomFieldElement() {
|
|
13
|
+
const bytes = randomBytes(32);
|
|
14
|
+
let value = 0n;
|
|
15
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
16
|
+
value = (value << 8n) + BigInt(bytes[i]);
|
|
17
|
+
}
|
|
18
|
+
return value % chunkJWNXBALH_cjs.FIELD_PRIME;
|
|
19
|
+
}
|
|
20
|
+
function bytesToHex(bytes) {
|
|
21
|
+
return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
22
|
+
}
|
|
23
|
+
function hexToBytes(hex) {
|
|
24
|
+
const str = hex.slice(2);
|
|
25
|
+
const bytes = new Uint8Array(str.length / 2);
|
|
26
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
27
|
+
bytes[i] = parseInt(str.slice(i * 2, i * 2 + 2), 16);
|
|
28
|
+
}
|
|
29
|
+
return bytes;
|
|
30
|
+
}
|
|
31
|
+
function bigintToBytes(value, length) {
|
|
32
|
+
const bytes = new Uint8Array(length);
|
|
33
|
+
let temp = value;
|
|
34
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
35
|
+
bytes[i] = Number(temp & 0xffn);
|
|
36
|
+
temp >>= 8n;
|
|
37
|
+
}
|
|
38
|
+
return bytes;
|
|
39
|
+
}
|
|
40
|
+
function bytesToBigint(bytes) {
|
|
41
|
+
let value = 0n;
|
|
42
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
43
|
+
value = (value << 8n) + BigInt(bytes[i]);
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
var init_crypto = chunkG7VZBCD6_cjs.__esm({
|
|
48
|
+
"src/utils/crypto.ts"() {
|
|
49
|
+
chunkJWNXBALH_cjs.init_poseidon();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
exports.bigintToBytes = bigintToBytes;
|
|
54
|
+
exports.bytesToBigint = bytesToBigint;
|
|
55
|
+
exports.bytesToHex = bytesToHex;
|
|
56
|
+
exports.hexToBytes = hexToBytes;
|
|
57
|
+
exports.init_crypto = init_crypto;
|
|
58
|
+
exports.randomBytes = randomBytes;
|
|
59
|
+
exports.randomFieldElement = randomFieldElement;
|
|
60
|
+
//# sourceMappingURL=chunk-3HQ7A6ZM.cjs.map
|
|
61
|
+
//# sourceMappingURL=chunk-3HQ7A6ZM.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/crypto.ts"],"names":["FIELD_PRIME","__esm","init_poseidon"],"mappings":";;;;;;AAWO,SAAS,YAAY,MAAA,EAA4B;AACtD,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,EAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,EAAA,OAAO,KAAA;AACT;AAOO,SAAS,kBAAA,GAA6B;AAE3C,EAAA,MAAM,KAAA,GAAQ,YAAY,EAAE,CAAA;AAG5B,EAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,KAAA,GAAA,CAAS,KAAA,IAAS,EAAA,IAAM,MAAA,CAAO,KAAA,CAAM,CAAC,CAAE,CAAA;AAAA,EAC1C;AAGA,EAAA,OAAO,KAAA,GAAQA,6BAAA;AACjB;AAKO,SAAS,WAAW,KAAA,EAAkC;AAC3D,EAAA,OAAO,KAAK,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,CACzB,GAAA,CAAI,OAAK,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CACxC,IAAA,CAAK,EAAE,CAAC,CAAA,CAAA;AACb;AAKO,SAAS,WAAW,GAAA,EAAgC;AACzD,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,GAAA,CAAI,SAAS,CAAC,CAAA;AAC3C,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,QAAA,CAAS,GAAA,CAAI,KAAA,CAAM,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,KAAA;AACT;AAKO,SAAS,aAAA,CAAc,OAAe,MAAA,EAA4B;AACvE,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,EAAA,IAAI,IAAA,GAAO,KAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AACpC,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,MAAA,CAAO,IAAA,GAAO,KAAK,CAAA;AAC9B,IAAA,IAAA,KAAS,EAAA;AAAA,EACX;AACA,EAAA,OAAO,KAAA;AACT;AAKO,SAAS,cAAc,KAAA,EAA2B;AACvD,EAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,KAAA,GAAA,CAAS,KAAA,IAAS,EAAA,IAAM,MAAA,CAAO,KAAA,CAAM,CAAC,CAAE,CAAA;AAAA,EAC1C;AACA,EAAA,OAAO,KAAA;AACT;AA/EA,IAAA,WAAA,GAAAC,uBAAA,CAAA;AAAA,EAAA,qBAAA,GAAA;AAMA,IAAAC,+BAAA,EAAA;AAAA,EAAA;AAAA,CAAA","file":"chunk-3HQ7A6ZM.cjs","sourcesContent":["/**\n * Cryptographic Utilities\n *\n * Secure random number generation and field arithmetic.\n */\n\nimport { FIELD_PRIME } from './poseidon.js'\n\n/**\n * Generate cryptographically secure random bytes\n */\nexport function randomBytes(length: number): Uint8Array {\n const bytes = new Uint8Array(length)\n crypto.getRandomValues(bytes)\n return bytes\n}\n\n/**\n * Generate a random field element (for blinding factors, etc.)\n *\n * Returns a value in range [0, FIELD_PRIME)\n */\nexport function randomFieldElement(): bigint {\n // Generate 32 bytes of randomness\n const bytes = randomBytes(32)\n\n // Convert to bigint\n let value = 0n\n for (let i = 0; i < bytes.length; i++) {\n value = (value << 8n) + BigInt(bytes[i]!)\n }\n\n // Reduce modulo field prime\n return value % FIELD_PRIME\n}\n\n/**\n * Convert bytes to hex string\n */\nexport function bytesToHex(bytes: Uint8Array): `0x${string}` {\n return `0x${Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/**\n * Convert hex string to bytes\n */\nexport function hexToBytes(hex: `0x${string}`): Uint8Array {\n const str = hex.slice(2)\n const bytes = new Uint8Array(str.length / 2)\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(str.slice(i * 2, i * 2 + 2), 16)\n }\n return bytes\n}\n\n/**\n * Convert bigint to bytes (big-endian)\n */\nexport function bigintToBytes(value: bigint, length: number): Uint8Array {\n const bytes = new Uint8Array(length)\n let temp = value\n for (let i = length - 1; i >= 0; i--) {\n bytes[i] = Number(temp & 0xffn)\n temp >>= 8n\n }\n return bytes\n}\n\n/**\n * Convert bytes to bigint (big-endian)\n */\nexport function bytesToBigint(bytes: Uint8Array): bigint {\n let value = 0n\n for (let i = 0; i < bytes.length; i++) {\n value = (value << 8n) + BigInt(bytes[i]!)\n }\n return value\n}\n\n/**\n * Modular exponentiation: base^exp mod modulus\n */\nexport function modPow(base: bigint, exp: bigint, modulus: bigint): bigint {\n let result = 1n\n base = base % modulus\n\n while (exp > 0n) {\n if (exp % 2n === 1n) {\n result = (result * base) % modulus\n }\n exp = exp >> 1n\n base = (base * base) % modulus\n }\n\n return result\n}\n\n/**\n * Modular inverse using extended Euclidean algorithm\n */\nexport function modInverse(a: bigint, modulus: bigint): bigint {\n let [oldR, r] = [a, modulus]\n let [oldS, s] = [1n, 0n]\n\n while (r !== 0n) {\n const quotient = oldR / r\n ;[oldR, r] = [r, oldR - quotient * r]\n ;[oldS, s] = [s, oldS - quotient * s]\n }\n\n if (oldR !== 1n) {\n throw new Error('Modular inverse does not exist')\n }\n\n return ((oldS % modulus) + modulus) % modulus\n}\n"]}
|