keri 0.0.0-dev.8b0703e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/data-type.d.ts +9 -0
  2. package/dist/data-type.js +1 -0
  3. package/dist/db/sqlite-db.d.ts +14 -0
  4. package/dist/db/sqlite-db.js +90 -0
  5. package/dist/events/common.d.ts +6 -0
  6. package/dist/events/common.js +1 -0
  7. package/dist/events/incept.d.ts +26 -0
  8. package/dist/events/incept.js +28 -0
  9. package/dist/events/interact.d.ts +14 -0
  10. package/dist/events/interact.js +20 -0
  11. package/dist/events/main.d.ts +4 -0
  12. package/dist/events/main.js +4 -0
  13. package/dist/events/reply.d.ts +15 -0
  14. package/dist/events/reply.js +20 -0
  15. package/dist/keri.d.ts +1 -0
  16. package/dist/keri.js +110 -0
  17. package/dist/keystore/encrypt.d.ts +2 -0
  18. package/dist/keystore/encrypt.js +38 -0
  19. package/dist/keystore/keystore-fs.d.ts +13 -0
  20. package/dist/keystore/keystore-fs.js +50 -0
  21. package/dist/keystore/keystore-web.d.ts +12 -0
  22. package/dist/keystore/keystore-web.js +48 -0
  23. package/dist/keystore/keystore.d.ts +15 -0
  24. package/dist/keystore/keystore.js +1 -0
  25. package/dist/main-common.d.ts +7 -0
  26. package/dist/main-common.js +7 -0
  27. package/dist/main-web.d.ts +2 -0
  28. package/dist/main-web.js +2 -0
  29. package/dist/main.d.ts +2 -0
  30. package/dist/main.js +2 -0
  31. package/dist/parser/base64.d.ts +6 -0
  32. package/dist/parser/base64.js +74 -0
  33. package/dist/parser/cesr-encoding.d.ts +34 -0
  34. package/dist/parser/cesr-encoding.js +158 -0
  35. package/dist/parser/codes.d.ts +143 -0
  36. package/dist/parser/codes.js +266 -0
  37. package/dist/parser/parser.d.ts +11 -0
  38. package/dist/parser/parser.js +150 -0
  39. package/dist/parser/version.d.ts +11 -0
  40. package/dist/parser/version.js +56 -0
  41. package/package.json +45 -0
