@ibgib/core-gib 0.1.43 → 0.1.45

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 (85) 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 +8 -4
  24. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  25. package/dist/keystone/keystone-helpers.mjs +76 -6
  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-constants.d.mts +9 -0
  41. package/dist/sync/sync-constants.d.mts.map +1 -1
  42. package/dist/sync/sync-constants.mjs +10 -0
  43. package/dist/sync/sync-constants.mjs.map +1 -1
  44. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +49 -19
  45. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -1
  46. package/dist/sync/sync-peer/sync-peer-v1.mjs +3 -3
  47. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  48. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +0 -38
  49. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  50. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +1 -83
  51. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  52. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +24 -4
  53. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  54. package/dist/sync/sync-saga-coordinator.d.mts +36 -13
  55. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  56. package/dist/sync/sync-saga-coordinator.mjs +246 -38
  57. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  58. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +1 -7
  59. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  60. package/dist/sync/sync-types.d.mts +11 -0
  61. package/dist/sync/sync-types.d.mts.map +1 -1
  62. package/dist/sync/sync-types.mjs.map +1 -1
  63. package/package.json +1 -1
  64. package/src/keystone/README.md +4 -3
  65. package/src/keystone/docs/architecture.md +3 -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 +100 -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/sync-constants.mts +12 -0
  78. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +53 -20
  79. package/src/sync/sync-peer/sync-peer-v1.mts +3 -3
  80. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +3 -107
  81. package/src/sync/sync-saga-context/sync-saga-context-types.mts +25 -4
  82. package/src/sync/sync-saga-coordinator.mts +313 -40
  83. package/src/sync/sync-saga-message/sync-saga-message-types.mts +1 -7
  84. package/src/sync/sync-types.mts +12 -0
  85. package/tmp.md +0 -274
@@ -20,7 +20,7 @@ const logalot = GLOBAL_LOG_A_LOT || true;
20
20
 
21
21
  /**
22
22
  * Facade for managing Keystone Identities.
23
- *
23
+ *
24
24
  * Handles Genesis, Authorized Evolution (Signing), and Validation.
25
25
  */
