code wiki / (root) / nx_iso20022_gate.nx

nx_iso20022_gate.nx source

↩ module page · 96 lines · 5209 B

1// nx_iso20022_gate.nx -- F989 INDEPENDENT GATE: ISO 20022 parse + integrity validation. 2// Proves field extraction, transaction counting, exact-cent amount summing, and above all that a 3// TAMPERED payment file (an amount altered but the control sum left stale) is REJECTED. Fail-closed on 4// a missing required field. XML uses no attributes so it is a clean NishiLang string literal. 5// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 6 7import "nx_iso20022_lib.nx" 8 9func ig_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 10func ig_putn(v: i64) -> i64 { 11 let t: *u8 = sys_mmap(32) 12 var o: i64 = 0 13 var m: i64 = v 14 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m } 15 let d: *u8 = sys_mmap(32) 16 var k: i64 = 0 17 if m == 0 { d[0] = 48 as u8; k = 1 } 18 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 19 var i: i64 = 0 20 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 } 21 sys_write(1, t, o) 22 return 0 23} 24func ig_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 { 25 if got == want { 26 cnt[0] = cnt[0] + 1 27 ig_puts(" PASS " as *u8); ig_puts(name); ig_puts(" = " as *u8); ig_putn(got); ig_puts("\n" as *u8) 28 return 1 29 } 30 cnt[1] = cnt[1] + 1 31 ig_puts(" FAIL " as *u8); ig_puts(name); ig_puts(" got " as *u8); ig_putn(got) 32 ig_puts(" want " as *u8); ig_putn(want); ig_puts("\n" as *u8) 33 return 0 34} 35 36func main(argc: i64, argv: *i64) -> i64 { 37 let cnt: *i64 = sys_mmap(16) as *i64 38 cnt[0] = 0 39 cnt[1] = 0 40 41 ig_puts("NISHI-ISO20022-GATE (F989 payment message integrity: tamper is rejected)\n" as *u8) 42 43 // VALID pain.001: 2 transactions, amounts 100.00 + 200.00 = 300.00, CtrlSum 300.00 44 let valid: *u8 = "<Document><CstmrCdtTrfInitn><GrpHdr><MsgId>MSG-2026-001</MsgId><NbOfTxs>2</NbOfTxs><CtrlSum>300.00</CtrlSum></GrpHdr><CdtTrfTxInf><InstdAmt>100.00</InstdAmt></CdtTrfTxInf><CdtTrfTxInf><InstdAmt>200.00</InstdAmt></CdtTrfTxInf></CstmrCdtTrfInitn></Document>" as *u8 45 let vl: i64 = iso_len(valid) 46 47 // ---- I1: field extraction (MsgId) ---- 48 let msgid: *u8 = sys_mmap(64) 49 iso_element(valid, vl, "MsgId" as *u8, msgid) 50 ig_ck(cnt, "I1 MsgId extracted (streq)" as *u8, mt_streq(msgid, "MSG-2026-001" as *u8), 1) 51 52 // ---- I2: transaction count ---- 53 ig_ck(cnt, "I2 CdtTrfTxInf count = 2" as *u8, iso_count(valid, vl, "CdtTrfTxInf" as *u8), 2) 54 55 // ---- I3: exact-cent amount sum = $300.00 ---- 56 ig_ck(cnt, "I3 sum of InstdAmt = 30000 minor units" as *u8, iso_sum_amounts(valid, vl, "InstdAmt" as *u8), 30000) 57 58 // ---- I4: amount parsing incl a single-fraction-digit value ---- 59 ig_ck(cnt, "I4 amount 100.00 -> 10000" as *u8, iso_amount_to_cents("100.00" as *u8), 10000) 60 ig_ck(cnt, "I4a amount 100.5 -> 10050 (single fraction digit padded)" as *u8, iso_amount_to_cents("100.5" as *u8), 10050) 61 ig_ck(cnt, "I4b amount 42 -> 4200 (no fraction)" as *u8, iso_amount_to_cents("42" as *u8), 4200) 62 63 // ---- I5: the valid message VALIDATES ---- 64 ig_ck(cnt, "I5 valid pain.001 -> ISO_OK (0)" as *u8, iso_validate(valid, vl), ISO_OK) 65 66 // ---- I6: TAMPER. Same message but one amount altered 200.00 -> 250.00, CtrlSum still 300.00 ---- 67 // actual sum is now 350.00 != declared 300.00 -> rejected. This is the payment-fraud tooth. 68 let tampered: *u8 = "<Document><CstmrCdtTrfInitn><GrpHdr><MsgId>MSG-2026-001</MsgId><NbOfTxs>2</NbOfTxs><CtrlSum>300.00</CtrlSum></GrpHdr><CdtTrfTxInf><InstdAmt>100.00</InstdAmt></CdtTrfTxInf><CdtTrfTxInf><InstdAmt>250.00</InstdAmt></CdtTrfTxInf></CstmrCdtTrfInitn></Document>" as *u8 69 ig_ck(cnt, "I6 TAMPERED amount (CtrlSum stale) -> ISO_SUM_MISMATCH (-4)" as *u8, 70 iso_validate(tampered, iso_len(tampered)), ISO_SUM_MISMATCH) 71 72 // ---- I7: wrong NbOfTxs (declares 3, has 2) -> ISO_TX_MISMATCH ---- 73 let badcount: *u8 = "<Document><GrpHdr><NbOfTxs>3</NbOfTxs><CtrlSum>300.00</CtrlSum></GrpHdr><CdtTrfTxInf><InstdAmt>100.00</InstdAmt></CdtTrfTxInf><CdtTrfTxInf><InstdAmt>200.00</InstdAmt></CdtTrfTxInf></Document>" as *u8 74 ig_ck(cnt, "I7 wrong NbOfTxs -> ISO_TX_MISMATCH (-2)" as *u8, 75 iso_validate(badcount, iso_len(badcount)), ISO_TX_MISMATCH) 76 77 // ---- I8: FAIL-CLOSED on a missing NbOfTxs field ---- 78 let nofield: *u8 = "<Document><GrpHdr><CtrlSum>300.00</CtrlSum></GrpHdr><CdtTrfTxInf><InstdAmt>100.00</InstdAmt></CdtTrfTxInf></Document>" as *u8 79 ig_ck(cnt, "I8 missing NbOfTxs -> ISO_NO_FIELD (-1) fail-closed" as *u8, 80 iso_validate(nofield, iso_len(nofield)), ISO_NO_FIELD) 81 82 // ---- I9: a missing element returns -1, not garbage ---- 83 let absent: *u8 = sys_mmap(64) 84 ig_ck(cnt, "I9 absent element -> -1" as *u8, iso_element(valid, vl, "NoSuchTag" as *u8, absent), 0 - 1) 85 86 ig_puts("nx_iso20022_gate: pass=" as *u8); ig_putn(cnt[0]) 87 ig_puts(" fail=" as *u8); ig_putn(cnt[1]); ig_puts("\n" as *u8) 88 if cnt[1] == 0 { 89 ig_puts("F989 nx_iso20022: VERDICT=GREEN (integrity checked not trusted; a tampered payment file is rejected)\n" as *u8) 90 sys_exit(0) 91 return 0 92 } 93 ig_puts("F989 nx_iso20022: VERDICT=RED\n" as *u8) 94 sys_exit(1) 95 return 1 96}