@spirobel/monero-wallet-api 0.4.0 → 0.5.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 (48) hide show
  1. package/README.md +80 -8
  2. package/dist/api.d.ts +4 -0
  3. package/dist/api.js +4 -0
  4. package/dist/io/atomicWrite.js +2 -1
  5. package/dist/io/logging.d.ts +40 -0
  6. package/dist/io/logging.js +174 -0
  7. package/dist/keypairs-seeds/keypairs.d.ts +8 -0
  8. package/dist/keypairs-seeds/keypairs.js +31 -3
  9. package/dist/multisig/DistributedKeyGenerator.d.ts +125 -0
  10. package/dist/multisig/DistributedKeyGenerator.js +197 -0
  11. package/dist/multisig/MultiSigTxSigner.d.ts +68 -0
  12. package/dist/multisig/MultiSigTxSigner.js +123 -0
  13. package/dist/multisig/escrow.d.ts +58 -0
  14. package/dist/multisig/escrow.js +104 -0
  15. package/dist/multisig/multisig.d.ts +36 -0
  16. package/dist/multisig/multisig.js +140 -0
  17. package/dist/node-interaction/nodeUrl.js +2 -1
  18. package/dist/scanning-syncing/backgroundWorker.d.ts +2 -0
  19. package/dist/scanning-syncing/backgroundWorker.js +20 -8
  20. package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.js +9 -7
  21. package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.js +2 -1
  22. package/dist/scanning-syncing/scanSettings.d.ts +11 -0
  23. package/dist/scanning-syncing/scanSettings.js +18 -3
  24. package/dist/scanning-syncing/scanresult/computeKeyImage.d.ts +2 -1
  25. package/dist/scanning-syncing/scanresult/computeKeyImage.js +4 -2
  26. package/dist/scanning-syncing/scanresult/scanCache.js +7 -3
  27. package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +11 -0
  28. package/dist/scanning-syncing/scanresult/scanCacheOpened.js +104 -11
  29. package/dist/scanning-syncing/scanresult/scanCoordination.js +63 -72
  30. package/dist/scanning-syncing/scanresult/scanResult.d.ts +1 -1
  31. package/dist/scanning-syncing/scanresult/scanResult.js +19 -6
  32. package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
  33. package/dist/scanning-syncing/worker-mains/coordinator-main.js +3 -2
  34. package/dist/scanning-syncing/worker-mains/cpubound-main.js +24 -14
  35. package/dist/scanning-syncing/worker-mains/multisig-main.d.ts +13 -0
  36. package/dist/scanning-syncing/worker-mains/multisig-main.js +31 -0
  37. package/dist/scanning-syncing/worker-mains/worker.js +23 -7
  38. package/dist/send-functionality/multisig.d.ts +72 -0
  39. package/dist/send-functionality/multisig.js +97 -0
  40. package/dist/send-functionality/transactionBuilding.d.ts +1 -0
  41. package/dist/send-functionality/transactionBuilding.js +23 -2
  42. package/dist/viewpair/ViewPair.d.ts +8 -0
  43. package/dist/viewpair/ViewPair.js +16 -8
  44. package/dist/wasm-processing/wasmFile.d.ts +1 -0
  45. package/dist/wasm-processing/wasmFile.js +8 -3
  46. package/dist/wasm-processing/wasmProcessor.d.ts +2 -2
  47. package/dist/wasm-processing/wasmProcessor.js +4 -5
  48. package/package.json +6 -2
