@calimero-network/mero-js 15.0.0 → 15.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ export { EphemeralClient, jsonCodec } from './ephemeral/index.js';
16
16
  export type { Codec, EphemeralEntry } from './ephemeral/index.js';
17
17
  export * from './cloud/index.js';
18
18
  export { signWarrant, intentHash } from './warrant/index.js';
19
+ export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from './device-cert/index.js';
20
+ export type { DeviceCertInput } from './device-cert/index.js';
19
21
  export type { WarrantInput } from './warrant/index.js';
20
22
  export * from './capabilities.js';
21
23
  export { DEFAULT_LOCAL_NODE_PORTS, localNodeUrl, nodeEndpoint, probeNodeHealth, discoverLocalNodes, } from './nodeDiscovery.js';
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ export { EphemeralClient, jsonCodec } from './ephemeral/index.js';
22
22
  export * from './cloud/index.js';
23
23
  // Warrant signing — mint the author's consent for a relay to run one intent
24
24
  export { signWarrant, intentHash } from './warrant/index.js';
25
+ export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from './device-cert/index.js';
25
26
  // Member capability bitmask constants & helpers
26
27
  export * from './capabilities.js';
27
28
  // Utilities
package/dist/index.mjs CHANGED
@@ -2522,9 +2522,7 @@ var CloudClient = class {
2522
2522
  }
2523
2523
  };
2524
2524
 
2525
- // src/warrant/warrant.ts
2526
- var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v1");
2527
- var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
2525
+ // src/crypto/internal.ts
2528
2526
  var PKCS8_ED25519_PREFIX = new Uint8Array([
2529
2527
  48,
2530
2528
  46,
@@ -2543,6 +2541,11 @@ var PKCS8_ED25519_PREFIX = new Uint8Array([
2543
2541
  4,
2544
2542
  32
2545
2543
  ]);
2544
+ function u32le(value) {
2545
+ const out = new Uint8Array(4);
2546
+ new DataView(out.buffer).setUint32(0, value, true);
2547
+ return out;
2548
+ }
2546
2549
  function hex(bytes) {
2547
2550
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2548
2551
  }
@@ -2582,10 +2585,6 @@ async function domainHash(domain, parts) {
2582
2585
  await crypto.subtle.digest("SHA-256", concat(...chunks))
2583
2586
  );
2584
2587
  }
2585
- async function intentHash(method, argsJson) {
2586
- const args = new TextEncoder().encode(JSON.stringify(argsJson));
2587
- return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
2588
- }
2589
2588
  async function importSigningKey(secretHex) {
2590
2589
  const seed = fromHex(secretHex, "deviceSecret", 32);
2591
2590
  const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
@@ -2604,6 +2603,31 @@ async function importSigningKey(secretHex) {
2604
2603
  );
2605
2604
  }
2606
2605
  }
2606
+ async function derivePublicKey(secretHex) {
2607
+ const seed = fromHex(secretHex, "deviceSecret", 32);
2608
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2609
+ const key = await crypto.subtle.importKey(
2610
+ "pkcs8",
2611
+ pkcs8,
2612
+ { name: "Ed25519" },
2613
+ true,
2614
+ ["sign"]
2615
+ );
2616
+ const jwk = await crypto.subtle.exportKey("jwk", key);
2617
+ const raw = jwk.x;
2618
+ return Uint8Array.from(
2619
+ atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
2620
+ (c) => c.charCodeAt(0)
2621
+ );
2622
+ }
2623
+
2624
+ // src/warrant/warrant.ts
2625
+ var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v1");
2626
+ var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
2627
+ async function intentHash(method, argsJson) {
2628
+ const args = new TextEncoder().encode(JSON.stringify(argsJson));
2629
+ return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
2630
+ }
2607
2631
  async function signWarrant(input) {
2608
2632
  const context = fromHex(input.context, "context", 32);
2609
2633
  const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
@@ -2638,21 +2662,72 @@ async function signWarrant(input) {
2638
2662
  )
2639
2663
  );
2640
2664
  }
