@veilo/sdk-core 0.1.17 → 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.
Files changed (218) hide show
  1. package/README.md +1296 -272
  2. package/SHIELD_INTEGRATION.md +143 -0
  3. package/config.d.ts +2 -0
  4. package/config.js +4 -0
  5. package/dist/cjs/client.d.ts +407 -0
  6. package/dist/cjs/client.js +951 -0
  7. package/dist/cjs/compactNote.d.ts +107 -0
  8. package/dist/cjs/compactNote.js +167 -0
  9. package/dist/cjs/config.d.ts +82 -0
  10. package/dist/cjs/config.js +57 -0
  11. package/dist/cjs/events.d.ts +77 -0
  12. package/dist/cjs/events.js +167 -0
  13. package/dist/cjs/idl/privacy_pool.d.ts +5 -0
  14. package/dist/cjs/idl/privacy_pool.js +15218 -0
  15. package/dist/cjs/idl/privacy_pool.json +10313 -0
  16. package/dist/cjs/index.d.ts +16 -0
  17. package/dist/cjs/index.js +67 -0
  18. package/dist/cjs/merkle.d.ts +77 -0
  19. package/dist/cjs/merkle.js +156 -0
  20. package/dist/cjs/poseidon.d.ts +29 -0
  21. package/dist/cjs/poseidon.js +100 -0
  22. package/dist/cjs/program.d.ts +37 -0
  23. package/dist/cjs/program.js +61 -0
  24. package/dist/cjs/proof.d.ts +183 -0
  25. package/dist/cjs/proof.js +292 -0
  26. package/dist/cjs/prover.d.ts +54 -0
  27. package/dist/cjs/prover.js +112 -0
  28. package/dist/cjs/random.d.ts +16 -0
  29. package/dist/cjs/random.js +28 -0
  30. package/dist/cjs/relayer.d.ts +318 -0
  31. package/dist/cjs/relayer.js +257 -0
  32. package/dist/cjs/retry.d.ts +32 -0
  33. package/dist/cjs/retry.js +75 -0
  34. package/dist/cjs/shield/alt.d.ts +87 -0
  35. package/dist/cjs/shield/alt.js +194 -0
  36. package/dist/cjs/shield/computeBudget.d.ts +61 -0
  37. package/dist/cjs/shield/computeBudget.js +64 -0
  38. package/dist/cjs/shield/errors.d.ts +58 -0
  39. package/dist/cjs/shield/errors.js +121 -0
  40. package/dist/cjs/shield/finalize.d.ts +45 -0
  41. package/dist/cjs/shield/finalize.js +119 -0
  42. package/dist/cjs/shield/index.d.ts +35 -0
  43. package/dist/cjs/shield/index.js +68 -0
  44. package/dist/cjs/shield/ix.d.ts +54 -0
  45. package/dist/cjs/shield/ix.js +119 -0
  46. package/dist/cjs/shield/owner.d.ts +36 -0
  47. package/dist/cjs/shield/owner.js +126 -0
  48. package/dist/cjs/shield/ports.d.ts +43 -0
  49. package/dist/cjs/shield/ports.js +153 -0
  50. package/dist/cjs/shield/preflight.d.ts +30 -0
  51. package/dist/cjs/shield/preflight.js +154 -0
  52. package/dist/cjs/shield/shield.d.ts +68 -0
  53. package/dist/cjs/shield/shield.js +499 -0
  54. package/dist/cjs/shield/types.d.ts +202 -0
  55. package/dist/cjs/shield/types.js +2 -0
  56. package/dist/cjs/utxo.d.ts +235 -0
  57. package/dist/cjs/utxo.js +407 -0
  58. package/dist/esm/client.d.ts +407 -0
  59. package/dist/esm/client.js +891 -0
  60. package/dist/esm/compactNote.d.ts +107 -0
  61. package/dist/esm/compactNote.js +156 -0
  62. package/dist/esm/config.d.ts +82 -0
  63. package/dist/esm/config.js +51 -0
  64. package/dist/esm/events.d.ts +77 -0
  65. package/dist/esm/events.js +129 -0
  66. package/dist/esm/idl/privacy_pool.d.ts +5 -0
  67. package/dist/esm/idl/privacy_pool.js +15216 -0
  68. package/dist/esm/idl/privacy_pool.json +10313 -0
  69. package/dist/esm/index.d.ts +16 -0
  70. package/dist/esm/index.js +29 -0
  71. package/dist/esm/merkle.d.ts +77 -0
  72. package/dist/esm/merkle.js +151 -0
  73. package/dist/esm/package.json +1 -0
  74. package/dist/esm/poseidon.d.ts +29 -0
  75. package/dist/esm/poseidon.js +87 -0
  76. package/dist/esm/program.d.ts +37 -0
  77. package/dist/esm/program.js +53 -0
  78. package/dist/esm/proof.d.ts +183 -0
  79. package/dist/esm/proof.js +281 -0
  80. package/dist/esm/prover.d.ts +54 -0
  81. package/dist/esm/prover.js +75 -0
  82. package/dist/esm/random.d.ts +16 -0
  83. package/dist/esm/random.js +21 -0
  84. package/dist/esm/relayer.d.ts +318 -0
  85. package/dist/esm/relayer.js +249 -0
  86. package/dist/esm/retry.d.ts +32 -0
  87. package/dist/esm/retry.js +71 -0
  88. package/dist/esm/shield/alt.d.ts +87 -0
  89. package/dist/esm/shield/alt.js +186 -0
  90. package/dist/esm/shield/computeBudget.d.ts +61 -0
  91. package/dist/esm/shield/computeBudget.js +61 -0
  92. package/dist/esm/shield/errors.d.ts +58 -0
  93. package/dist/esm/shield/errors.js +115 -0
  94. package/dist/esm/shield/finalize.d.ts +45 -0
  95. package/dist/esm/shield/finalize.js +83 -0
  96. package/dist/esm/shield/index.d.ts +35 -0
  97. package/dist/esm/shield/index.js +32 -0
  98. package/dist/esm/shield/ix.d.ts +54 -0
  99. package/dist/esm/shield/ix.js +82 -0
  100. package/dist/esm/shield/owner.d.ts +36 -0
  101. package/dist/esm/shield/owner.js +122 -0
  102. package/dist/esm/shield/ports.d.ts +43 -0
  103. package/dist/esm/shield/ports.js +147 -0
  104. package/dist/esm/shield/preflight.d.ts +30 -0
  105. package/dist/esm/shield/preflight.js +151 -0
  106. package/dist/esm/shield/shield.d.ts +68 -0
  107. package/dist/esm/shield/shield.js +492 -0
  108. package/dist/esm/shield/types.d.ts +202 -0
  109. package/dist/esm/shield/types.js +1 -0
  110. package/dist/esm/utxo.d.ts +235 -0
  111. package/dist/esm/utxo.js +382 -0
  112. package/dist/src/client.d.ts +407 -0
  113. package/dist/src/client.js +951 -0
  114. package/dist/src/compactNote.d.ts +107 -0
  115. package/dist/src/compactNote.js +167 -0
  116. package/dist/src/config.d.ts +82 -0
  117. package/dist/src/config.js +57 -0
  118. package/dist/src/events.d.ts +77 -0
  119. package/dist/src/events.js +167 -0
  120. package/dist/src/idl/privacy_pool.d.ts +5 -0
  121. package/dist/src/idl/privacy_pool.js +15218 -0
  122. package/dist/src/index.d.ts +16 -0
  123. package/dist/src/index.js +67 -0
  124. package/dist/src/merkle.d.ts +77 -0
  125. package/dist/src/merkle.js +156 -0
  126. package/dist/src/poseidon.d.ts +29 -0
  127. package/dist/src/poseidon.js +100 -0
  128. package/dist/src/program.d.ts +37 -0
  129. package/dist/src/program.js +61 -0
  130. package/dist/src/proof.d.ts +183 -0
  131. package/dist/src/proof.js +292 -0
  132. package/dist/src/prover.d.ts +54 -0
  133. package/dist/src/prover.js +112 -0
  134. package/dist/src/random.d.ts +16 -0
  135. package/dist/src/random.js +28 -0
  136. package/dist/src/relayer.d.ts +318 -0
  137. package/dist/src/relayer.js +257 -0
  138. package/dist/src/retry.d.ts +32 -0
  139. package/dist/src/retry.js +75 -0
  140. package/dist/src/shield/alt.d.ts +87 -0
  141. package/dist/src/shield/alt.js +194 -0
  142. package/dist/src/shield/computeBudget.d.ts +61 -0
  143. package/dist/src/shield/computeBudget.js +64 -0
  144. package/dist/src/shield/errors.d.ts +58 -0
  145. package/dist/src/shield/errors.js +121 -0
  146. package/dist/src/shield/finalize.d.ts +45 -0
  147. package/dist/src/shield/finalize.js +119 -0
  148. package/dist/src/shield/index.d.ts +35 -0
  149. package/dist/src/shield/index.js +68 -0
  150. package/dist/src/shield/ix.d.ts +54 -0
  151. package/dist/src/shield/ix.js +119 -0
  152. package/dist/src/shield/owner.d.ts +36 -0
  153. package/dist/src/shield/owner.js +126 -0
  154. package/dist/src/shield/ports.d.ts +43 -0
  155. package/dist/src/shield/ports.js +153 -0
  156. package/dist/src/shield/preflight.d.ts +30 -0
  157. package/dist/src/shield/preflight.js +154 -0
  158. package/dist/src/shield/shield.d.ts +68 -0
  159. package/dist/src/shield/shield.js +499 -0
  160. package/dist/src/shield/types.d.ts +202 -0
  161. package/dist/src/shield/types.js +2 -0
  162. package/dist/src/utxo.d.ts +235 -0
  163. package/dist/src/utxo.js +407 -0
  164. package/dist/tests/compact-note.test.d.ts +1 -0
  165. package/dist/tests/compact-note.test.js +173 -0
  166. package/dist/tests/config.test.d.ts +1 -0
  167. package/dist/tests/config.test.js +102 -0
  168. package/dist/tests/edge-cases.test.d.ts +1 -0
  169. package/dist/tests/edge-cases.test.js +220 -0
  170. package/dist/tests/encryption.test.d.ts +1 -0
  171. package/dist/tests/encryption.test.js +215 -0
  172. package/dist/tests/events.test.d.ts +1 -0
  173. package/dist/tests/events.test.js +78 -0
  174. package/dist/tests/multi-tree.test.d.ts +1 -0
  175. package/dist/tests/multi-tree.test.js +405 -0
  176. package/dist/tests/pda.test.d.ts +1 -0
  177. package/dist/tests/pda.test.js +229 -0
  178. package/dist/tests/poseidon-builder-parity.test.d.ts +1 -0
  179. package/dist/tests/poseidon-builder-parity.test.js +72 -0
  180. package/dist/tests/poseidon.test.d.ts +1 -0
  181. package/dist/tests/poseidon.test.js +142 -0
  182. package/dist/tests/proof.test.d.ts +1 -0
  183. package/dist/tests/proof.test.js +296 -0
  184. package/dist/tests/relayer.test.d.ts +1 -0
  185. package/dist/tests/relayer.test.js +271 -0
  186. package/dist/tests/sdk.integration.test.d.ts +1 -0
  187. package/dist/tests/sdk.integration.test.js +330 -0
  188. package/dist/tests/shield-owner.test.d.ts +1 -0
  189. package/dist/tests/shield-owner.test.js +89 -0
  190. package/dist/tests/shield-preflight.test.d.ts +1 -0
  191. package/dist/tests/shield-preflight.test.js +87 -0
  192. package/dist/tests/shield-realproof.test.d.ts +1 -0
  193. package/dist/tests/shield-realproof.test.js +272 -0
  194. package/dist/tests/shield.test.d.ts +1 -0
  195. package/dist/tests/shield.test.js +403 -0
  196. package/dist/tests/utxo.test.d.ts +1 -0
  197. package/dist/tests/utxo.test.js +140 -0
  198. package/package.json +105 -11
  199. package/poseidon.d.ts +2 -0
  200. package/poseidon.js +4 -0
  201. package/proof.d.ts +2 -0
  202. package/proof.js +4 -0
  203. package/prover.d.ts +2 -0
  204. package/prover.js +4 -0
  205. package/shield.d.ts +2 -0
  206. package/shield.js +4 -0
  207. package/src/client.ts +0 -352
  208. package/src/config.ts +0 -13
  209. package/src/index.ts +0 -6
  210. package/src/merkle.ts +0 -178
  211. package/src/note.ts +0 -193
  212. package/src/poseidon.ts +0 -62
  213. package/src/proof.ts +0 -170
  214. package/test/script.js +0 -0
  215. package/test-tsconfig.json +0 -19
  216. package/tests/note.test.ts +0 -50
  217. package/tests/sdk.integration.test.ts +0 -210
  218. package/tsconfig.json +0 -18
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("mocha");
4
+ const assert_1 = require("assert");
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ const src_1 = require("../src");
7
+ const OWNER_RELAYER = "https://relayer-server.onrender.com";
8
+ function json(body, status = 200) {
9
+ return new Response(JSON.stringify(body), {
10
+ status,
11
+ headers: { "Content-Type": "application/json" },
12
+ });
13
+ }
14
+ describe("resolveShieldOwner()", () => {
15
+ const originalFetch = globalThis.fetch;
16
+ afterEach(() => {
17
+ globalThis.fetch = originalFetch;
18
+ });
19
+ it("uses Veilo's default owner service without exposing a client parameter", async () => {
20
+ const wallet = web3_js_1.Keypair.generate().publicKey;
21
+ let requestedUrl = "";
22
+ let requestedHeaders;
23
+ globalThis.fetch = async (input, init) => {
24
+ requestedUrl = String(input);
25
+ requestedHeaders = init?.headers;
26
+ return json({
27
+ success: true,
28
+ username: "alice",
29
+ pubK: wallet.toBase58(),
30
+ veiloPublicKey: "123456789",
31
+ });
32
+ };
33
+ const owner = await (0, src_1.resolveShieldOwner)({ username: "alice" });
34
+ assert_1.strict.equal(requestedUrl, `${OWNER_RELAYER}/api/auth/veiloPublicKey?username=alice`);
35
+ assert_1.strict.equal(new Headers(requestedHeaders).has("x-api-key"), false, "public owner lookup must not embed a client-side API secret");
36
+ assert_1.strict.equal(owner.veiloPublicKey, 123456789n);
37
+ assert_1.strict.equal(owner.noteViewingKey.toBase58(), wallet.toBase58());
38
+ assert_1.strict.equal(owner.acknowledgeOwnerInvariant, true);
39
+ });
40
+ it("pre-registers an unknown Solana address through the same default service", async () => {
41
+ const wallet = web3_js_1.Keypair.generate().publicKey;
42
+ const requests = [];
43
+ globalThis.fetch = async (input, init) => {
44
+ requests.push({
45
+ url: String(input),
46
+ method: init?.method,
47
+ body: typeof init?.body === "string" ? init.body : undefined,
48
+ });
49
+ if (requests.length === 1) {
50
+ return json({ success: false, error: "not found" }, 404);
51
+ }
52
+ return json({ success: true, veiloPublicKey: "987654321" });
53
+ };
54
+ const owner = await (0, src_1.resolveShieldOwner)({ publicKey: wallet });
55
+ assert_1.strict.equal(requests[0].url, `${OWNER_RELAYER}/api/auth/veiloPublicKey?publicKey=${wallet.toBase58()}`);
56
+ assert_1.strict.equal(requests[1].url, `${OWNER_RELAYER}/api/auth/pre-register-key`);
57
+ assert_1.strict.equal(requests[1].method, "POST");
58
+ assert_1.strict.deepEqual(JSON.parse(requests[1].body), {
59
+ solanaAddress: wallet.toBase58(),
60
+ });
61
+ assert_1.strict.equal(owner.veiloPublicKey, 987654321n);
62
+ assert_1.strict.equal(owner.noteViewingKey.toBase58(), wallet.toBase58());
63
+ assert_1.strict.equal(owner.acknowledgeOwnerInvariant, true);
64
+ });
65
+ it("rejects a lookup that returns only one half of the owner", async () => {
66
+ globalThis.fetch = async () => json({ success: true, pubK: web3_js_1.Keypair.generate().publicKey.toBase58() });
67
+ await assert_1.strict.rejects((0, src_1.resolveShieldOwner)({ username: "alice" }), (error) => {
68
+ assert_1.strict.ok(error instanceof src_1.ShieldError);
69
+ assert_1.strict.match(error.message, /both keys/i);
70
+ return true;
71
+ });
72
+ });
73
+ it("rejects a public-key lookup if Veilo returns a different wallet", async () => {
74
+ const requested = web3_js_1.Keypair.generate().publicKey;
75
+ const returned = web3_js_1.Keypair.generate().publicKey;
76
+ globalThis.fetch = async () => json({
77
+ success: true,
78
+ pubK: returned.toBase58(),
79
+ veiloPublicKey: "123",
80
+ });
81
+ await assert_1.strict.rejects((0, src_1.resolveShieldOwner)({ publicKey: requested }), (error) => {
82
+ assert_1.strict.ok(error instanceof src_1.ShieldError);
83
+ assert_1.strict.match(error.message, /different wallet/i);
84
+ assert_1.strict.equal(error.context?.requested, requested.toBase58());
85
+ assert_1.strict.equal(error.context?.returned, returned.toBase58());
86
+ return true;
87
+ });
88
+ });
89
+ });
@@ -0,0 +1 @@
1
+ import "mocha";
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("mocha");
4
+ const assert_1 = require("assert");
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ const spl_token_1 = require("@solana/spl-token");
7
+ const src_1 = require("../src");
8
+ const USDC = new web3_js_1.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
9
+ describe("preflightShield()", () => {
10
+ it("rejects a zero-allowance delegate and returns a revoke remedy", async () => {
11
+ const signer = web3_js_1.Keypair.generate().publicKey;
12
+ const delegate = web3_js_1.Keypair.generate().publicKey;
13
+ const tokenAccount = web3_js_1.Keypair.generate().publicKey;
14
+ const data = Buffer.alloc(spl_token_1.AccountLayout.span);
15
+ spl_token_1.AccountLayout.encode({
16
+ mint: USDC,
17
+ owner: signer,
18
+ amount: 10000000n,
19
+ delegateOption: 1,
20
+ delegate,
21
+ state: spl_token_1.AccountState.Initialized,
22
+ isNativeOption: 0,
23
+ isNative: 0n,
24
+ delegatedAmount: 0n,
25
+ closeAuthorityOption: 0,
26
+ closeAuthority: web3_js_1.PublicKey.default,
27
+ }, data);
28
+ const connection = {
29
+ async getAccountInfo() {
30
+ return {
31
+ data,
32
+ executable: false,
33
+ lamports: 0,
34
+ owner: spl_token_1.TOKEN_PROGRAM_ID,
35
+ rentEpoch: 0,
36
+ };
37
+ },
38
+ };
39
+ await assert_1.strict.rejects((0, src_1.preflightShield)({
40
+ connection,
41
+ amount: 1000000n,
42
+ mint: USDC,
43
+ signer: { publicKey: signer, tokenAccount },
44
+ options: { skipPoolState: true, skipBalance: true },
45
+ }), (error) => {
46
+ assert_1.strict.ok(error instanceof src_1.ShieldError);
47
+ assert_1.strict.equal(error.code, "TOKEN_ACCOUNT_DELEGATED");
48
+ assert_1.strict.equal(error.context?.delegatedAmount, "0");
49
+ assert_1.strict.equal(error.remedy?.instructions.length, 1);
50
+ assert_1.strict.equal(error.remedy?.instructions[0].programId.toBase58(), spl_token_1.TOKEN_PROGRAM_ID.toBase58());
51
+ return true;
52
+ });
53
+ });
54
+ it("uses the caller's zero priority fee in the SOL balance requirement", async () => {
55
+ const signer = web3_js_1.Keypair.generate().publicKey;
56
+ const amount = 1000n;
57
+ const rentPerMarker = 10n;
58
+ const exactlyEnough = amount + rentPerMarker * 2n + 5000n;
59
+ const connection = {
60
+ async getMinimumBalanceForRentExemption() {
61
+ return Number(rentPerMarker);
62
+ },
63
+ async getBalance() {
64
+ return Number(exactlyEnough);
65
+ },
66
+ };
67
+ await (0, src_1.preflightShield)({
68
+ connection,
69
+ amount,
70
+ mint: src_1.NATIVE_SOL_MINT,
71
+ signer: { publicKey: signer, tokenAccount: signer },
72
+ options: { skipPoolState: true },
73
+ computeUnitPriceMicroLamports: 0,
74
+ });
75
+ await assert_1.strict.rejects((0, src_1.preflightShield)({
76
+ connection,
77
+ amount,
78
+ mint: src_1.NATIVE_SOL_MINT,
79
+ signer: { publicKey: signer, tokenAccount: signer },
80
+ options: { skipPoolState: true },
81
+ }), (error) => {
82
+ assert_1.strict.ok(error instanceof src_1.ShieldError);
83
+ assert_1.strict.equal(error.code, "INSUFFICIENT_SOL");
84
+ return true;
85
+ });
86
+ });
87
+ });
@@ -0,0 +1 @@
1
+ import "mocha";
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ require("mocha");
40
+ const assert_1 = require("assert");
41
+ const fs_1 = require("fs");
42
+ const path_1 = require("path");
43
+ const web3_js_1 = require("@solana/web3.js");
44
+ const spl_token_1 = require("@solana/spl-token");
45
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
46
+ const src_1 = require("../src");
47
+ /**
48
+ * The test that proves the proof is real.
49
+ *
50
+ * Every other shield test stubs the prover, so they verify assembly, size, and
51
+ * ownership — but not the one thing everything else rests on: that the circuit
52
+ * inputs `shield()` constructs actually satisfy the transaction circuit. A
53
+ * shield that assembles perfectly and proves nothing is worthless, and the
54
+ * failure would only surface on-chain as a generic "proof verification failed".
55
+ *
56
+ * So this runs the REAL snarkjs prover against the REAL circuit artifacts and
57
+ * verifies the result against the REAL verification key — the same three files
58
+ * the deployed program's verifier was built from. No RPC and no wallet needed:
59
+ * proof validity is a property of the witness, not of the network.
60
+ *
61
+ * Skipped automatically when the artifacts are absent (they are large and live
62
+ * outside this package), so a fresh checkout still gets a green suite.
63
+ */
64
+ const ARTIFACT_ROOTS = [
65
+ (0, path_1.resolve)(__dirname, "../../privacy-program/zk/circuits"),
66
+ (0, path_1.resolve)(process.cwd(), "../privacy-program/zk/circuits"),
67
+ ];
68
+ function findArtifacts() {
69
+ for (const root of ARTIFACT_ROOTS) {
70
+ const wasm = (0, path_1.resolve)(root, "transaction/transaction_js/transaction.wasm");
71
+ const zkey = (0, path_1.resolve)(root, "transaction/transaction_final.zkey");
72
+ const vkey = (0, path_1.resolve)(root, "transaction/transaction_verification_key.json");
73
+ if ((0, fs_1.existsSync)(wasm) && (0, fs_1.existsSync)(zkey) && (0, fs_1.existsSync)(vkey)) {
74
+ return { wasm, zkey, vkey };
75
+ }
76
+ }
77
+ return null;
78
+ }
79
+ const artifacts = findArtifacts();
80
+ (artifacts ? describe : describe.skip)("shield() with the real prover", function () {
81
+ this.timeout(600000);
82
+ let groth16;
83
+ let vkey;
84
+ before(async function () {
85
+ await (0, src_1.initPoseidon)();
86
+ try {
87
+ ({ groth16 } = await Promise.resolve().then(() => __importStar(require("snarkjs"))));
88
+ }
89
+ catch {
90
+ this.skip();
91
+ }
92
+ vkey = JSON.parse((0, fs_1.readFileSync)(artifacts.vkey, "utf8"));
93
+ });
94
+ async function stubAlt(mint, outputTreeId) {
95
+ return new web3_js_1.AddressLookupTableAccount({
96
+ key: web3_js_1.PublicKey.unique(),
97
+ state: {
98
+ deactivationSlot: BigInt("18446744073709551615"),
99
+ lastExtendedSlot: 0,
100
+ lastExtendedSlotStartIndex: 0,
101
+ authority: undefined,
102
+ addresses: (0, src_1.requiredAltKeys)({ mint, outputTreeId }).map((k) => k.address),
103
+ },
104
+ });
105
+ }
106
+ const connection = {
107
+ getLatestBlockhash: async () => ({
108
+ blockhash: "11111111111111111111111111111111",
109
+ lastValidBlockHeight: 1,
110
+ }),
111
+ getMinimumBalanceForRentExemption: async () => 961680,
112
+ };
113
+ /**
114
+ * The real prover, capturing the public signals so we can verify them
115
+ * independently of the proof itself.
116
+ */
117
+ function realProver(capture) {
118
+ return async (inputs) => {
119
+ const { formatInputsForSnarkjs } = await Promise.resolve().then(() => __importStar(require("../src/proof.js")));
120
+ const { proof, publicSignals } = await groth16.fullProve(formatInputsForSnarkjs(inputs), artifacts.wasm, artifacts.zkey);
121
+ capture.publicSignals = publicSignals;
122
+ return proof;
123
+ };
124
+ }
125
+ async function runShield(opts = {}) {
126
+ const mint = opts.mint ?? src_1.NATIVE_SOL_MINT;
127
+ const amount = opts.amount ?? 1500000000n;
128
+ const outputTreeId = opts.outputTreeId ?? 0;
129
+ // The recipient is a completely separate party from the signer — this is
130
+ // the shield-to-someone-else case, which is the whole point of the feature.
131
+ const recipientWallet = tweetnacl_1.default.sign.keyPair();
132
+ const recipientVeiloKey = (0, src_1.generateKeypair)();
133
+ const owner = (0, src_1.unsafeShieldOwner)({
134
+ veiloPublicKey: recipientVeiloKey.publicKey,
135
+ noteViewingKey: new web3_js_1.PublicKey(recipientWallet.publicKey),
136
+ acknowledgeOwnerInvariant: true,
137
+ });
138
+ const signerPubkey = web3_js_1.PublicKey.unique();
139
+ const capture = {};
140
+ const result = await (0, src_1.shield)({
141
+ connection,
142
+ amount,
143
+ mint,
144
+ owner,
145
+ signer: {
146
+ publicKey: signerPubkey,
147
+ tokenAccount: mint.equals(src_1.NATIVE_SOL_MINT)
148
+ ? undefined
149
+ : await (0, spl_token_1.getAssociatedTokenAddress)(mint, signerPubkey),
150
+ },
151
+ prover: realProver(capture),
152
+ treeSource: (0, src_1.staticTreeSource)({
153
+ inputTreeId: 0,
154
+ // A plausible root. Deposits do not constrain it (the circuit disables
155
+ // the Merkle check for zero-amount inputs) but it IS a public input, so
156
+ // it must survive into the proof unchanged.
157
+ inputRoot: (0, src_1.bigIntToBytesBE)(0x1f2e3d4c5b6a798897a6b5c4d3e2f10011223344556677889900aabbccddeeffn %
158
+ src_1.BN254_FR_MODULUS),
159
+ outputTreeId,
160
+ outputNextIndex: 7,
161
+ }),
162
+ alt: (0, src_1.explicitAlt)(await stubAlt(mint, outputTreeId)),
163
+ cache: (0, src_1.noCache)(),
164
+ preflight: false,
165
+ });
166
+ return { result, owner, recipientWallet, signerPubkey, capture, mint, amount };
167
+ }
168
+ it("produces a Groth16 proof that the real verification key accepts", async () => {
169
+ const { result, capture } = await runShield();
170
+ assert_1.strict.ok(capture.publicSignals, "prover did not return public signals");
171
+ // Reconstruct the snarkjs-shaped proof from what shield() cached, so we are
172
+ // verifying the bytes that actually go on-chain rather than the prover's
173
+ // own output object.
174
+ const raw = toSnarkjsProof(result.proofCache.proof);
175
+ const ok = await groth16.verify(vkey, capture.publicSignals, raw);
176
+ assert_1.strict.ok(ok, "the real verification key REJECTED the proof shield() built — the circuit " +
177
+ "inputs are wrong and every shield would fail on-chain with 'proof verification failed'");
178
+ });
179
+ it("commits the public inputs the instruction actually carries", async () => {
180
+ const { result, capture, amount } = await runShield({ amount: 2000000n });
181
+ const signals = capture.publicSignals;
182
+ // The circuit's public signals, in order, are the same eight values the
183
+ // program reads back out of the instruction. If these drift, the on-chain
184
+ // verifier rejects even though snarkjs is happy — so check them explicitly
185
+ // against what got encoded, not against what we passed in.
186
+ const cache = result.proofCache;
187
+ const asField = (hex) => (0, src_1.bytesToBigIntBE)(unhex(hex)) % src_1.BN254_FR_MODULUS;
188
+ const bySignal = signals.map((s) => BigInt(s));
189
+ const expected = new Set([
190
+ asField(cache.root),
191
+ asField(cache.extDataHash),
192
+ asField(cache.inputNullifiers[0]),
193
+ asField(cache.inputNullifiers[1]),
194
+ asField(cache.outputCommitments[0]),
195
+ asField(cache.outputCommitments[1]),
196
+ ].map((v) => v.toString()));
197
+ for (const want of expected) {
198
+ assert_1.strict.ok(bySignal.some((s) => s.toString() === want), `public signal ${want} is committed by the proof but absent from the ` +
199
+ `instruction encoding — the on-chain verifier would reject this`);
200
+ }
201
+ // The deposit amount must appear as the (positive) public amount.
202
+ assert_1.strict.equal(cache.publicAmount, amount.toString());
203
+ });
204
+ it("binds ext_data_hash to the ExtData the instruction encodes", async () => {
205
+ const { result, signerPubkey } = await runShield();
206
+ const cache = result.proofCache;
207
+ const recomputed = (0, src_1.computeExtDataHash)({
208
+ recipient: new web3_js_1.PublicKey(cache.extData.recipient),
209
+ relayer: new web3_js_1.PublicKey(cache.extData.relayer),
210
+ fee: BigInt(cache.extData.fee),
211
+ refund: BigInt(cache.extData.refund),
212
+ claimant: new web3_js_1.PublicKey(cache.extData.claimant),
213
+ });
214
+ assert_1.strict.equal(Buffer.from(recomputed).toString("hex"), cache.extDataHash, "ext_data_hash does not match the encoded ExtData — the program checks this " +
215
+ "equality before verifying the proof and would reject with InvalidExtData");
216
+ assert_1.strict.equal(cache.extData.relayer, signerPubkey.toBase58());
217
+ // The claimant slot must be the default for flows without claimant-gated
218
+ // recovery; a non-default value here silently changes the hash.
219
+ assert_1.strict.equal(cache.extData.claimant, "11111111111111111111111111111111");
220
+ });
221
+ it("creates a note only the recipient can find, from a signer who is not the owner", async () => {
222
+ const { result, owner, recipientWallet, signerPubkey, mint, amount } = await runShield({ amount: 3000000000n });
223
+ // The signer is nobody's owner here.
224
+ assert_1.strict.notEqual(owner.noteViewingKey.toBase58(), signerPubkey.toBase58());
225
+ const recovered = (0, src_1.decryptCompactNoteCipher)(recipientWallet.secretKey, result.note.compact.ephemeralPublicKey, result.note.compact.compactBlob);
226
+ assert_1.strict.ok(recovered, "the recipient could not decrypt the note meant for them");
227
+ assert_1.strict.equal(recovered.amount, amount);
228
+ // And the recovered secret must reconstruct the on-chain commitment — this
229
+ // is what makes the note actually spendable rather than merely readable.
230
+ const rebuilt = (0, src_1.commitUTXO)({
231
+ amount,
232
+ pubkey: owner.veiloPublicKey,
233
+ blinding: (0, src_1.bytesToBigIntBE)(recovered.blinding),
234
+ mintAddress: (0, src_1.pubkeyToField)(mint),
235
+ });
236
+ assert_1.strict.equal(Buffer.from(rebuilt).toString("hex"), Buffer.from(result.note.commitment).toString("hex"), "the decrypted blinding does not reproduce the committed note — the note " +
237
+ "would be undiscoverable and unspendable");
238
+ // The stranger check, restated on a real proof rather than a stubbed one.
239
+ const stranger = tweetnacl_1.default.sign.keyPair();
240
+ assert_1.strict.equal((0, src_1.decryptCompactNoteCipher)(stranger.secretKey, result.note.compact.ephemeralPublicKey, result.note.compact.compactBlob), null);
241
+ });
242
+ it("proves an SPL shield as well as a native one", async () => {
243
+ const USDC = new web3_js_1.PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
244
+ const { result, capture } = await runShield({ mint: USDC, amount: 25000000n });
245
+ const ok = await groth16.verify(vkey, capture.publicSignals, toSnarkjsProof(result.proofCache.proof));
246
+ assert_1.strict.ok(ok, "the SPL shield's proof was rejected by the verification key");
247
+ });
248
+ });
249
+ // -- helpers ------------------------------------------------------------------
250
+ const unhex = (s) => new Uint8Array(Buffer.from(s, "hex"));
251
+ /**
252
+ * Turn the packed on-chain proof back into the snarkjs object shape.
253
+ *
254
+ * `encodeSnarkjsProofToTransactionProof` swaps the G2 coordinate pairs for
255
+ * alt_bn128, so the inverse has to swap them back. Round-tripping through this
256
+ * is deliberate: it verifies the exact 256 bytes the instruction carries, not
257
+ * the prover's output.
258
+ */
259
+ function toSnarkjsProof(packed) {
260
+ const be = (bytes, from) => BigInt("0x" + Buffer.from(bytes.slice(from, from + 32)).toString("hex")).toString();
261
+ return {
262
+ pi_a: [be(packed.proofA, 0), be(packed.proofA, 32), "1"],
263
+ pi_b: [
264
+ [be(packed.proofB, 32), be(packed.proofB, 0)],
265
+ [be(packed.proofB, 96), be(packed.proofB, 64)],
266
+ ["1", "0"],
267
+ ],
268
+ pi_c: [be(packed.proofC, 0), be(packed.proofC, 32), "1"],
269
+ protocol: "groth16",
270
+ curve: "bn128",
271
+ };
272
+ }
@@ -0,0 +1 @@
1
+ import "mocha";