@ibgib/core-gib 0.1.47 → 0.1.48

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 (98) hide show
  1. package/dist/common/other/ibgib-helper.d.mts +12 -0
  2. package/dist/common/other/ibgib-helper.d.mts.map +1 -1
  3. package/dist/common/other/ibgib-helper.mjs +39 -0
  4. package/dist/common/other/ibgib-helper.mjs.map +1 -1
  5. package/dist/keystone/kdf/kdf-helpers.mjs +2 -2
  6. package/dist/keystone/kdf/kdf-helpers.mjs.map +1 -1
  7. package/dist/keystone/keystone-config-builder.d.mts +2 -1
  8. package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
  9. package/dist/keystone/keystone-config-builder.mjs +8 -2
  10. package/dist/keystone/keystone-config-builder.mjs.map +1 -1
  11. package/dist/keystone/keystone-constants.d.mts +24 -3
  12. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  13. package/dist/keystone/keystone-constants.mjs +22 -1
  14. package/dist/keystone/keystone-constants.mjs.map +1 -1
  15. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  16. package/dist/keystone/keystone-helpers.mjs +7 -9
  17. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  18. package/dist/keystone/keystone-service-v1.d.mts +4 -1
  19. package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
  20. package/dist/keystone/keystone-service-v1.mjs +6 -1
  21. package/dist/keystone/keystone-service-v1.mjs.map +1 -1
  22. package/dist/keystone/keystone-service-v1.respec.mjs +26 -26
  23. package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
  24. package/dist/keystone/keystone-types.d.mts +24 -5
  25. package/dist/keystone/keystone-types.d.mts.map +1 -1
  26. package/dist/keystone/keystone-types.mjs.map +1 -1
  27. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +1 -1
  28. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
  29. package/dist/sync/sync-conflict-basic-divergence.respec.mjs +1 -1
  30. package/dist/sync/sync-conflict-basic-divergence.respec.mjs.map +1 -1
  31. package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +1 -1
  32. package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
  33. package/dist/sync/sync-conflict-text-merge.respec.mjs +1 -1
  34. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  35. package/dist/sync/sync-constants.d.mts +47 -1
  36. package/dist/sync/sync-constants.d.mts.map +1 -1
  37. package/dist/sync/sync-constants.mjs +49 -1
  38. package/dist/sync/sync-constants.mjs.map +1 -1
  39. package/dist/sync/sync-innerspace-constants.respec.mjs +1 -1
  40. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  41. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +1 -1
  42. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  43. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +33 -19
  44. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -1
  45. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +1 -1
  46. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  47. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +1 -1
  48. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  49. package/dist/sync/sync-innerspace-partial-update.respec.mjs +1 -1
  50. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  51. package/dist/sync/sync-innerspace.respec.mjs +1 -1
  52. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  53. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  54. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +5 -0
  55. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  56. package/dist/sync/sync-peer/sync-peer-v1.d.mts +6 -1
  57. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  58. package/dist/sync/sync-peer/sync-peer-v1.mjs +56 -23
  59. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  60. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +7 -3
  61. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  62. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +32 -3
  63. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  64. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +16 -0
  65. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  66. package/dist/sync/sync-saga-coordinator.d.mts +18 -3
  67. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  68. package/dist/sync/sync-saga-coordinator.mjs +240 -55
  69. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  70. package/dist/sync/sync-types.d.mts +1 -1
  71. package/dist/sync/sync-types.d.mts.map +1 -1
  72. package/package.json +1 -1
  73. package/src/common/other/ibgib-helper.mts +39 -0
  74. package/src/keystone/kdf/kdf-helpers.mts +2 -2
  75. package/src/keystone/keystone-config-builder.mts +13 -2
  76. package/src/keystone/keystone-constants.mts +24 -2
  77. package/src/keystone/keystone-helpers.mts +5 -10
  78. package/src/keystone/keystone-service-v1.mts +5 -0
  79. package/src/keystone/keystone-service-v1.respec.mts +25 -25
  80. package/src/keystone/keystone-types.mts +27 -7
  81. package/src/sync/sync-conflict-adv-multitimelines.respec.mts +1 -1
  82. package/src/sync/sync-conflict-basic-divergence.respec.mts +1 -1
  83. package/src/sync/sync-conflict-basic-multitimelines.respec.mts +1 -1
  84. package/src/sync/sync-conflict-text-merge.respec.mts +1 -1
  85. package/src/sync/sync-constants.mts +51 -1
  86. package/src/sync/sync-innerspace-constants.respec.mts +1 -1
  87. package/src/sync/sync-innerspace-deep-updates.respec.mts +1 -1
  88. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +36 -19
  89. package/src/sync/sync-innerspace-dest-ahead.respec.mts +1 -1
  90. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
  91. package/src/sync/sync-innerspace-partial-update.respec.mts +1 -1
  92. package/src/sync/sync-innerspace.respec.mts +1 -1
  93. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +5 -0
  94. package/src/sync/sync-peer/sync-peer-v1.mts +63 -25
  95. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +52 -4
  96. package/src/sync/sync-saga-context/sync-saga-context-types.mts +17 -0
  97. package/src/sync/sync-saga-coordinator.mts +295 -62
  98. package/src/sync/sync-types.mts +1 -1
