@ibgib/core-gib 0.1.42 → 0.1.44

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 (88) hide show
  1. package/dist/keystone/kdf/kdf-constants.d.mts +25 -0
  2. package/dist/keystone/kdf/kdf-constants.d.mts.map +1 -0
  3. package/dist/keystone/kdf/kdf-constants.mjs +28 -0
  4. package/dist/keystone/kdf/kdf-constants.mjs.map +1 -0
  5. package/dist/keystone/kdf/kdf-helpers.d.mts +45 -0
  6. package/dist/keystone/kdf/kdf-helpers.d.mts.map +1 -0
  7. package/dist/keystone/kdf/kdf-helpers.mjs +94 -0
  8. package/dist/keystone/kdf/kdf-helpers.mjs.map +1 -0
  9. package/dist/keystone/kdf/kdf-types.d.mts +49 -0
  10. package/dist/keystone/kdf/kdf-types.d.mts.map +1 -0
  11. package/dist/keystone/kdf/kdf-types.mjs +2 -0
  12. package/dist/keystone/kdf/kdf-types.mjs.map +1 -0
  13. package/dist/keystone/keystone-config-builder.d.mts +65 -12
  14. package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
  15. package/dist/keystone/keystone-config-builder.mjs +138 -46
  16. package/dist/keystone/keystone-config-builder.mjs.map +1 -1
  17. package/dist/keystone/keystone-config-builder.respec.mjs +21 -13
  18. package/dist/keystone/keystone-config-builder.respec.mjs.map +1 -1
  19. package/dist/keystone/keystone-constants.d.mts +15 -0
  20. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  21. package/dist/keystone/keystone-constants.mjs +16 -0
  22. package/dist/keystone/keystone-constants.mjs.map +1 -1
  23. package/dist/keystone/keystone-helpers.d.mts +4 -4
  24. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  25. package/dist/keystone/keystone-helpers.mjs +8 -5
  26. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  27. package/dist/keystone/keystone-service-v1.d.mts +1 -1
  28. package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
  29. package/dist/keystone/keystone-service-v1.mjs +6 -5
  30. package/dist/keystone/keystone-service-v1.mjs.map +1 -1
  31. package/dist/keystone/keystone-service-v1.respec.mjs +72 -45
  32. package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
  33. package/dist/keystone/keystone-types.d.mts +28 -18
  34. package/dist/keystone/keystone-types.d.mts.map +1 -1
  35. package/dist/keystone/keystone-types.mjs +26 -15
  36. package/dist/keystone/keystone-types.mjs.map +1 -1
  37. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts.map +1 -1
  38. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs +7 -10
  39. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs.map +1 -1
  40. package/dist/sync/sync-conflict-text-merge.respec.mjs +26 -26
  41. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  42. package/dist/sync/sync-constants.d.mts +9 -0
  43. package/dist/sync/sync-constants.d.mts.map +1 -1
  44. package/dist/sync/sync-constants.mjs +10 -0
  45. package/dist/sync/sync-constants.mjs.map +1 -1
  46. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +7 -0
  47. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +1 -0
  48. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +282 -0
  49. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -0
  50. package/dist/sync/sync-saga-coordinator.d.mts +22 -11
  51. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  52. package/dist/sync/sync-saga-coordinator.mjs +120 -27
  53. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  54. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +1 -7
  55. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  56. package/dist/sync/sync-types.d.mts +11 -0
  57. package/dist/sync/sync-types.d.mts.map +1 -1
  58. package/dist/sync/sync-types.mjs.map +1 -1
  59. package/dist/test/mock-space.d.mts +1 -38
  60. package/dist/test/mock-space.d.mts.map +1 -1
  61. package/dist/test/mock-space.mjs +73 -78
  62. package/dist/test/mock-space.mjs.map +1 -1
  63. package/package.json +1 -1
  64. package/src/keystone/README.md +119 -0
  65. package/src/keystone/docs/architecture.md +32 -1
  66. package/src/keystone/kdf/kdf-constants.mts +34 -0
  67. package/src/keystone/kdf/kdf-helpers.mts +105 -0
  68. package/src/keystone/kdf/kdf-types.mts +58 -0
  69. package/src/keystone/keystone-config-builder.mts +170 -47
  70. package/src/keystone/keystone-config-builder.respec.mts +21 -14
  71. package/src/keystone/keystone-constants.mts +21 -2
  72. package/src/keystone/keystone-helpers.mts +19 -14
  73. package/src/keystone/keystone-service-v1.mts +23 -22
  74. package/src/keystone/keystone-service-v1.respec.mts +71 -44
  75. package/src/keystone/keystone-types.mts +37 -23
  76. package/src/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mts +9 -13
  77. package/src/sync/README.md +122 -5
  78. package/src/sync/docs/architecture.md +2 -2
  79. package/src/sync/{SYNC_TESTING.md → docs/testing.md} +113 -28
  80. package/src/sync/sync-conflict-text-merge.respec.mts +25 -25
  81. package/src/sync/sync-constants.mts +12 -0
  82. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +349 -0
  83. package/src/sync/sync-saga-coordinator.mts +158 -33
  84. package/src/sync/sync-saga-message/sync-saga-message-types.mts +1 -7
  85. package/src/sync/sync-types.mts +12 -0
  86. package/src/test/mock-space.mts +72 -72
  87. package/tmp.md +0 -274
  88. package/src/sync/docs/verification.md +0 -43
