wire-mesh-core 1.46.0 → 1.48.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/adapters/frame-codec.d.cts +1 -1
- package/dist/adapters/frame-codec.d.mts +1 -1
- package/dist/adapters/node-fs-storage.cjs +3 -24
- package/dist/adapters/node-identity.d.cts +2 -2
- package/dist/adapters/node-identity.d.mts +2 -2
- package/dist/adapters/tcp-transport.d.cts +1 -1
- package/dist/adapters/tcp-transport.d.mts +1 -1
- package/dist/adapters/threshold-identity.cjs +42 -0
- package/dist/adapters/threshold-identity.d.cts +33 -0
- package/dist/adapters/threshold-identity.d.mts +33 -0
- package/dist/adapters/threshold-identity.mjs +41 -0
- package/dist/adapters/threshold-wasm.cjs +197 -0
- package/dist/adapters/threshold-wasm.d.cts +89 -0
- package/dist/adapters/threshold-wasm.d.mts +89 -0
- package/dist/adapters/threshold-wasm.mjs +174 -0
- package/dist/adapters/tls-transport.d.cts +1 -1
- package/dist/adapters/tls-transport.d.mts +1 -1
- package/dist/domain/bulk.d.cts +2 -2
- package/dist/domain/bulk.d.mts +2 -2
- package/dist/domain/capability-grant.cjs +1 -1
- package/dist/domain/capability-grant.d.cts +3 -3
- package/dist/domain/capability-grant.d.mts +3 -3
- package/dist/domain/capability-grant.mjs +1 -1
- package/dist/domain/capability-request.cjs +1 -1
- package/dist/domain/capability-request.d.cts +2 -2
- package/dist/domain/capability-request.d.mts +2 -2
- package/dist/domain/capability-request.mjs +1 -1
- package/dist/domain/data-sync.d.cts +2 -2
- package/dist/domain/data-sync.d.mts +2 -2
- package/dist/domain/device-id.d.cts +1 -1
- package/dist/domain/device-id.d.mts +1 -1
- package/dist/domain/grant-candidates.d.cts +1 -1
- package/dist/domain/grant-candidates.d.mts +1 -1
- package/dist/domain/handshake.d.cts +1 -1
- package/dist/domain/handshake.d.mts +1 -1
- package/dist/domain/mesh-session.d.cts +3 -3
- package/dist/domain/mesh-session.d.mts +3 -3
- package/dist/domain/notice-board.d.cts +3 -3
- package/dist/domain/notice-board.d.mts +3 -3
- package/dist/domain/relay-hub.d.cts +2 -2
- package/dist/domain/relay-hub.d.mts +2 -2
- package/dist/domain/relay-use-gate.d.cts +2 -2
- package/dist/domain/relay-use-gate.d.mts +2 -2
- package/dist/domain/revocation-view.cjs +1 -1
- package/dist/domain/revocation-view.d.cts +2 -2
- package/dist/domain/revocation-view.d.mts +2 -2
- package/dist/domain/revocation-view.mjs +1 -1
- package/dist/domain/room-rekey.d.cts +3 -3
- package/dist/domain/room-rekey.d.mts +3 -3
- package/dist/domain/room-token-verification.cjs +1 -1
- package/dist/domain/room-token-verification.d.cts +1 -1
- package/dist/domain/room-token-verification.d.mts +1 -1
- package/dist/domain/room-token-verification.mjs +1 -1
- package/dist/domain/room.d.cts +4 -4
- package/dist/domain/room.d.mts +4 -4
- package/dist/domain/shard-manifest.d.cts +1 -1
- package/dist/domain/shard-manifest.d.mts +1 -1
- package/dist/domain/threshold-subject.cjs +35 -0
- package/dist/domain/threshold-subject.d.cts +33 -0
- package/dist/domain/threshold-subject.d.mts +33 -0
- package/dist/domain/threshold-subject.mjs +32 -0
- package/dist/domain/tokens.cjs +2 -1
- package/dist/domain/tokens.d.cts +2 -2
- package/dist/domain/tokens.d.mts +2 -2
- package/dist/domain/tokens.mjs +2 -2
- package/dist/domain/webrtc-signaling.cjs +1 -1
- package/dist/domain/webrtc-signaling.d.cts +2 -2
- package/dist/domain/webrtc-signaling.d.mts +2 -2
- package/dist/domain/webrtc-signaling.mjs +1 -1
- package/dist/generated/protocol.cjs +83 -0
- package/dist/generated/protocol.d.cts +2 -2
- package/dist/generated/protocol.d.mts +2 -2
- package/dist/generated/protocol.mjs +73 -1
- package/dist/{identity-DHf0J6IA.d.cts → identity-9TmmK7vP.d.mts} +1 -1
- package/dist/{identity-Oelt3uEn.d.mts → identity-CUkDHCRK.d.cts} +1 -1
- package/dist/ports/identity.d.cts +1 -1
- package/dist/ports/identity.d.mts +1 -1
- package/dist/ports/transport.d.cts +1 -1
- package/dist/ports/transport.d.mts +1 -1
- package/dist/{protocol-D8CU6s2_.d.cts → protocol-CNFRVx9w.d.cts} +277 -1
- package/dist/{protocol-D8CU6s2_.d.mts → protocol-CNFRVx9w.d.mts} +277 -1
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/{room-token-verification-BQhqt1Rm.d.mts → room-token-verification-BdtM1rQ4.d.mts} +2 -2
- package/dist/{room-token-verification-DQGdYNg4.d.cts → room-token-verification-DpOfZOdl.d.cts} +2 -2
- package/dist/{tokens-CdQwzCyJ.mjs → tokens-B0dpTLhS.mjs} +2 -2
- package/dist/{tokens-Bh82oidM.d.mts → tokens-CVyPoJ6l.d.mts} +5 -3
- package/dist/{tokens-B1-MAIST.d.cts → tokens-Cl8sQo7o.d.cts} +5 -3
- package/dist/{tokens-DxGVURpB.cjs → tokens-Dh6mG6p_.cjs} +7 -1
- package/dist/{transport-BNeF6kDe.d.mts → transport-C7KVkhgb.d.mts} +1 -1
- package/dist/{transport-BbSGNRFZ.d.cts → transport-De0zHlaA.d.cts} +1 -1
- package/package.json +15 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as Frame } from "../protocol-
|
|
1
|
+
import { N as Frame } from "../protocol-CNFRVx9w.cjs";
|
|
2
2
|
//#region src/adapters/frame-codec.d.ts
|
|
3
3
|
export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
|
|
4
4
|
/** A frame that fails schema validation, caught separately from a decode failure so it can be dropped without disconnecting. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as Frame } from "../protocol-
|
|
1
|
+
import { N as Frame } from "../protocol-CNFRVx9w.mjs";
|
|
2
2
|
//#region src/adapters/frame-codec.d.ts
|
|
3
3
|
export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
|
|
4
4
|
/** A frame that fails schema validation, caught separately from a decode failure so it can be dropped without disconnecting. */
|
|
@@ -1,30 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
-
key = keys[i];
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
-
get: ((k) => from[k]).bind(null, key),
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
20
|
-
value: mod,
|
|
21
|
-
enumerable: true
|
|
22
|
-
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
2
|
+
const require_rolldown_runtime = require("../rolldown-runtime-VH7oDXx4.cjs");
|
|
24
3
|
let node_fs_promises = require("node:fs/promises");
|
|
25
|
-
node_fs_promises = __toESM(node_fs_promises, 1);
|
|
4
|
+
node_fs_promises = require_rolldown_runtime.__toESM(node_fs_promises, 1);
|
|
26
5
|
let node_path = require("node:path");
|
|
27
|
-
node_path = __toESM(node_path, 1);
|
|
6
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
28
7
|
//#region src/adapters/node-fs-storage.ts
|
|
29
8
|
/** A Node filesystem-backed KeyValueStorage -- the durable Node-side counterpart to indexeddb-storage.ts's browser one, and memory-storage.ts's in-process one, satisfying the identical contract. Every key is treated directly as a relative path under the given directory (creating nested directories as needed), which every key this codebase constructs is already suited to: internally generated, ASCII, path-shaped by design (e.g. "data/<peer-hex>/entry/<seq>") rather than arbitrary untrusted input, matching the same assumption indexeddb-storage.ts's own comment already states for its key range bounds. */
|
|
30
9
|
function isEnoent(error) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as IdentityKey, D as DeviceId } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { B as IdentityKey, D as DeviceId } from "../protocol-CNFRVx9w.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-CUkDHCRK.cjs";
|
|
3
3
|
import { webcrypto } from "node:crypto";
|
|
4
4
|
//#region src/adapters/node-identity.d.ts
|
|
5
5
|
export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as IdentityKey, D as DeviceId } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { B as IdentityKey, D as DeviceId } from "../protocol-CNFRVx9w.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-9TmmK7vP.mjs";
|
|
3
3
|
import { webcrypto } from "node:crypto";
|
|
4
4
|
//#region src/adapters/node-identity.d.ts
|
|
5
5
|
export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Transport } from "../transport-
|
|
1
|
+
import { r as Transport } from "../transport-De0zHlaA.cjs";
|
|
2
2
|
//#region src/adapters/tcp-transport.d.ts
|
|
3
3
|
/** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
|
|
4
4
|
export declare function createTcpTransport(): Transport;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Transport } from "../transport-
|
|
1
|
+
import { r as Transport } from "../transport-C7KVkhgb.mjs";
|
|
2
2
|
//#region src/adapters/tcp-transport.d.ts
|
|
3
3
|
/** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
|
|
4
4
|
export declare function createTcpTransport(): Transport;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_domain_threshold_subject = require("../domain/threshold-subject.cjs");
|
|
3
|
+
const require_adapters_threshold_wasm = require("./threshold-wasm.cjs");
|
|
4
|
+
const require_adapters_node_identity = require("./node-identity.cjs");
|
|
5
|
+
//#region src/adapters/threshold-identity.ts
|
|
6
|
+
const ALG_ED25519 = -8;
|
|
7
|
+
const FIRST_SESSION_ID = 1n;
|
|
8
|
+
const SESSION_ID_STEP = 1n;
|
|
9
|
+
/**
|
|
10
|
+
* Builds a group's threshold-backed `IdentityPort`. `deviceId`/ `identityKey` are the group's own (`group-device-id = SHA-256(group public key)`, the ordinary `identity.cddl` rule applied to the DKG's output) -- indistinguishable on the wire from any ordinary single-device Ed25519 identity, per this domain's own defining property.
|
|
11
|
+
*/
|
|
12
|
+
async function createThresholdIdentity(groupVerifyingKey, publicKeyPackage, threshold, participants, coordinator) {
|
|
13
|
+
const deviceId = await require_adapters_node_identity.deriveDeviceId(groupVerifyingKey);
|
|
14
|
+
const identityKey = {
|
|
15
|
+
alg: ALG_ED25519,
|
|
16
|
+
"public-key": Uint8Array.from(groupVerifyingKey)
|
|
17
|
+
};
|
|
18
|
+
let nextSessionId = FIRST_SESSION_ID;
|
|
19
|
+
return {
|
|
20
|
+
deviceId,
|
|
21
|
+
identityKey,
|
|
22
|
+
async sign() {
|
|
23
|
+
return Promise.reject(/* @__PURE__ */ new Error("ThresholdIdentity.sign requires a ThresholdSubject, not a bare message -- use signSubject"));
|
|
24
|
+
},
|
|
25
|
+
verify: require_adapters_node_identity.verifyWithPublicKey,
|
|
26
|
+
deriveDeviceId: require_adapters_node_identity.deriveDeviceId,
|
|
27
|
+
async signSubject(subject, deadlineUnixMs) {
|
|
28
|
+
const sessionId = nextSessionId;
|
|
29
|
+
nextSessionId += SESSION_ID_STEP;
|
|
30
|
+
const commitments = await coordinator.commitRound(sessionId, participants, subject, deadlineUnixMs);
|
|
31
|
+
if (commitments.length < threshold) throw new Error(`only ${String(commitments.length)} of ${String(threshold)} required participants committed`);
|
|
32
|
+
const shares = await coordinator.signRound(sessionId, commitments);
|
|
33
|
+
const message = require_domain_threshold_subject.toBeSigned(subject);
|
|
34
|
+
const signingPackage = require_adapters_threshold_wasm.signingBuildPackage(commitments, message);
|
|
35
|
+
const signature = require_adapters_threshold_wasm.signingAggregate(signingPackage, shares, publicKeyPackage);
|
|
36
|
+
if (!await require_adapters_node_identity.verifyWithPublicKey(identityKey, message, signature)) throw new Error("aggregate threshold signature failed to verify against the group's own key -- refusing to return it");
|
|
37
|
+
return signature;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
exports.createThresholdIdentity = createThresholdIdentity;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { D as DeviceId } from "../protocol-CNFRVx9w.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-CUkDHCRK.cjs";
|
|
3
|
+
import { DeviceKeyed } from "./threshold-wasm.cjs";
|
|
4
|
+
import { ThresholdSubject } from "../domain/threshold-subject.cjs";
|
|
5
|
+
//#region src/adapters/threshold-identity.d.ts
|
|
6
|
+
/** One participant's round-1 response: its FROST commitments, keyed by device-id. */
|
|
7
|
+
export type SigningCommitmentEntry = DeviceKeyed;
|
|
8
|
+
/** One participant's round-2 response: its signature share, keyed by device-id. */
|
|
9
|
+
export type SignatureShareEntry = DeviceKeyed;
|
|
10
|
+
/**
|
|
11
|
+
* The network side of threshold signing, supplied by the caller. Never assumes a specific transport, framing, or retry/timeout policy -- those are the caller's own concern, matching this project's async-contracts convention. A second implementation on a completely different transport (a different harness's own RPC, an in-process test double) satisfies this exact contract with zero changes to the contract or its callers.
|
|
12
|
+
*/
|
|
13
|
+
export interface ThresholdCoordinator {
|
|
14
|
+
/**
|
|
15
|
+
* Sends `threshold-commit` to every one of `participants` for `subject`, and collects at least `threshold` valid responses. Implementations decide their own quorum/timeout/retry policy; this call either returns enough commitments to proceed or rejects.
|
|
16
|
+
*/
|
|
17
|
+
commitRound: (sessionId: bigint, participants: readonly DeviceId[], subject: ThresholdSubject, deadlineUnixMs: number) => Promise<SigningCommitmentEntry[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Sends `threshold-sign` (the collected commitments, no subject) to every participant that committed, and collects their signature shares.
|
|
20
|
+
*/
|
|
21
|
+
signRound: (sessionId: bigint, commitments: readonly SigningCommitmentEntry[]) => Promise<SignatureShareEntry[]>;
|
|
22
|
+
}
|
|
23
|
+
export interface ThresholdIdentity extends IdentityPort {
|
|
24
|
+
/**
|
|
25
|
+
* The real entry point: signs `subject` (never a bare hash -- `ThresholdSubject` always carries the full decoded content, per this domain's own non-negotiable security invariant), round-tripping through the coordinator for both FROST rounds, then verifying the aggregate signature before returning it.
|
|
26
|
+
*/
|
|
27
|
+
signSubject: (subject: ThresholdSubject, deadlineUnixMs: number) => Promise<Uint8Array<ArrayBuffer>>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds a group's threshold-backed `IdentityPort`. `deviceId`/ `identityKey` are the group's own (`group-device-id = SHA-256(group public key)`, the ordinary `identity.cddl` rule applied to the DKG's output) -- indistinguishable on the wire from any ordinary single-device Ed25519 identity, per this domain's own defining property.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createThresholdIdentity(groupVerifyingKey: Uint8Array, publicKeyPackage: Uint8Array, threshold: number, participants: readonly DeviceId[], coordinator: Readonly<ThresholdCoordinator>): Promise<ThresholdIdentity>;
|
|
33
|
+
//#endregion
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { D as DeviceId } from "../protocol-CNFRVx9w.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-9TmmK7vP.mjs";
|
|
3
|
+
import { DeviceKeyed } from "./threshold-wasm.mjs";
|
|
4
|
+
import { ThresholdSubject } from "../domain/threshold-subject.mjs";
|
|
5
|
+
//#region src/adapters/threshold-identity.d.ts
|
|
6
|
+
/** One participant's round-1 response: its FROST commitments, keyed by device-id. */
|
|
7
|
+
export type SigningCommitmentEntry = DeviceKeyed;
|
|
8
|
+
/** One participant's round-2 response: its signature share, keyed by device-id. */
|
|
9
|
+
export type SignatureShareEntry = DeviceKeyed;
|
|
10
|
+
/**
|
|
11
|
+
* The network side of threshold signing, supplied by the caller. Never assumes a specific transport, framing, or retry/timeout policy -- those are the caller's own concern, matching this project's async-contracts convention. A second implementation on a completely different transport (a different harness's own RPC, an in-process test double) satisfies this exact contract with zero changes to the contract or its callers.
|
|
12
|
+
*/
|
|
13
|
+
export interface ThresholdCoordinator {
|
|
14
|
+
/**
|
|
15
|
+
* Sends `threshold-commit` to every one of `participants` for `subject`, and collects at least `threshold` valid responses. Implementations decide their own quorum/timeout/retry policy; this call either returns enough commitments to proceed or rejects.
|
|
16
|
+
*/
|
|
17
|
+
commitRound: (sessionId: bigint, participants: readonly DeviceId[], subject: ThresholdSubject, deadlineUnixMs: number) => Promise<SigningCommitmentEntry[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Sends `threshold-sign` (the collected commitments, no subject) to every participant that committed, and collects their signature shares.
|
|
20
|
+
*/
|
|
21
|
+
signRound: (sessionId: bigint, commitments: readonly SigningCommitmentEntry[]) => Promise<SignatureShareEntry[]>;
|
|
22
|
+
}
|
|
23
|
+
export interface ThresholdIdentity extends IdentityPort {
|
|
24
|
+
/**
|
|
25
|
+
* The real entry point: signs `subject` (never a bare hash -- `ThresholdSubject` always carries the full decoded content, per this domain's own non-negotiable security invariant), round-tripping through the coordinator for both FROST rounds, then verifying the aggregate signature before returning it.
|
|
26
|
+
*/
|
|
27
|
+
signSubject: (subject: ThresholdSubject, deadlineUnixMs: number) => Promise<Uint8Array<ArrayBuffer>>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Builds a group's threshold-backed `IdentityPort`. `deviceId`/ `identityKey` are the group's own (`group-device-id = SHA-256(group public key)`, the ordinary `identity.cddl` rule applied to the DKG's output) -- indistinguishable on the wire from any ordinary single-device Ed25519 identity, per this domain's own defining property.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createThresholdIdentity(groupVerifyingKey: Uint8Array, publicKeyPackage: Uint8Array, threshold: number, participants: readonly DeviceId[], coordinator: Readonly<ThresholdCoordinator>): Promise<ThresholdIdentity>;
|
|
33
|
+
//#endregion
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { toBeSigned } from "../domain/threshold-subject.mjs";
|
|
2
|
+
import { signingAggregate, signingBuildPackage } from "./threshold-wasm.mjs";
|
|
3
|
+
import { deriveDeviceId, verifyWithPublicKey } from "./node-identity.mjs";
|
|
4
|
+
//#region src/adapters/threshold-identity.ts
|
|
5
|
+
const ALG_ED25519 = -8;
|
|
6
|
+
const FIRST_SESSION_ID = 1n;
|
|
7
|
+
const SESSION_ID_STEP = 1n;
|
|
8
|
+
/**
|
|
9
|
+
* Builds a group's threshold-backed `IdentityPort`. `deviceId`/ `identityKey` are the group's own (`group-device-id = SHA-256(group public key)`, the ordinary `identity.cddl` rule applied to the DKG's output) -- indistinguishable on the wire from any ordinary single-device Ed25519 identity, per this domain's own defining property.
|
|
10
|
+
*/
|
|
11
|
+
async function createThresholdIdentity(groupVerifyingKey, publicKeyPackage, threshold, participants, coordinator) {
|
|
12
|
+
const deviceId = await deriveDeviceId(groupVerifyingKey);
|
|
13
|
+
const identityKey = {
|
|
14
|
+
alg: ALG_ED25519,
|
|
15
|
+
"public-key": Uint8Array.from(groupVerifyingKey)
|
|
16
|
+
};
|
|
17
|
+
let nextSessionId = FIRST_SESSION_ID;
|
|
18
|
+
return {
|
|
19
|
+
deviceId,
|
|
20
|
+
identityKey,
|
|
21
|
+
async sign() {
|
|
22
|
+
return Promise.reject(/* @__PURE__ */ new Error("ThresholdIdentity.sign requires a ThresholdSubject, not a bare message -- use signSubject"));
|
|
23
|
+
},
|
|
24
|
+
verify: verifyWithPublicKey,
|
|
25
|
+
deriveDeviceId,
|
|
26
|
+
async signSubject(subject, deadlineUnixMs) {
|
|
27
|
+
const sessionId = nextSessionId;
|
|
28
|
+
nextSessionId += SESSION_ID_STEP;
|
|
29
|
+
const commitments = await coordinator.commitRound(sessionId, participants, subject, deadlineUnixMs);
|
|
30
|
+
if (commitments.length < threshold) throw new Error(`only ${String(commitments.length)} of ${String(threshold)} required participants committed`);
|
|
31
|
+
const shares = await coordinator.signRound(sessionId, commitments);
|
|
32
|
+
const message = toBeSigned(subject);
|
|
33
|
+
const signingPackage = signingBuildPackage(commitments, message);
|
|
34
|
+
const signature = signingAggregate(signingPackage, shares, publicKeyPackage);
|
|
35
|
+
if (!await verifyWithPublicKey(identityKey, message, signature)) throw new Error("aggregate threshold signature failed to verify against the group's own key -- refusing to return it");
|
|
36
|
+
return signature;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { createThresholdIdentity };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_rolldown_runtime = require("../rolldown-runtime-VH7oDXx4.cjs");
|
|
3
|
+
const require_generated_protocol = require("../generated/protocol.cjs");
|
|
4
|
+
let wasm_dist_wire_mesh_threshold_wasm_js = require("../../wasm-dist/wire_mesh_threshold_wasm.js");
|
|
5
|
+
wasm_dist_wire_mesh_threshold_wasm_js = require_rolldown_runtime.__toESM(wasm_dist_wire_mesh_threshold_wasm_js, 1);
|
|
6
|
+
//#region src/adapters/threshold-wasm.ts
|
|
7
|
+
/**
|
|
8
|
+
* A typed TS wrapper over the WASM build of `wire-mesh-threshold` (the audited `frost-core`/`frost-ed25519` crates, ZcashFoundation, NCC-audited) -- wire-mesh#29's own chosen route for a TS FROST(Ed25519, SHA-512) participant, over a from-scratch reimplementation of the cryptography.
|
|
9
|
+
*
|
|
10
|
+
* Built by `scripts/build-threshold-wasm.sh` into `wasm-dist/` (gitignored, a genuine compiled build artifact like `dist/`, never committed) -- run it before importing this module, in dev and in CI alike. This module performs NO domain logic of its own, only re-typing the raw wasm bindings' `Uint8Array`/`Array<any>` surface against this package's own `DeviceId` type and Node-capable-device-only availability: FROST participation cannot use Web Crypto at all (raw scalar/point arithmetic is deliberately outside what Web Crypto exposes), so unlike `node-identity.ts`'s counterpart in `web-crypto-identity.ts`, this adapter has no browser-side equivalent in v1 -- per wire-mesh#29's own resolved design, a browser is a threshold-group BEARER only, never a SHAREHOLDER, in v1.
|
|
11
|
+
*/
|
|
12
|
+
function isUint8Array(value) {
|
|
13
|
+
return value instanceof Uint8Array;
|
|
14
|
+
}
|
|
15
|
+
/** Copies into a fresh, whole-buffer `Uint8Array<ArrayBuffer>` -- the wasm-bindgen-generated `.d.ts` declares its `Uint8Array` returns unparameterized (`Uint8Array<ArrayBufferLike>`), which callers such as `verifyWithPublicKey` (`node-identity.ts`) reject; this is the same normalisation that adapter's own `toBufferSource` already applies at its boundary. */
|
|
16
|
+
function toBufferSource(bytes) {
|
|
17
|
+
return Uint8Array.from(bytes);
|
|
18
|
+
}
|
|
19
|
+
function toParallelArrays(entries) {
|
|
20
|
+
return [entries.map((e) => e.deviceId), entries.map((e) => e.value)];
|
|
21
|
+
}
|
|
22
|
+
function fromParallelArrays(ids, values) {
|
|
23
|
+
if (ids.length !== values.length) throw new Error(`wasm returned mismatched parallel arrays: ${String(ids.length)} ids, ${String(values.length)} values`);
|
|
24
|
+
const result = [];
|
|
25
|
+
for (let i = 0; i < ids.length; i += 1) {
|
|
26
|
+
const id = ids[i];
|
|
27
|
+
const value = values[i];
|
|
28
|
+
if (!isUint8Array(value)) throw new Error("wasm returned a non-Uint8Array value in a parallel array");
|
|
29
|
+
result.push({
|
|
30
|
+
deviceId: require_generated_protocol.deviceIdSchema.parse(id),
|
|
31
|
+
value: toBufferSource(value)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/** Round 1: samples this participant's own polynomial and commits to it. See `wire_mesh_threshold::dkg::round1`'s own doc comment for the full design. */
|
|
37
|
+
function dkgRound1(ownDeviceId, maxSigners, minSigners) {
|
|
38
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.dkg_round1(ownDeviceId, maxSigners, minSigners);
|
|
39
|
+
return {
|
|
40
|
+
secretPackage: toBufferSource(out.secretPackage),
|
|
41
|
+
package: toBufferSource(out.package)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Splits a serialized DKG round-1 package (dkgRound1's own `package` output) into `threshold-keygen-round1`'s own wire shape: the Feldman commitment as an array of independently-serialized coefficients (`commitment: [* bstr]`) and the Schnorr proof of knowledge as a separate byte string -- unlike frost-core's own combined-blob serialization. The inverse of combineRound1Package. */
|
|
45
|
+
function splitRound1Package(serializedPackage) {
|
|
46
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.split_round1_package(serializedPackage);
|
|
47
|
+
const commitment = [];
|
|
48
|
+
for (const coefficient of out.commitment) {
|
|
49
|
+
if (!isUint8Array(coefficient)) throw new Error("wasm returned a non-Uint8Array entry in split_round1_package's own commitment array");
|
|
50
|
+
commitment.push(toBufferSource(coefficient));
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
commitment,
|
|
54
|
+
proofOfKnowledge: toBufferSource(out.proofOfKnowledge)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Reconstructs a serialized DKG round-1 package (the same combined-blob shape dkgRound2/dkgRound3/dkgTranscriptDigest expect) from the two independently-serialized wire fields `threshold-keygen-round1` carries. The inverse of splitRound1Package. */
|
|
58
|
+
function combineRound1Package(commitment, proofOfKnowledge) {
|
|
59
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.combine_round1_package([...commitment], proofOfKnowledge));
|
|
60
|
+
}
|
|
61
|
+
/** Round 2: verifies every other participant's round-1 proof of knowledge and computes this participant's own pairwise sub-shares. `round1` MUST NOT include this participant's own package. */
|
|
62
|
+
function dkgRound2(ownSecretPackage, round1) {
|
|
63
|
+
const [ids, packages] = toParallelArrays(round1);
|
|
64
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.dkg_round2(ownSecretPackage, ids, packages);
|
|
65
|
+
return {
|
|
66
|
+
secretPackage: toBufferSource(out.secretPackage),
|
|
67
|
+
outgoing: fromParallelArrays(out.recipientIds, out.packages)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Round 3 (local, no wire traffic): verifies every received round-2 package and sums them into this participant's own long-term key package. `round1`/`round2` MUST NOT include this participant's own packages. */
|
|
71
|
+
function dkgRound3(ownSecretPackage, round1, round2) {
|
|
72
|
+
const [ids1, packages1] = toParallelArrays(round1);
|
|
73
|
+
const [ids2, packages2] = toParallelArrays(round2);
|
|
74
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.dkg_round3(ownSecretPackage, ids1, packages1, ids2, packages2);
|
|
75
|
+
return {
|
|
76
|
+
keyPackage: toBufferSource(out.keyPackage),
|
|
77
|
+
publicKeyPackage: toBufferSource(out.publicKeyPackage),
|
|
78
|
+
groupVerifyingKey: toBufferSource(out.groupVerifyingKey)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** The echo-broadcast transcript digest this participant sends on `threshold-keygen-confirm` -- SHA-256 over the FULL ordered set of every round-1 package (including this participant's own), so two honest participants' digests are directly comparable. */
|
|
82
|
+
function dkgTranscriptDigest(allRound1, groupVerifyingKey) {
|
|
83
|
+
const [ids, packages] = toParallelArrays(allRound1);
|
|
84
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.dkg_transcript_digest(ids, packages, groupVerifyingKey));
|
|
85
|
+
}
|
|
86
|
+
/** Verifies this participant's own transcript digest/group key against what a peer reported. A mismatch means the ceremony MUST abort, never be repaired in place. */
|
|
87
|
+
function dkgConfirmMatches(ownDigest, ownGroupKey, peerDigest, peerGroupKey) {
|
|
88
|
+
return wasm_dist_wire_mesh_threshold_wasm_js.dkg_confirm_matches(ownDigest, ownGroupKey, peerDigest, peerGroupKey);
|
|
89
|
+
}
|
|
90
|
+
/** Extracts a key package's own signing-share bytes -- what `reshareRound1` needs as `ownOldSigningShare`. */
|
|
91
|
+
function keyPackageSigningShare(keyPackage) {
|
|
92
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.key_package_signing_share(keyPackage));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The pure-crypto half of round 1: generates a fresh nonce pair and its commitments. Persisting `nonces` durably before this participant's own round-1 response leaves the device is the CALLER's own obligation -- nonce reuse across two released signature shares discloses this participant's long-term key share outright. This function has no storage dependency and cannot enforce that obligation itself.
|
|
96
|
+
*/
|
|
97
|
+
function signingRound1Commit(ownKeyPackage) {
|
|
98
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.signing_round1_commit(ownKeyPackage);
|
|
99
|
+
return {
|
|
100
|
+
nonces: toBufferSource(out.nonces),
|
|
101
|
+
commitments: toBufferSource(out.commitments)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** Splits a serialized SigningCommitments blob (signingRound1Commit's own `commitments` output) into the two independently-serialized halves `threshold-commitment`'s wire shape carries (`hiding: bstr, binding: bstr`) -- unlike frost-core's own combined-blob serialization, which is opaque and not spec-shaped. The inverse of combineCommitments. */
|
|
105
|
+
function splitCommitments(commitments) {
|
|
106
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.split_commitments(commitments);
|
|
107
|
+
return {
|
|
108
|
+
hiding: toBufferSource(out.hiding),
|
|
109
|
+
binding: toBufferSource(out.binding)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** Reconstructs a serialized SigningCommitments blob (the same combined-blob shape signingBuildPackage/signingRound2Sign expect) from the two independently-serialized halves `threshold-commitment` carries on the wire. The inverse of splitCommitments. */
|
|
113
|
+
function combineCommitments(hiding, binding) {
|
|
114
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.combine_commitments(hiding, binding));
|
|
115
|
+
}
|
|
116
|
+
/** Coordinator-side: builds the signing-package bytes every participant's round 2 is computed against. */
|
|
117
|
+
function signingBuildPackage(commitments, message) {
|
|
118
|
+
const [ids, values] = toParallelArrays(commitments);
|
|
119
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.signing_build_package(ids, values, message));
|
|
120
|
+
}
|
|
121
|
+
/** Round 2: releases this participant's signature share. The CALLER MUST have already taken (one-shot) `nonces` from its own durable nonce store before calling this. */
|
|
122
|
+
function signingRound2Sign(nonces, signingPackage, ownKeyPackage) {
|
|
123
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.signing_round2_sign(nonces, signingPackage, ownKeyPackage));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Coordinator-side: sums and verifies the collected shares into the final aggregate signature -- an ordinary 64-byte Ed25519 signature. Throws if verification fails (a malformed or forged share); a caller MUST treat any thrown error here as "publish nothing".
|
|
127
|
+
*/
|
|
128
|
+
function signingAggregate(signingPackage, shares, publicKeyPackage) {
|
|
129
|
+
const [ids, values] = toParallelArrays(shares);
|
|
130
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.signing_aggregate(signingPackage, ids, values, publicKeyPackage));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Survivor side: re-shares this device's own Lagrange-weighted sub-share of the group secret across a new (possibly different) participant set. See `wire_mesh_threshold::reshare`'s own module doc comment (Rust side) for the full design rationale -- deliberately not built on a zero-secret "refresh" delta, which cannot onboard a device with no prior share or safely change the threshold.
|
|
134
|
+
*/
|
|
135
|
+
function reshareRound1(ownDeviceId, ownOldSigningShare, survivorDeviceIds, newParticipantDeviceIds, newMinSigners) {
|
|
136
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.reshare_round1(ownDeviceId, ownOldSigningShare, [...survivorDeviceIds], [...newParticipantDeviceIds], newMinSigners);
|
|
137
|
+
return {
|
|
138
|
+
commitment: toBufferSource(out.commitment),
|
|
139
|
+
outgoing: fromParallelArrays(out.recipientIds, out.shares)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/** Splits a survivor's serialized broadcast commitment (reshareRound1's own `commitment` output) into `threshold-keygen-round1`'s own wire shape: an array of independently-serialized coefficients (`commitment: [* bstr]`) -- unlike reshareRound1's own whole-blob serialization. The inverse of reshareCombineCommitmentParts. */
|
|
143
|
+
function reshareSplitCommitment(commitment) {
|
|
144
|
+
const out = [];
|
|
145
|
+
for (const part of wasm_dist_wire_mesh_threshold_wasm_js.reshare_split_commitment(commitment)) {
|
|
146
|
+
if (!isUint8Array(part)) throw new Error("wasm returned a non-Uint8Array entry in reshare_split_commitment's own output array");
|
|
147
|
+
out.push(toBufferSource(part));
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
/** Reconstructs a survivor's serialized broadcast commitment (the same whole-blob shape reshareCombineCommitments expects each entry of its own commitments array to be) from the wire's own per-coefficient array. The inverse of reshareSplitCommitment. */
|
|
152
|
+
function reshareCombineCommitmentParts(parts) {
|
|
153
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.reshare_combine_commitment_parts([...parts]));
|
|
154
|
+
}
|
|
155
|
+
/** Sums T survivors' broadcast commitment vectors into the one combined VSS commitment `reshareDerivePublicKeyPackage` needs. */
|
|
156
|
+
function reshareCombineCommitments(commitments) {
|
|
157
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.reshare_combine_commitments([...commitments]));
|
|
158
|
+
}
|
|
159
|
+
/** The echo-broadcast transcript digest a member of the new participant set sends on threshold-keygen-confirm for a reshare -- the reshare analogue of dkgTranscriptDigest, structurally distinct because a reshare's own survivor commitment carries no proof-of-knowledge component: deserializing one as a DKG round-1 package fails outright, since the two are different wire shapes entirely. `survivorCommitments` entries are each the same whole-blob shape reshareRound1's own `commitment` output is (NOT the wire's own split [* bstr] parts -- combine those first via reshareCombineCommitmentParts if collected off the wire). */
|
|
160
|
+
function reshareTranscriptDigest(survivorCommitments, groupVerifyingKey) {
|
|
161
|
+
const [ids, commitments] = toParallelArrays(survivorCommitments);
|
|
162
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.reshare_transcript_digest(ids, commitments, groupVerifyingKey));
|
|
163
|
+
}
|
|
164
|
+
/** The group's derived public key package given the combined commitment and the new participant set. `groupVerifyingKey` is what `threshold-keygen-confirm`'s own `group-key` field carries and what a reshare's own verifier obligation checks against `existing-group-key` (MUST equal it -- a reshare that changes the group key is a takeover, not a reshare). */
|
|
165
|
+
function reshareDerivePublicKeyPackage(combinedCommitment, newParticipantDeviceIds) {
|
|
166
|
+
const out = wasm_dist_wire_mesh_threshold_wasm_js.reshare_derive_public_key_package(combinedCommitment, [...newParticipantDeviceIds]);
|
|
167
|
+
return {
|
|
168
|
+
publicKeyPackage: toBufferSource(out.publicKeyPackage),
|
|
169
|
+
groupVerifyingKey: toBufferSource(out.groupVerifyingKey)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/** New-participant side (local): verifies each received share against its own embedded commitment, sums the validated shares, and builds this participant's final key package. */
|
|
173
|
+
function reshareCombineReceivedShares(ownDeviceId, received, publicKeyPackage, newMinSigners) {
|
|
174
|
+
return toBufferSource(wasm_dist_wire_mesh_threshold_wasm_js.reshare_combine_received_shares(ownDeviceId, [...received], publicKeyPackage, newMinSigners));
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
exports.combineCommitments = combineCommitments;
|
|
178
|
+
exports.combineRound1Package = combineRound1Package;
|
|
179
|
+
exports.dkgConfirmMatches = dkgConfirmMatches;
|
|
180
|
+
exports.dkgRound1 = dkgRound1;
|
|
181
|
+
exports.dkgRound2 = dkgRound2;
|
|
182
|
+
exports.dkgRound3 = dkgRound3;
|
|
183
|
+
exports.dkgTranscriptDigest = dkgTranscriptDigest;
|
|
184
|
+
exports.keyPackageSigningShare = keyPackageSigningShare;
|
|
185
|
+
exports.reshareCombineCommitmentParts = reshareCombineCommitmentParts;
|
|
186
|
+
exports.reshareCombineCommitments = reshareCombineCommitments;
|
|
187
|
+
exports.reshareCombineReceivedShares = reshareCombineReceivedShares;
|
|
188
|
+
exports.reshareDerivePublicKeyPackage = reshareDerivePublicKeyPackage;
|
|
189
|
+
exports.reshareRound1 = reshareRound1;
|
|
190
|
+
exports.reshareSplitCommitment = reshareSplitCommitment;
|
|
191
|
+
exports.reshareTranscriptDigest = reshareTranscriptDigest;
|
|
192
|
+
exports.signingAggregate = signingAggregate;
|
|
193
|
+
exports.signingBuildPackage = signingBuildPackage;
|
|
194
|
+
exports.signingRound1Commit = signingRound1Commit;
|
|
195
|
+
exports.signingRound2Sign = signingRound2Sign;
|
|
196
|
+
exports.splitCommitments = splitCommitments;
|
|
197
|
+
exports.splitRound1Package = splitRound1Package;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { D as DeviceId } from "../protocol-CNFRVx9w.cjs";
|
|
2
|
+
//#region src/adapters/threshold-wasm.d.ts
|
|
3
|
+
/** One `(deviceId, bytes)` pair -- the wasm boundary's own encoding of a map keyed by participant, since wasm-bindgen has no built-in `Map<Uint8Array, Uint8Array>` marshalling. */
|
|
4
|
+
export interface DeviceKeyed<T extends Uint8Array = Uint8Array<ArrayBuffer>> {
|
|
5
|
+
deviceId: DeviceId;
|
|
6
|
+
value: T;
|
|
7
|
+
}
|
|
8
|
+
export interface DkgRound1Result {
|
|
9
|
+
secretPackage: Uint8Array<ArrayBuffer>;
|
|
10
|
+
package: Uint8Array<ArrayBuffer>;
|
|
11
|
+
}
|
|
12
|
+
/** Round 1: samples this participant's own polynomial and commits to it. See `wire_mesh_threshold::dkg::round1`'s own doc comment for the full design. */
|
|
13
|
+
export declare function dkgRound1(ownDeviceId: DeviceId, maxSigners: number, minSigners: number): DkgRound1Result;
|
|
14
|
+
export interface SplitRound1PackageResult {
|
|
15
|
+
commitment: Uint8Array<ArrayBuffer>[];
|
|
16
|
+
proofOfKnowledge: Uint8Array<ArrayBuffer>;
|
|
17
|
+
}
|
|
18
|
+
/** Splits a serialized DKG round-1 package (dkgRound1's own `package` output) into `threshold-keygen-round1`'s own wire shape: the Feldman commitment as an array of independently-serialized coefficients (`commitment: [* bstr]`) and the Schnorr proof of knowledge as a separate byte string -- unlike frost-core's own combined-blob serialization. The inverse of combineRound1Package. */
|
|
19
|
+
export declare function splitRound1Package(serializedPackage: Uint8Array): SplitRound1PackageResult;
|
|
20
|
+
/** Reconstructs a serialized DKG round-1 package (the same combined-blob shape dkgRound2/dkgRound3/dkgTranscriptDigest expect) from the two independently-serialized wire fields `threshold-keygen-round1` carries. The inverse of splitRound1Package. */
|
|
21
|
+
export declare function combineRound1Package(commitment: readonly Uint8Array[], proofOfKnowledge: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
22
|
+
export interface DkgRound2Result {
|
|
23
|
+
secretPackage: Uint8Array<ArrayBuffer>;
|
|
24
|
+
outgoing: DeviceKeyed[];
|
|
25
|
+
}
|
|
26
|
+
/** Round 2: verifies every other participant's round-1 proof of knowledge and computes this participant's own pairwise sub-shares. `round1` MUST NOT include this participant's own package. */
|
|
27
|
+
export declare function dkgRound2(ownSecretPackage: Uint8Array, round1: readonly DeviceKeyed[]): DkgRound2Result;
|
|
28
|
+
export interface DkgRound3Result {
|
|
29
|
+
keyPackage: Uint8Array<ArrayBuffer>;
|
|
30
|
+
publicKeyPackage: Uint8Array<ArrayBuffer>;
|
|
31
|
+
groupVerifyingKey: Uint8Array<ArrayBuffer>;
|
|
32
|
+
}
|
|
33
|
+
/** Round 3 (local, no wire traffic): verifies every received round-2 package and sums them into this participant's own long-term key package. `round1`/`round2` MUST NOT include this participant's own packages. */
|
|
34
|
+
export declare function dkgRound3(ownSecretPackage: Uint8Array, round1: readonly DeviceKeyed[], round2: readonly DeviceKeyed[]): DkgRound3Result;
|
|
35
|
+
/** The echo-broadcast transcript digest this participant sends on `threshold-keygen-confirm` -- SHA-256 over the FULL ordered set of every round-1 package (including this participant's own), so two honest participants' digests are directly comparable. */
|
|
36
|
+
export declare function dkgTranscriptDigest(allRound1: readonly DeviceKeyed[], groupVerifyingKey: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
37
|
+
/** Verifies this participant's own transcript digest/group key against what a peer reported. A mismatch means the ceremony MUST abort, never be repaired in place. */
|
|
38
|
+
export declare function dkgConfirmMatches(ownDigest: Uint8Array, ownGroupKey: Uint8Array, peerDigest: Uint8Array, peerGroupKey: Uint8Array): boolean;
|
|
39
|
+
/** Extracts a key package's own signing-share bytes -- what `reshareRound1` needs as `ownOldSigningShare`. */
|
|
40
|
+
export declare function keyPackageSigningShare(keyPackage: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
41
|
+
export interface SigningRound1Result {
|
|
42
|
+
nonces: Uint8Array<ArrayBuffer>;
|
|
43
|
+
commitments: Uint8Array<ArrayBuffer>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The pure-crypto half of round 1: generates a fresh nonce pair and its commitments. Persisting `nonces` durably before this participant's own round-1 response leaves the device is the CALLER's own obligation -- nonce reuse across two released signature shares discloses this participant's long-term key share outright. This function has no storage dependency and cannot enforce that obligation itself.
|
|
47
|
+
*/
|
|
48
|
+
export declare function signingRound1Commit(ownKeyPackage: Uint8Array): SigningRound1Result;
|
|
49
|
+
export interface SplitCommitmentsResult {
|
|
50
|
+
hiding: Uint8Array<ArrayBuffer>;
|
|
51
|
+
binding: Uint8Array<ArrayBuffer>;
|
|
52
|
+
}
|
|
53
|
+
/** Splits a serialized SigningCommitments blob (signingRound1Commit's own `commitments` output) into the two independently-serialized halves `threshold-commitment`'s wire shape carries (`hiding: bstr, binding: bstr`) -- unlike frost-core's own combined-blob serialization, which is opaque and not spec-shaped. The inverse of combineCommitments. */
|
|
54
|
+
export declare function splitCommitments(commitments: Uint8Array): SplitCommitmentsResult;
|
|
55
|
+
/** Reconstructs a serialized SigningCommitments blob (the same combined-blob shape signingBuildPackage/signingRound2Sign expect) from the two independently-serialized halves `threshold-commitment` carries on the wire. The inverse of splitCommitments. */
|
|
56
|
+
export declare function combineCommitments(hiding: Uint8Array, binding: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
57
|
+
/** Coordinator-side: builds the signing-package bytes every participant's round 2 is computed against. */
|
|
58
|
+
export declare function signingBuildPackage(commitments: readonly DeviceKeyed[], message: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
59
|
+
/** Round 2: releases this participant's signature share. The CALLER MUST have already taken (one-shot) `nonces` from its own durable nonce store before calling this. */
|
|
60
|
+
export declare function signingRound2Sign(nonces: Uint8Array, signingPackage: Uint8Array, ownKeyPackage: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
61
|
+
/**
|
|
62
|
+
* Coordinator-side: sums and verifies the collected shares into the final aggregate signature -- an ordinary 64-byte Ed25519 signature. Throws if verification fails (a malformed or forged share); a caller MUST treat any thrown error here as "publish nothing".
|
|
63
|
+
*/
|
|
64
|
+
export declare function signingAggregate(signingPackage: Uint8Array, shares: readonly DeviceKeyed[], publicKeyPackage: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
65
|
+
export interface ReshareRound1Result {
|
|
66
|
+
commitment: Uint8Array<ArrayBuffer>;
|
|
67
|
+
outgoing: DeviceKeyed[];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Survivor side: re-shares this device's own Lagrange-weighted sub-share of the group secret across a new (possibly different) participant set. See `wire_mesh_threshold::reshare`'s own module doc comment (Rust side) for the full design rationale -- deliberately not built on a zero-secret "refresh" delta, which cannot onboard a device with no prior share or safely change the threshold.
|
|
71
|
+
*/
|
|
72
|
+
export declare function reshareRound1(ownDeviceId: DeviceId, ownOldSigningShare: Uint8Array, survivorDeviceIds: readonly DeviceId[], newParticipantDeviceIds: readonly DeviceId[], newMinSigners: number): ReshareRound1Result;
|
|
73
|
+
/** Splits a survivor's serialized broadcast commitment (reshareRound1's own `commitment` output) into `threshold-keygen-round1`'s own wire shape: an array of independently-serialized coefficients (`commitment: [* bstr]`) -- unlike reshareRound1's own whole-blob serialization. The inverse of reshareCombineCommitmentParts. */
|
|
74
|
+
export declare function reshareSplitCommitment(commitment: Uint8Array): Uint8Array<ArrayBuffer>[];
|
|
75
|
+
/** Reconstructs a survivor's serialized broadcast commitment (the same whole-blob shape reshareCombineCommitments expects each entry of its own commitments array to be) from the wire's own per-coefficient array. The inverse of reshareSplitCommitment. */
|
|
76
|
+
export declare function reshareCombineCommitmentParts(parts: readonly Uint8Array[]): Uint8Array<ArrayBuffer>;
|
|
77
|
+
/** Sums T survivors' broadcast commitment vectors into the one combined VSS commitment `reshareDerivePublicKeyPackage` needs. */
|
|
78
|
+
export declare function reshareCombineCommitments(commitments: readonly Uint8Array[]): Uint8Array<ArrayBuffer>;
|
|
79
|
+
/** The echo-broadcast transcript digest a member of the new participant set sends on threshold-keygen-confirm for a reshare -- the reshare analogue of dkgTranscriptDigest, structurally distinct because a reshare's own survivor commitment carries no proof-of-knowledge component: deserializing one as a DKG round-1 package fails outright, since the two are different wire shapes entirely. `survivorCommitments` entries are each the same whole-blob shape reshareRound1's own `commitment` output is (NOT the wire's own split [* bstr] parts -- combine those first via reshareCombineCommitmentParts if collected off the wire). */
|
|
80
|
+
export declare function reshareTranscriptDigest(survivorCommitments: readonly DeviceKeyed[], groupVerifyingKey: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
81
|
+
export interface ReshareDerivePublicKeyPackageResult {
|
|
82
|
+
publicKeyPackage: Uint8Array<ArrayBuffer>;
|
|
83
|
+
groupVerifyingKey: Uint8Array<ArrayBuffer>;
|
|
84
|
+
}
|
|
85
|
+
/** The group's derived public key package given the combined commitment and the new participant set. `groupVerifyingKey` is what `threshold-keygen-confirm`'s own `group-key` field carries and what a reshare's own verifier obligation checks against `existing-group-key` (MUST equal it -- a reshare that changes the group key is a takeover, not a reshare). */
|
|
86
|
+
export declare function reshareDerivePublicKeyPackage(combinedCommitment: Uint8Array, newParticipantDeviceIds: readonly DeviceId[]): ReshareDerivePublicKeyPackageResult;
|
|
87
|
+
/** New-participant side (local): verifies each received share against its own embedded commitment, sums the validated shares, and builds this participant's final key package. */
|
|
88
|
+
export declare function reshareCombineReceivedShares(ownDeviceId: DeviceId, received: readonly Uint8Array[], publicKeyPackage: Uint8Array, newMinSigners: number): Uint8Array<ArrayBuffer>;
|
|
89
|
+
//#endregion
|