nx_gif_boundary_gate_t139.nx source
↩ module page · 120 lines · 10655 B
1// nx_gif_boundary_gate_t139.nx -- Generates a 4x4 GIF image with a hashed pixel sequence and verifies its SHA-256 digest against expected values.
2import "nx_syscalls.nx"
3import "nx_gate_verdict.nx"
4import "nx_sha256.nx"
5import "nx_gif_decode_t139.nx"
6// append one 3-bit LZW code, LSB-first (GIF bit order); buf must be zeroed (OR-only)
7func gg_putcode(buf: *u8, bitpos: *i64, code: i64) -> i64 {
8 var i: i64=0
9 while i<3 {
10 let bit: i64=(code>>i)&1
11 let bp: i64=bitpos[0]
12 if bit==1 { let by: i64=bp/8; let bo: i64=bp%8; buf[by]=((buf[by] as i64)|(1<<bo)) as u8 }
13 bitpos[0]=bitpos[0]+1
14 i=i+1
15 }
16 return 0
17}
18
19// build a 4x4 GIF89a with a 4-entry GCT (red,green,blue,white) whose pixel-index
20// STORAGE sequence is pixseq[16]; interlaced sets descriptor bit 6. returns length.
21func gg_build_gif(out: *u8, pixseq: *u8, interlaced: i64) -> i64 {
22 out[0]=0x47 as u8; out[1]=0x49 as u8; out[2]=0x46 as u8
23 out[3]=0x38 as u8; out[4]=0x39 as u8; out[5]=0x61 as u8
24 out[6]=4 as u8; out[7]=0 as u8; out[8]=4 as u8; out[9]=0 as u8
25 out[10]=0x81 as u8; out[11]=0 as u8; out[12]=0 as u8
26 out[13]=255 as u8; out[14]=0 as u8; out[15]=0 as u8
27 out[16]=0 as u8; out[17]=255 as u8; out[18]=0 as u8
28 out[19]=0 as u8; out[20]=0 as u8; out[21]=255 as u8
29 out[22]=255 as u8; out[23]=255 as u8; out[24]=255 as u8
30 var o: i64=25
31 out[o]=0x2C as u8
32 out[o+1]=0 as u8; out[o+2]=0 as u8; out[o+3]=0 as u8; out[o+4]=0 as u8
33 out[o+5]=4 as u8; out[o+6]=0 as u8; out[o+7]=4 as u8; out[o+8]=0 as u8
34 if interlaced==1 { out[o+9]=0x40 as u8 } else { out[o+9]=0 as u8 }
35 o=o+10
36 out[o]=2 as u8; o=o+1
37 let lzbuf: *u8=sys_mmap(256)
38 let bitpos: *i64=sys_mmap(8) as *i64
39 bitpos[0]=0
40 var p: i64=0
41 while p<16 { gg_putcode(lzbuf,bitpos,4); gg_putcode(lzbuf,bitpos,pixseq[p] as i64); p=p+1 }
42 gg_putcode(lzbuf,bitpos,5)
43 let nbytes: i64=(bitpos[0]+7)/8
44 out[o]=nbytes as u8; o=o+1
45 var q: i64=0
46 while q<nbytes { out[o]=lzbuf[q]; o=o+1; q=q+1 }
47 out[o]=0 as u8; o=o+1
48 out[o]=0x3B as u8; o=o+1
49 return o
50}
51
52
53func gb_hash(raw: *u8, n: i64, expected: *u8) -> i64 {
54 let wn: i64=sha256_workspace_bytes(); let ws: *u8=gif_own(wn+64)
55 if ws==(0 as *u8) { return 0 }
56 let digest: *u8=((ws as i64)+wn) as *u8
57 var ok: i64=1
58 if sha256_init_workspace(ws,wn)!=0 { ok=0 } else { sha256_update(ws as *Sha256,raw,n); sha256_final(ws as *Sha256,digest)
59 let hex: *u8="0123456789abcdef";var i: i64=0;while i<32 { let v: i64=digest[i] as i64;if hex[v>>4]!=expected[i*2] || hex[v&15]!=expected[i*2+1] { ok=0 } i=i+1 }
60 }
61 if gif_release(ws,wn+64)!=0 { ok=0 } return ok
62}
63func gb_pages() -> i64 {
64 let buf: *u8=gif_own(512);if buf==(0 as *u8) { return 0-1 }
65 let fd: i64=sys_openat_rd("/proc/self/statm");if fd<0 { gif_release(buf,512);return 0-1 }
66 let n: i64=sys_read(fd,buf,511);let rc: i64=sys_close(fd);var value: i64=0;var i: i64=0
67 if n<=0 || rc!=0 { gif_release(buf,512);return 0-1 }
68 while i<n {let c: i64=buf[i] as i64;if c<48 || c>57 {break}value=value*10+c-48;i=i+1}
69 if gif_release(buf,512)!=0 {return 0-1}return value
70}
71func main() -> i64 {
72 let ctr: *i64=gv_ctr();gv_head("GIF bounded first-image decoder; original-pixel differential gate")
73 let raw: *u8=sys_mmap(512);let seq: *u8=sys_mmap(32);var i: i64=0;while i<16{seq[i]=(i/4) as u8;i=i+1}
74 let n: i64=gg_build_gif(raw,seq,0);let wh: *i64=sys_mmap(32) as *i64;let info: *i64=sys_mmap(128) as *i64
75 let rgb: *u8=gif_decode_rgb(raw,n,wh);var ok: i64=0;if rgb!=(0 as *u8){if wh[0]==4 && wh[1]==4{if rgb[0]==(255 as u8) && rgb[1]==(0 as u8) && rgb[2]==(0 as u8) && rgb[15]==(0 as u8) && rgb[16]==(255 as u8){ok=1}}}
76 gv_check("opaque palette KAT",ok,ctr)
77 let gray: *u8=gif_decode(raw,n,wh);ok=0;if gray!=(0 as *u8){if gray[0]==(53 as u8) && gray[5]==(182 as u8) && gray[10]==(18 as u8) && gray[15]==(255 as u8){ok=1}}
78 gv_check("historic gray exact coefficients",ok,ctr);sys_munmap(gray,32)
79 let interraw: *u8=sys_mmap(512);i=0;while i<4{seq[i]=0 as u8;seq[4+i]=2 as u8;seq[8+i]=1 as u8;seq[12+i]=3 as u8;i=i+1}
80 let ni: i64=gg_build_gif(interraw,seq,1);let interrgb: *u8=gif_decode_rgb(interraw,ni,wh);ok=0;if rgb!=(0 as *u8) && interrgb!=(0 as *u8){ok=1;i=0;while i<48{if rgb[i]!=interrgb[i]{ok=0}i=i+1}}
81 gv_check("interlaced wire differs display pixels identical",ok,ctr);sys_munmap(interrgb,64);sys_munmap(rgb,64)
82 var refused: i64=0;i=0;while i<n-1{let p: *u8=gif_decode_rgba_checked(raw,i,wh,info);if p==(0 as *u8){refused=refused+1}else{gif_release(p,wh[0]*wh[1]*4)}i=i+1}
83 gv_check("every incomplete first-image prefix refuses",refused==n-1,ctr)
84 let saved: u8=raw[4];raw[4]=0x30 as u8;var bad: *u8=gif_decode_rgb(raw,n,wh);gv_check("full GIF version signature enforced",bad==(0 as *u8),ctr);raw[4]=saved
85 raw[35]=255 as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("mincode255 refused before dictionary init",bad==(0 as *u8),ctr);raw[35]=1 as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("mincode1 refused",bad==(0 as *u8),ctr);raw[35]=2 as u8
86 let oldbyte: u8=raw[37];raw[37]=0x3c as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("future dictionary code refused",bad==(0 as *u8),ctr);raw[37]=oldbyte
87 raw[37]=0 as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("extra initial literal does not silently overfill image",bad==(0 as *u8),ctr);raw[37]=oldbyte
88 raw[6]=1 as u8;raw[8]=1 as u8;raw[30]=1 as u8;raw[32]=1 as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("excess decoded pixels refused not clipped",bad==(0 as *u8),ctr);raw[6]=4 as u8;raw[8]=4 as u8;raw[30]=4 as u8;raw[32]=4 as u8
89
90 let ext: *u8=sys_mmap(512);i=0;while i<25{ext[i]=raw[i];i=i+1}ext[25]=0x21 as u8;ext[26]=0xf9 as u8;ext[27]=4 as u8;ext[28]=5 as u8;ext[29]=5 as u8;ext[30]=0 as u8;ext[31]=0 as u8;ext[32]=0 as u8;i=25;while i<n{ext[i+8]=raw[i];i=i+1}
91 let alpha: *u8=gif_decode_rgba_checked(ext,n+8,wh,info);ok=0;if alpha!=(0 as *u8){if alpha[3]==(0 as u8) && alpha[19]==(255 as u8) && alpha[16]==(0 as u8) && alpha[17]==(255 as u8){ok=1}}
92 gv_check("RGBA exposes first-image transparency without discarding palette colour",ok==1 && info[8]==0 && info[9]==5,ctr);gif_release(alpha,64)
93 bad=gif_decode_rgb(ext,n+8,wh);gv_check("legacy RGB refuses required alpha rather than fabricate black/red matte",bad==(0 as *u8) && wh[0]==0 && wh[1]==0,ctr)
94 ext[32]=1 as u8;bad=gif_decode_rgb(ext,n+8,wh);gv_check("malformed graphics-control terminator refused",bad==(0 as *u8),ctr)
95 raw[6]=6 as u8;raw[8]=6 as u8;raw[26]=1 as u8;raw[28]=1 as u8
96 let rect: *u8=gif_decode_rgba_checked(raw,n,wh,info);gv_check("checked rectangle preserves offsets and logical canvas metadata",rect!=(0 as *u8) && wh[0]==4 && wh[1]==4 && info[10]==1 && info[11]==1 && info[12]==6 && info[13]==6,ctr);gif_release(rect,64)
97 bad=gif_decode_rgb(raw,n,wh);gv_check("legacy RGB refuses unimplemented canvas composition",bad==(0 as *u8),ctr);raw[6]=4 as u8;raw[8]=4 as u8;raw[26]=0 as u8;raw[28]=0 as u8
98 raw[37]=0x2c as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("early EOI with too few pixels refused",bad==(0 as *u8),ctr);raw[37]=oldbyte
99 let lastcode: u8=raw[n-3];raw[n-3]=0 as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("missing EOI refused despite enough pixels",bad==(0 as *u8),ctr);raw[n-3]=lastcode
100 let local: *u8=sys_mmap(512);i=0;while i<13{local[i]=raw[i];i=i+1}local[10]=0 as u8;i=0;while i<10{local[13+i]=raw[25+i];i=i+1}local[22]=0x81 as u8;i=0;while i<12{local[23+i]=raw[13+i];i=i+1}i=35;while i<n{local[i]=raw[i];i=i+1}
101 let lr: *u8=gif_decode_rgb(local,n,wh);ok=0;if lr!=(0 as *u8){if lr[0]==(255 as u8) && lr[16]==(255 as u8) && lr[32]==(255 as u8){ok=1}}
102 gv_check("local colour table selected with no global table",ok,ctr);sys_munmap(lr,64)
103 local[22]=0x80 as u8;i=35;while i<n{local[i-6]=local[i];i=i+1}bad=gif_decode_rgb(local,n-6,wh);gv_check("decoded palette index outside table refused",bad==(0 as *u8),ctr)
104 raw[10]=0x87 as u8;bad=gif_decode_rgb(raw,n,wh);gv_check("truncated declared global table refused",bad==(0 as *u8),ctr);raw[10]=0x81 as u8
105
106 let initial_literal: *u8="\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x81\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x01\x28\x00\x3b";let literal_rgb: *u8=gif_decode_rgb(initial_literal,40,wh);ok=0;if literal_rgb!=(0 as *u8){if wh[0]==1 && wh[1]==1 && literal_rgb[0]==(255 as u8) && literal_rgb[1]==(0 as u8) && literal_rgb[2]==(0 as u8){ok=1}}gv_check("initial clear is recommendation; literal-first agrees with libvips",ok,ctr);if literal_rgb!=(0 as *u8){literal_rgb[18]=90 as u8;let warm: *u8=sys_mmap(1);gv_check("legacy output retains logical plus16 allocation and historical release",literal_rgb[18]==(90 as u8) && sys_munmap(literal_rgb,19)==0,ctr)}
107 let before: i64=gb_pages();i=0;ok=1;while i<100{let a: *u8=gif_decode_opaque_owned(raw,n,wh,3);if a==(0 as *u8){ok=0}else{if gif_release(a,48)!=0{ok=0}}raw[37]=0x3c as u8;let b: *u8=gif_decode_opaque_owned(raw,n,wh,3);if b!=(0 as *u8){ok=0;gif_release(b,48)}raw[37]=oldbyte;i=i+1}let after: i64=gb_pages()
108 gv_puts("scratch pages before=");gv_num(before);gv_puts(" after=");gv_num(after);gv_puts("\n");gv_check("100 success/failure cycles retain no mapped scratch pages",ok==1 && before>0 && before==after,ctr)
109 let lb: *i64=sys_mmap(16) as *i64;let original: *u8=sys_read_file("/tmp/strut-2d17175184e088f9.gif",lb)
110 ok=0;if original!=(0 as *u8){ok=gb_hash(original,lb[0],"2d17175184e088f93cff9f165644c93f0a9bbfb77757ae154d28e5602b747811")}
111 gv_check("original1339248B identity pinned",ok==1 && lb[0]==1339248,ctr)
112 let rgba: *u8=gif_decode_rgba_checked(original,lb[0],wh,info);ok=0;if rgba!=(0 as *u8){ok=gb_hash(rgba,wh[0]*wh[1]*4,"0ded56809f61d65a9a4d343d10525372240cc9a98a4e49d284209e238697f1f2")}
113 gv_check("original first-frame RGBA equals independent libvips pixel bytes",ok==1 && wh[0]==268 && wh[1]==402,ctr)
114 gv_check("first-frame metadata delay5cs disposal1 offset0 explicit",info[9]==5 && info[14]==1 && info[10]==0 && info[11]==0 && info[15]==GIF_OK_FIRST_IMAGE,ctr);gif_release(rgba,430944)
115 let realrgb: *u8=gif_decode_rgb(original,lb[0],wh);ok=0;if realrgb!=(0 as *u8){ok=gb_hash(realrgb,wh[0]*wh[1]*3,"54196d195b2efe55a593b36c6420868120b3e6426063239b36b00e648d61dc61")}
116 gv_check("original RGB equals independent first-frame RGB",ok,ctr);sys_munmap(realrgb,323224)
117 let realgray: *u8=gif_decode(original,lb[0],wh);ok=0;if realgray!=(0 as *u8){ok=gb_hash(realgray,wh[0]*wh[1],"0da7efd29b40b60fb8acc590580e029440479a2b129bee55c5f31c12ae905923")}
118 gv_check("original gray equals independent RGB plus historic transform",ok,ctr);sys_munmap(realgray,107752)
119 let rc: i64=gv_verdict("GIF-BOUNDARY-GATE",ctr,"first image only; no animation playback/compositing claim");return rc
120}