@@ -7,6 +7,7 @@ import {
7
7
  clone,
8
8
  unique,
9
9
  delay,
10
+ hash,
10
11
  } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
11
12
  import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
12
13
  import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
@@ -16,7 +17,7 @@ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
16
17
  import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
17
18
  import { IbGibSpaceAny } from "../witness/space/space-base-v1.mjs";
18
19
  import { putInSpace, getLatestAddrs, getFromSpace, registerNewIbGib } from "../witness/space/space-helper.mjs";
19
- import { KeystoneIbGib_V1, KeystonePoolConfig_HashV1 } from "../keystone/keystone-types.mjs";
20
+ import { KeystoneChallengePool, KeystoneChallengeType, KeystoneIbGib_V1, KeystonePoolConfig_HashV1, KeystoneReplenishStrategy } from "../keystone/keystone-types.mjs";
20
21
  import { KeystoneService_V1 } from "../keystone/keystone-service-v1.mjs";
21
22
  import { deriveKey } from "../keystone/kdf/kdf-helpers.mjs";
22
23
  import { KdfStrategy } from "../keystone/kdf/kdf-constants.mjs";
@@ -25,7 +26,26 @@ import {
25
26
  SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN,
26
27
  SyncConflictStrategy,
27
28
  SYNC_CONFLICT_STRATEGY_VALID_VALUES,
28
- DEFAULT_SESSION_IDENTITY_INITIAL_DELEGATE_SECRET,
29
+ SESSION_IDENTITY_KEYSTONE_SECRET_TRANSITIONPOOL,
30
+ SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
31
+ SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
32
+ SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
33
+ SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
34
+ SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
35
+ SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
36
+ SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE,
37
+ SESSION_IDENTITY_KEYSTONE_TRANSITION_POOL_ID,
38
+ SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE_TRANSITIONPOOL,
39
+ SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY_TRANSITIONPOOL,
40
+ SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM_TRANSITIONPOOL,
41
+ SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL_TRANSITIONPOOL,
42
+ SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING_TRANSITIONPOOL,
43
+ SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO_TRANSITIONPOOL,
44
+ SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS_TRANSITIONPOOL,
45
+ SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_TRANSITIONPOOL,
46
+ SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_DELEGATE,
47
+ SESSION_IDENTITY_KEYSTONE_DELEGATE_POOL_ID,
48
+ SESSION_IDENTITY_KEYSTONE_PRIMARY_POOL_ID,
29
49
  } from "./sync-constants.mjs";
