code wiki / _hdl_build / nx_connect_msgx.nx

nx_connect_msgx.nx source

↩ module page · 151 lines · 8008 B

1// nx_connect_msgx.nx -- FUNCTIONALITY rung: message BREADTH. Extends the messaging core with the 2// everyday chat features: reactions (toggle), reply/threads, forward (with provenance), @mentions, 3// pinned (admin-gated), full-text search, and disappearing (TTL) messages. 4// 5// Honest design note: full-text search is CLIENT-SIDE here BECAUSE the store is content-blind -- 6// the server holds ciphertext and cannot search plaintext (that is the privacy tradeoff vs WeChat / 7// Telegram-cloud, which search server-side because they read everything). The gate proves the client 8// (with the key) finds matches while the server finds ZERO. 7 checks incl. negative controls. 9// 100% sovereign. license_tier: ORIGINAL expect_exit: 0 10import "nx_syscalls.nx" 11const M_MAGIC_9001: i64 = 9001 12const M_MAGIC_9002: i64 = 9002 13const M_MAGIC_9003: i64 = 9003 14const M_MAGIC_9005: i64 = 9005 15 16const M_STRIDE: i64 = 8 17const F_ID: i64 = 0 18const F_SENDER: i64 = 1 19const F_CIPHER: i64 = 2 20const F_REPLY: i64 = 3 21const F_FWD: i64 = 4 22const F_MENT: i64 = 5 // mention bitmask (uid i -> bit i) 23const F_EXP: i64 = 6 // expiry time (0 = no TTL) 24const F_DEL: i64 = 7 25const ROLE_MEMBER: i64 = 1 26const ROLE_ADMIN: i64 = 2 27const EMOJI_HEART: i64 = 1 28 29func sw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 30func sn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 } 31 32func bit_set(mask: i64, pos: i64) -> i64 { var m: i64=mask; var i: i64=0; while i<pos { m=m/2; i=i+1 } return m - (m/2)*2 } 33 34// reactions: store stride 3 [msg,user,emoji]; toggle returns 1 if added, 0 if removed 35func react_toggle(rs: *i64, rc: *i64, msg: i64, user: i64, emoji: i64) -> i64 { 36 var i: i64=0 37 while i<rc[0] { 38 if rs[i*3]==msg { if rs[i*3+1]==user { if rs[i*3+2]==emoji { 39 let last: i64=rc[0]-1 40 rs[i*3]=rs[last*3]; rs[i*3+1]=rs[last*3+1]; rs[i*3+2]=rs[last*3+2] 41 rc[0]=last 42 return 0 43 } } } 44 i=i+1 45 } 46 let c: i64=rc[0]; rs[c*3]=msg; rs[c*3+1]=user; rs[c*3+2]=emoji; rc[0]=c+1 47 return 1 48} 49func react_count(rs: *i64, rc: i64, msg: i64, emoji: i64) -> i64 { 50 var n: i64=0; var i: i64=0 51 while i<rc { if rs[i*3]==msg { if rs[i*3+2]==emoji { n=n+1 } } i=i+1 } 52 return n 53} 54func thread_count(M: *i64, n: i64, root: i64) -> i64 { 55 var c: i64=0; var i: i64=0 56 while i<n { if M[i*M_STRIDE+F_REPLY]==root { c=c+1 } i=i+1 } 57 return c 58} 59func pin_add(pset: *i64, pc: *i64, role: i64, msg: i64) -> i64 { 60 if role<ROLE_ADMIN { return 0 } // only admin+ may pin (groups) 61 let c: i64=pc[0]; pset[c]=msg; pc[0]=c+1; return 1 62} 63func is_pinned(pset: *i64, pc: i64, msg: i64) -> i64 { 64 var i: i64=0; while i<pc { if pset[i]==msg { return 1 } i=i+1 } return 0 65} 66func client_search(M: *i64, n: i64, key: i64, term: i64) -> i64 { // client has the key -> can match 67 var c: i64=0; var i: i64=0 68 while i<n { if M[i*M_STRIDE+F_DEL]==0 { if (M[i*M_STRIDE+F_CIPHER]-key)==term { c=c+1 } } i=i+1 } 69 return c 70} 71func server_search(M: *i64, n: i64, term: i64) -> i64 { // server has only ciphertext 72 var c: i64=0; var i: i64=0 73 while i<n { if M[i*M_STRIDE+F_CIPHER]==term { c=c+1 } i=i+1 } 74 return c 75} 76func visible(expiry: i64, now: i64) -> i64 { // disappearing TTL 77 if expiry==0 { return 1 } 78 if now<expiry { return 1 } 79 return 0 80} 81 82func tcheck(pass: i64, label: *u8, fails: *i64) -> i64 { 83 sw(" " as *u8); sw(label); sw(": " as *u8) 84 if pass==1 { sw("PASS\n" as *u8) } else { sw("FAIL\n" as *u8); fails[0]=fails[0]+1 } 85 return 0 86} 87 88func main() -> i64 { 89 let fails: *i64 = sys_mmap(16) as *i64 90 fails[0]=0 91 let key: i64 = 50 92 let M: *i64 = sys_mmap(512) as *i64 93 // [id, sender, cipher=content+key, reply_to, fwd_from, mention_mask, expiry, deleted] 94 M[0*M_STRIDE+F_ID]=1; M[0*M_STRIDE+F_SENDER]=1; M[0*M_STRIDE+F_CIPHER]=M_MAGIC_9001+key; M[0*M_STRIDE+F_REPLY]=0; M[0*M_STRIDE+F_FWD]=0; M[0*M_STRIDE+F_MENT]=4; M[0*M_STRIDE+F_EXP]=0; M[0*M_STRIDE+F_DEL]=0 // mentions uid2 (bit2=4) 95 M[1*M_STRIDE+F_ID]=2; M[1*M_STRIDE+F_SENDER]=2; M[1*M_STRIDE+F_CIPHER]=M_MAGIC_9002+key; M[1*M_STRIDE+F_REPLY]=1; M[1*M_STRIDE+F_FWD]=0; M[1*M_STRIDE+F_MENT]=0; M[1*M_STRIDE+F_EXP]=0; M[1*M_STRIDE+F_DEL]=0 // reply to id1 96 M[2*M_STRIDE+F_ID]=3; M[2*M_STRIDE+F_SENDER]=1; M[2*M_STRIDE+F_CIPHER]=M_MAGIC_9003+key; M[2*M_STRIDE+F_REPLY]=1; M[2*M_STRIDE+F_FWD]=0; M[2*M_STRIDE+F_MENT]=0; M[2*M_STRIDE+F_EXP]=0; M[2*M_STRIDE+F_DEL]=0 // reply to id1 97 M[3*M_STRIDE+F_ID]=4; M[3*M_STRIDE+F_SENDER]=3; M[3*M_STRIDE+F_CIPHER]=M_MAGIC_9001+key; M[3*M_STRIDE+F_REPLY]=0; M[3*M_STRIDE+F_FWD]=1; M[3*M_STRIDE+F_MENT]=0; M[3*M_STRIDE+F_EXP]=0; M[3*M_STRIDE+F_DEL]=0 // forwarded from sender1 98 M[4*M_STRIDE+F_ID]=5; M[4*M_STRIDE+F_SENDER]=2; M[4*M_STRIDE+F_CIPHER]=M_MAGIC_9005+key; M[4*M_STRIDE+F_REPLY]=0; M[4*M_STRIDE+F_FWD]=0; M[4*M_STRIDE+F_MENT]=0; M[4*M_STRIDE+F_EXP]=100; M[4*M_STRIDE+F_DEL]=0 // disappearing, expiry=100 99 let n: i64 = 5 100 101 let rs: *i64 = sys_mmap(512) as *i64 102 let rc: *i64 = sys_mmap(16) as *i64; rc[0]=0 103 104 sw("=== nx_connect_msgx -- message breadth (reactions, threads, forward, mentions, pin, search, TTL) ===\n" as *u8) 105 sw("-- gate checks --\n" as *u8) 106 107 // T1 reactions toggle 108 let r_add1: i64 = react_toggle(rs,rc, 1, 2, EMOJI_HEART) // user2 hearts msg1 109 let r_add2: i64 = react_toggle(rs,rc, 1, 3, EMOJI_HEART) // user3 hearts msg1 110 let cnt2: i64 = react_count(rs, rc[0], 1, EMOJI_HEART) 111 let r_off: i64 = react_toggle(rs,rc, 1, 2, EMOJI_HEART) // user2 un-hearts (toggle) 112 let cnt1: i64 = react_count(rs, rc[0], 1, EMOJI_HEART) 113 var t1: i64=0; if r_add1==1 { if r_add2==1 { if cnt2==2 { if r_off==0 { if cnt1==1 { t1=1 } } } } } 114 tcheck(t1, "T1 reactions (toggle add/remove, per-user count)" as *u8, fails) 115 116 // T2 reply/threads 117 var t2: i64=0; if thread_count(M,n,1)==2 { t2=1 } 118 tcheck(t2, "T2 reply/threads (2 replies to root)" as *u8, fails) 119 120 // T3 forward provenance + content preserved 121 var t3: i64=0; if M[3*M_STRIDE+F_FWD]==1 { if (M[3*M_STRIDE+F_CIPHER]-key)==M_MAGIC_9001 { t3=1 } } 122 tcheck(t3, "T3 forward (provenance kept, content preserved)" as *u8, fails) 123 124 // T4 mentions 125 var t4: i64=0; if bit_set(M[0*M_STRIDE+F_MENT],2)==1 { if bit_set(M[0*M_STRIDE+F_MENT],3)==0 { t4=1 } } 126 tcheck(t4, "T4 @mentions (uid2 mentioned, uid3 not)" as *u8, fails) 127 128 // T5 pinned (admin-gated) 129 let pset: *i64 = sys_mmap(64) as *i64 130 let pc: *i64 = sys_mmap(16) as *i64; pc[0]=0 131 let pin_mem: i64 = pin_add(pset,pc, ROLE_MEMBER, 1) // member cannot pin 132 let pin_adm: i64 = pin_add(pset,pc, ROLE_ADMIN, 1) // admin pins 133 var t5: i64=0; if pin_mem==0 { if pin_adm==1 { if is_pinned(pset,pc[0],1)==1 { if is_pinned(pset,pc[0],3)==0 { t5=1 } } } } 134 tcheck(t5, "T5 pinned (admin-gated; pin/unpin state)" as *u8, fails) 135 136 // T6 full-text search: client finds, server (content-blind) finds nothing 137 let cli: i64 = client_search(M, n, key, M_MAGIC_9003) 138 let srv: i64 = server_search(M, n, M_MAGIC_9003) 139 var t6: i64=0; if cli==1 { if srv==0 { t6=1 } } 140 tcheck(t6, "T6 search is client-side by content-blind design (client=1, server=0)" as *u8, fails) 141 142 // T7 disappearing TTL 143 var t7: i64=0; if visible(M[4*M_STRIDE+F_EXP],50)==1 { if visible(M[4*M_STRIDE+F_EXP],150)==0 { t7=1 } } 144 tcheck(t7, "T7 disappearing messages (visible before TTL, gone after)" as *u8, fails) 145 146 sw(" fails=" as *u8); sn(fails[0]); sw("\n" as *u8) 147 if fails[0]==0 { sw("VERDICT: GREEN (message breadth: reactions/threads/forward/mentions/pin/search/TTL all correct)\n" as *u8); sys_exit(0) } 148 sw("VERDICT: RED\n" as *u8) 149 sys_exit(1) 150 return 1 151}