From c2a28e43ff64fa1cdfe90c8e67630a2086c43b3a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 25 Sep 2026 22:23:40 +0000 Subject: [PATCH 1/4] proof: the wide PNG encodings write stored blocks of 65535 bytes enc.pour and enc.rgb.go write the blocks enc.feed writes, with the IDAT CRC run and Adler-32, and enc.nblk counts them; U32.div and U32.mod read as Nat. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A1bVZYFbhKkn2BKHKthcVP --- proof/wp11-png-finish.bend | 3119 ++++++++++++++++++++++++++++++++++++ 1 file changed, 3119 insertions(+) create mode 100644 proof/wp11-png-finish.bend diff --git a/proof/wp11-png-finish.bend b/proof/wp11-png-finish.bend new file mode 100644 index 0000000..927e9a1 --- /dev/null +++ b/proof/wp11-png-finish.bend @@ -0,0 +1,3119 @@ +# proof/wp11-png-finish: lemmas for the PNG encodings past one stored block +# (IMG-PNG-2) and for ancillary chunks in the chunk walker (IMG-PNG-9). Each +# is a law proved here, or a def whose type is the fact it proves; PROOF.bend +# imports this file, so the gate checks it. No number near 2^29 or 2^32 is +# written as a Nat: the checker holds a Nat in unary. +import Base +import ../LAWS.bend as Laws +import ../main.bend as Img +import ../src/crc.bend as Crc +import ../src/png.bend as Png +import ../src/inflate.bend as Inf +import ./u32.bend as U32L +import ./wp1-crc.bend as Wp1 +import ./wp2-inflate.bend as Wp2 +import ./wp6-raster.bend as R +import ./wp9-png-roundtrip.bend as W9 + +# ---- A. U32 and Nat facts ---- + +# U32s of the same value are the same U32 +def u32.same(+uu: U32, +vv: U32, en: {U32.to_nat(uu) == U32.to_nat(vv) : Nat}) -> {uu == vv : U32}: + U32L.ueq(uu, vv, Equal.trans(Bool, U32.is_eq(uu, vv), Nat.is_eq(U32.to_nat(vv), U32.to_nat(vv)), True{}, + Equal.trans(Bool, U32.is_eq(uu, vv), Nat.is_eq(U32.to_nat(uu), U32.to_nat(vv)), Nat.is_eq(U32.to_nat(vv), + U32.to_nat(vv)), R.u32_eq(uu, vv), Equal.cong(Nat, Bool, kk => Nat.is_eq(kk, U32.to_nat(vv)), U32.to_nat(uu), + U32.to_nat(vv), en)), + R.nat_eq_refl(U32.to_nat(vv)))) + +# a U32 is_zero calls zero is worth 0 +def zero.val(+uu: U32, ez: {True{} == U32.is_zero(uu) : Bool}) -> {U32.to_nat(uu) == 0n : Nat}: + Equal.cong(U32, Nat, xx => U32.to_nat(xx), uu, 0, U32L.ueq(uu, 0, Equal.sym(Bool, True{}, U32.is_zero(uu), ez))) + +# a U32 worth 0 is zero +def zero.is(+uu: U32, e0: {U32.to_nat(uu) == 0n : Nat}) -> {U32.is_zero(uu) == True{} : Bool}: + Equal.trans(Bool, U32.is_zero(uu), Nat.is_eq(U32.to_nat(uu), 0n), True{}, R.u32_eq(uu, 0), + Equal.cong(Nat, Bool, kk => Nat.is_eq(kk, 0n), U32.to_nat(uu), 0n, e0)) + +# a U32 is_eq calls 1 is worth 1 +def one.val(+uu: U32, e1: {True{} == U32.is_eq(uu, 1) : Bool}) -> {U32.to_nat(uu) == 1n : Nat}: + Equal.cong(U32, Nat, xx => U32.to_nat(xx), uu, 1, U32L.ueq(uu, 1, Equal.sym(Bool, True{}, U32.is_eq(uu, 1), e1))) + +# a U32 above some successor's predecessor is not zero, once is_zero's answer is named +def pos.at( + zz: Bool, + +uu: U32, + +kk: Nat, + +ez: {U32.is_zero(uu) == zz : Bool}, + +hh: {Nat.is_le(1n+kk, U32.to_nat(uu)) == True{} : Bool} +) -> {U32.is_zero(uu) == False{} : Bool}: + match zz: + case False{}: + ez + case True{}: + +e0 = {zero.val(uu, Equal.sym(Bool, U32.is_zero(uu), True{}, ez)) : {U32.to_nat(uu) == 0n : Nat}} + Empty.absurd({U32.is_zero(uu) == False{} : Bool}, U32L.false_true(Equal.trans(Bool, False{}, + Nat.is_le(1n+kk, U32.to_nat(uu)), True{}, Equal.sym(Bool, Nat.is_le(1n+kk, U32.to_nat(uu)), False{}, + Equal.cong(Nat, Bool, xx => Nat.is_le(1n+kk, xx), U32.to_nat(uu), 0n, e0)), hh))) + +# a U32 at least a successor is not zero +def pos(+uu: U32, +kk: Nat, hh: {Nat.is_le(1n+kk, U32.to_nat(uu)) == True{} : Bool}) -> {U32.is_zero(uu) == False{} : + Bool}: + pos.at(U32.is_zero(uu), uu, kk, {==}, hh) + +# a U32 neither 0 nor 1 less one is not zero, once is_zero's answer is named +def two.at( + zz: Bool, + +uu: U32, + +ez: {U32.is_zero((uu - 1 : U32)) == zz : Bool}, + +hz: {False{} == U32.is_zero(uu) : Bool}, + +h1: {False{} == U32.is_eq(uu, 1) : Bool} +) -> {U32.is_zero((uu - 1 : U32)) == False{} : Bool}: + match zz: + case False{}: + ez + case True{}: + +e0 = {zero.val((uu - 1 : U32), Equal.sym(Bool, U32.is_zero((uu - 1 : U32)), True{}, ez)) : + {U32.to_nat((uu - 1 : U32)) == 0n : Nat}} + +e1 = {Equal.trans(Nat, U32.to_nat(uu), 1n+U32.to_nat((uu - 1 : U32)), 1n, Wp1.u32_dec(uu, Equal.sym(Bool, + False{}, U32.is_zero(uu), hz)), Equal.cong(Nat, Nat, kk => 1n+kk, U32.to_nat((uu - 1 : U32)), 0n, e0)) : + {U32.to_nat(uu) == 1n : Nat}} + Empty.absurd({U32.is_zero((uu - 1 : U32)) == False{} : Bool}, U32L.false_true(Equal.trans(Bool, False{}, + U32.is_eq(uu, 1), True{}, h1, Equal.trans(Bool, U32.is_eq(uu, 1), Nat.is_eq(U32.to_nat(uu), 1n), True{}, + R.u32_eq(uu, 1), Equal.cong(Nat, Bool, kk => Nat.is_eq(kk, 1n), U32.to_nat(uu), 1n, e1))))) + +# a U32 neither 0 nor 1, less one, is not zero +def two( + +uu: U32, + +hz: {False{} == U32.is_zero(uu) : Bool}, + +h1: {False{} == U32.is_eq(uu, 1) : Bool} +) -> {U32.is_zero((uu - 1 : U32)) == False{} : Bool}: + two.at(U32.is_zero((uu - 1 : U32)), uu, {==}, hz, h1) + +# not at most is above +def nle.lt(aa: Nat, bb: Nat, hh: {Nat.is_le(aa, bb) == False{} : Bool}) -> {Nat.is_lt(bb, aa) == True{} : Bool}: + match aa bb: + case 0n bb0: + Empty.absurd({Nat.is_lt(bb0, 0n) == True{} : Bool}, U32L.false_true(Equal.trans(Bool, False{}, Nat.is_le(0n, bb0), + True{}, Equal.sym(Bool, Nat.is_le(0n, bb0), False{}, hh), R.le_zero(bb0)))) + case 1n+_ap 0n: + {==} + case 1n+ap 1n+bp: + nle.lt(ap, bp, hh) + +# one more on the left of a sum, one less on the right: the same sum +def shift( + +aa: Nat, + +uu: U32, + +vv: U32, + +nn: Nat, + +ev: {U32.to_nat(uu) == 1n+U32.to_nat(vv) : Nat}, + +ee: {Nat.add(aa, U32.to_nat(uu)) == nn : Nat} +) -> {Nat.add(1n+aa, U32.to_nat(vv)) == nn : Nat}: + Equal.trans(Nat, 1n+Nat.add(aa, U32.to_nat(vv)), Nat.add(aa, U32.to_nat(uu)), nn, + Equal.trans(Nat, 1n+Nat.add(aa, U32.to_nat(vv)), Nat.add(aa, 1n+U32.to_nat(vv)), Nat.add(aa, U32.to_nat(uu)), + Equal.sym(Nat, Nat.add(aa, 1n+U32.to_nat(vv)), 1n+Nat.add(aa, U32.to_nat(vv)), R.add_succ(aa, + U32.to_nat(vv))), + Equal.cong(Nat, Nat, kk => Nat.add(aa, kk), 1n+U32.to_nat(vv), U32.to_nat(uu), Equal.sym(Nat, U32.to_nat(uu), + 1n+U32.to_nat(vv), ev))), + ee) + +# a list at most cap's value long is counted in a U32 to its length +def len.of( + +xs: List<&2, U32>, + +cap: U32, + +hh: {Nat.is_le(List.length(&2, U32, xs), U32.to_nat(cap)) == True{} : Bool} +) -> {U32.to_nat(Png.enc.len(xs, 0)) == List.length(&2, U32, xs) : Nat}: + Equal.trans(Nat, U32.to_nat(Png.enc.len(xs, 0)), U32.to_nat(U32.from_nat(List.length(&2, U32, xs))), + List.length(&2, U32, xs), Equal.cong(U32, Nat, uu => U32.to_nat(uu), Png.enc.len(xs, 0), + U32.from_nat(List.length(&2, U32, xs)), W9.len.word(xs)), W9.nat.fits(List.length(&2, U32, xs), cap, hh)) + +# ---- B. enc.crc.list, and the bytes enc.pour writes ---- + +# enc.crc.list is the CRC fold and the bytes reversed onto the accumulator +def crcl( + xs: List<&2, U32>, + +cc: U32, + +acc: List<&2, U32> +) -> {Png.enc.crc.list(xs, cc, acc) == (Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) : U32 & List<&2, + U32>}: + match xs: + case Nil{}: + {==} + case +hd <> tl: + crcl(tl, Crc.crc.byte(cc, hd), hd <> acc) + +# the bytes enc.pour writes, in order: its walk without the CRC +def bs( + xs: List<&2, U32>, + znew: Bool, + zlast: Bool, + +room: U32, + +left: U32, + +len: U32, + +bf: U32 +) -> List<&2, U32>: + match xs znew zlast: + case Nil{} _z _last: + [] + case +h <> +t False{} False{}: + +room2 = (room - 1 : U32) + h <> bs(t, False{}, U32.is_eq(room2, 1), room2, (left - 1 : U32), len, bf) + case +h <> +t False{} True{}: + +left2 = (left - 1 : U32) + h <> bs(t, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2)) + case +h <> t True{} _last: + +nlen = (len .^. 65535 : U32) + +left2 = (left - 1 : U32) + +room2 = (len - 1 : U32) + bf <> Png.enc.byte(len) <> Png.enc.hi(len) <> Png.enc.byte(nlen) <> Png.enc.hi(nlen) <> h <> bs(t, + U32.is_zero(room2), U32.is_eq(room2, 1), room2, left2, Png.enc.cap(left2), Png.enc.bf(left2)) + +# enc.pour is enc.crc.list over bs +def pour.bs( + xs: List<&2, U32>, + znew: Bool, + zlast: Bool, + +room: U32, + +left: U32, + +len: U32, + +bf: U32, + +cc: U32, + +acc: List<&2, U32> +) -> {Png.enc.pour(xs, znew, zlast, room, left, len, bf, cc, acc) == Png.enc.crc.list(bs(xs, znew, zlast, room, left, + len, bf), cc, acc) : U32 & List<&2, U32>}: + match xs znew zlast: + case Nil{} _z _last: + {==} + case +h <> +t False{} False{}: + pour.bs(t, False{}, U32.is_eq((room - 1 : U32), 1), (room - 1 : U32), (left - 1 : U32), len, bf, + Crc.crc.byte(cc, h), h <> acc) + case +h <> +t False{} True{}: + +left2 = (left - 1 : U32) + pour.bs(t, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2), Crc.crc.byte(cc, h), h <> acc) + case +h <> t True{} _last: + +nlen = (len .^. 65535 : U32) + +b1 = Png.enc.byte(len) + +b2 = Png.enc.hi(len) + +b3 = Png.enc.byte(nlen) + +b4 = Png.enc.hi(nlen) + +c1 = Crc.crc.byte(cc, bf) + +c2 = Crc.crc.byte(c1, b1) + +c3 = Crc.crc.byte(c2, b2) + +c4 = Crc.crc.byte(c3, b3) + +c5 = Crc.crc.byte(c4, b4) + +left2 = (left - 1 : U32) + +room2 = (len - 1 : U32) + pour.bs(t, U32.is_zero(room2), U32.is_eq(room2, 1), room2, left2, Png.enc.cap(left2), Png.enc.bf(left2), + Crc.crc.byte(c5, h), h <> b4 <> b3 <> b2 <> b1 <> bf <> acc) + +# ---- C. bs against enc.feed, byte by byte ---- + +# The block size, 65535, is named mx here and its value is U32.to_nat(mx): a +# closed Nat as large as 65535 in a type is expanded in unary and overflows +# the checker's stack. Each lemma takes mx with {mx == 65535 : U32}. + +# where the open block stands against the nx bytes still to come: a final +# block holds them all, rp their count; any other block is full, its room the +# feed's, and more bytes follow it +def fin.ok(fin: Bool, +rp: U32, +rf: U32, +nx: Nat) -> Type: + match fin: + case True{}: + {U32.to_nat(rp) == nx : Nat} + case False{}: + {U32.to_nat(rp) == U32.to_nat(rf) : Nat} & {Nat.is_lt(U32.to_nat(rp), nx) == True{} : Bool} + +# at a block boundary the walk carries the next block's length and BFINAL +def at.edge(+rp: U32, +left: U32, +plen: U32, +pbf: U32) -> Type: + {U32.is_zero(rp) == True{} : Bool} -> {plen == Png.enc.cap(left) : U32} & {pbf == Png.enc.bf(left) : U32} + +# what sim proves: the open block's header, the block so far, then the rest +# of bs are enc.feed's blocks of mx bytes +def sim.ty( + +xs: List<&2, U32>, + +znew: Bool, + +zlast: Bool, + +zf: Bool, + +fin: Bool, + +acc: List<&2, U32>, + +rf: U32, + +rp: U32, + +left: U32, + +plen: U32, + +pbf: U32, + +ll: U32, + +mx: U32 +) -> Type: + {List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, U32, acc, bs(xs, znew, zlast, + rp, left, plen, pbf))) == Png.enc.feed(xs, zf, rf, mx, acc) : List<&2, U32>} + +# one byte less on both sides of fin.ok +def fo.dec( + fin: Bool, + +rp: U32, + +rf: U32, + +rp2: U32, + +rf2: U32, + +nt: Nat, + +ep: {U32.to_nat(rp) == 1n+U32.to_nat(rp2) : Nat}, + +ef: {U32.to_nat(rf) == 1n+U32.to_nat(rf2) : Nat}, + hf: fin.ok(fin, rp, rf, 1n+nt) +) -> fin.ok(fin, rp2, rf2, nt): + match fin: + case True{}: + Wp1.succ_inj(U32.to_nat(rp2), nt, Equal.trans(Nat, 1n+U32.to_nat(rp2), U32.to_nat(rp), 1n+nt, Equal.sym(Nat, + U32.to_nat(rp), 1n+U32.to_nat(rp2), ep), hf)) + case False{}: + (e_rr, h_lt) = hf + +e2 = {Wp1.succ_inj(U32.to_nat(rp2), U32.to_nat(rf2), Equal.trans(Nat, 1n+U32.to_nat(rp2), U32.to_nat(rp), + 1n+U32.to_nat(rf2), Equal.sym(Nat, U32.to_nat(rp), 1n+U32.to_nat(rp2), ep), Equal.trans(Nat, U32.to_nat(rp), + U32.to_nat(rf), 1n+U32.to_nat(rf2), e_rr, ef))) : {U32.to_nat(rp2) == U32.to_nat(rf2) : Nat}} + +l2 = {Equal.trans(Bool, Nat.is_lt(1n+U32.to_nat(rp2), 1n+nt), Nat.is_lt(U32.to_nat(rp), 1n+nt), True{}, + Equal.cong(Nat, Bool, kk => Nat.is_lt(kk, 1n+nt), 1n+U32.to_nat(rp2), U32.to_nat(rp), Equal.sym(Nat, + U32.to_nat(rp), 1n+U32.to_nat(rp2), ep)), h_lt) : {Nat.is_lt(U32.to_nat(rp2), nt) == True{} : Bool}} + (e2, l2) + +# enc.cap.at with the block size named +def capm(zz: Bool, +left: U32, +mx: U32) -> U32: + match zz: + case True{}: + left + case False{}: + mx + +# enc.cap.at is capm at 65535 +def cap.m(zz: Bool, +left: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> {Png.enc.cap.at(zz, left) == capm(zz, left, mx) : + U32}: + match zz: + case True{}: + {==} + case False{}: + Equal.sym(U32, mx, 65535, emx) + +# the block size is not zero +def mx.nz(+mx: U32, +emx: {mx == 65535 : U32}) -> {U32.is_zero(mx) == False{} : Bool}: + Equal.cong(U32, Bool, uu => U32.is_zero(uu), mx, 65535, emx) + +# at most 65535 is at most the block size +def le.mx(+left: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> {U32.is_le(left, mx) == U32.is_le(left, 65535) : Bool}: + Equal.cong(U32, Bool, uu => U32.is_le(left, uu), mx, 65535, emx) + +# a new block's length is not zero when bytes are left +def cap.nz( + zz: Bool, + +left: U32, + +mx: U32, + +kk: Nat, + +nzm: {U32.is_zero(mx) == False{} : Bool}, + +hn: {U32.to_nat(left) == 1n+kk : Nat} +) -> {U32.is_zero(capm(zz, left, mx)) == False{} : Bool}: + match zz: + case True{}: + Wp1.u32_nonzero(left, kk, hn) + case False{}: + nzm + +# a new block's room after its first byte is within the feed's +def cap.le( + zz: Bool, + +left: U32, + +mx: U32, + +kk: Nat, + +nzm: {U32.is_zero(mx) == False{} : Bool}, + +ez: {U32.is_le(left, mx) == zz : Bool}, + +hn: {U32.to_nat(left) == 1n+kk : Nat} +) -> {Nat.is_le(U32.to_nat((capm(zz, left, mx) - 1 : U32)), U32.to_nat((mx - 1 : U32))) == True{} : Bool}: + match zz: + case True{}: + +l1 = (left - 1 : U32) + +m1 = (mx - 1 : U32) + +e_l = {Wp1.u32_dec(left, Wp1.u32_nonzero(left, kk, hn)) : {U32.to_nat(left) == 1n+U32.to_nat(l1) : Nat}} + +e_m = {Wp1.u32_dec(mx, nzm) : {U32.to_nat(mx) == 1n+U32.to_nat(m1) : Nat}} + +h0 = {Equal.trans(Bool, Nat.is_le(U32.to_nat(left), U32.to_nat(mx)), U32.is_le(left, mx), True{}, + Equal.sym(Bool, U32.is_le(left, mx), Nat.is_le(U32.to_nat(left), U32.to_nat(mx)), R.u32_le(left, mx)), ez) : + {Nat.is_le(U32.to_nat(left), U32.to_nat(mx)) == True{} : Bool}} + R.le_rw_r(1n+U32.to_nat(l1), U32.to_nat(mx), 1n+U32.to_nat(m1), e_m, R.le_rw_l(U32.to_nat(left), + 1n+U32.to_nat(l1), U32.to_nat(mx), e_l, h0)) + case False{}: + R.le_refl(U32.to_nat((mx - 1 : U32))) + +# where a new block stands: final when the bytes left fit, else full +def cap.fo( + zz: Bool, + +left: U32, + +mx: U32, + +kk: Nat, + +nzm: {U32.is_zero(mx) == False{} : Bool}, + +ez: {U32.is_le(left, mx) == zz : Bool}, + +hn: {U32.to_nat(left) == 1n+kk : Nat} +) -> fin.ok(zz, (capm(zz, left, mx) - 1 : U32), (mx - 1 : U32), kk): + match zz: + case True{}: + Wp1.u32_pred(left, kk, hn) + case False{}: + +m1 = (mx - 1 : U32) + +e_m = {Wp1.u32_dec(mx, nzm) : {U32.to_nat(mx) == 1n+U32.to_nat(m1) : Nat}} + +h0 = {Equal.trans(Bool, Nat.is_le(1n+kk, 1n+U32.to_nat(m1)), U32.is_le(left, mx), False{}, + Equal.sym(Bool, U32.is_le(left, mx), Nat.is_le(1n+kk, 1n+U32.to_nat(m1)), Equal.trans(Bool, + U32.is_le(left, mx), Nat.is_le(U32.to_nat(left), U32.to_nat(mx)), Nat.is_le(1n+kk, 1n+U32.to_nat(m1)), + R.u32_le(left, mx), Equal.trans(Bool, Nat.is_le(U32.to_nat(left), U32.to_nat(mx)), Nat.is_le(1n+kk, + U32.to_nat(mx)), Nat.is_le(1n+kk, 1n+U32.to_nat(m1)), Equal.cong(Nat, Bool, xx => Nat.is_le(xx, + U32.to_nat(mx)), U32.to_nat(left), 1n+kk, hn), Equal.cong(Nat, Bool, xx => Nat.is_le(1n+kk, xx), + U32.to_nat(mx), 1n+U32.to_nat(m1), e_m)))), ez) : {Nat.is_le(kk, U32.to_nat(m1)) == False{} : Bool}} + ({==}, nle.lt(kk, U32.to_nat(m1), h0)) + +# fin.ok of enc.cap.at's room from capm's +def fo.cm( + +zz: Bool, + +left: U32, + +mx: U32, + +nt: Nat, + +emx: {mx == 65535 : U32}, + hh: fin.ok(zz, (capm(zz, left, mx) - 1 : U32), (mx - 1 : U32), nt) +) -> fin.ok(zz, (Png.enc.cap.at(zz, left) - 1 : U32), (mx - 1 : U32), nt): + %Equal.sym(U32, Png.enc.cap.at(zz, left), capm(zz, left, mx), cap.m(zz, left, mx, emx)) : fin.ok(zz, (_ - 1 : U32), + (mx - 1 : U32), nt) + hh + +# the header bs writes at a new block is enc.head's for the block's BFINAL +def hdr( + zz: Bool, + +left: U32, + +rest: List<&2, U32> +) -> {Png.enc.bf.at(zz) <> Png.enc.byte(Png.enc.cap.at(zz, left)) <> Png.enc.hi(Png.enc.cap.at(zz, left)) <> + Png.enc.byte((Png.enc.cap.at(zz, left) .^. 65535 : U32)) <> Png.enc.hi((Png.enc.cap.at(zz, left) .^. 65535 : U32)) + <> rest == List.append(&2, U32, Png.enc.head(zz, Png.enc.cap.at(zz, left), (Png.enc.cap.at(zz, left) .^. 65535 : + U32)), rest) : List<&2, U32>}: + match zz: + case True{}: + {==} + case False{}: + {==} + +# the open block, reversed, is counted to its header's length when it ends +def len.blk( + +acc: List<&2, U32>, + +rf: U32, + +ll: U32, + +mx: U32, + +ha: {Nat.add(List.length(&2, U32, acc), U32.to_nat(rf)) == U32.to_nat(mx) : Nat}, + +hl: {U32.to_nat(ll) == List.length(&2, U32, acc) : Nat} +) -> {Png.enc.len(List.reverse(&2, U32, acc), 0) == ll : U32}: + +ra = List.reverse(&2, U32, acc) + +na = List.length(&2, U32, acc) + +e_r = {Wp2.len_rev(acc) : {List.length(&2, U32, ra) == na : Nat}} + +h_b = {Equal.trans(Bool, Nat.is_le(na, U32.to_nat(mx)), Nat.is_le(na, Nat.add(na, U32.to_nat(rf))), True{}, + Equal.cong(Nat, Bool, kk => Nat.is_le(na, kk), U32.to_nat(mx), Nat.add(na, U32.to_nat(rf)), Equal.sym(Nat, + Nat.add(na, U32.to_nat(rf)), U32.to_nat(mx), ha)), Wp2.nle_add(na, U32.to_nat(rf))) : {Nat.is_le(na, + U32.to_nat(mx)) == True{} : Bool}} + +h_r = {R.le_rw_l(na, List.length(&2, U32, ra), U32.to_nat(mx), Equal.sym(Nat, List.length(&2, U32, ra), na, e_r), + h_b) : {Nat.is_le(List.length(&2, U32, ra), U32.to_nat(mx)) == True{} : Bool}} + u32.same(Png.enc.len(ra, 0), ll, Equal.trans(Nat, U32.to_nat(Png.enc.len(ra, 0)), na, U32.to_nat(ll), Equal.trans(Nat, + U32.to_nat(Png.enc.len(ra, 0)), List.length(&2, U32, ra), na, len.of(ra, mx, h_r), e_r), Equal.sym(Nat, + U32.to_nat(ll), na, hl))) + +# no bytes left: the open block is enc.feed's final block +def sim.nil( + fin: Bool, + +acc: List<&2, U32>, + +rf: U32, + +rp: U32, + +ll: U32, + +mx: U32, + +ha: {Nat.add(List.length(&2, U32, acc), U32.to_nat(rf)) == U32.to_nat(mx) : Nat}, + +hl: {U32.to_nat(ll) == Nat.add(List.length(&2, U32, acc), U32.to_nat(rp)) : Nat}, + hf: fin.ok(fin, rp, rf, 0n) +) -> {List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse(&2, U32, acc)) == + Png.enc.stored(True{}, List.reverse(&2, U32, acc)) : List<&2, U32>}: + match fin: + case False{}: + (_e_rr, h_lt) = hf + Empty.absurd({List.append(&2, U32, Png.enc.head(False{}, ll, (ll .^. 65535 : U32)), List.reverse(&2, U32, acc)) == + Png.enc.stored(True{}, List.reverse(&2, U32, acc)) : List<&2, U32>}, U32L.false_true(Equal.trans(Bool, + False{}, Nat.is_lt(U32.to_nat(rp), 0n), True{}, R.lt_zero_false(U32.to_nat(rp)), h_lt))) + case True{}: + +e_rp = {hf : {U32.to_nat(rp) == 0n : Nat}} + +ra = List.reverse(&2, U32, acc) + +na = List.length(&2, U32, acc) + +hd = Png.enc.head(True{}, ll, (ll .^. 65535 : U32)) + +hl0 = {Equal.trans(Nat, U32.to_nat(ll), Nat.add(na, 0n), na, Equal.trans(Nat, U32.to_nat(ll), Nat.add(na, + U32.to_nat(rp)), Nat.add(na, 0n), hl, Equal.cong(Nat, Nat, kk => Nat.add(na, kk), U32.to_nat(rp), 0n, e_rp)), + R.add_zero(na)) : {U32.to_nat(ll) == na : Nat}} + +e_len = {len.blk(acc, rf, ll, mx, ha, hl0) : {Png.enc.len(ra, 0) == ll : U32}} + Equal.trans(List<&2, U32>, List.append(&2, U32, hd, ra), Png.enc.cat(hd, ra), Png.enc.stored(True{}, ra), + Equal.sym(List<&2, U32>, Png.enc.cat(hd, ra), List.append(&2, U32, hd, ra), Wp2.cat_app(hd, ra)), + Equal.cong(U32, List<&2, U32>, uu => Png.enc.cat(Png.enc.head(True{}, uu, (uu .^. 65535 : U32)), ra), ll, + Png.enc.len(ra, 0), Equal.sym(U32, Png.enc.len(ra, 0), ll, e_len))) + +# a room that is not zero leaves at.edge nothing to ask +def edge.no( + +rp: U32, + +left: U32, + +plen: U32, + +pbf: U32, + +nz: {U32.is_zero(rp) == False{} : Bool} +) -> at.edge(rp, left, plen, pbf): + ez => Empty.absurd({plen == Png.enc.cap(left) : U32} & {pbf == Png.enc.bf(left) : U32}, + U32L.false_true(Equal.trans(Bool, False{}, U32.is_zero(rp), True{}, Equal.sym(Bool, U32.is_zero(rp), False{}, nz), + ez))) + +# a new block's bytes as bs writes them for length u and BFINAL v: the +# header, the first byte, then the rest of the walk +def open.bs( + +h: U32, + +t: List<&2, U32>, + +l2: U32, + +uu: U32, + +vv: U32 +) -> List<&2, U32>: + +nlen = (uu .^. 65535 : U32) + +room2 = (uu - 1 : U32) + vv <> Png.enc.byte(uu) <> Png.enc.hi(uu) <> Png.enc.byte(nlen) <> Png.enc.hi(nlen) <> h <> bs(t, U32.is_zero(room2), + U32.is_eq(room2, 1), room2, l2, Png.enc.cap(l2), Png.enc.bf(l2)) + +# a new block from left bytes, h then t: bs's bytes are enc.feed's from a +# block holding h alone +def open.feed( + +h: U32, + +t: List<&2, U32>, + +left: U32, + +mx: U32, + +ih: {List.append(&2, U32, Png.enc.head(U32.is_le(left, 65535), Png.enc.cap(left), (Png.enc.cap(left) .^. 65535 : + U32)), h <> bs(t, U32.is_zero((Png.enc.cap(left) - 1 : U32)), U32.is_eq((Png.enc.cap(left) - 1 : U32), 1), + (Png.enc.cap(left) - 1 : U32), (left - 1 : U32), Png.enc.cap((left - 1 : U32)), Png.enc.bf((left - 1 : U32)))) == + Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>} +) -> {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(t, U32.is_zero((mx - 1 : + U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}: + +zz = U32.is_le(left, 65535) + +cp = Png.enc.cap(left) + +l2 = (left - 1 : U32) + +q = bs(t, U32.is_zero((cp - 1 : U32)), U32.is_eq((cp - 1 : U32), 1), (cp - 1 : U32), l2, Png.enc.cap(l2), + Png.enc.bf(l2)) + Equal.trans(List<&2, U32>, open.bs(h, t, l2, cp, Png.enc.bf(left)), List.append(&2, U32, Png.enc.head(zz, cp, (cp .^. + 65535 : U32)), h <> q), Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]), + hdr(zz, left, h <> q), ih) + +# the facts a new block's walk starts from, for sim: the feed holds h, with +# mx - 1 bytes of room; bs has cap(left) - 1 left in the block +def open.ih( + +h: U32, + +t: List<&2, U32>, + +left: U32, + +mx: U32, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, t) : Nat}, + sim_t: @zn: Bool -> @zl: Bool -> @zf: Bool -> @fin: Bool -> @rf: U32 -> @rp: U32 -> @plen: U32 -> @pbf: U32 -> + @ll: U32 -> {zn == U32.is_zero(rp) : Bool} -> {zl == U32.is_eq(rp, 1) : Bool} -> {zf == U32.is_zero(rf) : Bool} -> + {Nat.add(1n, U32.to_nat(rf)) == U32.to_nat(mx) : Nat} -> {U32.to_nat(ll) == Nat.add(1n, U32.to_nat(rp)) : Nat} + -> {Nat.is_le(U32.to_nat(rp), U32.to_nat(rf)) == True{} : Bool} -> {U32.to_nat((left - 1 : U32)) == + List.length(&2, U32, t) : Nat} -> fin.ok(fin, rp, rf, List.length(&2, U32, t)) -> at.edge(rp, (left - 1 : U32), + plen, pbf) -> sim.ty(t, zn, zl, zf, fin, [h], rf, rp, (left - 1 : U32), plen, pbf, ll, mx) +) -> {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(t, U32.is_zero((mx - 1 : + U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}: + +nt = List.length(&2, U32, t) + +zz = U32.is_le(left, 65535) + +cp = Png.enc.cap(left) + +cm = capm(zz, left, mx) + +c1 = (cp - 1 : U32) + +m1 = (mx - 1 : U32) + +l2 = (left - 1 : U32) + +nzm = {mx.nz(mx, emx) : {U32.is_zero(mx) == False{} : Bool}} + +e_cm = {cap.m(zz, left, mx, emx) : {cp == cm : U32}} + +ezm = {le.mx(left, mx, emx) : {U32.is_le(left, mx) == zz : Bool}} + +nz_cp = {Equal.trans(Bool, U32.is_zero(cp), U32.is_zero(cm), False{}, Equal.cong(U32, Bool, uu => U32.is_zero(uu), + cp, cm, e_cm), cap.nz(zz, left, mx, nt, nzm, hn)) : {U32.is_zero(cp) == False{} : Bool}} + +ha2 = {Equal.sym(Nat, U32.to_nat(mx), 1n+U32.to_nat(m1), Wp1.u32_dec(mx, nzm)) : {Nat.add(1n, U32.to_nat(m1)) == + U32.to_nat(mx) : Nat}} + +hl2 = {Wp1.u32_dec(cp, nz_cp) : {U32.to_nat(cp) == Nat.add(1n, U32.to_nat(c1)) : Nat}} + +hle2 = {Equal.trans(Bool, Nat.is_le(U32.to_nat(c1), U32.to_nat(m1)), Nat.is_le(U32.to_nat((cm - 1 : U32)), + U32.to_nat(m1)), True{}, Equal.cong(U32, Bool, uu => Nat.is_le(U32.to_nat((uu - 1 : U32)), U32.to_nat(m1)), cp, cm, + e_cm), cap.le(zz, left, mx, nt, nzm, ezm, hn)) : {Nat.is_le(U32.to_nat(c1), U32.to_nat(m1)) == True{} : Bool}} + +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} + hf2 = {fo.cm(zz, left, mx, nt, emx, cap.fo(zz, left, mx, nt, nzm, ezm, hn)) : fin.ok(zz, c1, m1, nt)} + open.feed(h, t, left, mx, sim_t(U32.is_zero(c1), U32.is_eq(c1, 1), U32.is_zero(m1), zz, m1, c1, Png.enc.cap(l2), + Png.enc.bf(l2), cp, {==}, {==}, {==}, ha2, hl2, hle2, hn2, hf2, _ez => ({==}, {==}))) + +# a block boundary with bytes left: the full block closes and a new one opens +def sim.edge( + fin: Bool, + +h: U32, + +t: List<&2, U32>, + +acc: List<&2, U32>, + +rf: U32, + +rp: U32, + +left: U32, + +plen: U32, + +pbf: U32, + +ll: U32, + +mx: U32, + +zf: Bool, + +hzf: {zf == U32.is_zero(rf) : Bool}, + +ha: {Nat.add(List.length(&2, U32, acc), U32.to_nat(rf)) == U32.to_nat(mx) : Nat}, + +hl: {U32.to_nat(ll) == Nat.add(List.length(&2, U32, acc), U32.to_nat(rp)) : Nat}, + +e0: {U32.to_nat(rp) == 0n : Nat}, + +e_ob: {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(t, U32.is_zero((mx - + 1 : U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}, + hf: fin.ok(fin, rp, rf, 1n+List.length(&2, U32, t)), + pe: {plen == Png.enc.cap(left) : U32} & {pbf == Png.enc.bf(left) : U32} +) -> {List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, U32, acc, open.bs(h, t, + (left - 1 : U32), plen, pbf))) == Png.enc.feed(h <> t, zf, rf, mx, acc) : List<&2, U32>}: + match fin: + case True{}: + Empty.absurd({List.append(&2, U32, Png.enc.head(True{}, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, U32, acc, + open.bs(h, t, (left - 1 : U32), plen, pbf))) == Png.enc.feed(h <> t, zf, rf, mx, acc) : List<&2, U32>}, + Wp1.zero_succ(List.length(&2, U32, t), Equal.trans(Nat, 0n, U32.to_nat(rp), 1n+List.length(&2, U32, t), + Equal.sym(Nat, U32.to_nat(rp), 0n, e0), hf))) + case False{}: + (e_rr, _h_lt) = hf + (e_plen, e_pbf) = pe + +na = List.length(&2, U32, acc) + +ra = List.reverse(&2, U32, acc) + +l2 = (left - 1 : U32) + +cp = Png.enc.cap(left) + +e_rf0 = {Equal.trans(Nat, U32.to_nat(rf), U32.to_nat(rp), 0n, Equal.sym(Nat, U32.to_nat(rp), U32.to_nat(rf), + e_rr), e0) : {U32.to_nat(rf) == 0n : Nat}} + +e_zf = {Equal.trans(Bool, zf, U32.is_zero(rf), True{}, hzf, zero.is(rf, e_rf0)) : {zf == True{} : Bool}} + +ff = Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]) + +hd0 = Png.enc.head(False{}, ll, (ll .^. 65535 : U32)) + +hl0 = {Equal.trans(Nat, U32.to_nat(ll), Nat.add(na, 0n), na, Equal.trans(Nat, U32.to_nat(ll), Nat.add(na, + U32.to_nat(rp)), Nat.add(na, 0n), hl, Equal.cong(Nat, Nat, kk => Nat.add(na, kk), U32.to_nat(rp), 0n, e0)), + R.add_zero(na)) : {U32.to_nat(ll) == na : Nat}} + +e_len = {len.blk(acc, rf, ll, mx, ha, hl0) : {Png.enc.len(ra, 0) == ll : U32}} + +e_bs = {Equal.trans(List<&2, U32>, open.bs(h, t, l2, plen, pbf), open.bs(h, t, l2, cp, Png.enc.bf(left)), ff, + Equal.trans(List<&2, U32>, open.bs(h, t, l2, plen, pbf), open.bs(h, t, l2, cp, pbf), open.bs(h, t, l2, cp, + Png.enc.bf(left)), Equal.cong(U32, List<&2, U32>, uu => open.bs(h, t, l2, uu, pbf), plen, cp, e_plen), + Equal.cong(U32, List<&2, U32>, uu => open.bs(h, t, l2, cp, uu), pbf, Png.enc.bf(left), e_pbf)), + e_ob) : {open.bs(h, t, l2, plen, pbf) == ff : List<&2, U32>}} + Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(h, t, l2, plen, pbf))), + List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), Png.enc.feed(h <> t, zf, rf, mx, acc), + Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(h, t, l2, plen, + pbf))), List.append(&2, U32, hd0, List.append(&2, U32, ra, ff)), List.append(&2, U32, List.append(&2, U32, + hd0, ra), ff), + Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(h, t, l2, plen, + pbf))), List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, ff)), List.append(&2, U32, hd0, + List.append(&2, U32, ra, ff)), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, + ys)), open.bs(h, t, l2, plen, pbf), ff, e_bs), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, hd0, ys), List.reverse.go(&2, U32, acc, + ff), List.append(&2, U32, ra, ff), W9.revgo_acc(acc, [], ff))), + Equal.sym(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), List.append(&2, U32, hd0, + List.append(&2, U32, ra, ff)), Wp2.app_assoc(hd0, ra, ff))), + Equal.trans(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), Png.enc.feed(h <> t, True{}, + rf, mx, acc), Png.enc.feed(h <> t, zf, rf, mx, acc), + Equal.trans(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), List.append(&2, U32, + Png.enc.cat(hd0, ra), ff), Png.enc.feed(h <> t, True{}, rf, mx, acc), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, ys, ff), List.append(&2, U32, hd0, ra), + Png.enc.cat(hd0, ra), Equal.sym(List<&2, U32>, Png.enc.cat(hd0, ra), List.append(&2, U32, hd0, ra), + Wp2.cat_app(hd0, ra))), + Equal.trans(List<&2, U32>, List.append(&2, U32, Png.enc.cat(hd0, ra), ff), Png.enc.cat(Png.enc.cat(hd0, + ra), ff), Png.enc.feed(h <> t, True{}, rf, mx, acc), + Equal.sym(List<&2, U32>, Png.enc.cat(Png.enc.cat(hd0, ra), ff), List.append(&2, U32, Png.enc.cat(hd0, + ra), ff), Wp2.cat_app(Png.enc.cat(hd0, ra), ff)), + Equal.cong(U32, List<&2, U32>, uu => Png.enc.cat(Png.enc.cat(Png.enc.head(False{}, uu, (uu .^. 65535 : + U32)), ra), ff), ll, Png.enc.len(ra, 0), Equal.sym(U32, Png.enc.len(ra, 0), ll, e_len)))), + Equal.cong(Bool, List<&2, U32>, zb => Png.enc.feed(h <> t, zb, rf, mx, acc), True{}, zf, Equal.sym(Bool, + zf, True{}, e_zf)))) + +# bs against enc.feed: the open block (acc, newest first, with rf bytes of +# room in the feed) under a header of length ll and BFINAL fin, then bs from +# rp bytes left in the block, are enc.feed's blocks +def sim( + xs: List<&2, U32>, + znew: Bool, + zlast: Bool, + +zf: Bool, + +fin: Bool, + +acc: List<&2, U32>, + +rf: U32, + +rp: U32, + +left: U32, + +plen: U32, + +pbf: U32, + +ll: U32, + +mx: U32, + +emx: {mx == 65535 : U32}, + +hzn: {znew == U32.is_zero(rp) : Bool}, + +hzl: {zlast == U32.is_eq(rp, 1) : Bool}, + +hzf: {zf == U32.is_zero(rf) : Bool}, + +ha: {Nat.add(List.length(&2, U32, acc), U32.to_nat(rf)) == U32.to_nat(mx) : Nat}, + +hl: {U32.to_nat(ll) == Nat.add(List.length(&2, U32, acc), U32.to_nat(rp)) : Nat}, + +hle: {Nat.is_le(U32.to_nat(rp), U32.to_nat(rf)) == True{} : Bool}, + +hn: {U32.to_nat(left) == List.length(&2, U32, xs) : Nat}, + hf: fin.ok(fin, rp, rf, List.length(&2, U32, xs)), + hb: at.edge(rp, left, plen, pbf) +) -> sim.ty(xs, znew, zlast, zf, fin, acc, rf, rp, left, plen, pbf, ll, mx): + match xs znew zlast: + case Nil{} _zn _zl: + sim.nil(fin, acc, rf, rp, ll, mx, ha, hl, hf) + case +h <> +t False{} False{}: + +rp2 = (rp - 1 : U32) + +rf2 = (rf - 1 : U32) + +l2 = (left - 1 : U32) + +nt = List.length(&2, U32, t) + +na = List.length(&2, U32, acc) + +nz_rp = {Equal.sym(Bool, False{}, U32.is_zero(rp), hzn) : {U32.is_zero(rp) == False{} : Bool}} + +e_rp = {Wp1.u32_dec(rp, nz_rp) : {U32.to_nat(rp) == 1n+U32.to_nat(rp2) : Nat}} + +nz_rp2 = {two(rp, hzn, hzl) : {U32.is_zero(rp2) == False{} : Bool}} + +h_rf = {R.le_rw_l(U32.to_nat(rp), 1n+U32.to_nat(rp2), U32.to_nat(rf), e_rp, hle) : + {Nat.is_le(1n+U32.to_nat(rp2), U32.to_nat(rf)) == True{} : Bool}} + +nz_rf = {pos(rf, U32.to_nat(rp2), h_rf) : {U32.is_zero(rf) == False{} : Bool}} + +e_rf = {Wp1.u32_dec(rf, nz_rf) : {U32.to_nat(rf) == 1n+U32.to_nat(rf2) : Nat}} + +e_zf = {Equal.trans(Bool, zf, U32.is_zero(rf), False{}, hzf, nz_rf) : {zf == False{} : Bool}} + +ha2 = {shift(na, rf, rf2, U32.to_nat(mx), e_rf, ha) : {Nat.add(1n+na, U32.to_nat(rf2)) == U32.to_nat(mx) : Nat}} + +hl2 = {Equal.sym(Nat, Nat.add(1n+na, U32.to_nat(rp2)), U32.to_nat(ll), shift(na, rp, rp2, U32.to_nat(ll), e_rp, + Equal.sym(Nat, U32.to_nat(ll), Nat.add(na, U32.to_nat(rp)), hl))) : {U32.to_nat(ll) == Nat.add(1n+na, + U32.to_nat(rp2)) : Nat}} + +hle2 = {R.le_rw_r(1n+U32.to_nat(rp2), U32.to_nat(rf), 1n+U32.to_nat(rf2), e_rf, h_rf) : + {Nat.is_le(U32.to_nat(rp2), U32.to_nat(rf2)) == True{} : Bool}} + +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} + hf2 = {fo.dec(fin, rp, rf, rp2, rf2, nt, e_rp, e_rf, hf) : fin.ok(fin, rp2, rf2, nt)} + Equal.trans(List<&2, U32>, List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, + U32, acc, bs(h <> t, False{}, False{}, rp, left, plen, pbf))), Png.enc.feed(h <> t, False{}, rf, mx, acc), + Png.enc.feed(h <> t, zf, rf, mx, acc), + sim(t, False{}, U32.is_eq(rp2, 1), U32.is_zero(rf2), fin, h <> acc, rf2, rp2, l2, plen, pbf, ll, mx, emx, + Equal.sym(Bool, U32.is_zero(rp2), False{}, nz_rp2), {==}, {==}, ha2, hl2, hle2, hn2, hf2, edge.no(rp2, l2, + plen, pbf, nz_rp2)), + Equal.cong(Bool, List<&2, U32>, zb => Png.enc.feed(h <> t, zb, rf, mx, acc), False{}, zf, Equal.sym(Bool, zf, + False{}, e_zf))) + case +h <> +t False{} True{}: + +rf2 = (rf - 1 : U32) + +l2 = (left - 1 : U32) + +nt = List.length(&2, U32, t) + +na = List.length(&2, U32, acc) + +e_rp = {one.val(rp, hzl) : {U32.to_nat(rp) == 1n+U32.to_nat(0) : Nat}} + +h_rf = {R.le_rw_l(U32.to_nat(rp), 1n, U32.to_nat(rf), e_rp, hle) : {Nat.is_le(1n, U32.to_nat(rf)) == True{} : + Bool}} + +nz_rf = {pos(rf, 0n, h_rf) : {U32.is_zero(rf) == False{} : Bool}} + +e_rf = {Wp1.u32_dec(rf, nz_rf) : {U32.to_nat(rf) == 1n+U32.to_nat(rf2) : Nat}} + +e_zf = {Equal.trans(Bool, zf, U32.is_zero(rf), False{}, hzf, nz_rf) : {zf == False{} : Bool}} + +ha2 = {shift(na, rf, rf2, U32.to_nat(mx), e_rf, ha) : {Nat.add(1n+na, U32.to_nat(rf2)) == U32.to_nat(mx) : Nat}} + +hl2 = {Equal.sym(Nat, Nat.add(1n+na, U32.to_nat(0)), U32.to_nat(ll), shift(na, rp, 0, U32.to_nat(ll), e_rp, + Equal.sym(Nat, U32.to_nat(ll), Nat.add(na, U32.to_nat(rp)), hl))) : {U32.to_nat(ll) == Nat.add(1n+na, + U32.to_nat(0)) : Nat}} + +hle2 = {R.le_zero(U32.to_nat(rf2)) : {Nat.is_le(U32.to_nat(0), U32.to_nat(rf2)) == True{} : Bool}} + +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} + hf2 = {fo.dec(fin, rp, rf, 0, rf2, nt, e_rp, e_rf, hf) : fin.ok(fin, 0, rf2, nt)} + Equal.trans(List<&2, U32>, List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, + U32, acc, bs(h <> t, False{}, True{}, rp, left, plen, pbf))), Png.enc.feed(h <> t, False{}, rf, mx, acc), + Png.enc.feed(h <> t, zf, rf, mx, acc), + sim(t, True{}, False{}, U32.is_zero(rf2), fin, h <> acc, rf2, 0, l2, Png.enc.cap(l2), Png.enc.bf(l2), ll, mx, + emx, {==}, {==}, {==}, ha2, hl2, hle2, hn2, hf2, _ez => ({==}, {==})), + Equal.cong(Bool, List<&2, U32>, zb => Png.enc.feed(h <> t, zb, rf, mx, acc), False{}, zf, Equal.sym(Bool, zf, + False{}, e_zf))) + case +h <> +t True{} _zl: + +l2 = (left - 1 : U32) + +ez = {Equal.sym(Bool, True{}, U32.is_zero(rp), hzn) : {U32.is_zero(rp) == True{} : Bool}} + +e0 = {zero.val(rp, hzn) : {U32.to_nat(rp) == 0n : Nat}} + +e_ob = {open.ih(h, t, left, mx, emx, hn, zn => zl => zb => fb => rf3 => rp3 => pl3 => pb3 => ll3 => a1 => a2 => + a3 => a4 => a5 => a6 => a7 => a8 => a9 => sim(t, zn, zl, zb, fb, [h], rf3, rp3, l2, pl3, pb3, ll3, mx, emx, + a1, a2, a3, a4, a5, a6, a7, a8, a9)) : {open.bs(h, t, l2, Png.enc.cap(left), Png.enc.bf(left)) == + Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}} + sim.edge(fin, h, t, acc, rf, rp, left, plen, pbf, ll, mx, zf, hzf, ha, hl, e0, e_ob, hf, hb(ez)) + +# the first block: bs from the start writes enc.feed's blocks for every +# non-empty list of left bytes +def sim.start( + +h: U32, + +t: List<&2, U32>, + +left: U32, + +mx: U32, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, t) : Nat} +) -> {bs(h <> t, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(h <> t, False{}, mx, + mx, []) : List<&2, U32>}: + +l2 = (left - 1 : U32) + open.ih(h, t, left, mx, emx, hn, zn => zl => zb => fb => rf3 => rp3 => pl3 => pb3 => ll3 => a1 => a2 => a3 => a4 => + a5 => a6 => a7 => a8 => a9 => sim(t, zn, zl, zb, fb, [h], rf3, rp3, l2, pl3, pb3, ll3, mx, emx, a1, a2, a3, a4, a5, + a6, a7, a8, a9)) + +# enc.blocks at 65535 for a list longer than one block is bs from the start +def sim.blocks( + xs: List<&2, U32>, + +mx: U32, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(Png.enc.len(xs, 0)) == List.length(&2, U32, xs) : Nat}, + +hbig: {U32.is_le(Png.enc.len(xs, 0), 65535) == False{} : Bool} +) -> {Png.enc.blocks(65535, xs) == bs(xs, True{}, False{}, 0, Png.enc.len(xs, 0), Png.enc.cap(Png.enc.len(xs, 0)), + Png.enc.bf(Png.enc.len(xs, 0))) : List<&2, U32>}: + match xs: + case Nil{}: + Empty.absurd({Png.enc.blocks(65535, []) == bs([], True{}, False{}, 0, 0, Png.enc.cap(0), Png.enc.bf(0)) : + List<&2, U32>}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hbig))) + case +h <> +t: + +nn = Png.enc.len(h <> t, 0) + +bb = bs(h <> t, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn)) + Equal.trans(List<&2, U32>, Png.enc.blocks(65535, h <> t), Png.enc.blocks.fit(False{}, 65535, nn, h <> t), bb, + Equal.cong(Bool, List<&2, U32>, zb => Png.enc.blocks.fit(zb, 65535, nn, h <> t), U32.is_le(nn, 65535), False{}, + hbig), + Equal.trans(List<&2, U32>, Png.enc.feed(h <> t, False{}, 65535, 65535, []), Png.enc.feed(h <> t, False{}, mx, mx, + []), bb, Equal.cong(U32, List<&2, U32>, uu => Png.enc.feed(h <> t, False{}, uu, uu, []), 65535, mx, + Equal.sym(U32, mx, 65535, emx)), Equal.sym(List<&2, U32>, bb, Png.enc.feed(h <> t, False{}, mx, mx, []), + sim.start(h, t, nn, mx, emx, hn)))) + +# ---- D. U32.div and U32.mod ---- + +# a word shifted left with c coming in: nothing falls out, and it is c + 2 w +def sho.ok(nn: Nat, +cc: Bool, +ww: Word(nn), pp: Bool & Word(nn)) -> Type: + match pp: + case (tt, ss): + {tt == False{} : Bool} & {Word.to_nat(nn, ss) == Nat.add(R.bit(cc), Nat.double(Word.to_nat(nn, ww))) : Nat} + +# one step of so: the lower bits shifted, then this bit in front +def sho.step( + +pp: Nat, + +cc: Bool, + +bb: Bool, + +tt: Word(pp), + yy: Bool & Word(pp), + ih: sho.ok(pp, bb, tt, yy) +) -> sho.ok(1n+pp, cc, WCon{bb, tt}, Word.shl.out.con(pp, cc, yy)): + match yy: + case (hi, +t2): + (e_hi, e_t2) = ih + +vt = Word.to_nat(pp, tt) + (e_hi, Equal.trans(Nat, Word.to_nat(1n+pp, WCon{cc, t2}), Nat.add(R.bit(cc), Nat.double(Word.to_nat(pp, t2))), + Nat.add(R.bit(cc), Nat.double(Word.to_nat(1n+pp, WCon{bb, tt}))), R.to_nat_con(pp, cc, t2), + Equal.cong(Nat, Nat, kk => Nat.add(R.bit(cc), Nat.double(kk)), Word.to_nat(pp, t2), Word.to_nat(1n+pp, + WCon{bb, tt}), Equal.trans(Nat, Word.to_nat(pp, t2), Nat.add(R.bit(bb), Nat.double(vt)), Word.to_nat(1n+pp, + WCon{bb, tt}), e_t2, Equal.sym(Nat, Word.to_nat(1n+pp, WCon{bb, tt}), Nat.add(R.bit(bb), Nat.double(vt)), + R.to_nat_con(pp, bb, tt)))))) + +# shifting a word left with c coming in, when c + 2 w is at most a word's value +def sho( + nn: Nat, + +cc: Bool, + +ww: Word(nn), + +tw: Word(nn), + +hh: {Nat.is_le(Nat.add(R.bit(cc), Nat.double(Word.to_nat(nn, ww))), Word.to_nat(nn, tw)) == True{} : Bool} +) -> sho.ok(nn, cc, ww, Word.shl.out(nn, cc, ww)): + match nn: + case 0n: + match cc ww tw: + case False{} WNil{} WNil{}: + ({==}, {==}) + case True{} WNil{} WNil{}: + Empty.absurd(sho.ok(0n, True{}, WNil{}, (True{}, WNil{})), U32L.false_true(hh)) + case 1n+(+pp): + match ww tw: + case WCon{+bb, +tt} WCon{+sb, +st}: + +vt = Word.to_nat(pp, tt) + +vs = Word.to_nat(pp, st) + +wb = Word.to_nat(1n+pp, WCon{bb, tt}) + +ws = Word.to_nat(1n+pp, WCon{sb, st}) + +xb = Nat.add(R.bit(bb), Nat.double(vt)) + +xs = Nat.add(R.bit(sb), Nat.double(vs)) + +h0 = {R.le_add_l(R.bit(cc), Nat.double(wb), ws, hh) : {Nat.is_le(Nat.double(wb), ws) == True{} : Bool}} + +h1 = {R.le_rw_r(Nat.double(xb), ws, xs, R.to_nat_con(pp, sb, st), R.le_rw_l(Nat.double(wb), Nat.double(xb), + ws, Equal.cong(Nat, Nat, kk => Nat.double(kk), wb, xb, R.to_nat_con(pp, bb, tt)), h0)) : + {Nat.is_le(Nat.double(xb), xs) == True{} : Bool}} + +h2 = {R.le_half(sb, xb, vs, h1) : {Nat.is_le(xb, vs) == True{} : Bool}} + sho.step(pp, cc, bb, tt, Word.shl.out(pp, bb, tt), sho(pp, bb, tt, st, h2)) + +# at least in Cmp is at most the other way +def ge.le(aa: Nat, bb: Nat, +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == True{} : Bool}) -> {Nat.is_le(bb, aa) == True{} : + Bool}: + match aa bb: + case 0n 0n: + {==} + case 0n 1n+bp: + Empty.absurd({Nat.is_le(1n+bp, 0n) == True{} : Bool}, U32L.false_true(hh)) + case 1n+_ap 0n: + {==} + case 1n+ap 1n+bp: + ge.le(ap, bp, hh) + +# not at least in Cmp is below +def nge.lt(aa: Nat, bb: Nat, +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == False{} : Bool}) -> {Nat.is_lt(aa, bb) == True{} : + Bool}: + match aa bb: + case 0n 0n: + Empty.absurd({Nat.is_lt(0n, 0n) == True{} : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hh))) + case 0n 1n+_bp: + {==} + case 1n+ap 0n: + Empty.absurd({Nat.is_lt(1n+ap, 0n) == True{} : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hh))) + case 1n+ap 1n+bp: + nge.lt(ap, bp, hh) + +# U32.is_ge is Nat's +def u.ge(+uu: U32, +vv: U32) -> {U32.is_ge(uu, vv) == Cmp.is_ge(Nat.cmp(U32.to_nat(uu), U32.to_nat(vv))) : Bool}: + Equal.cong(Cmp, Bool, cc => Cmp.is_ge(cc), U32.cmp(uu, vv), Nat.cmp(U32.to_nat(uu), U32.to_nat(vv)), Wp2.u_cmp(uu, + vv)) + +# a bit plus x is below y when 2 plus x is at most y +def bit.lt( + aa: Bool, + +xx: Nat, + +yy: Nat, + +hh: {Nat.is_le(2n+xx, yy) == True{} : Bool} +) -> {Nat.is_lt(Nat.add(R.bit(aa), xx), yy) == True{} : Bool}: + match aa: + case False{}: + Equal.trans(Bool, Nat.is_lt(xx, yy), Nat.is_le(1n+xx, yy), True{}, R.lt_le_succ(xx, yy), R.le_trans(1n+xx, 2n+xx, + yy, R.le_succ(1n+xx), hh)) + case True{}: + Equal.trans(Bool, Nat.is_lt(1n+xx, yy), Nat.is_le(2n+xx, yy), True{}, R.lt_le_succ(1n+xx, yy), hh) + +# 2 r and a bit is below 2 b when r is below b +def dbl.lt( + +aa: Bool, + +rn: Nat, + +bn: Nat, + +hh: {Nat.is_lt(rn, bn) == True{} : Bool} +) -> {Nat.is_lt(Nat.add(R.bit(aa), Nat.double(rn)), Nat.add(bn, bn)) == True{} : Bool}: + +h1 = {Equal.trans(Bool, Nat.is_le(1n+rn, bn), Nat.is_lt(rn, bn), True{}, Equal.sym(Bool, Nat.is_lt(rn, bn), + Nat.is_le(1n+rn, bn), R.lt_le_succ(rn, bn)), hh) : {Nat.is_le(1n+rn, bn) == True{} : Bool}} + +h2 = {R.le_add_both(1n+rn, bn, 1n+rn, bn, h1, h1) : {Nat.is_le(Nat.add(1n+rn, 1n+rn), Nat.add(bn, bn)) == True{} : + Bool}} + +h3 = {Equal.trans(Nat, 2n+Nat.double(rn), 2n+Nat.add(rn, rn), Nat.add(1n+rn, 1n+rn), Equal.cong(Nat, Nat, kk => + 2n+kk, Nat.double(rn), Nat.add(rn, rn), R.double_add(rn)), Equal.cong(Nat, Nat, kk => 1n+kk, 1n+Nat.add(rn, rn), + Nat.add(rn, 1n+rn), Equal.sym(Nat, Nat.add(rn, 1n+rn), 1n+Nat.add(rn, rn), R.add_succ(rn, rn)))) : + {2n+Nat.double(rn) == Nat.add(1n+rn, 1n+rn) : Nat}} + +h4 = {R.le_rw_l(Nat.add(1n+rn, 1n+rn), 2n+Nat.double(rn), Nat.add(bn, bn), Equal.sym(Nat, 2n+Nat.double(rn), + Nat.add(1n+rn, 1n+rn), h3), h2) : {Nat.is_le(2n+Nat.double(rn), Nat.add(bn, bn)) == True{} : Bool}} + bit.lt(aa, Nat.double(rn), Nat.add(bn, bn), h4) + +# a + 2 (q b + r) is 2 q b + (a + 2 r) +def alg.lhs( + +an: Nat, + +qb: Nat, + +rn: Nat +) -> {Nat.add(an, Nat.double(Nat.add(qb, rn))) == Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))) : Nat}: + Equal.trans(Nat, Nat.add(an, Nat.double(Nat.add(qb, rn))), Nat.add(an, Nat.add(Nat.double(qb), Nat.double(rn))), + Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), Equal.cong(Nat, Nat, kk => Nat.add(an, kk), + Nat.double(Nat.add(qb, rn)), Nat.add(Nat.double(qb), Nat.double(rn)), R.double_dist(qb, rn)), R.add_swap(an, + Nat.double(qb), Nat.double(rn))) + +# what U32.divmod.go gives: the word is q * b + r, with r below b +def dm.ok(mm: Nat, +aw: Word(mm), +bu: U32, qr: Word(mm) & U32) -> Type: + match qr: + case (+qw, +ru): + {Word.to_nat(mm, aw) == Nat.add(Nat.mul(Word.to_nat(mm, qw), U32.to_nat(bu)), U32.to_nat(ru)) : Nat} & + {Nat.is_lt(U32.to_nat(ru), U32.to_nat(bu)) == True{} : Bool} + +# the step where the new bit makes the remainder reach b: q gets a 1 and b comes off +def dm.sub( + +pp: Nat, + +a0: Bool, + +hi: Word(pp), + +bu: U32, + +qw: Word(pp), + +rn: Nat, + +su: U32, + +e1: {Word.to_nat(pp, hi) == Nat.add(Nat.mul(Word.to_nat(pp, qw), U32.to_nat(bu)), rn) : Nat}, + +es: {U32.to_nat(su) == Nat.add(R.bit(a0), Nat.double(rn)) : Nat}, + +hge: {Nat.is_le(U32.to_nat(bu), U32.to_nat(su)) == True{} : Bool}, + +hlt: {Nat.is_lt(U32.to_nat(su), Nat.add(U32.to_nat(bu), U32.to_nat(bu))) == True{} : Bool} +) -> dm.ok(1n+pp, WCon{a0, hi}, bu, (WCon{True{}, qw}, U32.sub(su, bu))): + +bn = U32.to_nat(bu) + +sn = U32.to_nat(su) + +qn = Word.to_nat(pp, qw) + +qb = Nat.mul(qn, bn) + +an = R.bit(a0) + +dd = Nat.mul(Nat.double(qn), bn) + +e_sub = {R.u32_sub_nat(su, bu, hge) : {U32.to_nat(U32.sub(su, bu)) == Nat.sub(sn, bn) : Nat}} + +e_l = {Equal.trans(Nat, Word.to_nat(1n+pp, WCon{a0, hi}), Nat.add(an, Nat.double(Nat.add(qb, rn))), + Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), Equal.trans(Nat, Word.to_nat(1n+pp, WCon{a0, hi}), + Nat.add(an, Nat.double(Word.to_nat(pp, hi))), Nat.add(an, Nat.double(Nat.add(qb, rn))), R.to_nat_con(pp, a0, hi), + Equal.cong(Nat, Nat, kk => Nat.add(an, Nat.double(kk)), Word.to_nat(pp, hi), Nat.add(qb, rn), e1)), alg.lhs(an, qb, + rn)) : {Word.to_nat(1n+pp, WCon{a0, hi}) == Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))) : Nat}} + +e_r = {Equal.trans(Nat, Nat.add(Nat.add(bn, dd), Nat.sub(sn, bn)), Nat.add(dd, sn), Nat.add(Nat.double(qb), + Nat.add(an, Nat.double(rn))), + Equal.trans(Nat, Nat.add(Nat.add(bn, dd), Nat.sub(sn, bn)), Nat.add(dd, Nat.add(bn, Nat.sub(sn, bn))), Nat.add(dd, + sn), + Equal.trans(Nat, Nat.add(Nat.add(bn, dd), Nat.sub(sn, bn)), Nat.add(bn, Nat.add(dd, Nat.sub(sn, bn))), + Nat.add(dd, Nat.add(bn, Nat.sub(sn, bn))), R.add_assoc(bn, dd, Nat.sub(sn, bn)), R.add_swap(bn, dd, + Nat.sub(sn, bn))), + Equal.cong(Nat, Nat, kk => Nat.add(dd, kk), Nat.add(bn, Nat.sub(sn, bn)), sn, R.add_sub(bn, sn, hge))), + Equal.trans(Nat, Nat.add(dd, sn), Nat.add(Nat.double(qb), sn), Nat.add(Nat.double(qb), Nat.add(an, + Nat.double(rn))), Equal.cong(Nat, Nat, kk => Nat.add(kk, sn), dd, Nat.double(qb), R.mul_double(qn, bn)), + Equal.cong(Nat, Nat, kk => Nat.add(Nat.double(qb), kk), sn, Nat.add(an, Nat.double(rn)), es))) : + {Nat.add(Nat.add(bn, dd), Nat.sub(sn, bn)) == Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))) : Nat}} + +e_all = {Equal.trans(Nat, Word.to_nat(1n+pp, WCon{a0, hi}), Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), + Nat.add(Nat.add(bn, dd), U32.to_nat(U32.sub(su, bu))), e_l, Equal.trans(Nat, Nat.add(Nat.double(qb), Nat.add(an, + Nat.double(rn))), Nat.add(Nat.add(bn, dd), Nat.sub(sn, bn)), Nat.add(Nat.add(bn, dd), U32.to_nat(U32.sub(su, bu))), + Equal.sym(Nat, Nat.add(Nat.add(bn, dd), Nat.sub(sn, bn)), Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), + e_r), Equal.cong(Nat, Nat, kk => Nat.add(Nat.add(bn, dd), kk), Nat.sub(sn, bn), U32.to_nat(U32.sub(su, bu)), + Equal.sym(Nat, U32.to_nat(U32.sub(su, bu)), Nat.sub(sn, bn), e_sub)))) : {Word.to_nat(1n+pp, WCon{a0, hi}) == + Nat.add(Nat.add(bn, dd), U32.to_nat(U32.sub(su, bu))) : Nat}} + +l_sub = {R.lt_rw_l(Nat.sub(sn, bn), U32.to_nat(U32.sub(su, bu)), bn, Equal.sym(Nat, U32.to_nat(U32.sub(su, bu)), + Nat.sub(sn, bn), e_sub), R.sub_lt(bn, sn, bn, hge, hlt)) : {Nat.is_lt(U32.to_nat(U32.sub(su, bu)), bn) == True{} : + Bool}} + (e_all, l_sub) + +# the step where the remainder stays below b: q gets a 0 +def dm.keep( + +pp: Nat, + +a0: Bool, + +hi: Word(pp), + +bu: U32, + +qw: Word(pp), + +rn: Nat, + +su: U32, + +e1: {Word.to_nat(pp, hi) == Nat.add(Nat.mul(Word.to_nat(pp, qw), U32.to_nat(bu)), rn) : Nat}, + +es: {U32.to_nat(su) == Nat.add(R.bit(a0), Nat.double(rn)) : Nat}, + +hlt: {Nat.is_lt(U32.to_nat(su), U32.to_nat(bu)) == True{} : Bool} +) -> dm.ok(1n+pp, WCon{a0, hi}, bu, (WCon{False{}, qw}, su)): + +bn = U32.to_nat(bu) + +qn = Word.to_nat(pp, qw) + +qb = Nat.mul(qn, bn) + +an = R.bit(a0) + +e_all = {Equal.trans(Nat, Word.to_nat(1n+pp, WCon{a0, hi}), Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), + Nat.add(Nat.mul(Nat.double(qn), bn), U32.to_nat(su)), Equal.trans(Nat, Word.to_nat(1n+pp, WCon{a0, hi}), + Nat.add(an, Nat.double(Nat.add(qb, rn))), Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), Equal.trans(Nat, + Word.to_nat(1n+pp, WCon{a0, hi}), Nat.add(an, Nat.double(Word.to_nat(pp, hi))), Nat.add(an, Nat.double(Nat.add(qb, + rn))), R.to_nat_con(pp, a0, hi), Equal.cong(Nat, Nat, kk => Nat.add(an, Nat.double(kk)), Word.to_nat(pp, hi), + Nat.add(qb, rn), e1)), alg.lhs(an, qb, rn)), Equal.trans(Nat, Nat.add(Nat.double(qb), Nat.add(an, Nat.double(rn))), + Nat.add(Nat.mul(Nat.double(qn), bn), Nat.add(an, Nat.double(rn))), Nat.add(Nat.mul(Nat.double(qn), bn), + U32.to_nat(su)), Equal.cong(Nat, Nat, kk => Nat.add(kk, Nat.add(an, Nat.double(rn))), Nat.double(qb), + Nat.mul(Nat.double(qn), bn), Equal.sym(Nat, Nat.mul(Nat.double(qn), bn), Nat.double(qb), R.mul_double(qn, bn))), + Equal.cong(Nat, Nat, kk => Nat.add(Nat.mul(Nat.double(qn), bn), kk), Nat.add(an, Nat.double(rn)), U32.to_nat(su), + Equal.sym(Nat, U32.to_nat(su), Nat.add(an, Nat.double(rn)), es)))) : {Word.to_nat(1n+pp, WCon{a0, hi}) == + Nat.add(Nat.mul(Nat.double(qn), bn), U32.to_nat(su)) : Nat}} + (e_all, hlt) + +# divmod.go.fin, as it picks on whether the shifted remainder reached b +def dm.fin( + +pp: Nat, + +a0: Bool, + +hi: Word(pp), + +bu: U32, + +qw: Word(pp), + +rn: Nat, + +su: U32, + zg: Bool, + +eg: {U32.is_ge(su, bu) == zg : Bool}, + +e1: {Word.to_nat(pp, hi) == Nat.add(Nat.mul(Word.to_nat(pp, qw), U32.to_nat(bu)), rn) : Nat}, + +es: {U32.to_nat(su) == Nat.add(R.bit(a0), Nat.double(rn)) : Nat}, + +hlt: {Nat.is_lt(U32.to_nat(su), Nat.add(U32.to_nat(bu), U32.to_nat(bu))) == True{} : Bool} +) -> dm.ok(1n+pp, WCon{a0, hi}, bu, U32.divmod.go.fin(pp, qw, su, bu, zg)): + match zg: + case True{}: + +hg = {Equal.trans(Bool, Cmp.is_ge(Nat.cmp(U32.to_nat(su), U32.to_nat(bu))), U32.is_ge(su, bu), True{}, + Equal.sym(Bool, U32.is_ge(su, bu), Cmp.is_ge(Nat.cmp(U32.to_nat(su), U32.to_nat(bu))), u.ge(su, bu)), eg) : + {Cmp.is_ge(Nat.cmp(U32.to_nat(su), U32.to_nat(bu))) == True{} : Bool}} + dm.sub(pp, a0, hi, bu, qw, rn, su, e1, es, ge.le(U32.to_nat(su), U32.to_nat(bu), hg), hlt) + case False{}: + +hg = {Equal.trans(Bool, Cmp.is_ge(Nat.cmp(U32.to_nat(su), U32.to_nat(bu))), U32.is_ge(su, bu), False{}, + Equal.sym(Bool, U32.is_ge(su, bu), Cmp.is_ge(Nat.cmp(U32.to_nat(su), U32.to_nat(bu))), u.ge(su, bu)), eg) : + {Cmp.is_ge(Nat.cmp(U32.to_nat(su), U32.to_nat(bu))) == False{} : Bool}} + dm.keep(pp, a0, hi, bu, qw, rn, su, e1, es, nge.lt(U32.to_nat(su), U32.to_nat(bu), hg)) + +# divmod.go.shl: the remainder shifted with the new bit, nothing falling out +def dm.shl( + +pp: Nat, + +a0: Bool, + +hi: Word(pp), + +bu: U32, + +qw: Word(pp), + +rw: Word(32n), + yy: Bool & Word(32n), + hy: sho.ok(32n, a0, rw, yy), + +e1: {Word.to_nat(pp, hi) == Nat.add(Nat.mul(Word.to_nat(pp, qw), U32.to_nat(bu)), Word.to_nat(32n, rw)) : Nat}, + +lt1: {Nat.is_lt(Word.to_nat(32n, rw), U32.to_nat(bu)) == True{} : Bool} +) -> dm.ok(1n+pp, WCon{a0, hi}, bu, U32.divmod.go.shl(pp, qw, bu, yy)): + match yy: + case (tt, +ss): + (e_t, +e_s) = hy + +rn = Word.to_nat(32n, rw) + +hlt = {R.lt_rw_l(Nat.add(R.bit(a0), Nat.double(rn)), U32.to_nat(U32{ss}), Nat.add(U32.to_nat(bu), + U32.to_nat(bu)), Equal.sym(Nat, Word.to_nat(32n, ss), Nat.add(R.bit(a0), Nat.double(rn)), e_s), dbl.lt(a0, rn, + U32.to_nat(bu), lt1)) : {Nat.is_lt(U32.to_nat(U32{ss}), Nat.add(U32.to_nat(bu), U32.to_nat(bu))) == True{} : + Bool}} + %Equal.sym(Bool, tt, False{}, e_t) : dm.ok(1n+pp, WCon{a0, hi}, bu, U32.divmod.go.fin(pp, qw, U32{ss}, bu, + Bool.or(_, U32.is_ge(U32{ss}, bu)))) + dm.fin(pp, a0, hi, bu, qw, rn, U32{ss}, U32.is_ge(U32{ss}, bu), {==}, e1, e_s, hlt) + +# divmod.go.rec with the remainder and the bound taken apart into words +def dm.rec2( + +pp: Nat, + +a0: Bool, + +hi: Word(pp), + +bu: U32, + +qw: Word(pp), + ru: U32, + tu: U32, + +e1: {Word.to_nat(pp, hi) == Nat.add(Nat.mul(Word.to_nat(pp, qw), U32.to_nat(bu)), U32.to_nat(ru)) : Nat}, + +lt1: {Nat.is_lt(U32.to_nat(ru), U32.to_nat(bu)) == True{} : Bool}, + +hb2: {Nat.is_le(Nat.add(U32.to_nat(bu), U32.to_nat(bu)), U32.to_nat(tu)) == True{} : Bool} +) -> dm.ok(1n+pp, WCon{a0, hi}, bu, U32.divmod.go.rec(pp, a0, bu, (qw, ru))): + match ru tu: + case U32{+rw} U32{+tw}: + +rn = Word.to_nat(32n, rw) + +bb = Nat.add(U32.to_nat(bu), U32.to_nat(bu)) + +hbd = {R.le_trans(Nat.add(R.bit(a0), Nat.double(rn)), bb, Word.to_nat(32n, tw), R.lt_le(Nat.add(R.bit(a0), + Nat.double(rn)), bb, dbl.lt(a0, rn, U32.to_nat(bu), lt1)), hb2) : {Nat.is_le(Nat.add(R.bit(a0), + Nat.double(rn)), Word.to_nat(32n, tw)) == True{} : Bool}} + dm.shl(pp, a0, hi, bu, qw, rw, Word.shl.out(32n, a0, rw), sho(32n, a0, rw, tw, hbd), e1, lt1) + +# divmod.go.rec: the bits above, divided, then this bit shifted in +def dm.rec( + +pp: Nat, + +a0: Bool, + +hi: Word(pp), + +bu: U32, + +tu: U32, + xx: Word(pp) & U32, + ih: dm.ok(pp, hi, bu, xx), + +hb2: {Nat.is_le(Nat.add(U32.to_nat(bu), U32.to_nat(bu)), U32.to_nat(tu)) == True{} : Bool} +) -> dm.ok(1n+pp, WCon{a0, hi}, bu, U32.divmod.go.rec(pp, a0, bu, xx)): + match xx: + case (+qw, +ru): + (e1, lt1) = ih + dm.rec2(pp, a0, hi, bu, qw, ru, tu, e1, lt1, hb2) + +# U32.divmod.go by a b above 0 with 2 b some U32's value: the word is q b + r, r below b +def dm( + mm: Nat, + aw: Word(mm), + +bu: U32, + +tu: U32, + +hb0: {Nat.is_lt(0n, U32.to_nat(bu)) == True{} : Bool}, + +hb2: {Nat.is_le(Nat.add(U32.to_nat(bu), U32.to_nat(bu)), U32.to_nat(tu)) == True{} : Bool} +) -> dm.ok(mm, aw, bu, U32.divmod.go(mm, aw, bu)): + match mm aw: + case 0n WNil{}: + ({==}, hb0) + case 1n+(+pp) WCon{+a0, +hi}: + dm.rec(pp, a0, hi, bu, tu, U32.divmod.go(pp, hi, bu), dm(pp, hi, bu, tu, hb0, hb2), hb2) + +# what U32.div and U32.mod give +def dvm.ty(+nu: U32, +bu: U32) -> Type: + {U32.to_nat(nu) == Nat.add(Nat.mul(U32.to_nat(U32.div(nu, bu)), U32.to_nat(bu)), U32.to_nat(U32.mod(nu, bu))) : Nat} + & {Nat.is_lt(U32.to_nat(U32.mod(nu, bu)), U32.to_nat(bu)) == True{} : Bool} + +# the quotient and remainder divmod.go leaves, read by div.fin and mod.fin +def dvm.pair( + +aw: Word(32n), + +bu: U32, + xx: Word(32n) & U32, + hh: dm.ok(32n, aw, bu, xx) +) -> {Word.to_nat(32n, aw) == Nat.add(Nat.mul(U32.to_nat(U32.div.fin(xx)), U32.to_nat(bu)), + U32.to_nat(U32.mod.fin(xx))) : Nat} & {Nat.is_lt(U32.to_nat(U32.mod.fin(xx)), U32.to_nat(bu)) == True{} : Bool}: + match xx: + case (+qw, +ru): + hh + +# U32.div and U32.mod by a nonzero b, once is_zero's answer is named +def dvm.at( + zz: Bool, + +aw: Word(32n), + +bu: U32, + +tu: U32, + +ez: {U32.is_zero(bu) == zz : Bool}, + +hb0: {Nat.is_lt(0n, U32.to_nat(bu)) == True{} : Bool}, + +hb2: {Nat.is_le(Nat.add(U32.to_nat(bu), U32.to_nat(bu)), U32.to_nat(tu)) == True{} : Bool} +) -> {Word.to_nat(32n, aw) == Nat.add(Nat.mul(U32.to_nat(U32.div.if(aw, bu, zz)), U32.to_nat(bu)), + U32.to_nat(U32.mod.if(aw, bu, zz))) : Nat} & {Nat.is_lt(U32.to_nat(U32.mod.if(aw, bu, zz)), U32.to_nat(bu)) == + True{} : Bool}: + match zz: + case False{}: + dvm.pair(aw, bu, U32.divmod.go(32n, aw, bu), dm(32n, aw, bu, tu, hb0, hb2)) + case True{}: + +e0 = {zero.val(bu, Equal.sym(Bool, U32.is_zero(bu), True{}, ez)) : {U32.to_nat(bu) == 0n : Nat}} + Empty.absurd({Word.to_nat(32n, aw) == Nat.add(Nat.mul(U32.to_nat(U32.div.if(aw, bu, True{})), U32.to_nat(bu)), + U32.to_nat(U32.mod.if(aw, bu, True{}))) : Nat} & {Nat.is_lt(U32.to_nat(U32.mod.if(aw, bu, True{})), + U32.to_nat(bu)) == True{} : Bool}, U32L.false_true(Equal.trans(Bool, False{}, Nat.is_lt(0n, U32.to_nat(bu)), + True{}, Equal.cong(Nat, Bool, kk => Nat.is_lt(0n, kk), 0n, U32.to_nat(bu), Equal.sym(Nat, U32.to_nat(bu), 0n, + e0)), hb0))) + +# U32.div and U32.mod: n is q b + r with r below b, for b above 0 whose double +# is some U32's value +def dvm( + nu: U32, + +bu: U32, + +tu: U32, + +hb0: {Nat.is_lt(0n, U32.to_nat(bu)) == True{} : Bool}, + +hb2: {Nat.is_le(Nat.add(U32.to_nat(bu), U32.to_nat(bu)), U32.to_nat(tu)) == True{} : Bool} +) -> dvm.ty(nu, bu): + match nu: + case U32{+aw}: + dvm.at(U32.is_zero(bu), aw, bu, tu, {==}, hb0, hb2) + +# ---- E. adding without a carry out, and the block count ---- + +# the adder's carry out of the top bit +def cy(nn: Nat, aw: Word(nn), bw: Word(nn), cc: Bool) -> Bool: + match nn: + case 0n: + cc + case 1n+pp: + match aw bw cc: + case WCon{False{}, at} WCon{False{}, bt} False{}: + cy(pp, at, bt, False{}) + case WCon{False{}, at} WCon{False{}, bt} True{}: + cy(pp, at, bt, False{}) + case WCon{False{}, at} WCon{True{}, bt} False{}: + cy(pp, at, bt, False{}) + case WCon{False{}, at} WCon{True{}, bt} True{}: + cy(pp, at, bt, True{}) + case WCon{True{}, at} WCon{False{}, bt} False{}: + cy(pp, at, bt, False{}) + case WCon{True{}, at} WCon{False{}, bt} True{}: + cy(pp, at, bt, True{}) + case WCon{True{}, at} WCon{True{}, bt} False{}: + cy(pp, at, bt, True{}) + case WCon{True{}, at} WCon{True{}, bt} True{}: + cy(pp, at, bt, True{}) + +# one bit of cfa: this bit's sum and carry, then the bits above +def cfa.arm( + +pp: Nat, + +at: Word(pp), + +bt: Word(pp), + +ab: Bool, + +bb: Bool, + +cc: Bool, + +ss: Bool, + +kk: Bool, + +e_bits: {Nat.add(R.bit(cc), Nat.add(R.bit(ab), R.bit(bb))) == Nat.add(R.bit(ss), Nat.double(R.bit(kk))) : Nat}, + +er: {Word.to_nat(pp, Word.adc(pp, at, bt, False{}, kk)) == Nat.add(R.bit(kk), Nat.add(Word.to_nat(pp, at), + Word.to_nat(pp, bt))) : Nat} +) -> {Word.to_nat(1n+pp, WCon{ss, Word.adc(pp, at, bt, False{}, kk)}) == Nat.add(R.bit(cc), Nat.add(Word.to_nat(1n+pp, + WCon{ab, at}), Word.to_nat(1n+pp, WCon{bb, bt}))) : Nat}: + +na = Word.to_nat(pp, at) + +nb = Word.to_nat(pp, bt) + +mm = Nat.add(R.bit(kk), Nat.add(na, nb)) + +wa = Word.to_nat(1n+pp, WCon{ab, at}) + +wb = Word.to_nat(1n+pp, WCon{bb, bt}) + +xa = Nat.add(R.bit(ab), Nat.double(na)) + +xb = Nat.add(R.bit(bb), Nat.double(nb)) + +e_in = {Equal.trans(Nat, Nat.add(R.bit(cc), Nat.add(wa, wb)), Nat.add(R.bit(cc), Nat.add(xa, wb)), + Nat.add(R.bit(cc), Nat.add(xa, xb)), + Equal.cong(Nat, Nat, xx => Nat.add(R.bit(cc), Nat.add(xx, wb)), wa, xa, R.to_nat_con(pp, ab, at)), + Equal.cong(Nat, Nat, xx => Nat.add(R.bit(cc), Nat.add(xa, xx)), wb, xb, R.to_nat_con(pp, bb, bt))) : + {Nat.add(R.bit(cc), Nat.add(wa, wb)) == Nat.add(R.bit(cc), Nat.add(xa, xb)) : Nat}} + +e_all = {Equal.trans(Nat, Nat.add(R.bit(cc), Nat.add(wa, wb)), Nat.add(R.bit(cc), Nat.add(xa, xb)), + Nat.add(R.bit(ss), Nat.double(mm)), e_in, R.sum_regroup(R.bit(cc), R.bit(ab), R.bit(bb), R.bit(ss), R.bit(kk), na, + nb, e_bits)) : {Nat.add(R.bit(cc), Nat.add(wa, wb)) == Nat.add(R.bit(ss), Nat.double(mm)) : Nat}} + Equal.trans(Nat, Word.to_nat(1n+pp, WCon{ss, Word.adc(pp, at, bt, False{}, kk)}), + Nat.add(R.bit(ss), Nat.double(Word.to_nat(pp, Word.adc(pp, at, bt, False{}, kk)))), + Nat.add(R.bit(cc), Nat.add(wa, wb)), + R.to_nat_con(pp, ss, Word.adc(pp, at, bt, False{}, kk)), + Equal.trans(Nat, Nat.add(R.bit(ss), Nat.double(Word.to_nat(pp, Word.adc(pp, at, bt, False{}, kk)))), + Nat.add(R.bit(ss), Nat.double(mm)), Nat.add(R.bit(cc), Nat.add(wa, wb)), + Equal.cong(Nat, Nat, xx => Nat.add(R.bit(ss), Nat.double(xx)), Word.to_nat(pp, Word.adc(pp, at, bt, False{}, kk)), + mm, er), + Equal.sym(Nat, Nat.add(R.bit(cc), Nat.add(wa, wb)), Nat.add(R.bit(ss), Nat.double(mm)), e_all))) + +# the adder with no carry out is the sum +def cfa( + nn: Nat, + aw: Word(nn), + bw: Word(nn), + cc: Bool, + +hh: {cy(nn, aw, bw, cc) == False{} : Bool} +) -> {Word.to_nat(nn, Word.adc(nn, aw, bw, False{}, cc)) == Nat.add(R.bit(cc), Nat.add(Word.to_nat(nn, aw), + Word.to_nat(nn, bw))) : Nat}: + match nn: + case 0n: + match aw bw cc: + case WNil{} WNil{} False{}: + {==} + case WNil{} WNil{} True{}: + Empty.absurd({0n == 1n : Nat}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hh))) + case 1n+(+pp): + match aw bw cc: + case WCon{False{}, +at} WCon{False{}, +bt} False{}: + cfa.arm(pp, at, bt, False{}, False{}, False{}, False{}, False{}, {==}, cfa(pp, at, bt, False{}, hh)) + case WCon{False{}, +at} WCon{False{}, +bt} True{}: + cfa.arm(pp, at, bt, False{}, False{}, True{}, True{}, False{}, {==}, cfa(pp, at, bt, False{}, hh)) + case WCon{False{}, +at} WCon{True{}, +bt} False{}: + cfa.arm(pp, at, bt, False{}, True{}, False{}, True{}, False{}, {==}, cfa(pp, at, bt, False{}, hh)) + case WCon{False{}, +at} WCon{True{}, +bt} True{}: + cfa.arm(pp, at, bt, False{}, True{}, True{}, False{}, True{}, {==}, cfa(pp, at, bt, True{}, hh)) + case WCon{True{}, +at} WCon{False{}, +bt} False{}: + cfa.arm(pp, at, bt, True{}, False{}, False{}, True{}, False{}, {==}, cfa(pp, at, bt, False{}, hh)) + case WCon{True{}, +at} WCon{False{}, +bt} True{}: + cfa.arm(pp, at, bt, True{}, False{}, True{}, False{}, True{}, {==}, cfa(pp, at, bt, True{}, hh)) + case WCon{True{}, +at} WCon{True{}, +bt} False{}: + cfa.arm(pp, at, bt, True{}, True{}, False{}, False{}, True{}, {==}, cfa(pp, at, bt, True{}, hh)) + case WCon{True{}, +at} WCon{True{}, +bt} True{}: + cfa.arm(pp, at, bt, True{}, True{}, True{}, True{}, True{}, {==}, cfa(pp, at, bt, True{}, hh)) + +# the carry out of a U32 add +def cy32(uu: U32, vv: U32) -> Bool: + match uu vv: + case U32{xw} U32{yw}: + cy(32n, xw, yw, False{}) + +# a U32 add with no carry out is the sum +def add.cf(uu: U32, vv: U32, +hh: {cy32(uu, vv) == False{} : Bool}) -> {U32.to_nat(U32.add(uu, vv)) == + Nat.add(U32.to_nat(uu), U32.to_nat(vv)) : Nat}: + match uu vv: + case U32{+xw} U32{+yw}: + cfa(32n, xw, yw, False{}, hh) + +# the block size doubled is a U32's value +def mx.dbl(+mx: U32, +emx: {mx == 65535 : U32}) -> {U32.to_nat(U32.add(mx, mx)) == Nat.add(U32.to_nat(mx), + U32.to_nat(mx)) : Nat}: + add.cf(mx, mx, Equal.cong(U32, Bool, uu => cy32(uu, uu), mx, 65535, emx)) + +# the block size is at least 2 +def mx.two(+mx: U32, +emx: {mx == 65535 : U32}) -> {U32.to_nat(mx) == 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32)) : + Nat}: + +m1 = (mx - 1 : U32) + +nz1 = {Equal.cong(U32, Bool, uu => U32.is_zero((uu - 1 : U32)), mx, 65535, emx) : {U32.is_zero(m1) == False{} : + Bool}} + Equal.trans(Nat, U32.to_nat(mx), 1n+U32.to_nat(m1), 2n+U32.to_nat((m1 - 1 : U32)), Wp1.u32_dec(mx, mx.nz(mx, emx)), + Equal.cong(Nat, Nat, kk => 1n+kk, U32.to_nat(m1), 1n+U32.to_nat((m1 - 1 : U32)), Wp1.u32_dec(m1, nz1))) + +# k blocks of m bytes hold x bytes with the last block not empty: k is ceil(x / m) +def kok(+xn: Nat, kk: Nat, +mn: Nat) -> Type: + match kk: + case 0n: + {xn == 0n : Nat} + case 1n+(+kp): + {Nat.is_lt(Nat.mul(kp, mn), xn) == True{} : Bool} & {Nat.is_le(xn, Nat.mul(1n+kp, mn)) == True{} : Bool} + +# x below x + y when y is above 0 +def lt.more(+xx: Nat, +yy: Nat, +hh: {Nat.is_lt(0n, yy) == True{} : Bool}) -> {Nat.is_lt(xx, Nat.add(xx, yy)) == True{} : + Bool}: + R.lt_rw_l(Nat.add(xx, 0n), xx, Nat.add(xx, yy), R.add_zero(xx), R.lt_add_mono(xx, 0n, yy, hh)) + +# q blocks exactly: ceil(q m / m) is q +def nb.exact( + qn: Nat, + +mn: Nat, + +xn: Nat, + +ee: {xn == Nat.mul(qn, mn) : Nat}, + +hm: {Nat.is_lt(0n, mn) == True{} : Bool} +) -> kok(xn, qn, mn): + match qn: + case 0n: + ee + case 1n+(+kp): + +km = Nat.mul(kp, mn) + +e2 = {Equal.trans(Nat, xn, Nat.add(mn, km), Nat.add(km, mn), ee, R.add_comm(mn, km)) : {xn == Nat.add(km, mn) : + Nat}} + (R.lt_rw_r(km, Nat.add(km, mn), xn, Equal.sym(Nat, xn, Nat.add(km, mn), e2), lt.more(km, mn, hm)), + R.le_rw_l(Nat.mul(1n+kp, mn), xn, Nat.mul(1n+kp, mn), Equal.sym(Nat, xn, Nat.mul(1n+kp, mn), ee), + R.le_refl(Nat.mul(1n+kp, mn)))) + +# q blocks and a remainder r from 1 to m - 1: ceil is q + 1 +def nb.rem( + +qn: Nat, + +mn: Nat, + +xn: Nat, + +rn: Nat, + +ee: {xn == Nat.add(Nat.mul(qn, mn), rn) : Nat}, + +h1: {Nat.is_lt(0n, rn) == True{} : Bool}, + +hr: {Nat.is_lt(rn, mn) == True{} : Bool} +) -> kok(xn, 1n+qn, mn): + +qm = Nat.mul(qn, mn) + (R.lt_rw_r(qm, Nat.add(qm, rn), xn, Equal.sym(Nat, xn, Nat.add(qm, rn), ee), lt.more(qm, rn, h1)), + R.le_rw_l(Nat.add(qm, rn), xn, Nat.mul(1n+qn, mn), Equal.sym(Nat, xn, Nat.add(qm, rn), ee), R.le_rw_r(Nat.add(qm, + rn), Nat.add(qm, mn), Nat.mul(1n+qn, mn), R.add_comm(qm, mn), R.le_add_mono(qm, rn, mn, R.lt_le(rn, mn, hr))))) + +# x at most x times m for m above 0 +def le.mul(+xx: Nat, +mn: Nat, +hm: {Nat.is_lt(0n, mn) == True{} : Bool}) -> {Nat.is_le(xx, Nat.mul(xx, mn)) == True{} : + Bool}: + +h1 = {Equal.trans(Bool, Nat.is_le(1n, mn), Nat.is_lt(0n, mn), True{}, Equal.sym(Bool, Nat.is_lt(0n, mn), + Nat.is_le(1n, mn), R.lt_le_succ(0n, mn)), hm) : {Nat.is_le(1n, mn) == True{} : Bool}} + R.le_rw_l(Nat.mul(1n, xx), xx, Nat.mul(xx, mn), R.add_zero(xx), R.le_rw_r(Nat.mul(1n, xx), Nat.mul(mn, xx), + Nat.mul(xx, mn), R.mul_comm(mn, xx), R.le_mul_mono(1n, mn, xx, h1))) + +# enc.nblk with the block size named +def nblk.m(+nn: U32, +mx: U32) -> U32: + Png.enc.nblk.at(U32.is_zero(U32.mod(nn, mx)), U32.div(nn, mx)) + +# enc.nblk is nblk.m at 65535 +def nblk.eq(+nn: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> {Png.enc.nblk(nn) == nblk.m(nn, mx) : U32}: + Equal.cong(U32, U32, uu => Png.enc.nblk.at(U32.is_zero(U32.mod(nn, uu)), U32.div(nn, uu)), 65535, mx, Equal.sym(U32, + mx, 65535, emx)) + +# nblk.m, once whether the remainder is zero is named +def nb.at( + zz: Bool, + +nn: U32, + +mx: U32, + +ez: {U32.is_zero(U32.mod(nn, mx)) == zz : Bool}, + +e_n: {U32.to_nat(nn) == Nat.add(Nat.mul(U32.to_nat(U32.div(nn, mx)), U32.to_nat(mx)), U32.to_nat(U32.mod(nn, + mx))) : Nat}, + +l_r: {Nat.is_lt(U32.to_nat(U32.mod(nn, mx)), U32.to_nat(mx)) == True{} : Bool}, + +hm: {Nat.is_lt(0n, U32.to_nat(mx)) == True{} : Bool} +) -> kok(U32.to_nat(nn), U32.to_nat(Png.enc.nblk.at(zz, U32.div(nn, mx))), U32.to_nat(mx)): + match zz: + case True{}: + +qu = U32.div(nn, mx) + +ru = U32.mod(nn, mx) + +qn = U32.to_nat(qu) + +mn = U32.to_nat(mx) + +xn = U32.to_nat(nn) + +e0 = {zero.val(ru, Equal.sym(Bool, U32.is_zero(ru), True{}, ez)) : {U32.to_nat(ru) == 0n : Nat}} + nb.exact(qn, mn, xn, Equal.trans(Nat, xn, Nat.add(Nat.mul(qn, mn), 0n), Nat.mul(qn, mn), Equal.trans(Nat, xn, + Nat.add(Nat.mul(qn, mn), U32.to_nat(ru)), Nat.add(Nat.mul(qn, mn), 0n), e_n, Equal.cong(Nat, Nat, kk => + Nat.add(Nat.mul(qn, mn), kk), U32.to_nat(ru), 0n, e0)), R.add_zero(Nat.mul(qn, mn))), hm) + case False{}: + +qu = U32.div(nn, mx) + +ru = U32.mod(nn, mx) + +qn = U32.to_nat(qu) + +mn = U32.to_nat(mx) + +xn = U32.to_nat(nn) + +h1 = {Equal.trans(Bool, Nat.is_lt(0n, U32.to_nat(ru)), Bool.not(Nat.is_eq(U32.to_nat(ru), 0n)), True{}, + R.pos_eq(U32.to_nat(ru)), Equal.cong(Bool, Bool, bb => Bool.not(bb), Nat.is_eq(U32.to_nat(ru), 0n), False{}, + Equal.trans(Bool, Nat.is_eq(U32.to_nat(ru), 0n), U32.is_zero(ru), False{}, Equal.sym(Bool, U32.is_zero(ru), + Nat.is_eq(U32.to_nat(ru), U32.to_nat(0)), R.u32_eq(ru, 0)), ez))) : {Nat.is_lt(0n, U32.to_nat(ru)) == True{} : + Bool}} + +h_q1 = {R.le_rw_r(Nat.add(qn, 1n), Nat.add(Nat.mul(qn, mn), U32.to_nat(ru)), xn, Equal.sym(Nat, xn, + Nat.add(Nat.mul(qn, mn), U32.to_nat(ru)), e_n), R.le_add_both(qn, Nat.mul(qn, mn), 1n, U32.to_nat(ru), + le.mul(qn, mn, hm), Equal.trans(Bool, Nat.is_le(1n, U32.to_nat(ru)), Nat.is_lt(0n, U32.to_nat(ru)), True{}, + Equal.sym(Bool, Nat.is_lt(0n, U32.to_nat(ru)), Nat.is_le(1n, U32.to_nat(ru)), R.lt_le_succ(0n, + U32.to_nat(ru))), h1))) : {Nat.is_le(Nat.add(qn, 1n), xn) == True{} : Bool}} + +e_q1 = {Equal.trans(Nat, U32.to_nat((qu + 1 : U32)), Nat.add(qn, 1n), 1n+qn, R.u32_add_below(qu, 1, nn, h_q1), + W9.add.one.nat(qn)) : {U32.to_nat((qu + 1 : U32)) == 1n+qn : Nat}} + %Equal.sym(Nat, U32.to_nat((qu + 1 : U32)), 1n+qn, e_q1) : kok(xn, _, mn) + nb.rem(qn, mn, xn, U32.to_nat(ru), e_n, h1, l_r) + +# the pair U32.div and U32.mod give, taken apart +def nb.go( + +nn: U32, + +mx: U32, + pr: dvm.ty(nn, mx), + +hm: {Nat.is_lt(0n, U32.to_nat(mx)) == True{} : Bool} +) -> kok(U32.to_nat(nn), U32.to_nat(nblk.m(nn, mx)), U32.to_nat(mx)): + (+e_n, +l_r) = pr + nb.at(U32.is_zero(U32.mod(nn, mx)), nn, mx, {==}, e_n, l_r, hm) + +# enc.nblk(n) blocks of 65535 bytes hold n bytes, the last one not empty +def nb.k(+nn: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> kok(U32.to_nat(nn), U32.to_nat(Png.enc.nblk(nn)), + U32.to_nat(mx)): + +mn = U32.to_nat(mx) + +hm = {Equal.trans(Bool, Nat.is_lt(0n, mn), Nat.is_lt(0n, 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32))), True{}, + Equal.cong(Nat, Bool, kk => Nat.is_lt(0n, kk), mn, 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32)), mx.two(mx, emx)), + {==}) : {Nat.is_lt(0n, mn) == True{} : Bool}} + +h2 = {R.le_rw_r(Nat.add(mn, mn), Nat.add(mn, mn), U32.to_nat(U32.add(mx, mx)), Equal.sym(Nat, + U32.to_nat(U32.add(mx, mx)), Nat.add(mn, mn), mx.dbl(mx, emx)), R.le_refl(Nat.add(mn, mn))) : + {Nat.is_le(Nat.add(mn, mn), U32.to_nat(U32.add(mx, mx))) == True{} : Bool}} + %Equal.sym(U32, Png.enc.nblk(nn), nblk.m(nn, mx), nblk.eq(nn, mx, emx)) : kok(U32.to_nat(nn), U32.to_nat(_), mn) + nb.go(nn, mx, dvm(nn, mx, U32.add(mx, mx), hm, h2), hm) + +# ---- F. how many bytes bs writes ---- + +# at most 0 is 0 +def le.zero(xx: Nat, +hh: {Nat.is_le(xx, 0n) == True{} : Bool}) -> {xx == 0n : Nat}: + match xx: + case 0n: + {==} + case 1n+pp: + Empty.absurd({1n+pp == 0n : Nat}, U32L.false_true(hh)) + +# nothing is below itself +def lt.irr(mm: Nat, +hh: {Nat.is_lt(mm, mm) == True{} : Bool}) -> Empty: + match mm: + case 0n: + U32L.false_true(hh) + case 1n+pp: + lt.irr(pp, hh) + +# m + x is not below m +def lt.self(+mm: Nat, +xx: Nat, +hh: {Nat.is_lt(Nat.add(mm, xx), mm) == True{} : Bool}) -> Empty: + lt.irr(mm, R.le_lt_trans(mm, Nat.add(mm, xx), mm, Wp2.nle_add(mm, xx), hh)) + +# a sum that is 0 has a right part 0 +def add.zero.r(aa: Nat, +bb: Nat, +hh: {Nat.add(aa, bb) == 0n : Nat}) -> {bb == 0n : Nat}: + match aa: + case 0n: + hh + case 1n+pp: + Empty.absurd({bb == 0n : Nat}, Wp1.zero_succ(Nat.add(pp, bb), Equal.sym(Nat, 1n+Nat.add(pp, bb), 0n, hh))) + +# no bytes left, no blocks left +def kok.nil(kk: Nat, +mn: Nat, hk: kok(0n, kk, mn)) -> {Nat.mul(kk, 5n) == 0n : Nat}: + match kk: + case 0n: + {==} + case 1n+(+kp): + (h_lt, _h_le) = hk + Empty.absurd({Nat.mul(1n+kp, 5n) == 0n : Nat}, U32L.false_true(Equal.trans(Bool, False{}, Nat.is_lt(Nat.mul(kp, + mn), 0n), True{}, R.lt_zero_false(Nat.mul(kp, mn)), h_lt))) + +# a new block's room after its first byte is at most the bytes after it +def ks.le( + zz: Bool, + +left: U32, + +mx: U32, + +nt: Nat, + +nzm: {U32.is_zero(mx) == False{} : Bool}, + +ez: {U32.is_le(left, mx) == zz : Bool}, + +hn: {U32.to_nat(left) == 1n+nt : Nat} +) -> {Nat.is_le(U32.to_nat((capm(zz, left, mx) - 1 : U32)), nt) == True{} : Bool}: + match zz: + case True{}: + R.le_rw_l(nt, U32.to_nat((left - 1 : U32)), nt, Equal.sym(Nat, U32.to_nat((left - 1 : U32)), nt, + Wp1.u32_pred(left, nt, hn)), R.le_refl(nt)) + case False{}: + +m1 = (mx - 1 : U32) + +e_m = {Wp1.u32_dec(mx, nzm) : {U32.to_nat(mx) == 1n+U32.to_nat(m1) : Nat}} + +h0 = {Equal.trans(Bool, Nat.is_le(1n+nt, 1n+U32.to_nat(m1)), U32.is_le(left, mx), False{}, + Equal.sym(Bool, U32.is_le(left, mx), Nat.is_le(1n+nt, 1n+U32.to_nat(m1)), Equal.trans(Bool, + U32.is_le(left, mx), Nat.is_le(U32.to_nat(left), U32.to_nat(mx)), Nat.is_le(1n+nt, 1n+U32.to_nat(m1)), + R.u32_le(left, mx), Equal.trans(Bool, Nat.is_le(U32.to_nat(left), U32.to_nat(mx)), Nat.is_le(1n+nt, + U32.to_nat(mx)), Nat.is_le(1n+nt, 1n+U32.to_nat(m1)), Equal.cong(Nat, Bool, xx => Nat.is_le(xx, + U32.to_nat(mx)), U32.to_nat(left), 1n+nt, hn), Equal.cong(Nat, Bool, xx => Nat.is_le(1n+nt, xx), + U32.to_nat(mx), 1n+U32.to_nat(m1), e_m)))), ez) : {Nat.is_le(nt, U32.to_nat(m1)) == False{} : Bool}} + R.lt_le(U32.to_nat(m1), nt, nle.lt(nt, U32.to_nat(m1), h0)) + +# the blocks after a new block: one fewer than before it +def ks.k( + zz: Bool, + kp: Nat, + +left: U32, + +mx: U32, + +nt: Nat, + +nzm: {U32.is_zero(mx) == False{} : Bool}, + +ez: {U32.is_le(left, mx) == zz : Bool}, + +hn: {U32.to_nat(left) == 1n+nt : Nat}, + +h_lt: {Nat.is_lt(Nat.mul(kp, U32.to_nat(mx)), 1n+nt) == True{} : Bool}, + +h_le: {Nat.is_le(1n+nt, Nat.add(U32.to_nat(mx), Nat.mul(kp, U32.to_nat(mx)))) == True{} : Bool} +) -> kok(Nat.sub(nt, U32.to_nat((capm(zz, left, mx) - 1 : U32))), kp, U32.to_nat(mx)): + match zz kp: + case True{} 0n: + +e_l = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat((left - 1 : U32)) == nt : Nat}} + Equal.trans(Nat, Nat.sub(nt, U32.to_nat((left - 1 : U32))), Nat.sub(nt, nt), 0n, Equal.cong(Nat, Nat, xx => + Nat.sub(nt, xx), U32.to_nat((left - 1 : U32)), nt, e_l), R.sub_zero_le(nt, nt, R.le_refl(nt))) + case True{} 1n+(+k2): + +mn = U32.to_nat(mx) + +h0 = {Equal.trans(Bool, Nat.is_le(U32.to_nat(left), mn), U32.is_le(left, mx), True{}, Equal.sym(Bool, + U32.is_le(left, mx), Nat.is_le(U32.to_nat(left), mn), R.u32_le(left, mx)), ez) : {Nat.is_le(U32.to_nat(left), + mn) == True{} : Bool}} + +h1 = {R.le_rw_l(U32.to_nat(left), 1n+nt, mn, hn, h0) : {Nat.is_le(1n+nt, mn) == True{} : Bool}} + Empty.absurd(kok(Nat.sub(nt, U32.to_nat((left - 1 : U32))), 1n+k2, mn), lt.self(mn, Nat.mul(k2, mn), + R.lt_le_trans(Nat.add(mn, Nat.mul(k2, mn)), 1n+nt, mn, h_lt, h1))) + case False{} 0n: + +mn = U32.to_nat(mx) + +m1 = U32.to_nat((mx - 1 : U32)) + +xn = Nat.sub(nt, m1) + +e_m = {Wp1.u32_dec(mx, nzm) : {mn == 1n+m1 : Nat}} + +h_m = {ks.le(False{}, left, mx, nt, nzm, ez, hn) : {Nat.is_le(m1, nt) == True{} : Bool}} + +e_x = {Equal.trans(Nat, 1n+nt, 1n+Nat.add(m1, xn), Nat.add(mn, xn), Equal.cong(Nat, Nat, kk => 1n+kk, nt, + Nat.add(m1, xn), Equal.sym(Nat, Nat.add(m1, xn), nt, R.add_sub(m1, nt, h_m))), Equal.cong(Nat, Nat, kk => + Nat.add(kk, xn), 1n+m1, mn, Equal.sym(Nat, mn, 1n+m1, e_m))) : {1n+nt == Nat.add(mn, xn) : Nat}} + +h2 = {R.le_rw_l(1n+nt, Nat.add(mn, xn), Nat.add(mn, 0n), e_x, h_le) : {Nat.is_le(Nat.add(mn, xn), Nat.add(mn, + 0n)) == True{} : Bool}} + le.zero(xn, R.le_cancel(mn, xn, 0n, h2)) + case False{} 1n+(+k2): + +mn = U32.to_nat(mx) + +m1 = U32.to_nat((mx - 1 : U32)) + +xn = Nat.sub(nt, m1) + +km = Nat.mul(k2, mn) + +e_m = {Wp1.u32_dec(mx, nzm) : {mn == 1n+m1 : Nat}} + +h_m = {ks.le(False{}, left, mx, nt, nzm, ez, hn) : {Nat.is_le(m1, nt) == True{} : Bool}} + +e_x = {Equal.trans(Nat, 1n+nt, 1n+Nat.add(m1, xn), Nat.add(mn, xn), Equal.cong(Nat, Nat, kk => 1n+kk, nt, + Nat.add(m1, xn), Equal.sym(Nat, Nat.add(m1, xn), nt, R.add_sub(m1, nt, h_m))), Equal.cong(Nat, Nat, kk => + Nat.add(kk, xn), 1n+m1, mn, Equal.sym(Nat, mn, 1n+m1, e_m))) : {1n+nt == Nat.add(mn, xn) : Nat}} + (R.lt_cancel(mn, km, xn, R.lt_rw_r(Nat.add(mn, km), 1n+nt, Nat.add(mn, xn), e_x, h_lt)), R.le_cancel(mn, xn, + Nat.mul(1n+k2, mn), R.le_rw_l(1n+nt, Nat.add(mn, xn), Nat.add(mn, Nat.mul(1n+k2, mn)), e_x, h_le))) + +# what cnt proves: bs writes its bytes and 5 more for each block header +def cnt.ty( + +xs: List<&2, U32>, + +znew: Bool, + +zlast: Bool, + +rp: U32, + +left: U32, + +plen: U32, + +pbf: U32, + +kk: Nat +) -> Type: + {List.length(&2, U32, bs(xs, znew, zlast, rp, left, plen, pbf)) == Nat.add(List.length(&2, U32, xs), Nat.mul(kk, + 5n)) : Nat} + +# the header, the first byte and the rest of a new block: six more bytes +def cnt.open( + +h: U32, + +t: List<&2, U32>, + +l2: U32, + +plen: U32, + +pbf: U32, + +kp: Nat, + +ih: {List.length(&2, U32, bs(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), + l2, Png.enc.cap(l2), Png.enc.bf(l2))) == Nat.add(List.length(&2, U32, t), Nat.mul(kp, 5n)) : Nat} +) -> {List.length(&2, U32, open.bs(h, t, l2, plen, pbf)) == Nat.add(1n+List.length(&2, U32, t), Nat.mul(1n+kp, 5n)) : + Nat}: + +nt = List.length(&2, U32, t) + +k5 = Nat.mul(kp, 5n) + Equal.trans(Nat, 6n+List.length(&2, U32, bs(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), + (plen - 1 : U32), l2, Png.enc.cap(l2), Png.enc.bf(l2))), 6n+Nat.add(nt, k5), 1n+Nat.add(nt, 5n+k5), + Equal.cong(Nat, Nat, xx => 6n+xx, List.length(&2, U32, bs(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : + U32), 1), (plen - 1 : U32), l2, Png.enc.cap(l2), Png.enc.bf(l2))), Nat.add(nt, k5), ih), + Equal.cong(Nat, Nat, xx => 1n+xx, 5n+Nat.add(nt, k5), Nat.add(nt, 5n+k5), Equal.sym(Nat, Nat.add(nt, 5n+k5), + 5n+Nat.add(nt, k5), R.add_swap(nt, 5n, k5)))) + +# kok along an equation of the byte count +def kok.rw(+xa: Nat, +xb: Nat, +kk: Nat, +mn: Nat, +ee: {xa == xb : Nat}, hk: kok(xa, kk, mn)) -> kok(xb, kk, mn): + %ee : kok(_, kk, mn) + hk + +# a new block with kp + 1 blocks to go: the header and the first byte, then +# the rest of the walk, with kp blocks after this one +def cnt.edge( + +h: U32, + +t: List<&2, U32>, + +left: U32, + +plen: U32, + +pbf: U32, + +mx: U32, + +emx: {mx == 65535 : U32}, + +kp: Nat, + +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, t) : Nat}, + +h_lt: {Nat.is_lt(Nat.mul(kp, U32.to_nat(mx)), 1n+List.length(&2, U32, t)) == True{} : Bool}, + +h_le: {Nat.is_le(1n+List.length(&2, U32, t), Nat.add(U32.to_nat(mx), Nat.mul(kp, U32.to_nat(mx)))) == True{} : + Bool}, + pe: {plen == Png.enc.cap(left) : U32} & {pbf == Png.enc.bf(left) : U32}, + cnt_t: @xn: Nat -> {Nat.add(U32.to_nat((plen - 1 : U32)), xn) == List.length(&2, U32, t) : Nat} -> kok(xn, kp, + U32.to_nat(mx)) -> cnt.ty(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), + (left - 1 : U32), Png.enc.cap((left - 1 : U32)), Png.enc.bf((left - 1 : U32)), kp) +) -> {List.length(&2, U32, open.bs(h, t, (left - 1 : U32), plen, pbf)) == Nat.add(1n+List.length(&2, U32, t), + Nat.mul(1n+kp, 5n)) : Nat}: + (+e_plen, _e_pbf) = pe + +nt = List.length(&2, U32, t) + +zz = U32.is_le(left, 65535) + +cm = capm(zz, left, mx) + +mn = U32.to_nat(mx) + +c2 = U32.to_nat((plen - 1 : U32)) + +nzm = {mx.nz(mx, emx) : {U32.is_zero(mx) == False{} : Bool}} + +ezm = {le.mx(left, mx, emx) : {U32.is_le(left, mx) == zz : Bool}} + +e_c = {Equal.cong(U32, Nat, uu => U32.to_nat((uu - 1 : U32)), plen, cm, Equal.trans(U32, plen, Png.enc.cap(left), cm, + e_plen, cap.m(zz, left, mx, emx))) : {c2 == U32.to_nat((cm - 1 : U32)) : Nat}} + +h_c = {R.le_rw_l(U32.to_nat((cm - 1 : U32)), c2, nt, Equal.sym(Nat, c2, U32.to_nat((cm - 1 : U32)), e_c), ks.le(zz, + left, mx, nt, nzm, ezm, hn)) : {Nat.is_le(c2, nt) == True{} : Bool}} + +x2 = Nat.sub(nt, c2) + +hx2 = {R.add_sub(c2, nt, h_c) : {Nat.add(c2, x2) == nt : Nat}} + hk2 = kok.rw(Nat.sub(nt, U32.to_nat((cm - 1 : U32))), x2, kp, mn, Equal.cong(Nat, Nat, kk => Nat.sub(nt, kk), + U32.to_nat((cm - 1 : U32)), c2, Equal.sym(Nat, c2, U32.to_nat((cm - 1 : U32)), e_c)), ks.k(zz, kp, left, mx, nt, + nzm, ezm, hn, h_lt, h_le)) + cnt.open(h, t, (left - 1 : U32), plen, pbf, kp, cnt_t(x2, hx2, hk2)) + +# bs from a state: its bytes, and a header for each of the kk blocks it opens, +# xn the bytes after the open block (rp of them still in it) +def cnt( + xs: List<&2, U32>, + znew: Bool, + zlast: Bool, + +kk: Nat, + +rp: U32, + +left: U32, + +plen: U32, + +pbf: U32, + +mx: U32, + +xn: Nat, + +emx: {mx == 65535 : U32}, + +hzn: {znew == U32.is_zero(rp) : Bool}, + +hzl: {zlast == U32.is_eq(rp, 1) : Bool}, + +hn: {U32.to_nat(left) == List.length(&2, U32, xs) : Nat}, + +hx: {Nat.add(U32.to_nat(rp), xn) == List.length(&2, U32, xs) : Nat}, + hk: kok(xn, kk, U32.to_nat(mx)), + hb: at.edge(rp, left, plen, pbf) +) -> cnt.ty(xs, znew, zlast, rp, left, plen, pbf, kk): + match xs znew zlast: + case Nil{} _zn _zl: + +e_x = {add.zero.r(U32.to_nat(rp), xn, hx) : {xn == 0n : Nat}} + Equal.sym(Nat, Nat.mul(kk, 5n), 0n, kok.nil(kk, U32.to_nat(mx), kok.rw(xn, 0n, kk, U32.to_nat(mx), e_x, hk))) + case +h <> +t False{} False{}: + +rp2 = (rp - 1 : U32) + +l2 = (left - 1 : U32) + +nt = List.length(&2, U32, t) + +nz_rp = {Equal.sym(Bool, False{}, U32.is_zero(rp), hzn) : {U32.is_zero(rp) == False{} : Bool}} + +e_rp = {Wp1.u32_dec(rp, nz_rp) : {U32.to_nat(rp) == 1n+U32.to_nat(rp2) : Nat}} + +nz_rp2 = {two(rp, hzn, hzl) : {U32.is_zero(rp2) == False{} : Bool}} + +hx2 = {Wp1.succ_inj(Nat.add(U32.to_nat(rp2), xn), nt, Equal.trans(Nat, 1n+Nat.add(U32.to_nat(rp2), xn), + Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, xn), 1n+U32.to_nat(rp2), + U32.to_nat(rp), Equal.sym(Nat, U32.to_nat(rp), 1n+U32.to_nat(rp2), e_rp)), hx)) : {Nat.add(U32.to_nat(rp2), + xn) == nt : Nat}} + +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} + Equal.cong(Nat, Nat, x2 => 1n+x2, List.length(&2, U32, bs(t, False{}, U32.is_eq(rp2, 1), rp2, l2, plen, pbf)), + Nat.add(nt, Nat.mul(kk, 5n)), cnt(t, False{}, U32.is_eq(rp2, 1), kk, rp2, l2, plen, pbf, mx, xn, emx, + Equal.sym(Bool, U32.is_zero(rp2), False{}, nz_rp2), {==}, hn2, hx2, hk, edge.no(rp2, l2, plen, pbf, nz_rp2))) + case +h <> +t False{} True{}: + +l2 = (left - 1 : U32) + +nt = List.length(&2, U32, t) + +e_rp = {one.val(rp, hzl) : {U32.to_nat(rp) == 1n : Nat}} + +hx2 = {Wp1.succ_inj(xn, nt, Equal.trans(Nat, 1n+xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, + kk2 => Nat.add(kk2, xn), 1n, U32.to_nat(rp), Equal.sym(Nat, U32.to_nat(rp), 1n, e_rp)), hx)) : + {Nat.add(U32.to_nat(0), xn) == nt : Nat}} + +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} + Equal.cong(Nat, Nat, x2 => 1n+x2, List.length(&2, U32, bs(t, True{}, False{}, 0, l2, Png.enc.cap(l2), + Png.enc.bf(l2))), Nat.add(nt, Nat.mul(kk, 5n)), cnt(t, True{}, False{}, kk, 0, l2, Png.enc.cap(l2), + Png.enc.bf(l2), mx, xn, emx, {==}, {==}, hn2, hx2, hk, _ez => ({==}, {==}))) + case +h <> +t True{} _zl: + match kk: + case 0n: + +nt = List.length(&2, U32, t) + +e0 = {zero.val(rp, hzn) : {U32.to_nat(rp) == 0n : Nat}} + +e_xn = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, xn), + 0n, U32.to_nat(rp), Equal.sym(Nat, U32.to_nat(rp), 0n, e0)), hx) : {xn == 1n+nt : Nat}} + Empty.absurd(cnt.ty(h <> t, True{}, _zl, rp, left, plen, pbf, 0n), Wp1.zero_succ(nt, Equal.trans(Nat, 0n, xn, + 1n+nt, Equal.sym(Nat, xn, 0n, hk), e_xn))) + case 1n+(+kp): + (+h_lt, +h_le) = hk + +nt = List.length(&2, U32, t) + +l2 = (left - 1 : U32) + +mn = U32.to_nat(mx) + +e0 = {zero.val(rp, hzn) : {U32.to_nat(rp) == 0n : Nat}} + +e_xn = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, xn), + 0n, U32.to_nat(rp), Equal.sym(Nat, U32.to_nat(rp), 0n, e0)), hx) : {xn == 1n+nt : Nat}} + +ez = {Equal.sym(Bool, True{}, U32.is_zero(rp), hzn) : {U32.is_zero(rp) == True{} : Bool}} + +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} + cnt.edge(h, t, left, plen, pbf, mx, emx, kp, hn, R.lt_rw_r(Nat.mul(kp, mn), xn, 1n+nt, e_xn, h_lt), + R.le_rw_l(xn, 1n+nt, Nat.mul(1n+kp, mn), e_xn, h_le), hb(ez), x2 => a1 => a2 => cnt(t, U32.is_zero((plen - 1 + : U32)), U32.is_eq((plen - 1 : U32), 1), kp, (plen - 1 : U32), l2, Png.enc.cap(l2), Png.enc.bf(l2), mx, x2, + emx, {==}, {==}, hn2, a1, a2, _ez => ({==}, {==}))) + +# the blocks enc.blocks writes for more than one block: the bytes, and 5 for +# each of the enc.nblk block headers +def cnt.blocks( + +xs: List<&2, U32>, + +mx: U32, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(Png.enc.len(xs, 0)) == List.length(&2, U32, xs) : Nat}, + +hbig: {U32.is_le(Png.enc.len(xs, 0), 65535) == False{} : Bool} +) -> {List.length(&2, U32, Png.enc.blocks(65535, xs)) == Nat.add(List.length(&2, U32, xs), + Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(xs, 0))), 5n)) : Nat}: + +nn = Png.enc.len(xs, 0) + +kk = U32.to_nat(Png.enc.nblk(nn)) + +bb = bs(xs, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn)) + Equal.trans(Nat, List.length(&2, U32, Png.enc.blocks(65535, xs)), List.length(&2, U32, bb), Nat.add(List.length(&2, + U32, xs), Nat.mul(kk, 5n)), Equal.cong(List<&2, U32>, Nat, ys => List.length(&2, U32, ys), Png.enc.blocks(65535, + xs), bb, sim.blocks(xs, mx, emx, hn, hbig)), cnt(xs, True{}, False{}, kk, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn), mx, + List.length(&2, U32, xs), emx, {==}, {==}, hn, {==}, kok.rw(U32.to_nat(nn), List.length(&2, U32, xs), kk, + U32.to_nat(mx), hn, nb.k(nn, mx, emx)), _ez => ({==}, {==}))) + +# ---- G. the wide file, laid out as spec.png ---- + +# the CRC register and the accumulator after a run of bytes +def fr(+xs: List<&2, U32>, +cc: U32, +acc: List<&2, U32>) -> U32 & List<&2, U32>: + (Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) + +# folding a list then more is folding both +def fold.app( + xs: List<&2, U32>, + +ys: List<&2, U32>, + +cc: U32 +) -> {Crc.crc.fold(List.append(&2, U32, xs, ys), cc) == Crc.crc.fold(ys, Crc.crc.fold(xs, cc)) : U32}: + match xs: + case Nil{}: + {==} + case +hd <> tl: + fold.app(tl, ys, Crc.crc.byte(cc, hd)) + +# a run, then more: one run over both +def fr.app( + +xs: List<&2, U32>, + +ys: List<&2, U32>, + +cc: U32, + +acc: List<&2, U32> +) -> {fr(ys, Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) == fr(List.append(&2, U32, xs, ys), cc, acc) : + U32 & List<&2, U32>}: + +f2 = Crc.crc.fold(ys, Crc.crc.fold(xs, cc)) + +fa = Crc.crc.fold(List.append(&2, U32, xs, ys), cc) + +r2 = List.reverse.go(&2, U32, ys, List.reverse.go(&2, U32, xs, acc)) + +ra = List.reverse.go(&2, U32, List.append(&2, U32, xs, ys), acc) + Equal.trans(U32 & List<&2, U32>, (f2, r2), (fa, r2), (fa, ra), + Equal.cong(U32, U32 & List<&2, U32>, uu => (uu, r2), f2, fa, Equal.sym(U32, fa, f2, fold.app(xs, ys, cc))), + Equal.cong(List<&2, U32>, U32 & List<&2, U32>, ll => (fa, ll), r2, ra, Equal.sym(List<&2, U32>, ra, r2, + W9.revgo_app(xs, ys, acc)))) + +# three runs reversed onto nothing, reversed back: the runs in order +def rev3( + +aa: List<&2, U32>, + +bb: List<&2, U32>, + +cc: List<&2, U32> +) -> {List.reverse(&2, U32, List.reverse.go(&2, U32, cc, List.reverse.go(&2, U32, bb, List.reverse.go(&2, U32, aa, + [])))) == List.append(&2, U32, aa, List.append(&2, U32, bb, cc)) : List<&2, U32>}: + +ab = List.append(&2, U32, aa, bb) + +abc = List.append(&2, U32, ab, cc) + Equal.trans(List<&2, U32>, List.reverse(&2, U32, List.reverse.go(&2, U32, cc, List.reverse.go(&2, U32, bb, + List.reverse.go(&2, U32, aa, [])))), List.reverse(&2, U32, List.reverse.go(&2, U32, abc, [])), + List.append(&2, U32, aa, List.append(&2, U32, bb, cc)), + Equal.cong(List<&2, U32>, List<&2, U32>, ll => List.reverse(&2, U32, ll), List.reverse.go(&2, U32, cc, + List.reverse.go(&2, U32, bb, List.reverse.go(&2, U32, aa, []))), List.reverse.go(&2, U32, abc, []), + Equal.trans(List<&2, U32>, List.reverse.go(&2, U32, cc, List.reverse.go(&2, U32, bb, List.reverse.go(&2, U32, + aa, []))), List.reverse.go(&2, U32, cc, List.reverse.go(&2, U32, ab, [])), List.reverse.go(&2, U32, abc, []), + Equal.cong(List<&2, U32>, List<&2, U32>, ll => List.reverse.go(&2, U32, cc, ll), List.reverse.go(&2, U32, bb, + List.reverse.go(&2, U32, aa, [])), List.reverse.go(&2, U32, ab, []), Equal.sym(List<&2, U32>, + List.reverse.go(&2, U32, ab, []), List.reverse.go(&2, U32, bb, List.reverse.go(&2, U32, aa, [])), + W9.revgo_app(aa, bb, []))), + Equal.sym(List<&2, U32>, List.reverse.go(&2, U32, abc, []), List.reverse.go(&2, U32, cc, List.reverse.go(&2, + U32, ab, [])), W9.revgo_app(ab, cc, [])))), + Equal.trans(List<&2, U32>, List.reverse(&2, U32, List.reverse.go(&2, U32, abc, [])), abc, List.append(&2, U32, aa, + List.append(&2, U32, bb, cc)), Wp2.rev_rev(abc), Wp2.app_assoc(aa, bb, cc))) + +# the end of the IDAT chunk as seal.crc writes it: the length, the type and +# data, the CRC-32 of them, then IEND, once the whole file is reversed +def tail.eq( + +ll: U32, + +tt: List<&2, U32>, + +ie: List<&2, U32> +) -> {List.reverse(&2, U32, Png.enc.cat.go(ie, Png.enc.cat.go(Png.enc.be((Crc.crc.fold(tt, 4294967295) .^. + 4294967295 : U32)), List.reverse.go(&2, U32, tt, Png.enc.cat.go(Png.enc.be(ll), []))))) == List.append(&2, U32, + Png.enc.be(ll), List.append(&2, U32, tt, List.append(&2, U32, Png.enc.be((Crc.crc.fold(tt, 4294967295) .^. + 4294967295 : U32)), ie))) : List<&2, U32>}: + +bl = Png.enc.be(ll) + +ee = Png.enc.be((Crc.crc.fold(tt, 4294967295) .^. 4294967295 : U32)) + +a0 = List.reverse.go(&2, U32, bl, []) + +a1 = List.reverse.go(&2, U32, tt, a0) + +a2 = List.reverse.go(&2, U32, ee, a1) + +lt = List.append(&2, U32, bl, tt) + Equal.trans(List<&2, U32>, List.reverse(&2, U32, Png.enc.cat.go(ie, Png.enc.cat.go(ee, List.reverse.go(&2, U32, tt, + Png.enc.cat.go(bl, []))))), List.reverse(&2, U32, List.reverse.go(&2, U32, ie, List.reverse.go(&2, U32, ee, + List.reverse.go(&2, U32, lt, [])))), List.append(&2, U32, bl, List.append(&2, U32, tt, List.append(&2, U32, ee, + ie))), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.reverse(&2, U32, ys), Png.enc.cat.go(ie, Png.enc.cat.go(ee, + List.reverse.go(&2, U32, tt, Png.enc.cat.go(bl, [])))), List.reverse.go(&2, U32, ie, List.reverse.go(&2, U32, ee, + List.reverse.go(&2, U32, lt, []))), + Equal.trans(List<&2, U32>, Png.enc.cat.go(ie, Png.enc.cat.go(ee, List.reverse.go(&2, U32, tt, Png.enc.cat.go(bl, + [])))), Png.enc.cat.go(ie, Png.enc.cat.go(ee, a1)), List.reverse.go(&2, U32, ie, List.reverse.go(&2, U32, ee, + List.reverse.go(&2, U32, lt, []))), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => Png.enc.cat.go(ie, Png.enc.cat.go(ee, List.reverse.go(&2, U32, + tt, ys))), Png.enc.cat.go(bl, []), a0, Wp2.catgo_rev(bl, [])), + Equal.trans(List<&2, U32>, Png.enc.cat.go(ie, Png.enc.cat.go(ee, a1)), Png.enc.cat.go(ie, a2), + List.reverse.go(&2, U32, ie, List.reverse.go(&2, U32, ee, List.reverse.go(&2, U32, lt, []))), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => Png.enc.cat.go(ie, ys), Png.enc.cat.go(ee, a1), a2, + Wp2.catgo_rev(ee, a1)), + Equal.trans(List<&2, U32>, Png.enc.cat.go(ie, a2), List.reverse.go(&2, U32, ie, a2), List.reverse.go(&2, U32, + ie, List.reverse.go(&2, U32, ee, List.reverse.go(&2, U32, lt, []))), Wp2.catgo_rev(ie, a2), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.reverse.go(&2, U32, ie, List.reverse.go(&2, U32, ee, + ys)), a1, List.reverse.go(&2, U32, lt, []), Equal.sym(List<&2, U32>, List.reverse.go(&2, U32, lt, []), a1, + W9.revgo_app(bl, tt, []))))))), + Equal.trans(List<&2, U32>, List.reverse(&2, U32, List.reverse.go(&2, U32, ie, List.reverse.go(&2, U32, ee, + List.reverse.go(&2, U32, lt, [])))), List.append(&2, U32, lt, List.append(&2, U32, ee, ie)), List.append(&2, U32, + bl, List.append(&2, U32, tt, List.append(&2, U32, ee, ie))), rev3(lt, ee, ie), Wp2.app_assoc(bl, tt, + List.append(&2, U32, ee, ie)))) + +# the zlib stream of stored blocks bb and an Adler-32 sum +def zb(+bb: List<&2, U32>, +sum: U32) -> List<&2, U32>: + Png.enc.cat([120, 1], Png.enc.cat(bb, Png.enc.be(sum))) + +# the IDAT type, the zlib header and the stored blocks +def t0(+bb: List<&2, U32>) -> List<&2, U32>: + List.append(&2, U32, Png.enc.be(Png.tag.idat()), List.append(&2, U32, [120, 1], bb)) + +# the chunk's type and data as enc.chunk counts them are t0 then the sum +def body.eq( + +bb: List<&2, U32>, + +sum: U32 +) -> {Png.enc.cat(Png.enc.be(Png.tag.idat()), zb(bb, sum)) == List.append(&2, U32, t0(bb), Png.enc.be(sum)) : + List<&2, U32>}: + +bi = Png.enc.be(Png.tag.idat()) + +bs2 = Png.enc.be(sum) + +zz = List.append(&2, U32, [120, 1], List.append(&2, U32, bb, bs2)) + Equal.trans(List<&2, U32>, Png.enc.cat(bi, zb(bb, sum)), List.append(&2, U32, bi, zz), List.append(&2, U32, t0(bb), + bs2), + Equal.trans(List<&2, U32>, Png.enc.cat(bi, zb(bb, sum)), List.append(&2, U32, bi, zb(bb, sum)), List.append(&2, + U32, bi, zz), Wp2.cat_app(bi, zb(bb, sum)), Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, + bi, ys), zb(bb, sum), zz, Equal.trans(List<&2, U32>, zb(bb, sum), List.append(&2, U32, [120, 1], + Png.enc.cat(bb, bs2)), zz, Wp2.cat_app([120, 1], Png.enc.cat(bb, bs2)), Equal.cong(List<&2, U32>, List<&2, U32>, + ys => List.append(&2, U32, [120, 1], ys), Png.enc.cat(bb, bs2), List.append(&2, U32, bb, bs2), + Wp2.cat_app(bb, bs2))))), + Equal.sym(List<&2, U32>, List.append(&2, U32, t0(bb), bs2), List.append(&2, U32, bi, zz), Equal.trans(List<&2, + U32>, List.append(&2, U32, t0(bb), bs2), List.append(&2, U32, bi, List.append(&2, U32, List.append(&2, U32, [120, + 1], bb), bs2)), List.append(&2, U32, bi, zz), Wp2.app_assoc(bi, List.append(&2, U32, [120, 1], bb), bs2), + Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, bi, ys), List.append(&2, U32, + List.append(&2, U32, [120, 1], bb), bs2), zz, Wp2.app_assoc([120, 1], bb, bs2))))) + +# the file after the IDAT type as the encoder writes it, from t0 on +def gg(+xs: List<&2, U32>, +uu: U32, +ie: List<&2, U32>) -> List<&2, U32>: + List.append(&2, U32, Png.enc.be(uu), List.append(&2, U32, xs, List.append(&2, U32, Png.enc.be((Crc.crc.fold(xs, + 4294967295) .^. 4294967295 : U32)), ie))) + +# enc.chunk of IDAT, then IEND, is gg of its type and data +def chunk.gg( + +data: List<&2, U32>, + +ie: List<&2, U32> +) -> {Png.enc.cat(Png.enc.chunk(Png.tag.idat(), data), ie) == gg(Png.enc.cat(Png.enc.be(Png.tag.idat()), data), + Png.enc.len(data, 0), ie) : List<&2, U32>}: + +body = Png.enc.cat(Png.enc.be(Png.tag.idat()), data) + +be_c = Png.enc.be(Crc.crc32(body)) + +be_n = Png.enc.be(Png.enc.len(data, 0)) + Equal.trans(List<&2, U32>, Png.enc.cat(Png.enc.cat(be_n, Png.enc.cat(body, be_c)), ie), List.append(&2, U32, + List.append(&2, U32, be_n, List.append(&2, U32, body, be_c)), ie), gg(body, Png.enc.len(data, 0), ie), + Equal.trans(List<&2, U32>, Png.enc.cat(Png.enc.cat(be_n, Png.enc.cat(body, be_c)), ie), List.append(&2, U32, + Png.enc.cat(be_n, Png.enc.cat(body, be_c)), ie), List.append(&2, U32, List.append(&2, U32, be_n, List.append(&2, + U32, body, be_c)), ie), Wp2.cat_app(Png.enc.cat(be_n, Png.enc.cat(body, be_c)), ie), Equal.cong(List<&2, U32>, + List<&2, U32>, ys => List.append(&2, U32, ys, ie), Png.enc.cat(be_n, Png.enc.cat(body, be_c)), List.append(&2, + U32, be_n, List.append(&2, U32, body, be_c)), Equal.trans(List<&2, U32>, Png.enc.cat(be_n, Png.enc.cat(body, + be_c)), List.append(&2, U32, be_n, Png.enc.cat(body, be_c)), List.append(&2, U32, be_n, List.append(&2, U32, + body, be_c)), Wp2.cat_app(be_n, Png.enc.cat(body, be_c)), Equal.cong(List<&2, U32>, List<&2, U32>, ys => + List.append(&2, U32, be_n, ys), Png.enc.cat(body, be_c), List.append(&2, U32, body, be_c), Wp2.cat_app(body, + be_c))))), + Equal.trans(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, be_n, List.append(&2, U32, body, be_c)), ie), + List.append(&2, U32, be_n, List.append(&2, U32, List.append(&2, U32, body, be_c), ie)), gg(body, + Png.enc.len(data, 0), ie), Wp2.app_assoc(be_n, List.append(&2, U32, body, be_c), ie), Equal.cong(List<&2, U32>, + List<&2, U32>, ys => List.append(&2, U32, be_n, ys), List.append(&2, U32, List.append(&2, U32, body, be_c), ie), + List.append(&2, U32, body, List.append(&2, U32, be_c, ie)), Wp2.app_assoc(body, be_c, ie)))) + +# the IDAT chunk from its CRC run: the run over the type, header and blocks, +# then the Adler-32 sum, the CRC, and IEND, is enc.chunk's IDAT then IEND +def tail.chunk( + +bb: List<&2, U32>, + +sum: U32, + +ll: U32, + +ie: List<&2, U32>, + +hl: {ll == Png.enc.len(zb(bb, sum), 0) : U32} +) -> {Png.enc.seal.adler(fr(t0(bb), 4294967295, Png.enc.cat.go(Png.enc.be(ll), [])), sum, ie) == + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(bb, sum)), ie) : List<&2, U32>}: + +aa = Png.enc.cat.go(Png.enc.be(ll), []) + +bs2 = Png.enc.be(sum) + +tt = List.append(&2, U32, t0(bb), bs2) + +c0 = Crc.crc.fold(t0(bb), 4294967295) + +r0 = List.reverse.go(&2, U32, t0(bb), aa) + +body = Png.enc.cat(Png.enc.be(Png.tag.idat()), zb(bb, sum)) + Equal.trans(List<&2, U32>, Png.enc.seal.crc(Png.enc.crc.list(bs2, c0, r0), ie), gg(tt, ll, ie), + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(bb, sum)), ie), + Equal.trans(List<&2, U32>, Png.enc.seal.crc(Png.enc.crc.list(bs2, c0, r0), ie), Png.enc.seal.crc(fr(tt, + 4294967295, aa), ie), gg(tt, ll, ie), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.seal.crc(pp, ie), Png.enc.crc.list(bs2, c0, r0), + fr(tt, 4294967295, aa), Equal.trans(U32 & List<&2, U32>, Png.enc.crc.list(bs2, c0, r0), fr(bs2, c0, r0), + fr(tt, 4294967295, aa), crcl(bs2, c0, r0), fr.app(t0(bb), bs2, 4294967295, aa))), + tail.eq(ll, tt, ie)), + Equal.sym(List<&2, U32>, Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(bb, sum)), ie), gg(tt, ll, ie), + Equal.trans(List<&2, U32>, Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(bb, sum)), ie), gg(body, + Png.enc.len(zb(bb, sum), 0), ie), gg(tt, ll, ie), chunk.gg(zb(bb, sum), ie), + Equal.trans(List<&2, U32>, gg(body, Png.enc.len(zb(bb, sum), 0), ie), gg(tt, Png.enc.len(zb(bb, sum), 0), ie), + gg(tt, ll, ie), Equal.cong(List<&2, U32>, List<&2, U32>, xs => gg(xs, Png.enc.len(zb(bb, sum), 0), ie), body, + tt, body.eq(bb, sum)), Equal.cong(U32, List<&2, U32>, uu => gg(tt, uu, ie), Png.enc.len(zb(bb, sum), 0), ll, + Equal.sym(U32, ll, Png.enc.len(zb(bb, sum), 0), hl)))))) + +# seal.wide up to the Adler field: the CRC run over the IDAT type, the zlib +# header and bs's blocks +def wide.front( + +raw: List<&2, U32>, + +nn: U32, + +sum: U32, + +aa: List<&2, U32>, + +ie: List<&2, U32> +) -> {Png.enc.seal.body(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, aa), raw, nn, sum, ie) == + Png.enc.seal.adler(fr(t0(bs(raw, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn))), 4294967295, aa), sum, + ie) : List<&2, U32>}: + +bi = Png.enc.be(Png.tag.idat()) + +bb = bs(raw, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn)) + +c1 = Crc.crc.fold(bi, 4294967295) + +a1 = List.reverse.go(&2, U32, bi, aa) + +c2 = Crc.crc.fold([120, 1], c1) + +a2 = List.reverse.go(&2, U32, [120, 1], a1) + Equal.trans(List<&2, U32>, Png.enc.seal.body(Png.enc.crc.list(bi, 4294967295, aa), raw, nn, sum, ie), + Png.enc.seal.body(fr(bi, 4294967295, aa), raw, nn, sum, ie), Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), sum, + ie), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.seal.body(pp, raw, nn, sum, ie), + Png.enc.crc.list(bi, 4294967295, aa), fr(bi, 4294967295, aa), crcl(bi, 4294967295, aa)), + Equal.trans(List<&2, U32>, Png.enc.seal.run(Png.enc.crc.list([120, 1], c1, a1), raw, nn, sum, ie), + Png.enc.seal.run(fr([120, 1], c1, a1), raw, nn, sum, ie), Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), sum, + ie), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.seal.run(pp, raw, nn, sum, ie), + Png.enc.crc.list([120, 1], c1, a1), fr([120, 1], c1, a1), crcl([120, 1], c1, a1)), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.seal.adler(pp, sum, ie), Png.enc.pour(raw, True{}, + False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn), c2, a2), fr(t0(bb), 4294967295, aa), + Equal.trans(U32 & List<&2, U32>, Png.enc.pour(raw, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn), c2, + a2), Png.enc.crc.list(bb, c2, a2), fr(t0(bb), 4294967295, aa), pour.bs(raw, True{}, False{}, 0, nn, + Png.enc.cap(nn), Png.enc.bf(nn), c2, a2), + Equal.trans(U32 & List<&2, U32>, Png.enc.crc.list(bb, c2, a2), fr(bb, c2, a2), fr(t0(bb), 4294967295, aa), + crcl(bb, c2, a2), + Equal.trans(U32 & List<&2, U32>, fr(bb, c2, a2), fr(List.append(&2, U32, [120, 1], bb), c1, a1), + fr(t0(bb), 4294967295, aa), fr.app([120, 1], bb, c1, a1), fr.app(bi, List.append(&2, U32, [120, 1], + bb), 4294967295, aa))))))) + +# seal.wide after the signature and IHDR: the IDAT chunk holding the zlib +# stream of stored blocks of 65535 bytes, then IEND, when its length field is +# right. The IHDR stays out of the statement: its CRC over a symbolic width +# and height costs the checker seconds each time a type holding it is read. +def wide.tail( + +raw: List<&2, U32>, + +mx: U32, + +ie: List<&2, U32>, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(Png.enc.len(raw, 0)) == List.length(&2, U32, raw) : Nat}, + +hbig: {U32.is_le(Png.enc.len(raw, 0), 65535) == False{} : Bool}, + +hl: {Png.enc.idat.ln(Png.enc.len(raw, 0)) == Png.enc.len(Laws.zlib.stored(65535, raw), 0) : U32} +) -> {Png.enc.seal.body(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, + Png.enc.cat.go(Png.enc.be(Png.enc.idat.ln(Png.enc.len(raw, 0))), [])), raw, Png.enc.len(raw, 0), Inf.adler.of(raw), + ie) == Png.enc.cat(Png.enc.chunk(Png.tag.idat(), Laws.zlib.stored(65535, raw)), ie) : List<&2, U32>}: + +nn = Png.enc.len(raw, 0) + +sum = Inf.adler.of(raw) + +ll = Png.enc.idat.ln(nn) + +aa = Png.enc.cat.go(Png.enc.be(ll), []) + +bb = bs(raw, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn)) + +bl = Png.enc.blocks(65535, raw) + +e_b = {sim.blocks(raw, mx, emx, hn, hbig) : {bl == bb : List<&2, U32>}} + +zz = Laws.zlib.stored(65535, raw) + +hl2 = {Equal.trans(U32, ll, Png.enc.len(zz, 0), Png.enc.len(zb(bb, sum), 0), hl, Equal.cong(List<&2, U32>, U32, ys => + Png.enc.len(zb(ys, sum), 0), bl, bb, e_b)) : {ll == Png.enc.len(zb(bb, sum), 0) : U32}} + Equal.trans(List<&2, U32>, Png.enc.seal.body(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, aa), raw, nn, + sum, ie), Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), sum, ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zz), + ie), wide.front(raw, nn, sum, aa, ie), Equal.trans(List<&2, U32>, Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), + sum, ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(bb, sum)), ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), + zz), ie), tail.chunk(bb, sum, ll, ie, hl2), Equal.cong(List<&2, U32>, List<&2, U32>, ys => + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(ys, sum)), ie), bb, bl, Equal.sym(List<&2, U32>, bl, bb, e_b)))) + +# 2 and x + 4 is x + 6 +def add.six(+xx: Nat) -> {2n+Nat.add(xx, 4n) == Nat.add(xx, 6n) : Nat}: + Equal.sym(Nat, Nat.add(xx, 6n), 2n+Nat.add(xx, 4n), Equal.trans(Nat, Nat.add(xx, 6n), 1n+Nat.add(xx, 5n), + 2n+Nat.add(xx, 4n), R.add_succ(xx, 5n), Equal.cong(Nat, Nat, kk => 1n+kk, Nat.add(xx, 5n), 1n+Nat.add(xx, 4n), + R.add_succ(xx, 4n)))) + +# the zlib stream of stored blocks of 65535 bytes: 6 bytes, the list, and 5 +# for each of enc.nblk's block headers +def zlib.len( + +raw: List<&2, U32>, + +mx: U32, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(Png.enc.len(raw, 0)) == List.length(&2, U32, raw) : Nat}, + +hbig: {U32.is_le(Png.enc.len(raw, 0), 65535) == False{} : Bool} +) -> {List.length(&2, U32, Laws.zlib.stored(65535, raw)) == Nat.add(Nat.add(List.length(&2, U32, raw), + Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(raw, 0))), 5n)), 6n) : Nat}: + +bl = Png.enc.blocks(65535, raw) + +be_s = Png.enc.be(Inf.adler.of(raw)) + +xx = Nat.add(List.length(&2, U32, raw), Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(raw, 0))), 5n)) + +ap = List.append(&2, U32, [120, 1], List.append(&2, U32, bl, be_s)) + Equal.trans(Nat, List.length(&2, U32, Laws.zlib.stored(65535, raw)), List.length(&2, U32, ap), Nat.add(xx, 6n), + Equal.cong(List<&2, U32>, Nat, ys => List.length(&2, U32, ys), Laws.zlib.stored(65535, raw), ap, Equal.trans(List<&2, + U32>, Laws.zlib.stored(65535, raw), List.append(&2, U32, [120, 1], Png.enc.cat(bl, be_s)), ap, Wp2.cat_app([120, 1], + Png.enc.cat(bl, be_s)), Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, [120, 1], ys), + Png.enc.cat(bl, be_s), List.append(&2, U32, bl, be_s), Wp2.cat_app(bl, be_s)))), + Equal.trans(Nat, List.length(&2, U32, ap), 2n+Nat.add(List.length(&2, U32, bl), 4n), Nat.add(xx, 6n), + Equal.cong(Nat, Nat, kk => 2n+kk, List.length(&2, U32, List.append(&2, U32, bl, be_s)), Nat.add(List.length(&2, + U32, bl), 4n), W9.len.app(bl, be_s)), + Equal.trans(Nat, 2n+Nat.add(List.length(&2, U32, bl), 4n), 2n+Nat.add(xx, 4n), Nat.add(xx, 6n), Equal.cong(Nat, + Nat, kk => 2n+Nat.add(kk, 4n), List.length(&2, U32, bl), xx, cnt.blocks(raw, mx, emx, hn, hbig)), + add.six(xx)))) + +# the IDAT length the encoder writes is the zlib stream's, when the stream is +# at most some U32's value long +def idat.len( + +raw: List<&2, U32>, + +mx: U32, + +tu: U32, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(Png.enc.len(raw, 0)) == List.length(&2, U32, raw) : Nat}, + +hbig: {U32.is_le(Png.enc.len(raw, 0), 65535) == False{} : Bool}, + +h_tu: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, raw), Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(raw, 0))), + 5n)), 6n), U32.to_nat(tu)) == True{} : Bool} +) -> {Png.enc.idat.ln(Png.enc.len(raw, 0)) == Png.enc.len(Laws.zlib.stored(65535, raw), 0) : U32}: + +nn = Png.enc.len(raw, 0) + +kb = Png.enc.nblk(nn) + +k5 = Nat.mul(U32.to_nat(kb), 5n) + +n0 = List.length(&2, U32, raw) + +xx = Nat.add(n0, k5) + +tn = U32.to_nat(tu) + +h_x = {R.le_add_r(xx, 6n, tn, h_tu) : {Nat.is_le(xx, tn) == True{} : Bool}} + +h_k = {R.le_add_l(n0, k5, tn, h_x) : {Nat.is_le(k5, tn) == True{} : Bool}} + +e_m = {R.u32_mul_below(kb, 5, tu, h_k) : {U32.to_nat((kb * 5 : U32)) == k5 : Nat}} + +h_a = {R.le_rw_l(xx, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), tn, Equal.trans(Nat, xx, Nat.add(U32.to_nat(nn), + k5), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), Equal.cong(Nat, Nat, kk => Nat.add(kk, k5), n0, + U32.to_nat(nn), Equal.sym(Nat, U32.to_nat(nn), n0, hn)), Equal.cong(Nat, Nat, kk => Nat.add(U32.to_nat(nn), kk), k5, + U32.to_nat((kb * 5 : U32)), Equal.sym(Nat, U32.to_nat((kb * 5 : U32)), k5, e_m))), h_x) : + {Nat.is_le(Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), tn) == True{} : Bool}} + +e_a = {Equal.trans(Nat, U32.to_nat((nn + (kb * 5 : U32) : U32)), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), xx, + R.u32_add_below(nn, (kb * 5 : U32), tu, h_a), Equal.trans(Nat, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), + Nat.add(n0, U32.to_nat((kb * 5 : U32))), xx, Equal.cong(Nat, Nat, kk => Nat.add(kk, U32.to_nat((kb * 5 : U32))), + U32.to_nat(nn), n0, hn), Equal.cong(Nat, Nat, kk => Nat.add(n0, kk), U32.to_nat((kb * 5 : U32)), k5, e_m))) : + {U32.to_nat((nn + (kb * 5 : U32) : U32)) == xx : Nat}} + +s1 = (nn + (kb * 5 : U32) : U32) + +h_6 = {R.le_rw_l(Nat.add(xx, 6n), Nat.add(U32.to_nat(s1), 6n), tn, Equal.cong(Nat, Nat, kk => Nat.add(kk, 6n), xx, + U32.to_nat(s1), Equal.sym(Nat, U32.to_nat(s1), xx, e_a)), h_tu) : {Nat.is_le(Nat.add(U32.to_nat(s1), U32.to_nat(6)), + tn) == True{} : Bool}} + +e_i = {Equal.trans(Nat, U32.to_nat((s1 + 6 : U32)), Nat.add(U32.to_nat(s1), 6n), Nat.add(xx, 6n), + R.u32_add_below(s1, 6, tu, h_6), Equal.cong(Nat, Nat, kk => Nat.add(kk, 6n), U32.to_nat(s1), xx, e_a)) : + {U32.to_nat(Png.enc.idat.ln(nn)) == Nat.add(xx, 6n) : Nat}} + +zz = Laws.zlib.stored(65535, raw) + +e_z = {zlib.len(raw, mx, emx, hn, hbig) : {List.length(&2, U32, zz) == Nat.add(xx, 6n) : Nat}} + +e_zl = {len.of(zz, tu, R.le_rw_l(Nat.add(xx, 6n), List.length(&2, U32, zz), tn, Equal.sym(Nat, List.length(&2, U32, + zz), Nat.add(xx, 6n), e_z), h_tu)) : {U32.to_nat(Png.enc.len(zz, 0)) == List.length(&2, U32, zz) : Nat}} + u32.same(Png.enc.idat.ln(nn), Png.enc.len(zz, 0), Equal.trans(Nat, U32.to_nat(Png.enc.idat.ln(nn)), Nat.add(xx, 6n), + U32.to_nat(Png.enc.len(zz, 0)), e_i, Equal.sym(Nat, U32.to_nat(Png.enc.len(zz, 0)), Nat.add(xx, 6n), Equal.trans(Nat, + U32.to_nat(Png.enc.len(zz, 0)), List.length(&2, U32, zz), Nat.add(xx, 6n), e_zl, e_z)))) + +# ---- H. enc.rgb.go against bs ---- + +# Adler-32 as enc.rgb.go adds it up, then packed +def afold(xs: List<&2, U32>, +aa: U32, +bb: U32) -> U32: + match xs: + case Nil{}: + ((bb << 16n : U32) .|. aa : U32) + case +x <> t: + +a2 = Png.enc.add(aa, x) + +b2 = Png.enc.add(bb, a2) + afold(t, a2, b2) + +# the raw bytes enc.rgb.go's cursor has still to write, for a picture of +# rows wn samples wide: a filter byte first at a row's start, red while the +# sample is still in px, then green and blue of col +def cur(filt: Bool, zred: Bool, zgrn: Bool, px: List<&2, U32>, +col: U32, +row: U32, +wn: Nat) -> List<&2, U32>: + match filt: + case True{}: + W9.sc(px, 0n, wn, True{}) + case False{}: + match zred: + case True{}: + W9.sc(px, U32.to_nat(row), wn, True{}) + case False{}: + match zgrn: + case True{}: + Png.enc.g(col) <> Png.enc.b(col) <> W9.sc(px, Png.enc.pred(U32.to_nat(row)), wn, True{}) + case False{}: + Png.enc.b(col) <> W9.sc(px, Png.enc.pred(U32.to_nat(row)), wn, True{}) + +# the room bs has in its open block: none at a block's start +def rm(zblock: Bool, +need: U32) -> U32: + match zblock: + case True{}: + 0 + case False{}: + need + +# the facts enc.rgb.go's block state carries, nr the raw bytes still to come: +# at a block's start, left counts them; inside a block, need bytes are left +# in it, and left less len counts the bytes after it +def rg.hyp( + zblock: Bool, + +zdone: Bool, + +zspan: Bool, + +zneed: Bool, + +nr: Nat, + +left: U32, + +len: U32, + +need: U32, + +pl: U32, + +plen: U32, + +pbf: U32 +) -> Type: + match zblock: + case True{}: + {zdone == U32.is_zero(left) : Bool} & {U32.to_nat(left) == nr : Nat} + case False{}: + {zdone == False{} : Bool} & ({zspan == True{} : Bool} & ({zneed == U32.is_zero(need) : Bool} & + ({U32.to_nat(pl) == nr : Nat} & ({Nat.add(U32.to_nat(len), nr) == Nat.add(U32.to_nat(left), U32.to_nat(need)) : + Nat} & at.edge(need, pl, plen, pbf))))) + +# what enc.rgb.go returns: the CRC run over bs's blocks, and Adler-32 of the raw bytes +def rg.val( + zblock: Bool, + +rr: List<&2, U32>, + +cc: U32, + +acc: List<&2, U32>, + +aa: U32, + +bb: U32, + +left: U32, + +need: U32, + +pl: U32, + +plen: U32, + +pbf: U32 +) -> (U32 & List<&2, U32>) & U32: + match zblock: + case True{}: + (fr(bs(rr, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left)), cc, acc), afold(rr, aa, bb)) + case False{}: + (fr(bs(rr, U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(rr, aa, bb)) + +# no raw bytes left: enc.rgb.go's end is bs's +def nil.r( + xs: List<&2, U32>, + +z1: Bool, + +z2: Bool, + +r1: U32, + +l1: U32, + +n1: U32, + +f1: U32, + +cc: U32, + +acc: List<&2, U32>, + +aa: U32, + +bb: U32, + +hh: {List.length(&2, U32, xs) == 0n : Nat} +) -> {Png.enc.rgb.fin(cc, acc, aa, bb) == (fr(bs(xs, z1, z2, r1, l1, n1, f1), cc, acc), afold(xs, aa, bb)) : (U32 & + List<&2, U32>) & U32}: + match xs: + case Nil{}: + {==} + case _x <> t: + Empty.absurd({Png.enc.rgb.fin(cc, acc, aa, bb) == (fr(bs(_x <> t, z1, z2, r1, l1, n1, f1), cc, acc), afold(_x <> t, + aa, bb)) : (U32 & List<&2, U32>) & U32}, Wp1.zero_succ(List.length(&2, U32, t), Equal.sym(Nat, 1n+List.length(&2, + U32, t), 0n, hh))) + +# one raw byte: bs writes it, and the block goes on or closes +def step( + z1: Bool, + +xb: U32, + +rr: List<&2, U32>, + +need: U32, + +pl: U32, + +plen: U32, + +pbf: U32, + +cc: U32, + +acc: List<&2, U32>, + +aa: U32, + +bb: U32, + -gg: (U32 & List<&2, U32>) & U32, + +ez1: {U32.is_eq(need, 1) == z1 : Bool}, + +nz: {U32.is_zero(need) == False{} : Bool}, + ih: @xx: U32 -> @yy: U32 -> at.edge((need - 1 : U32), (pl - 1 : U32), xx, yy) -> {gg == (fr(bs(rr, U32.is_zero((need - + 1 : U32)), U32.is_eq((need - 1 : U32), 1), (need - 1 : U32), (pl - 1 : U32), xx, yy), Crc.crc.byte(cc, xb), + xb <> acc), afold(rr, Png.enc.add(aa, xb), Png.enc.add(bb, Png.enc.add(aa, xb)))) : (U32 & List<&2, U32>) & U32} +) -> {gg == (fr(bs(xb <> rr, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(xb <> rr, aa, bb)) : + (U32 & List<&2, U32>) & U32}: + match z1: + case True{}: + +n1 = (need - 1 : U32) + +p1 = (pl - 1 : U32) + +c1 = Crc.crc.byte(cc, xb) + +a2 = Png.enc.add(aa, xb) + +b2 = Png.enc.add(bb, a2) + +e1 = {one.val(need, Equal.sym(Bool, U32.is_eq(need, 1), True{}, ez1)) : {U32.to_nat(need) == 1n : Nat}} + +e0 = {u32.same(n1, 0, Wp1.u32_pred(need, 0n, e1)) : {n1 == 0 : U32}} + %Equal.sym(Bool, U32.is_eq(need, 1), True{}, ez1) : {gg == (fr(bs(xb <> rr, False{}, _, need, pl, plen, pbf), cc, + acc), afold(xb <> rr, aa, bb)) : (U32 & List<&2, U32>) & U32} + Equal.trans((U32 & List<&2, U32>) & U32, gg, (fr(bs(rr, U32.is_zero(n1), U32.is_eq(n1, 1), n1, p1, + Png.enc.cap(p1), Png.enc.bf(p1)), c1, xb <> acc), afold(rr, a2, b2)), (fr(bs(rr, True{}, False{}, 0, p1, + Png.enc.cap(p1), Png.enc.bf(p1)), c1, xb <> acc), afold(rr, a2, b2)), + ih(Png.enc.cap(p1), Png.enc.bf(p1), _ez => ({==}, {==})), + Equal.cong(U32, (U32 & List<&2, U32>) & U32, uu => (fr(bs(rr, U32.is_zero(uu), U32.is_eq(uu, 1), uu, p1, + Png.enc.cap(p1), Png.enc.bf(p1)), c1, xb <> acc), afold(rr, a2, b2)), n1, 0, e0)) + case False{}: + +n1 = (need - 1 : U32) + +p1 = (pl - 1 : U32) + +c1 = Crc.crc.byte(cc, xb) + +a2 = Png.enc.add(aa, xb) + +b2 = Png.enc.add(bb, a2) + +nz1 = {two(need, Equal.sym(Bool, U32.is_zero(need), False{}, nz), Equal.sym(Bool, U32.is_eq(need, 1), False{}, + ez1)) : {U32.is_zero(n1) == False{} : Bool}} + %Equal.sym(Bool, U32.is_eq(need, 1), False{}, ez1) : {gg == (fr(bs(xb <> rr, False{}, _, need, pl, plen, pbf), cc, + acc), afold(xb <> rr, aa, bb)) : (U32 & List<&2, U32>) & U32} + Equal.trans((U32 & List<&2, U32>) & U32, gg, (fr(bs(rr, U32.is_zero(n1), U32.is_eq(n1, 1), n1, p1, plen, pbf), c1, + xb <> acc), afold(rr, a2, b2)), (fr(bs(rr, False{}, U32.is_eq(n1, 1), n1, p1, plen, pbf), c1, xb <> acc), + afold(rr, a2, b2)), + ih(plen, pbf, edge.no(n1, p1, plen, pbf, nz1)), + Equal.cong(Bool, (U32 & List<&2, U32>) & U32, zb => (fr(bs(rr, zb, U32.is_eq(n1, 1), n1, p1, plen, pbf), c1, + xb <> acc), afold(rr, a2, b2)), U32.is_zero(n1), False{}, nz1)) + +# a raw byte in a block, from the rg state: the facts for the state after it, +# then step, then rg.val read with the byte in front +def rg.byte( + +pp: Nat, + +xb: U32, + +rr: List<&2, U32>, + +r2: List<&2, U32>, + +need: U32, + +pl: U32, + +plen: U32, + +pbf: U32, + +cc: U32, + +acc: List<&2, U32>, + +aa: U32, + +bb: U32, + +left: U32, + +len: U32, + +kk: Nat, + +xn: Nat, + -gg: (U32 & List<&2, U32>) & U32, + +e_r: {rr == xb <> r2 : List<&2, U32>}, + +e_zn: {False{} == U32.is_zero(need) : Bool}, + +hx: {Nat.add(U32.to_nat(need), xn) == List.length(&2, U32, rr) : Nat}, + +hw: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, rr), 1n), Nat.double(kk)), 2n+pp) == True{} : Bool}, + +e_pl: {U32.to_nat(pl) == List.length(&2, U32, rr) : Nat}, + +e_ll: {Nat.add(U32.to_nat(len), List.length(&2, U32, rr)) == Nat.add(U32.to_nat(left), U32.to_nat(need)) : Nat}, + ih: @xx: U32 -> @yy: U32 -> at.edge((need - 1 : U32), (pl - 1 : U32), xx, yy) -> {Nat.add(U32.to_nat((need - 1 : U32)), + xn) == List.length(&2, U32, r2) : Nat} -> {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, r2), 1n), + Nat.double(kk)), 1n+pp) == True{} : Bool} -> {U32.to_nat((pl - 1 : U32)) == List.length(&2, U32, r2) : Nat} -> + {Nat.add(U32.to_nat(len), List.length(&2, U32, r2)) == Nat.add(U32.to_nat(left), U32.to_nat((need - 1 : U32))) : + Nat} -> {gg == (fr(bs(r2, U32.is_zero((need - 1 : U32)), U32.is_eq((need - 1 : U32), 1), (need - 1 : U32), (pl - 1 : + U32), xx, yy), Crc.crc.byte(cc, xb), xb <> acc), afold(r2, Png.enc.add(aa, xb), Png.enc.add(bb, Png.enc.add(aa, + xb)))) : (U32 & List<&2, U32>) & U32} +) -> {gg == rg.val(False{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}: + +n1 = (need - 1 : U32) + +nr = List.length(&2, U32, r2) + +nz = {Equal.sym(Bool, False{}, U32.is_zero(need), e_zn) : {U32.is_zero(need) == False{} : Bool}} + +e_n = {Wp1.u32_dec(need, nz) : {U32.to_nat(need) == 1n+U32.to_nat(n1) : Nat}} + +e_len = {Equal.cong(List<&2, U32>, Nat, ys => List.length(&2, U32, ys), rr, xb <> r2, e_r) : {List.length(&2, U32, + rr) == 1n+nr : Nat}} + +hx2 = {Wp1.succ_inj(Nat.add(U32.to_nat(n1), xn), nr, Equal.trans(Nat, 1n+Nat.add(U32.to_nat(n1), xn), + Nat.add(U32.to_nat(need), xn), 1n+nr, Equal.cong(Nat, Nat, kz => Nat.add(kz, xn), 1n+U32.to_nat(n1), + U32.to_nat(need), Equal.sym(Nat, U32.to_nat(need), 1n+U32.to_nat(n1), e_n)), Equal.trans(Nat, Nat.add(U32.to_nat(need), + xn), List.length(&2, U32, rr), 1n+nr, hx, e_len))) : {Nat.add(U32.to_nat(n1), xn) == nr : Nat}} + +hw2 = {Equal.trans(Bool, Nat.is_le(Nat.add(Nat.add(1n+nr, 1n), Nat.double(kk)), 2n+pp), Nat.is_le(Nat.add(Nat.add( + List.length(&2, U32, rr), 1n), Nat.double(kk)), 2n+pp), True{}, Equal.cong(Nat, Bool, kz => + Nat.is_le(Nat.add(Nat.add(kz, 1n), Nat.double(kk)), 2n+pp), 1n+nr, List.length(&2, U32, rr), Equal.sym(Nat, + List.length(&2, U32, rr), 1n+nr, e_len)), hw) : {Nat.is_le(Nat.add(Nat.add(nr, 1n), Nat.double(kk)), 1n+pp) == + True{} : Bool}} + +epl2 = {Wp1.u32_pred(pl, nr, Equal.trans(Nat, U32.to_nat(pl), List.length(&2, U32, rr), 1n+nr, e_pl, e_len)) : + {U32.to_nat((pl - 1 : U32)) == nr : Nat}} + +ell2 = {Wp1.succ_inj(Nat.add(U32.to_nat(len), nr), Nat.add(U32.to_nat(left), U32.to_nat(n1)), Equal.trans(Nat, + 1n+Nat.add(U32.to_nat(len), nr), Nat.add(U32.to_nat(len), 1n+nr), 1n+Nat.add(U32.to_nat(left), U32.to_nat(n1)), + Equal.sym(Nat, Nat.add(U32.to_nat(len), 1n+nr), 1n+Nat.add(U32.to_nat(len), nr), R.add_succ(U32.to_nat(len), nr)), + Equal.trans(Nat, Nat.add(U32.to_nat(len), 1n+nr), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), + 1n+Nat.add(U32.to_nat(left), U32.to_nat(n1)), Equal.trans(Nat, Nat.add(U32.to_nat(len), 1n+nr), + Nat.add(U32.to_nat(len), List.length(&2, U32, rr)), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), Equal.cong(Nat, Nat, + kz => Nat.add(U32.to_nat(len), kz), 1n+nr, List.length(&2, U32, rr), Equal.sym(Nat, List.length(&2, U32, rr), 1n+nr, + e_len)), Equal.trans(Nat, Nat.add(U32.to_nat(len), List.length(&2, U32, rr)), Nat.add(U32.to_nat(left), + U32.to_nat(need)), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), e_ll, Equal.cong(Nat, Nat, kz => + Nat.add(U32.to_nat(left), kz), U32.to_nat(need), 1n+U32.to_nat(n1), e_n))), R.add_succ(U32.to_nat(left), + U32.to_nat(n1))))) : {Nat.add(U32.to_nat(len), nr) == Nat.add(U32.to_nat(left), U32.to_nat(n1)) : Nat}} + Equal.trans((U32 & List<&2, U32>) & U32, gg, (fr(bs(xb <> r2, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, + acc), afold(xb <> r2, aa, bb)), rg.val(False{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), + step(U32.is_eq(need, 1), xb, r2, need, pl, plen, pbf, cc, acc, aa, bb, gg, {==}, nz, xx => yy => ee => ih(xx, yy, + ee, hx2, hw2, epl2, ell2)), + Equal.sym((U32 & List<&2, U32>) & U32, rg.val(False{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), + (fr(bs(xb <> r2, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(xb <> r2, aa, bb)), + Equal.trans((U32 & List<&2, U32>) & U32, rg.val(False{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), + (fr(bs(rr, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(rr, aa, bb)), + (fr(bs(xb <> r2, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(xb <> r2, aa, bb)), + Equal.cong(Bool, (U32 & List<&2, U32>) & U32, zb => (fr(bs(rr, zb, U32.is_eq(need, 1), need, pl, plen, pbf), + cc, acc), afold(rr, aa, bb)), U32.is_zero(need), False{}, nz), + Equal.cong(List<&2, U32>, (U32 & List<&2, U32>) & U32, ys => (fr(bs(ys, False{}, U32.is_eq(need, 1), need, pl, + plen, pbf), cc, acc), afold(ys, aa, bb)), rr, xb <> r2, e_r)))) + +# the five header bytes bs writes at a block's start from left bytes +def hd5(+left: U32) -> List<&2, U32>: + +len = Png.enc.cap(left) + +nlen = (len .^. 65535 : U32) + [Png.enc.bf(left), Png.enc.byte(len), Png.enc.hi(len), Png.enc.byte(nlen), Png.enc.hi(nlen)] + +# a new block, split as enc.rgb.go writes it: the header, then the bytes with +# the block's whole length in hand, once whether that length is 1 is named +def spl.at( + z1: Bool, + +h: U32, + +t: List<&2, U32>, + +left: U32, + +ez1: {U32.is_eq(Png.enc.cap(left), 1) == z1 : Bool}, + +nzc: {U32.is_zero(Png.enc.cap(left)) == False{} : Bool} +) -> {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == List.append(&2, U32, hd5(left), bs(h <> t, + False{}, U32.is_eq(Png.enc.cap(left), 1), Png.enc.cap(left), left, Png.enc.cap((left - 1 : U32)), + Png.enc.bf((left - 1 : U32)))) : List<&2, U32>}: + match z1: + case True{}: + +cp = Png.enc.cap(left) + +l1 = (left - 1 : U32) + +e1 = {one.val(cp, Equal.sym(Bool, U32.is_eq(cp, 1), True{}, ez1)) : {U32.to_nat(cp) == 1n : Nat}} + +e0 = {u32.same((cp - 1 : U32), 0, Wp1.u32_pred(cp, 0n, e1)) : {(cp - 1 : U32) == 0 : U32}} + %Equal.sym(Bool, U32.is_eq(cp, 1), True{}, ez1) : {open.bs(h, t, l1, cp, Png.enc.bf(left)) == List.append(&2, U32, + hd5(left), bs(h <> t, False{}, _, cp, left, Png.enc.cap(l1), Png.enc.bf(l1))) : List<&2, U32>} + Equal.cong(U32, List<&2, U32>, uu => List.append(&2, U32, hd5(left), h <> bs(t, U32.is_zero(uu), U32.is_eq(uu, 1), + uu, l1, Png.enc.cap(l1), Png.enc.bf(l1))), (cp - 1 : U32), 0, e0) + case False{}: + +cp = Png.enc.cap(left) + +l1 = (left - 1 : U32) + +nz1 = {two(cp, Equal.sym(Bool, U32.is_zero(cp), False{}, nzc), Equal.sym(Bool, U32.is_eq(cp, 1), False{}, ez1)) : + {U32.is_zero((cp - 1 : U32)) == False{} : Bool}} + %Equal.sym(Bool, U32.is_eq(cp, 1), False{}, ez1) : {open.bs(h, t, l1, cp, Png.enc.bf(left)) == List.append(&2, U32, + hd5(left), bs(h <> t, False{}, _, cp, left, Png.enc.cap(l1), Png.enc.bf(l1))) : List<&2, U32>} + Equal.cong(Bool, List<&2, U32>, zb => List.append(&2, U32, hd5(left), h <> bs(t, zb, U32.is_eq((cp - 1 : U32), 1), + (cp - 1 : U32), l1, Png.enc.cap(l1), Png.enc.bf(l1))), U32.is_zero((cp - 1 : U32)), False{}, nz1) + +# a block's start with bytes left: the header, then the bytes with the block's +# whole length in hand +def spl( + xs: List<&2, U32>, + +left: U32, + +hn: {U32.to_nat(left) == List.length(&2, U32, xs) : Nat}, + +nzl: {U32.is_zero(left) == False{} : Bool}, + +nzc: {U32.is_zero(Png.enc.cap(left)) == False{} : Bool} +) -> {bs(xs, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left)) == List.append(&2, U32, hd5(left), bs(xs, + False{}, U32.is_eq(Png.enc.cap(left), 1), Png.enc.cap(left), left, Png.enc.cap((left - 1 : U32)), + Png.enc.bf((left - 1 : U32)))) : List<&2, U32>}: + match xs: + case Nil{}: + Empty.absurd({bs([], True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left)) == List.append(&2, U32, + hd5(left), bs([], False{}, U32.is_eq(Png.enc.cap(left), 1), Png.enc.cap(left), left, Png.enc.cap((left - 1 : + U32)), Png.enc.bf((left - 1 : U32)))) : List<&2, U32>}, U32L.false_true(Equal.trans(Bool, False{}, + U32.is_zero(left), True{}, Equal.sym(Bool, U32.is_zero(left), False{}, nzl), zero.is(left, hn)))) + case +h <> +t: + spl.at(U32.is_eq(Png.enc.cap(left), 1), h, t, left, {==}, nzc) + +# the pair at.edge gives, used to rewrite bs's length and BFINAL +def n0.pe( + +rr: List<&2, U32>, + +pl: U32, + +plen: U32, + +pbf: U32, + pe: {plen == Png.enc.cap(pl) : U32} & {pbf == Png.enc.bf(pl) : U32} +) -> {bs(rr, True{}, False{}, 0, pl, plen, pbf) == bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), Png.enc.bf(pl)) : + List<&2, U32>}: + (+e_l, +e_b) = pe + Equal.trans(List<&2, U32>, bs(rr, True{}, False{}, 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), + pbf), bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), Png.enc.bf(pl)), Equal.cong(U32, List<&2, U32>, uu => bs(rr, + True{}, False{}, 0, pl, uu, pbf), plen, Png.enc.cap(pl), e_l), Equal.cong(U32, List<&2, U32>, uu => bs(rr, True{}, + False{}, 0, pl, Png.enc.cap(pl), uu), pbf, Png.enc.bf(pl), e_b)) + +# a block's end in enc.rgb.go's state is a block's start in bs's +def n0.bs( + +rr: List<&2, U32>, + +need: U32, + +pl: U32, + +plen: U32, + +pbf: U32, + +left2: U32, + +ez: {True{} == U32.is_zero(need) : Bool}, + +e_pl: {U32.to_nat(pl) == List.length(&2, U32, rr) : Nat}, + +e_l2: {U32.to_nat(left2) == List.length(&2, U32, rr) : Nat}, + hb: at.edge(need, pl, plen, pbf) +) -> {bs(rr, U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf) == bs(rr, True{}, False{}, 0, left2, + Png.enc.cap(left2), Png.enc.bf(left2)) : List<&2, U32>}: + +e0 = {u32.same(need, 0, zero.val(need, ez)) : {need == 0 : U32}} + +e_p = {u32.same(pl, left2, Equal.trans(Nat, U32.to_nat(pl), List.length(&2, U32, rr), U32.to_nat(left2), e_pl, + Equal.sym(Nat, U32.to_nat(left2), List.length(&2, U32, rr), e_l2))) : {pl == left2 : U32}} + Equal.trans(List<&2, U32>, bs(rr, U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf), bs(rr, True{}, False{}, + 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2)), + Equal.cong(U32, List<&2, U32>, uu => bs(rr, U32.is_zero(uu), U32.is_eq(uu, 1), uu, pl, plen, pbf), need, 0, e0), + Equal.trans(List<&2, U32>, bs(rr, True{}, False{}, 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), + Png.enc.bf(pl)), bs(rr, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2)), n0.pe(rr, pl, plen, pbf, + hb(Equal.sym(Bool, True{}, U32.is_zero(need), ez))), Equal.cong(U32, List<&2, U32>, uu => bs(rr, True{}, False{}, + 0, uu, Png.enc.cap(uu), Png.enc.bf(uu)), pl, left2, e_p))) + +# out of fuel at a block's start: no raw bytes are left +def z0.m1( + kk: Nat, + +xn: Nat, + +nr: Nat, + +mn: Nat, + +hx: {xn == nr : Nat}, + hk: kok(xn, kk, mn), + +hw: {Nat.is_le(Nat.add(Nat.add(nr, 0n), Nat.double(kk)), 1n) == True{} : Bool} +) -> {nr == 0n : Nat}: + match kk: + case 0n: + Equal.trans(Nat, nr, xn, 0n, Equal.sym(Nat, xn, nr, hx), hk) + case 1n+kp: + Empty.absurd({nr == 0n : Nat}, U32L.false_true(R.le_add_l(Nat.add(nr, 0n), 2n+Nat.double(kp), 1n, hw))) + +# out of fuel inside a block: no raw bytes are left +def z0.s2(+nr: Nat, +dk: Nat, +hw: {Nat.is_le(Nat.add(Nat.add(nr, 1n), dk), 1n) == True{} : Bool}) -> {nr == 0n : Nat}: + +h1 = {R.le_add_r(Nat.add(nr, 1n), dk, 1n, hw) : {Nat.is_le(Nat.add(nr, 1n), 1n) == True{} : Bool}} + +h2 = {R.le_rw_l(Nat.add(nr, 1n), 1n+Nat.add(nr, 0n), 1n, R.add_succ(nr, 0n), h1) : {Nat.is_le(Nat.add(nr, 0n), 0n) == + True{} : Bool}} + Equal.trans(Nat, nr, Nat.add(nr, 0n), 0n, Equal.sym(Nat, Nat.add(nr, 0n), nr, R.add_zero(nr)), le.zero(Nat.add(nr, 0n), + h2)) + +# the fuel after a block header: one step fewer, one block fewer, one more to close it +def hw.head( + +nr: Nat, + +dk: Nat, + +pp: Nat, + +hw: {Nat.is_le(Nat.add(Nat.add(nr, 0n), 2n+dk), 2n+pp) == True{} : Bool} +) -> {Nat.is_le(Nat.add(Nat.add(nr, 1n), dk), 1n+pp) == True{} : Bool}: + +ee = {Equal.trans(Nat, Nat.add(Nat.add(nr, 0n), 2n+dk), Nat.add(nr, 2n+dk), 1n+Nat.add(Nat.add(nr, 1n), dk), + Equal.cong(Nat, Nat, kz => Nat.add(kz, 2n+dk), Nat.add(nr, 0n), nr, R.add_zero(nr)), Equal.trans(Nat, Nat.add(nr, + 2n+dk), 1n+Nat.add(nr, 1n+dk), 1n+Nat.add(Nat.add(nr, 1n), dk), R.add_succ(nr, 1n+dk), Equal.cong(Nat, Nat, kz => + 1n+kz, Nat.add(nr, 1n+dk), Nat.add(Nat.add(nr, 1n), dk), Equal.sym(Nat, Nat.add(Nat.add(nr, 1n), dk), Nat.add(nr, + 1n+dk), R.add_assoc(nr, 1n, dk))))) : {Nat.add(Nat.add(nr, 0n), 2n+dk) == 1n+Nat.add(Nat.add(nr, 1n), dk) : Nat}} + R.le_rw_l(Nat.add(Nat.add(nr, 0n), 2n+dk), 1n+Nat.add(Nat.add(nr, 1n), dk), 2n+pp, ee, hw) + +# the fuel at a block's end: the step that closes it +def hw.end( + +nr: Nat, + +dk: Nat, + +pp: Nat, + +hw: {Nat.is_le(Nat.add(Nat.add(nr, 1n), dk), 2n+pp) == True{} : Bool} +) -> {Nat.is_le(Nat.add(Nat.add(nr, 0n), dk), 1n+pp) == True{} : Bool}: + R.le_rw_l(Nat.add(Nat.add(nr, 1n), dk), 1n+Nat.add(Nat.add(nr, 0n), dk), 2n+pp, Equal.cong(Nat, Nat, kz => Nat.add(kz, + dk), Nat.add(nr, 1n), 1n+Nat.add(nr, 0n), R.add_succ(nr, 0n)), hw) + +# a sum that is 0 has a left part 0 +def add.zero.l(aa: Nat, +bb: Nat, +hh: {Nat.add(aa, bb) == 0n : Nat}) -> {aa == 0n : Nat}: + match aa: + case 0n: + {==} + case 1n+pp: + Empty.absurd({1n+pp == 0n : Nat}, Wp1.zero_succ(Nat.add(pp, bb), Equal.sym(Nat, 1n+Nat.add(pp, bb), 0n, hh))) + +# a byte is due in the block, so the raw bytes are not gone +def need.nil( + +need: U32, + +xn: Nat, + +e_zn: {False{} == U32.is_zero(need) : Bool}, + +hx: {Nat.add(U32.to_nat(need), xn) == 0n : Nat} +) -> Empty: + U32L.false_true(Equal.trans(Bool, False{}, U32.is_zero(need), True{}, e_zn, zero.is(need, add.zero.l(U32.to_nat(need), + xn, hx)))) + +# the filter byte: 0, then the row's samples +def cur.filt( + +s: U32, + +t: List<&2, U32>, + +row: U32, + +wp: Nat, + +er: {U32.to_nat(row) == 1n+wp : Nat} +) -> {W9.sc(s <> t, 0n, 1n+wp, True{}) == 0 <> W9.sc(s <> t, U32.to_nat(row), 1n+wp, True{}) : List<&2, U32>}: + Equal.cong(Nat, List<&2, U32>, kz => 0 <> W9.sc(s <> t, kz, 1n+wp, True{}), 1n+wp, U32.to_nat(row), Equal.sym(Nat, + U32.to_nat(row), 1n+wp, er)) + +# a red byte: the sample's red, then its green and blue and the rest of the row +def cur.red( + +s: U32, + +t: List<&2, U32>, + +row: U32, + +wn: Nat, + +hrow: {U32.is_zero(row) == False{} : Bool} +) -> {W9.sc(s <> t, U32.to_nat(row), wn, True{}) == Png.enc.r(s) <> Png.enc.g(s) <> Png.enc.b(s) <> W9.sc(t, + Png.enc.pred(U32.to_nat(row)), wn, True{}) : List<&2, U32>}: + +r1 = U32.to_nat((row - 1 : U32)) + +er = {Wp1.u32_dec(row, hrow) : {U32.to_nat(row) == 1n+r1 : Nat}} + Equal.trans(List<&2, U32>, W9.sc(s <> t, U32.to_nat(row), wn, True{}), W9.sc(s <> t, 1n+r1, wn, True{}), Png.enc.r(s) + <> Png.enc.g(s) <> Png.enc.b(s) <> W9.sc(t, Png.enc.pred(U32.to_nat(row)), wn, True{}), + Equal.cong(Nat, List<&2, U32>, kz => W9.sc(s <> t, kz, wn, True{}), U32.to_nat(row), 1n+r1, er), + Equal.cong(Nat, List<&2, U32>, kz => Png.enc.r(s) <> Png.enc.g(s) <> Png.enc.b(s) <> W9.sc(t, Png.enc.pred(kz), wn, + True{}), 1n+r1, U32.to_nat(row), Equal.sym(Nat, U32.to_nat(row), 1n+r1, er))) + +# a row's last blue byte: the next row starts with its filter byte +def cur.last( + +col: U32, + +px: List<&2, U32>, + +row: U32, + +wn: Nat, + +e1: {True{} == U32.is_eq(row, 1) : Bool} +) -> {Png.enc.b(col) <> W9.sc(px, Png.enc.pred(U32.to_nat(row)), wn, True{}) == Png.enc.b(col) <> W9.sc(px, 0n, wn, + True{}) : List<&2, U32>}: + Equal.cong(Nat, List<&2, U32>, kz => Png.enc.b(col) <> W9.sc(px, Png.enc.pred(kz), wn, True{}), U32.to_nat(row), 1n, + one.val(row, e1)) + +# a blue byte inside a row: the next sample's red comes next +def cur.blue( + +col: U32, + +px: List<&2, U32>, + +row: U32, + +wn: Nat, + +hrow: {U32.is_zero(row) == False{} : Bool} +) -> {Png.enc.b(col) <> W9.sc(px, Png.enc.pred(U32.to_nat(row)), wn, True{}) == Png.enc.b(col) <> W9.sc(px, + U32.to_nat((row - 1 : U32)), wn, True{}) : List<&2, U32>}: + Equal.cong(Nat, List<&2, U32>, kz => Png.enc.b(col) <> W9.sc(px, Png.enc.pred(kz), wn, True{}), U32.to_nat(row), + 1n+U32.to_nat((row - 1 : U32)), Wp1.u32_dec(row, hrow)) + +# enc.rgb.go writes bs's blocks of the raw bytes its cursor walks, with their +# CRC run, and the Adler-32 of those bytes, while its fuel covers a step per +# raw byte and two per block (the header, and the step that closes it) +def rg( + fuel: Nat, + +zblock: Bool, + +zdone: Bool, + +zspan: Bool, + +zneed: Bool, + +filt: Bool, + +zred: Bool, + +zgrn: Bool, + +zlast: Bool, + +px: List<&2, U32>, + +col: U32, + +row: U32, + +ww: U32, + +need: U32, + +cc: U32, + +acc: List<&2, U32>, + +aa: U32, + +bb: U32, + +left: U32, + +len: U32, + +pl: U32, + +plen: U32, + +pbf: U32, + +kk: Nat, + +xn: Nat, + +wp: Nat, + +mx: U32, + +emx: {mx == 65535 : U32}, + +ew: {U32.to_nat(ww) == 1n+wp : Nat}, + +hrow: {U32.is_zero(row) == False{} : Bool}, + hfw: {filt == True{} : Bool} -> {row == ww : U32}, + hbl: {filt == False{} : Bool} -> {zred == False{} : Bool} -> {zgrn == False{} : Bool} -> {zlast == U32.is_eq(row, 1) : + Bool}, + +hx: {Nat.add(U32.to_nat(rm(zblock, need)), xn) == List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)) : + Nat}, + hk: kok(xn, kk, U32.to_nat(mx)), + +hw: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)), + R.bit(Bool.not(zblock))), Nat.double(kk)), 1n+fuel) == True{} : Bool}, + hb: rg.hyp(zblock, zdone, zspan, zneed, List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)), left, len, + need, pl, plen, pbf) +) -> {Png.enc.rgb.go(fuel, zblock, zdone, zspan, zneed, filt, zred, zgrn, zlast, px, col, row, ww, need, cc, acc, aa, bb, + left, len) == rg.val(zblock, cur(filt, zred, zgrn, px, col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : + (U32 & List<&2, U32>) & U32}: + match fuel: + case 0n: + match zblock: + case True{}: + +rr = cur(filt, zred, zgrn, px, col, row, 1n+wp) + nil.r(rr, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left), cc, acc, aa, bb, z0.m1(kk, xn, + List.length(&2, U32, rr), U32.to_nat(mx), hx, hk, hw)) + case False{}: + +rr = cur(filt, zred, zgrn, px, col, row, 1n+wp) + nil.r(rr, U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf, cc, acc, aa, bb, + z0.s2(List.length(&2, U32, rr), Nat.double(kk), hw)) + case 1n+(+pp): + match zblock: + case True{}: + match zdone: + case True{}: + (e_zd, e_l) = hb + +rr = cur(filt, zred, zgrn, px, col, row, 1n+wp) + nil.r(rr, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left), cc, acc, aa, bb, + Equal.trans(Nat, List.length(&2, U32, rr), U32.to_nat(left), 0n, Equal.sym(Nat, U32.to_nat(left), + List.length(&2, U32, rr), e_l), zero.val(left, e_zd))) + case False{}: + match kk: + case 0n: + (e_zd, e_l) = hb + +rr = cur(filt, zred, zgrn, px, col, row, 1n+wp) + +e_r0 = {Equal.trans(Nat, U32.to_nat(left), List.length(&2, U32, rr), 0n, e_l, Equal.trans(Nat, + List.length(&2, U32, rr), xn, 0n, Equal.sym(Nat, xn, List.length(&2, U32, rr), hx), hk)) : + {U32.to_nat(left) == 0n : Nat}} + Empty.absurd({Png.enc.rgb.go(1n+pp, True{}, False{}, zspan, zneed, filt, zred, zgrn, zlast, px, col, + row, ww, need, cc, acc, aa, bb, left, len) == rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, + plen, pbf) : (U32 & List<&2, U32>) & U32}, U32L.false_true(Equal.trans(Bool, False{}, + U32.is_zero(left), True{}, e_zd, zero.is(left, e_r0)))) + case 1n+(+kp): + match hk hb: + case Tuple{h_lt, h_le} Tuple{e_zd, +e_l}: + +rr = cur(filt, zred, zgrn, px, col, row, 1n+wp) + +nr = List.length(&2, U32, rr) + +mn = U32.to_nat(mx) + +l1 = (left - 1 : U32) + +nt = U32.to_nat(l1) + +nzl = {Equal.sym(Bool, False{}, U32.is_zero(left), e_zd) : {U32.is_zero(left) == False{} : Bool}} + +e_lt = {Wp1.u32_dec(left, nzl) : {U32.to_nat(left) == 1n+nt : Nat}} + +e_R = {Equal.trans(Nat, nr, U32.to_nat(left), 1n+nt, Equal.sym(Nat, U32.to_nat(left), nr, e_l), + e_lt) : {nr == 1n+nt : Nat}} + +zz = U32.is_le(left, 65535) + +cp = Png.enc.cap(left) + +cm = capm(zz, left, mx) + +c1 = (cp - 1 : U32) + +nzm = {mx.nz(mx, emx) : {U32.is_zero(mx) == False{} : Bool}} + +ezm = {le.mx(left, mx, emx) : {U32.is_le(left, mx) == zz : Bool}} + +e_cm = {cap.m(zz, left, mx, emx) : {cp == cm : U32}} + +nz_cp = {Equal.trans(Bool, U32.is_zero(cp), U32.is_zero(cm), False{}, Equal.cong(U32, Bool, uu => + U32.is_zero(uu), cp, cm, e_cm), cap.nz(zz, left, mx, nt, nzm, e_lt)) : {U32.is_zero(cp) == + False{} : Bool}} + +e_cp = {Wp1.u32_dec(cp, nz_cp) : {U32.to_nat(cp) == 1n+U32.to_nat(c1) : Nat}} + +e_c = {Equal.cong(U32, Nat, uu => U32.to_nat((uu - 1 : U32)), cp, cm, e_cm) : {U32.to_nat(c1) == + U32.to_nat((cm - 1 : U32)) : Nat}} + +h_c = {R.le_rw_l(U32.to_nat((cm - 1 : U32)), U32.to_nat(c1), nt, Equal.sym(Nat, U32.to_nat(c1), + U32.to_nat((cm - 1 : U32)), e_c), ks.le(zz, left, mx, nt, nzm, ezm, e_lt)) : + {Nat.is_le(U32.to_nat(c1), nt) == True{} : Bool}} + +x2 = Nat.sub(nt, U32.to_nat(c1)) + +hx2 = {Equal.trans(Nat, Nat.add(U32.to_nat(cp), x2), 1n+Nat.add(U32.to_nat(c1), x2), nr, + Equal.cong(Nat, Nat, kz => Nat.add(kz, x2), U32.to_nat(cp), 1n+U32.to_nat(c1), e_cp), + Equal.trans(Nat, 1n+Nat.add(U32.to_nat(c1), x2), 1n+nt, nr, Equal.cong(Nat, Nat, kz => 1n+kz, + Nat.add(U32.to_nat(c1), x2), nt, R.add_sub(U32.to_nat(c1), nt, h_c)), Equal.sym(Nat, nr, 1n+nt, + e_R))) : {Nat.add(U32.to_nat(cp), x2) == nr : Nat}} + +h_lt2 = {R.lt_rw_r(Nat.mul(kp, mn), xn, 1n+nt, Equal.trans(Nat, xn, nr, 1n+nt, hx, e_R), h_lt) : + {Nat.is_lt(Nat.mul(kp, mn), 1n+nt) == True{} : Bool}} + +h_le2 = {R.le_rw_l(xn, 1n+nt, Nat.add(mn, Nat.mul(kp, mn)), Equal.trans(Nat, xn, nr, 1n+nt, hx, e_R), + h_le) : {Nat.is_le(1n+nt, Nat.add(mn, Nat.mul(kp, mn))) == True{} : Bool}} + hk2 = kok.rw(Nat.sub(nt, U32.to_nat((cm - 1 : U32))), x2, kp, mn, Equal.cong(Nat, Nat, kz => + Nat.sub(nt, kz), U32.to_nat((cm - 1 : U32)), U32.to_nat(c1), Equal.sym(Nat, U32.to_nat(c1), + U32.to_nat((cm - 1 : U32)), e_c)), ks.k(zz, kp, left, mx, nt, nzm, ezm, e_lt, h_lt2, h_le2)) + +hw2 = {hw.head(nr, Nat.double(kp), pp, hw) : {Nat.is_le(Nat.add(Nat.add(nr, 1n), Nat.double(kp)), + 1n+pp) == True{} : Bool}} + +ell2 = {Equal.trans(Nat, Nat.add(U32.to_nat(cp), nr), Nat.add(nr, U32.to_nat(cp)), + Nat.add(U32.to_nat(left), U32.to_nat(cp)), R.add_comm(U32.to_nat(cp), nr), Equal.cong(Nat, Nat, + kz => Nat.add(kz, U32.to_nat(cp)), nr, U32.to_nat(left), Equal.sym(Nat, U32.to_nat(left), nr, + e_l))) : {Nat.add(U32.to_nat(cp), nr) == Nat.add(U32.to_nat(left), U32.to_nat(cp)) : Nat}} + +bf = Png.enc.bf(left) + +nlen = (cp .^. 65535 : U32) + +b1 = Png.enc.byte(cp) + +b2 = Png.enc.hi(cp) + +b3 = Png.enc.byte(nlen) + +b4 = Png.enc.hi(nlen) + +c5 = Crc.crc.byte(Crc.crc.byte(Crc.crc.byte(Crc.crc.byte(Crc.crc.byte(cc, bf), b1), b2), b3), b4) + +a4 = {b4 <> b3 <> b2 <> b1 <> bf <> acc : List<&2, U32>} + +bb2 = bs(rr, False{}, U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)) + +ih = {rg(pp, False{}, False{}, True{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, + aa, bb, left, cp, left, Png.enc.cap(l1), Png.enc.bf(l1), kp, x2, wp, mx, emx, ew, hrow, hfw, hbl, + hx2, hk2, hw2, ({==}, ({==}, (Equal.sym(Bool, U32.is_zero(cp), False{}, nz_cp), (e_l, (ell2, + edge.no(cp, left, Png.enc.cap(l1), Png.enc.bf(l1), nz_cp))))))) : {Png.enc.rgb.go(pp, False{}, + False{}, True{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp) + == (fr(bs(rr, U32.is_zero(cp), U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, + a4), afold(rr, aa, bb)) : (U32 & List<&2, U32>) & U32}} + Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, False{}, False{}, True{}, False{}, filt, + zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp), (fr(bb2, c5, a4), afold(rr, aa, + bb)), rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), + Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, False{}, False{}, True{}, False{}, filt, + zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp), (fr(bs(rr, U32.is_zero(cp), + U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, a4), afold(rr, aa, bb)), + (fr(bb2, c5, a4), afold(rr, aa, bb)), ih, Equal.cong(Bool, (U32 & List<&2, U32>) & U32, zb => + (fr(bs(rr, zb, U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, a4), afold(rr, + aa, bb)), U32.is_zero(cp), False{}, nz_cp)), + Equal.sym((U32 & List<&2, U32>) & U32, rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, plen, + pbf), (fr(bb2, c5, a4), afold(rr, aa, bb)), Equal.trans((U32 & List<&2, U32>) & U32, + rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), (fr(List.append(&2, U32, + hd5(left), bb2), cc, acc), afold(rr, aa, bb)), (fr(bb2, c5, a4), afold(rr, aa, bb)), + Equal.cong(List<&2, U32>, (U32 & List<&2, U32>) & U32, ys => (fr(ys, cc, acc), afold(rr, aa, bb)), + bs(rr, True{}, False{}, 0, left, cp, bf), List.append(&2, U32, hd5(left), bb2), spl(rr, left, + e_l, nzl, nz_cp)), Equal.cong(U32 & List<&2, U32>, (U32 & List<&2, U32>) & U32, qq => (qq, + afold(rr, aa, bb)), fr(List.append(&2, U32, hd5(left), bb2), cc, acc), fr(bb2, c5, a4), + Equal.sym(U32 & List<&2, U32>, fr(bb2, c5, a4), fr(List.append(&2, U32, hd5(left), bb2), cc, + acc), fr.app(hd5(left), bb2, cc, acc)))))) + case False{}: + match zdone: + case True{}: + (e_d, _rest) = hb + Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, True{}, zspan, zneed, filt, zred, zgrn, zlast, px, col, row, + ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, cur(filt, zred, zgrn, px, col, row, 1n+wp), cc, + acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}, U32L.false_true(Equal.sym(Bool, + True{}, False{}, e_d))) + case False{}: + match zspan: + case False{}: + (_e_d, (e_s, _rest)) = hb + Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, False{}, zneed, filt, zred, zgrn, zlast, px, + col, row, ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, cur(filt, zred, zgrn, px, col, + row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}, + U32L.false_true(e_s)) + case True{}: + match zneed: + case True{}: + (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, hbe))))) = hb + +rr = cur(filt, zred, zgrn, px, col, row, 1n+wp) + +nr = List.length(&2, U32, rr) + +l2 = (left - len : U32) + +e_n0 = {zero.val(need, e_zn) : {U32.to_nat(need) == 0n : Nat}} + +e_lf = {Equal.trans(Nat, U32.to_nat(left), Nat.add(U32.to_nat(left), 0n), Nat.add(U32.to_nat(len), + nr), Equal.sym(Nat, Nat.add(U32.to_nat(left), 0n), U32.to_nat(left), + R.add_zero(U32.to_nat(left))), Equal.trans(Nat, Nat.add(U32.to_nat(left), 0n), + Nat.add(U32.to_nat(left), U32.to_nat(need)), Nat.add(U32.to_nat(len), nr), Equal.cong(Nat, Nat, + kz => Nat.add(U32.to_nat(left), kz), 0n, U32.to_nat(need), Equal.sym(Nat, U32.to_nat(need), 0n, + e_n0)), Equal.sym(Nat, Nat.add(U32.to_nat(len), nr), Nat.add(U32.to_nat(left), + U32.to_nat(need)), e_ll))) : {U32.to_nat(left) == Nat.add(U32.to_nat(len), nr) : Nat}} + +h_ll = {R.le_rw_r(U32.to_nat(len), Nat.add(U32.to_nat(len), nr), U32.to_nat(left), Equal.sym(Nat, + U32.to_nat(left), Nat.add(U32.to_nat(len), nr), e_lf), Wp2.nle_add(U32.to_nat(len), nr)) : + {Nat.is_le(U32.to_nat(len), U32.to_nat(left)) == True{} : Bool}} + +e_l2 = {Equal.trans(Nat, U32.to_nat(l2), Nat.sub(U32.to_nat(left), U32.to_nat(len)), nr, + R.u32_sub_nat(left, len, h_ll), Equal.trans(Nat, Nat.sub(U32.to_nat(left), U32.to_nat(len)), + Nat.sub(Nat.add(U32.to_nat(len), nr), U32.to_nat(len)), nr, Equal.cong(Nat, Nat, kz => + Nat.sub(kz, U32.to_nat(len)), U32.to_nat(left), Nat.add(U32.to_nat(len), nr), e_lf), + R.sub_add_cancel(U32.to_nat(len), nr))) : {U32.to_nat(l2) == nr : Nat}} + +hx2 = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(need), xn), nr, Equal.cong(Nat, Nat, kz => + Nat.add(kz, xn), 0n, U32.to_nat(need), Equal.sym(Nat, U32.to_nat(need), 0n, e_n0)), hx) : + {Nat.add(U32.to_nat(0), xn) == nr : Nat}} + +ih = {rg(pp, True{}, U32.is_zero(l2), False{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, + need, cc, acc, aa, bb, l2, len, pl, plen, pbf, kk, xn, wp, mx, emx, ew, hrow, hfw, hbl, hx2, hk, + hw.end(nr, Nat.double(kk), pp, hw), ({==}, e_l2)) : {Png.enc.rgb.go(pp, True{}, + U32.is_zero(l2), False{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, need, cc, acc, aa, + bb, l2, len) == (fr(bs(rr, True{}, False{}, 0, l2, Png.enc.cap(l2), Png.enc.bf(l2)), cc, acc), + afold(rr, aa, bb)) : (U32 & List<&2, U32>) & U32}} + Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, True{}, U32.is_zero(l2), False{}, + False{}, filt, zred, zgrn, zlast, px, col, row, ww, need, cc, acc, aa, bb, l2, len), + (fr(bs(rr, True{}, False{}, 0, l2, Png.enc.cap(l2), Png.enc.bf(l2)), cc, acc), afold(rr, aa, + bb)), rg.val(False{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), ih, + Equal.cong(List<&2, U32>, (U32 & List<&2, U32>) & U32, ys => (fr(ys, cc, acc), afold(rr, aa, + bb)), bs(rr, True{}, False{}, 0, l2, Png.enc.cap(l2), Png.enc.bf(l2)), bs(rr, + U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf), Equal.sym(List<&2, U32>, bs(rr, + U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf), bs(rr, True{}, False{}, 0, l2, + Png.enc.cap(l2), Png.enc.bf(l2)), n0.bs(rr, need, pl, plen, pbf, l2, e_zn, e_pl, e_l2, hbe)))) + case False{}: + match filt: + case True{}: + match px: + case Nil{}: + (_e_d, (_e_s, (e_zn, _rest))) = hb + Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, True{}, False{}, True{}, zred, zgrn, zlast, [], col, row, ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, cur(True{}, zred, zgrn, [], col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}, need.nil(need, xn, e_zn, hx)) + case +s <> +t: + (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb + +r2 = cur(False{}, True{}, False{}, s <> t, col, row, 1n+wp) + +e_R = {cur.filt(s, t, row, wp, Equal.trans(Nat, U32.to_nat(row), U32.to_nat(ww), 1n+wp, Equal.cong(U32, Nat, uu => U32.to_nat(uu), row, ww, hfw({==})), ew)) : {cur(True{}, zred, zgrn, s <> t, col, row, 1n+wp) == 0 <> r2 : List<&2, U32>}} + rg.byte(pp, 0, cur(True{}, zred, zgrn, s <> t, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, s <> t, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, 0), 0 <> acc, Png.enc.add(aa, 0), Png.enc.add(bb, Png.enc.add(aa, 0)), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, s <> t, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, 0), 0 <> acc, Png.enc.add(aa, 0), Png.enc.add(bb, Png.enc.add(aa, 0)), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), _e1 => e2 => _e3 => Empty.absurd({False{} == U32.is_eq(row, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + case False{}: + match zred: + case True{}: + match zgrn: + case _gn: + match zlast: + case _ls: + match px: + case Nil{}: + (_e_d, (_e_s, (e_zn, _rest))) = hb + Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, True{}, False{}, False{}, True{}, _gn, _ls, [], col, row, ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, cur(False{}, True{}, _gn, [], col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}, need.nil(need, xn, e_zn, hx)) + case +s <> +t: + (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb + +r2 = cur(False{}, False{}, True{}, t, s, row, 1n+wp) + +e_R = {cur.red(s, t, row, 1n+wp, hrow) : {cur(False{}, True{}, _gn, s <> t, col, row, 1n+wp) == Png.enc.r(s) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.r(s), cur(False{}, True{}, _gn, s <> t, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, True{}, False{}, t, s, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.r(s)), Png.enc.r(s) <> acc, Png.enc.add(aa, Png.enc.r(s)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.r(s))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, True{}, False{}, t, s, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.r(s)), Png.enc.r(s) <> acc, Png.enc.add(aa, Png.enc.r(s)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.r(s))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), _e1 => _e2 => e3 => Empty.absurd({False{} == U32.is_eq(row, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e3))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + case False{}: + match zgrn: + case True{}: + (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb + +r2 = cur(False{}, False{}, False{}, px, col, row, 1n+wp) + +e_R = {{==} : {cur(False{}, False{}, True{}, px, col, row, 1n+wp) == Png.enc.g(col) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.g(col), cur(False{}, False{}, True{}, px, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, False{}, U32.is_eq(row, 1), px, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.g(col)), Png.enc.g(col) <> acc, Png.enc.add(aa, Png.enc.g(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.g(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, False{}, U32.is_eq(row, 1), px, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.g(col)), Png.enc.g(col) <> acc, Png.enc.add(aa, Png.enc.g(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.g(col))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), _e1 => _e2 => _e3 => {==}, h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + case False{}: + match zlast: + case True{}: + (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb + +r2 = cur(True{}, True{}, False{}, px, col, ww, 1n+wp) + +e_R = {cur.last(col, px, row, 1n+wp, hbl({==}, {==}, {==})) : {cur(False{}, False{}, False{}, px, col, row, 1n+wp) == Png.enc.b(col) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.b(col), cur(False{}, False{}, False{}, px, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), True{}, True{}, False{}, False{}, px, col, ww, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), True{}, True{}, False{}, False{}, px, col, ww, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, Wp1.u32_nonzero(ww, wp, ew), _ef => {==}, ef => Empty.absurd({True{} == False{} : Bool} -> {False{} == False{} : Bool} -> {False{} == U32.is_eq(ww, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, ef))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + case False{}: + (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb + +r2 = cur(False{}, True{}, False{}, px, col, (row - 1 : U32), 1n+wp) + +e_R = {cur.blue(col, px, row, 1n+wp, hrow) : {cur(False{}, False{}, False{}, px, col, row, 1n+wp) == Png.enc.b(col) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.b(col), cur(False{}, False{}, False{}, px, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, px, col, (row - 1 : U32), ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, px, col, (row - 1 : U32), ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, two(row, Equal.sym(Bool, U32.is_zero(row), False{}, hrow), hbl({==}, {==}, {==})), ef => Empty.absurd({(row - 1 : U32) == ww : U32}, U32L.false_true(ef)), _e1 => e2 => _e3 => Empty.absurd({False{} == U32.is_eq((row - 1 : U32), 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + +# ---- I. Adler-32 as enc.rgb.go adds it is Inf.adler.of ---- + +# The Adler modulus, 65521, is named pm below, for the same reason as mx. + +# enc.add.at with the modulus named +def addm(zz: Bool, +tt: U32, +pm: U32) -> U32: + match zz: + case True{}: + (tt - pm : U32) + case False{}: + tt + +# enc.add.at is addm at 65521 +def addm.eq(zz: Bool, +tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> {Png.enc.add.at(zz, tt) == addm(zz, tt, pm) : + U32}: + match zz: + case True{}: + Equal.cong(U32, U32, uu => (tt - uu : U32), 65521, pm, Equal.sym(U32, pm, 65521, epm)) + case False{}: + {==} + +# at most and below cannot both hold the other way round +def le.lt.no(+aa: Nat, +bb: Nat, +h1: {Nat.is_le(aa, bb) == True{} : Bool}, +h2: {Nat.is_lt(bb, aa) == True{} : Bool}) -> + Empty: + lt.irr(aa, R.le_lt_trans(aa, bb, aa, h1, h2)) + +# t below 2 m is t mod m after one subtraction of m, or none: which one is t >= m's answer +def md.at( + zz: Bool, + qn: Nat, + +tt: U32, + +pm: U32, + +ez: {U32.is_ge(tt, pm) == zz : Bool}, + +e_t: {U32.to_nat(tt) == Nat.add(Nat.mul(qn, U32.to_nat(pm)), U32.to_nat(U32.mod(tt, pm))) : Nat}, + +l_r: {Nat.is_lt(U32.to_nat(U32.mod(tt, pm)), U32.to_nat(pm)) == True{} : Bool}, + +ht: {Nat.is_lt(U32.to_nat(tt), Nat.add(U32.to_nat(pm), U32.to_nat(pm))) == True{} : Bool} +) -> {addm(zz, tt, pm) == U32.mod(tt, pm) : U32}: + match zz qn: + case True{} 0n: + +mn = U32.to_nat(pm) + +rn = U32.to_nat(U32.mod(tt, pm)) + +hg = {ge.le(U32.to_nat(tt), mn, Equal.trans(Bool, Cmp.is_ge(Nat.cmp(U32.to_nat(tt), mn)), U32.is_ge(tt, pm), + True{}, Equal.sym(Bool, U32.is_ge(tt, pm), Cmp.is_ge(Nat.cmp(U32.to_nat(tt), mn)), u.ge(tt, pm)), ez)) : + {Nat.is_le(mn, U32.to_nat(tt)) == True{} : Bool}} + Empty.absurd({(tt - pm : U32) == U32.mod(tt, pm) : U32}, le.lt.no(mn, rn, R.le_rw_r(mn, U32.to_nat(tt), rn, e_t, + hg), l_r)) + case True{} 1n+qp: + match qp: + case 0n: + +mn = U32.to_nat(pm) + +rn = U32.to_nat(U32.mod(tt, pm)) + +hg = {ge.le(U32.to_nat(tt), mn, Equal.trans(Bool, Cmp.is_ge(Nat.cmp(U32.to_nat(tt), mn)), U32.is_ge(tt, pm), + True{}, Equal.sym(Bool, U32.is_ge(tt, pm), Cmp.is_ge(Nat.cmp(U32.to_nat(tt), mn)), u.ge(tt, pm)), ez)) : + {Nat.is_le(mn, U32.to_nat(tt)) == True{} : Bool}} + +e_t2 = {Equal.trans(Nat, U32.to_nat(tt), Nat.add(Nat.add(mn, 0n), rn), Nat.add(mn, rn), e_t, Equal.cong(Nat, + Nat, kz => Nat.add(kz, rn), Nat.add(mn, 0n), mn, R.add_zero(mn))) : {U32.to_nat(tt) == Nat.add(mn, rn) : + Nat}} + u32.same((tt - pm : U32), U32.mod(tt, pm), Equal.trans(Nat, U32.to_nat((tt - pm : U32)), Nat.sub(U32.to_nat(tt), + mn), rn, R.u32_sub_nat(tt, pm, hg), Equal.trans(Nat, Nat.sub(U32.to_nat(tt), mn), Nat.sub(Nat.add(mn, rn), + mn), rn, Equal.cong(Nat, Nat, kz => Nat.sub(kz, mn), U32.to_nat(tt), Nat.add(mn, rn), e_t2), + R.sub_add_cancel(mn, rn)))) + case 1n+(+qq): + +mn = U32.to_nat(pm) + +rn = U32.to_nat(U32.mod(tt, pm)) + +yy = Nat.add(mn, Nat.mul(qq, mn)) + +h1 = {R.le_add_mono(mn, mn, yy, Wp2.nle_add(mn, Nat.mul(qq, mn))) : {Nat.is_le(Nat.add(mn, mn), Nat.add(mn, + yy)) == True{} : Bool}} + +h2 = {R.le_rw_r(Nat.add(mn, mn), Nat.add(Nat.add(mn, yy), rn), U32.to_nat(tt), Equal.sym(Nat, U32.to_nat(tt), + Nat.add(Nat.add(mn, yy), rn), e_t), R.le_trans(Nat.add(mn, mn), Nat.add(mn, yy), Nat.add(Nat.add(mn, yy), + rn), h1, Wp2.nle_add(Nat.add(mn, yy), rn))) : {Nat.is_le(Nat.add(mn, mn), U32.to_nat(tt)) == True{} : Bool}} + Empty.absurd({(tt - pm : U32) == U32.mod(tt, pm) : U32}, le.lt.no(Nat.add(mn, mn), U32.to_nat(tt), h2, ht)) + case False{} 0n: + u32.same(tt, U32.mod(tt, pm), e_t) + case False{} 1n+(+qp): + +mn = U32.to_nat(pm) + +rn = U32.to_nat(U32.mod(tt, pm)) + +yy = Nat.add(mn, Nat.mul(qp, mn)) + +hl = {nge.lt(U32.to_nat(tt), mn, Equal.trans(Bool, Cmp.is_ge(Nat.cmp(U32.to_nat(tt), mn)), U32.is_ge(tt, pm), + False{}, Equal.sym(Bool, U32.is_ge(tt, pm), Cmp.is_ge(Nat.cmp(U32.to_nat(tt), mn)), u.ge(tt, pm)), ez)) : + {Nat.is_lt(U32.to_nat(tt), mn) == True{} : Bool}} + +h2 = {R.le_rw_r(mn, Nat.add(yy, rn), U32.to_nat(tt), Equal.sym(Nat, U32.to_nat(tt), Nat.add(yy, rn), e_t), + R.le_trans(mn, yy, Nat.add(yy, rn), Wp2.nle_add(mn, Nat.mul(qp, mn)), Wp2.nle_add(yy, rn))) : {Nat.is_le(mn, + U32.to_nat(tt)) == True{} : Bool}} + Empty.absurd({tt == U32.mod(tt, pm) : U32}, le.lt.no(mn, U32.to_nat(tt), h2, hl)) + +# the modulus doubled is a U32's value +def pm.dbl(+pm: U32, +epm: {pm == 65521 : U32}) -> {U32.to_nat(U32.add(pm, pm)) == Nat.add(U32.to_nat(pm), + U32.to_nat(pm)) : Nat}: + add.cf(pm, pm, Equal.cong(U32, Bool, uu => cy32(uu, uu), pm, 65521, epm)) + +# U32.mod by the modulus: a quotient and a remainder below it +def pm.dvm(+tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> dvm.ty(tt, pm): + +mn = U32.to_nat(pm) + +hm = {Equal.trans(Bool, Nat.is_lt(0n, mn), U32.is_lt(0, pm), True{}, Equal.sym(Bool, U32.is_lt(0, pm), Nat.is_lt(0n, + mn), R.u32_lt(0, pm)), Equal.cong(U32, Bool, uu => U32.is_lt(0, uu), pm, 65521, epm)) : {Nat.is_lt(0n, mn) == True{} : + Bool}} + +h2 = {R.le_rw_r(Nat.add(mn, mn), Nat.add(mn, mn), U32.to_nat(U32.add(pm, pm)), Equal.sym(Nat, + U32.to_nat(U32.add(pm, pm)), Nat.add(mn, mn), pm.dbl(pm, epm)), R.le_refl(Nat.add(mn, mn))) : + {Nat.is_le(Nat.add(mn, mn), U32.to_nat(U32.add(pm, pm))) == True{} : Bool}} + dvm(tt, pm, U32.add(pm, pm), hm, h2) + +# the pair pm.dvm gives, taken apart, for one subtraction +def md.go( + +tt: U32, + +pm: U32, + pr: dvm.ty(tt, pm), + +ht: {Nat.is_lt(U32.to_nat(tt), Nat.add(U32.to_nat(pm), U32.to_nat(pm))) == True{} : Bool} +) -> {addm(U32.is_ge(tt, pm), tt, pm) == U32.mod(tt, pm) : U32}: + (+e_t, +l_r) = pr + md.at(U32.is_ge(tt, pm), U32.to_nat(U32.div(tt, pm)), tt, pm, {==}, e_t, l_r, ht) + +# enc.add.at of a sum below twice the modulus is the sum mod 65521 +def mod.once( + +tt: U32, + +pm: U32, + +epm: {pm == 65521 : U32}, + +ht: {Nat.is_lt(U32.to_nat(tt), Nat.add(U32.to_nat(pm), U32.to_nat(pm))) == True{} : Bool} +) -> {Png.enc.add.at(U32.is_ge(tt, 65521), tt) == (tt % 65521 : U32) : U32}: + +e65 = {Equal.sym(U32, pm, 65521, epm) : {65521 == pm : U32}} + Equal.trans(U32, Png.enc.add.at(U32.is_ge(tt, 65521), tt), addm(U32.is_ge(tt, pm), tt, pm), (tt % 65521 : U32), + Equal.trans(U32, Png.enc.add.at(U32.is_ge(tt, 65521), tt), Png.enc.add.at(U32.is_ge(tt, pm), tt), addm(U32.is_ge(tt, + pm), tt, pm), Equal.cong(U32, U32, uu => Png.enc.add.at(U32.is_ge(tt, uu), tt), 65521, pm, e65), + addm.eq(U32.is_ge(tt, pm), tt, pm, epm)), + Equal.trans(U32, addm(U32.is_ge(tt, pm), tt, pm), U32.mod(tt, pm), (tt % 65521 : U32), md.go(tt, pm, pm.dvm(tt, pm, + epm), ht), Equal.cong(U32, U32, uu => U32.mod(tt, uu), pm, 65521, epm))) + +# the remainder pm.dvm gives, read as mod 65521 +def mod.lt.go(+tt: U32, +pm: U32, +epm: {pm == 65521 : U32}, pr: dvm.ty(tt, pm)) -> {Nat.is_lt(U32.to_nat((tt % 65521 : + U32)), U32.to_nat(pm)) == True{} : Bool}: + (_e_t, +l_r) = pr + R.lt_rw_l(U32.to_nat(U32.mod(tt, pm)), U32.to_nat((tt % 65521 : U32)), U32.to_nat(pm), Equal.cong(U32, Nat, uu => + U32.to_nat(U32.mod(tt, uu)), pm, 65521, epm), l_r) + +# U32.mod by 65521 is below it +def mod.lt(+tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> {Nat.is_lt(U32.to_nat((tt % 65521 : U32)), U32.to_nat(pm)) + == True{} : Bool}: + mod.lt.go(tt, pm, epm, pm.dvm(tt, pm, epm)) + +# one Adler-32 add of values below the modulus is the add mod 65521 +def add.mod( + +ss: U32, + +xx: U32, + +pm: U32, + +epm: {pm == 65521 : U32}, + +hs: {Nat.is_lt(U32.to_nat(ss), U32.to_nat(pm)) == True{} : Bool}, + +hx: {Nat.is_lt(U32.to_nat(xx), U32.to_nat(pm)) == True{} : Bool} +) -> {Png.enc.add(ss, xx) == ((ss + xx : U32) % 65521 : U32) : U32}: + +mn = U32.to_nat(pm) + +sn = U32.to_nat(ss) + +xn = U32.to_nat(xx) + +h1 = {Equal.trans(Bool, Nat.is_le(1n+sn, mn), Nat.is_lt(sn, mn), True{}, Equal.sym(Bool, Nat.is_lt(sn, mn), + Nat.is_le(1n+sn, mn), R.lt_le_succ(sn, mn)), hs) : {Nat.is_le(1n+sn, mn) == True{} : Bool}} + +h2 = {R.le_add_both(1n+sn, mn, xn, mn, h1, R.lt_le(xn, mn, hx)) : {Nat.is_le(1n+Nat.add(sn, xn), Nat.add(mn, mn)) == + True{} : Bool}} + +h3 = {Equal.trans(Bool, Nat.is_lt(Nat.add(sn, xn), Nat.add(mn, mn)), Nat.is_le(1n+Nat.add(sn, xn), Nat.add(mn, mn)), + True{}, R.lt_le_succ(Nat.add(sn, xn), Nat.add(mn, mn)), h2) : {Nat.is_lt(Nat.add(sn, xn), Nat.add(mn, mn)) == + True{} : Bool}} + +e_s = {R.u32_add_below(ss, xx, U32.add(pm, pm), R.le_rw_r(Nat.add(sn, xn), Nat.add(mn, mn), U32.to_nat(U32.add(pm, + pm)), Equal.sym(Nat, U32.to_nat(U32.add(pm, pm)), Nat.add(mn, mn), pm.dbl(pm, epm)), R.lt_le(Nat.add(sn, xn), + Nat.add(mn, mn), h3))) : {U32.to_nat((ss + xx : U32)) == Nat.add(sn, xn) : Nat}} + mod.once((ss + xx : U32), pm, epm, R.lt_rw_l(Nat.add(sn, xn), U32.to_nat((ss + xx : U32)), Nat.add(mn, mn), + Equal.sym(Nat, U32.to_nat((ss + xx : U32)), Nat.add(sn, xn), e_s), h3)) + +# a byte is below the modulus +def byte.pm(+xx: U32, +pm: U32, +epm: {pm == 65521 : U32}, +hh: {U32.is_le(xx, 255) == True{} : Bool}) -> + {Nat.is_lt(U32.to_nat(xx), U32.to_nat(pm)) == True{} : Bool}: + R.le_lt_trans(U32.to_nat(xx), U32.to_nat(255), U32.to_nat(pm), Equal.trans(Bool, Nat.is_le(U32.to_nat(xx), + U32.to_nat(255)), U32.is_le(xx, 255), True{}, Equal.sym(Bool, U32.is_le(xx, 255), Nat.is_le(U32.to_nat(xx), + U32.to_nat(255)), R.u32_le(xx, 255)), hh), Equal.trans(Bool, Nat.is_lt(U32.to_nat(255), U32.to_nat(pm)), + U32.is_lt(255, pm), True{}, Equal.sym(Bool, U32.is_lt(255, pm), Nat.is_lt(U32.to_nat(255), U32.to_nat(pm)), + R.u32_lt(255, pm)), Equal.cong(U32, Bool, uu => U32.is_lt(255, uu), pm, 65521, epm))) + +# afold of bytes is Inf.adler's fold, from sums below the modulus +def ad.eq( + xs: List<&2, U32>, + +aa: U32, + +bb: U32, + +pm: U32, + +epm: {pm == 65521 : U32}, + +hby: {Laws.bytes.go(xs, True{}) == True{} : Bool}, + +ha: {Nat.is_lt(U32.to_nat(aa), U32.to_nat(pm)) == True{} : Bool}, + +hb: {Nat.is_lt(U32.to_nat(bb), U32.to_nat(pm)) == True{} : Bool} +) -> {afold(xs, aa, bb) == Inf.adler.fin(Inf.adler.go(xs, aa, bb)) : U32}: + match xs: + case Nil{}: + {==} + case +x <> +t: + +a2 = ((aa + x : U32) % 65521 : U32) + +b2 = ((bb + a2 : U32) % 65521 : U32) + +hxb = {Wp2.bytes.ok(t, U32.is_le(x, 255), hby) : {U32.is_le(x, 255) == True{} : Bool}} + +e_a = {add.mod(aa, x, pm, epm, ha, byte.pm(x, pm, epm, hxb)) : {Png.enc.add(aa, x) == a2 : U32}} + +l_a = {mod.lt((aa + x : U32), pm, epm) : {Nat.is_lt(U32.to_nat(a2), U32.to_nat(pm)) == True{} : Bool}} + +e_b = {Equal.trans(U32, Png.enc.add(bb, Png.enc.add(aa, x)), Png.enc.add(bb, a2), b2, Equal.cong(U32, U32, uu => + Png.enc.add(bb, uu), Png.enc.add(aa, x), a2, e_a), add.mod(bb, a2, pm, epm, hb, l_a)) : {Png.enc.add(bb, + Png.enc.add(aa, x)) == b2 : U32}} + +l_b = {mod.lt((bb + a2 : U32), pm, epm) : {Nat.is_lt(U32.to_nat(b2), U32.to_nat(pm)) == True{} : Bool}} + Equal.trans(U32, afold(t, Png.enc.add(aa, x), Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, b2), + Inf.adler.fin(Inf.adler.go(t, a2, b2)), + Equal.trans(U32, afold(t, Png.enc.add(aa, x), Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, + Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, b2), Equal.cong(U32, U32, uu => afold(t, uu, Png.enc.add(bb, + Png.enc.add(aa, x))), Png.enc.add(aa, x), a2, e_a), Equal.cong(U32, U32, uu => afold(t, a2, uu), + Png.enc.add(bb, Png.enc.add(aa, x)), b2, e_b)), + ad.eq(t, a2, b2, pm, epm, Wp2.bytes.tail(t, U32.is_le(x, 255), hby), l_a, l_b)) + +# enc.rgb.go's Adler-32 of bytes is Inf.adler.of +def afold.adler( + +xs: List<&2, U32>, + +pm: U32, + +epm: {pm == 65521 : U32}, + +hby: {Laws.bytes(xs) == True{} : Bool} +) -> {afold(xs, 1, 0) == Inf.adler.of(xs) : U32}: + +lt1 = {Equal.trans(Bool, Nat.is_lt(U32.to_nat(1), U32.to_nat(pm)), U32.is_lt(1, pm), True{}, Equal.sym(Bool, + U32.is_lt(1, pm), Nat.is_lt(U32.to_nat(1), U32.to_nat(pm)), R.u32_lt(1, pm)), Equal.cong(U32, Bool, uu => + U32.is_lt(1, uu), pm, 65521, epm)) : {Nat.is_lt(U32.to_nat(1), U32.to_nat(pm)) == True{} : Bool}} + +lt0 = {Equal.trans(Bool, Nat.is_lt(U32.to_nat(0), U32.to_nat(pm)), U32.is_lt(0, pm), True{}, Equal.sym(Bool, + U32.is_lt(0, pm), Nat.is_lt(U32.to_nat(0), U32.to_nat(pm)), R.u32_lt(0, pm)), Equal.cong(U32, Bool, uu => + U32.is_lt(0, uu), pm, 65521, epm)) : {Nat.is_lt(U32.to_nat(0), U32.to_nat(pm)) == True{} : Bool}} + ad.eq(xs, 1, 0, pm, epm, hby, lt1, lt0) + +# ---- J. enc.wide.rgb after the signature and IHDR ---- + +# twice k, as a product +def mul2(kk: Nat) -> {Nat.mul(kk, 2n) == Nat.double(kk) : Nat}: + match kk: + case 0n: + {==} + case 1n+kp: + Equal.cong(Nat, Nat, xx => 2n+xx, Nat.mul(kp, 2n), Nat.double(kp), mul2(kp)) + +# a count above 65535 is not zero, once is_zero's answer is named +def big.nz.at(zz: Bool, +nn: U32, +ez: {U32.is_zero(nn) == zz : Bool}, +hbig: {U32.is_le(nn, 65535) == False{} : Bool}) -> + {U32.is_zero(nn) == False{} : Bool}: + match zz: + case False{}: + ez + case True{}: + +e0 = {U32L.ueq(nn, 0, ez) : {nn == 0 : U32}} + Empty.absurd({U32.is_zero(nn) == False{} : Bool}, U32L.false_true(Equal.trans(Bool, False{}, U32.is_le(nn, 65535), + True{}, Equal.sym(Bool, U32.is_le(nn, 65535), False{}, hbig), Equal.cong(U32, Bool, uu => U32.is_le(uu, 65535), + nn, 0, e0)))) + +# the fuel enc.wide.rgb.z gives enc.rgb.go: a step per raw byte and two per +# block, less one +def rgb.fuel( + +nn: U32, + +tu: U32, + +nr: Nat, + +hn: {U32.to_nat(nn) == nr : Nat}, + +nz: {U32.is_zero(nn) == False{} : Bool}, + +h_tu: {Nat.is_le(Nat.add(Nat.add(nr, Nat.mul(U32.to_nat(Png.enc.nblk(nn)), 5n)), 6n), U32.to_nat(tu)) == True{} : + Bool} +) -> {Nat.is_le(Nat.add(Nat.add(nr, 0n), Nat.double(U32.to_nat(Png.enc.nblk(nn)))), 1n+U32.to_nat(((nn + + (Png.enc.nblk(nn) * 2 : U32) : U32) - 1 : U32))) == True{} : Bool}: + +kb = Png.enc.nblk(nn) + +kn = U32.to_nat(kb) + +k2 = Nat.mul(kn, 2n) + +tn = U32.to_nat(tu) + +s1 = (nn + (kb * 2 : U32) : U32) + +h5 = {R.le_add_r(Nat.add(nr, Nat.mul(kn, 5n)), 6n, tn, h_tu) : {Nat.is_le(Nat.add(nr, Nat.mul(kn, 5n)), tn) == True{} : + Bool}} + +h25 = {R.le_rw_r(k2, Nat.mul(5n, kn), Nat.mul(kn, 5n), R.mul_comm(5n, kn), R.le_rw_l(Nat.mul(2n, kn), k2, + Nat.mul(5n, kn), R.mul_comm(2n, kn), R.le_mul_mono(2n, 5n, kn, {==}))) : {Nat.is_le(k2, Nat.mul(kn, 5n)) == True{} : + Bool}} + +h2 = {R.le_trans(Nat.add(nr, k2), Nat.add(nr, Nat.mul(kn, 5n)), tn, R.le_add_mono(nr, k2, Nat.mul(kn, 5n), h25), h5) : + {Nat.is_le(Nat.add(nr, k2), tn) == True{} : Bool}} + +e_m = {R.u32_mul_below(kb, 2, tu, R.le_add_l(nr, k2, tn, h2)) : {U32.to_nat((kb * 2 : U32)) == k2 : Nat}} + +e_s = {Equal.trans(Nat, U32.to_nat(s1), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 2 : U32))), Nat.add(nr, k2), + R.u32_add_below(nn, (kb * 2 : U32), tu, R.le_rw_l(Nat.add(nr, k2), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 2 : + U32))), tn, Equal.trans(Nat, Nat.add(nr, k2), Nat.add(U32.to_nat(nn), k2), Nat.add(U32.to_nat(nn), U32.to_nat((kb * + 2 : U32))), Equal.cong(Nat, Nat, xx => Nat.add(xx, k2), nr, U32.to_nat(nn), Equal.sym(Nat, U32.to_nat(nn), nr, hn)), + Equal.cong(Nat, Nat, xx => Nat.add(U32.to_nat(nn), xx), k2, U32.to_nat((kb * 2 : U32)), Equal.sym(Nat, + U32.to_nat((kb * 2 : U32)), k2, e_m))), h2)), Equal.trans(Nat, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 2 : U32))), + Nat.add(nr, U32.to_nat((kb * 2 : U32))), Nat.add(nr, k2), Equal.cong(Nat, Nat, xx => Nat.add(xx, U32.to_nat((kb * 2 : + U32))), U32.to_nat(nn), nr, hn), Equal.cong(Nat, Nat, xx => Nat.add(nr, xx), U32.to_nat((kb * 2 : U32)), k2, e_m))) : + {U32.to_nat(s1) == Nat.add(nr, k2) : Nat}} + +e_n = {Equal.trans(Nat, U32.to_nat(nn), 1n+U32.to_nat((nn - 1 : U32)), 1n+U32.to_nat((nn - 1 : U32)), Wp1.u32_dec(nn, + nz), {==}) : {U32.to_nat(nn) == 1n+U32.to_nat((nn - 1 : U32)) : Nat}} + +nz1 = {Wp1.u32_nonzero(s1, Nat.add(U32.to_nat((nn - 1 : U32)), k2), Equal.trans(Nat, U32.to_nat(s1), Nat.add(nr, k2), + 1n+Nat.add(U32.to_nat((nn - 1 : U32)), k2), e_s, Equal.cong(Nat, Nat, xx => Nat.add(xx, k2), nr, 1n+U32.to_nat((nn - + 1 : U32)), Equal.trans(Nat, nr, U32.to_nat(nn), 1n+U32.to_nat((nn - 1 : U32)), Equal.sym(Nat, U32.to_nat(nn), nr, hn), + e_n)))) : {U32.is_zero(s1) == False{} : Bool}} + +e_st = {Equal.sym(Nat, U32.to_nat(s1), 1n+U32.to_nat((s1 - 1 : U32)), Wp1.u32_dec(s1, nz1)) : {1n+U32.to_nat((s1 - 1 + : U32)) == U32.to_nat(s1) : Nat}} + +e_l = {Equal.trans(Nat, Nat.add(Nat.add(nr, 0n), Nat.double(kn)), Nat.add(nr, Nat.double(kn)), Nat.add(nr, k2), + Equal.cong(Nat, Nat, xx => Nat.add(xx, Nat.double(kn)), Nat.add(nr, 0n), nr, R.add_zero(nr)), Equal.cong(Nat, Nat, + xx => Nat.add(nr, xx), Nat.double(kn), k2, Equal.sym(Nat, k2, Nat.double(kn), mul2(kn)))) : + {Nat.add(Nat.add(nr, 0n), Nat.double(kn)) == Nat.add(nr, k2) : Nat}} + R.le_rw_r(Nat.add(Nat.add(nr, 0n), Nat.double(kn)), Nat.add(nr, k2), 1n+U32.to_nat((s1 - 1 : U32)), Equal.trans(Nat, + Nat.add(nr, k2), U32.to_nat(s1), 1n+U32.to_nat((s1 - 1 : U32)), Equal.sym(Nat, U32.to_nat(s1), Nat.add(nr, k2), e_s), + Equal.sym(Nat, 1n+U32.to_nat((s1 - 1 : U32)), U32.to_nat(s1), e_st)), R.le_rw_l(Nat.add(nr, k2), + Nat.add(Nat.add(nr, 0n), Nat.double(kn)), Nat.add(nr, k2), Equal.sym(Nat, Nat.add(Nat.add(nr, 0n), Nat.double(kn)), + Nat.add(nr, k2), e_l), R.le_refl(Nat.add(nr, k2)))) + +# enc.wide.rgb after the signature and IHDR: the IDAT chunk holding the zlib +# stream of the scanlines in stored blocks of 65535 bytes, then IEND +def rgb.tail( + +px: List<&2, U32>, + +ww: U32, + +wp: Nat, + +mx: U32, + +pm: U32, + +tu: U32, + +ie: List<&2, U32>, + +emx: {mx == 65535 : U32}, + +epm: {pm == 65521 : U32}, + +ew: {U32.to_nat(ww) == 1n+wp : Nat}, + +hn: {U32.to_nat(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0)) == List.length(&2, U32, W9.sc(px, 0n, 1n+wp, True{})) + : Nat}, + +hbig: {U32.is_le(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0), 65535) == False{} : Bool}, + +hby: {Laws.bytes(W9.sc(px, 0n, 1n+wp, True{})) == True{} : Bool}, + +hl: {Png.enc.idat.ln(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0)) == Png.enc.len(Laws.zlib.stored(65535, + W9.sc(px, 0n, 1n+wp, True{})), 0) : U32}, + +h_tu: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, W9.sc(px, 0n, 1n+wp, True{})), + Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0))), 5n)), 6n), U32.to_nat(tu)) == True{} + : Bool} +) -> {Png.enc.wide.rgb.go(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, + Png.enc.cat.go(Png.enc.be(Png.enc.idat.ln(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0))), [])), px, ww, + Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0), ie) == Png.enc.cat(Png.enc.chunk(Png.tag.idat(), + Laws.zlib.stored(65535, W9.sc(px, 0n, 1n+wp, True{}))), ie) : List<&2, U32>}: + +raw = W9.sc(px, 0n, 1n+wp, True{}) + +nr = List.length(&2, U32, raw) + +nn = Png.enc.len(raw, 0) + +kn = U32.to_nat(Png.enc.nblk(nn)) + +ll = Png.enc.idat.ln(nn) + +aa = Png.enc.cat.go(Png.enc.be(ll), []) + +bi = Png.enc.be(Png.tag.idat()) + +c1 = Crc.crc.fold(bi, 4294967295) + +a1 = List.reverse.go(&2, U32, bi, aa) + +c2 = Crc.crc.fold([120, 1], c1) + +a2 = List.reverse.go(&2, U32, [120, 1], a1) + +steps = ((nn + (Png.enc.nblk(nn) * 2 : U32) : U32) - 1 : U32) + +sum = Inf.adler.of(raw) + +bb = bs(raw, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn)) + +bl = Png.enc.blocks(65535, raw) + +e_b = {sim.blocks(raw, mx, emx, hn, hbig) : {bl == bb : List<&2, U32>}} + +zz = Laws.zlib.stored(65535, raw) + +hl2 = {Equal.trans(U32, ll, Png.enc.len(zz, 0), Png.enc.len(zb(bb, sum), 0), hl, Equal.cong(List<&2, U32>, U32, ys => + Png.enc.len(zb(ys, sum), 0), bl, bb, e_b)) : {ll == Png.enc.len(zb(bb, sum), 0) : U32}} + +nz = {big.nz.at(U32.is_zero(nn), nn, {==}, hbig) : {U32.is_zero(nn) == False{} : Bool}} + -go = Png.enc.rgb.go(U32.to_nat(steps), True{}, False{}, False{}, False{}, True{}, True{}, False{}, False{}, px, 0, ww, + ww, 0, c2, a2, 1, 0, nn, 0) + +e_go = {rg(U32.to_nat(steps), True{}, False{}, False{}, False{}, True{}, True{}, False{}, False{}, px, 0, ww, ww, 0, c2, + a2, 1, 0, nn, 0, nn, 0, 0, kn, nr, wp, mx, emx, ew, Wp1.u32_nonzero(ww, wp, ew), _ef => {==}, ef => + Empty.absurd({True{} == False{} : Bool} -> {False{} == False{} : Bool} -> {False{} == U32.is_eq(ww, 1) : Bool}, + U32L.false_true(Equal.sym(Bool, True{}, False{}, ef))), {==}, kok.rw(U32.to_nat(nn), nr, kn, U32.to_nat(mx), hn, + nb.k(nn, mx, emx)), rgb.fuel(nn, tu, nr, hn, nz, h_tu), (Equal.sym(Bool, U32.is_zero(nn), False{}, nz), hn)) : {go == + (fr(bb, c2, a2), afold(raw, 1, 0)) : (U32 & List<&2, U32>) & U32}} + +e_fr = {Equal.trans(U32 & List<&2, U32>, fr(bb, c2, a2), fr(List.append(&2, U32, [120, 1], bb), c1, a1), fr(t0(bb), + 4294967295, aa), fr.app([120, 1], bb, c1, a1), fr.app(bi, List.append(&2, U32, [120, 1], bb), 4294967295, aa)) : + {fr(bb, c2, a2) == fr(t0(bb), 4294967295, aa) : U32 & List<&2, U32>}} + Equal.trans(List<&2, U32>, Png.enc.wide.rgb.go(Png.enc.crc.list(bi, 4294967295, aa), px, ww, nn, ie), + Png.enc.wide.rgb.go(fr(bi, 4294967295, aa), px, ww, nn, ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zz), ie), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.wide.rgb.go(pp, px, ww, nn, ie), Png.enc.crc.list(bi, + 4294967295, aa), fr(bi, 4294967295, aa), crcl(bi, 4294967295, aa)), + Equal.trans(List<&2, U32>, Png.enc.wide.rgb.z(Png.enc.crc.list([120, 1], c1, a1), px, ww, nn, ie), + Png.enc.wide.rgb.z(fr([120, 1], c1, a1), px, ww, nn, ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zz), ie), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.wide.rgb.z(pp, px, ww, nn, ie), + Png.enc.crc.list([120, 1], c1, a1), fr([120, 1], c1, a1), crcl([120, 1], c1, a1)), + Equal.trans(List<&2, U32>, Png.enc.wide.rgb.out(go, ie), Png.enc.wide.rgb.out((fr(bb, c2, a2), afold(raw, 1, 0)), + ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zz), ie), + Equal.cong((U32 & List<&2, U32>) & U32, List<&2, U32>, gg => Png.enc.wide.rgb.out(gg, ie), go, (fr(bb, c2, a2), + afold(raw, 1, 0)), e_go), + Equal.trans(List<&2, U32>, Png.enc.seal.adler(fr(bb, c2, a2), afold(raw, 1, 0), ie), + Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), sum, ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zz), ie), + Equal.trans(List<&2, U32>, Png.enc.seal.adler(fr(bb, c2, a2), afold(raw, 1, 0), ie), + Png.enc.seal.adler(fr(bb, c2, a2), sum, ie), Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), sum, ie), + Equal.cong(U32, List<&2, U32>, uu => Png.enc.seal.adler(fr(bb, c2, a2), uu, ie), afold(raw, 1, 0), sum, + afold.adler(raw, pm, epm, hby)), + Equal.cong(U32 & List<&2, U32>, List<&2, U32>, pp => Png.enc.seal.adler(pp, sum, ie), fr(bb, c2, a2), + fr(t0(bb), 4294967295, aa), e_fr)), + Equal.trans(List<&2, U32>, Png.enc.seal.adler(fr(t0(bb), 4294967295, aa), sum, ie), + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(bb, sum)), ie), Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zz), + ie), tail.chunk(bb, sum, ll, ie, hl2), Equal.cong(List<&2, U32>, List<&2, U32>, ys => + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(ys, sum)), ie), bb, bl, Equal.sym(List<&2, U32>, bl, bb, + e_b))))))) From 01ffdcababf59749f3a418754fea908a79a104c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 00:33:24 +0000 Subject: [PATCH 2/4] proof: ancillary chunks leave the PNG chunk walk as it was State png_roundtrip over the 2^29 bound and png_walk_anc in LAWS.bend. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A1bVZYFbhKkn2BKHKthcVP --- LAWS.bend | 90 +++++++++++ proof/wp11-png-finish.bend | 323 +++++++++++++++++++++++++++++++++++++ 2 files changed, 413 insertions(+) diff --git a/LAWS.bend b/LAWS.bend index c88655b..8e18a9b 100644 --- a/LAWS.bend +++ b/LAWS.bend @@ -2478,3 +2478,93 @@ law jpeg_unstuff: for +ok: U32 {jpg.read8(List.length(&2, JByte, bs), Jpeg.decode.read.n(8, Jpeg.Bits{0, ok, 0, Jenc.encode.stuff.all( List.reverse(&2, U32, jpg.bytes(bs)), [])})) == jpg.bytes(bs) : List<&2, U32>} + +# ---- wp11-png-finish ---- + +# LAW: a well-formed raster with both sides nonzero and fewer than 2^29 samples decodes from its PNG to itself. The +# bound is taken as a8, a U32 whose value is 8 w h: 8 w h is some U32's value exactly when w h is below 2^29 (a closed +# 2^29 in a law would be expanded in unary) +# IMG-PNG-2 +law png_roundtrip: + for +ww: U32 + for +hh: U32 + for +px: List<&2, U32> + for +a8: U32 + for h_ok: {png_ok(ww, hh, px) == True{} : Bool} + for h_a8: {U32.to_nat(a8) == Nat.mul(8n, Nat.mul(U32.to_nat(hh), U32.to_nat(ww))) : Nat} + {spec.png.back(Img.encode_png(Img.raster(ww, hh, px))) == Some{Img.raster(ww, hh, px)} : Maybe<&2, Img.Raster>} + +# an ancillary chunk (PNG section 5.4): its four-byte type, read as one number most significant byte first, and its +# data +type Anc is Data: + Anc{+typ: U32, +data: List<&2, U32>} + +# ancillary chunks laid out as spec.chunk, one after another, then rest +def spec.ancs(cs: List<&2, Anc>, rest: List<&2, U32>) -> List<&2, U32>: + match cs: + case Nil{}: + rest + case Anc{+typ, +data} <> tl: + spec.chunk(spec.be4(typ), data, spec.ancs(tl, rest)) + +# the ancillary bit (PNG section 5.4): bit 5 of the type's first byte is 1 +def spec.anc.bit(+typ: U32) -> Bool: + U32.is_eq(U32.and(U32.shrn(typ, 24n), 32), 32) + +# each chunk is ancillary, is not tRNS (1951551059, the bytes 116 82 78 83), and has fewer than 2^32 data bytes +def spec.ancs.ok(cs: List<&2, Anc>) -> Type: + match cs: + case Nil{}: + Unit + case Anc{+typ, +data} <> tl: + {spec.anc.bit(typ) == True{} : Bool} & ({U32.is_eq(typ, 1951551059) == False{} : Bool} & (spec.fits(data) & + spec.ancs.ok(tl))) + +# a PNG file as spec.png lays it out, with ancillary chunks where PNG section 5.6 allows them: a0 after IHDR, a1 after +# PLTE, a2 after tRNS, and a3 after the IDAT chunks, before IEND +def spec.png.anc( + +ww: U32, + +hh: U32, + +cc: U32, + a0: List<&2, Anc>, + plte: Maybe<&2, List<&2, U32>>, + a1: List<&2, Anc>, + trns: Maybe<&2, List<&2, U32>>, + a2: List<&2, Anc>, + idats: List<&2, List<&2, U32>>, + a3: List<&2, Anc> +) -> List<&2, U32>: + List.append(&2, U32, Img.png_sig(), spec.chunk([73, 72, 68, 82], spec.ihdr.data(ww, hh, cc), spec.ancs(a0, + spec.chunk.opt([80, 76, 84, 69], plte, spec.ancs(a1, spec.chunk.opt([116, 82, 78, 83], trns, spec.ancs(a2, + spec.idats(idats, spec.ancs(a3, spec.chunk([73, 69, 78, 68], [], [])))))))))) + +# LAW: ancillary chunks where PNG section 5.6 allows them leave what decode_png makes of a file: the file png_walk +# reads, with ancillary chunks after IHDR, PLTE, tRNS and the IDAT chunks, decodes to the raster px.of packs from the +# unfiltered inflated IDAT data, with the IHDR colour type and the PLTE and tRNS data +# IMG-PNG-9 +# IMG-PIX-1 +law png_walk_anc: + for +ww: U32 + for +hh: U32 + for +cc: U32 + for +a0: List<&2, Anc> + for +plte: Maybe<&2, List<&2, U32>> + for +a1: List<&2, Anc> + for +trns: Maybe<&2, List<&2, U32>> + for +a2: List<&2, Anc> + for +idats: List<&2, List<&2, U32>> + for +a3: List<&2, Anc> + for h_ww: {U32.is_gt(ww, 0) == True{} : Bool} + for h_hh: {U32.is_gt(hh, 0) == True{} : Bool} + for h_cc: {spec.colour.ok(cc) == True{} : Bool} + for h_pl: {spec.plte.ok(cc, plte) == True{} : Bool} + for h_tr: {spec.trns.ok(cc, plte, trns) == True{} : Bool} + for h_fp: spec.fits.opt(plte) + for h_ft: spec.fits.opt(trns) + for h_fi: spec.fits.all(idats) + for h_a0: spec.ancs.ok(a0) + for h_a1: spec.ancs.ok(a1) + for h_a2: spec.ancs.ok(a2) + for h_a3: spec.ancs.ok(a3) + {Img.decode_png(spec.png.anc(ww, hh, cc, a0, plte, a1, trns, a2, idats, a3)) == spec.decoded(Inf.inflate( + List.concat(&2, U32, idats)), ww, hh, cc, spec.or.nil(plte), spec.or.nil(trns)) : Maybe<&2, Img.Raster>} diff --git a/proof/wp11-png-finish.bend b/proof/wp11-png-finish.bend index 927e9a1..0cc49d5 100644 --- a/proof/wp11-png-finish.bend +++ b/proof/wp11-png-finish.bend @@ -3117,3 +3117,326 @@ def rgb.tail( ie), tail.chunk(bb, sum, ll, ie, hl2), Equal.cong(List<&2, U32>, List<&2, U32>, ys => Png.enc.cat(Png.enc.chunk(Png.tag.idat(), zb(ys, sum)), ie), bb, bl, Equal.sym(List<&2, U32>, bl, bb, e_b))))))) + +# ---- K. ancillary chunks in the chunk walker ---- + +# W9.st with the IDAT run's end named: done once a chunk after the IDAT +# chunks has closed the run +def sd( + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +trns: Maybe<&2, List<&2, U32>>, + +idat: List<&2, U32>, + +sid: Bool, + +done: Bool +) -> Png.Pg: + Png.Pg{ww, hh, 8, cc, 0, 0, 0, idat, Laws.spec.or.nil(plte), Laws.spec.or.nil(trns), True{}, + Maybe.is_some(&2, List<&2, U32>, plte), sid, done, Maybe.is_some(&2, List<&2, U32>, trns), False{}} + +# the walker's dispatch on a type that is none of the five it reads, with the +# ancillary bit set: the chunk closes the IDAT run +def anc.at( + z1: Bool, + z2: Bool, + z3: Bool, + z4: Bool, + z5: Bool, + an: Bool, + +sp: Bool, + +si: Bool, + +sdn: Bool, + +st: Bool, + +colour: U32, + +data: List<&2, U32>, + +pg: Png.Pg, + +e1: {z1 == False{} : Bool}, + +e2: {z2 == False{} : Bool}, + +e3: {z3 == False{} : Bool}, + +e4: {z4 == False{} : Bool}, + +e5: {z5 == False{} : Bool}, + +ea: {an == True{} : Bool} +) -> {Png.png.apply.at(False{}, z1, z2, z3, z4, z5, an, True{}, sp, si, sdn, st, colour, data, pg) == + Png.NMore{Png.png.seal(pg)} : Png.Nx}: + match z1 z2 z3 z4 z5 an: + case False{} False{} False{} False{} False{} True{}: + {==} + case True{} _z2 _z3 _z4 _z5 _an: + Empty.absurd({Png.png.apply.at(False{}, True{}, _z2, _z3, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, data, pg) + == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e1))) + case False{} True{} _z3 _z4 _z5 _an: + Empty.absurd({Png.png.apply.at(False{}, False{}, True{}, _z3, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, data, + pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))) + case False{} False{} True{} _z4 _z5 _an: + Empty.absurd({Png.png.apply.at(False{}, False{}, False{}, True{}, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, + data, pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e3))) + case False{} False{} False{} True{} _z5 _an: + Empty.absurd({Png.png.apply.at(False{}, False{}, False{}, False{}, True{}, _z5, _an, True{}, sp, si, sdn, st, + colour, data, pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, + e4))) + case False{} False{} False{} False{} True{} _an: + Empty.absurd({Png.png.apply.at(False{}, False{}, False{}, False{}, False{}, True{}, _an, True{}, sp, si, sdn, st, + colour, data, pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, + e5))) + case False{} False{} False{} False{} False{} False{}: + Empty.absurd({Png.png.apply.at(False{}, False{}, False{}, False{}, False{}, False{}, False{}, True{}, sp, si, sdn, + st, colour, data, pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(ea)) + +# a type with the ancillary bit is not one whose bit is clear, once is_eq's answer is named +def neq.at( + zz: Bool, + +tt: U32, + +kk: U32, + +ez: {U32.is_eq(tt, kk) == zz : Bool}, + +hb: {Laws.spec.anc.bit(tt) == True{} : Bool}, + +hk: {Laws.spec.anc.bit(kk) == False{} : Bool} +) -> {U32.is_eq(tt, kk) == False{} : Bool}: + match zz: + case False{}: + ez + case True{}: + Empty.absurd({U32.is_eq(tt, kk) == False{} : Bool}, U32L.false_true(Equal.trans(Bool, False{}, + Laws.spec.anc.bit(kk), True{}, Equal.sym(Bool, Laws.spec.anc.bit(kk), False{}, hk), Equal.trans(Bool, + Laws.spec.anc.bit(kk), Laws.spec.anc.bit(tt), True{}, Equal.cong(U32, Bool, uu => Laws.spec.anc.bit(uu), kk, tt, + Equal.sym(U32, tt, kk, U32L.ueq(tt, kk, ez))), hb)))) + +# a type with the ancillary bit is not one whose bit is clear +def neq( + +tt: U32, + +kk: U32, + +hb: {Laws.spec.anc.bit(tt) == True{} : Bool}, + +hk: {Laws.spec.anc.bit(kk) == False{} : Bool} +) -> {U32.is_eq(tt, kk) == False{} : Bool}: + neq.at(U32.is_eq(tt, kk), tt, kk, {==}, hb, hk) + +# an ancillary chunk that is not tRNS: the walker closes the IDAT run and goes on +def anc.step( + +tt: U32, + +data: List<&2, U32>, + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +trns: Maybe<&2, List<&2, U32>>, + +idat: List<&2, U32>, + +sid: Bool, + +done: Bool, + +hb: {Laws.spec.anc.bit(tt) == True{} : Bool}, + +ht: {U32.is_eq(tt, 1951551059) == False{} : Bool} +) -> {Png.png.apply(tt, data, sd(ww, hh, cc, plte, trns, idat, sid, done)) == Png.NMore{sd(ww, hh, cc, plte, trns, idat, + sid, Bool.or(sid, done))} : Png.Nx}: + anc.at(U32.is_eq(tt, Png.tag.ihdr()), U32.is_eq(tt, Png.tag.idat()), U32.is_eq(tt, Png.tag.iend()), U32.is_eq(tt, + Png.tag.plte()), U32.is_eq(tt, Png.tag.trns()), Png.tag.anc(tt), Maybe.is_some(&2, List<&2, U32>, plte), sid, done, + Maybe.is_some(&2, List<&2, U32>, trns), cc, data, sd(ww, hh, cc, plte, trns, idat, sid, done), neq(tt, + Png.tag.ihdr(), hb, {==}), neq(tt, Png.tag.idat(), hb, {==}), neq(tt, Png.tag.iend(), hb, {==}), neq(tt, + Png.tag.plte(), hb, {==}), ht, hb) + +# the IDAT run's end after ancillary chunks: closed once one follows an IDAT +def dn(cs: List<&2, Laws.Anc>, +sid: Bool, done: Bool) -> Bool: + match cs: + case Nil{}: + done + case _ac <> tl: + dn(tl, sid, Bool.or(sid, done)) + +# before any IDAT, ancillary chunks leave the run open +def dn.ff(cs: List<&2, Laws.Anc>) -> {dn(cs, False{}, False{}) == False{} : Bool}: + match cs: + case Nil{}: + {==} + case _ac <> tl: + dn.ff(tl) + +# ancillary chunks: the walker skips them, closing the IDAT run if one came +def anc.walk( + cs: List<&2, Laws.Anc>, + +rest: List<&2, U32>, + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +trns: Maybe<&2, List<&2, U32>>, + +idat: List<&2, U32>, + +sid: Bool, + +done: Bool, + hc: Laws.spec.ancs.ok(cs) +) -> {Png.png.go(Laws.spec.ancs(cs, rest), Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, idat, sid, + done)) == Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, idat, sid, dn(cs, sid, + done))) : Maybe<&2, Png.Pic>}: + match cs: + case Nil{}: + {==} + case Laws.Anc{+tt, +data} <> +tl: + (hb, (ht, (hf, htl))) = hc + +r1 = Laws.spec.ancs(tl, rest) + +pg = sd(ww, hh, cc, plte, trns, idat, sid, done) + +pg2 = sd(ww, hh, cc, plte, trns, idat, sid, Bool.or(sid, done)) + +ea = {Equal.trans(Png.Nx, Png.png.apply(Png.be.u32(W9.bt3(tt), W9.bt2(tt), W9.bt1(tt), W9.bt0(tt)), + List.reverse(&2, U32, data), pg), Png.png.apply(tt, List.reverse(&2, U32, data), pg), Png.NMore{pg2}, + Equal.cong(U32, Png.Nx, uu => Png.png.apply(uu, List.reverse(&2, U32, data), pg), Png.be.u32(W9.bt3(tt), + W9.bt2(tt), W9.bt1(tt), W9.bt0(tt)), tt, W9.be.back(tt)), anc.step(tt, List.reverse(&2, U32, data), ww, hh, cc, + plte, trns, idat, sid, done, hb, ht)) : {Png.png.apply(Png.be.u32(W9.bt3(tt), W9.bt2(tt), W9.bt1(tt), + W9.bt0(tt)), List.reverse(&2, U32, data), pg) == Png.NMore{pg2} : Png.Nx}} + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.chunk([W9.bt3(tt), W9.bt2(tt), W9.bt1(tt), W9.bt0(tt)], data, + r1), Png.ZLen{}, False{}, 0, 0, [], [], pg), Png.png.go(r1, Png.ZLen{}, False{}, 0, 0, [], [], pg2), + Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, idat, sid, dn(tl, sid, + Bool.or(sid, done)))), + W9.chunk.more(W9.bt3(tt), W9.bt2(tt), W9.bt1(tt), W9.bt0(tt), data, r1, pg, pg2, hf, ea), + anc.walk(tl, rest, ww, hh, cc, plte, trns, idat, sid, Bool.or(sid, done), htl)) + +# before any IDAT: ancillary chunks leave the state as it was +def anc.pre( + +cs: List<&2, Laws.Anc>, + +rest: List<&2, U32>, + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +trns: Maybe<&2, List<&2, U32>>, + hc: Laws.spec.ancs.ok(cs) +) -> {Png.png.go(Laws.spec.ancs(cs, rest), Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, [], False{})) + == Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, [], False{})) : Maybe<&2, + Png.Pic>}: + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.ancs(cs, rest), Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, + plte, trns, [], False{}, False{})), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, [], + False{}, dn(cs, False{}, False{}))), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, + [], False{}, False{})), anc.walk(cs, rest, ww, hh, cc, plte, trns, [], False{}, False{}, hc), Equal.cong(Bool, + Maybe<&2, Png.Pic>, bb => Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, [], False{}, + bb)), dn(cs, False{}, False{}), False{}, dn.ff(cs))) + +# the IDAT chunks, ancillary chunks, then IEND: with done the IDAT data read +# so far, the image is the samples of done and the rest of the data, inflated +def walk.idats( + ds: List<&2, List<&2, U32>>, + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +trns: Maybe<&2, List<&2, U32>>, + +a3: List<&2, Laws.Anc>, + +done: List<&2, U32>, + +sid: Bool, + +h_nd: {W9.need(cc, plte) == True{} : Bool}, + hf: Laws.spec.fits.all(ds), + ha: Laws.spec.ancs.ok(a3) +) -> {Png.png.go(Laws.spec.idats(ds, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], []))), Png.ZLen{}, + False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid)) == + Png.png.samples(Inf.inflate(List.append(&2, U32, done, List.concat(&2, U32, ds))), ww, hh, cc, Laws.spec.or.nil(plte), + Laws.spec.or.nil(trns)) : Maybe<&2, Png.Pic>}: + match ds: + case Nil{}: + +pl = Laws.spec.or.nil(plte) + +tr = Laws.spec.or.nil(trns) + +ie = Laws.spec.chunk([73, 69, 78, 68], [], []) + +pg = sd(ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid, dn(a3, sid, False{})) + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.ancs(a3, ie), Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, + plte, trns, List.reverse(&2, U32, done), sid, False{})), Png.png.go(ie, Png.ZLen{}, False{}, 0, 0, [], [], pg), + Png.png.samples(Inf.inflate(List.append(&2, U32, done, [])), ww, hh, cc, pl, tr), + anc.walk(a3, ie, ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid, False{}, ha), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(ie, Png.ZLen{}, False{}, 0, 0, [], [], pg), + Png.png.finish(Png.pg.iend(pg)), Png.png.samples(Inf.inflate(List.append(&2, U32, done, [])), ww, hh, cc, pl, + tr), + W9.chunk.end(73, 69, 78, 68, [], pg, Png.pg.iend(pg), {==}, W9.iend.ok.true(W9.need(cc, plte), pg, h_nd)), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.finish(Png.pg.iend(pg)), Png.png.samples(Inf.inflate(done), ww, hh, cc, + pl, tr), Png.png.samples(Inf.inflate(List.append(&2, U32, done, [])), ww, hh, cc, pl, tr), + Equal.cong(List<&2, U32>, Maybe<&2, Png.Pic>, xs => Png.png.samples(Inf.inflate(xs), ww, hh, cc, pl, tr), + List.reverse(&2, U32, List.reverse(&2, U32, done)), done, Wp2.rev_rev(done)), + Equal.cong(List<&2, U32>, Maybe<&2, Png.Pic>, xs => Png.png.samples(Inf.inflate(xs), ww, hh, cc, pl, tr), + done, List.append(&2, U32, done, []), Equal.sym(List<&2, U32>, List.append(&2, U32, done, []), done, + Wp2.app_nil(done)))))) + case +dd <> +tl: + (hd, htl) = hf + +pl = Laws.spec.or.nil(plte) + +tr = Laws.spec.or.nil(trns) + +rest = Laws.spec.idats(tl, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], []))) + +pg = W9.st(ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid) + +d2 = List.append(&2, U32, done, dd) + Equal.trans(Maybe<&2, Png.Pic>, + Png.png.go(Laws.spec.chunk([73, 68, 65, 84], dd, rest), Png.ZLen{}, False{}, 0, 0, [], [], pg), + Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, List.append(&2, U32, + List.reverse(&2, U32, dd), List.reverse(&2, U32, done)), True{})), + Png.png.samples(Inf.inflate(List.append(&2, U32, done, List.append(&2, U32, dd, List.concat(&2, U32, tl)))), ww, + hh, cc, pl, tr), + W9.chunk.more(73, 68, 65, 84, dd, rest, pg, W9.st(ww, hh, cc, plte, trns, List.append(&2, U32, List.reverse(&2, + U32, dd), List.reverse(&2, U32, done)), True{}), hd, W9.idat.step(ww, hh, cc, plte, trns, dd, List.reverse(&2, + U32, done), sid, h_nd)), + Equal.trans(Maybe<&2, Png.Pic>, + Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, List.append(&2, U32, + List.reverse(&2, U32, dd), List.reverse(&2, U32, done)), True{})), + Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, List.reverse(&2, U32, d2), + True{})), + Png.png.samples(Inf.inflate(List.append(&2, U32, done, List.append(&2, U32, dd, List.concat(&2, U32, tl)))), + ww, hh, cc, pl, tr), + Equal.cong(List<&2, U32>, Maybe<&2, Png.Pic>, xs => Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], + W9.st(ww, hh, cc, plte, trns, xs, True{})), List.append(&2, U32, List.reverse(&2, U32, dd), List.reverse(&2, + U32, done)), List.reverse(&2, U32, d2), W9.rev_app(done, dd)), + Equal.trans(Maybe<&2, Png.Pic>, + Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, List.reverse(&2, U32, d2), + True{})), + Png.png.samples(Inf.inflate(List.append(&2, U32, d2, List.concat(&2, U32, tl))), ww, hh, cc, pl, tr), + Png.png.samples(Inf.inflate(List.append(&2, U32, done, List.append(&2, U32, dd, List.concat(&2, U32, tl)))), + ww, hh, cc, pl, tr), + walk.idats(tl, ww, hh, cc, plte, trns, a3, d2, True{}, h_nd, htl, ha), + Equal.cong(List<&2, U32>, Maybe<&2, Png.Pic>, xs => Png.png.samples(Inf.inflate(xs), ww, hh, cc, pl, tr), + List.append(&2, U32, d2, List.concat(&2, U32, tl)), List.append(&2, U32, done, List.append(&2, U32, dd, + List.concat(&2, U32, tl))), Wp2.app_assoc(done, dd, List.concat(&2, U32, tl)))))) + +# the chunks after the signature, with ancillary chunks after IHDR, PLTE, +# tRNS and the IDAT chunks: the samples of the IDAT data, inflated +def walk.png( + +ww: U32, + +hh: U32, + +cc: U32, + +a0: List<&2, Laws.Anc>, + +plte: Maybe<&2, List<&2, U32>>, + +a1: List<&2, Laws.Anc>, + +trns: Maybe<&2, List<&2, U32>>, + +a2: List<&2, Laws.Anc>, + +idats: List<&2, List<&2, U32>>, + +a3: List<&2, Laws.Anc>, + +h_ww: {U32.is_gt(ww, 0) == True{} : Bool}, + +h_hh: {U32.is_gt(hh, 0) == True{} : Bool}, + +h_cc: {Laws.spec.colour.ok(cc) == True{} : Bool}, + +h_pl: {Laws.spec.plte.ok(cc, plte) == True{} : Bool}, + +h_tr: {Laws.spec.trns.ok(cc, plte, trns) == True{} : Bool}, + h_fp: Laws.spec.fits.opt(plte), + h_ft: Laws.spec.fits.opt(trns), + h_fi: Laws.spec.fits.all(idats), + h_a0: Laws.spec.ancs.ok(a0), + h_a1: Laws.spec.ancs.ok(a1), + h_a2: Laws.spec.ancs.ok(a2), + h_a3: Laws.spec.ancs.ok(a3) +) -> {Png.decode(Laws.spec.chunk([73, 72, 68, 82], Laws.spec.ihdr.data(ww, hh, cc), Laws.spec.ancs(a0, + Laws.spec.chunk.opt([80, 76, 84, 69], plte, Laws.spec.ancs(a1, Laws.spec.chunk.opt([116, 82, 78, 83], trns, + Laws.spec.ancs(a2, Laws.spec.idats(idats, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], [])))))))))) == + Png.png.samples(Inf.inflate(List.concat(&2, U32, idats)), ww, hh, cc, Laws.spec.or.nil(plte), Laws.spec.or.nil(trns)) : + Maybe<&2, Png.Pic>}: + +r3 = Laws.spec.idats(idats, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], []))) + +q2 = Laws.spec.ancs(a2, r3) + +r2 = Laws.spec.chunk.opt([116, 82, 78, 83], trns, q2) + +q1 = Laws.spec.ancs(a1, r2) + +r1 = Laws.spec.chunk.opt([80, 76, 84, 69], plte, q1) + +q0 = Laws.spec.ancs(a0, r1) + +s0 = W9.st(ww, hh, cc, None{}, None{}, [], False{}) + +s1 = W9.st(ww, hh, cc, plte, None{}, [], False{}) + +s2 = W9.st(ww, hh, cc, plte, trns, [], False{}) + +out = Png.png.samples(Inf.inflate(List.concat(&2, U32, idats)), ww, hh, cc, Laws.spec.or.nil(plte), + Laws.spec.or.nil(trns)) + Equal.trans(Maybe<&2, Png.Pic>, + Png.png.go(Laws.spec.chunk([73, 72, 68, 82], Laws.spec.ihdr.data(ww, hh, cc), q0), Png.ZLen{}, False{}, 0, 0, [], [], + Png.pg.empty()), + Png.png.go(q0, Png.ZLen{}, False{}, 0, 0, [], [], s0), out, + W9.chunk.more(73, 72, 68, 82, Laws.spec.ihdr.data(ww, hh, cc), q0, Png.pg.empty(), s0, {==}, W9.ihdr.step(ww, hh, cc, + h_ww, h_hh, h_cc)), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q0, Png.ZLen{}, False{}, 0, 0, [], [], s0), Png.png.go(r1, Png.ZLen{}, + False{}, 0, 0, [], [], s0), out, anc.pre(a0, r1, ww, hh, cc, None{}, None{}, h_a0), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(r1, Png.ZLen{}, False{}, 0, 0, [], [], s0), Png.png.go(q1, Png.ZLen{}, + False{}, 0, 0, [], [], s1), out, W9.walk.plte(ww, hh, cc, plte, q1, h_pl, h_fp), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q1, Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(r2, Png.ZLen{}, + False{}, 0, 0, [], [], s1), out, anc.pre(a1, r2, ww, hh, cc, plte, None{}, h_a1), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(r2, Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(q2, + Png.ZLen{}, False{}, 0, 0, [], [], s2), out, W9.walk.trns(ww, hh, cc, plte, trns, q2, h_tr, h_ft), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q2, Png.ZLen{}, False{}, 0, 0, [], [], s2), Png.png.go(r3, + Png.ZLen{}, False{}, 0, 0, [], [], s2), out, anc.pre(a2, r3, ww, hh, cc, plte, trns, h_a2), + walk.idats(idats, ww, hh, cc, plte, trns, a3, [], False{}, W9.need.ok(cc, plte, h_pl), h_fi, h_a3))))))) From a0dabbc85dc856c5ebb17da6d84689a376b54e6a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 02:31:53 +0000 Subject: [PATCH 3/4] proof: prove the PNG round trip below 2^29 samples, and ancillary chunks IMG-PNG-2 is reworded to rasters of fewer than 2^29 samples and proved: png_roundtrip covers the stored blocks of 65535 bytes that encode_png writes past one block, for colour type 6 (enc.pour) and colour type 2 (enc.rgb.go). png_walk_anc proves IMG-PNG-9 and the PNG side of IMG-PIX-1 for files with ancillary chunks, and with tRNS before PLTE. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A1bVZYFbhKkn2BKHKthcVP --- LAWS.bend | 33 +- PROOF.bend | 310 +++++++- SPEC.md | 13 +- proof/wp11-png-finish.bend | 1368 ++++++++++++++++++++++++++++-------- 4 files changed, 1393 insertions(+), 331 deletions(-) diff --git a/LAWS.bend b/LAWS.bend index 8e18a9b..b7c17a3 100644 --- a/LAWS.bend +++ b/LAWS.bend @@ -2520,12 +2520,28 @@ def spec.ancs.ok(cs: List<&2, Anc>) -> Type: {spec.anc.bit(typ) == True{} : Bool} & ({U32.is_eq(typ, 1951551059) == False{} : Bool} & (spec.fits(data) & spec.ancs.ok(tl))) -# a PNG file as spec.png lays it out, with ancillary chunks where PNG section 5.6 allows them: a0 after IHDR, a1 after -# PLTE, a2 after tRNS, and a3 after the IDAT chunks, before IEND +# PLTE, ancillary chunks a1 and tRNS, then rest; with late, tRNS comes first, an order the decoder also takes when +# the colour type allows tRNS with no PLTE yet +def spec.mid( + late: Bool, + plte: Maybe<&2, List<&2, U32>>, + a1: List<&2, Anc>, + trns: Maybe<&2, List<&2, U32>>, + rest: List<&2, U32> +) -> List<&2, U32>: + match late: + case False{}: + spec.chunk.opt([80, 76, 84, 69], plte, spec.ancs(a1, spec.chunk.opt([116, 82, 78, 83], trns, rest))) + case True{}: + spec.chunk.opt([116, 82, 78, 83], trns, spec.ancs(a1, spec.chunk.opt([80, 76, 84, 69], plte, rest))) + +# a PNG file as spec.png lays it out, with ancillary chunks where PNG section 5.6 allows them: a0 after IHDR, a1 +# between PLTE and tRNS, a2 after them, and a3 after the IDAT chunks, before IEND def spec.png.anc( +ww: U32, +hh: U32, +cc: U32, + late: Bool, a0: List<&2, Anc>, plte: Maybe<&2, List<&2, U32>>, a1: List<&2, Anc>, @@ -2535,18 +2551,20 @@ def spec.png.anc( a3: List<&2, Anc> ) -> List<&2, U32>: List.append(&2, U32, Img.png_sig(), spec.chunk([73, 72, 68, 82], spec.ihdr.data(ww, hh, cc), spec.ancs(a0, - spec.chunk.opt([80, 76, 84, 69], plte, spec.ancs(a1, spec.chunk.opt([116, 82, 78, 83], trns, spec.ancs(a2, - spec.idats(idats, spec.ancs(a3, spec.chunk([73, 69, 78, 68], [], [])))))))))) + spec.mid(late, plte, a1, trns, spec.ancs(a2, spec.idats(idats, spec.ancs(a3, spec.chunk([73, 69, 78, 68], [], + [])))))))) # LAW: ancillary chunks where PNG section 5.6 allows them leave what decode_png makes of a file: the file png_walk -# reads, with ancillary chunks after IHDR, PLTE, tRNS and the IDAT chunks, decodes to the raster px.of packs from the -# unfiltered inflated IDAT data, with the IHDR colour type and the PLTE and tRNS data +# reads, with ancillary chunks after IHDR, PLTE, tRNS and the IDAT chunks, and with tRNS before PLTE where the decoder +# takes that order (late), decodes to the raster px.of packs from the unfiltered inflated IDAT data, with the IHDR +# colour type and the PLTE and tRNS data # IMG-PNG-9 # IMG-PIX-1 law png_walk_anc: for +ww: U32 for +hh: U32 for +cc: U32 + for +late: Bool for +a0: List<&2, Anc> for +plte: Maybe<&2, List<&2, U32>> for +a1: List<&2, Anc> @@ -2559,6 +2577,7 @@ law png_walk_anc: for h_cc: {spec.colour.ok(cc) == True{} : Bool} for h_pl: {spec.plte.ok(cc, plte) == True{} : Bool} for h_tr: {spec.trns.ok(cc, plte, trns) == True{} : Bool} + for h_late: {Bool.or(Bool.not(late), spec.trns.ok(cc, None{}, trns)) == True{} : Bool} for h_fp: spec.fits.opt(plte) for h_ft: spec.fits.opt(trns) for h_fi: spec.fits.all(idats) @@ -2566,5 +2585,5 @@ law png_walk_anc: for h_a1: spec.ancs.ok(a1) for h_a2: spec.ancs.ok(a2) for h_a3: spec.ancs.ok(a3) - {Img.decode_png(spec.png.anc(ww, hh, cc, a0, plte, a1, trns, a2, idats, a3)) == spec.decoded(Inf.inflate( + {Img.decode_png(spec.png.anc(ww, hh, cc, late, a0, plte, a1, trns, a2, idats, a3)) == spec.decoded(Inf.inflate( List.concat(&2, U32, idats)), ww, hh, cc, spec.or.nil(plte), spec.or.nil(trns)) : Maybe<&2, Img.Raster>} diff --git a/PROOF.bend b/PROOF.bend index 70ecd66..d9011a6 100644 --- a/PROOF.bend +++ b/PROOF.bend @@ -19,6 +19,7 @@ import ./proof/wp8-jpeg-numeric.bend as W8 import ./proof/wp9-png-roundtrip.bend as W9 import ./src/inflate.bend as Inf import ./proof/wp10-jpeg-finish.bend as W10 +import ./proof/wp11-png-finish.bend as W11 # U32.or with 0xFF000000 first has alpha 255, whatever the other operand: # the 32 bits are taken apart four at a time, and Bool.or(True, b) is True. @@ -5258,6 +5259,63 @@ def rt.px( Equal.cong(Maybe<&2, List<&2, U32>>, Maybe<&2, Img.Raster>, mm => Laws.spec.raster(mm, ww, hh), Png.px.of(ct, W9.chans.all(op, px), [], []), Some{px}, rt.pix(op, px, hao))) +# the pixel stage after the layout: the one-block layout around any zlib stream of the scanlines that inflates to +# them decodes to the raster. The layout is stated stuck on zb, which is False +def rt.tail( + +zb: Bool, + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +op: Bool, + +wp: Nat, + +hp: Nat, + +ez: {zb == False{} : Bool}, + hao: {Laws.all_opaque(px) == op : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_h: {U32.to_nat(hh) == 1n+hp : Nat}, + +hl: {List.length(&2, U32, px) == Nat.mul(1n+hp, 1n+wp) : Nat}, + e_m: {U32.to_nat(U32.mul(ww, Png.enc.nch(op))) == Nat.mul(U32.to_nat(ww), U32.to_nat(Png.enc.nch(op))) : Nat}, + h_fz: Laws.spec.fits(Png.enc.zlib(W9.sc(px, 0n, 1n+wp, op), Png.enc.len(W9.sc(px, 0n, 1n+wp, op), 0))), + +h_nl: {U32.to_nat(Png.enc.len(W9.sc(px, 0n, 1n+wp, op), 0)) == List.length(&2, U32, W9.sc(px, 0n, 1n+wp, op)) : Nat} +) -> {Img.decode_png(Png.enc.seal.at(zb, ww, hh, op, W9.sc(px, 0n, 1n+wp, op), Png.enc.len(W9.sc(px, 0n, 1n+wp, op), + 0))) == Some{Img.raster(ww, hh, px)} : Maybe<&2, Img.Raster>}: + +ww1 = {1n+wp : Nat} + +hh1 = {1n+hp : Nat} + +ss = W9.sc(px, 0n, ww1, op) + +rows = W9.rows.of(hh1, ww1, op, px) + +ll = Png.enc.len(ss, 0) + +zz = Png.enc.zlib(ss, ll) + +e_s = {W9.sc.rows(hh1, wp, op, px, hl) : {ss == W9.scan(rows) : List<&2, U32>}} + +h_by = {Equal.trans(Bool, Laws.bytes(ss), Laws.bytes.go(W9.scan(rows), True{}), True{}, Equal.cong(List<&2, U32>, + Bool, xs => Laws.bytes.go(xs, True{}), ss, W9.scan(rows), e_s), W9.bytes.scan(rows, W9.masked.rows.of(hh1, ww1, op, + px))) : {Laws.bytes(ss) == True{} : Bool}} + +e_inf = {Laws.inflate_enc_zlib(ss, h_by, h_nl) : {Inf.inflate(zz) == Some{ss} : Maybe<&2, List<&2, U32>>}} + +ct = Png.enc.ct(op) + +h_ww = W9.gt.pos(ww, wp, e_w) + +h_hh = W9.gt.pos(hh, hp, e_h) + +a6 = Img.decode_png(Png.enc.seal.at(zb, ww, hh, op, ss, ll)) + +a8 = Img.decode_png(Laws.spec.png(ww, hh, ct, None{}, None{}, [zz])) + +a9 = Laws.spec.decoded(Inf.inflate(List.concat(&2, U32, [zz])), ww, hh, ct, [], []) + +a10 = Laws.spec.decoded(Some{ss}, ww, hh, ct, [], []) + Equal.trans(Maybe<&2, Img.Raster>, a6, a8, Some{Img.raster(ww, hh, px)}, + Equal.trans(Maybe<&2, Img.Raster>, a6, Img.decode_png(Png.enc.seal.one(ww, hh, op, ss, ll)), a8, + Equal.cong(Bool, Maybe<&2, Img.Raster>, zc => Img.decode_png(Png.enc.seal.at(zc, ww, hh, op, ss, ll)), + zb, False{}, ez), + Equal.cong(List<&2, U32>, Maybe<&2, Img.Raster>, xs => Img.decode_png(xs), Png.enc.seal.one(ww, hh, op, ss, + ll), Laws.spec.png(ww, hh, ct, None{}, None{}, [zz]), W9.seal.one.same(ww, hh, op, ss, ll))), + Equal.trans(Maybe<&2, Img.Raster>, a8, a9, Some{Img.raster(ww, hh, px)}, + Laws.png_walk(ww, hh, ct, None{}, None{}, [zz], h_ww, h_hh, rt.col(op), rt.plte(op), {==}, Unit{}, Unit{}, + (h_fz, Unit{})), + Equal.trans(Maybe<&2, Img.Raster>, a9, Laws.spec.decoded(Inf.inflate(zz), ww, hh, ct, [], []), + Some{Img.raster(ww, hh, px)}, + Equal.cong(List<&2, U32>, Maybe<&2, Img.Raster>, xs => Laws.spec.decoded(Inf.inflate(xs), ww, hh, ct, [], + []), List.append(&2, U32, zz, []), zz, Wp2.app_nil(zz)), + Equal.trans(Maybe<&2, Img.Raster>, Laws.spec.decoded(Inf.inflate(zz), ww, hh, ct, [], []), a10, + Some{Img.raster(ww, hh, px)}, + Equal.cong(Maybe<&2, List<&2, U32>>, Maybe<&2, Img.Raster>, mm => Laws.spec.decoded(mm, ww, hh, ct, [], + []), Inf.inflate(zz), Some{ss}, e_inf), + rt.px(ww, hh, px, op, wp, hp, hao, e_w, e_h, hl, e_m))))) + # the one-block round trip, with the width and height 1 + w' and 1 + h', and # op whether every sample is opaque def rt.go( @@ -5346,20 +5404,10 @@ def rt.go( {U32.is_gt(ll, 65535) == False{} : Bool}} h_fz = {W9.fits.small(zz, ls, cap, cap2, W9.zlib.len(ss, ll, le_l), h_ls, hc) : Laws.spec.fits(zz)} - +h_by = {Equal.trans(Bool, Laws.bytes(ss), Laws.bytes.go(W9.scan(rows), True{}), True{}, Equal.cong(List<&2, U32>, - Bool, xs => Laws.bytes.go(xs, True{}), ss, W9.scan(rows), e_s), W9.bytes.scan(rows, W9.masked.rows.of(hh1, ww1, op, - px))) : {Laws.bytes(ss) == True{} : Bool}} +h_nl = {Equal.trans(Nat, U32.to_nat(ll), nn, ls, t_l, Equal.sym(Nat, ls, nn, e_ls)) : {U32.to_nat(ll) == ls : Nat}} - +e_inf = {Laws.inflate_enc_zlib(ss, h_by, h_nl) : {Inf.inflate(zz) == Some{ss} : Maybe<&2, List<&2, U32>>}} - +ct = Png.enc.ct(op) - +h_ww = W9.gt.pos(ww, wp, e_w) - +h_hh = W9.gt.pos(hh, hp, e_h) +a2 = Img.decode_png(Png.enc.paint(ww, hh, op, px)) +a4 = Img.decode_png(Png.enc.seal(ww, hh, op, Png.enc.raw(px, 0n, ww1, op, [], 0))) +a6 = Img.decode_png(Png.enc.seal.at(U32.is_gt(ll, 65535), ww, hh, op, ss, ll)) - +a8 = Img.decode_png(Laws.spec.png(ww, hh, ct, None{}, None{}, [zz])) - +a9 = Laws.spec.decoded(Inf.inflate(List.concat(&2, U32, [zz])), ww, hh, ct, [], []) - +a10 = Laws.spec.decoded(Some{ss}, ww, hh, ct, [], []) Equal.trans(Maybe<&2, Img.Raster>, Laws.spec.png.back(Png.enc.open(Png.enc.good(ww, hh, px), ww, hh, px)), a2, Some{Img.raster(ww, hh, px)}, Equal.trans(Maybe<&2, Img.Raster>, Laws.spec.png.back(Png.enc.open(Png.enc.good(ww, hh, px), ww, hh, px)), @@ -5384,24 +5432,7 @@ def rt.go( r0, ss, Wp2.rev_rev(ss)), Equal.cong(U32, Maybe<&2, Img.Raster>, uu => Img.decode_png(Png.enc.seal(ww, hh, op, (ss, uu))), m0, ll, e_m0))), - Equal.trans(Maybe<&2, Img.Raster>, a6, a8, Some{Img.raster(ww, hh, px)}, - Equal.trans(Maybe<&2, Img.Raster>, a6, Img.decode_png(Png.enc.seal.one(ww, hh, op, ss, ll)), a8, - Equal.cong(Bool, Maybe<&2, Img.Raster>, zb => Img.decode_png(Png.enc.seal.at(zb, ww, hh, op, ss, ll)), - U32.is_gt(ll, 65535), False{}, f_ll), - Equal.cong(List<&2, U32>, Maybe<&2, Img.Raster>, xs => Img.decode_png(xs), Png.enc.seal.one(ww, hh, op, ss, - ll), Laws.spec.png(ww, hh, ct, None{}, None{}, [zz]), W9.seal.one.same(ww, hh, op, ss, ll))), - Equal.trans(Maybe<&2, Img.Raster>, a8, a9, Some{Img.raster(ww, hh, px)}, - Laws.png_walk(ww, hh, ct, None{}, None{}, [zz], h_ww, h_hh, rt.col(op), rt.plte(op), {==}, Unit{}, Unit{}, - (h_fz, Unit{})), - Equal.trans(Maybe<&2, Img.Raster>, a9, Laws.spec.decoded(Inf.inflate(zz), ww, hh, ct, [], []), - Some{Img.raster(ww, hh, px)}, - Equal.cong(List<&2, U32>, Maybe<&2, Img.Raster>, xs => Laws.spec.decoded(Inf.inflate(xs), ww, hh, ct, [], - []), List.append(&2, U32, zz, []), zz, Wp2.app_nil(zz)), - Equal.trans(Maybe<&2, Img.Raster>, Laws.spec.decoded(Inf.inflate(zz), ww, hh, ct, [], []), a10, - Some{Img.raster(ww, hh, px)}, - Equal.cong(Maybe<&2, List<&2, U32>>, Maybe<&2, Img.Raster>, mm => Laws.spec.decoded(mm, ww, hh, ct, [], - []), Inf.inflate(zz), Some{ss}, e_inf), - rt.px(ww, hh, px, op, wp, hp, hao, e_w, e_h, hl, e_m)))))))) + rt.tail(U32.is_gt(ll, 65535), ww, hh, px, op, wp, hp, f_ll, hao, e_w, e_h, hl, e_m, h_fz, h_nl)))) # the width and height as successors def rt.pos( @@ -5691,3 +5722,226 @@ def Laws.jpeg_unstuff(bs, ok): 0, W10.stf(xs, [])})), xs, Equal.cong(List<&2, U32>, List<&2, U32>, zs => Laws.jpg.read8(nn, Jpeg.decode.read.n(8, Jpeg.Bits{0, ok, 0, zs})), Jenc.encode.stuff.all(List.reverse(&2, U32, xs), []), W10.stf(xs, []), W10.stall.rev(xs, [], [])), W10.rd.list(bs, ok, [])) + +# ---- wp11-png-finish ---- + +# IMG-PNG-9 and IMG-PIX-1: ancillary chunks where PNG section 5.6 allows them leave what the walker hands the pixel +# stage +def Laws.png_walk_anc( + ww, + hh, + cc, + late, + a0, + plte, + a1, + trns, + a2, + idats, + a3, + h_ww, + h_hh, + h_cc, + h_pl, + h_tr, + h_late, + h_fp, + h_ft, + h_fi, + h_a0, + h_a1, + h_a2, + h_a3 +): + +mm = Inf.inflate(List.concat(&2, U32, idats)) + +pl = Laws.spec.or.nil(plte) + +tr = Laws.spec.or.nil(trns) + +fl = Laws.spec.chunk([73, 72, 68, 82], Laws.spec.ihdr.data(ww, hh, cc), Laws.spec.ancs(a0, Laws.spec.mid(late, plte, + a1, trns, Laws.spec.ancs(a2, Laws.spec.idats(idats, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], + []))))))) + Equal.trans(Maybe<&2, Img.Raster>, Img.decode_png.pic(Png.decode(fl)), Img.decode_png.pic(Png.png.samples(mm, ww, hh, + cc, pl, tr)), Laws.spec.decoded(mm, ww, hh, cc, pl, tr), + Equal.cong(Maybe<&2, Png.Pic>, Maybe<&2, Img.Raster>, xx => Img.decode_png.pic(xx), Png.decode(fl), + Png.png.samples(mm, ww, hh, cc, pl, tr), W11.walk.png(ww, hh, cc, late, a0, plte, a1, trns, a2, idats, a3, h_ww, + h_hh, h_cc, h_pl, h_tr, h_late, h_fp, h_ft, h_fi, h_a0, h_a1, h_a2, h_a3)), + W9.frame.decoded(mm, ww, hh, cc, pl, tr)) + +# IMG-PNG-2 when the scanlines fit one stored block: png_roundtrip_one, with the scanline count a word's value +def rt2.one( + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +wp: Nat, + +hp: Nat, + h_ok: {Laws.png_ok(ww, hh, px) == True{} : Bool}, + +hao: {Laws.all_opaque(px) == Png.enc.opaque(px, True{}) : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_h: {U32.to_nat(hh) == 1n+hp : Nat}, + +t_nb: {U32.to_nat(Png.enc.nbytes(W11.opq(px), ww, hh)) == W11.snn(hp, wp, W11.opq(px)) : Nat}, + h_one: {U32.is_le(Png.enc.nbytes(Png.enc.opaque(px, True{}), ww, hh), 65535) == True{} : Bool} +) -> {Laws.spec.png.back(Img.encode_png(Img.raster(ww, hh, px))) == Some{Img.raster(ww, hh, px)} : Maybe<&2, + Img.Raster>}: + +op = Png.enc.opaque(px, True{}) + +ao = Laws.all_opaque(px) + +nb = Png.enc.nbytes(op, ww, hh) + +hn = U32.to_nat(hh) + +wn = U32.to_nat(ww) + +e_n = {Equal.trans(Nat, Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))), Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, + Laws.spec.nch(ao))), Laws.spec.scan.len(ww, hh, ao), + Equal.cong(Bool, Nat, oo => Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(oo))), op, ao, Equal.sym(Bool, ao, op, + hao)), + Equal.trans(Nat, Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(ao))), Nat.mul(hn, 1n+Nat.mul(1n+wp, + Laws.spec.nch(ao))), Laws.spec.scan.len(ww, hh, ao), + Equal.cong(Nat, Nat, xx => Nat.mul(xx, 1n+Nat.mul(1n+wp, Laws.spec.nch(ao))), 1n+hp, hn, Equal.sym(Nat, hn, + 1n+hp, e_h)), + Equal.cong(Nat, Nat, xx => Nat.mul(hn, 1n+Nat.mul(xx, Laws.spec.nch(ao))), 1n+wp, wn, Equal.sym(Nat, wn, 1n+wp, + e_w)))) : {Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))) == Laws.spec.scan.len(ww, hh, ao) : Nat}} + Laws.png_roundtrip_one(ww, hh, px, nb, h_ok, Equal.trans(Nat, U32.to_nat(nb), Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, + Laws.spec.nch(op))), Laws.spec.scan.len(ww, hh, ao), t_nb, e_n), h_one) + +# IMG-PNG-2 past one stored block: the stored blocks of 65535 bytes, whose sizes fit a word by the bound 8 w h +def rt2.wide( + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +a8: U32, + +wp: Nat, + +hp: Nat, + e_good: {Png.enc.good(ww, hh, px) == True{} : Bool}, + +hao: {Laws.all_opaque(px) == Png.enc.opaque(px, True{}) : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_h: {U32.to_nat(hh) == 1n+hp : Nat}, + +hl: {List.length(&2, U32, px) == Nat.mul(1n+hp, 1n+wp) : Nat}, + +t_nb: {U32.to_nat(Png.enc.nbytes(W11.opq(px), ww, hh)) == W11.snn(hp, wp, W11.opq(px)) : Nat}, + +e_t: {U32.to_nat(a8) == Nat.mul(8n, Nat.mul(1n+hp, 1n+wp)) : Nat}, + +h5: {Nat.is_le(W11.snn(hp, wp, W11.opq(px)), Nat.mul(Nat.mul(1n+hp, 1n+wp), 5n)) == True{} : Bool}, + +h_n: {Nat.is_le(W11.snn(hp, wp, W11.opq(px)), U32.to_nat(a8)) == True{} : Bool}, + +hbn: {U32.is_le(Png.enc.nbytes(Png.enc.opaque(px, True{}), ww, hh), 65535) == False{} : Bool} +) -> {Laws.spec.png.back(Img.encode_png(Img.raster(ww, hh, px))) == Some{Img.raster(ww, hh, px)} : Maybe<&2, + Img.Raster>}: + +op = Png.enc.opaque(px, True{}) + +ww1 = {1n+wp : Nat} + +hh1 = {1n+hp : Nat} + +aa = Nat.mul(hh1, ww1) + +nn = Nat.mul(hh1, 1n+Nat.mul(ww1, Laws.spec.nch(op))) + +ss = W9.sc(px, 0n, ww1, op) + +ll = Png.enc.len(ss, 0) + +nb = Png.enc.nbytes(op, ww, hh) + +ls = List.length(&2, U32, ss) + +rows = W9.rows.of(hh1, ww1, op, px) + +e_s = {W9.sc.rows(hh1, wp, op, px, hl) : {ss == W9.scan(rows) : List<&2, U32>}} + +e_ls = {Equal.trans(Nat, ls, List.length(&2, U32, W9.scan(rows)), nn, Equal.cong(List<&2, U32>, Nat, xs => + List.length(&2, U32, xs), ss, W9.scan(rows), e_s), W9.len.scan(hh1, ww1, op, px, hl)) : {ls == nn : Nat}} + +hn = {W11.len.of(ss, a8, R.le_rw_l(nn, ls, U32.to_nat(a8), Equal.sym(Nat, ls, nn, e_ls), h_n)) : + {U32.to_nat(ll) == ls : Nat}} + +e_nbl = {W11.u32.same(nb, ll, Equal.trans(Nat, U32.to_nat(nb), nn, U32.to_nat(ll), t_nb, Equal.trans(Nat, nn, ls, + U32.to_nat(ll), Equal.sym(Nat, ls, nn, e_ls), Equal.sym(Nat, U32.to_nat(ll), ls, hn)))) : {nb == ll : U32}} + +hbig = {Equal.trans(Bool, U32.is_le(ll, 65535), U32.is_le(nb, 65535), False{}, Equal.cong(U32, Bool, uu => + U32.is_le(uu, 65535), ll, nb, Equal.sym(U32, nb, ll, e_nbl)), hbn) : {U32.is_le(ll, 65535) == False{} : Bool}} + +h_tu = W11.tu.ok(ss, 65535, a8, aa, {==}, hn, hbig, R.le_rw_l(nn, ls, Nat.mul(aa, 5n), Equal.sym(Nat, ls, nn, + e_ls), h5), e_t) + +h_by = {Equal.trans(Bool, Laws.bytes(ss), Laws.bytes.go(W9.scan(rows), True{}), True{}, Equal.cong(List<&2, U32>, + Bool, xs => Laws.bytes.go(xs, True{}), ss, W9.scan(rows), e_s), W9.bytes.scan(rows, W9.masked.rows.of(hh1, ww1, op, + px))) : {Laws.bytes(ss) == True{} : Bool}} + +zf = Nat.is_lt(ls, 0n) + +ef = {Equal.sym(Bool, False{}, zf, R.lt_zero_false(ls)) : {zf == False{} : Bool}} + +kz = Nat.add(Nat.add(ls, Nat.mul(U32.to_nat(Png.enc.nblk(ll)), 5n)), 6n) + h_fz = {W9.nat.fits(List.length(&2, U32, Png.enc.zlib(ss, ll)), a8, R.le_rw_l(kz, List.length(&2, U32, + Laws.zlib.stored(65535, ss)), U32.to_nat(a8), Equal.sym(Nat, List.length(&2, U32, Laws.zlib.stored(65535, ss)), kz, + W11.zlib.len(ss, 65535, {==}, hn, hbig)), h_tu)) : Laws.spec.fits(Png.enc.zlib(ss, ll))} + Equal.trans(Maybe<&2, Img.Raster>, Laws.spec.png.back(Png.enc.open(Png.enc.good(ww, hh, px), ww, hh, px)), + Laws.spec.png.back(Some{Png.enc.seal.at(zf, ww, hh, op, ss, ll)}), Some{Img.raster(ww, hh, px)}, + Equal.cong(Maybe<&2, List<&2, U32>>, Maybe<&2, Img.Raster>, mm => Laws.spec.png.back(mm), + Png.enc.open(Png.enc.good(ww, + hh, px), ww, hh, px), Some{Png.enc.seal.at(zf, ww, hh, op, ss, ll)}, W11.wide.rt(zf, ww, hh, px, wp, a8, ef, + e_good, e_w, e_nbl, hn, hbig, h_by, h_tu)), + rt.tail(zf, ww, hh, px, op, wp, hp, ef, hao, e_w, e_h, hl, W11.nb.em(ww, op, wp, hp, a8, e_w, h_n), h_fz, hn)) + +# IMG-PNG-2: split on how the scanline count compares with 65535 +def rt2.at( + cc: Cmp, + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +a8: U32, + +wp: Nat, + +hp: Nat, + h_ok: {Laws.png_ok(ww, hh, px) == True{} : Bool}, + e_good: {Png.enc.good(ww, hh, px) == True{} : Bool}, + +hao: {Laws.all_opaque(px) == Png.enc.opaque(px, True{}) : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_h: {U32.to_nat(hh) == 1n+hp : Nat}, + +hl: {List.length(&2, U32, px) == Nat.mul(1n+hp, 1n+wp) : Nat}, + +t_nb: {U32.to_nat(Png.enc.nbytes(W11.opq(px), ww, hh)) == W11.snn(hp, wp, W11.opq(px)) : Nat}, + +e_t: {U32.to_nat(a8) == Nat.mul(8n, Nat.mul(1n+hp, 1n+wp)) : Nat}, + +h5: {Nat.is_le(W11.snn(hp, wp, W11.opq(px)), Nat.mul(Nat.mul(1n+hp, 1n+wp), 5n)) == True{} : Bool}, + +h_n: {Nat.is_le(W11.snn(hp, wp, W11.opq(px)), U32.to_nat(a8)) == True{} : Bool}, + +ec: {U32.cmp(Png.enc.nbytes(Png.enc.opaque(px, True{}), ww, hh), 65535) == cc : Cmp} +) -> {Laws.spec.png.back(Img.encode_png(Img.raster(ww, hh, px))) == Some{Img.raster(ww, hh, px)} : Maybe<&2, + Img.Raster>}: + match cc: + case LT{}: + rt2.one(ww, hh, px, wp, hp, h_ok, hao, e_w, e_h, t_nb, Equal.cong(Cmp, Bool, xc => Cmp.is_le(xc), + U32.cmp(Png.enc.nbytes(Png.enc.opaque(px, True{}), ww, hh), 65535), LT{}, ec)) + case EQ{}: + rt2.one(ww, hh, px, wp, hp, h_ok, hao, e_w, e_h, t_nb, Equal.cong(Cmp, Bool, xc => Cmp.is_le(xc), + U32.cmp(Png.enc.nbytes(Png.enc.opaque(px, True{}), ww, hh), 65535), EQ{}, ec)) + case GT{}: + rt2.wide(ww, hh, px, a8, wp, hp, e_good, hao, e_w, e_h, hl, t_nb, e_t, h5, h_n, Equal.cong(Cmp, Bool, xc => + Cmp.is_le(xc), U32.cmp(Png.enc.nbytes(Png.enc.opaque(px, True{}), ww, hh), 65535), GT{}, ec)) + +# IMG-PNG-2 with the width and height as successors: the sizes from the bound 8 w h +def rt2.pos( + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +a8: U32, + h_ok: {Laws.png_ok(ww, hh, px) == True{} : Bool}, + e_good: {Png.enc.good(ww, hh, px) == True{} : Bool}, + +hl: {List.length(&2, U32, px) == Nat.mul(U32.to_nat(hh), U32.to_nat(ww)) : Nat}, + +h_a8: {U32.to_nat(a8) == Nat.mul(8n, Nat.mul(U32.to_nat(hh), U32.to_nat(ww))) : Nat}, + pw: &wp: Nat -> {U32.to_nat(ww) == 1n+wp : Nat}, + ph: &hp: Nat -> {U32.to_nat(hh) == 1n+hp : Nat} +) -> {Laws.spec.png.back(Img.encode_png(Img.raster(ww, hh, px))) == Some{Img.raster(ww, hh, px)} : Maybe<&2, + Img.Raster>}: + (+wp, e_w0) = pw + (+hp, e_h0) = ph + +e_w = {e_w0 : {U32.to_nat(ww) == 1n+wp : Nat}} + +e_h = {e_h0 : {U32.to_nat(hh) == 1n+hp : Nat}} + +op = Png.enc.opaque(px, True{}) + +hn = U32.to_nat(hh) + +wn = U32.to_nat(ww) + +aa = Nat.mul(1n+hp, 1n+wp) + +nn = Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))) + +hao = {Equal.sym(Bool, op, Laws.all_opaque(px), opaque.all(px, True{})) : {Laws.all_opaque(px) == op : Bool}} + +e_l2 = {Equal.trans(Nat, List.length(&2, U32, px), Nat.mul(hn, wn), aa, hl, Equal.trans(Nat, Nat.mul(hn, wn), + Nat.mul(1n+hp, wn), aa, Equal.cong(Nat, Nat, xx => Nat.mul(xx, wn), hn, 1n+hp, e_h), Equal.cong(Nat, Nat, xx => + Nat.mul(1n+hp, xx), wn, 1n+wp, e_w))) : {List.length(&2, U32, px) == aa : Nat}} + +e_t = {Equal.trans(Nat, U32.to_nat(a8), Nat.mul(8n, Nat.mul(hn, wn)), Nat.mul(8n, aa), h_a8, Equal.trans(Nat, + Nat.mul(8n, Nat.mul(hn, wn)), Nat.mul(8n, Nat.mul(1n+hp, wn)), Nat.mul(8n, aa), Equal.cong(Nat, Nat, xx => + Nat.mul(8n, Nat.mul(xx, wn)), hn, 1n+hp, e_h), Equal.cong(Nat, Nat, xx => Nat.mul(8n, Nat.mul(1n+hp, xx)), wn, + 1n+wp, e_w))) : {U32.to_nat(a8) == Nat.mul(8n, aa) : Nat}} + +h5 = {W11.scan5(1n+hp, wp, Laws.spec.nch(op), W11.nch4(op)) : {Nat.is_le(nn, Nat.mul(aa, 5n)) == True{} : Bool}} + +h_n = {R.le_rw_r(nn, Nat.mul(8n, aa), U32.to_nat(a8), Equal.sym(Nat, U32.to_nat(a8), Nat.mul(8n, aa), e_t), + R.le_trans(nn, Nat.mul(aa, 5n), Nat.mul(8n, aa), h5, W11.five.eight(aa))) : {Nat.is_le(nn, U32.to_nat(a8)) == + True{} : Bool}} + +t_nb = {W11.nb.val(ww, hh, op, wp, hp, a8, e_w, e_h, h_n) : {U32.to_nat(Png.enc.nbytes(op, ww, hh)) == nn : Nat}} + rt2.at(U32.cmp(Png.enc.nbytes(op, ww, hh), 65535), ww, hh, px, a8, wp, hp, h_ok, e_good, hao, e_w, e_h, e_l2, t_nb, + e_t, h5, h_n, {==}) + +# IMG-PNG-2: one stored block when the scanlines fit, the stored blocks of 65535 bytes otherwise +def Laws.png_roundtrip(ww, hh, px, a8, h_ok, h_a8): + +aa = Nat.mul(U32.to_nat(hh), U32.to_nat(ww)) + +ll = List.length(&2, U32, px) + +nw = Bool.not(Nat.is_eq(U32.to_nat(ww), 0n)) + +nh = Bool.not(Nat.is_eq(U32.to_nat(hh), 0n)) + +ok = {h_ok : {Laws.png_ok(ww, hh, px) == True{} : Bool}} + +e_sides = {U32L.and_left(Bool.and(nw, nh), Bool.and(Laws.below(32n, aa), Nat.is_eq(ll, aa)), ok) : + {Bool.and(nw, nh) == True{} : Bool}} + +e_r = {U32L.and_right(Bool.and(nw, nh), Bool.and(Laws.below(32n, aa), Nat.is_eq(ll, aa)), ok) : + {Bool.and(Laws.below(32n, aa), Nat.is_eq(ll, aa)) == True{} : Bool}} + +e_la = {Wp4.nat_eq_true(ll, aa, U32L.and_right(Laws.below(32n, aa), Nat.is_eq(ll, aa), e_r)) : {ll == aa : Nat}} + +z_w = not.true(Nat.is_eq(U32.to_nat(ww), 0n), U32L.and_left(nw, nh, e_sides)) + +z_h = not.true(Nat.is_eq(U32.to_nat(hh), 0n), U32L.and_right(nw, nh, e_sides)) + +e_good = rt.good.at(Png.enc.good(ww, hh, px), ww, hh, px, Laws.png_encodes(ww, hh, px, ok)) + rt2.pos(ww, hh, px, a8, ok, e_good, e_la, h_a8, Wp4.nat_pos(U32.to_nat(ww), z_w), Wp4.nat_pos(U32.to_nat(hh), z_h)) diff --git a/SPEC.md b/SPEC.md index 599fb41..59ba37b 100644 --- a/SPEC.md +++ b/SPEC.md @@ -42,7 +42,7 @@ What a sample means, for every decoder and encoder. | ID | Requirement | Level | Status | Law | | :---- | :---- | :---- | :---- | :---- | -| IMG-PIX-1 | Every sample `decode_png` and `decode_jpeg` return is packed `0xAARRGGBB`. Every JPEG sample has alpha 255, and a gray JPEG sample carries its Y value in R, G and B. | Proved | pending | LAWS.bend jpeg_rgb_opaque; LAWS.bend jpeg_gray_opaque; LAWS.bend jpeg_decode_packed; LAWS.bend jpeg_decode_opaque; LAWS.bend jpeg_gray_level | +| IMG-PIX-1 | Every sample `decode_png` and `decode_jpeg` return is packed `0xAARRGGBB`. Every JPEG sample has alpha 255, and a gray JPEG sample carries its Y value in R, G and B. | Proved | proved | LAWS.bend jpeg_rgb_opaque; LAWS.bend jpeg_gray_opaque; LAWS.bend jpeg_decode_packed; LAWS.bend jpeg_decode_opaque; LAWS.bend jpeg_gray_level; LAWS.bend png_walk_anc | | IMG-PIX-2 | `encode_jpeg` reads only the low 24 bits of each sample: two rasters that differ only in alpha encode to the same bytes. | Proved | proved | LAWS.bend jpeg_alpha_blind | ### PNG (IMG-PNG) @@ -52,14 +52,14 @@ What a sample means, for every decoder and encoder. | ID | Requirement | Level | Status | Law | | :---- | :---- | :---- | :---- | :---- | | IMG-PNG-1 | `parse_signature(xs)` is `Some(png_sig())` exactly when `xs` begins with the eight bytes 137 80 78 71 13 10 26 10, and none otherwise. | Proved | proved | LAWS.bend sig_opens; LAWS.bend sig_only | -| IMG-PNG-2 | For every well-formed raster `r` with both sides nonzero, `decode_png(encode_png(r))` is `Some(r)`. | Proved | pending | LAWS.bend png_roundtrip_one | +| IMG-PNG-2 | For every well-formed raster `r` with both sides nonzero and fewer than 2^29 samples, `decode_png(encode_png(r))` is `Some(r)`. | Proved | proved | LAWS.bend png_roundtrip_one; LAWS.bend png_roundtrip | | IMG-PNG-3 | For every raster `r` of fewer than 2^32 samples, `encode_png(r)` is none exactly when a side of `r` is 0, `r` is not well formed, or `w * h` is 2^32 or more. | Proved | proved | LAWS.bend png_encodes; LAWS.bend png_refuses | | IMG-PNG-4 | When `encode_png(r)` is some, its IHDR has bit depth 8 and interlace 0, and colour type 2 exactly when every sample of `r` has alpha 255, colour type 6 otherwise. | Proved | proved | LAWS.bend png_ihdr | | IMG-PNG-5 | `Crc.crc32(xs)` equals the bitwise ISO 3309 CRC-32 of `xs` for every byte list, and `decode_png` returns none for every input in which some chunk's stored CRC differs from the CRC-32 of its type and data. | Proved | proved | LAWS.bend crc32_bitwise; LAWS.bend png_crc_refused | | IMG-PNG-6 | For every filter type 0 to 4 and every scanlines of a given width and bytes per pixel, `Png.unfilter` applied to the rows filtered by the PNG specification's filter function returns `Some` of the rows. | Proved | proved | LAWS.bend unfilter_filter | | IMG-PNG-7 | For every byte list `xs` shorter than 2^32 bytes and every block size from 1 to 65535, `Inf.inflate` of the zlib stream of `xs` in stored blocks of that size is `Some(xs)`. | Proved | proved | LAWS.bend inflate_stored; LAWS.bend inflate_enc_zlib | | IMG-PNG-8 | `decode_png` returns none for every input whose IHDR has a bit depth other than 8, an interlace method other than 0, or a colour type outside 0, 2, 3, 4 and 6. | Proved | proved | LAWS.bend png_depth_refused; LAWS.bend png_interlace_refused; LAWS.bend png_colour_refused | -| IMG-PNG-9 | For each colour type, each decoded sample is the packing of the unfiltered bytes the PNG specification gives: gray `g` as `0xFFgggggg`, gray and alpha as `0xAAgggggg`, RGB as `0xFFrrggbb`, RGBA as `0xAArrggbb`, an index as its palette entry with alpha from tRNS or 255, and a colour matching a tRNS key with alpha 0. | Proved | pending | LAWS.bend png_px_grey; LAWS.bend png_px_grey_key; LAWS.bend png_px_ga; LAWS.bend png_px_rgb; LAWS.bend png_px_rgb_key; LAWS.bend png_px_rgba; LAWS.bend png_px_indexed; LAWS.bend png_samples_frame; LAWS.bend png_walk | +| IMG-PNG-9 | For each colour type, each decoded sample is the packing of the unfiltered bytes the PNG specification gives: gray `g` as `0xFFgggggg`, gray and alpha as `0xAAgggggg`, RGB as `0xFFrrggbb`, RGBA as `0xAArrggbb`, an index as its palette entry with alpha from tRNS or 255, and a colour matching a tRNS key with alpha 0. | Proved | proved | LAWS.bend png_px_grey; LAWS.bend png_px_grey_key; LAWS.bend png_px_ga; LAWS.bend png_px_rgb; LAWS.bend png_px_rgb_key; LAWS.bend png_px_rgba; LAWS.bend png_px_indexed; LAWS.bend png_samples_frame; LAWS.bend png_walk; LAWS.bend png_walk_anc | | IMG-PNG-10 | `decode_png` reads the fixed and dynamic Huffman DEFLATE streams other encoders (zlib, libpng) write. | Trusted | | | ### JPEG (IMG-JPG) @@ -83,13 +83,10 @@ What a sample means, for every decoder and encoder. | :---- | :---- | :---- | | IMG-JPG-2 | Refusal: a SOF0 segment with a factor outside 1, 2 and 4 makes `decode_jpeg` none, for one component or three, whatever precedes and follows it (`jpeg_refuse_factor1`, `jpeg_refuse_factor3`), and also after fill bytes before its marker and with a length field longer than its components (`jpeg_refuse_factor1_any`, `jpeg_refuse_factor3_any`); a SOF0 segment of any other component count is none whatever its factors (`jpeg_refuse_count`). Placement: a scan component takes the factors of the frame component whose identifier it names, the first with that identifier (`jpeg_comp_index`); the MCU walk goes from data unit `bi` to `bi + 1`, then to the next scan component, then to the next MCU (`jpeg_walk_unit`, `jpeg_walk_comp`, `jpeg_walk_mcu`); from the scan's first block the decoder's own walk visits the frame's MCUs in raster order, `ceil(w / 8 hmax)` to a row, and in each MCU the scan's components and their `hi * vi` units in T.81 order, the unit, component and column counters never wrapping (`jpeg_walk_frame`), and the U32 block count the decoder runs, `decode.nblocks`, is that order's length over `ceil(h / 8 vmax)` MCU rows when the scan carries the frame's data units and the count fits a U32 (`jpeg_walk_count`); the `hi * vi` units of any scan component sit in T.81 A.2.3's grid, `hi` to a row, each sample covering `hmax / hi` by `vmax / vi` pixels (`jpeg_mcu_grid`, `jpeg_mcu_grid_comp`); painting a block writes sample `k` over exactly the `pw` by `ph` pixels at `(ox + (k mod 8) * pw, oy + (k div 8) * ph)` inside the frame, for every sample size, 4 by 4 included, and onto every plane, one earlier blocks painted included (`jpeg_block_cover`, `jpeg_block_cover_all`); the decoder reads a plane out point by point, sample `k` being the value `Array.get` finds at index `k` (`jpeg_points_at`). Colour: sample `k` of the colour pass is `Jpeg.rgb` of point `k`'s Y, Cb and Cr (`jpeg_rgbs_at`) | that `Array.get` at an index finds the value the last `Array.set` at that index wrote, and a set at another index leaves it (the planes are perfect binary trees of `2^d` leaves, and the lemmas must follow the masked index down the tree), which joins the painting laws to `jpeg_points_at`. The row is worded for frames of at most 2^31 points: above that `decode.plane`'s depth, taken from `U32.shl(nn)`, wraps and points alias | | IMG-JPG-3 | Alpha 255 holds for every sample `decode_jpeg` returns (`jpeg_decode_opaque`, IMG-PIX-1), and `encode_jpeg`'s bytes have the layout IMG-JPG-5 proves. The encoder's entropy-coded bytes have every 255 followed by a 0, for every size and samples (`jpeg_enc_stuffed`), and the decoder's bit reader, reading eight bits at a time from the encoder's stuffing of any bytes, reads the bytes back with the stuffed zeros dropped (`jpeg_unstuff`); the decoder's marker walk over the encoder's header reaches the entropy-coded data with the frame carrying the encoder's width and height, its scan and its tables, a baseline frame read and nothing refused (`jpeg_enc_header_walk`); inside the data the walk keeps every byte of stuffed data and stops at EOI (`jpeg_ent_walk`); so for every well-formed raster with both sides from 1 to 65535, `decode_jpeg(encode_jpeg(r))` is the decoder's scan decode, `decode.run`, of the encoder's own entropy-coded bytes in the frame of `r`'s width and height (`jpeg_round_trip_scan`); that scan decode is none or a picture of its frame's width and height, whatever the bytes (`jpeg_run_sized`); so `decode_jpeg(encode_jpeg(r))` is none or a raster of `r`'s size (`jpeg_round_trip_sized`) | that `decode.run` on the encoder's entropy-coded bytes is not none: that every Huffman lookup finds its symbol and every block ends by 64 coefficients, which is the bit writer (`encode.bits`, `encode.pack`, the pad with 1 bits: that the bytes it writes carry the codes' bits in order) against the bit reader reading codes of 1 to 16 bits across byte boundaries (the byte-aligned case is `jpeg_unstuff`), the Annex K tables `encode.huff` builds against the ones `decode.canon` builds and `decode.look` searches, and the encoder's three paths (neutral, solid, `encode.go`) each writing `ceil(w / 8) * ceil(h / 8)` MCUs of three blocks, each a DC code and magnitude, AC run and size codes and magnitudes, and EOB | -| IMG-PIX-1 | The JPEG side. `Jpeg.rgb` and `Jpeg.gray` give alpha 255 for every input (`jpeg_rgb_opaque`, `jpeg_gray_opaque`); every sample `decode_jpeg` returns is packed by `Jpeg.gray`, or every one by `Jpeg.rgb` (`jpeg_decode_packed`); every sample it returns has alpha 255 (`jpeg_decode_opaque`); a gray sample carries its level's low byte in R, G and B (`jpeg_gray_level`) | that every sample `decode_png` returns is `0xAARRGGBB`: `png_walk` (IMG-PNG-9) reaches `decode_png` for files in the standard chunk order, not yet for files with ancillary chunks. `jpeg_decode_packed` does not say that the gray packing is the one chosen for a one-component frame | -| IMG-PNG-2 | the one-block encoding: every raster `png_ok` accepts (both sides nonzero, `w * h` samples, `w * h` below 2^32) whose scanlines, `h * (1 + w * c)` bytes for c channels (3 when every sample is opaque, 4 otherwise), are at most 65535 decodes from its PNG to itself (`png_roundtrip_one`), through `png_walk`, `inflate_enc_zlib`, `unfilter_filter` with filter None, and `png_px_rgb` / `png_px_rgba` | the two wide paths `encode_png` takes past 65535 scanline bytes: `enc.seal.wide` (colour type 6, `enc.pour`) and `enc.wide.rgb` (colour type 2, `enc.rgb.go`) must be shown to write `zlib.stored(65535, raw)` with the IDAT CRC. And the row is false as worded, even with the approved bound of fewer than 2^32 samples: the scanline count `enc.nbytes` and the IDAT length are U32s, so a raster of 2^32 scanline bytes or more encodes to a file that does not decode (a decision for the maintainer) | -| IMG-PNG-9 | `Png.px.of`, the pixel stage, packs unfiltered bytes as the row says for every colour type: gray, gray with a tRNS key, gray and alpha, RGB, RGB with a tRNS key, RGBA (`png_px_grey`, `png_px_grey_key`, `png_px_ga`, `png_px_rgb`, `png_px_rgb_key`, `png_px_rgba`), and each index it decodes as its palette entry with alpha from tRNS or 255 (`png_px_indexed`); the decoder's last stage is `px.of` of `Png.unfilter`'s output with the width and height kept (`png_samples_frame`); and the walker lift, `png_walk`: a file of the signature, IHDR (any nonzero width and height, bit depth 8, a colour type the row names, methods 0), PLTE and tRNS where section 11 allows them, any IDAT chunks and IEND, each chunk framed with its CRC-32 and shorter than 2^32 bytes, decodes to the raster `px.of` packs, for the IHDR colour type and the PLTE and tRNS data, from `Png.unfilter` of the concatenated IDAT data inflated | files whose chunks come in another order the decoder accepts: ancillary chunks (which the walker skips, closing the IDAT run) between the critical ones | -Every Proved row but IMG-JPG-1, IMG-JPG-4, IMG-JPG-5, IMG-PIX-2, IMG-RAS-1, IMG-RAS-2, IMG-RAS-3, IMG-RAS-4, IMG-RAS-5, IMG-PNG-1, IMG-PNG-3, IMG-PNG-4, IMG-PNG-5, IMG-PNG-6, IMG-PNG-7 and IMG-PNG-8 is pending; IMG-PIX-1, IMG-PNG-2, IMG-PNG-9, IMG-JPG-2 and IMG-JPG-3 have the partial laws above. The rollout in [docs/rfc/ezimg-spec.md](docs/rfc/ezimg-spec.md) orders them: the behavior changes first (IMG-PIX-1 needed BC-1, which has landed; IMG-JPG-2 needed BC-2 and IMG-JPG-4 needed BC-3, which have landed), then refusals and frames (IMG-PNG-3, IMG-PNG-8, IMG-JPG-1, IMG-RAS-1, IMG-RAS-2), then content (IMG-PNG-5, IMG-PNG-7, IMG-PNG-6, IMG-PNG-9, IMG-PNG-4, IMG-RAS-3, IMG-RAS-4, and the headline IMG-PNG-2), and the JPEG content rows last (IMG-PIX-1, IMG-JPG-5, IMG-JPG-2, IMG-JPG-6, IMG-JPG-3). +Every Proved row but IMG-JPG-1, IMG-JPG-4, IMG-JPG-5, IMG-PIX-1, IMG-PIX-2, IMG-RAS-1, IMG-RAS-2, IMG-RAS-3, IMG-RAS-4, IMG-RAS-5, IMG-PNG-1, IMG-PNG-2, IMG-PNG-3, IMG-PNG-4, IMG-PNG-5, IMG-PNG-6, IMG-PNG-7, IMG-PNG-8 and IMG-PNG-9 is pending; IMG-JPG-2 and IMG-JPG-3 have the partial laws above. The rollout in [docs/rfc/ezimg-spec.md](docs/rfc/ezimg-spec.md) orders them: the behavior changes first (IMG-PIX-1 needed BC-1, which has landed; IMG-JPG-2 needed BC-2 and IMG-JPG-4 needed BC-3, which have landed), then refusals and frames (IMG-PNG-3, IMG-PNG-8, IMG-JPG-1, IMG-RAS-1, IMG-RAS-2), then content (IMG-PNG-5, IMG-PNG-7, IMG-PNG-6, IMG-PNG-9, IMG-PNG-4, IMG-RAS-3, IMG-RAS-4, and the headline IMG-PNG-2), and the JPEG content rows last (IMG-PIX-1, IMG-JPG-5, IMG-JPG-2, IMG-JPG-6, IMG-JPG-3). -IMG-PNG-2 is false as worded for rasters of 2^32 scanline bytes or more, which fewer than 2^32 samples do not rule out (above); no other row is known to be false. IMG-JPG-2 covers every sampling layout the frame parser accepts, which BC-2 made decode correctly (REVIEW-13). +No row is known to be false. IMG-JPG-2 covers every sampling layout the frame parser accepts, which BC-2 made decode correctly (REVIEW-13). ## Trust boundary diff --git a/proof/wp11-png-finish.bend b/proof/wp11-png-finish.bend index 0cc49d5..2003c08 100644 --- a/proof/wp11-png-finish.bend +++ b/proof/wp11-png-finish.bend @@ -56,8 +56,11 @@ def pos.at( Equal.cong(Nat, Bool, xx => Nat.is_le(1n+kk, xx), U32.to_nat(uu), 0n, e0)), hh))) # a U32 at least a successor is not zero -def pos(+uu: U32, +kk: Nat, hh: {Nat.is_le(1n+kk, U32.to_nat(uu)) == True{} : Bool}) -> {U32.is_zero(uu) == False{} : - Bool}: +def pos( + +uu: U32, + +kk: Nat, + hh: {Nat.is_le(1n+kk, U32.to_nat(uu)) == True{} : Bool} +) -> {U32.is_zero(uu) == False{} : Bool}: pos.at(U32.is_zero(uu), uu, kk, {==}, hh) # a U32 neither 0 nor 1 less one is not zero, once is_zero's answer is named @@ -134,8 +137,7 @@ def crcl( xs: List<&2, U32>, +cc: U32, +acc: List<&2, U32> -) -> {Png.enc.crc.list(xs, cc, acc) == (Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) : U32 & List<&2, - U32>}: +) -> {Png.enc.crc.list(xs, cc, acc) == (Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) : U32 & List<&2, U32>}: match xs: case Nil{}: {==} @@ -281,8 +283,12 @@ def capm(zz: Bool, +left: U32, +mx: U32) -> U32: mx # enc.cap.at is capm at 65535 -def cap.m(zz: Bool, +left: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> {Png.enc.cap.at(zz, left) == capm(zz, left, mx) : - U32}: +def cap.m( + zz: Bool, + +left: U32, + +mx: U32, + +emx: {mx == 65535 : U32} +) -> {Png.enc.cap.at(zz, left) == capm(zz, left, mx) : U32}: match zz: case True{}: {==} @@ -379,10 +385,10 @@ def hdr( zz: Bool, +left: U32, +rest: List<&2, U32> -) -> {Png.enc.bf.at(zz) <> Png.enc.byte(Png.enc.cap.at(zz, left)) <> Png.enc.hi(Png.enc.cap.at(zz, left)) <> - Png.enc.byte((Png.enc.cap.at(zz, left) .^. 65535 : U32)) <> Png.enc.hi((Png.enc.cap.at(zz, left) .^. 65535 : U32)) - <> rest == List.append(&2, U32, Png.enc.head(zz, Png.enc.cap.at(zz, left), (Png.enc.cap.at(zz, left) .^. 65535 : - U32)), rest) : List<&2, U32>}: +) -> {Png.enc.bf.at(zz) <> Png.enc.byte(Png.enc.cap.at(zz, left)) <> Png.enc.hi(Png.enc.cap.at(zz, + left)) <> Png.enc.byte((Png.enc.cap.at(zz, left) .^. 65535 : U32)) <> Png.enc.hi((Png.enc.cap.at(zz, + left) .^. 65535 : U32)) <> rest == List.append(&2, U32, Png.enc.head(zz, Png.enc.cap.at(zz, left), + (Png.enc.cap.at(zz, left) .^. 65535 : U32)), rest) : List<&2, U32>}: match zz: case True{}: {==} @@ -459,57 +465,73 @@ def edge.no( # a new block's bytes as bs writes them for length u and BFINAL v: the # header, the first byte, then the rest of the walk def open.bs( - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +l2: U32, +uu: U32, +vv: U32 ) -> List<&2, U32>: +nlen = (uu .^. 65535 : U32) +room2 = (uu - 1 : U32) - vv <> Png.enc.byte(uu) <> Png.enc.hi(uu) <> Png.enc.byte(nlen) <> Png.enc.hi(nlen) <> h <> bs(t, U32.is_zero(room2), + vv <> Png.enc.byte(uu) <> Png.enc.hi(uu) <> Png.enc.byte(nlen) <> Png.enc.hi(nlen) <> hd <> bs(tl, U32.is_zero(room2), U32.is_eq(room2, 1), room2, l2, Png.enc.cap(l2), Png.enc.bf(l2)) -# a new block from left bytes, h then t: bs's bytes are enc.feed's from a -# block holding h alone +# a new block's header for left bytes, as enc.feed opens it +def hd1(+left: U32) -> List<&2, U32>: + Png.enc.head(U32.is_le(left, 65535), Png.enc.cap(left), (Png.enc.cap(left) .^. 65535 : U32)) + +# bs after a new block's first byte, for left bytes +def bs1(+tl: List<&2, U32>, +left: U32) -> List<&2, U32>: + +room = (Png.enc.cap(left) - 1 : U32) + bs(tl, U32.is_zero(room), U32.is_eq(room, 1), room, (left - 1 : U32), Png.enc.cap((left - 1 : U32)), + Png.enc.bf((left - 1 : U32))) + +# enc.feed after a new block's first byte hd +def fd1(+tl: List<&2, U32>, +mx: U32, +hd: U32) -> List<&2, U32>: + Png.enc.feed(tl, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [hd]) + +# a new block from left bytes, hd then tl: bs's bytes are enc.feed's from a +# block holding hd alone def open.feed( - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +left: U32, +mx: U32, - +ih: {List.append(&2, U32, Png.enc.head(U32.is_le(left, 65535), Png.enc.cap(left), (Png.enc.cap(left) .^. 65535 : - U32)), h <> bs(t, U32.is_zero((Png.enc.cap(left) - 1 : U32)), U32.is_eq((Png.enc.cap(left) - 1 : U32), 1), - (Png.enc.cap(left) - 1 : U32), (left - 1 : U32), Png.enc.cap((left - 1 : U32)), Png.enc.bf((left - 1 : U32)))) == - Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>} -) -> {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(t, U32.is_zero((mx - 1 : - U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}: + +ih: {List.append(&2, U32, hd1(left), hd <> bs1(tl, left)) == fd1(tl, mx, hd) : List<&2, U32>} +) -> {open.bs(hd, tl, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(tl, + U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [hd]) : List<&2, U32>}: +zz = U32.is_le(left, 65535) +cp = Png.enc.cap(left) +l2 = (left - 1 : U32) - +q = bs(t, U32.is_zero((cp - 1 : U32)), U32.is_eq((cp - 1 : U32), 1), (cp - 1 : U32), l2, Png.enc.cap(l2), + +q = bs(tl, U32.is_zero((cp - 1 : U32)), U32.is_eq((cp - 1 : U32), 1), (cp - 1 : U32), l2, Png.enc.cap(l2), Png.enc.bf(l2)) - Equal.trans(List<&2, U32>, open.bs(h, t, l2, cp, Png.enc.bf(left)), List.append(&2, U32, Png.enc.head(zz, cp, (cp .^. - 65535 : U32)), h <> q), Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]), - hdr(zz, left, h <> q), ih) + Equal.trans(List<&2, U32>, open.bs(hd, tl, l2, cp, Png.enc.bf(left)), List.append(&2, U32, Png.enc.head(zz, cp, + (cp .^. + 65535 : U32)), hd <> q), Png.enc.feed(tl, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [hd]), + hdr(zz, left, hd <> q), ih) + +# the simulation's hypothesis for the rest of a block opened by hd +def open.ih.ty(+hd: U32, +tl: List<&2, U32>, +left: U32, +mx: U32) -> Type: + @zn: Bool -> @zl: Bool -> @zf: Bool -> @fin: Bool -> @rf: U32 -> @rp: U32 -> @plen: U32 -> @pbf: U32 -> + @ll: U32 -> {zn == U32.is_zero(rp) : Bool} -> {zl == U32.is_eq(rp, 1) : Bool} -> {zf == U32.is_zero(rf) : Bool} -> + {Nat.add(1n, U32.to_nat(rf)) == U32.to_nat(mx) : Nat} -> {U32.to_nat(ll) == Nat.add(1n, U32.to_nat(rp)) : Nat} + -> {Nat.is_le(U32.to_nat(rp), U32.to_nat(rf)) == True{} : Bool} -> {U32.to_nat((left - 1 : U32)) == + List.length(&2, U32, tl) : Nat} -> fin.ok(fin, rp, rf, List.length(&2, U32, tl)) -> at.edge(rp, (left - 1 : U32), + plen, pbf) -> sim.ty(tl, zn, zl, zf, fin, [hd], rf, rp, (left - 1 : U32), plen, pbf, ll, mx) -# the facts a new block's walk starts from, for sim: the feed holds h, with +# the facts a new block's walk starts from, for sim: the feed holds hd, with # mx - 1 bytes of room; bs has cap(left) - 1 left in the block def open.ih( - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +left: U32, +mx: U32, +emx: {mx == 65535 : U32}, - +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, t) : Nat}, - sim_t: @zn: Bool -> @zl: Bool -> @zf: Bool -> @fin: Bool -> @rf: U32 -> @rp: U32 -> @plen: U32 -> @pbf: U32 -> - @ll: U32 -> {zn == U32.is_zero(rp) : Bool} -> {zl == U32.is_eq(rp, 1) : Bool} -> {zf == U32.is_zero(rf) : Bool} -> - {Nat.add(1n, U32.to_nat(rf)) == U32.to_nat(mx) : Nat} -> {U32.to_nat(ll) == Nat.add(1n, U32.to_nat(rp)) : Nat} - -> {Nat.is_le(U32.to_nat(rp), U32.to_nat(rf)) == True{} : Bool} -> {U32.to_nat((left - 1 : U32)) == - List.length(&2, U32, t) : Nat} -> fin.ok(fin, rp, rf, List.length(&2, U32, t)) -> at.edge(rp, (left - 1 : U32), - plen, pbf) -> sim.ty(t, zn, zl, zf, fin, [h], rf, rp, (left - 1 : U32), plen, pbf, ll, mx) -) -> {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(t, U32.is_zero((mx - 1 : - U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}: - +nt = List.length(&2, U32, t) + +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, tl) : Nat}, + sim_t: open.ih.ty(hd, tl, left, mx) +) -> {open.bs(hd, tl, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(tl, + U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [hd]) : List<&2, U32>}: + +nt = List.length(&2, U32, tl) +zz = U32.is_le(left, 65535) +cp = Png.enc.cap(left) +cm = capm(zz, left, mx) @@ -529,14 +551,14 @@ def open.ih( e_cm), cap.le(zz, left, mx, nt, nzm, ezm, hn)) : {Nat.is_le(U32.to_nat(c1), U32.to_nat(m1)) == True{} : Bool}} +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} hf2 = {fo.cm(zz, left, mx, nt, emx, cap.fo(zz, left, mx, nt, nzm, ezm, hn)) : fin.ok(zz, c1, m1, nt)} - open.feed(h, t, left, mx, sim_t(U32.is_zero(c1), U32.is_eq(c1, 1), U32.is_zero(m1), zz, m1, c1, Png.enc.cap(l2), + open.feed(hd, tl, left, mx, sim_t(U32.is_zero(c1), U32.is_eq(c1, 1), U32.is_zero(m1), zz, m1, c1, Png.enc.cap(l2), Png.enc.bf(l2), cp, {==}, {==}, {==}, ha2, hl2, hle2, hn2, hf2, _ez => ({==}, {==}))) # a block boundary with bytes left: the full block closes and a new one opens def sim.edge( fin: Bool, - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +acc: List<&2, U32>, +rf: U32, +rp: U32, @@ -550,17 +572,16 @@ def sim.edge( +ha: {Nat.add(List.length(&2, U32, acc), U32.to_nat(rf)) == U32.to_nat(mx) : Nat}, +hl: {U32.to_nat(ll) == Nat.add(List.length(&2, U32, acc), U32.to_nat(rp)) : Nat}, +e0: {U32.to_nat(rp) == 0n : Nat}, - +e_ob: {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(t, U32.is_zero((mx - - 1 : U32)), (mx - 1 : U32), mx, [h]) : List<&2, U32>}, - hf: fin.ok(fin, rp, rf, 1n+List.length(&2, U32, t)), + +e_ob: {open.bs(hd, tl, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == fd1(tl, mx, hd) : List<&2, U32>}, + hf: fin.ok(fin, rp, rf, 1n+List.length(&2, U32, tl)), pe: {plen == Png.enc.cap(left) : U32} & {pbf == Png.enc.bf(left) : U32} -) -> {List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, U32, acc, open.bs(h, t, - (left - 1 : U32), plen, pbf))) == Png.enc.feed(h <> t, zf, rf, mx, acc) : List<&2, U32>}: +) -> {List.append(&2, U32, Png.enc.head(fin, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, U32, acc, open.bs(hd, tl, + (left - 1 : U32), plen, pbf))) == Png.enc.feed(hd <> tl, zf, rf, mx, acc) : List<&2, U32>}: match fin: case True{}: Empty.absurd({List.append(&2, U32, Png.enc.head(True{}, ll, (ll .^. 65535 : U32)), List.reverse.go(&2, U32, acc, - open.bs(h, t, (left - 1 : U32), plen, pbf))) == Png.enc.feed(h <> t, zf, rf, mx, acc) : List<&2, U32>}, - Wp1.zero_succ(List.length(&2, U32, t), Equal.trans(Nat, 0n, U32.to_nat(rp), 1n+List.length(&2, U32, t), + open.bs(hd, tl, (left - 1 : U32), plen, pbf))) == Png.enc.feed(hd <> tl, zf, rf, mx, acc) : List<&2, U32>}, + Wp1.zero_succ(List.length(&2, U32, tl), Equal.trans(Nat, 0n, U32.to_nat(rp), 1n+List.length(&2, U32, tl), Equal.sym(Nat, U32.to_nat(rp), 0n, e0), hf))) case False{}: (e_rr, _h_lt) = hf @@ -572,45 +593,47 @@ def sim.edge( +e_rf0 = {Equal.trans(Nat, U32.to_nat(rf), U32.to_nat(rp), 0n, Equal.sym(Nat, U32.to_nat(rp), U32.to_nat(rf), e_rr), e0) : {U32.to_nat(rf) == 0n : Nat}} +e_zf = {Equal.trans(Bool, zf, U32.is_zero(rf), True{}, hzf, zero.is(rf, e_rf0)) : {zf == True{} : Bool}} - +ff = Png.enc.feed(t, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [h]) + +ff = Png.enc.feed(tl, U32.is_zero((mx - 1 : U32)), (mx - 1 : U32), mx, [hd]) +hd0 = Png.enc.head(False{}, ll, (ll .^. 65535 : U32)) +hl0 = {Equal.trans(Nat, U32.to_nat(ll), Nat.add(na, 0n), na, Equal.trans(Nat, U32.to_nat(ll), Nat.add(na, U32.to_nat(rp)), Nat.add(na, 0n), hl, Equal.cong(Nat, Nat, kk => Nat.add(na, kk), U32.to_nat(rp), 0n, e0)), R.add_zero(na)) : {U32.to_nat(ll) == na : Nat}} +e_len = {len.blk(acc, rf, ll, mx, ha, hl0) : {Png.enc.len(ra, 0) == ll : U32}} - +e_bs = {Equal.trans(List<&2, U32>, open.bs(h, t, l2, plen, pbf), open.bs(h, t, l2, cp, Png.enc.bf(left)), ff, - Equal.trans(List<&2, U32>, open.bs(h, t, l2, plen, pbf), open.bs(h, t, l2, cp, pbf), open.bs(h, t, l2, cp, - Png.enc.bf(left)), Equal.cong(U32, List<&2, U32>, uu => open.bs(h, t, l2, uu, pbf), plen, cp, e_plen), - Equal.cong(U32, List<&2, U32>, uu => open.bs(h, t, l2, cp, uu), pbf, Png.enc.bf(left), e_pbf)), - e_ob) : {open.bs(h, t, l2, plen, pbf) == ff : List<&2, U32>}} - Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(h, t, l2, plen, pbf))), - List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), Png.enc.feed(h <> t, zf, rf, mx, acc), - Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(h, t, l2, plen, + +e_bs = {Equal.trans(List<&2, U32>, open.bs(hd, tl, l2, plen, pbf), open.bs(hd, tl, l2, cp, Png.enc.bf(left)), ff, + Equal.trans(List<&2, U32>, open.bs(hd, tl, l2, plen, pbf), open.bs(hd, tl, l2, cp, pbf), open.bs(hd, tl, l2, cp, + Png.enc.bf(left)), Equal.cong(U32, List<&2, U32>, uu => open.bs(hd, tl, l2, uu, pbf), plen, cp, e_plen), + Equal.cong(U32, List<&2, U32>, uu => open.bs(hd, tl, l2, cp, uu), pbf, Png.enc.bf(left), e_pbf)), + e_ob) : {open.bs(hd, tl, l2, plen, pbf) == ff : List<&2, U32>}} + Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(hd, tl, l2, plen, + pbf))), + List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), Png.enc.feed(hd <> tl, zf, rf, mx, acc), + Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(hd, tl, l2, plen, pbf))), List.append(&2, U32, hd0, List.append(&2, U32, ra, ff)), List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), - Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(h, t, l2, plen, + Equal.trans(List<&2, U32>, List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, open.bs(hd, tl, l2, plen, pbf))), List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, ff)), List.append(&2, U32, hd0, List.append(&2, U32, ra, ff)), Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, hd0, List.reverse.go(&2, U32, acc, - ys)), open.bs(h, t, l2, plen, pbf), ff, e_bs), + ys)), open.bs(hd, tl, l2, plen, pbf), ff, e_bs), Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, hd0, ys), List.reverse.go(&2, U32, acc, ff), List.append(&2, U32, ra, ff), W9.revgo_acc(acc, [], ff))), Equal.sym(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), List.append(&2, U32, hd0, List.append(&2, U32, ra, ff)), Wp2.app_assoc(hd0, ra, ff))), - Equal.trans(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), Png.enc.feed(h <> t, True{}, - rf, mx, acc), Png.enc.feed(h <> t, zf, rf, mx, acc), + Equal.trans(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), Png.enc.feed(hd <> tl, + True{}, + rf, mx, acc), Png.enc.feed(hd <> tl, zf, rf, mx, acc), Equal.trans(List<&2, U32>, List.append(&2, U32, List.append(&2, U32, hd0, ra), ff), List.append(&2, U32, - Png.enc.cat(hd0, ra), ff), Png.enc.feed(h <> t, True{}, rf, mx, acc), + Png.enc.cat(hd0, ra), ff), Png.enc.feed(hd <> tl, True{}, rf, mx, acc), Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, ys, ff), List.append(&2, U32, hd0, ra), Png.enc.cat(hd0, ra), Equal.sym(List<&2, U32>, Png.enc.cat(hd0, ra), List.append(&2, U32, hd0, ra), Wp2.cat_app(hd0, ra))), Equal.trans(List<&2, U32>, List.append(&2, U32, Png.enc.cat(hd0, ra), ff), Png.enc.cat(Png.enc.cat(hd0, - ra), ff), Png.enc.feed(h <> t, True{}, rf, mx, acc), + ra), ff), Png.enc.feed(hd <> tl, True{}, rf, mx, acc), Equal.sym(List<&2, U32>, Png.enc.cat(Png.enc.cat(hd0, ra), ff), List.append(&2, U32, Png.enc.cat(hd0, ra), ff), Wp2.cat_app(Png.enc.cat(hd0, ra), ff)), Equal.cong(U32, List<&2, U32>, uu => Png.enc.cat(Png.enc.cat(Png.enc.head(False{}, uu, (uu .^. 65535 : U32)), ra), ff), ll, Png.enc.len(ra, 0), Equal.sym(U32, Png.enc.len(ra, 0), ll, e_len)))), - Equal.cong(Bool, List<&2, U32>, zb => Png.enc.feed(h <> t, zb, rf, mx, acc), True{}, zf, Equal.sym(Bool, + Equal.cong(Bool, List<&2, U32>, zb => Png.enc.feed(hd <> tl, zb, rf, mx, acc), True{}, zf, Equal.sym(Bool, zf, True{}, e_zf)))) # bs against enc.feed: the open block (acc, newest first, with rf bytes of @@ -712,17 +735,18 @@ def sim( # the first block: bs from the start writes enc.feed's blocks for every # non-empty list of left bytes def sim.start( - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +left: U32, +mx: U32, +emx: {mx == 65535 : U32}, - +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, t) : Nat} -) -> {bs(h <> t, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(h <> t, False{}, mx, - mx, []) : List<&2, U32>}: + +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, tl) : Nat} +) -> {bs(hd <> tl, True{}, False{}, 0, left, Png.enc.cap(left), Png.enc.bf(left)) == Png.enc.feed(hd <> tl, False{}, + mx, mx, []) : List<&2, U32>}: +l2 = (left - 1 : U32) - open.ih(h, t, left, mx, emx, hn, zn => zl => zb => fb => rf3 => rp3 => pl3 => pb3 => ll3 => a1 => a2 => a3 => a4 => - a5 => a6 => a7 => a8 => a9 => sim(t, zn, zl, zb, fb, [h], rf3, rp3, l2, pl3, pb3, ll3, mx, emx, a1, a2, a3, a4, a5, + open.ih(hd, tl, left, mx, emx, hn, zn => zl => zb => fb => rf3 => rp3 => pl3 => pb3 => ll3 => a1 => a2 => a3 => a4 => + a5 => a6 => a7 => a8 => a9 => sim(tl, zn, zl, zb, fb, [hd], rf3, rp3, l2, pl3, pb3, ll3, mx, emx, a1, a2, a3, a4, + a5, a6, a7, a8, a9)) # enc.blocks at 65535 for a list longer than one block is bs from the start @@ -744,7 +768,8 @@ def sim.blocks( Equal.trans(List<&2, U32>, Png.enc.blocks(65535, h <> t), Png.enc.blocks.fit(False{}, 65535, nn, h <> t), bb, Equal.cong(Bool, List<&2, U32>, zb => Png.enc.blocks.fit(zb, 65535, nn, h <> t), U32.is_le(nn, 65535), False{}, hbig), - Equal.trans(List<&2, U32>, Png.enc.feed(h <> t, False{}, 65535, 65535, []), Png.enc.feed(h <> t, False{}, mx, mx, + Equal.trans(List<&2, U32>, Png.enc.feed(h <> t, False{}, 65535, 65535, []), Png.enc.feed(h <> t, False{}, mx, + mx, []), bb, Equal.cong(U32, List<&2, U32>, uu => Png.enc.feed(h <> t, False{}, uu, uu, []), 65535, mx, Equal.sym(U32, mx, 65535, emx)), Equal.sym(List<&2, U32>, bb, Png.enc.feed(h <> t, False{}, mx, mx, []), sim.start(h, t, nn, mx, emx, hn)))) @@ -809,8 +834,11 @@ def sho( sho.step(pp, cc, bb, tt, Word.shl.out(pp, bb, tt), sho(pp, bb, tt, st, h2)) # at least in Cmp is at most the other way -def ge.le(aa: Nat, bb: Nat, +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == True{} : Bool}) -> {Nat.is_le(bb, aa) == True{} : - Bool}: +def ge.le( + aa: Nat, + bb: Nat, + +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == True{} : Bool} +) -> {Nat.is_le(bb, aa) == True{} : Bool}: match aa bb: case 0n 0n: {==} @@ -822,8 +850,11 @@ def ge.le(aa: Nat, bb: Nat, +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == True{} : Bool}) ge.le(ap, bp, hh) # not at least in Cmp is below -def nge.lt(aa: Nat, bb: Nat, +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == False{} : Bool}) -> {Nat.is_lt(aa, bb) == True{} : - Bool}: +def nge.lt( + aa: Nat, + bb: Nat, + +hh: {Cmp.is_ge(Nat.cmp(aa, bb)) == False{} : Bool} +) -> {Nat.is_lt(aa, bb) == True{} : Bool}: match aa bb: case 0n 0n: Empty.absurd({Nat.is_lt(0n, 0n) == True{} : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hh))) @@ -1155,6 +1186,10 @@ def cy(nn: Nat, aw: Word(nn), bw: Word(nn), cc: Bool) -> Bool: case WCon{True{}, at} WCon{True{}, bt} True{}: cy(pp, at, bt, True{}) +# two words' values added +def wsum(+pp: Nat, +at: Word(pp), +bt: Word(pp)) -> Nat: + Nat.add(Word.to_nat(pp, at), Word.to_nat(pp, bt)) + # one bit of cfa: this bit's sum and carry, then the bits above def cfa.arm( +pp: Nat, @@ -1166,8 +1201,7 @@ def cfa.arm( +ss: Bool, +kk: Bool, +e_bits: {Nat.add(R.bit(cc), Nat.add(R.bit(ab), R.bit(bb))) == Nat.add(R.bit(ss), Nat.double(R.bit(kk))) : Nat}, - +er: {Word.to_nat(pp, Word.adc(pp, at, bt, False{}, kk)) == Nat.add(R.bit(kk), Nat.add(Word.to_nat(pp, at), - Word.to_nat(pp, bt))) : Nat} + +er: {Word.to_nat(pp, Word.adc(pp, at, bt, False{}, kk)) == Nat.add(R.bit(kk), wsum(pp, at, bt)) : Nat} ) -> {Word.to_nat(1n+pp, WCon{ss, Word.adc(pp, at, bt, False{}, kk)}) == Nat.add(R.bit(cc), Nat.add(Word.to_nat(1n+pp, WCon{ab, at}), Word.to_nat(1n+pp, WCon{bb, bt}))) : Nat}: +na = Word.to_nat(pp, at) @@ -1237,20 +1271,27 @@ def cy32(uu: U32, vv: U32) -> Bool: cy(32n, xw, yw, False{}) # a U32 add with no carry out is the sum -def add.cf(uu: U32, vv: U32, +hh: {cy32(uu, vv) == False{} : Bool}) -> {U32.to_nat(U32.add(uu, vv)) == - Nat.add(U32.to_nat(uu), U32.to_nat(vv)) : Nat}: +def add.cf( + uu: U32, + vv: U32, + +hh: {cy32(uu, vv) == False{} : Bool} +) -> {U32.to_nat(U32.add(uu, vv)) == Nat.add(U32.to_nat(uu), U32.to_nat(vv)) : Nat}: match uu vv: case U32{+xw} U32{+yw}: cfa(32n, xw, yw, False{}, hh) # the block size doubled is a U32's value -def mx.dbl(+mx: U32, +emx: {mx == 65535 : U32}) -> {U32.to_nat(U32.add(mx, mx)) == Nat.add(U32.to_nat(mx), - U32.to_nat(mx)) : Nat}: +def mx.dbl( + +mx: U32, + +emx: {mx == 65535 : U32} +) -> {U32.to_nat(U32.add(mx, mx)) == Nat.add(U32.to_nat(mx), U32.to_nat(mx)) : Nat}: add.cf(mx, mx, Equal.cong(U32, Bool, uu => cy32(uu, uu), mx, 65535, emx)) # the block size is at least 2 -def mx.two(+mx: U32, +emx: {mx == 65535 : U32}) -> {U32.to_nat(mx) == 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32)) : - Nat}: +def mx.two( + +mx: U32, + +emx: {mx == 65535 : U32} +) -> {U32.to_nat(mx) == 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32)) : Nat}: +m1 = (mx - 1 : U32) +nz1 = {Equal.cong(U32, Bool, uu => U32.is_zero((uu - 1 : U32)), mx, 65535, emx) : {U32.is_zero(m1) == False{} : Bool}} @@ -1266,8 +1307,11 @@ def kok(+xn: Nat, kk: Nat, +mn: Nat) -> Type: {Nat.is_lt(Nat.mul(kp, mn), xn) == True{} : Bool} & {Nat.is_le(xn, Nat.mul(1n+kp, mn)) == True{} : Bool} # x below x + y when y is above 0 -def lt.more(+xx: Nat, +yy: Nat, +hh: {Nat.is_lt(0n, yy) == True{} : Bool}) -> {Nat.is_lt(xx, Nat.add(xx, yy)) == True{} : - Bool}: +def lt.more( + +xx: Nat, + +yy: Nat, + +hh: {Nat.is_lt(0n, yy) == True{} : Bool} +) -> {Nat.is_lt(xx, Nat.add(xx, yy)) == True{} : Bool}: R.lt_rw_l(Nat.add(xx, 0n), xx, Nat.add(xx, yy), R.add_zero(xx), R.lt_add_mono(xx, 0n, yy, hh)) # q blocks exactly: ceil(q m / m) is q @@ -1305,8 +1349,11 @@ def nb.rem( rn), Nat.add(qm, mn), Nat.mul(1n+qn, mn), R.add_comm(qm, mn), R.le_add_mono(qm, rn, mn, R.lt_le(rn, mn, hr))))) # x at most x times m for m above 0 -def le.mul(+xx: Nat, +mn: Nat, +hm: {Nat.is_lt(0n, mn) == True{} : Bool}) -> {Nat.is_le(xx, Nat.mul(xx, mn)) == True{} : - Bool}: +def le.mul( + +xx: Nat, + +mn: Nat, + +hm: {Nat.is_lt(0n, mn) == True{} : Bool} +) -> {Nat.is_le(xx, Nat.mul(xx, mn)) == True{} : Bool}: +h1 = {Equal.trans(Bool, Nat.is_le(1n, mn), Nat.is_lt(0n, mn), True{}, Equal.sym(Bool, Nat.is_lt(0n, mn), Nat.is_le(1n, mn), R.lt_le_succ(0n, mn)), hm) : {Nat.is_le(1n, mn) == True{} : Bool}} R.le_rw_l(Nat.mul(1n, xx), xx, Nat.mul(xx, mn), R.add_zero(xx), R.le_rw_r(Nat.mul(1n, xx), Nat.mul(mn, xx), @@ -1321,14 +1368,17 @@ def nblk.eq(+nn: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> {Png.enc.nblk(nn) Equal.cong(U32, U32, uu => Png.enc.nblk.at(U32.is_zero(U32.mod(nn, uu)), U32.div(nn, uu)), 65535, mx, Equal.sym(U32, mx, 65535, emx)) +# n's quotient by m times m, plus the remainder +def dq(+nn: U32, +mx: U32) -> Nat: + Nat.add(Nat.mul(U32.to_nat(U32.div(nn, mx)), U32.to_nat(mx)), U32.to_nat(U32.mod(nn, mx))) + # nblk.m, once whether the remainder is zero is named def nb.at( zz: Bool, +nn: U32, +mx: U32, +ez: {U32.is_zero(U32.mod(nn, mx)) == zz : Bool}, - +e_n: {U32.to_nat(nn) == Nat.add(Nat.mul(U32.to_nat(U32.div(nn, mx)), U32.to_nat(mx)), U32.to_nat(U32.mod(nn, - mx))) : Nat}, + +e_n: {U32.to_nat(nn) == dq(nn, mx) : Nat}, +l_r: {Nat.is_lt(U32.to_nat(U32.mod(nn, mx)), U32.to_nat(mx)) == True{} : Bool}, +hm: {Nat.is_lt(0n, U32.to_nat(mx)) == True{} : Bool} ) -> kok(U32.to_nat(nn), U32.to_nat(Png.enc.nblk.at(zz, U32.div(nn, mx))), U32.to_nat(mx)): @@ -1375,8 +1425,11 @@ def nb.go( nb.at(U32.is_zero(U32.mod(nn, mx)), nn, mx, {==}, e_n, l_r, hm) # enc.nblk(n) blocks of 65535 bytes hold n bytes, the last one not empty -def nb.k(+nn: U32, +mx: U32, +emx: {mx == 65535 : U32}) -> kok(U32.to_nat(nn), U32.to_nat(Png.enc.nblk(nn)), - U32.to_nat(mx)): +def nb.k( + +nn: U32, + +mx: U32, + +emx: {mx == 65535 : U32} +) -> kok(U32.to_nat(nn), U32.to_nat(Png.enc.nblk(nn)), U32.to_nat(mx)): +mn = U32.to_nat(mx) +hm = {Equal.trans(Bool, Nat.is_lt(0n, mn), Nat.is_lt(0n, 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32))), True{}, Equal.cong(Nat, Bool, kk => Nat.is_lt(0n, kk), mn, 2n+U32.to_nat(((mx - 1 : U32) - 1 : U32)), mx.two(mx, emx)), @@ -1518,23 +1571,27 @@ def cnt.ty( {List.length(&2, U32, bs(xs, znew, zlast, rp, left, plen, pbf)) == Nat.add(List.length(&2, U32, xs), Nat.mul(kk, 5n)) : Nat} +# bs after a block's first byte, with plen bytes in the block and l2 left after it +def bs2(+tl: List<&2, U32>, +plen: U32, +l2: U32) -> List<&2, U32>: + bs(tl, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), l2, Png.enc.cap(l2), + Png.enc.bf(l2)) + # the header, the first byte and the rest of a new block: six more bytes def cnt.open( - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +l2: U32, +plen: U32, +pbf: U32, +kp: Nat, - +ih: {List.length(&2, U32, bs(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), - l2, Png.enc.cap(l2), Png.enc.bf(l2))) == Nat.add(List.length(&2, U32, t), Nat.mul(kp, 5n)) : Nat} -) -> {List.length(&2, U32, open.bs(h, t, l2, plen, pbf)) == Nat.add(1n+List.length(&2, U32, t), Nat.mul(1n+kp, 5n)) : - Nat}: - +nt = List.length(&2, U32, t) + +ih: {List.length(&2, U32, bs2(tl, plen, l2)) == Nat.add(List.length(&2, U32, tl), Nat.mul(kp, 5n)) : Nat} +) -> {List.length(&2, U32, open.bs(hd, tl, l2, plen, pbf)) == Nat.add(1n+List.length(&2, U32, tl), Nat.mul(1n+kp, + 5n)) : Nat}: + +nt = List.length(&2, U32, tl) +k5 = Nat.mul(kp, 5n) - Equal.trans(Nat, 6n+List.length(&2, U32, bs(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), + Equal.trans(Nat, 6n+List.length(&2, U32, bs(tl, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), l2, Png.enc.cap(l2), Png.enc.bf(l2))), 6n+Nat.add(nt, k5), 1n+Nat.add(nt, 5n+k5), - Equal.cong(Nat, Nat, xx => 6n+xx, List.length(&2, U32, bs(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : + Equal.cong(Nat, Nat, xx => 6n+xx, List.length(&2, U32, bs(tl, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), l2, Png.enc.cap(l2), Png.enc.bf(l2))), Nat.add(nt, k5), ih), Equal.cong(Nat, Nat, xx => 1n+xx, 5n+Nat.add(nt, k5), Nat.add(nt, 5n+k5), Equal.sym(Nat, Nat.add(nt, 5n+k5), 5n+Nat.add(nt, k5), R.add_swap(nt, 5n, k5)))) @@ -1544,29 +1601,32 @@ def kok.rw(+xa: Nat, +xb: Nat, +kk: Nat, +mn: Nat, +ee: {xa == xb : Nat}, hk: ko %ee : kok(_, kk, mn) hk +# the count's hypothesis for the rest of a block opened with plen bytes +def cnt.edge.ty(-tl: List<&2, U32>, -left: U32, -plen: U32, -kp: Nat, -mx: U32) -> Type: + @xn: Nat -> {Nat.add(U32.to_nat((plen - 1 : U32)), xn) == List.length(&2, U32, tl) : Nat} -> kok(xn, kp, + U32.to_nat(mx)) -> cnt.ty(tl, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), + (left - 1 : U32), Png.enc.cap((left - 1 : U32)), Png.enc.bf((left - 1 : U32)), kp) + # a new block with kp + 1 blocks to go: the header and the first byte, then # the rest of the walk, with kp blocks after this one def cnt.edge( - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +left: U32, +plen: U32, +pbf: U32, +mx: U32, +emx: {mx == 65535 : U32}, +kp: Nat, - +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, t) : Nat}, - +h_lt: {Nat.is_lt(Nat.mul(kp, U32.to_nat(mx)), 1n+List.length(&2, U32, t)) == True{} : Bool}, - +h_le: {Nat.is_le(1n+List.length(&2, U32, t), Nat.add(U32.to_nat(mx), Nat.mul(kp, U32.to_nat(mx)))) == True{} : - Bool}, + +hn: {U32.to_nat(left) == 1n+List.length(&2, U32, tl) : Nat}, + +h_lt: {Nat.is_lt(Nat.mul(kp, U32.to_nat(mx)), 1n+List.length(&2, U32, tl)) == True{} : Bool}, + +h_le: {Nat.is_le(1n+List.length(&2, U32, tl), Nat.mul(1n+kp, U32.to_nat(mx))) == True{} : Bool}, pe: {plen == Png.enc.cap(left) : U32} & {pbf == Png.enc.bf(left) : U32}, - cnt_t: @xn: Nat -> {Nat.add(U32.to_nat((plen - 1 : U32)), xn) == List.length(&2, U32, t) : Nat} -> kok(xn, kp, - U32.to_nat(mx)) -> cnt.ty(t, U32.is_zero((plen - 1 : U32)), U32.is_eq((plen - 1 : U32), 1), (plen - 1 : U32), - (left - 1 : U32), Png.enc.cap((left - 1 : U32)), Png.enc.bf((left - 1 : U32)), kp) -) -> {List.length(&2, U32, open.bs(h, t, (left - 1 : U32), plen, pbf)) == Nat.add(1n+List.length(&2, U32, t), + cnt_t: cnt.edge.ty(tl, left, plen, kp, mx) +) -> {List.length(&2, U32, open.bs(hd, tl, (left - 1 : U32), plen, pbf)) == Nat.add(1n+List.length(&2, U32, tl), Nat.mul(1n+kp, 5n)) : Nat}: (+e_plen, _e_pbf) = pe - +nt = List.length(&2, U32, t) + +nt = List.length(&2, U32, tl) +zz = U32.is_le(left, 65535) +cm = capm(zz, left, mx) +mn = U32.to_nat(mx) @@ -1582,7 +1642,7 @@ def cnt.edge( hk2 = kok.rw(Nat.sub(nt, U32.to_nat((cm - 1 : U32))), x2, kp, mn, Equal.cong(Nat, Nat, kk => Nat.sub(nt, kk), U32.to_nat((cm - 1 : U32)), c2, Equal.sym(Nat, c2, U32.to_nat((cm - 1 : U32)), e_c)), ks.k(zz, kp, left, mx, nt, nzm, ezm, hn, h_lt, h_le)) - cnt.open(h, t, (left - 1 : U32), plen, pbf, kp, cnt_t(x2, hx2, hk2)) + cnt.open(hd, tl, (left - 1 : U32), plen, pbf, kp, cnt_t(x2, hx2, hk2)) # bs from a state: its bytes, and a header for each of the kk blocks it opens, # xn the bytes after the open block (rp of them still in it) @@ -1640,7 +1700,8 @@ def cnt( case 0n: +nt = List.length(&2, U32, t) +e0 = {zero.val(rp, hzn) : {U32.to_nat(rp) == 0n : Nat}} - +e_xn = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, xn), + +e_xn = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, + xn), 0n, U32.to_nat(rp), Equal.sym(Nat, U32.to_nat(rp), 0n, e0)), hx) : {xn == 1n+nt : Nat}} Empty.absurd(cnt.ty(h <> t, True{}, _zl, rp, left, plen, pbf, 0n), Wp1.zero_succ(nt, Equal.trans(Nat, 0n, xn, 1n+nt, Equal.sym(Nat, xn, 0n, hk), e_xn))) @@ -1650,7 +1711,8 @@ def cnt( +l2 = (left - 1 : U32) +mn = U32.to_nat(mx) +e0 = {zero.val(rp, hzn) : {U32.to_nat(rp) == 0n : Nat}} - +e_xn = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, xn), + +e_xn = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(rp), xn), 1n+nt, Equal.cong(Nat, Nat, kk2 => Nat.add(kk2, + xn), 0n, U32.to_nat(rp), Equal.sym(Nat, U32.to_nat(rp), 0n, e0)), hx) : {xn == 1n+nt : Nat}} +ez = {Equal.sym(Bool, True{}, U32.is_zero(rp), hzn) : {U32.is_zero(rp) == True{} : Bool}} +hn2 = {Wp1.u32_pred(left, nt, hn) : {U32.to_nat(l2) == nt : Nat}} @@ -1674,7 +1736,8 @@ def cnt.blocks( +bb = bs(xs, True{}, False{}, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn)) Equal.trans(Nat, List.length(&2, U32, Png.enc.blocks(65535, xs)), List.length(&2, U32, bb), Nat.add(List.length(&2, U32, xs), Nat.mul(kk, 5n)), Equal.cong(List<&2, U32>, Nat, ys => List.length(&2, U32, ys), Png.enc.blocks(65535, - xs), bb, sim.blocks(xs, mx, emx, hn, hbig)), cnt(xs, True{}, False{}, kk, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn), mx, + xs), bb, sim.blocks(xs, mx, emx, hn, hbig)), cnt(xs, True{}, False{}, kk, 0, nn, Png.enc.cap(nn), Png.enc.bf(nn), + mx, List.length(&2, U32, xs), emx, {==}, {==}, hn, {==}, kok.rw(U32.to_nat(nn), List.length(&2, U32, xs), kk, U32.to_nat(mx), hn, nb.k(nn, mx, emx)), _ez => ({==}, {==}))) @@ -1702,8 +1765,8 @@ def fr.app( +ys: List<&2, U32>, +cc: U32, +acc: List<&2, U32> -) -> {fr(ys, Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) == fr(List.append(&2, U32, xs, ys), cc, acc) : - U32 & List<&2, U32>}: +) -> {fr(ys, Crc.crc.fold(xs, cc), List.reverse.go(&2, U32, xs, acc)) == fr(List.append(&2, U32, xs, ys), cc, + acc) : U32 & List<&2, U32>}: +f2 = Crc.crc.fold(ys, Crc.crc.fold(xs, cc)) +fa = Crc.crc.fold(List.append(&2, U32, xs, ys), cc) +r2 = List.reverse.go(&2, U32, ys, List.reverse.go(&2, U32, xs, acc)) @@ -1744,10 +1807,10 @@ def tail.eq( +ll: U32, +tt: List<&2, U32>, +ie: List<&2, U32> -) -> {List.reverse(&2, U32, Png.enc.cat.go(ie, Png.enc.cat.go(Png.enc.be((Crc.crc.fold(tt, 4294967295) .^. - 4294967295 : U32)), List.reverse.go(&2, U32, tt, Png.enc.cat.go(Png.enc.be(ll), []))))) == List.append(&2, U32, - Png.enc.be(ll), List.append(&2, U32, tt, List.append(&2, U32, Png.enc.be((Crc.crc.fold(tt, 4294967295) .^. - 4294967295 : U32)), ie))) : List<&2, U32>}: +) -> {List.reverse(&2, U32, Png.enc.cat.go(ie, Png.enc.cat.go(Png.enc.be((Crc.crc.fold(tt, + 4294967295) .^. 4294967295 : U32)), List.reverse.go(&2, U32, tt, Png.enc.cat.go(Png.enc.be(ll), []))))) == + List.append(&2, U32, Png.enc.be(ll), List.append(&2, U32, tt, List.append(&2, U32, Png.enc.be((Crc.crc.fold(tt, + 4294967295) .^. 4294967295 : U32)), ie))) : List<&2, U32>}: +bl = Png.enc.be(ll) +ee = Png.enc.be((Crc.crc.fold(tt, 4294967295) .^. 4294967295 : U32)) +a0 = List.reverse.go(&2, U32, bl, []) @@ -1792,8 +1855,8 @@ def t0(+bb: List<&2, U32>) -> List<&2, U32>: def body.eq( +bb: List<&2, U32>, +sum: U32 -) -> {Png.enc.cat(Png.enc.be(Png.tag.idat()), zb(bb, sum)) == List.append(&2, U32, t0(bb), Png.enc.be(sum)) : - List<&2, U32>}: +) -> {Png.enc.cat(Png.enc.be(Png.tag.idat()), zb(bb, sum)) == List.append(&2, U32, t0(bb), Png.enc.be(sum)) : List<&2, + U32>}: +bi = Png.enc.be(Png.tag.idat()) +bs2 = Png.enc.be(sum) +zz = List.append(&2, U32, [120, 1], List.append(&2, U32, bb, bs2)) @@ -1965,7 +2028,8 @@ def zlib.len( +xx = Nat.add(List.length(&2, U32, raw), Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(raw, 0))), 5n)) +ap = List.append(&2, U32, [120, 1], List.append(&2, U32, bl, be_s)) Equal.trans(Nat, List.length(&2, U32, Laws.zlib.stored(65535, raw)), List.length(&2, U32, ap), Nat.add(xx, 6n), - Equal.cong(List<&2, U32>, Nat, ys => List.length(&2, U32, ys), Laws.zlib.stored(65535, raw), ap, Equal.trans(List<&2, + Equal.cong(List<&2, U32>, Nat, ys => List.length(&2, U32, ys), Laws.zlib.stored(65535, raw), ap, + Equal.trans(List<&2, U32>, Laws.zlib.stored(65535, raw), List.append(&2, U32, [120, 1], Png.enc.cat(bl, be_s)), ap, Wp2.cat_app([120, 1], Png.enc.cat(bl, be_s)), Equal.cong(List<&2, U32>, List<&2, U32>, ys => List.append(&2, U32, [120, 1], ys), Png.enc.cat(bl, be_s), List.append(&2, U32, bl, be_s), Wp2.cat_app(bl, be_s)))), @@ -1976,6 +2040,14 @@ def zlib.len( Nat, kk => 2n+Nat.add(kk, 4n), List.length(&2, U32, bl), xx, cnt.blocks(raw, mx, emx, hn, hbig)), add.six(xx)))) +# the IDAT data's length for n raw bytes in k blocks: n + 5 k + 6 +def kzn(+nr: Nat, +nn: U32) -> Nat: + Nat.add(Nat.add(nr, Nat.mul(U32.to_nat(Png.enc.nblk(nn)), 5n)), 6n) + +# the IDAT data's length for the raw bytes xs +def kzs(+xs: List<&2, U32>) -> Nat: + kzn(List.length(&2, U32, xs), Png.enc.len(xs, 0)) + # the IDAT length the encoder writes is the zlib stream's, when the stream is # at most some U32's value long def idat.len( @@ -1985,8 +2057,7 @@ def idat.len( +emx: {mx == 65535 : U32}, +hn: {U32.to_nat(Png.enc.len(raw, 0)) == List.length(&2, U32, raw) : Nat}, +hbig: {U32.is_le(Png.enc.len(raw, 0), 65535) == False{} : Bool}, - +h_tu: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, raw), Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(raw, 0))), - 5n)), 6n), U32.to_nat(tu)) == True{} : Bool} + +h_tu: {Nat.is_le(kzs(raw), U32.to_nat(tu)) == True{} : Bool} ) -> {Png.enc.idat.ln(Png.enc.len(raw, 0)) == Png.enc.len(Laws.zlib.stored(65535, raw), 0) : U32}: +nn = Png.enc.len(raw, 0) +kb = Png.enc.nblk(nn) @@ -1997,12 +2068,14 @@ def idat.len( +h_x = {R.le_add_r(xx, 6n, tn, h_tu) : {Nat.is_le(xx, tn) == True{} : Bool}} +h_k = {R.le_add_l(n0, k5, tn, h_x) : {Nat.is_le(k5, tn) == True{} : Bool}} +e_m = {R.u32_mul_below(kb, 5, tu, h_k) : {U32.to_nat((kb * 5 : U32)) == k5 : Nat}} - +h_a = {R.le_rw_l(xx, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), tn, Equal.trans(Nat, xx, Nat.add(U32.to_nat(nn), + +h_a = {R.le_rw_l(xx, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), tn, Equal.trans(Nat, xx, + Nat.add(U32.to_nat(nn), k5), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), Equal.cong(Nat, Nat, kk => Nat.add(kk, k5), n0, U32.to_nat(nn), Equal.sym(Nat, U32.to_nat(nn), n0, hn)), Equal.cong(Nat, Nat, kk => Nat.add(U32.to_nat(nn), kk), k5, U32.to_nat((kb * 5 : U32)), Equal.sym(Nat, U32.to_nat((kb * 5 : U32)), k5, e_m))), h_x) : {Nat.is_le(Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), tn) == True{} : Bool}} - +e_a = {Equal.trans(Nat, U32.to_nat((nn + (kb * 5 : U32) : U32)), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), xx, + +e_a = {Equal.trans(Nat, U32.to_nat((nn + (kb * 5 : U32) : U32)), Nat.add(U32.to_nat(nn), + U32.to_nat((kb * 5 : U32))), xx, R.u32_add_below(nn, (kb * 5 : U32), tu, h_a), Equal.trans(Nat, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 5 : U32))), Nat.add(n0, U32.to_nat((kb * 5 : U32))), xx, Equal.cong(Nat, Nat, kk => Nat.add(kk, U32.to_nat((kb * 5 : U32))), U32.to_nat(nn), n0, hn), Equal.cong(Nat, Nat, kk => Nat.add(n0, kk), U32.to_nat((kb * 5 : U32)), k5, e_m))) : @@ -2019,7 +2092,8 @@ def idat.len( +e_zl = {len.of(zz, tu, R.le_rw_l(Nat.add(xx, 6n), List.length(&2, U32, zz), tn, Equal.sym(Nat, List.length(&2, U32, zz), Nat.add(xx, 6n), e_z), h_tu)) : {U32.to_nat(Png.enc.len(zz, 0)) == List.length(&2, U32, zz) : Nat}} u32.same(Png.enc.idat.ln(nn), Png.enc.len(zz, 0), Equal.trans(Nat, U32.to_nat(Png.enc.idat.ln(nn)), Nat.add(xx, 6n), - U32.to_nat(Png.enc.len(zz, 0)), e_i, Equal.sym(Nat, U32.to_nat(Png.enc.len(zz, 0)), Nat.add(xx, 6n), Equal.trans(Nat, + U32.to_nat(Png.enc.len(zz, 0)), e_i, Equal.sym(Nat, U32.to_nat(Png.enc.len(zz, 0)), Nat.add(xx, 6n), + Equal.trans(Nat, U32.to_nat(Png.enc.len(zz, 0)), List.length(&2, U32, zz), Nat.add(xx, 6n), e_zl, e_z)))) # ---- H. enc.rgb.go against bs ---- @@ -2118,16 +2192,34 @@ def nil.r( +aa: U32, +bb: U32, +hh: {List.length(&2, U32, xs) == 0n : Nat} -) -> {Png.enc.rgb.fin(cc, acc, aa, bb) == (fr(bs(xs, z1, z2, r1, l1, n1, f1), cc, acc), afold(xs, aa, bb)) : (U32 & - List<&2, U32>) & U32}: +) -> {Png.enc.rgb.fin(cc, acc, aa, bb) == (fr(bs(xs, z1, z2, r1, l1, n1, f1), cc, acc), afold(xs, aa, + bb)) : (U32 & List<&2, U32>) & U32}: match xs: case Nil{}: {==} case _x <> t: - Empty.absurd({Png.enc.rgb.fin(cc, acc, aa, bb) == (fr(bs(_x <> t, z1, z2, r1, l1, n1, f1), cc, acc), afold(_x <> t, - aa, bb)) : (U32 & List<&2, U32>) & U32}, Wp1.zero_succ(List.length(&2, U32, t), Equal.sym(Nat, 1n+List.length(&2, + Empty.absurd({Png.enc.rgb.fin(cc, acc, aa, bb) == (fr(bs(_x <> t, z1, z2, r1, l1, n1, f1), cc, acc), + afold(_x <> t, + aa, bb)) : (U32 & List<&2, U32>) & U32}, Wp1.zero_succ(List.length(&2, U32, t), Equal.sym(Nat, + 1n+List.length(&2, U32, t), 0n, hh))) +# the walk's hypothesis for the bytes after xb +def step.ty( + -xb: U32, + -rr: List<&2, U32>, + -need: U32, + -pl: U32, + -cc: U32, + -acc: List<&2, U32>, + -aa: U32, + -bb: U32, + -gg: (U32 & List<&2, U32>) & U32 +) -> Type: + @xx: U32 -> @yy: U32 -> at.edge((need - 1 : U32), (pl - 1 : U32), xx, yy) -> {gg == (fr(bs(rr, U32.is_zero((need - + 1 : U32)), U32.is_eq((need - 1 : U32), 1), (need - 1 : U32), (pl - 1 : U32), xx, yy), Crc.crc.byte(cc, xb), + xb <> acc), afold(rr, Png.enc.add(aa, xb), Png.enc.add(bb, Png.enc.add(aa, xb)))) : (U32 & List<&2, U32>) & U32} + # one raw byte: bs writes it, and the block goes on or closes def step( z1: Bool, @@ -2144,11 +2236,9 @@ def step( -gg: (U32 & List<&2, U32>) & U32, +ez1: {U32.is_eq(need, 1) == z1 : Bool}, +nz: {U32.is_zero(need) == False{} : Bool}, - ih: @xx: U32 -> @yy: U32 -> at.edge((need - 1 : U32), (pl - 1 : U32), xx, yy) -> {gg == (fr(bs(rr, U32.is_zero((need - - 1 : U32)), U32.is_eq((need - 1 : U32), 1), (need - 1 : U32), (pl - 1 : U32), xx, yy), Crc.crc.byte(cc, xb), - xb <> acc), afold(rr, Png.enc.add(aa, xb), Png.enc.add(bb, Png.enc.add(aa, xb)))) : (U32 & List<&2, U32>) & U32} -) -> {gg == (fr(bs(xb <> rr, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(xb <> rr, aa, bb)) : - (U32 & List<&2, U32>) & U32}: + ih: step.ty(xb, rr, need, pl, cc, acc, aa, bb, gg) +) -> {gg == (fr(bs(xb <> rr, False{}, U32.is_eq(need, 1), need, pl, plen, pbf), cc, acc), afold(xb <> rr, aa, + bb)) : (U32 & List<&2, U32>) & U32}: match z1: case True{}: +n1 = (need - 1 : U32) @@ -2183,6 +2273,31 @@ def step( Equal.cong(Bool, (U32 & List<&2, U32>) & U32, zb => (fr(bs(rr, zb, U32.is_eq(n1, 1), n1, p1, plen, pbf), c1, xb <> acc), afold(rr, a2, b2)), U32.is_zero(n1), False{}, nz1)) +# the walk's hypothesis for the bytes after xb, with the fuel and counts +def rg.byte.ty( + -pp: Nat, + -xb: U32, + -r2: List<&2, U32>, + -need: U32, + -pl: U32, + -cc: U32, + -acc: List<&2, U32>, + -aa: U32, + -bb: U32, + -left: U32, + -len: U32, + -kk: Nat, + -xn: Nat, + -gg: (U32 & List<&2, U32>) & U32 +) -> Type: + @xx: U32 -> @yy: U32 -> at.edge((need - 1 : U32), (pl - 1 : U32), xx, yy) -> {Nat.add(U32.to_nat((need - 1 : U32)), + xn) == List.length(&2, U32, r2) : Nat} -> {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, r2), 1n), + Nat.double(kk)), 1n+pp) == True{} : Bool} -> {U32.to_nat((pl - 1 : U32)) == List.length(&2, U32, r2) : Nat} -> + {Nat.add(U32.to_nat(len), List.length(&2, U32, r2)) == Nat.add(U32.to_nat(left), U32.to_nat((need - 1 : U32))) : + Nat} -> {gg == (fr(bs(r2, U32.is_zero((need - 1 : U32)), U32.is_eq((need - 1 : U32), 1), (need - 1 : U32), (pl - 1 : + U32), xx, yy), Crc.crc.byte(cc, xb), xb <> acc), afold(r2, Png.enc.add(aa, xb), Png.enc.add(bb, Png.enc.add(aa, + xb)))) : (U32 & List<&2, U32>) & U32} + # a raw byte in a block, from the rg state: the facts for the state after it, # then step, then rg.val read with the byte in front def rg.byte( @@ -2209,13 +2324,7 @@ def rg.byte( +hw: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, rr), 1n), Nat.double(kk)), 2n+pp) == True{} : Bool}, +e_pl: {U32.to_nat(pl) == List.length(&2, U32, rr) : Nat}, +e_ll: {Nat.add(U32.to_nat(len), List.length(&2, U32, rr)) == Nat.add(U32.to_nat(left), U32.to_nat(need)) : Nat}, - ih: @xx: U32 -> @yy: U32 -> at.edge((need - 1 : U32), (pl - 1 : U32), xx, yy) -> {Nat.add(U32.to_nat((need - 1 : U32)), - xn) == List.length(&2, U32, r2) : Nat} -> {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, r2), 1n), - Nat.double(kk)), 1n+pp) == True{} : Bool} -> {U32.to_nat((pl - 1 : U32)) == List.length(&2, U32, r2) : Nat} -> - {Nat.add(U32.to_nat(len), List.length(&2, U32, r2)) == Nat.add(U32.to_nat(left), U32.to_nat((need - 1 : U32))) : - Nat} -> {gg == (fr(bs(r2, U32.is_zero((need - 1 : U32)), U32.is_eq((need - 1 : U32), 1), (need - 1 : U32), (pl - 1 : - U32), xx, yy), Crc.crc.byte(cc, xb), xb <> acc), afold(r2, Png.enc.add(aa, xb), Png.enc.add(bb, Png.enc.add(aa, - xb)))) : (U32 & List<&2, U32>) & U32} + ih: rg.byte.ty(pp, xb, r2, need, pl, cc, acc, aa, bb, left, len, kk, xn, gg) ) -> {gg == rg.val(False{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}: +n1 = (need - 1 : U32) +nr = List.length(&2, U32, r2) @@ -2225,7 +2334,8 @@ def rg.byte( rr) == 1n+nr : Nat}} +hx2 = {Wp1.succ_inj(Nat.add(U32.to_nat(n1), xn), nr, Equal.trans(Nat, 1n+Nat.add(U32.to_nat(n1), xn), Nat.add(U32.to_nat(need), xn), 1n+nr, Equal.cong(Nat, Nat, kz => Nat.add(kz, xn), 1n+U32.to_nat(n1), - U32.to_nat(need), Equal.sym(Nat, U32.to_nat(need), 1n+U32.to_nat(n1), e_n)), Equal.trans(Nat, Nat.add(U32.to_nat(need), + U32.to_nat(need), Equal.sym(Nat, U32.to_nat(need), 1n+U32.to_nat(n1), + e_n)), Equal.trans(Nat, Nat.add(U32.to_nat(need), xn), List.length(&2, U32, rr), 1n+nr, hx, e_len))) : {Nat.add(U32.to_nat(n1), xn) == nr : Nat}} +hw2 = {Equal.trans(Bool, Nat.is_le(Nat.add(Nat.add(1n+nr, 1n), Nat.double(kk)), 2n+pp), Nat.is_le(Nat.add(Nat.add( List.length(&2, U32, rr), 1n), Nat.double(kk)), 2n+pp), True{}, Equal.cong(Nat, Bool, kz => @@ -2239,7 +2349,8 @@ def rg.byte( Equal.sym(Nat, Nat.add(U32.to_nat(len), 1n+nr), 1n+Nat.add(U32.to_nat(len), nr), R.add_succ(U32.to_nat(len), nr)), Equal.trans(Nat, Nat.add(U32.to_nat(len), 1n+nr), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), 1n+Nat.add(U32.to_nat(left), U32.to_nat(n1)), Equal.trans(Nat, Nat.add(U32.to_nat(len), 1n+nr), - Nat.add(U32.to_nat(len), List.length(&2, U32, rr)), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), Equal.cong(Nat, Nat, + Nat.add(U32.to_nat(len), List.length(&2, U32, rr)), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), Equal.cong(Nat, + Nat, kz => Nat.add(U32.to_nat(len), kz), 1n+nr, List.length(&2, U32, rr), Equal.sym(Nat, List.length(&2, U32, rr), 1n+nr, e_len)), Equal.trans(Nat, Nat.add(U32.to_nat(len), List.length(&2, U32, rr)), Nat.add(U32.to_nat(left), U32.to_nat(need)), Nat.add(U32.to_nat(left), 1n+U32.to_nat(n1)), e_ll, Equal.cong(Nat, Nat, kz => @@ -2269,13 +2380,13 @@ def hd5(+left: U32) -> List<&2, U32>: # the block's whole length in hand, once whether that length is 1 is named def spl.at( z1: Bool, - +h: U32, - +t: List<&2, U32>, + +hd: U32, + +tl: List<&2, U32>, +left: U32, +ez1: {U32.is_eq(Png.enc.cap(left), 1) == z1 : Bool}, +nzc: {U32.is_zero(Png.enc.cap(left)) == False{} : Bool} -) -> {open.bs(h, t, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == List.append(&2, U32, hd5(left), bs(h <> t, - False{}, U32.is_eq(Png.enc.cap(left), 1), Png.enc.cap(left), left, Png.enc.cap((left - 1 : U32)), +) -> {open.bs(hd, tl, (left - 1 : U32), Png.enc.cap(left), Png.enc.bf(left)) == List.append(&2, U32, hd5(left), + bs(hd <> tl, False{}, U32.is_eq(Png.enc.cap(left), 1), Png.enc.cap(left), left, Png.enc.cap((left - 1 : U32)), Png.enc.bf((left - 1 : U32)))) : List<&2, U32>}: match z1: case True{}: @@ -2283,18 +2394,22 @@ def spl.at( +l1 = (left - 1 : U32) +e1 = {one.val(cp, Equal.sym(Bool, U32.is_eq(cp, 1), True{}, ez1)) : {U32.to_nat(cp) == 1n : Nat}} +e0 = {u32.same((cp - 1 : U32), 0, Wp1.u32_pred(cp, 0n, e1)) : {(cp - 1 : U32) == 0 : U32}} - %Equal.sym(Bool, U32.is_eq(cp, 1), True{}, ez1) : {open.bs(h, t, l1, cp, Png.enc.bf(left)) == List.append(&2, U32, - hd5(left), bs(h <> t, False{}, _, cp, left, Png.enc.cap(l1), Png.enc.bf(l1))) : List<&2, U32>} - Equal.cong(U32, List<&2, U32>, uu => List.append(&2, U32, hd5(left), h <> bs(t, U32.is_zero(uu), U32.is_eq(uu, 1), + %Equal.sym(Bool, U32.is_eq(cp, 1), True{}, ez1) : {open.bs(hd, tl, l1, cp, Png.enc.bf(left)) == List.append(&2, + U32, + hd5(left), bs(hd <> tl, False{}, _, cp, left, Png.enc.cap(l1), Png.enc.bf(l1))) : List<&2, U32>} + Equal.cong(U32, List<&2, U32>, uu => List.append(&2, U32, hd5(left), hd <> bs(tl, U32.is_zero(uu), U32.is_eq(uu, + 1), uu, l1, Png.enc.cap(l1), Png.enc.bf(l1))), (cp - 1 : U32), 0, e0) case False{}: +cp = Png.enc.cap(left) +l1 = (left - 1 : U32) +nz1 = {two(cp, Equal.sym(Bool, U32.is_zero(cp), False{}, nzc), Equal.sym(Bool, U32.is_eq(cp, 1), False{}, ez1)) : {U32.is_zero((cp - 1 : U32)) == False{} : Bool}} - %Equal.sym(Bool, U32.is_eq(cp, 1), False{}, ez1) : {open.bs(h, t, l1, cp, Png.enc.bf(left)) == List.append(&2, U32, - hd5(left), bs(h <> t, False{}, _, cp, left, Png.enc.cap(l1), Png.enc.bf(l1))) : List<&2, U32>} - Equal.cong(Bool, List<&2, U32>, zb => List.append(&2, U32, hd5(left), h <> bs(t, zb, U32.is_eq((cp - 1 : U32), 1), + %Equal.sym(Bool, U32.is_eq(cp, 1), False{}, ez1) : {open.bs(hd, tl, l1, cp, Png.enc.bf(left)) == List.append(&2, + U32, + hd5(left), bs(hd <> tl, False{}, _, cp, left, Png.enc.cap(l1), Png.enc.bf(l1))) : List<&2, U32>} + Equal.cong(Bool, List<&2, U32>, zb => List.append(&2, U32, hd5(left), hd <> bs(tl, zb, U32.is_eq((cp - 1 : U32), + 1), (cp - 1 : U32), l1, Png.enc.cap(l1), Png.enc.bf(l1))), U32.is_zero((cp - 1 : U32)), False{}, nz1) # a block's start with bytes left: the header, then the bytes with the block's @@ -2324,8 +2439,8 @@ def n0.pe( +plen: U32, +pbf: U32, pe: {plen == Png.enc.cap(pl) : U32} & {pbf == Png.enc.bf(pl) : U32} -) -> {bs(rr, True{}, False{}, 0, pl, plen, pbf) == bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), Png.enc.bf(pl)) : - List<&2, U32>}: +) -> {bs(rr, True{}, False{}, 0, pl, plen, pbf) == bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), + Png.enc.bf(pl)) : List<&2, U32>}: (+e_l, +e_b) = pe Equal.trans(List<&2, U32>, bs(rr, True{}, False{}, 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), pbf), bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), Png.enc.bf(pl)), Equal.cong(U32, List<&2, U32>, uu => bs(rr, @@ -2352,8 +2467,10 @@ def n0.bs( Equal.trans(List<&2, U32>, bs(rr, U32.is_zero(need), U32.is_eq(need, 1), need, pl, plen, pbf), bs(rr, True{}, False{}, 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2)), Equal.cong(U32, List<&2, U32>, uu => bs(rr, U32.is_zero(uu), U32.is_eq(uu, 1), uu, pl, plen, pbf), need, 0, e0), - Equal.trans(List<&2, U32>, bs(rr, True{}, False{}, 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, pl, Png.enc.cap(pl), - Png.enc.bf(pl)), bs(rr, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2)), n0.pe(rr, pl, plen, pbf, + Equal.trans(List<&2, U32>, bs(rr, True{}, False{}, 0, pl, plen, pbf), bs(rr, True{}, False{}, 0, pl, + Png.enc.cap(pl), + Png.enc.bf(pl)), bs(rr, True{}, False{}, 0, left2, Png.enc.cap(left2), Png.enc.bf(left2)), n0.pe(rr, pl, plen, + pbf, hb(Equal.sym(Bool, True{}, U32.is_zero(need), ez))), Equal.cong(U32, List<&2, U32>, uu => bs(rr, True{}, False{}, 0, uu, Png.enc.cap(uu), Png.enc.bf(uu)), pl, left2, e_p))) @@ -2378,7 +2495,8 @@ def z0.s2(+nr: Nat, +dk: Nat, +hw: {Nat.is_le(Nat.add(Nat.add(nr, 1n), dk), 1n) +h1 = {R.le_add_r(Nat.add(nr, 1n), dk, 1n, hw) : {Nat.is_le(Nat.add(nr, 1n), 1n) == True{} : Bool}} +h2 = {R.le_rw_l(Nat.add(nr, 1n), 1n+Nat.add(nr, 0n), 1n, R.add_succ(nr, 0n), h1) : {Nat.is_le(Nat.add(nr, 0n), 0n) == True{} : Bool}} - Equal.trans(Nat, nr, Nat.add(nr, 0n), 0n, Equal.sym(Nat, Nat.add(nr, 0n), nr, R.add_zero(nr)), le.zero(Nat.add(nr, 0n), + Equal.trans(Nat, nr, Nat.add(nr, 0n), 0n, Equal.sym(Nat, Nat.add(nr, 0n), nr, R.add_zero(nr)), le.zero(Nat.add(nr, + 0n), h2)) # the fuel after a block header: one step fewer, one block fewer, one more to close it @@ -2425,30 +2543,32 @@ def need.nil( # the filter byte: 0, then the row's samples def cur.filt( - +s: U32, - +t: List<&2, U32>, + +sv: U32, + +tl: List<&2, U32>, +row: U32, +wp: Nat, +er: {U32.to_nat(row) == 1n+wp : Nat} -) -> {W9.sc(s <> t, 0n, 1n+wp, True{}) == 0 <> W9.sc(s <> t, U32.to_nat(row), 1n+wp, True{}) : List<&2, U32>}: - Equal.cong(Nat, List<&2, U32>, kz => 0 <> W9.sc(s <> t, kz, 1n+wp, True{}), 1n+wp, U32.to_nat(row), Equal.sym(Nat, +) -> {W9.sc(sv <> tl, 0n, 1n+wp, True{}) == 0 <> W9.sc(sv <> tl, U32.to_nat(row), 1n+wp, True{}) : List<&2, U32>}: + Equal.cong(Nat, List<&2, U32>, kz => 0 <> W9.sc(sv <> tl, kz, 1n+wp, True{}), 1n+wp, U32.to_nat(row), Equal.sym(Nat, U32.to_nat(row), 1n+wp, er)) # a red byte: the sample's red, then its green and blue and the rest of the row def cur.red( - +s: U32, - +t: List<&2, U32>, + +sv: U32, + +tl: List<&2, U32>, +row: U32, +wn: Nat, +hrow: {U32.is_zero(row) == False{} : Bool} -) -> {W9.sc(s <> t, U32.to_nat(row), wn, True{}) == Png.enc.r(s) <> Png.enc.g(s) <> Png.enc.b(s) <> W9.sc(t, +) -> {W9.sc(sv <> tl, U32.to_nat(row), wn, True{}) == Png.enc.r(sv) <> Png.enc.g(sv) <> Png.enc.b(sv) <> W9.sc(tl, Png.enc.pred(U32.to_nat(row)), wn, True{}) : List<&2, U32>}: +r1 = U32.to_nat((row - 1 : U32)) +er = {Wp1.u32_dec(row, hrow) : {U32.to_nat(row) == 1n+r1 : Nat}} - Equal.trans(List<&2, U32>, W9.sc(s <> t, U32.to_nat(row), wn, True{}), W9.sc(s <> t, 1n+r1, wn, True{}), Png.enc.r(s) - <> Png.enc.g(s) <> Png.enc.b(s) <> W9.sc(t, Png.enc.pred(U32.to_nat(row)), wn, True{}), - Equal.cong(Nat, List<&2, U32>, kz => W9.sc(s <> t, kz, wn, True{}), U32.to_nat(row), 1n+r1, er), - Equal.cong(Nat, List<&2, U32>, kz => Png.enc.r(s) <> Png.enc.g(s) <> Png.enc.b(s) <> W9.sc(t, Png.enc.pred(kz), wn, + Equal.trans(List<&2, U32>, W9.sc(sv <> tl, U32.to_nat(row), wn, True{}), W9.sc(sv <> tl, 1n+r1, wn, True{}), + Png.enc.r(sv) + <> Png.enc.g(sv) <> Png.enc.b(sv) <> W9.sc(tl, Png.enc.pred(U32.to_nat(row)), wn, True{}), + Equal.cong(Nat, List<&2, U32>, kz => W9.sc(sv <> tl, kz, wn, True{}), U32.to_nat(row), 1n+r1, er), + Equal.cong(Nat, List<&2, U32>, kz => Png.enc.r(sv) <> Png.enc.g(sv) <> Png.enc.b(sv) <> W9.sc(tl, Png.enc.pred(kz), + wn, True{}), 1n+r1, U32.to_nat(row), Equal.sym(Nat, U32.to_nat(row), 1n+r1, er))) # a row's last blue byte: the next row starts with its filter byte @@ -2475,6 +2595,29 @@ def cur.blue( Equal.cong(Nat, List<&2, U32>, kz => Png.enc.b(col) <> W9.sc(px, Png.enc.pred(kz), wn, True{}), U32.to_nat(row), 1n+U32.to_nat((row - 1 : U32)), Wp1.u32_dec(row, hrow)) +# at a filter byte or a blue channel, the next is not a red or green one, and zlast says the row's last pixel +def rg.hbl(filt: Bool, zred: Bool, zgrn: Bool, zlast: Bool, +row: U32) -> Type: + {filt == False{} : Bool} -> {zred == False{} : Bool} -> {zgrn == False{} : Bool} -> {zlast == U32.is_eq(row, 1) : + Bool} + +# how many bytes are left from the cursor +def curl(filt: Bool, zred: Bool, zgrn: Bool, px: List<&2, U32>, +col: U32, +row: U32, +wp: Nat) -> Nat: + List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)) + +# the steps the walk takes from the cursor: the bytes, one more when a block is open, and two per block +def rgw( + filt: Bool, + zred: Bool, + zgrn: Bool, + px: List<&2, U32>, + +col: U32, + +row: U32, + +wp: Nat, + zblock: Bool, + +kk: Nat +) -> Nat: + Nat.add(Nat.add(curl(filt, zred, zgrn, px, col, row, wp), R.bit(Bool.not(zblock))), Nat.double(kk)) + # enc.rgb.go writes bs's blocks of the raw bytes its cursor walks, with their # CRC run, and the Adler-32 of those bytes, while its fuel covers a step per # raw byte and two per block (the header, and the step that closes it) @@ -2510,18 +2653,14 @@ def rg( +ew: {U32.to_nat(ww) == 1n+wp : Nat}, +hrow: {U32.is_zero(row) == False{} : Bool}, hfw: {filt == True{} : Bool} -> {row == ww : U32}, - hbl: {filt == False{} : Bool} -> {zred == False{} : Bool} -> {zgrn == False{} : Bool} -> {zlast == U32.is_eq(row, 1) : - Bool}, - +hx: {Nat.add(U32.to_nat(rm(zblock, need)), xn) == List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)) : - Nat}, + hbl: rg.hbl(filt, zred, zgrn, zlast, row), + +hx: {Nat.add(U32.to_nat(rm(zblock, need)), xn) == curl(filt, zred, zgrn, px, col, row, wp) : Nat}, hk: kok(xn, kk, U32.to_nat(mx)), - +hw: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)), - R.bit(Bool.not(zblock))), Nat.double(kk)), 1n+fuel) == True{} : Bool}, - hb: rg.hyp(zblock, zdone, zspan, zneed, List.length(&2, U32, cur(filt, zred, zgrn, px, col, row, 1n+wp)), left, len, - need, pl, plen, pbf) -) -> {Png.enc.rgb.go(fuel, zblock, zdone, zspan, zneed, filt, zred, zgrn, zlast, px, col, row, ww, need, cc, acc, aa, bb, - left, len) == rg.val(zblock, cur(filt, zred, zgrn, px, col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : - (U32 & List<&2, U32>) & U32}: + +hw: {Nat.is_le(rgw(filt, zred, zgrn, px, col, row, wp, zblock, kk), 1n+fuel) == True{} : Bool}, + hb: rg.hyp(zblock, zdone, zspan, zneed, curl(filt, zred, zgrn, px, col, row, wp), left, len, need, pl, plen, pbf) +) -> {Png.enc.rgb.go(fuel, zblock, zdone, zspan, zneed, filt, zred, zgrn, zlast, px, col, row, ww, need, cc, acc, aa, + bb, left, len) == rg.val(zblock, cur(filt, zred, zgrn, px, col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, + pbf) : (U32 & List<&2, U32>) & U32}: match fuel: case 0n: match zblock: @@ -2591,7 +2730,8 @@ def rg( e_R))) : {Nat.add(U32.to_nat(cp), x2) == nr : Nat}} +h_lt2 = {R.lt_rw_r(Nat.mul(kp, mn), xn, 1n+nt, Equal.trans(Nat, xn, nr, 1n+nt, hx, e_R), h_lt) : {Nat.is_lt(Nat.mul(kp, mn), 1n+nt) == True{} : Bool}} - +h_le2 = {R.le_rw_l(xn, 1n+nt, Nat.add(mn, Nat.mul(kp, mn)), Equal.trans(Nat, xn, nr, 1n+nt, hx, e_R), + +h_le2 = {R.le_rw_l(xn, 1n+nt, Nat.add(mn, Nat.mul(kp, mn)), Equal.trans(Nat, xn, nr, 1n+nt, hx, + e_R), h_le) : {Nat.is_le(1n+nt, Nat.add(mn, Nat.mul(kp, mn))) == True{} : Bool}} hk2 = kok.rw(Nat.sub(nt, U32.to_nat((cm - 1 : U32))), x2, kp, mn, Equal.cong(Nat, Nat, kz => Nat.sub(nt, kz), U32.to_nat((cm - 1 : U32)), U32.to_nat(c1), Equal.sym(Nat, U32.to_nat(c1), @@ -2611,27 +2751,36 @@ def rg( +c5 = Crc.crc.byte(Crc.crc.byte(Crc.crc.byte(Crc.crc.byte(Crc.crc.byte(cc, bf), b1), b2), b3), b4) +a4 = {b4 <> b3 <> b2 <> b1 <> bf <> acc : List<&2, U32>} +bb2 = bs(rr, False{}, U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)) - +ih = {rg(pp, False{}, False{}, True{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, - aa, bb, left, cp, left, Png.enc.cap(l1), Png.enc.bf(l1), kp, x2, wp, mx, emx, ew, hrow, hfw, hbl, + +ih = {rg(pp, False{}, False{}, True{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, cp, + c5, a4, + aa, bb, left, cp, left, Png.enc.cap(l1), Png.enc.bf(l1), kp, x2, wp, mx, emx, ew, hrow, hfw, + hbl, hx2, hk2, hw2, ({==}, ({==}, (Equal.sym(Bool, U32.is_zero(cp), False{}, nz_cp), (e_l, (ell2, edge.no(cp, left, Png.enc.cap(l1), Png.enc.bf(l1), nz_cp))))))) : {Png.enc.rgb.go(pp, False{}, - False{}, True{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp) + False{}, True{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, + cp) == (fr(bs(rr, U32.is_zero(cp), U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, a4), afold(rr, aa, bb)) : (U32 & List<&2, U32>) & U32}} - Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, False{}, False{}, True{}, False{}, filt, - zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp), (fr(bb2, c5, a4), afold(rr, aa, + Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, False{}, False{}, True{}, False{}, + filt, + zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp), (fr(bb2, c5, a4), afold(rr, + aa, bb)), rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), - Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, False{}, False{}, True{}, False{}, filt, - zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp), (fr(bs(rr, U32.is_zero(cp), + Equal.trans((U32 & List<&2, U32>) & U32, Png.enc.rgb.go(pp, False{}, False{}, True{}, False{}, + filt, + zred, zgrn, zlast, px, col, row, ww, cp, c5, a4, aa, bb, left, cp), (fr(bs(rr, + U32.is_zero(cp), U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, a4), afold(rr, aa, bb)), (fr(bb2, c5, a4), afold(rr, aa, bb)), ih, Equal.cong(Bool, (U32 & List<&2, U32>) & U32, zb => - (fr(bs(rr, zb, U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, a4), afold(rr, + (fr(bs(rr, zb, U32.is_eq(cp, 1), cp, left, Png.enc.cap(l1), Png.enc.bf(l1)), c5, a4), + afold(rr, aa, bb)), U32.is_zero(cp), False{}, nz_cp)), Equal.sym((U32 & List<&2, U32>) & U32, rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), (fr(bb2, c5, a4), afold(rr, aa, bb)), Equal.trans((U32 & List<&2, U32>) & U32, rg.val(True{}, rr, cc, acc, aa, bb, left, need, pl, plen, pbf), (fr(List.append(&2, U32, hd5(left), bb2), cc, acc), afold(rr, aa, bb)), (fr(bb2, c5, a4), afold(rr, aa, bb)), - Equal.cong(List<&2, U32>, (U32 & List<&2, U32>) & U32, ys => (fr(ys, cc, acc), afold(rr, aa, bb)), + Equal.cong(List<&2, U32>, (U32 & List<&2, U32>) & U32, ys => (fr(ys, cc, acc), afold(rr, aa, + bb)), bs(rr, True{}, False{}, 0, left, cp, bf), List.append(&2, U32, hd5(left), bb2), spl(rr, left, e_l, nzl, nz_cp)), Equal.cong(U32 & List<&2, U32>, (U32 & List<&2, U32>) & U32, qq => (qq, afold(rr, aa, bb)), fr(List.append(&2, U32, hd5(left), bb2), cc, acc), fr(bb2, c5, a4), @@ -2661,7 +2810,8 @@ def rg( +nr = List.length(&2, U32, rr) +l2 = (left - len : U32) +e_n0 = {zero.val(need, e_zn) : {U32.to_nat(need) == 0n : Nat}} - +e_lf = {Equal.trans(Nat, U32.to_nat(left), Nat.add(U32.to_nat(left), 0n), Nat.add(U32.to_nat(len), + +e_lf = {Equal.trans(Nat, U32.to_nat(left), Nat.add(U32.to_nat(left), 0n), + Nat.add(U32.to_nat(len), nr), Equal.sym(Nat, Nat.add(U32.to_nat(left), 0n), U32.to_nat(left), R.add_zero(U32.to_nat(left))), Equal.trans(Nat, Nat.add(U32.to_nat(left), 0n), Nat.add(U32.to_nat(left), U32.to_nat(need)), Nat.add(U32.to_nat(len), nr), Equal.cong(Nat, Nat, @@ -2679,7 +2829,8 @@ def rg( +hx2 = {Equal.trans(Nat, xn, Nat.add(U32.to_nat(need), xn), nr, Equal.cong(Nat, Nat, kz => Nat.add(kz, xn), 0n, U32.to_nat(need), Equal.sym(Nat, U32.to_nat(need), 0n, e_n0)), hx) : {Nat.add(U32.to_nat(0), xn) == nr : Nat}} - +ih = {rg(pp, True{}, U32.is_zero(l2), False{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, + +ih = {rg(pp, True{}, U32.is_zero(l2), False{}, False{}, filt, zred, zgrn, zlast, px, col, row, + ww, need, cc, acc, aa, bb, l2, len, pl, plen, pbf, kk, xn, wp, mx, emx, ew, hrow, hfw, hbl, hx2, hk, hw.end(nr, Nat.double(kk), pp, hw), ({==}, e_l2)) : {Png.enc.rgb.go(pp, True{}, U32.is_zero(l2), False{}, False{}, filt, zred, zgrn, zlast, px, col, row, ww, need, cc, acc, aa, @@ -2700,12 +2851,30 @@ def rg( match px: case Nil{}: (_e_d, (_e_s, (e_zn, _rest))) = hb - Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, True{}, False{}, True{}, zred, zgrn, zlast, [], col, row, ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, cur(True{}, zred, zgrn, [], col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}, need.nil(need, xn, e_zn, hx)) + Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, True{}, False{}, True{}, zred, + zgrn, zlast, [], col, row, ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, + cur(True{}, zred, zgrn, [], col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, + plen, pbf) : (U32 & List<&2, U32>) & U32}, need.nil(need, xn, e_zn, hx)) case +s <> +t: (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb +r2 = cur(False{}, True{}, False{}, s <> t, col, row, 1n+wp) - +e_R = {cur.filt(s, t, row, wp, Equal.trans(Nat, U32.to_nat(row), U32.to_nat(ww), 1n+wp, Equal.cong(U32, Nat, uu => U32.to_nat(uu), row, ww, hfw({==})), ew)) : {cur(True{}, zred, zgrn, s <> t, col, row, 1n+wp) == 0 <> r2 : List<&2, U32>}} - rg.byte(pp, 0, cur(True{}, zred, zgrn, s <> t, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, s <> t, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, 0), 0 <> acc, Png.enc.add(aa, 0), Png.enc.add(bb, Png.enc.add(aa, 0)), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, s <> t, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, 0), 0 <> acc, Png.enc.add(aa, 0), Png.enc.add(bb, Png.enc.add(aa, 0)), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), _e1 => e2 => _e3 => Empty.absurd({False{} == U32.is_eq(row, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + +e_R = {cur.filt(s, t, row, wp, Equal.trans(Nat, U32.to_nat(row), U32.to_nat(ww), + 1n+wp, Equal.cong(U32, Nat, uu => U32.to_nat(uu), row, ww, + hfw({==})), ew)) : {cur(True{}, zred, zgrn, s <> t, col, row, 1n+wp) == + 0 <> r2 : List<&2, U32>}} + rg.byte(pp, 0, cur(True{}, zred, zgrn, s <> t, col, row, 1n+wp), r2, need, pl, plen, + pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, + U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, s <> t, col, row, + ww, (need - 1 : U32), Crc.crc.byte(cc, 0), 0 <> acc, Png.enc.add(aa, 0), + Png.enc.add(bb, Png.enc.add(aa, 0)), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, + xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, + U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, s <> t, col, row, + ww, (need - 1 : U32), Crc.crc.byte(cc, 0), 0 <> acc, Png.enc.add(aa, 0), + Png.enc.add(bb, Png.enc.add(aa, 0)), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, + mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), + _e1 => e2 => _e3 => Empty.absurd({False{} == U32.is_eq(row, 1) : Bool}, + U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))), h2, hk, h3, ({==}, ({==}, + ({==}, (h4, (h5, h1))))))) case False{}: match zred: case True{}: @@ -2716,31 +2885,102 @@ def rg( match px: case Nil{}: (_e_d, (_e_s, (e_zn, _rest))) = hb - Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, True{}, False{}, False{}, True{}, _gn, _ls, [], col, row, ww, need, cc, acc, aa, bb, left, len) == rg.val(False{}, cur(False{}, True{}, _gn, [], col, row, 1n+wp), cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, U32>) & U32}, need.nil(need, xn, e_zn, hx)) + Empty.absurd({Png.enc.rgb.go(1n+pp, False{}, False{}, True{}, False{}, + False{}, True{}, _gn, _ls, [], col, row, ww, need, cc, acc, aa, bb, left, + len) == rg.val(False{}, cur(False{}, True{}, _gn, [], col, row, 1n+wp), + cc, acc, aa, bb, left, need, pl, plen, pbf) : (U32 & List<&2, + U32>) & U32}, need.nil(need, xn, e_zn, hx)) case +s <> +t: (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb +r2 = cur(False{}, False{}, True{}, t, s, row, 1n+wp) - +e_R = {cur.red(s, t, row, 1n+wp, hrow) : {cur(False{}, True{}, _gn, s <> t, col, row, 1n+wp) == Png.enc.r(s) <> r2 : List<&2, U32>}} - rg.byte(pp, Png.enc.r(s), cur(False{}, True{}, _gn, s <> t, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, True{}, False{}, t, s, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.r(s)), Png.enc.r(s) <> acc, Png.enc.add(aa, Png.enc.r(s)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.r(s))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, True{}, False{}, t, s, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.r(s)), Png.enc.r(s) <> acc, Png.enc.add(aa, Png.enc.r(s)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.r(s))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), _e1 => _e2 => e3 => Empty.absurd({False{} == U32.is_eq(row, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e3))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + +e_R = {cur.red(s, t, row, 1n+wp, hrow) : {cur(False{}, True{}, _gn, + s <> t, col, row, 1n+wp) == Png.enc.r(s) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.r(s), cur(False{}, True{}, _gn, s <> t, col, row, + 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, + Png.enc.rgb.go(pp, False{}, False{}, True{}, + U32.is_zero((need - 1 : U32)), False{}, False{}, True{}, False{}, t, s, + row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.r(s)), + Png.enc.r(s) <> acc, Png.enc.add(aa, Png.enc.r(s)), Png.enc.add(bb, + Png.enc.add(aa, Png.enc.r(s))), left, len), e_R, e_zn, hx, hw, e_pl, + e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, + False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, + True{}, False{}, t, s, row, ww, (need - 1 : U32), Crc.crc.byte(cc, + Png.enc.r(s)), Png.enc.r(s) <> acc, Png.enc.add(aa, Png.enc.r(s)), + Png.enc.add(bb, Png.enc.add(aa, Png.enc.r(s))), left, len, + (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, + ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), + _e1 => _e2 => e3 => Empty.absurd({False{} == U32.is_eq(row, 1) : Bool}, + U32L.false_true(Equal.sym(Bool, True{}, False{}, e3))), h2, hk, h3, + ({==}, ({==}, ({==}, (h4, (h5, h1))))))) case False{}: match zgrn: case True{}: (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb +r2 = cur(False{}, False{}, False{}, px, col, row, 1n+wp) - +e_R = {{==} : {cur(False{}, False{}, True{}, px, col, row, 1n+wp) == Png.enc.g(col) <> r2 : List<&2, U32>}} - rg.byte(pp, Png.enc.g(col), cur(False{}, False{}, True{}, px, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, False{}, U32.is_eq(row, 1), px, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.g(col)), Png.enc.g(col) <> acc, Png.enc.add(aa, Png.enc.g(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.g(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, False{}, U32.is_eq(row, 1), px, col, row, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.g(col)), Png.enc.g(col) <> acc, Png.enc.add(aa, Png.enc.g(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.g(col))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), _e1 => _e2 => _e3 => {==}, h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + +e_R = {{==} : {cur(False{}, False{}, True{}, px, col, row, + 1n+wp) == Png.enc.g(col) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.g(col), cur(False{}, False{}, True{}, px, col, row, 1n+wp), r2, + need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, + False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, + False{}, U32.is_eq(row, 1), px, col, row, ww, (need - 1 : U32), + Crc.crc.byte(cc, Png.enc.g(col)), Png.enc.g(col) <> acc, Png.enc.add(aa, + Png.enc.g(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.g(col))), left, len), + e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, + False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, False{}, + False{}, U32.is_eq(row, 1), px, col, row, ww, (need - 1 : U32), + Crc.crc.byte(cc, Png.enc.g(col)), Png.enc.g(col) <> acc, Png.enc.add(aa, + Png.enc.g(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.g(col))), left, len, + (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, hrow, + ef => Empty.absurd({row == ww : U32}, U32L.false_true(ef)), + _e1 => _e2 => _e3 => {==}, h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) case False{}: match zlast: case True{}: (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb +r2 = cur(True{}, True{}, False{}, px, col, ww, 1n+wp) - +e_R = {cur.last(col, px, row, 1n+wp, hbl({==}, {==}, {==})) : {cur(False{}, False{}, False{}, px, col, row, 1n+wp) == Png.enc.b(col) <> r2 : List<&2, U32>}} - rg.byte(pp, Png.enc.b(col), cur(False{}, False{}, False{}, px, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), True{}, True{}, False{}, False{}, px, col, ww, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), True{}, True{}, False{}, False{}, px, col, ww, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, Wp1.u32_nonzero(ww, wp, ew), _ef => {==}, ef => Empty.absurd({True{} == False{} : Bool} -> {False{} == False{} : Bool} -> {False{} == U32.is_eq(ww, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, ef))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + +e_R = {cur.last(col, px, row, 1n+wp, hbl({==}, {==}, {==})) : {cur(False{}, + False{}, False{}, px, col, row, 1n+wp) == Png.enc.b(col) <> r2 : List<&2, + U32>}} + rg.byte(pp, Png.enc.b(col), cur(False{}, False{}, False{}, px, col, row, + 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, + Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), + True{}, True{}, False{}, False{}, px, col, ww, ww, (need - 1 : U32), + Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, + Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, + len), e_R, e_zn, hx, hw, e_pl, e_ll, + xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, + U32.is_zero((need - 1 : U32)), True{}, True{}, False{}, False{}, px, col, + ww, ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), + Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, + Png.enc.add(aa, Png.enc.b(col))), left, len, (pl - 1 : U32), xx, yy, kk, + xn, wp, mx, emx, ew, Wp1.u32_nonzero(ww, wp, ew), _ef => {==}, + ef => Empty.absurd({True{} == False{} : Bool} -> {False{} == + False{} : Bool} -> {False{} == U32.is_eq(ww, 1) : Bool}, + U32L.false_true(Equal.sym(Bool, True{}, False{}, ef))), h2, hk, h3, ({==}, + ({==}, ({==}, (h4, (h5, h1))))))) case False{}: (_e_d, (_e_s, (+e_zn, (+e_pl, (+e_ll, _hbe))))) = hb +r2 = cur(False{}, True{}, False{}, px, col, (row - 1 : U32), 1n+wp) - +e_R = {cur.blue(col, px, row, 1n+wp, hrow) : {cur(False{}, False{}, False{}, px, col, row, 1n+wp) == Png.enc.b(col) <> r2 : List<&2, U32>}} - rg.byte(pp, Png.enc.b(col), cur(False{}, False{}, False{}, px, col, row, 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, px, col, (row - 1 : U32), ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, px, col, (row - 1 : U32), ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, Png.enc.b(col))), left, len, (pl - 1 : U32), xx, yy, kk, xn, wp, mx, emx, ew, two(row, Equal.sym(Bool, U32.is_zero(row), False{}, hrow), hbl({==}, {==}, {==})), ef => Empty.absurd({(row - 1 : U32) == ww : U32}, U32L.false_true(ef)), _e1 => e2 => _e3 => Empty.absurd({False{} == U32.is_eq((row - 1 : U32), 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))), h2, hk, h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) + +e_R = {cur.blue(col, px, row, 1n+wp, hrow) : {cur(False{}, False{}, False{}, + px, col, row, 1n+wp) == Png.enc.b(col) <> r2 : List<&2, U32>}} + rg.byte(pp, Png.enc.b(col), cur(False{}, False{}, False{}, px, col, row, + 1n+wp), r2, need, pl, plen, pbf, cc, acc, aa, bb, left, len, kk, xn, + Png.enc.rgb.go(pp, False{}, False{}, True{}, U32.is_zero((need - 1 : U32)), + False{}, True{}, False{}, False{}, px, col, (row - 1 : U32), ww, + (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), Png.enc.b(col) <> acc, + Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, Png.enc.add(aa, + Png.enc.b(col))), left, len), e_R, e_zn, hx, hw, e_pl, e_ll, + xx => yy => h1 => h2 => h3 => h4 => h5 => rg(pp, False{}, False{}, True{}, + U32.is_zero((need - 1 : U32)), False{}, True{}, False{}, False{}, px, col, + (row - 1 : U32), ww, (need - 1 : U32), Crc.crc.byte(cc, Png.enc.b(col)), + Png.enc.b(col) <> acc, Png.enc.add(aa, Png.enc.b(col)), Png.enc.add(bb, + Png.enc.add(aa, Png.enc.b(col))), left, len, (pl - 1 : U32), xx, yy, kk, + xn, wp, mx, emx, ew, two(row, Equal.sym(Bool, U32.is_zero(row), False{}, + hrow), hbl({==}, {==}, {==})), ef => Empty.absurd({(row - 1 : U32) == + ww : U32}, U32L.false_true(ef)), + _e1 => e2 => _e3 => Empty.absurd({False{} == U32.is_eq((row - 1 : U32), + 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))), h2, hk, + h3, ({==}, ({==}, ({==}, (h4, (h5, h1))))))) # ---- I. Adler-32 as enc.rgb.go adds it is Inf.adler.of ---- @@ -2755,8 +2995,12 @@ def addm(zz: Bool, +tt: U32, +pm: U32) -> U32: tt # enc.add.at is addm at 65521 -def addm.eq(zz: Bool, +tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> {Png.enc.add.at(zz, tt) == addm(zz, tt, pm) : - U32}: +def addm.eq( + zz: Bool, + +tt: U32, + +pm: U32, + +epm: {pm == 65521 : U32} +) -> {Png.enc.add.at(zz, tt) == addm(zz, tt, pm) : U32}: match zz: case True{}: Equal.cong(U32, U32, uu => (tt - uu : U32), 65521, pm, Equal.sym(U32, pm, 65521, epm)) @@ -2764,8 +3008,12 @@ def addm.eq(zz: Bool, +tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> {Png.enc {==} # at most and below cannot both hold the other way round -def le.lt.no(+aa: Nat, +bb: Nat, +h1: {Nat.is_le(aa, bb) == True{} : Bool}, +h2: {Nat.is_lt(bb, aa) == True{} : Bool}) -> - Empty: +def le.lt.no( + +aa: Nat, + +bb: Nat, + +h1: {Nat.is_le(aa, bb) == True{} : Bool}, + +h2: {Nat.is_lt(bb, aa) == True{} : Bool} +) -> Empty: lt.irr(aa, R.le_lt_trans(aa, bb, aa, h1, h2)) # t below 2 m is t mod m after one subtraction of m, or none: which one is t >= m's answer @@ -2799,7 +3047,8 @@ def md.at( +e_t2 = {Equal.trans(Nat, U32.to_nat(tt), Nat.add(Nat.add(mn, 0n), rn), Nat.add(mn, rn), e_t, Equal.cong(Nat, Nat, kz => Nat.add(kz, rn), Nat.add(mn, 0n), mn, R.add_zero(mn))) : {U32.to_nat(tt) == Nat.add(mn, rn) : Nat}} - u32.same((tt - pm : U32), U32.mod(tt, pm), Equal.trans(Nat, U32.to_nat((tt - pm : U32)), Nat.sub(U32.to_nat(tt), + u32.same((tt - pm : U32), U32.mod(tt, pm), Equal.trans(Nat, U32.to_nat((tt - pm : U32)), + Nat.sub(U32.to_nat(tt), mn), rn, R.u32_sub_nat(tt, pm, hg), Equal.trans(Nat, Nat.sub(U32.to_nat(tt), mn), Nat.sub(Nat.add(mn, rn), mn), rn, Equal.cong(Nat, Nat, kz => Nat.sub(kz, mn), U32.to_nat(tt), Nat.add(mn, rn), e_t2), R.sub_add_cancel(mn, rn)))) @@ -2828,15 +3077,18 @@ def md.at( Empty.absurd({tt == U32.mod(tt, pm) : U32}, le.lt.no(mn, U32.to_nat(tt), h2, hl)) # the modulus doubled is a U32's value -def pm.dbl(+pm: U32, +epm: {pm == 65521 : U32}) -> {U32.to_nat(U32.add(pm, pm)) == Nat.add(U32.to_nat(pm), - U32.to_nat(pm)) : Nat}: +def pm.dbl( + +pm: U32, + +epm: {pm == 65521 : U32} +) -> {U32.to_nat(U32.add(pm, pm)) == Nat.add(U32.to_nat(pm), U32.to_nat(pm)) : Nat}: add.cf(pm, pm, Equal.cong(U32, Bool, uu => cy32(uu, uu), pm, 65521, epm)) # U32.mod by the modulus: a quotient and a remainder below it def pm.dvm(+tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> dvm.ty(tt, pm): +mn = U32.to_nat(pm) +hm = {Equal.trans(Bool, Nat.is_lt(0n, mn), U32.is_lt(0, pm), True{}, Equal.sym(Bool, U32.is_lt(0, pm), Nat.is_lt(0n, - mn), R.u32_lt(0, pm)), Equal.cong(U32, Bool, uu => U32.is_lt(0, uu), pm, 65521, epm)) : {Nat.is_lt(0n, mn) == True{} : + mn), R.u32_lt(0, pm)), Equal.cong(U32, Bool, uu => U32.is_lt(0, uu), pm, 65521, epm)) : {Nat.is_lt(0n, mn) == + True{} : Bool}} +h2 = {R.le_rw_r(Nat.add(mn, mn), Nat.add(mn, mn), U32.to_nat(U32.add(pm, pm)), Equal.sym(Nat, U32.to_nat(U32.add(pm, pm)), Nat.add(mn, mn), pm.dbl(pm, epm)), R.le_refl(Nat.add(mn, mn))) : @@ -2869,15 +3121,22 @@ def mod.once( epm), ht), Equal.cong(U32, U32, uu => U32.mod(tt, uu), pm, 65521, epm))) # the remainder pm.dvm gives, read as mod 65521 -def mod.lt.go(+tt: U32, +pm: U32, +epm: {pm == 65521 : U32}, pr: dvm.ty(tt, pm)) -> {Nat.is_lt(U32.to_nat((tt % 65521 : - U32)), U32.to_nat(pm)) == True{} : Bool}: +def mod.lt.go( + +tt: U32, + +pm: U32, + +epm: {pm == 65521 : U32}, + pr: dvm.ty(tt, pm) +) -> {Nat.is_lt(U32.to_nat((tt % 65521 : U32)), U32.to_nat(pm)) == True{} : Bool}: (_e_t, +l_r) = pr R.lt_rw_l(U32.to_nat(U32.mod(tt, pm)), U32.to_nat((tt % 65521 : U32)), U32.to_nat(pm), Equal.cong(U32, Nat, uu => U32.to_nat(U32.mod(tt, uu)), pm, 65521, epm), l_r) # U32.mod by 65521 is below it -def mod.lt(+tt: U32, +pm: U32, +epm: {pm == 65521 : U32}) -> {Nat.is_lt(U32.to_nat((tt % 65521 : U32)), U32.to_nat(pm)) - == True{} : Bool}: +def mod.lt( + +tt: U32, + +pm: U32, + +epm: {pm == 65521 : U32} +) -> {Nat.is_lt(U32.to_nat((tt % 65521 : U32)), U32.to_nat(pm)) == True{} : Bool}: mod.lt.go(tt, pm, epm, pm.dvm(tt, pm, epm)) # one Adler-32 add of values below the modulus is the add mod 65521 @@ -2906,8 +3165,12 @@ def add.mod( Equal.sym(Nat, U32.to_nat((ss + xx : U32)), Nat.add(sn, xn), e_s), h3)) # a byte is below the modulus -def byte.pm(+xx: U32, +pm: U32, +epm: {pm == 65521 : U32}, +hh: {U32.is_le(xx, 255) == True{} : Bool}) -> - {Nat.is_lt(U32.to_nat(xx), U32.to_nat(pm)) == True{} : Bool}: +def byte.pm( + +xx: U32, + +pm: U32, + +epm: {pm == 65521 : U32}, + +hh: {U32.is_le(xx, 255) == True{} : Bool} +) -> {Nat.is_lt(U32.to_nat(xx), U32.to_nat(pm)) == True{} : Bool}: R.le_lt_trans(U32.to_nat(xx), U32.to_nat(255), U32.to_nat(pm), Equal.trans(Bool, Nat.is_le(U32.to_nat(xx), U32.to_nat(255)), U32.is_le(xx, 255), True{}, Equal.sym(Bool, U32.is_le(xx, 255), Nat.is_le(U32.to_nat(xx), U32.to_nat(255)), R.u32_le(xx, 255)), hh), Equal.trans(Bool, Nat.is_lt(U32.to_nat(255), U32.to_nat(pm)), @@ -2941,7 +3204,8 @@ def ad.eq( Equal.trans(U32, afold(t, Png.enc.add(aa, x), Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, b2), Inf.adler.fin(Inf.adler.go(t, a2, b2)), Equal.trans(U32, afold(t, Png.enc.add(aa, x), Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, - Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, b2), Equal.cong(U32, U32, uu => afold(t, uu, Png.enc.add(bb, + Png.enc.add(bb, Png.enc.add(aa, x))), afold(t, a2, b2), Equal.cong(U32, U32, uu => afold(t, uu, + Png.enc.add(bb, Png.enc.add(aa, x))), Png.enc.add(aa, x), a2, e_a), Equal.cong(U32, U32, uu => afold(t, a2, uu), Png.enc.add(bb, Png.enc.add(aa, x)), b2, e_b)), ad.eq(t, a2, b2, pm, epm, Wp2.bytes.tail(t, U32.is_le(x, 255), hby), l_a, l_b)) @@ -2972,8 +3236,12 @@ def mul2(kk: Nat) -> {Nat.mul(kk, 2n) == Nat.double(kk) : Nat}: Equal.cong(Nat, Nat, xx => 2n+xx, Nat.mul(kp, 2n), Nat.double(kp), mul2(kp)) # a count above 65535 is not zero, once is_zero's answer is named -def big.nz.at(zz: Bool, +nn: U32, +ez: {U32.is_zero(nn) == zz : Bool}, +hbig: {U32.is_le(nn, 65535) == False{} : Bool}) -> - {U32.is_zero(nn) == False{} : Bool}: +def big.nz.at( + zz: Bool, + +nn: U32, + +ez: {U32.is_zero(nn) == zz : Bool}, + +hbig: {U32.is_le(nn, 65535) == False{} : Bool} +) -> {U32.is_zero(nn) == False{} : Bool}: match zz: case False{}: ez @@ -2991,21 +3259,22 @@ def rgb.fuel( +nr: Nat, +hn: {U32.to_nat(nn) == nr : Nat}, +nz: {U32.is_zero(nn) == False{} : Bool}, - +h_tu: {Nat.is_le(Nat.add(Nat.add(nr, Nat.mul(U32.to_nat(Png.enc.nblk(nn)), 5n)), 6n), U32.to_nat(tu)) == True{} : - Bool} -) -> {Nat.is_le(Nat.add(Nat.add(nr, 0n), Nat.double(U32.to_nat(Png.enc.nblk(nn)))), 1n+U32.to_nat(((nn + - (Png.enc.nblk(nn) * 2 : U32) : U32) - 1 : U32))) == True{} : Bool}: + +h_tu: {Nat.is_le(kzn(nr, nn), U32.to_nat(tu)) == True{} : Bool} +) -> {Nat.is_le(Nat.add(Nat.add(nr, 0n), Nat.double(U32.to_nat(Png.enc.nblk(nn)))), + 1n+U32.to_nat(((nn + (Png.enc.nblk(nn) * 2 : U32) : U32) - 1 : U32))) == True{} : Bool}: +kb = Png.enc.nblk(nn) +kn = U32.to_nat(kb) +k2 = Nat.mul(kn, 2n) +tn = U32.to_nat(tu) +s1 = (nn + (kb * 2 : U32) : U32) - +h5 = {R.le_add_r(Nat.add(nr, Nat.mul(kn, 5n)), 6n, tn, h_tu) : {Nat.is_le(Nat.add(nr, Nat.mul(kn, 5n)), tn) == True{} : + +h5 = {R.le_add_r(Nat.add(nr, Nat.mul(kn, 5n)), 6n, tn, h_tu) : {Nat.is_le(Nat.add(nr, Nat.mul(kn, 5n)), + tn) == True{} : Bool}} +h25 = {R.le_rw_r(k2, Nat.mul(5n, kn), Nat.mul(kn, 5n), R.mul_comm(5n, kn), R.le_rw_l(Nat.mul(2n, kn), k2, Nat.mul(5n, kn), R.mul_comm(2n, kn), R.le_mul_mono(2n, 5n, kn, {==}))) : {Nat.is_le(k2, Nat.mul(kn, 5n)) == True{} : Bool}} - +h2 = {R.le_trans(Nat.add(nr, k2), Nat.add(nr, Nat.mul(kn, 5n)), tn, R.le_add_mono(nr, k2, Nat.mul(kn, 5n), h25), h5) : + +h2 = {R.le_trans(Nat.add(nr, k2), Nat.add(nr, Nat.mul(kn, 5n)), tn, R.le_add_mono(nr, k2, Nat.mul(kn, 5n), h25), + h5) : {Nat.is_le(Nat.add(nr, k2), tn) == True{} : Bool}} +e_m = {R.u32_mul_below(kb, 2, tu, R.le_add_l(nr, k2, tn, h2)) : {U32.to_nat((kb * 2 : U32)) == k2 : Nat}} +e_s = {Equal.trans(Nat, U32.to_nat(s1), Nat.add(U32.to_nat(nn), U32.to_nat((kb * 2 : U32))), Nat.add(nr, k2), @@ -3014,14 +3283,17 @@ def rgb.fuel( 2 : U32))), Equal.cong(Nat, Nat, xx => Nat.add(xx, k2), nr, U32.to_nat(nn), Equal.sym(Nat, U32.to_nat(nn), nr, hn)), Equal.cong(Nat, Nat, xx => Nat.add(U32.to_nat(nn), xx), k2, U32.to_nat((kb * 2 : U32)), Equal.sym(Nat, U32.to_nat((kb * 2 : U32)), k2, e_m))), h2)), Equal.trans(Nat, Nat.add(U32.to_nat(nn), U32.to_nat((kb * 2 : U32))), - Nat.add(nr, U32.to_nat((kb * 2 : U32))), Nat.add(nr, k2), Equal.cong(Nat, Nat, xx => Nat.add(xx, U32.to_nat((kb * 2 : - U32))), U32.to_nat(nn), nr, hn), Equal.cong(Nat, Nat, xx => Nat.add(nr, xx), U32.to_nat((kb * 2 : U32)), k2, e_m))) : + Nat.add(nr, U32.to_nat((kb * 2 : U32))), Nat.add(nr, k2), Equal.cong(Nat, Nat, xx => Nat.add(xx, + U32.to_nat((kb * 2 : + U32))), U32.to_nat(nn), nr, hn), Equal.cong(Nat, Nat, xx => Nat.add(nr, xx), U32.to_nat((kb * 2 : U32)), k2, + e_m))) : {U32.to_nat(s1) == Nat.add(nr, k2) : Nat}} +e_n = {Equal.trans(Nat, U32.to_nat(nn), 1n+U32.to_nat((nn - 1 : U32)), 1n+U32.to_nat((nn - 1 : U32)), Wp1.u32_dec(nn, nz), {==}) : {U32.to_nat(nn) == 1n+U32.to_nat((nn - 1 : U32)) : Nat}} +nz1 = {Wp1.u32_nonzero(s1, Nat.add(U32.to_nat((nn - 1 : U32)), k2), Equal.trans(Nat, U32.to_nat(s1), Nat.add(nr, k2), 1n+Nat.add(U32.to_nat((nn - 1 : U32)), k2), e_s, Equal.cong(Nat, Nat, xx => Nat.add(xx, k2), nr, 1n+U32.to_nat((nn - - 1 : U32)), Equal.trans(Nat, nr, U32.to_nat(nn), 1n+U32.to_nat((nn - 1 : U32)), Equal.sym(Nat, U32.to_nat(nn), nr, hn), + 1 : U32)), Equal.trans(Nat, nr, U32.to_nat(nn), 1n+U32.to_nat((nn - 1 : U32)), Equal.sym(Nat, U32.to_nat(nn), nr, + hn), e_n)))) : {U32.is_zero(s1) == False{} : Bool}} +e_st = {Equal.sym(Nat, U32.to_nat(s1), 1n+U32.to_nat((s1 - 1 : U32)), Wp1.u32_dec(s1, nz1)) : {1n+U32.to_nat((s1 - 1 : U32)) == U32.to_nat(s1) : Nat}} @@ -3030,11 +3302,24 @@ def rgb.fuel( xx => Nat.add(nr, xx), Nat.double(kn), k2, Equal.sym(Nat, k2, Nat.double(kn), mul2(kn)))) : {Nat.add(Nat.add(nr, 0n), Nat.double(kn)) == Nat.add(nr, k2) : Nat}} R.le_rw_r(Nat.add(Nat.add(nr, 0n), Nat.double(kn)), Nat.add(nr, k2), 1n+U32.to_nat((s1 - 1 : U32)), Equal.trans(Nat, - Nat.add(nr, k2), U32.to_nat(s1), 1n+U32.to_nat((s1 - 1 : U32)), Equal.sym(Nat, U32.to_nat(s1), Nat.add(nr, k2), e_s), + Nat.add(nr, k2), U32.to_nat(s1), 1n+U32.to_nat((s1 - 1 : U32)), Equal.sym(Nat, U32.to_nat(s1), Nat.add(nr, k2), + e_s), Equal.sym(Nat, 1n+U32.to_nat((s1 - 1 : U32)), U32.to_nat(s1), e_st)), R.le_rw_l(Nat.add(nr, k2), Nat.add(Nat.add(nr, 0n), Nat.double(kn)), Nat.add(nr, k2), Equal.sym(Nat, Nat.add(Nat.add(nr, 0n), Nat.double(kn)), Nat.add(nr, k2), e_l), R.le_refl(Nat.add(nr, k2)))) +# the scanlines of a picture 1 + w' wide +def sco(+px: List<&2, U32>, +wp: Nat, +op: Bool) -> List<&2, U32>: + W9.sc(px, 0n, 1n+wp, op) + +# the IDAT data length the encoder writes for the raw bytes xs +def ilen(+xs: List<&2, U32>) -> U32: + Png.enc.idat.ln(Png.enc.len(xs, 0)) + +# the zlib stream of xs in stored blocks of 65535 bytes +def zst(+xs: List<&2, U32>) -> List<&2, U32>: + Laws.zlib.stored(65535, xs) + # enc.wide.rgb after the signature and IHDR: the IDAT chunk holding the zlib # stream of the scanlines in stored blocks of 65535 bytes, then IEND def rgb.tail( @@ -3048,15 +3333,11 @@ def rgb.tail( +emx: {mx == 65535 : U32}, +epm: {pm == 65521 : U32}, +ew: {U32.to_nat(ww) == 1n+wp : Nat}, - +hn: {U32.to_nat(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0)) == List.length(&2, U32, W9.sc(px, 0n, 1n+wp, True{})) - : Nat}, - +hbig: {U32.is_le(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0), 65535) == False{} : Bool}, - +hby: {Laws.bytes(W9.sc(px, 0n, 1n+wp, True{})) == True{} : Bool}, - +hl: {Png.enc.idat.ln(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0)) == Png.enc.len(Laws.zlib.stored(65535, - W9.sc(px, 0n, 1n+wp, True{})), 0) : U32}, - +h_tu: {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, W9.sc(px, 0n, 1n+wp, True{})), - Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0))), 5n)), 6n), U32.to_nat(tu)) == True{} - : Bool} + +hn: {U32.to_nat(Png.enc.len(sco(px, wp, True{}), 0)) == List.length(&2, U32, sco(px, wp, True{})) : Nat}, + +hbig: {U32.is_le(Png.enc.len(sco(px, wp, True{}), 0), 65535) == False{} : Bool}, + +hby: {Laws.bytes(sco(px, wp, True{})) == True{} : Bool}, + +hl: {ilen(sco(px, wp, True{})) == Png.enc.len(zst(sco(px, wp, True{})), 0) : U32}, + +h_tu: {Nat.is_le(kzs(sco(px, wp, True{})), U32.to_nat(tu)) == True{} : Bool} ) -> {Png.enc.wide.rgb.go(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, Png.enc.cat.go(Png.enc.be(Png.enc.idat.ln(Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0))), [])), px, ww, Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0), ie) == Png.enc.cat(Png.enc.chunk(Png.tag.idat(), @@ -3081,13 +3362,16 @@ def rgb.tail( +hl2 = {Equal.trans(U32, ll, Png.enc.len(zz, 0), Png.enc.len(zb(bb, sum), 0), hl, Equal.cong(List<&2, U32>, U32, ys => Png.enc.len(zb(ys, sum), 0), bl, bb, e_b)) : {ll == Png.enc.len(zb(bb, sum), 0) : U32}} +nz = {big.nz.at(U32.is_zero(nn), nn, {==}, hbig) : {U32.is_zero(nn) == False{} : Bool}} - -go = Png.enc.rgb.go(U32.to_nat(steps), True{}, False{}, False{}, False{}, True{}, True{}, False{}, False{}, px, 0, ww, + -go = Png.enc.rgb.go(U32.to_nat(steps), True{}, False{}, False{}, False{}, True{}, True{}, False{}, False{}, px, 0, + ww, ww, 0, c2, a2, 1, 0, nn, 0) - +e_go = {rg(U32.to_nat(steps), True{}, False{}, False{}, False{}, True{}, True{}, False{}, False{}, px, 0, ww, ww, 0, c2, + +e_go = {rg(U32.to_nat(steps), True{}, False{}, False{}, False{}, True{}, True{}, False{}, False{}, px, 0, ww, ww, 0, + c2, a2, 1, 0, nn, 0, nn, 0, 0, kn, nr, wp, mx, emx, ew, Wp1.u32_nonzero(ww, wp, ew), _ef => {==}, ef => Empty.absurd({True{} == False{} : Bool} -> {False{} == False{} : Bool} -> {False{} == U32.is_eq(ww, 1) : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, ef))), {==}, kok.rw(U32.to_nat(nn), nr, kn, U32.to_nat(mx), hn, - nb.k(nn, mx, emx)), rgb.fuel(nn, tu, nr, hn, nz, h_tu), (Equal.sym(Bool, U32.is_zero(nn), False{}, nz), hn)) : {go == + nb.k(nn, mx, emx)), rgb.fuel(nn, tu, nr, hn, nz, h_tu), (Equal.sym(Bool, U32.is_zero(nn), False{}, + nz), hn)) : {go == (fr(bb, c2, a2), afold(raw, 1, 0)) : (U32 & List<&2, U32>) & U32}} +e_fr = {Equal.trans(U32 & List<&2, U32>, fr(bb, c2, a2), fr(List.append(&2, U32, [120, 1], bb), c1, a1), fr(t0(bb), 4294967295, aa), fr.app([120, 1], bb, c1, a1), fr.app(bi, List.append(&2, U32, [120, 1], bb), 4294967295, aa)) : @@ -3163,10 +3447,12 @@ def anc.at( case False{} False{} False{} False{} False{} True{}: {==} case True{} _z2 _z3 _z4 _z5 _an: - Empty.absurd({Png.png.apply.at(False{}, True{}, _z2, _z3, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, data, pg) + Empty.absurd({Png.png.apply.at(False{}, True{}, _z2, _z3, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, data, + pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e1))) case False{} True{} _z3 _z4 _z5 _an: - Empty.absurd({Png.png.apply.at(False{}, False{}, True{}, _z3, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, data, + Empty.absurd({Png.png.apply.at(False{}, False{}, True{}, _z3, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, + data, pg) == Png.NMore{Png.png.seal(pg)} : Png.Nx}, U32L.false_true(Equal.sym(Bool, True{}, False{}, e2))) case False{} False{} True{} _z4 _z5 _an: Empty.absurd({Png.png.apply.at(False{}, False{}, False{}, True{}, _z4, _z5, _an, True{}, sp, si, sdn, st, colour, @@ -3224,8 +3510,8 @@ def anc.step( +done: Bool, +hb: {Laws.spec.anc.bit(tt) == True{} : Bool}, +ht: {U32.is_eq(tt, 1951551059) == False{} : Bool} -) -> {Png.png.apply(tt, data, sd(ww, hh, cc, plte, trns, idat, sid, done)) == Png.NMore{sd(ww, hh, cc, plte, trns, idat, - sid, Bool.or(sid, done))} : Png.Nx}: +) -> {Png.png.apply(tt, data, sd(ww, hh, cc, plte, trns, idat, sid, done)) == Png.NMore{sd(ww, hh, cc, plte, trns, + idat, sid, Bool.or(sid, done))} : Png.Nx}: anc.at(U32.is_eq(tt, Png.tag.ihdr()), U32.is_eq(tt, Png.tag.idat()), U32.is_eq(tt, Png.tag.iend()), U32.is_eq(tt, Png.tag.plte()), U32.is_eq(tt, Png.tag.trns()), Png.tag.anc(tt), Maybe.is_some(&2, List<&2, U32>, plte), sid, done, Maybe.is_some(&2, List<&2, U32>, trns), cc, data, sd(ww, hh, cc, plte, trns, idat, sid, done), neq(tt, @@ -3295,14 +3581,16 @@ def anc.pre( +plte: Maybe<&2, List<&2, U32>>, +trns: Maybe<&2, List<&2, U32>>, hc: Laws.spec.ancs.ok(cs) -) -> {Png.png.go(Laws.spec.ancs(cs, rest), Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, [], False{})) - == Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, [], False{})) : Maybe<&2, - Png.Pic>}: +) -> {Png.png.go(Laws.spec.ancs(cs, rest), Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, [], + False{})) == Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, [], + False{})) : Maybe<&2, Png.Pic>}: Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.ancs(cs, rest), Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, - plte, trns, [], False{}, False{})), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, [], + plte, trns, [], False{}, False{})), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, + [], False{}, dn(cs, False{}, False{}))), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, [], False{}, False{})), anc.walk(cs, rest, ww, hh, cc, plte, trns, [], False{}, False{}, hc), Equal.cong(Bool, - Maybe<&2, Png.Pic>, bb => Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, [], False{}, + Maybe<&2, Png.Pic>, bb => Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, plte, trns, [], + False{}, bb)), dn(cs, False{}, False{}), False{}, dn.ff(cs))) # the IDAT chunks, ancillary chunks, then IEND: with done the IDAT data read @@ -3322,15 +3610,16 @@ def walk.idats( ha: Laws.spec.ancs.ok(a3) ) -> {Png.png.go(Laws.spec.idats(ds, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], []))), Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid)) == - Png.png.samples(Inf.inflate(List.append(&2, U32, done, List.concat(&2, U32, ds))), ww, hh, cc, Laws.spec.or.nil(plte), - Laws.spec.or.nil(trns)) : Maybe<&2, Png.Pic>}: + Png.png.samples(Inf.inflate(List.append(&2, U32, done, List.concat(&2, U32, ds))), ww, hh, cc, + Laws.spec.or.nil(plte), Laws.spec.or.nil(trns)) : Maybe<&2, Png.Pic>}: match ds: case Nil{}: +pl = Laws.spec.or.nil(plte) +tr = Laws.spec.or.nil(trns) +ie = Laws.spec.chunk([73, 69, 78, 68], [], []) +pg = sd(ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid, dn(a3, sid, False{})) - Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.ancs(a3, ie), Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, cc, + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.ancs(a3, ie), Png.ZLen{}, False{}, 0, 0, [], [], sd(ww, hh, + cc, plte, trns, List.reverse(&2, U32, done), sid, False{})), Png.png.go(ie, Png.ZLen{}, False{}, 0, 0, [], [], pg), Png.png.samples(Inf.inflate(List.append(&2, U32, done, [])), ww, hh, cc, pl, tr), anc.walk(a3, ie, ww, hh, cc, plte, trns, List.reverse(&2, U32, done), sid, False{}, ha), @@ -3338,7 +3627,8 @@ def walk.idats( Png.png.finish(Png.pg.iend(pg)), Png.png.samples(Inf.inflate(List.append(&2, U32, done, [])), ww, hh, cc, pl, tr), W9.chunk.end(73, 69, 78, 68, [], pg, Png.pg.iend(pg), {==}, W9.iend.ok.true(W9.need(cc, plte), pg, h_nd)), - Equal.trans(Maybe<&2, Png.Pic>, Png.png.finish(Png.pg.iend(pg)), Png.png.samples(Inf.inflate(done), ww, hh, cc, + Equal.trans(Maybe<&2, Png.Pic>, Png.png.finish(Png.pg.iend(pg)), Png.png.samples(Inf.inflate(done), ww, hh, + cc, pl, tr), Png.png.samples(Inf.inflate(List.append(&2, U32, done, [])), ww, hh, cc, pl, tr), Equal.cong(List<&2, U32>, Maybe<&2, Png.Pic>, xs => Png.png.samples(Inf.inflate(xs), ww, hh, cc, pl, tr), List.reverse(&2, U32, List.reverse(&2, U32, done)), done, Wp2.rev_rev(done)), @@ -3382,12 +3672,107 @@ def walk.idats( List.append(&2, U32, d2, List.concat(&2, U32, tl)), List.append(&2, U32, done, List.append(&2, U32, dd, List.concat(&2, U32, tl))), Wp2.app_assoc(done, dd, List.concat(&2, U32, tl)))))) -# the chunks after the signature, with ancillary chunks after IHDR, PLTE, -# tRNS and the IDAT chunks: the samples of the IDAT data, inflated +# the PLTE chunk after tRNS: its colour type allows it and its length is a palette's, so the state keeps its data +# beside tRNS's +def plte.late( + +ww: U32, + +hh: U32, + +cc: U32, + +pp: List<&2, U32>, + +trns: Maybe<&2, List<&2, U32>>, + h_pl: {Laws.spec.plte.ok(cc, Some{pp}) == True{} : Bool} +) -> {Png.png.apply(Png.be.u32(80, 76, 84, 69), List.reverse(&2, U32, pp), W9.st(ww, hh, cc, None{}, trns, [], + False{})) == Png.NMore{W9.st(ww, hh, cc, Some{pp}, trns, [], False{})} : Png.Nx}: + +ok = Bool.or(U32.is_eq(cc, 2), Bool.or(U32.is_eq(cc, 3), U32.is_eq(cc, 6))) + +rp = List.reverse(&2, U32, pp) + +e_len = {Wp2.len_rev(pp) : {List.length(&2, U32, rp) == List.length(&2, U32, pp) : Nat}} + +e_ok = {Equal.trans(Bool, Bool.and(ok, Png.png.mod3(rp)), Bool.and(ok, Laws.spec.pal.len(pp)), True{}, + Equal.cong(Nat, Bool, kk => Bool.and(ok, Bool.and(U32.is_gt(U32.from_nat(kk), 0), + Bool.and(U32.is_zero((U32.from_nat(kk) % 3 : U32)), U32.is_le(U32.from_nat(kk), 768)))), + List.length(&2, U32, rp), List.length(&2, U32, pp), e_len), h_pl) : + {Bool.and(ok, Png.png.mod3(rp)) == True{} : Bool}} + +pg0 = W9.st(ww, hh, cc, None{}, trns, [], False{}) + Equal.trans(Png.Nx, Png.png.allow(Bool.and(ok, Png.png.mod3(rp)), Png.pg.plte(pg0, List.reverse(&2, U32, rp))), + Png.NMore{Png.pg.plte(pg0, List.reverse(&2, U32, rp))}, + Png.NMore{W9.st(ww, hh, cc, Some{pp}, trns, [], False{})}, + W9.allow.true(Bool.and(ok, Png.png.mod3(rp)), Png.pg.plte(pg0, List.reverse(&2, U32, rp)), e_ok), + Equal.cong(List<&2, U32>, Png.Nx, xs => Png.NMore{Png.pg.plte(pg0, xs)}, List.reverse(&2, U32, rp), pp, + Wp2.rev_rev(pp))) + +# PLTE after tRNS, when there is one +def walk.plte.late( + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +trns: Maybe<&2, List<&2, U32>>, + +rest: List<&2, U32>, + h_pl: {Laws.spec.plte.ok(cc, plte) == True{} : Bool}, + hf: Laws.spec.fits.opt(plte) +) -> {Png.png.go(Laws.spec.chunk.opt([80, 76, 84, 69], plte, rest), Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, + cc, None{}, trns, [], False{})) == Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, + [], False{})) : Maybe<&2, Png.Pic>}: + match plte: + case None{}: + {==} + case Some{+pp}: + W9.chunk.more(80, 76, 84, 69, pp, rest, W9.st(ww, hh, cc, None{}, trns, [], False{}), W9.st(ww, hh, cc, Some{pp}, + trns, [], False{}), hf, plte.late(ww, hh, cc, pp, trns, h_pl)) + +# PLTE, a1 and tRNS, in either order: the state after them keeps both +def walk.mid( + late: Bool, + +ww: U32, + +hh: U32, + +cc: U32, + +plte: Maybe<&2, List<&2, U32>>, + +a1: List<&2, Laws.Anc>, + +trns: Maybe<&2, List<&2, U32>>, + +rest: List<&2, U32>, + h_pl: {Laws.spec.plte.ok(cc, plte) == True{} : Bool}, + h_tr: {Laws.spec.trns.ok(cc, plte, trns) == True{} : Bool}, + h_late: {Bool.or(Bool.not(late), Laws.spec.trns.ok(cc, None{}, trns)) == True{} : Bool}, + h_fp: Laws.spec.fits.opt(plte), + h_ft: Laws.spec.fits.opt(trns), + h_a1: Laws.spec.ancs.ok(a1) +) -> {Png.png.go(Laws.spec.mid(late, plte, a1, trns, rest), Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, + None{}, None{}, [], False{})) == Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], W9.st(ww, hh, cc, plte, trns, + [], False{})) : Maybe<&2, Png.Pic>}: + match late: + case False{}: + +r2 = Laws.spec.chunk.opt([116, 82, 78, 83], trns, rest) + +q1 = Laws.spec.ancs(a1, r2) + +s1 = W9.st(ww, hh, cc, plte, None{}, [], False{}) + +s2 = W9.st(ww, hh, cc, plte, trns, [], False{}) + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.chunk.opt([80, 76, 84, 69], plte, q1), Png.ZLen{}, False{}, + 0, 0, [], [], W9.st(ww, hh, cc, None{}, None{}, [], False{})), Png.png.go(q1, Png.ZLen{}, False{}, 0, 0, [], [], + s1), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], s2), + W9.walk.plte(ww, hh, cc, plte, q1, h_pl, h_fp), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q1, Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(r2, + Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], s2), + anc.pre(a1, r2, ww, hh, cc, plte, None{}, h_a1), + W9.walk.trns(ww, hh, cc, plte, trns, rest, h_tr, h_ft))) + case True{}: + +r2 = Laws.spec.chunk.opt([80, 76, 84, 69], plte, rest) + +q1 = Laws.spec.ancs(a1, r2) + +s1 = W9.st(ww, hh, cc, None{}, trns, [], False{}) + +s2 = W9.st(ww, hh, cc, plte, trns, [], False{}) + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.chunk.opt([116, 82, 78, 83], trns, q1), Png.ZLen{}, + False{}, 0, 0, [], [], W9.st(ww, hh, cc, None{}, None{}, [], False{})), Png.png.go(q1, Png.ZLen{}, False{}, 0, + 0, [], [], s1), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], s2), + W9.walk.trns(ww, hh, cc, None{}, trns, q1, h_late, h_ft), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q1, Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(r2, + Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(rest, Png.ZLen{}, False{}, 0, 0, [], [], s2), + anc.pre(a1, r2, ww, hh, cc, None{}, trns, h_a1), + walk.plte.late(ww, hh, cc, plte, trns, rest, h_pl, h_fp))) + +# the chunks after the signature, with ancillary chunks after IHDR, between PLTE and tRNS (in either order), after +# them and after the IDAT chunks: the samples of the IDAT data, inflated def walk.png( +ww: U32, +hh: U32, +cc: U32, + +late: Bool, +a0: List<&2, Laws.Anc>, +plte: Maybe<&2, List<&2, U32>>, +a1: List<&2, Laws.Anc>, @@ -3400,6 +3785,7 @@ def walk.png( +h_cc: {Laws.spec.colour.ok(cc) == True{} : Bool}, +h_pl: {Laws.spec.plte.ok(cc, plte) == True{} : Bool}, +h_tr: {Laws.spec.trns.ok(cc, plte, trns) == True{} : Bool}, + +h_late: {Bool.or(Bool.not(late), Laws.spec.trns.ok(cc, None{}, trns)) == True{} : Bool}, h_fp: Laws.spec.fits.opt(plte), h_ft: Laws.spec.fits.opt(trns), h_fi: Laws.spec.fits.all(idats), @@ -3408,35 +3794,441 @@ def walk.png( h_a2: Laws.spec.ancs.ok(a2), h_a3: Laws.spec.ancs.ok(a3) ) -> {Png.decode(Laws.spec.chunk([73, 72, 68, 82], Laws.spec.ihdr.data(ww, hh, cc), Laws.spec.ancs(a0, - Laws.spec.chunk.opt([80, 76, 84, 69], plte, Laws.spec.ancs(a1, Laws.spec.chunk.opt([116, 82, 78, 83], trns, - Laws.spec.ancs(a2, Laws.spec.idats(idats, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], [])))))))))) == - Png.png.samples(Inf.inflate(List.concat(&2, U32, idats)), ww, hh, cc, Laws.spec.or.nil(plte), Laws.spec.or.nil(trns)) : - Maybe<&2, Png.Pic>}: + Laws.spec.mid(late, plte, a1, trns, Laws.spec.ancs(a2, Laws.spec.idats(idats, Laws.spec.ancs(a3, + Laws.spec.chunk([73, 69, 78, 68], [], [])))))))) == Png.png.samples(Inf.inflate(List.concat(&2, U32, idats)), ww, + hh, cc, Laws.spec.or.nil(plte), Laws.spec.or.nil(trns)) : Maybe<&2, Png.Pic>}: +r3 = Laws.spec.idats(idats, Laws.spec.ancs(a3, Laws.spec.chunk([73, 69, 78, 68], [], []))) +q2 = Laws.spec.ancs(a2, r3) - +r2 = Laws.spec.chunk.opt([116, 82, 78, 83], trns, q2) - +q1 = Laws.spec.ancs(a1, r2) - +r1 = Laws.spec.chunk.opt([80, 76, 84, 69], plte, q1) + +r1 = Laws.spec.mid(late, plte, a1, trns, q2) +q0 = Laws.spec.ancs(a0, r1) +s0 = W9.st(ww, hh, cc, None{}, None{}, [], False{}) - +s1 = W9.st(ww, hh, cc, plte, None{}, [], False{}) +s2 = W9.st(ww, hh, cc, plte, trns, [], False{}) +out = Png.png.samples(Inf.inflate(List.concat(&2, U32, idats)), ww, hh, cc, Laws.spec.or.nil(plte), Laws.spec.or.nil(trns)) - Equal.trans(Maybe<&2, Png.Pic>, - Png.png.go(Laws.spec.chunk([73, 72, 68, 82], Laws.spec.ihdr.data(ww, hh, cc), q0), Png.ZLen{}, False{}, 0, 0, [], [], - Png.pg.empty()), - Png.png.go(q0, Png.ZLen{}, False{}, 0, 0, [], [], s0), out, - W9.chunk.more(73, 72, 68, 82, Laws.spec.ihdr.data(ww, hh, cc), q0, Png.pg.empty(), s0, {==}, W9.ihdr.step(ww, hh, cc, - h_ww, h_hh, h_cc)), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(Laws.spec.chunk([73, 72, 68, 82], Laws.spec.ihdr.data(ww, hh, cc), q0), + Png.ZLen{}, False{}, 0, 0, [], [], Png.pg.empty()), Png.png.go(q0, Png.ZLen{}, False{}, 0, 0, [], [], s0), out, + W9.chunk.more(73, 72, 68, 82, Laws.spec.ihdr.data(ww, hh, cc), q0, Png.pg.empty(), s0, {==}, W9.ihdr.step(ww, hh, + cc, h_ww, h_hh, h_cc)), Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q0, Png.ZLen{}, False{}, 0, 0, [], [], s0), Png.png.go(r1, Png.ZLen{}, False{}, 0, 0, [], [], s0), out, anc.pre(a0, r1, ww, hh, cc, None{}, None{}, h_a0), - Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(r1, Png.ZLen{}, False{}, 0, 0, [], [], s0), Png.png.go(q1, Png.ZLen{}, - False{}, 0, 0, [], [], s1), out, W9.walk.plte(ww, hh, cc, plte, q1, h_pl, h_fp), - Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q1, Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(r2, Png.ZLen{}, - False{}, 0, 0, [], [], s1), out, anc.pre(a1, r2, ww, hh, cc, plte, None{}, h_a1), - Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(r2, Png.ZLen{}, False{}, 0, 0, [], [], s1), Png.png.go(q2, - Png.ZLen{}, False{}, 0, 0, [], [], s2), out, W9.walk.trns(ww, hh, cc, plte, trns, q2, h_tr, h_ft), - Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q2, Png.ZLen{}, False{}, 0, 0, [], [], s2), Png.png.go(r3, - Png.ZLen{}, False{}, 0, 0, [], [], s2), out, anc.pre(a2, r3, ww, hh, cc, plte, trns, h_a2), - walk.idats(idats, ww, hh, cc, plte, trns, a3, [], False{}, W9.need.ok(cc, plte, h_pl), h_fi, h_a3))))))) + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(r1, Png.ZLen{}, False{}, 0, 0, [], [], s0), Png.png.go(q2, Png.ZLen{}, + False{}, 0, 0, [], [], s2), out, walk.mid(late, ww, hh, cc, plte, a1, trns, q2, h_pl, h_tr, h_late, h_fp, h_ft, + h_a1), + Equal.trans(Maybe<&2, Png.Pic>, Png.png.go(q2, Png.ZLen{}, False{}, 0, 0, [], [], s2), Png.png.go(r3, + Png.ZLen{}, False{}, 0, 0, [], [], s2), out, anc.pre(a2, r3, ww, hh, cc, plte, trns, h_a2), + walk.idats(idats, ww, hh, cc, plte, trns, a3, [], False{}, W9.need.ok(cc, plte, h_pl), h_fi, h_a3))))) + +# ---- L. the sizes from 8 w h, and the wide encodings as the one-block layout ---- + +# p a is at most p b when a is at most b +def ml.le( + pp: Nat, + +aa: Nat, + +bb: Nat, + +hh: {Nat.is_le(aa, bb) == True{} : Bool} +) -> {Nat.is_le(Nat.mul(pp, aa), Nat.mul(pp, bb)) == True{} : Bool}: + match pp: + case 0n: + {==} + case 1n+(+qq): + R.le_add_both(aa, bb, Nat.mul(qq, aa), Nat.mul(qq, bb), hh, ml.le(qq, aa, bb, hh)) + +# the encoder's channel count is at most 4 +def nch4(op: Bool) -> {Nat.is_le(Laws.spec.nch(op), 4n) == True{} : Bool}: + match op: + case True{}: + {==} + case False{}: + {==} + +# one row: 1 + w k is at most 5 w, for w above 0 and k at most 4 +def row5( + +wp: Nat, + +kk: Nat, + +hk: {Nat.is_le(kk, 4n) == True{} : Bool} +) -> {Nat.is_le(1n+Nat.mul(1n+wp, kk), Nat.mul(1n+wp, 5n)) == True{} : Bool}: + R.le_add_both(1n+kk, 5n, Nat.mul(wp, kk), Nat.mul(wp, 5n), hk, ml.le(wp, kk, 5n, R.le_trans(kk, 4n, 5n, hk, {==}))) + +# the scanline bytes are at most 5 w h +def scan5( + hn: Nat, + +wp: Nat, + +kk: Nat, + +hk: {Nat.is_le(kk, 4n) == True{} : Bool} +) -> {Nat.is_le(Nat.mul(hn, 1n+Nat.mul(1n+wp, kk)), Nat.mul(Nat.mul(hn, 1n+wp), 5n)) == True{} : Bool}: + match hn: + case 0n: + {==} + case 1n+(+hp): + +bb = {1n+Nat.mul(1n+wp, kk) : Nat} + +wn = {1n+wp : Nat} + R.le_rw_r(Nat.add(bb, Nat.mul(hp, bb)), Nat.add(Nat.mul(wn, 5n), Nat.mul(Nat.mul(hp, wn), 5n)), + Nat.mul(Nat.add(wn, Nat.mul(hp, wn)), 5n), Equal.sym(Nat, Nat.mul(Nat.add(wn, Nat.mul(hp, wn)), 5n), + Nat.add(Nat.mul(wn, 5n), Nat.mul(Nat.mul(hp, wn), 5n)), R.mul_add(wn, Nat.mul(hp, wn), 5n)), + R.le_add_both(bb, Nat.mul(wn, 5n), Nat.mul(hp, bb), Nat.mul(Nat.mul(hp, wn), 5n), row5(wp, kk, hk), + scan5(hp, wp, kk, hk))) + +# 5 x below 5 y: x below y +def lt.c5( + xx: Nat, + yy: Nat, + +hh: {Nat.is_lt(Nat.mul(xx, 5n), Nat.mul(yy, 5n)) == True{} : Bool} +) -> {Nat.is_lt(xx, yy) == True{} : Bool}: + match xx yy: + case 0n 0n: + hh + case 0n 1n+_yp: + {==} + case 1n+_xp 0n: + hh + case 1n+xp 1n+yp: + lt.c5(xp, yp, hh) + +# (5 p) 5 is 25 p +def m25(pp: Nat) -> {Nat.mul(Nat.mul(pp, 5n), 5n) == Nat.mul(pp, 25n) : Nat}: + match pp: + case 0n: + {==} + case 1n+(+qq): + Equal.cong(Nat, Nat, xx => Nat.add(25n, xx), Nat.mul(Nat.mul(qq, 5n), 5n), Nat.mul(qq, 25n), m25(qq)) + +# 5 a is at most 8 a +def five.eight(+aa: Nat) -> {Nat.is_le(Nat.mul(aa, 5n), Nat.mul(8n, aa)) == True{} : Bool}: + R.le_rw_r(Nat.mul(aa, 5n), Nat.add(Nat.mul(5n, aa), Nat.mul(3n, aa)), Nat.mul(8n, aa), Equal.sym(Nat, + Nat.mul(Nat.add(5n, 3n), aa), Nat.add(Nat.mul(5n, aa), Nat.mul(3n, aa)), R.mul_add(5n, 3n, aa)), + R.le_rw_l(Nat.mul(5n, aa), Nat.mul(aa, 5n), Nat.add(Nat.mul(5n, aa), Nat.mul(3n, aa)), R.mul_comm(5n, aa), + R.le_add_more(Nat.mul(5n, aa), Nat.mul(5n, aa), Nat.mul(3n, aa), R.le_refl(Nat.mul(5n, aa))))) + +# 11 + y is at most 3 a when y is at most a and 6 is too +def eleven( + +yy: Nat, + +aa: Nat, + +hy: {Nat.is_le(yy, aa) == True{} : Bool}, + +h6: {Nat.is_le(6n, aa) == True{} : Bool} +) -> {Nat.is_le(11n+yy, Nat.mul(3n, aa)) == True{} : Bool}: + +a0 = Nat.add(aa, 0n) + +h6z = {R.le_rw_r(6n, aa, a0, Equal.sym(Nat, a0, aa, R.add_zero(aa)), h6) : {Nat.is_le(6n, a0) == True{} : Bool}} + +h11 = {R.le_trans(11n, 12n, Nat.add(aa, a0), {==}, R.le_add_both(6n, aa, 6n, a0, h6, h6z)) : {Nat.is_le(11n, + Nat.add(aa, a0)) == True{} : Bool}} + R.le_rw_l(Nat.add(yy, 11n), 11n+yy, Nat.mul(3n, aa), R.add_comm(yy, 11n), R.le_add_both(yy, aa, 11n, Nat.add(aa, a0), + hy, h11)) + +# the stored blocks' bytes fit in 8 a: n + 5 k + 6 is at most 8 a when n is at most 5 a, k blocks of m bytes hold +# the n bytes, m is at least 25 and n is above m +def kb( + kk: Nat, + +xn: Nat, + +mn: Nat, + +aa: Nat, + hk: kok(xn, kk, mn), + +h5: {Nat.is_le(xn, Nat.mul(aa, 5n)) == True{} : Bool}, + +hm: {Nat.is_le(25n, mn) == True{} : Bool}, + +hb: {Nat.is_lt(mn, xn) == True{} : Bool} +) -> {Nat.is_le(Nat.add(Nat.add(xn, Nat.mul(kk, 5n)), 6n), Nat.mul(8n, aa)) == True{} : Bool}: + match kk: + case 0n: + Empty.absurd({Nat.is_le(Nat.add(Nat.add(xn, 0n), 6n), Nat.mul(8n, aa)) == True{} : Bool}, + U32L.false_true(Equal.trans(Bool, False{}, Nat.is_lt(mn, 0n), True{}, R.lt_zero_false(mn), R.lt_rw_r(mn, xn, 0n, + hk, hb)))) + case 1n+(+kp): + (hl, _hr) = hk + +yy = Nat.mul(kp, 5n) + +x5 = Nat.mul(aa, 5n) + +y25 = {R.le_rw_l(Nat.mul(kp, 25n), Nat.mul(yy, 5n), Nat.mul(kp, mn), Equal.sym(Nat, Nat.mul(yy, 5n), + Nat.mul(kp, 25n), m25(kp)), ml.le(kp, 25n, mn, hm)) : {Nat.is_le(Nat.mul(yy, 5n), Nat.mul(kp, mn)) == True{} : + Bool}} + +ya = {lt.c5(yy, aa, R.le_lt_trans(Nat.mul(yy, 5n), Nat.mul(kp, mn), x5, y25, R.lt_le_trans(Nat.mul(kp, mn), xn, + x5, hl, h5))) : {Nat.is_lt(yy, aa) == True{} : Bool}} + +a5 = {lt.c5(5n, aa, R.le_lt_trans(25n, mn, x5, hm, R.lt_le_trans(mn, xn, x5, hb, h5))) : {Nat.is_lt(5n, aa) == + True{} : Bool}} + +h6 = {Equal.trans(Bool, Nat.is_le(6n, aa), Nat.is_lt(5n, aa), True{}, Equal.sym(Bool, Nat.is_lt(5n, aa), + Nat.is_le(6n, aa), R.lt_le_succ(5n, aa)), a5) : {Nat.is_le(6n, aa) == True{} : Bool}} + +h5c = {R.le_rw_r(xn, x5, Nat.mul(5n, aa), R.mul_comm(aa, 5n), h5) : {Nat.is_le(xn, Nat.mul(5n, aa)) == True{} : + Bool}} + +lhs = Nat.add(Nat.add(xn, 5n+yy), 6n) + +e1 = {Equal.trans(Nat, lhs, Nat.add(xn, 5n+Nat.add(yy, 6n)), Nat.add(xn, 11n+yy), R.add_assoc(xn, 5n+yy, 6n), + Equal.cong(Nat, Nat, zz => Nat.add(xn, Nat.add(5n, zz)), Nat.add(yy, 6n), Nat.add(6n, yy), R.add_comm(yy, + 6n))) : {lhs == Nat.add(xn, 11n+yy) : Nat}} + R.le_rw_r(lhs, Nat.add(Nat.mul(5n, aa), Nat.mul(3n, aa)), Nat.mul(8n, aa), Equal.sym(Nat, Nat.mul(Nat.add(5n, 3n), + aa), Nat.add(Nat.mul(5n, aa), Nat.mul(3n, aa)), R.mul_add(5n, 3n, aa)), + R.le_rw_l(Nat.add(xn, 11n+yy), lhs, Nat.add(Nat.mul(5n, aa), Nat.mul(3n, aa)), Equal.sym(Nat, lhs, + Nat.add(xn, 11n+yy), e1), R.le_add_both(xn, Nat.mul(5n, aa), 11n+yy, Nat.mul(3n, aa), h5c, eleven(yy, aa, + R.lt_le(yy, aa, ya), h6)))) + +# the IDAT data of the wide encodings fits in t, a word whose value is 8 a, when the scanlines are at most 5 a bytes +def tu.ok( + +raw: List<&2, U32>, + +mx: U32, + +tu: U32, + +aa: Nat, + +emx: {mx == 65535 : U32}, + +hn: {U32.to_nat(Png.enc.len(raw, 0)) == List.length(&2, U32, raw) : Nat}, + +hbig: {U32.is_le(Png.enc.len(raw, 0), 65535) == False{} : Bool}, + +h5: {Nat.is_le(List.length(&2, U32, raw), Nat.mul(aa, 5n)) == True{} : Bool}, + +et: {U32.to_nat(tu) == Nat.mul(8n, aa) : Nat} +) -> {Nat.is_le(Nat.add(Nat.add(List.length(&2, U32, raw), Nat.mul(U32.to_nat(Png.enc.nblk(Png.enc.len(raw, 0))), 5n)), + 6n), U32.to_nat(tu)) == True{} : Bool}: + +ll = Png.enc.len(raw, 0) + +xn = U32.to_nat(ll) + +ln = List.length(&2, U32, raw) + +mn = U32.to_nat(mx) + +kn = U32.to_nat(Png.enc.nblk(ll)) + +hm = {Equal.trans(Bool, Nat.is_le(25n, mn), U32.is_le(25, mx), True{}, Equal.sym(Bool, U32.is_le(25, mx), + Nat.is_le(25n, mn), R.u32_le(25, mx)), Equal.cong(U32, Bool, uu => U32.is_le(25, uu), mx, 65535, emx)) : + {Nat.is_le(25n, mn) == True{} : Bool}} + +hle = {Equal.trans(Bool, Nat.is_le(xn, mn), U32.is_le(ll, mx), False{}, Equal.sym(Bool, U32.is_le(ll, mx), + Nat.is_le(xn, mn), R.u32_le(ll, mx)), Equal.trans(Bool, U32.is_le(ll, mx), U32.is_le(ll, 65535), False{}, + Equal.cong(U32, Bool, uu => U32.is_le(ll, uu), mx, 65535, emx), hbig)) : {Nat.is_le(xn, mn) == False{} : Bool}} + +h5x = {R.le_rw_l(ln, xn, Nat.mul(aa, 5n), Equal.sym(Nat, xn, ln, hn), h5) : {Nat.is_le(xn, Nat.mul(aa, 5n)) == + True{} : Bool}} + +k1 = {kb(kn, xn, mn, aa, nb.k(ll, mx, emx), h5x, hm, nle.lt(xn, mn, hle)) : {Nat.is_le(Nat.add(Nat.add(xn, + Nat.mul(kn, 5n)), 6n), Nat.mul(8n, aa)) == True{} : Bool}} + R.le_rw_r(Nat.add(Nat.add(ln, Nat.mul(kn, 5n)), 6n), Nat.mul(8n, aa), U32.to_nat(tu), Equal.sym(Nat, U32.to_nat(tu), + Nat.mul(8n, aa), et), R.le_rw_l(Nat.add(Nat.add(xn, Nat.mul(kn, 5n)), 6n), Nat.add(Nat.add(ln, Nat.mul(kn, 5n)), + 6n), Nat.mul(8n, aa), Equal.cong(Nat, Nat, zz => Nat.add(Nat.add(zz, Nat.mul(kn, 5n)), 6n), xn, ln, hn), k1)) + +# w k, taken in a word, does not wrap when h (1 + w k) is at most a word's value +def nb.em( + +ww: U32, + +op: Bool, + +wp: Nat, + +hp: Nat, + +cap: U32, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +h_n: {Nat.is_le(Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))), U32.to_nat(cap)) == True{} : Bool} +) -> {U32.to_nat(U32.mul(ww, Png.enc.nch(op))) == Nat.mul(U32.to_nat(ww), U32.to_nat(Png.enc.nch(op))) : Nat}: + +kk = Laws.spec.nch(op) + +wk = Nat.mul(1n+wp, kk) + +cn = U32.to_nat(cap) + +nc = Png.enc.nch(op) + +h_y = {R.le_add_r(1n+wk, Nat.mul(hp, 1n+wk), cn, h_n) : {Nat.is_le(1n+wk, cn) == True{} : Bool}} + +h_wk = {R.le_trans(wk, 1n+wk, cn, W9.le.succ(wk), h_y) : {Nat.is_le(wk, cn) == True{} : Bool}} + +e_m1n = {Equal.trans(Nat, Nat.mul(U32.to_nat(ww), U32.to_nat(nc)), Nat.mul(1n+wp, U32.to_nat(nc)), wk, + Equal.cong(Nat, Nat, xx => Nat.mul(xx, U32.to_nat(nc)), U32.to_nat(ww), 1n+wp, e_w), Equal.cong(Nat, Nat, xx => + Nat.mul(1n+wp, xx), U32.to_nat(nc), kk, W9.nch.val(op))) : {Nat.mul(U32.to_nat(ww), U32.to_nat(nc)) == wk : Nat}} + R.u32_mul_below(ww, nc, cap, R.le_rw_l(wk, Nat.mul(U32.to_nat(ww), U32.to_nat(nc)), cn, Equal.sym(Nat, + Nat.mul(U32.to_nat(ww), U32.to_nat(nc)), wk, e_m1n), h_wk)) + +# the filtered byte count, taken in a word, is h (1 + w k) when that is at most a word's value +def nb.val( + +ww: U32, + +hh: U32, + +op: Bool, + +wp: Nat, + +hp: Nat, + +cap: U32, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_h: {U32.to_nat(hh) == 1n+hp : Nat}, + +h_n: {Nat.is_le(Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))), U32.to_nat(cap)) == True{} : Bool} +) -> {U32.to_nat(Png.enc.nbytes(op, ww, hh)) == Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))) : Nat}: + +kk = Laws.spec.nch(op) + +wk = Nat.mul(1n+wp, kk) + +nn = Nat.mul(1n+hp, 1n+wk) + +cn = U32.to_nat(cap) + +nc = Png.enc.nch(op) + +m1 = U32.mul(ww, nc) + +h_y = {R.le_add_r(1n+wk, Nat.mul(hp, 1n+wk), cn, h_n) : {Nat.is_le(1n+wk, cn) == True{} : Bool}} + +e_m1n = {Equal.trans(Nat, Nat.mul(U32.to_nat(ww), U32.to_nat(nc)), Nat.mul(1n+wp, U32.to_nat(nc)), wk, + Equal.cong(Nat, Nat, xx => Nat.mul(xx, U32.to_nat(nc)), U32.to_nat(ww), 1n+wp, e_w), Equal.cong(Nat, Nat, xx => + Nat.mul(1n+wp, xx), U32.to_nat(nc), kk, W9.nch.val(op))) : {Nat.mul(U32.to_nat(ww), U32.to_nat(nc)) == wk : Nat}} + +t1 = {Equal.trans(Nat, U32.to_nat(m1), Nat.mul(U32.to_nat(ww), U32.to_nat(nc)), wk, nb.em(ww, op, wp, hp, cap, e_w, + h_n), e_m1n) : {U32.to_nat(m1) == wk : Nat}} + +x1 = U32.add(m1, 1) + +e_x = {Equal.trans(Nat, Nat.add(U32.to_nat(m1), 1n), Nat.add(wk, 1n), 1n+wk, Equal.cong(Nat, Nat, xx => Nat.add(xx, + 1n), U32.to_nat(m1), wk, t1), W9.add.one.nat(wk)) : {Nat.add(U32.to_nat(m1), 1n) == 1n+wk : Nat}} + +t2 = {Equal.trans(Nat, U32.to_nat(x1), Nat.add(U32.to_nat(m1), 1n), 1n+wk, R.u32_add_below(m1, 1, cap, + R.le_rw_l(1n+wk, Nat.add(U32.to_nat(m1), 1n), cn, Equal.sym(Nat, Nat.add(U32.to_nat(m1), 1n), 1n+wk, e_x), h_y)), + e_x) : {U32.to_nat(x1) == 1n+wk : Nat}} + +e_3 = {Equal.trans(Nat, Nat.mul(U32.to_nat(hh), U32.to_nat(x1)), Nat.mul(1n+hp, U32.to_nat(x1)), nn, Equal.cong(Nat, + Nat, xx => Nat.mul(xx, U32.to_nat(x1)), U32.to_nat(hh), 1n+hp, e_h), Equal.cong(Nat, Nat, xx => Nat.mul(1n+hp, xx), + U32.to_nat(x1), 1n+wk, t2)) : {Nat.mul(U32.to_nat(hh), U32.to_nat(x1)) == nn : Nat}} + Equal.trans(Nat, U32.to_nat(U32.mul(hh, x1)), Nat.mul(U32.to_nat(hh), U32.to_nat(x1)), nn, R.u32_mul_below(hh, x1, + cap, R.le_rw_l(nn, Nat.mul(U32.to_nat(hh), U32.to_nat(x1)), cn, Equal.sym(Nat, Nat.mul(U32.to_nat(hh), + U32.to_nat(x1)), nn, e_3), h_n)), e_3) + +# not at most: above +def gt.nle(cc: Cmp, +hh: {Cmp.is_le(cc) == False{} : Bool}) -> {Cmp.is_gt(cc) == True{} : Bool}: + match cc: + case LT{}: + Empty.absurd({Cmp.is_gt(LT{}) == True{} : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hh))) + case EQ{}: + Empty.absurd({Cmp.is_gt(EQ{}) == True{} : Bool}, U32L.false_true(Equal.sym(Bool, True{}, False{}, hh))) + case GT{}: + {==} + + +# the raw scanline list and its count, as the encoder builds them: the scanlines and their length +def raw.pair( + +px: List<&2, U32>, + +ww: U32, + +wp: Nat, + +op: Bool, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat} +) -> {Png.enc.raw(px, 0n, U32.to_nat(ww), op, [], 0) == (W9.sc(px, 0n, 1n+wp, op), Png.enc.len(W9.sc(px, 0n, 1n+wp, + op), 0)) : List<&2, U32> & U32}: + +ss = W9.sc(px, 0n, 1n+wp, op) + +ll = Png.enc.len(ss, 0) + +r0 = List.reverse(&2, U32, List.reverse.go(&2, U32, ss, [])) + +m0 = W9.cnt(px, 0n, 1n+wp, op, 0) + +ls = List.length(&2, U32, ss) + +e_m0 = {Equal.trans(U32, m0, U32.from_nat(ls), ll, W9.cnt.word(px, 0n, 1n+wp, op, 0n), Equal.sym(U32, ll, + U32.from_nat(ls), W9.len.word(ss))) : {m0 == ll : U32}} + Equal.trans(List<&2, U32> & U32, Png.enc.raw(px, 0n, U32.to_nat(ww), op, [], 0), Png.enc.raw(px, 0n, 1n+wp, op, [], + 0), (ss, ll), + Equal.cong(Nat, List<&2, U32> & U32, kn => Png.enc.raw(px, 0n, kn, op, [], 0), U32.to_nat(ww), 1n+wp, e_w), + Equal.trans(List<&2, U32> & U32, Png.enc.raw(px, 0n, 1n+wp, op, [], 0), (r0, m0), (ss, ll), W9.raw.eq(px, 0n, + 1n+wp, op, [], 0), + Equal.trans(List<&2, U32> & U32, (r0, m0), (ss, m0), (ss, ll), + Equal.cong(List<&2, U32>, List<&2, U32> & U32, xs => (xs, m0), r0, ss, Wp2.rev_rev(ss)), + Equal.cong(U32, List<&2, U32> & U32, uu => (ss, uu), m0, ll, e_m0)))) + +# colour type 6 past one stored block: the wide layout is the one-block layout around the stored blocks of 65535 +# bytes. Both sides are stated stuck on a flag, since the IHDR's CRC over a symbolic width and height is slow to +# normalise; the flags are rewritten to True and False only for the step that unfolds the layouts +def core.f( + +zt: Bool, + +zf: Bool, + +ww: U32, + +hh: U32, + +ss: List<&2, U32>, + +et: {zt == True{} : Bool}, + +ef: {zf == False{} : Bool}, + +hn: {U32.to_nat(Png.enc.len(ss, 0)) == List.length(&2, U32, ss) : Nat}, + +hbig: {U32.is_le(Png.enc.len(ss, 0), 65535) == False{} : Bool}, + +hl: {Png.enc.idat.ln(Png.enc.len(ss, 0)) == Png.enc.len(Laws.zlib.stored(65535, ss), 0) : U32} +) -> {Png.enc.seal.at(zt, ww, hh, False{}, ss, Png.enc.len(ss, 0)) == Png.enc.seal.at(zf, ww, hh, False{}, ss, + Png.enc.len(ss, 0)) : List<&2, U32>}: + %Equal.sym(Bool, zt, True{}, et) : {Png.enc.seal.at(_, ww, hh, False{}, ss, Png.enc.len(ss, 0)) == Png.enc.seal.at(zf, + ww, hh, False{}, ss, Png.enc.len(ss, 0)) : List<&2, U32>} + %Equal.sym(Bool, zf, False{}, ef) : {Png.enc.seal.at(True{}, ww, hh, False{}, ss, Png.enc.len(ss, 0)) == + Png.enc.seal.at(_, ww, hh, False{}, ss, Png.enc.len(ss, 0)) : List<&2, U32>} + Equal.cong(List<&2, U32>, List<&2, U32>, tl => Png.enc.cat(Png.enc.sig(), Png.enc.cat(Png.enc.chunk(Png.tag.ihdr(), + Png.enc.ihdr(ww, hh, Png.enc.ct(False{}))), tl)), + Png.enc.seal.body(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, + Png.enc.cat.go(Png.enc.be(Png.enc.idat.ln(Png.enc.len(ss, 0))), [])), ss, Png.enc.len(ss, 0), Inf.adler.of(ss), + Png.enc.chunk(Png.tag.iend(), [])), + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), Laws.zlib.stored(65535, ss)), Png.enc.chunk(Png.tag.iend(), [])), + wide.tail(ss, 65535, Png.enc.chunk(Png.tag.iend(), []), {==}, hn, hbig, hl)) + +# colour type 2 past one stored block, written from the samples: the one-block layout around the stored blocks of +# 65535 bytes, stated stuck on flags as core.f is +def core.t( + +zo: Bool, + +zf: Bool, + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +wp: Nat, + +tu: U32, + +eo: {zo == True{} : Bool}, + +ef: {zf == False{} : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +hn: {U32.to_nat(Png.enc.len(sco(px, wp, True{}), 0)) == List.length(&2, U32, sco(px, wp, True{})) : Nat}, + +hbig: {U32.is_le(Png.enc.len(sco(px, wp, True{}), 0), 65535) == False{} : Bool}, + +hby: {Laws.bytes(sco(px, wp, True{})) == True{} : Bool}, + +h_tu: {Nat.is_le(kzs(sco(px, wp, True{})), U32.to_nat(tu)) == True{} : Bool} +) -> {Png.enc.paint.wide(zo, ww, hh, px, Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0)) == Png.enc.seal.at(zf, ww, hh, + zo, W9.sc(px, 0n, 1n+wp, True{}), Png.enc.len(W9.sc(px, 0n, 1n+wp, True{}), 0)) : List<&2, U32>}: + +ss = W9.sc(px, 0n, 1n+wp, True{}) + +ll = Png.enc.len(ss, 0) + +ie = Png.enc.chunk(Png.tag.iend(), []) + +hl = idat.len(ss, 65535, tu, {==}, hn, hbig, h_tu) + %Equal.sym(Bool, zo, True{}, eo) : {Png.enc.paint.wide(_, ww, hh, px, ll) == Png.enc.seal.at(zf, ww, hh, _, ss, ll) : + List<&2, U32>} + %Equal.sym(Bool, zf, False{}, ef) : {Png.enc.paint.wide(True{}, ww, hh, px, ll) == Png.enc.seal.at(_, ww, hh, True{}, + ss, ll) : List<&2, U32>} + Equal.cong(List<&2, U32>, List<&2, U32>, tl => Png.enc.cat(Png.enc.sig(), Png.enc.cat(Png.enc.chunk(Png.tag.ihdr(), + Png.enc.ihdr(ww, hh, Png.enc.ct(True{}))), tl)), + Png.enc.wide.rgb.go(Png.enc.crc.list(Png.enc.be(Png.tag.idat()), 4294967295, + Png.enc.cat.go(Png.enc.be(Png.enc.idat.ln(ll)), [])), px, ww, ll, ie), + Png.enc.cat(Png.enc.chunk(Png.tag.idat(), Laws.zlib.stored(65535, ss)), ie), + rgb.tail(px, ww, wp, 65535, 65521, tu, ie, {==}, {==}, e_w, hn, hbig, hby, hl, h_tu)) + +# the wide encodings, colour type 2 from the samples and colour type 6 from the raw list, are the one-block layout +# around the stored blocks of 65535 bytes. The layout is stated stuck on zf, which is False, and on zo, which is op +def wide.op( + op: Bool, + +zo: Bool, + +zf: Bool, + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +wp: Nat, + +nb: U32, + +tu: U32, + +eo: {zo == op : Bool}, + +ef: {zf == False{} : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_nb: {nb == Png.enc.len(W9.sc(px, 0n, 1n+wp, op), 0) : U32}, + +hn: {U32.to_nat(Png.enc.len(sco(px, wp, op), 0)) == List.length(&2, U32, sco(px, wp, op)) : Nat}, + +hbig: {U32.is_le(Png.enc.len(sco(px, wp, op), 0), 65535) == False{} : Bool}, + +hby: {Laws.bytes(sco(px, wp, op)) == True{} : Bool}, + +h_tu: {Nat.is_le(kzs(sco(px, wp, op)), U32.to_nat(tu)) == True{} : Bool} +) -> {Png.enc.paint.wide(zo, ww, hh, px, nb) == Png.enc.seal.at(zf, ww, hh, zo, W9.sc(px, 0n, 1n+wp, op), + Png.enc.len(W9.sc(px, 0n, 1n+wp, op), 0)) : List<&2, U32>}: + match op: + case True{}: + +ss = W9.sc(px, 0n, 1n+wp, True{}) + +ll = Png.enc.len(ss, 0) + Equal.trans(List<&2, U32>, Png.enc.paint.wide(zo, ww, hh, px, nb), Png.enc.paint.wide(zo, ww, hh, px, ll), + Png.enc.seal.at(zf, ww, hh, zo, ss, ll), + Equal.cong(U32, List<&2, U32>, uu => Png.enc.paint.wide(zo, ww, hh, px, uu), nb, ll, e_nb), + core.t(zo, zf, ww, hh, px, wp, tu, eo, ef, e_w, hn, hbig, hby, h_tu)) + case False{}: + +ss = W9.sc(px, 0n, 1n+wp, False{}) + +ll = Png.enc.len(ss, 0) + +hl = idat.len(ss, 65535, tu, {==}, hn, hbig, h_tu) + +hg = {gt.nle(U32.cmp(ll, 65535), hbig) : {U32.is_gt(ll, 65535) == True{} : Bool}} + %Equal.sym(Bool, zo, False{}, eo) : {Png.enc.paint.wide(_, ww, hh, px, nb) == Png.enc.seal.at(zf, ww, hh, _, ss, + ll) : List<&2, U32>} + Equal.trans(List<&2, U32>, Png.enc.paint.wide(False{}, ww, hh, px, nb), Png.enc.seal(ww, hh, False{}, (ss, ll)), + Png.enc.seal.at(zf, ww, hh, False{}, ss, ll), + Equal.cong(List<&2, U32> & U32, List<&2, U32>, pr => Png.enc.seal(ww, hh, False{}, pr), Png.enc.raw(px, 0n, + U32.to_nat(ww), False{}, [], 0), (ss, ll), raw.pair(px, ww, wp, False{}, e_w)), + core.f(U32.is_gt(ll, 65535), zf, ww, hh, ss, hg, ef, hn, hbig, hl)) + +# whether every sample is opaque, as the encoder asks +def opq(+px: List<&2, U32>) -> Bool: + Png.enc.opaque(px, True{}) + +# the scanline byte count h (1 + w k), for 1 + h' rows of 1 + w' pixels of the encoder's channels +def snn(+hp: Nat, +wp: Nat, op: Bool) -> Nat: + Nat.mul(1n+hp, 1n+Nat.mul(1n+wp, Laws.spec.nch(op))) + +# a picture past one stored block: its encoding is the one-block layout around the stored blocks of 65535 bytes, +# the layout stated stuck on zf, which is False +def wide.rt( + +zf: Bool, + +ww: U32, + +hh: U32, + +px: List<&2, U32>, + +wp: Nat, + +tu: U32, + +ef: {zf == False{} : Bool}, + e_good: {Png.enc.good(ww, hh, px) == True{} : Bool}, + +e_w: {U32.to_nat(ww) == 1n+wp : Nat}, + +e_nb: {Png.enc.nbytes(opq(px), ww, hh) == Png.enc.len(sco(px, wp, opq(px)), 0) : U32}, + +hn: {U32.to_nat(Png.enc.len(sco(px, wp, opq(px)), 0)) == List.length(&2, U32, sco(px, wp, opq(px))) : Nat}, + +hbig: {U32.is_le(Png.enc.len(sco(px, wp, opq(px)), 0), 65535) == False{} : Bool}, + +hby: {Laws.bytes(sco(px, wp, opq(px))) == True{} : Bool}, + +h_tu: {Nat.is_le(kzs(sco(px, wp, opq(px))), U32.to_nat(tu)) == True{} : Bool} +) -> {Png.enc.open(Png.enc.good(ww, hh, px), ww, hh, px) == Some{Png.enc.seal.at(zf, ww, hh, Png.enc.opaque(px, + True{}), W9.sc(px, 0n, 1n+wp, Png.enc.opaque(px, True{})), Png.enc.len(W9.sc(px, 0n, 1n+wp, Png.enc.opaque(px, + True{})), 0))} : Maybe<&2, List<&2, U32>>}: + +op = Png.enc.opaque(px, True{}) + +nb = Png.enc.nbytes(op, ww, hh) + +ss = W9.sc(px, 0n, 1n+wp, op) + +ll = Png.enc.len(ss, 0) + +so = Png.enc.seal.at(zf, ww, hh, op, ss, ll) + +hg = {Equal.trans(Bool, U32.is_gt(nb, 65535), U32.is_gt(ll, 65535), True{}, Equal.cong(U32, Bool, uu => + U32.is_gt(uu, 65535), nb, ll, e_nb), gt.nle(U32.cmp(ll, 65535), hbig)) : {U32.is_gt(nb, 65535) == True{} : Bool}} + Equal.trans(Maybe<&2, List<&2, U32>>, Png.enc.open(Png.enc.good(ww, hh, px), ww, hh, px), Png.enc.open(True{}, ww, + hh, px), Some{so}, + Equal.cong(Bool, Maybe<&2, List<&2, U32>>, zb => Png.enc.open(zb, ww, hh, px), Png.enc.good(ww, hh, px), True{}, + e_good), + Equal.trans(Maybe<&2, List<&2, U32>>, Png.enc.open(True{}, ww, hh, px), Some{Png.enc.paint.at(True{}, ww, hh, op, + px, nb)}, Some{so}, + Equal.cong(Bool, Maybe<&2, List<&2, U32>>, zb => Some{Png.enc.paint.at(zb, ww, hh, op, px, nb)}, U32.is_gt(nb, + 65535), True{}, hg), + Equal.cong(List<&2, U32>, Maybe<&2, List<&2, U32>>, xs => Some{xs}, Png.enc.paint.wide(op, ww, hh, px, nb), so, + wide.op(op, op, zf, ww, hh, px, wp, nb, tu, {==}, ef, e_w, e_nb, hn, hbig, hby, h_tu)))) From 92d39374ac8a8501ac914dcf81265f9490995255 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 03:10:53 +0000 Subject: [PATCH 4/4] docs: record WP11 in the law inventory Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A1bVZYFbhKkn2BKHKthcVP --- docs/rfc/ezimg-law-inventory.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/rfc/ezimg-law-inventory.md b/docs/rfc/ezimg-law-inventory.md index 3225c96..ae95d69 100644 --- a/docs/rfc/ezimg-law-inventory.md +++ b/docs/rfc/ezimg-law-inventory.md @@ -331,4 +331,5 @@ requirement depends on. | WP9, PNG round trip (IMG-PNG-2, IMG-PNG-9 lift) | done, both partial; IMG-PNG-2 false as worded past 2^32 scanline bytes (decision) | `png_walk` lifts the pixel stage to `decode_png`: a file of the signature, IHDR, PLTE and tRNS where allowed, any IDAT chunks and IEND, each chunk framed (`spec.chunk`: length, type, data, `crc.ref`) and shorter than 2^32 bytes, decodes to the raster `px.of` packs from `Png.unfilter` of the concatenated IDAT data inflated, with the IHDR colour type and the PLTE and tRNS data. `png_roundtrip_one` proves IMG-PNG-2 for every raster `png_ok` accepts whose scanlines fit one stored block (at most 65535 bytes): the encoder's file is `spec.png` with one IDAT (`seal.one.same`), then `png_walk`, `inflate_enc_zlib`, `unfilter_filter` with filter None, and `png_px_rgb` / `png_px_rgba` with the samples read back bit by bit (`be.back`: `be.u32` of `spec.be4`'s bytes is the word, 32 bits taken apart and 24 `Bool.or(b, False)` rewrites). Code, byte-identical on the probe outputs: `enc.r`, `enc.g`, `enc.b` mask with the constant first. Lemmas in `proof/wp9-png-roundtrip.bend`. Mutants (IDAT data appended in the wrong order, PLTE kept reversed, tRNS dropped at finish, IHDR width and height swapped, green written for blue, filter byte 1, alpha written 255): each fails the gate. Left: the wide paths (`enc.seal.wide` / `enc.pour`, `enc.wide.rgb` / `enc.rgb.go`), ancillary chunks for IMG-PNG-9, and the row's wording: `enc.nbytes` and the IDAT length are U32s, so a 32768 by 32768 raster with one non-opaque sample (2^30 samples) counts 32768 scanline bytes and takes the one-block path with a wrong LEN | | WP10, JPEG placement and the round trip's structure (IMG-JPG-2, IMG-JPG-3) | done, both partial; IMG-JPG-2 false as worded above 2^31 points | IMG-JPG-2: `jpeg_block_cover_all` (every sample size, 4 by 4 included, onto any plane), `jpeg_mcu_grid_comp` (the A.2.3 grid for any scan component), `jpeg_refuse_factor1_any`, `jpeg_refuse_factor3_any` (fill bytes before the marker, a length longer than the components), `jpeg_refuse_count` (any other component count), `jpeg_points_at` (sample k of a plane's read-out is `Array.get` at k), `jpeg_walk_frame` (the decoder's own walk visits every MCU in raster order and each MCU's units in T.81 order, no counter wrapping) and `jpeg_walk_count` (the U32 block count `decode.nblocks` is that order's length when it fits). IMG-JPG-3: `jpeg_enc_stuffed`, `jpeg_unstuff` (the bit reader reads stuffed bytes back, eight bits at a time), `jpeg_enc_header_walk`, `jpeg_ent_walk`, `jpeg_round_trip_scan` (`decode_jpeg(encode_jpeg(r))` is the scan decode of the encoder's entropy-coded bytes in `r`'s frame), `jpeg_run_sized`, `jpeg_round_trip_sized` (none or a raster of `r`'s size). Code, byte-identical on all probe outputs and on crafted fill, marker and truncation cases: block painting written by rows, columns and pixels as the law-side cover is (`decode.splat`), which also drops `jpeg_block_cover`'s 1024-write normalisation from the gate; `decode.emit` reads a plane point by point in order (`decode.points`); `decode.nbits` and the entropy walk compare bytes with `U32.is_eq`, and `decode.nbits` ors the new bit in first; the encoder keeps raw bytes and stuffs once at the flush (`encode.stuff.all`), and dispatches on its tag with `U32.is_eq`; the block count is named (`decode.nblocks`). Lemmas in `proof/wp10-jpeg-finish.bend`, among them `dup` (two copies of an array, each equal to it: proofs are live, so an array cannot go to two lemmas) and the MCU-walk runs (`run.units` to `run.rows`). Mutants: a block column at `col * ph`, a scan component's factors taken from frame component `comp`, factor 3 accepted, a component count of 2 accepted, the read-out starting at point 1, an MCU row skipped, the block count summed from 1, a 255 not stuffed, the SOF width's low byte masked with 254, a stuffed 0 dropped by the walk, the entropy bytes not reversed, a gray picture's sides swapped, a colour picture's height as its width, a stuffed 255 read as 254: each fails its law or that law's lemma. Left: IMG-JPG-2's `Array.get` after `Array.set` lemmas, and the row is false for frames above 2^31 points (`decode.plane`'s depth wraps; decision); IMG-JPG-3's Huffman round trip, that `decode.run` of the encoder's bytes is not none. Gate about 4 m 20 s, main's 4 m 50 s | | WP13, JPEG planes (IMG-JPG-2) | done; IMG-JPG-2 proved | `jpeg_get_set` (`Array.get` at an index finds what the last `Array.set` there wrote, in any array) and `jpeg_get_set_other` (on a perfect binary tree of 2^d leaves, d below 32, a set at one index below 2^d leaves what `Array.get` finds at another): the lemmas mirror an array as a data tree (`W13.Tr`, so a proof can use it twice), follow the index as `Array.swap.go` and `Array.get.go` walk it, and show the mask `i & (2^d - 1)` is `i` below 2^d (`mask_w`, the size of a perfect tree being the word of bit d, `size_bits`). `jpeg_plane_depth`: for 1 to 2^d points, d at most 31, `decode.depth` is below 32 and its 2^depth leaves are at least the points, the U32 shl wrap at exactly 2^31 points included (a bound on U32.log2 from below and above, `le1`, `le2`). `jpeg_paint_at`: painting a block onto such a plane leaves at pixel (x, y), point y * w + x, the sample whose pw by ph pixels take it in, the last in the block's order, else the old value (`jpg.block.at`). `jpeg_blocks_paint`: `decode.blocks` paints the k-th unit it decodes at `decode.geom` of the k-th place of its walk (`jpg.trace`) onto its component's plane. `jpeg_plane_at`: a plane after those units, read at (x, y), is `jpg.point`. `jpeg_place` composes them over `decode_jpeg`: for a frame of at most 2^31 points, pixel (x, y) of any raster it returns is gray of Y, or rgb of Y, Cb and Cr, each `jpg.point` over the decoded units from a zero plane; with `jpeg_walk_frame` (the walk is T.81 A.2.3's order), `jpeg_mcu_grid_comp` (each unit's A.2.3 grid place and sample size) and `jpeg_paint_at` (replication) that is the row. Where samples of different units would cover one pixel the later one shows; A.2.3's grid tiles the frame so none do, and that tiling arithmetic is not itself a law. Code, byte-identical on every probe: `decode.depth` tests zero with `U32.is_eq` instead of a literal pattern (`decode.depth.of`). Big Nat constants never appear in a checked type: the checker normalises `Nat.pow(2n, 32n)` even against itself, so the bound is `w * h <= 2^d, d <= 31`. Mutants: a pixel written one point on, the depth from nn - 1, Cb painted with component 2's units, a block of another component painted too, Cb and Cr swapped in the colour pass: each fails its law's proof; an `Array.set` one index on fails `jpeg_get_set` and one that also writes the next index fails `jpeg_get_set_other` on a concrete plane. Gate about 4 m 17 s, main's 4 m 25 s | +| WP11, PNG round trip past one block and ancillary chunks (IMG-PNG-2, IMG-PNG-9, IMG-PIX-1) | done; IMG-PNG-2 proved after rewording, IMG-PNG-9 and IMG-PIX-1 proved | IMG-PNG-2 reworded to rasters of fewer than 2^29 samples (the bound is a U32 witness `a8` whose value is `8 w h`), and `png_roundtrip` proves it: below 65536 scanline bytes through `png_roundtrip_one`, above it through the two wide paths. Colour type 6 (`enc.seal.wide`, `enc.pour`): `pour.bs` and the `sim` simulation against `enc.feed` give `zlib.stored(65535, raw)` with the IDAT CRC (`wide.tail`); colour type 2 (`enc.wide.rgb`, `enc.rgb.go`): the `rg` simulation with fuel `n + 2k + 1` bytes, `afold.adler` (the running Adler sums are `Inf.adler.of`) and `rgb.tail` give the same chunk. The block count `enc.nblk` is ceil(n / 65535) by U32 div and mod (`nb.k`), the IDAT length `n + 5k + 6` does not wrap (`idat.len`, `tu.ok`: `n <= 5 w h` and `n + 5k + 6 <= 8 w h`), and `rt.tail`, the one-block proof's pixel stage, now shared by both paths. IMG-PNG-9 and the PNG side of IMG-PIX-1: `png_walk_anc` extends `png_walk` to ancillary chunks after IHDR, between PLTE and tRNS, after them and after the IDAT chunks (`anc.walk`: the walker skips each, closing the IDAT run), and to tRNS before PLTE, the one other order the decoder takes (colour type 2); with trailing bytes, a second IHDR, PLTE or tRNS, a critical unknown chunk or an IDAT after the run refused, these are every file `decode_png` accepts. No code change. Lemmas in `proof/wp11-png-finish.bend`; the IHDR's CRC over a symbolic width and height is slow to normalise, so the wide proofs state the layout stuck on flags (`core.f`, `core.t`, `wide.rt`) and unfold it once. Mutants: a stored block's NLEN high byte from LEN in `enc.pour`, colour type 2's Adler B sum missing a byte in `enc.rgb.go`, `enc.nblk` adding 2 for a partial block, the ancillary bit read as bit 4, and PLTE refused after tRNS: each fails its lemma (`pour.bs`, `rg`, `nb.at`, `anc.step`, `plte.late`). No row is known to be false. Gate about 6 m 40 s, main's 4 m 30 s (the W11 lemmas check in about 2 m 30 s, the W9 import included) | | Phase 4b, cheap rows | next | IMG-PNG-3, IMG-PNG-8, IMG-JPG-1, IMG-RAS-1, IMG-RAS-2; these need ordering and product lemmas on U32 (`is_lt`, `is_le`, `*` without wrap) next to `ueq` |