diff --git a/03_Script_Starter_Kit/binary_utils.mjs b/03_Script_Starter_Kit/binary_utils.mjs index b31e720..786b16c 100644 --- a/03_Script_Starter_Kit/binary_utils.mjs +++ b/03_Script_Starter_Kit/binary_utils.mjs @@ -6,38 +6,199 @@ export function requireBytes(data) { } export function assertRange(data, offset, length) { requireBytes(data); - if (!Number.isInteger(offset)||!Number.isInteger(length)||offset<0||length<0||offset+length>data.length) throw new RangeError("Range outside buffer"); + if ( + !Number.isInteger(offset) || + !Number.isInteger(length) || + offset < 0 || + length < 0 || + offset + length > data.length + ) + throw new RangeError("Range outside buffer"); } -export function cloneBytes(data){ requireBytes(data); return new Uint8Array(data); } -export function sliceBytes(data,offset,length){ assertRange(data,offset,length); return data.slice(offset,offset+length); } -export function bytesToHex(data,separator=" "){ requireBytes(data); return Array.from(data,b=>b.toString(16).padStart(2,"0")).join(separator).toUpperCase(); } -export function hexToBytes(text){ - const input=String(text); - if(/[^0-9a-f\s,:-]/i.test(input)) throw new Error("Invalid character in hex text"); - const s=input.replace(/[\s,:-]/g,""); - if(s.length%2) throw new Error("Hex text must contain complete bytes"); - const out=new Uint8Array(s.length/2); for(let i=0;i b.toString(16).padStart(2, "0")) + .join(separator) + .toUpperCase(); +} +export function hexToBytes(text) { + const input = String(text); + if (/[^0-9a-f\s,:-]/i.test(input)) + throw new Error("Invalid character in hex text"); + const s = input.replace(/[\s,:-]/g, ""); + if (s.length % 2) throw new Error("Hex text must contain complete bytes"); + const out = new Uint8Array(s.length / 2); + for (let i = 0; i < out.length; i++) + out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16); + return out; +} +export function asciiPreview(data, replacement = ".") { + requireBytes(data); + return Array.from(data, (b) => + b >= 32 && b <= 126 ? String.fromCharCode(b) : replacement, + ).join(""); +} +export function readU16LE(d, o) { + assertRange(d, o, 2); + return d[o] | (d[o + 1] << 8); +} +export function readU16BE(d, o) { + assertRange(d, o, 2); + return (d[o] << 8) | d[o + 1]; +} +export function readU32LE(d, o) { + assertRange(d, o, 4); + return (d[o] | (d[o + 1] << 8) | (d[o + 2] << 16) | (d[o + 3] << 24)) >>> 0; +} +export function readU32BE(d, o) { + assertRange(d, o, 4); + return ((d[o] << 24) | (d[o + 1] << 16) | (d[o + 2] << 8) | d[o + 3]) >>> 0; +} +export function writeU16LE(d, o, v) { + assertRange(d, o, 2); + d[o] = v & 255; + d[o + 1] = (v >>> 8) & 255; +} +export function writeU16BE(d, o, v) { + assertRange(d, o, 2); + d[o] = (v >>> 8) & 255; + d[o + 1] = v & 255; +} +export function writeU32LE(d, o, v) { + assertRange(d, o, 4); + for (let i = 0; i < 4; i++) d[o + i] = (v >>> (8 * i)) & 255; +} +export function writeU32BE(d, o, v) { + assertRange(d, o, 4); + for (let i = 0; i < 4; i++) d[o + i] = (v >>> (8 * (3 - i))) & 255; +} +export function findPattern(data, pattern, start = 0) { + requireBytes(data); + requireBytes(pattern); + const hits = []; + for (let i = start; i <= data.length - pattern.length; i++) { + let ok = true; + for (let j = 0; j < pattern.length; j++) + if (data[i + j] !== pattern[j]) { + ok = false; + break; + } + if (ok) hits.push(i); + } + return hits; +} +export function countByte(data, value) { + requireBytes(data); + let n = 0; + for (const b of data) if (b === (value & 255)) n++; + return n; +} +export function isBlank( + data, + offset = 0, + length = data.length - offset, + blank = 0xff, +) { + assertRange(data, offset, length); + for (let i = offset; i < offset + length; i++) + if (data[i] !== blank) return false; + return true; +} +export function diffRanges(a, b) { + requireBytes(a); + requireBytes(b); + if (a.length !== b.length) throw new Error("Length mismatch"); + const out = []; + let s = -1; + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i] && s < 0) s = i; + if ((a[i] === b[i] || i === a.length - 1) && s >= 0) { + const e = a[i] === b[i] ? i - 1 : i; + out.push({ start: s, end: e, length: e - s + 1 }); + s = -1; + } + } + return out; +} +export function changedByteCount(a, b) { + return diffRanges(a, b).reduce((n, r) => n + r.length, 0); +} +export function sum8(data) { + requireBytes(data); + let s = 0; + for (const b of data) s = (s + b) & 255; + return s; +} +export function xor8(data) { + requireBytes(data); + let x = 0; + for (const b of data) x ^= b; + return x; +} +export function crc16CcittFalse(data) { + requireBytes(data); + let crc = 0xffff; + for (const b of data) { + crc ^= b << 8; + for (let i = 0; i < 8; i++) + crc = (crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1) & 0xffff; + } + return crc; +} +export function crc32(data) { + requireBytes(data); + let crc = 0xffffffff; + for (const b of data) { + crc ^= b; + for (let i = 0; i < 8; i++) crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0); + } + return (crc ^ 0xffffffff) >>> 0; +} +export function adler32(data) { + requireBytes(data); + let a = 1, + b = 0; + for (const v of data) { + a = (a + v) % 65521; + b = (b + a) % 65521; + } + return ((b << 16) | a) >>> 0; +} +export function bcdToInt(byte) { + const hi = (byte >>> 4) & 15, + lo = byte & 15; + if (hi > 9 || lo > 9) throw new Error("Invalid BCD"); + return hi * 10 + lo; +} +export function intToBcd(value) { + if (!Number.isInteger(value) || value < 0 || value > 99) + throw new RangeError("BCD value must be 0..99"); + return (Math.floor(value / 10) << 4) | (value % 10); +} +export function constantTimeEqual(a, b) { + requireBytes(a); + requireBytes(b); + if (a.length !== b.length) return false; + let d = 0; + for (let i = 0; i < a.length; i++) d |= a[i] ^ b[i]; + return d === 0; +} +export function allowListedWrite(copy, offset, newBytes, allowedRanges) { + requireBytes(copy); + requireBytes(newBytes); + assertRange(copy, offset, newBytes.length); + const ok = allowedRanges.some( + (r) => offset >= r.start && offset + newBytes.length - 1 <= r.end, + ); + if (!ok) throw new Error("Write is outside allow-list"); + copy.set(newBytes, offset); + return copy; } -export function asciiPreview(data,replacement="."){ requireBytes(data); return Array.from(data,b=>b>=32&&b<=126?String.fromCharCode(b):replacement).join(""); } -export function readU16LE(d,o){assertRange(d,o,2);return d[o]|(d[o+1]<<8);} -export function readU16BE(d,o){assertRange(d,o,2);return (d[o]<<8)|d[o+1];} -export function readU32LE(d,o){assertRange(d,o,4);return (d[o]|d[o+1]<<8|d[o+2]<<16|d[o+3]<<24)>>>0;} -export function readU32BE(d,o){assertRange(d,o,4);return ((d[o]<<24)|(d[o+1]<<16)|(d[o+2]<<8)|d[o+3])>>>0;} -export function writeU16LE(d,o,v){assertRange(d,o,2);d[o]=v&255;d[o+1]=(v>>>8)&255;} -export function writeU16BE(d,o,v){assertRange(d,o,2);d[o]=(v>>>8)&255;d[o+1]=v&255;} -export function writeU32LE(d,o,v){assertRange(d,o,4);for(let i=0;i<4;i++)d[o+i]=(v>>>(8*i))&255;} -export function writeU32BE(d,o,v){assertRange(d,o,4);for(let i=0;i<4;i++)d[o+i]=(v>>>(8*(3-i)))&255;} -export function findPattern(data,pattern,start=0){requireBytes(data);requireBytes(pattern);const hits=[];for(let i=start;i<=data.length-pattern.length;i++){let ok=true;for(let j=0;j=0){const e=a[i]===b[i]?i-1:i;out.push({start:s,end:e,length:e-s+1});s=-1;}}return out;} -export function changedByteCount(a,b){return diffRanges(a,b).reduce((n,r)=>n+r.length,0);} -export function sum8(data){requireBytes(data);let s=0;for(const b of data)s=(s+b)&255;return s;} -export function xor8(data){requireBytes(data);let x=0;for(const b of data)x^=b;return x;} -export function crc16CcittFalse(data){requireBytes(data);let crc=0xFFFF;for(const b of data){crc^=b<<8;for(let i=0;i<8;i++)crc=((crc&0x8000)?(crc<<1)^0x1021:crc<<1)&0xFFFF;}return crc;} -export function crc32(data){requireBytes(data);let crc=0xFFFFFFFF;for(const b of data){crc^=b;for(let i=0;i<8;i++)crc=(crc>>>1)^((crc&1)?0xEDB88320:0);}return (crc^0xFFFFFFFF)>>>0;} -export function adler32(data){requireBytes(data);let a=1,b=0;for(const v of data){a=(a+v)%65521;b=(b+a)%65521;}return ((b<<16)|a)>>>0;} -export function bcdToInt(byte){const hi=(byte>>>4)&15,lo=byte&15;if(hi>9||lo>9)throw new Error("Invalid BCD");return hi*10+lo;} -export function intToBcd(value){if(!Number.isInteger(value)||value<0||value>99)throw new RangeError("BCD value must be 0..99");return ((Math.floor(value/10)<<4)|(value%10));} -export function constantTimeEqual(a,b){requireBytes(a);requireBytes(b);if(a.length!==b.length)return false;let d=0;for(let i=0;ioffset>=r.start&&offset+newBytes.length-1<=r.end);if(!ok)throw new Error("Write is outside allow-list");copy.set(newBytes,offset);return copy;} diff --git a/03_Script_Starter_Kit/examples/01_read_only_inspector.mjs b/03_Script_Starter_Kit/examples/01_read_only_inspector.mjs index fdff63e..ab4c9ed 100644 --- a/03_Script_Starter_Kit/examples/01_read_only_inspector.mjs +++ b/03_Script_Starter_Kit/examples/01_read_only_inspector.mjs @@ -1,2 +1,15 @@ -import { bytesToHex, asciiPreview, countByte, crc32 } from "../binary_utils.mjs"; -export function inspect(data){return {length:data.length,first32:bytesToHex(data.slice(0,32)),ascii:asciiPreview(data.slice(0,64)),ffBytes:countByte(data,0xFF),crc32:crc32(data).toString(16).padStart(8,"0").toUpperCase()};} +import { + bytesToHex, + asciiPreview, + countByte, + crc32, +} from "../binary_utils.mjs"; +export function inspect(data) { + return { + length: data.length, + first32: bytesToHex(data.slice(0, 32)), + ascii: asciiPreview(data.slice(0, 64)), + ffBytes: countByte(data, 0xff), + crc32: crc32(data).toString(16).padStart(8, "0").toUpperCase(), + }; +} diff --git a/03_Script_Starter_Kit/examples/02_double_read_verifier.mjs b/03_Script_Starter_Kit/examples/02_double_read_verifier.mjs index 34352da..01048ee 100644 --- a/03_Script_Starter_Kit/examples/02_double_read_verifier.mjs +++ b/03_Script_Starter_Kit/examples/02_double_read_verifier.mjs @@ -1,2 +1,9 @@ import { constantTimeEqual, crc32 } from "../binary_utils.mjs"; -export function verifyTwoReads(a,b){return {sameLength:a.length===b.length,identical:constantTimeEqual(a,b),crcA:crc32(a),crcB:crc32(b)};} +export function verifyTwoReads(a, b) { + return { + sameLength: a.length === b.length, + identical: constantTimeEqual(a, b), + crcA: crc32(a), + crcB: crc32(b), + }; +} diff --git a/03_Script_Starter_Kit/examples/03_pattern_inventory.mjs b/03_Script_Starter_Kit/examples/03_pattern_inventory.mjs index 73c0153..78e843a 100644 --- a/03_Script_Starter_Kit/examples/03_pattern_inventory.mjs +++ b/03_Script_Starter_Kit/examples/03_pattern_inventory.mjs @@ -1,2 +1,7 @@ import { findPattern, hexToBytes } from "../binary_utils.mjs"; -export function inventory(data,patterns){return patterns.map(p=>({label:p.label,offsets:findPattern(data,hexToBytes(p.hex))}));} +export function inventory(data, patterns) { + return patterns.map((p) => ({ + label: p.label, + offsets: findPattern(data, hexToBytes(p.hex)), + })); +} diff --git a/03_Script_Starter_Kit/examples/04_allowlisted_patch_demo.mjs b/03_Script_Starter_Kit/examples/04_allowlisted_patch_demo.mjs index c1e41fd..1cc8a82 100644 --- a/03_Script_Starter_Kit/examples/04_allowlisted_patch_demo.mjs +++ b/03_Script_Starter_Kit/examples/04_allowlisted_patch_demo.mjs @@ -1,3 +1,9 @@ import { cloneBytes, allowListedWrite, diffRanges } from "../binary_utils.mjs"; // Synthetic demonstration only. No vehicle-security data or real module offsets. -export function demo(input){const output=cloneBytes(input);allowListedWrite(output,4,new Uint8Array([0xAA,0x55]),[{start:4,end:5}]);return {output,changes:diffRanges(input,output)};} +export function demo(input) { + const output = cloneBytes(input); + allowListedWrite(output, 4, new Uint8Array([0xaa, 0x55]), [ + { start: 4, end: 5 }, + ]); + return { output, changes: diffRanges(input, output) }; +} diff --git a/03_Script_Starter_Kit/examples/05_checksum_test_vectors.mjs b/03_Script_Starter_Kit/examples/05_checksum_test_vectors.mjs index 9a0b867..64c14c2 100644 --- a/03_Script_Starter_Kit/examples/05_checksum_test_vectors.mjs +++ b/03_Script_Starter_Kit/examples/05_checksum_test_vectors.mjs @@ -1,2 +1,14 @@ -import { hexToBytes,crc16CcittFalse,crc32,adler32 } from "../binary_utils.mjs"; -export function selfTest(){const d=new TextEncoder().encode("123456789");return {crc16Ok:crc16CcittFalse(d)===0x29B1,crc32Ok:crc32(d)===0xCBF43926,adler32:adler32(d)};} +import { + hexToBytes, + crc16CcittFalse, + crc32, + adler32, +} from "../binary_utils.mjs"; +export function selfTest() { + const d = new TextEncoder().encode("123456789"); + return { + crc16Ok: crc16CcittFalse(d) === 0x29b1, + crc32Ok: crc32(d) === 0xcbf43926, + adler32: adler32(d), + }; +} diff --git a/03_Script_Starter_Kit/examples/06_authorized_job_record_validator.mjs b/03_Script_Starter_Kit/examples/06_authorized_job_record_validator.mjs index 441c3d9..54192ca 100644 --- a/03_Script_Starter_Kit/examples/06_authorized_job_record_validator.mjs +++ b/03_Script_Starter_Kit/examples/06_authorized_job_record_validator.mjs @@ -1,2 +1,17 @@ -const REQUIRED=["caseId","customerName","vehicleVin","proofOfOwnershipRef","authorizationRef","technician","timestampUtc","requestedService"]; -export function validateAuthorizedJob(job){const missing=REQUIRED.filter(k=>!String(job[k]??"").trim());const vinOk=/^[A-HJ-NPR-Z0-9]{17}$/.test(String(job.vehicleVin||"").toUpperCase());return {valid:missing.length===0&&vinOk,missing,vinOk};} +const REQUIRED = [ + "caseId", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "technician", + "timestampUtc", + "requestedService", +]; +export function validateAuthorizedJob(job) { + const missing = REQUIRED.filter((k) => !String(job[k] ?? "").trim()); + const vinOk = /^[A-HJ-NPR-Z0-9]{17}$/.test( + String(job.vehicleVin || "").toUpperCase(), + ); + return { valid: missing.length === 0 && vinOk, missing, vinOk }; +} diff --git a/03_Script_Starter_Kit/examples/07_key_inventory_audit.mjs b/03_Script_Starter_Kit/examples/07_key_inventory_audit.mjs index b141227..01b1483 100644 --- a/03_Script_Starter_Kit/examples/07_key_inventory_audit.mjs +++ b/03_Script_Starter_Kit/examples/07_key_inventory_audit.mjs @@ -1,2 +1,12 @@ // Administrative inventory only. Does not calculate, extract, clone, generate or program credentials. -export function auditKeyInventory(entries){return entries.map((e,i)=>({row:i+1,assetTag:String(e.assetTag||""),type:String(e.type||""),source:String(e.source||""),sealed:Boolean(e.sealed),assigned:Boolean(e.assigned),notes:String(e.notes||"")}));} +export function auditKeyInventory(entries) { + return entries.map((e, i) => ({ + row: i + 1, + assetTag: String(e.assetTag || ""), + type: String(e.type || ""), + source: String(e.source || ""), + sealed: Boolean(e.sealed), + assigned: Boolean(e.assigned), + notes: String(e.notes || ""), + })); +} diff --git a/03_Script_Starter_Kit/examples/08_redacted_security_report.mjs b/03_Script_Starter_Kit/examples/08_redacted_security_report.mjs index c1ab527..fb292c8 100644 --- a/03_Script_Starter_Kit/examples/08_redacted_security_report.mjs +++ b/03_Script_Starter_Kit/examples/08_redacted_security_report.mjs @@ -1,2 +1,16 @@ -export function redact(value,keepLast=4){const s=String(value??"");return s.length<=keepLast?"*".repeat(s.length):"*".repeat(s.length-keepLast)+s.slice(-keepLast);} -export function securityReport(job){return {caseId:job.caseId,vin:redact(job.vehicleVin,6),authorizationRef:redact(job.authorizationRef,4),technician:job.technician,timestampUtc:job.timestampUtc,status:job.status};} +export function redact(value, keepLast = 4) { + const s = String(value ?? ""); + return s.length <= keepLast + ? "*".repeat(s.length) + : "*".repeat(s.length - keepLast) + s.slice(-keepLast); +} +export function securityReport(job) { + return { + caseId: job.caseId, + vin: redact(job.vehicleVin, 6), + authorizationRef: redact(job.authorizationRef, 4), + technician: job.technician, + timestampUtc: job.timestampUtc, + status: job.status, + }; +} diff --git a/03_Script_Starter_Kit/examples/32_dump_fingerprint.mjs b/03_Script_Starter_Kit/examples/32_dump_fingerprint.mjs index 60b6515..441c261 100644 --- a/03_Script_Starter_Kit/examples/32_dump_fingerprint.mjs +++ b/03_Script_Starter_Kit/examples/32_dump_fingerprint.mjs @@ -6,8 +6,8 @@ export function fingerprintDump(data, sourceName = "synthetic-buffer") { length: data.length, crc32: crc32(data).toString(16).padStart(8, "0").toUpperCase(), adler32: adler32(data).toString(16).padStart(8, "0").toUpperCase(), - ffBytes: countByte(data, 0xFF), + ffBytes: countByte(data, 0xff), first16: bytesToHex(data.slice(0, 16)), - last16: bytesToHex(data.slice(-16)) + last16: bytesToHex(data.slice(-16)), }; } diff --git a/03_Script_Starter_Kit/examples/33_structured_change_report.mjs b/03_Script_Starter_Kit/examples/33_structured_change_report.mjs index 4ce7178..0e85310 100644 --- a/03_Script_Starter_Kit/examples/33_structured_change_report.mjs +++ b/03_Script_Starter_Kit/examples/33_structured_change_report.mjs @@ -10,10 +10,16 @@ export function buildChangeReport(original, candidate, allowedRanges = []) { changedBytes: changedByteCount(original, candidate), changedRanges: ranges.map((range) => ({ ...range, - allowed: allowedRanges.some((allowed) => rangeContains(allowed, range.start, range.end)), + allowed: allowedRanges.some((allowed) => + rangeContains(allowed, range.start, range.end), + ), before: bytesToHex(original.slice(range.start, range.end + 1)), - after: bytesToHex(candidate.slice(range.start, range.end + 1)) + after: bytesToHex(candidate.slice(range.start, range.end + 1)), })), - approved: ranges.every((range) => allowedRanges.some((allowed) => rangeContains(allowed, range.start, range.end))) + approved: ranges.every((range) => + allowedRanges.some((allowed) => + rangeContains(allowed, range.start, range.end), + ), + ), }; } diff --git a/03_Script_Starter_Kit/examples/34_checksum_model_selector.mjs b/03_Script_Starter_Kit/examples/34_checksum_model_selector.mjs index 7f6d86c..7a8dab2 100644 --- a/03_Script_Starter_Kit/examples/34_checksum_model_selector.mjs +++ b/03_Script_Starter_Kit/examples/34_checksum_model_selector.mjs @@ -2,7 +2,10 @@ Demonstrates the generic CRC engine pattern (see 17_MultiPROG_SDK/utilities/crc_engine.mjs) so a script can pick a named checksum model at runtime instead of hard-coding one algorithm. Read-only: computes and reports checksums, never writes to a module. */ -import { crcNamed, CRC_MODELS } from "../../17_MultiPROG_SDK/utilities/crc_engine.mjs"; +import { + crcNamed, + CRC_MODELS, +} from "../../17_MultiPROG_SDK/utilities/crc_engine.mjs"; import { fileURLToPath } from "node:url"; export function checksumReport(data, modelNames = Object.keys(CRC_MODELS)) { diff --git a/03_Script_Starter_Kit/examples/35_flash_sector_map_parser.mjs b/03_Script_Starter_Kit/examples/35_flash_sector_map_parser.mjs index e016a04..f3ad027 100644 --- a/03_Script_Starter_Kit/examples/35_flash_sector_map_parser.mjs +++ b/03_Script_Starter_Kit/examples/35_flash_sector_map_parser.mjs @@ -3,14 +3,22 @@ Sector boundaries are platform/part-specific and must be supplied by the caller (from the exact part's datasheet or tool vendor documentation) — never assumed. See 04_Workflows/MCU_READ_WRITE_WORKFLOW.md and 01_Knowledge_Base/AUTOMOTIVE_MEMORY_CONCEPTS.md. */ -import { requireBytes, assertRange, sliceBytes, isBlank, crc32 } from "../binary_utils.mjs"; +import { + requireBytes, + assertRange, + sliceBytes, + isBlank, + crc32, +} from "../binary_utils.mjs"; -export function parseSectorMap(data, sectors, blankValue = 0xFF) { +export function parseSectorMap(data, sectors, blankValue = 0xff) { requireBytes(data); - if (!Array.isArray(sectors) || sectors.length === 0) throw new Error("sectors must be a non-empty array"); + if (!Array.isArray(sectors) || sectors.length === 0) + throw new Error("sectors must be a non-empty array"); return sectors.map((sector) => { const { name, start, length } = sector; - if (typeof name !== "string" || !name) throw new Error("sector.name must be a non-empty string"); + if (typeof name !== "string" || !name) + throw new Error("sector.name must be a non-empty string"); assertRange(data, start, length); const region = sliceBytes(data, start, length); return { @@ -23,8 +31,13 @@ export function parseSectorMap(data, sectors, blankValue = 0xFF) { }); } -export function summarizeSectorMap(data, sectors, blankValue = 0xFF) { +export function summarizeSectorMap(data, sectors, blankValue = 0xff) { const parsed = parseSectorMap(data, sectors, blankValue); const blankCount = parsed.filter((s) => s.blank).length; - return { totalSectors: parsed.length, blankSectors: blankCount, usedSectors: parsed.length - blankCount, sectors: parsed }; + return { + totalSectors: parsed.length, + blankSectors: blankCount, + usedSectors: parsed.length - blankCount, + sectors: parsed, + }; } diff --git a/03_Script_Starter_Kit/examples/36_vin_extractor_validator.mjs b/03_Script_Starter_Kit/examples/36_vin_extractor_validator.mjs index bbc373c..d6ba35f 100644 --- a/03_Script_Starter_Kit/examples/36_vin_extractor_validator.mjs +++ b/03_Script_Starter_Kit/examples/36_vin_extractor_validator.mjs @@ -6,9 +6,29 @@ import { requireBytes, assertRange } from "../binary_utils.mjs"; const TRANSLITERATION = { - A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7, H: 8, - J: 1, K: 2, L: 3, M: 4, N: 5, P: 7, R: 9, - S: 2, T: 3, U: 4, V: 5, W: 6, X: 7, Y: 8, Z: 9, + A: 1, + B: 2, + C: 3, + D: 4, + E: 5, + F: 6, + G: 7, + H: 8, + J: 1, + K: 2, + L: 3, + M: 4, + N: 5, + P: 7, + R: 9, + S: 2, + T: 3, + U: 4, + V: 5, + W: 6, + X: 7, + Y: 8, + Z: 9, }; const WEIGHTS = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2]; @@ -22,12 +42,15 @@ function transliterate(ch) { export function extractVin(data, offset) { requireBytes(data); assertRange(data, offset, 17); - const text = Array.from(data.slice(offset, offset + 17), (b) => String.fromCharCode(b)).join(""); + const text = Array.from(data.slice(offset, offset + 17), (b) => + String.fromCharCode(b), + ).join(""); return text.toUpperCase(); } export function computeVinCheckDigit(vin) { - if (typeof vin !== "string" || vin.length !== 17) throw new Error("VIN must be exactly 17 characters"); + if (typeof vin !== "string" || vin.length !== 17) + throw new Error("VIN must be exactly 17 characters"); if (/[IOQ]/i.test(vin)) throw new Error("VIN must not contain I, O, or Q"); let sum = 0; for (let i = 0; i < 17; i++) sum += transliterate(vin[i]) * WEIGHTS[i]; @@ -38,7 +61,11 @@ export function computeVinCheckDigit(vin) { export function validateVin(vin) { const expected = computeVinCheckDigit(vin); const actual = vin[8]; - return { valid: expected === actual, expectedCheckDigit: expected, actualCheckDigit: actual }; + return { + valid: expected === actual, + expectedCheckDigit: expected, + actualCheckDigit: actual, + }; } export function selfTest() { diff --git a/03_Script_Starter_Kit/examples/37_binary_search_pattern_locator.mjs b/03_Script_Starter_Kit/examples/37_binary_search_pattern_locator.mjs index 7673eee..362c224 100644 --- a/03_Script_Starter_Kit/examples/37_binary_search_pattern_locator.mjs +++ b/03_Script_Starter_Kit/examples/37_binary_search_pattern_locator.mjs @@ -2,8 +2,10 @@ O(log n) alternative to linear findPattern() scans, e.g. for looking up a sector containing a given address inside a large, sorted sector map. */ export function binarySearchOffset(sortedOffsets, target) { - if (!Array.isArray(sortedOffsets)) throw new Error("sortedOffsets must be an array"); - let lo = 0, hi = sortedOffsets.length - 1; + if (!Array.isArray(sortedOffsets)) + throw new Error("sortedOffsets must be an array"); + let lo = 0, + hi = sortedOffsets.length - 1; while (lo <= hi) { const mid = (lo + hi) >>> 1; if (sortedOffsets[mid] === target) return mid; @@ -15,8 +17,10 @@ export function binarySearchOffset(sortedOffsets, target) { /* sortedSectors: array of {name, start, length}, sorted ascending by start, non-overlapping. */ export function findSectorForOffset(sortedSectors, offset) { - if (!Array.isArray(sortedSectors) || sortedSectors.length === 0) throw new Error("sortedSectors must be a non-empty array"); - let lo = 0, hi = sortedSectors.length - 1; + if (!Array.isArray(sortedSectors) || sortedSectors.length === 0) + throw new Error("sortedSectors must be a non-empty array"); + let lo = 0, + hi = sortedSectors.length - 1; while (lo <= hi) { const mid = (lo + hi) >>> 1; const sector = sortedSectors[mid]; diff --git a/03_Script_Starter_Kit/examples/38_bitfield_and_signed_int_utils.mjs b/03_Script_Starter_Kit/examples/38_bitfield_and_signed_int_utils.mjs index 6b0565f..d130989 100644 --- a/03_Script_Starter_Kit/examples/38_bitfield_and_signed_int_utils.mjs +++ b/03_Script_Starter_Kit/examples/38_bitfield_and_signed_int_utils.mjs @@ -19,26 +19,50 @@ export function readI16BE(data, offset) { } export function readI32LE(data, offset) { assertRange(data, offset, 4); - return (data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24)) | 0; + return ( + data[offset] | + (data[offset + 1] << 8) | + (data[offset + 2] << 16) | + (data[offset + 3] << 24) | + 0 + ); } export function readI32BE(data, offset) { assertRange(data, offset, 4); - return ((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]) | 0; + return ( + (data[offset] << 24) | + (data[offset + 1] << 16) | + (data[offset + 2] << 8) | + data[offset + 3] | + 0 + ); } /* Bit numbering: bit 0 = least significant bit. */ export function getBits(value, startBit, numBits) { - if (!Number.isInteger(startBit) || !Number.isInteger(numBits) || startBit < 0 || numBits <= 0 || startBit + numBits > 32) { + if ( + !Number.isInteger(startBit) || + !Number.isInteger(numBits) || + startBit < 0 || + numBits <= 0 || + startBit + numBits > 32 + ) { throw new RangeError("Invalid bit range"); } - const mask = (numBits === 32 ? 0xFFFFFFFF : (1 << numBits) - 1) >>> 0; + const mask = (numBits === 32 ? 0xffffffff : (1 << numBits) - 1) >>> 0; return (value >>> startBit) & mask; } export function setBits(value, startBit, numBits, newValue) { - if (!Number.isInteger(startBit) || !Number.isInteger(numBits) || startBit < 0 || numBits <= 0 || startBit + numBits > 32) { + if ( + !Number.isInteger(startBit) || + !Number.isInteger(numBits) || + startBit < 0 || + numBits <= 0 || + startBit + numBits > 32 + ) { throw new RangeError("Invalid bit range"); } - const mask = ((numBits === 32 ? 0xFFFFFFFF : (1 << numBits) - 1) >>> 0); + const mask = (numBits === 32 ? 0xffffffff : (1 << numBits) - 1) >>> 0; const cleared = value & ~(mask << startBit); return (cleared | ((newValue & mask) << startBit)) >>> 0; } diff --git a/03_Script_Starter_Kit/examples/39_key_learning_session_report.mjs b/03_Script_Starter_Kit/examples/39_key_learning_session_report.mjs index 8e3b206..77e998e 100644 --- a/03_Script_Starter_Kit/examples/39_key_learning_session_report.mjs +++ b/03_Script_Starter_Kit/examples/39_key_learning_session_report.mjs @@ -3,22 +3,42 @@ document any security algorithm, PIN/seed value, or bypass technique. See 04_Workflows/AUTHORIZED_KEY_LEARNING_WORKFLOW.md. */ export function buildKeyLearningReport(session) { - const required = ["caseId", "vin", "authorizedBy", "existingKeyCountBefore", "keysAddedCount", "keysRemovedCount"]; + const required = [ + "caseId", + "vin", + "authorizedBy", + "existingKeyCountBefore", + "keysAddedCount", + "keysRemovedCount", + ]; for (const field of required) { - if (session[field] === undefined || session[field] === null || session[field] === "") { + if ( + session[field] === undefined || + session[field] === null || + session[field] === "" + ) { throw new Error(`Missing required field: ${field}`); } } - if (!Number.isInteger(session.existingKeyCountBefore) || session.existingKeyCountBefore < 0) { + if ( + !Number.isInteger(session.existingKeyCountBefore) || + session.existingKeyCountBefore < 0 + ) { throw new Error("existingKeyCountBefore must be a non-negative integer"); } if (!Number.isInteger(session.keysAddedCount) || session.keysAddedCount < 0) { throw new Error("keysAddedCount must be a non-negative integer"); } - if (!Number.isInteger(session.keysRemovedCount) || session.keysRemovedCount < 0) { + if ( + !Number.isInteger(session.keysRemovedCount) || + session.keysRemovedCount < 0 + ) { throw new Error("keysRemovedCount must be a non-negative integer"); } - const expectedKeyCountAfter = session.existingKeyCountBefore + session.keysAddedCount - session.keysRemovedCount; + const expectedKeyCountAfter = + session.existingKeyCountBefore + + session.keysAddedCount - + session.keysRemovedCount; return { caseId: session.caseId, vin: session.vin, diff --git a/03_Script_Starter_Kit/examples/airbag_authorized_safe/17_airbag_case_intake_validator.mjs b/03_Script_Starter_Kit/examples/airbag_authorized_safe/17_airbag_case_intake_validator.mjs index ef2a850..1ce00a1 100644 --- a/03_Script_Starter_Kit/examples/airbag_authorized_safe/17_airbag_case_intake_validator.mjs +++ b/03_Script_Starter_Kit/examples/airbag_authorized_safe/17_airbag_case_intake_validator.mjs @@ -1,19 +1,29 @@ /* Authorized-shop administrative example. Does not read, alter, or conceal crash/deployment data. */ const REQUIRED = [ - "caseId", "timestampUtc", "technician", "customerName", "vehicleVin", - "proofOfOwnershipRef", "authorizationRef", "requestedService" + "caseId", + "timestampUtc", + "technician", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "requestedService", ]; export function validateAirbagCase(caseRecord) { - const missing = REQUIRED.filter(k => !String(caseRecord[k] ?? "").trim()); - const vin = String(caseRecord.vehicleVin ?? "").trim().toUpperCase(); + const missing = REQUIRED.filter((k) => !String(caseRecord[k] ?? "").trim()); + const vin = String(caseRecord.vehicleVin ?? "") + .trim() + .toUpperCase(); const vinValid = /^[A-HJ-NPR-Z0-9]{17}$/.test(vin); - const authorizationValid = Boolean(String(caseRecord.authorizationRef ?? "").trim()); + const authorizationValid = Boolean( + String(caseRecord.authorizationRef ?? "").trim(), + ); return { valid: missing.length === 0 && vinValid && authorizationValid, missing, vinValid, - authorizationValid + authorizationValid, }; } diff --git a/03_Script_Starter_Kit/examples/airbag_authorized_safe/18_airbag_module_read_consistency.mjs b/03_Script_Starter_Kit/examples/airbag_authorized_safe/18_airbag_module_read_consistency.mjs index 5ff98ad..04d2210 100644 --- a/03_Script_Starter_Kit/examples/airbag_authorized_safe/18_airbag_module_read_consistency.mjs +++ b/03_Script_Starter_Kit/examples/airbag_authorized_safe/18_airbag_module_read_consistency.mjs @@ -6,6 +6,6 @@ export function verifyAirbagReadConsistency(readA, readB) { sameLength: readA.length === readB.length, identical: constantTimeEqual(readA, readB), crcA: crc32(readA), - crcB: crc32(readB) + crcB: crc32(readB), }; } diff --git a/03_Script_Starter_Kit/examples/airbag_authorized_safe/19_airbag_crash_data_disclosure_redactor.mjs b/03_Script_Starter_Kit/examples/airbag_authorized_safe/19_airbag_crash_data_disclosure_redactor.mjs index 456678d..385bf55 100644 --- a/03_Script_Starter_Kit/examples/airbag_authorized_safe/19_airbag_crash_data_disclosure_redactor.mjs +++ b/03_Script_Starter_Kit/examples/airbag_authorized_safe/19_airbag_crash_data_disclosure_redactor.mjs @@ -14,6 +14,6 @@ export function airbagStatusReport(job) { technician: job.technician, timestampUtc: job.timestampUtc, deploymentStatusAsFound: job.deploymentStatusAsFound, - status: job.status + status: job.status, }; } diff --git a/03_Script_Starter_Kit/examples/airbag_authorized_safe/20_airbag_backup_naming_policy.mjs b/03_Script_Starter_Kit/examples/airbag_authorized_safe/20_airbag_backup_naming_policy.mjs index 7b9ed7e..9a2a6cd 100644 --- a/03_Script_Starter_Kit/examples/airbag_authorized_safe/20_airbag_backup_naming_policy.mjs +++ b/03_Script_Starter_Kit/examples/airbag_authorized_safe/20_airbag_backup_naming_policy.mjs @@ -1,12 +1,21 @@ /* Produces a consistent, sanitized filename for authorized airbag/SRS module backups. */ function safe(value) { - return String(value ?? "unknown").trim().replace(/[^A-Za-z0-9._-]+/g, "_").slice(0, 50); + return String(value ?? "unknown") + .trim() + .replace(/[^A-Za-z0-9._-]+/g, "_") + .slice(0, 50); } export function buildAirbagBackupName(meta) { const stamp = safe(meta.timestampUtc).replace(/[:]/g, "-"); - return [ - safe(meta.caseId), safe(meta.vehicleVin), safe(meta.module), - safe(meta.memoryRegion), safe(meta.readNumber), stamp - ].join("_") + ".bin"; + return ( + [ + safe(meta.caseId), + safe(meta.vehicleVin), + safe(meta.module), + safe(meta.memoryRegion), + safe(meta.readNumber), + stamp, + ].join("_") + ".bin" + ); } diff --git a/03_Script_Starter_Kit/examples/airbag_authorized_safe/21_airbag_service_completion_audit.mjs b/03_Script_Starter_Kit/examples/airbag_authorized_safe/21_airbag_service_completion_audit.mjs index e8b60cb..7c43ecf 100644 --- a/03_Script_Starter_Kit/examples/airbag_authorized_safe/21_airbag_service_completion_audit.mjs +++ b/03_Script_Starter_Kit/examples/airbag_authorized_safe/21_airbag_service_completion_audit.mjs @@ -7,7 +7,7 @@ export function auditAirbagCompletion(job) { duplicateReadsMatched: job.duplicateReadsMatched === true, crashDataUnaltered: job.crashDataUnaltered === true, customerAcknowledged: Boolean(job.customerAcknowledgmentRef), - technicianSigned: Boolean(job.technicianSignatureRef) + technicianSigned: Boolean(job.technicianSignatureRef), }; return { complete: Object.values(checks).every(Boolean), checks }; } diff --git a/03_Script_Starter_Kit/examples/ecu_authorized_safe/22_ecu_case_intake_validator.mjs b/03_Script_Starter_Kit/examples/ecu_authorized_safe/22_ecu_case_intake_validator.mjs index 96f19c9..e304b0f 100644 --- a/03_Script_Starter_Kit/examples/ecu_authorized_safe/22_ecu_case_intake_validator.mjs +++ b/03_Script_Starter_Kit/examples/ecu_authorized_safe/22_ecu_case_intake_validator.mjs @@ -1,18 +1,28 @@ /* Authorized-shop administrative example. */ const REQUIRED = [ - "caseId", "timestampUtc", "technician", "customerName", "vehicleVin", - "proofOfOwnershipRef", "authorizationRef", "requestedService" + "caseId", + "timestampUtc", + "technician", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "requestedService", ]; export function validateEcuCase(caseRecord) { - const missing = REQUIRED.filter(k => !String(caseRecord[k] ?? "").trim()); - const vin = String(caseRecord.vehicleVin ?? "").trim().toUpperCase(); + const missing = REQUIRED.filter((k) => !String(caseRecord[k] ?? "").trim()); + const vin = String(caseRecord.vehicleVin ?? "") + .trim() + .toUpperCase(); const vinValid = /^[A-HJ-NPR-Z0-9]{17}$/.test(vin); - const authorizationValid = Boolean(String(caseRecord.authorizationRef ?? "").trim()); + const authorizationValid = Boolean( + String(caseRecord.authorizationRef ?? "").trim(), + ); return { valid: missing.length === 0 && vinValid && authorizationValid, missing, vinValid, - authorizationValid + authorizationValid, }; } diff --git a/03_Script_Starter_Kit/examples/ecu_authorized_safe/23_ecu_calibration_read_consistency.mjs b/03_Script_Starter_Kit/examples/ecu_authorized_safe/23_ecu_calibration_read_consistency.mjs index 9925bf3..8bd6a24 100644 --- a/03_Script_Starter_Kit/examples/ecu_authorized_safe/23_ecu_calibration_read_consistency.mjs +++ b/03_Script_Starter_Kit/examples/ecu_authorized_safe/23_ecu_calibration_read_consistency.mjs @@ -6,6 +6,6 @@ export function verifyEcuReadConsistency(readA, readB) { sameLength: readA.length === readB.length, identical: constantTimeEqual(readA, readB), crcA: crc32(readA), - crcB: crc32(readB) + crcB: crc32(readB), }; } diff --git a/03_Script_Starter_Kit/examples/ecu_authorized_safe/24_ecu_partnumber_crosscheck.mjs b/03_Script_Starter_Kit/examples/ecu_authorized_safe/24_ecu_partnumber_crosscheck.mjs index 98e82d5..45a99a8 100644 --- a/03_Script_Starter_Kit/examples/ecu_authorized_safe/24_ecu_partnumber_crosscheck.mjs +++ b/03_Script_Starter_Kit/examples/ecu_authorized_safe/24_ecu_partnumber_crosscheck.mjs @@ -8,6 +8,6 @@ export function crosscheckPartNumber(data, field, expectedPartNumber) { return { found, expected: String(expectedPartNumber ?? ""), - matches: found === String(expectedPartNumber ?? "") + matches: found === String(expectedPartNumber ?? ""), }; } diff --git a/03_Script_Starter_Kit/examples/ecu_authorized_safe/25_ecu_change_scope_guard.mjs b/03_Script_Starter_Kit/examples/ecu_authorized_safe/25_ecu_change_scope_guard.mjs index 29a0825..48012b1 100644 --- a/03_Script_Starter_Kit/examples/ecu_authorized_safe/25_ecu_change_scope_guard.mjs +++ b/03_Script_Starter_Kit/examples/ecu_authorized_safe/25_ecu_change_scope_guard.mjs @@ -6,13 +6,19 @@ function rangeInside(change, allowed) { return change.start >= allowed.start && change.end <= allowed.end; } -export function validateAuthorizedEcuChangeScope(original, modified, allowedRanges) { +export function validateAuthorizedEcuChangeScope( + original, + modified, + allowedRanges, +) { const changes = diffRanges(original, modified); - const violations = changes.filter(c => !allowedRanges.some(a => rangeInside(c, a))); + const violations = changes.filter( + (c) => !allowedRanges.some((a) => rangeInside(c, a)), + ); return { valid: violations.length === 0, changes, violations, - changedBytes: changes.reduce((n, r) => n + r.length, 0) + changedBytes: changes.reduce((n, r) => n + r.length, 0), }; } diff --git a/03_Script_Starter_Kit/examples/ecu_authorized_safe/26_ecu_service_completion_audit.mjs b/03_Script_Starter_Kit/examples/ecu_authorized_safe/26_ecu_service_completion_audit.mjs index 0b3ba24..731f57a 100644 --- a/03_Script_Starter_Kit/examples/ecu_authorized_safe/26_ecu_service_completion_audit.mjs +++ b/03_Script_Starter_Kit/examples/ecu_authorized_safe/26_ecu_service_completion_audit.mjs @@ -7,7 +7,7 @@ export function auditEcuCompletion(job) { duplicateReadsMatched: job.duplicateReadsMatched === true, partNumberVerified: job.partNumberVerified === true, customerAcknowledged: Boolean(job.customerAcknowledgmentRef), - technicianSigned: Boolean(job.technicianSignatureRef) + technicianSigned: Boolean(job.technicianSignatureRef), }; return { complete: Object.values(checks).every(Boolean), checks }; } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/09_immo_case_intake_validator.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/09_immo_case_intake_validator.mjs index 4211931..18589e8 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/09_immo_case_intake_validator.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/09_immo_case_intake_validator.mjs @@ -1,19 +1,29 @@ /* Authorized-shop administrative example. Does not read, derive, calculate, program, clone, or bypass immobilizer credentials. */ const REQUIRED = [ - "caseId", "timestampUtc", "technician", "customerName", "vehicleVin", - "proofOfOwnershipRef", "authorizationRef", "requestedService" + "caseId", + "timestampUtc", + "technician", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "requestedService", ]; export function validateImmoCase(caseRecord) { - const missing = REQUIRED.filter(k => !String(caseRecord[k] ?? "").trim()); - const vin = String(caseRecord.vehicleVin ?? "").trim().toUpperCase(); + const missing = REQUIRED.filter((k) => !String(caseRecord[k] ?? "").trim()); + const vin = String(caseRecord.vehicleVin ?? "") + .trim() + .toUpperCase(); const vinValid = /^[A-HJ-NPR-Z0-9]{17}$/.test(vin); - const authorizationValid = Boolean(String(caseRecord.authorizationRef ?? "").trim()); + const authorizationValid = Boolean( + String(caseRecord.authorizationRef ?? "").trim(), + ); return { valid: missing.length === 0 && vinValid && authorizationValid, missing, vinValid, - authorizationValid + authorizationValid, }; } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/10_immo_module_read_consistency.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/10_immo_module_read_consistency.mjs index ec8ff43..53076fe 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/10_immo_module_read_consistency.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/10_immo_module_read_consistency.mjs @@ -4,7 +4,12 @@ import { constantTimeEqual, crc32, diffRanges } from "../../binary_utils.mjs"; export function compareAuthorizedReads(readA, readB) { if (readA.length !== readB.length) { - return { valid: false, reason: "Different file lengths", lengthA: readA.length, lengthB: readB.length }; + return { + valid: false, + reason: "Different file lengths", + lengthA: readA.length, + lengthB: readB.length, + }; } const identical = constantTimeEqual(readA, readB); return { @@ -13,6 +18,6 @@ export function compareAuthorizedReads(readA, readB) { length: readA.length, crc32A: crc32(readA).toString(16).padStart(8, "0").toUpperCase(), crc32B: crc32(readB).toString(16).padStart(8, "0").toUpperCase(), - changedRanges: identical ? [] : diffRanges(readA, readB) + changedRanges: identical ? [] : diffRanges(readA, readB), }; } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/11_immo_dump_quality_report.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/11_immo_dump_quality_report.mjs index 878e4ed..eea197e 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/11_immo_dump_quality_report.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/11_immo_dump_quality_report.mjs @@ -4,15 +4,18 @@ import { countByte, crc32, asciiPreview } from "../../binary_utils.mjs"; export function buildDumpQualityReport(data) { if (!data.length) return { valid: false, reason: "Empty input" }; - const ff = countByte(data, 0xFF); + const ff = countByte(data, 0xff); const zero = countByte(data, 0x00); return { valid: true, length: data.length, crc32: crc32(data).toString(16).padStart(8, "0").toUpperCase(), - ffPercent: Number((ff * 100 / data.length).toFixed(2)), - zeroPercent: Number((zero * 100 / data.length).toFixed(2)), + ffPercent: Number(((ff * 100) / data.length).toFixed(2)), + zeroPercent: Number(((zero * 100) / data.length).toFixed(2)), printablePreview: asciiPreview(data.slice(0, 64)), - warning: ff === data.length || zero === data.length ? "Input appears blank or erased" : "" + warning: + ff === data.length || zero === data.length + ? "Input appears blank or erased" + : "", }; } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/12_authorized_key_count_reconciliation.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/12_authorized_key_count_reconciliation.mjs index ca552d7..3b72f79 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/12_authorized_key_count_reconciliation.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/12_authorized_key_count_reconciliation.mjs @@ -7,10 +7,17 @@ export function reconcileKeys(record) { const retained = Number(record.keysRetainedByShop ?? 0); const expectedReturn = received + added - retained; return { - received, returned, added, retained, expectedReturn, - balanced: Number.isInteger(received) && Number.isInteger(returned) && - Number.isInteger(added) && Number.isInteger(retained) && - [received, returned, added, retained].every(v => v >= 0) && - returned === expectedReturn + received, + returned, + added, + retained, + expectedReturn, + balanced: + Number.isInteger(received) && + Number.isInteger(returned) && + Number.isInteger(added) && + Number.isInteger(retained) && + [received, returned, added, retained].every((v) => v >= 0) && + returned === expectedReturn, }; } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/14_immo_backup_naming_policy.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/14_immo_backup_naming_policy.mjs index 5140b43..eda369a 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/14_immo_backup_naming_policy.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/14_immo_backup_naming_policy.mjs @@ -1,12 +1,21 @@ /* Produces a consistent, sanitized filename for authorized backups. */ function safe(value) { - return String(value ?? "unknown").trim().replace(/[^A-Za-z0-9._-]+/g, "_").slice(0, 50); + return String(value ?? "unknown") + .trim() + .replace(/[^A-Za-z0-9._-]+/g, "_") + .slice(0, 50); } export function buildBackupName(meta) { const stamp = safe(meta.timestampUtc).replace(/[:]/g, "-"); - return [ - safe(meta.caseId), safe(meta.vehicleVin), safe(meta.module), - safe(meta.memoryRegion), safe(meta.readNumber), stamp - ].join("_") + ".bin"; + return ( + [ + safe(meta.caseId), + safe(meta.vehicleVin), + safe(meta.module), + safe(meta.memoryRegion), + safe(meta.readNumber), + stamp, + ].join("_") + ".bin" + ); } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/15_immo_change_scope_guard.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/15_immo_change_scope_guard.mjs index 80845bf..aea91f5 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/15_immo_change_scope_guard.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/15_immo_change_scope_guard.mjs @@ -6,13 +6,19 @@ function rangeInside(change, allowed) { return change.start >= allowed.start && change.end <= allowed.end; } -export function validateAuthorizedChangeScope(original, modified, allowedRanges) { +export function validateAuthorizedChangeScope( + original, + modified, + allowedRanges, +) { const changes = diffRanges(original, modified); - const violations = changes.filter(c => !allowedRanges.some(a => rangeInside(c, a))); + const violations = changes.filter( + (c) => !allowedRanges.some((a) => rangeInside(c, a)), + ); return { valid: violations.length === 0, changes, violations, - changedBytes: changes.reduce((n, r) => n + r.length, 0) + changedBytes: changes.reduce((n, r) => n + r.length, 0), }; } diff --git a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/16_immo_service_completion_audit.mjs b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/16_immo_service_completion_audit.mjs index 75c00b8..dbbec4a 100644 --- a/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/16_immo_service_completion_audit.mjs +++ b/03_Script_Starter_Kit/examples/immobilizer_authorized_safe/16_immo_service_completion_audit.mjs @@ -8,7 +8,7 @@ export function auditCompletion(job) { physicalKeysReconciled: job.physicalKeysReconciled === true, customerAcknowledged: Boolean(job.customerAcknowledgmentRef), securityDataRedacted: job.securityDataRedacted === true, - technicianSigned: Boolean(job.technicianSignatureRef) + technicianSigned: Boolean(job.technicianSignatureRef), }; return { complete: Object.values(checks).every(Boolean), checks }; } diff --git a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/27_module_case_intake_validator.mjs b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/27_module_case_intake_validator.mjs index eac6839..14d4161 100644 --- a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/27_module_case_intake_validator.mjs +++ b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/27_module_case_intake_validator.mjs @@ -1,18 +1,29 @@ /* Authorized-shop administrative example for BCM/instrument cluster/TCU work. */ const REQUIRED = [ - "caseId", "timestampUtc", "technician", "customerName", "vehicleVin", - "proofOfOwnershipRef", "authorizationRef", "requestedService", "module" + "caseId", + "timestampUtc", + "technician", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "requestedService", + "module", ]; export function validateModuleCase(caseRecord) { - const missing = REQUIRED.filter(k => !String(caseRecord[k] ?? "").trim()); - const vin = String(caseRecord.vehicleVin ?? "").trim().toUpperCase(); + const missing = REQUIRED.filter((k) => !String(caseRecord[k] ?? "").trim()); + const vin = String(caseRecord.vehicleVin ?? "") + .trim() + .toUpperCase(); const vinValid = /^[A-HJ-NPR-Z0-9]{17}$/.test(vin); - const authorizationValid = Boolean(String(caseRecord.authorizationRef ?? "").trim()); + const authorizationValid = Boolean( + String(caseRecord.authorizationRef ?? "").trim(), + ); return { valid: missing.length === 0 && vinValid && authorizationValid, missing, vinValid, - authorizationValid + authorizationValid, }; } diff --git a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/28_module_read_consistency.mjs b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/28_module_read_consistency.mjs index 0c996a5..af681ca 100644 --- a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/28_module_read_consistency.mjs +++ b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/28_module_read_consistency.mjs @@ -6,6 +6,6 @@ export function verifyModuleReadConsistency(readA, readB) { sameLength: readA.length === readB.length, identical: constantTimeEqual(readA, readB), crcA: crc32(readA), - crcB: crc32(readB) + crcB: crc32(readB), }; } diff --git a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/29_module_backup_naming_policy.mjs b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/29_module_backup_naming_policy.mjs index 4ea97cf..fdb73a0 100644 --- a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/29_module_backup_naming_policy.mjs +++ b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/29_module_backup_naming_policy.mjs @@ -1,12 +1,21 @@ /* Produces a consistent, sanitized filename for authorized module backups. */ function safe(value) { - return String(value ?? "unknown").trim().replace(/[^A-Za-z0-9._-]+/g, "_").slice(0, 50); + return String(value ?? "unknown") + .trim() + .replace(/[^A-Za-z0-9._-]+/g, "_") + .slice(0, 50); } export function buildModuleBackupName(meta) { const stamp = safe(meta.timestampUtc).replace(/[:]/g, "-"); - return [ - safe(meta.caseId), safe(meta.vehicleVin), safe(meta.module), - safe(meta.memoryRegion), safe(meta.readNumber), stamp - ].join("_") + ".bin"; + return ( + [ + safe(meta.caseId), + safe(meta.vehicleVin), + safe(meta.module), + safe(meta.memoryRegion), + safe(meta.readNumber), + stamp, + ].join("_") + ".bin" + ); } diff --git a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/30_module_change_scope_guard.mjs b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/30_module_change_scope_guard.mjs index 54431d9..e80e87b 100644 --- a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/30_module_change_scope_guard.mjs +++ b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/30_module_change_scope_guard.mjs @@ -8,13 +8,19 @@ function rangeInside(change, allowed) { return change.start >= allowed.start && change.end <= allowed.end; } -export function validateAuthorizedModuleChangeScope(original, modified, allowedRanges) { +export function validateAuthorizedModuleChangeScope( + original, + modified, + allowedRanges, +) { const changes = diffRanges(original, modified); - const violations = changes.filter(c => !allowedRanges.some(a => rangeInside(c, a))); + const violations = changes.filter( + (c) => !allowedRanges.some((a) => rangeInside(c, a)), + ); return { valid: violations.length === 0, changes, violations, - changedBytes: changes.reduce((n, r) => n + r.length, 0) + changedBytes: changes.reduce((n, r) => n + r.length, 0), }; } diff --git a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/31_module_service_completion_audit.mjs b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/31_module_service_completion_audit.mjs index ebb4b71..d42d30d 100644 --- a/03_Script_Starter_Kit/examples/other_modules_authorized_safe/31_module_service_completion_audit.mjs +++ b/03_Script_Starter_Kit/examples/other_modules_authorized_safe/31_module_service_completion_audit.mjs @@ -7,7 +7,7 @@ export function auditModuleCompletion(job) { duplicateReadsMatched: job.duplicateReadsMatched === true, mileageFieldUnchanged: job.mileageFieldUnchanged === true, customerAcknowledged: Boolean(job.customerAcknowledgmentRef), - technicianSigned: Boolean(job.technicianSignatureRef) + technicianSigned: Boolean(job.technicianSignatureRef), }; return { complete: Object.values(checks).every(Boolean), checks }; } diff --git a/03_Script_Starter_Kit/templates/checksum_region_verifier.mjs b/03_Script_Starter_Kit/templates/checksum_region_verifier.mjs index dd13ca6..2b8c48b 100644 --- a/03_Script_Starter_Kit/templates/checksum_region_verifier.mjs +++ b/03_Script_Starter_Kit/templates/checksum_region_verifier.mjs @@ -2,24 +2,30 @@ import { assertRange, requireBytes } from "../binary_utils.mjs"; export function verifyChecksumRegion(data, region, checksum, algorithm) { requireBytes(data); - if (!region || !checksum || typeof algorithm !== "function") throw new TypeError("Region, checksum, and algorithm are required"); + if (!region || !checksum || typeof algorithm !== "function") + throw new TypeError("Region, checksum, and algorithm are required"); assertRange(data, region.start, region.length); assertRange(data, checksum.offset, checksum.length); - if (![1, 2, 4].includes(checksum.length)) throw new RangeError("Checksum length must be 1, 2, or 4 bytes"); + if (![1, 2, 4].includes(checksum.length)) + throw new RangeError("Checksum length must be 1, 2, or 4 bytes"); const endian = checksum.endian === undefined ? "LE" : checksum.endian; - if (endian !== "LE" && endian !== "BE") throw new RangeError("Checksum endian must be LE or BE"); - const computed = algorithm(data.slice(region.start, region.start + region.length)) >>> 0; + if (endian !== "LE" && endian !== "BE") + throw new RangeError("Checksum endian must be LE or BE"); + const computed = + algorithm(data.slice(region.start, region.start + region.length)) >>> 0; let stored = 0; for (let index = 0; index < checksum.length; index++) { - const shift = endian === "BE" ? 8 * (checksum.length - index - 1) : 8 * index; + const shift = + endian === "BE" ? 8 * (checksum.length - index - 1) : 8 * index; stored = (stored | (data[checksum.offset + index] << shift)) >>> 0; } - const mask = checksum.length === 4 ? 0xFFFFFFFF : (2 ** (checksum.length * 8)) - 1; + const mask = + checksum.length === 4 ? 0xffffffff : 2 ** (checksum.length * 8) - 1; return { region: { start: region.start, length: region.length }, checksum: { offset: checksum.offset, length: checksum.length, endian }, stored: stored & mask, computed: computed & mask, - matches: (stored & mask) === (computed & mask) + matches: (stored & mask) === (computed & mask), }; } diff --git a/03_Script_Starter_Kit/tests/test_additional_examples.mjs b/03_Script_Starter_Kit/tests/test_additional_examples.mjs index 03af74d..ce71fc3 100644 --- a/03_Script_Starter_Kit/tests/test_additional_examples.mjs +++ b/03_Script_Starter_Kit/tests/test_additional_examples.mjs @@ -8,23 +8,59 @@ import { checksumReport } from "../examples/34_checksum_model_selector.mjs"; const payload = new Uint8Array([1, 2, 3, 4]); const withChecksum = new Uint8Array([1, 2, 3, 4, 0, 0, 0, 0]); new DataView(withChecksum.buffer).setUint32(4, adler32(payload), false); -assert.equal(verifyChecksumRegion(withChecksum, { start: 0, length: 4 }, { offset: 4, length: 4, endian: "BE" }, adler32).matches, true); +assert.equal( + verifyChecksumRegion( + withChecksum, + { start: 0, length: 4 }, + { offset: 4, length: 4, endian: "BE" }, + adler32, + ).matches, + true, +); withChecksum[0] = 9; -assert.equal(verifyChecksumRegion(withChecksum, { start: 0, length: 4 }, { offset: 4, length: 4, endian: "BE" }, adler32).matches, false); +assert.equal( + verifyChecksumRegion( + withChecksum, + { start: 0, length: 4 }, + { offset: 4, length: 4, endian: "BE" }, + adler32, + ).matches, + false, +); assert.deepEqual(hexToBytes("00:0f ff"), new Uint8Array([0, 15, 255])); assert.throws(() => hexToBytes("12zz34"), /Invalid character/); -assert.throws(() => verifyChecksumRegion(withChecksum, { start: 0, length: 4 }, { offset: 4, length: 4, endian: "BIG" }, adler32), /endian must be LE or BE/); +assert.throws( + () => + verifyChecksumRegion( + withChecksum, + { start: 0, length: 4 }, + { offset: 4, length: 4, endian: "BIG" }, + adler32, + ), + /endian must be LE or BE/, +); const fingerprint = fingerprintDump(payload, "fixture.bin"); assert.equal(fingerprint.length, 4); assert.equal(fingerprint.ffBytes, 0); -const report = buildChangeReport(new Uint8Array([1, 2, 3]), new Uint8Array([1, 9, 3]), [{ start: 1, end: 1 }]); +const report = buildChangeReport( + new Uint8Array([1, 2, 3]), + new Uint8Array([1, 9, 3]), + [{ start: 1, end: 1 }], +); assert.equal(report.changedBytes, 1); assert.equal(report.approved, true); -assert.equal(buildChangeReport(new Uint8Array([1, 2, 3]), new Uint8Array([1, 9, 3])).approved, false); +assert.equal( + buildChangeReport(new Uint8Array([1, 2, 3]), new Uint8Array([1, 9, 3])) + .approved, + false, +); -const checksums = checksumReport(new TextEncoder().encode("123456789"), ["crc32", "crc16_arc"]); +const checksums = checksumReport(new TextEncoder().encode("123456789"), [ + "crc32", + "crc16_arc", +]); assert.equal(checksums.crc32, "cbf43926"); assert.equal(checksums.crc16_arc, "bb3d"); diff --git a/03_Script_Starter_Kit/tests/test_binary_utils.mjs b/03_Script_Starter_Kit/tests/test_binary_utils.mjs index ff397c1..6305317 100644 --- a/03_Script_Starter_Kit/tests/test_binary_utils.mjs +++ b/03_Script_Starter_Kit/tests/test_binary_utils.mjs @@ -1,7 +1,10 @@ import { strict as assert } from "node:assert"; import { crc32, diffRanges, bytesToHex } from "../binary_utils.mjs"; -const v=new TextEncoder().encode("123456789"); -assert.equal(crc32(v),0xCBF43926); -assert.equal(bytesToHex(new Uint8Array([0,15,255])),"00 0F FF"); -assert.deepEqual(diffRanges(new Uint8Array([1,2,3,4]),new Uint8Array([1,9,8,4])),[{start:1,end:2,length:2}]); +const v = new TextEncoder().encode("123456789"); +assert.equal(crc32(v), 0xcbf43926); +assert.equal(bytesToHex(new Uint8Array([0, 15, 255])), "00 0F FF"); +assert.deepEqual( + diffRanges(new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 9, 8, 4])), + [{ start: 1, end: 2, length: 2 }], +); console.log("All tests passed"); diff --git a/03_Script_Starter_Kit/tests/test_expansion_examples.mjs b/03_Script_Starter_Kit/tests/test_expansion_examples.mjs index 6115f26..9f09d51 100644 --- a/03_Script_Starter_Kit/tests/test_expansion_examples.mjs +++ b/03_Script_Starter_Kit/tests/test_expansion_examples.mjs @@ -1,14 +1,36 @@ import { strict as assert } from "node:assert"; import { crc32 } from "../binary_utils.mjs"; -import { parseSectorMap, summarizeSectorMap } from "../examples/35_flash_sector_map_parser.mjs"; -import { extractVin, computeVinCheckDigit, validateVin, selfTest as vinSelfTest } from "../examples/36_vin_extractor_validator.mjs"; -import { binarySearchOffset, findSectorForOffset } from "../examples/37_binary_search_pattern_locator.mjs"; -import { readI8, readI16LE, readI16BE, readI32LE, readI32BE, getBits, setBits } from "../examples/38_bitfield_and_signed_int_utils.mjs"; -import { buildKeyLearningReport, verifyKeyCountReconciliation } from "../examples/39_key_learning_session_report.mjs"; +import { + parseSectorMap, + summarizeSectorMap, +} from "../examples/35_flash_sector_map_parser.mjs"; +import { + extractVin, + computeVinCheckDigit, + validateVin, + selfTest as vinSelfTest, +} from "../examples/36_vin_extractor_validator.mjs"; +import { + binarySearchOffset, + findSectorForOffset, +} from "../examples/37_binary_search_pattern_locator.mjs"; +import { + readI8, + readI16LE, + readI16BE, + readI32LE, + readI32BE, + getBits, + setBits, +} from "../examples/38_bitfield_and_signed_int_utils.mjs"; +import { + buildKeyLearningReport, + verifyKeyCountReconciliation, +} from "../examples/39_key_learning_session_report.mjs"; // 35_flash_sector_map_parser { - const data = new Uint8Array(16).fill(0xFF); + const data = new Uint8Array(16).fill(0xff); data.set([1, 2, 3, 4], 8); const sectors = [ { name: "boot", start: 0, length: 8 }, @@ -17,11 +39,16 @@ import { buildKeyLearningReport, verifyKeyCountReconciliation } from "../example const parsed = parseSectorMap(data, sectors); assert.equal(parsed[0].blank, true); assert.equal(parsed[1].blank, false); - assert.equal(parsed[1].crc32, crc32(data.slice(8, 16)).toString(16).padStart(8, "0").toUpperCase()); + assert.equal( + parsed[1].crc32, + crc32(data.slice(8, 16)).toString(16).padStart(8, "0").toUpperCase(), + ); const summary = summarizeSectorMap(data, sectors); assert.equal(summary.blankSectors, 1); assert.equal(summary.usedSectors, 1); - assert.throws(() => parseSectorMap(data, [{ name: "oob", start: 10, length: 100 }])); + assert.throws(() => + parseSectorMap(data, [{ name: "oob", start: 10, length: 100 }]), + ); } // 36_vin_extractor_validator @@ -54,16 +81,19 @@ import { buildKeyLearningReport, verifyKeyCountReconciliation } from "../example // 38_bitfield_and_signed_int_utils { - assert.equal(readI8(new Uint8Array([0xFF]), 0), -1); - assert.equal(readI8(new Uint8Array([0x7F]), 0), 127); + assert.equal(readI8(new Uint8Array([0xff]), 0), -1); + assert.equal(readI8(new Uint8Array([0x7f]), 0), 127); assert.equal(readI16LE(new Uint8Array([0x00, 0x01]), 0), 256); assert.equal(readI16BE(new Uint8Array([0x00, 0x01]), 0), 1); - assert.equal(readI16LE(new Uint8Array([0xFF, 0xFF]), 0), -1); - assert.equal(readI16BE(new Uint8Array([0xFF, 0xFF]), 0), -1); - assert.equal(readI32LE(new Uint8Array([0x00, 0x00, 0x00, 0x01]), 0), 16777216); + assert.equal(readI16LE(new Uint8Array([0xff, 0xff]), 0), -1); + assert.equal(readI16BE(new Uint8Array([0xff, 0xff]), 0), -1); + assert.equal( + readI32LE(new Uint8Array([0x00, 0x00, 0x00, 0x01]), 0), + 16777216, + ); assert.equal(readI32BE(new Uint8Array([0x00, 0x00, 0x00, 0x01]), 0), 1); - assert.equal(readI32LE(new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]), 0), -1); - assert.equal(readI32BE(new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]), 0), -1); + assert.equal(readI32LE(new Uint8Array([0xff, 0xff, 0xff, 0xff]), 0), -1); + assert.equal(readI32BE(new Uint8Array([0xff, 0xff, 0xff, 0xff]), 0), -1); assert.equal(getBits(0b10110100, 2, 3), 0b101); assert.equal(setBits(0b10110100, 2, 3, 0b011), 172); @@ -84,8 +114,14 @@ import { buildKeyLearningReport, verifyKeyCountReconciliation } from "../example assert.equal(report.expectedKeyCountAfter, 3); assert.equal(verifyKeyCountReconciliation(report, 3).matches, true); assert.equal(verifyKeyCountReconciliation(report, 2).matches, false); - assert.throws(() => buildKeyLearningReport({ ...session, caseId: "" }), /Missing required field/); - assert.throws(() => buildKeyLearningReport({ ...session, keysAddedCount: -1 }), /non-negative integer/); + assert.throws( + () => buildKeyLearningReport({ ...session, caseId: "" }), + /Missing required field/, + ); + assert.throws( + () => buildKeyLearningReport({ ...session, keysAddedCount: -1 }), + /non-negative integer/, + ); } console.log("Expansion examples passed"); diff --git a/08_Collected_MultiPROG_Scripts/Original/01_read_only_inspector.mjs b/08_Collected_MultiPROG_Scripts/Original/01_read_only_inspector.mjs index fdff63e..ab4c9ed 100644 --- a/08_Collected_MultiPROG_Scripts/Original/01_read_only_inspector.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/01_read_only_inspector.mjs @@ -1,2 +1,15 @@ -import { bytesToHex, asciiPreview, countByte, crc32 } from "../binary_utils.mjs"; -export function inspect(data){return {length:data.length,first32:bytesToHex(data.slice(0,32)),ascii:asciiPreview(data.slice(0,64)),ffBytes:countByte(data,0xFF),crc32:crc32(data).toString(16).padStart(8,"0").toUpperCase()};} +import { + bytesToHex, + asciiPreview, + countByte, + crc32, +} from "../binary_utils.mjs"; +export function inspect(data) { + return { + length: data.length, + first32: bytesToHex(data.slice(0, 32)), + ascii: asciiPreview(data.slice(0, 64)), + ffBytes: countByte(data, 0xff), + crc32: crc32(data).toString(16).padStart(8, "0").toUpperCase(), + }; +} diff --git a/08_Collected_MultiPROG_Scripts/Original/02_double_read_verifier.mjs b/08_Collected_MultiPROG_Scripts/Original/02_double_read_verifier.mjs index 34352da..01048ee 100644 --- a/08_Collected_MultiPROG_Scripts/Original/02_double_read_verifier.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/02_double_read_verifier.mjs @@ -1,2 +1,9 @@ import { constantTimeEqual, crc32 } from "../binary_utils.mjs"; -export function verifyTwoReads(a,b){return {sameLength:a.length===b.length,identical:constantTimeEqual(a,b),crcA:crc32(a),crcB:crc32(b)};} +export function verifyTwoReads(a, b) { + return { + sameLength: a.length === b.length, + identical: constantTimeEqual(a, b), + crcA: crc32(a), + crcB: crc32(b), + }; +} diff --git a/08_Collected_MultiPROG_Scripts/Original/03_pattern_inventory.mjs b/08_Collected_MultiPROG_Scripts/Original/03_pattern_inventory.mjs index 73c0153..78e843a 100644 --- a/08_Collected_MultiPROG_Scripts/Original/03_pattern_inventory.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/03_pattern_inventory.mjs @@ -1,2 +1,7 @@ import { findPattern, hexToBytes } from "../binary_utils.mjs"; -export function inventory(data,patterns){return patterns.map(p=>({label:p.label,offsets:findPattern(data,hexToBytes(p.hex))}));} +export function inventory(data, patterns) { + return patterns.map((p) => ({ + label: p.label, + offsets: findPattern(data, hexToBytes(p.hex)), + })); +} diff --git a/08_Collected_MultiPROG_Scripts/Original/04_allowlisted_patch_demo.mjs b/08_Collected_MultiPROG_Scripts/Original/04_allowlisted_patch_demo.mjs index c1e41fd..1cc8a82 100644 --- a/08_Collected_MultiPROG_Scripts/Original/04_allowlisted_patch_demo.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/04_allowlisted_patch_demo.mjs @@ -1,3 +1,9 @@ import { cloneBytes, allowListedWrite, diffRanges } from "../binary_utils.mjs"; // Synthetic demonstration only. No vehicle-security data or real module offsets. -export function demo(input){const output=cloneBytes(input);allowListedWrite(output,4,new Uint8Array([0xAA,0x55]),[{start:4,end:5}]);return {output,changes:diffRanges(input,output)};} +export function demo(input) { + const output = cloneBytes(input); + allowListedWrite(output, 4, new Uint8Array([0xaa, 0x55]), [ + { start: 4, end: 5 }, + ]); + return { output, changes: diffRanges(input, output) }; +} diff --git a/08_Collected_MultiPROG_Scripts/Original/05_checksum_test_vectors.mjs b/08_Collected_MultiPROG_Scripts/Original/05_checksum_test_vectors.mjs index 9a0b867..64c14c2 100644 --- a/08_Collected_MultiPROG_Scripts/Original/05_checksum_test_vectors.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/05_checksum_test_vectors.mjs @@ -1,2 +1,14 @@ -import { hexToBytes,crc16CcittFalse,crc32,adler32 } from "../binary_utils.mjs"; -export function selfTest(){const d=new TextEncoder().encode("123456789");return {crc16Ok:crc16CcittFalse(d)===0x29B1,crc32Ok:crc32(d)===0xCBF43926,adler32:adler32(d)};} +import { + hexToBytes, + crc16CcittFalse, + crc32, + adler32, +} from "../binary_utils.mjs"; +export function selfTest() { + const d = new TextEncoder().encode("123456789"); + return { + crc16Ok: crc16CcittFalse(d) === 0x29b1, + crc32Ok: crc32(d) === 0xcbf43926, + adler32: adler32(d), + }; +} diff --git a/08_Collected_MultiPROG_Scripts/Original/06_authorized_job_record_validator.mjs b/08_Collected_MultiPROG_Scripts/Original/06_authorized_job_record_validator.mjs index 441c3d9..54192ca 100644 --- a/08_Collected_MultiPROG_Scripts/Original/06_authorized_job_record_validator.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/06_authorized_job_record_validator.mjs @@ -1,2 +1,17 @@ -const REQUIRED=["caseId","customerName","vehicleVin","proofOfOwnershipRef","authorizationRef","technician","timestampUtc","requestedService"]; -export function validateAuthorizedJob(job){const missing=REQUIRED.filter(k=>!String(job[k]??"").trim());const vinOk=/^[A-HJ-NPR-Z0-9]{17}$/.test(String(job.vehicleVin||"").toUpperCase());return {valid:missing.length===0&&vinOk,missing,vinOk};} +const REQUIRED = [ + "caseId", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "technician", + "timestampUtc", + "requestedService", +]; +export function validateAuthorizedJob(job) { + const missing = REQUIRED.filter((k) => !String(job[k] ?? "").trim()); + const vinOk = /^[A-HJ-NPR-Z0-9]{17}$/.test( + String(job.vehicleVin || "").toUpperCase(), + ); + return { valid: missing.length === 0 && vinOk, missing, vinOk }; +} diff --git a/08_Collected_MultiPROG_Scripts/Original/07_key_inventory_audit.mjs b/08_Collected_MultiPROG_Scripts/Original/07_key_inventory_audit.mjs index b141227..01b1483 100644 --- a/08_Collected_MultiPROG_Scripts/Original/07_key_inventory_audit.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/07_key_inventory_audit.mjs @@ -1,2 +1,12 @@ // Administrative inventory only. Does not calculate, extract, clone, generate or program credentials. -export function auditKeyInventory(entries){return entries.map((e,i)=>({row:i+1,assetTag:String(e.assetTag||""),type:String(e.type||""),source:String(e.source||""),sealed:Boolean(e.sealed),assigned:Boolean(e.assigned),notes:String(e.notes||"")}));} +export function auditKeyInventory(entries) { + return entries.map((e, i) => ({ + row: i + 1, + assetTag: String(e.assetTag || ""), + type: String(e.type || ""), + source: String(e.source || ""), + sealed: Boolean(e.sealed), + assigned: Boolean(e.assigned), + notes: String(e.notes || ""), + })); +} diff --git a/08_Collected_MultiPROG_Scripts/Original/08_redacted_security_report.mjs b/08_Collected_MultiPROG_Scripts/Original/08_redacted_security_report.mjs index c1ab527..fb292c8 100644 --- a/08_Collected_MultiPROG_Scripts/Original/08_redacted_security_report.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/08_redacted_security_report.mjs @@ -1,2 +1,16 @@ -export function redact(value,keepLast=4){const s=String(value??"");return s.length<=keepLast?"*".repeat(s.length):"*".repeat(s.length-keepLast)+s.slice(-keepLast);} -export function securityReport(job){return {caseId:job.caseId,vin:redact(job.vehicleVin,6),authorizationRef:redact(job.authorizationRef,4),technician:job.technician,timestampUtc:job.timestampUtc,status:job.status};} +export function redact(value, keepLast = 4) { + const s = String(value ?? ""); + return s.length <= keepLast + ? "*".repeat(s.length) + : "*".repeat(s.length - keepLast) + s.slice(-keepLast); +} +export function securityReport(job) { + return { + caseId: job.caseId, + vin: redact(job.vehicleVin, 6), + authorizationRef: redact(job.authorizationRef, 4), + technician: job.technician, + timestampUtc: job.timestampUtc, + status: job.status, + }; +} diff --git a/08_Collected_MultiPROG_Scripts/Original/09_immo_case_intake_validator.mjs b/08_Collected_MultiPROG_Scripts/Original/09_immo_case_intake_validator.mjs index 4211931..18589e8 100644 --- a/08_Collected_MultiPROG_Scripts/Original/09_immo_case_intake_validator.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/09_immo_case_intake_validator.mjs @@ -1,19 +1,29 @@ /* Authorized-shop administrative example. Does not read, derive, calculate, program, clone, or bypass immobilizer credentials. */ const REQUIRED = [ - "caseId", "timestampUtc", "technician", "customerName", "vehicleVin", - "proofOfOwnershipRef", "authorizationRef", "requestedService" + "caseId", + "timestampUtc", + "technician", + "customerName", + "vehicleVin", + "proofOfOwnershipRef", + "authorizationRef", + "requestedService", ]; export function validateImmoCase(caseRecord) { - const missing = REQUIRED.filter(k => !String(caseRecord[k] ?? "").trim()); - const vin = String(caseRecord.vehicleVin ?? "").trim().toUpperCase(); + const missing = REQUIRED.filter((k) => !String(caseRecord[k] ?? "").trim()); + const vin = String(caseRecord.vehicleVin ?? "") + .trim() + .toUpperCase(); const vinValid = /^[A-HJ-NPR-Z0-9]{17}$/.test(vin); - const authorizationValid = Boolean(String(caseRecord.authorizationRef ?? "").trim()); + const authorizationValid = Boolean( + String(caseRecord.authorizationRef ?? "").trim(), + ); return { valid: missing.length === 0 && vinValid && authorizationValid, missing, vinValid, - authorizationValid + authorizationValid, }; } diff --git a/08_Collected_MultiPROG_Scripts/Original/10_immo_module_read_consistency.mjs b/08_Collected_MultiPROG_Scripts/Original/10_immo_module_read_consistency.mjs index ec8ff43..53076fe 100644 --- a/08_Collected_MultiPROG_Scripts/Original/10_immo_module_read_consistency.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/10_immo_module_read_consistency.mjs @@ -4,7 +4,12 @@ import { constantTimeEqual, crc32, diffRanges } from "../../binary_utils.mjs"; export function compareAuthorizedReads(readA, readB) { if (readA.length !== readB.length) { - return { valid: false, reason: "Different file lengths", lengthA: readA.length, lengthB: readB.length }; + return { + valid: false, + reason: "Different file lengths", + lengthA: readA.length, + lengthB: readB.length, + }; } const identical = constantTimeEqual(readA, readB); return { @@ -13,6 +18,6 @@ export function compareAuthorizedReads(readA, readB) { length: readA.length, crc32A: crc32(readA).toString(16).padStart(8, "0").toUpperCase(), crc32B: crc32(readB).toString(16).padStart(8, "0").toUpperCase(), - changedRanges: identical ? [] : diffRanges(readA, readB) + changedRanges: identical ? [] : diffRanges(readA, readB), }; } diff --git a/08_Collected_MultiPROG_Scripts/Original/11_immo_dump_quality_report.mjs b/08_Collected_MultiPROG_Scripts/Original/11_immo_dump_quality_report.mjs index 878e4ed..eea197e 100644 --- a/08_Collected_MultiPROG_Scripts/Original/11_immo_dump_quality_report.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/11_immo_dump_quality_report.mjs @@ -4,15 +4,18 @@ import { countByte, crc32, asciiPreview } from "../../binary_utils.mjs"; export function buildDumpQualityReport(data) { if (!data.length) return { valid: false, reason: "Empty input" }; - const ff = countByte(data, 0xFF); + const ff = countByte(data, 0xff); const zero = countByte(data, 0x00); return { valid: true, length: data.length, crc32: crc32(data).toString(16).padStart(8, "0").toUpperCase(), - ffPercent: Number((ff * 100 / data.length).toFixed(2)), - zeroPercent: Number((zero * 100 / data.length).toFixed(2)), + ffPercent: Number(((ff * 100) / data.length).toFixed(2)), + zeroPercent: Number(((zero * 100) / data.length).toFixed(2)), printablePreview: asciiPreview(data.slice(0, 64)), - warning: ff === data.length || zero === data.length ? "Input appears blank or erased" : "" + warning: + ff === data.length || zero === data.length + ? "Input appears blank or erased" + : "", }; } diff --git a/08_Collected_MultiPROG_Scripts/Original/12_authorized_key_count_reconciliation.mjs b/08_Collected_MultiPROG_Scripts/Original/12_authorized_key_count_reconciliation.mjs index ca552d7..3b72f79 100644 --- a/08_Collected_MultiPROG_Scripts/Original/12_authorized_key_count_reconciliation.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/12_authorized_key_count_reconciliation.mjs @@ -7,10 +7,17 @@ export function reconcileKeys(record) { const retained = Number(record.keysRetainedByShop ?? 0); const expectedReturn = received + added - retained; return { - received, returned, added, retained, expectedReturn, - balanced: Number.isInteger(received) && Number.isInteger(returned) && - Number.isInteger(added) && Number.isInteger(retained) && - [received, returned, added, retained].every(v => v >= 0) && - returned === expectedReturn + received, + returned, + added, + retained, + expectedReturn, + balanced: + Number.isInteger(received) && + Number.isInteger(returned) && + Number.isInteger(added) && + Number.isInteger(retained) && + [received, returned, added, retained].every((v) => v >= 0) && + returned === expectedReturn, }; } diff --git a/08_Collected_MultiPROG_Scripts/Original/14_immo_backup_naming_policy.mjs b/08_Collected_MultiPROG_Scripts/Original/14_immo_backup_naming_policy.mjs index 5140b43..eda369a 100644 --- a/08_Collected_MultiPROG_Scripts/Original/14_immo_backup_naming_policy.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/14_immo_backup_naming_policy.mjs @@ -1,12 +1,21 @@ /* Produces a consistent, sanitized filename for authorized backups. */ function safe(value) { - return String(value ?? "unknown").trim().replace(/[^A-Za-z0-9._-]+/g, "_").slice(0, 50); + return String(value ?? "unknown") + .trim() + .replace(/[^A-Za-z0-9._-]+/g, "_") + .slice(0, 50); } export function buildBackupName(meta) { const stamp = safe(meta.timestampUtc).replace(/[:]/g, "-"); - return [ - safe(meta.caseId), safe(meta.vehicleVin), safe(meta.module), - safe(meta.memoryRegion), safe(meta.readNumber), stamp - ].join("_") + ".bin"; + return ( + [ + safe(meta.caseId), + safe(meta.vehicleVin), + safe(meta.module), + safe(meta.memoryRegion), + safe(meta.readNumber), + stamp, + ].join("_") + ".bin" + ); } diff --git a/08_Collected_MultiPROG_Scripts/Original/15_immo_change_scope_guard.mjs b/08_Collected_MultiPROG_Scripts/Original/15_immo_change_scope_guard.mjs index 80845bf..aea91f5 100644 --- a/08_Collected_MultiPROG_Scripts/Original/15_immo_change_scope_guard.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/15_immo_change_scope_guard.mjs @@ -6,13 +6,19 @@ function rangeInside(change, allowed) { return change.start >= allowed.start && change.end <= allowed.end; } -export function validateAuthorizedChangeScope(original, modified, allowedRanges) { +export function validateAuthorizedChangeScope( + original, + modified, + allowedRanges, +) { const changes = diffRanges(original, modified); - const violations = changes.filter(c => !allowedRanges.some(a => rangeInside(c, a))); + const violations = changes.filter( + (c) => !allowedRanges.some((a) => rangeInside(c, a)), + ); return { valid: violations.length === 0, changes, violations, - changedBytes: changes.reduce((n, r) => n + r.length, 0) + changedBytes: changes.reduce((n, r) => n + r.length, 0), }; } diff --git a/08_Collected_MultiPROG_Scripts/Original/16_immo_service_completion_audit.mjs b/08_Collected_MultiPROG_Scripts/Original/16_immo_service_completion_audit.mjs index 75c00b8..dbbec4a 100644 --- a/08_Collected_MultiPROG_Scripts/Original/16_immo_service_completion_audit.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/16_immo_service_completion_audit.mjs @@ -8,7 +8,7 @@ export function auditCompletion(job) { physicalKeysReconciled: job.physicalKeysReconciled === true, customerAcknowledged: Boolean(job.customerAcknowledgmentRef), securityDataRedacted: job.securityDataRedacted === true, - technicianSigned: Boolean(job.technicianSignatureRef) + technicianSigned: Boolean(job.technicianSignatureRef), }; return { complete: Object.values(checks).every(Boolean), checks }; } diff --git a/08_Collected_MultiPROG_Scripts/Original/binary_utils.mjs b/08_Collected_MultiPROG_Scripts/Original/binary_utils.mjs index 481ef62..d34f226 100644 --- a/08_Collected_MultiPROG_Scripts/Original/binary_utils.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/binary_utils.mjs @@ -6,36 +6,196 @@ export function requireBytes(data) { } export function assertRange(data, offset, length) { requireBytes(data); - if (!Number.isInteger(offset)||!Number.isInteger(length)||offset<0||length<0||offset+length>data.length) throw new RangeError("Range outside buffer"); + if ( + !Number.isInteger(offset) || + !Number.isInteger(length) || + offset < 0 || + length < 0 || + offset + length > data.length + ) + throw new RangeError("Range outside buffer"); } -export function cloneBytes(data){ requireBytes(data); return new Uint8Array(data); } -export function sliceBytes(data,offset,length){ assertRange(data,offset,length); return data.slice(offset,offset+length); } -export function bytesToHex(data,separator=" "){ requireBytes(data); return Array.from(data,b=>b.toString(16).padStart(2,"0")).join(separator).toUpperCase(); } -export function hexToBytes(text){ - const s=String(text).replace(/[^0-9a-f]/gi,""); - if(s.length%2) throw new Error("Hex text must contain complete bytes"); - const out=new Uint8Array(s.length/2); for(let i=0;i b.toString(16).padStart(2, "0")) + .join(separator) + .toUpperCase(); +} +export function hexToBytes(text) { + const s = String(text).replace(/[^0-9a-f]/gi, ""); + if (s.length % 2) throw new Error("Hex text must contain complete bytes"); + const out = new Uint8Array(s.length / 2); + for (let i = 0; i < out.length; i++) + out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16); + return out; +} +export function asciiPreview(data, replacement = ".") { + requireBytes(data); + return Array.from(data, (b) => + b >= 32 && b <= 126 ? String.fromCharCode(b) : replacement, + ).join(""); +} +export function readU16LE(d, o) { + assertRange(d, o, 2); + return d[o] | (d[o + 1] << 8); +} +export function readU16BE(d, o) { + assertRange(d, o, 2); + return (d[o] << 8) | d[o + 1]; +} +export function readU32LE(d, o) { + assertRange(d, o, 4); + return (d[o] | (d[o + 1] << 8) | (d[o + 2] << 16) | (d[o + 3] << 24)) >>> 0; +} +export function readU32BE(d, o) { + assertRange(d, o, 4); + return ((d[o] << 24) | (d[o + 1] << 16) | (d[o + 2] << 8) | d[o + 3]) >>> 0; +} +export function writeU16LE(d, o, v) { + assertRange(d, o, 2); + d[o] = v & 255; + d[o + 1] = (v >>> 8) & 255; +} +export function writeU16BE(d, o, v) { + assertRange(d, o, 2); + d[o] = (v >>> 8) & 255; + d[o + 1] = v & 255; +} +export function writeU32LE(d, o, v) { + assertRange(d, o, 4); + for (let i = 0; i < 4; i++) d[o + i] = (v >>> (8 * i)) & 255; +} +export function writeU32BE(d, o, v) { + assertRange(d, o, 4); + for (let i = 0; i < 4; i++) d[o + i] = (v >>> (8 * (3 - i))) & 255; +} +export function findPattern(data, pattern, start = 0) { + requireBytes(data); + requireBytes(pattern); + const hits = []; + for (let i = start; i <= data.length - pattern.length; i++) { + let ok = true; + for (let j = 0; j < pattern.length; j++) + if (data[i + j] !== pattern[j]) { + ok = false; + break; + } + if (ok) hits.push(i); + } + return hits; +} +export function countByte(data, value) { + requireBytes(data); + let n = 0; + for (const b of data) if (b === (value & 255)) n++; + return n; +} +export function isBlank( + data, + offset = 0, + length = data.length - offset, + blank = 0xff, +) { + assertRange(data, offset, length); + for (let i = offset; i < offset + length; i++) + if (data[i] !== blank) return false; + return true; +} +export function diffRanges(a, b) { + requireBytes(a); + requireBytes(b); + if (a.length !== b.length) throw new Error("Length mismatch"); + const out = []; + let s = -1; + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i] && s < 0) s = i; + if ((a[i] === b[i] || i === a.length - 1) && s >= 0) { + const e = a[i] === b[i] ? i - 1 : i; + out.push({ start: s, end: e, length: e - s + 1 }); + s = -1; + } + } + return out; +} +export function changedByteCount(a, b) { + return diffRanges(a, b).reduce((n, r) => n + r.length, 0); +} +export function sum8(data) { + requireBytes(data); + let s = 0; + for (const b of data) s = (s + b) & 255; + return s; +} +export function xor8(data) { + requireBytes(data); + let x = 0; + for (const b of data) x ^= b; + return x; +} +export function crc16CcittFalse(data) { + requireBytes(data); + let crc = 0xffff; + for (const b of data) { + crc ^= b << 8; + for (let i = 0; i < 8; i++) + crc = (crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1) & 0xffff; + } + return crc; +} +export function crc32(data) { + requireBytes(data); + let crc = 0xffffffff; + for (const b of data) { + crc ^= b; + for (let i = 0; i < 8; i++) crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0); + } + return (crc ^ 0xffffffff) >>> 0; +} +export function adler32(data) { + requireBytes(data); + let a = 1, + b = 0; + for (const v of data) { + a = (a + v) % 65521; + b = (b + a) % 65521; + } + return ((b << 16) | a) >>> 0; +} +export function bcdToInt(byte) { + const hi = (byte >>> 4) & 15, + lo = byte & 15; + if (hi > 9 || lo > 9) throw new Error("Invalid BCD"); + return hi * 10 + lo; +} +export function intToBcd(value) { + if (!Number.isInteger(value) || value < 0 || value > 99) + throw new RangeError("BCD value must be 0..99"); + return (Math.floor(value / 10) << 4) | (value % 10); +} +export function constantTimeEqual(a, b) { + requireBytes(a); + requireBytes(b); + if (a.length !== b.length) return false; + let d = 0; + for (let i = 0; i < a.length; i++) d |= a[i] ^ b[i]; + return d === 0; +} +export function allowListedWrite(copy, offset, newBytes, allowedRanges) { + requireBytes(copy); + requireBytes(newBytes); + assertRange(copy, offset, newBytes.length); + const ok = allowedRanges.some( + (r) => offset >= r.start && offset + newBytes.length - 1 <= r.end, + ); + if (!ok) throw new Error("Write is outside allow-list"); + copy.set(newBytes, offset); + return copy; } -export function asciiPreview(data,replacement="."){ requireBytes(data); return Array.from(data,b=>b>=32&&b<=126?String.fromCharCode(b):replacement).join(""); } -export function readU16LE(d,o){assertRange(d,o,2);return d[o]|(d[o+1]<<8);} -export function readU16BE(d,o){assertRange(d,o,2);return (d[o]<<8)|d[o+1];} -export function readU32LE(d,o){assertRange(d,o,4);return (d[o]|d[o+1]<<8|d[o+2]<<16|d[o+3]<<24)>>>0;} -export function readU32BE(d,o){assertRange(d,o,4);return ((d[o]<<24)|(d[o+1]<<16)|(d[o+2]<<8)|d[o+3])>>>0;} -export function writeU16LE(d,o,v){assertRange(d,o,2);d[o]=v&255;d[o+1]=(v>>>8)&255;} -export function writeU16BE(d,o,v){assertRange(d,o,2);d[o]=(v>>>8)&255;d[o+1]=v&255;} -export function writeU32LE(d,o,v){assertRange(d,o,4);for(let i=0;i<4;i++)d[o+i]=(v>>>(8*i))&255;} -export function writeU32BE(d,o,v){assertRange(d,o,4);for(let i=0;i<4;i++)d[o+i]=(v>>>(8*(3-i)))&255;} -export function findPattern(data,pattern,start=0){requireBytes(data);requireBytes(pattern);const hits=[];for(let i=start;i<=data.length-pattern.length;i++){let ok=true;for(let j=0;j=0){const e=a[i]===b[i]?i-1:i;out.push({start:s,end:e,length:e-s+1});s=-1;}}return out;} -export function changedByteCount(a,b){return diffRanges(a,b).reduce((n,r)=>n+r.length,0);} -export function sum8(data){requireBytes(data);let s=0;for(const b of data)s=(s+b)&255;return s;} -export function xor8(data){requireBytes(data);let x=0;for(const b of data)x^=b;return x;} -export function crc16CcittFalse(data){requireBytes(data);let crc=0xFFFF;for(const b of data){crc^=b<<8;for(let i=0;i<8;i++)crc=((crc&0x8000)?(crc<<1)^0x1021:crc<<1)&0xFFFF;}return crc;} -export function crc32(data){requireBytes(data);let crc=0xFFFFFFFF;for(const b of data){crc^=b;for(let i=0;i<8;i++)crc=(crc>>>1)^((crc&1)?0xEDB88320:0);}return (crc^0xFFFFFFFF)>>>0;} -export function adler32(data){requireBytes(data);let a=1,b=0;for(const v of data){a=(a+v)%65521;b=(b+a)%65521;}return ((b<<16)|a)>>>0;} -export function bcdToInt(byte){const hi=(byte>>>4)&15,lo=byte&15;if(hi>9||lo>9)throw new Error("Invalid BCD");return hi*10+lo;} -export function intToBcd(value){if(!Number.isInteger(value)||value<0||value>99)throw new RangeError("BCD value must be 0..99");return ((Math.floor(value/10)<<4)|(value%10));} -export function constantTimeEqual(a,b){requireBytes(a);requireBytes(b);if(a.length!==b.length)return false;let d=0;for(let i=0;ioffset>=r.start&&offset+newBytes.length-1<=r.end);if(!ok)throw new Error("Write is outside allow-list");copy.set(newBytes,offset);return copy;} diff --git a/08_Collected_MultiPROG_Scripts/Original/test_binary_utils.mjs b/08_Collected_MultiPROG_Scripts/Original/test_binary_utils.mjs index 0cd7874..78b15db 100644 --- a/08_Collected_MultiPROG_Scripts/Original/test_binary_utils.mjs +++ b/08_Collected_MultiPROG_Scripts/Original/test_binary_utils.mjs @@ -1,7 +1,10 @@ import { strict as assert } from "node:assert"; import { crc32, diffRanges, bytesToHex } from "./binary_utils.mjs"; -const v=new TextEncoder().encode("123456789"); -assert.equal(crc32(v),0xCBF43926); -assert.equal(bytesToHex(new Uint8Array([0,15,255])),"00 0F FF"); -assert.deepEqual(diffRanges(new Uint8Array([1,2,3,4]),new Uint8Array([1,9,8,4])),[{start:1,end:2,length:2}]); +const v = new TextEncoder().encode("123456789"); +assert.equal(crc32(v), 0xcbf43926); +assert.equal(bytesToHex(new Uint8Array([0, 15, 255])), "00 0F FF"); +assert.deepEqual( + diffRanges(new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 9, 8, 4])), + [{ start: 1, end: 2, length: 2 }], +); console.log("All tests passed"); diff --git a/09_Collected_JS/administrative/script_catalog.mjs b/09_Collected_JS/administrative/script_catalog.mjs index 6b4263c..c61ef57 100644 --- a/09_Collected_JS/administrative/script_catalog.mjs +++ b/09_Collected_JS/administrative/script_catalog.mjs @@ -11,19 +11,29 @@ export function buildScriptIndex(sourceText, options = {}) { const source = toText(sourceText); const path = toText(options.path || ""); const headerMatch = source.match(/^\/\*([\s\S]*?)\*\//m); - const functions = [...source.matchAll(/(?:export\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/g)].map((match) => ({ + const functions = [ + ...source.matchAll(/(?:export\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/g), + ].map((match) => ({ name: match[1], - line: lineNumberAtIndex(source, match.index ?? 0) + line: lineNumberAtIndex(source, match.index ?? 0), })); - const classes = [...source.matchAll(/class\s+([A-Za-z_$][\w$]*)/g)].map((match) => ({ + const classes = [...source.matchAll(/class\s+([A-Za-z_$][\w$]*)/g)].map( + (match) => ({ + name: match[1], + line: lineNumberAtIndex(source, match.index ?? 0), + }), + ); + const imports = [ + ...source.matchAll(/import\s+(?:[^"']+?\s+from\s+)?["']([^"']+)["']/g), + ].map((match) => ({ + specifier: match[1], + })); + const exports = [ + ...source.matchAll( + /export\s+(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/g, + ), + ].map((match) => ({ name: match[1], - line: lineNumberAtIndex(source, match.index ?? 0) - })); - const imports = [...source.matchAll(/import\s+(?:[^"']+?\s+from\s+)?["']([^"']+)["']/g)].map((match) => ({ - specifier: match[1] - })); - const exports = [...source.matchAll(/export\s+(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/g)].map((match) => ({ - name: match[1] })); return { path, @@ -32,7 +42,7 @@ export function buildScriptIndex(sourceText, options = {}) { functions, classes, imports, - exports + exports, }; } diff --git a/09_Collected_JS/binary/dataview_helpers.mjs b/09_Collected_JS/binary/dataview_helpers.mjs index e848cc6..b3d231b 100644 --- a/09_Collected_JS/binary/dataview_helpers.mjs +++ b/09_Collected_JS/binary/dataview_helpers.mjs @@ -1,21 +1,58 @@ /* Minimal stateful binary reader over a Uint8Array, similar in spirit to jBinary/binary-parser readers. */ export class BinaryReader { constructor(data) { - if (!(data instanceof Uint8Array)) throw new TypeError("Uint8Array required"); + if (!(data instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); this.data = data; this.view = new DataView(data.buffer, data.byteOffset, data.byteLength); this.pos = 0; } - get remaining() { return this.data.length - this.pos; } - seek(pos) { this.pos = pos; return this; } - skip(n) { this.pos += n; return this; } - readUint8() { const v = this.view.getUint8(this.pos); this.pos += 1; return v; } - readInt8() { const v = this.view.getInt8(this.pos); this.pos += 1; return v; } - readUint16LE() { const v = this.view.getUint16(this.pos, true); this.pos += 2; return v; } - readUint16BE() { const v = this.view.getUint16(this.pos, false); this.pos += 2; return v; } - readUint32LE() { const v = this.view.getUint32(this.pos, true); this.pos += 4; return v; } - readUint32BE() { const v = this.view.getUint32(this.pos, false); this.pos += 4; return v; } - readBytes(n) { const v = this.data.slice(this.pos, this.pos + n); this.pos += n; return v; } + get remaining() { + return this.data.length - this.pos; + } + seek(pos) { + this.pos = pos; + return this; + } + skip(n) { + this.pos += n; + return this; + } + readUint8() { + const v = this.view.getUint8(this.pos); + this.pos += 1; + return v; + } + readInt8() { + const v = this.view.getInt8(this.pos); + this.pos += 1; + return v; + } + readUint16LE() { + const v = this.view.getUint16(this.pos, true); + this.pos += 2; + return v; + } + readUint16BE() { + const v = this.view.getUint16(this.pos, false); + this.pos += 2; + return v; + } + readUint32LE() { + const v = this.view.getUint32(this.pos, true); + this.pos += 4; + return v; + } + readUint32BE() { + const v = this.view.getUint32(this.pos, false); + this.pos += 4; + return v; + } + readBytes(n) { + const v = this.data.slice(this.pos, this.pos + n); + this.pos += n; + return v; + } readCString(maxLen = this.remaining) { const start = this.pos; let end = start; diff --git a/09_Collected_JS/binary/struct_reader.mjs b/09_Collected_JS/binary/struct_reader.mjs index e1bbd88..fcf3ca1 100644 --- a/09_Collected_JS/binary/struct_reader.mjs +++ b/09_Collected_JS/binary/struct_reader.mjs @@ -8,14 +8,14 @@ import { BinaryReader } from "./dataview_helpers.mjs"; ]) */ const READERS = { - u8: r => r.readUint8(), - i8: r => r.readInt8(), - u16le: r => r.readUint16LE(), - u16be: r => r.readUint16BE(), - u32le: r => r.readUint32LE(), - u32be: r => r.readUint32BE(), + u8: (r) => r.readUint8(), + i8: (r) => r.readInt8(), + u16le: (r) => r.readUint16LE(), + u16be: (r) => r.readUint16BE(), + u32le: (r) => r.readUint32LE(), + u32be: (r) => r.readUint32BE(), cstring: (r, field) => r.readCString(field.maxLen), - bytes: (r, field) => r.readBytes(field.length) + bytes: (r, field) => r.readBytes(field.length), }; export function parseStruct(data, fields) { @@ -25,7 +25,9 @@ export function parseStruct(data, fields) { const readOne = READERS[field.type]; if (!readOne) throw new Error(`Unknown field type: ${field.type}`); if (field.count) { - out[field.name] = Array.from({ length: field.count }, () => readOne(reader, field)); + out[field.name] = Array.from({ length: field.count }, () => + readOne(reader, field), + ); } else { out[field.name] = readOne(reader, field); } diff --git a/09_Collected_JS/checksums/adler32.mjs b/09_Collected_JS/checksums/adler32.mjs index cc97825..e898d15 100644 --- a/09_Collected_JS/checksums/adler32.mjs +++ b/09_Collected_JS/checksums/adler32.mjs @@ -8,7 +8,8 @@ const MOD_ADLER = 65521; /* Adler-32 (zlib). Check value for "123456789" is 0x091E01DE. */ export function adler32(data) { requireBytes(data); - let a = 1, b = 0; + let a = 1, + b = 0; for (const byte of data) { a = (a + byte) % MOD_ADLER; b = (b + a) % MOD_ADLER; diff --git a/09_Collected_JS/checksums/crc16.mjs b/09_Collected_JS/checksums/crc16.mjs index 1a4ca23..53567c2 100644 --- a/09_Collected_JS/checksums/crc16.mjs +++ b/09_Collected_JS/checksums/crc16.mjs @@ -6,11 +6,11 @@ function requireBytes(data) { /* CRC-16/CCITT-FALSE (poly 0x1021, init 0xFFFF, no reflect). Check value for "123456789" is 0x29B1. */ export function crc16CcittFalse(data) { requireBytes(data); - let crc = 0xFFFF; + let crc = 0xffff; for (const b of data) { crc ^= b << 8; for (let i = 0; i < 8; i++) { - crc = (crc & 0x8000) ? ((crc << 1) ^ 0x1021) & 0xFFFF : (crc << 1) & 0xFFFF; + crc = crc & 0x8000 ? ((crc << 1) ^ 0x1021) & 0xffff : (crc << 1) & 0xffff; } } return crc; @@ -19,12 +19,12 @@ export function crc16CcittFalse(data) { /* CRC-16/MODBUS (poly 0x8005 reflected as 0xA001, init 0xFFFF, reflected). Check value for "123456789" is 0x4B37. */ export function crc16Modbus(data) { requireBytes(data); - let crc = 0xFFFF; + let crc = 0xffff; for (const byte of data) { crc ^= byte; for (let i = 0; i < 8; i++) { - crc = (crc & 1) ? (crc >>> 1) ^ 0xA001 : crc >>> 1; + crc = crc & 1 ? (crc >>> 1) ^ 0xa001 : crc >>> 1; } } - return crc & 0xFFFF; + return crc & 0xffff; } diff --git a/09_Collected_JS/checksums/crc32.mjs b/09_Collected_JS/checksums/crc32.mjs index 45a97d7..dfd414a 100644 --- a/09_Collected_JS/checksums/crc32.mjs +++ b/09_Collected_JS/checksums/crc32.mjs @@ -1,9 +1,12 @@ export function normalizeBytes(data) { if (data instanceof Uint8Array) return data; - if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + if (ArrayBuffer.isView(data)) + return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); if (data instanceof ArrayBuffer) return new Uint8Array(data); if (typeof data === "string") return new TextEncoder().encode(data); - throw new TypeError("Uint8Array, ArrayBuffer, typed array, or string required"); + throw new TypeError( + "Uint8Array, ArrayBuffer, typed array, or string required", + ); } function requireBytes(data) { @@ -13,25 +16,25 @@ function requireBytes(data) { /* CRC-32 (IEEE 802.3, poly 0xEDB88320 reflected, init 0xFFFFFFFF). Check value for "123456789" is 0xCBF43926. */ export function crc32(data) { const bytes = requireBytes(data); - let crc = 0xFFFFFFFF; + let crc = 0xffffffff; for (const b of bytes) { crc ^= b; for (let i = 0; i < 8; i++) { - crc = (crc >>> 1) ^ ((crc & 1) ? 0xEDB88320 : 0); + crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0); } } - return (crc ^ 0xFFFFFFFF) >>> 0; + return (crc ^ 0xffffffff) >>> 0; } /* CRC-32C (Castagnoli, poly 0x82F63B78 reflected, init 0xFFFFFFFF). Check value for "123456789" is 0xE3069283. */ export function crc32c(data) { const bytes = requireBytes(data); - let crc = 0xFFFFFFFF; + let crc = 0xffffffff; for (const b of bytes) { crc ^= b; for (let i = 0; i < 8; i++) { - crc = (crc & 1) ? (crc >>> 1) ^ 0x82F63B78 : crc >>> 1; + crc = crc & 1 ? (crc >>> 1) ^ 0x82f63b78 : crc >>> 1; } } - return (crc ^ 0xFFFFFFFF) >>> 0; + return (crc ^ 0xffffffff) >>> 0; } diff --git a/09_Collected_JS/checksums/crc64.mjs b/09_Collected_JS/checksums/crc64.mjs index c54bf7f..472705c 100644 --- a/09_Collected_JS/checksums/crc64.mjs +++ b/09_Collected_JS/checksums/crc64.mjs @@ -3,8 +3,8 @@ function requireBytes(data) { return data; } -const POLY = 0xC96C5795D7870F42n; -const MASK64 = 0xFFFFFFFFFFFFFFFFn; +const POLY = 0xc96c5795d7870f42n; +const MASK64 = 0xffffffffffffffffn; /* CRC-64/XZ (poly 0x42F0E1EBA9EA3693 reflected, init all-ones, reflected). Check value for "123456789" is 0x995DC9BBDF1939FA. Uses BigInt; returns a zero-padded 16-hex-digit string since the value exceeds safe integer range. */ @@ -14,7 +14,7 @@ export function crc64Xz(data) { for (const b of data) { crc ^= BigInt(b); for (let i = 0; i < 8; i++) { - crc = (crc & 1n) ? ((crc >> 1n) ^ POLY) & MASK64 : (crc >> 1n) & MASK64; + crc = crc & 1n ? ((crc >> 1n) ^ POLY) & MASK64 : (crc >> 1n) & MASK64; } } return ((crc ^ MASK64) & MASK64).toString(16).padStart(16, "0"); diff --git a/09_Collected_JS/checksums/crc8.mjs b/09_Collected_JS/checksums/crc8.mjs index a1558fc..ac441cd 100644 --- a/09_Collected_JS/checksums/crc8.mjs +++ b/09_Collected_JS/checksums/crc8.mjs @@ -6,11 +6,11 @@ function requireBytes(data) { /* CRC-8 (poly 0x07, init 0x00, no reflect, no xorout). Check value for ASCII "123456789" is 0xF4. */ export function crc8(data, poly = 0x07, init = 0x00) { requireBytes(data); - let crc = init & 0xFF; + let crc = init & 0xff; for (const b of data) { crc ^= b; for (let i = 0; i < 8; i++) { - crc = (crc & 0x80) ? ((crc << 1) ^ poly) & 0xFF : (crc << 1) & 0xFF; + crc = crc & 0x80 ? ((crc << 1) ^ poly) & 0xff : (crc << 1) & 0xff; } } return crc; diff --git a/09_Collected_JS/checksums/fletcher.mjs b/09_Collected_JS/checksums/fletcher.mjs index 2a9505f..88bc3bc 100644 --- a/09_Collected_JS/checksums/fletcher.mjs +++ b/09_Collected_JS/checksums/fletcher.mjs @@ -6,7 +6,8 @@ function requireBytes(data) { /* Fletcher-16 over bytes (modulus 255). */ export function fletcher16(data) { requireBytes(data); - let sum1 = 0, sum2 = 0; + let sum1 = 0, + sum2 = 0; for (const b of data) { sum1 = (sum1 + b) % 255; sum2 = (sum2 + sum1) % 255; @@ -18,9 +19,11 @@ export function fletcher16(data) { export function fletcher32(data) { requireBytes(data); const words = []; - for (let i = 0; i + 1 < data.length; i += 2) words.push(data[i] | (data[i + 1] << 8)); + for (let i = 0; i + 1 < data.length; i += 2) + words.push(data[i] | (data[i + 1] << 8)); if (data.length % 2 === 1) words.push(data[data.length - 1]); - let sum1 = 0, sum2 = 0; + let sum1 = 0, + sum2 = 0; for (const w of words) { sum1 = (sum1 + w) % 65535; sum2 = (sum2 + sum1) % 65535; diff --git a/09_Collected_JS/encoding/ascii.mjs b/09_Collected_JS/encoding/ascii.mjs index 187a066..4f82c9e 100644 --- a/09_Collected_JS/encoding/ascii.mjs +++ b/09_Collected_JS/encoding/ascii.mjs @@ -9,14 +9,16 @@ export function isPrintableAscii(byte) { export function asciiPreview(data, replacement = ".") { requireBytes(data); - return Array.from(data, b => (isPrintableAscii(b) ? String.fromCharCode(b) : replacement)).join(""); + return Array.from(data, (b) => + isPrintableAscii(b) ? String.fromCharCode(b) : replacement, + ).join(""); } export function encodeAscii(text) { const out = new Uint8Array(text.length); for (let i = 0; i < text.length; i++) { const code = text.charCodeAt(i); - out[i] = code <= 127 ? code : 0x3F; // '?' for non-ASCII input + out[i] = code <= 127 ? code : 0x3f; // '?' for non-ASCII input } return out; } diff --git a/09_Collected_JS/encoding/bcd.mjs b/09_Collected_JS/encoding/bcd.mjs index d73a69a..1c2ff81 100644 --- a/09_Collected_JS/encoding/bcd.mjs +++ b/09_Collected_JS/encoding/bcd.mjs @@ -4,14 +4,16 @@ function requireBytes(data) { } export function bcdByteToInt(byte) { - const hi = (byte >>> 4) & 0xF, lo = byte & 0xF; + const hi = (byte >>> 4) & 0xf, + lo = byte & 0xf; if (hi > 9 || lo > 9) throw new Error("Invalid BCD nibble"); return hi * 10 + lo; } export function intToBcdByte(value) { - if (!Number.isInteger(value) || value < 0 || value > 99) throw new RangeError("BCD value must be 0..99"); - return ((Math.floor(value / 10) << 4) | (value % 10)) & 0xFF; + if (!Number.isInteger(value) || value < 0 || value > 99) + throw new RangeError("BCD value must be 0..99"); + return ((Math.floor(value / 10) << 4) | (value % 10)) & 0xff; } /* Decodes a run of packed-BCD bytes into a decimal digit string, e.g. [0x20,0x26] -> "2026". */ diff --git a/09_Collected_JS/encoding/hex.mjs b/09_Collected_JS/encoding/hex.mjs index 59020da..d71aa69 100644 --- a/09_Collected_JS/encoding/hex.mjs +++ b/09_Collected_JS/encoding/hex.mjs @@ -5,13 +5,16 @@ function requireBytes(data) { export function encodeHex(data, separator = "") { requireBytes(data); - return Array.from(data, b => b.toString(16).padStart(2, "0")).join(separator).toUpperCase(); + return Array.from(data, (b) => b.toString(16).padStart(2, "0")) + .join(separator) + .toUpperCase(); } export function decodeHex(text) { const s = String(text).replace(/[^0-9a-f]/gi, ""); if (s.length % 2) throw new Error("Hex text must contain complete bytes"); const out = new Uint8Array(s.length / 2); - for (let i = 0; i < out.length; i++) out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16); + for (let i = 0; i < out.length; i++) + out[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16); return out; } diff --git a/09_Collected_JS/hashing/md5.mjs b/09_Collected_JS/hashing/md5.mjs index a08cbb6..9dd63e9 100644 --- a/09_Collected_JS/hashing/md5.mjs +++ b/09_Collected_JS/hashing/md5.mjs @@ -3,16 +3,19 @@ function requireBytes(data) { return data; } -function rotl(x, n) { return (x << n) | (x >>> (32 - n)); } +function rotl(x, n) { + return (x << n) | (x >>> (32 - n)); +} const S = [ - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, + 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, + 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, + 21, ]; const K = new Int32Array(64); -for (let i = 0; i < 64; i++) K[i] = (Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000)) | 0; +for (let i = 0; i < 64; i++) + K[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; function padMessageLE(data) { let k = data.length + 1; @@ -29,7 +32,8 @@ function padMessageLE(data) { function toHexLE(v) { let s = ""; - for (let i = 0; i < 4; i++) s += ((v >>> (i * 8)) & 0xFF).toString(16).padStart(2, "0"); + for (let i = 0; i < 4; i++) + s += ((v >>> (i * 8)) & 0xff).toString(16).padStart(2, "0"); return s; } @@ -38,22 +42,42 @@ export function md5(data) { requireBytes(data); const msg = padMessageLE(data); const dv = new DataView(msg.buffer); - let a0 = 0x67452301, b0 = 0xefcdab89, c0 = 0x98badcfe, d0 = 0x10325476; + let a0 = 0x67452301, + b0 = 0xefcdab89, + c0 = 0x98badcfe, + d0 = 0x10325476; const M = new Uint32Array(16); for (let off = 0; off < msg.length; off += 64) { for (let j = 0; j < 16; j++) M[j] = dv.getUint32(off + j * 4, true); - let A = a0, B = b0, C = c0, D = d0; + let A = a0, + B = b0, + C = c0, + D = d0; for (let i = 0; i < 64; i++) { let F, g; - if (i < 16) { F = (B & C) | ((~B) & D); g = i; } - else if (i < 32) { F = (D & B) | ((~D) & C); g = (5 * i + 1) % 16; } - else if (i < 48) { F = B ^ C ^ D; g = (3 * i + 5) % 16; } - else { F = C ^ (B | (~D)); g = (7 * i) % 16; } + if (i < 16) { + F = (B & C) | (~B & D); + g = i; + } else if (i < 32) { + F = (D & B) | (~D & C); + g = (5 * i + 1) % 16; + } else if (i < 48) { + F = B ^ C ^ D; + g = (3 * i + 5) % 16; + } else { + F = C ^ (B | ~D); + g = (7 * i) % 16; + } F = (F + A + K[i] + M[g]) >>> 0; - A = D; D = C; C = B; + A = D; + D = C; + C = B; B = (B + rotl(F, S[i])) >>> 0; } - a0 = (a0 + A) >>> 0; b0 = (b0 + B) >>> 0; c0 = (c0 + C) >>> 0; d0 = (d0 + D) >>> 0; + a0 = (a0 + A) >>> 0; + b0 = (b0 + B) >>> 0; + c0 = (c0 + C) >>> 0; + d0 = (d0 + D) >>> 0; } return toHexLE(a0) + toHexLE(b0) + toHexLE(c0) + toHexLE(d0); } diff --git a/09_Collected_JS/hashing/sha1.mjs b/09_Collected_JS/hashing/sha1.mjs index 495e3cc..3ef7833 100644 --- a/09_Collected_JS/hashing/sha1.mjs +++ b/09_Collected_JS/hashing/sha1.mjs @@ -5,14 +5,20 @@ function requireBytes(data) { return data; } -function rotl(x, n) { return (x << n) | (x >>> (32 - n)); } +function rotl(x, n) { + return (x << n) | (x >>> (32 - n)); +} /* SHA-1 reference implementation (FIPS 180-4). Check value for "abc" is a9993e364706816aba3e25717850c26c9cd0d89. */ export function sha1(data) { requireBytes(data); const msg = padMessageBE(data); const dv = new DataView(msg.buffer); - let h0 = 0x67452301, h1 = 0xEFCDAB89, h2 = 0x98BADCFE, h3 = 0x10325476, h4 = 0xC3D2E1F0; + let h0 = 0x67452301, + h1 = 0xefcdab89, + h2 = 0x98badcfe, + h3 = 0x10325476, + h4 = 0xc3d2e1f0; const w = new Uint32Array(80); for (let off = 0; off < msg.length; off += 64) { for (let t = 0; t < 16; t++) w[t] = dv.getUint32(off + t * 4); @@ -20,17 +26,40 @@ export function sha1(data) { const v = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; w[t] = rotl(v, 1); } - let a = h0, b = h1, c = h2, d = h3, e = h4; + let a = h0, + b = h1, + c = h2, + d = h3, + e = h4; for (let t = 0; t < 80; t++) { let f, k; - if (t < 20) { f = (b & c) | ((~b) & d); k = 0x5A827999; } - else if (t < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; } - else if (t < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } - else { f = b ^ c ^ d; k = 0xCA62C1D6; } + if (t < 20) { + f = (b & c) | (~b & d); + k = 0x5a827999; + } else if (t < 40) { + f = b ^ c ^ d; + k = 0x6ed9eba1; + } else if (t < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8f1bbcdc; + } else { + f = b ^ c ^ d; + k = 0xca62c1d6; + } const temp = (rotl(a, 5) + f + e + k + w[t]) >>> 0; - e = d; d = c; c = rotl(b, 30); b = a; a = temp; + e = d; + d = c; + c = rotl(b, 30); + b = a; + a = temp; } - h0 = (h0 + a) >>> 0; h1 = (h1 + b) >>> 0; h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0; h4 = (h4 + e) >>> 0; + h0 = (h0 + a) >>> 0; + h1 = (h1 + b) >>> 0; + h2 = (h2 + c) >>> 0; + h3 = (h3 + d) >>> 0; + h4 = (h4 + e) >>> 0; } - return [h0, h1, h2, h3, h4].map(v => v.toString(16).padStart(8, "0")).join(""); + return [h0, h1, h2, h3, h4] + .map((v) => v.toString(16).padStart(8, "0")) + .join(""); } diff --git a/09_Collected_JS/hashing/sha256.mjs b/09_Collected_JS/hashing/sha256.mjs index 9b2a5e0..ccdfcda 100644 --- a/09_Collected_JS/hashing/sha256.mjs +++ b/09_Collected_JS/hashing/sha256.mjs @@ -6,24 +6,29 @@ function requireBytes(data) { } const K = new Uint32Array([ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]); -function rotr(x, n) { return (x >>> n) | (x << (32 - n)); } +function rotr(x, n) { + return (x >>> n) | (x << (32 - n)); +} /* SHA-256 reference implementation (FIPS 180-4). Check value for "abc" is ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad. */ export function sha256(data) { requireBytes(data); const H = new Uint32Array([ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19, ]); const msg = padMessageBE(data); const dv = new DataView(msg.buffer); @@ -38,16 +43,28 @@ export function sha256(data) { let [a, b, c, d, e, f, g, h] = H; for (let t = 0; t < 64; t++) { const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25); - const ch = (e & f) ^ ((~e) & g); + const ch = (e & f) ^ (~e & g); const temp1 = (h + S1 + ch + K[t] + W[t]) >>> 0; const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22); const maj = (a & b) ^ (a & c) ^ (b & c); const temp2 = (S0 + maj) >>> 0; - h = g; g = f; f = e; e = (d + temp1) >>> 0; - d = c; c = b; b = a; a = (temp1 + temp2) >>> 0; + h = g; + g = f; + f = e; + e = (d + temp1) >>> 0; + d = c; + c = b; + b = a; + a = (temp1 + temp2) >>> 0; } - H[0] = (H[0] + a) >>> 0; H[1] = (H[1] + b) >>> 0; H[2] = (H[2] + c) >>> 0; H[3] = (H[3] + d) >>> 0; - H[4] = (H[4] + e) >>> 0; H[5] = (H[5] + f) >>> 0; H[6] = (H[6] + g) >>> 0; H[7] = (H[7] + h) >>> 0; + H[0] = (H[0] + a) >>> 0; + H[1] = (H[1] + b) >>> 0; + H[2] = (H[2] + c) >>> 0; + H[3] = (H[3] + d) >>> 0; + H[4] = (H[4] + e) >>> 0; + H[5] = (H[5] + f) >>> 0; + H[6] = (H[6] + g) >>> 0; + H[7] = (H[7] + h) >>> 0; } - return Array.from(H, v => v.toString(16).padStart(8, "0")).join(""); + return Array.from(H, (v) => v.toString(16).padStart(8, "0")).join(""); } diff --git a/09_Collected_JS/tests/test_admin_utils.mjs b/09_Collected_JS/tests/test_admin_utils.mjs index e0b56a0..07308fc 100644 --- a/09_Collected_JS/tests/test_admin_utils.mjs +++ b/09_Collected_JS/tests/test_admin_utils.mjs @@ -1,11 +1,18 @@ import assert from "node:assert/strict"; import { crc32, crc32c, normalizeBytes } from "../checksums/crc32.mjs"; -import { buildScriptIndex, extractFunctionNames, summarizeScriptIndex } from "../administrative/script_catalog.mjs"; +import { + buildScriptIndex, + extractFunctionNames, + summarizeScriptIndex, +} from "../administrative/script_catalog.mjs"; const bytes = normalizeBytes("123456789"); -assert.deepEqual(Array.from(bytes), [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39]); -assert.equal(crc32(bytes), 0xCBF43926); -assert.equal(crc32c(bytes), 0xE3069283); +assert.deepEqual( + Array.from(bytes), + [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39], +); +assert.equal(crc32(bytes), 0xcbf43926); +assert.equal(crc32c(bytes), 0xe3069283); const source = `/* Safe administrative note */ export function openCase() {} diff --git a/09_Collected_JS/tests/test_vectors.mjs b/09_Collected_JS/tests/test_vectors.mjs index 6c0737f..1a39fec 100644 --- a/09_Collected_JS/tests/test_vectors.mjs +++ b/09_Collected_JS/tests/test_vectors.mjs @@ -13,16 +13,18 @@ export function runSelfTest() { const check = new TextEncoder().encode("123456789"); const abc = new TextEncoder().encode("abc"); const results = { - crc8: crc8(check) === 0xF4, - crc16CcittFalse: crc16CcittFalse(check) === 0x29B1, - crc16Modbus: crc16Modbus(check) === 0x4B37, - crc32: crc32(check) === 0xCBF43926, - crc32c: crc32c(check) === 0xE3069283, + crc8: crc8(check) === 0xf4, + crc16CcittFalse: crc16CcittFalse(check) === 0x29b1, + crc16Modbus: crc16Modbus(check) === 0x4b37, + crc32: crc32(check) === 0xcbf43926, + crc32c: crc32c(check) === 0xe3069283, crc64Xz: crc64Xz(check) === "995dc9bbdf1939fa", - adler32: adler32(check) === 0x091E01DE, + adler32: adler32(check) === 0x091e01de, sha1: sha1(abc) === "a9993e364706816aba3e25717850c26c9cd0d89d", - sha256: sha256(abc) === "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - md5: md5(abc) === "900150983cd24fb0d6963f7d28e17f72" + sha256: + sha256(abc) === + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + md5: md5(abc) === "900150983cd24fb0d6963f7d28e17f72", }; results.allPassed = Object.values(results).every(Boolean); return results; diff --git a/16_Tests/MultiPROG/test_buffer_utils.mjs b/16_Tests/MultiPROG/test_buffer_utils.mjs index 36b4cf2..a069e9d 100644 --- a/16_Tests/MultiPROG/test_buffer_utils.mjs +++ b/16_Tests/MultiPROG/test_buffer_utils.mjs @@ -1,10 +1,14 @@ -import { strict as assert } from 'node:assert'; -import { cloneBytes, diffRanges, bytesToHex } from '../../03_Script_Starter_Kit/binary_utils.mjs'; +import { strict as assert } from "node:assert"; +import { + cloneBytes, + diffRanges, + bytesToHex, +} from "../../03_Script_Starter_Kit/binary_utils.mjs"; const sample = new Uint8Array([0x01, 0x02, 0x03, 0x04]); const clone = cloneBytes(sample); assert.deepStrictEqual(clone, sample); -assert.strictEqual(bytesToHex(sample), '01 02 03 04'); +assert.strictEqual(bytesToHex(sample), "01 02 03 04"); assert.deepStrictEqual(diffRanges(sample, clone), []); -console.log('buffer utils tests passed'); +console.log("buffer utils tests passed"); diff --git a/17_MultiPROG_SDK/examples/example_readonly_report.mjs b/17_MultiPROG_SDK/examples/example_readonly_report.mjs index b5802b2..2e5b91f 100644 --- a/17_MultiPROG_SDK/examples/example_readonly_report.mjs +++ b/17_MultiPROG_SDK/examples/example_readonly_report.mjs @@ -3,14 +3,15 @@ * Demonstrates the structure expected for SDK-based script authorship. */ -import { bytesToHex } from '../../03_Script_Starter_Kit/binary_utils.mjs'; +import { bytesToHex } from "../../03_Script_Starter_Kit/binary_utils.mjs"; function buildExampleReport(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError('Uint8Array required'); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); return { length: buffer.length, hex: bytesToHex(buffer), - preview: buffer.slice(0, 8) + preview: buffer.slice(0, 8), }; } diff --git a/17_MultiPROG_SDK/templates/template_binary_tool.mjs b/17_MultiPROG_SDK/templates/template_binary_tool.mjs index dca45bb..7809642 100644 --- a/17_MultiPROG_SDK/templates/template_binary_tool.mjs +++ b/17_MultiPROG_SDK/templates/template_binary_tool.mjs @@ -9,16 +9,19 @@ const SCRIPT_METADATA = { version: "0.1.0", purpose: "Binary processing", author: "Repository contributor", - validation: "Synthetic test data only" + validation: "Synthetic test data only", }; function toHex(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError("Uint8Array required"); - return Array.from(buffer).map(b => b.toString(16).padStart(2, "0")).join(" "); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); + return Array.from(buffer) + .map((b) => b.toString(16).padStart(2, "0")) + .join(" "); } function main() { - const sample = new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF]); + const sample = new Uint8Array([0xde, 0xad, 0xbe, 0xef]); console.log(toHex(sample)); } diff --git a/17_MultiPROG_SDK/templates/template_byteswap_workflow.mjs b/17_MultiPROG_SDK/templates/template_byteswap_workflow.mjs index 2dc49b6..c77a4da 100644 --- a/17_MultiPROG_SDK/templates/template_byteswap_workflow.mjs +++ b/17_MultiPROG_SDK/templates/template_byteswap_workflow.mjs @@ -5,15 +5,16 @@ */ const SCRIPT_METADATA = { - name: 'template_byteswap_workflow', - version: '0.1.0', - purpose: 'Byte-swap workflow', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_byteswap_workflow", + version: "0.1.0", + purpose: "Byte-swap workflow", + author: "Repository contributor", + validation: "Synthetic test data only", }; function byteswap(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError('Uint8Array required'); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); const swapped = new Uint8Array(buffer.length); for (let index = 0; index < buffer.length; index += 1) { swapped[index] = buffer[buffer.length - 1 - index]; diff --git a/17_MultiPROG_SDK/templates/template_checksum_workflow.mjs b/17_MultiPROG_SDK/templates/template_checksum_workflow.mjs index d45ceff..8d820ab 100644 --- a/17_MultiPROG_SDK/templates/template_checksum_workflow.mjs +++ b/17_MultiPROG_SDK/templates/template_checksum_workflow.mjs @@ -5,18 +5,19 @@ */ const SCRIPT_METADATA = { - name: 'template_checksum_workflow', - version: '0.1.0', - purpose: 'Checksum validation workflow', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_checksum_workflow", + version: "0.1.0", + purpose: "Checksum validation workflow", + author: "Repository contributor", + validation: "Synthetic test data only", }; function checksumWorkflow(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError('Uint8Array required'); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); let sum = 0; for (const byte of buffer) sum += byte; - return { length: buffer.length, checksum: sum & 0xFF }; + return { length: buffer.length, checksum: sum & 0xff }; } function main() { diff --git a/17_MultiPROG_SDK/templates/template_compare_workflow.mjs b/17_MultiPROG_SDK/templates/template_compare_workflow.mjs index 814f383..daa32d5 100644 --- a/17_MultiPROG_SDK/templates/template_compare_workflow.mjs +++ b/17_MultiPROG_SDK/templates/template_compare_workflow.mjs @@ -5,15 +5,16 @@ */ const SCRIPT_METADATA = { - name: 'template_compare_workflow', - version: '0.1.0', - purpose: 'Buffer comparison workflow', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_compare_workflow", + version: "0.1.0", + purpose: "Buffer comparison workflow", + author: "Repository contributor", + validation: "Synthetic test data only", }; function compareBuffers(left, right) { - if (!(left instanceof Uint8Array) || !(right instanceof Uint8Array)) throw new TypeError('Uint8Array required'); + if (!(left instanceof Uint8Array) || !(right instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); const maxLength = Math.max(left.length, right.length); const differences = []; for (let index = 0; index < maxLength; index += 1) { diff --git a/17_MultiPROG_SDK/templates/template_diff_report.mjs b/17_MultiPROG_SDK/templates/template_diff_report.mjs index ac1b8b7..264af82 100644 --- a/17_MultiPROG_SDK/templates/template_diff_report.mjs +++ b/17_MultiPROG_SDK/templates/template_diff_report.mjs @@ -5,19 +5,21 @@ */ const SCRIPT_METADATA = { - name: 'template_diff_report', - version: '0.1.0', - purpose: 'Buffer diff reporting', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_diff_report", + version: "0.1.0", + purpose: "Buffer diff reporting", + author: "Repository contributor", + validation: "Synthetic test data only", }; function buildDiffSummary(before, after) { - if (!(before instanceof Uint8Array) || !(after instanceof Uint8Array)) throw new TypeError('Uint8Array required'); + if (!(before instanceof Uint8Array) || !(after instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); const changes = []; const limit = Math.max(before.length, after.length); for (let i = 0; i < limit; i++) { - if (before[i] !== after[i]) changes.push({ index: i, before: before[i], after: after[i] }); + if (before[i] !== after[i]) + changes.push({ index: i, before: before[i], after: after[i] }); } return { changedBytes: changes.length, changes }; } diff --git a/17_MultiPROG_SDK/templates/template_eeprom.mjs b/17_MultiPROG_SDK/templates/template_eeprom.mjs index b11f9e4..6ae5645 100644 --- a/17_MultiPROG_SDK/templates/template_eeprom.mjs +++ b/17_MultiPROG_SDK/templates/template_eeprom.mjs @@ -9,14 +9,15 @@ const SCRIPT_METADATA = { version: "0.1.0", purpose: "EEPROM-like processing", author: "Repository contributor", - validation: "Synthetic test data only" + validation: "Synthetic test data only", }; function buildReport(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError("Uint8Array required"); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); return { length: buffer.length, - checksum: buffer.reduce((sum, byte) => sum + byte, 0) + checksum: buffer.reduce((sum, byte) => sum + byte, 0), }; } diff --git a/17_MultiPROG_SDK/templates/template_flash.mjs b/17_MultiPROG_SDK/templates/template_flash.mjs index 70f3c50..564582b 100644 --- a/17_MultiPROG_SDK/templates/template_flash.mjs +++ b/17_MultiPROG_SDK/templates/template_flash.mjs @@ -9,19 +9,20 @@ const SCRIPT_METADATA = { version: "0.1.0", purpose: "Flash-like processing", author: "Repository contributor", - validation: "Synthetic test data only" + validation: "Synthetic test data only", }; function inspectFlash(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError("Uint8Array required"); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); return { length: buffer.length, - blankBytes: buffer.filter(byte => byte === 0xFF).length + blankBytes: buffer.filter((byte) => byte === 0xff).length, }; } function main() { - const sample = new Uint8Array([0xFF, 0x01, 0xFF, 0x02]); + const sample = new Uint8Array([0xff, 0x01, 0xff, 0x02]); console.log(JSON.stringify(inspectFlash(sample))); // HOST_READ_BUFFER(); } diff --git a/17_MultiPROG_SDK/templates/template_inventory_workflow.mjs b/17_MultiPROG_SDK/templates/template_inventory_workflow.mjs index 970d126..7a43498 100644 --- a/17_MultiPROG_SDK/templates/template_inventory_workflow.mjs +++ b/17_MultiPROG_SDK/templates/template_inventory_workflow.mjs @@ -5,24 +5,24 @@ */ const SCRIPT_METADATA = { - name: 'template_inventory_workflow', - version: '0.1.0', - purpose: 'Inventory reconciliation workflow', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_inventory_workflow", + version: "0.1.0", + purpose: "Inventory reconciliation workflow", + author: "Repository contributor", + validation: "Synthetic test data only", }; function inventoryWorkflow(items) { - if (!Array.isArray(items)) throw new TypeError('Expected an array'); + if (!Array.isArray(items)) throw new TypeError("Expected an array"); return { itemCount: items.length, uniqueCount: new Set(items).size, - summary: items.map(item => ({ value: item })) + summary: items.map((item) => ({ value: item })), }; } function main() { - const sample = ['A', 'B', 'A']; + const sample = ["A", "B", "A"]; console.log(JSON.stringify(inventoryWorkflow(sample), null, 2)); } diff --git a/17_MultiPROG_SDK/templates/template_merge_workflow.mjs b/17_MultiPROG_SDK/templates/template_merge_workflow.mjs index 26be665..9edbef0 100644 --- a/17_MultiPROG_SDK/templates/template_merge_workflow.mjs +++ b/17_MultiPROG_SDK/templates/template_merge_workflow.mjs @@ -5,11 +5,11 @@ */ const SCRIPT_METADATA = { - name: 'template_merge_workflow', - version: '0.1.0', - purpose: 'Buffer merge workflow', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_merge_workflow", + version: "0.1.0", + purpose: "Buffer merge workflow", + author: "Repository contributor", + validation: "Synthetic test data only", }; function mergeBuffers(...parts) { @@ -17,7 +17,8 @@ function mergeBuffers(...parts) { const merged = new Uint8Array(totalLength); let offset = 0; for (const part of parts) { - if (!(part instanceof Uint8Array)) throw new TypeError('Uint8Array required'); + if (!(part instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); merged.set(part, offset); offset += part.length; } @@ -25,7 +26,10 @@ function mergeBuffers(...parts) { } function main() { - const merged = mergeBuffers(new Uint8Array([0x01, 0x02]), new Uint8Array([0x03, 0x04])); + const merged = mergeBuffers( + new Uint8Array([0x01, 0x02]), + new Uint8Array([0x03, 0x04]), + ); console.log(JSON.stringify(Array.from(merged))); } diff --git a/17_MultiPROG_SDK/templates/template_patch_guard.mjs b/17_MultiPROG_SDK/templates/template_patch_guard.mjs index bec66b8..76eedc4 100644 --- a/17_MultiPROG_SDK/templates/template_patch_guard.mjs +++ b/17_MultiPROG_SDK/templates/template_patch_guard.mjs @@ -5,23 +5,30 @@ */ const SCRIPT_METADATA = { - name: 'template_patch_guard', - version: '0.1.0', - purpose: 'Allow-listed patch validation', - author: 'Repository contributor', - validation: 'Synthetic test data only' + name: "template_patch_guard", + version: "0.1.0", + purpose: "Allow-listed patch validation", + author: "Repository contributor", + validation: "Synthetic test data only", }; function validatePatchPlan(offset, patchBytes, allowedRanges) { - if (!Number.isInteger(offset) || offset < 0) throw new RangeError('offset must be a non-negative integer'); - if (!(patchBytes instanceof Uint8Array)) throw new TypeError('Uint8Array required'); - const allowed = allowedRanges.some(range => offset >= range.start && offset + patchBytes.length - 1 <= range.end); - if (!allowed) throw new Error('Patch falls outside allow-list'); + if (!Number.isInteger(offset) || offset < 0) + throw new RangeError("offset must be a non-negative integer"); + if (!(patchBytes instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); + const allowed = allowedRanges.some( + (range) => + offset >= range.start && offset + patchBytes.length - 1 <= range.end, + ); + if (!allowed) throw new Error("Patch falls outside allow-list"); return { ok: true, offset, length: patchBytes.length }; } function main() { - const plan = validatePatchPlan(16, new Uint8Array([0xAA]), [{ start: 0, end: 31 }]); + const plan = validatePatchPlan(16, new Uint8Array([0xaa]), [ + { start: 0, end: 31 }, + ]); console.log(JSON.stringify(plan)); } diff --git a/17_MultiPROG_SDK/templates/template_readonly.mjs b/17_MultiPROG_SDK/templates/template_readonly.mjs index 15f6246..73c4fc3 100644 --- a/17_MultiPROG_SDK/templates/template_readonly.mjs +++ b/17_MultiPROG_SDK/templates/template_readonly.mjs @@ -9,7 +9,7 @@ const SCRIPT_METADATA = { version: "0.1.0", purpose: "Read-only inspection", author: "Repository contributor", - validation: "Synthetic test data only" + validation: "Synthetic test data only", }; function log(message) { @@ -17,9 +17,15 @@ function log(message) { } function inspectBuffer(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError("Uint8Array required"); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); log(`Buffer length: ${buffer.length}`); - return { length: buffer.length, preview: Array.from(buffer.slice(0, 16)).map(b => b.toString(16).padStart(2, "0")).join(" ") }; + return { + length: buffer.length, + preview: Array.from(buffer.slice(0, 16)) + .map((b) => b.toString(16).padStart(2, "0")) + .join(" "), + }; } function main() { diff --git a/17_MultiPROG_SDK/templates/template_reporting.mjs b/17_MultiPROG_SDK/templates/template_reporting.mjs index 2687a67..085c9bb 100644 --- a/17_MultiPROG_SDK/templates/template_reporting.mjs +++ b/17_MultiPROG_SDK/templates/template_reporting.mjs @@ -9,14 +9,17 @@ const SCRIPT_METADATA = { version: "0.1.0", purpose: "Reporting workflow", author: "Repository contributor", - validation: "Synthetic test data only" + validation: "Synthetic test data only", }; function buildReport(buffer) { - if (!(buffer instanceof Uint8Array)) throw new TypeError("Uint8Array required"); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); return { length: buffer.length, - hex: Array.from(buffer).map(b => b.toString(16).padStart(2, "0")).join(" ") + hex: Array.from(buffer) + .map((b) => b.toString(16).padStart(2, "0")) + .join(" "), }; } diff --git a/17_MultiPROG_SDK/templates/template_validator.mjs b/17_MultiPROG_SDK/templates/template_validator.mjs index 1ee5810..a3cda98 100644 --- a/17_MultiPROG_SDK/templates/template_validator.mjs +++ b/17_MultiPROG_SDK/templates/template_validator.mjs @@ -9,17 +9,21 @@ const SCRIPT_METADATA = { version: "0.1.0", purpose: "Validation workflow", author: "Repository contributor", - validation: "Synthetic test data only" + validation: "Synthetic test data only", }; function validateBuffer(buffer, expectedLength) { - if (!(buffer instanceof Uint8Array)) throw new TypeError("Uint8Array required"); - if (buffer.length !== expectedLength) throw new RangeError(`Expected ${expectedLength} bytes but received ${buffer.length}`); + if (!(buffer instanceof Uint8Array)) + throw new TypeError("Uint8Array required"); + if (buffer.length !== expectedLength) + throw new RangeError( + `Expected ${expectedLength} bytes but received ${buffer.length}`, + ); return { ok: true, length: buffer.length }; } function main() { - const sample = new Uint8Array([0xAA, 0xBB, 0xCC]); + const sample = new Uint8Array([0xaa, 0xbb, 0xcc]); console.log(JSON.stringify(validateBuffer(sample, 3))); } diff --git a/17_MultiPROG_SDK/tests/buffer_helpers.test.mjs b/17_MultiPROG_SDK/tests/buffer_helpers.test.mjs index 6824e4b..ba27f33 100644 --- a/17_MultiPROG_SDK/tests/buffer_helpers.test.mjs +++ b/17_MultiPROG_SDK/tests/buffer_helpers.test.mjs @@ -1,8 +1,14 @@ -import test from 'node:test'; -import assert from 'node:assert/strict'; -import { cloneBytes, diffRanges, bytesToHex, readU16LE, writeU16LE } from '../../03_Script_Starter_Kit/binary_utils.mjs'; +import test from "node:test"; +import assert from "node:assert/strict"; +import { + cloneBytes, + diffRanges, + bytesToHex, + readU16LE, + writeU16LE, +} from "../../03_Script_Starter_Kit/binary_utils.mjs"; -test('cloneBytes preserves data and does not alias', () => { +test("cloneBytes preserves data and does not alias", () => { const source = new Uint8Array([1, 2, 3, 4]); const clone = cloneBytes(source); clone[0] = 9; @@ -10,15 +16,17 @@ test('cloneBytes preserves data and does not alias', () => { assert.equal(clone[0], 9); }); -test('diffRanges reports changes correctly', () => { +test("diffRanges reports changes correctly", () => { const before = new Uint8Array([0, 1, 2, 3]); const after = new Uint8Array([0, 9, 2, 3]); - assert.deepEqual(diffRanges(before, after), [{ start: 1, end: 1, length: 1 }]); + assert.deepEqual(diffRanges(before, after), [ + { start: 1, end: 1, length: 1 }, + ]); }); -test('hex and numeric helpers work', () => { +test("hex and numeric helpers work", () => { const buffer = new Uint8Array([0x34, 0x12]); - assert.equal(bytesToHex(buffer), '34 12'); + assert.equal(bytesToHex(buffer), "34 12"); const out = new Uint8Array(2); writeU16LE(out, 0, 0x1234); assert.equal(readU16LE(out, 0), 0x1234); diff --git a/17_MultiPROG_SDK/tests/crc_engine.test.mjs b/17_MultiPROG_SDK/tests/crc_engine.test.mjs index 8ef486f..49d266d 100644 --- a/17_MultiPROG_SDK/tests/crc_engine.test.mjs +++ b/17_MultiPROG_SDK/tests/crc_engine.test.mjs @@ -1,39 +1,46 @@ -import test from 'node:test'; -import assert from 'node:assert/strict'; -import { crc, crcNamed, createCrcModel, CRC_MODELS } from '../utilities/crc_engine.mjs'; +import test from "node:test"; +import assert from "node:assert/strict"; +import { + crc, + crcNamed, + createCrcModel, + CRC_MODELS, +} from "../utilities/crc_engine.mjs"; // Standard CRC "check" vectors for the ASCII string "123456789", as published by // the CRC RevEng catalogue (https://reveng.sourceforge.io/crc-catalogue/). -const CHECK_MESSAGE = new TextEncoder().encode('123456789'); +const CHECK_MESSAGE = new TextEncoder().encode("123456789"); -test('named CRC models match published check values', () => { - assert.equal(crcNamed(CHECK_MESSAGE, 'crc8'), 0xF4); - assert.equal(crcNamed(CHECK_MESSAGE, 'crc8_maxim'), 0xA1); - assert.equal(crcNamed(CHECK_MESSAGE, 'crc16_ccitt_false'), 0x29B1); - assert.equal(crcNamed(CHECK_MESSAGE, 'crc16_arc'), 0xBB3D); - assert.equal(crcNamed(CHECK_MESSAGE, 'crc16_modbus'), 0x4B37); - assert.equal(crcNamed(CHECK_MESSAGE, 'crc32'), 0xCBF43926); - assert.equal(crcNamed(CHECK_MESSAGE, 'crc32_mpeg2'), 0x0376E6E7); +test("named CRC models match published check values", () => { + assert.equal(crcNamed(CHECK_MESSAGE, "crc8"), 0xf4); + assert.equal(crcNamed(CHECK_MESSAGE, "crc8_maxim"), 0xa1); + assert.equal(crcNamed(CHECK_MESSAGE, "crc16_ccitt_false"), 0x29b1); + assert.equal(crcNamed(CHECK_MESSAGE, "crc16_arc"), 0xbb3d); + assert.equal(crcNamed(CHECK_MESSAGE, "crc16_modbus"), 0x4b37); + assert.equal(crcNamed(CHECK_MESSAGE, "crc32"), 0xcbf43926); + assert.equal(crcNamed(CHECK_MESSAGE, "crc32_mpeg2"), 0x0376e6e7); }); -test('crcNamed rejects unknown model names', () => { - assert.throws(() => crcNamed(CHECK_MESSAGE, 'not_a_model')); +test("crcNamed rejects unknown model names", () => { + assert.throws(() => crcNamed(CHECK_MESSAGE, "not_a_model")); }); -test('crc rejects unsupported widths', () => { - assert.throws(() => crc(CHECK_MESSAGE, { ...CRC_MODELS.crc16_arc, width: 12 })); +test("crc rejects unsupported widths", () => { + assert.throws(() => + crc(CHECK_MESSAGE, { ...CRC_MODELS.crc16_arc, width: 12 }), + ); }); -test('crc requires a Uint8Array', () => { +test("crc requires a Uint8Array", () => { assert.throws(() => crc([1, 2, 3], CRC_MODELS.crc32)); }); -test('createCrcModel produces a reusable bound calculator', () => { +test("createCrcModel produces a reusable bound calculator", () => { const calcCrc32 = createCrcModel(CRC_MODELS.crc32); - assert.equal(calcCrc32(CHECK_MESSAGE), 0xCBF43926); + assert.equal(calcCrc32(CHECK_MESSAGE), 0xcbf43926); }); -test('empty buffer returns the model init/xorout combination', () => { - assert.equal(crcNamed(new Uint8Array(0), 'crc32'), 0x00000000); - assert.equal(crcNamed(new Uint8Array(0), 'crc16_ccitt_false'), 0xFFFF); +test("empty buffer returns the model init/xorout combination", () => { + assert.equal(crcNamed(new Uint8Array(0), "crc32"), 0x00000000); + assert.equal(crcNamed(new Uint8Array(0), "crc16_ccitt_false"), 0xffff); }); diff --git a/17_MultiPROG_SDK/tests/encoding_helpers.test.mjs b/17_MultiPROG_SDK/tests/encoding_helpers.test.mjs index b3345f4..7c77b4a 100644 --- a/17_MultiPROG_SDK/tests/encoding_helpers.test.mjs +++ b/17_MultiPROG_SDK/tests/encoding_helpers.test.mjs @@ -1,15 +1,18 @@ -import test from 'node:test'; -import assert from 'node:assert/strict'; -import { encodeHex, decodeHex } from '../../09_Collected_JS/encoding/hex.mjs'; -import { bcdByteToInt, intToBcdByte } from '../../09_Collected_JS/encoding/bcd.mjs'; +import test from "node:test"; +import assert from "node:assert/strict"; +import { encodeHex, decodeHex } from "../../09_Collected_JS/encoding/hex.mjs"; +import { + bcdByteToInt, + intToBcdByte, +} from "../../09_Collected_JS/encoding/bcd.mjs"; -test('hex helpers round-trip bytes', () => { - const data = new Uint8Array([0xAA, 0xBB, 0x0F]); - assert.equal(encodeHex(data), 'AABB0F'); - assert.deepEqual(Array.from(decodeHex('AABB0F')), [0xAA, 0xBB, 0x0F]); +test("hex helpers round-trip bytes", () => { + const data = new Uint8Array([0xaa, 0xbb, 0x0f]); + assert.equal(encodeHex(data), "AABB0F"); + assert.deepEqual(Array.from(decodeHex("AABB0F")), [0xaa, 0xbb, 0x0f]); }); -test('BCD helpers convert values correctly', () => { +test("BCD helpers convert values correctly", () => { assert.equal(bcdByteToInt(0x23), 23); assert.equal(intToBcdByte(23), 0x23); }); diff --git a/17_MultiPROG_SDK/tests/template_catalog.test.mjs b/17_MultiPROG_SDK/tests/template_catalog.test.mjs index f67f64a..4149b8d 100644 --- a/17_MultiPROG_SDK/tests/template_catalog.test.mjs +++ b/17_MultiPROG_SDK/tests/template_catalog.test.mjs @@ -1,40 +1,51 @@ -import test from 'node:test'; -import assert from 'node:assert/strict'; -import { readdirSync, readFileSync } from 'node:fs'; -import path from 'node:path'; +import test from "node:test"; +import assert from "node:assert/strict"; +import { readdirSync, readFileSync } from "node:fs"; +import path from "node:path"; -const templateDir = path.resolve('17_MultiPROG_SDK/templates'); -const templates = readdirSync(templateDir).filter(name => name.endsWith('.mjs')).sort(); +const templateDir = path.resolve("17_MultiPROG_SDK/templates"); +const templates = readdirSync(templateDir) + .filter((name) => name.endsWith(".mjs")) + .sort(); const expectedTemplates = [ - 'template_binary_tool.mjs', - 'template_byteswap_workflow.mjs', - 'template_checksum_workflow.mjs', - 'template_compare_workflow.mjs', - 'template_diff_report.mjs', - 'template_eeprom.mjs', - 'template_flash.mjs', - 'template_inventory_workflow.mjs', - 'template_merge_workflow.mjs', - 'template_patch_guard.mjs', - 'template_readonly.mjs', - 'template_reporting.mjs', - 'template_validator.mjs' + "template_binary_tool.mjs", + "template_byteswap_workflow.mjs", + "template_checksum_workflow.mjs", + "template_compare_workflow.mjs", + "template_diff_report.mjs", + "template_eeprom.mjs", + "template_flash.mjs", + "template_inventory_workflow.mjs", + "template_merge_workflow.mjs", + "template_patch_guard.mjs", + "template_readonly.mjs", + "template_reporting.mjs", + "template_validator.mjs", ]; -test('SDK templates catalog contains the expected starter set', () => { +test("SDK templates catalog contains the expected starter set", () => { for (const template of expectedTemplates) { - assert.ok(templates.includes(template), `${template} is missing from the template catalog`); + assert.ok( + templates.includes(template), + `${template} is missing from the template catalog`, + ); } }); -test('compare, merge, and byte-swap templates include their workflow metadata', () => { +test("compare, merge, and byte-swap templates include their workflow metadata", () => { const combined = templates - .filter(name => ['template_compare_workflow.mjs', 'template_merge_workflow.mjs', 'template_byteswap_workflow.mjs'].includes(name)) - .map(name => readFileSync(path.join(templateDir, name), 'utf8')) - .join('\n'); + .filter((name) => + [ + "template_compare_workflow.mjs", + "template_merge_workflow.mjs", + "template_byteswap_workflow.mjs", + ].includes(name), + ) + .map((name) => readFileSync(path.join(templateDir, name), "utf8")) + .join("\n"); - assert.ok(combined.includes('Buffer comparison workflow')); - assert.ok(combined.includes('Buffer merge workflow')); - assert.ok(combined.includes('Byte-swap workflow')); + assert.ok(combined.includes("Buffer comparison workflow")); + assert.ok(combined.includes("Buffer merge workflow")); + assert.ok(combined.includes("Byte-swap workflow")); }); diff --git a/17_MultiPROG_SDK/tests/workflow_templates.test.mjs b/17_MultiPROG_SDK/tests/workflow_templates.test.mjs index d479a7a..02baa3b 100644 --- a/17_MultiPROG_SDK/tests/workflow_templates.test.mjs +++ b/17_MultiPROG_SDK/tests/workflow_templates.test.mjs @@ -1,35 +1,50 @@ -import test from 'node:test'; -import assert from 'node:assert/strict'; -import { readFileSync } from 'node:fs'; -import path from 'node:path'; +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import path from "node:path"; -const templateDir = path.resolve('17_MultiPROG_SDK/templates'); +const templateDir = path.resolve("17_MultiPROG_SDK/templates"); -const checksumTemplate = readFileSync(path.join(templateDir, 'template_checksum_workflow.mjs'), 'utf8'); -const inventoryTemplate = readFileSync(path.join(templateDir, 'template_inventory_workflow.mjs'), 'utf8'); +const checksumTemplate = readFileSync( + path.join(templateDir, "template_checksum_workflow.mjs"), + "utf8", +); +const inventoryTemplate = readFileSync( + path.join(templateDir, "template_inventory_workflow.mjs"), + "utf8", +); const expectedSnippets = [ - 'template_checksum_workflow', - 'Checksum validation workflow', - 'template_inventory_workflow', - 'Inventory reconciliation workflow' + "template_checksum_workflow", + "Checksum validation workflow", + "template_inventory_workflow", + "Inventory reconciliation workflow", ]; -test('checksum workflow template contains expected metadata', () => { - for (const snippet of ['template_checksum_workflow', 'Checksum validation workflow']) { +test("checksum workflow template contains expected metadata", () => { + for (const snippet of [ + "template_checksum_workflow", + "Checksum validation workflow", + ]) { assert.ok(checksumTemplate.includes(snippet)); } }); -test('inventory workflow template contains expected metadata', () => { - for (const snippet of ['template_inventory_workflow', 'Inventory reconciliation workflow']) { +test("inventory workflow template contains expected metadata", () => { + for (const snippet of [ + "template_inventory_workflow", + "Inventory reconciliation workflow", + ]) { assert.ok(inventoryTemplate.includes(snippet)); } }); -test('workflow templates are documented in the SDK structure', () => { - const readme = readFileSync(path.resolve('17_MultiPROG_SDK/README.md'), 'utf8'); +test("workflow templates are documented in the SDK structure", () => { + const readme = readFileSync( + path.resolve("17_MultiPROG_SDK/README.md"), + "utf8", + ); for (const snippet of expectedSnippets) { - assert.ok(readme.includes(snippet) || readme.includes('templates/')); + assert.ok(readme.includes(snippet) || readme.includes("templates/")); } }); diff --git a/17_MultiPROG_SDK/utilities/_verify_crc.mjs b/17_MultiPROG_SDK/utilities/_verify_crc.mjs index 895659f..c5f3d5b 100644 --- a/17_MultiPROG_SDK/utilities/_verify_crc.mjs +++ b/17_MultiPROG_SDK/utilities/_verify_crc.mjs @@ -1,19 +1,24 @@ import { crc, CRC_MODELS, crcNamed } from "./crc_engine.mjs"; const msg = new TextEncoder().encode("123456789"); const vectors = { - crc8: 0xF4, - crc8_maxim: 0xA1, - crc16_ccitt_false: 0x29B1, - crc16_arc: 0xBB3D, - crc16_modbus: 0x4B37, - crc32: 0xCBF43926, - crc32_mpeg2: 0x0376E6E7 + crc8: 0xf4, + crc8_maxim: 0xa1, + crc16_ccitt_false: 0x29b1, + crc16_arc: 0xbb3d, + crc16_modbus: 0x4b37, + crc32: 0xcbf43926, + crc32_mpeg2: 0x0376e6e7, }; let allOk = true; for (const [name, expected] of Object.entries(vectors)) { const got = crcNamed(msg, name); const ok = got === expected; if (!ok) allOk = false; - console.log(name, got.toString(16), expected.toString(16), ok ? "OK" : "MISMATCH"); + console.log( + name, + got.toString(16), + expected.toString(16), + ok ? "OK" : "MISMATCH", + ); } console.log(allOk ? "ALL_OK" : "FAILURES"); diff --git a/17_MultiPROG_SDK/utilities/crc_engine.mjs b/17_MultiPROG_SDK/utilities/crc_engine.mjs index 7dfd91a..dd54dcd 100644 --- a/17_MultiPROG_SDK/utilities/crc_engine.mjs +++ b/17_MultiPROG_SDK/utilities/crc_engine.mjs @@ -29,32 +29,83 @@ function reflectBits(value, bits) { export function crc(data, model) { requireBytes(data); const { width, poly, init, refin, refout, xorout } = model; - if (![8, 16, 24, 32].includes(width)) throw new RangeError("width must be one of 8, 16, 24, 32"); - const mask = width === 32 ? 0xFFFFFFFF : ((1 << width) - 1) >>> 0; + if (![8, 16, 24, 32].includes(width)) + throw new RangeError("width must be one of 8, 16, 24, 32"); + const mask = width === 32 ? 0xffffffff : ((1 << width) - 1) >>> 0; const topBit = 1 << (width - 1); let reg = init >>> 0; for (let byte of data) { if (refin) byte = reflectBits(byte, 8); reg = (reg ^ (byte << (width - 8))) >>> 0; for (let i = 0; i < 8; i++) { - const msbSet = width === 32 ? (reg & 0x80000000) !== 0 : (reg & topBit) !== 0; + const msbSet = + width === 32 ? (reg & 0x80000000) !== 0 : (reg & topBit) !== 0; reg = msbSet ? ((reg << 1) ^ poly) >>> 0 : (reg << 1) >>> 0; } reg &= mask; } if (refout) reg = reflectBits(reg, width); - return (((reg ^ xorout) & mask) >>> 0); + return ((reg ^ xorout) & mask) >>> 0; } /** Well-known named CRC models, ready to pass to {@link crc}. */ export const CRC_MODELS = { - crc8: { width: 8, poly: 0x07, init: 0x00, refin: false, refout: false, xorout: 0x00 }, - crc8_maxim: { width: 8, poly: 0x31, init: 0x00, refin: true, refout: true, xorout: 0x00 }, - crc16_ccitt_false: { width: 16, poly: 0x1021, init: 0xFFFF, refin: false, refout: false, xorout: 0x0000 }, - crc16_arc: { width: 16, poly: 0x8005, init: 0x0000, refin: true, refout: true, xorout: 0x0000 }, - crc16_modbus: { width: 16, poly: 0x8005, init: 0xFFFF, refin: true, refout: true, xorout: 0x0000 }, - crc32: { width: 32, poly: 0x04C11DB7, init: 0xFFFFFFFF, refin: true, refout: true, xorout: 0xFFFFFFFF }, - crc32_mpeg2: { width: 32, poly: 0x04C11DB7, init: 0xFFFFFFFF, refin: false, refout: false, xorout: 0x00000000 } + crc8: { + width: 8, + poly: 0x07, + init: 0x00, + refin: false, + refout: false, + xorout: 0x00, + }, + crc8_maxim: { + width: 8, + poly: 0x31, + init: 0x00, + refin: true, + refout: true, + xorout: 0x00, + }, + crc16_ccitt_false: { + width: 16, + poly: 0x1021, + init: 0xffff, + refin: false, + refout: false, + xorout: 0x0000, + }, + crc16_arc: { + width: 16, + poly: 0x8005, + init: 0x0000, + refin: true, + refout: true, + xorout: 0x0000, + }, + crc16_modbus: { + width: 16, + poly: 0x8005, + init: 0xffff, + refin: true, + refout: true, + xorout: 0x0000, + }, + crc32: { + width: 32, + poly: 0x04c11db7, + init: 0xffffffff, + refin: true, + refout: true, + xorout: 0xffffffff, + }, + crc32_mpeg2: { + width: 32, + poly: 0x04c11db7, + init: 0xffffffff, + refin: false, + refout: false, + xorout: 0x00000000, + }, }; /** Convenience helper: compute a named model's CRC. */ diff --git a/MANIFEST.json b/MANIFEST.json index f789059..64f15a3 100644 --- a/MANIFEST.json +++ b/MANIFEST.json @@ -51,113 +51,113 @@ }, { "path": "03_Script_Starter_Kit/binary_utils.mjs", - "size": 4671, - "sha256": "ba08f2ac18998e6854d85786de5a9bc0e9c7ef9e8ad7924663d34c9487b0c341" + "size": 5748, + "sha256": "002cb1b91dbeb6882210ca9d5b06e044aa315f3b623920f4ba0d47d62c18ff63" }, { "path": "03_Script_Starter_Kit/examples/01_read_only_inspector.mjs", - "size": 306, - "sha256": "18156a9cc515306ea14a38b4ecc20401d6a8c2511542ea08df803d1e38132a0e" + "size": 358, + "sha256": "29b332da18c61ec65b8ca5d5db15f6aba34b16c0af7aef1b06d96a59c0a5750f" }, { "path": "03_Script_Starter_Kit/examples/02_double_read_verifier.mjs", - "size": 203, - "sha256": "526487814bb04cb955a9ac666d3b1e77390c4a8462f2422488d905c2334c12b6" + "size": 240, + "sha256": "099b6acdc56c1403967c8f8def819f0e59cb1ae7e472e7012cf466b355369973" }, { "path": "03_Script_Starter_Kit/examples/03_pattern_inventory.mjs", - "size": 192, - "sha256": "4e1d5e1ecd3f8f284be57c173ca481e7c55d6a719c3d72214d656aafde20735a" + "size": 219, + "sha256": "c81df6685529de1c9946c39f29893911fee8c59996527ae4c53bdbbf9d54760a" }, { "path": "03_Script_Starter_Kit/examples/04_allowlisted_patch_demo.mjs", - "size": 345, - "sha256": "fac79790cac46e6e9299a618769e355a9153fd63ce145664ced729517dd37943" + "size": 381, + "sha256": "a059293e1010f2b57801d02b7b0e97559adacafb68acd5210687bdee4dafccdf" }, { "path": "03_Script_Starter_Kit/examples/05_checksum_test_vectors.mjs", - "size": 249, - "sha256": "95dd4b2f4001c7f4f645fd972061805139cf5b41ed528f3013e4cdf9f30cb01d" + "size": 297, + "sha256": "2227f3999d736cb2ffdd8347bef39d00061790cbce4a4d9aeb7e7d807527aeda" }, { "path": "03_Script_Starter_Kit/examples/06_authorized_job_record_validator.mjs", - "size": 387, - "sha256": "28581b002a52398f2e14752490c0a3165c48b055bb3ed4505e6a4ca03f074942" + "size": 456, + "sha256": "ed082376bff56fd54b3e6589c18f2b50b077620b989a5bf4417ae4771035c0c3" }, { "path": "03_Script_Starter_Kit/examples/07_key_inventory_audit.mjs", - "size": 351, - "sha256": "e86e045e48f7cb2d5d8f760e745b5f5434dd8e30b20be34f511e03b487d92d96" + "size": 415, + "sha256": "e03f7c0372a77e83cdb8b4be26c1ca7c2305f99bb921fc583f5741c5a477c6e8" }, { "path": "03_Script_Starter_Kit/examples/08_redacted_security_report.mjs", - "size": 381, - "sha256": "24882fd08420d906c6c87e6d8cf6fa30e3351d986787d7a6c3c2611d8f471399" + "size": 461, + "sha256": "3774504b4c55f60d73989c06531ff594a1a352fd703d3956a7b515e1c871d5c0" }, { "path": "03_Script_Starter_Kit/examples/32_dump_fingerprint.mjs", - "size": 483, - "sha256": "c6fa0fa4c3c2e3be275ef99ffb2cf4a972f205c5d79f76748d54794419f84ae0" + "size": 471, + "sha256": "14c6c16bd9b156f950e3147d7f7d415d7d5b7196acb6932e78659bc5fa703a62" }, { "path": "03_Script_Starter_Kit/examples/33_structured_change_report.mjs", - "size": 823, - "sha256": "06c13810f940911ecc840d65cd254e1b16ff698e79d06f7e8b54d3f56b710de8" + "size": 850, + "sha256": "b265866a04a4c8956f7c0e954bae245f5614a322e6295ebfc60cca8bac910ecf" }, { "path": "03_Script_Starter_Kit/examples/34_checksum_model_selector.mjs", - "size": 983, - "sha256": "fdb47c13d34a6182ff4dfbfdb804556cd57945370871c292ca0f603f4cb5d4ae" + "size": 966, + "sha256": "28a26a9f0175db2622817832566e0e93f04356aa93aec1ff7c49cea03b9e1b85" }, { "path": "03_Script_Starter_Kit/examples/35_flash_sector_map_parser.mjs", - "size": 1545, - "sha256": "c2c05312356d67f1f0b106b3a4f1a88fa37f00750c8be4c24b2f67c89e4eccb2" + "size": 1555, + "sha256": "30e6c08bf52d8f5126550d0a81ec3c96b2955f6162c99bafdfcdc2e1c43e9e7b" }, { "path": "03_Script_Starter_Kit/examples/36_vin_extractor_validator.mjs", - "size": 1970, - "sha256": "87b497606501561c03df7096aed7d0052d6c881dda705282e9bdfe2bf79183fd" + "size": 1989, + "sha256": "0c804c7f143ad5e9ac6183c0530ea4623cb36a597121026df019a0962746c5c5" }, { "path": "03_Script_Starter_Kit/examples/37_binary_search_pattern_locator.mjs", - "size": 1232, - "sha256": "bd3768307edabd9356498064d0595b64765d4e53b78a238ad0c738b3e30f9f99" + "size": 1220, + "sha256": "6e2c2c6ad5513d47cbe3f3ff18472fd7e24a4337493b1e210c7c92b0776798fa" }, { "path": "03_Script_Starter_Kit/examples/38_bitfield_and_signed_int_utils.mjs", - "size": 1901, - "sha256": "7c0333bc36781c7d9d2d3cda69307dbd7fd0f8a8513181ccaca352e8e759af0d" + "size": 1951, + "sha256": "784ec2a6e02d63146a071aabb7260b1b829822cb300beffc1c50769a373318b5" }, { "path": "03_Script_Starter_Kit/examples/39_key_learning_session_report.mjs", - "size": 1905, - "sha256": "8075711e347cd30b992ac856ac082b44a188d420d8a7de1d5530c659bb6aee32" + "size": 1954, + "sha256": "3f986a7945696b32cbf0117e2689b02ed19272f510ef61ac13d77fc309d4cc45" }, { "path": "03_Script_Starter_Kit/examples/airbag_authorized_safe/17_airbag_case_intake_validator.mjs", - "size": 758, - "sha256": "78c0557df83822e3a731079935a2824bc48a446a5cd0d417fa801cb0ac13267f" + "size": 774, + "sha256": "d7a8110cb32ba7765d2dd8cac769b3675b21126e1faafc2bf9a19e19925db75e" }, { "path": "03_Script_Starter_Kit/examples/airbag_authorized_safe/18_airbag_module_read_consistency.mjs", - "size": 397, - "sha256": "b9679d96d432dbc7a3ebe1234222d89e9d8bd62e74a731260feec4435b48cf2c" + "size": 387, + "sha256": "f20721742dae16dd87190be85346a9b973ce1cdc5b1b179359120b5c65ca729b" }, { "path": "03_Script_Starter_Kit/examples/airbag_authorized_safe/19_airbag_crash_data_disclosure_redactor.mjs", - "size": 775, - "sha256": "6c308586475129d12479b7a86100fe6572d31e67a6e40ae9034e6e5e91a85e4c" + "size": 757, + "sha256": "3b0f0f9a066f04f1bc3c8e039333bfa2dcbf0b159db7508086cd0d8ac5357f5e" }, { "path": "03_Script_Starter_Kit/examples/airbag_authorized_safe/20_airbag_backup_naming_policy.mjs", - "size": 487, - "sha256": "cd91e20f4ea0af4058f1e471d9538d585ea8ef1d64378bd2f4746aaa122e0fb3" + "size": 531, + "sha256": "57c4d42136f9967d99d9aa013000d82184ec1074e867d5de33b1ac9dd80e6929" }, { "path": "03_Script_Starter_Kit/examples/airbag_authorized_safe/21_airbag_service_completion_audit.mjs", - "size": 644, - "sha256": "bcef13df3f2ab4ecc14ffd3b36195d321742d77867521c23fa09fa2214c0a6f6" + "size": 632, + "sha256": "6415ec3dccba1b173c7c401a72fcf4546e62815a47f7591d3d891dfb9be91150" }, { "path": "03_Script_Starter_Kit/examples/airbag_authorized_safe/README.md", @@ -166,28 +166,28 @@ }, { "path": "03_Script_Starter_Kit/examples/ecu_authorized_safe/22_ecu_case_intake_validator.mjs", - "size": 695, - "sha256": "daeb1e4c4f288fcf38dd81df7ae3cd5aecb6896fe83e9cabdba6962b20b511bf" + "size": 712, + "sha256": "84f93b17985eb9a6b2970b7bf5d6ed0c23ce8a5871c0e006ab97f061311be38b" }, { "path": "03_Script_Starter_Kit/examples/ecu_authorized_safe/23_ecu_calibration_read_consistency.mjs", - "size": 404, - "sha256": "f765c2f93a702884f5dc17afa7d9a21767987cbe8966103ad2c6faea4e5c0536" + "size": 394, + "sha256": "365991287a980790b955f58e9bce3426bd5e98a919616f60c1b2a5cfd26d16e0" }, { "path": "03_Script_Starter_Kit/examples/ecu_authorized_safe/24_ecu_partnumber_crosscheck.mjs", - "size": 558, - "sha256": "6d9740863777954e79750ac0193345a97447339dd5cd809507d7f382c863863c" + "size": 546, + "sha256": "ac50cf432a8451369252883b0a80f3f7b94aad14631e4e633ee783fe4c243f8c" }, { "path": "03_Script_Starter_Kit/examples/ecu_authorized_safe/25_ecu_change_scope_guard.mjs", - "size": 713, - "sha256": "4f14ccc0d5ced13bfd1f82553abc7d31172f3bdc560b69fb4117c0ddb3dd4cad" + "size": 718, + "sha256": "f58e42c4c799321deed0a15d1f836f14361cc05a64359ec9d0ee128efd32448d" }, { "path": "03_Script_Starter_Kit/examples/ecu_authorized_safe/26_ecu_service_completion_audit.mjs", - "size": 641, - "sha256": "273a901c6d56996e2581198a6ab165147601acbf7a93b893673a96839682e0f0" + "size": 629, + "sha256": "1bae9c170207e9a848a7245c5284e3c789a7bc190e063a5e5bc9f8682e5b7e2d" }, { "path": "03_Script_Starter_Kit/examples/ecu_authorized_safe/README.md", @@ -196,23 +196,23 @@ }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/09_immo_case_intake_validator.mjs", - "size": 766, - "sha256": "db363224eebfdbb1cb27bca692db9d25364a6ee9077770384b954a411332f605" + "size": 801, + "sha256": "01d015ccdcf1b4edda8952055e55d6a0904325624b357731659205eafd0e8195" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/10_immo_module_read_consistency.mjs", - "size": 734, - "sha256": "166915eb000e26031ba34607a371d182124780029010249dd1ba95b6db3a3d93" + "size": 764, + "sha256": "8f8f0aaec12d9345da64f42fe10e1b799a5b378a44573e92a5d8d2bed103b52d" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/11_immo_dump_quality_report.mjs", - "size": 790, - "sha256": "b8d93fcd3208ca38c4376173d8d5d850d244b8cc572cf2e552fbba1f2749ad90" + "size": 817, + "sha256": "7a8faa47bc7da683005f48296577d4f57ed22f732e6b1175ed74ee2266f2f1bc" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/12_authorized_key_count_reconciliation.mjs", - "size": 737, - "sha256": "fbc6e47c850f4a80f4c6390a8c9c0207ebfe785f93c897de7f6b40f4728faa06" + "size": 774, + "sha256": "21dfc385ba67092f158b949c754303336fef840ea03cb3ab3197d6ad2eaf0e9b" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/13_security_value_redactor.mjs", @@ -221,18 +221,18 @@ }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/14_immo_backup_naming_policy.mjs", - "size": 451, - "sha256": "eb73cc5cae0fb5b0ef9e6a8d569958f4a9504506b6b93b1511e6698f45220439" + "size": 507, + "sha256": "b30ffe482b1b5d0a81488032f976a564913f6a325b8f69c1b978deb3c6949da1" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/15_immo_change_scope_guard.mjs", - "size": 683, - "sha256": "9700dd36c27863e795665d3b4e615832f958feaf117f201b6f157065817089b3" + "size": 706, + "sha256": "b116ceb7fcabf79c3c24f76bd7e9b091585ccc933e6aace6818a27809f00a020" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/16_immo_service_completion_audit.mjs", - "size": 694, - "sha256": "dd29d920ff57fb8d5696f72361f083b0c4e851f245f062bf9e001388fd9af9a4" + "size": 695, + "sha256": "db9dd131a0e8f899132b639f1d06dc2b3eea2bda080de2462a0747c57a8c8a80" }, { "path": "03_Script_Starter_Kit/examples/immobilizer_authorized_safe/README.md", @@ -241,28 +241,28 @@ }, { "path": "03_Script_Starter_Kit/examples/other_modules_authorized_safe/27_module_case_intake_validator.mjs", - "size": 744, - "sha256": "18d9c2c567a9da532fd05f888fc2953af58c03ad1de9dc9303e689c445fe00eb" + "size": 763, + "sha256": "8fab0cbc95487a57453e1fa54337a260615858c83d2a9db8eb20e20bd3a9502e" }, { "path": "03_Script_Starter_Kit/examples/other_modules_authorized_safe/28_module_read_consistency.mjs", - "size": 397, - "sha256": "394afc2e58884869a7c0376b8256716cbce70d1dc011aa20b1ab0ee521685416" + "size": 387, + "sha256": "85bb7d89ca284e431a4df7e92e20b7dfd1e2f5d02579edf19e4866d7f84a53d0" }, { "path": "03_Script_Starter_Kit/examples/other_modules_authorized_safe/29_module_backup_naming_policy.mjs", - "size": 476, - "sha256": "c38ba3e4e11f0d758e4ac996ccd6434794225a2ead2ba5f643809999eed03db2" + "size": 520, + "sha256": "7e84684f7bb172fef867789f7913e11946af81045f44894680201267f8133fd6" }, { "path": "03_Script_Starter_Kit/examples/other_modules_authorized_safe/30_module_change_scope_guard.mjs", - "size": 863, - "sha256": "8a4e421e9d2aee8a444a49d58112fc4c8ad5a1d8e4998b3076dbcd24cdfdd684" + "size": 866, + "sha256": "487c4f8897b4a34f9c3f9d6112be82be9d96dec76bbb085651622dab88a34b4f" }, { "path": "03_Script_Starter_Kit/examples/other_modules_authorized_safe/31_module_service_completion_audit.mjs", - "size": 650, - "sha256": "8e7078215db0db5ed4aad25443c2534f9603a31ec95a66dee449e78829351982" + "size": 638, + "sha256": "e5abd3d67dcd193abe9ba973477e9e81deecf749a01bcac846c4e8c213251610" }, { "path": "03_Script_Starter_Kit/examples/other_modules_authorized_safe/README.md", @@ -272,7 +272,7 @@ { "path": "03_Script_Starter_Kit/templates/checksum_region_verifier.mjs", "size": 1383, - "sha256": "5f4567383be8569e2e57f18c2eef10798b69ff2416e8a9f95797335a8d09a18f" + "sha256": "df20899f32d0521b44d4498e07858e2e2d223082e097db67a4523bd759c224e1" }, { "path": "03_Script_Starter_Kit/templates/multiprog_safe_template.mjs", @@ -281,18 +281,18 @@ }, { "path": "03_Script_Starter_Kit/tests/test_additional_examples.mjs", - "size": 1881, - "sha256": "5f59f2bdb63c7fa0e7859e6ab4fa12a3d24c3277b240220b668ec2fefb0a6261" + "size": 1976, + "sha256": "ff8ccf7e22ee9aeab25f8b2efb5ac9d5df18bb7c7100420b9bf2cc01878e690d" }, { "path": "03_Script_Starter_Kit/tests/test_binary_utils.mjs", - "size": 407, - "sha256": "f067c3b4f7d6782808e738d4b4eacf14b0321b82571b67994f618452d0d6e0aa" + "size": 435, + "sha256": "d2081786819f0fbde6e9f91cb09e72fade6894a7bd3882922ce4739667536ef0" }, { "path": "03_Script_Starter_Kit/tests/test_expansion_examples.mjs", - "size": 4082, - "sha256": "72731f254473b99ac5a8c2bcb0354c993b3f3fa215a4ea3b685a1c68bcc23245" + "size": 4090, + "sha256": "50400058d90833fce8994e7b1582ced9b4fb038af12251abb5b6412025f43ea8" }, { "path": "04_Workflows/AUTHORIZED_KEY_LEARNING_WORKFLOW.md", @@ -464,6 +464,26 @@ "size": 2326, "sha256": "b1f305f2ec3e985c910afd0ae6e978865212c1625393cfe6780597cfd40d8fca" }, + { + "path": "08_Collected_MultiPROG_Scripts/Archived/README.md", + "size": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "08_Collected_MultiPROG_Scripts/Community/README.md", + "size": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "08_Collected_MultiPROG_Scripts/Examples/README.md", + "size": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "08_Collected_MultiPROG_Scripts/GitHub/binary-parser/README.md", + "size": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, { "path": "08_Collected_MultiPROG_Scripts/GitHub/CarKeyGuyNL_Multi-Prog-Scripts/EWS_Code_generator.mjs", "size": 5866, @@ -511,63 +531,63 @@ }, { "path": "08_Collected_MultiPROG_Scripts/Original/01_read_only_inspector.mjs", - "size": 306, - "sha256": "18156a9cc515306ea14a38b4ecc20401d6a8c2511542ea08df803d1e38132a0e" + "size": 358, + "sha256": "29b332da18c61ec65b8ca5d5db15f6aba34b16c0af7aef1b06d96a59c0a5750f" }, { "path": "08_Collected_MultiPROG_Scripts/Original/02_double_read_verifier.mjs", - "size": 203, - "sha256": "526487814bb04cb955a9ac666d3b1e77390c4a8462f2422488d905c2334c12b6" + "size": 240, + "sha256": "099b6acdc56c1403967c8f8def819f0e59cb1ae7e472e7012cf466b355369973" }, { "path": "08_Collected_MultiPROG_Scripts/Original/03_pattern_inventory.mjs", - "size": 192, - "sha256": "4e1d5e1ecd3f8f284be57c173ca481e7c55d6a719c3d72214d656aafde20735a" + "size": 219, + "sha256": "c81df6685529de1c9946c39f29893911fee8c59996527ae4c53bdbbf9d54760a" }, { "path": "08_Collected_MultiPROG_Scripts/Original/04_allowlisted_patch_demo.mjs", - "size": 345, - "sha256": "fac79790cac46e6e9299a618769e355a9153fd63ce145664ced729517dd37943" + "size": 381, + "sha256": "a059293e1010f2b57801d02b7b0e97559adacafb68acd5210687bdee4dafccdf" }, { "path": "08_Collected_MultiPROG_Scripts/Original/05_checksum_test_vectors.mjs", - "size": 249, - "sha256": "95dd4b2f4001c7f4f645fd972061805139cf5b41ed528f3013e4cdf9f30cb01d" + "size": 297, + "sha256": "2227f3999d736cb2ffdd8347bef39d00061790cbce4a4d9aeb7e7d807527aeda" }, { "path": "08_Collected_MultiPROG_Scripts/Original/06_authorized_job_record_validator.mjs", - "size": 387, - "sha256": "28581b002a52398f2e14752490c0a3165c48b055bb3ed4505e6a4ca03f074942" + "size": 456, + "sha256": "ed082376bff56fd54b3e6589c18f2b50b077620b989a5bf4417ae4771035c0c3" }, { "path": "08_Collected_MultiPROG_Scripts/Original/07_key_inventory_audit.mjs", - "size": 351, - "sha256": "e86e045e48f7cb2d5d8f760e745b5f5434dd8e30b20be34f511e03b487d92d96" + "size": 415, + "sha256": "e03f7c0372a77e83cdb8b4be26c1ca7c2305f99bb921fc583f5741c5a477c6e8" }, { "path": "08_Collected_MultiPROG_Scripts/Original/08_redacted_security_report.mjs", - "size": 381, - "sha256": "24882fd08420d906c6c87e6d8cf6fa30e3351d986787d7a6c3c2611d8f471399" + "size": 461, + "sha256": "3774504b4c55f60d73989c06531ff594a1a352fd703d3956a7b515e1c871d5c0" }, { "path": "08_Collected_MultiPROG_Scripts/Original/09_immo_case_intake_validator.mjs", - "size": 766, - "sha256": "db363224eebfdbb1cb27bca692db9d25364a6ee9077770384b954a411332f605" + "size": 801, + "sha256": "01d015ccdcf1b4edda8952055e55d6a0904325624b357731659205eafd0e8195" }, { "path": "08_Collected_MultiPROG_Scripts/Original/10_immo_module_read_consistency.mjs", - "size": 734, - "sha256": "166915eb000e26031ba34607a371d182124780029010249dd1ba95b6db3a3d93" + "size": 764, + "sha256": "8f8f0aaec12d9345da64f42fe10e1b799a5b378a44573e92a5d8d2bed103b52d" }, { "path": "08_Collected_MultiPROG_Scripts/Original/11_immo_dump_quality_report.mjs", - "size": 790, - "sha256": "b8d93fcd3208ca38c4376173d8d5d850d244b8cc572cf2e552fbba1f2749ad90" + "size": 817, + "sha256": "7a8faa47bc7da683005f48296577d4f57ed22f732e6b1175ed74ee2266f2f1bc" }, { "path": "08_Collected_MultiPROG_Scripts/Original/12_authorized_key_count_reconciliation.mjs", - "size": 737, - "sha256": "fbc6e47c850f4a80f4c6390a8c9c0207ebfe785f93c897de7f6b40f4728faa06" + "size": 774, + "sha256": "21dfc385ba67092f158b949c754303336fef840ea03cb3ab3197d6ad2eaf0e9b" }, { "path": "08_Collected_MultiPROG_Scripts/Original/13_security_value_redactor.mjs", @@ -576,23 +596,23 @@ }, { "path": "08_Collected_MultiPROG_Scripts/Original/14_immo_backup_naming_policy.mjs", - "size": 451, - "sha256": "eb73cc5cae0fb5b0ef9e6a8d569958f4a9504506b6b93b1511e6698f45220439" + "size": 507, + "sha256": "b30ffe482b1b5d0a81488032f976a564913f6a325b8f69c1b978deb3c6949da1" }, { "path": "08_Collected_MultiPROG_Scripts/Original/15_immo_change_scope_guard.mjs", - "size": 683, - "sha256": "9700dd36c27863e795665d3b4e615832f958feaf117f201b6f157065817089b3" + "size": 706, + "sha256": "b116ceb7fcabf79c3c24f76bd7e9b091585ccc933e6aace6818a27809f00a020" }, { "path": "08_Collected_MultiPROG_Scripts/Original/16_immo_service_completion_audit.mjs", - "size": 694, - "sha256": "dd29d920ff57fb8d5696f72361f083b0c4e851f245f062bf9e001388fd9af9a4" + "size": 695, + "sha256": "db9dd131a0e8f899132b639f1d06dc2b3eea2bda080de2462a0747c57a8c8a80" }, { "path": "08_Collected_MultiPROG_Scripts/Original/binary_utils.mjs", - "size": 4567, - "sha256": "b5645c1560828f97acfa0578e214754cb21f233f514dea5f133529346654fdd0" + "size": 5637, + "sha256": "ae4947054a93e6dbdd3da6f1db05703b6541ddd5546c87f1f737df76adf95f6a" }, { "path": "08_Collected_MultiPROG_Scripts/Original/multiprog_safe_template.mjs", @@ -601,8 +621,8 @@ }, { "path": "08_Collected_MultiPROG_Scripts/Original/test_binary_utils.mjs", - "size": 406, - "sha256": "b424eaba7c78efcde0458bafa4a74a1424e1ccfd52823d9f55d328b342d35b59" + "size": 434, + "sha256": "66bab858b5d530e754bffd59c80ece8aa5dc37b38f0b532e71f9cff9adbf7a84" }, { "path": "08_Collected_MultiPROG_Scripts/README.md", @@ -621,88 +641,88 @@ }, { "path": "09_Collected_JS/administrative/script_catalog.mjs", - "size": 1728, - "sha256": "f11a93c24b031ecfc367bc8fe88c23d023e87cf23a21ecab3297d2c63a7c11ae" + "size": 1738, + "sha256": "f81651ce744ee1634d5024879b847841d2c52634dba6a97b3649437a0e672756" }, { "path": "09_Collected_JS/binary/dataview_helpers.mjs", - "size": 1468, - "sha256": "04ef48405f8c9d578fedffe3cf0ae29cb2bef79ea1cf73d1537d51e5f13d4216" + "size": 1571, + "sha256": "0d504c75818513e01745d856cab09a6b76942054ae30e37f4daf11d1170bbb3f" }, { "path": "09_Collected_JS/binary/struct_reader.mjs", - "size": 1088, - "sha256": "470a26697b5a5d4a0be52021a1604591536f96ce0a649e49c9ff8d6f1fdf9aed" + "size": 1082, + "sha256": "626a49e4d7d929f24523c93fd30d8ff0f9b2a0364faf4c00ee2862f91fabfce2" }, { "path": "09_Collected_JS/checksums/adler32.mjs", - "size": 440, - "sha256": "08bba9ae975765bc288e70135c7aea4f7063b0e8c5c9149c8bcbd27104c02e03" + "size": 427, + "sha256": "c07cdbbc4184cc03dec011b0054f9cf59ee4bd22c92be9f71e31f0a71e24952d" }, { "path": "09_Collected_JS/checksums/crc16.mjs", - "size": 903, - "sha256": "27b87f99de40ce6481f8b02dd6532b65e5b68b079e35c85dea4f80b7f8e7eef2" + "size": 869, + "sha256": "5048d939ab64760d4b8771b46e58c33cc9bf38cff305e02f0747c474ce8b5f95" }, { "path": "09_Collected_JS/checksums/crc32.mjs", - "size": 1283, - "sha256": "8f75655eb06d3a533f7458b1778bf36937a39122d47990877b8d7a2acc8584d4" + "size": 1255, + "sha256": "6d516a055bbe91cbf187357e020bd108608f19195f4fac5f1021d6cda7b7832c" }, { "path": "09_Collected_JS/checksums/crc64.mjs", - "size": 767, - "sha256": "a9a9e4d7ee26a7e69c7ca5e9013d6db2a9721341e2ddf48ac7d22d455a4e6b50" + "size": 744, + "sha256": "f57edf320db079e3289aa39cbc79a86d42016e393feda27e1816c3f77dbf1d76" }, { "path": "09_Collected_JS/checksums/crc8.mjs", - "size": 525, - "sha256": "7cbbb3e9df49e12732bac2d866acd89863122fa8ccc12bac37715c68af7e0dac" + "size": 506, + "sha256": "fc4318146c8b2ffedf5e5ebe00ae20bed04a66785c61e59a83ac14ce0e2fd5ef" }, { "path": "09_Collected_JS/checksums/fletcher.mjs", - "size": 875, - "sha256": "096557f7eb0746b84de31e8d392c5e6ababd0fa8648a868830272993928e6ab3" + "size": 858, + "sha256": "e296b7237c81798ff487b263d6d4a84505b4b5f93fb3441e4b1b5f2ac801cd8b" }, { "path": "09_Collected_JS/encoding/ascii.mjs", - "size": 660, - "sha256": "789cff1a8daef369530137d79dc016a3d1bcb196ff60d3d5c275302db6c5eacc" + "size": 646, + "sha256": "d935384bc42a4cc15acfa0a8dfcfa130d18962c21786c52eafbe874bbb42ebbf" }, { "path": "09_Collected_JS/encoding/bcd.mjs", - "size": 811, - "sha256": "645205a14510dd1c67b0ca4061de9fe1b409e64d178f1ea1fab633ab0ca91cf3" + "size": 796, + "sha256": "09db57f972c44d2ae4016a526b13a1940d5b3571f42cef0e0124e8f8aea9fec9" }, { "path": "09_Collected_JS/encoding/hex.mjs", - "size": 629, - "sha256": "fca861f1e3103bfbe4c0b5d8a7de89b504a559fec5224239086f82da67b6aba1" + "size": 628, + "sha256": "bf4a6d08674f60e7408110118730a65c9a11282c72d9cd263d21d9be1fe03f1a" }, { "path": "09_Collected_JS/encoding/utf8.mjs", - "size": 378, - "sha256": "c24e24dff1c08e6b689d32ec2de034a35874a7a2a121521f3496e6144de687c8" + "size": 369, + "sha256": "29e453b146d708d369a167cc7c42423f18bbeefb7ce6bc21791595113b15de8f" }, { "path": "09_Collected_JS/hashing/_pad.mjs", - "size": 576, - "sha256": "5fb75f11b31806ca10942af87820dda98f71cb6d6eeac2e2b79a9a20e065aeac" + "size": 562, + "sha256": "a74fae5efc879d1db8ef1e6676fef854a9b6379765a60b644c3ee260a7135c9b" }, { "path": "09_Collected_JS/hashing/md5.mjs", - "size": 2180, - "sha256": "d16657cf6ee9765fd1b7ef0be4009551c57afe40ab279f6675ec5a91398be899" + "size": 2246, + "sha256": "a228f3f98fd0fae02d1f2171536b92aa4a274e595a138530b995510fb01a1188" }, { "path": "09_Collected_JS/hashing/sha1.mjs", - "size": 1539, - "sha256": "81030b7e4ed8e5e87a88edaa61983496457a4d120e3d870d6cf909e0d0a40254" + "size": 1665, + "sha256": "5946d9d94782e9a7309397f6149b5cbbfdc7d74f07a0da0a702a6096cbe4d7b9" }, { "path": "09_Collected_JS/hashing/sha256.mjs", - "size": 2676, - "sha256": "2fab620737487841ac3dc44f1b39677e11374d58209b1a272f763c235118507e" + "size": 2693, + "sha256": "91d12d2837609fc38b8cb20365222d8f1c4ad958a7cf543645c12b49905f05ae" }, { "path": "09_Collected_JS/README.md", @@ -711,13 +731,13 @@ }, { "path": "09_Collected_JS/tests/test_admin_utils.mjs", - "size": 962, - "sha256": "18db775821614eea74793fbf3d187c5e8a268d3279347571dc4a44125664f336" + "size": 955, + "sha256": "13a6c83047837a47e4475b80b32b1daea3e4e344aa9dc97f920cfc5fec43b3ab" }, { "path": "09_Collected_JS/tests/test_vectors.mjs", - "size": 1522, - "sha256": "81a955abb172697066c73fcbf64cfaf68cc792d71295561b548492898bf5bcc8" + "size": 1500, + "sha256": "3827815a8c48bdb0fc78476511b271733587cec8008b5662696fa73fa4fc031b" }, { "path": "10_Source_Repositories/README.md", @@ -951,8 +971,8 @@ }, { "path": "16_Tests/MultiPROG/test_buffer_utils.mjs", - "size": 441, - "sha256": "531d025c253c6e8bbc7d3c5899cc95ece73e628b2076f4d9cd92cb4391592a27" + "size": 438, + "sha256": "6b87a381fac35bd9097941b832c81ac1dee16bed041a14446805fdab8ed06b47" }, { "path": "16_Tests/MultiPROG/TEST_GUIDE.md", @@ -1011,8 +1031,8 @@ }, { "path": "17_MultiPROG_SDK/examples/example_readonly_report.mjs", - "size": 568, - "sha256": "9531f8ca37ed566137e008a5e0b73cdc281d51e712e5947bd59dbb28bfed395e" + "size": 555, + "sha256": "2774c0d4405c1f0bb5ddccda253381281ae5cde59d8df1792ccce344411005d4" }, { "path": "17_MultiPROG_SDK/package.json", @@ -1066,103 +1086,103 @@ }, { "path": "17_MultiPROG_SDK/templates/template_binary_tool.mjs", - "size": 713, - "sha256": "44ad6a153d1d1d3832616a698ed2ac48da7dbee0e3ee20b12f318a23ff72b13f" + "size": 705, + "sha256": "de577c5d09e17f60258111fb3f34b99813f2dcad2eca2101df1f7cc6d6c7d638" }, { "path": "17_MultiPROG_SDK/templates/template_byteswap_workflow.mjs", - "size": 860, - "sha256": "0408a174c7c23600260e17b5e8dba9e3eef2987054eb19e30af33aa4a86386ae" + "size": 836, + "sha256": "4ebf34ec8c3563d1df4bb6d77f64c14f6fbdc757d6749cc47c8de30d3199c07a" }, { "path": "17_MultiPROG_SDK/templates/template_checksum_workflow.mjs", - "size": 798, - "sha256": "5e6a5a3093780c067a8b3efd394b717922c5601b5bb38c311ea9482a0d8a3b23" + "size": 776, + "sha256": "ce7da9fb532f0fafc3a3cb359c9937b2d5e471f231438075da6bbb7aa142605a" }, { "path": "17_MultiPROG_SDK/templates/template_compare_workflow.mjs", - "size": 1103, - "sha256": "ad3af18143646dc1e5920900e352dee99aeda6ea74307686ad48f98ad193df84" + "size": 1075, + "sha256": "12c3275b4f272793a206d50b5ceb87f2f2d71199c5e870066bab8e21326731d9" }, { "path": "17_MultiPROG_SDK/templates/template_diff_report.mjs", - "size": 1036, - "sha256": "cbede11acd30fe0b7f74feef44a31ecfec9389c3d0c1278fa517c8bc5694f044" + "size": 1016, + "sha256": "97f2991ad52ce345acf6cfe5c232450f2c1071ce6e7235d2b7de5aabc47f78ff" }, { "path": "17_MultiPROG_SDK/templates/template_eeprom.mjs", - "size": 880, - "sha256": "e6912b099c9ecbe650ddacb32787e322e7a98d313d2de428bf3cbd26b46157ff" + "size": 855, + "sha256": "2966f2cf7ae8af2e67f88521952abbe51d5a0d4de26ffa6ac193112f376233da" }, { "path": "17_MultiPROG_SDK/templates/template_flash.mjs", - "size": 791, - "sha256": "72d321eb39bce162bc9578a2cde0208b243170260e55741c8663ade0d8ca92df" + "size": 770, + "sha256": "2fc231b219cf07de620df705adde523687dfef10e9166de51714708b2faf2e6d" }, { "path": "17_MultiPROG_SDK/templates/template_inventory_workflow.mjs", - "size": 809, - "sha256": "734be92c2b3bb30316a45c597020b48f1fa613a74d493b37e6e83bc8614a6804" + "size": 784, + "sha256": "ea5ed02ccdbca44abffbfdad75010422dd489fae971ea950dbabd66ce64d659a" }, { "path": "17_MultiPROG_SDK/templates/template_merge_workflow.mjs", - "size": 938, - "sha256": "7d7732562ccd1721dd0ed35db216955737001c69b334c1f5b25eac82bb4432dc" + "size": 926, + "sha256": "a0e3e9475c58ecdf843f376902a41fe6b8867d4aa1b95dc6ee8335e5b0e66d28" }, { "path": "17_MultiPROG_SDK/templates/template_patch_guard.mjs", - "size": 1065, - "sha256": "32c62ce6a6cc2b80b8cb39b7f22bdb7835d0e3777d49bfbe174c37eaa4d983af" + "size": 1072, + "sha256": "65571fd9a4f1b6a1d7bdd40ff9c12ca3f66a366aff5a638134357208b844c671" }, { "path": "17_MultiPROG_SDK/templates/template_readonly.mjs", "size": 985, - "sha256": "8586522c73c807ee55f05bd4609b5ecd69f19e37263fd379d313227376ff2e59" + "sha256": "2be6e8e0f111e95af1c5ee59c5dca7bd9bc02d24d9a811ef9d13c4a78de72026" }, { "path": "17_MultiPROG_SDK/templates/template_reporting.mjs", - "size": 771, - "sha256": "21d4219f2f03b86a034e8cf4869b6ad39f889b025b5fbb150e95caa2246fee1e" + "size": 765, + "sha256": "3035bcec7de67f023c8139bfe773eeccf0cb253896c0f03c44248a8f813d0915" }, { "path": "17_MultiPROG_SDK/templates/template_validator.mjs", - "size": 843, - "sha256": "1b3d5d225ad3e2393b1b8345465bc3ccfd972d410b337382b8748a9739c09773" + "size": 839, + "sha256": "066789a687a8eb55357ac7b0a32303ac3c104ba5f4c89f910fe761dabb26b66e" }, { "path": "17_MultiPROG_SDK/tests/buffer_helpers.test.mjs", - "size": 923, - "sha256": "4006821515db6eabc4ec7114720df1283e32843038bf0a2584b1d210b29c49fc" + "size": 918, + "sha256": "4acb0f503aa662b7d270cbc882e0012b7612a2f7621ae65d3f27046edd934301" }, { "path": "17_MultiPROG_SDK/tests/crc_engine.test.mjs", - "size": 1686, - "sha256": "a5e5f4379599d5bef8207c415802cfa0ed0d2ff2f1f8493480d4271d23ed1aa6" + "size": 1664, + "sha256": "602c96f31845995c9905772703fae3ae80055dfe04c931a2dad2fdeaad601053" }, { "path": "17_MultiPROG_SDK/tests/encoding_helpers.test.mjs", - "size": 605, - "sha256": "e8c417f64846c0cf5663ed172a313039acbcc1db6dc0fe61eca7c5808957c89c" + "size": 595, + "sha256": "5b709995a22e8c167754ce2e07e85aeff686e3045866e24076cb8e00eaf96e5c" }, { "path": "17_MultiPROG_SDK/tests/template_catalog.test.mjs", - "size": 1519, - "sha256": "92c72a14c4a3075f12afc0ee45ede4b35d83ae9a65d5802a9824538d80324c1d" + "size": 1556, + "sha256": "420e2f9f53fe58871de762d61fc8b3e24cc3ef38ba695cb926ebd7381e6b7899" }, { "path": "17_MultiPROG_SDK/tests/workflow_templates.test.mjs", - "size": 1351, - "sha256": "a2ccc4fc13d02d75d73b38134e8bc409d8a9d529c882ae4f3156b540cdfb8d0d" + "size": 1370, + "sha256": "c4755f971257e7b5d86ec0084cfa89df0f5bdb9016946ad6e0be467b90996107" }, { "path": "17_MultiPROG_SDK/utilities/_verify_crc.mjs", - "size": 608, - "sha256": "2c314eb8ac8a5779edf3468b343f8f2a33aae25a382e6026b43e55ca1ef1ab13" + "size": 611, + "sha256": "0c891863ca23517868c0d52cc63fc45bb85670a61cefb898e53c13a87e71b45c" }, { "path": "17_MultiPROG_SDK/utilities/crc_engine.mjs", - "size": 3248, - "sha256": "9b4510b713931cbdf89c60914f23a5aa496a7a65c2ceed564bbd3bbcf0a55c26" + "size": 3378, + "sha256": "beb3ad564baf0d9e804d7313432fae49cc6b410b88a1705f200dd844941cdb50" }, { "path": "18_Documentation/BEGINNER_GUIDE.md", @@ -1276,8 +1296,8 @@ }, { "path": "MANIFEST.json", - "size": 53145, - "sha256": "4d134c1f95221c71fc607c76eb333c75b6139f4f28e52af7c80720f6867d404a" + "size": 52781, + "sha256": "79274991c0597ef13296e79fb95a4d2c01c7b14f47733c57d70a8ffd904a7956" }, { "path": "README.md",