30
50
  import {
31
51
  appendToTimeline, createTimeline, getHistory, getHistoryAddrs, Rel8nInfo, Rel8nRemovalInfo
@@ -63,9 +83,11 @@ import { graftTimelines, } from "./graft-info/graft-info-helpers.mjs";
63
83
  import { GRAFT_INFO_REL8N_NAME } from "./graft-info/graft-info-constants.mjs";
64
84
  import { GraftInfoIbGib_V1 } from "./graft-info/graft-info-types.mjs";
65
85
  import { validateIbGibIntrinsically } from "@ibgib/ts-gib/dist/V1/validate-helper.mjs";
66
- import { KEYSTONE_VERB_MANAGE } from "../keystone/keystone-constants.mjs";
67
- import { validateKeystoneGraph } from "../keystone/keystone-helpers.mjs";
86
+ import { KEYSTONE_VERB_MANAGE, KEYSTONE_VERB_SIGN } from "../keystone/keystone-constants.mjs";
87
+ import { addToBindingMap, generateOpaqueChallengeId, validateGenesisKeystone, validateKeystoneGraph } from "../keystone/keystone-helpers.mjs";
68
88
  import { SYNC_SAGA_CONTEXT_ATOM } from "./sync-saga-context/sync-saga-context-constants.mjs";
89
+ import { createStandardPoolConfig } from "../keystone/keystone-config-builder.mjs";
90
+ import { KeystoneStrategyFactory } from "../keystone/strategy/keystone-strategy-factory.mjs";
69
91
 
70
92
 
71
93
  const logalot = GLOBAL_LOG_A_LOT;
@@ -214,7 +236,18 @@ export class SyncSagaCoordinator {
214
236
  // creates the initial session identity (keystone). the flow
215
237
  // (i think) will go: evolve saga frame, then sign keystone,
216
238
  // then create/send context.
217
- sessionIdentity = await this.getSessionIdentity({ sagaId, identitySecret, metaspace, localSpace });
239
+ const resCreateSessionIdentity = await this.createSessionIdentity({
240
+ sagaId,
241
+ primaryIdentity: identity,
242
+ nonSessionSecret: identitySecret,
243
+ metaspace,
244
+ localSpace
245
+ });
246
+ sessionIdentity = resCreateSessionIdentity.sessionIdentity;
247
+ if (identity) {
248
+ if (!resCreateSessionIdentity.newPrimaryIdentity) { throw new Error(`(UNEXPECTED) identity truthy but resCreateSessionIdentity.newPrimaryIdentity falsy? (E: 4f82e88a3cc5bd7e58a40f8d77bda826)`); }
249
+ identity = resCreateSessionIdentity.newPrimaryIdentity;
250
+ }
218
251
  }
219
252
 
220
253
  // if (logalot) { console.log(`${lc} sessionIdentity: ${sessionIdentity ? pretty(sessionIdentity) : 'undefined'} (I: abc01872800b3a66b819a05898bba826)`); }
@@ -350,20 +383,31 @@ export class SyncSagaCoordinator {
350
383
  }
351
384
  }
352
385
 
