proofseal 0.0.1 → 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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +13 -0
  3. package/README.md +210 -2
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +440 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/config.d.ts +19 -0
  8. package/dist/config.js +58 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/core/canonical.d.ts +16 -0
  11. package/dist/core/canonical.js +29 -0
  12. package/dist/core/canonical.js.map +1 -0
  13. package/dist/core/hash.d.ts +32 -0
  14. package/dist/core/hash.js +81 -0
  15. package/dist/core/hash.js.map +1 -0
  16. package/dist/core/marker-lint.d.ts +5 -0
  17. package/dist/core/marker-lint.js +55 -0
  18. package/dist/core/marker-lint.js.map +1 -0
  19. package/dist/core/paths.d.ts +10 -0
  20. package/dist/core/paths.js +13 -0
  21. package/dist/core/paths.js.map +1 -0
  22. package/dist/harness/quantize.d.ts +38 -0
  23. package/dist/harness/quantize.js +76 -0
  24. package/dist/harness/quantize.js.map +1 -0
  25. package/dist/harness/run.d.ts +61 -0
  26. package/dist/harness/run.js +137 -0
  27. package/dist/harness/run.js.map +1 -0
  28. package/dist/history/gitinfo.d.ts +16 -0
  29. package/dist/history/gitinfo.js +69 -0
  30. package/dist/history/gitinfo.js.map +1 -0
  31. package/dist/history/jsonl.d.ts +28 -0
  32. package/dist/history/jsonl.js +71 -0
  33. package/dist/history/jsonl.js.map +1 -0
  34. package/dist/history/queries.d.ts +43 -0
  35. package/dist/history/queries.js +86 -0
  36. package/dist/history/queries.js.map +1 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.js +19 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/keys/derive.d.ts +28 -0
  41. package/dist/keys/derive.js +59 -0
  42. package/dist/keys/derive.js.map +1 -0
  43. package/dist/manifest/schema.d.ts +1068 -0
  44. package/dist/manifest/schema.js +102 -0
  45. package/dist/manifest/schema.js.map +1 -0
  46. package/dist/manifest/seal.d.ts +41 -0
  47. package/dist/manifest/seal.js +185 -0
  48. package/dist/manifest/seal.js.map +1 -0
  49. package/dist/manifest/verify.d.ts +102 -0
  50. package/dist/manifest/verify.js +246 -0
  51. package/dist/manifest/verify.js.map +1 -0
  52. package/dist/mcp/server.d.ts +1 -0
  53. package/dist/mcp/server.js +138 -0
  54. package/dist/mcp/server.js.map +1 -0
  55. package/package.json +50 -3
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Append-only JSONL history (proofs/history.jsonl) — ADR-0001 §5.5.
3
+ *
4
+ * JSONL hygiene (extraction-map pitfall 9): reads tolerate blank lines
5
+ * and a missing trailing newline; writes emit exactly one '\n' per line;
6
+ * parse errors surface 1-indexed line numbers.
7
+ */
8
+ import { appendFileSync, existsSync, readFileSync } from 'node:fs';
9
+ /** Was this claim verified at seal time? (per-type semantics) */
10
+ export function claimVerified(claim) {
11
+ switch (claim.type) {
12
+ case 'file-hash':
13
+ return !!claim.sha256;
14
+ case 'marker':
15
+ return claim.markerVerified === true;
16
+ case 'harness':
17
+ return !!claim.expectedSha256;
18
+ }
19
+ }
20
+ function claimSnapshotHash(claim) {
21
+ if (claim.type === 'harness')
22
+ return claim.expectedSha256 ?? '';
23
+ return claim.sha256 ?? '';
24
+ }
25
+ /** Append a compact snapshot of a sealed manifest. Exactly one '\n' per line. */
26
+ export function appendHistory(historyPath, manifest, manifestHash) {
27
+ const claims = {};
28
+ for (const c of manifest.claims) {
29
+ claims[c.id] = { sha256: claimSnapshotHash(c), verified: claimVerified(c) };
30
+ }
31
+ const entry = {
32
+ v: 1,
33
+ commit: manifest.gitCommit,
34
+ issuedAt: manifest.issuedAt,
35
+ branch: manifest.branch,
36
+ manifestHash,
37
+ summary: manifest.summary,
38
+ claims,
39
+ };
40
+ const line = JSON.stringify(entry);
41
+ if (/[\r\n]/.test(line)) {
42
+ throw new Error('history entry serialized with embedded newline — refusing to corrupt JSONL');
43
+ }
44
+ appendFileSync(historyPath, line + '\n');
45
+ return entry;
46
+ }
47
+ /**
48
+ * Load JSONL history in FILE order. File order is not chronology (union
49
+ * merges can interleave branches) — queries sort by issuedAt via
50
+ * sortByIssuedAt(). Tolerates blank lines / no trailing newline.
51
+ */
52
+ export function loadHistory(historyPath) {
53
+ if (!existsSync(historyPath))
54
+ return [];
55
+ const raw = readFileSync(historyPath, 'utf8');
56
+ const out = [];
57
+ const lines = raw.split('\n');
58
+ for (let i = 0; i < lines.length; i++) {
59
+ const line = lines[i].replace(/\r$/, '').trim();
60
+ if (!line)
61
+ continue; // blank lines tolerated
62
+ try {
63
+ out.push(JSON.parse(line));
64
+ }
65
+ catch (e) {
66
+ throw new Error(`history parse error at line ${i + 1}: ${e.message}`);
67
+ }
68
+ }
69
+ return out;
70
+ }
71
+ //# sourceMappingURL=jsonl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/history/jsonl.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAkBnE,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,KAAiC;IAC7D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QACxB,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,cAAc,KAAK,IAAI,CAAC;QACvC,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;IAClC,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAiC;IAC1D,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;IAChE,OAAO,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,QAAkB,EAAE,YAAoB;IACzF,MAAM,MAAM,GAAsC,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,CAAC;IACD,MAAM,KAAK,GAAiB;QAC1B,CAAC,EAAE,CAAC;QACJ,MAAM,EAAE,QAAQ,CAAC,SAAS;QAC1B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,YAAY;QACZ,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,MAAM;KACP,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IACD,cAAc,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI;YAAE,SAAS,CAAC,wBAAwB;QAC7C,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,GAAG,CAAC,KAAM,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Temporal history queries — ported from ruflo witness lib.mjs
3
+ * (fixTimeline, diffLatest, findRegressionIntroductions), generalized
4
+ * from fixes to claims.
5
+ */
6
+ import type { HistoryEntry } from './jsonl.js';
7
+ /**
8
+ * Chronological order = `issuedAt` (ISO 8601 → lexicographic compare), with
9
+ * file order as the tie-break. Raw file-line order is NOT chronology: two
10
+ * branches sealing concurrently and union-merging proofs/history.jsonl can
11
+ * interleave lines arbitrarily. Stable sort keeps same-timestamp entries in
12
+ * file order.
13
+ */
14
+ export declare function sortByIssuedAt(history: HistoryEntry[]): HistoryEntry[];
15
+ export interface RegressionIntroduction {
16
+ id: string;
17
+ lastPassCommit: string | null;
18
+ lastPassIssuedAt: string | null;
19
+ regressedAtCommit: string;
20
+ regressedAtIssuedAt: string;
21
+ }
22
+ /**
23
+ * For each claim currently regressed (verified=false in the latest entry),
24
+ * walk backwards to the most recent pass; the entry after it localizes
25
+ * the regression-introducing commit range. "Latest" = max issuedAt, not
26
+ * last file line (see sortByIssuedAt).
27
+ */
28
+ export declare function findRegressionIntroductions(unordered: HistoryEntry[]): RegressionIntroduction[];
29
+ export interface TimelinePoint {
30
+ commit: string;
31
+ issuedAt: string;
32
+ status: 'pass' | 'regressed' | 'absent';
33
+ }
34
+ /** Status timeline for a single claim across all history entries (issuedAt order). */
35
+ export declare function fixTimeline(unordered: HistoryEntry[], claimId: string): TimelinePoint[];
36
+ export interface LatestDiff {
37
+ newlyRegressed: string[];
38
+ newlyPassing: string[];
39
+ added: string[];
40
+ removed: string[];
41
+ }
42
+ /** Compare the latest entry to the previous (by issuedAt) and report transitions. */
43
+ export declare function diffLatest(unordered: HistoryEntry[]): LatestDiff;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Chronological order = `issuedAt` (ISO 8601 → lexicographic compare), with
3
+ * file order as the tie-break. Raw file-line order is NOT chronology: two
4
+ * branches sealing concurrently and union-merging proofs/history.jsonl can
5
+ * interleave lines arbitrarily. Stable sort keeps same-timestamp entries in
6
+ * file order.
7
+ */
8
+ export function sortByIssuedAt(history) {
9
+ return history
10
+ .map((entry, fileIndex) => ({ entry, fileIndex }))
11
+ .sort((a, b) => {
12
+ if (a.entry.issuedAt < b.entry.issuedAt)
13
+ return -1;
14
+ if (a.entry.issuedAt > b.entry.issuedAt)
15
+ return 1;
16
+ return a.fileIndex - b.fileIndex;
17
+ })
18
+ .map((x) => x.entry);
19
+ }
20
+ /**
21
+ * For each claim currently regressed (verified=false in the latest entry),
22
+ * walk backwards to the most recent pass; the entry after it localizes
23
+ * the regression-introducing commit range. "Latest" = max issuedAt, not
24
+ * last file line (see sortByIssuedAt).
25
+ */
26
+ export function findRegressionIntroductions(unordered) {
27
+ if (unordered.length === 0)
28
+ return [];
29
+ const history = sortByIssuedAt(unordered);
30
+ const latest = history[history.length - 1];
31
+ const out = [];
32
+ for (const [id, state] of Object.entries(latest.claims)) {
33
+ if (state.verified)
34
+ continue;
35
+ let lastPass = null;
36
+ let regressedAt = latest;
37
+ for (let i = history.length - 2; i >= 0; i--) {
38
+ const e = history[i];
39
+ const s = e.claims[id];
40
+ if (s && s.verified) {
41
+ lastPass = e;
42
+ break;
43
+ }
44
+ regressedAt = e;
45
+ }
46
+ out.push({
47
+ id,
48
+ lastPassCommit: lastPass?.commit ?? null,
49
+ lastPassIssuedAt: lastPass?.issuedAt ?? null,
50
+ regressedAtCommit: regressedAt.commit,
51
+ regressedAtIssuedAt: regressedAt.issuedAt,
52
+ });
53
+ }
54
+ return out;
55
+ }
56
+ /** Status timeline for a single claim across all history entries (issuedAt order). */
57
+ export function fixTimeline(unordered, claimId) {
58
+ return sortByIssuedAt(unordered).map((e) => ({
59
+ commit: e.commit,
60
+ issuedAt: e.issuedAt,
61
+ status: e.claims[claimId] ? (e.claims[claimId].verified ? 'pass' : 'regressed') : 'absent',
62
+ }));
63
+ }
64
+ /** Compare the latest entry to the previous (by issuedAt) and report transitions. */
65
+ export function diffLatest(unordered) {
66
+ if (unordered.length < 2)
67
+ return { newlyRegressed: [], newlyPassing: [], added: [], removed: [] };
68
+ const history = sortByIssuedAt(unordered);
69
+ const prev = history[history.length - 2];
70
+ const curr = history[history.length - 1];
71
+ const diff = { newlyRegressed: [], newlyPassing: [], added: [], removed: [] };
72
+ for (const id of Object.keys(curr.claims)) {
73
+ if (!(id in prev.claims))
74
+ diff.added.push(id);
75
+ else if (prev.claims[id].verified && !curr.claims[id].verified)
76
+ diff.newlyRegressed.push(id);
77
+ else if (!prev.claims[id].verified && curr.claims[id].verified)
78
+ diff.newlyPassing.push(id);
79
+ }
80
+ for (const id of Object.keys(prev.claims)) {
81
+ if (!(id in curr.claims))
82
+ diff.removed.push(id);
83
+ }
84
+ return diff;
85
+ }
86
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/history/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ProofSeal public library API (ADR-0001 §4.3 — published contract).
3
+ * CLI and MCP server are thin wrappers over these exports.
4
+ */
5
+ export { canonicalize } from './core/canonical.js';
6
+ export { sha256Hex, sha256Bytes, fileSha256, fileSha256CrlfNormalized, fileContains, markerPresent, markerOccurrences } from './core/hash.js';
7
+ export { normalizeClaimPath } from './core/paths.js';
8
+ export { lintMarker } from './core/marker-lint.js';
9
+ export { deriveKey, signBytes, verifyBytes, SEED_DERIVATION, type DerivedKey } from './keys/derive.js';
10
+ export { seal, refreshClaim, type SealOptions, type SealResult, type SealWarning } from './manifest/seal.js';
11
+ export { verify, checkSignature, classifyFileClaim, toVerifyJson, THREAT_MODEL_NOTE, CRLF_DETAIL, REFERENCE_VECTOR_HINT, type VerifyOptions, type VerifyResult, type VerifyJson, type ClaimResult, type VerifySummary, type SignatureCheck, } from './manifest/verify.js';
12
+ export { SCHEMA_ID, ClaimSchema, ManifestSchema, PlatformSchema, WitnessSchema, ConfigSchema, type ManifestPlatform, type Claim, type ClaimState, type ClaimStatus, type FileHashClaim, type MarkerClaim, type HarnessClaim, type Manifest, type ManifestSummary, type Witness, type Integrity, type Tolerance, type ProofSealConfig, } from './manifest/schema.js';
13
+ export { loadHistory, appendHistory, claimVerified, type HistoryEntry, type HistoryClaimState, } from './history/jsonl.js';
14
+ export { fixTimeline, diffLatest, findRegressionIntroductions, sortByIssuedAt, type TimelinePoint, type LatestDiff, type RegressionIntroduction, } from './history/queries.js';
15
+ export { enrichRegressionsWithGit, UNREACHABLE_TAG, type RegressionGitInfo, type EnrichedRegression, } from './history/gitinfo.js';
16
+ export { runHarness, parseNumericOutput, type HarnessDef, type HarnessResult, type HarnessStatus, } from './harness/run.js';
17
+ export { roundHalfEven, quantizeValues, packLEFloat64, hashQuantized, allClose, DEFAULT_DECIMALS, DEFAULT_TOLERANCE, type AllCloseResult, } from './harness/quantize.js';
18
+ export { loadConfig, saveConfig, defaultConfig, CONFIG_FILENAME, type ResolvedConfig, } from './config.js';
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * ProofSeal public library API (ADR-0001 §4.3 — published contract).
3
+ * CLI and MCP server are thin wrappers over these exports.
4
+ */
5
+ export { canonicalize } from './core/canonical.js';
6
+ export { sha256Hex, sha256Bytes, fileSha256, fileSha256CrlfNormalized, fileContains, markerPresent, markerOccurrences } from './core/hash.js';
7
+ export { normalizeClaimPath } from './core/paths.js';
8
+ export { lintMarker } from './core/marker-lint.js';
9
+ export { deriveKey, signBytes, verifyBytes, SEED_DERIVATION } from './keys/derive.js';
10
+ export { seal, refreshClaim } from './manifest/seal.js';
11
+ export { verify, checkSignature, classifyFileClaim, toVerifyJson, THREAT_MODEL_NOTE, CRLF_DETAIL, REFERENCE_VECTOR_HINT, } from './manifest/verify.js';
12
+ export { SCHEMA_ID, ClaimSchema, ManifestSchema, PlatformSchema, WitnessSchema, ConfigSchema, } from './manifest/schema.js';
13
+ export { loadHistory, appendHistory, claimVerified, } from './history/jsonl.js';
14
+ export { fixTimeline, diffLatest, findRegressionIntroductions, sortByIssuedAt, } from './history/queries.js';
15
+ export { enrichRegressionsWithGit, UNREACHABLE_TAG, } from './history/gitinfo.js';
16
+ export { runHarness, parseNumericOutput, } from './harness/run.js';
17
+ export { roundHalfEven, quantizeValues, packLEFloat64, hashQuantized, allClose, DEFAULT_DECIMALS, DEFAULT_TOLERANCE, } from './harness/quantize.js';
18
+ export { loadConfig, saveConfig, defaultConfig, CONFIG_FILENAME, } from './config.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,wBAAwB,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC9I,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAmB,MAAM,kBAAkB,CAAC;AAEvG,OAAO,EAAE,IAAI,EAAE,YAAY,EAAuD,MAAM,oBAAoB,CAAC;AAC7G,OAAO,EACL,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,qBAAqB,GAOtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,SAAS,EACT,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EACb,YAAY,GAcb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,GAGd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,WAAW,EACX,UAAU,EACV,2BAA2B,EAC3B,cAAc,GAIf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,wBAAwB,EACxB,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,UAAU,EACV,kBAAkB,GAInB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,eAAe,GAEhB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Deterministic, commit-bound Ed25519 keys — zero key management.
3
+ *
4
+ * seed = sha256(gitCommit + ':' + salt + ':proofseal/v1')
5
+ * privKey = PKCS#8(seed) (node:crypto raw-seed import)
6
+ * publicKey = SPKI DER last 32 bytes, lowercase hex
7
+ *
8
+ * IMPORTANT (threat model): anyone at the same commit can re-derive the
9
+ * private key. This is tamper-EVIDENCE bound to a git commit, NOT
10
+ * third-party authentication. The salt prevents cross-repo manifest
11
+ * splicing between forks at identical commits.
12
+ */
13
+ import { type KeyObject } from 'node:crypto';
14
+ export declare const SEED_DERIVATION = "sha256(gitCommit + ':' + salt + ':proofseal/v1')";
15
+ export interface DerivedKey {
16
+ /** 32-byte raw seed. */
17
+ seed: Buffer;
18
+ /** Raw Ed25519 public key, lowercase hex (64 chars). */
19
+ publicKeyHex: string;
20
+ /** node:crypto private key object, ready for sign(). */
21
+ privateKey: KeyObject;
22
+ }
23
+ /** Derive the commit-bound Ed25519 keypair for a repo. */
24
+ export declare function deriveKey(gitCommit: string, salt: string): DerivedKey;
25
+ /** Ed25519-sign raw message bytes; returns lowercase hex (128 chars). */
26
+ export declare function signBytes(privateKey: KeyObject, message: Buffer): string;
27
+ /** Verify an Ed25519 signature (hex) over raw message bytes with a raw hex pubkey. */
28
+ export declare function verifyBytes(publicKeyHex: string, message: Buffer, signatureHex: string): boolean;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Deterministic, commit-bound Ed25519 keys — zero key management.
3
+ *
4
+ * seed = sha256(gitCommit + ':' + salt + ':proofseal/v1')
5
+ * privKey = PKCS#8(seed) (node:crypto raw-seed import)
6
+ * publicKey = SPKI DER last 32 bytes, lowercase hex
7
+ *
8
+ * IMPORTANT (threat model): anyone at the same commit can re-derive the
9
+ * private key. This is tamper-EVIDENCE bound to a git commit, NOT
10
+ * third-party authentication. The salt prevents cross-repo manifest
11
+ * splicing between forks at identical commits.
12
+ */
13
+ import { createPrivateKey, createPublicKey, sign as cryptoSign, verify as cryptoVerify, createHash, } from 'node:crypto';
14
+ /** PKCS#8 DER prefix for a raw 32-byte Ed25519 seed. */
15
+ const PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
16
+ /** SPKI DER prefix for a raw 32-byte Ed25519 public key. */
17
+ const SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
18
+ export const SEED_DERIVATION = "sha256(gitCommit + ':' + salt + ':proofseal/v1')";
19
+ /** Derive the commit-bound Ed25519 keypair for a repo. */
20
+ export function deriveKey(gitCommit, salt) {
21
+ const seed = createHash('sha256')
22
+ .update(`${gitCommit}:${salt}:proofseal/v1`)
23
+ .digest();
24
+ const privateKey = createPrivateKey({
25
+ key: Buffer.concat([PKCS8_PREFIX, seed]),
26
+ format: 'der',
27
+ type: 'pkcs8',
28
+ });
29
+ const publicKey = createPublicKey(privateKey);
30
+ const der = publicKey.export({ format: 'der', type: 'spki' });
31
+ return {
32
+ seed,
33
+ publicKeyHex: der.subarray(der.length - 32).toString('hex'),
34
+ privateKey,
35
+ };
36
+ }
37
+ /** Ed25519-sign raw message bytes; returns lowercase hex (128 chars). */
38
+ export function signBytes(privateKey, message) {
39
+ return cryptoSign(null, message, privateKey).toString('hex');
40
+ }
41
+ /** Verify an Ed25519 signature (hex) over raw message bytes with a raw hex pubkey. */
42
+ export function verifyBytes(publicKeyHex, message, signatureHex) {
43
+ if (!/^[0-9a-f]{64}$/.test(publicKeyHex))
44
+ return false;
45
+ if (!/^[0-9a-f]{128}$/.test(signatureHex))
46
+ return false;
47
+ try {
48
+ const publicKey = createPublicKey({
49
+ key: Buffer.concat([SPKI_PREFIX, Buffer.from(publicKeyHex, 'hex')]),
50
+ format: 'der',
51
+ type: 'spki',
52
+ });
53
+ return cryptoVerify(null, message, publicKey, Buffer.from(signatureHex, 'hex'));
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ //# sourceMappingURL=derive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/keys/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,IAAI,IAAI,UAAU,EAClB,MAAM,IAAI,YAAY,EACtB,UAAU,GAEX,MAAM,aAAa,CAAC;AAErB,wDAAwD;AACxD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;AAC5E,4DAA4D;AAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;AAEnE,MAAM,CAAC,MAAM,eAAe,GAAG,kDAAkD,CAAC;AAWlF,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,IAAY;IACvD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC;SAC9B,MAAM,CAAC,GAAG,SAAS,IAAI,IAAI,eAAe,CAAC;SAC3C,MAAM,EAAE,CAAC;IACZ,MAAM,UAAU,GAAG,gBAAgB,CAAC;QAClC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACxC,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAW,CAAC;IACxE,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC3D,UAAU;KACX,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,SAAS,CAAC,UAAqB,EAAE,OAAe;IAC9D,OAAO,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,YAAoB,EAAE,OAAe,EAAE,YAAoB;IACrF,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,eAAe,CAAC;YAChC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;YACnE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}