PROOF.bend

bend-osdev-cipher-modes@0.1.0.0 · 1,953 lines · 170 definitions

1import Base
2import bend-osdev-bytes@0.1.0.0/bytes.bend as B
3import bend-osdev-bytes@0.1.0.0/LAWS.bend as BL
4import bend-osdev-bytes@0.1.0.0/PROOF.bend as BP
5import bend-osdev-word64@0.1.0.0/word64.bend as W
6import bend-osdev-cipher-modes@0.1.0.0/cipher_modes.bend as M
7import bend-osdev-cipher-modes@0.1.0.0/aes.bend as X
8import bend-osdev-cipher-modes@0.1.0.0/pkcs7.bend as P
9import bend-osdev-cipher-modes@0.1.0.0/cbc.bend as C
10import bend-osdev-cipher-modes@0.1.0.0/xts.bend as T
11import bend-osdev-cipher-modes@0.1.0.0/ccm.bend as CC
12import bend-osdev-cipher-modes@0.1.0.0/cmac.bend as CM
13import bend-osdev-cipher-modes@0.1.0.0/aes_modes.bend as D
14import bend-osdev-cipher-modes@0.1.0.0/LAWS.bend as Laws
15
16# How the proofs go. The modes work on blocks; the byte layer splits a byte
17# string into blocks and joins blocks back. The lemmas below show:
18#   * XOR with the same block twice is the identity (bit by bit);
19#   * a word split into bytes and joined back is the word, and the bytes of a
20#     joined word are the (masked) bytes (bit slicing, every bit symbolic);
21#   * splitting joined blocks gives the blocks back, and joining a split
22#     byte string gives it back (induction, 16 bytes at a time);
23#   * every to_list of an Octets is masked (the bytes interface laws
24#     octets_of_to and octets_to_of), so the bytes a mode reads back are the
25#     bytes it wrote.
26# Nothing here looks inside Octets: only the bytes laws and its list layer.
27
28# XOR
29
30def bx.bool(a: Bool, b: Bool) -> {Bool.xor(a, Bool.xor(a, b)) == b : Bool}:
31  match a b:
32    case False{} False{}:
33      {==}
34    case False{} True{}:
35      {==}
36    case True{} False{}:
37      {==}
38    case True{} True{}:
39      {==}
40
41def bx.word(n: Nat, a: Word(n), b: Word(n)) -> {Word.xor(n, a, Word.xor(n, a, b)) == b : Word(n)}:
42  match n:
43    case 0n:
44      match b:
45        case WNil{}:
46          {==}
47    case 1n+p:
48      match a b:
49        case WCon{ah, at} WCon{bh, bt}:
50          %bx.bool(ah, bh) : {WCon{Bool.xor(ah, Bool.xor(ah, bh)), Word.xor(p, at, Word.xor(p, at, bt))} == WCon{_, bt} : Word(1n+p)}
51          %bx.word(p, at, bt) : {WCon{Bool.xor(ah, Bool.xor(ah, bh)), Word.xor(p, at, Word.xor(p, at, bt))} == WCon{Bool.xor(ah, Bool.xor(ah, bh)), _} : Word(1n+p)}
52          {==}
53
54def bx.u32(a: U32, b: U32) -> {U32.xor(a, U32.xor(a, b)) == b : U32}:
55  match a b:
56    case U32{x} U32{y}:
57      %bx.word(32n, x, y) : {U32{Word.xor(32n, x, Word.xor(32n, x, y))} == U32{_} : U32}
58      {==}
59
60# xor(a, xor(a, b)) == b on blocks
61def bx.block(+a: M.CmBlock, +b: M.CmBlock) -> {M.CmBlock.xor(a, M.CmBlock.xor(a, b)) == b : M.CmBlock}:
62  match a b:
63    case M.CmBlock{a0, a1, a2, a3} M.CmBlock{b0, b1, b2, b3}:
64      %bx.u32(a0, b0) : {M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3})) == M.CmBlock{_, b1, b2, b3} : M.CmBlock}
65      %bx.u32(a1, b1) : {M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3})) == M.CmBlock{U32.xor(a0, U32.xor(a0, b0)), _, b2, b3} : M.CmBlock}
66      %bx.u32(a2, b2) : {M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3})) == M.CmBlock{U32.xor(a0, U32.xor(a0, b0)), U32.xor(a1, U32.xor(a1, b1)), _, b3} : M.CmBlock}
67      %bx.u32(a3, b3) : {M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3})) == M.CmBlock{U32.xor(a0, U32.xor(a0, b0)), U32.xor(a1, U32.xor(a1, b1)), U32.xor(a2, U32.xor(a2, b2)), _} : M.CmBlock}
68      {==}
69
70# Bits: each lemma splits its words into their 32 bits, so the slicing
71# computes
72
73def bits.word_bytes(w: U32) -> {M.cm.word(M.cm.b0(w), M.cm.b1(w), M.cm.b2(w), M.cm.b3(w)) == w : U32}:
74  match w:
75    case U32{WCon{w0, WCon{w1, WCon{w2, WCon{w3, WCon{w4, WCon{w5, WCon{w6, WCon{w7, WCon{w8, WCon{w9, WCon{w10, WCon{w11, WCon{w12, WCon{w13, WCon{w14, WCon{w15, WCon{w16, WCon{w17, WCon{w18, WCon{w19, WCon{w20, WCon{w21, WCon{w22, WCon{w23, WCon{w24, WCon{w25, WCon{w26, WCon{w27, WCon{w28, WCon{w29, WCon{w30, WCon{w31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
76      {==}
77
78def bits.byte0_word(a: U32, b: U32, c: U32, d: U32) -> {M.cm.b0(M.cm.word(a, b, c, d)) == B.byte(a) : U32}:
79  match a b c d:
80    case U32{WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WCon{a8, WCon{a9, WCon{a10, WCon{a11, WCon{a12, WCon{a13, WCon{a14, WCon{a15, WCon{a16, WCon{a17, WCon{a18, WCon{a19, WCon{a20, WCon{a21, WCon{a22, WCon{a23, WCon{a24, WCon{a25, WCon{a26, WCon{a27, WCon{a28, WCon{a29, WCon{a30, WCon{a31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{b0, WCon{b1, WCon{b2, WCon{b3, WCon{b4, WCon{b5, WCon{b6, WCon{b7, WCon{b8, WCon{b9, WCon{b10, WCon{b11, WCon{b12, WCon{b13, WCon{b14, WCon{b15, WCon{b16, WCon{b17, WCon{b18, WCon{b19, WCon{b20, WCon{b21, WCon{b22, WCon{b23, WCon{b24, WCon{b25, WCon{b26, WCon{b27, WCon{b28, WCon{b29, WCon{b30, WCon{b31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{c0, WCon{c1, WCon{c2, WCon{c3, WCon{c4, WCon{c5, WCon{c6, WCon{c7, WCon{c8, WCon{c9, WCon{c10, WCon{c11, WCon{c12, WCon{c13, WCon{c14, WCon{c15, WCon{c16, WCon{c17, WCon{c18, WCon{c19, WCon{c20, WCon{c21, WCon{c22, WCon{c23, WCon{c24, WCon{c25, WCon{c26, WCon{c27, WCon{c28, WCon{c29, WCon{c30, WCon{c31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{d0, WCon{d1, WCon{d2, WCon{d3, WCon{d4, WCon{d5, WCon{d6, WCon{d7, WCon{d8, WCon{d9, WCon{d10, WCon{d11, WCon{d12, WCon{d13, WCon{d14, WCon{d15, WCon{d16, WCon{d17, WCon{d18, WCon{d19, WCon{d20, WCon{d21, WCon{d22, WCon{d23, WCon{d24, WCon{d25, WCon{d26, WCon{d27, WCon{d28, WCon{d29, WCon{d30, WCon{d31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
81      {==}
82
83def bits.byte1_word(a: U32, b: U32, c: U32, d: U32) -> {M.cm.b1(M.cm.word(a, b, c, d)) == B.byte(b) : U32}:
84  match a b c d:
85    case U32{WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WCon{a8, WCon{a9, WCon{a10, WCon{a11, WCon{a12, WCon{a13, WCon{a14, WCon{a15, WCon{a16, WCon{a17, WCon{a18, WCon{a19, WCon{a20, WCon{a21, WCon{a22, WCon{a23, WCon{a24, WCon{a25, WCon{a26, WCon{a27, WCon{a28, WCon{a29, WCon{a30, WCon{a31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{b0, WCon{b1, WCon{b2, WCon{b3, WCon{b4, WCon{b5, WCon{b6, WCon{b7, WCon{b8, WCon{b9, WCon{b10, WCon{b11, WCon{b12, WCon{b13, WCon{b14, WCon{b15, WCon{b16, WCon{b17, WCon{b18, WCon{b19, WCon{b20, WCon{b21, WCon{b22, WCon{b23, WCon{b24, WCon{b25, WCon{b26, WCon{b27, WCon{b28, WCon{b29, WCon{b30, WCon{b31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{c0, WCon{c1, WCon{c2, WCon{c3, WCon{c4, WCon{c5, WCon{c6, WCon{c7, WCon{c8, WCon{c9, WCon{c10, WCon{c11, WCon{c12, WCon{c13, WCon{c14, WCon{c15, WCon{c16, WCon{c17, WCon{c18, WCon{c19, WCon{c20, WCon{c21, WCon{c22, WCon{c23, WCon{c24, WCon{c25, WCon{c26, WCon{c27, WCon{c28, WCon{c29, WCon{c30, WCon{c31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{d0, WCon{d1, WCon{d2, WCon{d3, WCon{d4, WCon{d5, WCon{d6, WCon{d7, WCon{d8, WCon{d9, WCon{d10, WCon{d11, WCon{d12, WCon{d13, WCon{d14, WCon{d15, WCon{d16, WCon{d17, WCon{d18, WCon{d19, WCon{d20, WCon{d21, WCon{d22, WCon{d23, WCon{d24, WCon{d25, WCon{d26, WCon{d27, WCon{d28, WCon{d29, WCon{d30, WCon{d31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
86      {==}
87
88def bits.byte2_word(a: U32, b: U32, c: U32, d: U32) -> {M.cm.b2(M.cm.word(a, b, c, d)) == B.byte(c) : U32}:
89  match a b c d:
90    case U32{WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WCon{a8, WCon{a9, WCon{a10, WCon{a11, WCon{a12, WCon{a13, WCon{a14, WCon{a15, WCon{a16, WCon{a17, WCon{a18, WCon{a19, WCon{a20, WCon{a21, WCon{a22, WCon{a23, WCon{a24, WCon{a25, WCon{a26, WCon{a27, WCon{a28, WCon{a29, WCon{a30, WCon{a31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{b0, WCon{b1, WCon{b2, WCon{b3, WCon{b4, WCon{b5, WCon{b6, WCon{b7, WCon{b8, WCon{b9, WCon{b10, WCon{b11, WCon{b12, WCon{b13, WCon{b14, WCon{b15, WCon{b16, WCon{b17, WCon{b18, WCon{b19, WCon{b20, WCon{b21, WCon{b22, WCon{b23, WCon{b24, WCon{b25, WCon{b26, WCon{b27, WCon{b28, WCon{b29, WCon{b30, WCon{b31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{c0, WCon{c1, WCon{c2, WCon{c3, WCon{c4, WCon{c5, WCon{c6, WCon{c7, WCon{c8, WCon{c9, WCon{c10, WCon{c11, WCon{c12, WCon{c13, WCon{c14, WCon{c15, WCon{c16, WCon{c17, WCon{c18, WCon{c19, WCon{c20, WCon{c21, WCon{c22, WCon{c23, WCon{c24, WCon{c25, WCon{c26, WCon{c27, WCon{c28, WCon{c29, WCon{c30, WCon{c31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{d0, WCon{d1, WCon{d2, WCon{d3, WCon{d4, WCon{d5, WCon{d6, WCon{d7, WCon{d8, WCon{d9, WCon{d10, WCon{d11, WCon{d12, WCon{d13, WCon{d14, WCon{d15, WCon{d16, WCon{d17, WCon{d18, WCon{d19, WCon{d20, WCon{d21, WCon{d22, WCon{d23, WCon{d24, WCon{d25, WCon{d26, WCon{d27, WCon{d28, WCon{d29, WCon{d30, WCon{d31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
91      {==}
92
93def bits.byte3_word(a: U32, b: U32, c: U32, d: U32) -> {M.cm.b3(M.cm.word(a, b, c, d)) == B.byte(d) : U32}:
94  match a b c d:
95    case U32{WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WCon{a8, WCon{a9, WCon{a10, WCon{a11, WCon{a12, WCon{a13, WCon{a14, WCon{a15, WCon{a16, WCon{a17, WCon{a18, WCon{a19, WCon{a20, WCon{a21, WCon{a22, WCon{a23, WCon{a24, WCon{a25, WCon{a26, WCon{a27, WCon{a28, WCon{a29, WCon{a30, WCon{a31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{b0, WCon{b1, WCon{b2, WCon{b3, WCon{b4, WCon{b5, WCon{b6, WCon{b7, WCon{b8, WCon{b9, WCon{b10, WCon{b11, WCon{b12, WCon{b13, WCon{b14, WCon{b15, WCon{b16, WCon{b17, WCon{b18, WCon{b19, WCon{b20, WCon{b21, WCon{b22, WCon{b23, WCon{b24, WCon{b25, WCon{b26, WCon{b27, WCon{b28, WCon{b29, WCon{b30, WCon{b31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{c0, WCon{c1, WCon{c2, WCon{c3, WCon{c4, WCon{c5, WCon{c6, WCon{c7, WCon{c8, WCon{c9, WCon{c10, WCon{c11, WCon{c12, WCon{c13, WCon{c14, WCon{c15, WCon{c16, WCon{c17, WCon{c18, WCon{c19, WCon{c20, WCon{c21, WCon{c22, WCon{c23, WCon{c24, WCon{c25, WCon{c26, WCon{c27, WCon{c28, WCon{c29, WCon{c30, WCon{c31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{d0, WCon{d1, WCon{d2, WCon{d3, WCon{d4, WCon{d5, WCon{d6, WCon{d7, WCon{d8, WCon{d9, WCon{d10, WCon{d11, WCon{d12, WCon{d13, WCon{d14, WCon{d15, WCon{d16, WCon{d17, WCon{d18, WCon{d19, WCon{d20, WCon{d21, WCon{d22, WCon{d23, WCon{d24, WCon{d25, WCon{d26, WCon{d27, WCon{d28, WCon{d29, WCon{d30, WCon{d31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
96      {==}
97
98def bits.byte_b0(w: U32) -> {B.byte(M.cm.b0(w)) == M.cm.b0(w) : U32}:
99  match w:
100    case U32{WCon{w0, WCon{w1, WCon{w2, WCon{w3, WCon{w4, WCon{w5, WCon{w6, WCon{w7, WCon{w8, WCon{w9, WCon{w10, WCon{w11, WCon{w12, WCon{w13, WCon{w14, WCon{w15, WCon{w16, WCon{w17, WCon{w18, WCon{w19, WCon{w20, WCon{w21, WCon{w22, WCon{w23, WCon{w24, WCon{w25, WCon{w26, WCon{w27, WCon{w28, WCon{w29, WCon{w30, WCon{w31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
101      {==}
102
103def bits.byte_b1(w: U32) -> {B.byte(M.cm.b1(w)) == M.cm.b1(w) : U32}:
104  match w:
105    case U32{WCon{w0, WCon{w1, WCon{w2, WCon{w3, WCon{w4, WCon{w5, WCon{w6, WCon{w7, WCon{w8, WCon{w9, WCon{w10, WCon{w11, WCon{w12, WCon{w13, WCon{w14, WCon{w15, WCon{w16, WCon{w17, WCon{w18, WCon{w19, WCon{w20, WCon{w21, WCon{w22, WCon{w23, WCon{w24, WCon{w25, WCon{w26, WCon{w27, WCon{w28, WCon{w29, WCon{w30, WCon{w31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
106      {==}
107
108def bits.byte_b2(w: U32) -> {B.byte(M.cm.b2(w)) == M.cm.b2(w) : U32}:
109  match w:
110    case U32{WCon{w0, WCon{w1, WCon{w2, WCon{w3, WCon{w4, WCon{w5, WCon{w6, WCon{w7, WCon{w8, WCon{w9, WCon{w10, WCon{w11, WCon{w12, WCon{w13, WCon{w14, WCon{w15, WCon{w16, WCon{w17, WCon{w18, WCon{w19, WCon{w20, WCon{w21, WCon{w22, WCon{w23, WCon{w24, WCon{w25, WCon{w26, WCon{w27, WCon{w28, WCon{w29, WCon{w30, WCon{w31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
111      {==}
112
113def bits.byte_b3(w: U32) -> {B.byte(M.cm.b3(w)) == M.cm.b3(w) : U32}:
114  match w:
115    case U32{WCon{w0, WCon{w1, WCon{w2, WCon{w3, WCon{w4, WCon{w5, WCon{w6, WCon{w7, WCon{w8, WCon{w9, WCon{w10, WCon{w11, WCon{w12, WCon{w13, WCon{w14, WCon{w15, WCon{w16, WCon{w17, WCon{w18, WCon{w19, WCon{w20, WCon{w21, WCon{w22, WCon{w23, WCon{w24, WCon{w25, WCon{w26, WCon{w27, WCon{w28, WCon{w29, WCon{w30, WCon{w31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
116      {==}
117
118def bits.byte_byte(y: U32) -> {B.byte(B.byte(y)) == B.byte(y) : U32}:
119  match y:
120    case U32{WCon{y0, WCon{y1, WCon{y2, WCon{y3, WCon{y4, WCon{y5, WCon{y6, WCon{y7, WCon{y8, WCon{y9, WCon{y10, WCon{y11, WCon{y12, WCon{y13, WCon{y14, WCon{y15, WCon{y16, WCon{y17, WCon{y18, WCon{y19, WCon{y20, WCon{y21, WCon{y22, WCon{y23, WCon{y24, WCon{y25, WCon{y26, WCon{y27, WCon{y28, WCon{y29, WCon{y30, WCon{y31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
121      {==}
122# Splits
123
124def sp.cons_blocks(b: M.CmBlock, s: M.CmSplit) -> {M.cm.split.blocks(M.cm.split.cons(b, s)) == Con{b, M.cm.split.blocks(s)} : List<&2, M.CmBlock>}:
125  match s:
126    case M.CmSplit{bs, t}:
127      {==}
128
129def sp.cons_tail(b: M.CmBlock, s: M.CmSplit) -> {M.cm.split.tail(M.cm.split.cons(b, s)) == M.cm.split.tail(s) : List<&2, U32>}:
130  match s:
131    case M.CmSplit{bs, t}:
132      {==}
133
134def sp.eta(s: M.CmSplit) -> {M.CmSplit{M.cm.split.blocks(s), M.cm.split.tail(s)} == s : M.CmSplit}:
135  match s:
136    case M.CmSplit{bs, t}:
137      {==}
138
139# Arithmetic: n + 16 and n leave the same remainder mod 16
140
141def sp.disc(n: Nat) -> Type:
142  match n:
143    case 0n:
144      Empty
145    case 1n+p:
146      Unit
147
148def sp.absurd(p: Nat, h: {1n+p == 0n : Nat}) -> Empty:
149  %h : sp.disc(_)
150  Unit{}
151
152def sp.absurd_tail(p: Nat, xs: List<&2, U32>, h: {1n+p == 0n : Nat}) -> {M.cm.split.tail(M.cm.split(B.mask(xs))) == Nil{} : List<&2, U32>}:
153  Empty.absurd({M.cm.split.tail(M.cm.split(B.mask(xs))) == Nil{} : List<&2, U32>}, sp.absurd(p, h))
154
155def sp.snd_go(n: Nat, m: Nat, d1: Nat, d2: Nat, r: Nat) -> {Pair.snd(Nat, Nat, Nat.divmod.go(n, m, d1, r)) == Pair.snd(Nat, Nat, Nat.divmod.go(n, m, d2, r)) : Nat}:
156  match n:
157    case 0n:
158      {==}
159    case 1n+np:
160      match m:
161        case 0n:
162          sp.snd_go(np, r, 1n+d1, 1n+d2, 0n)
163        case 1n+mp:
164          sp.snd_go(np, mp, d1, d2, 1n+r)
165
166def sp.mod16(n: Nat) -> {Nat.mod(Nat.add(16n, n), 16n) == Nat.mod(n, 16n) : Nat}:
167  sp.snd_go(n, 15n, 1n, 0n, 0n)
168
169
170# Booleans: False is not True
171
172def bo.disc(b: Bool) -> Type:
173  match b:
174    case False{}:
175      Unit
176    case True{}:
177      Empty
178
179def bo.empty(h: {False{} == True{} : Bool}) -> Empty:
180  %h : bo.disc(_)
181  Unit{}
182
183def bo.absurd(-A: Type, h: {False{} == True{} : Bool}) -> A:
184  Empty.absurd(A, bo.empty(h))
185
186# Lists of bytes (the bytes list layer)
187
188def li.mask_mask(zs: List<&2, U32>) -> {B.mask(B.mask(zs)) == B.mask(zs) : List<&2, U32>}:
189  match zs:
190    case Nil{}:
191      {==}
192    case Con{+z, +t}:
193      %bits.byte_byte(z) : {Con{B.byte(B.byte(z)), B.mask(B.mask(t))} == Con{_, B.mask(t)} : List<&2, U32>}
194      %li.mask_mask(t) : {Con{B.byte(B.byte(z)), B.mask(B.mask(t))} == Con{B.byte(B.byte(z)), _} : List<&2, U32>}
195      {==}
196
197def li.take_append(+a: List<&2, U32>, +b: List<&2, U32>) -> {B.take(B.len(a), B.append(a, b)) == a : List<&2, U32>}:
198  match a:
199    case Nil{}:
200      {==}
201    case Con{+h, +t}:
202      %Equal.sym(List<&2, U32>, B.take(B.len(t), B.append(t, b)), t, li.take_append(t, b)) : {Con{h, _} == Con{h, t} : List<&2, U32>}
203      {==}
204
205def li.drop_append(+a: List<&2, U32>, +b: List<&2, U32>) -> {B.drop(B.len(a), B.append(a, b)) == b : List<&2, U32>}:
206  match a:
207    case Nil{}:
208      {==}
209    case Con{+h, +t}:
210      li.drop_append(t, b)
211
212def li.mask_append(+a: List<&2, U32>, +b: List<&2, U32>) -> {B.mask(B.append(a, b)) == B.append(B.mask(a), B.mask(b)) : List<&2, U32>}:
213  match a:
214    case Nil{}:
215      {==}
216    case Con{+h, +t}:
217      %li.mask_append(t, b) : {Con{B.byte(h), B.mask(B.append(t, b))} == Con{B.byte(h), _} : List<&2, U32>}
218      {==}
219
220def li.mask_drop(+n: Nat, +xs: List<&2, U32>) -> {B.mask(B.drop(n, xs)) == B.drop(n, B.mask(xs)) : List<&2, U32>}:
221  match n:
222    case 0n:
223      {==}
224    case 1n+p:
225      match xs:
226        case Nil{}:
227          {==}
228        case Con{+h, +t}:
229          li.mask_drop(p, t)
230
231def li.mask_take(+n: Nat, +xs: List<&2, U32>) -> {B.mask(B.take(n, xs)) == B.take(n, B.mask(xs)) : List<&2, U32>}:
232  match n:
233    case 0n:
234      {==}
235    case 1n+p:
236      match xs:
237        case Nil{}:
238          {==}
239        case Con{+h, +t}:
240          %li.mask_take(p, t) : {Con{B.byte(h), B.mask(B.take(p, t))} == Con{B.byte(h), _} : List<&2, U32>}
241          {==}
242
243def li.len_append(+a: List<&2, U32>, +b: List<&2, U32>) -> {B.len(B.append(a, b)) == Nat.add(B.len(a), B.len(b)) : Nat}:
244  match a:
245    case Nil{}:
246      {==}
247    case Con{+h, +t}:
248      %li.len_append(t, b) : {1n+B.len(B.append(t, b)) == 1n+_ : Nat}
249      {==}
250
251def li.len_drop(+n: Nat, +xs: List<&2, U32>) -> {B.len(B.drop(n, xs)) == Nat.sub(B.len(xs), n) : Nat}:
252  match n:
253    case 0n:
254      match xs:
255        case Nil{}:
256          {==}
257        case Con{+h, +t}:
258          {==}
259    case 1n+p:
260      match xs:
261        case Nil{}:
262          {==}
263        case Con{+h, +t}:
264          li.len_drop(p, t)
265
266def li.len_take(+n: Nat, +xs: List<&2, U32>) -> {Nat.is_le(n, B.len(xs)) == True{} : Bool} -> {B.len(B.take(n, xs)) == n : Nat}:
267  match n:
268    case 0n:
269      h => {==}
270    case 1n+p:
271      match xs:
272        case Nil{}:
273          h => bo.absurd({B.len(B.take(1n+p, Nil{})) == 1n+p : Nat}, h)
274        case Con{+x, +t}:
275          h => %li.len_take(p, t)(h) : {1n+B.len(B.take(p, t)) == 1n+_ : Nat}
276            {==}
277
278# Naturals
279
280def na.add_sub(+a: Nat, +b: Nat) -> {Nat.is_le(a, b) == True{} : Bool} -> {Nat.add(a, Nat.sub(b, a)) == b : Nat}:
281  match a b:
282    case 0n 0n:
283      h => {==}
284    case 0n 1n+bp:
285      h => {==}
286    case 1n+ap 0n:
287      h => bo.absurd({Nat.add(1n+ap, Nat.sub(0n, 1n+ap)) == 0n : Nat}, h)
288    case 1n+ap 1n+bp:
289      h => %na.add_sub(ap, bp)(h) : {1n+Nat.add(ap, Nat.sub(bp, ap)) == 1n+_ : Nat}
290        {==}
291
292def na.lt_le(+a: Nat, +b: Nat) -> {Nat.is_lt(a, b) == True{} : Bool} -> {Nat.is_le(a, b) == True{} : Bool}:
293  match a b:
294    case 0n 0n:
295      h => bo.absurd({Nat.is_le(0n, 0n) == True{} : Bool}, h)
296    case 0n 1n+bp:
297      h => {==}
298    case 1n+ap 0n:
299      h => bo.absurd({Nat.is_le(1n+ap, 0n) == True{} : Bool}, h)
300    case 1n+ap 1n+bp:
301      h => na.lt_le(ap, bp)(h)
302
303# Blocks in lists
304
305def sp.hd(bs: List<&2, M.CmBlock>) -> M.CmBlock:
306  match bs:
307    case Nil{}:
308      M.CmBlock.zero()
309    case Con{b, t}:
310      b
311
312def sp.tl(bs: List<&2, M.CmBlock>) -> List<&2, M.CmBlock>:
313  match bs:
314    case Nil{}:
315      Nil{}
316    case Con{b, t}:
317      t
318
319# splitting the bytes of a block gives the block back
320def sp.blk(b: M.CmBlock, rest: List<&2, U32>) -> {M.cm.split(M.cm.bytes_onto(b, rest)) == M.cm.split.cons(b, M.cm.split(rest)) : M.CmSplit}:
321  match b:
322    case M.CmBlock{U32{WCon{p0, WCon{p1, WCon{p2, WCon{p3, WCon{p4, WCon{p5, WCon{p6, WCon{p7, WCon{p8, WCon{p9, WCon{p10, WCon{p11, WCon{p12, WCon{p13, WCon{p14, WCon{p15, WCon{p16, WCon{p17, WCon{p18, WCon{p19, WCon{p20, WCon{p21, WCon{p22, WCon{p23, WCon{p24, WCon{p25, WCon{p26, WCon{p27, WCon{p28, WCon{p29, WCon{p30, WCon{p31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{q0, WCon{q1, WCon{q2, WCon{q3, WCon{q4, WCon{q5, WCon{q6, WCon{q7, WCon{q8, WCon{q9, WCon{q10, WCon{q11, WCon{q12, WCon{q13, WCon{q14, WCon{q15, WCon{q16, WCon{q17, WCon{q18, WCon{q19, WCon{q20, WCon{q21, WCon{q22, WCon{q23, WCon{q24, WCon{q25, WCon{q26, WCon{q27, WCon{q28, WCon{q29, WCon{q30, WCon{q31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{r0, WCon{r1, WCon{r2, WCon{r3, WCon{r4, WCon{r5, WCon{r6, WCon{r7, WCon{r8, WCon{r9, WCon{r10, WCon{r11, WCon{r12, WCon{r13, WCon{r14, WCon{r15, WCon{r16, WCon{r17, WCon{r18, WCon{r19, WCon{r20, WCon{r21, WCon{r22, WCon{r23, WCon{r24, WCon{r25, WCon{r26, WCon{r27, WCon{r28, WCon{r29, WCon{r30, WCon{r31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{s0, WCon{s1, WCon{s2, WCon{s3, WCon{s4, WCon{s5, WCon{s6, WCon{s7, WCon{s8, WCon{s9, WCon{s10, WCon{s11, WCon{s12, WCon{s13, WCon{s14, WCon{s15, WCon{s16, WCon{s17, WCon{s18, WCon{s19, WCon{s20, WCon{s21, WCon{s22, WCon{s23, WCon{s24, WCon{s25, WCon{s26, WCon{s27, WCon{s28, WCon{s29, WCon{s30, WCon{s31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
323      {==}
324
325# the bytes of a block are bytes: masking changes nothing
326def sp.mask_blk(b: M.CmBlock, rest: List<&2, U32>) -> {B.mask(M.cm.bytes_onto(b, rest)) == M.cm.bytes_onto(b, B.mask(rest)) : List<&2, U32>}:
327  match b:
328    case M.CmBlock{U32{WCon{p0, WCon{p1, WCon{p2, WCon{p3, WCon{p4, WCon{p5, WCon{p6, WCon{p7, WCon{p8, WCon{p9, WCon{p10, WCon{p11, WCon{p12, WCon{p13, WCon{p14, WCon{p15, WCon{p16, WCon{p17, WCon{p18, WCon{p19, WCon{p20, WCon{p21, WCon{p22, WCon{p23, WCon{p24, WCon{p25, WCon{p26, WCon{p27, WCon{p28, WCon{p29, WCon{p30, WCon{p31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{q0, WCon{q1, WCon{q2, WCon{q3, WCon{q4, WCon{q5, WCon{q6, WCon{q7, WCon{q8, WCon{q9, WCon{q10, WCon{q11, WCon{q12, WCon{q13, WCon{q14, WCon{q15, WCon{q16, WCon{q17, WCon{q18, WCon{q19, WCon{q20, WCon{q21, WCon{q22, WCon{q23, WCon{q24, WCon{q25, WCon{q26, WCon{q27, WCon{q28, WCon{q29, WCon{q30, WCon{q31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{r0, WCon{r1, WCon{r2, WCon{r3, WCon{r4, WCon{r5, WCon{r6, WCon{r7, WCon{r8, WCon{r9, WCon{r10, WCon{r11, WCon{r12, WCon{r13, WCon{r14, WCon{r15, WCon{r16, WCon{r17, WCon{r18, WCon{r19, WCon{r20, WCon{r21, WCon{r22, WCon{r23, WCon{r24, WCon{r25, WCon{r26, WCon{r27, WCon{r28, WCon{r29, WCon{r30, WCon{r31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{s0, WCon{s1, WCon{s2, WCon{s3, WCon{s4, WCon{s5, WCon{s6, WCon{s7, WCon{s8, WCon{s9, WCon{s10, WCon{s11, WCon{s12, WCon{s13, WCon{s14, WCon{s15, WCon{s16, WCon{s17, WCon{s18, WCon{s19, WCon{s20, WCon{s21, WCon{s22, WCon{s23, WCon{s24, WCon{s25, WCon{s26, WCon{s27, WCon{s28, WCon{s29, WCon{s30, WCon{s31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
329      {==}
330
331# the block of 16 bytes, as bytes again
332def sp.blk16(y0: U32, y1: U32, y2: U32, y3: U32, y4: U32, y5: U32, y6: U32, y7: U32, y8: U32, y9: U32, y10: U32, y11: U32, y12: U32, y13: U32, y14: U32, y15: U32, rest: List<&2, U32>) -> {M.cm.bytes_onto(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), rest) == Con{B.byte(y0), Con{B.byte(y1), Con{B.byte(y2), Con{B.byte(y3), Con{B.byte(y4), Con{B.byte(y5), Con{B.byte(y6), Con{B.byte(y7), Con{B.byte(y8), Con{B.byte(y9), Con{B.byte(y10), Con{B.byte(y11), Con{B.byte(y12), Con{B.byte(y13), Con{B.byte(y14), Con{B.byte(y15), rest}}}}}}}}}}}}}}}} : List<&2, U32>}:
333  match y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 y14 y15:
334    case U32{WCon{y00, WCon{y01, WCon{y02, WCon{y03, WCon{y04, WCon{y05, WCon{y06, WCon{y07, WCon{y08, WCon{y09, WCon{y010, WCon{y011, WCon{y012, WCon{y013, WCon{y014, WCon{y015, WCon{y016, WCon{y017, WCon{y018, WCon{y019, WCon{y020, WCon{y021, WCon{y022, WCon{y023, WCon{y024, WCon{y025, WCon{y026, WCon{y027, WCon{y028, WCon{y029, WCon{y030, WCon{y031, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y10, WCon{y11, WCon{y12, WCon{y13, WCon{y14, WCon{y15, WCon{y16, WCon{y17, WCon{y18, WCon{y19, WCon{y110, WCon{y111, WCon{y112, WCon{y113, WCon{y114, WCon{y115, WCon{y116, WCon{y117, WCon{y118, WCon{y119, WCon{y120, WCon{y121, WCon{y122, WCon{y123, WCon{y124, WCon{y125, WCon{y126, WCon{y127, WCon{y128, WCon{y129, WCon{y130, WCon{y131, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y20, WCon{y21, WCon{y22, WCon{y23, WCon{y24, WCon{y25, WCon{y26, WCon{y27, WCon{y28, WCon{y29, WCon{y210, WCon{y211, WCon{y212, WCon{y213, WCon{y214, WCon{y215, WCon{y216, WCon{y217, WCon{y218, WCon{y219, WCon{y220, WCon{y221, WCon{y222, WCon{y223, WCon{y224, WCon{y225, WCon{y226, WCon{y227, WCon{y228, WCon{y229, WCon{y230, WCon{y231, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y30, WCon{y31, WCon{y32, WCon{y33, WCon{y34, WCon{y35, WCon{y36, WCon{y37, WCon{y38, WCon{y39, WCon{y310, WCon{y311, WCon{y312, WCon{y313, WCon{y314, WCon{y315, WCon{y316, WCon{y317, WCon{y318, WCon{y319, WCon{y320, WCon{y321, WCon{y322, WCon{y323, WCon{y324, WCon{y325, WCon{y326, WCon{y327, WCon{y328, WCon{y329, WCon{y330, WCon{y331, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y40, WCon{y41, WCon{y42, WCon{y43, WCon{y44, WCon{y45, WCon{y46, WCon{y47, WCon{y48, WCon{y49, WCon{y410, WCon{y411, WCon{y412, WCon{y413, WCon{y414, WCon{y415, WCon{y416, WCon{y417, WCon{y418, WCon{y419, WCon{y420, WCon{y421, WCon{y422, WCon{y423, WCon{y424, WCon{y425, WCon{y426, WCon{y427, WCon{y428, WCon{y429, WCon{y430, WCon{y431, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y50, WCon{y51, WCon{y52, WCon{y53, WCon{y54, WCon{y55, WCon{y56, WCon{y57, WCon{y58, WCon{y59, WCon{y510, WCon{y511, WCon{y512, WCon{y513, WCon{y514, WCon{y515, WCon{y516, WCon{y517, WCon{y518, WCon{y519, WCon{y520, WCon{y521, WCon{y522, WCon{y523, WCon{y524, WCon{y525, WCon{y526, WCon{y527, WCon{y528, WCon{y529, WCon{y530, WCon{y531, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y60, WCon{y61, WCon{y62, WCon{y63, WCon{y64, WCon{y65, WCon{y66, WCon{y67, WCon{y68, WCon{y69, WCon{y610, WCon{y611, WCon{y612, WCon{y613, WCon{y614, WCon{y615, WCon{y616, WCon{y617, WCon{y618, WCon{y619, WCon{y620, WCon{y621, WCon{y622, WCon{y623, WCon{y624, WCon{y625, WCon{y626, WCon{y627, WCon{y628, WCon{y629, WCon{y630, WCon{y631, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y70, WCon{y71, WCon{y72, WCon{y73, WCon{y74, WCon{y75, WCon{y76, WCon{y77, WCon{y78, WCon{y79, WCon{y710, WCon{y711, WCon{y712, WCon{y713, WCon{y714, WCon{y715, WCon{y716, WCon{y717, WCon{y718, WCon{y719, WCon{y720, WCon{y721, WCon{y722, WCon{y723, WCon{y724, WCon{y725, WCon{y726, WCon{y727, WCon{y728, WCon{y729, WCon{y730, WCon{y731, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y80, WCon{y81, WCon{y82, WCon{y83, WCon{y84, WCon{y85, WCon{y86, WCon{y87, WCon{y88, WCon{y89, WCon{y810, WCon{y811, WCon{y812, WCon{y813, WCon{y814, WCon{y815, WCon{y816, WCon{y817, WCon{y818, WCon{y819, WCon{y820, WCon{y821, WCon{y822, WCon{y823, WCon{y824, WCon{y825, WCon{y826, WCon{y827, WCon{y828, WCon{y829, WCon{y830, WCon{y831, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y90, WCon{y91, WCon{y92, WCon{y93, WCon{y94, WCon{y95, WCon{y96, WCon{y97, WCon{y98, WCon{y99, WCon{y910, WCon{y911, WCon{y912, WCon{y913, WCon{y914, WCon{y915, WCon{y916, WCon{y917, WCon{y918, WCon{y919, WCon{y920, WCon{y921, WCon{y922, WCon{y923, WCon{y924, WCon{y925, WCon{y926, WCon{y927, WCon{y928, WCon{y929, WCon{y930, WCon{y931, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y100, WCon{y101, WCon{y102, WCon{y103, WCon{y104, WCon{y105, WCon{y106, WCon{y107, WCon{y108, WCon{y109, WCon{y1010, WCon{y1011, WCon{y1012, WCon{y1013, WCon{y1014, WCon{y1015, WCon{y1016, WCon{y1017, WCon{y1018, WCon{y1019, WCon{y1020, WCon{y1021, WCon{y1022, WCon{y1023, WCon{y1024, WCon{y1025, WCon{y1026, WCon{y1027, WCon{y1028, WCon{y1029, WCon{y1030, WCon{y1031, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y110, WCon{y111, WCon{y112, WCon{y113, WCon{y114, WCon{y115, WCon{y116, WCon{y117, WCon{y118, WCon{y119, WCon{y1110, WCon{y1111, WCon{y1112, WCon{y1113, WCon{y1114, WCon{y1115, WCon{y1116, WCon{y1117, WCon{y1118, WCon{y1119, WCon{y1120, WCon{y1121, WCon{y1122, WCon{y1123, WCon{y1124, WCon{y1125, WCon{y1126, WCon{y1127, WCon{y1128, WCon{y1129, WCon{y1130, WCon{y1131, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y120, WCon{y121, WCon{y122, WCon{y123, WCon{y124, WCon{y125, WCon{y126, WCon{y127, WCon{y128, WCon{y129, WCon{y1210, WCon{y1211, WCon{y1212, WCon{y1213, WCon{y1214, WCon{y1215, WCon{y1216, WCon{y1217, WCon{y1218, WCon{y1219, WCon{y1220, WCon{y1221, WCon{y1222, WCon{y1223, WCon{y1224, WCon{y1225, WCon{y1226, WCon{y1227, WCon{y1228, WCon{y1229, WCon{y1230, WCon{y1231, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y130, WCon{y131, WCon{y132, WCon{y133, WCon{y134, WCon{y135, WCon{y136, WCon{y137, WCon{y138, WCon{y139, WCon{y1310, WCon{y1311, WCon{y1312, WCon{y1313, WCon{y1314, WCon{y1315, WCon{y1316, WCon{y1317, WCon{y1318, WCon{y1319, WCon{y1320, WCon{y1321, WCon{y1322, WCon{y1323, WCon{y1324, WCon{y1325, WCon{y1326, WCon{y1327, WCon{y1328, WCon{y1329, WCon{y1330, WCon{y1331, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y140, WCon{y141, WCon{y142, WCon{y143, WCon{y144, WCon{y145, WCon{y146, WCon{y147, WCon{y148, WCon{y149, WCon{y1410, WCon{y1411, WCon{y1412, WCon{y1413, WCon{y1414, WCon{y1415, WCon{y1416, WCon{y1417, WCon{y1418, WCon{y1419, WCon{y1420, WCon{y1421, WCon{y1422, WCon{y1423, WCon{y1424, WCon{y1425, WCon{y1426, WCon{y1427, WCon{y1428, WCon{y1429, WCon{y1430, WCon{y1431, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y150, WCon{y151, WCon{y152, WCon{y153, WCon{y154, WCon{y155, WCon{y156, WCon{y157, WCon{y158, WCon{y159, WCon{y1510, WCon{y1511, WCon{y1512, WCon{y1513, WCon{y1514, WCon{y1515, WCon{y1516, WCon{y1517, WCon{y1518, WCon{y1519, WCon{y1520, WCon{y1521, WCon{y1522, WCon{y1523, WCon{y1524, WCon{y1525, WCon{y1526, WCon{y1527, WCon{y1528, WCon{y1529, WCon{y1530, WCon{y1531, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
335      {==}
336
337# a masked list is its blocks and its tail joined back
338def sp.join_split(ys: List<&2, U32>) -> {M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(ys))), M.cm.split.tail(M.cm.split(B.mask(ys)))) == B.mask(ys) : List<&2, U32>}:
339  match ys:
340    case Nil{}:
341      {==}
342    case Con{+y0, +r0}:
343      match r0:
344        case Nil{}:
345          {==}
346        case Con{+y1, +r1}:
347          match r1:
348            case Nil{}:
349              {==}
350            case Con{+y2, +r2}:
351              match r2:
352                case Nil{}:
353                  {==}
354                case Con{+y3, +r3}:
355                  match r3:
356                    case Nil{}:
357                      {==}
358                    case Con{+y4, +r4}:
359                      match r4:
360                        case Nil{}:
361                          {==}
362                        case Con{+y5, +r5}:
363                          match r5:
364                            case Nil{}:
365                              {==}
366                            case Con{+y6, +r6}:
367                              match r6:
368                                case Nil{}:
369                                  {==}
370                                case Con{+y7, +r7}:
371                                  match r7:
372                                    case Nil{}:
373                                      {==}
374                                    case Con{+y8, +r8}:
375                                      match r8:
376                                        case Nil{}:
377                                          {==}
378                                        case Con{+y9, +r9}:
379                                          match r9:
380                                            case Nil{}:
381                                              {==}
382                                            case Con{+y10, +r10}:
383                                              match r10:
384                                                case Nil{}:
385                                                  {==}
386                                                case Con{+y11, +r11}:
387                                                  match r11:
388                                                    case Nil{}:
389                                                      {==}
390                                                    case Con{+y12, +r12}:
391                                                      match r12:
392                                                        case Nil{}:
393                                                          {==}
394                                                        case Con{+y13, +r13}:
395                                                          match r13:
396                                                            case Nil{}:
397                                                              {==}
398                                                            case Con{+y14, +r14}:
399                                                              match r14:
400                                                                case Nil{}:
401                                                                  {==}
402                                                                case Con{+y15, +t}:
403                                                                  %Equal.sym(List<&2, M.CmBlock>, M.cm.split.blocks(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))), Con{M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split.blocks(M.cm.split(B.mask(t)))}, sp.cons_blocks(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))) : {M.cm.join_onto(_, M.cm.split.tail(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t))))) == Con{B.byte(y0), Con{B.byte(y1), Con{B.byte(y2), Con{B.byte(y3), Con{B.byte(y4), Con{B.byte(y5), Con{B.byte(y6), Con{B.byte(y7), Con{B.byte(y8), Con{B.byte(y9), Con{B.byte(y10), Con{B.byte(y11), Con{B.byte(y12), Con{B.byte(y13), Con{B.byte(y14), Con{B.byte(y15), B.mask(t)}}}}}}}}}}}}}}}} : List<&2, U32>}
404                                                                  %Equal.sym(List<&2, U32>, M.cm.split.tail(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))), M.cm.split.tail(M.cm.split(B.mask(t))), sp.cons_tail(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))) : {M.cm.join_onto(Con{M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split.blocks(M.cm.split(B.mask(t)))}, _) == Con{B.byte(y0), Con{B.byte(y1), Con{B.byte(y2), Con{B.byte(y3), Con{B.byte(y4), Con{B.byte(y5), Con{B.byte(y6), Con{B.byte(y7), Con{B.byte(y8), Con{B.byte(y9), Con{B.byte(y10), Con{B.byte(y11), Con{B.byte(y12), Con{B.byte(y13), Con{B.byte(y14), Con{B.byte(y15), B.mask(t)}}}}}}}}}}}}}}}} : List<&2, U32>}
405                                                                  %Equal.sym(List<&2, U32>, M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(t))), M.cm.split.tail(M.cm.split(B.mask(t)))), B.mask(t), sp.join_split(t)) : {M.cm.bytes_onto(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), _) == Con{B.byte(y0), Con{B.byte(y1), Con{B.byte(y2), Con{B.byte(y3), Con{B.byte(y4), Con{B.byte(y5), Con{B.byte(y6), Con{B.byte(y7), Con{B.byte(y8), Con{B.byte(y9), Con{B.byte(y10), Con{B.byte(y11), Con{B.byte(y12), Con{B.byte(y13), Con{B.byte(y14), Con{B.byte(y15), B.mask(t)}}}}}}}}}}}}}}}} : List<&2, U32>}
406                                                                  sp.blk16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15, B.mask(t))
407
408# a list of whole blocks splits with no tail
409def sp.mod_tail(ys: List<&2, U32>) -> {Nat.mod(B.len(ys), 16n) == 0n : Nat} -> {M.cm.split.tail(M.cm.split(B.mask(ys))) == Nil{} : List<&2, U32>}:
410  match ys:
411    case Nil{}:
412      h => {==}
413    case Con{+y0, +r0}:
414      match r0:
415        case Nil{}:
416          h => sp.absurd_tail(0n, Con{y0, Nil{}}, h)
417        case Con{+y1, +r1}:
418          match r1:
419            case Nil{}:
420              h => sp.absurd_tail(1n, Con{y0, Con{y1, Nil{}}}, h)
421            case Con{+y2, +r2}:
422              match r2:
423                case Nil{}:
424                  h => sp.absurd_tail(2n, Con{y0, Con{y1, Con{y2, Nil{}}}}, h)
425                case Con{+y3, +r3}:
426                  match r3:
427                    case Nil{}:
428                      h => sp.absurd_tail(3n, Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}}, h)
429                    case Con{+y4, +r4}:
430                      match r4:
431                        case Nil{}:
432                          h => sp.absurd_tail(4n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}}, h)
433                        case Con{+y5, +r5}:
434                          match r5:
435                            case Nil{}:
436                              h => sp.absurd_tail(5n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}}, h)
437                            case Con{+y6, +r6}:
438                              match r6:
439                                case Nil{}:
440                                  h => sp.absurd_tail(6n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}}, h)
441                                case Con{+y7, +r7}:
442                                  match r7:
443                                    case Nil{}:
444                                      h => sp.absurd_tail(7n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}}, h)
445                                    case Con{+y8, +r8}:
446                                      match r8:
447                                        case Nil{}:
448                                          h => sp.absurd_tail(8n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}}, h)
449                                        case Con{+y9, +r9}:
450                                          match r9:
451                                            case Nil{}:
452                                              h => sp.absurd_tail(9n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}}, h)
453                                            case Con{+y10, +r10}:
454                                              match r10:
455                                                case Nil{}:
456                                                  h => sp.absurd_tail(10n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}}, h)
457                                                case Con{+y11, +r11}:
458                                                  match r11:
459                                                    case Nil{}:
460                                                      h => sp.absurd_tail(11n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}}, h)
461                                                    case Con{+y12, +r12}:
462                                                      match r12:
463                                                        case Nil{}:
464                                                          h => sp.absurd_tail(12n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}}, h)
465                                                        case Con{+y13, +r13}:
466                                                          match r13:
467                                                            case Nil{}:
468                                                              h => sp.absurd_tail(13n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}}, h)
469                                                            case Con{+y14, +r14}:
470                                                              match r14:
471                                                                case Nil{}:
472                                                                  h => sp.absurd_tail(14n, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}}, h)
473                                                                case Con{+y15, +t}:
474                                                                  h => %Equal.sym(List<&2, U32>, M.cm.split.tail(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))), M.cm.split.tail(M.cm.split(B.mask(t))), sp.cons_tail(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))) : {_ == Nil{} : List<&2, U32>}
475                                                                    sp.mod_tail(t)(Equal.trans(Nat, Nat.mod(B.len(t), 16n), Nat.mod(Nat.add(16n, B.len(t)), 16n), 0n, Equal.sym(Nat, Nat.mod(Nat.add(16n, B.len(t)), 16n), Nat.mod(B.len(t), 16n), sp.mod16(B.len(t))), h))
476
477# the bytes of the block of any 16 values are those values, masked
478def sp.blk16g(z0: U32, z1: U32, z2: U32, z3: U32, z4: U32, z5: U32, z6: U32, z7: U32, z8: U32, z9: U32, z10: U32, z11: U32, z12: U32, z13: U32, z14: U32, z15: U32, rest: List<&2, U32>) -> {M.cm.bytes_onto(M.cm.block16(z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15), rest) == Con{B.byte(z0), Con{B.byte(z1), Con{B.byte(z2), Con{B.byte(z3), Con{B.byte(z4), Con{B.byte(z5), Con{B.byte(z6), Con{B.byte(z7), Con{B.byte(z8), Con{B.byte(z9), Con{B.byte(z10), Con{B.byte(z11), Con{B.byte(z12), Con{B.byte(z13), Con{B.byte(z14), Con{B.byte(z15), rest}}}}}}}}}}}}}}}} : List<&2, U32>}:
479  match z0 z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 z11 z12 z13 z14 z15:
480    case U32{WCon{z00, WCon{z01, WCon{z02, WCon{z03, WCon{z04, WCon{z05, WCon{z06, WCon{z07, WCon{z08, WCon{z09, WCon{z010, WCon{z011, WCon{z012, WCon{z013, WCon{z014, WCon{z015, WCon{z016, WCon{z017, WCon{z018, WCon{z019, WCon{z020, WCon{z021, WCon{z022, WCon{z023, WCon{z024, WCon{z025, WCon{z026, WCon{z027, WCon{z028, WCon{z029, WCon{z030, WCon{z031, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z10, WCon{z11, WCon{z12, WCon{z13, WCon{z14, WCon{z15, WCon{z16, WCon{z17, WCon{z18, WCon{z19, WCon{z110, WCon{z111, WCon{z112, WCon{z113, WCon{z114, WCon{z115, WCon{z116, WCon{z117, WCon{z118, WCon{z119, WCon{z120, WCon{z121, WCon{z122, WCon{z123, WCon{z124, WCon{z125, WCon{z126, WCon{z127, WCon{z128, WCon{z129, WCon{z130, WCon{z131, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z20, WCon{z21, WCon{z22, WCon{z23, WCon{z24, WCon{z25, WCon{z26, WCon{z27, WCon{z28, WCon{z29, WCon{z210, WCon{z211, WCon{z212, WCon{z213, WCon{z214, WCon{z215, WCon{z216, WCon{z217, WCon{z218, WCon{z219, WCon{z220, WCon{z221, WCon{z222, WCon{z223, WCon{z224, WCon{z225, WCon{z226, WCon{z227, WCon{z228, WCon{z229, WCon{z230, WCon{z231, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z30, WCon{z31, WCon{z32, WCon{z33, WCon{z34, WCon{z35, WCon{z36, WCon{z37, WCon{z38, WCon{z39, WCon{z310, WCon{z311, WCon{z312, WCon{z313, WCon{z314, WCon{z315, WCon{z316, WCon{z317, WCon{z318, WCon{z319, WCon{z320, WCon{z321, WCon{z322, WCon{z323, WCon{z324, WCon{z325, WCon{z326, WCon{z327, WCon{z328, WCon{z329, WCon{z330, WCon{z331, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z40, WCon{z41, WCon{z42, WCon{z43, WCon{z44, WCon{z45, WCon{z46, WCon{z47, WCon{z48, WCon{z49, WCon{z410, WCon{z411, WCon{z412, WCon{z413, WCon{z414, WCon{z415, WCon{z416, WCon{z417, WCon{z418, WCon{z419, WCon{z420, WCon{z421, WCon{z422, WCon{z423, WCon{z424, WCon{z425, WCon{z426, WCon{z427, WCon{z428, WCon{z429, WCon{z430, WCon{z431, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z50, WCon{z51, WCon{z52, WCon{z53, WCon{z54, WCon{z55, WCon{z56, WCon{z57, WCon{z58, WCon{z59, WCon{z510, WCon{z511, WCon{z512, WCon{z513, WCon{z514, WCon{z515, WCon{z516, WCon{z517, WCon{z518, WCon{z519, WCon{z520, WCon{z521, WCon{z522, WCon{z523, WCon{z524, WCon{z525, WCon{z526, WCon{z527, WCon{z528, WCon{z529, WCon{z530, WCon{z531, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z60, WCon{z61, WCon{z62, WCon{z63, WCon{z64, WCon{z65, WCon{z66, WCon{z67, WCon{z68, WCon{z69, WCon{z610, WCon{z611, WCon{z612, WCon{z613, WCon{z614, WCon{z615, WCon{z616, WCon{z617, WCon{z618, WCon{z619, WCon{z620, WCon{z621, WCon{z622, WCon{z623, WCon{z624, WCon{z625, WCon{z626, WCon{z627, WCon{z628, WCon{z629, WCon{z630, WCon{z631, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z70, WCon{z71, WCon{z72, WCon{z73, WCon{z74, WCon{z75, WCon{z76, WCon{z77, WCon{z78, WCon{z79, WCon{z710, WCon{z711, WCon{z712, WCon{z713, WCon{z714, WCon{z715, WCon{z716, WCon{z717, WCon{z718, WCon{z719, WCon{z720, WCon{z721, WCon{z722, WCon{z723, WCon{z724, WCon{z725, WCon{z726, WCon{z727, WCon{z728, WCon{z729, WCon{z730, WCon{z731, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z80, WCon{z81, WCon{z82, WCon{z83, WCon{z84, WCon{z85, WCon{z86, WCon{z87, WCon{z88, WCon{z89, WCon{z810, WCon{z811, WCon{z812, WCon{z813, WCon{z814, WCon{z815, WCon{z816, WCon{z817, WCon{z818, WCon{z819, WCon{z820, WCon{z821, WCon{z822, WCon{z823, WCon{z824, WCon{z825, WCon{z826, WCon{z827, WCon{z828, WCon{z829, WCon{z830, WCon{z831, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z90, WCon{z91, WCon{z92, WCon{z93, WCon{z94, WCon{z95, WCon{z96, WCon{z97, WCon{z98, WCon{z99, WCon{z910, WCon{z911, WCon{z912, WCon{z913, WCon{z914, WCon{z915, WCon{z916, WCon{z917, WCon{z918, WCon{z919, WCon{z920, WCon{z921, WCon{z922, WCon{z923, WCon{z924, WCon{z925, WCon{z926, WCon{z927, WCon{z928, WCon{z929, WCon{z930, WCon{z931, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z100, WCon{z101, WCon{z102, WCon{z103, WCon{z104, WCon{z105, WCon{z106, WCon{z107, WCon{z108, WCon{z109, WCon{z1010, WCon{z1011, WCon{z1012, WCon{z1013, WCon{z1014, WCon{z1015, WCon{z1016, WCon{z1017, WCon{z1018, WCon{z1019, WCon{z1020, WCon{z1021, WCon{z1022, WCon{z1023, WCon{z1024, WCon{z1025, WCon{z1026, WCon{z1027, WCon{z1028, WCon{z1029, WCon{z1030, WCon{z1031, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z110, WCon{z111, WCon{z112, WCon{z113, WCon{z114, WCon{z115, WCon{z116, WCon{z117, WCon{z118, WCon{z119, WCon{z1110, WCon{z1111, WCon{z1112, WCon{z1113, WCon{z1114, WCon{z1115, WCon{z1116, WCon{z1117, WCon{z1118, WCon{z1119, WCon{z1120, WCon{z1121, WCon{z1122, WCon{z1123, WCon{z1124, WCon{z1125, WCon{z1126, WCon{z1127, WCon{z1128, WCon{z1129, WCon{z1130, WCon{z1131, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z120, WCon{z121, WCon{z122, WCon{z123, WCon{z124, WCon{z125, WCon{z126, WCon{z127, WCon{z128, WCon{z129, WCon{z1210, WCon{z1211, WCon{z1212, WCon{z1213, WCon{z1214, WCon{z1215, WCon{z1216, WCon{z1217, WCon{z1218, WCon{z1219, WCon{z1220, WCon{z1221, WCon{z1222, WCon{z1223, WCon{z1224, WCon{z1225, WCon{z1226, WCon{z1227, WCon{z1228, WCon{z1229, WCon{z1230, WCon{z1231, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z130, WCon{z131, WCon{z132, WCon{z133, WCon{z134, WCon{z135, WCon{z136, WCon{z137, WCon{z138, WCon{z139, WCon{z1310, WCon{z1311, WCon{z1312, WCon{z1313, WCon{z1314, WCon{z1315, WCon{z1316, WCon{z1317, WCon{z1318, WCon{z1319, WCon{z1320, WCon{z1321, WCon{z1322, WCon{z1323, WCon{z1324, WCon{z1325, WCon{z1326, WCon{z1327, WCon{z1328, WCon{z1329, WCon{z1330, WCon{z1331, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z140, WCon{z141, WCon{z142, WCon{z143, WCon{z144, WCon{z145, WCon{z146, WCon{z147, WCon{z148, WCon{z149, WCon{z1410, WCon{z1411, WCon{z1412, WCon{z1413, WCon{z1414, WCon{z1415, WCon{z1416, WCon{z1417, WCon{z1418, WCon{z1419, WCon{z1420, WCon{z1421, WCon{z1422, WCon{z1423, WCon{z1424, WCon{z1425, WCon{z1426, WCon{z1427, WCon{z1428, WCon{z1429, WCon{z1430, WCon{z1431, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{z150, WCon{z151, WCon{z152, WCon{z153, WCon{z154, WCon{z155, WCon{z156, WCon{z157, WCon{z158, WCon{z159, WCon{z1510, WCon{z1511, WCon{z1512, WCon{z1513, WCon{z1514, WCon{z1515, WCon{z1516, WCon{z1517, WCon{z1518, WCon{z1519, WCon{z1520, WCon{z1521, WCon{z1522, WCon{z1523, WCon{z1524, WCon{z1525, WCon{z1526, WCon{z1527, WCon{z1528, WCon{z1529, WCon{z1530, WCon{z1531, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
481      {==}
482
483# the tail of a split has fewer than 16 bytes
484def sp.tail_short(ys: List<&2, U32>) -> {Nat.is_lt(B.len(M.cm.split.tail(M.cm.split(B.mask(ys)))), 16n) == True{} : Bool}:
485  match ys:
486    case Nil{}:
487      {==}
488    case Con{+y0, +r0}:
489      match r0:
490        case Nil{}:
491          {==}
492        case Con{+y1, +r1}:
493          match r1:
494            case Nil{}:
495              {==}
496            case Con{+y2, +r2}:
497              match r2:
498                case Nil{}:
499                  {==}
500                case Con{+y3, +r3}:
501                  match r3:
502                    case Nil{}:
503                      {==}
504                    case Con{+y4, +r4}:
505                      match r4:
506                        case Nil{}:
507                          {==}
508                        case Con{+y5, +r5}:
509                          match r5:
510                            case Nil{}:
511                              {==}
512                            case Con{+y6, +r6}:
513                              match r6:
514                                case Nil{}:
515                                  {==}
516                                case Con{+y7, +r7}:
517                                  match r7:
518                                    case Nil{}:
519                                      {==}
520                                    case Con{+y8, +r8}:
521                                      match r8:
522                                        case Nil{}:
523                                          {==}
524                                        case Con{+y9, +r9}:
525                                          match r9:
526                                            case Nil{}:
527                                              {==}
528                                            case Con{+y10, +r10}:
529                                              match r10:
530                                                case Nil{}:
531                                                  {==}
532                                                case Con{+y11, +r11}:
533                                                  match r11:
534                                                    case Nil{}:
535                                                      {==}
536                                                    case Con{+y12, +r12}:
537                                                      match r12:
538                                                        case Nil{}:
539                                                          {==}
540                                                        case Con{+y13, +r13}:
541                                                          match r13:
542                                                            case Nil{}:
543                                                              {==}
544                                                            case Con{+y14, +r14}:
545                                                              match r14:
546                                                                case Nil{}:
547                                                                  {==}
548                                                                case Con{+y15, +t}:
549                                                                  %Equal.sym(List<&2, U32>, M.cm.split.tail(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))), M.cm.split.tail(M.cm.split(B.mask(t))), sp.cons_tail(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))) : {Nat.is_lt(B.len(_), 16n) == True{} : Bool}
550                                                                  sp.tail_short(t)
551
552# the tail of a masked split is masked
553def sp.tail_masked(ys: List<&2, U32>) -> {B.mask(M.cm.split.tail(M.cm.split(B.mask(ys)))) == M.cm.split.tail(M.cm.split(B.mask(ys))) : List<&2, U32>}:
554  match ys:
555    case Nil{}:
556      li.mask_mask(Nil{})
557    case Con{+y0, +r0}:
558      match r0:
559        case Nil{}:
560          li.mask_mask(Con{y0, Nil{}})
561        case Con{+y1, +r1}:
562          match r1:
563            case Nil{}:
564              li.mask_mask(Con{y0, Con{y1, Nil{}}})
565            case Con{+y2, +r2}:
566              match r2:
567                case Nil{}:
568                  li.mask_mask(Con{y0, Con{y1, Con{y2, Nil{}}}})
569                case Con{+y3, +r3}:
570                  match r3:
571                    case Nil{}:
572                      li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}})
573                    case Con{+y4, +r4}:
574                      match r4:
575                        case Nil{}:
576                          li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}})
577                        case Con{+y5, +r5}:
578                          match r5:
579                            case Nil{}:
580                              li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}})
581                            case Con{+y6, +r6}:
582                              match r6:
583                                case Nil{}:
584                                  li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}})
585                                case Con{+y7, +r7}:
586                                  match r7:
587                                    case Nil{}:
588                                      li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}})
589                                    case Con{+y8, +r8}:
590                                      match r8:
591                                        case Nil{}:
592                                          li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}})
593                                        case Con{+y9, +r9}:
594                                          match r9:
595                                            case Nil{}:
596                                              li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}})
597                                            case Con{+y10, +r10}:
598                                              match r10:
599                                                case Nil{}:
600                                                  li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}})
601                                                case Con{+y11, +r11}:
602                                                  match r11:
603                                                    case Nil{}:
604                                                      li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}})
605                                                    case Con{+y12, +r12}:
606                                                      match r12:
607                                                        case Nil{}:
608                                                          li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}})
609                                                        case Con{+y13, +r13}:
610                                                          match r13:
611                                                            case Nil{}:
612                                                              li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}})
613                                                            case Con{+y14, +r14}:
614                                                              match r14:
615                                                                case Nil{}:
616                                                                  li.mask_mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}})
617                                                                case Con{+y15, +t}:
618                                                                  %Equal.sym(List<&2, U32>, M.cm.split.tail(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))), M.cm.split.tail(M.cm.split(B.mask(t))), sp.cons_tail(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))) : {B.mask(_) == _ : List<&2, U32>}
619                                                                  sp.tail_masked(t)
620
621# a byte string of at least 16 bytes has a first block
622def sp.nonempty(ys: List<&2, U32>) -> {Nat.is_le(16n, B.len(ys)) == True{} : Bool} -> {Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(ys)))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(ys))))} == M.cm.split.blocks(M.cm.split(B.mask(ys))) : List<&2, M.CmBlock>}:
623  match ys:
624    case Nil{}:
625      h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Nil{})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Nil{}))))} == M.cm.split.blocks(M.cm.split(B.mask(Nil{}))) : List<&2, M.CmBlock>}, h)
626    case Con{+y0, +r0}:
627      match r0:
628        case Nil{}:
629          h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Nil{}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Nil{}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Nil{}}))) : List<&2, M.CmBlock>}, h)
630        case Con{+y1, +r1}:
631          match r1:
632            case Nil{}:
633              h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Nil{}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Nil{}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Nil{}}}))) : List<&2, M.CmBlock>}, h)
634            case Con{+y2, +r2}:
635              match r2:
636                case Nil{}:
637                  h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Nil{}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Nil{}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Nil{}}}}))) : List<&2, M.CmBlock>}, h)
638                case Con{+y3, +r3}:
639                  match r3:
640                    case Nil{}:
641                      h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}}))) : List<&2, M.CmBlock>}, h)
642                    case Con{+y4, +r4}:
643                      match r4:
644                        case Nil{}:
645                          h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}}))) : List<&2, M.CmBlock>}, h)
646                        case Con{+y5, +r5}:
647                          match r5:
648                            case Nil{}:
649                              h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}}))) : List<&2, M.CmBlock>}, h)
650                            case Con{+y6, +r6}:
651                              match r6:
652                                case Nil{}:
653                                  h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}}))) : List<&2, M.CmBlock>}, h)
654                                case Con{+y7, +r7}:
655                                  match r7:
656                                    case Nil{}:
657                                      h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
658                                    case Con{+y8, +r8}:
659                                      match r8:
660                                        case Nil{}:
661                                          h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
662                                        case Con{+y9, +r9}:
663                                          match r9:
664                                            case Nil{}:
665                                              h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
666                                            case Con{+y10, +r10}:
667                                              match r10:
668                                                case Nil{}:
669                                                  h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
670                                                case Con{+y11, +r11}:
671                                                  match r11:
672                                                    case Nil{}:
673                                                      h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
674                                                    case Con{+y12, +r12}:
675                                                      match r12:
676                                                        case Nil{}:
677                                                          h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
678                                                        case Con{+y13, +r13}:
679                                                          match r13:
680                                                            case Nil{}:
681                                                              h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
682                                                            case Con{+y14, +r14}:
683                                                              match r14:
684                                                                case Nil{}:
685                                                                  h => bo.absurd({Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}})))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}}))))} == M.cm.split.blocks(M.cm.split(B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}}))) : List<&2, M.CmBlock>}, h)
686                                                                case Con{+y15, +t}:
687                                                                  h => %Equal.sym(List<&2, M.CmBlock>, M.cm.split.blocks(M.cm.split.cons(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))), Con{M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split.blocks(M.cm.split(B.mask(t)))}, sp.cons_blocks(M.cm.block16(B.byte(y0), B.byte(y1), B.byte(y2), B.byte(y3), B.byte(y4), B.byte(y5), B.byte(y6), B.byte(y7), B.byte(y8), B.byte(y9), B.byte(y10), B.byte(y11), B.byte(y12), B.byte(y13), B.byte(y14), B.byte(y15)), M.cm.split(B.mask(t)))) : {Con{sp.hd(_), sp.tl(_)} == _ : List<&2, M.CmBlock>}
688                                                                    {==}
689
690# fewer than 16 bytes are all tail
691def sp.short_split(ys: List<&2, U32>) -> {Nat.is_lt(B.len(ys), 16n) == True{} : Bool} -> {M.cm.split(ys) == M.CmSplit{Nil{}, ys} : M.CmSplit}:
692  match ys:
693    case Nil{}:
694      h => {==}
695    case Con{+y0, +r0}:
696      match r0:
697        case Nil{}:
698          h => {==}
699        case Con{+y1, +r1}:
700          match r1:
701            case Nil{}:
702              h => {==}
703            case Con{+y2, +r2}:
704              match r2:
705                case Nil{}:
706                  h => {==}
707                case Con{+y3, +r3}:
708                  match r3:
709                    case Nil{}:
710                      h => {==}
711                    case Con{+y4, +r4}:
712                      match r4:
713                        case Nil{}:
714                          h => {==}
715                        case Con{+y5, +r5}:
716                          match r5:
717                            case Nil{}:
718                              h => {==}
719                            case Con{+y6, +r6}:
720                              match r6:
721                                case Nil{}:
722                                  h => {==}
723                                case Con{+y7, +r7}:
724                                  match r7:
725                                    case Nil{}:
726                                      h => {==}
727                                    case Con{+y8, +r8}:
728                                      match r8:
729                                        case Nil{}:
730                                          h => {==}
731                                        case Con{+y9, +r9}:
732                                          match r9:
733                                            case Nil{}:
734                                              h => {==}
735                                            case Con{+y10, +r10}:
736                                              match r10:
737                                                case Nil{}:
738                                                  h => {==}
739                                                case Con{+y11, +r11}:
740                                                  match r11:
741                                                    case Nil{}:
742                                                      h => {==}
743                                                    case Con{+y12, +r12}:
744                                                      match r12:
745                                                        case Nil{}:
746                                                          h => {==}
747                                                        case Con{+y13, +r13}:
748                                                          match r13:
749                                                            case Nil{}:
750                                                              h => {==}
751                                                            case Con{+y14, +r14}:
752                                                              match r14:
753                                                                case Nil{}:
754                                                                  h => {==}
755                                                                case Con{+y15, +t}:
756                                                                  match t:
757                                                                    case Nil{}:
758                                                                      h => bo.absurd({M.cm.split(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Con{y15, Nil{}}}}}}}}}}}}}}}}}) == M.CmSplit{Nil{}, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Con{y15, Nil{}}}}}}}}}}}}}}}}}} : M.CmSplit}, h)
759                                                                    case Con{+z, +zs}:
760                                                                      h => bo.absurd({M.cm.split(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Con{y15, Con{z, zs}}}}}}}}}}}}}}}}}) == M.CmSplit{Nil{}, Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Con{y15, Con{z, zs}}}}}}}}}}}}}}}}}} : M.CmSplit}, h)
761
762# a block of exactly 16 bytes gives them back, masked
763def sp.bb16(ys: List<&2, U32>) -> {Nat.is_eq(B.len(ys), 16n) == True{} : Bool} -> {M.cm.bytes_of(M.cm.block_of(ys)) == B.mask(ys) : List<&2, U32>}:
764  match ys:
765    case Nil{}:
766      h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Nil{})) == B.mask(Nil{}) : List<&2, U32>}, h)
767    case Con{+y0, +r0}:
768      match r0:
769        case Nil{}:
770          h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Nil{}})) == B.mask(Con{y0, Nil{}}) : List<&2, U32>}, h)
771        case Con{+y1, +r1}:
772          match r1:
773            case Nil{}:
774              h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Nil{}}})) == B.mask(Con{y0, Con{y1, Nil{}}}) : List<&2, U32>}, h)
775            case Con{+y2, +r2}:
776              match r2:
777                case Nil{}:
778                  h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Nil{}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Nil{}}}}) : List<&2, U32>}, h)
779                case Con{+y3, +r3}:
780                  match r3:
781                    case Nil{}:
782                      h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Nil{}}}}}) : List<&2, U32>}, h)
783                    case Con{+y4, +r4}:
784                      match r4:
785                        case Nil{}:
786                          h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Nil{}}}}}}) : List<&2, U32>}, h)
787                        case Con{+y5, +r5}:
788                          match r5:
789                            case Nil{}:
790                              h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Nil{}}}}}}}) : List<&2, U32>}, h)
791                            case Con{+y6, +r6}:
792                              match r6:
793                                case Nil{}:
794                                  h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Nil{}}}}}}}}) : List<&2, U32>}, h)
795                                case Con{+y7, +r7}:
796                                  match r7:
797                                    case Nil{}:
798                                      h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Nil{}}}}}}}}}) : List<&2, U32>}, h)
799                                    case Con{+y8, +r8}:
800                                      match r8:
801                                        case Nil{}:
802                                          h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Nil{}}}}}}}}}}) : List<&2, U32>}, h)
803                                        case Con{+y9, +r9}:
804                                          match r9:
805                                            case Nil{}:
806                                              h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Nil{}}}}}}}}}}}) : List<&2, U32>}, h)
807                                            case Con{+y10, +r10}:
808                                              match r10:
809                                                case Nil{}:
810                                                  h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Nil{}}}}}}}}}}}}) : List<&2, U32>}, h)
811                                                case Con{+y11, +r11}:
812                                                  match r11:
813                                                    case Nil{}:
814                                                      h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Nil{}}}}}}}}}}}}}) : List<&2, U32>}, h)
815                                                    case Con{+y12, +r12}:
816                                                      match r12:
817                                                        case Nil{}:
818                                                          h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Nil{}}}}}}}}}}}}}}) : List<&2, U32>}, h)
819                                                        case Con{+y13, +r13}:
820                                                          match r13:
821                                                            case Nil{}:
822                                                              h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Nil{}}}}}}}}}}}}}}}) : List<&2, U32>}, h)
823                                                            case Con{+y14, +r14}:
824                                                              match r14:
825                                                                case Nil{}:
826                                                                  h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Nil{}}}}}}}}}}}}}}}}) : List<&2, U32>}, h)
827                                                                case Con{+y15, +t}:
828                                                                  match t:
829                                                                    case Nil{}:
830                                                                      h => sp.blk16g(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15, Nil{})
831                                                                    case Con{+z, +zs}:
832                                                                      h => bo.absurd({M.cm.bytes_of(M.cm.block_of(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Con{y15, Con{z, zs}}}}}}}}}}}}}}}}})) == B.mask(Con{y0, Con{y1, Con{y2, Con{y3, Con{y4, Con{y5, Con{y6, Con{y7, Con{y8, Con{y9, Con{y10, Con{y11, Con{y12, Con{y13, Con{y14, Con{y15, Con{z, zs}}}}}}}}}}}}}}}}}) : List<&2, U32>}, h)
833
834# the block of a block's bytes is the block
835def sp.block_bytes(b: M.CmBlock) -> {M.cm.block_of(M.cm.bytes_of(b)) == b : M.CmBlock}:
836  match b:
837    case M.CmBlock{U32{WCon{p0, WCon{p1, WCon{p2, WCon{p3, WCon{p4, WCon{p5, WCon{p6, WCon{p7, WCon{p8, WCon{p9, WCon{p10, WCon{p11, WCon{p12, WCon{p13, WCon{p14, WCon{p15, WCon{p16, WCon{p17, WCon{p18, WCon{p19, WCon{p20, WCon{p21, WCon{p22, WCon{p23, WCon{p24, WCon{p25, WCon{p26, WCon{p27, WCon{p28, WCon{p29, WCon{p30, WCon{p31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{q0, WCon{q1, WCon{q2, WCon{q3, WCon{q4, WCon{q5, WCon{q6, WCon{q7, WCon{q8, WCon{q9, WCon{q10, WCon{q11, WCon{q12, WCon{q13, WCon{q14, WCon{q15, WCon{q16, WCon{q17, WCon{q18, WCon{q19, WCon{q20, WCon{q21, WCon{q22, WCon{q23, WCon{q24, WCon{q25, WCon{q26, WCon{q27, WCon{q28, WCon{q29, WCon{q30, WCon{q31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{r0, WCon{r1, WCon{r2, WCon{r3, WCon{r4, WCon{r5, WCon{r6, WCon{r7, WCon{r8, WCon{r9, WCon{r10, WCon{r11, WCon{r12, WCon{r13, WCon{r14, WCon{r15, WCon{r16, WCon{r17, WCon{r18, WCon{r19, WCon{r20, WCon{r21, WCon{r22, WCon{r23, WCon{r24, WCon{r25, WCon{r26, WCon{r27, WCon{r28, WCon{r29, WCon{r30, WCon{r31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, U32{WCon{s0, WCon{s1, WCon{s2, WCon{s3, WCon{s4, WCon{s5, WCon{s6, WCon{s7, WCon{s8, WCon{s9, WCon{s10, WCon{s11, WCon{s12, WCon{s13, WCon{s14, WCon{s15, WCon{s16, WCon{s17, WCon{s18, WCon{s19, WCon{s20, WCon{s21, WCon{s22, WCon{s23, WCon{s24, WCon{s25, WCon{s26, WCon{s27, WCon{s28, WCon{s29, WCon{s30, WCon{s31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
838      {==}
839
840# Joining and splitting
841
842def sp.split_join(bs: List<&2, M.CmBlock>) -> {M.cm.split(M.cm.join_onto(bs, Nil{})) == M.CmSplit{bs, Nil{}} : M.CmSplit}:
843  match bs:
844    case Nil{}:
845      {==}
846    case Con{+b, +t}:
847      %Equal.sym(M.CmSplit, M.cm.split(M.cm.bytes_onto(b, M.cm.join_onto(t, Nil{}))), M.cm.split.cons(b, M.cm.split(M.cm.join_onto(t, Nil{}))), sp.blk(b, M.cm.join_onto(t, Nil{}))) : {_ == M.CmSplit{Con{b, t}, Nil{}} : M.CmSplit}
848      %Equal.sym(M.CmSplit, M.cm.split(M.cm.join_onto(t, Nil{})), M.CmSplit{t, Nil{}}, sp.split_join(t)) : {M.cm.split.cons(b, _) == M.CmSplit{Con{b, t}, Nil{}} : M.CmSplit}
849      {==}
850
851def sp.mask_join(bs: List<&2, M.CmBlock>) -> {B.mask(M.cm.join_onto(bs, Nil{})) == M.cm.join_onto(bs, Nil{}) : List<&2, U32>}:
852  match bs:
853    case Nil{}:
854      {==}
855    case Con{+b, +t}:
856      %Equal.sym(List<&2, U32>, B.mask(M.cm.bytes_onto(b, M.cm.join_onto(t, Nil{}))), M.cm.bytes_onto(b, B.mask(M.cm.join_onto(t, Nil{}))), sp.mask_blk(b, M.cm.join_onto(t, Nil{}))) : {_ == M.cm.bytes_onto(b, M.cm.join_onto(t, Nil{})) : List<&2, U32>}
857      %Equal.sym(List<&2, U32>, B.mask(M.cm.join_onto(t, Nil{})), M.cm.join_onto(t, Nil{}), sp.mask_join(t)) : {M.cm.bytes_onto(b, _) == M.cm.bytes_onto(b, M.cm.join_onto(t, Nil{})) : List<&2, U32>}
858      {==}
859
860# Every Octets is masked: to_list(o) = to_list(of_list(to_list(o))) = mask(to_list(o))
861def oc.masked(+o: B.Octets) -> {B.mask(B.Octets.to_list(o)) == B.Octets.to_list(o) : List<&2, U32>}:
862  Equal.trans(List<&2, U32>, B.mask(B.Octets.to_list(o)), B.Octets.to_list(B.Octets.of_list(B.Octets.to_list(o))), B.Octets.to_list(o), Equal.sym(List<&2, U32>, B.Octets.to_list(B.Octets.of_list(B.Octets.to_list(o))), B.mask(B.Octets.to_list(o)), BL.octets_to_of(B.Octets.to_list(o))), Equal.cong(B.Octets, List<&2, U32>, x => B.Octets.to_list(x), B.Octets.of_list(B.Octets.to_list(o)), o, BL.octets_of_to(o)))
863
864def oc.len(+o: B.Octets, +n: Nat, h: {B.Octets.len(o) == n : Nat}) -> {B.len(B.Octets.to_list(o)) == n : Nat}:
865  Equal.trans(Nat, B.len(B.Octets.to_list(o)), B.Octets.len(o), n, Equal.sym(Nat, B.Octets.len(o), B.len(B.Octets.to_list(o)), BL.octets_len_list(o)), h)
866
867def oc.mod(+o: B.Octets, h: {Nat.mod(B.Octets.len(o), 16n) == 0n : Nat}) -> {Nat.mod(B.len(B.Octets.to_list(o)), 16n) == 0n : Nat}:
868  Equal.trans(Nat, Nat.mod(B.len(B.Octets.to_list(o)), 16n), Nat.mod(B.Octets.len(o), 16n), 0n, Equal.sym(Nat, Nat.mod(B.Octets.len(o), 16n), Nat.mod(B.len(B.Octets.to_list(o)), 16n), Equal.cong(Nat, Nat, n => Nat.mod(n, 16n), B.Octets.len(o), B.len(B.Octets.to_list(o)), BL.octets_len_list(o))), h)
869
870# a 16-byte IV is the block of its bytes
871def cbcp.iv(+iv: B.Octets, h: {B.Octets.len(iv) == 16n : Nat}) -> {C.cbc.iv(iv) == Done{M.cm.block_of(B.Octets.to_list(iv))} : Result<&2, &2, M.CmError, M.CmBlock>}:
872  %Equal.sym(Nat, B.len(B.Octets.to_list(iv)), 16n, oc.len(iv, 16n, h)) : {M.cm.need_block.pick(Nat.is_eq(_, 16n), B.Octets.to_list(iv), M.CmBadIvLength{B.len(B.Octets.to_list(iv))}) == Done{M.cm.block_of(B.Octets.to_list(iv))} : Result<&2, &2, M.CmError, M.CmBlock>}
873  {==}
874
875
876# The tail-recursive forms the modes run are the structural ones, for every
877# input: each loop with an accumulator is its structural form reversed onto
878# the accumulator, and reversing twice gives the order back. Then the byte
879# layers built from them are the structural byte layers, and so are the
880# public defs (Cbc.encrypt == Cbc.encrypt.ref, ...).
881
882def tr.add_succ(+a: Nat, +n: Nat) -> {Nat.add(a, 1n+n) == 1n+Nat.add(a, n) : Nat}:
883  match a:
884    case 0n:
885      {==}
886    case 1n+q:
887      Equal.cong(Nat, Nat, x => 1n+x, Nat.add(q, 1n+n), 1n+Nat.add(q, n), tr.add_succ(q, n))
888
889def tr.add_zero(+a: Nat) -> {Nat.add(a, 0n) == a : Nat}:
890  match a:
891    case 0n:
892      {==}
893    case 1n+q:
894      Equal.cong(Nat, Nat, x => 1n+x, Nat.add(q, 0n), q, tr.add_zero(q))
895
896def tr.rr(xs: List<&2, M.CmBlock>, acc: List<&2, M.CmBlock>, b: List<&2, M.CmBlock>) -> {M.cm.blocks.rev_onto(M.cm.blocks.rev_onto(xs, acc), b) == M.cm.blocks.rev_onto(acc, List.append(&2, M.CmBlock, xs, b)) : List<&2, M.CmBlock>}:
897  match xs:
898    case Nil{}:
899      {==}
900    case Con{h, t}:
901      tr.rr(t, Con{h, acc}, b)
902
903def tr.append_eq(+xs: List<&2, M.CmBlock>, +ys: List<&2, M.CmBlock>) -> {List.append(&2, M.CmBlock, xs, ys) == M.cm.blocks.append(xs, ys) : List<&2, M.CmBlock>}:
904  Equal.sym(List<&2, M.CmBlock>, M.cm.blocks.append(xs, ys), List.append(&2, M.CmBlock, xs, ys), tr.rr(xs, Nil{}, ys))
905
906def tr.len_go(+bs: List<&2, M.CmBlock>, +n: Nat) -> {M.cm.blocks.len.go(bs, n) == Nat.add(List.length(&2, M.CmBlock, bs), n) : Nat}:
907  match bs:
908    case Nil{}:
909      {==}
910    case Con{h, t}:
911      Equal.trans(Nat, M.cm.blocks.len.go(t, 1n+n), Nat.add(List.length(&2, M.CmBlock, t), 1n+n), 1n+Nat.add(List.length(&2, M.CmBlock, t), n), tr.len_go(t, 1n+n), tr.add_succ(List.length(&2, M.CmBlock, t), n))
912
913def tr.len_eq(+bs: List<&2, M.CmBlock>) -> {List.length(&2, M.CmBlock, bs) == M.cm.blocks.len(bs) : Nat}:
914  Equal.sym(Nat, M.cm.blocks.len(bs), List.length(&2, M.CmBlock, bs), Equal.trans(Nat, M.cm.blocks.len.go(bs, 0n), Nat.add(List.length(&2, M.CmBlock, bs), 0n), List.length(&2, M.CmBlock, bs), tr.len_go(bs, 0n), tr.add_zero(List.length(&2, M.CmBlock, bs))))
915
916# Splitting: the blocks so far, reversed in acc, go in front of the
917# structural split's blocks
918
919def tr.split_fin(acc: List<&2, M.CmBlock>, s: M.CmSplit) -> M.CmSplit:
920  match s:
921    case M.CmSplit{bs, t}:
922      M.CmSplit{M.cm.blocks.rev_onto(acc, bs), t}
923
924def tr.split_fin_cons(+b: M.CmBlock, +acc: List<&2, M.CmBlock>, +s: M.CmSplit) -> {tr.split_fin(Con{b, acc}, s) == tr.split_fin(acc, M.cm.split.cons(b, s)) : M.CmSplit}:
925  match s:
926    case M.CmSplit{bs, t}:
927      {==}
928
929def tr.split_fin_nil(+s: M.CmSplit) -> {tr.split_fin(Nil{}, s) == s : M.CmSplit}:
930  match s:
931    case M.CmSplit{bs, t}:
932      {==}
933
934def tr.split_go(+xs: List<&2, U32>, +acc: List<&2, M.CmBlock>) -> {M.cm.split.go(xs, acc) == tr.split_fin(acc, M.cm.split(xs)) : M.CmSplit}:
935  match xs:
936    case Nil{}:
937      {==}
938    case Con{+y0, +r0}:
939      match r0:
940        case Nil{}:
941          {==}
942        case Con{+y1, +r1}:
943          match r1:
944            case Nil{}:
945              {==}
946            case Con{+y2, +r2}:
947              match r2:
948                case Nil{}:
949                  {==}
950                case Con{+y3, +r3}:
951                  match r3:
952                    case Nil{}:
953                      {==}
954                    case Con{+y4, +r4}:
955                      match r4:
956                        case Nil{}:
957                          {==}
958                        case Con{+y5, +r5}:
959                          match r5:
960                            case Nil{}:
961                              {==}
962                            case Con{+y6, +r6}:
963                              match r6:
964                                case Nil{}:
965                                  {==}
966                                case Con{+y7, +r7}:
967                                  match r7:
968                                    case Nil{}:
969                                      {==}
970                                    case Con{+y8, +r8}:
971                                      match r8:
972                                        case Nil{}:
973                                          {==}
974                                        case Con{+y9, +r9}:
975                                          match r9:
976                                            case Nil{}:
977                                              {==}
978                                            case Con{+y10, +r10}:
979                                              match r10:
980                                                case Nil{}:
981                                                  {==}
982                                                case Con{+y11, +r11}:
983                                                  match r11:
984                                                    case Nil{}:
985                                                      {==}
986                                                    case Con{+y12, +r12}:
987                                                      match r12:
988                                                        case Nil{}:
989                                                          {==}
990                                                        case Con{+y13, +r13}:
991                                                          match r13:
992                                                            case Nil{}:
993                                                              {==}
994                                                            case Con{+y14, +r14}:
995                                                              match r14:
996                                                                case Nil{}:
997                                                                  {==}
998                                                                case Con{+y15, +t}:
999                                                                  Equal.trans(M.CmSplit, M.cm.split.go(t, Con{M.cm.block16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15), acc}), tr.split_fin(Con{M.cm.block16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15), acc}, M.cm.split(t)), tr.split_fin(acc, M.cm.split.cons(M.cm.block16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15), M.cm.split(t))), tr.split_go(t, Con{M.cm.block16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15), acc}), tr.split_fin_cons(M.cm.block16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15), acc, M.cm.split(t)))
1000
1001def tr.split_eq(+xs: List<&2, U32>) -> {M.cm.split(xs) == M.cm.split.fast(xs) : M.CmSplit}:
1002  Equal.sym(M.CmSplit, M.cm.split.fast(xs), M.cm.split(xs), Equal.trans(M.CmSplit, M.cm.split.go(xs, Nil{}), tr.split_fin(Nil{}, M.cm.split(xs)), M.cm.split(xs), tr.split_go(xs, Nil{}), tr.split_fin_nil(M.cm.split(xs))))
1003
1004# Joining
1005
1006def tr.join_go(xs: List<&2, M.CmBlock>, rs: List<&2, M.CmBlock>, +rest: List<&2, U32>) -> {M.cm.join.go(M.cm.blocks.rev_onto(xs, rs), rest) == M.cm.join.go(rs, M.cm.join_onto(xs, rest)) : List<&2, U32>}:
1007  match xs:
1008    case Nil{}:
1009      {==}
1010    case Con{x, t}:
1011      tr.join_go(t, Con{x, rs}, rest)
1012
1013def tr.join_eq(+bs: List<&2, M.CmBlock>, +rest: List<&2, U32>) -> {M.cm.join_onto(bs, rest) == M.cm.join_onto.fast(bs, rest) : List<&2, U32>}:
1014  Equal.sym(List<&2, U32>, M.cm.join_onto.fast(bs, rest), M.cm.join_onto(bs, rest), tr.join_go(bs, Nil{}, rest))
1015
1016# The modes on blocks
1017
1018def tr.cbc_enc_go(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +iv: M.CmBlock, +acc: List<&2, M.CmBlock>) -> {C.cbc.enc.go(~K, ~enc, k, bs, iv, acc) == M.cm.blocks.rev_onto(acc, C.cbc.enc(~K, ~enc, k, bs, iv)) : List<&2, M.CmBlock>}:
1019  match bs:
1020    case Nil{}:
1021      {==}
1022    case Con{+p, +t}:
1023      tr.cbc_enc_go(~K, ~enc, k, t, enc(k, M.CmBlock.xor(iv, p)), Con{enc(k, M.CmBlock.xor(iv, p)), acc})
1024
1025def tr.cbc_enc_eq(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +bs: List<&2, M.CmBlock>, +iv: M.CmBlock) -> {C.cbc.enc(~K, ~enc, k, bs, iv) == C.cbc.enc.fast(~K, ~enc, k, bs, iv) : List<&2, M.CmBlock>}:
1026  Equal.sym(List<&2, M.CmBlock>, C.cbc.enc.fast(~K, ~enc, k, bs, iv), C.cbc.enc(~K, ~enc, k, bs, iv), tr.cbc_enc_go(~K, ~enc, k, bs, iv, Nil{}))
1027
1028def tr.cbc_dec_go(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +iv: M.CmBlock, +acc: List<&2, M.CmBlock>) -> {C.cbc.dec.go(~K, ~dec, k, bs, iv, acc) == M.cm.blocks.rev_onto(acc, C.cbc.dec(~K, ~dec, k, bs, iv)) : List<&2, M.CmBlock>}:
1029  match bs:
1030    case Nil{}:
1031      {==}
1032    case Con{+c, +t}:
1033      tr.cbc_dec_go(~K, ~dec, k, t, c, Con{M.CmBlock.xor(iv, dec(k, c)), acc})
1034
1035def tr.cbc_dec_eq(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +bs: List<&2, M.CmBlock>, +iv: M.CmBlock) -> {C.cbc.dec(~K, ~dec, k, bs, iv) == C.cbc.dec.fast(~K, ~dec, k, bs, iv) : List<&2, M.CmBlock>}:
1036  Equal.sym(List<&2, M.CmBlock>, C.cbc.dec.fast(~K, ~dec, k, bs, iv), C.cbc.dec(~K, ~dec, k, bs, iv), tr.cbc_dec_go(~K, ~dec, k, bs, iv, Nil{}))
1037
1038def tr.xts_enc_go(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +t: M.CmBlock, +acc: List<&2, M.CmBlock>) -> {T.xts.enc.go(~K, ~enc, k, bs, t, acc) == M.cm.blocks.rev_onto(acc, T.xts.enc(~K, ~enc, k, bs, t)) : List<&2, M.CmBlock>}:
1039  match bs:
1040    case Nil{}:
1041      {==}
1042    case Con{+p, +rest}:
1043      tr.xts_enc_go(~K, ~enc, k, rest, T.Xts.mul_alpha(t), Con{T.xts.benc(~K, ~enc, k, p, t), acc})
1044
1045def tr.xts_enc_eq(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +bs: List<&2, M.CmBlock>, +t: M.CmBlock) -> {T.xts.enc(~K, ~enc, k, bs, t) == T.xts.enc.fast(~K, ~enc, k, bs, t) : List<&2, M.CmBlock>}:
1046  Equal.sym(List<&2, M.CmBlock>, T.xts.enc.fast(~K, ~enc, k, bs, t), T.xts.enc(~K, ~enc, k, bs, t), tr.xts_enc_go(~K, ~enc, k, bs, t, Nil{}))
1047
1048def tr.xts_dec_go(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +t: M.CmBlock, +acc: List<&2, M.CmBlock>) -> {T.xts.dec.go(~K, ~dec, k, bs, t, acc) == M.cm.blocks.rev_onto(acc, T.xts.dec(~K, ~dec, k, bs, t)) : List<&2, M.CmBlock>}:
1049  match bs:
1050    case Nil{}:
1051      {==}
1052    case Con{+c, +rest}:
1053      tr.xts_dec_go(~K, ~dec, k, rest, T.Xts.mul_alpha(t), Con{T.xts.bdec(~K, ~dec, k, c, t), acc})
1054
1055def tr.xts_dec_eq(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +bs: List<&2, M.CmBlock>, +t: M.CmBlock) -> {T.xts.dec(~K, ~dec, k, bs, t) == T.xts.dec.fast(~K, ~dec, k, bs, t) : List<&2, M.CmBlock>}:
1056  Equal.sym(List<&2, M.CmBlock>, T.xts.dec.fast(~K, ~dec, k, bs, t), T.xts.dec(~K, ~dec, k, bs, t), tr.xts_dec_go(~K, ~dec, k, bs, t, Nil{}))
1057
1058def tr.init_go(rest: List<&2, M.CmBlock>, +p: M.CmBlock, +acc: List<&2, M.CmBlock>) -> {T.xts.init.go(rest, p, acc) == M.cm.blocks.rev_onto(acc, T.xts.init(rest, p)) : List<&2, M.CmBlock>}:
1059  match rest:
1060    case Nil{}:
1061      {==}
1062    case Con{+q, +r}:
1063      tr.init_go(r, q, Con{p, acc})
1064
1065def tr.init_eq(+rest: List<&2, M.CmBlock>, +p: M.CmBlock) -> {T.xts.init(rest, p) == T.xts.init.fast(rest, p) : List<&2, M.CmBlock>}:
1066  Equal.sym(List<&2, M.CmBlock>, T.xts.init.fast(rest, p), T.xts.init(rest, p), tr.init_go(rest, p, Nil{}))
1067
1068# The byte layers
1069
1070def tr.cbc_e2(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +v: M.CmBlock, s: M.CmSplit, +n: Nat) -> {C.cbc.e2(~K, ~enc, k, v, s, n) == C.cbc.e2.fast(~K, ~enc, k, v, s, n) : Result<&2, &2, M.CmError, B.Octets>}:
1071  match s:
1072    case M.CmSplit{+bs, tail}:
1073      match tail:
1074        case Nil{}:
1075          %tr.cbc_enc_eq(~K, ~enc, k, bs, v) : {Done{B.Octets.of_list(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, bs, v), Nil{}))} == Done{B.Octets.of_list(M.cm.join_onto.fast(_, Nil{}))} : Result<&2, &2, M.CmError, B.Octets>}
1076          %tr.join_eq(C.cbc.enc(~K, ~enc, k, bs, v), Nil{}) : {Done{B.Octets.of_list(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, bs, v), Nil{}))} == Done{B.Octets.of_list(_)} : Result<&2, &2, M.CmError, B.Octets>}
1077          {==}
1078        case Con{h, t}:
1079          {==}
1080
1081def tr.cbc_e1(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, r: Result<&2, &2, M.CmError, M.CmBlock>, +xs: List<&2, U32>) -> {C.cbc.e1(~K, ~enc, k, r, xs) == C.cbc.e1.fast(~K, ~enc, k, r, xs) : Result<&2, &2, M.CmError, B.Octets>}:
1082  match r:
1083    case Fail{e}:
1084      {==}
1085    case Done{+v}:
1086      %tr.split_eq(xs) : {C.cbc.e2(~K, ~enc, k, v, M.cm.split(xs), B.len(xs)) == C.cbc.e2.fast(~K, ~enc, k, v, _, B.len.fast(xs)) : Result<&2, &2, M.CmError, B.Octets>}
1087      %BL.len_fast(xs) : {C.cbc.e2(~K, ~enc, k, v, M.cm.split(xs), B.len(xs)) == C.cbc.e2.fast(~K, ~enc, k, v, M.cm.split(xs), _) : Result<&2, &2, M.CmError, B.Octets>}
1088      tr.cbc_e2(~K, ~enc, k, v, M.cm.split(xs), B.len(xs))
1089
1090def tr.cbc_d2(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +v: M.CmBlock, s: M.CmSplit, +n: Nat) -> {C.cbc.d2(~K, ~dec, k, v, s, n) == C.cbc.d2.fast(~K, ~dec, k, v, s, n) : Result<&2, &2, M.CmError, B.Octets>}:
1091  match s:
1092    case M.CmSplit{+bs, tail}:
1093      match tail:
1094        case Nil{}:
1095          %tr.cbc_dec_eq(~K, ~dec, k, bs, v) : {Done{B.Octets.of_list(M.cm.join_onto(C.cbc.dec(~K, ~dec, k, bs, v), Nil{}))} == Done{B.Octets.of_list(M.cm.join_onto.fast(_, Nil{}))} : Result<&2, &2, M.CmError, B.Octets>}
1096          %tr.join_eq(C.cbc.dec(~K, ~dec, k, bs, v), Nil{}) : {Done{B.Octets.of_list(M.cm.join_onto(C.cbc.dec(~K, ~dec, k, bs, v), Nil{}))} == Done{B.Octets.of_list(_)} : Result<&2, &2, M.CmError, B.Octets>}
1097          {==}
1098        case Con{h, t}:
1099          {==}
1100
1101def tr.cbc_d1(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, r: Result<&2, &2, M.CmError, M.CmBlock>, +xs: List<&2, U32>) -> {C.cbc.d1(~K, ~dec, k, r, xs) == C.cbc.d1.fast(~K, ~dec, k, r, xs) : Result<&2, &2, M.CmError, B.Octets>}:
1102  match r:
1103    case Fail{e}:
1104      {==}
1105    case Done{+v}:
1106      %tr.split_eq(xs) : {C.cbc.d2(~K, ~dec, k, v, M.cm.split(xs), B.len(xs)) == C.cbc.d2.fast(~K, ~dec, k, v, _, B.len.fast(xs)) : Result<&2, &2, M.CmError, B.Octets>}
1107      %BL.len_fast(xs) : {C.cbc.d2(~K, ~dec, k, v, M.cm.split(xs), B.len(xs)) == C.cbc.d2.fast(~K, ~dec, k, v, M.cm.split(xs), _) : Result<&2, &2, M.CmError, B.Octets>}
1108      tr.cbc_d2(~K, ~dec, k, v, M.cm.split(xs), B.len(xs))
1109
1110def tr.cbc_encrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +iv: B.Octets, +m: B.Octets) -> {C.Cbc.encrypt.ref(~K, ~enc, k, iv, m) == C.Cbc.encrypt(~K, ~enc, k, iv, m) : Result<&2, &2, M.CmError, B.Octets>}:
1111  tr.cbc_e1(~K, ~enc, k, C.cbc.iv(iv), B.Octets.to_list(m))
1112
1113def tr.cbc_decrypt(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +iv: B.Octets, +c: B.Octets) -> {C.Cbc.decrypt.ref(~K, ~dec, k, iv, c) == C.Cbc.decrypt(~K, ~dec, k, iv, c) : Result<&2, &2, M.CmError, B.Octets>}:
1114  tr.cbc_d1(~K, ~dec, k, C.cbc.iv(iv), B.Octets.to_list(c))
1115
1116def tr.xts_eout(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +t: M.CmBlock, +init: List<&2, M.CmBlock>, +last: M.CmBlock, +tail: List<&2, U32>) -> {T.xts.eout(~K, ~enc, k, t, init, last, tail) == T.xts.eout.fast(~K, ~enc, k, t, init, last, tail) : List<&2, U32>}:
1117  %tr.len_eq(init) : {T.xts.eout(~K, ~enc, k, t, init, last, tail) == M.cm.join_onto.fast(M.cm.blocks.append(T.xts.enc.fast(~K, ~enc, k, init, t), Con{T.xts.steal_c(~K, ~enc, k, last, tail, T.xts.alpha_n(_, t)), Nil{}}), T.xts.steal_t(~K, ~enc, k, last, tail, T.xts.alpha_n(_, t))) : List<&2, U32>}
1118  %tr.xts_enc_eq(~K, ~enc, k, init, t) : {T.xts.eout(~K, ~enc, k, t, init, last, tail) == M.cm.join_onto.fast(M.cm.blocks.append(_, Con{T.xts.steal_c(~K, ~enc, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t)), Nil{}}), T.xts.steal_t(~K, ~enc, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t))) : List<&2, U32>}
1119  %tr.append_eq(T.xts.enc(~K, ~enc, k, init, t), Con{T.xts.steal_c(~K, ~enc, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t)), Nil{}}) : {T.xts.eout(~K, ~enc, k, t, init, last, tail) == M.cm.join_onto.fast(_, T.xts.steal_t(~K, ~enc, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t))) : List<&2, U32>}
1120  %tr.join_eq(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k, init, t), Con{T.xts.steal_c(~K, ~enc, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t)), Nil{}}), T.xts.steal_t(~K, ~enc, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t))) : {T.xts.eout(~K, ~enc, k, t, init, last, tail) == _ : List<&2, U32>}
1121  {==}
1122
1123def tr.xts_dout(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +t: M.CmBlock, +init: List<&2, M.CmBlock>, +last: M.CmBlock, +tail: List<&2, U32>) -> {T.xts.dout(~K, ~dec, k, t, init, last, tail) == T.xts.dout.fast(~K, ~dec, k, t, init, last, tail) : List<&2, U32>}:
1124  %tr.len_eq(init) : {T.xts.dout(~K, ~dec, k, t, init, last, tail) == M.cm.join_onto.fast(T.xts.dec.fast(~K, ~dec, k, init, t), T.xts.dsteal(~K, ~dec, k, last, tail, T.xts.alpha_n(_, t))) : List<&2, U32>}
1125  %tr.xts_dec_eq(~K, ~dec, k, init, t) : {T.xts.dout(~K, ~dec, k, t, init, last, tail) == M.cm.join_onto.fast(_, T.xts.dsteal(~K, ~dec, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t))) : List<&2, U32>}
1126  %tr.join_eq(T.xts.dec(~K, ~dec, k, init, t), T.xts.dsteal(~K, ~dec, k, last, tail, T.xts.alpha_n(List.length(&2, M.CmBlock, init), t))) : {T.xts.dout(~K, ~dec, k, t, init, last, tail) == _ : List<&2, U32>}
1127  {==}
1128
1129def tr.xts_e2(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +t: M.CmBlock, s: M.CmSplit, +n: Nat) -> {T.xts.e2(~K, ~enc, k, t, s, n) == T.xts.e2.fast(~K, ~enc, k, t, s, n) : Result<&2, &2, M.CmError, B.Octets>}:
1130  match s:
1131    case M.CmSplit{bs, +tail}:
1132      match bs:
1133        case Nil{}:
1134          {==}
1135        case Con{+p, +rest}:
1136          %tr.init_eq(rest, p) : {Done{B.Octets.of_list(T.xts.eout(~K, ~enc, k, t, T.xts.init(rest, p), T.xts.last(rest, p), tail))} == Done{B.Octets.of_list(T.xts.eout.fast(~K, ~enc, k, t, _, T.xts.last(rest, p), tail))} : Result<&2, &2, M.CmError, B.Octets>}
1137          %tr.xts_eout(~K, ~enc, k, t, T.xts.init(rest, p), T.xts.last(rest, p), tail) : {Done{B.Octets.of_list(T.xts.eout(~K, ~enc, k, t, T.xts.init(rest, p), T.xts.last(rest, p), tail))} == Done{B.Octets.of_list(_)} : Result<&2, &2, M.CmError, B.Octets>}
1138          {==}
1139
1140def tr.xts_d2(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +t: M.CmBlock, s: M.CmSplit, +n: Nat) -> {T.xts.d2(~K, ~dec, k, t, s, n) == T.xts.d2.fast(~K, ~dec, k, t, s, n) : Result<&2, &2, M.CmError, B.Octets>}:
1141  match s:
1142    case M.CmSplit{bs, +tail}:
1143      match bs:
1144        case Nil{}:
1145          {==}
1146        case Con{+c, +rest}:
1147          %tr.init_eq(rest, c) : {Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, T.xts.init(rest, c), T.xts.last(rest, c), tail))} == Done{B.Octets.of_list(T.xts.dout.fast(~K, ~dec, k, t, _, T.xts.last(rest, c), tail))} : Result<&2, &2, M.CmError, B.Octets>}
1148          %tr.xts_dout(~K, ~dec, k, t, T.xts.init(rest, c), T.xts.last(rest, c), tail) : {Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, T.xts.init(rest, c), T.xts.last(rest, c), tail))} == Done{B.Octets.of_list(_)} : Result<&2, &2, M.CmError, B.Octets>}
1149          {==}
1150
1151def tr.xts_e1(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, r: Result<&2, &2, M.CmError, M.CmBlock>, +xs: List<&2, U32>) -> {T.xts.e1(~K, ~enc, k, r, xs) == T.xts.e1.fast(~K, ~enc, k, r, xs) : Result<&2, &2, M.CmError, B.Octets>}:
1152  match r:
1153    case Fail{e}:
1154      {==}
1155    case Done{+t}:
1156      %tr.split_eq(xs) : {T.xts.e2(~K, ~enc, k, t, M.cm.split(xs), B.len(xs)) == T.xts.e2.fast(~K, ~enc, k, t, _, B.len.fast(xs)) : Result<&2, &2, M.CmError, B.Octets>}
1157      %BL.len_fast(xs) : {T.xts.e2(~K, ~enc, k, t, M.cm.split(xs), B.len(xs)) == T.xts.e2.fast(~K, ~enc, k, t, M.cm.split(xs), _) : Result<&2, &2, M.CmError, B.Octets>}
1158      tr.xts_e2(~K, ~enc, k, t, M.cm.split(xs), B.len(xs))
1159
1160def tr.xts_d1(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, r: Result<&2, &2, M.CmError, M.CmBlock>, +xs: List<&2, U32>) -> {T.xts.d1(~K, ~dec, k, r, xs) == T.xts.d1.fast(~K, ~dec, k, r, xs) : Result<&2, &2, M.CmError, B.Octets>}:
1161  match r:
1162    case Fail{e}:
1163      {==}
1164    case Done{+t}:
1165      %tr.split_eq(xs) : {T.xts.d2(~K, ~dec, k, t, M.cm.split(xs), B.len(xs)) == T.xts.d2.fast(~K, ~dec, k, t, _, B.len.fast(xs)) : Result<&2, &2, M.CmError, B.Octets>}
1166      %BL.len_fast(xs) : {T.xts.d2(~K, ~dec, k, t, M.cm.split(xs), B.len(xs)) == T.xts.d2.fast(~K, ~dec, k, t, M.cm.split(xs), _) : Result<&2, &2, M.CmError, B.Octets>}
1167      tr.xts_d2(~K, ~dec, k, t, M.cm.split(xs), B.len(xs))
1168
1169def tr.xts_encrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k1: K, +k2: K, +i: B.Octets, +p: B.Octets) -> {T.Xts.encrypt.ref(~K, ~enc, k1, k2, i, p) == T.Xts.encrypt(~K, ~enc, k1, k2, i, p) : Result<&2, &2, M.CmError, B.Octets>}:
1170  tr.xts_e1(~K, ~enc, k1, T.xts.tweak(~K, ~enc, k2, i), B.Octets.to_list(p))
1171
1172def tr.xts_decrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, ~dec: K -> M.CmBlock -> M.CmBlock, +k1: K, +k2: K, +i: B.Octets, +c: B.Octets) -> {T.Xts.decrypt.ref(~K, ~enc, ~dec, k1, k2, i, c) == T.Xts.decrypt(~K, ~enc, ~dec, k1, k2, i, c) : Result<&2, &2, M.CmError, B.Octets>}:
1173  tr.xts_d1(~K, ~dec, k1, T.xts.tweak(~K, ~enc, k2, i), B.Octets.to_list(c))
1174
1175# a bind whose continuations agree on every value agrees
1176def tr.bind_cong(r: Result<&2, &2, M.CmError, B.Octets>, f: B.Octets -> Result<&2, &2, M.CmError, B.Octets>, g: B.Octets -> Result<&2, &2, M.CmError, B.Octets>, h: @c: B.Octets -> {f(c) == g(c) : Result<&2, &2, M.CmError, B.Octets>}) -> {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, r, f) == Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, r, g) : Result<&2, &2, M.CmError, B.Octets>}:
1177  match r:
1178    case Fail{e}:
1179      {==}
1180    case Done{c}:
1181      h(c)
1182
1183
1184# CCM: the tail-recursive forms are the structural ones, piece by piece
1185
1186def tr.pad(+xs: List<&2, U32>) -> {CC.ccm.pad(xs) == CC.ccm.pad.fast(xs) : List<&2, U32>}:
1187  %BL.len_fast(xs) : {CC.ccm.pad(xs) == B.append.fast(xs, B.zeros(Nat.mod(Nat.sub(16n, Nat.mod(_, 16n)), 16n))) : List<&2, U32>}
1188  %BL.append_fast(xs, B.zeros(Nat.mod(Nat.sub(16n, Nat.mod(B.len(xs), 16n)), 16n))) : {CC.ccm.pad(xs) == _ : List<&2, U32>}
1189  {==}
1190
1191def tr.aad(empty: Bool, +a: List<&2, U32>) -> {CC.ccm.aad.pick(empty, a) == CC.ccm.aad.pick.fast(empty, a) : List<&2, U32>}:
1192  match empty:
1193    case True{}:
1194      {==}
1195    case False{}:
1196      %BL.len_fast(a) : {CC.ccm.aad.pick(False{}, a) == CC.ccm.pad.fast(B.append(CC.ccm.alen.pick(U32.is_lt(U32.from_nat(_), 65280), U32.from_nat(_)), a)) : List<&2, U32>}
1197      %tr.pad(B.append(CC.ccm.alen.pick(U32.is_lt(U32.from_nat(B.len(a)), 65280), U32.from_nat(B.len(a))), a)) : {CC.ccm.aad.pick(False{}, a) == _ : List<&2, U32>}
1198      {==}
1199
1200def tr.mac(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +l: Nat, +nonce: List<&2, U32>, +a: List<&2, U32>, +p: List<&2, U32>) -> {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.mac.fast(~K, ~enc, k, m, l, nonce, a, p) : M.CmBlock}:
1201  %BL.len_fast(a) : {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.cbcmac(~K, ~enc, k, M.cm.split.blocks(M.cm.split.fast(B.append(Con{U32.from_nat(Nat.add(Nat.add(Nat.mul(64n, Nat.min(_, 1n)), Nat.mul(8n, Nat.div(Nat.sub(m, 2n), 2n))), Nat.sub(l, 1n))), B.append(nonce, CC.ccm.be(l, U32.from_nat(B.len.fast(p))))}, B.append.fast(CC.ccm.aad.pick.fast(Nat.is_eq(_, 0n), a), CC.ccm.pad.fast(p))))), M.CmBlock.zero()) : M.CmBlock}
1202  %BL.len_fast(p) : {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.cbcmac(~K, ~enc, k, M.cm.split.blocks(M.cm.split.fast(B.append(Con{U32.from_nat(Nat.add(Nat.add(Nat.mul(64n, Nat.min(B.len(a), 1n)), Nat.mul(8n, Nat.div(Nat.sub(m, 2n), 2n))), Nat.sub(l, 1n))), B.append(nonce, CC.ccm.be(l, U32.from_nat(_)))}, B.append.fast(CC.ccm.aad.pick.fast(Nat.is_eq(B.len(a), 0n), a), CC.ccm.pad.fast(p))))), M.CmBlock.zero()) : M.CmBlock}
1203  %tr.pad(p) : {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.cbcmac(~K, ~enc, k, M.cm.split.blocks(M.cm.split.fast(B.append(Con{U32.from_nat(Nat.add(Nat.add(Nat.mul(64n, Nat.min(B.len(a), 1n)), Nat.mul(8n, Nat.div(Nat.sub(m, 2n), 2n))), Nat.sub(l, 1n))), B.append(nonce, CC.ccm.be(l, U32.from_nat(B.len(p))))}, B.append.fast(CC.ccm.aad.pick.fast(Nat.is_eq(B.len(a), 0n), a), _)))), M.CmBlock.zero()) : M.CmBlock}
1204  %tr.aad(Nat.is_eq(B.len(a), 0n), a) : {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.cbcmac(~K, ~enc, k, M.cm.split.blocks(M.cm.split.fast(B.append(Con{U32.from_nat(Nat.add(Nat.add(Nat.mul(64n, Nat.min(B.len(a), 1n)), Nat.mul(8n, Nat.div(Nat.sub(m, 2n), 2n))), Nat.sub(l, 1n))), B.append(nonce, CC.ccm.be(l, U32.from_nat(B.len(p))))}, B.append.fast(_, CC.ccm.pad(p))))), M.CmBlock.zero()) : M.CmBlock}
1205  %BL.append_fast(CC.ccm.aad.pick(Nat.is_eq(B.len(a), 0n), a), CC.ccm.pad(p)) : {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.cbcmac(~K, ~enc, k, M.cm.split.blocks(M.cm.split.fast(B.append(Con{U32.from_nat(Nat.add(Nat.add(Nat.mul(64n, Nat.min(B.len(a), 1n)), Nat.mul(8n, Nat.div(Nat.sub(m, 2n), 2n))), Nat.sub(l, 1n))), B.append(nonce, CC.ccm.be(l, U32.from_nat(B.len(p))))}, _))), M.CmBlock.zero()) : M.CmBlock}
1206  %tr.split_eq(B.append(Con{U32.from_nat(Nat.add(Nat.add(Nat.mul(64n, Nat.min(B.len(a), 1n)), Nat.mul(8n, Nat.div(Nat.sub(m, 2n), 2n))), Nat.sub(l, 1n))), B.append(nonce, CC.ccm.be(l, U32.from_nat(B.len(p))))}, B.append(CC.ccm.aad.pick(Nat.is_eq(B.len(a), 0n), a), CC.ccm.pad(p)))) : {CC.ccm.mac(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.cbcmac(~K, ~enc, k, M.cm.split.blocks(_), M.CmBlock.zero()) : M.CmBlock}
1207  {==}
1208
1209def tr.tag(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +l: Nat, +nonce: List<&2, U32>, +a: List<&2, U32>, +p: List<&2, U32>) -> {CC.ccm.tag(~K, ~enc, k, m, l, nonce, a, p) == CC.ccm.tag.fast(~K, ~enc, k, m, l, nonce, a, p) : List<&2, U32>}:
1210  %tr.mac(~K, ~enc, k, m, l, nonce, a, p) : {CC.ccm.tag(~K, ~enc, k, m, l, nonce, a, p) == B.take(m, M.cm.bytes_of(_)) : List<&2, U32>}
1211  {==}
1212
1213def tr.ctrb_go(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +a0: M.CmBlock, +i: U32, +acc: List<&2, M.CmBlock>) -> {CC.ccm.ctrb.go(~K, ~enc, k, bs, a0, i, acc) == M.cm.blocks.rev_onto(acc, CC.ccm.ctrb(~K, ~enc, k, bs, a0, i)) : List<&2, M.CmBlock>}:
1214  match bs:
1215    case Nil{}:
1216      {==}
1217    case Con{+b, +rest}:
1218      tr.ctrb_go(~K, ~enc, k, rest, a0, U32.add(i, 1), Con{M.CmBlock.xor(b, enc(k, CC.ccm.ai(a0, i))), acc})
1219
1220def tr.ctrb_eq(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +bs: List<&2, M.CmBlock>, +a0: M.CmBlock, +i: U32) -> {CC.ccm.ctrb(~K, ~enc, k, bs, a0, i) == CC.ccm.ctrb.fast(~K, ~enc, k, bs, a0, i) : List<&2, M.CmBlock>}:
1221  Equal.sym(List<&2, M.CmBlock>, CC.ccm.ctrb.fast(~K, ~enc, k, bs, a0, i), CC.ccm.ctrb(~K, ~enc, k, bs, a0, i), tr.ctrb_go(~K, ~enc, k, bs, a0, i, Nil{}))
1222
1223def tr.xcrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, s: M.CmSplit) -> {CC.ccm.xcrypt(~K, ~enc, k, a0, s) == CC.ccm.xcrypt.fast(~K, ~enc, k, a0, s) : List<&2, U32>}:
1224  match s:
1225    case M.CmSplit{+bs, +tail}:
1226      %tr.len_eq(bs) : {CC.ccm.xcrypt(~K, ~enc, k, a0, M.CmSplit{bs, tail}) == M.cm.join_onto.fast(CC.ccm.ctrb.fast(~K, ~enc, k, bs, a0, 1), M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(_))))))) : List<&2, U32>}
1227      %tr.ctrb_eq(~K, ~enc, k, bs, a0, 1) : {CC.ccm.xcrypt(~K, ~enc, k, a0, M.CmSplit{bs, tail}) == M.cm.join_onto.fast(_, M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs)))))))) : List<&2, U32>}
1228      %tr.join_eq(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs)))))))) : {CC.ccm.xcrypt(~K, ~enc, k, a0, M.CmSplit{bs, tail}) == _ : List<&2, U32>}
1229      {==}
1230
1231def tr.ebody(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>) -> {CC.ccm.ebody(~K, ~enc, k, m, nv, av, pv) == CC.ccm.ebody.fast(~K, ~enc, k, m, nv, av, pv) : List<&2, U32>}:
1232  %tr.split_eq(pv) : {CC.ccm.ebody(~K, ~enc, k, m, nv, av, pv) == B.append.fast(CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), _), M.cm.xor_bytes(CC.ccm.tag.fast(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : List<&2, U32>}
1233  %tr.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)) : {CC.ccm.ebody(~K, ~enc, k, m, nv, av, pv) == B.append.fast(_, M.cm.xor_bytes(CC.ccm.tag.fast(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : List<&2, U32>}
1234  %tr.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv) : {CC.ccm.ebody(~K, ~enc, k, m, nv, av, pv) == B.append.fast(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(_, M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : List<&2, U32>}
1235  %BL.append_fast(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : {CC.ccm.ebody(~K, ~enc, k, m, nv, av, pv) == _ : List<&2, U32>}
1236  {==}
1237
1238def tr.e2(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>, r: Result<&2, &2, M.CmError, Unit>) -> {CC.ccm.e2(~K, ~enc, k, m, nv, av, pv, r) == CC.ccm.e2.fast(~K, ~enc, k, m, nv, av, pv, r) : Result<&2, &2, M.CmError, B.Octets>}:
1239  match r:
1240    case Fail{e}:
1241      {==}
1242    case Done{u}:
1243      %tr.ebody(~K, ~enc, k, m, nv, av, pv) : {Done{B.Octets.of_list(CC.ccm.ebody(~K, ~enc, k, m, nv, av, pv))} == Done{B.Octets.of_list(_)} : Result<&2, &2, M.CmError, B.Octets>}
1244      {==}
1245
1246def tr.ccm_encrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nonce: B.Octets, +aad: B.Octets, +p: B.Octets) -> {CC.Ccm.encrypt.ref(~K, ~enc, k, m, nonce, aad, p) == CC.Ccm.encrypt(~K, ~enc, k, m, nonce, aad, p) : Result<&2, &2, M.CmError, B.Octets>}:
1247  %BL.len_fast(B.Octets.to_list(p)) : {CC.Ccm.encrypt.ref(~K, ~enc, k, m, nonce, aad, p) == CC.ccm.e2.fast(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p), CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), _)) : Result<&2, &2, M.CmError, B.Octets>}
1248  tr.e2(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p), CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), B.len(B.Octets.to_list(p))))
1249
1250def tr.dbody(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +cv: List<&2, U32>) -> {CC.ccm.dbody(~K, ~enc, k, m, nv, av, cv) == CC.ccm.dbody.fast(~K, ~enc, k, m, nv, av, cv) : Result<&2, &2, M.CmError, B.Octets>}:
1251  %BL.len_fast(cv) : {CC.ccm.dbody(~K, ~enc, k, m, nv, av, cv) == CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(Nat.sub(_, m), cv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))), CC.ccm.tag.fast(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split.fast(B.take.fast(Nat.sub(_, m), cv))))), CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split.fast(B.take.fast(Nat.sub(_, m), cv)))) : Result<&2, &2, M.CmError, B.Octets>}
1252  %BL.take_fast(Nat.sub(B.len(cv), m), cv) : {CC.ccm.dbody(~K, ~enc, k, m, nv, av, cv) == CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(Nat.sub(B.len(cv), m), cv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))), CC.ccm.tag.fast(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split.fast(_)))), CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split.fast(_))) : Result<&2, &2, M.CmError, B.Octets>}
1253  %tr.split_eq(B.take(Nat.sub(B.len(cv), m), cv)) : {CC.ccm.dbody(~K, ~enc, k, m, nv, av, cv) == CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(Nat.sub(B.len(cv), m), cv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))), CC.ccm.tag.fast(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), _))), CC.ccm.xcrypt.fast(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), _)) : Result<&2, &2, M.CmError, B.Octets>}
1254  %tr.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(B.take(Nat.sub(B.len(cv), m), cv))) : {CC.ccm.dbody(~K, ~enc, k, m, nv, av, cv) == CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(Nat.sub(B.len(cv), m), cv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))), CC.ccm.tag.fast(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, _)), _) : Result<&2, &2, M.CmError, B.Octets>}
1255  %tr.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(B.take(Nat.sub(B.len(cv), m), cv)))) : {CC.ccm.dbody(~K, ~enc, k, m, nv, av, cv) == CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(Nat.sub(B.len(cv), m), cv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))), _), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(B.take(Nat.sub(B.len(cv), m), cv)))) : Result<&2, &2, M.CmError, B.Octets>}
1256  {==}
1257
1258def tr.d3(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +cv: List<&2, U32>, r: Result<&2, &2, M.CmError, Unit>) -> {CC.ccm.d3(~K, ~enc, k, m, nv, av, cv, r) == CC.ccm.d3.fast(~K, ~enc, k, m, nv, av, cv, r) : Result<&2, &2, M.CmError, B.Octets>}:
1259  match r:
1260    case Fail{e}:
1261      {==}
1262    case Done{u}:
1263      tr.dbody(~K, ~enc, k, m, nv, av, cv)
1264
1265def tr.d2(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, ok: Bool, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +cv: List<&2, U32>) -> {CC.ccm.d2(~K, ~enc, ok, k, m, nv, av, cv) == CC.ccm.d2.fast(~K, ~enc, ok, k, m, nv, av, cv) : Result<&2, &2, M.CmError, B.Octets>}:
1266  match ok:
1267    case False{}:
1268      %BL.len_fast(cv) : {CC.ccm.d2(~K, ~enc, False{}, k, m, nv, av, cv) == Fail{M.CmTooShort{_}} : Result<&2, &2, M.CmError, B.Octets>}
1269      {==}
1270    case True{}:
1271      %BL.len_fast(cv) : {CC.ccm.d2(~K, ~enc, True{}, k, m, nv, av, cv) == CC.ccm.d3.fast(~K, ~enc, k, m, nv, av, cv, CC.ccm.checks(m, B.len(nv), Nat.sub(_, m))) : Result<&2, &2, M.CmError, B.Octets>}
1272      tr.d3(~K, ~enc, k, m, nv, av, cv, CC.ccm.checks(m, B.len(nv), Nat.sub(B.len(cv), m)))
1273
1274def tr.ccm_decrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nonce: B.Octets, +aad: B.Octets, +c: B.Octets) -> {CC.Ccm.decrypt.ref(~K, ~enc, k, m, nonce, aad, c) == CC.Ccm.decrypt(~K, ~enc, k, m, nonce, aad, c) : Result<&2, &2, M.CmError, B.Octets>}:
1275  %BL.len_fast(B.Octets.to_list(c)) : {CC.Ccm.decrypt.ref(~K, ~enc, k, m, nonce, aad, c) == CC.ccm.d2.fast(~K, ~enc, Nat.is_le(m, _), k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(c)) : Result<&2, &2, M.CmError, B.Octets>}
1276  tr.d2(~K, ~enc, Nat.is_le(m, B.len(B.Octets.to_list(c))), k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(c))
1277
1278# CBC on blocks
1279
1280def cbcp.go(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, ~dec: K -> M.CmBlock -> M.CmBlock, ~inv: @k: K -> @b: M.CmBlock -> {dec(k, enc(k, b)) == b : M.CmBlock}, +k: K, bs: List<&2, M.CmBlock>, +iv: M.CmBlock) -> {C.cbc.dec(~K, ~dec, k, C.cbc.enc(~K, ~enc, k, bs, iv), iv) == bs : List<&2, M.CmBlock>}:
1281  match bs:
1282    case Nil{}:
1283      {==}
1284    case Con{+p, +t}:
1285      %Equal.sym(M.CmBlock, dec(k, enc(k, M.CmBlock.xor(iv, p))), M.CmBlock.xor(iv, p), inv(k, M.CmBlock.xor(iv, p))) : {Con{M.CmBlock.xor(iv, _), C.cbc.dec(~K, ~dec, k, C.cbc.enc(~K, ~enc, k, t, enc(k, M.CmBlock.xor(iv, p))), enc(k, M.CmBlock.xor(iv, p)))} == Con{p, t} : List<&2, M.CmBlock>}
1286      %bx.block(iv, p) : {Con{M.CmBlock.xor(iv, M.CmBlock.xor(iv, p)), C.cbc.dec(~K, ~dec, k, C.cbc.enc(~K, ~enc, k, t, enc(k, M.CmBlock.xor(iv, p))), enc(k, M.CmBlock.xor(iv, p)))} == Con{_, t} : List<&2, M.CmBlock>}
1287      %cbcp.go(~K, ~enc, ~dec, ~inv, k, t, enc(k, M.CmBlock.xor(iv, p))) : {Con{M.CmBlock.xor(iv, M.CmBlock.xor(iv, p)), C.cbc.dec(~K, ~dec, k, C.cbc.enc(~K, ~enc, k, t, enc(k, M.CmBlock.xor(iv, p))), enc(k, M.CmBlock.xor(iv, p)))} == Con{M.CmBlock.xor(iv, M.CmBlock.xor(iv, p)), _} : List<&2, M.CmBlock>}
1288      {==}
1289
1290def Laws.cbc_blocks_round_trip(K, enc, dec, inv, k, iv, bs):
1291  +v = iv
1292  +b = bs
1293  # the tail-recursive forms are the structural ones
1294  %tr.cbc_enc_eq(~K, ~enc, k, b, v) : {C.cbc.dec.fast(~K, ~dec, k, _, iv) == bs : List<&2, M.CmBlock>}
1295  %tr.cbc_dec_eq(~K, ~dec, k, C.cbc.enc(~K, ~enc, k, b, v), v) : {_ == bs : List<&2, M.CmBlock>}
1296  cbcp.go(~K, ~enc, ~dec, ~inv, k, b, v)
1297
1298def Laws.cbc_round_trip(K, enc, dec, inv, k, iv, m, hi, hm):
1299  +et = sp.mod_tail(B.Octets.to_list(m))(oc.mod(m, hm))
1300  # the public defs are the structural ones
1301  %tr.cbc_encrypt(~K, ~enc, k, iv, m) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, _, c => C.Cbc.decrypt(~K, ~dec, k, iv, c)) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1302  %tr.bind_cong(C.Cbc.encrypt.ref(~K, ~enc, k, iv, m), c => C.Cbc.decrypt.ref(~K, ~dec, k, iv, c), c => C.Cbc.decrypt(~K, ~dec, k, iv, c), c => tr.cbc_decrypt(~K, ~dec, k, iv, c)) : {_ == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1303  # the IV is a block
1304  %Equal.sym(Result<&2, &2, M.CmError, M.CmBlock>, C.cbc.iv(iv), Done{M.cm.block_of(B.Octets.to_list(iv))}, cbcp.iv(iv, hi)) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, C.cbc.e1(~K, ~enc, k, _, B.Octets.to_list(m)), c => C.cbc.d1(~K, ~dec, k, _, B.Octets.to_list(c))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1305  # the message is masked
1306  %oc.masked(m) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, C.cbc.e2(~K, ~enc, k, M.cm.block_of(B.Octets.to_list(iv)), M.cm.split(_), B.len(B.Octets.to_list(m))), c => C.cbc.d1(~K, ~dec, k, Done{M.cm.block_of(B.Octets.to_list(iv))}, B.Octets.to_list(c))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1307  # its split is its blocks and tail
1308  %sp.eta(M.cm.split(B.mask(B.Octets.to_list(m)))) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, C.cbc.e2(~K, ~enc, k, M.cm.block_of(B.Octets.to_list(iv)), _, B.len(B.Octets.to_list(m))), c => C.cbc.d1(~K, ~dec, k, Done{M.cm.block_of(B.Octets.to_list(iv))}, B.Octets.to_list(c))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1309  # whole blocks leave no tail, so encryption succeeds
1310  %Equal.sym(List<&2, U32>, M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(m)))), Nil{}, et) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, C.cbc.e2(~K, ~enc, k, M.cm.block_of(B.Octets.to_list(iv)), M.CmSplit{M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), _}, B.len(B.Octets.to_list(m))), c => C.cbc.d1(~K, ~dec, k, Done{M.cm.block_of(B.Octets.to_list(iv))}, B.Octets.to_list(c))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1311  # decryption reads the ciphertext's bytes back, masked
1312  %Equal.sym(List<&2, U32>, B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}))), B.mask(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{})), BL.octets_to_of(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}))) : {C.cbc.d2(~K, ~dec, k, M.cm.block_of(B.Octets.to_list(iv)), M.cm.split(_), B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}))))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1313  # which they already are
1314  %Equal.sym(List<&2, U32>, B.mask(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{})), M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}), sp.mask_join(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))))) : {C.cbc.d2(~K, ~dec, k, M.cm.block_of(B.Octets.to_list(iv)), M.cm.split(_), B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}))))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1315  # and they split into the ciphertext blocks
1316  %Equal.sym(M.CmSplit, M.cm.split(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{})), M.CmSplit{C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}}, sp.split_join(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))))) : {C.cbc.d2(~K, ~dec, k, M.cm.block_of(B.Octets.to_list(iv)), _, B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), Nil{}))))) == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1317  # CBC on blocks
1318  %Equal.sym(List<&2, M.CmBlock>, C.cbc.dec(~K, ~dec, k, C.cbc.enc(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv))), M.cm.block_of(B.Octets.to_list(iv))), M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), cbcp.go(~K, ~enc, ~dec, ~inv, k, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.block_of(B.Octets.to_list(iv)))) : {Done{B.Octets.of_list(M.cm.join_onto(_, Nil{}))} == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1319  # the plaintext blocks and the empty tail
1320  %et : {Done{B.Octets.of_list(M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), _))} == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1321  # join back to the message
1322  %Equal.sym(List<&2, U32>, M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(m)))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(m))))), B.mask(B.Octets.to_list(m)), sp.join_split(B.Octets.to_list(m))) : {Done{B.Octets.of_list(_)} == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1323  # 
1324  %Equal.sym(List<&2, U32>, B.mask(B.Octets.to_list(m)), B.Octets.to_list(m), oc.masked(m)) : {Done{B.Octets.of_list(_)} == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1325  # 
1326  %Equal.sym(B.Octets, B.Octets.of_list(B.Octets.to_list(m)), m, BL.octets_of_to(m)) : {Done{_} == Done{m} : Result<&2, &2, M.CmError, B.Octets>}
1327  {==}
1328
1329# XOR, cancelling on the right: xor(xor(a, b), b) == a
1330
1331def bx.rbool(a: Bool, b: Bool) -> {Bool.xor(Bool.xor(a, b), b) == a : Bool}:
1332  match a b:
1333    case False{} False{}:
1334      {==}
1335    case False{} True{}:
1336      {==}
1337    case True{} False{}:
1338      {==}
1339    case True{} True{}:
1340      {==}
1341
1342def bx.rword(n: Nat, a: Word(n), b: Word(n)) -> {Word.xor(n, Word.xor(n, a, b), b) == a : Word(n)}:
1343  match n:
1344    case 0n:
1345      match a:
1346        case WNil{}:
1347          {==}
1348    case 1n+p:
1349      match a b:
1350        case WCon{ah, at} WCon{bh, bt}:
1351          %bx.rbool(ah, bh) : {WCon{Bool.xor(Bool.xor(ah, bh), bh), Word.xor(p, Word.xor(p, at, bt), bt)} == WCon{_, at} : Word(1n+p)}
1352          %bx.rword(p, at, bt) : {WCon{Bool.xor(Bool.xor(ah, bh), bh), Word.xor(p, Word.xor(p, at, bt), bt)} == WCon{Bool.xor(Bool.xor(ah, bh), bh), _} : Word(1n+p)}
1353          {==}
1354
1355def bx.ru32(a: U32, b: U32) -> {U32.xor(U32.xor(a, b), b) == a : U32}:
1356  match a b:
1357    case U32{x} U32{y}:
1358      %bx.rword(32n, x, y) : {U32{Word.xor(32n, Word.xor(32n, x, y), y)} == U32{_} : U32}
1359      {==}
1360
1361def bx.rblock(+a: M.CmBlock, +b: M.CmBlock) -> {M.CmBlock.xor(M.CmBlock.xor(a, b), b) == a : M.CmBlock}:
1362  match a b:
1363    case M.CmBlock{a0, a1, a2, a3} M.CmBlock{b0, b1, b2, b3}:
1364      %bx.ru32(a0, b0) : {M.CmBlock.xor(M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3}), M.CmBlock{b0, b1, b2, b3}) == M.CmBlock{_, a1, a2, a3} : M.CmBlock}
1365      %bx.ru32(a1, b1) : {M.CmBlock.xor(M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3}), M.CmBlock{b0, b1, b2, b3}) == M.CmBlock{U32.xor(U32.xor(a0, b0), b0), _, a2, a3} : M.CmBlock}
1366      %bx.ru32(a2, b2) : {M.CmBlock.xor(M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3}), M.CmBlock{b0, b1, b2, b3}) == M.CmBlock{U32.xor(U32.xor(a0, b0), b0), U32.xor(U32.xor(a1, b1), b1), _, a3} : M.CmBlock}
1367      %bx.ru32(a3, b3) : {M.CmBlock.xor(M.CmBlock.xor(M.CmBlock{a0, a1, a2, a3}, M.CmBlock{b0, b1, b2, b3}), M.CmBlock{b0, b1, b2, b3}) == M.CmBlock{U32.xor(U32.xor(a0, b0), b0), U32.xor(U32.xor(a1, b1), b1), U32.xor(U32.xor(a2, b2), b2), _} : M.CmBlock}
1368      {==}
1369
1370# XTS on blocks
1371
1372# one block under one tweak: D(E(p xor t) xor t xor t) xor t == p
1373def xtsp.blk(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, ~dec: K -> M.CmBlock -> M.CmBlock, ~inv: @k: K -> @b: M.CmBlock -> {dec(k, enc(k, b)) == b : M.CmBlock}, +k: K, +p: M.CmBlock, +t: M.CmBlock) -> {T.xts.bdec(~K, ~dec, k, T.xts.benc(~K, ~enc, k, p, t), t) == p : M.CmBlock}:
1374  %Equal.sym(M.CmBlock, M.CmBlock.xor(M.CmBlock.xor(enc(k, M.CmBlock.xor(p, t)), t), t), enc(k, M.CmBlock.xor(p, t)), bx.rblock(enc(k, M.CmBlock.xor(p, t)), t)) : {M.CmBlock.xor(dec(k, _), t) == p : M.CmBlock}
1375  %Equal.sym(M.CmBlock, dec(k, enc(k, M.CmBlock.xor(p, t))), M.CmBlock.xor(p, t), inv(k, M.CmBlock.xor(p, t))) : {M.CmBlock.xor(_, t) == p : M.CmBlock}
1376  bx.rblock(p, t)
1377
1378def xtsp.go(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, ~dec: K -> M.CmBlock -> M.CmBlock, ~inv: @k: K -> @b: M.CmBlock -> {dec(k, enc(k, b)) == b : M.CmBlock}, +k: K, bs: List<&2, M.CmBlock>, +t: M.CmBlock) -> {T.xts.dec(~K, ~dec, k, T.xts.enc(~K, ~enc, k, bs, t), t) == bs : List<&2, M.CmBlock>}:
1379  match bs:
1380    case Nil{}:
1381      {==}
1382    case Con{+p, +rest}:
1383      %Equal.sym(M.CmBlock, T.xts.bdec(~K, ~dec, k, T.xts.benc(~K, ~enc, k, p, t), t), p, xtsp.blk(~K, ~enc, ~dec, ~inv, k, p, t)) : {Con{_, T.xts.dec(~K, ~dec, k, T.xts.enc(~K, ~enc, k, rest, T.Xts.mul_alpha(t)), T.Xts.mul_alpha(t))} == Con{p, rest} : List<&2, M.CmBlock>}
1384      %Equal.sym(List<&2, M.CmBlock>, T.xts.dec(~K, ~dec, k, T.xts.enc(~K, ~enc, k, rest, T.Xts.mul_alpha(t)), T.Xts.mul_alpha(t)), rest, xtsp.go(~K, ~enc, ~dec, ~inv, k, rest, T.Xts.mul_alpha(t))) : {Con{p, _} == Con{p, rest} : List<&2, M.CmBlock>}
1385      {==}
1386
1387def Laws.xts_blocks_round_trip(K, enc, dec, inv, k1, t, bs):
1388  +v = t
1389  +b = bs
1390  # the tail-recursive forms are the structural ones
1391  %tr.xts_enc_eq(~K, ~enc, k1, b, v) : {T.xts.dec.fast(~K, ~dec, k1, _, t) == bs : List<&2, M.CmBlock>}
1392  %tr.xts_dec_eq(~K, ~dec, k1, T.xts.enc(~K, ~enc, k1, b, v), v) : {_ == bs : List<&2, M.CmBlock>}
1393  xtsp.go(~K, ~enc, ~dec, ~inv, k1, b, v)
1394
1395# CMAC: the state after a ++ b is the state after a, then b
1396
1397def cmacp.feed(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, xs: List<&2, U32>, s: CM.CmacState, ys: List<&2, U32>) -> {CM.cmac.feed(~K, ~enc, k, B.append(xs, ys), s) == CM.cmac.feed(~K, ~enc, k, ys, CM.cmac.feed(~K, ~enc, k, xs, s)) : CM.CmacState}:
1398  match xs:
1399    case Nil{}:
1400      {==}
1401    case Con{h, t}:
1402      cmacp.feed(~K, ~enc, k, t, CM.cmac.step(~K, ~enc, k, s, h), ys)
1403
1404def Laws.cmac_streaming(K, enc, k, s, a, b):
1405  %Equal.sym(List<&2, U32>, B.Octets.to_list(B.Octets.append(a, b)), B.append(B.Octets.to_list(a), B.Octets.to_list(b)), BL.octets_append_list(a, b)) : {CM.cmac.feed(~K, ~enc, k, _, s) == CM.cmac.feed(~K, ~enc, k, B.Octets.to_list(b), CM.cmac.feed(~K, ~enc, k, B.Octets.to_list(a), s)) : CM.CmacState}
1406  cmacp.feed(~K, ~enc, k, B.Octets.to_list(a), s, B.Octets.to_list(b))
1407
1408
1409# More on joining and splitting
1410
1411def sp.mask_join_onto(bs: List<&2, M.CmBlock>, +rest: List<&2, U32>) -> {B.mask(M.cm.join_onto(bs, rest)) == M.cm.join_onto(bs, B.mask(rest)) : List<&2, U32>}:
1412  match bs:
1413    case Nil{}:
1414      {==}
1415    case Con{+b, +t}:
1416      %Equal.sym(List<&2, U32>, B.mask(M.cm.bytes_onto(b, M.cm.join_onto(t, rest))), M.cm.bytes_onto(b, B.mask(M.cm.join_onto(t, rest))), sp.mask_blk(b, M.cm.join_onto(t, rest))) : {_ == M.cm.bytes_onto(b, M.cm.join_onto(t, B.mask(rest))) : List<&2, U32>}
1417      %sp.mask_join_onto(t, rest) : {M.cm.bytes_onto(b, B.mask(M.cm.join_onto(t, rest))) == M.cm.bytes_onto(b, _) : List<&2, U32>}
1418      {==}
1419
1420# blocks joined in front of a short tail split back into those blocks and tail
1421def sp.split_join_short(bs: List<&2, M.CmBlock>, +rest: List<&2, U32>) -> {M.cm.split(rest) == M.CmSplit{Nil{}, rest} : M.CmSplit} -> {M.cm.split(M.cm.join_onto(bs, rest)) == M.CmSplit{bs, rest} : M.CmSplit}:
1422  match bs:
1423    case Nil{}:
1424      h => h
1425    case Con{+b, +t}:
1426      h => %Equal.sym(M.CmSplit, M.cm.split(M.cm.bytes_onto(b, M.cm.join_onto(t, rest))), M.cm.split.cons(b, M.cm.split(M.cm.join_onto(t, rest))), sp.blk(b, M.cm.join_onto(t, rest))) : {_ == M.CmSplit{Con{b, t}, rest} : M.CmSplit}
1427        %Equal.sym(M.CmSplit, M.cm.split(M.cm.join_onto(t, rest)), M.CmSplit{t, rest}, sp.split_join_short(t, rest)(h)) : {M.cm.split.cons(b, _) == M.CmSplit{Con{b, t}, rest} : M.CmSplit}
1428        {==}
1429
1430def sp.join_append(bs: List<&2, M.CmBlock>, +x: M.CmBlock, +rest: List<&2, U32>) -> {M.cm.join_onto(List.append(&2, M.CmBlock, bs, Con{x, Nil{}}), rest) == M.cm.join_onto(bs, M.cm.bytes_onto(x, rest)) : List<&2, U32>}:
1431  match bs:
1432    case Nil{}:
1433      {==}
1434    case Con{+b, +t}:
1435      %sp.join_append(t, x, rest) : {M.cm.bytes_onto(b, M.cm.join_onto(List.append(&2, M.CmBlock, t, Con{x, Nil{}}), rest)) == M.cm.bytes_onto(b, _) : List<&2, U32>}
1436      {==}
1437
1438# The last block and the others
1439
1440def li.init_app(es: List<&2, M.CmBlock>, +x: M.CmBlock, +e: M.CmBlock) -> {T.xts.init(List.append(&2, M.CmBlock, es, Con{x, Nil{}}), e) == Con{e, es} : List<&2, M.CmBlock>}:
1441  match es:
1442    case Nil{}:
1443      {==}
1444    case Con{+e2, +es2}:
1445      %li.init_app(es2, x, e2) : {Con{e, T.xts.init(List.append(&2, M.CmBlock, es2, Con{x, Nil{}}), e2)} == Con{e, _} : List<&2, M.CmBlock>}
1446      {==}
1447
1448def li.last_app(es: List<&2, M.CmBlock>, +x: M.CmBlock, +e: M.CmBlock) -> {T.xts.last(List.append(&2, M.CmBlock, es, Con{x, Nil{}}), e) == x : M.CmBlock}:
1449  match es:
1450    case Nil{}:
1451      {==}
1452    case Con{+e2, +es2}:
1453      li.last_app(es2, x, e2)
1454
1455def li.init_last(rest: List<&2, M.CmBlock>, +p: M.CmBlock) -> {List.append(&2, M.CmBlock, T.xts.init(rest, p), Con{T.xts.last(rest, p), Nil{}}) == Con{p, rest} : List<&2, M.CmBlock>}:
1456  match rest:
1457    case Nil{}:
1458      {==}
1459    case Con{+q, +r}:
1460      %li.init_last(r, q) : {Con{p, List.append(&2, M.CmBlock, T.xts.init(r, q), Con{T.xts.last(r, q), Nil{}})} == Con{p, _} : List<&2, M.CmBlock>}
1461      {==}
1462
1463def li.len_enc(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +t: M.CmBlock) -> {List.length(&2, M.CmBlock, T.xts.enc(~K, ~enc, k, bs, t)) == List.length(&2, M.CmBlock, bs) : Nat}:
1464  match bs:
1465    case Nil{}:
1466      {==}
1467    case Con{+p, +rest}:
1468      %li.len_enc(~K, ~enc, k, rest, T.Xts.mul_alpha(t)) : {1n+List.length(&2, M.CmBlock, T.xts.enc(~K, ~enc, k, rest, T.Xts.mul_alpha(t))) == 1n+_ : Nat}
1469      {==}
1470
1471# The byte layer
1472
1473def oc.le16(+o: B.Octets, h: {Nat.is_le(16n, B.Octets.len(o)) == True{} : Bool}) -> {Nat.is_le(16n, B.len(B.Octets.to_list(o))) == True{} : Bool}:
1474  %BL.octets_len_list(o) : {Nat.is_le(16n, _) == True{} : Bool}
1475  h
1476
1477def xtsp.tweak(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k2: K, +i: B.Octets, h: {B.Octets.len(i) == 16n : Nat}) -> {T.xts.tweak(~K, ~enc, k2, i) == Done{enc(k2, M.cm.block_of(B.Octets.to_list(i)))} : Result<&2, &2, M.CmError, M.CmBlock>}:
1478  %Equal.sym(Nat, B.len(B.Octets.to_list(i)), 16n, oc.len(i, 16n, h)) : {T.xts.tweak.go(~K, ~enc, k2, M.cm.need_block.pick(Nat.is_eq(_, 16n), B.Octets.to_list(i), M.CmBadTweakLength{B.len(B.Octets.to_list(i))})) == Done{enc(k2, M.cm.block_of(B.Octets.to_list(i)))} : Result<&2, &2, M.CmError, M.CmBlock>}
1479  {==}
1480
1481# the final partial ciphertext block is masked, and splits into no blocks
1482def xtsp.mask_steal_t(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +p: M.CmBlock, tl: List<&2, U32>, +t: M.CmBlock) -> {B.mask(T.xts.steal_t(~K, ~enc, k, p, tl, t)) == T.xts.steal_t(~K, ~enc, k, p, tl, t) : List<&2, U32>}:
1483  match tl:
1484    case Nil{}:
1485      {==}
1486    case Con{+h, +r}:
1487      %Equal.sym(List<&2, U32>, B.mask(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), B.take(B.len(Con{h, r}), B.mask(M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), li.mask_take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))) : {_ == B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))) : List<&2, U32>}
1488      %Equal.sym(List<&2, U32>, B.mask(M.cm.bytes_onto(T.xts.benc(~K, ~enc, k, p, t), Nil{})), M.cm.bytes_onto(T.xts.benc(~K, ~enc, k, p, t), B.mask(Nil{})), sp.mask_blk(T.xts.benc(~K, ~enc, k, p, t), Nil{})) : {B.take(B.len(Con{h, r}), _) == B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))) : List<&2, U32>}
1489      {==}
1490
1491def xtsp.lt_take(+n: Nat, +b: M.CmBlock, +h: {Nat.is_lt(n, 16n) == True{} : Bool}) -> {Nat.is_lt(B.len(B.take(n, M.cm.bytes_of(b))), 16n) == True{} : Bool}:
1492  %Equal.sym(Nat, B.len(B.take(n, M.cm.bytes_of(b))), n, li.len_take(n, M.cm.bytes_of(b))(na.lt_le(n, 16n)(h))) : {Nat.is_lt(_, 16n) == True{} : Bool}
1493  h
1494
1495def xtsp.split_steal_t(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +p: M.CmBlock, tl: List<&2, U32>, +t: M.CmBlock) -> {Nat.is_lt(B.len(tl), 16n) == True{} : Bool} -> {M.cm.split(T.xts.steal_t(~K, ~enc, k, p, tl, t)) == M.CmSplit{Nil{}, T.xts.steal_t(~K, ~enc, k, p, tl, t)} : M.CmSplit}:
1496  match tl:
1497    case Nil{}:
1498      h => {==}
1499    case Con{+x, +r}:
1500      h => sp.short_split(B.take(B.len(Con{x, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))(xtsp.lt_take(B.len(Con{x, r}), T.xts.benc(~K, ~enc, k, p, t), h))
1501
1502# the bytes the stealing passes through: tl, then the stolen tail of b
1503def xtsp.len16(+tl: List<&2, U32>, +b: M.CmBlock, h: {Nat.is_lt(B.len(tl), 16n) == True{} : Bool}) -> {Nat.is_eq(B.len(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))), 16n) == True{} : Bool}:
1504  %Equal.sym(Nat, B.len(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))), Nat.add(B.len(tl), B.len(B.drop(B.len(tl), M.cm.bytes_of(b)))), li.len_append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))) : {Nat.is_eq(_, 16n) == True{} : Bool}
1505  %Equal.sym(Nat, B.len(B.drop(B.len(tl), M.cm.bytes_of(b))), Nat.sub(16n, B.len(tl)), li.len_drop(B.len(tl), M.cm.bytes_of(b))) : {Nat.is_eq(Nat.add(B.len(tl), _), 16n) == True{} : Bool}
1506  %Equal.sym(Nat, Nat.add(B.len(tl), Nat.sub(16n, B.len(tl))), 16n, na.add_sub(B.len(tl), 16n)(na.lt_le(B.len(tl), 16n)(h))) : {Nat.is_eq(_, 16n) == True{} : Bool}
1507  {==}
1508
1509def xtsp.maskY(+tl: List<&2, U32>, +b: M.CmBlock, hm: {B.mask(tl) == tl : List<&2, U32>}) -> {B.mask(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))) == B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))) : List<&2, U32>}:
1510  %Equal.sym(List<&2, U32>, B.mask(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))), B.append(B.mask(tl), B.mask(B.drop(B.len(tl), M.cm.bytes_of(b)))), li.mask_append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))) : {_ == B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))) : List<&2, U32>}
1511  %Equal.sym(List<&2, U32>, B.mask(B.drop(B.len(tl), M.cm.bytes_of(b))), B.drop(B.len(tl), B.mask(M.cm.bytes_of(b))), li.mask_drop(B.len(tl), M.cm.bytes_of(b))) : {B.append(B.mask(tl), _) == B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))) : List<&2, U32>}
1512  %Equal.sym(List<&2, U32>, B.mask(M.cm.bytes_onto(b, Nil{})), M.cm.bytes_onto(b, B.mask(Nil{})), sp.mask_blk(b, Nil{})) : {B.append(B.mask(tl), B.drop(B.len(tl), _)) == B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))) : List<&2, U32>}
1513  %Equal.sym(List<&2, U32>, B.mask(tl), tl, hm) : {B.append(_, B.drop(B.len(tl), M.cm.bytes_of(b))) == B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))) : List<&2, U32>}
1514  {==}
1515
1516def xtsp.ppY(+tl: List<&2, U32>, +b: M.CmBlock, hm: {B.mask(tl) == tl : List<&2, U32>}, hl: {Nat.is_lt(B.len(tl), 16n) == True{} : Bool}) -> {M.cm.bytes_of(M.cm.block_of(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))))) == B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))) : List<&2, U32>}:
1517  Equal.trans(List<&2, U32>, M.cm.bytes_of(M.cm.block_of(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))))), B.mask(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b)))), B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))), sp.bb16(B.append(tl, B.drop(B.len(tl), M.cm.bytes_of(b))))(xtsp.len16(tl, b, hl)), xtsp.maskY(tl, b, hm))
1518
1519# Ciphertext stealing undoes itself: the last whole block p and a tail tl
1520# (masked, fewer than 16 bytes), encrypted by steal_c and steal_t and
1521# decrypted by dsteal, come back as p's bytes and then tl
1522def xtsp.steal(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, ~dec: K -> M.CmBlock -> M.CmBlock, ~inv: @k: K -> @b: M.CmBlock -> {dec(k, enc(k, b)) == b : M.CmBlock}, +k: K, +p: M.CmBlock, tl: List<&2, U32>, +t: M.CmBlock) -> {B.mask(tl) == tl : List<&2, U32>} -> {Nat.is_lt(B.len(tl), 16n) == True{} : Bool} -> {T.xts.dsteal(~K, ~dec, k, T.xts.steal_c(~K, ~enc, k, p, tl, t), T.xts.steal_t(~K, ~enc, k, p, tl, t), t) == M.cm.bytes_onto(p, tl) : List<&2, U32>}:
1523  match tl:
1524    case Nil{}:
1525      hm => hl => %Equal.sym(M.CmBlock, T.xts.bdec(~K, ~dec, k, T.xts.benc(~K, ~enc, k, p, t), t), p, xtsp.blk(~K, ~enc, ~dec, ~inv, k, p, t)) : {M.cm.bytes_of(_) == M.cm.bytes_onto(p, Nil{}) : List<&2, U32>}
1526        {==}
1527    case Con{+h, +r}:
1528      +hm => +hl => %Equal.sym(M.CmBlock, T.xts.bdec(~K, ~dec, k, T.xts.benc(~K, ~enc, k, M.cm.block_of(B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))), T.Xts.mul_alpha(t)), T.Xts.mul_alpha(t)), M.cm.block_of(B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))), xtsp.blk(~K, ~enc, ~dec, ~inv, k, M.cm.block_of(B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))), T.Xts.mul_alpha(t))) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, M.cm.block_of(B.append(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), B.drop(B.len(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), M.cm.bytes_of(_)))), t), B.take(B.len(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), M.cm.bytes_of(_))) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1529              %Equal.sym(Nat, B.len(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), B.len(Con{h, r}), li.len_take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))(na.lt_le(B.len(Con{h, r}), 16n)(hl))) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, M.cm.block_of(B.append(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), B.drop(_, M.cm.bytes_of(M.cm.block_of(B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))))))), t), B.take(_, M.cm.bytes_of(M.cm.block_of(B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))))))) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1530              %Equal.sym(List<&2, U32>, M.cm.bytes_of(M.cm.block_of(B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))))), B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), xtsp.ppY(Con{h, r}, T.xts.benc(~K, ~enc, k, p, t), hm, hl)) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, M.cm.block_of(B.append(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), B.drop(B.len(Con{h, r}), _))), t), B.take(B.len(Con{h, r}), _)) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1531              %Equal.sym(List<&2, U32>, B.take(B.len(Con{h, r}), B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))), Con{h, r}, li.take_append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, M.cm.block_of(B.append(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), B.drop(B.len(Con{h, r}), B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))))), t), _) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1532              %Equal.sym(List<&2, U32>, B.drop(B.len(Con{h, r}), B.append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))), B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), li.drop_append(Con{h, r}, B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))))) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, M.cm.block_of(B.append(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), _)), t), Con{h, r}) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1533              %Equal.sym(List<&2, U32>, B.append(B.take(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), B.drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)), BL.take_drop(B.len(Con{h, r}), M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t)))) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, M.cm.block_of(_), t), Con{h, r}) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1534              %Equal.sym(M.CmBlock, M.cm.block_of(M.cm.bytes_of(T.xts.benc(~K, ~enc, k, p, t))), T.xts.benc(~K, ~enc, k, p, t), sp.block_bytes(T.xts.benc(~K, ~enc, k, p, t))) : {M.cm.bytes_onto(T.xts.bdec(~K, ~dec, k, _, t), Con{h, r}) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1535              %Equal.sym(M.CmBlock, T.xts.bdec(~K, ~dec, k, T.xts.benc(~K, ~enc, k, p, t), t), p, xtsp.blk(~K, ~enc, ~dec, ~inv, k, p, t)) : {M.cm.bytes_onto(_, Con{h, r}) == M.cm.bytes_onto(p, Con{h, r}) : List<&2, U32>}
1536        {==}
1537
1538def xtsp.d2(~K: Data, ~dec: K -> M.CmBlock -> M.CmBlock, +k: K, +t: M.CmBlock, ec: List<&2, M.CmBlock>, +sc: M.CmBlock, +st: List<&2, U32>, +n: Nat) -> {T.xts.d2(~K, ~dec, k, t, M.CmSplit{List.append(&2, M.CmBlock, ec, Con{sc, Nil{}}), st}, n) == Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, ec, sc, st))} : Result<&2, &2, M.CmError, B.Octets>}:
1539  match ec:
1540    case Nil{}:
1541      {==}
1542    case Con{+e, +es}:
1543      %Equal.sym(List<&2, M.CmBlock>, T.xts.init(List.append(&2, M.CmBlock, es, Con{sc, Nil{}}), e), Con{e, es}, li.init_app(es, sc, e)) : {Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, _, T.xts.last(List.append(&2, M.CmBlock, es, Con{sc, Nil{}}), e), st))} == Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, Con{e, es}, sc, st))} : Result<&2, &2, M.CmError, B.Octets>}
1544      %Equal.sym(M.CmBlock, T.xts.last(List.append(&2, M.CmBlock, es, Con{sc, Nil{}}), e), sc, li.last_app(es, sc, e)) : {Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, Con{e, es}, _, st))} == Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k, t, Con{e, es}, sc, st))} : Result<&2, &2, M.CmError, B.Octets>}
1545      {==}
1546
1547def Laws.xts_round_trip(K, enc, dec, inv, k1, k2, i, p, hi, hp):
1548  +hne = sp.nonempty(B.Octets.to_list(p))(oc.le16(p, hp))
1549  +mo = Equal.trans(List<&2, U32>, B.mask(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))), M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), B.mask(T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))), M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))), sp.mask_join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))), Equal.cong(List<&2, U32>, List<&2, U32>, x => M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), x), B.mask(T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), xtsp.mask_steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))
1550  # the public defs are the structural ones
1551  %tr.xts_encrypt(~K, ~enc, k1, k2, i, p) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, _, c => T.Xts.decrypt(~K, ~enc, ~dec, k1, k2, i, c)) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1552  %tr.bind_cong(T.Xts.encrypt.ref(~K, ~enc, k1, k2, i, p), c => T.Xts.decrypt.ref(~K, ~enc, ~dec, k1, k2, i, c), c => T.Xts.decrypt(~K, ~enc, ~dec, k1, k2, i, c), c => tr.xts_decrypt(~K, ~enc, ~dec, k1, k2, i, c)) : {_ == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1553  # the tweak
1554  %Equal.sym(Result<&2, &2, M.CmError, M.CmBlock>, T.xts.tweak(~K, ~enc, k2, i), Done{enc(k2, M.cm.block_of(B.Octets.to_list(i)))}, xtsp.tweak(~K, ~enc, k2, i, hi)) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, T.xts.e1(~K, ~enc, k1, _, B.Octets.to_list(p)), c => T.xts.d1(~K, ~dec, k1, _, B.Octets.to_list(c))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1555  # the data unit is masked
1556  %oc.masked(p) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, T.xts.e2(~K, ~enc, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), M.cm.split(_), B.len(B.Octets.to_list(p))), c => T.xts.d1(~K, ~dec, k1, Done{enc(k2, M.cm.block_of(B.Octets.to_list(i)))}, B.Octets.to_list(c))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1557  # its blocks and tail
1558  %sp.eta(M.cm.split(B.mask(B.Octets.to_list(p)))) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, T.xts.e2(~K, ~enc, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), _, B.len(B.Octets.to_list(p))), c => T.xts.d1(~K, ~dec, k1, Done{enc(k2, M.cm.block_of(B.Octets.to_list(i)))}, B.Octets.to_list(c))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1559  # at least one block, so encryption succeeds
1560  %hne : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, T.xts.e2(~K, ~enc, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), M.CmSplit{_, M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p))))}, B.len(B.Octets.to_list(p))), c => T.xts.d1(~K, ~dec, k1, Done{enc(k2, M.cm.block_of(B.Octets.to_list(i)))}, B.Octets.to_list(c))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1561  # decryption reads the ciphertext back, masked
1562  %Equal.sym(List<&2, U32>, B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))), B.mask(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))), BL.octets_to_of(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))) : {T.xts.d2(~K, ~dec, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), M.cm.split(_), B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1563  # which it already is
1564  %Equal.sym(List<&2, U32>, B.mask(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))), M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))), mo) : {T.xts.d2(~K, ~dec, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), M.cm.split(_), B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1565  # it splits into the ciphertext blocks and the partial block
1566  %Equal.sym(M.CmSplit, M.cm.split(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))), M.CmSplit{List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))}, sp.split_join_short(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))(xtsp.split_steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))(sp.tail_short(B.Octets.to_list(p))))) : {T.xts.d2(~K, ~dec, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), _, B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1567  # decryption takes the last block apart
1568  %Equal.sym(Result<&2, &2, M.CmError, B.Octets>, T.xts.d2(~K, ~dec, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), M.CmSplit{List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))}, B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))))), Done{B.Octets.of_list(T.xts.dout(~K, ~dec, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))}, xtsp.d2(~K, ~dec, k1, enc(k2, M.cm.block_of(B.Octets.to_list(i))), T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), B.len(B.Octets.to_list(B.Octets.of_list(M.cm.join_onto(List.append(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), Con{T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), Nil{}}), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))))))))) : {_ == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1569  # XTS on blocks
1570  %Equal.sym(List<&2, M.CmBlock>, T.xts.dec(~K, ~dec, k1, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))), T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), xtsp.go(~K, ~enc, ~dec, ~inv, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))) : {Done{B.Octets.of_list(M.cm.join_onto(_, T.xts.dsteal(~K, ~dec, k1, T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1571  # as many ciphertext blocks as plaintext blocks: the same last tweak
1572  %Equal.sym(Nat, List.length(&2, M.CmBlock, T.xts.enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), li.len_enc(~K, ~enc, k1, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))) : {Done{B.Octets.of_list(M.cm.join_onto(T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), T.xts.dsteal(~K, ~dec, k1, T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.alpha_n(_, enc(k2, M.cm.block_of(B.Octets.to_list(i)))))))} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1573  # ciphertext stealing undoes itself
1574  %Equal.sym(List<&2, U32>, T.xts.dsteal(~K, ~dec, k1, T.xts.steal_c(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.steal_t(~K, ~enc, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i))))), M.cm.bytes_onto(T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p))))), xtsp.steal(~K, ~enc, ~dec, ~inv, k1, T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p)))), T.xts.alpha_n(List.length(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))), enc(k2, M.cm.block_of(B.Octets.to_list(i)))))(sp.tail_masked(B.Octets.to_list(p)))(sp.tail_short(B.Octets.to_list(p)))) : {Done{B.Octets.of_list(M.cm.join_onto(T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), _))} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1575  # the blocks back together
1576  %sp.join_append(T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p))))) : {Done{B.Octets.of_list(_)} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1577  # 
1578  %Equal.sym(List<&2, M.CmBlock>, List.append(&2, M.CmBlock, T.xts.init(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), Con{T.xts.last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))), Nil{}}), Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))}, li.init_last(sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))))) : {Done{B.Octets.of_list(M.cm.join_onto(_, M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p))))))} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1579  # 
1580  %Equal.sym(List<&2, M.CmBlock>, Con{sp.hd(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p))))), sp.tl(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))))}, M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))), hne) : {Done{B.Octets.of_list(M.cm.join_onto(_, M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p))))))} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1581  # and with the tail, the data unit
1582  %Equal.sym(List<&2, U32>, M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(B.Octets.to_list(p)))), M.cm.split.tail(M.cm.split(B.mask(B.Octets.to_list(p))))), B.mask(B.Octets.to_list(p)), sp.join_split(B.Octets.to_list(p))) : {Done{B.Octets.of_list(_)} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1583  # 
1584  %Equal.sym(List<&2, U32>, B.mask(B.Octets.to_list(p)), B.Octets.to_list(p), oc.masked(p)) : {Done{B.Octets.of_list(_)} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1585  # 
1586  %Equal.sym(B.Octets, B.Octets.of_list(B.Octets.to_list(p)), p, BL.octets_of_to(p)) : {Done{_} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1587  {==}
1588# XOR with a byte twice, and with itself
1589
1590def bx.wself(n: Nat, w: Word(n)) -> {Word.xor(n, w, w) == Word.zero(n) : Word(n)}:
1591  match n:
1592    case 0n:
1593      match w:
1594        case WNil{}:
1595          {==}
1596    case 1n+p:
1597      match w:
1598        case WCon{h, t}:
1599          match h:
1600            case False{}:
1601              %bx.wself(p, t) : {WCon{False{}, Word.xor(p, t, t)} == WCon{False{}, _} : Word(1n+p)}
1602              {==}
1603            case True{}:
1604              %bx.wself(p, t) : {WCon{False{}, Word.xor(p, t, t)} == WCon{False{}, _} : Word(1n+p)}
1605              {==}
1606
1607def bits.xor_self(a: U32) -> {B.byte(U32.xor(a, a)) == 0 : U32}:
1608  match a:
1609    case U32{x}:
1610      %Equal.sym(Word(32n), Word.xor(32n, x, x), Word.zero(32n), bx.wself(32n, x)) : {B.byte(U32{_}) == 0 : U32}
1611      {==}
1612
1613def bits.xor_xor(a: U32, y: U32) -> {B.byte(U32.xor(B.byte(U32.xor(a, y)), y)) == B.byte(a) : U32}:
1614  match a y:
1615    case U32{WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WCon{a8, WCon{a9, WCon{a10, WCon{a11, WCon{a12, WCon{a13, WCon{a14, WCon{a15, WCon{a16, WCon{a17, WCon{a18, WCon{a19, WCon{a20, WCon{a21, WCon{a22, WCon{a23, WCon{a24, WCon{a25, WCon{a26, WCon{a27, WCon{a28, WCon{a29, WCon{a30, WCon{a31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} U32{WCon{y0, WCon{y1, WCon{y2, WCon{y3, WCon{y4, WCon{y5, WCon{y6, WCon{y7, WCon{y8, WCon{y9, WCon{y10, WCon{y11, WCon{y12, WCon{y13, WCon{y14, WCon{y15, WCon{y16, WCon{y17, WCon{y18, WCon{y19, WCon{y20, WCon{y21, WCon{y22, WCon{y23, WCon{y24, WCon{y25, WCon{y26, WCon{y27, WCon{y28, WCon{y29, WCon{y30, WCon{y31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:
1616      %Equal.sym(Word(8n), Word.xor(8n, Word.xor(8n, WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WNil{}}}}}}}}}, WCon{y0, WCon{y1, WCon{y2, WCon{y3, WCon{y4, WCon{y5, WCon{y6, WCon{y7, WNil{}}}}}}}}}), WCon{y0, WCon{y1, WCon{y2, WCon{y3, WCon{y4, WCon{y5, WCon{y6, WCon{y7, WNil{}}}}}}}}}), WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WNil{}}}}}}}}}, bx.rword(8n, WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WNil{}}}}}}}}}, WCon{y0, WCon{y1, WCon{y2, WCon{y3, WCon{y4, WCon{y5, WCon{y6, WCon{y7, WNil{}}}}}}}}})) : {U32{W.W64.bits.cat(8n, 24n, _, Word.zero(24n))} == B.byte(U32{WCon{a0, WCon{a1, WCon{a2, WCon{a3, WCon{a4, WCon{a5, WCon{a6, WCon{a7, WCon{a8, WCon{a9, WCon{a10, WCon{a11, WCon{a12, WCon{a13, WCon{a14, WCon{a15, WCon{a16, WCon{a17, WCon{a18, WCon{a19, WCon{a20, WCon{a21, WCon{a22, WCon{a23, WCon{a24, WCon{a25, WCon{a26, WCon{a27, WCon{a28, WCon{a29, WCon{a30, WCon{a31, WNil{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}) : U32}
1617      {==}
1618
1619
1620def li.mask_xor(xs: List<&2, U32>, ys: List<&2, U32>) -> {B.mask(M.cm.xor_bytes(xs, ys)) == M.cm.xor_bytes(xs, ys) : List<&2, U32>}:
1621  match xs:
1622    case Nil{}:
1623      {==}
1624    case Con{+a, +s}:
1625      match ys:
1626        case Nil{}:
1627          {==}
1628        case Con{+b, +t}:
1629          %bits.byte_byte(U32.xor(a, b)) : {Con{B.byte(B.byte(U32.xor(a, b))), B.mask(M.cm.xor_bytes(s, t))} == Con{_, M.cm.xor_bytes(s, t)} : List<&2, U32>}
1630          %li.mask_xor(s, t) : {Con{B.byte(B.byte(U32.xor(a, b))), B.mask(M.cm.xor_bytes(s, t))} == Con{B.byte(B.byte(U32.xor(a, b))), _} : List<&2, U32>}
1631          {==}
1632
1633def li.len_xor(xs: List<&2, U32>, ys: List<&2, U32>) -> {Nat.is_le(B.len(xs), B.len(ys)) == True{} : Bool} -> {B.len(M.cm.xor_bytes(xs, ys)) == B.len(xs) : Nat}:
1634  match xs:
1635    case Nil{}:
1636      h => {==}
1637    case Con{+a, +s}:
1638      match ys:
1639        case Nil{}:
1640          h => bo.absurd({B.len(M.cm.xor_bytes(Con{a, s}, Nil{})) == B.len(Con{a, s}) : Nat}, h)
1641        case Con{+b, +t}:
1642          h => %li.len_xor(s, t)(h) : {1n+B.len(M.cm.xor_bytes(s, t)) == 1n+_ : Nat}
1643            {==}
1644
1645def li.xor_xor(xs: List<&2, U32>, ys: List<&2, U32>) -> {Nat.is_le(B.len(xs), B.len(ys)) == True{} : Bool} -> {M.cm.xor_bytes(M.cm.xor_bytes(xs, ys), ys) == B.mask(xs) : List<&2, U32>}:
1646  match xs:
1647    case Nil{}:
1648      h => {==}
1649    case Con{+a, +s}:
1650      match ys:
1651        case Nil{}:
1652          h => bo.absurd({M.cm.xor_bytes(M.cm.xor_bytes(Con{a, s}, Nil{}), Nil{}) == B.mask(Con{a, s}) : List<&2, U32>}, h)
1653        case Con{+b, +t}:
1654          h => %Equal.sym(U32, B.byte(U32.xor(B.byte(U32.xor(a, b)), b)), B.byte(a), bits.xor_xor(a, b)) : {Con{_, M.cm.xor_bytes(M.cm.xor_bytes(s, t), t)} == Con{B.byte(a), B.mask(s)} : List<&2, U32>}
1655            %Equal.sym(List<&2, U32>, M.cm.xor_bytes(M.cm.xor_bytes(s, t), t), B.mask(s), li.xor_xor(s, t)(h)) : {Con{B.byte(a), _} == Con{B.byte(a), B.mask(s)} : List<&2, U32>}
1656            {==}
1657
1658def li.len_bytes(+b: M.CmBlock, +rest: List<&2, U32>) -> {B.len(M.cm.bytes_onto(b, rest)) == Nat.add(16n, B.len(rest)) : Nat}:
1659  {==}
1660
1661def na.add_zero(a: Nat) -> {Nat.add(a, 0n) == a : Nat}:
1662  match a:
1663    case 0n:
1664      {==}
1665    case 1n+p:
1666      %na.add_zero(p) : {1n+Nat.add(p, 0n) == 1n+_ : Nat}
1667      {==}
1668
1669def na.add_succ(a: Nat, +b: Nat) -> {Nat.add(a, 1n+b) == 1n+Nat.add(a, b) : Nat}:
1670  match a:
1671    case 0n:
1672      {==}
1673    case 1n+p:
1674      %na.add_succ(p, b) : {1n+Nat.add(p, 1n+b) == 1n+_ : Nat}
1675      {==}
1676
1677def na.sub_zero(a: Nat) -> {Nat.sub(a, 0n) == a : Nat}:
1678  match a:
1679    case 0n:
1680      {==}
1681    case 1n+p:
1682      {==}
1683
1684# (a + b) - b == a
1685def na.sub_add(+a: Nat, +b: Nat) -> {Nat.sub(Nat.add(a, b), b) == a : Nat}:
1686  match b:
1687    case 0n:
1688      %Equal.sym(Nat, Nat.add(a, 0n), a, na.add_zero(a)) : {Nat.sub(_, 0n) == a : Nat}
1689      na.sub_zero(a)
1690    case 1n+p:
1691      %Equal.sym(Nat, Nat.add(a, 1n+p), 1n+Nat.add(a, p), na.add_succ(a, p)) : {Nat.sub(_, 1n+p) == a : Nat}
1692      na.sub_add(a, p)
1693
1694def na.le_zero(a: Nat) -> {Nat.is_le(0n, a) == True{} : Bool}:
1695  match a:
1696    case 0n:
1697      {==}
1698    case 1n+q:
1699      {==}
1700
1701# b <= a + b
1702def na.le_add(+a: Nat, +b: Nat) -> {Nat.is_le(b, Nat.add(a, b)) == True{} : Bool}:
1703  match b:
1704    case 0n:
1705      %Equal.sym(Nat, Nat.add(a, 0n), a, na.add_zero(a)) : {Nat.is_le(0n, _) == True{} : Bool}
1706      na.le_zero(a)
1707    case 1n+p:
1708      %Equal.sym(Nat, Nat.add(a, 1n+p), 1n+Nat.add(a, p), na.add_succ(a, p)) : {Nat.is_le(1n+p, _) == True{} : Bool}
1709      na.le_add(a, p)
1710
1711def bo.and_r(+a: Bool, +b: Bool) -> {Bool.and(a, b) == True{} : Bool} -> {b == True{} : Bool}:
1712  match a:
1713    case False{}:
1714      h => bo.absurd({b == True{} : Bool}, h)
1715    case True{}:
1716      h => h
1717
1718def bo.and_l(+a: Bool, +b: Bool) -> {Bool.and(a, b) == True{} : Bool} -> {a == True{} : Bool}:
1719  match a:
1720    case False{}:
1721      h => bo.absurd({False{} == True{} : Bool}, h)
1722    case True{}:
1723      h => {==}
1724
1725def rs.disc(r: Result<&2, &2, M.CmError, Unit>) -> Type:
1726  match r:
1727    case Fail{e}:
1728      Unit
1729    case Done{u}:
1730      Empty
1731
1732def rs.empty(+e: M.CmError, +u: Unit, h: {Fail{e} == Done{u} : Result<&2, &2, M.CmError, Unit>}) -> Empty:
1733  %h : rs.disc(_)
1734  Unit{}
1735
1736def rs.absurd(-A: Type, +e: M.CmError, +u: Unit, h: {Fail{e} == Done{u} : Result<&2, &2, M.CmError, Unit>}) -> A:
1737  Empty.absurd(A, rs.empty(e, u, h))
1738
1739
1740# CCM
1741
1742# checks that pass mean a tag of at most 16 bytes
1743def ccmp.tag_le.go(b: Bool, +m: Nat, +nl: Nat, +n: Nat, +u: Unit) -> {CC.ccm.tag_ok(m) == b : Bool} -> {CC.ccm.checks(m, nl, n) == Done{u} : Result<&2, &2, M.CmError, Unit>} -> {Nat.is_le(m, 16n) == True{} : Bool}:
1744  match b:
1745    case False{}:
1746      eb => h => rs.absurd({Nat.is_le(m, 16n) == True{} : Bool}, M.CmBadTagLength{m}, u, Equal.trans(Result<&2, &2, M.CmError, Unit>, CC.ccm.checks.tag(False{}, m, nl, n), CC.ccm.checks.tag(CC.ccm.tag_ok(m), m, nl, n), Done{u}, Equal.cong(Bool, Result<&2, &2, M.CmError, Unit>, x => CC.ccm.checks.tag(x, m, nl, n), False{}, CC.ccm.tag_ok(m), Equal.sym(Bool, CC.ccm.tag_ok(m), False{}, eb)), h))
1747    case True{}:
1748      eb => h => bo.and_l(Nat.is_le(m, 16n), Nat.is_eq(Nat.mod(m, 2n), 0n))(bo.and_r(Nat.is_le(4n, m), Bool.and(Nat.is_le(m, 16n), Nat.is_eq(Nat.mod(m, 2n), 0n)))(eb))
1749
1750def ccmp.tag_le(+m: Nat, +nl: Nat, +n: Nat, +u: Unit, h: {CC.ccm.checks(m, nl, n) == Done{u} : Result<&2, &2, M.CmError, Unit>}) -> {Nat.is_le(m, 16n) == True{} : Bool}:
1751  ccmp.tag_le.go(CC.ccm.tag_ok(m), m, nl, n, u)({==})(h)
1752
1753def ccmp.diff_self(xs: List<&2, U32>) -> {M.cm.diff(xs, xs, 0) == 0 : U32}:
1754  match xs:
1755    case Nil{}:
1756      {==}
1757    case Con{+a, +s}:
1758      %Equal.sym(U32, B.byte(U32.xor(a, a)), 0, bits.xor_self(a)) : {M.cm.diff(s, s, U32.or(0, _)) == 0 : U32}
1759      ccmp.diff_self(s)
1760
1761def ccmp.ct_refl(+xs: List<&2, U32>) -> {M.cm.ct_eq(xs, xs) == True{} : Bool}:
1762  %Equal.sym(U32, M.cm.diff(xs, xs, 0), 0, ccmp.diff_self(xs)) : {U32.is_eq(_, 0) == True{} : Bool}
1763  {==}
1764
1765def ccmp.len_ctrb(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +a0: M.CmBlock, +i: U32) -> {List.length(&2, M.CmBlock, CC.ccm.ctrb(~K, ~enc, k, bs, a0, i)) == List.length(&2, M.CmBlock, bs) : Nat}:
1766  match bs:
1767    case Nil{}:
1768      {==}
1769    case Con{+b, +rest}:
1770      %ccmp.len_ctrb(~K, ~enc, k, rest, a0, U32.add(i, 1)) : {1n+List.length(&2, M.CmBlock, CC.ccm.ctrb(~K, ~enc, k, rest, a0, U32.add(i, 1))) == 1n+_ : Nat}
1771      {==}
1772
1773# CTR twice is the identity on blocks
1774def ccmp.ctrb2(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +a0: M.CmBlock, +i: U32) -> {CC.ccm.ctrb(~K, ~enc, k, CC.ccm.ctrb(~K, ~enc, k, bs, a0, i), a0, i) == bs : List<&2, M.CmBlock>}:
1775  match bs:
1776    case Nil{}:
1777      {==}
1778    case Con{+b, +rest}:
1779      %Equal.sym(M.CmBlock, M.CmBlock.xor(M.CmBlock.xor(b, enc(k, CC.ccm.ai(a0, i))), enc(k, CC.ccm.ai(a0, i))), b, bx.rblock(b, enc(k, CC.ccm.ai(a0, i)))) : {Con{_, CC.ccm.ctrb(~K, ~enc, k, CC.ccm.ctrb(~K, ~enc, k, rest, a0, U32.add(i, 1)), a0, U32.add(i, 1))} == Con{b, rest} : List<&2, M.CmBlock>}
1780      %Equal.sym(List<&2, M.CmBlock>, CC.ccm.ctrb(~K, ~enc, k, CC.ccm.ctrb(~K, ~enc, k, rest, a0, U32.add(i, 1)), a0, U32.add(i, 1)), rest, ccmp.ctrb2(~K, ~enc, k, rest, a0, U32.add(i, 1))) : {Con{b, _} == Con{b, rest} : List<&2, M.CmBlock>}
1781      {==}
1782
1783def ccmp.mask_xcrypt(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, s: M.CmSplit) -> {B.mask(CC.ccm.xcrypt(~K, ~enc, k, a0, s)) == CC.ccm.xcrypt(~K, ~enc, k, a0, s) : List<&2, U32>}:
1784  match s:
1785    case M.CmSplit{+bs, +tail}:
1786      %Equal.sym(List<&2, U32>, B.mask(M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs))))))))), M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), B.mask(M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs))))))))), sp.mask_join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs))))))))) : {_ == M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs)))))))) : List<&2, U32>}
1787      %li.mask_xor(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs))))))) : {M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), B.mask(M.cm.xor_bytes(tail, M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, bs))))))))) == M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, 1), _) : List<&2, U32>}
1788      {==}
1789
1790def ccmp.len_join(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, bs: List<&2, M.CmBlock>, +a0: M.CmBlock, +i: U32, +x: List<&2, U32>, +y: List<&2, U32>, h: {B.len(x) == B.len(y) : Nat}) -> {B.len(M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, bs, a0, i), x)) == B.len(M.cm.join_onto(bs, y)) : Nat}:
1791  match bs:
1792    case Nil{}:
1793      h
1794    case Con{+b, +rest}:
1795      %Equal.sym(Nat, B.len(M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, rest, a0, U32.add(i, 1)), x)), B.len(M.cm.join_onto(rest, y)), ccmp.len_join(~K, ~enc, k, rest, a0, U32.add(i, 1), x, y, h)) : {Nat.add(16n, _) == Nat.add(16n, B.len(M.cm.join_onto(rest, y))) : Nat}
1796      {==}
1797# the CTR tail is as short as the plaintext tail
1798def ccmp.xt_short(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, +ys: List<&2, U32>) -> {Nat.is_lt(B.len(M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))), 16n) == True{} : Bool}:
1799  %Equal.sym(Nat, B.len(M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))), B.len(M.cm.split.tail(M.cm.split(B.mask(ys)))), li.len_xor(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))(na.lt_le(B.len(M.cm.split.tail(M.cm.split(B.mask(ys)))), 16n)(sp.tail_short(ys)))) : {Nat.is_lt(_, 16n) == True{} : Bool}
1800  sp.tail_short(ys)
1801
1802# CTR from counter 1 undoes itself (on a masked byte string)
1803def ccmp.xx(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, +ys: List<&2, U32>) -> {CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(B.mask(ys))))) == B.mask(ys) : List<&2, U32>}:
1804  %sp.eta(M.cm.split(B.mask(ys))) : {CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, a0, _))) == B.mask(ys) : List<&2, U32>}
1805  %Equal.sym(M.CmSplit, M.cm.split(M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1), M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))))), M.CmSplit{CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1), M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))}, sp.split_join_short(CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1), M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))))(sp.short_split(M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))))(ccmp.xt_short(~K, ~enc, k, a0, ys)))) : {CC.ccm.xcrypt(~K, ~enc, k, a0, _) == B.mask(ys) : List<&2, U32>}
1806  %Equal.sym(Nat, List.length(&2, M.CmBlock, CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1)), List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))), ccmp.len_ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1)) : {M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1), a0, 1), M.cm.xor_bytes(M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(_))))))) == B.mask(ys) : List<&2, U32>}
1807  %Equal.sym(List<&2, M.CmBlock>, CC.ccm.ctrb(~K, ~enc, k, CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1), a0, 1), M.cm.split.blocks(M.cm.split(B.mask(ys))), ccmp.ctrb2(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1)) : {M.cm.join_onto(_, M.cm.xor_bytes(M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))) == B.mask(ys) : List<&2, U32>}
1808  %Equal.sym(List<&2, U32>, M.cm.xor_bytes(M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))), B.mask(M.cm.split.tail(M.cm.split(B.mask(ys)))), li.xor_xor(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))(na.lt_le(B.len(M.cm.split.tail(M.cm.split(B.mask(ys)))), 16n)(sp.tail_short(ys)))) : {M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(ys))), _) == B.mask(ys) : List<&2, U32>}
1809  %Equal.sym(List<&2, U32>, B.mask(M.cm.split.tail(M.cm.split(B.mask(ys)))), M.cm.split.tail(M.cm.split(B.mask(ys))), sp.tail_masked(ys)) : {M.cm.join_onto(M.cm.split.blocks(M.cm.split(B.mask(ys))), _) == B.mask(ys) : List<&2, U32>}
1810  sp.join_split(ys)
1811
1812# and keeps its length
1813def ccmp.len_xc(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, +ys: List<&2, U32>) -> {B.len(CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(B.mask(ys)))) == B.len(B.mask(ys)) : Nat}:
1814  %sp.eta(M.cm.split(B.mask(ys))) : {B.len(CC.ccm.xcrypt(~K, ~enc, k, a0, _)) == B.len(B.mask(ys)) : Nat}
1815  %sp.join_split(ys) : {B.len(M.cm.join_onto(CC.ccm.ctrb(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1), M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))))) == B.len(_) : Nat}
1816  ccmp.len_join(~K, ~enc, k, M.cm.split.blocks(M.cm.split(B.mask(ys))), a0, 1, M.cm.xor_bytes(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys)))))))))), M.cm.split.tail(M.cm.split(B.mask(ys))), li.len_xor(M.cm.split.tail(M.cm.split(B.mask(ys))), M.cm.bytes_of(enc(k, CC.ccm.ai(a0, U32.add(1, U32.from_nat(List.length(&2, M.CmBlock, M.cm.split.blocks(M.cm.split(B.mask(ys))))))))))(na.lt_le(B.len(M.cm.split.tail(M.cm.split(B.mask(ys)))), 16n)(sp.tail_short(ys))))
1817
1818def ccmp.xxp(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, +p: B.Octets) -> {CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(B.Octets.to_list(p))))) == B.Octets.to_list(p) : List<&2, U32>}:
1819  %oc.masked(p) : {CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(_)))) == _ : List<&2, U32>}
1820  ccmp.xx(~K, ~enc, k, a0, B.Octets.to_list(p))
1821
1822def ccmp.len_xcp(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +a0: M.CmBlock, +p: B.Octets) -> {B.len(CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(B.Octets.to_list(p)))) == B.len(B.Octets.to_list(p)) : Nat}:
1823  %oc.masked(p) : {B.len(CC.ccm.xcrypt(~K, ~enc, k, a0, M.cm.split(_))) == B.len(_) : Nat}
1824  ccmp.len_xc(~K, ~enc, k, a0, B.Octets.to_list(p))
1825
1826def ccmp.len_tag(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +l: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>, h: {Nat.is_le(m, 16n) == True{} : Bool}) -> {B.len(CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv)) == m : Nat}:
1827  li.len_take(m, M.cm.bytes_of(CC.ccm.mac(~K, ~enc, k, m, l, nv, av, pv)))(h)
1828
1829def ccmp.le_tag(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +l: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>, +h: {Nat.is_le(m, 16n) == True{} : Bool}) -> {Nat.is_le(B.len(CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv)), 16n) == True{} : Bool}:
1830  %Equal.sym(Nat, B.len(CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv)), m, ccmp.len_tag(~K, ~enc, k, m, l, nv, av, pv, h)) : {Nat.is_le(_, 16n) == True{} : Bool}
1831  h
1832
1833def ccmp.mask_tag(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +l: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>) -> {B.mask(CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv)) == CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv) : List<&2, U32>}:
1834  %Equal.sym(List<&2, U32>, B.mask(CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv)), B.take(m, B.mask(M.cm.bytes_of(CC.ccm.mac(~K, ~enc, k, m, l, nv, av, pv)))), li.mask_take(m, M.cm.bytes_of(CC.ccm.mac(~K, ~enc, k, m, l, nv, av, pv)))) : {_ == CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv) : List<&2, U32>}
1835  %Equal.sym(List<&2, U32>, B.mask(M.cm.bytes_onto(CC.ccm.mac(~K, ~enc, k, m, l, nv, av, pv), Nil{})), M.cm.bytes_onto(CC.ccm.mac(~K, ~enc, k, m, l, nv, av, pv), B.mask(Nil{})), sp.mask_blk(CC.ccm.mac(~K, ~enc, k, m, l, nv, av, pv), Nil{})) : {B.take(m, _) == CC.ccm.tag(~K, ~enc, k, m, l, nv, av, pv) : List<&2, U32>}
1836  {==}
1837
1838def ccmp.mask_eb(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>) -> {B.mask(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))) == B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : List<&2, U32>}:
1839  %Equal.sym(List<&2, U32>, B.mask(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))), B.append(B.mask(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), B.mask(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))), li.mask_append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))) : {_ == B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : List<&2, U32>}
1840  %ccmp.mask_xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)) : {B.append(B.mask(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), B.mask(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))) == B.append(_, M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))) : List<&2, U32>}
1841  %li.mask_xor(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))) : {B.append(B.mask(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), B.mask(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))) == B.append(B.mask(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), _) : List<&2, U32>}
1842  {==}
1843
1844def ccmp.len_eb(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nv: List<&2, U32>, +av: List<&2, U32>, +pv: List<&2, U32>, +h: {Nat.is_le(m, 16n) == True{} : Bool}) -> {B.len(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))) == Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), m) : Nat}:
1845  %Equal.sym(Nat, B.len(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))), Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), B.len(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))), li.len_append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv)), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv)))))) : {_ == Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), m) : Nat}
1846  %Equal.sym(Nat, B.len(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))), B.len(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv)), li.len_xor(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv))))(ccmp.le_tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv, h))) : {Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), _) == Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), m) : Nat}
1847  %Equal.sym(Nat, B.len(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv)), m, ccmp.len_tag(~K, ~enc, k, m, Nat.sub(15n, B.len(nv)), nv, av, pv, h)) : {Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), _) == Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(nv)), nv), M.cm.split(pv))), m) : Nat}
1848  {==}
1849
1850# decryption accepts what encryption produced, whatever the parameter checks answer
1851def ccmp.main(~K: Data, ~enc: K -> M.CmBlock -> M.CmBlock, +k: K, +m: Nat, +nonce: B.Octets, +aad: B.Octets, +p: B.Octets, r: Result<&2, &2, M.CmError, Unit>) -> {CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), B.len(B.Octets.to_list(p))) == r : Result<&2, &2, M.CmError, Unit>} -> {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, CC.ccm.e2(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p), r), c => CC.Ccm.decrypt.ref(~K, ~enc, k, m, nonce, aad, c)) == Result.map(&2, &2, M.CmError, B.Octets, B.Octets, c => p, CC.ccm.e2(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p), r)) : Result<&2, &2, M.CmError, B.Octets>}:
1852  match r:
1853    case Fail{e}:
1854      h => {==}
1855    case Done{+u}:
1856      +h => +hm = ccmp.tag_le(m, B.len(B.Octets.to_list(nonce)), B.len(B.Octets.to_list(p)), u, h)
1857        +leb = ccmp.len_eb(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p), hm)
1858        # decryption reads the ciphertext back, masked
1859        %Equal.sym(List<&2, U32>, B.Octets.to_list(B.Octets.of_list(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))))), B.mask(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), BL.octets_to_of(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))))) : {CC.ccm.d2(~K, ~enc, Nat.is_le(m, B.len(_)), k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), _) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1860        # which it already is
1861        %Equal.sym(List<&2, U32>, B.mask(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))), ccmp.mask_eb(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))) : {CC.ccm.d2(~K, ~enc, Nat.is_le(m, B.len(_)), k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), _) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1862        # it is longer than the tag
1863        %Equal.sym(Nat, B.len(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m), leb) : {CC.ccm.d2(~K, ~enc, Nat.is_le(m, _), k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1864        # 
1865        %Equal.sym(Bool, Nat.is_le(m, Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m)), True{}, na.le_add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m)) : {CC.ccm.d2(~K, ~enc, _, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1866        # its body is as long as the message
1867        %Equal.sym(Nat, B.len(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m), leb) : {CC.ccm.d3(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))), CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), Nat.sub(_, m))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1868        # 
1869        %Equal.sym(Nat, Nat.sub(Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m), m), B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), na.sub_add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m)) : {CC.ccm.d3(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))), CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), _)) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1870        # 
1871        %Equal.sym(Nat, B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), B.len(B.Octets.to_list(p)), ccmp.len_xcp(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), p)) : {CC.ccm.d3(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))), CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), _)) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1872        # so its checks pass as encryption's did
1873        %Equal.sym(Result<&2, &2, M.CmError, Unit>, CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), B.len(B.Octets.to_list(p))), Done{u}, h) : {CC.ccm.d3(~K, ~enc, k, m, B.Octets.to_list(nonce), B.Octets.to_list(aad), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))), _) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1874        # the body and the tag apart
1875        %Equal.sym(Nat, B.len(B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m), leb) : {CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(Nat.sub(_, m), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.take(Nat.sub(_, m), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))))))), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.take(Nat.sub(_, m), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1876        # 
1877        %Equal.sym(Nat, Nat.sub(Nat.add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m), m), B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), na.sub_add(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), m)) : {CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(_, B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.take(_, B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))))))), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.take(_, B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1878        # 
1879        %Equal.sym(List<&2, U32>, B.take(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), li.take_append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))) : {CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(B.drop(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(_)))), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(_))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1880        # 
1881        %Equal.sym(List<&2, U32>, B.drop(B.len(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))), B.append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), li.drop_append(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))), M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))))) : {CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(_, M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))))))), CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p)))))) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1882        # CTR undoes itself: the plaintext
1883        %Equal.sym(List<&2, U32>, CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(CC.ccm.xcrypt(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), M.cm.split(B.Octets.to_list(p))))), B.Octets.to_list(p), ccmp.xxp(~K, ~enc, k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)), p)) : {CC.ccm.open(M.cm.ct_eq(M.cm.xor_bytes(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), _)), _) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1884        # the received tag, unmasked from S_0
1885        %Equal.sym(List<&2, U32>, M.cm.xor_bytes(M.cm.xor_bytes(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce))))), B.mask(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))), li.xor_xor(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), M.cm.bytes_of(enc(k, CC.ccm.a0(Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce)))))(ccmp.le_tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p), hm))) : {CC.ccm.open(M.cm.ct_eq(_, CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))), B.Octets.to_list(p)) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1886        # 
1887        %Equal.sym(List<&2, U32>, B.mask(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), ccmp.mask_tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))) : {CC.ccm.open(M.cm.ct_eq(_, CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))), B.Octets.to_list(p)) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1888        # matches the tag recomputed
1889        %Equal.sym(Bool, M.cm.ct_eq(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)), CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p))), True{}, ccmp.ct_refl(CC.ccm.tag(~K, ~enc, k, m, Nat.sub(15n, B.len(B.Octets.to_list(nonce))), B.Octets.to_list(nonce), B.Octets.to_list(aad), B.Octets.to_list(p)))) : {CC.ccm.open(_, B.Octets.to_list(p)) == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1890        # 
1891        %Equal.sym(B.Octets, B.Octets.of_list(B.Octets.to_list(p)), p, BL.octets_of_to(p)) : {Done{_} == Done{p} : Result<&2, &2, M.CmError, B.Octets>}
1892        {==}
1893
1894def Laws.ccm_round_trip(K, enc, k, m, nonce, aad, p):
1895  # the public defs are the structural ones
1896  %tr.ccm_encrypt(~K, ~enc, k, m, nonce, aad, p) : {Result.bind(&2, &2, M.CmError, B.Octets, B.Octets, _, c => CC.Ccm.decrypt(~K, ~enc, k, m, nonce, aad, c)) == Result.map(&2, &2, M.CmError, B.Octets, B.Octets, c => p, _) : Result<&2, &2, M.CmError, B.Octets>}
1897  %tr.bind_cong(CC.Ccm.encrypt.ref(~K, ~enc, k, m, nonce, aad, p), c => CC.Ccm.decrypt.ref(~K, ~enc, k, m, nonce, aad, c), c => CC.Ccm.decrypt(~K, ~enc, k, m, nonce, aad, c), c => tr.ccm_decrypt(~K, ~enc, k, m, nonce, aad, c)) : {_ == Result.map(&2, &2, M.CmError, B.Octets, B.Octets, c => p, CC.Ccm.encrypt.ref(~K, ~enc, k, m, nonce, aad, p)) : Result<&2, &2, M.CmError, B.Octets>}
1898  ccmp.main(~K, ~enc, k, m, nonce, aad, p, CC.ccm.checks(m, B.len(B.Octets.to_list(nonce)), B.len(B.Octets.to_list(p))))({==})
1899
1900# A block through Octets and back
1901
1902def Laws.block_octets_round_trip(b):
1903  %Equal.sym(List<&2, U32>, B.Octets.to_list(B.Octets.of_list(M.cm.bytes_of(b))), B.mask(M.cm.bytes_of(b)), BL.octets_to_of(M.cm.bytes_of(b))) : {M.CmBlock.of_octets.pick(Nat.is_eq(B.len(_), 16n), _) == Some{b} : Maybe<&2, M.CmBlock>}
1904  %Equal.sym(List<&2, U32>, B.mask(M.cm.bytes_onto(b, Nil{})), M.cm.bytes_onto(b, B.mask(Nil{})), sp.mask_blk(b, Nil{})) : {M.CmBlock.of_octets.pick(Nat.is_eq(B.len(_), 16n), _) == Some{b} : Maybe<&2, M.CmBlock>}
1905  %Equal.sym(M.CmBlock, M.cm.block_of(M.cm.bytes_of(b)), b, sp.block_bytes(b)) : {Some{_} == Some{b} : Maybe<&2, M.CmBlock>}
1906  {==}
1907
1908# Vectors
1909
1910def Laws.aes128_fips197_c1():
1911  {==}
1912
1913def Laws.aes_bad_key_length():
1914  {==}
1915
1916def Laws.cbc_sp800_38a_f21_block1():
1917  {==}
1918
1919def Laws.cbc_not_whole_blocks():
1920  {==}
1921
1922def Laws.cbc_short_iv():
1923  {==}
1924
1925def Laws.pkcs7_pad_empty():
1926  {==}
1927
1928def Laws.pkcs7_pad_15():
1929  {==}
1930
1931def Laws.pkcs7_unpad_15():
1932  {==}
1933
1934def Laws.pkcs7_unpad_zero():
1935  {==}
1936
1937def Laws.pkcs7_unpad_mixed():
1938  {==}
1939
1940def Laws.xts_short():
1941  {==}
1942
1943def Laws.xts_sector():
1944  {==}
1945
1946def Laws.ccm_bad_tag_length():
1947  {==}
1948
1949def Laws.ccm_bad_nonce_length():
1950  {==}
1951
1952def Laws.cmac_rfc4493_k1():
1953  {==}