blowfish.bend

bend-osdev-blowfish@0.1.0.0 · 384 lines · 0 definitions

1# Blowfish (B. Schneier, "Description of a New Variable-Length Key, 64-Bit
2# Block Cipher (Blowfish)", Fast Software Encryption 1993): a 64-bit block
3# cipher with a key of 32 to 448 bits.
4#
5# The block is two big-endian 32-bit halves xL, xR. Each of the sixteen
6# rounds is xL = xL xor P_i, xR = F(xL) xor xR, then the halves exchanged;
7# after the last round the exchange is undone and xR = xR xor P17,
8# xL = xL xor P18. F(x) = ((S1[a] + S2[b]) xor S3[c]) + S4[d], a .. d the
9# bytes of x, most significant first. The key schedule starts from the
10# digits of pi (P1 .. P18, then the four S-boxes), XORs the key into the
11# P-array, and replaces P1 .. P18 and then every S-box entry, two at a time,
12# with successive encryptions of the zero block.
13#
14# The key holds the cipher as a list of steps: sixteen rounds
15#   (L, R) -> (R xor F(L xor P_i), L xor P_i)
16# and the final (L, R) -> (R xor P18, L xor P17). Decryption undoes them last
17# to first (the specification's decryption, P in reverse order), so
18# decrypt(encrypt(b)) == b is provable for every key and block, whatever the
19# S-boxes hold.
20import Base
21import bend-osdev-bytes@0.1.1.0/bytes.bend as B
22import bend-osdev-cipher-core@0.1.0.0/cipher_core.bend as L
23
24# BEGIN GENERATED by gen/tables.py: tables
25# the first 1042 words of the fractional part of pi: P1 .. P18, then
26# S1, S2, S3, S4 (256 words each)
27def bf.pi.list() -> List<&2, U32>:
28  [608135816, 2242054355, 320440878, 57701188, 2752067618, 698298832, 137296536, 3964562569,
29    1160258022, 953160567, 3193202383, 887688300, 3232508343, 3380367581, 1065670069, 3041331479,
30    2450970073, 2306472731, 3509652390, 2564797868, 805139163, 3491422135, 3101798381, 1780907670,
31    3128725573, 4046225305, 614570311, 3012652279, 134345442, 2240740374, 1667834072, 1901547113,
32    2757295779, 4103290238, 227898511, 1921955416, 1904987480, 2182433518, 2069144605, 3260701109,
33    2620446009, 720527379, 3318853667, 677414384, 3393288472, 3101374703, 2390351024, 1614419982,
34    1822297739, 2954791486, 3608508353, 3174124327, 2024746970, 1432378464, 3864339955, 2857741204,
35    1464375394, 1676153920, 1439316330, 715854006, 3033291828, 289532110, 2706671279, 2087905683,
36    3018724369, 1668267050, 732546397, 1947742710, 3462151702, 2609353502, 2950085171, 1814351708,
37    2050118529, 680887927, 999245976, 1800124847, 3300911131, 1713906067, 1641548236, 4213287313,
38    1216130144, 1575780402, 4018429277, 3917837745, 3693486850, 3949271944, 596196993, 3549867205,
39    258830323, 2213823033, 772490370, 2760122372, 1774776394, 2652871518, 566650946, 4142492826,
40    1728879713, 2882767088, 1783734482, 3629395816, 2517608232, 2874225571, 1861159788, 326777828,
41    3124490320, 2130389656, 2716951837, 967770486, 1724537150, 2185432712, 2364442137, 1164943284,
42    2105845187, 998989502, 3765401048, 2244026483, 1075463327, 1455516326, 1322494562, 910128902,
43    469688178, 1117454909, 936433444, 3490320968, 3675253459, 1240580251, 122909385, 2157517691,
44    634681816, 4142456567, 3825094682, 3061402683, 2540495037, 79693498, 3249098678, 1084186820,
45    1583128258, 426386531, 1761308591, 1047286709, 322548459, 995290223, 1845252383, 2603652396,
46    3431023940, 2942221577, 3202600964, 3727903485, 1712269319, 422464435, 3234572375, 1170764815,
47    3523960633, 3117677531, 1434042557, 442511882, 3600875718, 1076654713, 1738483198, 4213154764,
48    2393238008, 3677496056, 1014306527, 4251020053, 793779912, 2902807211, 842905082, 4246964064,
49    1395751752, 1040244610, 2656851899, 3396308128, 445077038, 3742853595, 3577915638, 679411651,
50    2892444358, 2354009459, 1767581616, 3150600392, 3791627101, 3102740896, 284835224, 4246832056,
51    1258075500, 768725851, 2589189241, 3069724005, 3532540348, 1274779536, 3789419226, 2764799539,
52    1660621633, 3471099624, 4011903706, 913787905, 3497959166, 737222580, 2514213453, 2928710040,
53    3937242737, 1804850592, 3499020752, 2949064160, 2386320175, 2390070455, 2415321851, 4061277028,
54    2290661394, 2416832540, 1336762016, 1754252060, 3520065937, 3014181293, 791618072, 3188594551,
55    3933548030, 2332172193, 3852520463, 3043980520, 413987798, 3465142937, 3030929376, 4245938359,
56    2093235073, 3534596313, 375366246, 2157278981, 2479649556, 555357303, 3870105701, 2008414854,
57    3344188149, 4221384143, 3956125452, 2067696032, 3594591187, 2921233993, 2428461, 544322398,
58    577241275, 1471733935, 610547355, 4027169054, 1432588573, 1507829418, 2025931657, 3646575487,
59    545086370, 48609733, 2200306550, 1653985193, 298326376, 1316178497, 3007786442, 2064951626,
60    458293330, 2589141269, 3591329599, 3164325604, 727753846, 2179363840, 146436021, 1461446943,
61    4069977195, 705550613, 3059967265, 3887724982, 4281599278, 3313849956, 1404054877, 2845806497,
62    146425753, 1854211946, 1266315497, 3048417604, 3681880366, 3289982499, 2909710000, 1235738493,
63    2632868024, 2414719590, 3970600049, 1771706367, 1449415276, 3266420449, 422970021, 1963543593,
64    2690192192, 3826793022, 1062508698, 1531092325, 1804592342, 2583117782, 2714934279, 4024971509,
65    1294809318, 4028980673, 1289560198, 2221992742, 1669523910, 35572830, 157838143, 1052438473,
66    1016535060, 1802137761, 1753167236, 1386275462, 3080475397, 2857371447, 1040679964, 2145300060,
67    2390574316, 1461121720, 2956646967, 4031777805, 4028374788, 33600511, 2920084762, 1018524850,
68    629373528, 3691585981, 3515945977, 2091462646, 2486323059, 586499841, 988145025, 935516892,
69    3367335476, 2599673255, 2839830854, 265290510, 3972581182, 2759138881, 3795373465, 1005194799,
70    847297441, 406762289, 1314163512, 1332590856, 1866599683, 4127851711, 750260880, 613907577,
71    1450815602, 3165620655, 3734664991, 3650291728, 3012275730, 3704569646, 1427272223, 778793252,
72    1343938022, 2676280711, 2052605720, 1946737175, 3164576444, 3914038668, 3967478842, 3682934266,
73    1661551462, 3294938066, 4011595847, 840292616, 3712170807, 616741398, 312560963, 711312465,
74    1351876610, 322626781, 1910503582, 271666773, 2175563734, 1594956187, 70604529, 3617834859,
75    1007753275, 1495573769, 4069517037, 2549218298, 2663038764, 504708206, 2263041392, 3941167025,
76    2249088522, 1514023603, 1998579484, 1312622330, 694541497, 2582060303, 2151582166, 1382467621,
77    776784248, 2618340202, 3323268794, 2497899128, 2784771155, 503983604, 4076293799, 907881277,
78    423175695, 432175456, 1378068232, 4145222326, 3954048622, 3938656102, 3820766613, 2793130115,
79    2977904593, 26017576, 3274890735, 3194772133, 1700274565, 1756076034, 4006520079, 3677328699,
80    720338349, 1533947780, 354530856, 688349552, 3973924725, 1637815568, 332179504, 3949051286,
81    53804574, 2852348879, 3044236432, 1282449977, 3583942155, 3416972820, 4006381244, 1617046695,
82    2628476075, 3002303598, 1686838959, 431878346, 2686675385, 1700445008, 1080580658, 1009431731,
83    832498133, 3223435511, 2605976345, 2271191193, 2516031870, 1648197032, 4164389018, 2548247927,
84    300782431, 375919233, 238389289, 3353747414, 2531188641, 2019080857, 1475708069, 455242339,
85    2609103871, 448939670, 3451063019, 1395535956, 2413381860, 1841049896, 1491858159, 885456874,
86    4264095073, 4001119347, 1565136089, 3898914787, 1108368660, 540939232, 1173283510, 2745871338,
87    3681308437, 4207628240, 3343053890, 4016749493, 1699691293, 1103962373, 3625875870, 2256883143,
88    3830138730, 1031889488, 3479347698, 1535977030, 4236805024, 3251091107, 2132092099, 1774941330,
89    1199868427, 1452454533, 157007616, 2904115357, 342012276, 595725824, 1480756522, 206960106,
90    497939518, 591360097, 863170706, 2375253569, 3596610801, 1814182875, 2094937945, 3421402208,
91    1082520231, 3463918190, 2785509508, 435703966, 3908032597, 1641649973, 2842273706, 3305899714,
92    1510255612, 2148256476, 2655287854, 3276092548, 4258621189, 236887753, 3681803219, 274041037,
93    1734335097, 3815195456, 3317970021, 1899903192, 1026095262, 4050517792, 356393447, 2410691914,
94    3873677099, 3682840055, 3913112168, 2491498743, 4132185628, 2489919796, 1091903735, 1979897079,
95    3170134830, 3567386728, 3557303409, 857797738, 1136121015, 1342202287, 507115054, 2535736646,
96    337727348, 3213592640, 1301675037, 2528481711, 1895095763, 1721773893, 3216771564, 62756741,
97    2142006736, 835421444, 2531993523, 1442658625, 3659876326, 2882144922, 676362277, 1392781812,
98    170690266, 3921047035, 1759253602, 3611846912, 1745797284, 664899054, 1329594018, 3901205900,
99    3045908486, 2062866102, 2865634940, 3543621612, 3464012697, 1080764994, 553557557, 3656615353,
100    3996768171, 991055499, 499776247, 1265440854, 648242737, 3940784050, 980351604, 3713745714,
101    1749149687, 3396870395, 4211799374, 3640570775, 1161844396, 3125318951, 1431517754, 545492359,
102    4268468663, 3499529547, 1437099964, 2702547544, 3433638243, 2581715763, 2787789398, 1060185593,
103    1593081372, 2418618748, 4260947970, 69676912, 2159744348, 86519011, 2512459080, 3838209314,
104    1220612927, 3339683548, 133810670, 1090789135, 1078426020, 1569222167, 845107691, 3583754449,
105    4072456591, 1091646820, 628848692, 1613405280, 3757631651, 526609435, 236106946, 48312990,
106    2942717905, 3402727701, 1797494240, 859738849, 992217954, 4005476642, 2243076622, 3870952857,
107    3732016268, 765654824, 3490871365, 2511836413, 1685915746, 3888969200, 1414112111, 2273134842,
108    3281911079, 4080962846, 172450625, 2569994100, 980381355, 4109958455, 2819808352, 2716589560,
109    2568741196, 3681446669, 3329971472, 1835478071, 660984891, 3704678404, 4045999559, 3422617507,
110    3040415634, 1762651403, 1719377915, 3470491036, 2693910283, 3642056355, 3138596744, 1364962596,
111    2073328063, 1983633131, 926494387, 3423689081, 2150032023, 4096667949, 1749200295, 3328846651,
112    309677260, 2016342300, 1779581495, 3079819751, 111262694, 1274766160, 443224088, 298511866,
113    1025883608, 3806446537, 1145181785, 168956806, 3641502830, 3584813610, 1689216846, 3666258015,
114    3200248200, 1692713982, 2646376535, 4042768518, 1618508792, 1610833997, 3523052358, 4130873264,
115    2001055236, 3610705100, 2202168115, 4028541809, 2961195399, 1006657119, 2006996926, 3186142756,
116    1430667929, 3210227297, 1314452623, 4074634658, 4101304120, 2273951170, 1399257539, 3367210612,
117    3027628629, 1190975929, 2062231137, 2333990788, 2221543033, 2438960610, 1181637006, 548689776,
118    2362791313, 3372408396, 3104550113, 3145860560, 296247880, 1970579870, 3078560182, 3769228297,
119    1714227617, 3291629107, 3898220290, 166772364, 1251581989, 493813264, 448347421, 195405023,
120    2709975567, 677966185, 3703036547, 1463355134, 2715995803, 1338867538, 1343315457, 2802222074,
121    2684532164, 233230375, 2599980071, 2000651841, 3277868038, 1638401717, 4028070440, 3237316320,
122    6314154, 819756386, 300326615, 590932579, 1405279636, 3267499572, 3150704214, 2428286686,
123    3959192993, 3461946742, 1862657033, 1266418056, 963775037, 2089974820, 2263052895, 1917689273,
124    448879540, 3550394620, 3981727096, 150775221, 3627908307, 1303187396, 508620638, 2975983352,
125    2726630617, 1817252668, 1876281319, 1457606340, 908771278, 3720792119, 3617206836, 2455994898,
126    1729034894, 1080033504, 976866871, 3556439503, 2881648439, 1522871579, 1555064734, 1336096578,
127    3548522304, 2579274686, 3574697629, 3205460757, 3593280638, 3338716283, 3079412587, 564236357,
128    2993598910, 1781952180, 1464380207, 3163844217, 3332601554, 1699332808, 1393555694, 1183702653,
129    3581086237, 1288719814, 691649499, 2847557200, 2895455976, 3193889540, 2717570544, 1781354906,
130    1676643554, 2592534050, 3230253752, 1126444790, 2770207658, 2633158820, 2210423226, 2615765581,
131    2414155088, 3127139286, 673620729, 2805611233, 1269405062, 4015350505, 3341807571, 4149409754,
132    1057255273, 2012875353, 2162469141, 2276492801, 2601117357, 993977747, 3918593370, 2654263191,
133    753973209, 36408145, 2530585658, 25011837, 3520020182, 2088578344, 530523599, 2918365339,
134    1524020338, 1518925132, 3760827505, 3759777254, 1202760957, 3985898139, 3906192525, 674977740,
135    4174734889, 2031300136, 2019492241, 3983892565, 4153806404, 3822280332, 352677332, 2297720250,
136    60907813, 90501309, 3286998549, 1016092578, 2535922412, 2839152426, 457141659, 509813237,
137    4120667899, 652014361, 1966332200, 2975202805, 55981186, 2327461051, 676427537, 3255491064,
138    2882294119, 3433927263, 1307055953, 942726286, 933058658, 2468411793, 3933900994, 4215176142,
139    1361170020, 2001714738, 2830558078, 3274259782, 1222529897, 1679025792, 2729314320, 3714953764,
140    1770335741, 151462246, 3013232138, 1682292957, 1483529935, 471910574, 1539241949, 458788160,
141    3436315007, 1807016891, 3718408830, 978976581, 1043663428, 3165965781, 1927990952, 4200891579,
142    2372276910, 3208408903, 3533431907, 1412390302, 2931980059, 4132332400, 1947078029, 3881505623,
143    4168226417, 2941484381, 1077988104, 1320477388, 886195818, 18198404, 3786409000, 2509781533,
144    112762804, 3463356488, 1866414978, 891333506, 18488651, 661792760, 1628790961, 3885187036,
145    3141171499, 876946877, 2693282273, 1372485963, 791857591, 2686433993, 3759982718, 3167212022,
146    3472953795, 2716379847, 445679433, 3561995674, 3504004811, 3574258232, 54117162, 3331405415,
147    2381918588, 3769707343, 4154350007, 1140177722, 4074052095, 668550556, 3214352940, 367459370,
148    261225585, 2610173221, 4209349473, 3468074219, 3265815641, 314222801, 3066103646, 3808782860,
149    282218597, 3406013506, 3773591054, 379116347, 1285071038, 846784868, 2669647154, 3771962079,
150    3550491691, 2305946142, 453669953, 1268987020, 3317592352, 3279303384, 3744833421, 2610507566,
151    3859509063, 266596637, 3847019092, 517658769, 3462560207, 3443424879, 370717030, 4247526661,
152    2224018117, 4143653529, 4112773975, 2788324899, 2477274417, 1456262402, 2901442914, 1517677493,
153    1846949527, 2295493580, 3734397586, 2176403920, 1280348187, 1908823572, 3871786941, 846861322,
154    1172426758, 3287448474, 3383383037, 1655181056, 3139813346, 901632758, 1897031941, 2986607138,
155    3066810236, 3447102507, 1393639104, 373351379, 950779232, 625454576, 3124240540, 4148612726,
156    2007998917, 544563296, 2244738638, 2330496472, 2058025392, 1291430526, 424198748, 50039436,
157    29584100, 3605783033, 2429876329, 2791104160, 1057563949, 3255363231, 3075367218, 3463963227,
158    1469046755, 985887462]
159# END GENERATED: tables
160
161# The four S-boxes (internal)
162type LcBfTabs is Data:
163  LcBfTabs{s1: L.LcTab, s2: L.LcTab, s3: L.LcTab, s4: L.LcTab}
164
165# F
166def bf.f(t: LcBfTabs, +x: U32) -> U32:
167  match t:
168    case LcBfTabs{s1, s2, s3, s4}:
169      U32.add(U32.xor(U32.add(L.lc.tab.get(8n, s1, L.lc.byte(x, 3n)), L.lc.tab.get(8n, s2, L.lc.byte(x, 2n))), L.lc.tab.get(8n, s3, L.lc.byte(x, 1n))), L.lc.tab.get(8n, s4, L.lc.byte(x, 0n)))
170
171# The steps of the cipher (internal)
172type LcBfOp is Data:
173  LcBfRound{p: U32, t: LcBfTabs}
174  LcBfFinal{p17: U32, p18: U32}
175
176def bf.op(o: LcBfOp, b: L.LcBlock64) -> L.LcBlock64:
177  match o:
178    case LcBfRound{p, t}:
179      match b:
180        case L.LcBlock64{l, r}:
181          +a = U32.xor(l, p)
182          L.LcBlock64{U32.xor(r, bf.f(t, a)), a}
183    case LcBfFinal{p17, p18}:
184      match b:
185        case L.LcBlock64{l, r}:
186          L.LcBlock64{U32.xor(r, p18), U32.xor(l, p17)}
187
188def bf.unop(o: LcBfOp, b: L.LcBlock64) -> L.LcBlock64:
189  match o:
190    case LcBfRound{p, t}:
191      match b:
192        case L.LcBlock64{x, +y}:
193          L.LcBlock64{U32.xor(y, p), U32.xor(x, bf.f(t, y))}
194    case LcBfFinal{p17, p18}:
195      match b:
196        case L.LcBlock64{x, y}:
197          L.LcBlock64{U32.xor(y, p17), U32.xor(x, p18)}
198
199def bf.run(os: List<&2, LcBfOp>, b: L.LcBlock64) -> L.LcBlock64:
200  match os:
201    case Nil{}:
202      b
203    case Con{o, t}:
204      bf.run(t, bf.op(o, b))
205
206def bf.unrun(os: List<&2, LcBfOp>, b: L.LcBlock64) -> L.LcBlock64:
207  match os:
208    case Nil{}:
209      b
210    case Con{o, t}:
211      bf.unop(o, bf.unrun(t, b))
212
213# The key schedule
214
215# the steps from a P-array of 18 words (n = 16 rounds, then the final)
216def bf.ops(n: Nat, ps: List<&2, U32>, +t: LcBfTabs) -> List<&2, LcBfOp>:
217  match n:
218    case 0n:
219      match ps:
220        case Con{p17, Con{p18, rest}}:
221          [LcBfFinal{p17, p18}]
222        case _:
223          Nil{}
224    case 1n+m:
225      match ps:
226        case Con{p, rest}:
227          Con{LcBfRound{p, t}, bf.ops(m, rest, t)}
228        case Nil{}:
229          Nil{}
230
231# n words of xs from offset i
232def bf.slice(xs: List<&2, U32>, i: Nat, n: Nat) -> List<&2, U32>:
233  B.take(n, B.drop(i, xs))
234
235# the key bytes repeated cyclically: n bytes, from the rest of the key ys
236# (the whole key xs when ys runs out)
237def bf.cycle(n: Nat, ys: List<&2, U32>, +xs: List<&2, U32>) -> List<&2, U32>:
238  match n:
239    case 0n:
240      Nil{}
241    case 1n+p:
242      match ys:
243        case Con{y, t}:
244          Con{y, bf.cycle(p, t, xs)}
245        case Nil{}:
246          match xs:
247            case Nil{}:
248              Nil{}
249            case Con{x, t}:
250              Con{x, bf.cycle(p, t, xs)}
251
252# P xored with the key bytes as big-endian words
253def bf.pkey(ps: List<&2, U32>, ks: List<&2, U32>) -> List<&2, U32>:
254  match ps ks:
255    case Con{p, pt} Con{a, Con{b, Con{c, Con{d, kt}}}}:
256      Con{U32.xor(p, L.lc.be(a, b, c, d)), bf.pkey(pt, kt)}
257    case _ _:
258      Nil{}
259
260# P entries i and i + 1 replaced by h and l
261def bf.set_p(i: Nat, ps: List<&2, U32>, +h: U32, +l: U32) -> List<&2, U32>:
262  match i:
263    case 0n:
264      match ps:
265        case Con{p, Con{q, u}}:
266          Con{h, Con{l, u}}
267        case _:
268          Nil{}
269    case 1n+j:
270      match ps:
271        case Con{p, t}:
272          Con{p, bf.set_p(j, t, h, l)}
273        case Nil{}:
274          Nil{}
275
276# entry j of the S-box k (0 to 3) set to v
277def bf.set_s(t: LcBfTabs, k: Nat, +j: U32, v: U32) -> LcBfTabs:
278  match t:
279    case LcBfTabs{s1, s2, s3, s4}:
280      match k:
281        case 0n:
282          LcBfTabs{L.lc.tab.set(8n, s1, j, v), s2, s3, s4}
283        case 1n+k1:
284          match k1:
285            case 0n:
286              LcBfTabs{s1, L.lc.tab.set(8n, s2, j, v), s3, s4}
287            case 1n+k2:
288              match k2:
289                case 0n:
290                  LcBfTabs{s1, s2, L.lc.tab.set(8n, s3, j, v), s4}
291                case 1n+k3:
292                  LcBfTabs{s1, s2, s3, L.lc.tab.set(8n, s4, j, v)}
293
294# The state of the key schedule: the P-array, the S-boxes, and the last
295# block encrypted
296type LcBfSt is Data:
297  LcBfSt{ps: List<&2, U32>, t: LcBfTabs, b: L.LcBlock64}
298
299def bf.fill_p.go(n: Nat, +i: Nat, +ps: List<&2, U32>, +t: LcBfTabs, c: L.LcBlock64) -> LcBfSt:
300  match n:
301    case 0n:
302      match c:
303        case L.LcBlock64{+h, +l}:
304          LcBfSt{bf.set_p(i, ps, h, l), t, L.LcBlock64{h, l}}
305    case 1n+m:
306      match c:
307        case L.LcBlock64{+h, +l}:
308          +ps2 = bf.set_p(i, ps, h, l)
309          bf.fill_p.go(m, Nat.add(i, 2n), ps2, t, bf.run(bf.ops(16n, ps2, t), L.LcBlock64{h, l}))
310
311# P1 .. P18 replaced, two at a time, by successive encryptions (nine)
312def bf.fill_p(s: LcBfSt) -> LcBfSt:
313  match s:
314    case LcBfSt{+ps, +t, b}:
315      bf.fill_p.go(8n, 0n, ps, t, bf.run(bf.ops(16n, ps, t), b))
316
317def bf.fill_s.go(n: Nat, +k: Nat, +j: U32, +ps: List<&2, U32>, +t: LcBfTabs, c: L.LcBlock64) -> LcBfSt:
318  match n:
319    case 0n:
320      match c:
321        case L.LcBlock64{+h, +l}:
322          LcBfSt{ps, bf.set_s(bf.set_s(t, k, j, h), k, U32.add(j, 1), l), L.LcBlock64{h, l}}
323    case 1n+m:
324      match c:
325        case L.LcBlock64{+h, +l}:
326          +t1 = bf.set_s(bf.set_s(t, k, j, h), k, U32.add(j, 1), l)
327          bf.fill_s.go(m, k, U32.add(j, 2), ps, t1, bf.run(bf.ops(16n, ps, t1), L.LcBlock64{h, l}))
328
329# the S-box k's 256 entries replaced, two at a time (128 encryptions)
330def bf.fill_s(+k: Nat, s: LcBfSt) -> LcBfSt:
331  match s:
332    case LcBfSt{+ps, +t, b}:
333      bf.fill_s.go(127n, k, 0, ps, t, bf.run(bf.ops(16n, ps, t), b))
334
335# A Blowfish key: the steps of the cipher (opaque; built by LcBlowfish.key)
336type LcBlowfishKey is Data:
337  LcBlowfishKey{ops: List<&2, LcBfOp>}
338
339# the S-boxes before the key: pi's words 18 to 1041
340def bf.tables(+pi: List<&2, U32>) -> LcBfTabs:
341  LcBfTabs{L.lc.tab(8n, bf.slice(pi, 18n, 256n)), L.lc.tab(8n, bf.slice(pi, 274n, 256n)), L.lc.tab(8n, bf.slice(pi, 530n, 256n)), L.lc.tab(8n, bf.slice(pi, 786n, 256n))}
342
343def bf.key.of(s: LcBfSt) -> LcBlowfishKey:
344  match s:
345    case LcBfSt{ps, +t, b}:
346      LcBlowfishKey{bf.ops(16n, ps, t)}
347
348def bf.key(+xs: List<&2, U32>) -> LcBlowfishKey:
349  +pi = bf.pi.list()
350  +t = bf.tables(pi)
351  +s0 : LcBfSt = LcBfSt{bf.pkey(B.take(18n, pi), bf.cycle(72n, xs, xs)), t, L.LcBlock64{0, 0}}
352  bf.key.of(bf.fill_s(3n, bf.fill_s(2n, bf.fill_s(1n, bf.fill_s(0n, bf.fill_p(s0))))))
353
354def bf.key.pick(ok: Bool, +xs: List<&2, U32>) -> Result<&2, &2, L.LcError, LcBlowfishKey>:
355  match ok:
356    case True{}:
357      Done{bf.key(xs)}
358    case False{}:
359      Fail{L.LcBadKeyLength{B.len(xs)}}
360
361# The cipher
362
363# a key of 4 to 56 bytes (32 to 448 bits, as the specification says)
364def LcBlowfish.key(o: B.Octets) -> Result<&2, &2, L.LcError, LcBlowfishKey>:
365  +xs = B.Octets.to_list(o)
366  +n = B.len(xs)
367  bf.key.pick(Bool.and(Nat.is_le(4n, n), Nat.is_le(n, 56n)), xs)
368
369# a key of 1 to 72 bytes: the key schedule takes up to 72 (18 words of P),
370# and some test sets use keys shorter than 4 bytes
371def LcBlowfish.key_any(o: B.Octets) -> Result<&2, &2, L.LcError, LcBlowfishKey>:
372  +xs = B.Octets.to_list(o)
373  +n = B.len(xs)
374  bf.key.pick(Bool.and(Nat.is_le(1n, n), Nat.is_le(n, 72n)), xs)
375
376def LcBlowfish.encrypt(k: LcBlowfishKey, b: L.LcBlock64) -> L.LcBlock64:
377  match k:
378    case LcBlowfishKey{ops}:
379      bf.run(ops, b)
380
381def LcBlowfish.decrypt(k: LcBlowfishKey, b: L.LcBlock64) -> L.LcBlock64:
382  match k:
383    case LcBlowfishKey{ops}:
384      bf.unrun(ops, b)