@ibgib/core-gib 0.1.61 → 0.1.62

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.
@@ -1 +1 @@
1
- {"version":3,"file":"keystone-types.d.mts","sourceRoot":"","sources":["../../src/keystone/keystone-types.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keystone-types.d.mts","sourceRoot":"","sources":["../../src/keystone/keystone-types.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIzD,eAAO,MAAM,sCAAsC,mBAAmB,CAAC;AACvE;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAC3B,OAAO,sCAAsC,CAG9C;AACL,eAAO,MAAM,qBAAqB;;CAEkB,CAAC;AACrD,eAAO,MAAM,oCAAoC,oBAAuC,CAAC;AACzF,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,qBAAqB,CAE/E;AAQD;;GAEG;AACH,eAAO,MAAM,kCAAkC,WAAW,CAAC;AAC3D;;GAEG;AACH,eAAO,MAAM,uCAAuC,gBAAgB,CAAC;AACrE;;GAEG;AACH,eAAO,MAAM,mCAAmC,YAAY,CAAC;AAC7D;;GAEG;AACH,eAAO,MAAM,sCAAsC,eAAe,CAAC;AACnE,MAAM,MAAM,yBAAyB,GAC/B,OAAO,kCAAkC,GACzC,OAAO,uCAAuC,GAC9C,OAAO,mCAAmC,GAC1C,OAAO,sCAAsC,CAC9C;AACL;;GAEG;AACH,eAAO,MAAM,yBAAyB;IAClC;;OAEG;;IAEH;;OAEG;;IAEH;;;;;;OAMG;;IAEH;;;OAGG;;CAEiD,CAAC;AACzD,eAAO,MAAM,wCAAwC,yDAA2C,CAAC;AACjG,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,yBAAyB,CAElF;AAGD,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,SAAS,EAAE,yBAAyB,CAAC;IAErC;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACnC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,EAAE,qBAAqB,CAAC;IAC5B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,oBAAoB,CAAC;IAC/B;;;;;;;;;OASG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACrE,IAAI,EAAE,OAAO,qBAAqB,CAAC,cAAc,CAAC;IAClD,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAM3D,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,qBAAqB,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,qBAAqB,CAAC,cAAc,CAAC;IAClD;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AAMzD,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,qBAAqB,CAAC;IAC5B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACjE,IAAI,EAAE,gBAAgB,CAAC;IACvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAMvD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;OAIG;IACH,MAAM,EAAE,kBAAkB,CAAC;IAE3B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAEtC;;;OAGG;IACH,UAAU,EAAE;QAAE,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,CAAA;KAAE,CAAC;IAIzD;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,MAAM,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAE9B;;OAEG;IACH,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAE9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACjC;;;OAGG;IACH,eAAe,EAAE,SAAS,CAAC;IAC3B;;;;;;;OAOG;IACH,YAAY,EAAE,SAAS,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAMD,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,OAAO,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACjD;;;OAGG;IACH,cAAc,EAAE,qBAAqB,EAAE,CAAC;IAExC;;OAEG;IACH,MAAM,EAAE,aAAa,EAAE,CAAC;IAExB;;OAEG;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IAExC;;;;OAIG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC;IAEnB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,GAAG,CAAC;IAExB;;;OAGG;IACH,SAAS,CAAC,EAAE;QAAE,CAAC,eAAe,EAAE,SAAS,GAAG,oBAAoB,CAAA;KAAE,CAAC;CACtE;AAED,MAAM,WAAW,iBAAkB,SAAQ,cAAc;CAGxD;AAED,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAAC,eAAe,EAAE,iBAAiB,CAAC;IAClF,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAChC;;;OAGG;IACH,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAE1B;;;OAGG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibgib/core-gib",
3
- "version": "0.1.61",
3
+ "version": "0.1.62",
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",
@@ -24,8 +24,8 @@ Keystones organize challenges into **pools** with specific purposes:
24
24
 
25
25
  * **Default Pool**: General-purpose signing operations
26
26
  * **Revoke Pool**: Permanent identity termination (one-time use, `verb: revoke`)
27
- * **Manage Pool**: Structural changes like adding pools (`verb: manage`)
28
- * **Foreign Pools**: Delegation to external identities (SSO-like workflows)
27
+ * **Manage Pool**: Structural changes like adding pools (`verb: manage`) or managing delegates
28
+ * **Foreign Pools**: Inward delegation to external identities (SSO co-signing workflows)
29
29
 
30
30
  Each pool configuration specifies:
31
31
  * **`id`**: Unique identifier within the keystone
@@ -33,6 +33,19 @@ Each pool configuration specifies:
33
33
  * **`algo` / `rounds`**: Hashing algorithm and KDF iteration count
34
34
  * **`behavior`**: Rules for capacity (`size`), replenishment (`replenish`), sequential/random consumption (`selectSequentially`/`selectRandomly`), and target binding (`targetBindingCount`).
35
35
 
36
+ ## Delegation (Inward vs. Outward)
37
+
38
+ Keystones support both **Inward Delegation** (bringing external keys inside this identity) and **Outward Delegation** (externalizing keystone responsibilities to other keystones).
39
+
40
+ ### 1. Inward Delegation (Foreign Pools)
41
+ Alice can delegate co-signing rights to Bob (e.g., for Single Sign-On) by embedding Bob's challenge pool in her Keystone. Bob can then sign claims on Alice's behalf without ever exposing Alice's master secret, sharing Bob's master secret, or requiring co-located servers.
42
+
43
+ ### 2. Outward Delegation (Delegate Keystones)
44
+ Alice can authorize entire external keystones to act on her behalf (e.g., authorizing a specific client keystone to sync data or sign messages) by adding them to her keystone's `delegates` map:
45
+ * **Manage Verb Authorized**: Adding or removing a delegate modifies the keystone's metadata. This transition is strictly rejected during validation unless authorized by a signature proof using the parent's `manage` pool (`KEYSTONE_VERB_MANAGE`).
46
+ * **Ancestry Linkage**: The delegate registration records the exact frame (`thisAddr`) in the parent timeline where the delegation is active. The validator enforces that `thisAddr` is a valid historical or current frame in the parent's timeline ancestry, preventing delegate replay or hijack attacks.
47
+ * **Soft-Linking**: Keeps delegate keystones "pure" and independent (with their own pools/lifecycle) while maintaining secure, verifiable delegation on the parent.
48
+
36
49
  ## Basic Usage
37
50
 
38
51
  ### Genesis (Create Identity)
@@ -14,10 +14,10 @@
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)
17
+ ### Inward Delegation (Foreign Pools)
18
18
 
19
19
  > [!IMPORTANT]
20
- > **🔀 Keystones support delegation** by embedding challenges from external identities.
20
+ > **🔀 Keystones support inward delegation** by embedding challenges from external identities.
21
21
 
22
22
  **Mechanism**:
23
23
  * **Use Case**: Alice adds Bob's challenge pool to her keystone
@@ -41,6 +41,25 @@
41
41
 
42
42
  See [KeystoneService_V1.addPools()](file:../keystone-service-v1.mts) for implementation.
43
43
 
44
+ ### Outward Delegation (Delegate Keystones)
45
+
46
+ > [!IMPORTANT]
47
+ > **🔀 Keystones support outward delegation** by authorizing entire external keystones (e.g. client keys) to act on their behalf.
48
+
49
+ **Mechanism**:
50
+ * **Use Case**: Alice registers a dedicated delegate keystone in her parent keystone to synchronize data.
51
+ * **Structure**: Alice's parent keystone stores a `delegates` mapping in its data. Each delegate info stores:
52
+ * `delegateTjpAddr`: The temporal junction point address (stable identity) of the delegate.
53
+ * `delegateAddr`: The current/latest frame address of the delegate.
54
+ * `thisAddr`: The exact frame address of the parent keystone where this delegation was registered.
55
+ * **Validation & Transition Security**:
56
+ - **Authorization**: Modifying the delegates map (registering/unregistering) requires a signature proof matching the `manage` verb (`KEYSTONE_VERB_MANAGE`).
57
+ - **Ancestry Verification**: The validator checks that `thisAddr` is a valid current or historical address in the parent keystone timeline (`prevIbGib.rel8ns.past` or current address), securing the timeline against replay or hijack attempts.
58
+ - **Well-Formedness**: The validator enforces that the keys in the `delegates` map match `delegateTjpAddr`, and all addresses are valid keystone addresses.
59
+ * **Soft-Linking Pattern**: Keeps delegate keystones pure/clean while establishing a secure, verifiable association on the parent.
60
+
61
+ See `KeystoneService_V1.registerDelegate()`, `unregisterDelegate()` (in [keystone-service-v1.mts](file:../keystone-service-v1.mts)), and `validateDelegates()` (in [keystone-helpers.mts](file:../keystone-helpers.mts)) for details.
62
+
44
63
  ## 3. Policy Engine (Selection & Mitigation)
45
64
 
46
65
  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:
@@ -0,0 +1,57 @@
1
+ # Keystone Delegation Models
2
+
3
+ Keystones support both **Inward Delegation** (integrating external keys/challenges) and **Outward Delegation** (externalizing keystone responsibilities to other keystones).
4
+
5
+ ---
6
+
7
+ ## 1. Inward Delegation (Foreign Pools)
8
+
9
+ * **Mechanism**: A keystone embeds challenges from an external identity (e.g., Alice's keystone containing Bob's co-signing/SSO pool).
10
+ * **Purpose**: Allows external custodians or identities to co-sign or sign specific claims on behalf of this identity without sharing master secrets.
11
+ * **Lifecycle**: Added/removed via standard pool evolution paths (`addPools` / `removePools`).
12
+
13
+ ---
14
+
15
+ ## 2. Outward Delegation (Delegate Keystones)
16
+
17
+ * **Mechanism**: A parent keystone stores a `delegates` map in its `data` object mapping `delegateTjpAddr` to `DelegateKeystoneInfo`.
18
+ * **Purpose**: Authorizes entire independent external keystones (such as a device key or client) to act on behalf of the parent identity.
19
+ * **Lifecycle**: Registered and unregistered via `registerDelegate()` and `unregisterDelegate()`.
20
+ * **Security Policies**:
21
+ * **Manage Verb Proof**: Mutating the delegates map is rejected during validation unless authorized by a signature proof using the parent's `manage` pool (`KEYSTONE_VERB_MANAGE`).
22
+ * **Ancestry Verification**: The delegate's `thisAddr` records the exact frame in the parent's timeline where the delegation took place. The validator enforces that `thisAddr` is a valid historical or current frame in the parent's timeline history.
23
+ * **Soft-Linking**: All relations use soft-links (embedded in `data`) to avoid merging cryptographic dependency graphs of different keystones.
24
+
25
+ ---
26
+
27
+ ## 3. The Multi-Tiered Identity Hierarchy
28
+
29
+ To balance high cryptographic security with practical daily usability (avoiding the performance and size overhead of constantly evolving a root identity), `ibgib` utilizes a multi-tiered delegation model:
30
+
31
+ ```
32
+ [ Tier 1: Root/Parent Keystone ] (High Security, Cold/Warm)
33
+
34
+ ▼ (Persistent Delegation via `delegates` map)
35
+ [ Tier 2: Sync/Device Keystone ] (Medium/Low Security, e.g. Laptop/Phone)
36
+
37
+ ▼ (Ephemeral Delegation via signed Claims / sync verb)
38
+ [ Tier 3: Session Keystone ] (Temporary, Tab-Specific)
39
+ ```
40
+
41
+ ### Tier 1: Root/Parent Keystone (Primary Identity)
42
+ * **Role**: The primary, slow-evolving root of the user's decentralized identity.
43
+ * **Secrets**: Typically derived from a strong, user-memorized passphrase.
44
+ * **Activity**: Rarely evolved. Only updated to register or unregister client devices.
45
+ * **Delegates**: Formally registers a device's keystone in its `delegates` map.
46
+
47
+ ### Tier 2: Sync/Device Keystone
48
+ * **Role**: A persistent client identity dedicated to a specific user device (e.g. laptop, phone).
49
+ * **Secrets**: Stored locally on the device (e.g. keychains, secure storage).
50
+ * **Activity**: Initiates business-level operations (like synchronization sagas) as the `senderIdentity`.
51
+ * **Authorization**: Verifiers trace this device keystone back to the Root/Parent's registered `delegates` map.
52
+
53
+ ### Tier 3: Session Keystone
54
+ * **Role**: An ephemeral, memory-only keystone created for a single sync session or browser tab.
55
+ * **Secrets**: Transient, thrown away on tab close or session timeout.
56
+ * **Authorization**: Authorized by the Tier 2 Sync/Device Keystone using an ad-hoc signed co-signing/delegation claim. No root evolution required.
57
+ * **Benefit**: Absolute isolation. If a device is compromised, the Root Keystone unregisters the Tier 2 Device delegate, instantly invalidating the device and all associated Tier 3 sessions.
@@ -95,7 +95,6 @@ export function isKeystoneVerb(value: string): value is KeystoneVerb {
95
95
  export const POOL_ID_REVOKE = KEYSTONE_VERB_REVOKE;
96
96
  export const POOL_ID_MANAGE = KEYSTONE_VERB_MANAGE;
97
97
  export const POOL_ID_DEFAULT = "default";
98
- export const POOL_ID_DELEGATE = "delegate";
99
98
  /**
100
99
  * Pool ID for the session keystone's transport connect pool.
101
100
  * Paired with {@link KEYSTONE_VERB_CONNECT}. Consumed once per sync session
@@ -8,7 +8,7 @@ import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
8
8
  import { getGib } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
9
9
 
10
10
  import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
11
- import { KEYSTONE_ATOM, KEYSTONE_HASH_MAX_ROUNDS, KEYSTONE_POOL_ID_REGEXP, KEYSTONE_SALT_REGEXP, KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP } from "./keystone-constants.mjs";
11
+ import { KEYSTONE_ATOM, KEYSTONE_HASH_MAX_ROUNDS, KEYSTONE_POOL_ID_REGEXP, KEYSTONE_SALT_REGEXP, KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP, KEYSTONE_VERB_MANAGE } from "./keystone-constants.mjs";
12
12
  import {
13
13
  KeystoneData_V1, KeystoneIbGib_V1, KeystoneIb_V1, KeystoneChallengePool,
14
14
  DeterministicResult, KeystoneProof, KeystonePoolConfig,
@@ -17,6 +17,7 @@ import {
17
17
  KeystoneChallengeType,
18
18
  KEYSTONE_CHALLENGE_TYPE_VALID_VALUES,
19
19
  KeystonePoolConfig_HashV1,
20
+ DelegateKeystoneInfo,
20
21
  } from "./keystone-types.mjs";
21
22
  import { MetaspaceService } from "../witness/space/metaspace/metaspace-types.mjs";
22
23
  import { IbGibSpaceAny } from "../witness/space/space-base-v1.mjs";
@@ -90,6 +91,22 @@ export async function parseKeystoneIb({
90
91
  }
91
92
  }
92
93
 
94
+ /**
95
+ * Helper to validate if an ib string is a well-formed keystone ib.
96
+ */
97
+ export async function validateKeystoneIb({
98
+ ib,
99
+ }: {
100
+ ib: Ib,
101
+ }): Promise<boolean> {
102
+ try {
103
+ await parseKeystoneIb({ ib });
104
+ return true;
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
109
+
93
110
  /**
94
111
  * The Policy Engine.
95
112
  * Calculates exactly which challenges MUST be consumed based on config and demands.
@@ -634,6 +651,11 @@ export async function validateGenesisKeystone({
634
651
 
635
652
  const { data, rel8ns } = keystoneIbGib;
636
653
 
654
+ const isValidIb = await validateKeystoneIb({ ib: keystoneIbGib.ib });
655
+ if (!isValidIb) {
656
+ errors.push(`${lc} invalid keystone ib (${keystoneIbGib.ib}). (E: ad7a88bc38c290a184dfbd42be48f526)`);
657
+ }
658
+
637
659
  // Validate username/description metadata if present
638
660
  const metadataErrors = validateKeystoneMetadata({ data });
639
661
  metadataErrors.forEach(x => errors.push(x));
@@ -670,6 +692,89 @@ export async function validateGenesisKeystone({
670
692
  }
671
693
  }
672
694
 
695
+ /**
696
+ * Helper to determine if two delegates maps differ.
697
+ */
698
+ export function isDelegatesChanged({
699
+ currDelegates,
700
+ prevDelegates,
701
+ }: {
702
+ currDelegates?: Record<string, DelegateKeystoneInfo>,
703
+ prevDelegates?: Record<string, DelegateKeystoneInfo>,
704
+ }): boolean {
705
+ const curr = currDelegates || {};
706
+ const prev = prevDelegates || {};
707
+ const currKeys = Object.keys(curr);
708
+ const prevKeys = Object.keys(prev);
709
+
710
+ if (currKeys.length !== prevKeys.length) { return true; }
711
+
712
+ for (const key of currKeys) {
713
+ const currVal = curr[key];
714
+ const prevVal = prev[key];
715
+ if (!prevVal) { return true; }
716
+ if (currVal.delegateTjpAddr !== prevVal.delegateTjpAddr ||
717
+ currVal.delegateAddr !== prevVal.delegateAddr ||
718
+ currVal.thisAddr !== prevVal.thisAddr) {
719
+ return true;
720
+ }
721
+ }
722
+
723
+ return false;
724
+ }
725
+
726
+ /**
727
+ * Validates the structure and constraints of the delegates map.
728
+ */
729
+ export async function validateDelegates({
730
+ currDelegates,
731
+ prevIbGib,
732
+ lc,
733
+ errors,
734
+ }: {
735
+ currDelegates: Record<string, DelegateKeystoneInfo>,
736
+ prevIbGib: KeystoneIbGib_V1,
737
+ lc: string,
738
+ errors: string[],
739
+ }): Promise<void> {
740
+ const currKeys = Object.keys(currDelegates);
741
+ const prevAddr = getIbGibAddr({ ibGib: prevIbGib });
742
+
743
+ for (const key of currKeys) {
744
+ const info = currDelegates[key];
745
+ if (key !== info.delegateTjpAddr) {
746
+ errors.push(`${lc} Invalid delegate mapping: Key '${key}' does not match delegateTjpAddr '${info.delegateTjpAddr}'. (E: 9c8da8bc38c290a184dfbd42be48f526)`);
747
+ }
748
+
749
+ // Verify addresses are valid keystone addresses
750
+ const [
751
+ parsedDelegateTjp,
752
+ parsedDelegate,
753
+ parsedThis,
754
+ ] = await Promise.all([
755
+ validateKeystoneIb({ ib: info.delegateTjpAddr.split('^')[0] }),
756
+ validateKeystoneIb({ ib: info.delegateAddr.split('^')[0] }),
757
+ validateKeystoneIb({ ib: info.thisAddr.split('^')[0] }),
758
+ ]);
759
+
760
+ if (!parsedDelegateTjp) {
761
+ errors.push(`${lc} Delegate delegateTjpAddr '${info.delegateTjpAddr}' is not a valid keystone address. (E: 10d8a8bc38c290a184dfbd42be48f526)`);
762
+ }
763
+ if (!parsedDelegate) {
764
+ errors.push(`${lc} Delegate delegateAddr '${info.delegateAddr}' is not a valid keystone address. (E: 20d8a8bc38c290a184dfbd42be48f526)`);
765
+ }
766
+ if (!parsedThis) {
767
+ errors.push(`${lc} Delegate thisAddr '${info.thisAddr}' is not a valid keystone address. (E: 30d8a8bc38c290a184dfbd42be48f526)`);
768
+ }
769
+
770
+ // Verify thisAddr is in the parent's past (or is the current parent address)
771
+ const isHistoricalParent = info.thisAddr === prevAddr || (prevIbGib.rel8ns?.past || []).includes(info.thisAddr);
772
+ if (!isHistoricalParent) {
773
+ errors.push(`${lc} Delegate thisAddr '${info.thisAddr}' is not a valid historical address in the parent keystone timeline. (E: 40d8a8bc38c290a184dfbd42be48f526)`);
774
+ }
775
+ }
776
+ }
777
+
673
778
  /**
674
779
  * Validates the transition from Prev -> Curr.
675
780
  * Enforces Cryptography AND Behavioral Policy.
@@ -700,28 +805,48 @@ export async function validateKeystoneTransition({
700
805
  const currData = currentIbGib.data!;
701
806
  const prevData = prevIbGib.data!;
702
807
 
808
+ const isValidIb = await validateKeystoneIb({ ib: currentIbGib.ib });
809
+ if (!isValidIb) {
810
+ errors.push(`${lc} invalid keystone ib (${currentIbGib.ib}). (E: a98dc8bc38c290a184dfbd42be48f526)`);
811
+ }
812
+
703
813
  // Validate username/description metadata if present
704
814
  const metadataErrors = validateKeystoneMetadata({ data: currData });
705
815
  metadataErrors.forEach(x => errors.push(x));
706
816
 
817
+ // Validate delegates map mutations if present
818
+ const currDelegates = currData.delegates || {};
819
+ const prevDelegates = prevData.delegates || {};
820
+ const delegatesChanged = isDelegatesChanged({ currDelegates, prevDelegates });
821
+
822
+ if (delegatesChanged) {
823
+ const hasManageProof = currData.proofs?.some(proof => proof.claim?.verb === KEYSTONE_VERB_MANAGE);
824
+ if (!hasManageProof) {
825
+ errors.push(`${lc} Policy Violation: Delegates map was mutated but no proof for manage verb ('${KEYSTONE_VERB_MANAGE}') is present. (E: 819fa8cb28c9b60e68994511a5825)`);
826
+ }
827
+ }
828
+
829
+ // Validate each delegate's structure and constraints
830
+ await validateDelegates({ currDelegates, prevIbGib, lc, errors });
831
+
707
832
  // must be sequential data.n values
708
833
  // note: "-2" because we don't want a "valid" sequential data.n if we
709
834
  // have an invalid prev and a valid currDataN of 0
710
835
  const currDataN = currData.n ?? -2;
711
836
  const prevDataN = prevData.n ?? -2;
712
837
  if (currDataN < 0) {
713
- errors.push('invalid keystone.currData.n is undefined or null.');
838
+ errors.push('invalid keystone.currData.n is undefined or null. (E: 9fbe38704b68829d18ea1d0940d0aa26)');
714
839
  }
715
840
  if (prevDataN < 0) {
716
- errors.push('invalid keystone.prevData.n is undefined or null.');
841
+ errors.push('invalid keystone.prevData.n is undefined or null. (E: 6dc5aa9c87017db6080ed4268b07af26)');
717
842
  };
718
843
  if (currDataN !== (prevDataN + 1)) {
719
- errors.push(`keystone data.n values are not sequential. prevData.n: ${prevDataN}, currData.n: ${currDataN}. `);
844
+ errors.push(`keystone data.n values are not sequential. prevData.n: ${prevDataN}, currData.n: ${currDataN}. (E: 5ae12809f2c67216d38d8ba8d6c42826)`);
720
845
  }
721
846
 
722
847
  for (const proof of currData.proofs) {
723
848
  if (proof.solutions.length === 0) {
724
- errors.push(`Proof ${proof.id || 'unknown'} has no solutions.`);
849
+ errors.push(`Proof ${proof.id || 'unknown'} has no solutions. (E: e2b4683ce0ce30f798ec77841e88c826)`);
725
850
  continue;
726
851
  }
727
852
 
@@ -860,6 +985,7 @@ export async function evolvePersistAndRegisterKeystone({
860
985
  if (prevData.challengePools) { dataToRemove.challengePools = []; }
861
986
  if (prevData.frameDetails) { dataToRemove.frameDetails = {}; }
862
987
  if (prevData.checkpointDetails) { dataToRemove.checkpointDetails = {}; }
988
+ if (prevData.delegates) { (dataToRemove as any).delegates = 'remove'; }
863
989
  if (Object.keys(dataToRemove).length === 0) { dataToRemove = undefined; }
864
990
 
865
991
  const resMut8 = await mut8({
@@ -1,22 +1,30 @@
1
1
  import { extractErrorMsg, mergeMapsOrArrays_Naive } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
- import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
2
+ import { getIbGibAddr, getIbAndGib } from '@ibgib/ts-gib/dist/helper.mjs';
3
+ import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
4
+ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
3
5
 
4
6
  import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
5
7
  import {
6
8
  KeystoneData_V1, KeystoneIbGib_V1, KeystonePoolConfig, KeystoneClaim,
7
9
  KeystoneChallengePool, KeystoneReplenishStrategy, KeystoneRevocationInfo,
10
+ DelegateKeystoneStatus,
8
11
  } from './keystone-types.mjs';
9
12
  import { KeystoneStrategyFactory } from './strategy/keystone-strategy-factory.mjs';
10
- import { POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE, KEYSTONE_CHECKPOINT_FREQUENCY } from './keystone-constants.mjs';
13
+ import {
14
+ POOL_ID_REVOKE, KEYSTONE_VERB_REVOKE, KEYSTONE_VERB_MANAGE,
15
+ KEYSTONE_CHECKPOINT_FREQUENCY, POOL_ID_MANAGE
16
+ } from './keystone-constants.mjs';
11
17
  import {
12
18
  createKeystoneIbGibImpl, evolvePersistAndRegisterKeystone,
13
19
  generateOpaqueChallengeId, resolveTargetPool, selectChallengeIds,
14
20
  solveAndReplenish, validateKeystoneTransition,
15
21
  validateGenesisKeystone, validateKeystoneGraph
16
22
  } from './keystone-helpers.mjs';
23
+ import { getLatestAddrs } from '../witness/space/space-helper.mjs';
17
24
  import { IbGibSpaceAny } from '../witness/space/space-base-v1.mjs';
18
25
  import { MetaspaceService } from '../witness/space/metaspace/metaspace-types.mjs';
19
26
  import { FlatIbGibGraph } from '../common/other/graph-types.mjs';
27
+ import { getTjpAddr } from '../common/other/ibgib-helper.mjs';
20
28
 
21
29
  const logalot = GLOBAL_LOG_A_LOT;
22
30
 
@@ -110,6 +118,7 @@ export class KeystoneService_V1 {
110
118
  frameDetails,
111
119
  metaspace,
112
120
  space,
121
+ dataToPatch,
113
122
  }: {
114
123
  latestKeystone: KeystoneIbGib_V1;
115
124
  /**
@@ -133,6 +142,7 @@ export class KeystoneService_V1 {
133
142
  frameDetails?: any;
134
143
  metaspace: MetaspaceService;
135
144
  space: IbGibSpaceAny;
145
+ dataToPatch?: Partial<KeystoneData_V1>;
136
146
  }): Promise<KeystoneIbGib_V1> {
137
147
  const lc = `${this.lc}[${this.sign.name}]`;
138
148
  try {
@@ -193,6 +203,8 @@ export class KeystoneService_V1 {
193
203
  proofs: [proof],
194
204
  frameDetails,
195
205
  checkpointDetails,
206
+ ...(prevData.delegates ? { delegates: prevData.delegates } : {}),
207
+ ...dataToPatch,
196
208
  };
197
209
 
198
210
  // 5. Commit (Evolve, Persist, Register)
@@ -236,6 +248,209 @@ export class KeystoneService_V1 {
236
248
  return errors;
237
249
  }
238
250
 
251
+ /**
252
+ * Registers a delegate keystone on the parent keystone by appending its information
253
+ * to the parent's `delegates` map. This operation is signed using the parent's `manage` pool.
254
+ * Validates the delegate keystone's entire graph/timeline before registering.
255
+ */
256
+ async registerDelegate({
257
+ parentKeystone,
258
+ delegateKeystone,
259
+ masterSecret,
260
+ frameDetails,
261
+ metaspace,
262
+ space,
263
+ }: {
264
+ parentKeystone: KeystoneIbGib_V1;
265
+ delegateKeystone: KeystoneIbGib_V1;
266
+ masterSecret: string;
267
+ frameDetails?: any;
268
+ metaspace: MetaspaceService;
269
+ space: IbGibSpaceAny;
270
+ }): Promise<KeystoneIbGib_V1> {
271
+ const lc = `${this.lc}[${this.registerDelegate.name}]`;
272
+ try {
273
+ if (logalot) { console.log(`${lc} starting...`); }
274
+
275
+ // 1. Validate the delegate keystone's entire graph/timeline
276
+ const validationErrors = await validateKeystoneGraph({
277
+ keystoneIbGib: delegateKeystone,
278
+ getLatest: true,
279
+ invalidIfMoreRecentKeystoneFoundInSpace: false,
280
+ space,
281
+ });
282
+ if (validationErrors.length > 0) {
283
+ throw new Error(`Delegate keystone validation failed: ${validationErrors.join(', ')} (E: 88fa8ab28c9b60e68994511a5825)`);
284
+ }
285
+
286
+ // 2. Verify that parent contains POOL_ID_MANAGE pool configuration
287
+ const prevData = parentKeystone.data!;
288
+ const hasManagePool = prevData.challengePools.some(p => p.id === POOL_ID_MANAGE);
289
+ if (!hasManagePool) {
290
+ throw new Error(`Parent keystone does not support delegation. Manage pool is required. (E: 818fa8ab28c9b60e68994511a5825)`);
291
+ }
292
+
293
+ const delegateTjpAddr = getTjpAddr({ ibGib: delegateKeystone });
294
+ if (!delegateTjpAddr) { throw new Error(`(UNEXPECTED) delegateTjpAddr falsy? (E: d4d6e8ad03c8925d4838b9a87b8f2826)`); }
295
+
296
+ // 3. Prepare the claim
297
+ const claim: Partial<KeystoneClaim> = {
298
+ target: delegateTjpAddr,
299
+ verb: KEYSTONE_VERB_MANAGE,
300
+ };
301
+
302
+ // 4. Update the delegates map
303
+ const currentDelegates = prevData.delegates ? { ...prevData.delegates } : {};
304
+ currentDelegates[delegateTjpAddr] = {
305
+ delegateTjpAddr,
306
+ delegateAddr: getIbGibAddr({ ibGib: delegateKeystone }),
307
+ thisAddr: getIbGibAddr({ ibGib: parentKeystone }),
308
+ };
309
+
310
+ // 5. Sign & evolve parent keystone using the 'manage' pool
311
+ const evolved = await this.sign({
312
+ latestKeystone: parentKeystone,
313
+ masterSecret,
314
+ claim,
315
+ poolId: POOL_ID_MANAGE,
316
+ frameDetails,
317
+ metaspace,
318
+ space,
319
+ dataToPatch: {
320
+ delegates: currentDelegates
321
+ }
322
+ });
323
+
324
+ return evolved;
325
+ } catch (error) {
326
+ console.error(`${lc} ${extractErrorMsg(error)}`);
327
+ throw error;
328
+ } finally {
329
+ if (logalot) { console.log(`${lc} complete.`); }
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Unregisters a delegate keystone from the parent keystone by removing its entry
335
+ * from the parent's `delegates` map. This operation is signed using the parent's `manage` pool.
336
+ */
337
+ async unregisterDelegate({
338
+ parentKeystone,
339
+ delegateTjpAddr,
340
+ masterSecret,
341
+ frameDetails,
342
+ metaspace,
343
+ space,
344
+ }: {
345
+ parentKeystone: KeystoneIbGib_V1;
346
+ delegateTjpAddr: IbGibAddr;
347
+ masterSecret: string;
348
+ frameDetails?: any;
349
+ metaspace: MetaspaceService;
350
+ space: IbGibSpaceAny;
351
+ }): Promise<KeystoneIbGib_V1> {
352
+ const lc = `${this.lc}[${this.unregisterDelegate.name}]`;
353
+ try {
354
+ if (logalot) { console.log(`${lc} starting...`); }
355
+
356
+ // 1. Verify that parent contains POOL_ID_MANAGE pool configuration
357
+ const prevData = parentKeystone.data!;
358
+ const hasManagePool = prevData.challengePools.some(p => p.id === POOL_ID_MANAGE);
359
+ if (!hasManagePool) {
360
+ throw new Error(`Parent keystone does not support delegation. Manage pool is required. (E: 3889f8ab28c9b60e68994511a5825)`);
361
+ }
362
+
363
+ // 2. Prepare the claim
364
+ const claim: Partial<KeystoneClaim> = {
365
+ target: delegateTjpAddr,
366
+ verb: KEYSTONE_VERB_MANAGE,
367
+ };
368
+
369
+ // 3. Update the delegates map
370
+ const currentDelegates = prevData.delegates ? { ...prevData.delegates } : {};
371
+ if (!currentDelegates[delegateTjpAddr]) {
372
+ throw new Error(`Delegate ${delegateTjpAddr} is not registered on this parent. (E: 81d9f8ab28c9b60e68994511a5825)`);
373
+ }
374
+ delete currentDelegates[delegateTjpAddr];
375
+
376
+ // 4. Sign & evolve parent keystone using the 'manage' pool
377
+ const evolved = await this.sign({
378
+ latestKeystone: parentKeystone,
379
+ masterSecret,
380
+ claim,
381
+ poolId: POOL_ID_MANAGE,
382
+ frameDetails,
383
+ metaspace,
384
+ space,
385
+ dataToPatch: {
386
+ delegates: currentDelegates
387
+ }
388
+ });
389
+
390
+ return evolved;
391
+ } catch (error) {
392
+ console.error(`${lc} ${extractErrorMsg(error)}`);
393
+ throw error;
394
+ } finally {
395
+ if (logalot) { console.log(`${lc} complete.`); }
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Gets the registration status of a delegate keystone from the parent's latest tip frame.
401
+ */
402
+ async getDelegateStatus({
403
+ parentTjpAddr,
404
+ delegateTjpAddr,
405
+ metaspace,
406
+ space,
407
+ }: {
408
+ parentTjpAddr: IbGibAddr;
409
+ delegateTjpAddr: IbGibAddr;
410
+ metaspace: MetaspaceService;
411
+ space: IbGibSpaceAny;
412
+ }): Promise<DelegateKeystoneStatus> {
413
+ const lc = `${this.lc}[${this.getDelegateStatus.name}]`;
414
+ try {
415
+ if (logalot) { console.log(`${lc} starting...`); }
416
+
417
+ const { ib, gib } = getIbAndGib({ ibGibAddr: parentTjpAddr });
418
+ const parentIbGib: IbGib_V1 = { ib, gib };
419
+ const resGetLatest = await getLatestAddrs({
420
+ ibGibs: [parentIbGib],
421
+ space,
422
+ });
423
+
424
+ if (!resGetLatest.data?.latestAddrsMap) {
425
+ return { registered: false };
426
+ }
427
+
428
+ const latestAddr = resGetLatest.data.latestAddrsMap[parentTjpAddr];
429
+ if (!latestAddr) {
430
+ return { registered: false };
431
+ }
432
+
433
+ const resGet = await metaspace.get({ addr: latestAddr, space });
434
+ const latestParent = resGet.ibGibs?.at(0) as KeystoneIbGib_V1;
435
+ if (!latestParent || !latestParent.data) {
436
+ return { registered: false };
437
+ }
438
+
439
+ const delegates = latestParent.data.delegates || {};
440
+ const delegateInfo = delegates[delegateTjpAddr];
441
+
442
+ return {
443
+ registered: !!delegateInfo,
444
+ delegateInfo,
445
+ };
446
+ } catch (error) {
447
+ console.error(`${lc} ${extractErrorMsg(error)}`);
448
+ throw error;
449
+ } finally {
450
+ if (logalot) { console.log(`${lc} complete.`); }
451
+ }
452
+ }
453
+
239
454
  /**
240
455
  * Validates a genesis keystone.
241
456
  *
@@ -429,6 +644,7 @@ export class KeystoneService_V1 {
429
644
  revocationInfo,
430
645
  frameDetails,
431
646
  checkpointDetails,
647
+ ...(prevData.delegates ? { delegates: prevData.delegates } : {}),
432
648
  };
433
649
 
434
650
  // 7. Commit
@@ -555,6 +771,7 @@ export class KeystoneService_V1 {
555
771
  challengePools: finalPools,
556
772
  proofs: [proof], // The proof authorizes the structure change
557
773
  checkpointDetails,
774
+ ...(prevData.delegates ? { delegates: prevData.delegates } : {}),
558
775
  };
559
776
 
560
777
  // 7. Commit