@metoncash/sdk-v1 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/dist/prover.js ADDED
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ /**
3
+ * prover.ts — Build Groth16 proofs for the deposit / withdraw / transfer circuits.
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.MetonSDK = void 0;
40
+ const path = __importStar(require("path"));
41
+ const snarkjs = __importStar(require("snarkjs"));
42
+ const jubjub_1 = require("./jubjub");
43
+ const note_1 = require("./note");
44
+ class MetonSDK {
45
+ constructor(cfg) {
46
+ this.cfg = cfg;
47
+ }
48
+ /**
49
+ * Convenience: derive artifact paths from a build directory laid out as this
50
+ * repo's `npm run build` / `npm run setup` produce:
51
+ * <dir>/<c>/<c>_js/<c>.wasm and <dir>/<c>/<c>_final.zkey
52
+ */
53
+ static fromBuildDir(dir) {
54
+ const mk = (c) => ({
55
+ wasm: path.join(dir, c, `${c}_js`, `${c}.wasm`),
56
+ zkey: path.join(dir, c, `${c}_final.zkey`),
57
+ });
58
+ return new MetonSDK({ deposit: mk("deposit"), withdraw: mk("withdraw"), transfer: mk("transfer") });
59
+ }
60
+ prove(art, input) {
61
+ return snarkjs.groth16.fullProve(input, art.wasm, art.zkey);
62
+ }
63
+ /** Deposit a public `amount`, producing a commitment to it. */
64
+ async deposit(args) {
65
+ const blinding = args.blinding ?? (0, jubjub_1.randomScalar)(252);
66
+ const [cx, cy] = (0, jubjub_1.commit)(args.amount, blinding);
67
+ const { proof, publicSignals } = await this.prove(this.cfg.deposit, {
68
+ amount: args.amount.toString(),
69
+ commitment_x: cx.toString(),
70
+ commitment_y: cy.toString(),
71
+ seqNo: args.seqNo.toString(),
72
+ account_id: args.accountId.toString(),
73
+ blinding: blinding.toString(),
74
+ });
75
+ return { proof, publicSignals, commitment: [cx, cy], blinding };
76
+ }
77
+ /** Withdraw a public `amount`, proving `balance ≥ amount`. */
78
+ async withdraw(args) {
79
+ const newBlind = args.newBlind ?? (0, jubjub_1.randomScalar)(252);
80
+ const remainder = args.balance - args.amount;
81
+ const [ox, oy] = (0, jubjub_1.commit)(args.balance, args.oldBlind);
82
+ const [nx, ny] = (0, jubjub_1.commit)(remainder, newBlind);
83
+ const { proof, publicSignals } = await this.prove(this.cfg.withdraw, {
84
+ amount: args.amount.toString(),
85
+ old_commitment_x: ox.toString(),
86
+ old_commitment_y: oy.toString(),
87
+ new_commitment_x: nx.toString(),
88
+ new_commitment_y: ny.toString(),
89
+ seqNo: args.seqNo.toString(),
90
+ account_id: args.accountId.toString(),
91
+ balance: args.balance.toString(),
92
+ old_blind: args.oldBlind.toString(),
93
+ new_blind: newBlind.toString(),
94
+ });
95
+ return { proof, publicSignals, newCommitment: [nx, ny], remainder, newBlind };
96
+ }
97
+ /** Private transfer of a hidden `amount` to a receiver's viewing key. */
98
+ async transfer(args) {
99
+ const senderNewBlind = args.senderNewBlind ?? (0, jubjub_1.randomScalar)(252);
100
+ const remainder = args.senderBalance - args.amount;
101
+ // Homomorphic relation old == new ⊕ amount holds for amount_blind below.
102
+ const amountBlind = args.amountBlind ?? (0, jubjub_1.mod)(args.senderOldBlind - senderNewBlind + jubjub_1.L, jubjub_1.L);
103
+ const ephScalar = args.ephScalar ?? (0, jubjub_1.randomScalar)(252);
104
+ const [ox, oy] = (0, jubjub_1.commit)(args.senderBalance, args.senderOldBlind);
105
+ const [snx, sny] = (0, jubjub_1.commit)(remainder, senderNewBlind);
106
+ const [amx, amy] = (0, jubjub_1.commit)(args.amount, amountBlind);
107
+ const [pkx, pky] = args.receiverViewPk;
108
+ const note = (0, note_1.encryptNote)(args.amount, amountBlind, pkx, pky, ephScalar);
109
+ const { proof, publicSignals } = await this.prove(this.cfg.transfer, {
110
+ old_sender_cx: ox.toString(),
111
+ old_sender_cy: oy.toString(),
112
+ new_sender_cx: snx.toString(),
113
+ new_sender_cy: sny.toString(),
114
+ amount_commit_x: amx.toString(),
115
+ amount_commit_y: amy.toString(),
116
+ receiver_view_pk_x: pkx.toString(),
117
+ receiver_view_pk_y: pky.toString(),
118
+ ephemeral_x: note.Rx.toString(),
119
+ ephemeral_y: note.Ry.toString(),
120
+ enc_amount: note.enc_amount.toString(),
121
+ enc_blind: note.enc_blind.toString(),
122
+ seqNo: args.seqNo.toString(),
123
+ account_id: args.accountId.toString(),
124
+ sender_balance: args.senderBalance.toString(),
125
+ sender_old_blind: args.senderOldBlind.toString(),
126
+ sender_new_blind: senderNewBlind.toString(),
127
+ amount: args.amount.toString(),
128
+ amount_blind: amountBlind.toString(),
129
+ eph_scalar: ephScalar.toString(),
130
+ });
131
+ return {
132
+ proof,
133
+ publicSignals,
134
+ newSenderCommitment: [snx, sny],
135
+ amountCommitment: [amx, amy],
136
+ note,
137
+ remainder,
138
+ senderNewBlind,
139
+ amountBlind,
140
+ ephScalar,
141
+ };
142
+ }
143
+ }
144
+ exports.MetonSDK = MetonSDK;
@@ -0,0 +1,2 @@
1
+ export { WalletKeys, generateWalletKeys, walletKeysFromSpend, viewKeyFromSpend } from "./keys";
2
+ export { SealNoteArgs, SealedNote, sealNote, openNote } from "./note";
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.openNote = exports.sealNote = exports.viewKeyFromSpend = exports.walletKeysFromSpend = exports.generateWalletKeys = void 0;
4
+ var keys_1 = require("./keys");
5
+ Object.defineProperty(exports, "generateWalletKeys", { enumerable: true, get: function () { return keys_1.generateWalletKeys; } });
6
+ Object.defineProperty(exports, "walletKeysFromSpend", { enumerable: true, get: function () { return keys_1.walletKeysFromSpend; } });
7
+ Object.defineProperty(exports, "viewKeyFromSpend", { enumerable: true, get: function () { return keys_1.viewKeyFromSpend; } });
8
+ var note_1 = require("./note");
9
+ Object.defineProperty(exports, "sealNote", { enumerable: true, get: function () { return note_1.sealNote; } });
10
+ Object.defineProperty(exports, "openNote", { enumerable: true, get: function () { return note_1.openNote; } });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * utils/keys.ts — wallet key generation.
3
+ *
4
+ * Each wallet has a SPEND key (authorizes spends; bound on-chain by address)
5
+ * and a VIEW key derived one-way from it. `viewSk` decrypts incoming notes and
6
+ * is safe to share with an auditor — it grants read access, not spend ability.
7
+ */
8
+ import { Point } from "../jubjub";
9
+ export interface WalletKeys {
10
+ spendSk: bigint;
11
+ spendPk: Point;
12
+ viewSk: bigint;
13
+ viewPk: Point;
14
+ }
15
+ /** Generate a fresh wallet keypair (random spend secret + derived view key). */
16
+ export declare function generateWalletKeys(): WalletKeys;
17
+ /** Derive the full key set from an existing spend secret. */
18
+ export declare function walletKeysFromSpend(spendSk: bigint): WalletKeys;
19
+ /** Derive just the viewing keypair (read-only; shareable for audit). */
20
+ export declare function viewKeyFromSpend(spendSk: bigint): {
21
+ viewSk: bigint;
22
+ viewPk: Point;
23
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * utils/keys.ts — wallet key generation.
4
+ *
5
+ * Each wallet has a SPEND key (authorizes spends; bound on-chain by address)
6
+ * and a VIEW key derived one-way from it. `viewSk` decrypts incoming notes and
7
+ * is safe to share with an auditor — it grants read access, not spend ability.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.generateWalletKeys = generateWalletKeys;
11
+ exports.walletKeysFromSpend = walletKeysFromSpend;
12
+ exports.viewKeyFromSpend = viewKeyFromSpend;
13
+ const jubjub_1 = require("../jubjub");
14
+ const note_1 = require("../note");
15
+ /** Generate a fresh wallet keypair (random spend secret + derived view key). */
16
+ function generateWalletKeys() {
17
+ return walletKeysFromSpend((0, jubjub_1.randomScalar)(252));
18
+ }
19
+ /** Derive the full key set from an existing spend secret. */
20
+ function walletKeysFromSpend(spendSk) {
21
+ const { skView, pkView } = (0, note_1.deriveViewKey)(spendSk);
22
+ return { spendSk, spendPk: (0, jubjub_1.derivePub)(spendSk), viewSk: skView, viewPk: pkView };
23
+ }
24
+ /** Derive just the viewing keypair (read-only; shareable for audit). */
25
+ function viewKeyFromSpend(spendSk) {
26
+ const { skView, pkView } = (0, note_1.deriveViewKey)(spendSk);
27
+ return { viewSk: skView, viewPk: pkView };
28
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * utils/note.ts — seal an encrypted note for a recipient.
3
+ *
4
+ * "Signing" a note here means producing the sender-side ECDH-sealed payload
5
+ * (R, enc_amount, enc_blind): a fresh ephemeral key R = k·G, with the amount and
6
+ * blind masked by a key derived from the ECDH shared secret k·pk_view. Only the
7
+ * holder of the recipient's viewing secret can open it. There is no separate
8
+ * signature — authenticity/secrecy come from the ECDH to the recipient's key.
9
+ */
10
+ import { Point } from "../jubjub";
11
+ import { Note } from "../note";
12
+ /** Minimal note fields needed to open it (the on-chain payload). */
13
+ export type SealedNote = Pick<Note, "Rx" | "Ry" | "enc_amount" | "enc_blind">;
14
+ export interface SealNoteArgs {
15
+ amount: bigint;
16
+ amountBlind: bigint;
17
+ receiverViewPk: Point;
18
+ /** Ephemeral scalar k. Defaults to fresh randomness — MUST be unique per note. */
19
+ ephScalar?: bigint;
20
+ }
21
+ /** Seal (encrypt) a note to the recipient's viewing key. */
22
+ export declare function sealNote(args: SealNoteArgs): Note;
23
+ /**
24
+ * Open a sealed note with the recipient's viewing secret, recovering the
25
+ * transferred amount and its blinding.
26
+ */
27
+ export declare function openNote(viewSk: bigint, note: SealedNote): {
28
+ amount: bigint;
29
+ amountBlind: bigint;
30
+ };
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /**
3
+ * utils/note.ts — seal an encrypted note for a recipient.
4
+ *
5
+ * "Signing" a note here means producing the sender-side ECDH-sealed payload
6
+ * (R, enc_amount, enc_blind): a fresh ephemeral key R = k·G, with the amount and
7
+ * blind masked by a key derived from the ECDH shared secret k·pk_view. Only the
8
+ * holder of the recipient's viewing secret can open it. There is no separate
9
+ * signature — authenticity/secrecy come from the ECDH to the recipient's key.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sealNote = sealNote;
13
+ exports.openNote = openNote;
14
+ const jubjub_1 = require("../jubjub");
15
+ const note_1 = require("../note");
16
+ /** Seal (encrypt) a note to the recipient's viewing key. */
17
+ function sealNote(args) {
18
+ const k = args.ephScalar ?? (0, jubjub_1.randomScalar)(252);
19
+ return (0, note_1.encryptNote)(args.amount, args.amountBlind, args.receiverViewPk[0], args.receiverViewPk[1], k);
20
+ }
21
+ /**
22
+ * Open a sealed note with the recipient's viewing secret, recovering the
23
+ * transferred amount and its blinding.
24
+ */
25
+ function openNote(viewSk, note) {
26
+ return (0, note_1.decryptNote)(viewSk, note.Rx, note.Ry, note.enc_amount, note.enc_blind);
27
+ }