noa-receipt
Version:
NOA Agent Action Receipt — open, offline-verifiable provenance for AI-agent actions. The governance/receipt organ only; the NOA brain is separate and proprietary.
190 lines (189 loc) • 4.86 kB
JavaScript
import { strCharCodeAt } from "./intrinsics.js";
const ZERO = 0x30;
const NINE = 0x39;
const LOWER_A = 0x61;
const LOWER_F = 0x66;
const UPPER_A = 0x41;
const UPPER_F = 0x46;
const COLON = 0x3a;
const DASH = 0x2d;
const PLUS = 0x2b;
const DOT = 0x2e;
const T_UPPER = 0x54;
const T_LOWER = 0x74;
const Z_UPPER = 0x5a;
const Z_LOWER = 0x7a;
function at(s, i) {
return strCharCodeAt(s, i);
}
function isDigit(c) {
return c >= ZERO && c <= NINE;
}
function isLowerHex(c) {
return (c >= ZERO && c <= NINE) || (c >= LOWER_A && c <= LOWER_F);
}
function isAnyHex(c) {
return (c >= ZERO && c <= NINE) || (c >= LOWER_A && c <= LOWER_F) || (c >= UPPER_A && c <= UPPER_F);
}
function lowerHexRun(s, from, n) {
for (let i = 0; i < n; i++) {
if (!isLowerHex(at(s, from + i)))
return false;
}
return true;
}
function digitRun(s, from, n) {
for (let i = 0; i < n; i++) {
if (!isDigit(at(s, from + i)))
return false;
}
return true;
}
function hasPrefix(s, lit) {
const n = lit.length;
if (s.length < n)
return false;
for (let i = 0; i < n; i++) {
if (at(s, i) !== at(lit, i))
return false;
}
return true;
}
export function isSha256Hash(s) {
if (typeof s !== "string")
return false;
if (s.length !== 71)
return false;
if (!hasPrefix(s, "sha256:"))
return false;
return lowerHexRun(s, 7, 64);
}
export function isParamsHash(s) {
if (typeof s !== "string")
return false;
if (s.length === 71 && hasPrefix(s, "sha256:"))
return lowerHexRun(s, 7, 64);
if (s.length === 76 && hasPrefix(s, "hmac-sha256:"))
return lowerHexRun(s, 12, 64);
return false;
}
export function isHex64(s) {
if (typeof s !== "string")
return false;
if (s.length !== 64)
return false;
return lowerHexRun(s, 0, 64);
}
export function isHex4(s) {
if (typeof s !== "string" || s.length !== 4)
return false;
for (let i = 0; i < 4; i++) {
if (!isAnyHex(at(s, i)))
return false;
}
return true;
}
export function isRfc3339(s) {
if (typeof s !== "string")
return false;
const n = s.length;
if (n < 20)
return false;
if (!digitRun(s, 0, 4))
return false;
if (at(s, 4) !== DASH)
return false;
if (!digitRun(s, 5, 2))
return false;
if (at(s, 7) !== DASH)
return false;
if (!digitRun(s, 8, 2))
return false;
const t = at(s, 10);
if (t !== T_UPPER && t !== T_LOWER)
return false;
if (!digitRun(s, 11, 2))
return false;
if (at(s, 13) !== COLON)
return false;
if (!digitRun(s, 14, 2))
return false;
if (at(s, 16) !== COLON)
return false;
if (!digitRun(s, 17, 2))
return false;
let i = 19;
if (at(s, i) === DOT) {
i++;
let frac = 0;
while (i < n && isDigit(at(s, i))) {
frac++;
i++;
}
if (frac < 1 || frac > 9)
return false;
}
const z = at(s, i);
if (z === Z_UPPER || z === Z_LOWER)
return i === n - 1;
if (z !== PLUS && z !== DASH)
return false;
if (n - i !== 6)
return false;
if (!digitRun(s, i + 1, 2))
return false;
if (at(s, i + 3) !== COLON)
return false;
return digitRun(s, i + 4, 2);
}
function num2(s, from) {
return (at(s, from) - ZERO) * 10 + (at(s, from + 1) - ZERO);
}
function num4(s, from) {
return ((at(s, from) - ZERO) * 1000 +
(at(s, from + 1) - ZERO) * 100 +
(at(s, from + 2) - ZERO) * 10 +
(at(s, from + 3) - ZERO));
}
function isLeapYear(y) {
if (y % 4 !== 0)
return false;
if (y % 100 !== 0)
return true;
return y % 400 === 0;
}
function daysInMonth(year, month) {
if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12)
return 31;
if (month === 4 || month === 6 || month === 9 || month === 11)
return 30;
if (month === 2)
return isLeapYear(year) ? 29 : 28;
return 0;
}
export function isRfc3339Instant(s) {
if (!isRfc3339(s))
return false;
const year = num4(s, 0);
const month = num2(s, 5);
const day = num2(s, 8);
if (month < 1 || month > 12)
return false;
if (day < 1 || day > daysInMonth(year, month))
return false;
if (num2(s, 11) > 23)
return false;
if (num2(s, 14) > 59)
return false;
if (num2(s, 17) > 60)
return false;
const n = s.length;
const last = at(s, n - 1);
if (last === Z_UPPER || last === Z_LOWER)
return true;
if (num2(s, n - 5) > 23)
return false;
if (num2(s, n - 2) > 59)
return false;
return true;
}