@totemsdk/omnia-host 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,12 +38,13 @@ The daemon configuration is read from environment variables:
38
38
 
39
39
  ### Signing model
40
40
 
41
- `OMNIA_HOST_SEED` (or the keyfile) is the base seed. The host derives a
42
- per-address seed (`derivePerAddressSeed(baseSeed, localAddressIndex)`) and
43
- signs every channel state with the flat WOTS key at index 0 of that seed; the
44
- channel participant's `publicKeyDigest` is `derivePKdigest(perAddressSeed, 0)`.
45
- The WOTS lease journal and watermark persist in `<OMNIA_HOST_DB>.lease/` so
46
- they survive restarts together with the channel database.
41
+ `OMNIA_HOST_SEED` (or the keyfile) is the base seed. The host derives the unified
42
+ child TreeKey (`createUnifiedChildTreeKey(baseSeed, localAddressIndex)`) and signs
43
+ every channel state (and the boot manifest) with serialized TreeSignatures; the
44
+ channel participant's `publicKeyDigest` is that TreeKey's root public key, and the
45
+ identity address is the matching Minima address. The WOTS lease journal and
46
+ watermark persist in `<OMNIA_HOST_DB>.lease/` so they survive restarts together
47
+ with the channel database.
47
48
 
48
49
  ### Read-only mode
49
50
 
package/dist/identity.js CHANGED
@@ -92,7 +92,22 @@ async function createHostManifest(config, signing, identity) {
92
92
  capabilities: ['omnia:open-channel', 'omnia:update-channel', 'omnia:route', 'omnia:settle'],
93
93
  tags: ['omnia', 'payment-channel', 'daemon'],
94
94
  };
95
- return (0, manifest_1.signManifest)(manifest, signing.perAddressSeed, 0);
95
+ // RFC-037: sign the manifest with the unified child TreeKey. Allocate a
96
+ // one-time leaf via the lease so restarts never reuse a WOTS leaf.
97
+ const reservation = await signing.leaseProvider.reserveKeyUse({
98
+ treeId: 'omnia-manifest',
99
+ purpose: 'manifest',
100
+ });
101
+ const useIndex = reservation.indices.l1 * 64 + reservation.indices.l2;
102
+ try {
103
+ const signed = await (0, manifest_1.signManifest)(manifest, signing.treeKey, useIndex);
104
+ await signing.leaseProvider.commitKeyUse(reservation.reservationId, 'manifest');
105
+ return signed;
106
+ }
107
+ catch (err) {
108
+ await signing.leaseProvider.burnReservation(reservation.reservationId, 'manifest-sign-failed').catch(() => { });
109
+ throw err;
110
+ }
96
111
  }
97
112
  /** Boot-time identity + manifest assembly. */
