@degenerate/sharedata 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { IShareDataInitialCryptoData, PersistedCreationConfig, ShareBlockType, ShareDataProofs } from '@degenerate/generic';
1
+ import { IAuthorizedSigner, IShareDataInitialCryptoData, PersistedCreationConfig, ShareBlockType, ShareDataProofs } from '@degenerate/generic';
2
2
  import { ShareData } from '../share-data/share-data';
3
3
  /**
4
4
  * The inputs a block builder needs to replay construction of a persisted
@@ -10,12 +10,18 @@ import { ShareData } from '../share-data/share-data';
10
10
  * - `initialCrypto` — the client-computed creation crypto, applied to the
11
11
  * in-construction block on the first proof lookup.
12
12
  * - `structuralProofs` — the per-purpose proof bundle, replayed in place of
13
- * a live signer so the rebuilt block carries byte-identical proofs.
13
+ * a live signer so the rebuilt block carries byte-identical proofs. This
14
+ * bundle also contains the delegate registration proofs (keyed by their
15
+ * `delegate:<key>:<ids>` purpose).
16
+ * - `authorizedSigners` — the delegated-signer grant tuples to re-apply via
17
+ * `addAuthorizedSigner`, so the rebuilt block re-derives the same signer
18
+ * set (and canonical hash) it had live. Empty for non-delegating blocks.
14
19
  */
15
20
  export interface ShareBlockBuilderInput {
16
21
  creationConfig: PersistedCreationConfig;
17
22
  initialCrypto: IShareDataInitialCryptoData;
18
23
  structuralProofs: ShareDataProofs;
24
+ authorizedSigners: IAuthorizedSigner[];
19
25
  }
