signify-ts 0.3.0 → 0.4.1
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.
- package/README.md +18 -0
- package/dist/exports.d.ts +1 -0
- package/dist/exports.js +1 -0
- package/dist/keri/app/aiding.d.ts +20 -5
- package/dist/keri/app/aiding.js +15 -19
- package/dist/keri/app/clienting.d.ts +27 -24
- package/dist/keri/app/clienting.js +86 -92
- package/dist/keri/app/controller.d.ts +4 -1
- package/dist/keri/app/controller.js +7 -3
- package/dist/keri/app/coring.d.ts +8 -1
- package/dist/keri/app/coring.js +11 -0
- package/dist/keri/core/authing.d.ts +24 -5
- package/dist/keri/core/authing.js +188 -15
- package/dist/keri/core/eventing.js +1 -1
- package/dist/keri/core/httping.d.ts +3 -0
- package/dist/keri/core/httping.js +3 -0
- package/dist/keri/core/keeping.d.ts +98 -23
- package/dist/keri/core/keeping.js +124 -22
- package/dist/keri/core/keyState.d.ts +30 -3
- package/dist/keri/core/keyState.js +9 -1
- package/dist/keri/core/manager.d.ts +1 -1
- package/dist/keri/core/manager.js +3 -3
- package/dist/keri/end/ending.js +2 -1
- package/dist/types/keria-api-schema.d.ts +142 -209
- package/dist/types/keria-api-schema.js +5 -0
- package/package.json +5 -5
|
@@ -7,6 +7,7 @@ import { b } from "./core.js";
|
|
|
7
7
|
import { Cipher } from "./cipher.js";
|
|
8
8
|
import { Diger } from "./diger.js";
|
|
9
9
|
import { Prefixer } from "./prefixer.js";
|
|
10
|
+
import { Verfer } from "./verfer.js";
|
|
10
11
|
/**
|
|
11
12
|
* Creates IdentifierManager instances based on the algorithm and key indexes.
|
|
12
13
|
*/
|
|
@@ -155,15 +156,17 @@ export class SaltyIdentifierManager {
|
|
|
155
156
|
const digers = nsigners.signers.map((nsigner) => new Diger({ code: this.dcode }, nsigner.verfer.qb64b).qb64);
|
|
156
157
|
return [verfers, digers];
|
|
157
158
|
}
|
|
158
|
-
async sign(ser, indexed = true, indices = undefined, ondices = undefined) {
|
|
159
|
+
async sign(ser, indexed = true, indices = undefined, ondices = undefined, _rotated) {
|
|
159
160
|
const signers = this.creator.create(this.icodes, this.ncount, this.ncode, this.transferable, this.pidx, 0, this.kidx, false);
|
|
160
161
|
if (indexed) {
|
|
161
162
|
const sigers = [];
|
|
162
163
|
let i = 0;
|
|
163
164
|
for (const [j, signer] of signers.signers.entries()) {
|
|
164
|
-
if (indices
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
if (indices &&
|
|
166
|
+
indices.length > 0 &&
|
|
167
|
+
indices.length === signers.signers.length) {
|
|
168
|
+
i = indices[j]; // default indexing behavior of pulling index order from signer order
|
|
169
|
+
if (!Number.isInteger(i) || i < 0) {
|
|
167
170
|
throw new Error(`Invalid signing index = ${i}, not whole number.`);
|
|
168
171
|
}
|
|
169
172
|
}
|
|
@@ -171,19 +174,19 @@ export class SaltyIdentifierManager {
|
|
|
171
174
|
i = j;
|
|
172
175
|
}
|
|
173
176
|
let o = 0;
|
|
174
|
-
if
|
|
177
|
+
// if ondices are specified then the count and order should match the indices list
|
|
178
|
+
// even if a given ondex is "undefined" which means to ignore the ondex (dual indexed sig)
|
|
179
|
+
// for that given index.
|
|
180
|
+
if (ondices && ondices.length > 0) {
|
|
175
181
|
o = ondices[j];
|
|
176
|
-
if (
|
|
177
|
-
(typeof o == 'number' &&
|
|
178
|
-
typeof o != 'number' &&
|
|
179
|
-
o >= 0))) {
|
|
182
|
+
if (o !== undefined && (!Number.isInteger(o) || o < 0)) {
|
|
180
183
|
throw new Error(`Invalid ondex = ${o}, not whole number.`);
|
|
181
184
|
}
|
|
182
185
|
}
|
|
183
186
|
else {
|
|
184
187
|
o = i;
|
|
185
188
|
}
|
|
186
|
-
sigers.push(signer.sign(ser, i, o
|
|
189
|
+
sigers.push(signer.sign(ser, i, o === undefined ? true : false, o));
|
|
187
190
|
}
|
|
188
191
|
return sigers.map((siger) => siger.qb64);
|
|
189
192
|
}
|
|
@@ -251,7 +254,7 @@ export class RandyIdentifierManager {
|
|
|
251
254
|
const digers = nsigners.signers.map((nsigner) => new Diger({ code: this.dcode }, nsigner.verfer.qb64b).qb64);
|
|
252
255
|
return [verfers, digers];
|
|
253
256
|
}
|
|
254
|
-
async sign(ser, indexed = true, indices = undefined, ondices = undefined) {
|
|
257
|
+
async sign(ser, indexed = true, indices = undefined, ondices = undefined, _rotated) {
|
|
255
258
|
const signers = this.prxs.map((prx) => this.decrypter.decrypt(new Cipher({ qb64: prx }).qb64b, undefined, this.transferable));
|
|
256
259
|
if (indexed) {
|
|
257
260
|
const sigers = [];
|
|
@@ -269,17 +272,14 @@ export class RandyIdentifierManager {
|
|
|
269
272
|
let o = 0;
|
|
270
273
|
if (ondices != undefined) {
|
|
271
274
|
o = ondices[j];
|
|
272
|
-
if (
|
|
273
|
-
(typeof o == 'number' &&
|
|
274
|
-
typeof o != 'number' &&
|
|
275
|
-
o >= 0))) {
|
|
275
|
+
if (o !== undefined && (!Number.isInteger(o) || o < 0)) {
|
|
276
276
|
throw new Error(`Invalid ondex = ${o}, not whole number.`);
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
else {
|
|
280
280
|
o = i;
|
|
281
281
|
}
|
|
282
|
-
sigers.push(signer.sign(ser, i, o
|
|
282
|
+
sigers.push(signer.sign(ser, i, o === undefined ? true : false, o));
|
|
283
283
|
}
|
|
284
284
|
return sigers.map((siger) => siger.qb64);
|
|
285
285
|
}
|
|
@@ -292,11 +292,57 @@ export class RandyIdentifierManager {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Identifier manager for group identifiers.
|
|
297
|
+
*
|
|
298
|
+
* A group identifier does not have its own private signing keys. Instead, this
|
|
299
|
+
* manager maps group event signing indexes onto the local member AID (`mhab`)
|
|
300
|
+
* and delegates actual signing to that member's key manager.
|
|
301
|
+
*
|
|
302
|
+
* The central invariant is that indexed rotation signatures carry two
|
|
303
|
+
* positions:
|
|
304
|
+
*
|
|
305
|
+
* - `index` points to the signer's current key in the event's current key list
|
|
306
|
+
* (`k`), which SignifyTS derives from `states`.
|
|
307
|
+
* - `ondex` points to the prior establishment event's next digest list (`n`),
|
|
308
|
+
* proving that the current key was a precommitted key.
|
|
309
|
+
*
|
|
310
|
+
* `rstates` are the proposed next digest source for the new event. They are not
|
|
311
|
+
* the signer authorization set for the event being signed.
|
|
312
|
+
*/
|
|
295
313
|
export class GroupIdentifierManager {
|
|
314
|
+
/**
|
|
315
|
+
* Creates a manager for either a new group event or an existing group AID.
|
|
316
|
+
*
|
|
317
|
+
* `states` and `rstates` are app-level key state records used when creating
|
|
318
|
+
* a new group event. `keys` and `ndigs` are persisted group manager params
|
|
319
|
+
* used when loading an existing group. For an existing group, `ndigs` is
|
|
320
|
+
* expected to be the current establishment event's next digest list.
|
|
321
|
+
*
|
|
322
|
+
* During group inception there is no separate prior establishment event, so
|
|
323
|
+
* `gpndigs` starts as the same digest list as `gdigs`. During rotation,
|
|
324
|
+
* `gdigs` changes to the proposed next digests, while `gpndigs` stays
|
|
325
|
+
* fixed for `ondex` derivation.
|
|
326
|
+
*/
|
|
296
327
|
constructor(manager, mhab, states = undefined, rstates = undefined, keys = [], ndigs = []) {
|
|
297
328
|
var _a, _b;
|
|
329
|
+
/**
|
|
330
|
+
* Current group signing public keys for the event being built. During
|
|
331
|
+
* rotation these come from `states[*].k[0]` and define signature `index`.
|
|
332
|
+
*/
|
|
298
333
|
this.gkeys = [];
|
|
334
|
+
/**
|
|
335
|
+
* Proposed next digest list for the event being built. During rotation
|
|
336
|
+
* these come from `rstates[*].n[0]`, are returned from `rotate()`, and are
|
|
337
|
+
* serialized as `group.ndigs`.
|
|
338
|
+
*/
|
|
299
339
|
this.gdigs = [];
|
|
340
|
+
/**
|
|
341
|
+
* Prior next digest list from the current group establishment event. For
|
|
342
|
+
* rotations, this is the authorization commitment set used to derive
|
|
343
|
+
* `ondex`; it must remain separate from proposed next digests in `gdigs`.
|
|
344
|
+
*/
|
|
345
|
+
this.gpndigs = [];
|
|
300
346
|
this.algo = Algos.group;
|
|
301
347
|
this.manager = manager;
|
|
302
348
|
if (states != undefined) {
|
|
@@ -307,36 +353,92 @@ export class GroupIdentifierManager {
|
|
|
307
353
|
}
|
|
308
354
|
this.gkeys = (_a = states === null || states === void 0 ? void 0 : states.map((state) => state['k'][0])) !== null && _a !== void 0 ? _a : keys;
|
|
309
355
|
this.gdigs = (_b = rstates === null || rstates === void 0 ? void 0 : rstates.map((state) => state['n'][0])) !== null && _b !== void 0 ? _b : ndigs;
|
|
356
|
+
this.gpndigs = this.gdigs;
|
|
310
357
|
this.mhab = mhab;
|
|
311
358
|
this.signers = [];
|
|
312
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Returns the inception key material for the group event.
|
|
362
|
+
*
|
|
363
|
+
* Inception has no prior group establishment event. The current keys and
|
|
364
|
+
* proposed next digests are therefore returned directly from the manager's
|
|
365
|
+
* configured `states` and `rstates`.
|
|
366
|
+
*/
|
|
313
367
|
async incept() {
|
|
314
368
|
return [this.gkeys, this.gdigs];
|
|
315
369
|
}
|
|
316
370
|
/**
|
|
317
|
-
* Performs a multisig rotation
|
|
371
|
+
* Performs a multisig rotation.
|
|
372
|
+
*
|
|
373
|
+
* `states` supplies the current group signing keys for the event being
|
|
374
|
+
* signed. `rstates` supplies the proposed next key digests to put in the
|
|
375
|
+
* new event. The prior next digests used for rotation `ondex` lookup stay
|
|
376
|
+
* unchanged until KERIA accepts the new establishment event and returns an
|
|
377
|
+
* updated group state.
|
|
378
|
+
*
|
|
318
379
|
* @param _ncodes
|
|
319
380
|
* @param _transferable
|
|
320
381
|
* @param states
|
|
321
|
-
* @param rstates
|
|
322
|
-
* You should pass in the current key
|
|
382
|
+
* @param rstates
|
|
323
383
|
*/
|
|
324
384
|
async rotate(_ncodes, _transferable, states, rstates) {
|
|
325
385
|
this.gkeys = states.map((state) => state['k'][0]);
|
|
326
386
|
this.gdigs = rstates.map((state) => state['n'][0]);
|
|
327
387
|
return [this.gkeys, this.gdigs];
|
|
328
388
|
}
|
|
329
|
-
|
|
389
|
+
/**
|
|
390
|
+
* Signs for the group by delegating to the local member keeper.
|
|
391
|
+
*/
|
|
392
|
+
async sign(ser, indexed = true, _indices = undefined, _ondices = undefined, rotated = false) {
|
|
330
393
|
if (!this.mhab.state) {
|
|
331
394
|
throw new Error(`No state in mhab`);
|
|
332
395
|
}
|
|
333
396
|
const key = this.mhab['state']['k'][0];
|
|
334
|
-
|
|
397
|
+
// The event's current key list authorizes the signature's `index`.
|
|
335
398
|
const csi = this.gkeys.indexOf(key); // csi = current signing index (from current rotation event)
|
|
336
|
-
|
|
399
|
+
if (csi < 0) {
|
|
400
|
+
throw new Error(`Group signing key ${key} is not present in current group signing keys.`);
|
|
401
|
+
}
|
|
402
|
+
let pni; // prior next index exposed as signature `ondex`
|
|
403
|
+
if (rotated) {
|
|
404
|
+
// Rotation call sites must explicitly request prior-next exposure,
|
|
405
|
+
// dual indexed signatures with both an index (csi) and an ondex (pni)
|
|
406
|
+
pni = this.priorNextIndexForKey(key);
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// Inception and non-rotation signatures satisfy only the current
|
|
410
|
+
// signing threshold. The event's `n` field is a precommitment for a
|
|
411
|
+
// future rotation, not an `ondex` source.
|
|
412
|
+
pni = undefined;
|
|
413
|
+
}
|
|
414
|
+
if (pni !== undefined && pni < 0) {
|
|
415
|
+
throw new Error(`Group signing key ${key} cannot derive ondex from prior next digest list.`);
|
|
416
|
+
}
|
|
417
|
+
// Delegate the actual signature to the local member AID keeper while
|
|
418
|
+
// supplying group-level index and ondex positions.
|
|
337
419
|
const mkeeper = this.manager.get(this.mhab);
|
|
338
420
|
return await mkeeper.sign(ser, indexed, [csi], [pni]);
|
|
339
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Finds the prior next digest position that precommitted the current key.
|
|
424
|
+
*
|
|
425
|
+
* This mirrors KERIpy's exposed-prior-next behavior: for each prior next
|
|
426
|
+
* digest, hash the current verifier key using that digest's code and compare
|
|
427
|
+
* the result to the digest at that position. A match means the signer has
|
|
428
|
+
* exposed that precommitted key, and the matching position is the `ondex`.
|
|
429
|
+
*/
|
|
430
|
+
priorNextIndexForKey(key) {
|
|
431
|
+
const verfer = new Verfer({ qb64: key });
|
|
432
|
+
for (const [index, ndig] of this.gpndigs.entries()) {
|
|
433
|
+
const priorDiger = new Diger({ qb64: ndig });
|
|
434
|
+
const keyDigest = new Diger({ code: priorDiger.code }, verfer.qb64b)
|
|
435
|
+
.qb64;
|
|
436
|
+
if (keyDigest === priorDiger.qb64) {
|
|
437
|
+
return index;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return -1;
|
|
441
|
+
}
|
|
340
442
|
params() {
|
|
341
443
|
return {
|
|
342
444
|
mhab: this.mhab,
|
|
@@ -17,15 +17,39 @@ export type RandyKeyState = components['schemas']['RandyKeyState'];
|
|
|
17
17
|
/**
|
|
18
18
|
* Defining properties a multi-signature group identifier manager.
|
|
19
19
|
*/
|
|
20
|
-
export type GroupKeyState = components['schemas']['GroupKeyState']
|
|
20
|
+
export type GroupKeyState = Omit<components['schemas']['GroupKeyState'], 'mhab'> & {
|
|
21
|
+
mhab: HabState;
|
|
22
|
+
};
|
|
21
23
|
/**
|
|
22
24
|
* Defining properties for an external module identifier manager that uses externally managed keys such as in an HSM or a KMS system.
|
|
23
25
|
*/
|
|
24
26
|
export type ExternState = components['schemas']['ExternState'];
|
|
27
|
+
type SchemaHabState = components['schemas']['HabState'];
|
|
25
28
|
/**
|
|
26
|
-
* Defining properties of an identifier habitat,
|
|
29
|
+
* Defining properties of an identifier habitat, known as a Hab in KERIpy.
|
|
30
|
+
*
|
|
31
|
+
* Omitting `state` alone would erase the algo variants — `keyof` a union of disjoint objects is
|
|
32
|
+
* `never` — so they are re-spelled, which also points `group` at the local GroupKeyState above.
|
|
27
33
|
*/
|
|
28
|
-
|
|
34
|
+
type BaseHabState = Omit<SchemaHabState, 'state' | 'salty' | 'randy' | 'group' | 'extern'> & ({
|
|
35
|
+
salty: SaltyKeyState;
|
|
36
|
+
} | {
|
|
37
|
+
randy: RandyKeyState;
|
|
38
|
+
} | {
|
|
39
|
+
group: GroupKeyState;
|
|
40
|
+
} | {
|
|
41
|
+
extern: ExternState;
|
|
42
|
+
});
|
|
43
|
+
/** Multisig group whose inception is still collecting member signatures; no key state yet. */
|
|
44
|
+
export type PendingHabState = BaseHabState & {
|
|
45
|
+
state?: undefined;
|
|
46
|
+
};
|
|
47
|
+
/** Fully inceptioned identifier; key state present. */
|
|
48
|
+
export type HabState = BaseHabState & {
|
|
49
|
+
state: KeyState;
|
|
50
|
+
};
|
|
51
|
+
export declare function isAccepted(hab: HabState | PendingHabState): hab is HabState;
|
|
52
|
+
export declare function requireKeyState(hab: HabState | PendingHabState): KeyState;
|
|
29
53
|
export type Icp = components['schemas']['ICP_V_1'] | components['schemas']['ICP_V_2'];
|
|
30
54
|
export type Ixn = components['schemas']['IXN_V_1'] | components['schemas']['IXN_V_2'];
|
|
31
55
|
export type ExnV1 = components['schemas']['EXN_V_1'];
|
|
@@ -50,6 +74,7 @@ export type DoneOperation = components['schemas']['DoneOperation'];
|
|
|
50
74
|
export type CredentialOperation = components['schemas']['CredentialOperation'];
|
|
51
75
|
export type GroupOperation = components['schemas']['GroupOperation'];
|
|
52
76
|
export type DelegatorOperation = components['schemas']['DelegatorOperation'];
|
|
77
|
+
export type KelOperation = components['schemas']['KelOperation'];
|
|
53
78
|
export type PendingOOBIOperation = components['schemas']['PendingOOBIOperation'];
|
|
54
79
|
export type PendingQueryOperation = components['schemas']['PendingQueryOperation'];
|
|
55
80
|
export type PendingEndRoleOperation = components['schemas']['PendingEndRoleOperation'];
|
|
@@ -96,3 +121,5 @@ export type FailedGroupOperation = components['schemas']['FailedGroupOperation']
|
|
|
96
121
|
export type FailedDelegatorOperation = components['schemas']['FailedDelegatorOperation'];
|
|
97
122
|
export type FailedOperation = FailedOOBIOperation | FailedQueryOperation | FailedEndRoleOperation | FailedWitnessOperation | FailedDelegationOperation | FailedRegistryOperation | FailedLocSchemeOperation | FailedChallengeOperation | FailedExchangeOperation | FailedSubmitOperation | FailedDoneOperation | FailedCredentialOperation | FailedGroupOperation | FailedDelegatorOperation;
|
|
98
123
|
export type GenericOperation = OOBIOperation | QueryOperation | EndRoleOperation | WitnessOperation | DelegationOperation | RegistryOperation | LocSchemeOperation | ChallengeOperation | ExchangeOperation | SubmitOperation | DoneOperation | CredentialOperation | GroupOperation | DelegatorOperation;
|
|
124
|
+
export type EndRole = components['schemas']['EndRole'];
|
|
125
|
+
export {};
|
|
@@ -242,7 +242,7 @@ interface SignArgs {
|
|
|
242
242
|
verfers?: Array<Verfer> | undefined;
|
|
243
243
|
indexed?: boolean;
|
|
244
244
|
indices?: Array<number> | undefined;
|
|
245
|
-
ondices?: Array<number> | undefined;
|
|
245
|
+
ondices?: Array<number | undefined> | undefined;
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
248
|
* Manages key pair creation, retrieval, and message signing.
|
|
@@ -722,14 +722,14 @@ export class Manager {
|
|
|
722
722
|
let o;
|
|
723
723
|
if (ondices != undefined) {
|
|
724
724
|
o = ondices[idx];
|
|
725
|
-
if (o
|
|
726
|
-
throw new Error(`Invalid other signing index = {o}, not None or not whole number.`);
|
|
725
|
+
if (o !== undefined && (!Number.isInteger(o) || o < 0)) {
|
|
726
|
+
throw new Error(`Invalid other signing index = ${o}, not None or not whole number.`);
|
|
727
727
|
}
|
|
728
728
|
}
|
|
729
729
|
else {
|
|
730
730
|
o = i;
|
|
731
731
|
}
|
|
732
|
-
const only = o
|
|
732
|
+
const only = o === undefined;
|
|
733
733
|
sigers.push(signer.sign(ser, i, only, o));
|
|
734
734
|
});
|
|
735
735
|
return sigers;
|
package/dist/keri/end/ending.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Siger } from "../core/siger.js";
|
|
2
2
|
import { Cigar } from "../core/cigar.js";
|
|
3
|
+
import { HEADER_SIG } from "../core/httping.js";
|
|
3
4
|
export const FALSY = [false, 0, '?0', 'no', 'false', 'False', 'off'];
|
|
4
5
|
export const TRUTHY = [true, 1, '?1', 'yes', 'true', 'True', 'on'];
|
|
5
6
|
export class Signage {
|
|
@@ -77,7 +78,7 @@ export function signature(signages) {
|
|
|
77
78
|
}));
|
|
78
79
|
values.push(items.join(';'));
|
|
79
80
|
}
|
|
80
|
-
return new Headers([[
|
|
81
|
+
return new Headers([[HEADER_SIG, values.join(',')]]);
|
|
81
82
|
}
|
|
82
83
|
export function designature(value) {
|
|
83
84
|
const values = value.replace(' ', '').split(',');
|