@@ -0,0 +1,9 @@
1
+ export type DataValue = string | number | boolean | DataObject | DataArray;
2
+ export type DataArray = DataValue[];
3
+ /**
4
+ * Defines a data object that can be serialized to JSON.
5
+ * E.g. key events and acdc objects
6
+ */
7
+ export interface DataObject {
8
+ [x: string]: DataValue;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { KeyEvent, ReplyEvent } from "../events/main.ts";
2
+ export interface SqliteEventStoreOptions {
3
+ filename?: string;
4
+ }
5
+ export declare class SqliteEventStore {
6
+ #private;
7
+ constructor(options?: SqliteEventStoreOptions);
8
+ init(): void;
9
+ insert(event: KeyEvent): Promise<void>;
10
+ get(id: string): Promise<any>;
11
+ aid(id: string): Promise<any[]>;
12
+ locations(id: string): Promise<ReplyEvent[]>;
13
+ list(): Promise<KeyEvent[]>;
14
+ }
@@ -0,0 +1,90 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _SqliteEventStore_db;
13
+ import { DatabaseSync } from "node:sqlite";
14
+ import { existsSync, mkdirSync } from "node:fs";
15
+ import { dirname } from "node:path";
16
+ function parseRow(row) {
17
+ if (!row || typeof row !== "object") {
18
+ throw new Error(`Row not found`);
19
+ }
20
+ const data = "data" in row && row["data"];
21
+ if (!data || typeof data !== "string") {
22
+ throw new Error(`Unexpected row format`);
23
+ }
24
+ return JSON.parse(data);
25
+ }
26
+ function ensureDirSync(filename) {
27
+ const dir = dirname(filename);
28
+ if (!existsSync(dir)) {
29
+ mkdirSync(dir);
30
+ }
31
+ }
32
+ export class SqliteEventStore {
33
+ constructor(options = {}) {
34
+ _SqliteEventStore_db.set(this, void 0);
35
+ if (options.filename) {
36
+ ensureDirSync(options.filename);
37
+ }
38
+ __classPrivateFieldSet(this, _SqliteEventStore_db, new DatabaseSync(options.filename ?? ":memory:"), "f");
39
+ }
40
+ init() {
41
+ __classPrivateFieldGet(this, _SqliteEventStore_db, "f").exec(`
42
+ CREATE TABLE IF NOT EXISTS events (
43
+ id TEXT PRIMARY KEY,
44
+ data JSON NOT NULL
45
+ );
46
+ `);
47
+ }
48
+ async insert(event) {
49
+ const sql = `
50
+ INSERT INTO events (id, data)
51
+ VALUES ($id, $data) ON CONFLICT(id) DO NOTHING;
52
+ `;
53
+ __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).run({
54
+ id: event.d,
55
+ data: JSON.stringify(event),
56
+ });
57
+ }
58
+ async get(id) {
59
+ const row = __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare("SELECT * FROM events WHERE id = ?").get(id);
60
+ return parseRow(row);
61
+ }
62
+ async aid(id) {
63
+ const sql = `
64
+ SELECT * FROM events WHERE json_extract(data, '$.i') = $aid
65
+ ORDER BY json_extract(data, '$.sn') DESC;
66
+ `;
67
+ const rows = __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).all({ aid: id });
68
+ return rows.map(parseRow);
69
+ }
70
+ async locations(id) {
71
+ const sql = `
72
+ SELECT * FROM
73
+ events
74
+ WHERE
75
+ json_extract(data, '$.t') = 'rpy' AND
76
+ json_extract(data, '$.r') = '/loc/scheme' AND
77
+ json_extract(data, '$.a.eid') = $id;
78
+ `;
79
+ const rows = __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).all({ id });
80
+ return rows.map(parseRow);
81
+ }
82
+ async list() {
83
+ const sql = `
84
+ SELECT * FROM events;
85
+ `;
86
+ const rows = __classPrivateFieldGet(this, _SqliteEventStore_db, "f").prepare(sql).all();
87
+ return rows.map(parseRow);
88
+ }
89
+ }
90
+ _SqliteEventStore_db = new WeakMap();
@@ -0,0 +1,6 @@
1
+ export interface KeyEvent {
2
+ v: string;
3
+ t: string;
4
+ d: string;
5
+ }
6
+ export type Threshold = string | string[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import type { DataArray } from "../data-type.ts";
2
+ import type { Threshold } from "./common.ts";
3
+ export interface InceptArgs {
4
+ k: string[];
5
+ kt: Threshold;
6
+ n: string[];
7
+ nt: Threshold;
8
+ b?: string[];
9
+ bt?: string;
10
+ }
11
+ export interface InceptEvent {
12
+ v: string;
13
+ t: "icp";
14
+ d: string;
15
+ i: string;
16
+ s: string;
17
+ kt: Threshold;
18
+ k: string[];
19
+ nt: Threshold;
20
+ n: string[];
21
+ bt: string;
22
+ b: string[];
23
+ c: string[];
24
+ a: DataArray;
25
+ }
26
+ export declare function incept(data: InceptArgs): InceptEvent;
@@ -0,0 +1,28 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { versify } from "../parser/version.js";
5
+ export function incept(data) {
6
+ const event = versify({
7
+ t: "icp",
8
+ d: "#".repeat(44),
9
+ i: "#".repeat(44),
10
+ s: "0",
11
+ kt: data.kt,
12
+ k: data.k,
13
+ nt: data.nt,
14
+ n: data.n,
15
+ bt: data.bt ?? "0",
16
+ b: data.b ?? [],
17
+ c: [],
18
+ a: [],
19
+ });
20
+ const encoder = new TextEncoder();
21
+ const digest = cesr.encode(MatterCode.Blake3_256, blake3
22
+ .create({ dkLen: 32 })
23
+ .update(encoder.encode(JSON.stringify(event)))
24
+ .digest());
25
+ event["d"] = digest;
26
+ event["i"] = digest;
27
+ return event;
28
+ }
@@ -0,0 +1,14 @@
1
+ import type { DataArray } from "../data-type.ts";
2
+ export interface InteractArgs {
3
+ i: string;
4
+ s: string;
5
+ a: DataArray;
6
+ }
7
+ export interface InteractEvent {
8
+ v: string;
9
+ t: "ixn";
10
+ d: string;
11
+ i: string;
12
+ a: DataArray;
13
+ }
14
+ export declare function interact(data: InteractArgs): InteractEvent;
@@ -0,0 +1,20 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { versify } from "../parser/version.js";
5
+ export function interact(data) {
6
+ const event = versify({
7
+ t: "ixn",
8
+ d: "#".repeat(44),
9
+ i: data.i,
10
+ s: data.s,
11
+ a: data.a,
12
+ });
13
+ const encoder = new TextEncoder();
14
+ const digest = cesr.encode(MatterCode.Blake3_256, blake3
15
+ .create({ dkLen: 32 })
16
+ .update(encoder.encode(JSON.stringify(event)))
17
+ .digest());
18
+ event["d"] = digest;
19
+ return event;
20
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./common.ts";
2
+ export * from "./incept.ts";
3
+ export * from "./reply.ts";
4
+ export * from "./interact.ts";
@@ -0,0 +1,4 @@
1
+ export * from "./common.js";
2
+ export * from "./incept.js";
3
+ export * from "./reply.js";
4
+ export * from "./interact.js";
@@ -0,0 +1,15 @@
1
+ import type { DataObject } from "../data-type.ts";
2
+ export interface ReplyArgs {
3
+ dt?: string;
4
+ r: string;
5
+ a: DataObject;
6
+ }
7
+ export interface ReplyEvent {
8
+ v: string;
9
+ t: "rpy";
10
+ d: string;
11
+ dt: string;
12
+ r: string;
13
+ a: DataObject;
14
+ }
15
+ export declare function reply(data: ReplyArgs): ReplyEvent;
@@ -0,0 +1,20 @@
1
+ import { blake3 } from "@noble/hashes/blake3";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { versify } from "../parser/version.js";
5
+ export function reply(data) {
6
+ const event = versify({
7
+ t: "rpy",
8
+ d: "#".repeat(44),
9
+ dt: data.dt ?? new Date().toISOString(),
10
+ r: data.r,
11
+ a: data.a,
12
+ });
13
+ const encoder = new TextEncoder();
14
+ const digest = cesr.encode(MatterCode.Blake3_256, blake3
15
+ .create({ dkLen: 32 })
16
+ .update(encoder.encode(JSON.stringify(event)))
17
+ .digest());
18
+ event["d"] = digest;
19
+ return event;
20
+ }
package/dist/keri.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/keri.js ADDED
@@ -0,0 +1,110 @@
1
+ import { program } from "commander";
2
+ import { parseStream } from "./parser/parser.js";
3
+ import { CounterCode } from "./parser/codes.js";
4
+ import { incept } from "./events/incept.js";
5
+ import cesr from "./parser/cesr-encoding.js";
6
+ import { encodeBase64Int } from "./parser/base64.js";
7
+ import { FileSystemKeyStore } from "./keystore/keystore-fs.js";
8
+ import { SqliteEventStore } from "./db/sqlite-db.js";
9
+ const db = new SqliteEventStore({ filename: ".keri/db.sqlite" });
10
+ db.init();
11
+ program.command("parse").action(async () => {
12
+ const stream = process.stdin;
13
+ for await (const event of parseStream(ReadableStream.from(stream))) {
14
+ console.log(event);
15
+ }
16
+ });
17
+ program
18
+ .command("keygen")
19
+ .requiredOption("--passcode <passcode>")
20
+ .action(async ({ passcode }) => {
21
+ const keystore = new FileSystemKeyStore({ dir: ".keri/keys", passphrase: passcode });
22
+ await keystore.incept();
23
+ });
24
+ program.command("resolve <oobi>").action(async (oobi) => {
25
+ const response = await fetch(oobi);
26
+ if (!response.ok) {
27
+ throw new Error(`Failed to fetch oobi: ${response.status} ${response.statusText}`);
28
+ }
29
+ if (!response.body) {
30
+ throw new Error(`No body in response`);
31
+ }
32
+ for await (const event of parseStream(response.body)) {
33
+ db.insert(event.payload);
34
+ }
35
+ });
36
+ program
37
+ .command("incept")
38
+ .requiredOption("--passcode <passcode>")
39
+ .requiredOption("--name <name>")
40
+ .option("--wit <wit>")
41
+ .action(async ({ passcode, name, wit }) => {
42
+ if (typeof passcode !== "string") {
43
+ throw new Error(`Invalid passcode`);
44
+ }
45
+ if (typeof name !== "string") {
46
+ throw new Error(`Invalid name`);
47
+ }
48
+ const keystore = new FileSystemKeyStore({ dir: ".keri/keys", passphrase: passcode });
49
+ const keys = [await keystore.incept()];
50
+ const wits = [];
51
+ if (typeof wit === "string") {
52
+ wits.push(wit);
53
+ }
54
+ const payload = incept({
55
+ kt: "1",
56
+ k: keys.map((key) => key.current),
57
+ nt: "1",
58
+ n: keys.map((key) => key.next),
59
+ bt: "1",
60
+ b: wits,
61
+ });
62
+ const witnessEndpoints = await Promise.all(wits.map(async (wit) => {
63
+ const result = await db.locations(wit);
64
+ if (result.length === 0) {
65
+ throw new Error(`No location found for wit ${wit}`);
66
+ }
67
+ return result[0].a.url;
68
+ }));
69
+ const sigs = await Promise.all(keys.map(async (key, index) => {
70
+ const sig = await keystore.sign(key.current, new TextEncoder().encode(JSON.stringify(payload)));
71
+ return cesr.index(sig, index);
72
+ }));
73
+ const sigGroup = `${CounterCode.ControllerIdxSigs}${encodeBase64Int(sigs.length, 2)}${sigs.join("")}`;
74
+ const attachmentSize = new TextEncoder().encode(sigGroup).length / 4;
75
+ const attachment = `${CounterCode.AttachmentGroup}${encodeBase64Int(attachmentSize, 2)}${sigGroup}`;
76
+ for (const wit of witnessEndpoints) {
77
+ const url = new URL("/receipts", wit);
78
+ const response = await fetch(url, {
79
+ method: "POST",
80
+ body: JSON.stringify(payload),
81
+ headers: {
82
+ "Content-Type": "application/cesr+json",
83
+ "CESR-ATTACHMENT": attachment,
84
+ },
85
+ });
86
+ if (!response.ok) {
87
+ throw new Error(`Failed to send event to wit ${wit}: ${response.status} ${response.statusText}`);
88
+ }
89
+ if (response.status !== 200) {
90
+ throw new Error(`Failed to send event to wit ${wit}: ${response.status} ${response.statusText}`);
91
+ }
92
+ if (response.body) {
93
+ for await (const receipt of parseStream(response.body)) {
94
+ await db.insert(receipt.payload);
95
+ console.log(receipt);
96
+ }
97
+ }
98
+ }
99
+ console.dir({
100
+ payload: payload,
101
+ sigs,
102
+ attachment,
103
+ });
104
+ });
105
+ program.command("export").action(async () => {
106
+ for (const event of await db.list()) {
107
+ console.log(event);
108
+ }
109
+ });
110
+ program.parse(process.argv);
@@ -0,0 +1,2 @@
1
+ export declare function encrypt(passphrase: string, data: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
2
+ export declare function decrypt(passphrase: string, ciphertext: Uint8Array): Promise<Uint8Array>;
@@ -0,0 +1,38 @@
1
+ export async function encrypt(passphrase, data) {
2
+ const encoder = new TextEncoder();
3
+ const encryptionKey = await crypto.subtle.importKey("raw", encoder.encode(passphrase), "PBKDF2", false, [
4
+ "deriveBits",
5
+ "deriveKey",
6
+ ]);
7
+ const salt = crypto.getRandomValues(new Uint8Array(16));
8
+ const iv = crypto.getRandomValues(new Uint8Array(16));
9
+ const key = await crypto.subtle.deriveKey({
10
+ name: "PBKDF2",
11
+ salt,
12
+ iterations: 100000,
13
+ hash: "SHA-256",
14
+ }, encryptionKey, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
15
+ const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, data);
16
+ const result = new Uint8Array(salt.byteLength + iv.byteLength + encrypted.byteLength);
17
+ result.set(salt, 0);
18
+ result.set(iv, salt.byteLength);
19
+ result.set(new Uint8Array(encrypted), salt.byteLength + iv.byteLength);
20
+ return result;
21
+ }
22
+ export async function decrypt(passphrase, ciphertext) {
23
+ const encoder = new TextEncoder();
24
+ const keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(passphrase), "PBKDF2", false, [
25
+ "deriveBits",
26
+ "deriveKey",
27
+ ]);
28
+ const salt = ciphertext.slice(0, 16);
29
+ const iv = ciphertext.slice(16, 32);
30
+ const encrypted = ciphertext.slice(32);
31
+ const key = await crypto.subtle.deriveKey({
32
+ name: "PBKDF2",
33
+ salt,
34
+ iterations: 100000,
35
+ hash: "SHA-256",
36
+ }, keyMaterial, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
37
+ return new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, encrypted));
38
+ }
@@ -0,0 +1,13 @@
1
+ import type { KeyStore, Key } from "./keystore.ts";
2
+ export interface FileSystemKeyStoreOptions {
3
+ dir: string;
4
+ passphrase: string;
5
+ }
6
+ export declare class FileSystemKeyStore implements KeyStore {
7
+ private readonly options;
8
+ constructor(options: FileSystemKeyStoreOptions);
9
+ private load;
10
+ incept(): Promise<Key>;
11
+ rotate(currentKey: string): Promise<Key>;
12
+ sign(publicKey: string, message: Uint8Array): Promise<string>;
13
+ }
@@ -0,0 +1,50 @@
1
+ import { ed25519 } from "@noble/curves/ed25519";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import cesr from "../parser/cesr-encoding.js";
4
+ import { MatterCode } from "../parser/codes.js";
5
+ import { decodeBase64, encodeBase64 } from "../parser/base64.js";
6
+ import { decrypt, encrypt } from "./encrypt.js";
7
+ import { join } from "node:path";
8
+ import { blake3 } from "@noble/hashes/blake3";
9
+ export class FileSystemKeyStore {
10
+ constructor(options) {
11
+ this.options = options;
12
+ }
13
+ async load(publicKey) {
14
+ const value = await readFile(join(this.options.dir, publicKey), "utf-8");
15
+ const [key0, key1] = value.split("\n");
16
+ return [
17
+ await decrypt(this.options.passphrase, decodeBase64(key0)),
18
+ await decrypt(this.options.passphrase, decodeBase64(key1)),
19
+ ];
20
+ }
21
+ async incept() {
22
+ const key0 = ed25519.utils.randomPrivateKey();
23
+ const key1 = ed25519.utils.randomPrivateKey();
24
+ await mkdir(this.options.dir, { recursive: true });
25
+ const current = cesr.encode(MatterCode.Ed25519, ed25519.getPublicKey(key0));
26
+ const next = cesr.encode(MatterCode.Blake3_256, blake3.create({ dkLen: 32 }).update(current).digest());
27
+ await writeFile(join(this.options.dir, current), [
28
+ encodeBase64(await encrypt(this.options.passphrase, key0)),
29
+ encodeBase64(await encrypt(this.options.passphrase, key1)),
30
+ "\n",
31
+ ].join("\n"));
32
+ return { current, next };
33
+ }
34
+ async rotate(currentKey) {
35
+ const [, key0] = await this.load(currentKey);
36
+ const key1 = ed25519.utils.randomPrivateKey();
37
+ const current = cesr.encode(MatterCode.Ed25519, ed25519.getPublicKey(key0));
38
+ const next = cesr.encode(MatterCode.Blake3_256, blake3.create({ dkLen: 32 }).update(current).digest());
39
+ await writeFile(join(this.options.dir, current), [
40
+ encodeBase64(await encrypt(this.options.passphrase, key0)),
41
+ encodeBase64(await encrypt(this.options.passphrase, key1)),
42
+ "\n",
43
+ ].join("\n"));
44
+ return { current, next };
45
+ }
46
+ async sign(publicKey, message) {
47
+ const [key] = await this.load(publicKey);
48
+ return cesr.sign(message, key, "ed25519");
49
+ }
50
+ }
@@ -0,0 +1,12 @@
1
+ import type { Key, KeyStore } from "./keystore.ts";
2
+ export interface WebKeyStoreOptions {
3
+ passphrase: string;
4
+ }
5
+ export declare class WebKeyStore implements KeyStore {
6
+ private readonly options;
7
+ constructor(options: WebKeyStoreOptions);
8
+ private load;
9
+ incept(): Promise<Key>;
10
+ rotate(currentKey: string): Promise<Key>;
11
+ sign(publicKey: string, message: Uint8Array): Promise<string>;
12
+ }
@@ -0,0 +1,48 @@
1
+ import { ed25519 } from "@noble/curves/ed25519";
2
+ import cesr from "../parser/cesr-encoding.js";
3
+ import { MatterCode } from "../parser/codes.js";
4
+ import { decodeBase64, encodeBase64 } from "../parser/base64.js";
5
+ import { decrypt, encrypt } from "./encrypt.js";
6
+ import { blake3 } from "@noble/hashes/blake3";
7
+ export class WebKeyStore {
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ async load(publicKey) {
12
+ const value = localStorage.getItem(publicKey);
13
+ if (!value) {
14
+ throw new Error("No such key");
15
+ }
16
+ const [key0, key1] = value.split("\n");
17
+ return [
18
+ await decrypt(this.options.passphrase, decodeBase64(key0)),
19
+ await decrypt(this.options.passphrase, decodeBase64(key1)),
20
+ ];
21
+ }
22
+ async incept() {
23
+ const key0 = ed25519.utils.randomPrivateKey();
24
+ const key1 = ed25519.utils.randomPrivateKey();
25
+ const current = cesr.encode(MatterCode.Ed25519, ed25519.getPublicKey(key0));
26
+ const next = cesr.encode(MatterCode.Blake3_256, blake3.create({ dkLen: 32 }).update(current).digest());
27
+ localStorage.setItem(current, [
28
+ encodeBase64(await encrypt(this.options.passphrase, key0)),
29
+ encodeBase64(await encrypt(this.options.passphrase, key1)),
30
+ ].join("\n"));
31
+ return { current, next };
32
+ }
33
+ async rotate(currentKey) {
34
+ const [, key0] = await this.load(currentKey);
35
+ const key1 = ed25519.utils.randomPrivateKey();
36
+ const current = cesr.encode(MatterCode.Ed25519, ed25519.getPublicKey(key0));
37
+ const next = cesr.encode(MatterCode.Blake3_256, blake3.create({ dkLen: 32 }).update(current).digest());
38
+ localStorage.setItem(current, [
39
+ encodeBase64(await encrypt(this.options.passphrase, key0)),
40
+ encodeBase64(await encrypt(this.options.passphrase, key1)),
41
+ ].join("\n"));
42
+ return { current, next };
43
+ }
44
+ async sign(publicKey, message) {
45
+ const [key] = await this.load(publicKey);
46
+ return cesr.sign(message, key, "ed25519");
47
+ }
48
+ }
@@ -0,0 +1,15 @@
1
+ export interface Key {
2
+ /**
3
+ * The public key of the tranferable key.
4
+ */
5
+ current: string;
6
+ /**
7
+ * Digest of the next public key of the key pair.
8
+ */
9
+ next: string;
10
+ }
11
+ export interface KeyStore {
12
+ incept(): Promise<Key>;
13
+ rotate(currentKey: string): Promise<Key>;
14
+ sign(publicKey: string, message: Uint8Array): Promise<string>;
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import cesr from "./parser/cesr-encoding.ts";
2
+ import { incept } from "./events/incept.ts";
3
+ export * from "./keystore/keystore.ts";
4
+ export * from "./parser/codes.ts";
5
+ export * from "./parser/base64.ts";
6
+ export * from "./parser/parser.ts";
7
+ export { incept, cesr };
@@ -0,0 +1,7 @@
1
+ import cesr from "./parser/cesr-encoding.js";
2
+ import { incept } from "./events/incept.js";
3
+ export * from "./keystore/keystore.js";
4
+ export * from "./parser/codes.js";
5
+ export * from "./parser/base64.js";
6
+ export * from "./parser/parser.js";
7
+ export { incept, cesr };
@@ -0,0 +1,2 @@
1
+ export * from "./keystore/keystore-web.ts";
2
+ export * from "./main-common.ts";
@@ -0,0 +1,2 @@
1
+ export * from "./keystore/keystore-web.js";
2
+ export * from "./main-common.js";
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./keystore/keystore-fs.ts";
2
+ export * from "./main-common.ts";
package/dist/main.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./keystore/keystore-fs.js";
2
+ export * from "./main-common.js";
@@ -0,0 +1,6 @@
1
+ export declare function encodeBase64(uint8: Uint8Array): string;
2
+ export declare function decodeBase64(b64: string): Uint8Array;
3
+ export declare function decodeBase64Int(value: string): number;
4
+ export declare function encodeBase64Int(value: number, length?: number): string;
5
+ export declare function encodeBase64Url(buffer: Uint8Array): string;
6
+ export declare function decodeBase64Url(input: string): Uint8Array;