chainproof 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/chain.d.ts +19 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +102 -0
- package/dist/chain.js.map +1 -0
- package/dist/crypto.d.ts +19 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +102 -0
- package/dist/crypto.js.map +1 -0
- package/dist/entry.d.ts +9 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +58 -0
- package/dist/entry.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/storage.d.ts +9 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +48 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/uuid7.d.ts +2 -0
- package/dist/uuid7.d.ts.map +1 -0
- package/dist/uuid7.js +26 -0
- package/dist/uuid7.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Forrest
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/chain.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Result } from '@valencets/resultkit';
|
|
2
|
+
import type { ChainEntry, ChainError, VerifyResult } from './types.js';
|
|
3
|
+
import type { KeyPair } from './crypto.js';
|
|
4
|
+
import type crypto from 'node:crypto';
|
|
5
|
+
export declare class ChainLog<T> {
|
|
6
|
+
private readonly _entries;
|
|
7
|
+
private readonly _keyPair;
|
|
8
|
+
private _prevHash;
|
|
9
|
+
constructor(keyPair: KeyPair);
|
|
10
|
+
get entries(): readonly ChainEntry<T>[];
|
|
11
|
+
get length(): number;
|
|
12
|
+
get lastHash(): string;
|
|
13
|
+
append(data: T): Result<ChainEntry<T>, ChainError>;
|
|
14
|
+
static verify<T>(entries: readonly ChainEntry<T>[], publicKey: crypto.KeyObject): VerifyResult;
|
|
15
|
+
verifyIntegrity(): VerifyResult;
|
|
16
|
+
toJsonl(): string;
|
|
17
|
+
static fromJsonl<T>(jsonl: string, keyPair: KeyPair): Result<ChainLog<T>, ChainError>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAG1C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAUrC,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,SAAS,CAAQ;gBAEZ,OAAO,EAAE,OAAO;IAM7B,IAAI,OAAO,IAAK,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,CAEvC;IAED,IAAI,MAAM,IAAK,MAAM,CAEpB;IAED,IAAI,QAAQ,IAAK,MAAM,CAEtB;IAED,MAAM,CAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;IAWnD,MAAM,CAAC,MAAM,CAAC,CAAC,EACb,OAAO,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,EACjC,SAAS,EAAE,MAAM,CAAC,SAAS,GAC1B,YAAY;IAmDf,eAAe,IAAK,YAAY;IAIhC,OAAO,IAAK,MAAM;IAMlB,MAAM,CAAC,SAAS,CAAC,CAAC,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;CAanC"}
|
package/dist/chain.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ok, err, fromThrowable } from '@valencets/resultkit';
|
|
2
|
+
import { verify } from './crypto.js';
|
|
3
|
+
import { createEntry, entryCanonicalBytes, entryHash, genesisHash } from './entry.js';
|
|
4
|
+
const safeJsonParse = fromThrowable((line) => JSON.parse(line), (e) => ({
|
|
5
|
+
code: 'PARSE_FAILED',
|
|
6
|
+
message: e instanceof Error ? e.message : 'JSON parse failed'
|
|
7
|
+
}));
|
|
8
|
+
export class ChainLog {
|
|
9
|
+
_entries;
|
|
10
|
+
_keyPair;
|
|
11
|
+
_prevHash;
|
|
12
|
+
constructor(keyPair) {
|
|
13
|
+
this._entries = [];
|
|
14
|
+
this._keyPair = keyPair;
|
|
15
|
+
this._prevHash = genesisHash();
|
|
16
|
+
}
|
|
17
|
+
get entries() {
|
|
18
|
+
return this._entries;
|
|
19
|
+
}
|
|
20
|
+
get length() {
|
|
21
|
+
return this._entries.length;
|
|
22
|
+
}
|
|
23
|
+
get lastHash() {
|
|
24
|
+
return this._prevHash;
|
|
25
|
+
}
|
|
26
|
+
append(data) {
|
|
27
|
+
const result = createEntry(data, this._entries.length, this._prevHash, this._keyPair);
|
|
28
|
+
if (result.isErr()) {
|
|
29
|
+
return err(result.error);
|
|
30
|
+
}
|
|
31
|
+
const entry = result.value;
|
|
32
|
+
this._entries.push(entry);
|
|
33
|
+
this._prevHash = entryHash(entry);
|
|
34
|
+
return ok(entry);
|
|
35
|
+
}
|
|
36
|
+
static verify(entries, publicKey) {
|
|
37
|
+
if (entries.length === 0) {
|
|
38
|
+
return { valid: true, chainLength: 0, lastValidSeq: -1, message: 'Empty chain' };
|
|
39
|
+
}
|
|
40
|
+
let expectedPrev = genesisHash();
|
|
41
|
+
let lastValidSeq = -1;
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
// Check hash chain link
|
|
44
|
+
if (entry.prevHash !== expectedPrev) {
|
|
45
|
+
return {
|
|
46
|
+
valid: false,
|
|
47
|
+
chainLength: entries.length,
|
|
48
|
+
lastValidSeq,
|
|
49
|
+
message: `Seq ${entry.seq}: hash chain broken — expected ${expectedPrev.slice(0, 8)}..., got ${entry.prevHash.slice(0, 8)}...`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Check signature
|
|
53
|
+
const canonical = entryCanonicalBytes(entry);
|
|
54
|
+
const sigResult = verify(publicKey, canonical, entry.signature);
|
|
55
|
+
if (sigResult.isErr()) {
|
|
56
|
+
return {
|
|
57
|
+
valid: false,
|
|
58
|
+
chainLength: entries.length,
|
|
59
|
+
lastValidSeq,
|
|
60
|
+
message: `Seq ${entry.seq}: signature verification error — ${sigResult.error.message}`
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (!sigResult.value) {
|
|
64
|
+
return {
|
|
65
|
+
valid: false,
|
|
66
|
+
chainLength: entries.length,
|
|
67
|
+
lastValidSeq,
|
|
68
|
+
message: `Seq ${entry.seq}: invalid signature`
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
expectedPrev = entryHash(entry);
|
|
72
|
+
lastValidSeq = entry.seq;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
valid: true,
|
|
76
|
+
chainLength: entries.length,
|
|
77
|
+
lastValidSeq,
|
|
78
|
+
message: `Chain verified: ${entries.length} entries`
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
verifyIntegrity() {
|
|
82
|
+
return ChainLog.verify(this._entries, this._keyPair.publicKey);
|
|
83
|
+
}
|
|
84
|
+
toJsonl() {
|
|
85
|
+
return this._entries
|
|
86
|
+
.map((entry) => JSON.stringify(entry))
|
|
87
|
+
.join('\n');
|
|
88
|
+
}
|
|
89
|
+
static fromJsonl(jsonl, keyPair) {
|
|
90
|
+
const lines = jsonl.split('\n').filter((line) => line.trim().length > 0);
|
|
91
|
+
const chain = new ChainLog(keyPair);
|
|
92
|
+
for (const line of lines) {
|
|
93
|
+
const parseResult = safeJsonParse(line);
|
|
94
|
+
if (parseResult.isErr())
|
|
95
|
+
return err(parseResult.error);
|
|
96
|
+
chain._entries.push(parseResult.value);
|
|
97
|
+
chain._prevHash = entryHash(parseResult.value);
|
|
98
|
+
}
|
|
99
|
+
return ok(chain);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { ResultAsync } from '@valencets/resultkit';
|
|
3
|
+
import type { Result } from '@valencets/resultkit';
|
|
4
|
+
import type { ChainError } from './types.js';
|
|
5
|
+
export interface KeyPair {
|
|
6
|
+
readonly privateKey: crypto.KeyObject;
|
|
7
|
+
readonly publicKey: crypto.KeyObject;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateKeyPair(): Result<KeyPair, ChainError>;
|
|
10
|
+
export declare function sha256(data: string): string;
|
|
11
|
+
export declare function sign(privateKey: crypto.KeyObject, data: string): Result<string, ChainError>;
|
|
12
|
+
export declare function verify(publicKey: crypto.KeyObject, data: string, signature: string): Result<boolean, ChainError>;
|
|
13
|
+
export declare function exportPrivateKey(key: crypto.KeyObject): string;
|
|
14
|
+
export declare function exportPublicKey(key: crypto.KeyObject): string;
|
|
15
|
+
export declare function importPrivateKey(pem: string): Result<crypto.KeyObject, ChainError>;
|
|
16
|
+
export declare function importPublicKey(pem: string): Result<crypto.KeyObject, ChainError>;
|
|
17
|
+
export declare function saveKeyPair(keyPair: KeyPair, dir: string): ResultAsync<void, ChainError>;
|
|
18
|
+
export declare function loadKeyPair(dir: string): ResultAsync<KeyPair, ChainError>;
|
|
19
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAEhC,OAAO,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAA;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAA;CACrC;AAED,wBAAgB,eAAe,IAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAU9D;AAED,wBAAgB,MAAM,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,IAAI,CAAE,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAU5F;AAED,wBAAgB,MAAM,CACpB,SAAS,EAAE,MAAM,CAAC,SAAS,EAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAW7B;AAED,wBAAgB,gBAAgB,CAAE,GAAG,EAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAE/D;AAED,wBAAgB,eAAe,CAAE,GAAG,EAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAE9D;AAED,wBAAgB,gBAAgB,CAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CASnF;AAED,wBAAgB,eAAe,CAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CASlF;AAED,wBAAgB,WAAW,CAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAgBzF;AAED,wBAAgB,WAAW,CAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,CAiB1E"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { ok, err, ResultAsync } from '@valencets/resultkit';
|
|
4
|
+
export function generateKeyPair() {
|
|
5
|
+
try {
|
|
6
|
+
const { privateKey, publicKey } = crypto.generateKeyPairSync('ed25519');
|
|
7
|
+
return ok({ privateKey, publicKey });
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
return err({
|
|
11
|
+
code: 'INVALID_KEY',
|
|
12
|
+
message: e instanceof Error ? e.message : 'Key generation failed'
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function sha256(data) {
|
|
17
|
+
return crypto.createHash('sha256').update(data, 'utf-8').digest('hex');
|
|
18
|
+
}
|
|
19
|
+
export function sign(privateKey, data) {
|
|
20
|
+
try {
|
|
21
|
+
const signature = crypto.sign(null, Buffer.from(data, 'utf-8'), privateKey);
|
|
22
|
+
return ok(signature.toString('base64'));
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
return err({
|
|
26
|
+
code: 'SIGN_FAILED',
|
|
27
|
+
message: e instanceof Error ? e.message : 'Signing failed'
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function verify(publicKey, data, signature) {
|
|
32
|
+
try {
|
|
33
|
+
const sigBuffer = Buffer.from(signature, 'base64');
|
|
34
|
+
const valid = crypto.verify(null, Buffer.from(data, 'utf-8'), publicKey, sigBuffer);
|
|
35
|
+
return ok(valid);
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
return err({
|
|
39
|
+
code: 'VERIFY_FAILED',
|
|
40
|
+
message: e instanceof Error ? e.message : 'Verification failed'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function exportPrivateKey(key) {
|
|
45
|
+
return key.export({ type: 'pkcs8', format: 'pem' });
|
|
46
|
+
}
|
|
47
|
+
export function exportPublicKey(key) {
|
|
48
|
+
return key.export({ type: 'spki', format: 'pem' });
|
|
49
|
+
}
|
|
50
|
+
export function importPrivateKey(pem) {
|
|
51
|
+
try {
|
|
52
|
+
return ok(crypto.createPrivateKey(pem));
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
return err({
|
|
56
|
+
code: 'INVALID_KEY',
|
|
57
|
+
message: e instanceof Error ? e.message : 'Invalid private key PEM'
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function importPublicKey(pem) {
|
|
62
|
+
try {
|
|
63
|
+
return ok(crypto.createPublicKey(pem));
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
return err({
|
|
67
|
+
code: 'INVALID_KEY',
|
|
68
|
+
message: e instanceof Error ? e.message : 'Invalid public key PEM'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function saveKeyPair(keyPair, dir) {
|
|
73
|
+
const privatePem = exportPrivateKey(keyPair.privateKey);
|
|
74
|
+
const publicPem = exportPublicKey(keyPair.publicKey);
|
|
75
|
+
return ResultAsync.fromPromise(fs.mkdir(dir, { recursive: true })
|
|
76
|
+
.then(() => Promise.all([
|
|
77
|
+
fs.writeFile(`${dir}/chain.key`, privatePem, { mode: 0o600 }),
|
|
78
|
+
fs.writeFile(`${dir}/chain.pub`, publicPem, { mode: 0o644 })
|
|
79
|
+
]))
|
|
80
|
+
.then(() => undefined), (e) => ({
|
|
81
|
+
code: 'IO_FAILED',
|
|
82
|
+
message: e instanceof Error ? e.message : 'Failed to save keys'
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
export function loadKeyPair(dir) {
|
|
86
|
+
return ResultAsync.fromPromise(Promise.all([
|
|
87
|
+
fs.readFile(`${dir}/chain.key`, 'utf-8'),
|
|
88
|
+
fs.readFile(`${dir}/chain.pub`, 'utf-8')
|
|
89
|
+
]), (e) => ({
|
|
90
|
+
code: 'IO_FAILED',
|
|
91
|
+
message: e instanceof Error ? e.message : 'Failed to load keys'
|
|
92
|
+
})).andThen(([privatePem, publicPem]) => {
|
|
93
|
+
const privateResult = importPrivateKey(privatePem);
|
|
94
|
+
if (privateResult.isErr())
|
|
95
|
+
return err(privateResult.error);
|
|
96
|
+
const publicResult = importPublicKey(publicPem);
|
|
97
|
+
if (publicResult.isErr())
|
|
98
|
+
return err(publicResult.error);
|
|
99
|
+
return ok({ privateKey: privateResult.value, publicKey: publicResult.value });
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/entry.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Result } from '@valencets/resultkit';
|
|
2
|
+
import type { ChainEntry, ChainError } from './types.js';
|
|
3
|
+
import type { KeyPair } from './crypto.js';
|
|
4
|
+
export declare function genesisHash(): string;
|
|
5
|
+
export declare function canonicalJson(data: unknown): string;
|
|
6
|
+
export declare function entryCanonicalBytes<T>(entry: ChainEntry<T>): string;
|
|
7
|
+
export declare function createEntry<T>(data: T, seq: number, prevHash: string, keyPair: KeyPair): Result<ChainEntry<T>, ChainError>;
|
|
8
|
+
export declare function entryHash<T>(entry: ChainEntry<T>): string;
|
|
9
|
+
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAK1C,wBAAgB,WAAW,IAAK,MAAM,CAErC;AAaD,wBAAgB,aAAa,CAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAG,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,CAUpE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAC3B,IAAI,EAAE,CAAC,EACP,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAyBnC;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAG,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,CAE1D"}
|
package/dist/entry.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ok, err } from '@valencets/resultkit';
|
|
2
|
+
import { sha256, sign } from './crypto.js';
|
|
3
|
+
import { uuid7 } from './uuid7.js';
|
|
4
|
+
const GENESIS_SEED = 'chainproof:genesis';
|
|
5
|
+
export function genesisHash() {
|
|
6
|
+
return sha256(GENESIS_SEED);
|
|
7
|
+
}
|
|
8
|
+
function sortedReplacer(_key, value) {
|
|
9
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
10
|
+
const sorted = {};
|
|
11
|
+
for (const k of Object.keys(value).sort()) {
|
|
12
|
+
sorted[k] = value[k];
|
|
13
|
+
}
|
|
14
|
+
return sorted;
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
export function canonicalJson(data) {
|
|
19
|
+
return JSON.stringify(data, sortedReplacer);
|
|
20
|
+
}
|
|
21
|
+
export function entryCanonicalBytes(entry) {
|
|
22
|
+
const obj = {
|
|
23
|
+
id: entry.id,
|
|
24
|
+
seq: entry.seq,
|
|
25
|
+
timestamp: entry.timestamp,
|
|
26
|
+
data: entry.data,
|
|
27
|
+
dataHash: entry.dataHash,
|
|
28
|
+
prevHash: entry.prevHash
|
|
29
|
+
};
|
|
30
|
+
return JSON.stringify(obj, sortedReplacer);
|
|
31
|
+
}
|
|
32
|
+
export function createEntry(data, seq, prevHash, keyPair) {
|
|
33
|
+
const id = uuid7();
|
|
34
|
+
const timestamp = Date.now() / 1000;
|
|
35
|
+
const dataHash = sha256(canonicalJson(data));
|
|
36
|
+
const unsigned = {
|
|
37
|
+
id,
|
|
38
|
+
seq,
|
|
39
|
+
timestamp,
|
|
40
|
+
data,
|
|
41
|
+
dataHash,
|
|
42
|
+
prevHash,
|
|
43
|
+
signature: ''
|
|
44
|
+
};
|
|
45
|
+
const canonical = entryCanonicalBytes(unsigned);
|
|
46
|
+
const signResult = sign(keyPair.privateKey, canonical);
|
|
47
|
+
if (signResult.isErr()) {
|
|
48
|
+
return err(signResult.error);
|
|
49
|
+
}
|
|
50
|
+
return ok({
|
|
51
|
+
...unsigned,
|
|
52
|
+
signature: signResult.value
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export function entryHash(entry) {
|
|
56
|
+
return sha256(entryCanonicalBytes(entry));
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAG9C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,MAAM,YAAY,GAAG,oBAAoB,CAAA;AAEzC,MAAM,UAAU,WAAW;IACzB,OAAO,MAAM,CAAC,YAAY,CAAC,CAAA;AAC7B,CAAC;AAED,SAAS,cAAc,CAAE,IAAY,EAAE,KAAc;IACnD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,MAAM,GAA4B,EAAE,CAAA;QAC1C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACrE,MAAM,CAAC,CAAC,CAAC,GAAI,KAAiC,CAAC,CAAC,CAAC,CAAA;QACnD,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,aAAa,CAAE,IAAa;IAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAK,KAAoB;IAC1D,MAAM,GAAG,GAAG;QACV,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAA;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,IAAO,EACP,GAAW,EACX,QAAgB,EAChB,OAAgB;IAEhB,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA;IACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IAE5C,MAAM,QAAQ,GAAkB;QAC9B,EAAE;QACF,GAAG;QACH,SAAS;QACT,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,SAAS,EAAE,EAAE;KACd,CAAA;IAED,MAAM,SAAS,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAA;IAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACtD,IAAI,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAED,OAAO,EAAE,CAAC;QACR,GAAG,QAAQ;QACX,SAAS,EAAE,UAAU,CAAC,KAAK;KAC5B,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAK,KAAoB;IAChD,OAAO,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAA;AAC3C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { ChainLog } from './chain.js';
|
|
2
|
+
export { generateKeyPair, sha256, sign, verify } from './crypto.js';
|
|
3
|
+
export { exportPrivateKey, exportPublicKey, importPrivateKey, importPublicKey } from './crypto.js';
|
|
4
|
+
export { saveKeyPair, loadKeyPair } from './crypto.js';
|
|
5
|
+
export type { KeyPair } from './crypto.js';
|
|
6
|
+
export { createEntry, entryHash, entryCanonicalBytes, canonicalJson, genesisHash } from './entry.js';
|
|
7
|
+
export { uuid7 } from './uuid7.js';
|
|
8
|
+
export { appendToFile, readFromFile, loadChainFromFile, saveChainToFile } from './storage.js';
|
|
9
|
+
export { ChainErrorCode } from './types.js';
|
|
10
|
+
export type { ChainErrorCode as ChainErrorCodeType, ChainError, ChainEntry, VerifyResult } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACtD,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACpG,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,YAAY,EAAE,cAAc,IAAI,kBAAkB,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { ChainLog } from './chain.js';
|
|
2
|
+
export { generateKeyPair, sha256, sign, verify } from './crypto.js';
|
|
3
|
+
export { exportPrivateKey, exportPublicKey, importPrivateKey, importPublicKey } from './crypto.js';
|
|
4
|
+
export { saveKeyPair, loadKeyPair } from './crypto.js';
|
|
5
|
+
export { createEntry, entryHash, entryCanonicalBytes, canonicalJson, genesisHash } from './entry.js';
|
|
6
|
+
export { uuid7 } from './uuid7.js';
|
|
7
|
+
export { appendToFile, readFromFile, loadChainFromFile, saveChainToFile } from './storage.js';
|
|
8
|
+
export { ChainErrorCode } from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEtD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,mBAAmB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACpG,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResultAsync } from '@valencets/resultkit';
|
|
2
|
+
import type { ChainEntry, ChainError } from './types.js';
|
|
3
|
+
import type { KeyPair } from './crypto.js';
|
|
4
|
+
import { ChainLog } from './chain.js';
|
|
5
|
+
export declare function appendToFile<T>(path: string, entry: ChainEntry<T>): ResultAsync<void, ChainError>;
|
|
6
|
+
export declare function readFromFile<T>(path: string): ResultAsync<ChainEntry<T>[], ChainError>;
|
|
7
|
+
export declare function loadChainFromFile<T>(path: string, keyPair: KeyPair): ResultAsync<ChainLog<T>, ChainError>;
|
|
8
|
+
export declare function saveChainToFile<T>(path: string, chain: ChainLog<T>): ResultAsync<void, ChainError>;
|
|
9
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,WAAW,EAAiB,MAAM,sBAAsB,CAAA;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAUrC,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GACnB,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAS/B;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,GACX,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,CAqB1C;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAWtC;AAED,wBAAgB,eAAe,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GACjB,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAS/B"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { ok, err, ResultAsync, fromThrowable } from '@valencets/resultkit';
|
|
3
|
+
import { ChainLog } from './chain.js';
|
|
4
|
+
const safeJsonParse = fromThrowable((line) => JSON.parse(line), (e) => ({
|
|
5
|
+
code: 'PARSE_FAILED',
|
|
6
|
+
message: e instanceof Error ? e.message : 'JSON parse failed'
|
|
7
|
+
}));
|
|
8
|
+
export function appendToFile(path, entry) {
|
|
9
|
+
const line = JSON.stringify(entry) + '\n';
|
|
10
|
+
return ResultAsync.fromPromise(fs.appendFile(path, line, 'utf-8'), (e) => ({
|
|
11
|
+
code: 'IO_FAILED',
|
|
12
|
+
message: e instanceof Error ? e.message : 'Failed to append to file'
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
export function readFromFile(path) {
|
|
16
|
+
return ResultAsync.fromPromise(fs.readFile(path, 'utf-8'), (e) => ({
|
|
17
|
+
code: 'IO_FAILED',
|
|
18
|
+
message: e instanceof Error ? e.message : 'Failed to read file'
|
|
19
|
+
})).andThen((content) => {
|
|
20
|
+
const lines = content.split('\n').filter((line) => line.trim().length > 0);
|
|
21
|
+
const entries = [];
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
const parseResult = safeJsonParse(line);
|
|
24
|
+
if (parseResult.isErr()) {
|
|
25
|
+
return err(parseResult.error).toAsync();
|
|
26
|
+
}
|
|
27
|
+
entries.push(parseResult.value);
|
|
28
|
+
}
|
|
29
|
+
return ok(entries).toAsync();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function loadChainFromFile(path, keyPair) {
|
|
33
|
+
return ResultAsync.fromPromise(fs.readFile(path, 'utf-8'), (e) => ({
|
|
34
|
+
code: 'IO_FAILED',
|
|
35
|
+
message: e instanceof Error ? e.message : 'Failed to read file'
|
|
36
|
+
})).andThen((content) => {
|
|
37
|
+
const result = ChainLog.fromJsonl(content, keyPair);
|
|
38
|
+
return result.toAsync();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export function saveChainToFile(path, chain) {
|
|
42
|
+
const content = chain.toJsonl() + '\n';
|
|
43
|
+
return ResultAsync.fromPromise(fs.writeFile(path, content, 'utf-8'), (e) => ({
|
|
44
|
+
code: 'IO_FAILED',
|
|
45
|
+
message: e instanceof Error ? e.message : 'Failed to write file'
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const ChainErrorCode: {
|
|
2
|
+
readonly INVALID_KEY: "INVALID_KEY";
|
|
3
|
+
readonly SIGN_FAILED: "SIGN_FAILED";
|
|
4
|
+
readonly VERIFY_FAILED: "VERIFY_FAILED";
|
|
5
|
+
readonly CHAIN_BROKEN: "CHAIN_BROKEN";
|
|
6
|
+
readonly IO_FAILED: "IO_FAILED";
|
|
7
|
+
readonly PARSE_FAILED: "PARSE_FAILED";
|
|
8
|
+
};
|
|
9
|
+
export type ChainErrorCode = typeof ChainErrorCode[keyof typeof ChainErrorCode];
|
|
10
|
+
export interface ChainError {
|
|
11
|
+
readonly code: ChainErrorCode;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ChainEntry<T> {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly seq: number;
|
|
17
|
+
readonly timestamp: number;
|
|
18
|
+
readonly data: T;
|
|
19
|
+
readonly dataHash: string;
|
|
20
|
+
readonly prevHash: string;
|
|
21
|
+
readonly signature: string;
|
|
22
|
+
}
|
|
23
|
+
export interface VerifyResult {
|
|
24
|
+
readonly valid: boolean;
|
|
25
|
+
readonly chainLength: number;
|
|
26
|
+
readonly lastValidSeq: number;
|
|
27
|
+
readonly message: string;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;;;CAOjB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,MAAM,OAAO,cAAc,CAAC,CAAA;AAE/E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,aAAa;IAC1B,aAAa,EAAE,eAAe;IAC9B,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;CACpB,CAAA"}
|
package/dist/uuid7.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid7.d.ts","sourceRoot":"","sources":["../src/uuid7.ts"],"names":[],"mappings":"AAEA,wBAAgB,KAAK,IAAK,MAAM,CAyB/B"}
|
package/dist/uuid7.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
export function uuid7() {
|
|
3
|
+
const now = Date.now();
|
|
4
|
+
const timeBytes = new Uint8Array(6);
|
|
5
|
+
// 48-bit millisecond timestamp (big-endian)
|
|
6
|
+
timeBytes[0] = (now / 2 ** 40) & 0xff;
|
|
7
|
+
timeBytes[1] = (now / 2 ** 32) & 0xff;
|
|
8
|
+
timeBytes[2] = (now / 2 ** 24) & 0xff;
|
|
9
|
+
timeBytes[3] = (now / 2 ** 16) & 0xff;
|
|
10
|
+
timeBytes[4] = (now / 2 ** 8) & 0xff;
|
|
11
|
+
timeBytes[5] = now & 0xff;
|
|
12
|
+
const randBytes = crypto.randomBytes(10);
|
|
13
|
+
// Set version 7 (0111) in bits 48-51
|
|
14
|
+
randBytes[0] = (randBytes[0] & 0x0f) | 0x70;
|
|
15
|
+
// Set variant 10 in bits 64-65
|
|
16
|
+
randBytes[2] = (randBytes[2] & 0x3f) | 0x80;
|
|
17
|
+
const hex = Buffer.concat([timeBytes, randBytes]).toString('hex');
|
|
18
|
+
return [
|
|
19
|
+
hex.slice(0, 8),
|
|
20
|
+
hex.slice(8, 12),
|
|
21
|
+
hex.slice(12, 16),
|
|
22
|
+
hex.slice(16, 20),
|
|
23
|
+
hex.slice(20, 32)
|
|
24
|
+
].join('-');
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=uuid7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid7.js","sourceRoot":"","sources":["../src/uuid7.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAEhC,MAAM,UAAU,KAAK;IACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAA;IACnC,4CAA4C;IAC5C,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;IACpC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,CAAA;IAEzB,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IACxC,qCAAqC;IACrC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAC5C,+BAA+B;IAC/B,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAE5C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjE,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACjB,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACb,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chainproof",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Hash-chained, Ed25519-signed append-only logs for TypeScript. Tamper-evident audit trails as a reusable primitive.",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.build.json",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"test:coverage": "vitest run --coverage",
|
|
20
|
+
"lint": "eslint .",
|
|
21
|
+
"validate": "tsc --noEmit && eslint .",
|
|
22
|
+
"prepublishOnly": "npm run validate && npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"audit-log",
|
|
26
|
+
"hash-chain",
|
|
27
|
+
"ed25519",
|
|
28
|
+
"append-only",
|
|
29
|
+
"tamper-evident",
|
|
30
|
+
"cryptography",
|
|
31
|
+
"receipt",
|
|
32
|
+
"integrity"
|
|
33
|
+
],
|
|
34
|
+
"author": "Forrest",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=22"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@valencets/resultkit": "^0.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^25.5.0",
|
|
44
|
+
"@vitest/coverage-v8": "^4.0.0",
|
|
45
|
+
"neostandard": "^0.12.0",
|
|
46
|
+
"typescript": "^5.9.0",
|
|
47
|
+
"vitest": "^4.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|