@novasamatech/host-container 0.8.5 → 0.8.6

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.
@@ -2,8 +2,32 @@
2
2
  * Derives 32 bytes of deterministic entropy using the three-layer
3
3
  * BLAKE2b-256 scheme specified in RFC-0007.
4
4
  *
5
+ * Layer 1 derives the `rootEntropySource` from the raw root account secret.
6
+ * Hosts that never hold the raw secret but receive `rootEntropySource` over the
7
+ * SSO handshake (RFC-0007 "Option 1") should call
8
+ * {@link deriveProductEntropyFromSource} instead — it skips layer 1 and yields
9
+ * identical output.
10
+ *
5
11
  * @param rootAccountSecret - Raw BIP-39 entropy bytes of the root account
6
12
  * @param productId - Identifier of the calling product (arbitrary-length string)
7
- * @param key - Caller-chosen key, up to 32 bytes
13
+ * @param key - Caller-chosen key, 1 to 32 bytes
8
14
  */
9
15
  export declare function deriveProductEntropy(rootAccountSecret: Uint8Array, productId: string, key: Uint8Array): Uint8Array;
16
+ /**
17
+ * Derives 32 bytes of deterministic entropy from a precomputed
18
+ * `rootEntropySource` — layers 2 and 3 of the RFC-0007 scheme.
19
+ *
20
+ * Use this when the host never holds the raw `rootAccountSecret` but receives
21
+ * `rootEntropySource = blake2b256_keyed(rootAccountSecret, "product-entropy-derivation")`
22
+ * over the SSO handshake (RFC-0007 "Option 1"). Given the same `rootEntropySource`,
23
+ * `productId`, and `key`, the output is byte-for-byte identical to
24
+ * {@link deriveProductEntropy} called with the corresponding `rootAccountSecret`.
25
+ *
26
+ * Do NOT pass a `rootEntropySource` to {@link deriveProductEntropy}: that would
27
+ * re-apply layer 1 and produce a different, non-conforming result.
28
+ *
29
+ * @param rootEntropySource - 32-byte source derived from the root account secret
30
+ * @param productId - Identifier of the calling product (arbitrary-length string)
31
+ * @param key - Caller-chosen key, 1 to 32 bytes
32
+ */
33
+ export declare function deriveProductEntropyFromSource(rootEntropySource: Uint8Array, productId: string, key: Uint8Array): Uint8Array;
@@ -1,4 +1,6 @@
1
1
  import { blake2b } from '@noble/hashes/blake2.js';
2
+ const textEncoder = new TextEncoder();
3
+ const DOMAIN_SEPARATOR = textEncoder.encode('product-entropy-derivation');
2
4
  function blake2b256Keyed(message, key) {
3
5
  return blake2b(message, { dkLen: 32, key });
4
6
  }