98
113
  async function createHostIdentityAndManifest(config, signing) {
package/dist/signing.d.ts CHANGED
@@ -2,20 +2,21 @@
2
2
  * Host signing material — derives the channel signer, WOTS lease provider,
3
3
  * and Minima address from env-provisioned key material.
4
4
  *
5
- * Key model (matches @totemsdk/omnia's verification path):
5
+ * Key model (RFC-037 unified WOTS):
6
6
  * - `baseSeed` comes from OMNIA_HOST_SEED (BIP39 mnemonic or 32-byte hex)
7
7
  * or from an OMNIA_HOST_KEYFILE JSON.
8
- * - `perAddressSeed = derivePerAddressSeed(baseSeed, localAddressIndex)`.
9
- * - The channel participant's `publicKeyDigest` is the flat WOTS PK digest
10
- * `derivePKdigest(perAddressSeed, 0)` — omnia verifies signatures with
11
- * `wotsVerifyDigest(sig, digest, pkDigest)`, which is key-index agnostic,
12
- * so the signer always signs with key index 0 of the per-address seed.
13
- * - The lease indices {addressIndex, l1, l2} are slot bookkeeping for
14
- * double-sign prevention (watermark monotonicity), not key derivation.
8
+ * - The channel key is the unified child TreeKey
9
+ * `createUnifiedChildTreeKey(baseSeed, localAddressIndex)`; the participant's
10
+ * `publicKeyDigest` is its tree-root public key — the same key the on-chain
11
+ * `MULTISIG` eltoo script embeds.
12
+ * - Signatures are serialized hierarchical `TreeSignature`s (`serializeTreeSignature`)
13
+ * over the reserved leaf `(l1*64 + l2)`, verified by `verifyChannelSignature`.
14
+ * - The lease indices {addressIndex, l1, l2} select the one-time leaf.
15
15
  *
16
16
  * The lease journal/watermark persist in a directory next to the channel DB
17
17
  * (`<dbPath>.lease/`) so they survive restarts together with the channel store.
18
18
  */
19
+ import { type TreeKey } from '@totemsdk/core';
19
20
  import type { StorageAdapter } from '@totemsdk/core';
20
21
  import type { ChannelSigner } from '@totemsdk/omnia';
21
22
  import type { WotsLeaseProvider } from '@totemsdk/wots-lease';
@@ -23,12 +24,14 @@ import type { OmniaHostConfig } from './config.js';
23
24
  export interface HostSigning {
24
25
  signer: ChannelSigner;
25
26
  leaseProvider: WotsLeaseProvider;
27
+ /** Minima address for the unified child TreeKey (identity + channels). */
26
28
  address: string;
29
+ /** Channel participant key: the unified child TreeKey root pubkey (RFC-037). */
27
30
  publicKeyDigest: string;
28
31
  /** 32-byte base seed (used by the identity/manifest layer). */
29
32
  baseSeed: Uint8Array;
30
- /** Per-address seed used for channel signing (key index 0). */
31
- perAddressSeed: Uint8Array;
33
+ /** Unified child TreeKey used for channel + manifest signing (RFC-037). */
34
+ treeKey: TreeKey;
32
35
  addressIndex: number;
33
36
  deviceId: string;
34
37
  }
package/dist/signing.js CHANGED
@@ -3,16 +3,16 @@
3
3
  * Host signing material — derives the channel signer, WOTS lease provider,
4
4
  * and Minima address from env-provisioned key material.
5
5
  *
6
- * Key model (matches @totemsdk/omnia's verification path):
6
+ * Key model (RFC-037 unified WOTS):
7
7
  * - `baseSeed` comes from OMNIA_HOST_SEED (BIP39 mnemonic or 32-byte hex)
8
8
  * or from an OMNIA_HOST_KEYFILE JSON.
9
- * - `perAddressSeed = derivePerAddressSeed(baseSeed, localAddressIndex)`.
10
- * - The channel participant's `publicKeyDigest` is the flat WOTS PK digest
11
- * `derivePKdigest(perAddressSeed, 0)` — omnia verifies signatures with
12
- * `wotsVerifyDigest(sig, digest, pkDigest)`, which is key-index agnostic,
13
- * so the signer always signs with key index 0 of the per-address seed.
14
- * - The lease indices {addressIndex, l1, l2} are slot bookkeeping for
15
- * double-sign prevention (watermark monotonicity), not key derivation.
9
+ * - The channel key is the unified child TreeKey
10
+ * `createUnifiedChildTreeKey(baseSeed, localAddressIndex)`; the participant's
11
+ * `publicKeyDigest` is its tree-root public key — the same key the on-chain
12
+ * `MULTISIG` eltoo script embeds.
13
+ * - Signatures are serialized hierarchical `TreeSignature`s (`serializeTreeSignature`)
14
+ * over the reserved leaf `(l1*64 + l2)`, verified by `verifyChannelSignature`.
15
+ * - The lease indices {addressIndex, l1, l2} select the one-time leaf.
16
16
  *
17
17
  * The lease journal/watermark persist in a directory next to the channel DB
18
18
  * (`<dbPath>.lease/`) so they survive restarts together with the channel store.
@@ -173,10 +173,10 @@ function createHostSigning(config) {
173
173
  throw new Error(`localAddressIndex ${addressIndex} is outside device slot ${deviceSlot} range ` +
174
174
  `${range.startAddressIndex}–${range.endAddressIndex}`);
175
175
  }
176
- const perAddressSeed = (0, core_1.derivePerAddressSeed)(baseSeed, addressIndex);
177
- const kp = (0, core_1.wotsKeypairFromSeed)(perAddressSeed, 0);
178
- const publicKeyDigest = `0x${(0, core_1.bytesToHex)(kp.pk)}`;
179
- const address = (0, core_1.wotsAddressFromKeypair)(kp);
176
+ const treeKey = (0, core_1.createUnifiedChildTreeKey)(baseSeed, addressIndex);
177
+ const publicKey = treeKey.getPublicKey();
178
+ const publicKeyDigest = `0x${(0, core_1.bytesToHex)(publicKey)}`;
179
+ const address = (0, core_1.scriptToAddress)((0, core_1.scriptFromWotsPk)(publicKey));
180
180
  const storage = new JsonFileStorageAdapter(leaseStorageDir(config.dbPath));
181
181
  const leaseProvider = new wots_lease_1.LocalLeaseProvider(storage, undefined, deviceId);
182
182
  const signer = {
@@ -184,13 +184,14 @@ function createHostSigning(config) {
184
184
  async sign(payload, indices) {
185
185
  // RFC-020 C1: honor the reserved leaf instead of hardcoding index 0. The
186
186
  // reservation must belong to this signer's address; the leaf within the
187
- // per-address seed is (l1*64 + l2). Callers must supply the pk digest for
188
- // the leaf they reserved (the default reservation is leaf (0,0)).
187
+ // per-address tree is (l1*64 + l2). Signatures are serialized TreeSignatures
188
+ // (RFC-037), verified by verifyChannelSignature against the tree-root pubkey.
189
189
  if (indices.addressIndex !== addressIndex) {
190
190
  throw new Error(`omnia-host signer address ${addressIndex} cannot sign reserved address ${indices.addressIndex}`);
191
191
  }
192
192
  const leafIndex = indices.l1 * 64 + indices.l2;
193
- return (0, core_1.wotsSign)(perAddressSeed, leafIndex, payload);
193
+ treeKey.setUses(leafIndex);
194
+ return (0, core_1.serializeTreeSignature)(treeKey.sign(payload));
194
195
  },
195
196
  };
196
197
  return {
@@ -199,7 +200,7 @@ function createHostSigning(config) {
199
200
  address,
200
201
  publicKeyDigest,
201
202
  baseSeed,
202
- perAddressSeed,
203
+ treeKey,
203
204
  addressIndex,
204
205
  deviceId,
205
206
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totemsdk/omnia-host",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "Durable Omnia node daemon for channel lifecycle, routing, and control APIs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -24,16 +24,16 @@
24
24
  "ws": "^8.21.1",
25
25
  "@totemsdk/chain-provider": "^0.2.1",
26
26
  "@totemsdk/core": "^1.2.11",
27
- "@totemsdk/identity": "^1.0.1",
27
+ "@totemsdk/omnia": "^2.0.1",
28
28
  "@totemsdk/manifest": "^1.0.0",
29
- "@totemsdk/omnia": "^1.0.2",
30
- "@totemsdk/omnia-factory": "^0.2.1",
31
- "@totemsdk/omnia-splice": "^0.2.1",
32
- "@totemsdk/omnia-vtxo": "^0.2.1",
33
- "@totemsdk/minima-rpc": "^0.2.2",
29
+ "@totemsdk/identity": "^1.0.1",
30
+ "@totemsdk/omnia-factory": "^0.4.0",
31
+ "@totemsdk/omnia-splice": "^0.3.0",
32
+ "@totemsdk/omnia-router": "^0.3.0",
33
+ "@totemsdk/omnia-vtxo": "^0.5.0",
34
34
  "@totemsdk/storage": "^0.1.0",
35
- "@totemsdk/wots-lease": "^1.0.1",
36
- "@totemsdk/omnia-router": "^0.2.1"
35
+ "@totemsdk/minima-rpc": "^0.2.2",
36
+ "@totemsdk/wots-lease": "^1.0.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/jest": "^30.0.0",