nx_swhid.nx source
↩ module page · 69 lines · 3017 B
1// nx_swhid.nx -- thin CLI over nx_swhid_lib. Compute the ISO/IEC 18670:2025 identifier of a file.
2//
3// The construction lives in the LIB so this command line and any in-process consumer prove the SAME
4// code, and so the gate can IMPORT the logic rather than fork this binary -- a fork is a boundary the
5// mutation harness is blind across, and a gate that cannot be mutated returns a GREEN that reads like
6// a proof while proving nothing.
7//
8// WHY A LIBRARIAN EMITS THIS ALONGSIDE ITS OWN sha256 AND NOT INSTEAD OF IT:
9// the SWHID is what the WORLD can check -- computed identically by everyone, from the bytes alone,
10// with no registry and no forge in the loop, and accepted as an identifier by SPDX 2.3 Annex F and
11// DataCite 4.7. The sha256 plus byte length is what WE trust, because SHA-1 has chosen-prefix
12// collisions (SHAttered, 2017) and is therefore an interoperable NAME, never tamper evidence.
13// Emitting only the SWHID would be a downgrade wearing a standard's number.
14// license_tier: ORIGINAL
15import "nx_syscalls.nx"
16import "nx_swhid_lib.nx"
17
18func swc_puts(s: *u8) -> i64 { sys_write(1, s, sw_len(s)); return 0 }
19
20func swc_num(v: i64) -> i64 {
21 let b: *u8 = sys_mmap(SW_HDR_MAX)
22 let n: i64 = sw_decimal(v, b, 0)
23 sys_write(1, b, n)
24 sys_munmap(b, SW_HDR_MAX)
25 return 0
26}
27
28func main(argc: i64, argv: *i64) -> i64 {
29 if argc < 3 {
30 swc_puts("usage: nx_swhid file <path>\n" as *u8)
31 swc_puts(" prints swh:1:cnt:<40 hex> -- the ISO/IEC 18670:2025 content identifier.\n" as *u8)
32 swc_puts(" Computed from the file BYTES alone: no filename, no path, no mtime, so it is\n" as *u8)
33 swc_puts(" stable across forges, renames and re-hosting, and anyone can recompute it.\n" as *u8)
34 swc_puts(" Also prints bytes=, because a digest says which bytes and only a LENGTH says how many.\n" as *u8)
35 return 3
36 }
37 let verb: *u8 = argv[1] as *u8
38 var isfile: i64 = 1
39 let f: *u8 = "file" as *u8
40 var i: i64 = 0
41 while f[i] != (0 as u8) { if verb[i] != f[i] { isfile = 0 } i = i + 1 }
42 if isfile == 1 { if verb[i] != (0 as u8) { isfile = 0 } }
43 if isfile == 0 {
44 swc_puts("REFUSED unknown-verb -- only 'file' exists today\n" as *u8)
45 return 3
46 }
47
48 let path: *u8 = argv[2] as *u8
49 // sys_read_file sizes its buffer FROM THE FILE and cannot short-read, so there is no cap to tune
50 // and no truncated read that would produce a confident WRONG identifier.
51 let lp: *i64 = sys_mmap(16) as *i64
52 let body: *u8 = sys_read_file(path, lp)
53 if (body as i64) == 0 {
54 swc_puts("REFUSED unreadable-file -- no identifier is emitted for bytes we do not hold\n" as *u8)
55 return 4
56 }
57 let n: i64 = lp[0]
58 let out: *u8 = sys_mmap(SW_IDLEN + 8)
59 let r: i64 = swhid_cnt(body, n, out)
60 if r < 0 {
61 swc_puts("REFUSED could-not-compute\n" as *u8)
62 return 4
63 }
64 swc_puts(out)
65 swc_puts(" bytes=" as *u8)
66 swc_num(n)
67 swc_puts("\n" as *u8)
68 return 0
69}