code wiki / (root) / nx_sign_envelope_lib.nx

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}