]> git.cryptolib.org Git - avr-crypto-lib.git/blob - keccak/keccak-asm.S
fixing style, typos and uart
[avr-crypto-lib.git] / keccak / keccak-asm.S
1 /* keccac-asm.S */
2 /*
3     This file is part of the AVR-Crypto-Lib.
4     Copyright (C) 2012  Daniel Otte (daniel.otte@rub.de)
5
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /**
20  * \file     keccak-asm.S
21  * \email    daniel.otte@rub.de
22  * \author   Daniel Otte
23  * \date     2012-12-16
24  * \license  GPLv3 or later
25  *
26  */
27
28 .nolist
29 #include "avr-asm-macros.S"
30 .list
31
32 .equ __zero_reg__, 1
33
34 /*
35 typedef struct{
36         uint64_t a[5][5];
37         uint16_t r;
38         uint8_t  bs;
39 } keccak_ctx_t;
40 */
41         .struct 0
42 ctx_a:
43         .struct ctx_a + 8 * 5 * 5
44 ctx_r:
45         .struct ctx_r + 2
46 ctx_bs:
47
48         .section .text
49
50         .global rho_pi_idx_table
51 rho_pi_idx_table:
52         .irp i, 0, 1, 2, 3, 4
53                 .irp j, 0, 1, 2, 3, 4
54                         .byte (((2 * \j + 3 * \i) % 5) * 5 + \i) * 8
55                 .endr
56         .endr
57
58 /*
59 #define ROT_BIT(a) (( (a) <= 4) ? ((a) << 1) : (0x01 | ((8 - (a)) << 1)))
60 #define ROT_CODE(a) ((((a) / 8 + ((((a) % 8) > 4) ? 1 : 0)) << 4) | ROT_BIT(((a) % 8)))
61
62 const uint8_t keccak_rotate_codes[5][5] PROGMEM = {
63         { ROT_CODE( 0), ROT_CODE( 1), ROT_CODE(62), ROT_CODE(28), ROT_CODE(27) },
64         { ROT_CODE(36), ROT_CODE(44), ROT_CODE( 6), ROT_CODE(55), ROT_CODE(20) },
65         { ROT_CODE( 3), ROT_CODE(10), ROT_CODE(43), ROT_CODE(25), ROT_CODE(39) },
66         { ROT_CODE(41), ROT_CODE(45), ROT_CODE(15), ROT_CODE(21), ROT_CODE( 8) },
67         { ROT_CODE(18), ROT_CODE( 2), ROT_CODE(61), ROT_CODE(56), ROT_CODE(14) }
68 };
69 */
70
71 keccak_rotate_codes:
72 .byte   0x00, 0x02, 0x85, 0x38, 0x36
73 .byte   0x48, 0x58, 0x15, 0x73, 0x28
74 .byte   0x06, 0x14, 0x56, 0x32, 0x53
75 .byte   0x52, 0x67, 0x23, 0x37, 0x10
76 .byte   0x24, 0x04, 0x87, 0x70, 0x25
77
78 keccak_rc_comp:
79 .byte   0x01, 0x92, 0xda, 0x70
80 .byte   0x9b, 0x21, 0xf1, 0x59
81 .byte   0x8a, 0x88, 0x39, 0x2a
82 .byte   0xbb, 0xcb, 0xd9, 0x53
83 .byte   0x52, 0xc0, 0x1a, 0x6a
84 .byte   0xf1, 0xd0, 0x21, 0x78
85
86         .align 2
87
88 rotate64_1bit_left:
89         bst r25, 7
90         rol r18
91         rol r19
92         rol r20
93         rol r21
94         rol r22
95         rol r23
96         rol r24
97         rol r25
98         bld r18, 0
99         ret
100
101 rotate64_1bit_right:
102         bst r18, 0
103         ror r25
104         ror r24
105         ror r23
106         ror r22
107         ror r21
108         ror r20
109         ror r19
110         ror r18
111         bld r25, 7
112         ret
113
114 rotate64_1byte_left:
115         mov r0, r25
116         mov r25, r24
117         mov r24, r23
118         mov r23, r22
119         mov r22, r21
120         mov r21, r20
121         mov r20, r19
122         mov r19, r18
123         mov r18, r0
124         ret
125
126 rotate64_2byte_left:
127         movw r0, r24
128         movw r24, r22
129         movw r22, r20
130         movw r20, r18
131         movw r18, r0
132         ret
133
134 rotate64_3byte_left:
135         mov r0, r25
136         mov r25, r22
137         mov r22, r19
138         mov r19, r24
139         mov r24, r21
140         mov r21, r18
141         mov r18, r23
142         mov r23, r20
143         mov r20, r0
144         ret
145
146 rotate64_4byte_left:
147         movw r0, r24
148         movw r24, r20
149         movw r20, r0
150         movw r0, r22
151         movw r22, r18
152         movw r18, r0
153         ret
154
155 rotate64_5byte_left:
156         mov r0, r25
157         mov r25, r20
158         mov r20, r23
159         mov r23, r18
160         mov r18, r21
161         mov r21, r24
162         mov r24, r19
163         mov r19, r22
164         mov r22, r0
165         ret
166
167 rotate64_6byte_left:
168         movw r0, r18
169         movw r18, r20
170         movw r20, r22
171         movw r22, r24
172         movw r24, r0
173         ret
174
175 rotate64_7byte_left:
176         mov r0, r18
177         mov r18, r19
178         mov r19, r20
179         mov r20, r21
180         mov r21, r22
181         mov r22, r23
182         mov r23, r24
183         mov r24, r25
184         mov r25, r0
185
186 byte_rot_jmp_table:
187         ret
188         rjmp rotate64_1byte_left
189         rjmp rotate64_2byte_left
190         rjmp rotate64_3byte_left
191         rjmp rotate64_4byte_left
192         rjmp rotate64_5byte_left
193         rjmp rotate64_6byte_left
194         rjmp rotate64_7byte_left
195
196
197 /*
198         void keccak_theta (uint64_t *a, uint64_t *b){
199         // uint64_t b[5][5];
200                 for(i = 0; i < 5; ++i){
201                         b[i][0] = a[0][i] ^ a[1][i] ^ a[2][i] ^ a[3][i] ^ a[4][i];
202                 }
203         }
204 */
205
206 /*********************************************
207  * theta_2a
208  *********************************************
209         input:
210                 r24:r25 = a ; uint64_t a[5][5]
211                 X = b       ; uint64_t *b
212         output:
213                 a[0..4][0] ^= b
214                 r20 = 0
215                 r21 = XX
216                 r22 = XX
217                 r24:r25 += 8
218                 X += 8
219                 Z = r24:r25 + 7 + 4 * 40
220 */
221 theta_2a:
222         ldi r20, 8
223 10:
224         movw ZL, r24
225         ld  r21, X+
226         .irp r, 0, 1, 2, 3, 4
227                 ld  r22, Z
228                 eor r22, r21
229                 st  Z, r22
230         .if \r != 4
231                 adiw ZL, 40
232         .endif
233         .endr
234         adiw r24, 1
235         dec r20
236         brne 10b
237         ret
238
239 /*********************************************
240  * theta_2b
241  *********************************************
242         input:
243                 r24:r25 = a+1 ; uint64_t a[5][5]
244                 X = b       ; uint64_t *b
245         output:
246                 a[0..4][0] ^= rol(b,1)
247                 r19 = XX
248                 r20 = 0
249                 r21 = XX
250                 r22 = XX
251                 r24:r25 += 8
252                 X += 8
253                 Z = r24:r25 + 7 + 4 * 40
254 */
255 theta_2b:
256         ldi r20, 7
257         ld r19, X+
258         lsl r19
259         rol __zero_reg__
260 10:
261         movw ZL, r24
262         ld  r21, X+
263         ror __zero_reg__
264         rol r21
265         rol __zero_reg__
266         .irp r, 0, 1, 2, 3, 4
267                 ld  r22, Z
268                 eor r22, r21
269                 st  Z, r22
270         .if \r != 4
271                 adiw ZL, 40
272         .endif
273         .endr
274         adiw r24, 1
275         dec r20
276         brne 10b
277         add r19, __zero_reg__
278         sbiw r24, 8
279         movw ZL, r24
280         .irp r, 0, 1, 2, 3, 4
281                 ld  r22, Z
282                 eor r22, r19
283                 st  Z, r22
284         .if \r != 4
285                 adiw ZL, 40
286         .endif
287         .endr
288         adiw r24, 9
289         clr __zero_reg__
290         ret
291
292 ;       a[i][j] =  b[i][j] ^ ((~(b[i][(j + 1) % 5])) & (b[i][(j + 2) % 5]));
293
294 /*********************************************
295  * chi_step
296  *********************************************
297         input:
298                 Y = a; uint8t *a;
299                 X = b; uint8t *b;
300                 Z = c; uint8t *c;
301         output:
302                 a[0..7] ^= ~b[0..7] & c[0..7]
303                 X += 8
304                 Y += 8
305                 Z += 8
306                 r16 = 0
307                 trash r21, r22, r23
308 */
309 chi_step:
310         ldi r16, 8
311 10:
312         ld r21, Y
313         ld r22, X+
314         ld r23, Z+
315         com r22
316         and r22, r23
317         eor r21, r22
318         st Y+, r21
319         dec r16
320         brne 10b
321         ret
322
323         .global keccak_nextBlock
324         .func keccak_nextBlock
325 keccak_nextBlock:
326         movw ZL, r24
327         subi ZL, lo8(-ctx_bs)
328         sbci ZH, hi8(-ctx_bs)
329         ld r20, Z
330         movw XL, r24
331         movw ZL, r22
332 10:
333         ld r22, X
334         ld r23, Z+
335         eor r22, r23
336         st X+, r22
337         dec r20
338         brne 10b
339         .endfunc
340
341         .global keccak_f1600
342         .func keccak_f1600
343 keccak_f1600:
344         push_range 2, 9
345         push r16
346         push_range 28, 29
347
348         stack_alloc_large 200, r26, r27
349         adiw XL, 1
350
351         clr r9
352 5:
353         movw r30, r24 ; Z = a
354
355         ldi r19, 5
356 10:
357         ldi r20, 8
358 20:
359         ld  r22, Z
360         adiw ZL, 40
361         ld  r21, Z
362         eor r22, r21
363         adiw ZL, 40
364         ld  r21, Z
365         eor r22, r21
366         adiw ZL, 40
367         ld  r21, Z
368         eor r22, r21
369         adiw ZL, 40
370         ld  r21, Z
371         eor r22, r21
372         adiw r24, 1
373         movw r30, r24
374         st X+, r22
375         dec r20
376         brne 20b
377
378         adiw XL, 8 * 4
379         dec r19
380         brne 10b
381 /*
382         for(i = 0; i < 5; ++i){
383                 for(j = 0; j < 5; ++j){
384                         a[j][i] ^= b[(4 + i) % 5][0];
385                 }
386         }
387
388 */
389 /* a[0..4][0]{0..7} ^= b[4][0]{0..7} */
390         sbiw XL, 5 * 8
391         sbiw r24, 40
392         rcall theta_2a
393 /* a[0..4][1]{0..7} ^= b[0][0]{0..7} */
394         subi XL, lo8(4 * 5 * 8 + 8)
395         sbci XH, hi8(4 * 5 * 8 + 8)
396         rcall theta_2a
397 /* a[0..4][2]{0..7} ^= b[1][0]{0..7} */
398         adiw XL, 4 * 8
399         rcall theta_2a
400 /* a[0..4][3]{0..7} ^= b[2][0]{0..7} */
401         adiw XL, 4 * 8
402         rcall theta_2a
403 /* a[0..4][4]{0..7} ^= b[3][0]{0..7} */
404         adiw XL, 4 * 8
405         rcall theta_2a
406 /*
407         for(i = 0; i < 5; ++i){
408         for(j = 0; j < 5; ++j){
409             a[j][i] ^= rotate64_1bit_left(b[(i + 1) % 5][0]);
410         }
411     }
412 */
413 /* a[0..4][0]{0..7} ^= rol(b[1][0]{0..7}) */
414         subi r24, lo8(5 * 8 - 1)
415         sbci r25, hi8(5 * 8 - 1)
416         subi XL, lo8(2 * 5 * 8 + 8)
417         sbci XH, hi8(2 * 5 * 8 + 8)
418         rcall theta_2b
419 /* a[0..4][1]{0..7} ^= rol(b[2][0]{0..7}) */
420         adiw XL, 4 * 8
421         rcall theta_2b
422 /* a[0..4][21]{0..7} ^= rol(b[3][0]{0..7}) */
423         adiw XL, 4 * 8
424         rcall theta_2b
425 /* a[0..4][3]{0..7} ^= rol(b[4][0]{0..7}) */
426         adiw XL, 4 * 8
427         rcall theta_2b
428 /* a[0..4][4]{0..7} ^= rol(b[0][0]{0..7}) */
429         subi XL, lo8(4 * 5 * 8 + 8)
430         sbci XH, hi8(4 * 5 * 8 + 8)
431         rcall theta_2b
432 /*
433    -- rho & pi --
434         for(i = 0; i < 5; ++i){
435                 for(j = 0; j < 5; ++j){
436                         b[(2 * i + 3 * j) % 5][j] =
437               rotate64left_code(a[j][i], pgm_read_byte(&(keccak_rotate_codes[i][j])));
438                 }
439         }
440
441    -- or --
442
443         const uint8_t *rot_code = (const uint8_t*)keccak_rotate_codes;
444     const uint8_t *idx_idx = (const uint8_t*)rho_pi_idx_table;
445     uint64_t *a_tmp = (uint64_t*)a;
446         for(i = 0; i < 25; ++i){
447                     *((uint64_t*)(((uint8_t*)b) + pgm_read_byte(idx_idx++))) =
448                 rotate64left_code(*a_tmp++, pgm_read_byte(rot_code++));
449
450         }
451
452 */
453
454 .equ B_REG_L, 6
455 .equ B_REG_H, 7
456
457         ldi r18, lo8(keccak_rotate_codes)
458         ldi r19, hi8(keccak_rotate_codes)
459         movw r2, r18
460         ldi r18, lo8(rho_pi_idx_table)
461         ldi r19, hi8(rho_pi_idx_table)
462         movw r4, r18
463         ldi r16, 25
464         mov r8, r16
465
466         sbiw r24, 5 * 8 + 1
467         movw YL, r24
468         sbiw XL, 8
469         movw B_REG_L, XL
470
471 10:
472         ld r18, Y+
473         ld r19, Y+
474         ld r20, Y+
475         ld r21, Y+
476         ld r22, Y+
477         ld r23, Y+
478         ld r24, Y+
479         ld r25, Y+
480         movw ZL, r2
481         lpm r16, Z+
482         movw r2, ZL
483 rotate64left_code:
484         ldi r30, pm_lo8(byte_rot_jmp_table)
485         ldi r31, pm_hi8(byte_rot_jmp_table)
486         mov r0, r16
487         andi r16, 0x70
488         swap r16
489         add r30, r16
490         adc r31, r1
491         mov r16, r0
492         andi r16, 0x0f
493         icall
494         clr r1
495 rotate64_nbit_autodir:
496         lsr r16
497         brcc rotate64_nbit_left
498 rotate64_nbit_right:
499         ldi r30, pm_lo8(rotate64_1bit_right)
500         ldi r31, pm_hi8(rotate64_1bit_right)
501         rjmp icall_r16_times
502 rotate64_nbit_left:
503         ldi r30, pm_lo8(rotate64_1bit_left)
504         ldi r31, pm_hi8(rotate64_1bit_left)
505 icall_r16_times:
506 1:      dec r16
507         brmi 2f
508         icall
509         rjmp 1b
510 2:
511         movw ZL, r4
512         lpm r16, Z+
513         movw r4, ZL
514         movw XL, B_REG_L
515         add XL, r16
516         adc XH, __zero_reg__
517         st X+, r18
518         st X+, r19
519         st X+, r20
520         st X+, r21
521         st X+, r22
522         st X+, r23
523         st X+, r24
524         st X+, r25
525
526         dec r8
527         brne 10b
528 /*
529         -- chi --
530         for(i = 0; i < 5; ++i){
531         a[i][0] ^= ((~(b[i][1])) & (b[i][2]));
532         a[i][1] ^= ((~(b[i][2])) & (b[i][3]));
533         a[i][2] ^= ((~(b[i][3])) & (b[i][4]));
534         a[i][3] ^= ((~(b[i][4])) & (b[i][0]));
535         a[i][4] ^= ((~(b[i][0])) & (b[i][1]));
536
537         }
538 */
539         ; memcpy(a, b, 200)
540         ; X points at b + 32 + 8 = b + 40 = b[1][0] has to point to b[0][0]
541         ldi r16, 200 / 8
542         sbiw XL, 5 * 8
543         movw ZL, XL
544         subi YL, lo8(5 * 5 * 8)
545         sbci YH, hi8(5 * 5 * 8)
546         movw r2, YL
547 10:
548         .rept 8
549         ld r22, X+
550         st Y+, r22
551         .endr
552         dec r16
553         brne 10b
554
555         ; Z points at b
556         movw XL, ZL
557         movw r4, ZL
558         adiw XL, 8
559         adiw ZL, 16
560         movw YL, r2
561         ldi r18, 5
562 10:
563         rcall chi_step
564         rcall chi_step
565         rcall chi_step
566         sbiw ZL, 5 * 8
567         rcall chi_step
568         sbiw XL, 5 * 8
569         rcall chi_step
570         adiw XL, 5 * 8
571         adiw ZL, 5 * 8
572         dec r18
573         brne 10b
574
575         /* -- iota -- */
576         ldi r30, lo8(keccak_rc_comp)
577         ldi r31, hi8(keccak_rc_comp)
578         add r30, r9
579         adc r31, __zero_reg__
580         lpm r20, Z+
581         movw YL, r2
582         ldi r21, 0x80
583         bst r20, 6
584         brtc 10f
585         ldd r22, Y+7
586         eor r22, r21
587         std Y+7, r22
588 10:
589         bst r20, 5
590         brtc 10f
591         ldd r22, Y+3
592         eor r22, r21
593         std Y+3, r22
594 10:
595         bst r20, 4
596         brtc 10f
597         ldd r22, Y+1
598         eor r22, r21
599         std Y+1, r22
600 10:
601         andi r20, 0x8f
602         ld r22, Y
603         eor r22, r20
604         st Y, r22
605
606         inc r9
607         mov r16, r9
608         cpi r16, 24
609         breq 20f
610         movw r24, YL
611         movw r26, r4
612         rjmp 5b
613 20:
614
615         stack_free_large3 200
616
617         pop_range 28, 29
618         pop r16
619         pop_range 2, 9
620         ret
621         .endfunc
622
623
624         .global keccak224_ctx2hash
625         .func keccak224_ctx2hash
626 keccak224_ctx2hash:
627         movw r20, r22
628         ldi r22, lo8(224)
629         ldi r23, hi8(224)
630         rjmp keccak_ctx2hash
631         .endfunc
632
633         .global keccak384_ctx2hash
634         .func keccak384_ctx2hash
635 keccak384_ctx2hash:
636         movw r20, r22
637         ldi r22, lo8(384)
638         ldi r23, hi8(384)
639         rjmp keccak_ctx2hash
640         .endfunc
641
642         .global keccak512_ctx2hash
643         .func keccak512_ctx2hash
644 keccak512_ctx2hash:
645         movw r20, r22
646         ldi r22, lo8(512)
647         ldi r23, hi8(512)
648         rjmp keccak_ctx2hash
649         .endfunc
650
651         .global keccak256_ctx2hash
652         .func keccak256_ctx2hash
653 keccak256_ctx2hash:
654         movw r20, r22
655         ldi r22, lo8(256)
656         ldi r23, hi8(256)
657         .endfunc
658
659 /*
660 void keccak_ctx2hash(void *dest, uint16_t length_b, keccak_ctx_t *ctx){
661         while(length_b>=ctx->r){
662                 memcpy(dest, ctx->a, ctx->bs);
663                 dest = (uint8_t*)dest + ctx->bs;
664                 length_b -= ctx->r;
665                 keccak_f1600(ctx->a);
666         }
667         memcpy(dest, ctx->a, (length_b+7)/8);
668 }
669 */
670         .global keccak_ctx2hash
671         .func keccak_ctx2hash
672 keccak_ctx2hash:
673         push_range 2, 10
674         movw r4, r20
675         movw r6, r24
676         movw ZL, r20
677         movw r8, r22
678         subi ZL, lo8(-ctx_r)
679         sbci ZH, hi8(-ctx_r)
680         ld r2, Z+
681         ld r3, Z+
682         ldd r10, Z+3 ; load blocksize (in bytes)
683 10:
684         ; length_b = (r9:r8) ; r = (r3:r2) ; (H:L)
685         cp  r2, r8
686         cpc r3, r9
687         brsh 40f
688         movw XL, r4
689         movw ZL, r6
690         mov r24, r10
691 20:
692         ld r22, X+
693         st Z+, r22
694         dec r24
695         brne 20b
696         movw r6, ZL
697         sub r8, r2
698         sbc r9, r3
699         movw r24, r4
700         rcall keccak_f1600
701         rjmp 10b
702 40:
703         movw XL, r4
704         movw ZL, r6
705         movw r24, r8
706         adiw r24, 7
707         lsr r25
708         ror r24
709         lsr r25
710         ror r24
711         lsr r25
712         ror r24
713         adiw r24, 0
714         breq 99f
715 10:
716         ld r22, X+
717         st Z+, r22
718         sbiw r24, 1
719         brne 10b
720 99:
721         pop_range 2, 10
722         ret
723         .endfunc
724
725
726         .global keccak224_init
727         .func keccak224_init
728 keccak224_init:
729         movw XL, r24
730         ldi r24, lo8(1152)
731         ldi r25, hi8(1152)
732         rjmp keccak_init_1
733         .endfunc
734
735         .global keccak384_init
736         .func keccak384_init
737 keccak384_init:
738         movw XL, r24
739         ldi r24, lo8( 832)
740         ldi r25, hi8( 832)
741         rjmp keccak_init_1
742         .endfunc
743
744         .global keccak512_init
745         .func keccak512_init
746 keccak512_init:
747         movw XL, r24
748         ldi r24, lo8( 576)
749         ldi r25, hi8( 576)
750         rjmp keccak_init_1
751         .endfunc
752
753         .global keccak256_init
754         .func keccak256_init
755 keccak256_init:
756         movw r22, r24
757         ldi r24, lo8(1088)
758         ldi r25, hi8(1088)
759         .endfunc
760 /*
761 void keccak_init(uint16_t r, keccak_ctx_t *ctx){
762         memset(ctx->a, 0x00, 5 * 5 * 8);
763         ctx->r = r;
764         ctx->bs = (uint8_t)(r / 8);
765 }
766 */
767         .global keccak_init
768         .func keccak_init
769 keccak_init:
770         movw XL, r22
771 keccak_init_1:
772         ldi r22, 200
773 10:
774         st X+, __zero_reg__
775         dec r22
776         brne 10b
777         st X+, r24
778         st X+, r25
779         lsr r25
780         ror r24
781         lsr r25
782         ror r24
783         lsr r25
784         ror r24
785         st X+, r24
786         ret
787         .endfunc
788
789 /*
790 void keccak_lastBlock(keccak_ctx_t *ctx, const void *block, uint16_t length_b){
791     uint8_t length_B;
792     uint8_t t;
793     while(length_b >= ctx->r){
794         keccak_nextBlock(ctx, block);
795         block = (uint8_t*)block + ctx->bs;
796         length_b -=  ctx->r;
797     }
798     length_B = length_b / 8;
799     memxor(ctx->a, block, length_B);
800     / * append 1 * /
801     if(length_b & 7){
802         / * we have some single bits * /
803         t = ((uint8_t*)block)[length_B] >> (8 - (length_b & 7));
804         t |= 0x01 << (length_b & 7);
805     }else{
806         t = 0x01;
807     }
808     ctx->a[length_B] ^= t;
809     if(length_b == ctx->r - 1){
810         keccak_f1600(ctx->a);
811     }
812
813 */
814 .set length_b_l,  2
815 .set length_b_h,  3
816 .set pbs,     10
817 .set pr_l,     8
818 .set pr_h,      9
819 .set ctx_l,       6
820 .set ctx_h,       7
821
822         .global keccak_lastBlock
823         .func keccak_lastBlock
824 keccak_lastBlock:
825         push_range 2, 10
826         movw r2, r20
827         movw r4, r22
828         movw r6, r24
829         movw XL, r24
830         subi XL, lo8(-ctx_r)
831         sbci XH, hi8(-ctx_r)
832         ld  pr_l, X+
833         ld  pr_h, X+
834         ld  pbs, X
835 10:
836         cp  length_b_l, pr_l
837         cpc length_b_h, pr_h
838         brlo 20f
839         movw r24, ctx_l
840         movw r22, r4
841         rcall keccak_nextBlock
842         add r4, pbs
843         adc r5, __zero_reg__
844         sub length_b_l, pr_l
845         sbc length_b_h, pr_h
846         rjmp 10b
847 20:
848         movw ZL, ctx_l
849         movw XL, r4
850         movw r22, length_b_l
851         lsr r23
852         ror r22
853         lsr r23
854         ror r22
855         lsr r23
856         ror r22
857         mov r23, r22
858         breq 20f
859 10:
860         ld r25, X+
861         ld r24, Z
862         eor r24, r25
863         st Z+, r24
864         dec r23
865         brne 10b
866 20:
867         ldi r25, 1
868         mov r18, length_b_l
869         andi r18, 7
870         breq 30f
871         /* we have trailing bits */
872         mov r19, r18
873         ld r24, X+
874         subi r18, 8
875         neg r18
876 10:
877         lsr r24
878         dec r18
879         brne 10b
880 10:
881         lsl r25
882         dec r19
883         brne 10b
884         or r25, r24
885 30:
886         ld r24, Z
887         eor r24, r25
888         st Z, r24
889
890         movw r24, pr_l
891         sbiw r24, 1
892         cp  length_b_l, r24
893         cpc length_b_h, r25
894         brne 20f
895         movw r24, ctx_l
896         rcall keccak_f1600
897 20:
898         movw XL, ctx_l
899         dec pbs
900         add XL, pbs
901         adc XH, __zero_reg__
902         ld r24, X
903         ldi r25, 0x80
904         eor r24, r25
905         st X, r24
906         movw r24, ctx_l
907         pop_range 2, 10
908         rjmp keccak_f1600
909         .endfunc
910