]> git.cryptolib.org Git - avr-crypto-lib.git/blobdiff - seed/seed-asm.S
modified structure
[avr-crypto-lib.git] / seed / seed-asm.S
diff --git a/seed/seed-asm.S b/seed/seed-asm.S
new file mode 100644 (file)
index 0000000..84866c3
--- /dev/null
@@ -0,0 +1,957 @@
+/* seed-asm.S */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2008  Daniel Otte (daniel.otte@rub.de)
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * \file       seed-asm.S
+ * \author     Daniel Otte 
+ * \date       2007-06-1
+ * \brief      SEED parts in assembler for AVR
+ * \par License        
+ * GPLv3 or later
+ * 
+ */
+#include "avr-asm-macros.S"
+
+/******************************************************************************/       
+/*
+#define M0 0xfc
+#define M1 0xf3
+#define M2 0xcf
+#define M3 0x3f
+
+#define X3 (((uint8_t*)(&x))[0])
+#define X2 (((uint8_t*)(&x))[1])
+#define X1 (((uint8_t*)(&x))[2])
+#define X0 (((uint8_t*)(&x))[3])
+
+#define Z3 (((uint8_t*)(&z))[0])
+#define Z2 (((uint8_t*)(&z))[1])
+#define Z1 (((uint8_t*)(&z))[2])
+#define Z0 (((uint8_t*)(&z))[3])
+
+uint32_t g_function(uint32_t x){
+       uint32_t z;
+       / * sbox substitution * /
+       X3 = pgm_read_byte(&(seed_sbox2[X3]));
+       X2 = pgm_read_byte(&(seed_sbox1[X2]));
+       X1 = pgm_read_byte(&(seed_sbox2[X1]));
+       X0 = pgm_read_byte(&(seed_sbox1[X0]));
+       / * now the permutation * /
+       Z0 = (X0 & M0) ^ (X1 & M1) ^ (X2 & M2) ^ (X3 & M3);
+       Z1 = (X0 & M1) ^ (X1 & M2) ^ (X2 & M3) ^ (X3 & M0);
+       Z2 = (X0 & M2) ^ (X1 & M3) ^ (X2 & M0) ^ (X3 & M1);
+       Z3 = (X0 & M3) ^ (X1 & M0) ^ (X2 & M1) ^ (X3 & M2);
+       return z;
+}
+*/
+M0 = 0xfc
+M1 = 0xf3
+M2 = 0xcf
+M3 = 0x3f
+X0 = 18
+X1 = 19
+X2 = 20
+X3 = 21
+Z0 = 25
+Z1 = 24
+Z2 = 23
+Z3 = 22
+T0 = X0
+T1 = 26
+T2 = 27
+T3 = X1
+/*
+ *  param x: r22:r25
+ *  X0 = R25
+ *  X1 = R24
+ *  X2 = R23
+ *  X3 = R22
+ */    
+seed_g_function:
+       ldi r30, lo8(seed_sbox1)
+       ldi r31, hi8(seed_sbox1)
+       movw r26, r30
+       add r30, Z2
+       adc r31, r1
+       lpm X2, Z
+       movw r30, r26
+       add r30, Z0
+       adc r31, r1
+       lpm X0, Z
+       inc r27 /* switch X to point to sbox2 */
+       movw r30, r26
+       add r30, Z3
+       adc r31, r1
+       lpm X3, Z
+       movw r30, r26
+       add r30, Z1
+       adc r31, r1
+       lpm X1, Z
+       /* now the secound part */
+       mov Z0, X0
+       mov Z1, X0
+       mov Z2, X0
+       mov Z3, X0
+       andi Z0, M0
+       andi Z1, M1
+       andi Z2, M2
+       andi Z3, M3     
+       mov T0, X1
+       mov T1, X1
+       mov T2, X1
+       ; mov T3, X1 /* T3 = X1 */
+       andi T0, M1
+       andi T1, M2
+       andi T2, M3
+       andi T3, M0
+       eor Z0, T0
+       eor Z1, T1
+       eor Z2, T2
+       eor Z3, T3
+       mov T0, X2
+       mov T1, X2
+       mov T2, X2
+       mov T3, X2
+       andi T0, M2
+       andi T1, M3
+       andi T2, M0
+       andi T3, M1
+       eor Z0, T0
+       eor Z1, T1
+       eor Z2, T2
+       eor Z3, T3
+       mov T0, X3
+       mov T1, X3
+       mov T2, X3
+       mov T3, X3
+       andi T0, M3
+       andi T1, M0
+       andi T2, M1
+       andi T3, M2
+       eor Z0, T0
+       eor Z1, T1
+       eor Z2, T2
+       eor Z3, T3
+       ret
+
+seed_sbox1:
+.byte   169,  133,  214,  211,   84,   29,  172,   37 
+.byte    93,   67,   24,   30,   81,  252,  202,   99 
+.byte    40,   68,   32,  157,  224,  226,  200,   23 
+.byte   165,  143,    3,  123,  187,   19,  210,  238 
+.byte   112,  140,   63,  168,   50,  221,  246,  116 
+.byte   236,  149,   11,   87,   92,   91,  189,    1 
+.byte    36,   28,  115,  152,   16,  204,  242,  217 
+.byte    44,   231, 114,  131,  155,  209,  134,  201 
+.byte    96,   80,  163,  235,   13,  182,  158,   79 
+.byte   183,   90,  198,  120,  166,   18,  175,  213 
+.byte    97,  195,  180,   65,   82,  125,  141,    8 
+.byte    31,  153,    0,   25,    4,   83,  247,  225 
+.byte   253,  118,   47,   39,  176,  139,   14,  171 
+.byte   162,  110,  147,   77,  105,  124,    9,   10 
+.byte   191,  239,  243,  197,  135,   20,  254,  100 
+.byte   222,   46,   75,   26,    6,   33,  107,  102 
+.byte     2,  245,  146,  138,   12,  179,  126,  208 
+.byte   122,   71,  150,  229,   38,  128,  173,  223 
+.byte   161,   48,   55,  174,   54,   21,   34,   56 
+.byte   244,  167,   69,   76,  129,  233,  132,  151 
+.byte    53,  203,  206,   60,  113,   17,  199,  137 
+.byte   117,  251,  218,  248,  148,   89,  130,  196 
+.byte   255,   73,   57,  103,  192,  207,  215,  184 
+.byte    15,  142,   66,   35,  145,  108,  219,  164 
+.byte    52,  241,   72,  194,  111,   61,   45,   64 
+.byte   190,   62,  188,  193,  170,  186,   78,   85 
+.byte    59,  220,  104,  127,  156,  216,   74,   86 
+.byte   119,  160,  237,   70,  181,   43,  101,  250 
+.byte   227,  185,  177,  159,   94,  249,  230,  178 
+.byte    49,  234,  109,   95,  228,  240,  205,  136 
+.byte    22,   58,   88,  212,   98,   41,    7,   51 
+.byte   232,   27,    5,  121,  144,  106,   42,  154
+
+
+seed_sbox2:
+.byte    56,  232,   45,  166,  207,  222,  179,  184 
+.byte   175,   96,   85,  199,   68,  111,  107,   91 
+.byte   195,   98,   51,  181,   41,  160,  226,  167 
+.byte   211,  145,   17,    6,   28,  188,   54,   75 
+.byte   239,  136,  108,  168,   23,  196,   22,  244 
+.byte   194,   69,  225,  214,   63,   61,  142,  152 
+.byte    40,   78,  246,   62,  165,  249,   13,  223 
+.byte   216,   43,  102,  122,   39,   47,  241,  114 
+.byte    66,  212,   65,  192,  115,  103,  172,  139 
+.byte   247,  173,  128,   31,  202,   44,  170,   52 
+.byte   210,   11,  238,  233,   93,  148,   24,  248 
+.byte    87,  174,    8,  197,   19,  205,  134,  185 
+.byte   255,  125,  193,   49,  245,  138,  106,  177 
+.byte   209,   32,  215,    2,   34,    4,  104,  113 
+.byte     7,  219,  157,  153,   97,  190,  230,   89 
+.byte   221,   81,  144,  220,  154,  163,  171,  208 
+.byte   129,   15,   71,   26,  227,  236,  141,  191 
+.byte   150,  123,   92,  162,  161,   99,   35,   77 
+.byte   200,  158,  156,   58,   12,   46,  186,  110 
+.byte   159,   90,  242,  146,  243,   73,  120,  204 
+.byte    21,  251,  112,  117,  127,   53,   16,    3 
+.byte   100,  109,  198,  116,  213,  180,  234,    9 
+.byte   118,   25,  254,   64,   18,  224,  189,    5 
+.byte   250,    1,  240,   42,   94,  169,   86,   67 
+.byte   133,   20,  137,  155,  176,  229,   72,  121 
+.byte   151,  252,   30,  130,   33,  140,   27,   95 
+.byte   119,   84,  178,   29,   37,   79,    0,   70 
+.byte   237,   88,   82,  235,  126,  218,  201,  253 
+.byte    48,  149,  101,   60,  182,  228,  187,  124 
+.byte    14,   80,   57,   38,   50,  132,  105,  147 
+.byte    55,  231,   36,  164,  203,   83,   10,  135 
+.byte   217,   76,  131,  143,  206,   59,   74,  183 
+
+/******************************************************************************/
+
+/*
+static
+uint64_t f_function(const uint64_t* a, uint32_t k0, uint32_t k1){
+       uint32_t c,d;
+
+       c = *a & 0x00000000FFFFFFFFLL;
+       d = (*a>>32) & 0x00000000FFFFFFFFLL;
+       
+       c ^= k0; d ^= k1;
+       d ^= c;
+       d = g_function(d);
+       c = bigendian_sum32(c,d);
+       c = g_function(c);
+       d = bigendian_sum32(c,d);
+       d = g_function(d);
+       c = bigendian_sum32(c,d);       
+       return ((uint64_t)d << 32) | c;
+}
+*/
+/*
+ * param a   r24:r25
+ * param k0  r20:r23
+ * param k1  r16:r19
+ */
+D0 = 10
+D1 = 11
+C0 = 12
+C1 = 13
+C2 = 14
+C3 = 15
+D2 = 16
+D3 = 17
+seed_f_function:
+       push_range 10, 17
+       movw r30, r24
+       ld C0, Z+
+       ld C1, Z+
+       ld C2, Z+
+       ld C3, Z+
+       eor C0, r20
+       eor C1, r21
+       eor C2, r22
+       eor C3, r23
+       ld r22, Z+
+       ld r23, Z+
+       ld r24, Z+
+       ld r25, Z+
+       eor r22, r16
+       eor r23, r17
+       eor r24, r18
+       eor r25, r19
+       eor r22, C0
+       eor r23, C1
+       eor r24, C2
+       eor r25, C3
+       rcall seed_g_function
+       mov D0, r22
+       mov D1, r23
+       mov D2, r24
+       mov D3, r25
+
+       add r25, C3
+       adc r24, C2
+       adc r23, C1
+       adc r22, C0
+       rcall seed_g_function
+       mov C0, r22
+       mov C1, r23
+       mov C2, r24
+       mov C3, r25
+
+       add r25, D3
+       adc r24, D2
+       adc r23, D1
+       adc r22, D0
+       rcall seed_g_function
+       mov D0, r22
+       mov D1, r23
+       mov D2, r24
+       mov D3, r25
+
+       add C3, r25
+       adc C2, r24
+       adc C1, r23
+       adc C0, r22
+
+       mov r18, C0
+       mov r19, C1
+       mov r20, C2
+       mov r21, C3
+       
+       pop_range 10, 17
+       ret
+
+/******************************************************************************/
+/*
+void seed_init(uint8_t * key, seed_ctx_t * ctx){
+       memcpy(ctx->k, key, 128/8);
+}
+*/
+
+.global seed_init
+seed_init:
+       movw r26, r24
+       movw r30, r22
+       ldi r22, 16
+1:
+       ld r0, X+
+       st Z+, r0
+       dec r22
+       brne 1b 
+       ret
+/******************************************************************************/
+/*
+typedef struct {
+       uint32_t k0, k1;
+} keypair_t;
+
+keypair_t getnextkeys(uint32_t *keystate, uint8_t curround){
+       keypair_t ret;
+       if (curround>15){
+               / * ERROR * /
+               ret.k0 = ret.k1 = 0;
+       } else {
+       / *     ret.k0 = seed_g_function(keystate[0] + keystate[2] - pgm_read_dword(&(seed_kc[curround])));
+               ret.k1 = seed_g_function(keystate[1] - keystate[3] + pgm_read_dword(&(seed_kc[curround]))); * /
+               ret.k0 = bigendian_sum32(keystate[0], keystate[2]);
+               ret.k0 = bigendian_sub32(ret.k0, pgm_read_dword(&(seed_kc[curround])));
+               ret.k0 = seed_g_function(ret.k0);
+               ret.k1 = bigendian_sub32(keystate[1], keystate[3]);
+               ret.k1 = bigendian_sum32(ret.k1, pgm_read_dword(&(seed_kc[curround])));
+               ret.k1 = seed_g_function(ret.k1);
+               
+               if (curround & 1){
+                       / * odd round (1,3,5, ...) * /
+                       ((uint64_t*)keystate)[1] = bigendian_rotl8_64( ((uint64_t*)keystate)[1] );
+               } else {
+                       / * even round (0,2,4, ...) * /
+                       ((uint64_t*)keystate)[0] = bigendian_rotr8_64(((uint64_t*)keystate)[0]);
+               }
+       }
+       return ret;
+}
+*/
+/*
+ * param keystate: r24:r25
+ * param curround: r22
+ */
+XRC0 = 10
+XRC1 = 11
+XRC2 = 12
+XRC3 = 13
+D0 = 14
+D1 = 15
+D2 = 16
+D3 = 17
+
+compute_keys:
+       ldi r30, lo8(seed_kc)
+       ldi r31, hi8(seed_kc)
+       lsl r22
+       lsl r22
+       add r30, r22
+       adc r31, r1
+       lpm XRC0, Z+
+       lpm XRC1, Z+
+       lpm XRC2, Z+
+       lpm XRC3, Z+
+       movw r28, r24
+       ldd r25, Y+0*4+3
+       ldd r24, Y+0*4+2
+       ldd r23, Y+0*4+1
+       ldd r22, Y+0*4+0
+       
+       ldd r0, Y+2*4+3
+       add r25, r0
+       ldd r0, Y+2*4+2
+       adc r24, r0
+       ldd r0, Y+2*4+1
+       adc r23, r0
+       ldd r0, Y+2*4+0
+       adc r22, r0
+
+       sub r25, XRC3
+       sbc r24, XRC2
+       sbc r23, XRC1
+       sbc r22, XRC0
+       rcall seed_g_function
+       mov D0, r22
+       mov D1, r23
+       mov D2, r24
+       mov D3, r25
+       
+
+       ldd r25, Y+1*4+3
+       ldd r24, Y+1*4+2
+       ldd r23, Y+1*4+1
+       ldd r22, Y+1*4+0
+
+       ldd r0, Y+3*4+3
+       sub r25, r0
+       ldd r0, Y+3*4+2
+       sbc r24, r0
+       ldd r0, Y+3*4+1
+       sbc r23, r0
+       ldd r0, Y+3*4+0
+       sbc r22, r0
+
+       add r25, XRC3
+       adc r24, XRC2
+       adc r23, XRC1
+       adc r22, XRC0
+       rcall seed_g_function
+
+       mov r21, D3
+       mov r20, D2
+       mov r19, D1
+       mov r18, D0 
+       ret
+
+seed_getnextkeys:
+       push_range 10, 17
+       push r28
+       push r29
+;      andi r22, 0x0F
+       bst r22,0
+       rcall compute_keys              
+       brtc even_round
+odd_round:
+
+       adiw r28, 8
+       ld r26, Y
+       ldd r0, Y+1
+       std Y+0, r0
+       ldd r0, Y+2
+       std Y+1, r0
+       ldd r0, Y+3
+       std Y+2, r0
+       ldd r0, Y+4
+       std Y+3, r0
+       ldd r0, Y+5
+       std Y+4, r0
+       ldd r0, Y+6
+       std Y+5, r0
+       ldd r0, Y+7
+       std Y+6, r0
+       std Y+7, r26    
+/*
+       movw r30, r28
+       ld r26, Z+
+       ldi r27, 7
+1:
+       ld r0, Z+
+       st Y+, r0
+       dec r27
+       brne 1b
+       st Y, r26
+*/     
+       rjmp 4f
+
+even_round:
+
+       ldd r26, Y+7
+       ldd r0, Y+6
+       std Y+7, r0
+       ldd r0, Y+5
+       std Y+6, r0
+       ldd r0, Y+4
+       std Y+5, r0
+       ldd r0, Y+3
+       std Y+4, r0
+       ldd r0, Y+2
+       std Y+3, r0
+       ldd r0, Y+1
+       std Y+2, r0
+       ldd r0, Y+0
+       std Y+1, r0
+       std Y+0, r26
+/*
+       adiw r28, 7     
+       ld r26, Y
+       ldi r27, 7      
+1:
+       ld r0, -Y
+       std Y+1, r0
+       dec r27
+       brne 1b
+       st Y, r26
+*/
+4:     
+       pop r29
+       pop r28
+       pop_range 10, 17
+       ret
+
+/******************************************************************************/
+/*
+keypair_t getprevkeys(uint32_t *keystate, uint8_t curround){
+       keypair_t ret;
+       if (curround>15){
+               / * ERROR * /
+               ret.k0 = ret.k1 = 0;
+       } else {
+               if (curround & 1){
+                       / * odd round (1,3,5, ..., 15) * /
+                       ((uint64_t*)keystate)[1] = bigendian_rotr8_64( ((uint64_t*)keystate)[1] );
+               } else {
+                       / * even round (0,2,4, ..., 14) * /
+                       ((uint64_t*)keystate)[0] = bigendian_rotl8_64(((uint64_t*)keystate)[0]);
+               }
+       / *     ret.k0 = seed_g_function(keystate[0] + keystate[2] - pgm_read_dword(&(seed_kc[curround])));
+               ret.k1 = seed_g_function(keystate[1] - keystate[3] + pgm_read_dword(&(seed_kc[curround]))); * /
+               ret.k0 = bigendian_sum32(keystate[0], keystate[2]);
+               ret.k0 = bigendian_sub32(ret.k0, pgm_read_dword(&(seed_kc[curround])));
+               ret.k0 = seed_g_function(ret.k0);
+               ret.k1 = bigendian_sub32(keystate[1], keystate[3]);
+               ret.k1 = bigendian_sum32(ret.k1, pgm_read_dword(&(seed_kc[curround])));
+               ret.k1 = seed_g_function(ret.k1);
+               }
+       return ret;
+}
+*/
+/*
+ * param keystate: r24:r25
+ * param curround: r22
+ */
+
+seed_getprevkeys:
+       push_range 10, 17
+       push r28
+       push r29
+       movw r28, r24   
+;      andi r22, 0x0F
+       bst r22, 0
+       brts r_odd_round
+r_even_round:
+       ldd r26, Y+0
+       ldd r0, Y+1
+       std Y+0, r0
+       ldd r0, Y+2
+       std Y+1, r0
+       ldd r0, Y+3
+       std Y+2, r0
+       ldd r0, Y+4
+       std Y+3, r0
+       ldd r0, Y+5
+       std Y+4, r0
+       ldd r0, Y+6
+       std Y+5, r0
+       ldd r0, Y+7
+       std Y+6, r0
+       std Y+7, r26    
+/*
+       movw r30, r28
+       ld r26, Z+
+       ldi r27, 7
+1:
+       ld r0, Z+
+       st Y+, r0
+       dec r27
+       brne 1b
+       st Y, r26
+*/     
+
+       rjmp 4f
+r_odd_round:
+       ldd r26, Y+8+7
+       ldd r0, Y+8+6
+       std Y+8+7, r0
+       ldd r0, Y+8+5
+       std Y+8+6, r0
+       ldd r0, Y+8+4
+       std Y+8+5, r0
+       ldd r0, Y+8+3
+       std Y+8+4, r0
+       ldd r0, Y+8+2
+       std Y+8+3, r0
+       ldd r0, Y+8+1
+       std Y+8+2, r0
+       ldd r0, Y+8+0
+       std Y+8+1, r0
+       std Y+8+0, r26
+/*
+       adiw r28, 7     
+       ld r26, Y
+       ldi r27, 7      
+1:
+       ld r0, -Y
+       std Y+1, r0
+       dec r27
+       brne 1b
+       st Y, r26
+*/
+4:
+       rcall compute_keys      
+
+       pop r29
+       pop r28
+       pop_range 10, 17
+       ret
+
+/******************************************************************************/
+
+seed_kc:
+.long   0xb979379e 
+.long   0x73f36e3c
+.long   0xe6e6dd78 
+.long   0xcccdbbf1 
+.long   0x999b77e3 
+.long   0x3337efc6 
+.long   0x676ede8d 
+.long   0xcfdcbc1b 
+.long   0x9eb97937
+.long   0x3c73f36e     
+.long   0x78e6e6dd
+.long   0xf1cccdbb
+.long   0xe3999b77
+.long   0xc63337ef
+.long   0x8d676ede
+.long   0x1bcfdcbc
+
+/******************************************************************************/
+/*
+#define L (((uint64_t*)buffer)[0])
+#define R (((uint64_t*)buffer)[1])
+
+void seed_enc(void * buffer, seed_ctx_t * ctx){
+       uint8_t r;
+       keypair_t k;
+       for(r=0; r<8; ++r){
+                       k = seed_getnextkeys(ctx->k, 2*r);
+/ *
+       DEBUG_S("\r\n\tDBG ka,0: "); uart_hexdump(&k.k0, 4);
+       DEBUG_S("\r\n\tDBG ka,1: "); uart_hexdump(&k.k1, 4);
+       DEBUG_S("\r\n\t DBG L:   "); uart_hexdump((uint8_t*)buffer+0, 8);
+       DEBUG_S("\r\n\t DBG R:   "); uart_hexdump((uint8_t*)buffer+8, 8);
+* /
+                       L ^= seed_f_function(&R,k.k0,k.k1);
+                       
+                       k = seed_getnextkeys(ctx->k, 2*r+1);
+/ *
+       DEBUG_S("\r\n\tDBG kb,0: "); uart_hexdump(&k.k0, 4);
+       DEBUG_S("\r\n\tDBG kb,1: "); uart_hexdump(&k.k1, 4);
+       DEBUG_S("\r\n\t DBG L:   "); uart_hexdump((uint8_t*)buffer+8, 8);
+       DEBUG_S("\r\n\t DBG R:   "); uart_hexdump((uint8_t*)buffer+0, 8);
+* /
+                       R ^= seed_f_function(&L,k.k0,k.k1);
+       }
+       / * just an exchange without temp. variable * /
+       L ^= R;
+       R ^= L;
+       L ^= R;
+}
+*/
+/*
+ * param buffer: r24:r25
+ * param ctx:    r22:r23
+ */
+CTR  = 9
+xLPTR = 10
+xRPTR = 12
+CPTR = 14
+
+.global seed_enc
+seed_enc:
+       push_range 9, 17
+       push r28
+       push r29        
+       clr CTR
+       movw xLPTR, r24
+       adiw r24, 8
+       movw xRPTR, r24         
+       movw CPTR, r22
+1:
+       movw r28, xLPTR
+       movw r24, CPTR
+       mov r22, CTR
+       lsl r22
+       rcall seed_getnextkeys  
+
+       /* use pen & paper to understand the following permutation */
+       movw r16, r22
+       movw r22, r18
+       movw r18, r24
+       movw r24, r20
+       movw r20, r22
+       movw r22, r24
+       movw r24, xRPTR 
+
+       rcall seed_f_function
+
+       ld r0, Y
+       eor r0, r18
+       st Y+, r0
+       ld r0, Y
+       eor r0, r19
+       st Y+, r0
+       ld r0, Y
+       eor r0, r20
+       st Y+, r0
+       ld r0, Y
+       eor r0, r21
+       st Y+, r0
+       ld r0, Y
+       eor r0, r22
+       st Y+, r0
+       ld r0, Y
+       eor r0, r23
+       st Y+, r0
+       ld r0, Y
+       eor r0, r24
+       st Y+, r0
+       ld r0, Y
+       eor r0, r25
+       st Y+, r0
+       /* secound half */
+       movw r24, CPTR
+       mov r22, CTR
+       lsl r22
+       inc r22
+       rcall seed_getnextkeys  
+
+       movw r16, r22
+       movw r22, r18
+       movw r18, r24
+       movw r24, r20
+       movw r20, r22
+       movw r22, r24
+       movw r24, xLPTR 
+       
+       rcall seed_f_function
+
+       ld r0, Y
+       eor r0, r18
+       st Y+, r0
+       ld r0, Y
+       eor r0, r19
+       st Y+, r0
+       ld r0, Y
+       eor r0, r20
+       st Y+, r0
+       ld r0, Y
+       eor r0, r21
+       st Y+, r0
+       ld r0, Y
+       eor r0, r22
+       st Y+, r0
+       ld r0, Y
+       eor r0, r23
+       st Y+, r0
+       ld r0, Y
+       eor r0, r24
+       st Y+, r0
+       ld r0, Y
+       eor r0, r25
+       st Y+, r0
+       
+       inc CTR
+       bst CTR, 3
+       brts 3f
+       rjmp 1b
+3:
+       movw r28, xLPTR
+       movw r30, xRPTR
+       ldi r17, 8
+4:
+       ld r10, Y
+       ld r11, Z
+       st Z+, r10
+       st Y+, r11
+       dec r17
+       brne 4b
+5:
+       pop r29
+       pop r28
+       pop_range 9, 17
+       ret
+
+/******************************************************************************/
+/*
+#define L (((uint64_t*)buffer)[0])
+#define R (((uint64_t*)buffer)[1])
+
+void seed_dec(void * buffer, seed_ctx_t * ctx){
+       int8_t r;
+       keypair_t k;
+       for(r=7; r>=0; --r){
+                       k = seed_getprevkeys(ctx->k, 2*r+1);
+/ *
+       DEBUG_S("\r\n\tDBG ka,0: "); uart_hexdump(&k.k0, 4);
+       DEBUG_S("\r\n\tDBG ka,1: "); uart_hexdump(&k.k1, 4);
+       DEBUG_S("\r\n\t DBG L: "); uart_hexdump((uint8_t*)buffer+0, 8);
+       DEBUG_S("\r\n\t DBG R: "); uart_hexdump((uint8_t*)buffer+8, 8);
+* /
+                       L ^= seed_f_function(&R,k.k0,k.k1);
+                       
+                       k = seed_getprevkeys(ctx->k, 2*r+0);
+/ *
+       DEBUG_S("\r\n\tDBG kb,0: "); uart_hexdump(&k.k0, 4);
+       DEBUG_S("\r\n\tDBG kb,1: "); uart_hexdump(&k.k1, 4);
+       DEBUG_S("\r\n\t DBG L: "); uart_hexdump((uint8_t*)buffer+8, 8);
+       DEBUG_S("\r\n\t DBG R: "); uart_hexdump((uint8_t*)buffer+0, 8);
+* /
+                       R ^= seed_f_function(&L,k.k0,k.k1);
+       }
+       / * just an exchange without temp. variable * /
+       L ^= R;
+       R ^= L;
+       L ^= R;
+}
+*/
+/*
+ * param buffer: r24:r25
+ * param ctx:    r22:r23
+ */
+CTR  = 9
+xLPTR = 10
+xRPTR = 12
+CPTR = 14
+
+.global seed_dec
+seed_dec:
+       push_range 9, 17
+       push r28
+       push r29        
+       ldi r16, 7
+       mov CTR, r16
+       movw xLPTR, r24
+       adiw r24, 8
+       movw xRPTR, r24         
+       movw CPTR, r22
+1:
+       movw r28, xLPTR
+       movw r24, CPTR
+       mov r22, CTR
+       lsl r22
+       inc r22
+       rcall seed_getprevkeys  
+
+       /* use pen & paper to understand the following permutation */
+       movw r16, r22
+       movw r22, r18
+       movw r18, r24
+       movw r24, r20
+       movw r20, r22
+       movw r22, r24
+       movw r24, xRPTR 
+
+       rcall seed_f_function
+
+       ld r0, Y
+       eor r0, r18
+       st Y+, r0
+       ld r0, Y
+       eor r0, r19
+       st Y+, r0
+       ld r0, Y
+       eor r0, r20
+       st Y+, r0
+       ld r0, Y
+       eor r0, r21
+       st Y+, r0
+       ld r0, Y
+       eor r0, r22
+       st Y+, r0
+       ld r0, Y
+       eor r0, r23
+       st Y+, r0
+       ld r0, Y
+       eor r0, r24
+       st Y+, r0
+       ld r0, Y
+       eor r0, r25
+       st Y+, r0
+       /* secound half */
+       movw r24, CPTR
+       mov r22, CTR
+       lsl r22
+       rcall seed_getprevkeys  
+
+       movw r16, r22
+       movw r22, r18
+       movw r18, r24
+       movw r24, r20
+       movw r20, r22
+       movw r22, r24
+       movw r24, xLPTR 
+       
+       rcall seed_f_function
+
+       ld r0, Y
+       eor r0, r18
+       st Y+, r0
+       ld r0, Y
+       eor r0, r19
+       st Y+, r0
+       ld r0, Y
+       eor r0, r20
+       st Y+, r0
+       ld r0, Y
+       eor r0, r21
+       st Y+, r0
+       ld r0, Y
+       eor r0, r22
+       st Y+, r0
+       ld r0, Y
+       eor r0, r23
+       st Y+, r0
+       ld r0, Y
+       eor r0, r24
+       st Y+, r0
+       ld r0, Y
+       eor r0, r25
+       st Y+, r0
+       
+       dec CTR
+       brmi 3f
+       rjmp 1b
+3:
+       movw r28, xLPTR
+       movw r30, xRPTR
+       ldi r17, 8
+4:
+       ld r10, Y
+       ld r11, Z
+       st Z+, r10
+       st Y+, r11
+       dec r17
+       brne 4b
+5:
+       pop r29
+       pop r28
+       pop_range 9, 17
+       ret
+