nx_sign_envelope_lib.nx source
↩ module page · 96 lines · 3160 B
1// nx_sign_envelope_lib.nx -- Nishi Sign CORE LIB: tamper-evident e-signature audit chain.
2// h[0]=sha256("nishi-sign-genesis"); h[n]=sha256(h[n-1] || canonical(event_n)) -> altering ANY
3// past event changes the audit head = TAMPER DETECTED BY CONSTRUCTION. Events canonicalized +
4// content-addressed (nx_canon_cid), persisted on the append-only seg_store (nx_registry).
5// LIB (no main) so the CLI organ AND the independent gate import the SAME shipped code.
6// SCALE-LAW (DECLARED): SE_EVT_CAP=4096 B/canonical event, fail-closed never truncates.
7// license_tier: ORIGINAL
8
9import "nx_sha256.nx"
10import "nx_canon_cid.nx"
11import "nx_registry.nx"
12
13const SE_EVT_CAP: i64 = 4096
14
15func se_catcopy(dst: *u8, off: i64, s: *u8) -> i64 {
16 var i: i64 = 0
17 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
18 return off + i
19}
20
21func se_catn(dst: *u8, off: i64, v: i64) -> i64 {
22 var m: i64 = v
23 var o: i64 = off
24 if m == 0 { dst[o] = 48 as u8; return o + 1 }
25 let t: *u8 = sys_mmap(24)
26 var k: i64 = 0
27 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
28 var i: i64 = 0
29 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
30 return o + k
31}
32
33// canonical event record for (env,seq,signer,action,ts) into out; returns len
34func se_event_encode(env: *u8, seq: i64, signer: *u8, action: *u8, ts: i64, out: *u8) -> i64 {
35 let seqs: *u8 = sys_mmap(24)
36 var so: i64 = se_catn(seqs, 0, seq)
37 seqs[so] = 0 as u8
38 let tss: *u8 = sys_mmap(24)
39 var to: i64 = se_catn(tss, 0, ts)
40 tss[to] = 0 as u8
41 let keys: *i64 = sys_mmap(8 * 5) as *i64
42 let vals: *i64 = sys_mmap(8 * 5) as *i64
43 keys[0] = ("env" as *u8) as i64
44 vals[0] = env as i64
45 keys[1] = ("seq" as *u8) as i64
46 vals[1] = seqs as i64
47 keys[2] = ("signer" as *u8) as i64
48 vals[2] = signer as i64
49 keys[3] = ("action" as *u8) as i64
50 vals[3] = action as i64
51 keys[4] = ("ts" as *u8) as i64
52 vals[4] = tss as i64
53 return canon_encode(keys, vals, 5, out)
54}
55
56// chain step: out32 = sha256( prev32 || evt[0..evtlen) )
57func se_chain(prev: *u8, evt: *u8, evtlen: i64, out32: *u8) -> i64 {
58 let buf: *u8 = sys_mmap(32 + SE_EVT_CAP + 16)
59 var i: i64 = 0
60 while i < 32 { buf[i] = prev[i]; i = i + 1 }
61 var j: i64 = 0
62 while j < evtlen { buf[32 + j] = evt[j]; j = j + 1 }
63 sha256_digest(buf, 32 + evtlen, out32)
64 return 0
65}
66
67// hex of 32-byte digest into out (64 chars + NUL)
68func se_hex(dg: *u8, out: *u8) -> i64 {
69 var i: i64 = 0
70 while i < 32 {
71 let b: i64 = dg[i] & 0xff
72 let hi: i64 = (b >> 4) & 15
73 let lo: i64 = b & 15
74 var c1: i64 = 48 + hi
75 if hi > 9 { c1 = 87 + hi }
76 var c2: i64 = 48 + lo
77 if lo > 9 { c2 = 87 + lo }
78 out[i * 2] = c1 as u8
79 out[i * 2 + 1] = c2 as u8
80 i = i + 1
81 }
82 out[64] = 0 as u8
83 return 64
84}
85
86// 1 if two 32-byte digests equal, else 0
87func se_eq32(a: *u8, b: *u8) -> i64 {
88 var i: i64 = 0
89 while i < 32 { if a[i] != b[i] { return 0 } i = i + 1 }
90 return 1
91}
92
93func se_genesis(out32: *u8) -> i64 {
94 sha256_digest("nishi-sign-genesis" as *u8, 18, out32)
95 return 0
96}