353
- private async getSessionSecret({
386
+ /**
387
+ * helper that KDFs the given identitySecret, using {@link sagaId} to do so.
388
+ *
389
+ * @returns deterministically derived session secret
390
+ */
391
+ private async deriveSessionSecret({
354
392
  sagaId,
355
- identitySecret,
393
+ nonSessionSecret,
356
394
  }: {
357
395
  sagaId: string,
358
- identitySecret: string,
396
+ /**
397
+ * driving secret behind the sync operation. usually, this will be the
398
+ * secret corresponding to a primary identity keystone. But this can
399
+ * also just be a one-time secret just to have more security in the
400
+ * transmission intrinsically.
401
+ */
402
+ nonSessionSecret: string,
359
403
  }): Promise<string> {
360
- const lc = `${this.lc}[${this.getSessionSecret.name}]`;
404
+ const lc = `${this.lc}[${this.deriveSessionSecret.name}]`;
361
405
  try {
362
406
  if (logalot) { console.log(`${lc} starting... (I: 0de03f8dcd3e32f1fca244e8f2a8a826)`); }
363
407
 
364
408
  // Derive session-specific secret using KDF
365
409
  const sessionSecret = await deriveKey({
366
- masterSecret: identitySecret,
410
+ masterSecret: nonSessionSecret,
367
411
  kdfOpts: {
368
412
  strategy: KdfStrategy.recursive_salt_wrap,
369
413
  salt: sagaId,
@@ -381,18 +425,18 @@ export class SyncSagaCoordinator {
381
425
  }
382
426
  }
383
427
 
384
- private async getInitialWeakDelegateSessionSecret({
428
+ private async getInitialWeakTransitionSessionSecret({
385
429
  sagaId,
386
430
  }: {
387
431
  sagaId: string,
388
432
  }): Promise<string> {
389
- const lc = `${this.lc}[${this.getInitialWeakDelegateSessionSecret.name}]`;
433
+ const lc = `${this.lc}[${this.getInitialWeakTransitionSessionSecret.name}]`;
390
434
  try {
391
435
  if (logalot) { console.log(`${lc} starting... (I: 872ab81a78827b9f2822b78459203226)`); }
392
436
 
393
437
  // Create delegate pool bootstrap secret (publicly derivable)
394
- const initialDelegateSecret = await deriveKey({
395
- masterSecret: DEFAULT_SESSION_IDENTITY_INITIAL_DELEGATE_SECRET, // Weak, publicly derivable secret
438
+ const initialTransitionSecret = await deriveKey({
439
+ masterSecret: SESSION_IDENTITY_KEYSTONE_SECRET_TRANSITIONPOOL, // Weak, publicly derivable secret
396
440
  kdfOpts: {
397
441
  strategy: KdfStrategy.recursive_salt_wrap,
398
442
  salt: sagaId,
@@ -401,7 +445,7 @@ export class SyncSagaCoordinator {
401
445
  }
402
446
  });
403
447
 
404
- return initialDelegateSecret;
448
+ return initialTransitionSecret;
405
449
  } catch (error) {
406
450
  console.error(`${lc} ${extractErrorMsg(error)}`);
407
451
  throw error;
@@ -410,75 +454,263 @@ export class SyncSagaCoordinator {
410
454
  }
411
455
  }
412
456
 
413
- private async getSessionIdentity({
457
+ private async getTransitionKeystonePool({
414
458
  sagaId,
415
- identitySecret,
459
+ }: {
460
+ sagaId: string,
461
+ }): Promise<KeystoneChallengePool> {
462
+ const lc = `${this.lc}[${this.getTransitionKeystonePool.name}]`;
463
+ try {
464
+ if (logalot) { console.log(`${lc} starting... (I: 1ec1c8db7438938b08b96559fcee0826)`); }
465
+
466
+ const config = createStandardPoolConfig({
467
+ salt: sagaId,
468
+ id: SESSION_IDENTITY_KEYSTONE_TRANSITION_POOL_ID,
469
+ type: KeystoneChallengeType.hash_reveal_v1,
470
+ size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE_TRANSITIONPOOL,
471
+ replenishStrategy: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY_TRANSITIONPOOL,
472
+ random: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM_TRANSITIONPOOL,
473
+ sequential: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL_TRANSITIONPOOL,
474
+ targetBinding: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING_TRANSITIONPOOL,
475
+ hashAlgorithm: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO_TRANSITIONPOOL,
476
+ hashRounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS_TRANSITIONPOOL,
477
+ verbs: SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_TRANSITIONPOOL,
478
+ });
479
+ const strategy = KeystoneStrategyFactory.create({ config });
480
+ const poolSecret = await strategy.derivePoolSecret({
481
+ masterSecret: await this.getInitialWeakTransitionSessionSecret({ sagaId }),
482
+ });
483
+ const challenges: { [id: string]: any } = {};
484
+ const bindingMap: { [char: string]: string[] } = {};
485
+
486
+ const targetSize = config.behavior.size;
487
+ const timestamp = Date.now().toString();
488
+ for (let i = 0; i < targetSize; i++) {
489
+ const challengeId = await generateOpaqueChallengeId({
490
+ salt: config.salt, timestamp, index: i
491
+ });
492
+ const solution = await strategy.generateSolution({
493
+ poolSecret, poolId: config.salt, challengeId,
494
+ });
495
+ const challenge = await strategy.generateChallenge({ solution });
496
+ challenges[challengeId] = challenge;
497
+ // Populate Binding Map
498
+ addToBindingMap(bindingMap, challengeId);
499
+ }
500
+
501
+ const transitionPool: KeystoneChallengePool = {
502
+ id: SESSION_IDENTITY_KEYSTONE_TRANSITION_POOL_ID,
503
+ config,
504
+ challenges,
505
+ bindingMap,
506
+ isForeign: true,
507
+ // metadata: { origin: 'receiver', role: 'delegate' } // don't need metadata since we have the pool id being 'delegate' (i think)
508
+ };
509
+
510
+ return transitionPool;
511
+ } catch (error) {
512
+ console.error(`${lc} ${extractErrorMsg(error)}`);
513
+ throw error;
514
+ } finally {
515
+ if (logalot) { console.log(`${lc} complete.`); }
516
+ }
517
+ }
518
+
519
+ private async getDelegateKeystonePool({
520
+ sagaId,
521
+ }: {
522
+ sagaId: string,
523
+ }): Promise<KeystoneChallengePool> {
524
+ const lc = `${this.lc}[${this.getDelegateKeystonePool.name}]`;
525
+ try {
526
+ if (logalot) { console.log(`${lc} starting... (I: 6b1d338f8e988e68f8d77e72ed00d526)`); }
527
+
528
+ // todo: change this to a helper function that does the delegated
529
+ // functionality better. also the f***ing binding map needs better
530
+ // implementation. f***ng glazed over by AI.
531
+
532
+ const config = createStandardPoolConfig({
533
+ salt: sagaId,
534
+ id: SESSION_IDENTITY_KEYSTONE_DELEGATE_POOL_ID,
535
+ type: KeystoneChallengeType.hash_reveal_v1,
536
+ size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE,
537
+ replenishStrategy: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
538
+ random: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
539
+ sequential: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
540
+ targetBinding: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
541
+ hashAlgorithm: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
542
+ hashRounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
543
+ verbs: SESSION_IDENTITY_KEYSTONE_CONFIG_VERBS_DELEGATE,
544
+ });
545
+ const strategy = KeystoneStrategyFactory.create({ config });
546
+ const poolSecret = await strategy.derivePoolSecret({
547
+ masterSecret: SESSION_IDENTITY_KEYSTONE_SECRET_TRANSITIONPOOL
548
+ });
549
+ const challenges: { [id: string]: any } = {};
550
+ const bindingMap: { [char: string]: string[] } = {};
551
+
552
+ const targetSize = config.behavior.size;
553
+ const timestamp = Date.now().toString();
554
+ for (let i = 0; i < targetSize; i++) {
555
+ const challengeId = await generateOpaqueChallengeId({
556
+ salt: config.salt, timestamp, index: i
557
+ });
558
+ const solution = await strategy.generateSolution({
559
+ poolSecret, poolId: config.salt, challengeId,
560
+ });
561
+ const challenge = await strategy.generateChallenge({ solution });
562
+ challenges[challengeId] = challenge;
563
+ // Populate Binding Map
564
+ addToBindingMap(bindingMap, challengeId);
565
+ }
566
+
567
+ const delegatePool: KeystoneChallengePool = {
568
+ id: SESSION_IDENTITY_KEYSTONE_DELEGATE_POOL_ID,
569
+ config,
570
+ challenges,
571
+ bindingMap,
572
+ isForeign: true,
573
+ // metadata: { origin: 'receiver', role: 'delegate' } // don't need metadata since we have the pool id being 'delegate' (i think)
574
+ };
575
+
576
+ return delegatePool;
577
+ } catch (error) {
578
+ console.error(`${lc} ${extractErrorMsg(error)}`);
579
+ throw error;
580
+ } finally {
581
+ if (logalot) { console.log(`${lc} complete.`); }
582
+ }
583
+ }
584
+
585
+ /**
586
+ * creates a session identity keystone based off of the given args.
587
+ *
588
+ * Then, if the {@link primaryIdentity} keystone is provided, this also
589
+ * **signs** this keystone pointing to the address of the sess
590
+ * @param param0
591
+ * @returns
592
+ */
593
+ private async createSessionIdentity({
594
+ sagaId,
595
+ primaryIdentity,
596
+ nonSessionSecret,
416
597
  metaspace,
417
598
  localSpace,
418
599
  }: {
600
+ /**
601
+ * unique to any one particular saga.
602
+ */
419
603
  sagaId: string,
420
- identitySecret: string,
604
+ /**
605
+ * optional main identity, e.g., Alice's keystone
606
+ */
607
+ primaryIdentity: KeystoneIbGib_V1 | undefined,
608
+ /**
609
+ * driving secret behind the sync operation. usually, this will be the
610
+ * secret corresponding to a primary identity keystone. But this can
611
+ * also just be a one-time secret just to have more security in the
612
+ * transmission intrinsically.
613
+ */
614
+ nonSessionSecret: string,
421
615
  metaspace: MetaspaceService,
422
616
  localSpace: IbGibSpaceAny,
423
- }): Promise<KeystoneIbGib_V1> {
424
- const lc = `${this.lc}[${this.getSessionIdentity.name}]`;
617
+ }): Promise<{
618
+ sessionIdentity: KeystoneIbGib_V1,
619
+ /**
620
+ * if truthy, this evolved from the incoming {@link primaryIdentity} and
621
+ * has already persisted/registered in the incoming {@link localSpace}.
622
+ */
623
+ newPrimaryIdentity: KeystoneIbGib_V1 | undefined
624
+ }> {
625
+ const lc = `${this.lc}[${this.createSessionIdentity.name}]`;
425
626
  try {
426
627
  if (logalot) { console.log(`${lc} starting... (I: 428392a4ee636b7bd8f7d5d89a87e826)`); }
427
628
 
428
- if (!identitySecret) { throw new Error(`(UNEXPECTED) identitySecret falsy? This is expected to be truthy by this point. (E: 8ce053fe59825a6678713128953b9d26)`); }
429
-
430
- const sessionSecret = await this.getSessionSecret({ sagaId, identitySecret });
629
+ if (!nonSessionSecret) { throw new Error(`(UNEXPECTED) nonSessionSecret falsy? This is expected to be truthy by this point. (E: 8ce053fe59825a6678713128953b9d26)`); }
431
630
 
432
- const init = await this.getInitialWeakDelegateSessionSecret({ sagaId });
631
+ const primarySessionSecret = await this.deriveSessionSecret({
632
+ sagaId, nonSessionSecret
633
+ });
433
634
 
635
+ // Generate keystone with two initial pools in two steps.
636
+ // 1. Create primary pool with genesis method to correspond to the
637
+ // sender/sender's secret/identity.
638
+ // 2. Create a separate pool and add separately because a
639
+ // different pw + config is used for the transition pool.
434
640
 
435
- // Create TWO pool configs: Primary (strong) + Delegate (weak bootstrap)
436
641
  const primaryPoolConfig: KeystonePoolConfig_HashV1 = {
437
642
  allowedVerbs: [KEYSTONE_VERB_MANAGE],
438
- id: 'primary',
439
- type: 'hash-reveal-v1',
643
+ id: SESSION_IDENTITY_KEYSTONE_PRIMARY_POOL_ID,
440
644
  salt: sagaId,
441
645
  behavior: {
442
- size: 100, // Large pool for many signatures
443
- replenish: 'top-up',
444
- selectSequentially: 2,
445
- selectRandomly: 2,
446
- targetBindingChars: 10
646
+ size: SESSION_IDENTITY_KEYSTONE_CONFIG_SIZE, // Large pool for many signatures
647
+ replenish: SESSION_IDENTITY_KEYSTONE_CONFIG_REPLENISH_STRATEGY,
648
+ selectSequentially: SESSION_IDENTITY_KEYSTONE_CONFIG_SEQUENTIAL,
649
+ selectRandomly: SESSION_IDENTITY_KEYSTONE_CONFIG_RANDOM,
650
+ targetBindingChars: SESSION_IDENTITY_KEYSTONE_CONFIG_TARGET_BINDING,
447
651
  },
448
- algo: 'SHA-256',
449
- rounds: 1
652
+ type: KeystoneChallengeType.hash_reveal_v1,
653
+ algo: SESSION_IDENTITY_KEYSTONE_CONFIG_ALGO,
654
+ rounds: SESSION_IDENTITY_KEYSTONE_CONFIG_ROUNDS,
450
655
  };
656
+ const sessionIdentity_genesis = await this.keystoneSvc.genesis({
657
+ masterSecret: primarySessionSecret,
658
+ configs: [primaryPoolConfig],
659
+ metaspace,
660
+ space: localSpace,
661
+ });
451
662
 
452
- const delegatePoolConfig: any = {
453
- id: 'delegate',
454
- type: 'hash-reveal-v1',
455
- salt: sagaId,
456
- behavior: {
457
- size: 10, // Small pool - only for initial handshake
458
- replenish: 'top-up',
459
- selectSequentially: 1,
460
- selectRandomly: 1,
461
- targetBindingChars: 0
462
- },
463
- algo: 'SHA-256',
464
- rounds: 1
465
- };
663
+ // #region sanity validation of genesis keystone
664
+ /**
665
+ * not necessary but since it's a new design, I'm putting in this
666
+ * immediate validation just to put it through its paces. (worth the
667
+ * slight perf hit).
668
+ */
669
+ const validationErrors = await validateGenesisKeystone({
670
+ keystoneIbGib: sessionIdentity_genesis
671
+ });
672
+ if (validationErrors) { throw new Error(`(UNEXPECTED) the sessionIdentity_genesis that we just created already has validation errors just after creation? (E: e9ca08cf0f8858bb1ace8b9fa89f8726)`); }
673
+ // #endregion sanity validation of genesis keystone
466
674
 
467
- // Generate keystone with DUAL pools. We have to first genesis with
468
- // one and then add the other, because we have two distinct
469
- // secrets.
470
- const sessionIdentity = await this.keystoneSvc.genesis({
471
- masterSecret: sessionSecret,
472
- configs: [primaryPoolConfig],
675
+ const transitionPool = await this.getTransitionKeystonePool({ sagaId });
676
+ /**
677
+ * Note this actually **signs** the initial {@link sessionIdentity_genesis}
678
+ * and requires the use of a pool with management priveleges.
679
+ */
680
+ const sessionIdentity_withTransitionPool = await this.keystoneSvc.addPools({
681
+ latestKeystone: sessionIdentity_genesis,
682
+ /**
683
+ * this secret does not do the delegate pool challenges,
684
+ * rather, this is the sessionSecret itself to evolve the
685
+ * keystone **to add** the delegate pool in the first place.
686
+ */
687
+ masterSecret: primarySessionSecret,
473
688
  metaspace,
474
- space: localSpace
689
+ space: localSpace,
690
+ newPools: [transitionPool],
475
691
  });
476
692
 
477
- // TODO: Store delegate pool separate challenges derived from bootstrap secret
478
- // This allows receiver to verify/evolve the delegate pool
479
- // For now, the keystone genesis with multiple configs handles this
693
+ let newPrimaryIdentity: KeystoneIbGib_V1 | undefined = undefined;
694
+ if (primaryIdentity) {
695
+ newPrimaryIdentity = await this.keystoneSvc.sign({
696
+ latestKeystone: primaryIdentity,
697
+ poolId: primaryPoolConfig.id,
698
+ claim: {
699
+ verb: KEYSTONE_VERB_SIGN,
700
+ target: getIbGibAddr({ ibGib: sessionIdentity_withTransitionPool }),
701
+ },
702
+ masterSecret: nonSessionSecret,
703
+ metaspace,
704
+ space: localSpace,
705
+ // frameDetails: undefined, // anything to put here?
706
+ // requiredChallengeIds: undefined, // not relevant I think
707
+ });
708
+ }
480
709
 
481
- return sessionIdentity;
710
+ return {
711
+ sessionIdentity: sessionIdentity_withTransitionPool,
712
+ newPrimaryIdentity,
713
+ }
482
714
  } catch (error) {
483
715
  console.error(`${lc} ${extractErrorMsg(error)}`);
484
716
  throw error;
@@ -846,6 +1078,7 @@ export class SyncSagaCoordinator {
846
1078
  masterSecret: sessionSecret,
847
1079
  metaspace,
848
1080
  });
1081
+ contextIbGib.fnIdentitySecret = () => Promise.resolve(sessionSecret);
849
1082
  }
850
1083
 
851
1084
  return contextIbGib;
@@ -1665,8 +1898,8 @@ export class SyncSagaCoordinator {
1665
1898
  if (ackData.stage !== SyncStage.ack) {
1666
1899
  throw new Error(`${lc} Invalid ack frame: ackData.stage !== SyncStage.ack (E: 2e8b0a94b5954a66a6a1a7a0b3f5b7a1)`);
1667
1900
  }
1668
- if (logalot) { console.log(`${lc} ackData: ${pretty(ackData)} (I: 7f8e9d0a1b2c3d4e5f6g7h8i9j0k)`); }
1669
- if (!sagaIbGib.data) { throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 385e389610282aa9c5dbe4083adbde26)`); }
1901
+ if (logalot) { console.log(`${lc} ackData: ${pretty(ackData)} (I: b817c5571c5e916fe8f90b892b3e8e26)`); }
1902
+ if (!sagaIbGib.data) { throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: e3f2e8f162484859787651b85c011826)`); }
1670
1903
  // #region sanity/validation
1671
1904
 
1672
1905
  // 1. Check for Conflicts
@@ -2889,7 +3122,7 @@ export class SyncSagaCoordinator {
2889
3122
 
2890
3123
  // Attach session keystone to saga frame via hard rel8n
2891
3124
  if (sessionIdentity) {
2892
- rel8ns.sessionKeystones = [getIbGibAddr({ ibGib: sessionIdentity })];
3125
+ rel8ns.sessionKeystone = [getIbGibAddr({ ibGib: sessionIdentity })];
2893
3126
  }
2894
3127
 
2895
3128
  const resNew = await createTimeline({
@@ -205,7 +205,7 @@ export interface SyncRel8ns_V1 extends IbGibRel8ns_V1 {
205
205
  * Each sync endpoint retrieves the session keystone from this rel8n
206
206
  * rather than searching spaces. Keystones are stored in durable spaces.
207
207
  */
208
- sessionKeystones?: IbGibAddr[];
208
+ sessionKeystone?: IbGibAddr[];
209
209
 
210
210
  /**
211
211
  * The message stone that contains the information about the particular