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}