@winbit32/wallet-kit 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 +21 -0
- package/README.md +117 -0
- package/dist/cosign/bytes.d.ts +10 -0
- package/dist/cosign/bytes.d.ts.map +1 -0
- package/dist/cosign/bytes.js +37 -0
- package/dist/cosign/bytes.js.map +1 -0
- package/dist/cosign/config.d.ts +58 -0
- package/dist/cosign/config.d.ts.map +1 -0
- package/dist/cosign/config.js +54 -0
- package/dist/cosign/config.js.map +1 -0
- package/dist/cosign/cosignSend.d.ts +104 -0
- package/dist/cosign/cosignSend.d.ts.map +1 -0
- package/dist/cosign/cosignSend.js +157 -0
- package/dist/cosign/cosignSend.js.map +1 -0
- package/dist/cosign/index.d.ts +33 -0
- package/dist/cosign/index.d.ts.map +1 -0
- package/dist/cosign/index.js +49 -0
- package/dist/cosign/index.js.map +1 -0
- package/dist/cosign/initiator.d.ts +121 -0
- package/dist/cosign/initiator.d.ts.map +1 -0
- package/dist/cosign/initiator.js +270 -0
- package/dist/cosign/initiator.js.map +1 -0
- package/dist/cosign/orchardFrost.d.ts +140 -0
- package/dist/cosign/orchardFrost.d.ts.map +1 -0
- package/dist/cosign/orchardFrost.js +227 -0
- package/dist/cosign/orchardFrost.js.map +1 -0
- package/dist/cosign/relay.d.ts +100 -0
- package/dist/cosign/relay.d.ts.map +1 -0
- package/dist/cosign/relay.js +359 -0
- package/dist/cosign/relay.js.map +1 -0
- package/dist/cosign/seed.d.ts +32 -0
- package/dist/cosign/seed.d.ts.map +1 -0
- package/dist/cosign/seed.js +69 -0
- package/dist/cosign/seed.js.map +1 -0
- package/dist/cosign/transports.d.ts +127 -0
- package/dist/cosign/transports.d.ts.map +1 -0
- package/dist/cosign/transports.js +426 -0
- package/dist/cosign/transports.js.map +1 -0
- package/dist/cosign/vaultShare.d.ts +65 -0
- package/dist/cosign/vaultShare.d.ts.map +1 -0
- package/dist/cosign/vaultShare.js +157 -0
- package/dist/cosign/vaultShare.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/monero/types.d.ts +75 -0
- package/dist/monero/types.d.ts.map +1 -0
- package/dist/monero/types.js +9 -0
- package/dist/monero/types.js.map +1 -0
- package/dist/scanner/baseUrl.d.ts +24 -0
- package/dist/scanner/baseUrl.d.ts.map +1 -0
- package/dist/scanner/baseUrl.js +35 -0
- package/dist/scanner/baseUrl.js.map +1 -0
- package/dist/scanner/moneroScannerClient.d.ts +97 -0
- package/dist/scanner/moneroScannerClient.d.ts.map +1 -0
- package/dist/scanner/moneroScannerClient.js +125 -0
- package/dist/scanner/moneroScannerClient.js.map +1 -0
- package/dist/scanner/zcashScannerClient.d.ts +116 -0
- package/dist/scanner/zcashScannerClient.d.ts.map +1 -0
- package/dist/scanner/zcashScannerClient.js +150 -0
- package/dist/scanner/zcashScannerClient.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Public surface of the WB32COSIGN co-signing client.
|
|
4
|
+
*
|
|
5
|
+
* Self-contained and framework-agnostic: load a WINBIT32 `.wult` share,
|
|
6
|
+
* derive the FROST UFVK / unified address, and drive a co-signed shielded
|
|
7
|
+
* send (QR pairing → two-round Orchard FROST ceremony → prove → broadcast)
|
|
8
|
+
* against any WB32COSIGN relay + NFPT PCZT endpoints. Wire format is
|
|
9
|
+
* byte-compatible with WINBIT32's `cosign.exe` and Secresea.
|
|
10
|
+
*
|
|
11
|
+
* Works in browsers and Node ≥ 18 (WebCrypto / Web Streams /
|
|
12
|
+
* BroadcastChannel are global in both; WebRTC is browser-only and skipped
|
|
13
|
+
* automatically by the transport factory).
|
|
14
|
+
*
|
|
15
|
+
* - `vaultShare` — load a WINBIT32 `.wult` co-signing share.
|
|
16
|
+
* - `config` — injectable host configuration (API/relay/WASM/network).
|
|
17
|
+
* - `orchardFrost` — Orchard FROST WASM engine (load, derive, ceremony ops).
|
|
18
|
+
* - `bytes` — hex/base64 helpers.
|
|
19
|
+
* - `seed` — deterministic vault-identity → Zcash seed (HKDF).
|
|
20
|
+
* - `transports` — WB32COSIGN message transports (BroadcastChannel/HTTP/WebRTC).
|
|
21
|
+
* - `relay` — session/QR, encrypted envelopes, Orchard FROST initiator.
|
|
22
|
+
* - `cosignSend` — PCZT send orchestration + thin PCZT API client.
|
|
23
|
+
* - `initiator` — headless full pipeline (scan → select → build → ceremony).
|
|
24
|
+
*/
|
|
25
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
28
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
29
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
30
|
+
}
|
|
31
|
+
Object.defineProperty(o, k2, desc);
|
|
32
|
+
}) : (function(o, m, k, k2) {
|
|
33
|
+
if (k2 === undefined) k2 = k;
|
|
34
|
+
o[k2] = m[k];
|
|
35
|
+
}));
|
|
36
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
37
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
__exportStar(require("./vaultShare"), exports);
|
|
41
|
+
__exportStar(require("./config"), exports);
|
|
42
|
+
__exportStar(require("./orchardFrost"), exports);
|
|
43
|
+
__exportStar(require("./bytes"), exports);
|
|
44
|
+
__exportStar(require("./seed"), exports);
|
|
45
|
+
__exportStar(require("./transports"), exports);
|
|
46
|
+
__exportStar(require("./relay"), exports);
|
|
47
|
+
__exportStar(require("./cosignSend"), exports);
|
|
48
|
+
__exportStar(require("./initiator"), exports);
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cosign/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;;;;;;;;;;;;;;AAEH,+CAA6B;AAC7B,2CAAyB;AACzB,iDAA+B;AAC/B,0CAAwB;AACxB,yCAAuB;AACvB,+CAA6B;AAC7B,0CAAwB;AACxB,+CAA6B;AAC7B,8CAA4B"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Headless co-sign initiator pipeline.
|
|
3
|
+
*
|
|
4
|
+
* The host-neutral remainder of Secresea's `CosignWalletService`: everything
|
|
5
|
+
* needed to drive "send shielded ZEC from a FROST vault, co-signed by a human
|
|
6
|
+
* on another device" without a browser or any UI framework:
|
|
7
|
+
*
|
|
8
|
+
* bundle (.wult) → derive UFVK/UA → scan notes (witness) → select notes
|
|
9
|
+
* (ZIP-317 fee) → POST /pczt/build → WB32COSIGN ceremony (QR pairing)
|
|
10
|
+
* → apply + prove → broadcast → txid.
|
|
11
|
+
*
|
|
12
|
+
* Designed for Node hosts (the payments-gateway MCP `make_payment` flow runs
|
|
13
|
+
* exactly this) as well as browsers. All I/O is injected: the wallet-scanner
|
|
14
|
+
* client comes from this package's `scanner/` module, the PCZT + relay
|
|
15
|
+
* endpoints from {@link CosignConfig}, and the WASM engine from the caller.
|
|
16
|
+
*/
|
|
17
|
+
import type { CosignConfig } from './config';
|
|
18
|
+
import type { CosignTransport } from './transports';
|
|
19
|
+
import { type CosignCallbacks, type CosignSessionParams, type SigningDisplay } from './relay';
|
|
20
|
+
import type { OrchardFrostWasmModule, OrchardKeyBundle } from './orchardFrost';
|
|
21
|
+
import type { WalletScannerClientType } from '../scanner/zcashScannerClient';
|
|
22
|
+
/** Orchard note commitment tree depth — a full witness has this many siblings. */
|
|
23
|
+
export declare const ORCHARD_MERKLE_DEPTH = 32;
|
|
24
|
+
/** Zatoshis per ZEC. */
|
|
25
|
+
export declare const ZATOSHIS_PER_ZEC = 100000000;
|
|
26
|
+
export declare const toZec: (zatoshis: number) => number;
|
|
27
|
+
export declare const toZatoshis: (zec: number) => number;
|
|
28
|
+
/** ZIP-317 conventional fee for the given action counts. */
|
|
29
|
+
export declare const estimateFeeZat: (numSpends: number, numOutputs: number) => number;
|
|
30
|
+
/** Raw note shape returned by the orchard-scanner (subset we consume). */
|
|
31
|
+
export interface ScannedNote {
|
|
32
|
+
commitment: string;
|
|
33
|
+
value: number;
|
|
34
|
+
nullifier?: string;
|
|
35
|
+
note_nullifier?: string;
|
|
36
|
+
rho?: string;
|
|
37
|
+
anchor_height: number;
|
|
38
|
+
anchor_root?: string;
|
|
39
|
+
leaf_position?: number | string;
|
|
40
|
+
merkle_path?: {
|
|
41
|
+
siblings?: string[];
|
|
42
|
+
};
|
|
43
|
+
note_plaintext?: {
|
|
44
|
+
diversifier?: string;
|
|
45
|
+
pk_d?: string;
|
|
46
|
+
rseed?: string;
|
|
47
|
+
value?: number;
|
|
48
|
+
};
|
|
49
|
+
block_height: number;
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
/** The scanner surface this pipeline needs (subset of the full client). */
|
|
53
|
+
export type ScannerForCosign = Pick<WalletScannerClientType, 'startOrchardScanJob' | 'getOrchardScanJob'>;
|
|
54
|
+
/**
|
|
55
|
+
* Coerce the `.wult` orchard payload into a validated {@link OrchardKeyBundle}.
|
|
56
|
+
* Throws a clear error if the share is missing the fields we need to co-sign.
|
|
57
|
+
*/
|
|
58
|
+
export declare const toOrchardBundle: (raw: unknown) => OrchardKeyBundle;
|
|
59
|
+
/**
|
|
60
|
+
* Map a scanned witness note → PCZT `SpendInput` (exact field names the
|
|
61
|
+
* orchard-scanner `build-pczt` deserialises). Requires a full witness
|
|
62
|
+
* (anchor root + leaf position + 32 siblings); throws otherwise so we never
|
|
63
|
+
* submit an unspendable note.
|
|
64
|
+
*/
|
|
65
|
+
export declare const noteToSpend: (note: ScannedNote) => Record<string, unknown>;
|
|
66
|
+
/**
|
|
67
|
+
* Greedily select notes (largest first) to cover `amountZat` plus the
|
|
68
|
+
* (count-dependent) ZIP-317 fee. Returns the chosen notes and the fee used.
|
|
69
|
+
*/
|
|
70
|
+
export declare const selectNotes: (notes: ScannedNote[], amountZat: number) => {
|
|
71
|
+
selected: ScannedNote[];
|
|
72
|
+
feeZat: number;
|
|
73
|
+
};
|
|
74
|
+
export interface ScanUfvkNotesParams {
|
|
75
|
+
scanner: ScannerForCosign;
|
|
76
|
+
ufvk: string;
|
|
77
|
+
birthdayHeight?: number;
|
|
78
|
+
apiKey?: string;
|
|
79
|
+
signal?: AbortSignal;
|
|
80
|
+
/** Override poll/timeout (tests). */
|
|
81
|
+
pollMs?: number;
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
}
|
|
84
|
+
/** Run a view-only witness scan of a FROST UFVK and return its notes. */
|
|
85
|
+
export declare const scanUfvkNotes: (p: ScanUfvkNotesParams) => Promise<ScannedNote[]>;
|
|
86
|
+
export interface HeadlessCosignSendParams {
|
|
87
|
+
config: CosignConfig;
|
|
88
|
+
wasm: OrchardFrostWasmModule;
|
|
89
|
+
/** Validated Orchard FROST bundle (see {@link toOrchardBundle}). */
|
|
90
|
+
bundle: OrchardKeyBundle;
|
|
91
|
+
/** UFVK + UA derived from the bundle (see `deriveOrchardAddressFromBundle`). */
|
|
92
|
+
ufvk: string;
|
|
93
|
+
unifiedAddress: string;
|
|
94
|
+
/** Optional ZIP-32 seed fingerprint for PCZT metadata. */
|
|
95
|
+
seedFingerprintHex?: string | null;
|
|
96
|
+
scanner: ScannerForCosign;
|
|
97
|
+
scannerApiKey?: string;
|
|
98
|
+
toAddress: string;
|
|
99
|
+
amountZat: number;
|
|
100
|
+
memoText?: string;
|
|
101
|
+
birthdayHeight?: number;
|
|
102
|
+
/** Fires with the WB32COSIGN QR payload once the session is created. */
|
|
103
|
+
onQrReady?: (qrPayload: string, session: CosignSessionParams) => void;
|
|
104
|
+
/** Override the default transport stack (tests / custom fabrics). */
|
|
105
|
+
createTransport?: (sessionId: string, encKeyHex: string) => CosignTransport;
|
|
106
|
+
callbacks?: CosignCallbacks;
|
|
107
|
+
/** Extra display fields shown on the cosigner's approval screen. */
|
|
108
|
+
display?: Partial<SigningDisplay>;
|
|
109
|
+
}
|
|
110
|
+
export interface HeadlessCosignSendResult {
|
|
111
|
+
txid: string;
|
|
112
|
+
signedPczt: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Drive a complete headless co-signed send: create the pairing session (QR),
|
|
116
|
+
* scan + select notes, build the PCZT server-side, run the per-action FROST
|
|
117
|
+
* ceremony with whoever scans the QR, then broadcast. Mirrors Secresea's
|
|
118
|
+
* `CosignWalletService.send` minus the UI wiring.
|
|
119
|
+
*/
|
|
120
|
+
export declare const runHeadlessCosignSend: (p: HeadlessCosignSendParams) => Promise<HeadlessCosignSendResult>;
|
|
121
|
+
//# sourceMappingURL=initiator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initiator.d.ts","sourceRoot":"","sources":["../../src/cosign/initiator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Headless co-sign initiator pipeline.
|
|
4
|
+
*
|
|
5
|
+
* The host-neutral remainder of Secresea's `CosignWalletService`: everything
|
|
6
|
+
* needed to drive "send shielded ZEC from a FROST vault, co-signed by a human
|
|
7
|
+
* on another device" without a browser or any UI framework:
|
|
8
|
+
*
|
|
9
|
+
* bundle (.wult) → derive UFVK/UA → scan notes (witness) → select notes
|
|
10
|
+
* (ZIP-317 fee) → POST /pczt/build → WB32COSIGN ceremony (QR pairing)
|
|
11
|
+
* → apply + prove → broadcast → txid.
|
|
12
|
+
*
|
|
13
|
+
* Designed for Node hosts (the payments-gateway MCP `make_payment` flow runs
|
|
14
|
+
* exactly this) as well as browsers. All I/O is injected: the wallet-scanner
|
|
15
|
+
* client comes from this package's `scanner/` module, the PCZT + relay
|
|
16
|
+
* endpoints from {@link CosignConfig}, and the WASM engine from the caller.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.runHeadlessCosignSend = exports.scanUfvkNotes = exports.selectNotes = exports.noteToSpend = exports.toOrchardBundle = exports.estimateFeeZat = exports.toZatoshis = exports.toZec = exports.ZATOSHIS_PER_ZEC = exports.ORCHARD_MERKLE_DEPTH = void 0;
|
|
20
|
+
const transports_1 = require("./transports");
|
|
21
|
+
const relay_1 = require("./relay");
|
|
22
|
+
const cosignSend_1 = require("./cosignSend");
|
|
23
|
+
// ─── Constants ──────────────────────────────────────────────────────
|
|
24
|
+
/** Orchard note commitment tree depth — a full witness has this many siblings. */
|
|
25
|
+
exports.ORCHARD_MERKLE_DEPTH = 32;
|
|
26
|
+
/** Zatoshis per ZEC. */
|
|
27
|
+
exports.ZATOSHIS_PER_ZEC = 100000000;
|
|
28
|
+
/** ZIP-317 marginal fee (zatoshis per logical action). */
|
|
29
|
+
const MARGINAL_FEE_ZAT = 5000;
|
|
30
|
+
/** ZIP-317 grace actions (fee is charged for at least this many). */
|
|
31
|
+
const GRACE_ACTIONS = 2;
|
|
32
|
+
/** Scan-job poll interval. */
|
|
33
|
+
const SCAN_POLL_MS = 4000;
|
|
34
|
+
/** Scan-job overall timeout. */
|
|
35
|
+
const SCAN_TIMEOUT_MS = 10 * 60 * 1000;
|
|
36
|
+
const HEX64 = /^[0-9a-fA-F]{64}$/;
|
|
37
|
+
const toZec = (zatoshis) => zatoshis / exports.ZATOSHIS_PER_ZEC;
|
|
38
|
+
exports.toZec = toZec;
|
|
39
|
+
const toZatoshis = (zec) => Math.round(zec * exports.ZATOSHIS_PER_ZEC);
|
|
40
|
+
exports.toZatoshis = toZatoshis;
|
|
41
|
+
/** ZIP-317 conventional fee for the given action counts. */
|
|
42
|
+
const estimateFeeZat = (numSpends, numOutputs) => MARGINAL_FEE_ZAT * Math.max(GRACE_ACTIONS, numSpends, numOutputs);
|
|
43
|
+
exports.estimateFeeZat = estimateFeeZat;
|
|
44
|
+
// ─── Bundle validation ──────────────────────────────────────────────
|
|
45
|
+
/**
|
|
46
|
+
* Coerce the `.wult` orchard payload into a validated {@link OrchardKeyBundle}.
|
|
47
|
+
* Throws a clear error if the share is missing the fields we need to co-sign.
|
|
48
|
+
*/
|
|
49
|
+
const toOrchardBundle = (raw) => {
|
|
50
|
+
const b = raw;
|
|
51
|
+
const share = b?.myShare;
|
|
52
|
+
const pkg = b?.publicKeyPackage;
|
|
53
|
+
if (!share?.id || !share.secretShare || !share.publicKey || !share.groupPublic) {
|
|
54
|
+
throw new Error('This share has no usable Orchard FROST key (missing myShare fields).');
|
|
55
|
+
}
|
|
56
|
+
if (!pkg?.groupPublic || !pkg.signerPubkeys) {
|
|
57
|
+
throw new Error('This share is missing its Orchard public key package.');
|
|
58
|
+
}
|
|
59
|
+
return b;
|
|
60
|
+
};
|
|
61
|
+
exports.toOrchardBundle = toOrchardBundle;
|
|
62
|
+
// ─── Note → spend mapping + selection ───────────────────────────────
|
|
63
|
+
/** Pick the first present, valid 64-hex value from a list of candidates. */
|
|
64
|
+
const firstHex64 = (...candidates) => {
|
|
65
|
+
for (const c of candidates) {
|
|
66
|
+
if (typeof c === 'string' && HEX64.test(c))
|
|
67
|
+
return c.toLowerCase();
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
const extractSiblings = (note) => {
|
|
72
|
+
const s = note.merkle_path?.siblings
|
|
73
|
+
?? note.merklePath?.siblings
|
|
74
|
+
?? note.merkle_path_siblings_hex
|
|
75
|
+
?? note.merklePathSiblingsHex;
|
|
76
|
+
return Array.isArray(s) ? s : [];
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Map a scanned witness note → PCZT `SpendInput` (exact field names the
|
|
80
|
+
* orchard-scanner `build-pczt` deserialises). Requires a full witness
|
|
81
|
+
* (anchor root + leaf position + 32 siblings); throws otherwise so we never
|
|
82
|
+
* submit an unspendable note.
|
|
83
|
+
*/
|
|
84
|
+
const noteToSpend = (note) => {
|
|
85
|
+
const diversifier = note.note_plaintext?.diversifier ?? note.diversifier;
|
|
86
|
+
const pkd = note.note_plaintext?.pk_d ?? note.pk_d;
|
|
87
|
+
const rseed = note.note_plaintext?.rseed ?? note.rseed;
|
|
88
|
+
const nullifierHex = firstHex64(note.note_nullifier, note.nullifier);
|
|
89
|
+
const rhoHex = firstHex64(note.rho, note.rho_hex);
|
|
90
|
+
const anchorRootHex = firstHex64(note.anchor_root, note.anchor_root_hex);
|
|
91
|
+
const siblings = extractSiblings(note);
|
|
92
|
+
const leafPosition = note.leaf_position ?? note.leafPosition;
|
|
93
|
+
if (!nullifierHex)
|
|
94
|
+
throw new Error('Note is missing its nullifier — rescan with witness=true.');
|
|
95
|
+
if (!rhoHex)
|
|
96
|
+
throw new Error('Note is missing rho — rescan with an up-to-date scanner.');
|
|
97
|
+
if (!anchorRootHex || leafPosition === undefined || siblings.length !== exports.ORCHARD_MERKLE_DEPTH) {
|
|
98
|
+
throw new Error('Note is missing a full Orchard witness (anchor/position/merkle path) — rescan with witness=true.');
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
noteCommitmentHex: note.commitment,
|
|
102
|
+
diversifierHex: diversifier,
|
|
103
|
+
pkdHex: pkd,
|
|
104
|
+
rseedHex: rseed,
|
|
105
|
+
rhoHex,
|
|
106
|
+
valueZatoshis: note.value,
|
|
107
|
+
anchorHeight: note.anchor_height,
|
|
108
|
+
anchorRootHex,
|
|
109
|
+
leafPosition: String(leafPosition),
|
|
110
|
+
merklePathSiblingsHex: siblings,
|
|
111
|
+
nullifierHex,
|
|
112
|
+
blockHeight: note.block_height,
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
exports.noteToSpend = noteToSpend;
|
|
116
|
+
/**
|
|
117
|
+
* Greedily select notes (largest first) to cover `amountZat` plus the
|
|
118
|
+
* (count-dependent) ZIP-317 fee. Returns the chosen notes and the fee used.
|
|
119
|
+
*/
|
|
120
|
+
const selectNotes = (notes, amountZat) => {
|
|
121
|
+
const sorted = [...notes].filter((n) => Number(n.value) > 0).sort((a, b) => b.value - a.value);
|
|
122
|
+
const selected = [];
|
|
123
|
+
let sum = 0;
|
|
124
|
+
for (const note of sorted) {
|
|
125
|
+
selected.push(note);
|
|
126
|
+
sum += Number(note.value);
|
|
127
|
+
// One recipient output; assume a change output for the fee estimate.
|
|
128
|
+
const feeZat = (0, exports.estimateFeeZat)(selected.length, 2);
|
|
129
|
+
if (sum >= amountZat + feeZat)
|
|
130
|
+
return { selected, feeZat };
|
|
131
|
+
}
|
|
132
|
+
const have = (0, exports.toZec)(sum).toFixed(8);
|
|
133
|
+
const need = (0, exports.toZec)(amountZat).toFixed(8);
|
|
134
|
+
throw new Error(`Insufficient shielded funds: have ${have} ZEC, need ${need} ZEC plus fee.`);
|
|
135
|
+
};
|
|
136
|
+
exports.selectNotes = selectNotes;
|
|
137
|
+
/** Run a view-only witness scan of a FROST UFVK and return its notes. */
|
|
138
|
+
const scanUfvkNotes = async (p) => {
|
|
139
|
+
const start = await p.scanner.startOrchardScanJob({
|
|
140
|
+
ufvk: p.ufvk,
|
|
141
|
+
witness: true,
|
|
142
|
+
autoDetect: p.birthdayHeight === undefined,
|
|
143
|
+
...(p.birthdayHeight !== undefined ? { birthdayHeight: p.birthdayHeight } : {}),
|
|
144
|
+
}, { apiKey: p.apiKey });
|
|
145
|
+
const jobId = start.data?.jobId;
|
|
146
|
+
const jobToken = start.data?.jobToken;
|
|
147
|
+
if (!jobId)
|
|
148
|
+
throw new Error('Scanner did not start a scan job.');
|
|
149
|
+
const deadline = Date.now() + (p.timeoutMs ?? SCAN_TIMEOUT_MS);
|
|
150
|
+
for (;;) {
|
|
151
|
+
if (p.signal?.aborted)
|
|
152
|
+
throw new Error('Scan cancelled.');
|
|
153
|
+
if (Date.now() > deadline)
|
|
154
|
+
throw new Error('Timed out scanning the wallet.');
|
|
155
|
+
const status = await p.scanner.getOrchardScanJob(jobId, { jobToken, apiKey: p.apiKey });
|
|
156
|
+
const job = status.data?.job;
|
|
157
|
+
if (job?.status === 'succeeded') {
|
|
158
|
+
return (job.results?.notes ?? []);
|
|
159
|
+
}
|
|
160
|
+
if (job?.status === 'failed') {
|
|
161
|
+
throw new Error(`Wallet scan failed: ${job.error ?? 'unknown error'}`);
|
|
162
|
+
}
|
|
163
|
+
await new Promise((r) => setTimeout(r, p.pollMs ?? SCAN_POLL_MS));
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
exports.scanUfvkNotes = scanUfvkNotes;
|
|
167
|
+
/**
|
|
168
|
+
* Drive a complete headless co-signed send: create the pairing session (QR),
|
|
169
|
+
* scan + select notes, build the PCZT server-side, run the per-action FROST
|
|
170
|
+
* ceremony with whoever scans the QR, then broadcast. Mirrors Secresea's
|
|
171
|
+
* `CosignWalletService.send` minus the UI wiring.
|
|
172
|
+
*/
|
|
173
|
+
const runHeadlessCosignSend = async (p) => {
|
|
174
|
+
if (!p.toAddress || !p.toAddress.startsWith('u1')) {
|
|
175
|
+
throw new Error('A unified (u1…) recipient address is required for shielded sends.');
|
|
176
|
+
}
|
|
177
|
+
if (!Number.isFinite(p.amountZat) || p.amountZat <= 0) {
|
|
178
|
+
throw new Error('Amount must be greater than zero.');
|
|
179
|
+
}
|
|
180
|
+
const bundle = (0, exports.toOrchardBundle)(p.bundle);
|
|
181
|
+
const { callbacks } = p;
|
|
182
|
+
// 1. Create the pairing session up-front so the human can scan while we build.
|
|
183
|
+
const { params, qrPayload } = (0, relay_1.createCosignSession)(p.config.relayBaseUrl);
|
|
184
|
+
p.onQrReady?.(qrPayload, params);
|
|
185
|
+
const transport = p.createTransport
|
|
186
|
+
? p.createTransport(params.sessionId, params.encKeyHex)
|
|
187
|
+
: (0, transports_1.createDefaultTransports)({
|
|
188
|
+
sessionId: params.sessionId,
|
|
189
|
+
relayBaseUrl: p.config.relayBaseUrl,
|
|
190
|
+
fetchImpl: p.config.fetchImpl,
|
|
191
|
+
myRole: 'init',
|
|
192
|
+
});
|
|
193
|
+
try {
|
|
194
|
+
// 2. Scan notes + select inputs.
|
|
195
|
+
callbacks?.onProgress?.('Scanning shielded notes...');
|
|
196
|
+
const notes = await (0, exports.scanUfvkNotes)({
|
|
197
|
+
scanner: p.scanner,
|
|
198
|
+
ufvk: p.ufvk,
|
|
199
|
+
birthdayHeight: p.birthdayHeight,
|
|
200
|
+
apiKey: p.scannerApiKey,
|
|
201
|
+
signal: callbacks?.signal,
|
|
202
|
+
});
|
|
203
|
+
const { selected, feeZat } = (0, exports.selectNotes)(notes, p.amountZat);
|
|
204
|
+
const spends = selected.map(exports.noteToSpend);
|
|
205
|
+
// 3. Assemble outputs (+ change back to ourselves).
|
|
206
|
+
const totalInZat = selected.reduce((s, n) => s + Number(n.value), 0);
|
|
207
|
+
const changeZat = totalInZat - p.amountZat - feeZat;
|
|
208
|
+
const memoHex = p.memoText
|
|
209
|
+
? Array.from(new TextEncoder().encode(p.memoText), (b) => b.toString(16).padStart(2, '0')).join('')
|
|
210
|
+
: undefined;
|
|
211
|
+
const outputs = [{
|
|
212
|
+
toUnifiedAddress: p.toAddress,
|
|
213
|
+
valueZatoshis: p.amountZat,
|
|
214
|
+
...(memoHex ? { memoHex } : {}),
|
|
215
|
+
}];
|
|
216
|
+
// 4. Build the unsigned PCZT server-side.
|
|
217
|
+
callbacks?.onProgress?.('Building the transaction...');
|
|
218
|
+
const built = await (0, cosignSend_1.buildPczt)(p.config, {
|
|
219
|
+
network: p.config.network,
|
|
220
|
+
...(p.seedFingerprintHex ? { seedFingerprintHex: p.seedFingerprintHex } : {}),
|
|
221
|
+
accountIndex: 0,
|
|
222
|
+
ufvk: p.ufvk,
|
|
223
|
+
feeZatoshis: feeZat,
|
|
224
|
+
spends,
|
|
225
|
+
outputs,
|
|
226
|
+
...(changeZat > 0 ? { changeUnifiedAddress: p.unifiedAddress } : {}),
|
|
227
|
+
});
|
|
228
|
+
if (!built?.pczt)
|
|
229
|
+
throw new Error('The server did not return a PCZT to sign.');
|
|
230
|
+
// 5. Co-sign each Orchard action with the remote cosigner, then broadcast.
|
|
231
|
+
const result = await (0, cosignSend_1.cosignSendPczt)({
|
|
232
|
+
config: p.config,
|
|
233
|
+
wasm: p.wasm,
|
|
234
|
+
encKeyHex: params.encKeyHex,
|
|
235
|
+
transport,
|
|
236
|
+
myPartyId: bundle.myShare.id,
|
|
237
|
+
share: {
|
|
238
|
+
id: bundle.myShare.id,
|
|
239
|
+
secretShare: bundle.myShare.secretShare,
|
|
240
|
+
publicKey: bundle.myShare.publicKey,
|
|
241
|
+
groupPublic: bundle.publicKeyPackage.groupPublic,
|
|
242
|
+
},
|
|
243
|
+
publicKeyPackage: {
|
|
244
|
+
signerPubkeys: bundle.publicKeyPackage.signerPubkeys,
|
|
245
|
+
groupPublic: bundle.publicKeyPackage.groupPublic,
|
|
246
|
+
},
|
|
247
|
+
unsignedPczt: built.pczt,
|
|
248
|
+
display: {
|
|
249
|
+
chain: 'Zcash',
|
|
250
|
+
ticker: 'ZEC',
|
|
251
|
+
amount: (0, exports.toZec)(p.amountZat).toString(),
|
|
252
|
+
toAddress: p.toAddress,
|
|
253
|
+
memo: p.memoText ?? '',
|
|
254
|
+
...p.display,
|
|
255
|
+
},
|
|
256
|
+
callbacks,
|
|
257
|
+
});
|
|
258
|
+
return { txid: result.txid, signedPczt: result.signedPczt };
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
// Tell the cosigner we're done and release the transport.
|
|
262
|
+
await (0, relay_1.endCosignSession)(params.encKeyHex, transport).catch(() => { });
|
|
263
|
+
try {
|
|
264
|
+
transport.close?.();
|
|
265
|
+
}
|
|
266
|
+
catch { /* best effort */ }
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
exports.runHeadlessCosignSend = runHeadlessCosignSend;
|
|
270
|
+
//# sourceMappingURL=initiator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initiator.js","sourceRoot":"","sources":["../../src/cosign/initiator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Orchard (RedPallas) FROST engine bridge.
|
|
3
|
+
*
|
|
4
|
+
* A framework-agnostic port of WINBIT32's `orchardFrostBridge` trimmed to
|
|
5
|
+
* the pieces an initiator needs: load the WASM, derive a UFVK / unified
|
|
6
|
+
* address from a FROST share, and (for tests / local 2-of-2) split a key
|
|
7
|
+
* with a trusted dealer. The two-round signing ceremony wrappers live here
|
|
8
|
+
* so their wire shapes stay matched to the relay protocol.
|
|
9
|
+
*
|
|
10
|
+
* Design for reuse: there is no module-global "current WASM" the way the
|
|
11
|
+
* original bridge keeps one. The loaded module is returned and passed
|
|
12
|
+
* explicitly into each function (dependency injection), so a host can run
|
|
13
|
+
* more than one engine instance and nothing leaks across React renders.
|
|
14
|
+
* The only internal state is a load cache keyed by asset URL.
|
|
15
|
+
*
|
|
16
|
+
* The underlying WASM is `orchard-frost-wasm` (built from frosty-lib /
|
|
17
|
+
* orchard-frost-wasm), served as static assets. See {@link CosignConfig}.
|
|
18
|
+
*/
|
|
19
|
+
import type { CosignConfig } from './config';
|
|
20
|
+
export interface OrchardFrostWasmModule {
|
|
21
|
+
/** Trusted-dealer split: returns JSON {shares, public_key_package}. */
|
|
22
|
+
keygen_with_dealer: (max_signers: number, min_signers: number) => string;
|
|
23
|
+
/** Round 1: opaque nonces + serialisable commitments for one signer. */
|
|
24
|
+
commit_nonces: (secret_share_hex: string) => string;
|
|
25
|
+
/** Round 2: a signature share, bound to the per-action randomizer. */
|
|
26
|
+
sign_with_nonces: (identifier_hex: string, secret_share_hex: string, public_hex: string, group_public_hex: string, nonces_opaque_hex: string, all_commitments_json: string, message_hex: string, randomizer_hex: string) => string;
|
|
27
|
+
/** Aggregate signature shares into a 64-byte RedPallas signature. */
|
|
28
|
+
aggregate: (commitments_json: string, message_hex: string, sig_shares_json: string, signer_pubkeys_json: string, group_public_hex: string, randomizer_hex: string) => string;
|
|
29
|
+
generate_randomizer: () => string;
|
|
30
|
+
get_group_verifying_key: (group_public_hex: string) => string;
|
|
31
|
+
/** Build an Orchard-only UFVK whose `ak` == the FROST group_public. */
|
|
32
|
+
build_orchard_ufvk_from_frost?: (group_public_hex: string, orchard_extras_hex: string) => string;
|
|
33
|
+
build_orchard_unified_address_from_frost?: (group_public_hex: string, orchard_extras_hex: string) => string;
|
|
34
|
+
/** Random 64-byte nk‖rivk extras compatible with a given group_public. */
|
|
35
|
+
orchard_random_extras?: (group_public_hex: string) => string;
|
|
36
|
+
/** wasm-bindgen (`--target web`) init entry point. */
|
|
37
|
+
default: (input: BufferSource | string | URL | Request | Response) => Promise<unknown>;
|
|
38
|
+
}
|
|
39
|
+
export interface OrchardKeyShare {
|
|
40
|
+
id: string;
|
|
41
|
+
secretShare: string;
|
|
42
|
+
publicKey: string;
|
|
43
|
+
groupPublic: string;
|
|
44
|
+
}
|
|
45
|
+
export interface OrchardPublicKeyPackage {
|
|
46
|
+
signerPubkeys: Record<string, string>;
|
|
47
|
+
groupPublic: string;
|
|
48
|
+
}
|
|
49
|
+
export interface OrchardKeyBundle {
|
|
50
|
+
myShare: OrchardKeyShare;
|
|
51
|
+
publicKeyPackage: OrchardPublicKeyPackage;
|
|
52
|
+
/** 64-byte nk‖rivk that, with the group_public (ak), forms the FVK. */
|
|
53
|
+
orchardExtras?: string;
|
|
54
|
+
minSigners?: number;
|
|
55
|
+
maxSigners?: number;
|
|
56
|
+
birthday?: number;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
export interface OrchardKeygenResult {
|
|
60
|
+
shares: Record<string, OrchardKeyShare>;
|
|
61
|
+
publicKeyPackage: OrchardPublicKeyPackage;
|
|
62
|
+
}
|
|
63
|
+
export interface OrchardKeygenWithExtras {
|
|
64
|
+
keygen: OrchardKeygenResult;
|
|
65
|
+
orchardExtras: string;
|
|
66
|
+
keygenAttempts: number;
|
|
67
|
+
}
|
|
68
|
+
export interface OrchardAddressResult {
|
|
69
|
+
unifiedAddress: string;
|
|
70
|
+
ufvk: string;
|
|
71
|
+
}
|
|
72
|
+
/** Attempts before giving up on producing an Orchard-compatible `ak`. */
|
|
73
|
+
export declare const DEFAULT_KEYGEN_RETRY_LIMIT = 32;
|
|
74
|
+
/**
|
|
75
|
+
* Load + initialise the Orchard FROST WASM.
|
|
76
|
+
*
|
|
77
|
+
* Uses `config.loadOrchardFrostWasm` when provided (hosts that bundle the WASM
|
|
78
|
+
* themselves). Otherwise lazily fetches the artefacts from `config.wasmBaseUrl`
|
|
79
|
+
* — the dynamic `import()` is deliberate: it keeps the ~500 KB engine off the
|
|
80
|
+
* critical path until a co-signing flow actually needs it.
|
|
81
|
+
*/
|
|
82
|
+
export declare const loadOrchardFrostWasm: (config: CosignConfig) => Promise<OrchardFrostWasmModule>;
|
|
83
|
+
/** Trusted-dealer t-of-n split (used by tests and local 2-of-2 setups). */
|
|
84
|
+
export declare const orchardKeygenWithDealer: (wasm: OrchardFrostWasmModule, maxSigners: number, minSigners: number) => OrchardKeygenResult;
|
|
85
|
+
/** Generate random 64-byte nk‖rivk extras compatible with `groupPublicHex`. */
|
|
86
|
+
export declare const generateOrchardExtras: (wasm: OrchardFrostWasmModule, groupPublicHex: string) => string;
|
|
87
|
+
/**
|
|
88
|
+
* Whether a 32-byte serialised group_public is a usable Orchard `ak`.
|
|
89
|
+
*
|
|
90
|
+
* Orchard's `SpendValidatingKey::from_bytes` rejects points whose y-sign bit
|
|
91
|
+
* (top bit of byte 31) is set, and the identity (all-zero) point. RedPallas
|
|
92
|
+
* keygen produces a random y-sign, so ~half of keygens are unusable as-is.
|
|
93
|
+
*/
|
|
94
|
+
export declare const isOrchardCompatibleGroupPublicHex: (groupPublicHex: string) => boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Trusted-dealer keygen that re-rolls until the group_public is an
|
|
97
|
+
* Orchard-compatible `ak`, then derives matching nk‖rivk extras. With
|
|
98
|
+
* p ≈ 0.5 per attempt, the default 32-attempt cap fails with probability
|
|
99
|
+
* ≈ 2^-32. Returns the keygen, the extras, and how many attempts it took.
|
|
100
|
+
*/
|
|
101
|
+
export declare const orchardKeygenWithCompatibleExtras: (wasm: OrchardFrostWasmModule, maxSigners: number, minSigners: number, options?: {
|
|
102
|
+
maxAttempts?: number;
|
|
103
|
+
}) => OrchardKeygenWithExtras;
|
|
104
|
+
/**
|
|
105
|
+
* Derive the Orchard UFVK + unified address for a FROST share bundle.
|
|
106
|
+
*
|
|
107
|
+
* The group_public is already the 32-byte serialised `ak`, so `ak‖nk‖rivk`
|
|
108
|
+
* trivially yields the Orchard FVK the PCZT will embed and verify against.
|
|
109
|
+
* Backfills missing `orchardExtras` (mutating the bundle so the caller can
|
|
110
|
+
* persist it) — without them the derived UFVK would not match the FROST
|
|
111
|
+
* signer's `ak` and every shielded send would fail.
|
|
112
|
+
*
|
|
113
|
+
* @returns the address pair, or null if extras can't be produced / the WASM
|
|
114
|
+
* lacks the FROST-native helpers.
|
|
115
|
+
*/
|
|
116
|
+
export declare const deriveOrchardAddressFromBundle: (wasm: OrchardFrostWasmModule, bundle: OrchardKeyBundle) => OrchardAddressResult | null;
|
|
117
|
+
export interface NonceCommitment {
|
|
118
|
+
/** Opaque, Rust-owned nonce handle — never leaves this device. */
|
|
119
|
+
noncesOpaque: string;
|
|
120
|
+
/** Serialisable per-signer commitments, shared with the other party. */
|
|
121
|
+
commitments: string;
|
|
122
|
+
}
|
|
123
|
+
/** Round 1: produce this signer's nonces (opaque) + commitments (shareable). */
|
|
124
|
+
export declare const orchardCommitNonces: (wasm: OrchardFrostWasmModule, secretShareHex: string) => NonceCommitment;
|
|
125
|
+
/**
|
|
126
|
+
* Round 2: produce this signer's signature share using its pre-committed
|
|
127
|
+
* nonces. Both parties MUST pass the same `allCommitmentsJson`, `messageHex`
|
|
128
|
+
* (sighash) and `randomizerHex` (the PCZT's per-action `alpha`).
|
|
129
|
+
*/
|
|
130
|
+
export declare const orchardSignWithNonces: (wasm: OrchardFrostWasmModule, identifierHex: string, secretShareHex: string, publicHex: string, groupPublicHex: string, noncesOpaqueHex: string, allCommitmentsJson: string, messageHex: string, randomizerHex: string) => string;
|
|
131
|
+
/**
|
|
132
|
+
* Aggregate signature shares into a 64-byte RedPallas signature.
|
|
133
|
+
* Returns the raw WASM JSON (`{ signature, ... }`); callers read `.signature`.
|
|
134
|
+
*/
|
|
135
|
+
export declare const orchardAggregate: (wasm: OrchardFrostWasmModule, commitmentsJson: string, messageHex: string, sigSharesJson: string, signerPubkeysJson: string, groupPublicHex: string, randomizerHex: string) => string;
|
|
136
|
+
/** Generate a random 32-byte scalar usable as a FROST randomizer (tests only — the live path uses the PCZT's alpha). */
|
|
137
|
+
export declare const orchardGenerateRandomizer: (wasm: OrchardFrostWasmModule) => string;
|
|
138
|
+
/** Derive the (un-randomized) group verifying key from a group_public. */
|
|
139
|
+
export declare const orchardGroupVerifyingKey: (wasm: OrchardFrostWasmModule, groupPublicHex: string) => string;
|
|
140
|
+
//# sourceMappingURL=orchardFrost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchardFrost.d.ts","sourceRoot":"","sources":["../../src/cosign/orchardFrost.ts"],"names":[],"mappings":"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"}
|