@@ -1,79 +1,74 @@
1
- import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
2
- /**
3
- * A simple in-memory map acting as a Space.
4
- * Pure Storage. No Indexing logic.
5
- *
6
- * Copied/Adapted from Keystone Respecs.
7
- */
8
- export class MockIbGibSpace {
9
- name;
10
- store = new Map();
11
- constructor(name = "mock_space") {
12
- this.name = name;
13
- }
14
- async put({ ibGib }) {
15
- const addr = getIbGibAddr({ ibGib });
16
- this.store.set(addr, JSON.parse(JSON.stringify(ibGib))); // Deep copy
17
- }
18
- async get({ addr }) {
19
- const data = this.store.get(addr);
20
- return data ? JSON.parse(JSON.stringify(data)) : null;
21
- }
22
- async witness(arg) {
23
- const cmd = arg.data?.cmd;
24
- if (cmd === 'get') {
25
- const addrs = arg.data.ibGibAddrs || [];
26
- const ibGibs = [];
27
- for (const addr of addrs) {
28
- const ig = await this.get({ addr });
29
- if (ig)
30
- ibGibs.push(ig);
31
- }
32
- return { ibGibs };
33
- }
34
- if (cmd === 'put') {
35
- const ibGibs = arg.ibGibs || [];
36
- for (const ibGib of ibGibs) {
37
- await this.put({ ibGib });
38
- }
39
- return { ibGibs: [] }; // Return empty result or whatever witness expects
40
- }
41
- return undefined;
42
- }
43
- }
44
- /**
45
- * A partial mock of Metaspace.
46
- */
47
- export class MockMetaspaceService {
48
- space;
49
- /**
50
- * Map of TJP Gib (Timeline ID) -> Latest IbGib Addr (Head)
51
- */
52
- timelineHeads = new Map();
53
- constructor(space) {
54
- this.space = space;
55
- }
56
- async getLocalUserSpace({ lock }) {
57
- return this.space;
58
- }
59
- async put(args) {
60
- const target = args.space || this.space;
61
- return target.put(args);
62
- }
63
- async registerNewIbGib(args) {
64
- const { ibGib } = args;
65
- const targetSpace = args.space || this.space;
66
- // 1. Ensure it is stored
67
- await targetSpace.put({ ibGib });
68
- // 2. Extract TJP
69
- const gib = ibGib.gib || '';
70
- let tjpGib = gib;
71
- if (gib.includes('.')) {
72
- const parts = gib.split('.');
73
- tjpGib = parts.slice(1).join('.');
74
- }
75
- const addr = getIbGibAddr({ ibGib });
76
- this.timelineHeads.set(tjpGib, addr);
77
- }
78
- }
1
+ // import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
2
+ // import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
3
+ export {};
4
+ // /**
5
+ // * A simple in-memory map acting as a Space.
6
+ // * Pure Storage. No Indexing logic.
7
+ // *
8
+ // * Copied/Adapted from Keystone Respecs.
9
+ // */
10
+ // export class MockIbGibSpace {
11
+ // store = new Map<string, IbGib_V1>();
12
+ // constructor(public name: string = "mock_space") { }
13
+ // async put({ ibGib }: { ibGib: IbGib_V1 }): Promise<void> {
14
+ // const addr = getIbGibAddr({ ibGib });
15
+ // this.store.set(addr, JSON.parse(JSON.stringify(ibGib))); // Deep copy
16
+ // }
17
+ // async get({ addr }: { addr: string }): Promise<IbGib_V1 | null> {
18
+ // const data = this.store.get(addr);
19
+ // return data ? JSON.parse(JSON.stringify(data)) : null;
20
+ // }
21
+ // async witness(arg: any): Promise<any> {
22
+ // const cmd = arg.data?.cmd;
23
+ // if (cmd === 'get') {
24
+ // const addrs = arg.data.ibGibAddrs || [];
25
+ // const ibGibs: IbGib_V1[] = [];
26
+ // for (const addr of addrs) {
27
+ // const ig = await this.get({ addr });
28
+ // if (ig) ibGibs.push(ig);
29
+ // }
30
+ // return { ibGibs };
31
+ // }
32
+ // if (cmd === 'put') {
33
+ // const ibGibs = arg.ibGibs || [];
34
+ // for (const ibGib of ibGibs) {
35
+ // await this.put({ ibGib });
36
+ // }
37
+ // return { ibGibs: [] }; // Return empty result or whatever witness expects
38
+ // }
39
+ // return undefined;
40
+ // }
41
+ // }
42
+ // /**
43
+ // * A partial mock of Metaspace.
44
+ // */
45
+ // export class MockMetaspaceService {
46
+ // /**
47
+ // * Map of TJP Gib (Timeline ID) -> Latest IbGib Addr (Head)
48
+ // */
49
+ // timelineHeads = new Map<string, string>();
50
+ // constructor(public space: MockIbGibSpace) { }
51
+ // async getLocalUserSpace({ lock }: { lock: boolean }): Promise<MockIbGibSpace> {
52
+ // return this.space;
53
+ // }
54
+ // async put(args: any): Promise<void> {
55
+ // const target = args.space || this.space;
56
+ // return target.put(args);
57
+ // }
58
+ // async registerNewIbGib(args: { ibGib: IbGib_V1, space?: any }): Promise<void> {
59
+ // const { ibGib } = args;
60
+ // const targetSpace = args.space || this.space;
61
+ // // 1. Ensure it is stored
62
+ // await targetSpace.put({ ibGib });
63
+ // // 2. Extract TJP
64
+ // const gib = ibGib.gib || '';
65
+ // let tjpGib = gib;
66
+ // if (gib.includes('.')) {
67
+ // const parts = gib.split('.');
68
+ // tjpGib = parts.slice(1).join('.');
69
+ // }
70
+ // const addr = getIbGibAddr({ ibGib });
71
+ // this.timelineHeads.set(tjpGib, addr);
72
+ // }
73
+ // }
79
74
  //# sourceMappingURL=mock-space.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mock-space.mjs","sourceRoot":"","sources":["../../src/test/mock-space.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAGJ;IAFnB,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEpC,YAAmB,OAAe,YAAY;QAA3B,SAAI,GAAJ,IAAI,CAAuB;IAAI,CAAC;IAEnD,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAuB;QACpC,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY;IACzE,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAoB;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAQ;QAClB,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;QAC1B,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;YACxC,MAAM,MAAM,GAAe,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpC,IAAI,EAAE;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC5B,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;YAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBACzB,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9B,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,kDAAkD;QAC7E,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,OAAO,oBAAoB;IAOV;IALnB;;OAEG;IACH,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,YAAmB,KAAqB;QAArB,UAAK,GAAL,KAAK,CAAgB;IAAI,CAAC;IAE7C,KAAK,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAqB;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,IAAS;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;QACxC,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAsC;QACzD,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QACvB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;QAE7C,yBAAyB;QACzB,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAEjC,iBAAiB;QACjB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;QAC5B,IAAI,MAAM,GAAG,GAAG,CAAC;QACjB,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;CACJ"}