@@ -9,16 +11,41 @@ function blake2b256(message) {
9
11
  * Derives 32 bytes of deterministic entropy using the three-layer
10
12
  * BLAKE2b-256 scheme specified in RFC-0007.
11
13
  *
14
+ * Layer 1 derives the `rootEntropySource` from the raw root account secret.
15
+ * Hosts that never hold the raw secret but receive `rootEntropySource` over the
16
+ * SSO handshake (RFC-0007 "Option 1") should call
17
+ * {@link deriveProductEntropyFromSource} instead — it skips layer 1 and yields
18
+ * identical output.
19
+ *
12
20
  * @param rootAccountSecret - Raw BIP-39 entropy bytes of the root account
13
21
  * @param productId - Identifier of the calling product (arbitrary-length string)
14
- * @param key - Caller-chosen key, up to 32 bytes
22
+ * @param key - Caller-chosen key, 1 to 32 bytes
15
23
  */
16
24
  export function deriveProductEntropy(rootAccountSecret, productId, key) {
25
+ const rootEntropySource = blake2b256Keyed(rootAccountSecret, DOMAIN_SEPARATOR);
26
+ return deriveProductEntropyFromSource(rootEntropySource, productId, key);
27
+ }
28
+ /**
29
+ * Derives 32 bytes of deterministic entropy from a precomputed
30
+ * `rootEntropySource` — layers 2 and 3 of the RFC-0007 scheme.
31
+ *
32
+ * Use this when the host never holds the raw `rootAccountSecret` but receives
33
+ * `rootEntropySource = blake2b256_keyed(rootAccountSecret, "product-entropy-derivation")`
34
+ * over the SSO handshake (RFC-0007 "Option 1"). Given the same `rootEntropySource`,
35
+ * `productId`, and `key`, the output is byte-for-byte identical to
36
+ * {@link deriveProductEntropy} called with the corresponding `rootAccountSecret`.
37
+ *
38
+ * Do NOT pass a `rootEntropySource` to {@link deriveProductEntropy}: that would
39
+ * re-apply layer 1 and produce a different, non-conforming result.
40
+ *
41
+ * @param rootEntropySource - 32-byte source derived from the root account secret
42
+ * @param productId - Identifier of the calling product (arbitrary-length string)
43
+ * @param key - Caller-chosen key, 1 to 32 bytes
44
+ */
45
+ export function deriveProductEntropyFromSource(rootEntropySource, productId, key) {
17
46
  if (key.length === 0 || key.length > 32) {
18
47
  throw new Error(`"key" must be between 1 and 32 bytes, got ${key.length}`);
19
48
  }
20
- const textEncoder = new TextEncoder();
21
- const rootEntropySource = blake2b256Keyed(rootAccountSecret, textEncoder.encode('product-entropy-derivation'));
22
49
  const perProductEntropy = blake2b256Keyed(rootEntropySource, blake2b256(textEncoder.encode(productId)));
23
50
  return blake2b256Keyed(perProductEntropy, key);
24
51
  }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,6 @@ export { createIframeProvider } from './createIframeProvider.js';
3
3
  export { createContainer } from './createContainer.js';
4
4
  export type { Container, ContainerHandlerOf, CreateContainerOptions, HostApiDebugMessageEvent } from './types.js';
5
5
  export { onHostApiDebugMessage } from './debugBus.js';
6
- export { deriveProductEntropy } from './deriveEntropy.js';
6
+ export { deriveProductEntropy, deriveProductEntropyFromSource } from './deriveEntropy.js';
7
7
  export { createRateLimiter } from './rateLimiter.js';
8
8
  export type { CreateRateLimiterConfig, RateLimiter, RateLimiterConfig, RateLimiterStrategy } from './rateLimiter.js';
package/dist/index.js CHANGED
@@ -2,5 +2,5 @@ export { createWebviewProvider } from './createWebviewProvider.js';
2
2
  export { createIframeProvider } from './createIframeProvider.js';
3
3
  export { createContainer } from './createContainer.js';
4
4
  export { onHostApiDebugMessage } from './debugBus.js';
5
- export { deriveProductEntropy } from './deriveEntropy.js';
5
+ export { deriveProductEntropy, deriveProductEntropyFromSource } from './deriveEntropy.js';
6
6
  export { createRateLimiter } from './rateLimiter.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/host-container",
3
3
  "type": "module",
4
- "version": "0.8.5",
4
+ "version": "0.8.6",
5
5
  "description": "Host container for hosting and managing products within the Polkadot ecosystem.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "@noble/hashes": "2.2.0",
29
29
  "polkadot-api": ">=2",
30
30
  "@polkadot-api/substrate-client": "^0.7.0",
31
- "@novasamatech/host-api": "0.8.5",
31
+ "@novasamatech/host-api": "0.8.6",
32
32
  "nanoevents": "9.1.0",
33
33
  "nanoid": "5.1.11",
34
34
  "neverthrow": "^8.2.0"