20
26
  /**
21
27
  * Rebuilds a ShareData of a single block type from its persisted recipe.
@@ -1 +1 @@
1
- {"version":3,"file":"block-factory-registry.d.ts","sourceRoot":"","sources":["../../src/persistence/block-factory-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,cAAc,EACd,eAAe,EAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAgBrD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,sBAAsB;IACnC,cAAc,EAAE,uBAAuB,CAAC;IACxC,aAAa,EAAE,2BAA2B,CAAC;IAC3C,gBAAgB,EAAE,eAAe,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,SAAS,CAAC;AAQ7E;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAClC,WAAW,cAAc,EACzB,SAAS,iBAAiB,KAC3B,IAEF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC7B,WAAW,cAAc,KAC1B,iBAAiB,GAAG,SAAoC,CAAC;AAE5D,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,GAAI,WAAW,cAAc,KAAG,OACtC,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAO,IAE1C,CAAC"}
1
+ {"version":3,"file":"block-factory-registry.d.ts","sourceRoot":"","sources":["../../src/persistence/block-factory-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,iBAAiB,EACjB,2BAA2B,EAC3B,uBAAuB,EACvB,cAAc,EACd,eAAe,EAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAgBrD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,sBAAsB;IACnC,cAAc,EAAE,uBAAuB,CAAC;IACxC,aAAa,EAAE,2BAA2B,CAAC;IAC3C,gBAAgB,EAAE,eAAe,CAAC;IAClC,iBAAiB,EAAE,iBAAiB,EAAE,CAAC;CAC1C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,SAAS,CAAC;AAQ7E;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAClC,WAAW,cAAc,EACzB,SAAS,iBAAiB,KAC3B,IAEF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC7B,WAAW,cAAc,KAC1B,iBAAiB,GAAG,SAAoC,CAAC;AAE5D,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,GAAI,WAAW,cAAc,KAAG,OACtC,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAO,IAE1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"deserialize-share-data.d.ts","sourceRoot":"","sources":["../../src/persistence/deserialize-share-data.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAYrD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,OAAO,KAAG,SAgHxD,CAAC"}
1
+ {"version":3,"file":"deserialize-share-data.d.ts","sourceRoot":"","sources":["../../src/persistence/deserialize-share-data.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAYrD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,OAAO,KAAG,SAqHxD,CAAC"}
@@ -55,6 +55,7 @@ const deserializeShareData = (snapshot) => {
55
55
  creationConfig: parsed.creationConfig,
56
56
  initialCrypto: parsed.initialCrypto,
57
57
  structuralProofs: parsed.structuralProofs,
58
+ authorizedSigners: parsed.authorizedSigners,
58
59
  });
59
60
  // Replay the transaction log in recorded order.
60
61
  for (const entry of parsed.transactionLog) {
@@ -68,8 +69,12 @@ const deserializeShareData = (snapshot) => {
68
69
  // verification, so the proposer-identity gate (the same one
69
70
  // addTransaction enforces live) must run on replay too. Checked first
70
71
  // so a swapped key fails as a not-authorized error rather than a
71
- // signature mismatch.
72
- if (entry.proof.publicKey !== block.creationPublicKey) {
72
+ // signature mismatch. Uses the same widened predicate as the live gate:
73
+ // the creation key for any function, or a delegate for its granted
74
+ // function (`entry.proof.purpose` is the function id). The signer set was
75
+ // re-derived from re-verified registration proofs during construction
76
+ // above, so an injected grant with no valid proof never reaches here.
77
+ if (!block.isAuthorizedSigner(entry.proof.publicKey, entry.proof.purpose)) {
73
78
  throw new generic_1.ShareDataTransactionNotAuthorizedError(parsed.id, entry.proof.publicKey);
74
79
  }
75
80
  // Re-verify the transaction proof against the block at its pre-entry
@@ -1 +1 @@
1
- {"version":3,"file":"serialize-share-data.d.ts","sourceRoot":"","sources":["../../src/persistence/serialize-share-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EAEjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAUrD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,GAC3B,WAAW,cAAc,EACzB,gBAAgB,uBAAuB,EACvC,OAAO,SAAS,EAChB,gBAAgB,oBAAoB,EAAE,KACvC,kBAgCF,CAAC"}
1
+ {"version":3,"file":"serialize-share-data.d.ts","sourceRoot":"","sources":["../../src/persistence/serialize-share-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EAEjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAUrD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB,GAC3B,WAAW,cAAc,EACzB,gBAAgB,uBAAuB,EACvC,OAAO,SAAS,EAChB,gBAAgB,oBAAoB,EAAE,KACvC,kBAoCF,CAAC"}
@@ -51,6 +51,10 @@ const serializeShareData = (blockType, creationConfig, block, transactionLog) =>
51
51
  },
52
52
  creationConfig,
53
53
  structuralProofs,
54
+ // The grant tuples re-applied via `addAuthorizedSigner` on replay; the
55
+ // matching registration proofs are already carried in `structuralProofs`
56
+ // (keyed by their `delegate:` purpose). Empty for non-delegating blocks.
57
+ authorizedSigners: block.authorizedSigners,
54
58
  transactionLog,
55
59
  expectedCurrentState: block.currentState,
56
60
  expectedCreationHash: block.creationHash,
@@ -1 +1 @@
1
- {"version":3,"file":"default-share-data-string.config.d.ts","sourceRoot":"","sources":["../../../../src/share-data/helpers/config/default-share-data-string.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAIvD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,gBAe1C,CAAC"}
1
+ {"version":3,"file":"default-share-data-string.config.d.ts","sourceRoot":"","sources":["../../../../src/share-data/helpers/config/default-share-data-string.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAIvD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,gBAoB1C,CAAC"}
@@ -16,6 +16,11 @@ exports.defaultShareDataStringConfig = [
16
16
  { key: 'currentState', process: stringify_1.stringify },
17
17
  { key: 'cryptoProofs', process: get_array_string_1.getArrayString },
18
18
  { key: 'structuralProofs', process: get_array_string_1.getArrayString },
19
+ // Folds the delegated authorized-signer set into the signed structure so a
20
+ // tampered snapshot cannot widen authorization without breaking the hash
21
+ // chain. `getArrayString([])` returns '', so blocks with no delegates hash
22
+ // identically to before this field existed — existing proofs stay valid.
23
+ { key: 'authorizedSigners', process: get_array_string_1.getArrayString },
19
24
  { key: 'events', process: get_array_string_1.getArrayString },
20
25
  { key: 'functions', process: get_array_string_1.getArrayString },
21
26
  { key: 'rules', process: get_array_string_1.getArrayString },
@@ -1,4 +1,4 @@
1
- import { IShareData, IShareDataEvent, IShareFunction, IShareRuleApplied, IShareRuleEvalutionResult, IShareDataTransactionHistory, IShareDataCryptoProof, EllipticalCurvesSigning, IShareDataInitialCryptoData } from '@degenerate/generic';
1
+ import { IShareData, IShareDataEvent, IShareFunction, IShareRuleApplied, IShareRuleEvalutionResult, IShareDataTransactionHistory, IShareDataCryptoProof, EllipticalCurvesSigning, IShareDataInitialCryptoData, IAuthorizedSigner } from '@degenerate/generic';
2
2
  /**
3
3
  * This contains the interface for the share data object
4
4
  */