26
26
  export class KeystoneService_V1 {
@@ -93,9 +93,9 @@ export class KeystoneService_V1 {
93
93
 
94
94
  /**
95
95
  * Signs a claim by solving challenges from a specific pool and evolving the Keystone timeline.
96
- *
96
+ *
97
97
  * Uses a hybrid selection strategy: Mandatory IDs (Alice) + Sequential (FIFO) + Random (Stochastic).
98
- *
98
+ *
99
99
  * Supports Delegation via `poolFilter` to find specific foreign pools.
100
100
  */
101
101
  async sign({
@@ -122,7 +122,7 @@ export class KeystoneService_V1 {
122
122
  */
123
123
  poolId?: string;
124
124
  /**
125
- * Optional predicate to find a pool.
125
+ * Optional predicate to find a pool.
126
126
  * Useful for finding delegates via metadata without knowing the exact ID.
127
127
  * e.g. (p) => p.metadata?.delegate === 'Bob'
128
128
  */
@@ -158,7 +158,7 @@ export class KeystoneService_V1 {
158
158
  });
159
159
 
160
160
  // 3. Pay the Cost (Solve & Replenish)
161
- // This helper handles the Strategy creation, Secret derivation, Solving,
161
+ // This helper handles the Strategy creation, Secret derivation, Solving,
162
162
  // and the calculation of the Next state for ALL pools.
163
163
  const { proof, nextPools } = await solveAndReplenish({
164
164
  targetPoolId: pool.id,
@@ -196,13 +196,13 @@ export class KeystoneService_V1 {
196
196
 
197
197
  /**
198
198
  * Validates a keystone.
199
- *
199
+ *
200
200
  * ## NOTES
201
- *
201
+ *
202
202
  * Atow (12/22/2025) this only validates the transition from Prev -> Curr.
203
- *
203
+ *
204
204
  * @returns Array of validation error strings. Empty array means Valid.
205
- *
205
+ *
206
206
  * @see {@link validateKeystoneTransition}
207
207
  */
208
208
  async validate({
@@ -220,11 +220,11 @@ export class KeystoneService_V1 {
220
220
 
221
221
  /**
222
222
  * Permanently revokes the Identity.
223
- *
223
+ *
224
224
  * Logic:
225
225
  * 1. Locates the 'revoke' pool.
226
226
  * 2. Solves required challenges to prove ownership.
227
- * 3. Wipes the pool (via 'scorched-earth' strategy in solveAndReplenish).
227
+ * 3. Wipes the pool (via the delete all strategy in solveAndReplenish).
228
228
  * 4. Sets the revocationInfo on the new frame.
229
229
  */
230
230
  async revoke({
@@ -270,8 +270,9 @@ export class KeystoneService_V1 {
270
270
  if (idsToSolve.length === 0) { throw new Error(`Revocation policy selected 0 challenges? Check config for pool ${pool.id}. Revocation requires proof. (E: 97e5a8356d241ae7b882db791cb1f825)`); }
271
271
 
272
272
  // 4. Pay the Cost & Scorched Earth
273
- // The revoke pool config should have 'replenish: scorched-earth',
274
- // causing solveAndReplenish to return an empty pool in nextPools.
273
+ // The revoke pool config should have 'replenishStrategy:
274
+ // KeystoneReplenishStrategy.deleteAll', causing solveAndReplenish
275
+ // to return an empty pool in nextPools.
275
276
  const { proof, nextPools } = await solveAndReplenish({
276
277
  targetPoolId: pool.id,
277
278
  prevPools: prevData.challengePools,
@@ -283,7 +284,7 @@ export class KeystoneService_V1 {
283
284
  // warn if nextPools contains pool.id that isn't empty (we were
284
285
  // supposed to do "scorched earth" which empties the pool)
285
286
  if (nextPools.find(p => p.id === pool.id && Object.keys(p.challenges).length > 0)) {
286
- console.warn(`${lc} revocation pool ${pool.id} is not empty after revocation. Is the revocation pool replenish strategy set to ${KeystoneReplenishStrategy.scorchedEarth}? (W: 300c28bc8b98fc3e3c0b0d988344f825)`);
287
+ console.warn(`${lc} revocation pool ${pool.id} is not empty after revocation. Is the revocation pool replenish strategy set to ${KeystoneReplenishStrategy.deleteAll}? (W: 300c28bc8b98fc3e3c0b0d988344f825)`);
287
288
  }
288
289
 
289
290
  // 5. Construct Revocation Info
@@ -316,11 +317,11 @@ export class KeystoneService_V1 {
316
317
 
317
318
  /**
318
319
  * Structural evolution: Adds new challenge pools to the keystone.
319
- *
320
- * Use Case: Adding a delegate (Server) for SSO, adding a recovery key,
320
+ *
321
+ * Use Case: Adding a delegate (Server) for SSO, adding a recovery key,
321
322
  * or rotating to a new set of pools.
322
- *
323
- * Requires the Master Secret to authorize the change via a pool containing
323
+ *
324
+ * Requires the Master Secret to authorize the change via a pool containing
324
325
  * the 'manage' verb.
325
326
  */
326
327
  async addPools({
@@ -332,14 +333,14 @@ export class KeystoneService_V1 {
332
333
  }: {
333
334
  latestKeystone: KeystoneIbGib_V1;
334
335
  /**
335
- * Alice's Master Secret.
336
+ * Alice's Master Secret.
336
337
  * Required to solve challenges from the Admin/Manage pool to authorize this change.
337
338
  */
338
339
  masterSecret: string;
339
340
  /**
340
- * The pools to add.
341
- * NOTE: These are fully constructed Pool objects.
342
- * If they are foreign (Bob's), Alice must have constructed them
341
+ * The pools to add.
342
+ * NOTE: These are fully constructed Pool objects.
343
+ * If they are foreign (Bob's), Alice must have constructed them
343
344
  * using Bob's challenges + Her config restrictions + isForeign=true.
344
345
  */
345
346
  newPools: KeystoneChallengePool[];
@@ -195,12 +195,15 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
195
195
 
196
196
  firstOfAll(sir, async () => {
197
197
  // Use our standard builder to get a valid config object
198
- config = createStandardPoolConfig(salt) as KeystonePoolConfig_HashV1;
198
+ config = createStandardPoolConfig({
199
+ id: salt,
200
+ salt,
201
+ }) as KeystonePoolConfig_HashV1;
199
202
  });
200
203
 
201
204
  await respecfully(sir, 'Derivation Logic', async () => {
202
205
 
203
- await ifWe(sir, 'derivePoolSecret with same inputs returns same output', async () => {
206
+ await ifWeMight(sir, 'derivePoolSecret with same inputs returns same output', async () => {
204
207
  const strategy = KeystoneStrategyFactory.create({ config });
205
208
 
206
209
  const secretA = await strategy.derivePoolSecret({ masterSecret });
@@ -210,7 +213,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
210
213
  iReckon(sir, secretA).asTo('secret length').isGonnaBeTruthy();
211
214
  });
212
215
 
213
- await ifWe(sir, 'derivePoolSecret with different master secret returns different output', async () => {
216
+ await ifWeMight(sir, 'derivePoolSecret with different master secret returns different output', async () => {
214
217
  const strategy = KeystoneStrategyFactory.create({ config });
215
218
 
216
219
  const secretA = await strategy.derivePoolSecret({ masterSecret });
@@ -219,7 +222,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
219
222
  iReckon(sir, secretA).asTo('secrets differ').not.willEqual(secretB);
220
223
  });
221
224
 
222
- await ifWe(sir, 'derivePoolSecret with different salt returns different output', async () => {
225
+ await ifWeMight(sir, 'derivePoolSecret with different salt returns different output', async () => {
223
226
  // Modify salt in a copy of config
224
227
  const configB = { ...config, salt: "OtherPool" };
225
228
  const strategyA = KeystoneStrategyFactory.create({ config });
@@ -234,7 +237,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
234
237
 
235
238
  await respecfully(sir, 'Challenge/Solution Logic', async () => {
236
239
 
237
- await ifWe(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
240
+ await ifWeMight(sir, 'generateSolution -> generateChallenge -> validateSolution loop works', async () => {
238
241
  const strategy = KeystoneStrategyFactory.create({ config });
239
242
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
240
243
  const challengeId = "a3ff7843552870fc28bef2b"; // arbitrary random challengeId
@@ -253,7 +256,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
253
256
  iReckon(sir, isValid).asTo('valid pair should pass').isGonnaBeTrue();
254
257
  });
255
258
 
256
- await ifWe(sir, 'validateSolution fails for mismatched values', async () => {
259
+ await ifWeMight(sir, 'validateSolution fails for mismatched values', async () => {
257
260
  const strategy = KeystoneStrategyFactory.create({ config });
258
261
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
259
262
  const challengeId = "8c994f3ed598f150e25513"; // arbitrary random challengeId
@@ -269,7 +272,7 @@ await respecfully(sir, 'Suite A: Strategy Vectors (HashRevealV1)', async () => {
269
272
  iReckon(sir, isValid).asTo('tampered solution should fail').isGonnaBeFalse();
270
273
  });
271
274
 
272
- await ifWe(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
275
+ await ifWeMight(sir, 'validateSolution fails for mismatched challenge hashes', async () => {
273
276
  const strategy = KeystoneStrategyFactory.create({ config });
274
277
  const poolSecret = await strategy.derivePoolSecret({ masterSecret });
275
278
 
@@ -310,8 +313,11 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
310
313
  });
311
314
 
312
315
  await respecfully(sir, 'Genesis', async () => {
313
- await ifWe(sir, 'creates a valid genesis frame and persists it', async () => {
314
- const config = createStandardPoolConfig(POOL_ID_DEFAULT);
316
+ await ifWeMight(sir, 'creates a valid genesis frame and persists it', async () => {
317
+ const config = createStandardPoolConfig({
318
+ id: POOL_ID_DEFAULT,
319
+ salt: POOL_ID_DEFAULT,
320
+ });
315
321
 
316
322
  genesisKeystone = await service.genesis({
317
323
  masterSecret,
@@ -338,7 +344,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
338
344
  });
339
345
 
340
346
  await respecfully(sir, 'Signing (Evolution)', async () => {
341
- await ifWe(sir, 'evolves the keystone with a valid proof', async () => {
347
+ await ifWeMight(sir, 'evolves the keystone with a valid proof', async () => {
342
348
  const claim: Partial<KeystoneClaim> = {
343
349
  target: "comment 123^gib",
344
350
  verb: "post"
@@ -368,7 +374,7 @@ await respecfully(sir, 'Suite B: Service Lifecycle', async () => {
368
374
  });
369
375
 
370
376
  await respecfully(sir, 'Validation', async () => {
371
- await ifWe(sir, 'validates the genesis->signed transition', async () => {
377
+ await ifWeMight(sir, 'validates the genesis->signed transition', async () => {
372
378
  const errors = await service.validate({
373
379
  prevIbGib: genesisKeystone,
374
380
  currentIbGib: signedKeystone,
@@ -400,8 +406,13 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
400
406
  mockMetaspace = new MockMetaspaceService(mockSpace);
401
407
 
402
408
  // Setup Alice's Identity
403
- const config = createStandardPoolConfig(POOL_ID_DEFAULT);
404
- config.behavior.size = 10;
409
+ const config = createStandardPoolConfig({
410
+ id: POOL_ID_DEFAULT,
411
+ salt: POOL_ID_DEFAULT,
412
+ targetBinding: 0,
413
+ size: 10,
414
+ });
415
+ // config.behavior.size = 10;
405
416
  genesisKeystone = await service.genesis({
406
417
  masterSecret: aliceSecret,
407
418
  configs: [config],
@@ -411,7 +422,7 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
411
422
  });
412
423
 
413
424
  await respecfully(sir, 'Wrong Secret (Forgery)', async () => {
414
- await ifWe(sir, 'prevents creation of forged frames', async () => {
425
+ await ifWeMight(sir, 'prevents creation of forged frames', async () => {
415
426
  const claim: Partial<KeystoneClaim> = { target: "comment 123^gib", verb: "post" };
416
427
 
417
428
  let errorCaught = false;
@@ -440,10 +451,13 @@ await respecfully(sir, 'Suite C: Security Vectors', async () => {
440
451
  });
441
452
 
442
453
  await respecfully(sir, 'Policy Violation (Restricted Verbs)', async () => {
443
- await ifWe(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
454
+ await ifWeMight(sir, 'throws error if signing forbidden verb with restricted pool', async () => {
444
455
  // Create a specific restricted pool config manually
445
456
  const restrictedPoolId = "read_only_pool";
446
- const restrictedConfig = createStandardPoolConfig(restrictedPoolId);
457
+ const restrictedConfig = createStandardPoolConfig({
458
+ id: restrictedPoolId,
459
+ salt: restrictedPoolId,
460
+ });
447
461
  // Manually restrict it (since Builder defaults to undefined/allow-all)
448
462
  restrictedConfig.allowedVerbs = ['read'];
449
463
 
@@ -495,8 +509,14 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
495
509
  mockMetaspace = new MockMetaspaceService(mockSpace);
496
510
 
497
511
  // Setup Identity WITH a Revocation Pool
498
- const stdConfig = createStandardPoolConfig(POOL_ID_DEFAULT);
499
- const revokeConfig = createRevocationPoolConfig(POOL_ID_REVOKE); // Special Config
512
+ const stdConfig = createStandardPoolConfig({
513
+ id: POOL_ID_DEFAULT,
514
+ salt: POOL_ID_DEFAULT,
515
+ });
516
+ const revokeConfig = createRevocationPoolConfig({
517
+ id: POOL_ID_REVOKE,
518
+ salt: POOL_ID_REVOKE,
519
+ }); // Special Config
500
520
 
501
521
  genesisKeystone = await service.genesis({
502
522
  masterSecret,
@@ -509,7 +529,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
509
529
  await respecfully(sir, 'Revoke Lifecycle', async () => {
510
530
  let revokedKeystone: KeystoneIbGib_V1;
511
531
 
512
- await ifWe(sir, 'successfully creates a revocation frame', async () => {
532
+ await ifWeMight(sir, 'successfully creates a revocation frame', async () => {
513
533
  revokedKeystone = await service.revoke({
514
534
  latestKeystone: genesisKeystone,
515
535
  masterSecret,
@@ -527,7 +547,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
527
547
  iReckon(sir, data.revocationInfo!.proof.claim.verb).willEqual(KEYSTONE_VERB_REVOKE);
528
548
  });
529
549
 
530
- await ifWe(sir, 'validates the revocation frame', async () => {
550
+ await ifWeMight(sir, 'validates the revocation frame', async () => {
531
551
  const errors = await service.validate({
532
552
  prevIbGib: genesisKeystone,
533
553
  currentIbGib: revokedKeystone!,
@@ -538,7 +558,7 @@ await respecfully(sir, 'Suite D: Revocation', async () => {
538
558
  iReckon(sir, errors.length).asTo('no validation errors').willEqual(0);
539
559
  });
540
560
 
541
- await ifWe(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
561
+ await ifWeMight(sir, 'consumed the revocation pool (Scorched Earth)', async () => {
542
562
  const data = revokedKeystone!.data!;
543
563
  const revokePool = data.challengePools.find(p => p.id === POOL_ID_REVOKE);
544
564
 
@@ -568,7 +588,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
568
588
 
569
589
  // Helper to generate a "Foreign" pool (e.g. from Bob)
570
590
  const createForeignPool = async (id: string, verbs: string[] = []): Promise<KeystoneChallengePool> => {
571
- const config = createStandardPoolConfig(id);
591
+ const config = createStandardPoolConfig({ id, salt: id });
572
592
  config.allowedVerbs = verbs;
573
593
 
574
594
  // We use the factory manually here to simulate Bob doing this offline
@@ -605,7 +625,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
605
625
  mockMetaspace = new MockMetaspaceService(mockSpace);
606
626
 
607
627
  // Alice Genesis: Standard pool (allows all verbs, including 'manage')
608
- const config = createStandardPoolConfig(POOL_ID_DEFAULT);
628
+ const config = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: POOL_ID_DEFAULT });
609
629
  aliceKeystone = await service.genesis({
610
630
  masterSecret: aliceSecret,
611
631
  configs: [config],
@@ -615,7 +635,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
615
635
  });
616
636
 
617
637
  await respecfully(sir, 'Happy Path', async () => {
618
- await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
638
+ await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
619
639
  const bobPool = await createForeignPool("pool_bob", ["post"]);
620
640
 
621
641
  const updatedKeystone = await service.addPools({
@@ -654,9 +674,10 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
654
674
  });
655
675
 
656
676
  await respecfully(sir, 'Permissions & Logic', async () => {
657
- await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
677
+ await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
658
678
  // 1. Create a restricted keystone
659
- const restrictedConfig = createStandardPoolConfig("read_only");
679
+ let id = "read_only";
680
+ const restrictedConfig = createStandardPoolConfig({ id, salt: id });
660
681
  restrictedConfig.allowedVerbs = ['read']; // No 'manage'
661
682
 
662
683
  const restrictedKeystone = await service.genesis({
@@ -686,7 +707,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
686
707
  iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
687
708
  });
688
709
 
689
- await ifWe(sir, 'fails on ID collision', async () => {
710
+ await ifWeMight(sir, 'fails on ID collision', async () => {
690
711
  // Try to add "pool_bob" again (it was added in Happy Path)
691
712
  const duplicatePool = await createForeignPool("pool_bob");
692
713
 
@@ -725,7 +746,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
725
746
 
726
747
  // Helper to simulate Bob creating a pool "offline" to give to Alice
727
748
  const createForeignPool = async (id: string, verbs: string[] = []): Promise<KeystoneChallengePool> => {
728
- const config = createStandardPoolConfig(id);
749
+ const config = createStandardPoolConfig({ id, salt: id });
729
750
  config.allowedVerbs = verbs;
730
751
 
731
752
  // We use the factory manually here to simulate Bob doing this on his own machine
@@ -762,7 +783,10 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
762
783
  mockMetaspace = new MockMetaspaceService(mockSpace);
763
784
 
764
785
  // Alice Genesis: Standard pool (allows all verbs, including 'manage')
765
- const config = createStandardPoolConfig(POOL_ID_DEFAULT);
786
+ const config = createStandardPoolConfig({
787
+ id: POOL_ID_DEFAULT,
788
+ salt: POOL_ID_DEFAULT,
789
+ });
766
790
  aliceKeystone = await service.genesis({
767
791
  masterSecret: aliceSecret,
768
792
  configs: [config],
@@ -772,7 +796,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
772
796
  });
773
797
 
774
798
  await respecfully(sir, 'Happy Path', async () => {
775
- await ifWe(sir, 'authorizes and adds a foreign pool', async () => {
799
+ await ifWeMight(sir, 'authorizes and adds a foreign pool', async () => {
776
800
  const bobPool = await createForeignPool("pool_bob", ["post"]);
777
801
 
778
802
  const updatedKeystone = await service.addPools({
@@ -811,9 +835,10 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
811
835
  });
812
836
 
813
837
  await respecfully(sir, 'Permissions & Logic', async () => {
814
- await ifWe(sir, 'fails if no pool allows "manage" verb', async () => {
838
+ await ifWeMight(sir, 'fails if no pool allows "manage" verb', async () => {
815
839
  // 1. Create a restricted keystone (read-only)
816
- const restrictedConfig = createStandardPoolConfig("read_only");
840
+ let id = "read_only";
841
+ const restrictedConfig = createStandardPoolConfig({ id, salt: id });
817
842
  restrictedConfig.allowedVerbs = ['read']; // No 'manage'
818
843
 
819
844
  const restrictedKeystone = await service.genesis({
@@ -843,7 +868,7 @@ await respecfully(sir, 'Suite E: Structural Evolution (addPools)', async () => {
843
868
  iReckon(sir, errorCaught).asTo('permission denied').isGonnaBeTrue();
844
869
  });
845
870
 
846
- await ifWe(sir, 'fails on ID collision', async () => {
871
+ await ifWeMight(sir, 'fails on ID collision', async () => {
847
872
  // Try to add "pool_bob" again (it was added in Happy Path)
848
873
  const duplicatePool = await createForeignPool("pool_bob");
849
874
 
@@ -883,11 +908,13 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
883
908
  let signedKeystone: KeystoneIbGib_V1;
884
909
 
885
910
  // We use a specific hybrid config to test exact selection logic
886
- const hybridConfig = createStandardPoolConfig(salt) as KeystonePoolConfig_HashV1;
887
- // 2 FIFO + 2 Random = 4 Total per sign
888
- hybridConfig.behavior.selectSequentially = 2;
889
- hybridConfig.behavior.selectRandomly = 2;
890
- hybridConfig.behavior.size = 20; // Small enough to track, large enough to be random
911
+ const hybridConfig = createStandardPoolConfig({
912
+ id: salt,
913
+ salt,
914
+ // 2 FIFO + 2 Random = 4 Total per sign
915
+ sequential: 2, random: 2, targetBinding: 0,
916
+ size: 20, // Small enough to track, large enough to be random
917
+ }) as KeystonePoolConfig_HashV1;
891
918
 
892
919
  firstOfAll(sir, async () => {
893
920
  mockSpace = new MockIbGibSpace();
@@ -903,7 +930,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
903
930
 
904
931
  await respecfully(sir, 'Proof Granularity & Math', async () => {
905
932
 
906
- await ifWe(sir, 'generates exactly the expected number of solutions', async () => {
933
+ await ifWeMight(sir, 'generates exactly the expected number of solutions', async () => {
907
934
  signedKeystone = await service.sign({
908
935
  latestKeystone: genesisKeystone,
909
936
  masterSecret: aliceSecret,
@@ -920,7 +947,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
920
947
  iReckon(sir, solutions.length).asTo('solution count').willEqual(4);
921
948
  });
922
949
 
923
- await ifWe(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
950
+ await ifWeMight(sir, 'verifies the math manually (White-box Crypto Check)', async () => {
924
951
  const proof = signedKeystone.data!.proofs[0];
925
952
  const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === salt)!;
926
953
 
@@ -949,7 +976,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
949
976
  }
950
977
  });
951
978
 
952
- await ifWe(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
979
+ await ifWeMight(sir, 'verifies FIFO logic (Deterministic Selection)', async () => {
953
980
  const proof = signedKeystone.data!.proofs[0];
954
981
  const poolSnapshot = genesisKeystone.data!.challengePools.find(p => p.id === salt)!;
955
982
 
@@ -971,7 +998,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
971
998
 
972
999
  await respecfully(sir, 'DTO & Serialization', async () => {
973
1000
 
974
- await ifWe(sir, 'survives a clone/JSON-cycle without corruption', async () => {
1001
+ await ifWeMight(sir, 'survives a clone/JSON-cycle without corruption', async () => {
975
1002
  // 1. Create a DTO (simulate network transmission/storage)
976
1003
  // 'clone' does a JSON stringify/parse under the hood (usually) or structured clone.
977
1004
  const dto = clone(signedKeystone);
@@ -991,7 +1018,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
991
1018
  iReckon(sir, errors.length).asTo('DTO validation errors').willEqual(0);
992
1019
  });
993
1020
 
994
- await ifWe(sir, 'ensures data contains no functions or circular refs', async () => {
1021
+ await ifWeMight(sir, 'ensures data contains no functions or circular refs', async () => {
995
1022
  // A crude but effective test: ensure JSON.stringify doesn't throw
996
1023
  // and the result is equal to the object (if we parsed it back).
997
1024
 
@@ -1005,7 +1032,7 @@ await respecfully(sir, 'Suite F: Deep Inspection', async () => {
1005
1032
  iReckon(sir, parsedSolution).asTo('deep property survives stringify').willEqual(originalSolution);
1006
1033
 
1007
1034
  // Ensure no extra properties were lost
1008
- // FIX: JSON.stringify removes keys with 'undefined' values.
1035
+ // FIX: JSON.stringify removes keys with 'undefined' values.
1009
1036
  // We must filter the original keys to match this behavior for a fair comparison.
1010
1037
  const origKeys = Object.keys(signedKeystone.data!)
1011
1038
  .filter(k => (signedKeystone.data as any)[k] !== undefined);
@@ -2,15 +2,25 @@ import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/ty
2
2
 
3
3
  import { KEYSTONE_ATOM } from "./keystone-constants.mjs";
4
4
 
5
+ // #region KeystoneChallengeType
6
+ export const KEYSTONE_CHALLENGE_TYPE_HASH_REVEAL_V1 = 'hash-reveal-v1';
5
7
  /**
6
8
  * The discriminator for the mechanism.
7
9
  * 'hash-reveal-v1': Standard Hash chain (Sigma-like).
8
10
  */
9
11
  export type KeystoneChallengeType =
10
- | 'hash-reveal-v1'
12
+ | typeof KEYSTONE_CHALLENGE_TYPE_HASH_REVEAL_V1
11
13
  // | 'decrypt-v1' // Future
12
14
  // | 'pow-v1'; // Future
13
15
  ;
16
+ export const KeystoneChallengeType = {
17
+ hash_reveal_v1: KEYSTONE_CHALLENGE_TYPE_HASH_REVEAL_V1,
18
+ } satisfies { [key: string]: KeystoneChallengeType };
19
+ export const KEYSTONE_CHALLENGE_TYPE_VALID_VALUES = Object.values(KeystoneChallengeType);
20
+ export function isValidKeystoneChallengeType(x: any): x is KeystoneChallengeType {
21
+ return typeof x === 'string' && KEYSTONE_CHALLENGE_TYPE_VALID_VALUES.includes(x as any);
22
+ }
23
+ // #endregion KeystoneChallengeType
14
24
 
15
25
  // ===========================================================================
16
26
  // CONFIGURATION
@@ -18,55 +28,56 @@ export type KeystoneChallengeType =
18
28
 
19
29
  // #region KeystoneReplenishStrategy
20
30
  /**
21
- * replaces each used challenge, "topping up" the pool to the pool's size
31
+ * @see {@link KeystoneReplenishStrategy.topUp}
22
32
  */
23
33
  export const KEYSTONE_REPLENISH_STRATEGY_TOP_UP = 'top-up';
24
34
  /**
25
- * replaces the entire pool with the new challenges
35
+ * @see {@link KeystoneReplenishStrategy.replaceAll}
26
36
  */
27
37
  export const KEYSTONE_REPLENISH_STRATEGY_REPLACE_ALL = 'replace-all';
28
38
  /**
29
- * do not replenish, only consume
30
- *
31
- * ## intent
32
- * adding this for revocation
39
+ * @see {@link KeystoneReplenishStrategy.consume}
33
40
  */
34
41
  export const KEYSTONE_REPLENISH_STRATEGY_CONSUME = 'consume';
35
42
  /**
36
- * Deletes ALL challenges in the pool, regardless of how many were used.
37
- * The "Nuclear Option" for revocation.
43
+ * @see {@link KeystoneReplenishStrategy.deleteAll}
38
44
  */
39
- export const KEYSTONE_REPLENISH_STRATEGY_SCORCHED_EARTH = 'scorched-earth';
45
+ export const KEYSTONE_REPLENISH_STRATEGY_DELETE_ALL = 'delete-all';
40
46
  export type KeystoneReplenishStrategy =
41
47
  | typeof KEYSTONE_REPLENISH_STRATEGY_TOP_UP
42
48
  | typeof KEYSTONE_REPLENISH_STRATEGY_REPLACE_ALL
43
49
  | typeof KEYSTONE_REPLENISH_STRATEGY_CONSUME
44
- | typeof KEYSTONE_REPLENISH_STRATEGY_SCORCHED_EARTH
50
+ | typeof KEYSTONE_REPLENISH_STRATEGY_DELETE_ALL
45
51
  ;
46
52
  /**
47
53
  * @see {@link KeystonePoolBehavior.replenish}
48
54
  */
49
55
  export const KeystoneReplenishStrategy = {
50
56
  /**
51
- * @see {@link KEYSTONE_REPLENISH_STRATEGY_TOP_UP}
57
+ * replaces each used challenge, "topping up" the pool to the pool's size
52
58
  */
53
59
  topUp: KEYSTONE_REPLENISH_STRATEGY_TOP_UP,
54
60
  /**
55
- * @see {@link KEYSTONE_REPLENISH_STRATEGY_REPLACE_ALL}
61
+ * replaces the entire pool with the new challenges
56
62
  */
57
63
  replaceAll: KEYSTONE_REPLENISH_STRATEGY_REPLACE_ALL,
58
64
  /**
59
- * @see {@link KEYSTONE_REPLENISH_STRATEGY_CONSUME}
65
+ * do not replenish, only consume
66
+ *
67
+ * ## intent
68
+ * adding this for revocation, though we have added deleteAll for this now.
69
+ * Leaving it in.
60
70
  */
61
71
  consume: KEYSTONE_REPLENISH_STRATEGY_CONSUME,
62
72
  /**
63
- * @see {@link KEYSTONE_REPLENISH_STRATEGY_SCORCHED_EARTH}
73
+ * Deletes ALL challenges in the pool, regardless of how many were used.
74
+ * The "Nuclear Option" for revocation.
64
75
  */
65
- scorchedEarth: KEYSTONE_REPLENISH_STRATEGY_SCORCHED_EARTH,
76
+ deleteAll: KEYSTONE_REPLENISH_STRATEGY_DELETE_ALL,
66
77
  } satisfies { [key: string]: KeystoneReplenishStrategy };
67
78
  export const KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES = Object.values(KeystoneReplenishStrategy);
68
79
  export function isKeystoneReplenishStrategy(x: any): x is KeystoneReplenishStrategy {
69
- return KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES.includes(x);
80
+ return typeof x === 'string' && KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES.includes(x as any);
70
81
  }
71
82
  // #endregion KeystoneReplenishStrategy
72
83
 
@@ -78,6 +89,9 @@ export interface KeystonePoolBehavior {
78
89
 
79
90
  /**
80
91
  * How do we fill the void left by consumed challenges?
92
+ *
93
+ * @see {@link KeystoneReplenishStrategy} individual members for information
94
+ * on each one.
81
95
  */
82
96
  replenish: KeystoneReplenishStrategy;
83
97
 
@@ -219,11 +233,11 @@ export interface KeystoneChallengePool {
219
233
  bindingMap: { [hexChar: string]: string[] };
220
234
 
221
235
  /**
222
- * If true, this pool's secrets are NOT derived from the Keystone's
236
+ * If true, this pool's secrets are NOT derived from the Keystone's
223
237
  * primary Master Secret. They are held by an external entity.
224
- *
238
+ *
225
239
  * ## intent
226
- *
240
+ *
227
241
  * The driving use case for this is signing in with a server "super node"
228
242
  * and giving that node the ability to sign on behalf of the user. This is a
229
243
  * common pattern in SSO-type workflows.
@@ -233,9 +247,9 @@ export interface KeystoneChallengePool {
233
247
  /**
234
248
  * Arbitrary metadata for the wallet/user to identify the pool.
235
249
  * e.g. { delegate: "PrimaryServer", purpose: "SSO" }
236
- *
250
+ *
237
251
  * ## intent
238
- *
252
+ *
239
253
  * The driving use case for this is signing in with a server "super node"
240
254
  * and giving that node the ability to sign on behalf of the user. This is a
241
255
  * common pattern in SSO-type workflows.
@@ -288,7 +302,7 @@ export interface KeystoneRevocationInfo {
288
302
  // TOP LEVEL IBGIB DATA
289
303
  // ===========================================================================
290
304
 
291
- export interface KeystoneIbInfo_V1 {
305
+ export interface KeystoneIb_V1 {
292
306
  atom: typeof KEYSTONE_ATOM;
293
307
  }
294
308
 
@@ -1,10 +1,10 @@
1
1
  import { hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
+
2
3
  import { KeystoneStrategy } from '../keystone-strategy.mjs';
3
4
  import {
4
- KeystonePoolConfig_HashV1,
5
- KeystoneChallenge_HashV1,
6
- KeystoneSolution_HashV1
5
+ KeystonePoolConfig_HashV1, KeystoneChallenge_HashV1, KeystoneSolution_HashV1
7
6
  } from '../../keystone-types.mjs';
7
+ import { kdf_recursiveSaltWrap } from '../../kdf/kdf-helpers.mjs';
8
8
 
9
9
  /**
10
10
  * The concrete implementation of the "Salted Wrap" Hash Reveal strategy.
@@ -26,17 +26,13 @@ export class KeystoneStrategy_HashRevealV1 extends KeystoneStrategy<
26
26
  const lc = `[${KeystoneStrategy_HashRevealV1.name}.${this.derivePoolSecret.name}]`;
27
27
  try {
28
28
  const { salt, rounds, algo } = this.config;
29
- // Map algo string to HashAlgorithm type if needed,
30
- // assuming config.algo matches the helper's expected inputs.
31
29
 
32
- let current = masterSecret;
33
- for (let i = 0; i < rounds; i++) {
34
- current = await hash({
35
- s: `${salt}${current}${salt}`,
36
- algorithm: algo
37
- });
38
- }
39
- return current;
30
+ return await kdf_recursiveSaltWrap({
31
+ masterSecret,
32
+ salt,
33
+ rounds,
34
+ algorithm: algo
35
+ });
40
36
  } catch (error) {
41
37
  console.error(`${lc} Error deriving pool secret: ${error.message}`);
42
38
  throw error;