verifyhash 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 +201 -0
- package/README.md +883 -0
- package/cli/abi/ContributionRegistry.json +881 -0
- package/cli/agent.js +2173 -0
- package/cli/anchor-artifact.js +853 -0
- package/cli/anchor.js +400 -0
- package/cli/claim.js +881 -0
- package/cli/core/agent-commit.js +448 -0
- package/cli/core/agent-session.js +598 -0
- package/cli/core/anchor-binding.js +663 -0
- package/cli/core/attestation.js +580 -0
- package/cli/core/evidence-plans.js +495 -0
- package/cli/core/fixtures/evidence-plans/baseline.json +19 -0
- package/cli/core/fulfill-intake.js +1082 -0
- package/cli/core/go-live-preflight.js +481 -0
- package/cli/core/license.js +534 -0
- package/cli/core/manifest.js +243 -0
- package/cli/core/packetseal.js +591 -0
- package/cli/core/registryArtifact.js +49 -0
- package/cli/core/revocation.js +539 -0
- package/cli/core/rfc3161.js +389 -0
- package/cli/core/timestamp.js +482 -0
- package/cli/core/trust-asof.js +479 -0
- package/cli/dataset.js +2950 -0
- package/cli/evidence.js +2227 -0
- package/cli/fulfill-webhook-http.js +438 -0
- package/cli/git.js +220 -0
- package/cli/hash.js +550 -0
- package/cli/identity.js +1072 -0
- package/cli/journal-cli.js +1110 -0
- package/cli/journal-log.js +454 -0
- package/cli/journal.js +334 -0
- package/cli/lineage.js +447 -0
- package/cli/list.js +287 -0
- package/cli/parcel.js +1509 -0
- package/cli/proof.js +578 -0
- package/cli/prove.js +300 -0
- package/cli/receipt.js +631 -0
- package/cli/registry.js +331 -0
- package/cli/reputation.js +344 -0
- package/cli/revocation.js +495 -0
- package/cli/serve-verify-http.js +298 -0
- package/cli/serve-verify.js +333 -0
- package/cli/show.js +339 -0
- package/cli/verify.js +383 -0
- package/cli/vh.js +3927 -0
- package/docs/ADOPT.md +183 -0
- package/docs/ADOPTION.json +11 -0
- package/docs/AGENTTRACE.md +247 -0
- package/docs/ANCHORING.md +167 -0
- package/docs/AUDIT.md +55 -0
- package/docs/CONFORMANCE.md +107 -0
- package/docs/DATALEDGER.md +638 -0
- package/docs/DECIDE.md +47 -0
- package/docs/DECISIONS-PENDING.md +27 -0
- package/docs/DEPLOY-PUBLIC-SITE.md +301 -0
- package/docs/ENGINE-LEDGER.json +12 -0
- package/docs/EVIDENCE.md +519 -0
- package/docs/GO-LIVE.md +66 -0
- package/docs/IDENTITY.md +123 -0
- package/docs/INDEPENDENT-VERIFICATION.md +377 -0
- package/docs/INTEGRITY-JOURNAL.md +337 -0
- package/docs/KEY-LIFECYCLE.md +179 -0
- package/docs/LICENSING.md +46 -0
- package/docs/LINEAGE.md +307 -0
- package/docs/LOOP-AUDIT-2026-07-03.json +580 -0
- package/docs/LOOP-HARDENING-PLAN.md +44 -0
- package/docs/MERKLE-LEAVES.md +113 -0
- package/docs/METRICS.jsonl +31 -0
- package/docs/MORNING.md +204 -0
- package/docs/PILOT.md +444 -0
- package/docs/PROOFPARCEL.md +227 -0
- package/docs/PROOFS.md +262 -0
- package/docs/RECEIPTS.md +341 -0
- package/docs/REPUTATION.md +158 -0
- package/docs/SDK.md +301 -0
- package/docs/STRATEGY-ARCHIVE.md +5055 -0
- package/docs/SUPERVISOR-RUNBOOK.md +52 -0
- package/docs/TRUST-BOUNDARIES.md +335 -0
- package/docs/TRUSTLEDGER.md +1976 -0
- package/docs/USAGE-BUDGET.json +121 -0
- package/docs/VERIFY-SERVICE.md +168 -0
- package/index.js +160 -0
- package/package.json +41 -0
- package/trustledger/build-standalone.js +796 -0
- package/trustledger/cli.js +3179 -0
- package/trustledger/close.js +391 -0
- package/trustledger/corpus.js +159 -0
- package/trustledger/dist/BUILD-PROVENANCE.json +99 -0
- package/trustledger/dist/trustledger-standalone.html +6197 -0
- package/trustledger/dist/trustledger-standalone.html.sha256 +1 -0
- package/trustledger/door-core.js +442 -0
- package/trustledger/fixtures/bank.csv +7 -0
- package/trustledger/fixtures/bank.malformed.csv +3 -0
- package/trustledger/fixtures/bank.noalias.csv +5 -0
- package/trustledger/fixtures/bank.ofx +34 -0
- package/trustledger/fixtures/bank.real.csv +5 -0
- package/trustledger/fixtures/corpus/_shared/prior-close.json +22 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/inputs.json +14 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/inputs.json +14 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/continuity-break--benign-twin/inputs.json +15 -0
- package/trustledger/fixtures/corpus/continuity-break--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/continuity-break--out-of-trust/inputs.json +15 -0
- package/trustledger/fixtures/corpus/continuity-break--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/inputs.json +13 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/inputs.json +13 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/inputs.json +15 -0
- package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/inputs.json +15 -0
- package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/inputs.json +16 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/inputs.json +13 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/inputs.json +13 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/inputs.json +13 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/e2e/bank.aliased.csv +4 -0
- package/trustledger/fixtures/e2e/bank.csv +4 -0
- package/trustledger/fixtures/e2e/bank.nsf.csv +4 -0
- package/trustledger/fixtures/e2e/quickbooks.csv +6 -0
- package/trustledger/fixtures/e2e/quickbooks.nsf.csv +8 -0
- package/trustledger/fixtures/e2e/rentroll.csv +6 -0
- package/trustledger/fixtures/e2e/rentroll.nsf.csv +8 -0
- package/trustledger/fixtures/e2e/rentroll.short.csv +5 -0
- package/trustledger/fixtures/plans/baseline.json +25 -0
- package/trustledger/fixtures/plans/price-binding.example.json +27 -0
- package/trustledger/fixtures/policy/ambiguous-deposit-example.json +12 -0
- package/trustledger/fixtures/policy/baseline.json +19 -0
- package/trustledger/fixtures/policy/ca-example.json +12 -0
- package/trustledger/fixtures/policy/negative-tenant-ledger-example.json +12 -0
- package/trustledger/fixtures/policy/owner-overdraw-example.json +12 -0
- package/trustledger/fixtures/quickbooks.csv +7 -0
- package/trustledger/fixtures/quickbooks.real.csv +5 -0
- package/trustledger/fixtures/rentroll.csv +6 -0
- package/trustledger/fixtures/rentroll.real.csv +4 -0
- package/trustledger/ingest.js +1163 -0
- package/trustledger/lib/policy-bundled-loader.js +44 -0
- package/trustledger/lib/sha256-vendored.js +227 -0
- package/trustledger/license.js +563 -0
- package/trustledger/match.js +551 -0
- package/trustledger/plans.js +551 -0
- package/trustledger/policy.js +398 -0
- package/trustledger/public/index.html +512 -0
- package/trustledger/reconcile.js +1486 -0
- package/trustledger/report.js +887 -0
- package/trustledger/seal.js +854 -0
- package/trustledger/server.js +391 -0
- package/trustledger/valueproof.js +350 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// trustledger/lib/policy-bundled-loader.js — the policy module's SOLE impure seam (T-65.1).
|
|
4
|
+
//
|
|
5
|
+
// WHY THIS FILE EXISTS
|
|
6
|
+
// trustledger/policy.js is pure (readPolicy/validatePolicy/applyPolicy: no clock, no I/O, no hidden
|
|
7
|
+
// state) EXCEPT for one convenience: loading the bundled per-state fixture policies from disk so
|
|
8
|
+
// `vh trust reconcile --state <code>` can resolve a code without a file path. That filesystem code —
|
|
9
|
+
// and ONLY that code — lives here, behind one clearly-named module boundary, so:
|
|
10
|
+
// * the browser bundle (EPIC-65) can shim/replace THIS ONE FILE (e.g. with the fixture JSON inlined)
|
|
11
|
+
// and ship policy.js's pure path byte-for-byte unchanged;
|
|
12
|
+
// * a static purity scan of the browser path (test/trustledger.browser-core.test.js) can allow
|
|
13
|
+
// exactly one fs-requiring module — this one — and fail if fs/http/net/etc. creep in anywhere else.
|
|
14
|
+
// policy.js requires this module LAZILY (inside bundledPolicies(), never at module top level), so merely
|
|
15
|
+
// loading policy.js executes no fs/path require at all.
|
|
16
|
+
//
|
|
17
|
+
// RAW I/O ONLY — NO POLICY LOGIC
|
|
18
|
+
// Validation, sorting, error naming (PolicyError), and the {code,file,policy} entry shape all stay in
|
|
19
|
+
// policy.js, so this module cannot drift from the schema: it reads directory names and file text from
|
|
20
|
+
// the package's OWN bundled fixtures directory (never a caller path) and nothing more. Errors are thrown
|
|
21
|
+
// RAW; policy.js wraps them into the same named PolicyErrors it always threw — zero behavior change.
|
|
22
|
+
|
|
23
|
+
const fs = require("fs");
|
|
24
|
+
const path = require("path");
|
|
25
|
+
|
|
26
|
+
// The package's own bundled fixtures directory. Same absolute path as the historical
|
|
27
|
+
// policy.js constant (trustledger/fixtures/policy) — this file just lives one level down.
|
|
28
|
+
const BUNDLED_DIR = path.join(__dirname, "..", "fixtures", "policy");
|
|
29
|
+
|
|
30
|
+
// List the bundled policy fixture FILENAMES (the "*.json" basenames, unsorted — policy.js
|
|
31
|
+
// sorts them so ordering stays that module's documented, deterministic concern). Throws raw.
|
|
32
|
+
function listBundledPolicyNames() {
|
|
33
|
+
return fs.readdirSync(BUNDLED_DIR).filter((n) => n.endsWith(".json"));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Read ONE bundled policy fixture by basename, returning { full, text } where `full` is the
|
|
37
|
+
// absolute path (policy.js reports it in each entry) and `text` is the raw UTF-8 file text
|
|
38
|
+
// (policy.js validates it). Throws raw.
|
|
39
|
+
function readBundledPolicyFile(name) {
|
|
40
|
+
const full = path.join(BUNDLED_DIR, name);
|
|
41
|
+
return { full, text: fs.readFileSync(full, "utf8") };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { BUNDLED_DIR, listBundledPolicyNames, readBundledPolicyFile };
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// trustledger/lib/sha256-vendored.js — a PURE-JS, ZERO-DEPENDENCY SHA-256 (T-65.1).
|
|
4
|
+
//
|
|
5
|
+
// WHY THIS FILE EXISTS
|
|
6
|
+
// The TrustLedger reconciliation core (ingest -> match -> reconcile -> report -> close) is pure JS with
|
|
7
|
+
// ONE Node-only dependency left on its hot path: close.js took SHA-256 from Node's built-in `crypto` to
|
|
8
|
+
// compute the period-close `inputsDigest`. That is correct in Node but makes the core non-portable — a
|
|
9
|
+
// browser has no Node `crypto` builtin — and the zero-install offline app (EPIC-65) must run the SAME core,
|
|
10
|
+
// byte-for-byte, inside a single HTML file. This module is the missing piece: a from-scratch SHA-256 that
|
|
11
|
+
// `require`s NOTHING (no Node core, no third-party package, no relative module), following the EXACT
|
|
12
|
+
// discipline of verifier/lib/keccak256-vendored.js (T-35.1). It is a drop-in for the one call close.js
|
|
13
|
+
// makes, so every existing `inputsDigest` byte is UNCHANGED.
|
|
14
|
+
//
|
|
15
|
+
// CORRECTNESS, NOT NOVELTY
|
|
16
|
+
// SHA-256 is the FIXED, standardized FIPS 180-4 algorithm: 64-byte blocks, Merkle–Damgård padding
|
|
17
|
+
// (0x80, zero fill, 64-bit big-endian bit length), the 64 published K round constants (fractional cube
|
|
18
|
+
// roots of the first 64 primes) and 8 published H init words (fractional square roots of the first 8
|
|
19
|
+
// primes). Everything below runs on plain 32-bit JS integer ops (>>> and | keep values in uint32 space;
|
|
20
|
+
// sums of up to five uint32 values stay < 2^53 so plain + is exact before the final >>> 0). This is
|
|
21
|
+
// independent CODE but never an independent ALGORITHM: test/trustledger.browser-core.test.js proves the
|
|
22
|
+
// output byte-identical to Node's `crypto.createHash("sha256")` across the published vectors, every
|
|
23
|
+
// committed fixture file, every committed close artifact, all block-padding edge lengths, and hundreds of
|
|
24
|
+
// random buffers — a single mismatch FAILS the suite, so this file cannot silently diverge.
|
|
25
|
+
//
|
|
26
|
+
// UTF-8, EXPLICITLY
|
|
27
|
+
// close.js hashes a canonical JSON STRING as UTF-8. Node spells that Buffer.from(s, "utf8"); a browser
|
|
28
|
+
// spells it TextEncoder. To depend on NEITHER, utf8Bytes() below is a from-scratch WHATWG-compatible
|
|
29
|
+
// UTF-8 encoder (surrogate pairs combined; LONE surrogates replaced with U+FFFD — exactly what both
|
|
30
|
+
// Buffer.from(s, "utf8") and TextEncoder produce), cross-checked byte-for-byte against Buffer.from in the
|
|
31
|
+
// same test suite.
|
|
32
|
+
//
|
|
33
|
+
// REQUIRES NOTHING: a grep of this source finds no CommonJS require call and no bare-name import.
|
|
34
|
+
// (Intentional — this property is asserted by test/trustledger.browser-core.test.js.)
|
|
35
|
+
|
|
36
|
+
// ---- FIPS 180-4 round constants: first 32 bits of the fractional parts of the cube roots of the first
|
|
37
|
+
// 64 primes (2..311). Published, fixed, independently checkable against the standard. ----------------------
|
|
38
|
+
const K = [
|
|
39
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
40
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
41
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
42
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
43
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
44
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
45
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
46
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
// 32-bit right-rotate (result kept unsigned via >>> 0 at the call sites' final masking).
|
|
50
|
+
function rotr(x, n) {
|
|
51
|
+
return ((x >>> n) | (x << (32 - n))) >>> 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// SHA-256 over `bytes` (Uint8Array/Buffer/array of byte values), returning a 32-byte Uint8Array.
|
|
55
|
+
function sha256Bytes(bytes) {
|
|
56
|
+
const len = bytes.length;
|
|
57
|
+
|
|
58
|
+
// ---- pad: 0x80, zero fill to 56 mod 64, then the 64-bit big-endian BIT length --------------------------
|
|
59
|
+
const total = Math.ceil((len + 9) / 64) * 64;
|
|
60
|
+
const msg = new Uint8Array(total); // zero-filled by construction
|
|
61
|
+
for (let i = 0; i < len; i++) msg[i] = bytes[i] & 0xff;
|
|
62
|
+
msg[len] = 0x80;
|
|
63
|
+
// Bit length as two 32-bit big-endian words. len < 2^53 in JS; the high word is floor(len*8 / 2^32)
|
|
64
|
+
// = floor(len / 2^29), the low word is (len*8) mod 2^32 (which is exactly what << gives).
|
|
65
|
+
const hiBits = Math.floor(len / 0x20000000);
|
|
66
|
+
const loBits = (len << 3) >>> 0;
|
|
67
|
+
msg[total - 8] = (hiBits >>> 24) & 0xff;
|
|
68
|
+
msg[total - 7] = (hiBits >>> 16) & 0xff;
|
|
69
|
+
msg[total - 6] = (hiBits >>> 8) & 0xff;
|
|
70
|
+
msg[total - 5] = hiBits & 0xff;
|
|
71
|
+
msg[total - 4] = (loBits >>> 24) & 0xff;
|
|
72
|
+
msg[total - 3] = (loBits >>> 16) & 0xff;
|
|
73
|
+
msg[total - 2] = (loBits >>> 8) & 0xff;
|
|
74
|
+
msg[total - 1] = loBits & 0xff;
|
|
75
|
+
|
|
76
|
+
// ---- FIPS 180-4 initial hash value ---------------------------------------------------------------------
|
|
77
|
+
let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;
|
|
78
|
+
let h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
|
|
79
|
+
|
|
80
|
+
const w = new Array(64);
|
|
81
|
+
|
|
82
|
+
// ---- compress each 64-byte block -----------------------------------------------------------------------
|
|
83
|
+
for (let off = 0; off < total; off += 64) {
|
|
84
|
+
// message schedule: 16 big-endian words from the block, expanded to 64
|
|
85
|
+
for (let i = 0; i < 16; i++) {
|
|
86
|
+
const b = off + i * 4;
|
|
87
|
+
w[i] = ((msg[b] << 24) | (msg[b + 1] << 16) | (msg[b + 2] << 8) | msg[b + 3]) >>> 0;
|
|
88
|
+
}
|
|
89
|
+
for (let i = 16; i < 64; i++) {
|
|
90
|
+
const s0 = (rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3)) >>> 0;
|
|
91
|
+
const s1 = (rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10)) >>> 0;
|
|
92
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
|
|
96
|
+
|
|
97
|
+
for (let i = 0; i < 64; i++) {
|
|
98
|
+
const S1 = (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) >>> 0;
|
|
99
|
+
const ch = ((e & f) ^ (~e & g)) >>> 0;
|
|
100
|
+
const temp1 = (h + S1 + ch + K[i] + w[i]) >>> 0;
|
|
101
|
+
const S0 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) >>> 0;
|
|
102
|
+
const maj = ((a & b) ^ (a & c) ^ (b & c)) >>> 0;
|
|
103
|
+
const temp2 = (S0 + maj) >>> 0;
|
|
104
|
+
h = g;
|
|
105
|
+
g = f;
|
|
106
|
+
f = e;
|
|
107
|
+
e = (d + temp1) >>> 0;
|
|
108
|
+
d = c;
|
|
109
|
+
c = b;
|
|
110
|
+
b = a;
|
|
111
|
+
a = (temp1 + temp2) >>> 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
h0 = (h0 + a) >>> 0;
|
|
115
|
+
h1 = (h1 + b) >>> 0;
|
|
116
|
+
h2 = (h2 + c) >>> 0;
|
|
117
|
+
h3 = (h3 + d) >>> 0;
|
|
118
|
+
h4 = (h4 + e) >>> 0;
|
|
119
|
+
h5 = (h5 + f) >>> 0;
|
|
120
|
+
h6 = (h6 + g) >>> 0;
|
|
121
|
+
h7 = (h7 + h) >>> 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ---- emit the 8 words big-endian ------------------------------------------------------------------------
|
|
125
|
+
const out = new Uint8Array(32);
|
|
126
|
+
const hs = [h0, h1, h2, h3, h4, h5, h6, h7];
|
|
127
|
+
for (let i = 0; i < 8; i++) {
|
|
128
|
+
out[i * 4] = (hs[i] >>> 24) & 0xff;
|
|
129
|
+
out[i * 4 + 1] = (hs[i] >>> 16) & 0xff;
|
|
130
|
+
out[i * 4 + 2] = (hs[i] >>> 8) & 0xff;
|
|
131
|
+
out[i * 4 + 3] = hs[i] & 0xff;
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Lowercase hex (no 0x prefix) of a byte array — matches crypto's .digest("hex").
|
|
137
|
+
function toHex(bytes) {
|
|
138
|
+
let s = "";
|
|
139
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
140
|
+
const b = bytes[i] & 0xff;
|
|
141
|
+
s += (b < 16 ? "0" : "") + b.toString(16);
|
|
142
|
+
}
|
|
143
|
+
return s;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* WHATWG/Node-compatible UTF-8 encoder for a JS string: surrogate pairs are combined into their
|
|
148
|
+
* astral code point; LONE surrogates are replaced with U+FFFD (byte-for-byte what BOTH
|
|
149
|
+
* Buffer.from(s, "utf8") and TextEncoder emit). Pure; no TextEncoder, no Buffer.
|
|
150
|
+
* @param {string} str the JS (UTF-16) string to encode
|
|
151
|
+
* @returns {Uint8Array} the UTF-8 bytes
|
|
152
|
+
*/
|
|
153
|
+
function utf8Bytes(str) {
|
|
154
|
+
if (typeof str !== "string") {
|
|
155
|
+
throw new TypeError("utf8Bytes requires a string");
|
|
156
|
+
}
|
|
157
|
+
const out = [];
|
|
158
|
+
for (let i = 0; i < str.length; i++) {
|
|
159
|
+
let cp = str.charCodeAt(i);
|
|
160
|
+
if (cp >= 0xd800 && cp <= 0xdbff) {
|
|
161
|
+
// high surrogate: pair with a following low surrogate, else U+FFFD
|
|
162
|
+
const next = i + 1 < str.length ? str.charCodeAt(i + 1) : 0;
|
|
163
|
+
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
164
|
+
cp = 0x10000 + ((cp - 0xd800) << 10) + (next - 0xdc00);
|
|
165
|
+
i++;
|
|
166
|
+
} else {
|
|
167
|
+
cp = 0xfffd;
|
|
168
|
+
}
|
|
169
|
+
} else if (cp >= 0xdc00 && cp <= 0xdfff) {
|
|
170
|
+
// lone low surrogate
|
|
171
|
+
cp = 0xfffd;
|
|
172
|
+
}
|
|
173
|
+
if (cp < 0x80) {
|
|
174
|
+
out.push(cp);
|
|
175
|
+
} else if (cp < 0x800) {
|
|
176
|
+
out.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
|
|
177
|
+
} else if (cp < 0x10000) {
|
|
178
|
+
out.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
|
|
179
|
+
} else {
|
|
180
|
+
out.push(
|
|
181
|
+
0xf0 | (cp >> 18),
|
|
182
|
+
0x80 | ((cp >> 12) & 0x3f),
|
|
183
|
+
0x80 | ((cp >> 6) & 0x3f),
|
|
184
|
+
0x80 | (cp & 0x3f)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return Uint8Array.from(out);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* SHA-256 over a byte buffer.
|
|
193
|
+
* @param {Uint8Array|Buffer|number[]} bytes input bytes
|
|
194
|
+
* @returns {Uint8Array} the 32-byte digest
|
|
195
|
+
*/
|
|
196
|
+
function sha256(bytes) {
|
|
197
|
+
if (
|
|
198
|
+
!(bytes instanceof Uint8Array) &&
|
|
199
|
+
!Array.isArray(bytes) &&
|
|
200
|
+
!(typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(bytes))
|
|
201
|
+
) {
|
|
202
|
+
throw new TypeError("sha256 requires a Uint8Array/Buffer/byte-array of input bytes");
|
|
203
|
+
}
|
|
204
|
+
return sha256Bytes(bytes);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* SHA-256 over a byte buffer, returned as a lowercase hex string WITHOUT a 0x prefix
|
|
209
|
+
* (matching crypto.createHash("sha256").update(bytes).digest("hex"), for drop-in cross-checking).
|
|
210
|
+
* @param {Uint8Array|Buffer|number[]} bytes input bytes
|
|
211
|
+
* @returns {string} 64-char lowercase hex
|
|
212
|
+
*/
|
|
213
|
+
function sha256Hex(bytes) {
|
|
214
|
+
return toHex(sha256(bytes));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* SHA-256 of a JS string's UTF-8 bytes, as lowercase hex — the exact drop-in for
|
|
219
|
+
* crypto.createHash("sha256").update(str, "utf8").digest("hex") (the one call close.js makes).
|
|
220
|
+
* @param {string} str the string to hash as UTF-8
|
|
221
|
+
* @returns {string} 64-char lowercase hex
|
|
222
|
+
*/
|
|
223
|
+
function sha256HexUtf8(str) {
|
|
224
|
+
return toHex(sha256Bytes(utf8Bytes(str)));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = { sha256, sha256Hex, sha256HexUtf8, utf8Bytes };
|