@@ -18,6 +18,7 @@ export declare class ShareData {
18
18
  private _signingCurve;
19
19
  private _lastUpdated;
20
20
  private _structuralProofs;
21
+ private _authorizedSigners;
21
22
  /**
22
23
  * This is the constructor for the share data object
23
24
  * @param id the id of the share data
@@ -90,6 +91,14 @@ export declare class ShareData {
90
91
  * This gets the structure proofs for the share data
91
92
  */
92
93
  get structuralProofs(): IShareDataCryptoProof[];
94
+ /**
95
+ * This gets the delegated authorized-signer grants for the share data.
96
+ * Each grant is a `{ publicKey, functionIds }` pair: a key the owner has
97
+ * delegated the right to propose transactions for, scoped to those function
98
+ * ids. The block owner (`creationPublicKey`) is always authorized and is
99
+ * NOT listed here.
100
+ */
101
+ get authorizedSigners(): IAuthorizedSigner[];
93
102
  /**
94
103
  * This gets the transaction history for the share block
95
104
  */
@@ -113,6 +122,49 @@ export declare class ShareData {
113
122
  * @param rule the rule to add to the share block
114
123
  */
115
124
  addRule(rule: IShareRuleApplied, cryptoProof: IShareDataCryptoProof): void;
125
+ /**
126
+ * Delegates `signerPublicKey` the right to propose runtime transactions for
127
+ * the given `functionIds` (and ONLY those — least privilege). Creation-time
128
+ * only: rejected once the block is locked. The registration is part of the
129
+ * signed structure, so a delegate cannot be injected into a tampered
130
+ * snapshot without invalidating the chain.
131
+ *
132
+ * Three gates, in order:
133
+ * 1. Owner-identity: `registrationProof.publicKey === creationPublicKey`.
134
+ * ONLY the block owner may delegate — this is the check `addFunction` /
135
+ * `addRule` deliberately omit (the HTTP layer supplies it there). It
136
+ * must live here because the security of the widened transaction gate
137
+ * (see {@link isAuthorizedSigner}) rests on "the allow-list was
138
+ * authorized by the owner." It also blocks transitive delegation: a
139
+ * delegate's key is never the creation key, so a delegate can never
140
+ * register further delegates.
141
+ * 2. Grant binding: the proof's `purpose` must equal
142
+ * `buildDelegatePurpose(signerPublicKey, functionIds)`. The proof signs
143
+ * over the PRE-append state (the grant is not yet folded into
144
+ * `_authorizedSigners`), so the purpose is the only thing that attests
145
+ * to the exact `(key, functionIds)` grant — without this a tampered
146
+ * snapshot could widen a delegate's scope without breaking the
147
+ * signature.
148
+ * 3. Structural verification against the current (pre-append) state,
149
+ * reusing the same machinery `addFunction` / `addRule` use; folds the
150
+ * proof into the hash chain and verifies the owner's signature.
151
+ *
152
+ * Throws {@link ShareDataIsLockedError} if locked,
153
+ * {@link ShareDataDelegationNotAuthorizedError} for a non-owner registrant /
154
+ * empty grant / mismatched purpose, and
155
+ * {@link ShareDataStructuralProofFailedError} if the proof does not verify.
156
+ */
157
+ addAuthorizedSigner(signerPublicKey: string, functionIds: string[], registrationProof: IShareDataCryptoProof): void;
158
+ /**
159
+ * Whether `publicKey` is authorized to propose a transaction for
160
+ * `functionId` on this block. The block owner (`creationPublicKey`) is
161
+ * always authorized for every function; a delegated key is authorized only
162
+ * for the function ids its registration granted. This is the single
163
+ * predicate behind the proposer-identity gate, called from both the live
164
+ * mutation path ({@link addTransaction}) and the persistence replay path so
165
+ * the two cannot drift.
166
+ */
167
+ isAuthorizedSigner(publicKey: string, functionId: string): boolean;
116
168
  /**
117
169
  * Append a pre-validated transaction to the history. Pass `transactionTime`
118
170
  * when the caller needs the recorded timestamp to be deterministic — for
@@ -159,12 +211,12 @@ export declare class ShareData {
159
211
  * This binds the proof to *this* function so a proof minted for one
160
212
  * function can't be replayed to drive another even if the proposed
161
213
  * state would satisfy both functions' rules.
162
- * 3. The proof's signer must be authorized for this block —
163
- * `proof.publicKey === creationPublicKey`. Signature validity alone
164
- * only proves *someone* signed the transition; this binds the
165
- * *authorized* someone (the block's creation key, the same key the
166
- * HTTP create/delete ACL authorizes against). Without it any valid
167
- * keypair could sign a legal transition.
214
+ * 3. The proof's signer must be authorized for this block AND this
215
+ * function — the creation key for any function, or a delegated key for
216
+ * the function ids its registration granted (`isAuthorizedSigner`).
217
+ * Signature validity alone only proves *someone* signed the transition;
218
+ * this binds the *authorized* someone. Without it any valid keypair
219
+ * could sign a legal transition.
168
220
  * 4. The proof must verify against the current state AND `proposedData`
169
221
  * (closes the amount-replay hole — see
170
222
  * `verifyTransactionProposalProof`).
@@ -1 +1 @@
1
- {"version":3,"file":"share-data.d.ts","sourceRoot":"","sources":["../../src/share-data/share-data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"share-data.d.ts","sourceRoot":"","sources":["../../src/share-data/share-data.ts"],"names":[],"mappings":"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"}
@@ -30,6 +30,7 @@ class ShareData {
30
30
  this._cryptoProofs = [];
31
31
  this._signingCurve = signingCurve;
32
32
  this._structuralProofs = [];
33
+ this._authorizedSigners = [];
33
34
  }
34
35
  /**
35
36
  * This initializes the cryptographic properties of the share data
@@ -139,6 +140,16 @@ class ShareData {
139
140
  get structuralProofs() {
140
141
  return this._structuralProofs;
141
142
  }
143
+ /**
144
+ * This gets the delegated authorized-signer grants for the share data.
145
+ * Each grant is a `{ publicKey, functionIds }` pair: a key the owner has
146
+ * delegated the right to propose transactions for, scoped to those function
147
+ * ids. The block owner (`creationPublicKey`) is always authorized and is
148
+ * NOT listed here.
149
+ */
150
+ get authorizedSigners() {
151
+ return this._authorizedSigners;
152
+ }
142
153
  /**
143
154
  * This gets the transaction history for the share block
144
155
  */
@@ -189,6 +200,78 @@ class ShareData {
189
200
  this._structuralProofs.push(cryptoProof);
190
201
  this._rules.push(rule);
191
202
  }
203
+ /**
204
+ * Delegates `signerPublicKey` the right to propose runtime transactions for
205
+ * the given `functionIds` (and ONLY those — least privilege). Creation-time
206
+ * only: rejected once the block is locked. The registration is part of the
207
+ * signed structure, so a delegate cannot be injected into a tampered
208
+ * snapshot without invalidating the chain.
209
+ *
210
+ * Three gates, in order:
211
+ * 1. Owner-identity: `registrationProof.publicKey === creationPublicKey`.
212
+ * ONLY the block owner may delegate — this is the check `addFunction` /
213
+ * `addRule` deliberately omit (the HTTP layer supplies it there). It
214
+ * must live here because the security of the widened transaction gate
215
+ * (see {@link isAuthorizedSigner}) rests on "the allow-list was
216
+ * authorized by the owner." It also blocks transitive delegation: a
217
+ * delegate's key is never the creation key, so a delegate can never
218
+ * register further delegates.
219
+ * 2. Grant binding: the proof's `purpose` must equal
220
+ * `buildDelegatePurpose(signerPublicKey, functionIds)`. The proof signs
221
+ * over the PRE-append state (the grant is not yet folded into
222
+ * `_authorizedSigners`), so the purpose is the only thing that attests
223
+ * to the exact `(key, functionIds)` grant — without this a tampered
224
+ * snapshot could widen a delegate's scope without breaking the
225
+ * signature.
226
+ * 3. Structural verification against the current (pre-append) state,
227
+ * reusing the same machinery `addFunction` / `addRule` use; folds the
228
+ * proof into the hash chain and verifies the owner's signature.
229
+ *
230
+ * Throws {@link ShareDataIsLockedError} if locked,
231
+ * {@link ShareDataDelegationNotAuthorizedError} for a non-owner registrant /
232
+ * empty grant / mismatched purpose, and
233
+ * {@link ShareDataStructuralProofFailedError} if the proof does not verify.
234
+ */
235
+ addAuthorizedSigner(signerPublicKey, functionIds, registrationProof) {
236
+ if (this._isLocked) {
237
+ throw new generic_1.ShareDataIsLockedError(this._id, generic_1.ShareDataTypes.AUTHORIZATION);
238
+ }
239
+ // Gate 1: owner-identity. Only the creation key may delegate.
240
+ if (registrationProof.publicKey !== this._creationPublicKey) {
241
+ throw new generic_1.ShareDataDelegationNotAuthorizedError(this._id, registrationProof.publicKey);
242
+ }
243
+ // Normalize so the purpose, the stored grant, and the canonical hash all
244
+ // agree byte-for-byte on live-create and on replay.
245
+ const normalizedFunctionIds = Array.from(new Set(functionIds.map((id) => id.trim()).filter((id) => id.length > 0))).sort();
246
+ if (normalizedFunctionIds.length === 0) {
247
+ throw new generic_1.ShareDataDelegationNotAuthorizedError(this._id, registrationProof.publicKey);
248
+ }
249
+ // Gate 2: the proof must bind this exact (key, functionIds) grant.
250
+ const expectedPurpose = (0, generic_1.buildDelegatePurpose)(signerPublicKey, normalizedFunctionIds);
251
+ if (registrationProof.purpose !== expectedPurpose) {
252
+ throw new generic_1.ShareDataDelegationNotAuthorizedError(this._id, registrationProof.publicKey);
253
+ }
254
+ // Gate 3: structural verification (pre-append, mirroring addFunction).
255
+ this.verifyStructuralProof(registrationProof);
256
+ this._structuralProofs.push(registrationProof);
257
+ this._authorizedSigners.push({ publicKey: signerPublicKey, functionIds: normalizedFunctionIds });
258
+ }
259
+ /**
260
+ * Whether `publicKey` is authorized to propose a transaction for
261
+ * `functionId` on this block. The block owner (`creationPublicKey`) is
262
+ * always authorized for every function; a delegated key is authorized only
263
+ * for the function ids its registration granted. This is the single
264
+ * predicate behind the proposer-identity gate, called from both the live
265
+ * mutation path ({@link addTransaction}) and the persistence replay path so
266
+ * the two cannot drift.
267
+ */
268
+ isAuthorizedSigner(publicKey, functionId) {
269
+ if (publicKey === this._creationPublicKey) {
270
+ return true;
271
+ }
272
+ const grant = this._authorizedSigners.find((s) => s.publicKey === publicKey);
273
+ return grant !== undefined && grant.functionIds.includes(functionId);
274
+ }
192
275
  /**
193
276
  * Append a pre-validated transaction to the history. Pass `transactionTime`
194
277
  * when the caller needs the recorded timestamp to be deterministic — for
@@ -254,12 +337,12 @@ class ShareData {
254
337
  * This binds the proof to *this* function so a proof minted for one
255
338
  * function can't be replayed to drive another even if the proposed
256
339
  * state would satisfy both functions' rules.
257
- * 3. The proof's signer must be authorized for this block —
258
- * `proof.publicKey === creationPublicKey`. Signature validity alone
259
- * only proves *someone* signed the transition; this binds the
260
- * *authorized* someone (the block's creation key, the same key the
261
- * HTTP create/delete ACL authorizes against). Without it any valid
262
- * keypair could sign a legal transition.
340
+ * 3. The proof's signer must be authorized for this block AND this
341
+ * function — the creation key for any function, or a delegated key for
342
+ * the function ids its registration granted (`isAuthorizedSigner`).
343
+ * Signature validity alone only proves *someone* signed the transition;
344
+ * this binds the *authorized* someone. Without it any valid keypair
345
+ * could sign a legal transition.
263
346
  * 4. The proof must verify against the current state AND `proposedData`
264
347
  * (closes the amount-replay hole — see
265
348
  * `verifyTransactionProposalProof`).
@@ -289,10 +372,14 @@ class ShareData {
289
372
  if (proof.purpose !== functionId) {
290
373
  throw new generic_1.ShareDataTransactionProofFailedError(this._id);
291
374
  }
292
- // Gate 3: bind the proposer identity. Only the block's creation key may
293
- // authorize runtime mutations. Checked before the (more expensive)
294
- // signature verification so an unauthorized signer fails fast.
295
- if (proof.publicKey !== this._creationPublicKey) {
375
+ // Gate 3: bind the proposer identity. The block's creation key may
376
+ // authorize any function; a delegated key may authorize only the
377
+ // function ids it was granted (see addAuthorizedSigner / isAuthorizedSigner).
378
+ // `functionId` equals `proof.purpose` here (enforced by Gate 2), so the
379
+ // scope check is against the function the proof is bound to. Checked
380
+ // before the (more expensive) signature verification so an unauthorized
381
+ // signer fails fast.
382
+ if (!this.isAuthorizedSigner(proof.publicKey, functionId)) {
296
383
  throw new generic_1.ShareDataTransactionNotAuthorizedError(this._id, proof.publicKey);
297
384
  }
298
385
  // Gate 4: proof binds current state + proposed state + chain position.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@degenerate/sharedata",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "This contains the ShareData Adaptive Framework Ecosystem (SAFE) network core code",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -49,10 +49,10 @@
49
49
  "url": "https://github.com/syncrude/safe/issues"
50
50
  },
51
51
  "homepage": "https://github.com/syncrude/safe#readme",
52
- "gitHead": "c33ed2f06679f5bd76c2eccf7054212c1820a014",
52
+ "gitHead": "9453d9ab785e03fd01eb5b408ed0e3ca22baefd5",
53
53
  "dependencies": {
54
- "@degenerate/generic": "^0.3.0",
55
- "@degenerate/rules": "^0.3.0",
54
+ "@degenerate/generic": "^0.4.0",
55
+ "@degenerate/rules": "^0.4.0",
56
56
  "zod": "^4.4.3"
57
57
  },
58
58
  "engines": {