2641
- async function derivePublicKey(secretHex) {
2642
- const seed = fromHex(secretHex, "deviceSecret", 32);
2643
- const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2644
- const key = await crypto.subtle.importKey(
2645
- "pkcs8",
2646
- pkcs8,
2647
- { name: "Ed25519" },
2648
- true,
2649
- ["sign"]
2665
+
2666
+ // src/device-cert/device-cert.ts
2667
+ var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
2668
+ var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
2669
+ var DEVICE_ID_DOMAIN = new TextEncoder().encode("calimero.device.id.v1");
2670
+ var ACCOUNT_GENESIS_VERSION = 1;
2671
+ async function mintDeviceId(account, nonce) {
2672
+ if (nonce.length !== 16) {
2673
+ throw new Error(`nonce must be 16 bytes, got ${nonce.length}`);
2674
+ }
2675
+ const accountBytes = fromHex(account, "account", 32);
2676
+ return hex(await domainHash(DEVICE_ID_DOMAIN, [accountBytes, nonce]));
2677
+ }
2678
+ async function deviceCertPayload(input) {
2679
+ return domainHash(CERT_DOMAIN, [
2680
+ fromHex(input.account, "account", 32),
2681
+ fromHex(input.device, "device", 32),
2682
+ fromHex(input.signPublicKey, "signPublicKey", 32),
2683
+ fromHex(input.kemPublicKey, "kemPublicKey", 32),
2684
+ u32le(input.keyEpoch),
2685
+ u32le(input.deviceEpoch)
2686
+ ]);
2687
+ }
2688
+ async function signDeviceCert(input) {
2689
+ const rootPublicKey = await derivePublicKey(input.rootSecret);
2690
+ const account = hex(
2691
+ await domainHash(ACCOUNT_ID_DOMAIN, [
2692
+ concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
2693
+ ])
2650
2694
  );
2651
- const jwk = await crypto.subtle.exportKey("jwk", key);
2652
- const raw = jwk.x;
2653
- return Uint8Array.from(
2654
- atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
2655
- (c) => c.charCodeAt(0)
2695
+ const keyEpoch = 0;
2696
+ const payload = await deviceCertPayload({
2697
+ account,
2698
+ device: input.device,
2699
+ signPublicKey: input.signPublicKey,
2700
+ kemPublicKey: input.kemPublicKey,
2701
+ keyEpoch,
2702
+ deviceEpoch: input.deviceEpoch
2703
+ });
2704
+ const key = await importSigningKey(input.rootSecret);
2705
+ const signature = new Uint8Array(
2706
+ await crypto.subtle.sign("Ed25519", key, payload)
2707
+ );
2708
+ const credential = concat(
2709
+ // AccountGenesis
2710
+ new Uint8Array([ACCOUNT_GENESIS_VERSION]),
2711
+ rootPublicKey,
2712
+ // chain: Vec<RootKeyHandoff>, empty
2713
+ u32le(0),
2714
+ // DeviceCert
2715
+ fromHex(account, "account", 32),
2716
+ fromHex(input.device, "device", 32),
2717
+ fromHex(input.signPublicKey, "signPublicKey", 32),
2718
+ fromHex(input.kemPublicKey, "kemPublicKey", 32),
2719
+ u32le(keyEpoch),
2720
+ u32le(input.deviceEpoch),
2721
+ signature
2722
+ );
2723
+ return hex(credential);
2724
+ }
2725
+ async function accountForRoot(rootSecret) {
2726
+ const rootPublicKey = await derivePublicKey(rootSecret);
2727
+ return hex(
2728
+ await domainHash(ACCOUNT_ID_DOMAIN, [
2729
+ concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
2730
+ ])
2656
2731
  );
2657
2732
  }
2658
2733
 
@@ -2748,6 +2823,7 @@ export {
2748
2823
  SseClient,
2749
2824
  WebHttpClient,
2750
2825
  WsClient,
2826
+ accountForRoot,
2751
2827
  buildAuthLoginUrl,
2752
2828
  combineSignals,
2753
2829
  compareSemver,
@@ -2766,14 +2842,17 @@ export {
2766
2842
  createRetryableMethod,
2767
2843
  createTimeoutSignal,
2768
2844
  createUniversalHttpClient,
2845
+ deviceCertPayload,
2769
2846
  discoverLocalNodes,
2770
2847
  hasCap,
2771
2848
  intentHash,
2772
2849
  jsonCodec,
2773
2850
  localNodeUrl,
2851
+ mintDeviceId,
2774
2852
  nodeEndpoint,
2775
2853
  parseAuthCallback,
2776
2854
  probeNodeHealth,
2855
+ signDeviceCert,
2777
2856
  signWarrant,
2778
2857
  withCap,
2779
2858
  withRetry,