1
+ {"version":3,"file":"mock-space.mjs","sourceRoot":"","sources":["../../src/test/mock-space.mts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;;AAEhE,MAAM;AACN,+CAA+C;AAC/C,sCAAsC;AACtC,KAAK;AACL,2CAA2C;AAC3C,MAAM;AACN,gCAAgC;AAChC,2CAA2C;AAE3C,0DAA0D;AAE1D,iEAAiE;AACjE,gDAAgD;AAChD,gFAAgF;AAChF,QAAQ;AAER,wEAAwE;AACxE,6CAA6C;AAC7C,iEAAiE;AACjE,QAAQ;AAER,8CAA8C;AAC9C,qCAAqC;AACrC,+BAA+B;AAC/B,uDAAuD;AACvD,6CAA6C;AAC7C,0CAA0C;AAC1C,uDAAuD;AACvD,2CAA2C;AAC3C,gBAAgB;AAChB,iCAAiC;AACjC,YAAY;AACZ,+BAA+B;AAC/B,+CAA+C;AAC/C,4CAA4C;AAC5C,6CAA6C;AAC7C,gBAAgB;AAChB,wFAAwF;AACxF,YAAY;AACZ,4BAA4B;AAC5B,QAAQ;AACR,IAAI;AAEJ,MAAM;AACN,kCAAkC;AAClC,MAAM;AACN,sCAAsC;AAEtC,UAAU;AACV,kEAAkE;AAClE,UAAU;AACV,iDAAiD;AAEjD,oDAAoD;AAEpD,sFAAsF;AACtF,6BAA6B;AAC7B,QAAQ;AAER,4CAA4C;AAC5C,mDAAmD;AACnD,mCAAmC;AACnC,QAAQ;AAER,sFAAsF;AACtF,kCAAkC;AAClC,wDAAwD;AAExD,oCAAoC;AACpC,4CAA4C;AAE5C,4BAA4B;AAC5B,uCAAuC;AACvC,4BAA4B;AAC5B,mCAAmC;AACnC,4CAA4C;AAC5C,iDAAiD;AACjD,YAAY;AACZ,gDAAgD;AAChD,gDAAgD;AAChD,QAAQ;AACR,IAAI"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibgib/core-gib",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "ibgib core functionality, including base architecture for witnesses, spaces, apps, robbots, etc., as well as shared utility functions. Node v19+ needed for heavily-used isomorphic webcrypto hashing consumed in both node and browsers.",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -16,5 +16,124 @@ Validation in this system is **Auditability**: to verify an identity (e.g., "Is
16
16
  3. **Hash-based**: Uses hash pre-imaging for quantum resistance (`hash-reveal-v1`).
17
17
  4. **Merkle Graphs**: Efficient communication by only transmitting missing graph nodes.
18
18
 
19
+ ## Challenge Pools
20
+
21
+ Keystones organize challenges into **pools** with specific purposes:
22
+
23
+ * **Default Pool**: General-purpose signing operations
24
+ * **Revoke Pool**: Permanent identity termination (one-time use, `verb: revoke`)
25
+ * **Manage Pool**: Structural changes like adding pools (`verb: manage`)
26
+ * **Foreign Pools**: Delegation to external identities (SSO-like workflows)
27
+
28
+ Each pool configuration specifies:
29
+ * **`poolId`**: Unique identifier within the keystone
30
+ * **`verb`**: Auto-routes operations (e.g., `revoke`, `manage`, `login`)
31
+ * **`replenishStrategy`**: What to do after using challenges in a pool, e.g.
32
+ `'top-up'`, `'replace-all'`, `'delete-all'`, etc.
33
+ * **`challengeCount`**: Number of hash challenges in the pool
34
+
35
+ ## Basic Usage
36
+
37
+ ### Genesis (Create Identity)
38
+
39
+ ```typescript
40
+ const keystone = await keystoneService.genesis({
41
+ masterSecret: "user-password",
42
+ configs: [
43
+ { poolId: 'default', challengeCount: 100, replenishStrategy: KeystoneReplenishStrategy.topUp },
44
+ { poolId: 'revoke', verb: 'revoke', challengeCount: 10, replenishStrategy: KeystoneReplenishStrategy.deleteAll }
45
+ ],
46
+ metaspace,
47
+ space
48
+ });
49
+ ```
50
+
51
+ ### Sign a Claim
52
+
53
+ ```typescript
54
+ const signedKeystone = await keystoneService.sign({
55
+ latestKeystone: keystone,
56
+ claim: { action: 'login', timestamp: Date.now() },
57
+ masterSecret: "user-password",
58
+ poolId: 'default', // or use verb-based auto-routing
59
+ metaspace,
60
+ space
61
+ });
62
+ ```
63
+
64
+ ### Revoke Identity
65
+
66
+ ```typescript
67
+ await keystoneService.revoke({
68
+ latestKeystone: keystone,
69
+ reason: "Device compromised",
70
+ masterSecret: "user-password",
71
+ metaspace,
72
+ space
73
+ });
74
+ ```
75
+
76
+ ## Delegation via Foreign Pools
77
+
78
+ > [!IMPORTANT]
79
+ > **🔑 Foreign pools enable delegation** - Alice can grant Bob signing authority for specific operations.
80
+
81
+ Alice can delegate signing authority to Bob by adding his challenge pool:
82
+
83
+ ```typescript
84
+ const aliceWithBobPool = await keystoneService.addPools({
85
+ latestKeystone: aliceKeystone,
86
+ newPoolConfigs: [
87
+ {
88
+ poolId: 'bob-sso',
89
+ verb: 'login',
90
+ foreignServerUrl: 'https://bob-server.com',
91
+ challengeCount: 50
92
+ }
93
+ ],
94
+ masterSecret: aliceSecret,
95
+ metaspace,
96
+ space
97
+ });
98
+ ```
99
+
100
+ Now Bob can sign login claims on Alice's behalf, but only for operations using the `login` verb.
101
+
102
+ **Trust Model**:
103
+ - Alice validates Bob's pool **shape** when adding (via `validateChallengePool`)
104
+ - Bob never transmits his secrets
105
+ - Communication secured via TLS
106
+ - Bob can validate his pool section when Alice evolves keystone
107
+
108
+ ## Validation
109
+
110
+ To verify a keystone timeline:
111
+
112
+ 1. **Replay** from genesis to current frame
113
+ 2. **Verify** each proof's hash pre-images match challenges
114
+ 3. **Validate** challenge selection matches policy engine rules
115
+ 4. **Check** revocation status (if revoked, identity cannot evolve)
116
+
117
+ Validation helpers:
118
+ * `validateEvolution()`: Verifies transition from previous to current frame
119
+ * `validateKeystoneTimeline()`: Replays entire timeline from genesis
120
+
121
+ ## Integration with Sync
122
+
123
+ Keystones integrate with the sync protocol to provide **session identity**:
124
+
125
+ * **Session Keystones**: Ephemeral identities created per sync saga
126
+ * **Saga Binding**: Session keystone salted with `sagaId`
127
+ * **Signature Frames**: Each saga frame can be signed with session identity
128
+
129
+ > [!CAUTION]
130
+ > **🚧 Session identity integration is NOT yet functional.** See [sync README](file:../sync/README.md#session-identity-usesessionidentity) for current status.
131
+
19
132
  ## Implementation
133
+
20
134
  The v1 implementation creates a pure TypeScript, isomorphic, hash-based identity system. It is designed to be "Non-Evil" and "Graph-Native".
135
+
136
+ **Key Files**:
137
+ * [keystone-service-v1.mts](file:./keystone-service-v1.mts): Core service implementation
138
+ * [keystone-types.mts](file:./keystone-types.mts): TypeScript type definitions
139
+ * [keystone-helpers.mts](file:./keystone-helpers.mts): Utility functions
@@ -14,6 +14,33 @@
14
14
  * **Challenge Pool**: A collection of puzzles stored in each Keystone Frame.
15
15
  * **Constraint/Policy Engine**: Logic that determines *which* challenges must be solved to authorize a specific action (Binding, FIFO, Stochastic).
16
16
 
17
+ ### Foreign Pools (Delegation)
18
+
19
+ > [!IMPORTANT]
20
+ > **🔀 Keystones support delegation** by embedding challenges from external identities.
21
+
22
+ **Mechanism**:
23
+ * **Use Case**: Alice adds Bob's challenge pool to her keystone
24
+ * **Validation**: Alice validates Bob's pool **shape** when adding (via `validateChallengePool`)
25
+ * **Signing**: Bob can sign claims on Alice's behalf (limited by `verb` field)
26
+ * **Trust Model**:
27
+ - Bob never transmits secrets across network
28
+ - Communication secured via TLS
29
+ - Bob can validate his pool section when Alice evolves keystone
30
+ * **SSO Pattern**: Enables Single Sign-On workflows without shared secrets
31
+
32
+ **Configuration**:
33
+ ```typescript
34
+ {
35
+ poolId: 'bob-sso',
36
+ verb: 'login',
37
+ foreignServerUrl: 'https://bob-server.com',
38
+ challengeCount: 50
39
+ }
40
+ ```
41
+
42
+ See [KeystoneService_V1.addPools()](file:../keystone-service-v1.mts) for implementation.
43
+
17
44
  ## 3. Policy Engine (Selection & Mitigation)
18
45
 
19
46
  To prevent replay attacks by Man-in-the-Middle (MITM) actors, the challenges required to sign a frame are selected via a multi-layered pipeline:
@@ -45,7 +72,11 @@ Inputs: `LatestKeystone`, `Claim`, `MasterSecret`.
45
72
  1. **Auto-Routing**: Selects pool based on Verb (e.g., 'revoke').
46
73
  2. **Selection**: Runs Policy Engine.
47
74
  3. **Solving**: Generates solutions.
48
- 4. **Replenishment**: Adds new challenges (Top-Up) or burns them.
75
+ 4. **Replenishment**: Adds new challenges based on pool's `replenishStrategy`:
76
+ * **`'top-up'`**: Refills consumed challenges (default, reusable identity)
77
+ * **`'replace-all'`**: Establishes completely new challenges (mitigate long-term pre-image attacks)
78
+ * **`'consume'`**: Do not re-add any challenges (limited number of uses)
79
+ * **`'delete-all'`**: Removes all challenges permanently (revocation, one-time operations)
49
80
 
50
81
  ### 5.3 Validate
51
82
  Inputs: `PreviousFrame`, `CurrentFrame`.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * KDF Strategy Constants
3
+ *
4
+ * Defines available key derivation function strategies.
5
+ */
6
+
7
+ // #region KdfStrategy
8
+ export const KDF_STRATEGY_RECURSIVE_SALT_WRAP = 'recursive-salt-wrap';
9
+ export type KdfStrategy =
10
+ | typeof KDF_STRATEGY_RECURSIVE_SALT_WRAP
11
+ ;
12
+
13
+ /**
14
+ * Available KDF strategies for deriving keys from master secrets.
15
+ *
16
+ * - `recursive-salt-wrap`: Hash(salt + current + salt) ^ rounds
17
+ * Used by KeystoneStrategy_HashRevealV1 for pool secret derivation
18
+ */
19
+ export const KdfStrategy = {
20
+ /**
21
+ * Recursive salt wrap strategy: Hash(salt + current + salt) ^ rounds
22
+ *
23
+ * This is the primary strategy used by keystones for deriving pool secrets
24
+ * from master secrets with configurable rounds for key stretching.
25
+ */
26
+ recursive_salt_wrap: KDF_STRATEGY_RECURSIVE_SALT_WRAP,
27
+ } satisfies { [key: string]: KdfStrategy };
28
+
29
+ export const KDF_STRATEGY_VALID_VALUES = Object.values(KdfStrategy);
30
+
31
+ export function isValidKdfStrategy(strategy: string): strategy is KdfStrategy {
32
+ return KDF_STRATEGY_VALID_VALUES.includes(strategy as KdfStrategy);
33
+ }
34
+ // #endregion KdfStrategy
@@ -0,0 +1,105 @@
1
+ import { extractErrorMsg, hash, HashAlgorithm } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
+
3
+ import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
4
+ import { KDF_STRATEGY_RECURSIVE_SALT_WRAP, KDF_STRATEGY_VALID_VALUES, KdfStrategy } from './kdf-constants.mjs';
5
+ import { DeriveKeyParams, KdfOptions_RecursiveSaltWrap } from './kdf-types.mjs';
6
+
7
+ const logalot = GLOBAL_LOG_A_LOT;
8
+
9
+ /**
10
+ * Derive a key from a master secret using the specified KDF strategy
11
+ *
12
+ * This is the main dispatch function for all KDF operations. It routes to the
13
+ * appropriate strategy implementation based on `kdfOpts.strategy`.
14
+ *
15
+ * @param params - Derivation parameters including master secret and KDF options
16
+ * @returns Derived key
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const derivedKey = await deriveKey({
21
+ * masterSecret: 'my-strong-password',
22
+ * kdfOpts: {
23
+ * strategy: KdfStrategy.recursiveSaltWrap,
24
+ * salt: 'pool-identifier',
25
+ * rounds: 10000,
26
+ * algorithm: 'SHA-256'
27
+ * }
28
+ * });
29
+ * ```
30
+ */
31
+ export async function deriveKey({
32
+ masterSecret,
33
+ kdfOpts
34
+ }: DeriveKeyParams): Promise<string> {
35
+ const lc = `[${deriveKey.name}]`;
36
+ try {
37
+ if (logalot) { console.log(`${lc} starting... (I: 268e87ec311874ee6822bf459c5a5426)`); }
38
+
39
+ const strategy = kdfOpts.strategy;
40
+
41
+ switch (strategy) {
42
+ case KdfStrategy['recursive-salt-wrap']:
43
+ return await kdf_recursiveSaltWrap({
44
+ masterSecret,
45
+ salt: kdfOpts.salt,
46
+ rounds: kdfOpts.rounds,
47
+ algorithm: kdfOpts.algorithm
48
+ });
49
+ default:
50
+ throw new Error(`Unknown KDF strategy: ${strategy}. valid values: ${KDF_STRATEGY_VALID_VALUES.join(', ')} (E: a1b2c3d4e5f6g7h8i9j0)`);
51
+ }
52
+
53
+ } catch (error) {
54
+ console.error(`${lc} ${extractErrorMsg(error)}`);
55
+ throw error;
56
+ } finally {
57
+ if (logalot) { console.log(`${lc} complete.`); }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Recursive Salt Wrap KDF Strategy
63
+ *
64
+ * Derives a key by recursively applying: Hash(salt + current + salt) for N rounds
65
+ *
66
+ * This is the strategy used by KeystoneStrategy_HashRevealV1 for deriving pool secrets.
67
+ *
68
+ * @param masterSecret - The initial secret/password to derive from
69
+ * @param salt - Salt value to wrap around the secret
70
+ * @param rounds - Number of hash iterations (key stretching)
71
+ * @param algorithm - Hash algorithm to use (default: SHA-256)
72
+ * @returns Derived key
73
+ */
74
+ export async function kdf_recursiveSaltWrap({
75
+ masterSecret,
76
+ salt,
77
+ rounds,
78
+ algorithm = HashAlgorithm.sha_256,
79
+ }: {
80
+ masterSecret: string;
81
+ salt: string;
82
+ rounds: number;
83
+ algorithm?: HashAlgorithm;
84
+ }): Promise<string> {
85
+ const lc = `[${kdf_recursiveSaltWrap.name}]`;
86
+ try {
87
+ if (logalot) { console.log(`${lc} starting... (I: 850868e50aba82ff28c77da8169e4c26)`); }
88
+
89
+ let current = masterSecret;
90
+
91
+ for (let i = 0; i < rounds; i++) {
92
+ current = await hash({
93
+ s: `${salt}${current}${salt}`,
94
+ algorithm
95
+ });
96
+ }
97
+
98
+ return current;
99
+ } catch (error) {
100
+ console.error(`${lc} ${extractErrorMsg(error)}`);
101
+ throw error;
102
+ } finally {
103
+ if (logalot) { console.log(`${lc} complete.`); }
104
+ }
105
+ }
@@ -0,0 +1,58 @@
1
+ import { HashAlgorithm } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
+ import { KdfStrategy } from './kdf-constants.mjs';
3
+
4
+ /**
5
+ * Base options for all KDF strategies
6
+ */
7
+ export interface KdfOptionsBase {
8
+ /**
9
+ * Name of the KDF strategy to use
10
+ */
11
+ strategy: KdfStrategy;
12
+ }
13
+
14
+ /**
15
+ * Options for recursive-salt-wrap KDF strategy
16
+ *
17
+ * Derives key by recursively applying: Hash(salt + current + salt) for N rounds
18
+ */
19
+ export interface KdfOptions_RecursiveSaltWrap extends KdfOptionsBase {
20
+ strategy: typeof import('./kdf-constants.mjs').KDF_STRATEGY_RECURSIVE_SALT_WRAP;
21
+
22
+ /**
23
+ * Salt value to wrap around the secret during each iteration
24
+ */
25
+ salt: string;
26
+
27
+ /**
28
+ * Number of hash iterations for key stretching
29
+ */
30
+ rounds: number;
31
+
32
+ /**
33
+ * Hash algorithm to use (default: SHA-256)
34
+ */
35
+ algorithm?: HashAlgorithm;
36
+ }
37
+
38
+ /**
39
+ * Union of all KDF option types
40
+ */
41
+ export type KdfOptions =
42
+ | KdfOptions_RecursiveSaltWrap
43
+ ;
44
+
45
+ /**
46
+ * Parameters for deriving a key using KDF
47
+ */
48
+ export interface DeriveKeyParams {
49
+ /**
50
+ * The initial secret/password to derive from
51
+ */
52
+ masterSecret: string;
53
+
54
+ /**
55
+ * KDF options specifying strategy and strategy-specific parameters
56
+ */
57
+ kdfOpts: KdfOptions;
58
+ }