@@ -0,0 +1,197 @@
1
+ import { frost_dkg_wasm } from "../wasm-processing/wasmFile";
2
+ import { WasmProcessor } from "../wasm-processing/wasmProcessor";
3
+ /**
4
+ * get the DKG public key from a 64-byte DKG secret key
5
+ * @param dkgSecretKey - 64 byte Uint8Array dkg secret key
6
+ * @returns - dkg public key as hex string
7
+ */
8
+ export async function getDkgPublicKey(dkgSecretKey) {
9
+ const dkg = await DistributedKeyGenerator.create();
10
+ const pubResult = dkg.getPublicKey(dkgSecretKey);
11
+ if ("message" in pubResult) {
12
+ throw new Error(`getPublicKey failed: ${pubResult.message}`);
13
+ }
14
+ return pubResult.dkg_public_key;
15
+ }
16
+ /**
17
+ * derive a Monero address (mainnet, stagenet, testnet) from a DKG group key.
18
+ * spend_public_key is the group_key hex from dkg_verify output.
19
+ * view_secret_key is the 32-byte view secret key hex. (see performEscrowViewPairECDH on how to get one)
20
+ *
21
+ * @returns object with view_key, mainnet_primary, stagenet_primary, testnet_primary
22
+ */
23
+ export async function getDkgMoneroAddress(spend_public_key, view_secret_key) {
24
+ const dkg = await DistributedKeyGenerator.create();
25
+ const result = dkg.getMoneroAddress({ spend_public_key, view_secret_key });
26
+ if ("message" in result) {
27
+ throw new Error(`getDkgMoneroAddress failed: ${result.message}`);
28
+ }
29
+ return result;
30
+ }
31
+ export class DistributedKeyGenerator extends WasmProcessor {
32
+ /**
33
+ * create distributed key generator wasm instance,
34
+ * without initializing generators
35
+ * (in case you just want to get the public dkg key from a secret dkg key)
36
+ *
37
+ * @returns - Promise<DistributedKeyGenerator>
38
+ */
39
+ static async create() {
40
+ const dkg = new DistributedKeyGenerator();
41
+ await dkg.initWasmModule(frost_dkg_wasm);
42
+ return dkg;
43
+ }
44
+ /**
45
+ * set up a distributed key generator with t threshold and n total participants
46
+ * @param t - total number of multisig participants
47
+ * @param n - threshold to sign a transaction
48
+ * @returns - Promise<DistributedKeyGenerator>
49
+ */
50
+ static async createAndSetupGenerators(t, n) {
51
+ const dkg = new DistributedKeyGenerator();
52
+ await dkg.initWasmModule(frost_dkg_wasm);
53
+ dkg.setupGenerators(t, n);
54
+ return dkg;
55
+ }
56
+ /**
57
+ * setupGenerators
58
+ * configure the max threshold and max participants for the DKG generators.
59
+ * if never called, defaults to 16, 16 used automatically on first DKG operation.
60
+ */
61
+ setupGenerators(t, n) {
62
+ //@ts-ignore
63
+ this.tinywasi.instance.exports.setup_generators(t, n);
64
+ }
65
+ /**
66
+ * derive the DKG public key from a 64-byte DKG secret key.
67
+ *
68
+ * @param dkgSecretKeyBytes 64-byte DKG secret key (from seed function)
69
+ * @returns the DKG public key as a hex string, or an error object
70
+ */
71
+ getPublicKey(dkgSecretKeyBytes) {
72
+ // set up write callback: rust will call input(64) to read the secret key bytes
73
+ this.writeToWasmMemory = (ptr, len) => {
74
+ this.writeArray(ptr, len, dkgSecretKeyBytes);
75
+ };
76
+ // set up read callback: rust will call output_string() to return the result JSON
77
+ let result;
78
+ this.readFromWasmMemory = (ptr, len) => {
79
+ result = JSON.parse(this.readString(ptr, len));
80
+ };
81
+ //@ts-ignore
82
+ this.tinywasi.instance.exports.dkg_get_public_key();
83
+ if (!result) {
84
+ return { message: "No response from dkg_get_public_key" };
85
+ }
86
+ return result;
87
+ }
88
+ /**
89
+ * participate in a DKG round (nothrow).
90
+ *
91
+ * @param params dkg_secret_key as 64-byte hex string, context, dkg_public_keys array (length is n implicitly), t (threshold)
92
+ * @returns The participation message as hex, or an error object
93
+ */
94
+ participateNoThrow(params) {
95
+ const jsonStr = JSON.stringify(params);
96
+ // set up write callback: rust will call input_string(json_len) to read the JSON
97
+ this.writeToWasmMemory = (ptr, len) => {
98
+ this.writeString(ptr, len, jsonStr);
99
+ };
100
+ // set up read callback: rust will call output_string() to return the result JSON
101
+ let result;
102
+ this.readFromWasmMemory = (ptr, len) => {
103
+ result = JSON.parse(this.readString(ptr, len));
104
+ };
105
+ this.readErrorFromWasmMemory = (ptr, len) => {
106
+ result = JSON.parse(this.readString(ptr, len));
107
+ };
108
+ //@ts-ignore
109
+ this.tinywasi.instance.exports.dkg_participate(jsonStr.length);
110
+ if (!result) {
111
+ return { message: "No response from dkg_participate" };
112
+ }
113
+ return result;
114
+ }
115
+ /**
116
+ * verify DKG participations and extract the group key (nothrow).
117
+ *
118
+ * @param params dkg_secret_key as 64-byte hex string, context, t (threshold), dkg_public_keys array (length is n implicitly),
119
+ * participations [ paricipant index -> hex participation message ]
120
+ * @returns The group key and params, faulty participants, not-enough message, or error
121
+ */
122
+ verifyNoThrow(params) {
123
+ const jsonStr = JSON.stringify(params);
124
+ // set up write callback: rust will call input_string(json_len) to read the JSON
125
+ this.writeToWasmMemory = (ptr, len) => {
126
+ this.writeString(ptr, len, jsonStr);
127
+ };
128
+ // set up read callback: rust will call output_string() to return the result JSON
129
+ let result;
130
+ this.readFromWasmMemory = (ptr, len) => {
131
+ result = JSON.parse(this.readString(ptr, len));
132
+ };
133
+ this.readErrorFromWasmMemory = (ptr, len) => {
134
+ result = JSON.parse(this.readString(ptr, len));
135
+ };
136
+ //@ts-ignore
137
+ this.tinywasi.instance.exports.dkg_verify(jsonStr.length);
138
+ if (!result) {
139
+ return { message: "No response from dkg_verify" };
140
+ }
141
+ return result;
142
+ }
143
+ /**
144
+ * derive a Monero address from a DKG group key.
145
+ *
146
+ * Input JSON keys expected by the rust wasm:
147
+ * spend_public_key (hex32) - the group_key hex from dkg_verify output
148
+ * view_secret_key (hex32) - 32-byte view secret key (see performEscrowViewPairECDH on how to get one)
149
+ *
150
+ * @param params - spendPublicKey and viewSecretKey as hex strings
151
+ * @returns object with view_key, mainnet_primary, stagenet_primary, testnet_primary
152
+ */
153
+ getMoneroAddress(params) {
154
+ const jsonStr = JSON.stringify(params);
155
+ // set up write callback: rust calls input_string(json_len)
156
+ this.writeToWasmMemory = (ptr, len) => {
157
+ this.writeString(ptr, len, jsonStr);
158
+ };
159
+ // set up read callback: rust calls output_string()
160
+ let result;
161
+ this.readFromWasmMemory = (ptr, len) => {
162
+ result = JSON.parse(this.readString(ptr, len));
163
+ };
164
+ this.readErrorFromWasmMemory = (ptr, len) => {
165
+ result = JSON.parse(this.readString(ptr, len));
166
+ };
167
+ //@ts-ignore
168
+ this.tinywasi.instance.exports.dkg_get_monero_address(jsonStr.length);
169
+ if (!result) {
170
+ return { message: "No response from dkg_get_monero_address" };
171
+ }
172
+ return result;
173
+ }
174
+ /**
175
+ * participate in a DKG round (throws on error).
176
+ */
177
+ participate(params) {
178
+ const result = this.participateNoThrow(params);
179
+ if ("message" in result) {
180
+ throw new Error(`participate failed: ${result.message}`);
181
+ }
182
+ return result;
183
+ }
184
+ /**
185
+ * verify DKG participations and extract the group key (throws on error).
186
+ */
187
+ verify(params) {
188
+ const result = this.verifyNoThrow(params);
189
+ if ("message" in result) {
190
+ throw new Error(`verify failed: ${result.message}`);
191
+ }
192
+ if ("faulty_participants" in result) {
193
+ throw new Error(`verify failed: ${result.faulty_participants}`);
194
+ }
195
+ return result;
196
+ }
197
+ }
@@ -0,0 +1,68 @@
1
+ import { WasmProcessor } from "../wasm-processing/wasmProcessor";
2
+ export type MoneroPreprocessParams = {
3
+ threshold_key: string;
4
+ unsigned_tx: string;
5
+ };
6
+ export type MoneroPreprocessResult = {
7
+ preprocess: string;
8
+ };
9
+ export type MoneroSignParams = {
10
+ preprocesses: Record<string, string>;
11
+ };
12
+ export type MoneroSignResult = {
13
+ share: string;
14
+ };
15
+ export type MoneroCompleteParams = {
16
+ shares: Record<string, string>;
17
+ };
18
+ export type MoneroCompleteResult = {
19
+ signed_tx: string;
20
+ };
21
+ export type MoneroErrorResponse = {
22
+ message: string;
23
+ };
24
+ export declare class MultiSigTxSigner extends WasmProcessor {
25
+ static create(): Promise<MultiSigTxSigner>;
26
+ /**
27
+ * preprocess
28
+ *
29
+ * @param params threshold_key hex, unsigned_tx hex
30
+ * @returns preprocess hex
31
+ */
32
+ preprocess(params: MoneroPreprocessParams): MoneroPreprocessResult;
33
+ /**
34
+ * preprocess - does not throw, with return error type
35
+ *
36
+ * @param params threshold_key hex, unsigned_tx hex
37
+ * @returns preprocess hex
38
+ */
39
+ preprocessNoThrow(params: MoneroPreprocessParams): MoneroPreprocessResult | MoneroErrorResponse;
40
+ /**
41
+ * sign
42
+ *
43
+ * @param params preprocesses map from all signers
44
+ * @returns share hex
45
+ */
46
+ sign(params: MoneroSignParams): MoneroSignResult;
47
+ /**
48
+ * sign - does not throw, with return error type
49
+ *
50
+ * @param params preprocesses map from all signers
51
+ * @returns share hex
52
+ */
53
+ signNoThrow(params: MoneroSignParams): MoneroSignResult | MoneroErrorResponse;
54
+ /**
55
+ * complete
56
+ *
57
+ * @param params shares map from all signers
58
+ * @returns signed_tx hex
59
+ */
60
+ complete(params: MoneroCompleteParams): MoneroCompleteResult;
61
+ /**
62
+ * complete - does not throw, with return error type
63
+ *
64
+ * @param params shares map from all signers
65
+ * @returns signed_tx hex
66
+ */
67
+ completeNoThrow(params: MoneroCompleteParams): MoneroCompleteResult | MoneroErrorResponse;
68
+ }
@@ -0,0 +1,123 @@
1
+ import { frost_dkg_wasm } from "../wasm-processing/wasmFile";
2
+ import { WasmProcessor } from "../wasm-processing/wasmProcessor";
3
+ export class MultiSigTxSigner extends WasmProcessor {
4
+ static async create() {
5
+ const signer = new MultiSigTxSigner();
6
+ await signer.initWasmModule(frost_dkg_wasm);
7
+ return signer;
8
+ }
9
+ /**
10
+ * preprocess
11
+ *
12
+ * @param params threshold_key hex, unsigned_tx hex
13
+ * @returns preprocess hex
14
+ */
15
+ preprocess(params) {
16
+ const result = this.preprocessNoThrow(params);
17
+ if ("message" in result) {
18
+ throw new Error(`preprocess failed: ${result.message}`);
19
+ }
20
+ return result;
21
+ }
22
+ /**
23
+ * preprocess - does not throw, with return error type
24
+ *
25
+ * @param params threshold_key hex, unsigned_tx hex
26
+ * @returns preprocess hex
27
+ */
28
+ preprocessNoThrow(params) {
29
+ const jsonStr = JSON.stringify(params);
30
+ this.writeToWasmMemory = (ptr, len) => {
31
+ this.writeString(ptr, len, jsonStr);
32
+ };
33
+ let result;
34
+ this.readFromWasmMemory = (ptr, len) => {
35
+ result = JSON.parse(this.readString(ptr, len));
36
+ };
37
+ this.readErrorFromWasmMemory = (ptr, len) => {
38
+ result = JSON.parse(this.readString(ptr, len));
39
+ };
40
+ //@ts-ignore
41
+ this.tinywasi.instance.exports.monero_preprocess(jsonStr.length);
42
+ if (!result) {
43
+ return { message: "No response from monero_preprocess" };
44
+ }
45
+ return result;
46
+ }
47
+ /**
48
+ * sign
49
+ *
50
+ * @param params preprocesses map from all signers
51
+ * @returns share hex
52
+ */
53
+ sign(params) {
54
+ const result = this.signNoThrow(params);
55
+ if ("message" in result) {
56
+ throw new Error(`sign failed: ${result.message}`);
57
+ }
58
+ return result;
59
+ }
60
+ /**
61
+ * sign - does not throw, with return error type
62
+ *
63
+ * @param params preprocesses map from all signers
64
+ * @returns share hex
65
+ */
66
+ signNoThrow(params) {
67
+ const jsonStr = JSON.stringify(params);
68
+ this.writeToWasmMemory = (ptr, len) => {
69
+ this.writeString(ptr, len, jsonStr);
70
+ };
71
+ let result;
72
+ this.readFromWasmMemory = (ptr, len) => {
73
+ result = JSON.parse(this.readString(ptr, len));
74
+ };
75
+ this.readErrorFromWasmMemory = (ptr, len) => {
76
+ result = JSON.parse(this.readString(ptr, len));
77
+ };
78
+ //@ts-ignore
79
+ this.tinywasi.instance.exports.monero_sign(jsonStr.length);
80
+ if (!result) {
81
+ return { message: "No response from monero_sign" };
82
+ }
83
+ return result;
84
+ }
85
+ /**
86
+ * complete
87
+ *
88
+ * @param params shares map from all signers
89
+ * @returns signed_tx hex
90
+ */
91
+ complete(params) {
92
+ const result = this.completeNoThrow(params);
93
+ if ("message" in result) {
94
+ throw new Error(`complete failed: ${result.message}`);
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * complete - does not throw, with return error type
100
+ *
101
+ * @param params shares map from all signers
102
+ * @returns signed_tx hex
103
+ */
104
+ completeNoThrow(params) {
105
+ const jsonStr = JSON.stringify(params);
106
+ this.writeToWasmMemory = (ptr, len) => {
107
+ this.writeString(ptr, len, jsonStr);
108
+ };
109
+ let result;
110
+ this.readFromWasmMemory = (ptr, len) => {
111
+ result = JSON.parse(this.readString(ptr, len));
112
+ };
113
+ this.readErrorFromWasmMemory = (ptr, len) => {
114
+ result = JSON.parse(this.readString(ptr, len));
115
+ };
116
+ //@ts-ignore
117
+ this.tinywasi.instance.exports.monero_complete(jsonStr.length);
118
+ if (!result) {
119
+ return { message: "No response from monero_complete" };
120
+ }
121
+ return result;
122
+ }
123
+ }
@@ -0,0 +1,58 @@
1
+ export declare function makeEscrowContext(context_index: number): {
2
+ ok: boolean;
3
+ error: string;
4
+ context?: undefined;
5
+ context_index?: undefined;
6
+ } | {
7
+ ok: boolean;
8
+ context: string;
9
+ context_index: number;
10
+ error?: undefined;
11
+ };
12
+ export declare function parseEscrowContext(input: string): {
13
+ ok: boolean;
14
+ error: string;
15
+ context?: undefined;
16
+ context_index?: undefined;
17
+ } | {
18
+ ok: boolean;
19
+ context: string;
20
+ context_index: string;
21
+ error?: undefined;
22
+ };
23
+ /**
24
+ * To give users the ability to conveniently partake in escrow transactions,
25
+ * the necessary secrets need to be organized well.
26
+ *
27
+ * The seedphrase package in this repository provides methods to derive
28
+ * secrets from a "walletroute" and a bip39 seedphrase.
29
+ *
30
+ * The "walletroute" is a string that is human readable and gives
31
+ * information on the context the wallet is created for.
32
+ *
33
+ * getWalletSecret() in the seedphrase package returns:
34
+ * 64 bytes of key data - uses KDF ( bip39.mnemonicToSeedSync of noble bip39)
35
+ *
36
+ * We use this method to derive the escrow-viewpair-comms secret from the
37
+ * "comms" key type of a walletroute. (consult the seedphrase package readme for more information)
38
+ *
39
+ * @param bip39_secret : 64 bytes key data
40
+ * @returns 32 bytes secret
41
+ */
42
+ export declare function deriveEscrowViewpairCommsSecret(bip39_secret: Uint8Array): Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
43
+ export declare function escrowViewPairECDHgetPublicKey(vp_comms_secret: Uint8Array): Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
44
+ /**
45
+ * In the typical escrow setup, from the perspective of the customer,
46
+ * the customer_sk is used together with the merchant pk to make the
47
+ * escrow wallet viewpair.
48
+ *
49
+ * From the perspective of the merchant,
50
+ * the merchant_sk is used together with the customer pk to make the
51
+ * escrow wallet viewpair.
52
+ *
53
+ * In the dispute flow case, the disputer shares the shared secret,
54
+ * that resulted from this ECDH exchange with the arbitrator.
55
+ * @param alice_sk - your viewpair secret
56
+ * @param bob_pk - the other multisig (escrow) party's viewpair public key
57
+ */
58
+ export declare function performEscrowViewPairECDH(alice_sk: Uint8Array, bob_pk: Uint8Array): Promise<string>;
@@ -0,0 +1,104 @@
1
+ import { ed25519, x25519 } from "@noble/curves/ed25519.js";
2
+ import { numberToBytesLE } from "@noble/curves/utils.js";
3
+ import { blake3 } from "@noble/hashes/blake3.js";
4
+ import { vk_from_entropy } from "../api";
5
+ export function makeEscrowContext(context_index) {
6
+ if (Number.isNaN(parseInt(String(context_index)))) {
7
+ return { ok: false, error: `invalid context_index: "${context_index}"` };
8
+ }
9
+ if (parseInt(String(context_index)) < 0) {
10
+ return {
11
+ ok: false,
12
+ error: `invalid context_index: "${context_index} < 0"`,
13
+ };
14
+ }
15
+ if (parseInt(String(context_index)) > 10000) {
16
+ return {
17
+ ok: false,
18
+ error: `invalid context_index: "${context_index} > 10000"`,
19
+ };
20
+ }
21
+ const context = "escrow-" + String(context_index);
22
+ return { ok: true, context, context_index };
23
+ }
24
+ export function parseEscrowContext(input) {
25
+ const parts = input.split("-");
26
+ if (parts.length < 1 || !parts[0] || parts[0] !== "escrow") {
27
+ return {
28
+ ok: false,
29
+ error: "missing escrow string before - ${context_index}",
30
+ };
31
+ }
32
+ const context_index = parts[1];
33
+ if (Number.isNaN(parseInt(String(context_index)))) {
34
+ return { ok: false, error: `invalid context_index: "${context_index}"` };
35
+ }
36
+ if (parseInt(String(context_index)) < 0) {
37
+ return {
38
+ ok: false,
39
+ error: `invalid context_index: "${context_index} < 0"`,
40
+ };
41
+ }
42
+ if (parseInt(String(context_index)) > 10000) {
43
+ return {
44
+ ok: false,
45
+ error: `invalid context_index: "${context_index} > 10000"`,
46
+ };
47
+ }
48
+ const context = "escrow-" + String(context_index);
49
+ return { ok: true, context, context_index };
50
+ }
51
+ /**
52
+ * To give users the ability to conveniently partake in escrow transactions,
53
+ * the necessary secrets need to be organized well.
54
+ *
55
+ * The seedphrase package in this repository provides methods to derive
56
+ * secrets from a "walletroute" and a bip39 seedphrase.
57
+ *
58
+ * The "walletroute" is a string that is human readable and gives
59
+ * information on the context the wallet is created for.
60
+ *
61
+ * getWalletSecret() in the seedphrase package returns:
62
+ * 64 bytes of key data - uses KDF ( bip39.mnemonicToSeedSync of noble bip39)
63
+ *
64
+ * We use this method to derive the escrow-viewpair-comms secret from the
65
+ * "comms" key type of a walletroute. (consult the seedphrase package readme for more information)
66
+ *
67
+ * @param bip39_secret : 64 bytes key data
68
+ * @returns 32 bytes secret
69
+ */
70
+ export function deriveEscrowViewpairCommsSecret(bip39_secret) {
71
+ if (bip39_secret.length !== 64) {
72
+ throw new Error("expected exactly 64 bytes for Multisig secret viewkey");
73
+ }
74
+ const txt = new TextEncoder();
75
+ return blake3(bip39_secret, { context: txt.encode("escrow-viewpair-comms") });
76
+ }
77
+ export function escrowViewPairECDHgetPublicKey(vp_comms_secret) {
78
+ return ed25519.getPublicKey(vp_comms_secret);
79
+ }
80
+ /**
81
+ * In the typical escrow setup, from the perspective of the customer,
82
+ * the customer_sk is used together with the merchant pk to make the
83
+ * escrow wallet viewpair.
84
+ *
85
+ * From the perspective of the merchant,
86
+ * the merchant_sk is used together with the customer pk to make the
87
+ * escrow wallet viewpair.
88
+ *
89
+ * In the dispute flow case, the disputer shares the shared secret,
90
+ * that resulted from this ECDH exchange with the arbitrator.
91
+ * @param alice_sk - your viewpair secret
92
+ * @param bob_pk - the other multisig (escrow) party's viewpair public key
93
+ */
94
+ export async function performEscrowViewPairECDH(alice_sk, bob_pk) {
95
+ const txt = new TextEncoder();
96
+ const aliceSecX = ed25519.utils.toMontgomerySecret(alice_sk);
97
+ const bobPubX = ed25519.utils.toMontgomery(bob_pk);
98
+ const sharedKey = x25519.getSharedSecret(aliceSecX, bobPubX);
99
+ const sharedSecret = blake3(sharedKey, {
100
+ context: txt.encode("escrow-viewpair-comms"),
101
+ });
102
+ const scalar = await vk_from_entropy(sharedSecret);
103
+ return scalar;
104
+ }
@@ -0,0 +1,36 @@
1
+ import type { DkgErrorResponse, DkgParticipateParams, DkgParticipateResult, DkgVerifyParams, DkgVerifyResult, DkgVerifyValidResult } from "./DistributedKeyGenerator";
2
+ export declare class MultiSig {
3
+ private worker?;
4
+ /**
5
+ * set up a distributed key generator with t threshold and n total participants
6
+ * @param t - total number of multisig participants
7
+ * @param n - threshold to sign a transaction
8
+ * @returns - Promise<DistributedKeyGenerator>
9
+ */
10
+ static createAndSetupGenerators(t: number, n: number): Promise<MultiSig>;
11
+ stopWorker(): void;
12
+ startWorker(t: number, n: number): Promise<void>;
13
+ /**
14
+ * participate in a DKG round (nothrow).
15
+ *
16
+ * @param params dkg_secret_key as 64-byte hex string, context, dkg_public_keys array (length is n implicitly), t (threshold)
17
+ * @returns The participation message as hex, or an error object
18
+ */
19
+ participateNoThrow(params: DkgParticipateParams): Promise<DkgParticipateResult | DkgErrorResponse>;
20
+ /**
21
+ * verify DKG participations and extract the group key (nothrow).
22
+ *
23
+ * @param params dkg_secret_key as 64-byte hex string, context, t (threshold), dkg_public_keys array (length is n implicitly),
24
+ * participations [ paricipant index -> hex participation message ]
25
+ * @returns The group key and params, faulty participants, not-enough message, or error
26
+ */
27
+ verifyNoThrow(params: DkgVerifyParams): Promise<DkgVerifyResult | DkgErrorResponse>;
28
+ /**
29
+ * participate in a DKG round (throws on error).
30
+ */
31
+ participate(params: DkgParticipateParams): Promise<DkgParticipateResult>;
32
+ /**
33
+ * verify DKG participations and extract the group key (throws on error).
34
+ */
35
+ verify(params: DkgVerifyParams): Promise<DkgVerifyValidResult>;
36
+ }