From 5996d11597ddd9d078aca493c96c383e109d9085 Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Sun, 26 Jan 2025 21:46:34 -0700 Subject: [PATCH 1/6] refactor: align object names with KERIpy and add function docs --- README.md | 2 +- docker-compose.yaml | 2 +- .../integration-scripts/modules/bip39_shim.ts | 15 +- .../integration-scripts/multisig-join.test.ts | 3 +- .../utils/multisig-utils.ts | 2 +- .../integration-scripts/utils/test-util.ts | 2 +- src/exports.ts | 2 +- src/keri/app/aiding.ts | 12 +- src/keri/app/clienting.ts | 11 +- src/keri/app/controller.ts | 4 +- src/keri/app/credentialing.ts | 14 +- src/keri/app/exchanging.ts | 6 +- src/keri/core/core.ts | 156 ++++++++++-- src/keri/core/eventing.ts | 22 +- src/keri/core/keeping.ts | 239 +++++++++++------- src/keri/core/{state.ts => keyState.ts} | 23 +- src/keri/core/manager.ts | 223 ++++++++++++---- src/keri/core/salter.ts | 37 +++ src/keri/core/serder.ts | 16 +- src/keri/core/vdring.ts | 8 +- test/app/aiding.test.ts | 6 +- test/app/credentialing.test.ts | 6 +- test/app/registry.test.ts | 16 +- test/app/test-utils.ts | 16 +- test/core/manager.test.ts | 46 ++-- test/core/prefixer.test.ts | 6 +- test/core/saider.test.ts | 9 +- test/core/utils.test.ts | 6 +- 28 files changed, 639 insertions(+), 271 deletions(-) rename src/keri/core/{state.ts => keyState.ts} (67%) diff --git a/README.md b/README.md index 0320e545..0a188508 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ The integration tests depends on a local instance of KERIA, vLEI-Server and Witn docker compose up --wait ``` -If successful, it should print someting like this: +If successful, it should print something like this: ```bash $ docker compose up --wait diff --git a/docker-compose.yaml b/docker-compose.yaml index 2c640091..6bcacd51 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -21,7 +21,7 @@ services: - 7723:7723 keria: - image: ${KERIA_IMAGE:-weboftrust/keria}:${KERIA_IMAGE_TAG:-0.2.0-dev6} + image: ${KERIA_IMAGE:-weboftrust/keria}:${KERIA_IMAGE_TAG:-0.2.0-rc1} environment: KERI_AGENT_CORS: 1 <<: *python-env diff --git a/examples/integration-scripts/modules/bip39_shim.ts b/examples/integration-scripts/modules/bip39_shim.ts index 9642e63b..1dd2eb8f 100644 --- a/examples/integration-scripts/modules/bip39_shim.ts +++ b/examples/integration-scripts/modules/bip39_shim.ts @@ -1,7 +1,14 @@ import { mnemonicToSeedSync, generateMnemonic } from 'bip39'; -import { Diger, Signer, MtrDex, Keeper, KeeperResult, Algos } from 'signify-ts'; +import { + Diger, + Signer, + MtrDex, + IdentifierManager, + IdentifierManagerResult, + Algos, +} from 'signify-ts'; -export class BIP39Shim implements Keeper { +export class BIP39Shim implements IdentifierManager { private icount: number; private ncount: number; private dcode: string | undefined; @@ -49,7 +56,7 @@ export class BIP39Shim implements Keeper { return keys; } - async incept(transferable: boolean): Promise { + async incept(transferable: boolean): Promise { const signers = this.keys(this.icount, this.kidx, transferable); const verfers = signers.map((signer) => signer.verfer.qb64); @@ -70,7 +77,7 @@ export class BIP39Shim implements Keeper { // eslint-disable-next-line @typescript-eslint/no-explicit-any count: any, //number, transferable: boolean - ): Promise { + ): Promise { const signers = this.keys( this.ncount, this.kidx + this.icount, diff --git a/examples/integration-scripts/multisig-join.test.ts b/examples/integration-scripts/multisig-join.test.ts index ef23df98..e7e289b9 100644 --- a/examples/integration-scripts/multisig-join.test.ts +++ b/examples/integration-scripts/multisig-join.test.ts @@ -164,6 +164,7 @@ describe('multisig-join', () => { waitOperation(client3, opOobi5), ]); + // rotate single sig const [rotateResult1, rotateResult2] = await Promise.all([ client1.identifiers().rotate(nameMember1), client2.identifiers().rotate(nameMember2), @@ -309,7 +310,7 @@ describe('multisig-join', () => { .exchanges() .send( nameMember1, - nameMultisig, + 'multisig', aid1, '/multisig/rot', { gid: serder1.pre, smids, rmids }, diff --git a/examples/integration-scripts/utils/multisig-utils.ts b/examples/integration-scripts/utils/multisig-utils.ts index df6fbd59..7cb99777 100644 --- a/examples/integration-scripts/utils/multisig-utils.ts +++ b/examples/integration-scripts/utils/multisig-utils.ts @@ -9,7 +9,7 @@ import signify, { messagize, } from 'signify-ts'; import { getStates, waitAndMarkNotification } from './test-util'; -import { HabState } from '../../../src/keri/core/state'; +import { HabState } from '../../../src/keri/core/keyState'; import assert from 'assert'; export interface AcceptMultisigInceptArgs { diff --git a/examples/integration-scripts/utils/test-util.ts b/examples/integration-scripts/utils/test-util.ts index f22b1950..dc1a71e3 100644 --- a/examples/integration-scripts/utils/test-util.ts +++ b/examples/integration-scripts/utils/test-util.ts @@ -9,7 +9,7 @@ import signify, { Tier, } from 'signify-ts'; import { RetryOptions, retry } from './retry'; -import { HabState } from '../../../src/keri/core/state'; +import { HabState } from '../../../src/keri/core/keyState'; import assert from 'assert'; import { resolveEnvironment } from './resolve-env'; diff --git a/src/exports.ts b/src/exports.ts index a5093c3d..27cf71d3 100644 --- a/src/exports.ts +++ b/src/exports.ts @@ -39,6 +39,6 @@ export * from './keri/core/signer'; export * from './keri/core/tholder'; export * from './keri/core/utils'; export * from './keri/core/verfer'; -export * from './keri/core/state'; +export * from './keri/core/keyState'; export * from './keri/end/ending'; diff --git a/src/keri/app/aiding.ts b/src/keri/app/aiding.ts index 8287db3a..bcb4cb3a 100644 --- a/src/keri/app/aiding.ts +++ b/src/keri/app/aiding.ts @@ -1,13 +1,13 @@ import { Tier } from '../core/salter'; import { Algos } from '../core/manager'; import { incept, interact, reply, rotate } from '../core/eventing'; -import { b, Ilks, Serials, Versionage } from '../core/core'; +import { b, Ilks, Serials, Vrsn_1_0 } from '../core/core'; import { Tholder } from '../core/tholder'; import { MtrDex } from '../core/matter'; import { Serder } from '../core/serder'; import { parseRangeHeaders } from '../core/httping'; -import { KeyManager } from '../core/keeping'; -import { HabState } from '../core/state'; +import { IdentifierManagerFactory } from '../core/keeping'; +import { HabState } from '../core/keyState'; /** Arguments required to create an identfier */ export interface CreateIdentiferArgs { @@ -63,7 +63,7 @@ export interface IdentifierDeps { headers?: Headers ): Promise; pidx: number; - manager: KeyManager | null; + manager: IdentifierManagerFactory | null; } /** @@ -225,7 +225,7 @@ export class Identifier { wits: wits, cnfg: [], data: data, - version: Versionage, + version: Vrsn_1_0, kind: Serials.JSON, code: dcode, intive: false, @@ -240,7 +240,7 @@ export class Identifier { wits: wits, cnfg: [], data: data, - version: Versionage, + version: Vrsn_1_0, kind: Serials.JSON, code: dcode, intive: false, diff --git a/src/keri/app/clienting.ts b/src/keri/app/clienting.ts index df1d7356..4a4a8bee 100644 --- a/src/keri/app/clienting.ts +++ b/src/keri/app/clienting.ts @@ -1,6 +1,6 @@ import { Authenticater } from '../core/authing'; import { HEADER_SIG_TIME } from '../core/httping'; -import { ExternalModule, KeyManager } from '../core/keeping'; +import { ExternalModule, IdentifierManagerFactory } from '../core/keeping'; import { Tier } from '../core/salter'; import { Identifier } from './aiding'; @@ -30,7 +30,10 @@ class State { } } -/** SignifyClient */ +/** + * An in-memory key manager that can connect to a KERIA Agent and use it to + * receive messages and act as a proxy for multi-signature operations and delegation operations. + */ export class SignifyClient { public controller: Controller; public url: string; @@ -38,7 +41,7 @@ export class SignifyClient { public pidx: number; public agent: Agent | null; public authn: Authenticater | null; - public manager: KeyManager | null; + public manager: IdentifierManagerFactory | null; public tier: Tier; public bootUrl: string; public exteralModules: ExternalModule[]; @@ -147,7 +150,7 @@ export class SignifyClient { if (this.controller.serder.ked.s == 0) { await this.approveDelegation(); } - this.manager = new KeyManager( + this.manager = new IdentifierManagerFactory( this.controller.salter, this.exteralModules ); diff --git a/src/keri/app/controller.ts b/src/keri/app/controller.ts index bdfcc7ba..57697fd6 100644 --- a/src/keri/app/controller.ts +++ b/src/keri/app/controller.ts @@ -5,7 +5,7 @@ import { Diger } from '../core/diger'; import { incept, rotate, interact } from '../core/eventing'; import { Serder } from '../core/serder'; import { Tholder } from '../core/tholder'; -import { Ilks, b, Serials, Versionage } from '../core/core'; +import { Ilks, b, Serials, Vrsn_1_0 } from '../core/core'; import { Verfer } from '../core/verfer'; import { Encrypter } from '../core/encrypter'; import { Decrypter } from '../core/decrypter'; @@ -173,7 +173,7 @@ export class Controller { dig: this.serder.ked['d'], sn: sn, data: [anchor], - version: Versionage, + version: Vrsn_1_0, kind: Serials.JSON, }); return [this.signer.sign(this.serder.raw, 0).qb64]; diff --git a/src/keri/app/credentialing.ts b/src/keri/app/credentialing.ts index 53e2a51a..89f423bd 100644 --- a/src/keri/app/credentialing.ts +++ b/src/keri/app/credentialing.ts @@ -5,11 +5,11 @@ import { b, d, Dict, - Ident, + Protocols, Ilks, Serials, versify, - Versionage, + Vrsn_1_0, } from '../core/core'; import { Saider } from '../core/saider'; import { Serder } from '../core/serder'; @@ -20,7 +20,7 @@ import { serializeIssExnAttachment, } from '../core/utils'; import { Operation } from './coring'; -import { HabState } from '../core/state'; +import { HabState } from '../core/keyState'; /** Types of credentials */ export class CredentialTypes { @@ -357,7 +357,7 @@ export class Credentials { }); const [, acdc] = Saider.saidify({ - v: versify(Ident.ACDC, undefined, Serials.JSON, 0), + v: versify(Protocols.ACDC, undefined, Serials.JSON, 0), d: '', u: args.u, i: args.i ?? hab.prefix, @@ -369,7 +369,7 @@ export class Credentials { }); const [, iss] = Saider.saidify({ - v: versify(Ident.KERI, undefined, Serials.JSON, 0), + v: versify(Protocols.KERI, undefined, Serials.JSON, 0), t: Ilks.iss, d: '', i: acdc.d, @@ -437,7 +437,7 @@ export class Credentials { const hab = await this.client.identifiers().get(name); const pre: string = hab.prefix; - const vs = versify(Ident.KERI, undefined, Serials.JSON, 0); + const vs = versify(Protocols.KERI, undefined, Serials.JSON, 0); const dt = datetime ?? new Date().toISOString().replace('Z', '000+00:00'); @@ -641,7 +641,7 @@ export class Registries { sn: sn + 1, data: data, dig: dig, - version: Versionage, + version: Vrsn_1_0, kind: Serials.JSON, }); const keeper = this.client.manager!.get(hab); diff --git a/src/keri/app/exchanging.ts b/src/keri/app/exchanging.ts index cb9f9e4b..eb7b41ce 100644 --- a/src/keri/app/exchanging.ts +++ b/src/keri/app/exchanging.ts @@ -1,11 +1,11 @@ import { SignifyClient } from './clienting'; -import { b, d, Dict, Ident, Ilks, Serials, versify } from '../core/core'; +import { b, d, Dict, Protocols, Ilks, Serials, versify } from '../core/core'; import { Serder } from '../core/serder'; import { nowUTC } from '../core/utils'; import { Pather } from '../core/pather'; import { Counter, CtrDex } from '../core/counter'; import { Saider } from '../core/saider'; -import { HabState } from '../core/state'; +import { HabState } from '../core/keyState'; /** * Exchanges @@ -155,7 +155,7 @@ export function exchange( modifiers?: Dict, embeds?: Dict ): [Serder, Uint8Array] { - const vs = versify(Ident.KERI, undefined, Serials.JSON, 0); + const vs = versify(Protocols.KERI, undefined, Serials.JSON, 0); const ilk = Ilks.exn; const dt = date !== undefined diff --git a/src/keri/core/core.ts b/src/keri/core/core.ts index ee75d997..e029190e 100644 --- a/src/keri/core/core.ts +++ b/src/keri/core/core.ts @@ -1,12 +1,21 @@ +/** + * Serialization types supported by the KERI and ACDC protocols and this Signify implementation. + */ export enum Serials { JSON = 'JSON', } -export enum Ident { +/** + * Protocol types supported by the KERI and ACDC protocols and this Signify implementation. + */ +export enum Protocols { KERI = 'KERI', ACDC = 'ACDC', } +/** + * Represents a protocol version of the KERI, ACDC, or other protocol specified in a CESR version string. + */ export class Version { public major: number; public minor: number; @@ -17,8 +26,14 @@ export class Version { } } -export const Versionage = new Version(); +/** + * Denotes version 1.0 of a protocol. + */ +export const Vrsn_1_0 = new Version(); +/** + * Types of KERI and ACDC events. + */ export const Ilks = { icp: 'icp', rot: 'rot', @@ -36,6 +51,9 @@ export const Ilks = { brv: 'brv', }; +/** + * Field labels for an inception event in V1 of the KERI protocol. + */ export const IcpLabels = [ 'v', 'i', @@ -50,6 +68,9 @@ export const IcpLabels = [ 'a', ]; +/** + * Field labels for an delegated inception event in V1 of the KERI protocol. + */ export const DipLabels = [ 'v', 'i', @@ -65,6 +86,9 @@ export const DipLabels = [ 'di', ]; +/** + * Field labels for a rotation event in V1 of the KERI protocol. + */ export const RotLabels = [ 'v', 'i', @@ -79,6 +103,10 @@ export const RotLabels = [ 'ba', 'a', ]; + +/** + * Field labels for an delegated rotation event in V1 of the KERI protocol. + */ export const DrtLabels = [ 'v', 'i', @@ -93,8 +121,15 @@ export const DrtLabels = [ 'ba', 'a', ]; + +/** + * Field labels for an interaction event in V1 of the KERI protocol. + */ export const IxnLabels = ['v', 'i', 's', 't', 'p', 'a']; +/** + * Field labels for a key state notice event in V1 of the KERI protocol. + */ export const KsnLabels = [ 'v', 'i', @@ -116,12 +151,18 @@ export const KsnLabels = [ 'r', ]; +/** + * Field labels for a reply event in V1 of the KERI protocol. + */ export const RpyLabels = ['v', 't', 'd', 'dt', 'r', 'a']; -const encoder = new TextEncoder(); -const decoder = new TextDecoder(); - +/** + * Full size of a CESR version string in bytes. + */ export const VERFULLSIZE = 17; +/** + * Minimum number of bytes a CESR parser must sniff to receive the entire version string. + */ export const MINSNIFFSIZE = 12 + VERFULLSIZE; export const MINSIGSIZE = 4; @@ -130,32 +171,38 @@ export const MINSIGSIZE = 4; // const version_pattern1 = `KERI\(\?P\[0\-9a\-f\]\)\(\?P\[0\-9a\-f\]\)\ // (\?P\[A\-Z\]\{4\}\)\(\?P\[0\-9a\-f\]\{6\}\)_` +/** + * Regular expression for a version 1 CESR object version string. + */ export const VEREX = '(KERI|ACDC)([0-9a-f])([0-9a-f])([A-Z]{4})([0-9a-f]{6})_'; +/** + * An interface for a basic dictionary type keyed by string with any value type. + * Mimics the Python dictionary type. + */ export interface Dict { [id: string]: TValue; } -// Regex pattern matching - /** - * @description This function is use to deversify the version - * Here we will use regex to to validate and extract serialization kind,size and version - * @param {string} versionString version string - * @return {Object} contaning prototol (KERI or ACDC), kind of serialization like cbor,json,mgpk - * version = version of object ,size = raw size integer + * Parses a serialization version string into the protocol, protocol version, serialization type, and raw size. + * Uses regex matchers to validate and extract version string parts. + * @param {string} versionString version string + * @return {Object} tuple of prototol (KERI or ACDC), kind of serialization like cbor,json, or mgpk, + * protocol version, and raw size of serialization */ export function deversify( versionString: string -): [Ident, Serials, Version, string] { +): [Protocols, Serials, Version, string] { let kind; let size; let proto; - const version = Versionage; + const version = Vrsn_1_0; // we need to identify how to match the buffers pattern ,like we do regex matching for strings const re = new RegExp(VEREX); + // Regex pattern matching const match = re.exec(versionString); if (match) { @@ -169,33 +216,48 @@ export function deversify( if (!Object.values(Serials).includes(kind as Serials)) { throw new Error(`Invalid serialization kind = ${kind}`); } - if (!Object.values(Ident).includes(proto as Ident)) { + if (!Object.values(Protocols).includes(proto as Protocols)) { throw new Error(`Invalid serialization kind = ${kind}`); } const ta = kind as keyof typeof Serials; kind = Serials[ta]; - const pa = proto as keyof typeof Ident; - proto = Ident[pa]; + const pa = proto as keyof typeof Protocols; + proto = Protocols[pa]; return [proto, kind, version, size]; } throw new Error(`Invalid version string = ${versionString}`); } +/** + * Returns a valid KERI serialization version string specifying the protocol, + * protocol version, serialization type, and raw byte size of the serialization. + * + * Defaults to version 1.0. + * @param ident + * @param version + * @param kind + * @param size + */ export function versify( - ident: Ident = Ident.KERI, + ident: Protocols = Protocols.KERI, version?: Version, kind: Serials = Serials.JSON, size: number = 0 ) { - version = version == undefined ? Versionage : version; - - return `${ident}${version.major.toString( - 16 - )}${version.minor.toString()}${kind}${size.toString(16).padStart(6, '0')}_`; + version = version == undefined ? Vrsn_1_0 : version; // defaults to Version 1 + const major = version.major.toString(16); // hex digits + const minor = version.minor.toString(16); // hex digits + // raw size in hex digits zero padded to 6 characters + const rawSize = size.toString(16).padStart(6, '0'); + const terminationChar = '_'; // v1 termination character + return `${ident}${major}${minor}${kind}${rawSize}${terminationChar}`; } +/** + * Map allowing lookup of Base64URLSafe characters by index. + */ export const B64ChrByIdx = new Map([ [0, 'A'], [1, 'B'], @@ -263,10 +325,18 @@ export const B64ChrByIdx = new Map([ [63, '_'], ]); +/** + * Map allowing lookup of Base64URLSafe index by character. + */ export const B64IdxByChr = new Map( Array.from(B64ChrByIdx, (entry) => [entry[1], entry[0]]) ); +/** + * Converts an integer to a Base64URLSafe encoded string, left padded as specified. + * @param i integer to convert + * @param l minimum length of Base64 digits left padded with Base64 0 == 'A' character. + */ export function intToB64(i: number, l = 1): string { let out = ''; while (l != 0) { @@ -285,11 +355,20 @@ export function intToB64(i: number, l = 1): string { return out; } +/** + * Converts an integer to a Base64URLSafe encoded string to a byte array, left padded as specified. + * @param i integer to convert + * @param l minimum length of Base64 digits left padded with Base64 0 == 'A' character. + */ export function intToB64b(n: number, l: number = 1): Uint8Array { const s = intToB64(n, l); return b(s); } +/** + * Converts a Base64URLSafe encoded string to an integer. + * @param s string to convert + */ export function b64ToInt(s: string): number { if (s.length == 0) { throw new Error('Empty string, conversion undefined.'); @@ -304,14 +383,32 @@ export function b64ToInt(s: string): number { return i; } +// Built in encoder and decoder for converting to and from UTF-8 strings and Uint8Array byte arrays. +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +/** + * Converts a UTF-8 string to bytes. + * Output is an encoded array of bytes. Assumes UTF-8 encoding. + * @param s string to be encoded as an array of bytes + */ export function b(s?: string): Uint8Array { return encoder.encode(s); } +/** + * Convert bytes to UTF-8 string. + * @param u array of bytes to be converted to UTF-8 string. + */ export function d(u?: Uint8Array): string { return decoder.decode(u); } +/** + * Concatenates two byte arrays together in a new byte array. + * @param one first byte array to be concatenated + * @param two second byte array to be concatenated + */ export function concat(one: Uint8Array, two: Uint8Array): Uint8Array { const out = new Uint8Array(one.length + two.length); out.set(one); @@ -319,6 +416,19 @@ export function concat(one: Uint8Array, two: Uint8Array): Uint8Array { return out; } +/** + * Converts a big-endian byte array into an integer. + * + * @param array - A `Uint8Array` of bytes representing a big-endian integer. + * @returns The integer represented by the byte array. + * + * Example: + * readInt(Uint8Array([0x01, 0x02, 0x03])) // returns 66051 + * + * How it works: + * - The function interprets the array as a big-endian number. + * - Each byte is added to the integer after shifting the previous value left by 8 bits (multiplying by 256). + */ export function readInt(array: Uint8Array) { let value = 0; for (let i = 0; i < array.length; i++) { diff --git a/src/keri/core/eventing.ts b/src/keri/core/eventing.ts index 3130b159..04fab984 100644 --- a/src/keri/core/eventing.ts +++ b/src/keri/core/eventing.ts @@ -2,12 +2,12 @@ import { b, concat, Dict, - Ident, + Protocols, Ilks, Serials, versify, Version, - Versionage, + Vrsn_1_0, } from './core'; import { Tholder } from './tholder'; import { CesrNumber } from './number'; @@ -61,7 +61,7 @@ export function rotate({ kind = undefined, intive = true, }: RotateArgs) { - const vs = versify(Ident.KERI, version, kind, 0); + const vs = versify(Protocols.KERI, version, kind, 0); const _ilk = ilk; if (_ilk != Ilks.rot && _ilk != Ilks.drt) { throw new Error(`Invalid ilk = ${ilk} for rot or drt.`); @@ -76,7 +76,7 @@ export function rotate({ if (isith == undefined) { _isit = Math.max(1, Math.ceil(keys.length / 2)); } else { - _isit = isith as number; + _isit = isith as number; // TODO this type as number does not make sense when isith is a string containing weighted thresholds } const tholder = new Tholder({ sith: _isit }); @@ -84,6 +84,7 @@ export function rotate({ throw new Error(`Invalid sith = ${tholder.num} less than 1.`); } if (tholder.size > keys.length) { + // TODO this error should say that the threshold has not been met throw new Error(`Invalid sith = ${tholder.num} for keys = ${keys}`); } @@ -107,7 +108,10 @@ export function rotate({ throw new Error(`Invalid sith = ${ntholder.num} less than 1.`); } if (ntholder.size > _ndigs.length) { - throw new Error(`Invalid sith = ${ntholder.num} for ndigs = ${ndigs}`); + // TODO this error should say that the threshold has not been met + throw new Error( + `Signing threshold failure: ${keys.length} number of signers not equal to or greater than sith = ${tholder.size} for keys = ${keys}` + ); } let _wits: Array; @@ -289,13 +293,13 @@ export function incept({ wits, cnfg, data, - version = Versionage, + version = Vrsn_1_0, kind = Serials.JSON, code, intive = false, delpre, }: InceptArgs) { - const vs = versify(Ident.KERI, version, kind, 0); + const vs = versify(Protocols.KERI, version, kind, 0); const ilk = delpre == undefined ? Ilks.icp : Ilks.dip; const sner = new CesrNumber({}, 0); @@ -528,7 +532,7 @@ interface InteractArgs { export function interact(args: InteractArgs): Serder { let { pre, dig, sn, data, version, kind } = args; - const vs = versify(Ident.KERI, version, kind, 0); + const vs = versify(Protocols.KERI, version, kind, 0); const ilk = Ilks.ixn; const sner = new CesrNumber({}, sn); @@ -560,7 +564,7 @@ export function reply( version: Version | undefined, kind: Serials = Serials.JSON ) { - const vs = versify(Ident.KERI, version, kind, 0); + const vs = versify(Protocols.KERI, version, kind, 0); if (data == undefined) { data = {}; } diff --git a/src/keri/core/keeping.ts b/src/keri/core/keeping.ts index 9dba85ef..4f12d7ed 100644 --- a/src/keri/core/keeping.ts +++ b/src/keri/core/keeping.ts @@ -9,11 +9,18 @@ import { Cipher } from './cipher'; import { Diger } from './diger'; import { Prefixer } from './prefixer'; import { Signer } from './signer'; -import { HabState, State } from './state'; +import { + ExternState, + GroupState, + HabState, + RandyState, + SaltyState, + KeyState, +} from './keyState'; /** External module definition */ export interface ExternalModuleType { - new (pidx: number, args: KeeperParams): Keeper; + new (pidx: number, args: IdentifierManagerParams): IdentifierManager; } export interface ExternalModule { @@ -22,14 +29,14 @@ export interface ExternalModule { module: ExternalModuleType; } -export type KeeperResult = [string[], string[]]; +export type IdentifierManagerResult = [string[], string[]]; export type SignResult = string[]; -export interface KeeperParams { +export interface IdentifierManagerParams { [key: string]: unknown; } -export interface SaltyParams extends KeeperParams { +export interface SaltyManagerParams extends IdentifierManagerParams { pidx: number; kidx: number; tier: Tier; @@ -41,27 +48,33 @@ export interface SaltyParams extends KeeperParams { sxlt: string | undefined; } -export interface RandyParams extends KeeperParams { +export interface RandyManagerParams extends IdentifierManagerParams { nxts?: string[]; prxs?: string[]; transferable: boolean; } -export interface GroupParams extends KeeperParams { +export interface GroupManagerParams extends IdentifierManagerParams { mhab: HabState; } -export interface Keeper { +/** + * Interface for KERI identifier (prefix) creation, rotation, and signing. + * @param T Type of the key keeper + */ +export interface IdentifierManager< + T extends IdentifierManagerParams = IdentifierManagerParams, +> { algo: Algos; signers: Signer[]; params(): T; - incept(transferable: boolean): Promise; + incept(transferable: boolean): Promise; rotate( ncodes: string[], transferable: boolean, - states?: State[], - rstates?: State[] - ): Promise; + states?: KeyState[], + rstates?: KeyState[] + ): Promise; sign( ser: Uint8Array, indexed?: boolean, @@ -70,9 +83,18 @@ export interface Keeper { ): Promise; } -export class KeyManager { +/** + * Creates IdentifierManager instances based on the algorithm and key indexes. + */ +export class IdentifierManagerFactory { private modules: Record = {}; + /** + * Creates a factory for generating IdentifierManagers. Requires a salt to be specified. + * Allows external key management modules to be configured. + * @param salter + * @param externalModules + */ constructor( private salter: Salter, externalModules: ExternalModule[] = [] @@ -84,10 +106,16 @@ export class KeyManager { } } + /** + * + * @param algo + * @param pidx + * @param kargs + */ new(algo: Algos, pidx: number, kargs: any) { switch (algo) { case Algos.salty: - return new SaltyKeeper( + return new SaltyIdentifierManager( this.salter!, pidx, kargs['kidx'], @@ -105,7 +133,7 @@ export class KeyManager { kargs['sxlt'] ); case Algos.randy: - return new RandyKeeper( + return new RandyIdentifierManager( this.salter!, kargs['code'], kargs['count'], @@ -119,7 +147,7 @@ export class KeyManager { kargs['nxts'] ); case Algos.group: - return new GroupKeeper( + return new GroupIdentifierManager( this, kargs['mhab'], kargs['states'], @@ -142,68 +170,91 @@ export class KeyManager { } } - get(aid: HabState): Keeper { - if (aid[Algos.salty]) { - const kargs = aid[Algos.salty]; - return new SaltyKeeper( - this.salter, - kargs['pidx'], - kargs['kidx'], - kargs['tier'], - kargs['transferable'], - kargs['stem'], - undefined, - undefined, - kargs['icodes'], - undefined, - undefined, - kargs['ncodes'], - kargs['dcode'], - undefined, - kargs['sxlt'] - ); - } else if (aid[Algos.randy]) { - const pre = new Prefixer({ qb64: aid['prefix'] }); - const kargs = aid[Algos.randy]!; - return new RandyKeeper( - this.salter, - undefined, - undefined, - undefined, - pre.transferable, - undefined, - undefined, - [], - undefined, - kargs['prxs'], - kargs['nxts'] - ); - } else if (aid[Algos.group]) { - const kargs = aid[Algos.group]; - return new GroupKeeper( - this, - kargs['mhab'], - undefined, - undefined, - kargs['keys'], - kargs['ndigs'] - ); - } else if (aid[Algos.extern]) { - const kargs = aid[Algos.extern]; - const typ = kargs.extern_type; - if (typ in this.modules) { - const mod = new this.modules[typ](kargs['pidx'], kargs); - return mod; - } else { - throw new Error(`unsupported external module type ${typ}`); + /** + * Generates an algorithm-specific IdentifierManager instance with correct keys based on + * the indexes provided by the HabState. + * @param aid HabState with the algorithm and key indexes + * @returns IdentifierManager instance + */ + get(aid: HabState): IdentifierManager { + const algo = aid[Algos.salty] + ? Algos.salty + : aid[Algos.randy] + ? Algos.randy + : aid[Algos.group] + ? Algos.group + : aid[Algos.extern] + ? Algos.extern + : undefined; + if (!algo) { + throw new Error('No algo specified'); + } + let kargs = aid[algo]; + if (!kargs) { + throw new Error('No kargs found in HabState'); + } + switch (algo) { + case Algos.salty: + kargs = kargs as SaltyState; + return new SaltyIdentifierManager( + this.salter, + kargs.pidx, + kargs.kidx, + kargs.tier, + kargs.transferable, + kargs.stem, + undefined, + undefined, + kargs.icodes, + undefined, + undefined, + kargs.ncodes, + kargs.dcode, + undefined, + kargs.sxlt + ); + case Algos.randy: + kargs = kargs as RandyState; + return new RandyIdentifierManager( + this.salter, + undefined, + undefined, + undefined, + new Prefixer({ qb64: aid['prefix'] }).transferable, + undefined, + undefined, + [], + undefined, + kargs.prxs, + kargs.nxts + ); + case Algos.group: + kargs = kargs as GroupState; + return new GroupIdentifierManager( + this, + kargs.mhab, + undefined, + undefined, + kargs.keys, + kargs.ndigs + ); + case Algos.extern: { + kargs = kargs as ExternState; + const typ = kargs.extern_type; + if (typ in this.modules) { + const mod = new this.modules[typ](kargs.pidx, kargs); + return mod; + } else { + throw new Error(`unsupported external module type ${typ}`); + } } - } else { - throw new Error(`Algo not allowed yet`); + default: + throw new Error('Algo not allowed yet'); } } } -export class SaltyKeeper implements Keeper { +export class SaltyIdentifierManager implements IdentifierManager { private aeid: string; private encrypter: Encrypter; private decrypter: Decrypter; @@ -298,7 +349,7 @@ export class SaltyKeeper implements Keeper { ).signers; } - params(): SaltyParams { + params(): SaltyManagerParams { return { sxlt: this.sxlt, pidx: this.pidx, @@ -312,7 +363,7 @@ export class SaltyKeeper implements Keeper { }; } - async incept(transferable: boolean): Promise { + async incept(transferable: boolean): Promise { this.transferable = transferable; this.kidx = 0; @@ -445,7 +496,7 @@ export class SaltyKeeper implements Keeper { } } -export class RandyKeeper implements Keeper { +export class RandyIdentifierManager implements IdentifierManager { private salter: Salter; private code: string; private count: number; @@ -515,7 +566,7 @@ export class RandyKeeper implements Keeper { ); } - params(): RandyParams { + params(): RandyManagerParams { return { nxts: this.nxts, prxs: this.prxs, @@ -523,7 +574,7 @@ export class RandyKeeper implements Keeper { }; } - async incept(transferable: boolean): Promise { + async incept(transferable: boolean): Promise { this.transferable = transferable; const signers = this.creator.create( @@ -560,7 +611,7 @@ export class RandyKeeper implements Keeper { async rotate( ncodes: string[], transferable: boolean - ): Promise { + ): Promise { this.ncodes = ncodes; this.transferable = transferable; this.prxs = this.nxts; @@ -651,8 +702,8 @@ export class RandyKeeper implements Keeper { } } -export class GroupKeeper implements Keeper { - private manager: KeyManager; +export class GroupIdentifierManager implements IdentifierManager { + private manager: IdentifierManagerFactory; private mhab: HabState; private gkeys: string[] = []; private gdigs: string[] = []; @@ -660,10 +711,10 @@ export class GroupKeeper implements Keeper { public signers: Signer[]; constructor( - manager: KeyManager, + manager: IdentifierManagerFactory, mhab: HabState, - states: State[] | undefined = undefined, - rstates: State[] | undefined = undefined, + states: KeyState[] | undefined = undefined, + rstates: KeyState[] | undefined = undefined, keys: string[] = [], ndigs: string[] = [] ) { @@ -682,16 +733,24 @@ export class GroupKeeper implements Keeper { this.signers = []; } - async incept(): Promise { + async incept(): Promise { return [this.gkeys, this.gdigs]; } + /** + * Performs a multisig rotation + * @param _ncodes + * @param _transferable + * @param states + * @param rstates key state records for the prior establishment event indicating next key digests. + * You should pass in the current key + */ async rotate( _ncodes: string[], _transferable: boolean, - states: State[], - rstates: State[] - ): Promise { + states: KeyState[], + rstates: KeyState[] + ): Promise { this.gkeys = states.map((state) => state['k'][0]); this.gdigs = rstates.map((state) => state['n'][0]); return [this.gkeys, this.gdigs]; @@ -705,8 +764,8 @@ export class GroupKeeper implements Keeper { const key = this.mhab['state']['k'][0]; const ndig = this.mhab['state']['n'][0]; - const csi = this.gkeys!.indexOf(key); - const pni = this.gdigs!.indexOf(ndig); + const csi = this.gkeys!.indexOf(key); // csi = current signing index (from current rotation event) + const pni = this.gdigs!.indexOf(ndig); // pni = prior next index (from last establishment event) const mkeeper = this.manager.get(this.mhab); return await mkeeper.sign(ser, indexed, [csi], [pni]); diff --git a/src/keri/core/state.ts b/src/keri/core/keyState.ts similarity index 67% rename from src/keri/core/state.ts rename to src/keri/core/keyState.ts index 14ae6047..12b47f74 100644 --- a/src/keri/core/state.ts +++ b/src/keri/core/keyState.ts @@ -1,7 +1,7 @@ import { Algos } from './manager'; import { Tier } from './salter'; -export interface State { +export interface KeyState { vn: [number, number]; i: string; s: string; @@ -26,7 +26,18 @@ export interface EstablishmentState { s: string; } -export interface SaltyState { +/** + * Marker interface for state configuring an IdentifierManager. + */ +export interface IdentifierManagerState {} + +/** + * Interface defining configuration parameters for a SaltyIdentifierManager + */ +export interface SaltyState extends IdentifierManagerState { + /** + * Encrypted + */ sxlt: string; pidx: number; kidx: number; @@ -38,18 +49,18 @@ export interface SaltyState { transferable: boolean; } -export interface RandyState { +export interface RandyState extends IdentifierManagerState { prxs: string[]; nxts: string[]; } -export interface GroupState { +export interface GroupState extends IdentifierManagerState { mhab: HabState; keys: string[]; ndigs: string[]; } -export interface ExternState { +export interface ExternState extends IdentifierManagerState { extern_type: string; pidx: number; [key: string]: unknown; @@ -59,7 +70,7 @@ export interface HabState { name: string; prefix: string; transferable: boolean; - state: State; + state: KeyState; windexes: unknown[]; icp_dt: string; [Algos.salty]?: SaltyState; diff --git a/src/keri/core/manager.ts b/src/keri/core/manager.ts index dbbb8f2d..6b40b7ee 100644 --- a/src/keri/core/manager.ts +++ b/src/keri/core/manager.ts @@ -9,6 +9,13 @@ import { Cigar } from './cigar'; import { Siger } from './siger'; import { b } from './core'; +/** + * Kinds of key pair generation algorithms. + * Salty is deterministic based on a salt and stem. + * Randy is random. + * Group is a multi-signature group algorithm indicating keys are retrieved from a group member which will be either Salty or Randy. + * Extern is an external key pair algorithm indicating keys are provided by an external source such as an HSM. + */ export enum Algos { randy = 'randy', salty = 'salty', @@ -16,31 +23,93 @@ export enum Algos { extern = 'extern', } +/** + * Lot (set) of public keys as an ordered list with indexes and the time created. + * Indexes refer to the index of the ordered sequence of keys in an establishment event (inception or rotation). + * Assumes the same length for each set of keys across all PubLot instances used for a given identifier. + */ class PubLot { - public pubs: Array = new Array(); // list qb64 public keys. - public ridx: number = 0; // index of rotation (est event) that uses public key set - public kidx: number = 0; // index of key in sequence of public keys - public dt: string = ''; // datetime ISO8601 when key set created + /** + * List of fully qualified, Base64 encoded public keys. Defaults to empty. + */ + public pubs: Array = new Array(); + /** + * Rotation index; index of rotation (est event) that uses this public key set. + * The index of the key set for an inception event is 0. + */ + public ridx: number = 0; + /** + * Key index; index of the starting key in the key set for this lot in sequence + * with reference to all public keys for the identifier. + * For example, if each set (PubLot.pubs) has 3 keys then ridx 2 has kidx of 2*3 = 6. + * Defaults to 0. + */ + public kidx: number = 0; + /** + * Datetime of when key set created formatted as an ISO 8601 compliant string. + */ + public dt: string = ''; } +/** + * Prefix's public key situation (set of public keys). + */ class PreSit { - public old: PubLot = new PubLot(); //previous publot - public new: PubLot = new PubLot(); //newly current publot - public nxt: PubLot = new PubLot(); //next public publot + /** + * Previous publot; previous public key set. + */ + public old: PubLot = new PubLot(); + /** + * New, current publot; current public key set. + */ + public new: PubLot = new PubLot(); + /** + * Next public publot + */ + public nxt: PubLot = new PubLot(); } +/** + * Identifier prefix parameters for creating new key pairs. + */ class PrePrm { - public pidx: number = 0; // prefix index for this keypair sequence - public algo: Algos = Algos.salty; // salty default uses indices and salt to create new key pairs - public salt: string = ''; // empty salt used for salty algo. - public stem: string = ''; // default unique path stem for salty algo - public tier: string = ''; // security tier for stretch index salty algo + /** + * Prefix index for this keypair sequence. + */ + public pidx: number = 0; + /** + * Key generation algorithm type. + * Defaults to Salty. + * Salty default uses indices and salt to create new key pairs. + */ + public algo: Algos = Algos.salty; + /** + * Used for salty algo. Defaults to empty. Unused for randy algo. + */ + public salt: string = ''; + /** + * Default unique path prefix used by the salty algo during key generation. + */ + public stem: string = ''; + /** + * Security tier for stretch index; used by the salty algo. + */ + public tier: string = ''; } +/** + * An identifier prefix's public key set (list) at a given rotation index ridx. + */ class PubSet { - pubs: Array = new Array(); // list qb64 public keys. + /** + * List of fully qualified, Base64 encoded public keys. + */ + pubs: Array = new Array(); } +/** + * + */ class PubPath { path: string = ''; code: string = ''; @@ -73,7 +142,21 @@ class Keys { } } +/** + * Interface for creating a key pair based on an algorithm. + */ export interface Creator { + /** + * Creates a key pair + * @param codes list of derivation codes one per key pair to create + * @param count count of key pairs to create if codes not provided + * @param code derivation code to use for count key pairs if codes not provided + * @param transferable true means use transferable derivation code. Otherwise, non-transferable derivation code. + * @param pidx prefix index for this keypair sequence + * @param ridx rotation index for this key pair set + * @param kidx starting key index for this key pair set + * @param temp true means use temp stretch otherwise use time set by tier for streching + */ create( codes: Array | undefined, count: number, @@ -84,8 +167,20 @@ export interface Creator { kidx: number, temp: boolean ): Keys; + + /** + * Salt used for key pair generation. + * Used only for Salty key creation. + */ salt: string; + /** + * String prefix used to stretch the prefix, salt, and seed into the key pair. + * Used only for Salty key creation. + */ stem: string; + /** + * Security tier used during stretching. + */ tier: Tier; } @@ -123,8 +218,19 @@ export class RandyCreator implements Creator { } } +/** + * Deterministically creates a key pair based on combining a salt with a path stretch algorithm. + * The salt is randomized if not provided. + */ export class SaltyCreator implements Creator { + /** + * The salter used to create the key pair. Contains the private key. + */ public salter: Salter; + /** + * Key material prefix used during key stretching. + * @private + */ private readonly _stem: string; constructor( salt: string | undefined = undefined, @@ -165,7 +271,7 @@ export class SaltyCreator implements Creator { } codes.forEach((code, idx) => { - // Previuos definition of path + // Previous definition of path // let path = this.stem + pidx.toString(16) + ridx.toString(16) + (kidx+idx).toString(16) const path = this.stem == '' @@ -282,6 +388,9 @@ interface SignArgs { ondices?: Array | undefined; } +/** + * Manages key pair creation, retrieval, and message signing. + */ export class Manager { private _seed?: string; private _salt?: string; @@ -340,6 +449,9 @@ export class Manager { return this._seed; } + /** + * qb64 auth encrypt id prefix + */ get aeid(): string | undefined { return this.ks.getGbls('aeid'); } @@ -450,22 +562,23 @@ export class Manager { seed != undefined ? new Decrypter({}, b(seed)) : undefined; } - incept({ - icodes = undefined, - icount = 1, - icode = MtrDex.Ed25519_Seed, - ncodes = undefined, - ncount = 1, - ncode = MtrDex.Ed25519_Seed, - dcode = MtrDex.Blake3_256, - algo = undefined, - salt = undefined, - stem = undefined, - tier = undefined, - rooted = true, - transferable = true, - temp = false, - }: ManagerInceptArgs): [Array, Array] { + incept(mgrIcpArgs: ManagerInceptArgs): [Array, Array] { + let { + icodes = undefined, + icount = 1, + icode = MtrDex.Ed25519_Seed, + ncodes = undefined, + ncount = 1, + ncode = MtrDex.Ed25519_Seed, + dcode = MtrDex.Blake3_256, + algo = undefined, + salt = undefined, + stem = undefined, + tier = undefined, + rooted = true, + transferable = true, + temp = false, + } = mgrIcpArgs; if (rooted && algo == undefined) { algo = this.algo; } @@ -704,16 +817,17 @@ export class Manager { } } - rotate({ - pre, - ncodes = undefined, - ncount = 1, - ncode = MtrDex.Ed25519_Seed, - dcode = MtrDex.Blake3_256, - transferable = true, - temp = false, - erase = true, - }: RotateArgs): [Array, Array] { + rotate(rotateArgs: RotateArgs): [Array, Array] { + let { + pre, + ncodes = undefined, + ncount = 1, + ncode = MtrDex.Ed25519_Seed, + dcode = MtrDex.Blake3_256, + transferable = true, + temp = false, + erase = true, + } = rotateArgs; const pp = this.ks.getPrms(pre); if (pp == undefined) { throw new Error(`Attempt to rotate nonexistent pre=${pre}.`); @@ -840,14 +954,15 @@ export class Manager { return [verfers, digers]; } - sign({ - ser, - pubs = undefined, - verfers = undefined, - indexed = true, - indices = undefined, - ondices = undefined, - }: SignArgs) { + sign(signArgs: SignArgs) { + let { + ser, + pubs = undefined, + verfers = undefined, + indexed = true, + indices = undefined, + ondices = undefined, + } = signArgs; const signers = new Array(); if (pubs == undefined && verfers == undefined) { @@ -980,6 +1095,9 @@ export function riKey(pre: string, ridx: number) { return pre + '.' + ridx.toString(16).padStart(32, '0'); } +/** + * Sub interface for key store specific functions. + */ export interface KeyStore { getGbls(key: string): string | undefined; pinGbls(key: string, val: string): void; @@ -1013,10 +1131,11 @@ export interface KeyStore { putPubs(keys: string, data: PubSet): boolean; } -/* - In memory test implementation of Keeper key store -*/ - +/** + * Keeper sets up named sub databases for key pair storage (KS). + * Methods provide key pair creation, storage, and data signing. + * In-memory test implementation of Keeper key store + */ class Keeper implements KeyStore { private readonly _gbls: Map; private readonly _pris: Map; diff --git a/src/keri/core/salter.ts b/src/keri/core/salter.ts index 0f821d9b..e96af4aa 100644 --- a/src/keri/core/salter.ts +++ b/src/keri/core/salter.ts @@ -4,6 +4,9 @@ import { Matter, MtrDex } from './matter'; import { EmptyMaterialError } from './kering'; import libsodium from 'libsodium-wrappers-sumo'; +/** + * Secret derivation security tier. + */ export enum Tier { low = 'low', med = 'med', @@ -18,9 +21,24 @@ interface SalterArgs { qb64?: string; qb2?: Uint8Array | undefined; } + +/** + * Maintains a random salt for secrets (private keys). + * Its .raw is random salt, .code as cipher suite for salt + */ export class Salter extends Matter { private readonly _tier: Tier | null; + /** + * Creates a Salter from the provided raw salt bytes or generates a random salt if raw is not provided. + * Defaults to low security tier. Only supports Salt_128 salt type. + * @param raw + * @param code + * @param tier + * @param qb64 + * @param qb64b + * @param qb2 + */ constructor({ raw, code = MtrDex.Salt_128, @@ -55,6 +73,16 @@ export class Salter extends Matter { this._tier = tier !== null ? tier : Tier.low; } + /** + * Stretches the salt to a secret key using the path, .raw, tier, and size determined by self.code. + * + * @param size number of bytes of the stretched seed + * @param path string of bytes prepended (prefixed) to the salt before stretching + * @param tier security tier for stretching + * @param temp boolean, True means use temporary, insecure tier; for testing only + * @returns stretched raw binary seed (secret) derived from path and .raw, and size using argon2d stretching algorithm. + * @private + */ private stretch( size: number = 32, path: string = '', @@ -98,6 +126,15 @@ export class Salter extends Matter { ); } + /** + * Returns Signer with .raw secret derived from code size, path, .raw salt, and tier. + * The signer's public key for its .verfer is derived from code and transferable. + * @param code derivation code indicating seed type + * @param transferable whether or not the key is for a transferable or non-transferable identifier. + * @param path string of bytes prepended (prefixed) to the salt before stretching + * @param tier security tier for stretching + * @param temp boolean, True means use temporary, insecure tier; for testing only + */ signer( code: string = MtrDex.Ed25519_Seed, transferable: boolean = true, diff --git a/src/keri/core/serder.ts b/src/keri/core/serder.ts index 217fa6c1..807733f6 100644 --- a/src/keri/core/serder.ts +++ b/src/keri/core/serder.ts @@ -2,11 +2,11 @@ import { MtrDex } from './matter'; import { deversify, Dict, - Ident, + Protocols, Serials, versify, Version, - Versionage, + Vrsn_1_0, } from './core'; import { Verfer } from './verfer'; import { Diger } from './diger'; @@ -16,9 +16,9 @@ export class Serder { private _kind: Serials; private _raw: string = ''; private _ked: Dict = {}; - private _ident: Ident = Ident.KERI; + private _ident: Protocols = Protocols.KERI; private _size: number = 0; - private _version: Version = Versionage; + private _version: Version = Vrsn_1_0; private readonly _code: string; constructor( @@ -73,11 +73,11 @@ export class Serder { private _exhale( ked: Dict, kind: Serials - ): [string, Ident, Serials, Dict, Version] { + ): [string, Protocols, Serials, Dict, Version] { return sizeify(ked, kind); } - get ident(): Ident { + get ident(): Protocols { return this._ident; } @@ -138,13 +138,13 @@ export function dumps(ked: Object, kind: Serials.JSON): string { export function sizeify( ked: Dict, kind?: Serials -): [string, Ident, Serials, Dict, Version] { +): [string, Protocols, Serials, Dict, Version] { if (!('v' in ked)) { throw new Error('Missing or empty version string'); } const [ident, knd, version] = deversify(ked['v'] as string); - if (version != Versionage) { + if (version != Vrsn_1_0) { throw new Error(`unsupported version ${version.toString()}`); } diff --git a/src/keri/core/vdring.ts b/src/keri/core/vdring.ts index 0d3b97b0..741217c2 100644 --- a/src/keri/core/vdring.ts +++ b/src/keri/core/vdring.ts @@ -2,9 +2,9 @@ import { randomNonce } from '../app/coring'; import { TraitDex } from '../app/habery'; import { Serials, - Versionage, + Vrsn_1_0, Version, - Ident, + Protocols, versify, Ilks, } from '../core/core'; @@ -31,11 +31,11 @@ namespace vdr { nonce = randomNonce(), baks = [], cnfg = [], - version = Versionage, + version = Vrsn_1_0, kind = Serials.JSON, code = MtrDex.Blake3_256, }: VDRInceptArgs): Serder { - const vs = versify(Ident.KERI, version, kind, 0); + const vs = versify(Protocols.KERI, version, kind, 0); const isn = 0; const ilk = Ilks.vcp; diff --git a/test/app/aiding.test.ts b/test/app/aiding.test.ts index 7d9bce8c..a805a713 100644 --- a/test/app/aiding.test.ts +++ b/test/app/aiding.test.ts @@ -10,7 +10,7 @@ import { Controller, Identifier, IdentifierDeps, - KeyManager, + IdentifierManagerFactory, Tier, randomPasscode, } from '../../src'; @@ -19,7 +19,7 @@ import { createMockIdentifierState } from './test-utils'; const bran = '0123456789abcdefghijk'; export class MockClient implements IdentifierDeps { - manager: KeyManager; + manager: IdentifierManagerFactory; controller: Controller; pidx = 0; @@ -28,7 +28,7 @@ export class MockClient implements IdentifierDeps { constructor(bran: string) { this.controller = new Controller(bran, Tier.low); - this.manager = new KeyManager(this.controller.salter); + this.manager = new IdentifierManagerFactory(this.controller.salter); } identifiers() { diff --git a/test/app/credentialing.test.ts b/test/app/credentialing.test.ts index 1cd5bea3..90a8ea19 100644 --- a/test/app/credentialing.test.ts +++ b/test/app/credentialing.test.ts @@ -8,7 +8,7 @@ import fetchMock from 'jest-fetch-mock'; import 'whatwg-fetch'; import { d, - Ident, + Protocols, Ilks, interact, Saider, @@ -352,7 +352,7 @@ describe('Ipex', () => { const [, acdc] = Saider.saidify(mockCredential.sad); // Create iss - const vs = versify(Ident.KERI, undefined, Serials.JSON, 0); + const vs = versify(Protocols.KERI, undefined, Serials.JSON, 0); const _iss = { v: vs, t: Ilks.iss, @@ -517,7 +517,7 @@ describe('Ipex', () => { const [, acdc] = Saider.saidify(mockCredential.sad); // Create iss - const vs = versify(Ident.KERI, undefined, Serials.JSON, 0); + const vs = versify(Protocols.KERI, undefined, Serials.JSON, 0); const _iss = { v: vs, t: Ilks.iss, diff --git a/test/app/registry.test.ts b/test/app/registry.test.ts index 255554cf..d29ef7c3 100644 --- a/test/app/registry.test.ts +++ b/test/app/registry.test.ts @@ -3,21 +3,25 @@ import { anyOfClass, anything, instance, mock, when } from 'ts-mockito'; import libsodium from 'libsodium-wrappers-sumo'; import 'whatwg-fetch'; import { Registries } from '../../src/keri/app/credentialing'; -import { Identifier, KeyManager, SaltyKeeper } from '../../src'; +import { + Identifier, + IdentifierManagerFactory, + SaltyIdentifierManager, +} from '../../src'; import { strict as assert } from 'assert'; -import { HabState, State } from '../../src/keri/core/state'; +import { HabState, KeyState } from '../../src/keri/core/keyState'; describe('registry', () => { it('should create a registry', async () => { await libsodium.ready; const mockedClient = mock(SignifyClient); const mockedIdentifiers = mock(Identifier); - const mockedKeyManager = mock(KeyManager); - const mockedKeeper = mock(SaltyKeeper); + const mockedKeyManager = mock(IdentifierManagerFactory); + const mockedKeeper = mock(SaltyIdentifierManager); const hab = { prefix: 'hab prefix', - state: { s: '0', d: 'a digest' } as State, + state: { s: '0', d: 'a digest' } as KeyState, } as HabState; when(mockedClient.manager).thenReturn(instance(mockedKeyManager)); @@ -66,7 +70,7 @@ describe('registry', () => { const hab = { prefix: 'hab prefix', - state: { s: 0, d: 'a digest', c: ['EO'] } as unknown as State, + state: { s: 0, d: 'a digest', c: ['EO'] } as unknown as KeyState, name: 'a name', transferable: true, windexes: [], diff --git a/test/app/test-utils.ts b/test/app/test-utils.ts index 668ad8ad..068ccc25 100644 --- a/test/app/test-utils.ts +++ b/test/app/test-utils.ts @@ -2,14 +2,18 @@ import { Algos, Controller, CreateIdentiferArgs, - KeyManager, + IdentifierManagerFactory, MtrDex, Serials, Tier, - Versionage, + Vrsn_1_0, incept, } from '../../src'; -import { EstablishmentState, HabState, State } from '../../src/keri/core/state'; +import { + EstablishmentState, + HabState, + KeyState, +} from '../../src/keri/core/keyState'; export async function createMockIdentifierState( name: string, @@ -17,7 +21,7 @@ export async function createMockIdentifierState( kargs: CreateIdentiferArgs = {} ): Promise { const controller = new Controller(bran, Tier.low); - const manager = new KeyManager(controller.salter); + const manager = new IdentifierManagerFactory(controller.salter); const algo = kargs.algo == undefined ? Algos.salty : kargs.algo; const transferable = kargs.transferable ?? true; @@ -79,7 +83,7 @@ export async function createMockIdentifierState( wits: wits, cnfg: [], data: data, - version: Versionage, + version: Vrsn_1_0, kind: Serials.JSON, code: dcode, intive: false, @@ -110,7 +114,7 @@ export async function createMockIdentifierState( et: '', c: [], di: serder.ked.di ?? '', - } as State, + } as KeyState, icp_dt: '2023-12-01T10:05:25.062609+00:00', }; } diff --git a/test/core/manager.test.ts b/test/core/manager.test.ts index 6f4a3d0c..3c1c348b 100644 --- a/test/core/manager.test.ts +++ b/test/core/manager.test.ts @@ -20,13 +20,13 @@ import { Siger } from '../../src/keri/core/siger'; import { b } from '../../src/keri/core/core'; import { Cigar } from '../../src/keri/core/cigar'; import { - Keeper, - KeeperParams, - KeyManager, + IdentifierManager, + IdentifierManagerParams, + IdentifierManagerFactory, Prefixer, - RandyKeeper, + RandyIdentifierManager, } from '../../src'; -import { RandyState, State } from '../../src/keri/core/state'; +import { RandyState, KeyState } from '../../src/keri/core/keyState'; import { randomUUID } from 'crypto'; describe('RandyCreator', () => { @@ -709,31 +709,35 @@ describe('Manager', () => { const passcode = '0123456789abcdefghijk'; const salter = new Salter({ raw: b(passcode) }); - const manager = new KeyManager(salter, []); + const manager = new IdentifierManagerFactory(salter, []); - const keeper0 = manager.new(Algos.randy, 0, {}) as RandyKeeper; + const keeper0 = manager.new( + Algos.randy, + 0, + {} + ) as RandyIdentifierManager; const [keys] = await keeper0.incept(false); const prefixes = new Prefixer({ qb64: keys[0] }); const keeper1 = manager.get({ prefix: prefixes.qb64, name: '', - state: {} as State, + state: {} as KeyState, randy: keeper0.params() as RandyState, transferable: false, windexes: [], icp_dt: '2023-12-01T10:05:25.062609+00:00', }); - assert(keeper0 instanceof RandyKeeper); - assert(keeper1 instanceof RandyKeeper); + assert(keeper0 instanceof RandyIdentifierManager); + assert(keeper1 instanceof RandyIdentifierManager); }); it('Should throw if algo is not supported', async () => { const passcode = '0123456789abcdefghijk'; const salter = new Salter({ raw: b(passcode) }); - const manager = new KeyManager(salter, []); + const manager = new IdentifierManagerFactory(salter, []); expect(() => manager.new(randomUUID() as Algos, 0, {})).toThrow( 'Unknown algo' @@ -742,21 +746,21 @@ describe('Manager', () => { manager.get({ prefix: '', name: '', - state: {} as State, + state: {} as KeyState, transferable: false, windexes: [], icp_dt: '2023-12-01T10:05:25.062609+00:00', }) - ).toThrow('Algo not allowed yet'); + ).toThrow('No algo specified'); }); describe('External Module ', () => { - class MockModule implements jest.Mocked { + class MockModule implements jest.Mocked { #params: Record; constructor( public pidx: number, - params: KeeperParams + params: IdentifierManagerParams ) { this.#params = params; } @@ -773,7 +777,7 @@ describe('Manager', () => { const passcode = '0123456789abcdefghijk'; const salter = new Salter({ raw: b(passcode) }); - const manager = new KeyManager(salter, [ + const manager = new IdentifierManagerFactory(salter, [ { module: MockModule, name: 'mock', type: 'mock' }, ]); @@ -791,7 +795,7 @@ describe('Manager', () => { const passcode = '0123456789abcdefghijk'; const salter = new Salter({ raw: b(passcode) }); - const manager = new KeyManager(salter, []); + const manager = new IdentifierManagerFactory(salter, []); const param = randomUUID(); expect(() => @@ -806,7 +810,7 @@ describe('Manager', () => { const passcode = '0123456789abcdefghijk'; const salter = new Salter({ raw: b(passcode) }); - const manager = new KeyManager(salter, [ + const manager = new IdentifierManagerFactory(salter, [ { module: MockModule, name: 'mock', type: 'mock' }, ]); @@ -815,7 +819,7 @@ describe('Manager', () => { const keeper = manager.get({ name: randomUUID(), prefix: '', - state: {} as unknown as State, + state: {} as unknown as KeyState, windexes: [], extern: { extern_type: 'mock', @@ -834,7 +838,7 @@ describe('Manager', () => { const passcode = '0123456789abcdefghijk'; const salter = new Salter({ raw: b(passcode) }); - const manager = new KeyManager(salter, []); + const manager = new IdentifierManagerFactory(salter, []); const param = randomUUID(); @@ -842,7 +846,7 @@ describe('Manager', () => { manager.get({ name: randomUUID(), prefix: '', - state: {} as unknown as State, + state: {} as unknown as KeyState, windexes: [], extern: { extern_type: 'mock', diff --git a/test/core/prefixer.test.ts b/test/core/prefixer.test.ts index 24595679..fcf5e004 100644 --- a/test/core/prefixer.test.ts +++ b/test/core/prefixer.test.ts @@ -1,10 +1,10 @@ import libsodium from 'libsodium-wrappers-sumo'; import { - Ident, + Protocols, Ilks, Serials, versify, - Versionage, + Vrsn_1_0, } from '../../src/keri/core/core'; import { MtrDex } from '../../src/keri/core/matter'; import { Prefixer } from '../../src/keri/core/prefixer'; @@ -28,7 +28,7 @@ describe('Prefixer', () => { ); // Test digest derivation from inception ked - const vs = versify(Ident.KERI, Versionage, Serials.JSON, 0); + const vs = versify(Protocols.KERI, Vrsn_1_0, Serials.JSON, 0); const sn = 0; const ilk = Ilks.icp; const sith = '1'; diff --git a/test/core/saider.test.ts b/test/core/saider.test.ts index fa39424a..14048a48 100644 --- a/test/core/saider.test.ts +++ b/test/core/saider.test.ts @@ -1,4 +1,9 @@ -import { Ident, Serials, versify, Versionage } from '../../src/keri/core/core'; +import { + Protocols, + Serials, + versify, + Vrsn_1_0, +} from '../../src/keri/core/core'; import { strict as assert } from 'assert'; import { MtrDex } from '../../src/keri/core/matter'; import libsodium from 'libsodium-wrappers-sumo'; @@ -11,7 +16,7 @@ describe('Saider', () => { const kind = Serials.JSON; const code = MtrDex.Blake3_256; - const vs = versify(Ident.KERI, Versionage, kind, 0); // vaccuous size == 0 + const vs = versify(Protocols.KERI, Vrsn_1_0, kind, 0); // vaccuous size == 0 assert.equal(vs, 'KERI10JSON000000_'); const sad4 = { v: vs, diff --git a/test/core/utils.test.ts b/test/core/utils.test.ts index e9520f29..94adfe11 100644 --- a/test/core/utils.test.ts +++ b/test/core/utils.test.ts @@ -1,4 +1,4 @@ -import { Ident, Saider, Serder, Serials, d, versify } from '../../src'; +import { Protocols, Saider, Serder, Serials, d, versify } from '../../src'; import { serializeACDCAttachment, serializeIssExnAttachment, @@ -8,7 +8,7 @@ describe(serializeIssExnAttachment, () => { it('serializes iss data', () => { const [, data] = Saider.saidify({ d: '', - v: versify(Ident.KERI, undefined, Serials.JSON, 0), + v: versify(Protocols.KERI, undefined, Serials.JSON, 0), }); const result = serializeIssExnAttachment(new Serder(data)); @@ -24,7 +24,7 @@ describe(serializeACDCAttachment, () => { const [, data] = Saider.saidify({ i: 'EP-hA0w9X5FDonCDxQv32OTCAvcxkZxgDLOnDb3Jcn3a', d: '', - v: versify(Ident.ACDC, undefined, Serials.JSON, 0), + v: versify(Protocols.ACDC, undefined, Serials.JSON, 0), a: { LEI: '123', }, From da4f5c3e0d8012c1324a1ab29e78c1c1a2ecd432 Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Tue, 4 Feb 2025 13:22:22 -0700 Subject: [PATCH 2/6] docs: add key management and siginput docs --- src/keri/app/controller.ts | 97 ++++++++++++++++++++++++++++------- src/keri/app/credentialing.ts | 2 +- src/keri/core/httping.ts | 12 +++-- src/keri/core/manager.ts | 9 ++++ src/keri/core/salter.ts | 17 ++++-- 5 files changed, 112 insertions(+), 25 deletions(-) diff --git a/src/keri/app/controller.ts b/src/keri/app/controller.ts index 57697fd6..49639c6a 100644 --- a/src/keri/app/controller.ts +++ b/src/keri/app/controller.ts @@ -89,17 +89,67 @@ export class Agent { * signing key represents the Account for the client on the agent */ export class Controller { + /* + The bran is the combination of the first 21 characters of the passcode passed in prefixed with 'A' and '0A'. + Looks like: '0A' + 'A' + 'thisismysecretkeyseed' + Or: "0AAthisismysecretkeyseed" + + This is interpreted as encoded Base64URLSafe characters when used as the salt for key generation. + */ private bran: string; + /** + * The stem is the prefix for the stretched input bytes the controller's cryptographic + * key pairs are derived from. + */ public stem: string; + /** + * The security tier for the identifiers created by this Controller. + */ public tier: Tier; + /** + * The rotation index used during key generation by this Controller. + */ public ridx: number; + /** + * The salter is a cryptographic salt used to derive the controller's cryptographic key pairs + * and is deterministically derived from the bran and the security tier. + */ public salter: any; + /** + * The current signing key used to sign requests for this controller. + */ public signer: any; + /** + * The next signing key of which a digest is committed to in an establishment event (inception or rotation) to become the + * signing key after the next rotation. + * @private + */ private nsigner: any; + /** + * Either the current establishment event, inception or rotation, or the interaction event used for delegation approval. + */ public serder: Serder; + /** + * Current public keys formatted in fully-qualified Base64. + * @private + */ private keys: string[]; + /** + * Digests of the next public keys formatted in fully-qualified Base64. + */ public ndigs: string[]; + /** + * Creates a Signify Controller starting at key index 0 that generates keys in + * memory based on the provided seed, or bran, the tier, and the rotation index. + * + * The rotation index is used as follows: + * + * @param bran + * @param tier + * @param ridx + * @param state + */ constructor( bran: string, tier: Tier, @@ -110,6 +160,13 @@ export class Controller { this.stem = 'signify:controller'; this.tier = tier; this.ridx = ridx; + const codes = undefined; // Defines the types of seeds that the SaltyCreator will create. Defaults to undefined. + const keyCount = 1; // The number of keys to create. Defaults to 1. + const transferable = true; // Whether the keys are transferable. Defaults to true. + const code = MtrDex.Ed25519_Seed; // The type cryptographic seed to create by default when not overiddeen by "codes". + const pidx = 0; // The index of this identifier prefix of all managed identifiers created for this SignifyClient Controller. Defaults to 0. + const kidx = 0; // The overall starting key index for the first key this rotation set of keys. This is not a local index to this set of keys but an index in the overall set of keys for all keys in this sequence. + // Defaults to 0. Multiply rotation index (ridx) times key count to get the overall key index. this.salter = new Salter({ qb64: this.bran, tier: this.tier }); @@ -119,30 +176,34 @@ export class Controller { this.stem ); + // Creates the first key pair used to sign the inception event. + // noinspection UnnecessaryLocalVariableJS + const initialKeyIndex = ridx; // will be zero for inception this.signer = creator .create( - undefined, - 1, - MtrDex.Ed25519_Seed, - true, - 0, - this.ridx, - 0, - false + codes, + keyCount, + code, + transferable, + pidx, + initialKeyIndex, + kidx ) - .signers.pop(); + .signers.pop(); // assumes only one key pair is created because keyCount is 1 + + // Creates the second key pair which a digest of the public key is committed to in the inception event. + const nextKeyIndex = ridx + 1; this.nsigner = creator .create( - undefined, - 1, - MtrDex.Ed25519_Seed, - true, - 0, - this.ridx + 1, - 0, - false + codes, + keyCount, + code, + transferable, + pidx, + nextKeyIndex, + kidx ) - .signers.pop(); + .signers.pop(); // assumes only one key pair is created because keyCount is 1 this.keys = [this.signer.verfer.qb64]; this.ndigs = [ new Diger({ code: MtrDex.Blake3_256 }, this.nsigner.verfer.qb64b) diff --git a/src/keri/app/credentialing.ts b/src/keri/app/credentialing.ts index 89f423bd..9d8fdf4a 100644 --- a/src/keri/app/credentialing.ts +++ b/src/keri/app/credentialing.ts @@ -332,7 +332,7 @@ export class Credentials { } /** - * Issue a credential + * Creates a credential in the specified registry to be GRANTed with IPEX to the intended recipient */ async issue( name: string, diff --git a/src/keri/core/httping.ts b/src/keri/core/httping.ts index 46e3ac14..9106dbf6 100644 --- a/src/keri/core/httping.ts +++ b/src/keri/core/httping.ts @@ -33,9 +33,16 @@ export interface SiginputArgs { context?: string; } +/** + * Generates, serializes, and signs a Signature-Input HTTP header value as a structured header + * @param signer + * @param sigInputArgs + */ export function siginput( signer: Signer, - { + sigInputArgs: SiginputArgs +): [Map, Siger | Cigar] { + const { name, method, path, @@ -46,8 +53,7 @@ export function siginput( alg, keyid, context, - }: SiginputArgs -): [Map, Siger | Cigar] { + } = sigInputArgs; const items = new Array(); const ifields = new Array<[string, Map]>(); diff --git a/src/keri/core/manager.ts b/src/keri/core/manager.ts index 6b40b7ee..88b7a6e4 100644 --- a/src/keri/core/manager.ts +++ b/src/keri/core/manager.ts @@ -205,14 +205,23 @@ export class RandyCreator implements Creator { return new Keys(signers); } + /** + * Unused for random key generation. + */ get salt(): string { return ''; } + /** + * Unused for random key generation. + */ get stem(): string { return ''; } + /** + * Unused for random key generation. + */ get tier(): Tier { return '' as Tier; } diff --git a/src/keri/core/salter.ts b/src/keri/core/salter.ts index e96af4aa..b6652558 100644 --- a/src/keri/core/salter.ts +++ b/src/keri/core/salter.ts @@ -127,8 +127,19 @@ export class Salter extends Matter { } /** - * Returns Signer with .raw secret derived from code size, path, .raw salt, and tier. - * The signer's public key for its .verfer is derived from code and transferable. + * Returns Signer with the private key secret derived from code the path, the user entered passcode as a salt, + * and the security tier sized by the CESR cryptographic seed size indicated by the code. See the example below. + * The Signer's public key for its .verfer is derived from its private key, the Matter code, and the transferable boolean. + * + * The construction of the raw hash bytes used looks like this: + * ( size, password, salt ) + * where + * ( code size, path, Base64Decode(passcode) ) + * for example, for the initial inception signing key the following parameters are used: + * ( 32, "signify:controller00", Base64Decode("Athisismysecretkeyseed") ) + * and for the initial rotation key pair the following parameters are used: + * ( 32, "signify:controller01", Base64Decode("Athisismysecretkeyseed") ) + * * @param code derivation code indicating seed type * @param transferable whether or not the key is for a transferable or non-transferable identifier. * @param path string of bytes prepended (prefixed) to the salt before stretching @@ -145,7 +156,7 @@ export class Salter extends Matter { const seed = this.stretch(Matter._rawSize(code), path, tier, temp); return new Signer({ - raw: seed, + raw: seed, // private key code: code, transferable: transferable, }); From 106766283f3d2933412d03ae17977a5c4ea3cf53 Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Thu, 6 Feb 2025 18:11:48 -0700 Subject: [PATCH 3/6] fix: npm audit failure fix; some tsconfig excludes --- package-lock.json | 7 ++++--- tsconfig.json | 1 + tsconfig.node.json | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52573347..1792ad32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6741,14 +6741,15 @@ } }, "node_modules/katex": { - "version": "0.16.11", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", - "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "version": "0.16.21", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz", + "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==", "dev": true, "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" ], + "license": "MIT", "dependencies": { "commander": "^8.3.0" }, diff --git a/tsconfig.json b/tsconfig.json index 84df33bd..3a9248ee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "include": ["src", "types", "test", "examples/integration-scripts"], + "exclude": ["node_modules", "dist"], "extends": "./tsconfig.node.json", "compilerOptions": { "noEmit": true, diff --git a/tsconfig.node.json b/tsconfig.node.json index 4f5481eb..c6f4f52c 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -3,6 +3,7 @@ "target": "ES2022", "module": "ES2022", "lib": ["dom", "esnext"], + "rootDir": ".", "moduleResolution": "node", "strict": true, "skipLibCheck": true, From 2a8ab973aaf943b9979b49b2288aa6ba2b1d81f8 Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Thu, 6 Feb 2025 18:17:14 -0700 Subject: [PATCH 4/6] docs: Add PubPath docs --- src/keri/core/manager.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/keri/core/manager.ts b/src/keri/core/manager.ts index 88b7a6e4..6a5cce7c 100644 --- a/src/keri/core/manager.ts +++ b/src/keri/core/manager.ts @@ -108,12 +108,24 @@ class PubSet { } /** - * + * Describes a path to a specific derived keypair for a given identifier */ class PubPath { + /** + * The path to a specific keypair. To generate a keypair you combine the path with the salt and tier. + */ path: string = ''; + /** + * Derivation code indicating the kind of cryptographic keypair to generate. Defaults to Ed25519. + */ code: string = ''; + /** + * Security tier to use to generate a keypair. Defaults to high. + */ tier: string = Tier.high; + /** + * Flag to control whether to generate a low security, temporary key. Used for speed for unit tests. Do NOT use for production identifiers. + */ temp: boolean = false; } From b654a0f0407325b5232a5949fc15e26145d3e88f Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Thu, 6 Feb 2025 18:19:36 -0700 Subject: [PATCH 5/6] docs: correct Salter constructer args docs --- src/keri/core/salter.ts | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/keri/core/salter.ts b/src/keri/core/salter.ts index b6652558..7125d3c2 100644 --- a/src/keri/core/salter.ts +++ b/src/keri/core/salter.ts @@ -32,21 +32,17 @@ export class Salter extends Matter { /** * Creates a Salter from the provided raw salt bytes or generates a random salt if raw is not provided. * Defaults to low security tier. Only supports Salt_128 salt type. - * @param raw - * @param code - * @param tier - * @param qb64 - * @param qb64b - * @param qb2 + * @param salterArgs defines the kind of cryptographic seed to create with a variety of raw material initialization sources. */ - constructor({ - raw, - code = MtrDex.Salt_128, - tier = Tier.low, - qb64, - qb64b, - qb2, - }: SalterArgs) { + constructor(salterArgs: SalterArgs) { + const { + raw, + code = MtrDex.Salt_128, + tier = Tier.low, + qb64, + qb64b, + qb2, + } = salterArgs; try { super({ raw, code, qb64, qb64b, qb2 }); } catch (e) { From 5cc1e3c864a52b6e39236bd4c268d23357a4b5ce Mon Sep 17 00:00:00 2001 From: Kent Bull Date: Thu, 6 Feb 2025 18:25:19 -0700 Subject: [PATCH 6/6] refactor: change key state interface names and add docs --- src/keri/core/keeping.ts | 12 ++++++------ src/keri/core/keyState.ts | 26 +++++++++++++++++++------- test/core/manager.test.ts | 4 ++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/keri/core/keeping.ts b/src/keri/core/keeping.ts index 4f12d7ed..5e6e2631 100644 --- a/src/keri/core/keeping.ts +++ b/src/keri/core/keeping.ts @@ -11,10 +11,10 @@ import { Prefixer } from './prefixer'; import { Signer } from './signer'; import { ExternState, - GroupState, + GroupKeyState, HabState, - RandyState, - SaltyState, + RandyKeyState, + SaltyKeyState, KeyState, } from './keyState'; @@ -195,7 +195,7 @@ export class IdentifierManagerFactory { } switch (algo) { case Algos.salty: - kargs = kargs as SaltyState; + kargs = kargs as SaltyKeyState; return new SaltyIdentifierManager( this.salter, kargs.pidx, @@ -214,7 +214,7 @@ export class IdentifierManagerFactory { kargs.sxlt ); case Algos.randy: - kargs = kargs as RandyState; + kargs = kargs as RandyKeyState; return new RandyIdentifierManager( this.salter, undefined, @@ -229,7 +229,7 @@ export class IdentifierManagerFactory { kargs.nxts ); case Algos.group: - kargs = kargs as GroupState; + kargs = kargs as GroupKeyState; return new GroupIdentifierManager( this, kargs.mhab, diff --git a/src/keri/core/keyState.ts b/src/keri/core/keyState.ts index 12b47f74..4dde8eed 100644 --- a/src/keri/core/keyState.ts +++ b/src/keri/core/keyState.ts @@ -32,9 +32,9 @@ export interface EstablishmentState { export interface IdentifierManagerState {} /** - * Interface defining configuration parameters for a SaltyIdentifierManager + * Interface defining configuration parameters for a specified, deterministic salt of an IdentifierManager. */ -export interface SaltyState extends IdentifierManagerState { +export interface SaltyKeyState extends IdentifierManagerState { /** * Encrypted */ @@ -49,23 +49,35 @@ export interface SaltyState extends IdentifierManagerState { transferable: boolean; } -export interface RandyState extends IdentifierManagerState { +/** + * Interface defining configuration parameters for a random seed identifier manager. + */ +export interface RandyKeyState extends IdentifierManagerState { prxs: string[]; nxts: string[]; } -export interface GroupState extends IdentifierManagerState { +/** + * Interface defining properties a multi-signature group identifier manager. + */ +export interface GroupKeyState extends IdentifierManagerState { mhab: HabState; keys: string[]; ndigs: string[]; } +/** + * Interface defining properties for an external module identifier manager that uses externally managed keys such as in an HSM or a KMS system. + */ export interface ExternState extends IdentifierManagerState { extern_type: string; pidx: number; [key: string]: unknown; } +/** + * Interface defining properties of an identifier habitat, know as a Hab in KERIpy. + */ export interface HabState { name: string; prefix: string; @@ -73,8 +85,8 @@ export interface HabState { state: KeyState; windexes: unknown[]; icp_dt: string; - [Algos.salty]?: SaltyState; - [Algos.randy]?: RandyState; - [Algos.group]?: GroupState; + [Algos.salty]?: SaltyKeyState; + [Algos.randy]?: RandyKeyState; + [Algos.group]?: GroupKeyState; [Algos.extern]?: ExternState; } diff --git a/test/core/manager.test.ts b/test/core/manager.test.ts index 3c1c348b..f1ab335b 100644 --- a/test/core/manager.test.ts +++ b/test/core/manager.test.ts @@ -26,7 +26,7 @@ import { Prefixer, RandyIdentifierManager, } from '../../src'; -import { RandyState, KeyState } from '../../src/keri/core/keyState'; +import { RandyKeyState, KeyState } from '../../src/keri/core/keyState'; import { randomUUID } from 'crypto'; describe('RandyCreator', () => { @@ -723,7 +723,7 @@ describe('Manager', () => { prefix: prefixes.qb64, name: '', state: {} as KeyState, - randy: keeper0.params() as RandyState, + randy: keeper0.params() as RandyKeyState, transferable: false, windexes: [], icp_dt: '2023-12-01T10:05:25.062609+00:00',