]> git.cryptolib.org Git - avr-crypto-lib.git/commitdiff
more mqq stuff
authorbg <bg@b1d182e4-1ff8-0310-901f-bddb46175740>
Mon, 29 Mar 2010 09:27:25 +0000 (09:27 +0000)
committerbg <bg@b1d182e4-1ff8-0310-901f-bddb46175740>
Mon, 29 Mar 2010 09:27:25 +0000 (09:27 +0000)
17 files changed:
hfal-performance.c
host/data2wiki.rb
mkfiles/mqq160-sign.mk [new file with mode: 0644]
mkfiles/mqq160-sign_c.mk [new file with mode: 0644]
mqq-sign/memxor.S [new file with mode: 0644]
mqq-sign/memxor.h [new file with mode: 0644]
mqq-sign/mqq160-sign-asm.S [new file with mode: 0644]
mqq-sign/mqq160-sign.c [new file with mode: 0644]
mqq-sign/mqq160-sign.h [new file with mode: 0644]
mqq-sign/mqq160-sign_P-asm.S [new file with mode: 0644]
mqq-sign/mqq160-sign_P-stub.c [new file with mode: 0644]
mqq-sign/mqq160-sign_P.c [new file with mode: 0644]
mqq-sign/mqq160-sign_P.h [new file with mode: 0644]
mqq-sign/mqq160-sign_testkey.c [new file with mode: 0644]
mqq-sign/mqq160-sign_testkey.h [new file with mode: 0644]
test_src/cli.h
test_src/main-mqq160-sign-test.c [new file with mode: 0644]

index 47fccf8ecc0abfedfe2b2db6ab6605bf2c42084e..6f51dc68bb2d21dcd93a78a776571cef9bd4afe0 100644 (file)
@@ -146,15 +146,6 @@ void hfal_stacksize(const hfdesc_t* hd){
        cli_putstr_P(PSTR("\r\n\r\n === "));
        cli_putstr_P(hf.name);
        cli_putstr_P(PSTR(" stack-usage === "
-                         "\r\n    type:             hashfunction"
-                         "\r\n    hashsize (bits):    "));
-       printvalue(hf.hashsize_b);
-
-       cli_putstr_P(PSTR("\r\n    ctxsize (bytes):    "));
-       printvalue(hf.ctxsize_B);
-
-       cli_putstr_P(PSTR("\r\n    blocksize (bits):   "));
-       printvalue(hf.blocksize_b);
 
        cli();
        stack_measure_init(&smctx, PATTERN_A);
index e1bc69953511c324a71c1e6415936d100141a1aa..72509174b34d2de953c12584eee13930278022f1 100644 (file)
@@ -73,10 +73,26 @@ def process_hashfunction(fin, name, fsize)
   lb = fin.readline()
   m = lb.match(/ctx2hash \(cycles\):[\s]*([\d]*)/)
   convtime = m[1].to_i()
+  begin
+    lb = fin.readline()
+  end until m = lb.match(/init \(bytes\):[\s]*([\d]*)/)
+  initstack = m[1].to_i()
+  lb = fin.readline()
+  m = lb.match(/nextBlock \(bytes\):[\s]*([\d]*)/)
+  nextblockstack = m[1].to_i()
+  lb = fin.readline()
+  m = lb.match(/lastBlock \(bytes\):[\s]*([\d]*)/)
+  lastblockstack = m[1].to_i()
+  lb = fin.readline()
+  m = lb.match(/ctx2hash \(bytes\):[\s]*([\d]*)/)
+  convstack = m[1].to_i()
+  s1 = (initstack>nextblockstack)?initstack:nextblockstack
+  s2 = (lastblockstack>convstack)?lastblockstack:convstack
+  stack = (s1>s2)?s1:s2  
   size = get_size_string(fsize)
-  printf("| %20s || %3s || %3s \n| %s \n| %4d || || %4d || %4d ||" +
+  printf("| %20s || %3s || %3s \n| %s \n| %4d || %4d || %4d || %4d ||" +
          " %6d || %6d || %7.2f || %6d || || || \n|-\n" , 
-        name, $lang, $lang, size, ctxsize, hashsize, blocksize, 
+        name, $lang, $lang, size, ctxsize, stack, hashsize, blocksize, 
            inittime, nextblocktime, nextblocktime.to_f/(blocksize/8),
                lastblocktime+convtime)
 end
diff --git a/mkfiles/mqq160-sign.mk b/mkfiles/mqq160-sign.mk
new file mode 100644 (file)
index 0000000..7970f11
--- /dev/null
@@ -0,0 +1,12 @@
+# Makefile for MQQ160-sign
+ALGO_NAME := MQQ160-SIGN
+
+# comment out the following line for removement of MQQ160-sign from the build process
+SIGNATURE += $(ALGO_NAME)
+
+$(ALGO_NAME)_DIR      := mqq-sign/
+$(ALGO_NAME)_OBJ      := mqq160-sign-asm.o mqq160-sign_P-asm.o mqq160-sign_testkey.o 
+$(ALGO_NAME)_TEST_BIN := main-mqq160-sign-test.o performance_test.o stack_measuring.o $(CLI_STD)
+$(ALGO_NAME)_NESSIE_TEST      := test 
+$(ALGO_NAME)_PERFORMANCE_TEST := performance
+
diff --git a/mkfiles/mqq160-sign_c.mk b/mkfiles/mqq160-sign_c.mk
new file mode 100644 (file)
index 0000000..7b97083
--- /dev/null
@@ -0,0 +1,12 @@
+# Makefile for MQQ160-sign
+ALGO_NAME := MQQ160-SIGN_C
+
+# comment out the following line for removement of MQQ160-sign from the build process
+SIGNATURE += $(ALGO_NAME)
+
+$(ALGO_NAME)_DIR      := mqq-sign/
+$(ALGO_NAME)_OBJ      := mqq160-sign.o mqq160-sign_P.o mqq160-sign_testkey.o memxor.o
+$(ALGO_NAME)_TEST_BIN := main-mqq160-sign-test.o performance_test.o stack_measuring.o $(CLI_STD)
+$(ALGO_NAME)_NESSIE_TEST      := test 
+$(ALGO_NAME)_PERFORMANCE_TEST := performance
+
diff --git a/mqq-sign/memxor.S b/mqq-sign/memxor.S
new file mode 100644 (file)
index 0000000..a32058b
--- /dev/null
@@ -0,0 +1,66 @@
+/* memxor.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:        memxor.S
+ * Author:      Daniel Otte
+ * Date:        2008-08-07
+ * License:     GPLv3 or later
+ * Description: memxor, XORing one block into another
+ *
+ */
+
+/*
+ * void memxor(void* dest, const void* src, uint16_t n);
+ */
+ /*
+  * param dest is passed in r24:r25
+  * param src  is passed in r22:r23
+  * param n    is passed in r20:r21
+  */
+.global memxor
+memxor:
+       movw r30, r24
+       movw r26, r22
+       movw r24, r20
+       adiw r24, 0
+       breq 2f
+1:
+       ld r20, X+
+       ld r21, Z
+       eor r20, r21
+       st Z+, r20
+       sbiw r24, 1
+       brne 1b
+2:
+       ret
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mqq-sign/memxor.h b/mqq-sign/memxor.h
new file mode 100644 (file)
index 0000000..a62a616
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef MEMXOR_H_
+#define MEMXOR_H_
+#include <stdint.h>
+
+void memxor(void* dest, const void* src, uint16_t n);
+
+#endif
diff --git a/mqq-sign/mqq160-sign-asm.S b/mqq-sign/mqq160-sign-asm.S
new file mode 100644 (file)
index 0000000..c2f494f
--- /dev/null
@@ -0,0 +1,540 @@
+/* mqq160-sign_P-asm.S */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 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     mqq160-sign_P-asm.S
+ * \email    daniel.otte@rub.de
+ * \author   Daniel Otte
+ * \date     2010-03-21
+ * \license  GPLv3 or later
+ *
+ */
+
+#include "avr-asm-macros.S"
+
+#if 0
+static void mqq_inv_affine_transformation(uint8_t* input_bytes, uint8_t* result, const mqq160_sign_key_t* key){
+       /* The matrix SInv is given as two permutations of 160 elements. */
+       uint8_t j, byteindex, bitindex, bitindex_d, byteindex_d, rp1, rp5;
+       uint8_t *r1_ptr, *r5_ptr;
+       uint8_t h1[20];
+
+       /* Initialize H1 and H2 = 0 */
+       memset(h1, 0, 20);
+       memset(result, 0, 20);
+
+       /*
+          Fill H1 with bits of InputBytes accordingly to RP1 permutation
+          and fill H2 with bits of InputBytes accordingly to RP5 permutation
+       */
+       bitindex_d = 0x80;
+       byteindex_d = 0;
+       j=160;
+       r1_ptr = key->rp1;
+       r5_ptr = key->rp5;
+       do{
+               rp1 = pgm_read_byte(r1_ptr++);
+               rp5 = pgm_read_byte(r5_ptr++);
+               byteindex = rp1>>3;
+               bitindex = 0x80 >> (rp1&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       h1[byteindex_d] ^= bitindex_d;
+               }
+
+               byteindex = rp5>>3;
+               bitindex = 0x80 >> (rp5&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       result[byteindex_d] ^= bitindex_d;
+               }
+               bitindex_d >>= 1;
+               if(bitindex_d==0){
+                       ++byteindex_d;
+                       bitindex_d = 0x80;
+               }
+       }while(--j);
+
+       for (j=0; j<20; j++){
+               result[j] ^= h1[j] ^ h1[pgm_read_byte(j+mod20_table)]
+                                  ^ h1[pgm_read_byte(8+j+mod20_table)]
+                                  ^ h1[pgm_read_byte(12+j+mod20_table)];
+       }
+}
+#endif
+
+fetch_bit:
+       ld r0, Z+
+       mov r28, r0
+       ldi r29, 0x80
+       andi r28, 7
+       breq 3f
+2:     lsr r29
+       dec r28
+       brne 2b
+3:     mov r28, r0
+       lsr r28
+       lsr r28
+       lsr r28
+       mov r0, r29
+       clr r29
+       add r28, r24
+       adc r29, r25
+       ld r28, Y
+       clt
+       and r28, r0
+       breq 4f
+       set
+4:  ret
+
+xres_0 = 18
+xres_1 = 19
+h_0 = 20
+h_1 = 21
+xrp5_0 = 22
+xrp5_1 = 23
+inp_0 =  24
+inp_1 =  25
+tmp_0 =  22
+tmp_1 =  23
+tmp_2 =  24
+tmp_3 =  25
+tmp_4 =  18
+
+/*
+ param input_bytes: r24:r25
+ param result:      r22:r23
+ param key:         r20:r21
+*/
+;.global mqq_inv_affine_transformation
+mqq_inv_affine_transformation:
+       push r17
+;      push r28
+;      push r29
+       stack_alloc 20
+       adiw r30, 1   /* Z points to stack space for h1 */
+       movw r28, r20 /* Y points to the key struct in RAM */
+       movw xres_0, r22
+       movw r26, r30 /* X points to h1[0] */
+       ldd xrp5_0, Y+8 /* load pointer rp5 to xrp5 */
+       ldd xrp5_1, Y+9
+       movw h_0, r30
+       ldd r30, Y+6 /* load pointer to rp1 in Z */
+       ldd r31, Y+7
+       ldi r17, 20
+20:    rcall fetch_bit
+       bld r1, 7
+       rcall fetch_bit
+       bld r1, 6
+       rcall fetch_bit
+       bld r1, 5
+       rcall fetch_bit
+       bld r1, 4
+       rcall fetch_bit
+       bld r1, 3
+       rcall fetch_bit
+       bld r1, 2
+       rcall fetch_bit
+       bld r1, 1
+       rcall fetch_bit
+       bld r1, 0
+       st X+, r1
+       dec r17
+       brne 20b
+;----
+       movw r26, xres_0 /* X points to result */
+       movw r30, xrp5_0
+       ldi r17, 20
+20:    rcall fetch_bit
+       bld r1, 7
+       rcall fetch_bit
+       bld r1, 6
+       rcall fetch_bit
+       bld r1, 5
+       rcall fetch_bit
+       bld r1, 4
+       rcall fetch_bit
+       bld r1, 3
+       rcall fetch_bit
+       bld r1, 2
+       rcall fetch_bit
+       bld r1, 1
+       rcall fetch_bit
+       bld r1, 0
+       st X+, r1
+       dec r17
+       brne 20b
+       clr r1
+; --- now we mix result with h1
+       sbiw r26, 20 /* adjusting X to point at result[0] */
+       movw tmp_2, h_0
+       ldi r30, lo8(affine_mix_lut)
+       ldi r31, hi8(affine_mix_lut)
+       ldi r17, 20
+30:
+       ld tmp_0, X
+       movw r28, tmp_2
+       ld tmp_1, Y+
+       movw tmp_2, r28
+       eor tmp_0, tmp_1
+       movw r28, h_0
+       lpm r0, Z+
+       mov tmp_4, r0
+       andi tmp_4, 0x0f
+       add r28, tmp_4
+       adc r29, r1
+       ld tmp_1, Y
+       eor tmp_0, tmp_1
+       adiw r28, 4
+       sbrc r0, 7
+       adiw r28, 4
+       ld tmp_1, Y
+       eor tmp_0, tmp_1
+       adiw r28, 4
+       sbrc r0, 6
+       adiw r28, 4
+       ld tmp_1, Y
+       eor tmp_0, tmp_1
+       st X+, tmp_0
+       dec r17
+       brne 30b
+
+       stack_free 20
+;      pop r29
+;      pop r28
+       pop r17
+       ret
+
+affine_mix_lut:
+       .byte 0x84, 0x85, 0x86, 0x87
+       .byte 0xC0, 0xC1, 0xC2, 0xC3
+       .byte 0x40, 0x41, 0x42, 0x43
+       .byte 0x44, 0x45, 0x46, 0x47
+       .byte 0x80, 0x81, 0x82, 0x83
+
+/******************************************************************************/
+
+xres  = 20
+tmp_0 = 23
+tmp_1 = 22
+tmp_2 = 21
+tmp_3 = 19
+/*
+  param i:    r24
+  param b1:   r22
+  param b2:   r20
+  param key:  r18:r19
+*/
+;.global mqq_q
+mqq_q:
+;      push r28
+;      push r29
+;      stack_alloc 25, r26, r27
+;      adiw r26, 1  /* X points to e[0] */
+       movw r28, r18
+       sbrs r24, 0
+       adiw r28, 2
+       ldd r30, Y+2
+       ldd r31, Y+3
+       ldi r28, 9
+10:    ld r0, Z+
+       st X+, r0
+       dec r28
+       brne 10b
+       sbiw r26, 9 /* adjust X to point at e[0] */
+;---
+       movw r28, r18
+       ld r30, Y+ /* Z points to a[0] in progmem */
+       ld r31, Y
+       sbrs r24, 0
+       rjmp 40f
+20:
+       sbrs r22, 7
+       rjmp 30f
+       ldi r25, 9
+       movw r28, r30
+25:    ld r0, Z
+    adiw r30, 9
+    ld r24, X
+       eor r24, r0
+       st X+, r24
+       dec r25
+       brne 25b
+       movw r30, r28
+       sbiw r26, 9
+30:
+       adiw r30, 1
+       lsl r22
+       breq 60f
+       rjmp 20b
+40:
+       sbrs r22, 7
+       rjmp 50f
+       ldi r25, 9
+       movw r28, r30
+45:    ld r0, Z+
+    ld r24, X
+       eor r24, r0
+       st X+, r24
+       dec r25
+       brne 45b
+       movw r30, r28
+       sbiw r26, 9
+50:
+       adiw r30, 9
+       lsl r22
+       breq 60f
+       rjmp 40b
+60:
+;------ all inputs are consumed, X points at e[0]
+;------ So we finished with obtaining e0 .. e7 and e8
+       movw r28, r26
+       ldd r0, Y+8
+       eor xres, r0
+;---
+
+/*
+   We can look at the bits of e0 .. e7 as a columns of a given matrix. We want to define 8 variables that have the rows
+   of that matrix. The variables need to be 16-bit because we will put into the upper 8 bits the bits of e0 .. e7,
+   and the bits of the variable result will be the Least Significant Bits of a[0] ... a[7].
+*/
+       adiw r28, 9 /* Y points at a[0] */
+       ldi r25, 8
+63:
+       ldi r24, 8
+       clr tmp_0
+65:    ld tmp_1, X
+       lsl tmp_1
+       st X+, tmp_1
+       rol tmp_0
+       dec r24
+       brne 65b
+;---
+       clr tmp_1
+       lsl xres
+       rol tmp_1
+       st Y+, tmp_1
+       st Y+, tmp_0
+       sbiw r26, 8
+       dec r25
+       brne 63b
+;------- First we apply upper triangular transformation
+       sbiw r28, 16  /* Y points at a[0] */
+       movw r30, r28 /* Z points at a[0] */
+
+col = 25
+       ldi r24, 8
+       clr col
+70:
+       mov r1, col
+       ldi tmp_3, 0x80
+       tst r1
+       breq 72f
+71:    lsr tmp_3
+       dec r1
+       brne 71b
+72:
+       clt
+       movw r28, r30 /* Y points at a[row]*/
+73:    ldd tmp_0, Y+1
+       and tmp_0, tmp_3
+       brne 74f
+       set
+       adiw r28, 2
+       rjmp 73b
+74:
+    /* Y points at a[row] */
+       /* if T is set we have to permute [Y] and [Z] */
+       brtc 75f
+       ld tmp_0, Y
+       ld tmp_1, Z
+       st Y, tmp_1
+       st Z, tmp_0
+       ldd tmp_0, Y+1
+       ldd tmp_1, Z+1
+       std Y+1, tmp_1
+       std Z+1, tmp_0
+75: /* permutation done */
+       ldi r26, 7
+       sub r26, col
+       breq 78f
+       movw r28, r30
+76:    adiw r28, 2
+       ldd tmp_0, Y+1
+       and tmp_0, tmp_3
+       breq 77f
+       ld tmp_0, Y
+       ld tmp_1, Z
+       eor tmp_0, tmp_1
+       st Y, tmp_0
+       ldd tmp_0, Y+1
+       ldd tmp_1, Z+1
+       eor tmp_0, tmp_1
+       std Y+1, tmp_0
+77:
+       dec r26
+       brne 76b
+78:
+       adiw r30, 2
+       inc col
+       dec r24
+       brne 70b
+79:
+;------ Then we eliminate 1s above the main diagonal
+
+       ldi col, 7
+       ldi tmp_3, 1
+       sbiw r30, 2
+80:
+       movw r28, r30
+       mov r26, col
+81:
+       sbiw r28, 2
+       ldd tmp_0, Y+1
+       and tmp_0, tmp_3
+       breq 82f
+       ld tmp_0, Y
+       ld tmp_1, Z
+       eor tmp_0, tmp_1
+       st Y, tmp_0
+       ldd tmp_0, Y+1
+       ldd tmp_1, Z+1
+       eor tmp_0, tmp_1
+       std Y+1, tmp_0
+82:
+       dec r26
+       brne 81b
+       sbiw r30, 2
+       lsl tmp_3
+       dec col
+       brne 80b
+89:
+;------ The result is in the Least Significant Bits of a[0] ... a[7]
+       /* Z should point at a[0] */
+       ldi r25, 8
+       clr r24
+90:
+       ld tmp_0, Z
+       adiw r30, 2
+       lsr tmp_0
+       rol r24
+       dec r25
+       brne 90b
+mqq_q_exit:
+;      stack_free 25
+;      pop r29
+;      pop r28
+       ret
+
+/******************************************************************************/
+
+/*
+  param dest:  r24:r25
+  param hash:  r22:r23
+  param key:   r20:r21
+*/
+
+dest_0 =  2
+dest_1 =  3
+xr1_0  =  4
+xr1_1  =  5
+key_0  =  6
+key_1  =  7
+i      =  8
+c      =  9
+qstack_0 = 10
+qstack_1 = 11
+
+.global mqq160_sign
+mqq160_sign:
+       push_range 2, 11
+       push_range 28, 29
+       stack_alloc 20, r26, r27  /* r1[20] + key */
+       adiw r26, 1 /* X points to stack memory */
+       movw key_0, r20
+       movw xr1_0, r26
+       movw dest_0, r24
+       /* call to mqq_inv_affine_transformation(hash, dest, &key); */
+       movw r24, r22
+       movw r22, dest_0
+       movw r20, key_0
+       rcall mqq_inv_affine_transformation
+
+       /* r1[0]=((uint8_t*)dest)[0]; */
+       movw r26, dest_0
+       movw r30, xr1_0
+       ld r0, X
+       st Z, r0
+;----
+       ldi r18, 19
+       mov c, r18
+       clr i
+       inc i
+       stack_alloc 25, r28, r29
+       adiw r28, 1
+       movw qstack_0, r28
+20:    mov r24, i
+       movw r26, xr1_0
+       add r26, i
+       adc r27, r1
+       sbiw r26, 1
+       ld r22, X
+       movw r26, dest_0
+       add r26, i
+       adc r27, r1
+       ld r20, X
+       movw r18, key_0
+       movw r26, qstack_0
+       rcall mqq_q
+       movw r26, xr1_0
+       add r26, i
+       adc r27, r1
+       st X, r24
+       inc i
+       dec c
+       brne 20b
+       stack_free 25
+;-----
+
+
+       movw r28, key_0
+       ldd r30, Y+8
+       ldd r31, Y+9
+       movw r26, xr1_0
+       ldi r18, 20
+30: ld r20, Z+
+       swap r20
+       andi r20, 0xF0
+       ld r21, Z+
+       andi r21, 0x0F
+       or r20, r21
+       ld r21, X
+       eor r21, r20
+       st X+, r21
+       dec r18
+       brne 30b
+;----
+
+       movw r24, xr1_0
+       movw r22, dest_0
+       movw r20, key_0
+       rcall mqq_inv_affine_transformation
+       stack_free 20
+       pop_range 28, 29
+       pop_range 2, 11
+       ret
+
+
diff --git a/mqq-sign/mqq160-sign.c b/mqq-sign/mqq160-sign.c
new file mode 100644 (file)
index 0000000..2843f7b
--- /dev/null
@@ -0,0 +1,199 @@
+/* mqq160-sign.c */
+/*
+   C code for MQQ160-SIGN suitable for 8-bit smart cards
+
+   It is supposed that the private key is "engraved" in
+   the ROM of the smart card - thus it is here stored as
+   predefined const arrays in "MQQ160-SIGN-PrivateKey.h"
+
+   Programmed by
+   Danilo Gligoroski and Rune Jensen and Daniel Otte
+   March 2010.
+
+   Verified by Danilo Gligoroski
+   March 2010.
+
+*/
+
+#include <string.h>
+#include <stdint.h>
+#include <avr/pgmspace.h>
+#include "memxor.h"
+#include "mqq160-sign.h"
+
+#include "cli.h"
+
+static uint8_t mod20_table[32] PROGMEM = {
+                4,  5,  6,  7,  8,  9, 10, 11,
+               12, 13, 14, 15, 16, 17, 18, 19,
+                0,  1,  2,  3,  4,  5,  6,  7,
+                8,  9, 10, 11, 12, 13, 14, 15,
+};
+
+static void memxor_idx(void* dest, const void* src, uint16_t length, uint8_t dist){
+       while(length--){
+               *((uint8_t*)dest) ^= *((uint8_t*)src);
+               dest = (uint8_t*)dest + 1;
+               src  = (uint8_t*)src  + dist;
+       }
+}
+/*
+This is just for testing purposes.
+It should be programmed in a more flexible way
+in the MQQ160-SIGN C Library.
+*/
+
+static void mqq_inv_affine_transformation(const uint8_t* input_bytes, uint8_t* result, const mqq160_sign_key_t* key){
+       /* The matrix SInv is given as two permutations of 160 elements. */
+       uint8_t j, byteindex, bitindex, bitindex_d, byteindex_d, rp1, rp5;
+       uint8_t *rp1_ptr, *rp5_ptr;
+       uint8_t h1[20];
+
+
+       /* Initialize H1 and H2 = 0 */
+       memset(h1, 0, 20);
+       memset(result, 0, 20);
+
+       /*
+          Fill H1 with bits of InputBytes accordingly to RP1 permutation
+          and fill H2 with bits of InputBytes accordingly to RP5 permutation
+       */
+       j=160;
+       byteindex_d = 0;
+       bitindex_d = 0x80;
+       rp1_ptr = key->rp1;
+       rp5_ptr = key->rp5;
+       do{
+               rp1 = *rp1_ptr++;
+               rp5 = *rp5_ptr++;
+               byteindex = rp1>>3;
+               bitindex = 0x80 >> (rp1&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       h1[byteindex_d] ^= bitindex_d;
+               }
+
+               byteindex = rp5>>3;
+               bitindex = 0x80 >> (rp5&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       result[byteindex_d] ^= bitindex_d;
+               }
+               bitindex_d >>= 1;
+               if(bitindex_d==0){
+                       ++byteindex_d;
+                       bitindex_d = 0x80;
+               }
+       }while(--j);
+//     cli_putstr_P(PSTR("\r\nDBG (ref): "));
+//     cli_hexdump(h1, 20);
+       for (j=0; j<20; j++){
+               result[j] ^= h1[j] ^ h1[pgm_read_byte(j+mod20_table)]
+                                  ^ h1[pgm_read_byte(8+j+mod20_table)]
+                                  ^ h1[pgm_read_byte(12+j+mod20_table)];
+       }
+}
+
+static uint16_t MaskShort[8] = {0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100};
+
+static uint8_t mqq_q(uint8_t i, uint8_t b1, uint8_t b2, const mqq160_sign_key_t* key){
+       uint8_t  e[9];
+       uint16_t a[8];
+       uint8_t result, column, row, k;
+       int8_t j;
+       uint16_t temp;
+       uint8_t *tmp_ptr=key->a;
+       if(i&1){
+               memcpy(e, key->cc1, 9);
+               while(b1){
+                       if(b1&0x80){
+                               memxor_idx((uint8_t*)e, tmp_ptr, 9, 9);
+                       }
+                       tmp_ptr++;
+                       b1 <<= 1;
+               }
+       }else{
+               memcpy(e, key->cc2, 9);
+               while(b1){
+                       if(b1&0x80){
+                               memxor((uint8_t*)e, tmp_ptr, 9);
+                       }
+                       tmp_ptr+=9;
+                       b1 <<= 1;
+               }
+       }
+       /* So we finished with obtaining e0 .. e7 and e8 */
+
+       /* We XOR e[8] with b2 and that will be initial value to transform in order to solve a linear system of equations */
+       result=b2 ^ e[8];
+
+       /*
+          We can look at the bits of e0 .. e7 as a columns of a given matrix. We want to define 8 variables that have the rows
+          of that matrix. The variables need to be 16-bit because we will put into the upper 8 bits the bits of e0 .. e7,
+          and the bits of the variable result will be the Least Significant Bits of a[0] ... a[7].
+   */
+       for(j=0; j<8; ++j){
+               row = 0;
+               for(k=0; k<8; ++k){
+                       row |= (e[k]&0x80)>>(k);
+                       e[k]<<=1;
+               }
+               a[j]=(((uint16_t)row)<<8) | (result>>7);
+               result <<= 1;
+       }
+
+       /* Now we finally realize Gausian elimination */
+
+       /* First we apply upper triangular transformation */
+       for(column=0; column<8; column++)
+       {
+               row=column;
+               while ((a[row] & MaskShort[column]) == 0){
+                       row++;
+               }
+               if(row>column)
+               {
+                       temp=a[column];
+                       a[column]=a[row];
+                       a[row]=temp;
+               }
+               for (j=column+1; j<8; j++)
+                       if ((a[j]&MaskShort[column]) !=0){
+                               a[j] ^= a[column];
+                       }
+       }
+
+       /* Then we eliminate 1s above the main diagonal */
+       for (column=7; column>0; column--){
+               for (j=column-1; j>=0; j--){
+                       if ((a[j]&MaskShort[column]) !=0){
+                               a[j] ^= a[column];
+                       }
+               }
+       }
+       /* The result is in the Least Significant Bits of a[0] ... a[7] */
+       result = 0;
+       for(j=0; j<8; ++j){
+               result <<=1;
+               result |= a[j]&1;
+       }
+       return(result);
+}
+
+void mqq160_sign(void* dest, const void* hash, const mqq160_sign_key_t* key){
+       uint8_t i, r1[20], byteindex;
+       mqq_inv_affine_transformation((uint8_t*)hash, (uint8_t*)dest, key);
+       r1[0]=((uint8_t*)dest)[0];
+       for(i=1; i<20; ++i){
+               r1[i] = mqq_q(i, r1[i-1], ((uint8_t*)dest)[i], key);
+       }
+       /*
+       Affine transformation is just for the second call. The constant is extracted
+       from the 4 LSBs of the first 40 bytes of RP5[] and xor-ed to input_bytes[].
+       */
+       byteindex = 0;
+       for (i=0; i<20; i++){
+               r1[i] ^=   (uint8_t)((key->rp5[byteindex])<<4)
+                                | (uint8_t)(key->rp5[byteindex+1]&0x0F);
+               byteindex += 2;
+       }
+       mqq_inv_affine_transformation(r1, (uint8_t*)dest, key);
+}
diff --git a/mqq-sign/mqq160-sign.h b/mqq-sign/mqq160-sign.h
new file mode 100644 (file)
index 0000000..bf6c5f7
--- /dev/null
@@ -0,0 +1,33 @@
+/* mqq160-sign.h */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 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/>.
+*/
+
+#ifndef MQQ160SIGN_H_
+#define MQQ160SIGN_H_
+
+typedef struct{
+       uint8_t *a;
+       uint8_t *cc1;
+       uint8_t *cc2;
+       uint8_t *rp1;
+       uint8_t *rp5;
+} mqq160_sign_key_t;
+
+void mqq160_sign(void* dest, const void* hash, const mqq160_sign_key_t* key);
+
+#endif /* MQQ160SIGN_H_ */
diff --git a/mqq-sign/mqq160-sign_P-asm.S b/mqq-sign/mqq160-sign_P-asm.S
new file mode 100644 (file)
index 0000000..1123455
--- /dev/null
@@ -0,0 +1,547 @@
+/* mqq160-sign_P-asm.S */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 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     mqq160-sign_P-asm.S
+ * \email    daniel.otte@rub.de
+ * \author   Daniel Otte
+ * \date     2010-03-21
+ * \license  GPLv3 or later
+ *
+ */
+
+#include "avr-asm-macros.S"
+
+#if 0
+static void mqq_inv_affine_transformation(uint8_t* input_bytes, uint8_t* result, const mqq160_sign_key_t* key){
+       /* The matrix SInv is given as two permutations of 160 elements. */
+       uint8_t j, byteindex, bitindex, bitindex_d, byteindex_d, rp1, rp5;
+       uint8_t *r1_ptr, *r5_ptr;
+       uint8_t h1[20];
+
+       /* Initialize H1 and H2 = 0 */
+       memset(h1, 0, 20);
+       memset(result, 0, 20);
+
+       /*
+          Fill H1 with bits of InputBytes accordingly to RP1 permutation
+          and fill H2 with bits of InputBytes accordingly to RP5 permutation
+       */
+       bitindex_d = 0x80;
+       byteindex_d = 0;
+       j=160;
+       r1_ptr = key->rp1;
+       r5_ptr = key->rp5;
+       do{
+               rp1 = pgm_read_byte(r1_ptr++);
+               rp5 = pgm_read_byte(r5_ptr++);
+               byteindex = rp1>>3;
+               bitindex = 0x80 >> (rp1&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       h1[byteindex_d] ^= bitindex_d;
+               }
+
+               byteindex = rp5>>3;
+               bitindex = 0x80 >> (rp5&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       result[byteindex_d] ^= bitindex_d;
+               }
+               bitindex_d >>= 1;
+               if(bitindex_d==0){
+                       ++byteindex_d;
+                       bitindex_d = 0x80;
+               }
+       }while(--j);
+
+       for (j=0; j<20; j++){
+               result[j] ^= h1[j] ^ h1[pgm_read_byte(j+mod20_table)]
+                                  ^ h1[pgm_read_byte(8+j+mod20_table)]
+                                  ^ h1[pgm_read_byte(12+j+mod20_table)];
+       }
+}
+#endif
+
+fetch_bit:
+       lpm r0, Z+
+       mov r28, r0
+       ldi r29, 0x80
+       andi r28, 7
+       breq 3f
+2:     lsr r29
+       dec r28
+       brne 2b
+3:     mov r28, r0
+       lsr r28
+       lsr r28
+       lsr r28
+       mov r0, r29
+       clr r29
+       add r28, r24
+       adc r29, r25
+       ld r28, Y
+       clt
+       and r28, r0
+       breq 4f
+       set
+4:  ret
+
+xres_0 = 18
+xres_1 = 19
+h_0 = 20
+h_1 = 21
+xrp5_0 = 22
+xrp5_1 = 23
+inp_0 =  24
+inp_1 =  25
+tmp_0 =  22
+tmp_1 =  23
+tmp_2 =  24
+tmp_3 =  25
+tmp_4 =  18
+
+/*
+ param input_bytes: r24:r25
+ param result:      r22:r23
+ param key:         r20:r21
+*/
+;.global mqq_inv_affine_transformation
+mqq_inv_affine_transformation:
+       push r17
+;      push r28
+;      push r29
+       stack_alloc 20
+       adiw r30, 1   /* Z points to stack space for h1 */
+       movw r28, r20 /* Y points to the key struct in RAM */
+       movw xres_0, r22
+       movw r26, r30 /* X points to h1[0] */
+       ldd xrp5_0, Y+8 /* load pointer rp5 to xrp5 */
+       ldd xrp5_1, Y+9
+       movw h_0, r30
+       ldd r30, Y+6 /* load pointer to rp1 in Z */
+       ldd r31, Y+7
+       ldi r17, 20
+20:    rcall fetch_bit
+       bld r1, 7
+       rcall fetch_bit
+       bld r1, 6
+       rcall fetch_bit
+       bld r1, 5
+       rcall fetch_bit
+       bld r1, 4
+       rcall fetch_bit
+       bld r1, 3
+       rcall fetch_bit
+       bld r1, 2
+       rcall fetch_bit
+       bld r1, 1
+       rcall fetch_bit
+       bld r1, 0
+       st X+, r1
+       dec r17
+       brne 20b
+;----
+       movw r26, xres_0 /* X points to result */
+       movw r30, xrp5_0
+       ldi r17, 20
+20:    rcall fetch_bit
+       bld r1, 7
+       rcall fetch_bit
+       bld r1, 6
+       rcall fetch_bit
+       bld r1, 5
+       rcall fetch_bit
+       bld r1, 4
+       rcall fetch_bit
+       bld r1, 3
+       rcall fetch_bit
+       bld r1, 2
+       rcall fetch_bit
+       bld r1, 1
+       rcall fetch_bit
+       bld r1, 0
+       st X+, r1
+       dec r17
+       brne 20b
+       clr r1
+; --- now we mix result with h1
+       sbiw r26, 20 /* adjusting X to point at result[0] */
+       movw tmp_2, h_0
+       ldi r30, lo8(affine_mix_lut)
+       ldi r31, hi8(affine_mix_lut)
+       ldi r17, 20
+30:
+       ld tmp_0, X
+       movw r28, tmp_2
+       ld tmp_1, Y+
+       movw tmp_2, r28
+       eor tmp_0, tmp_1
+       movw r28, h_0
+       lpm r0, Z+
+       mov tmp_4, r0
+       andi tmp_4, 0x0f
+       add r28, tmp_4
+       adc r29, r1
+       ld tmp_1, Y
+       eor tmp_0, tmp_1
+       adiw r28, 4
+       sbrc r0, 7
+       adiw r28, 4
+       ld tmp_1, Y
+       eor tmp_0, tmp_1
+       adiw r28, 4
+       sbrc r0, 6
+       adiw r28, 4
+       ld tmp_1, Y
+       eor tmp_0, tmp_1
+       st X+, tmp_0
+       dec r17
+       brne 30b
+
+       stack_free 20
+;      pop r29
+;      pop r28
+       pop r17
+       ret
+
+affine_mix_lut:
+       .byte 0x84, 0x85, 0x86, 0x87
+       .byte 0xC0, 0xC1, 0xC2, 0xC3
+       .byte 0x40, 0x41, 0x42, 0x43
+       .byte 0x44, 0x45, 0x46, 0x47
+       .byte 0x80, 0x81, 0x82, 0x83
+
+/******************************************************************************/
+
+xres  = 20
+tmp_0 = 23
+tmp_1 = 22
+tmp_2 = 21
+tmp_3 = 19
+/*
+  param i:    r24
+  param b1:   r22
+  param b2:   r20
+  param key:  r18:r19
+*/
+;.global mqq_q
+mqq_q:
+;      push r28
+;      push r29
+;      stack_alloc 25, r26, r27
+;      adiw r26, 1  /* X points to e[0] */
+       movw r28, r18
+       sbrs r24, 0
+       adiw r28, 2
+       ldd r30, Y+2
+       ldd r31, Y+3
+       ldi r28, 9
+10:    lpm r0, Z+
+       st X+, r0
+       dec r28
+       brne 10b
+       sbiw r26, 9 /* adjust X to point at e[0] */
+;---
+       movw r28, r18
+       ld r30, Y+ /* Z points to a[0] in progmem */
+       ld r31, Y
+       sbrs r24, 0
+       rjmp 40f
+20:
+       sbrs r22, 7
+       rjmp 30f
+       ldi r25, 9
+       movw r28, r30
+25:    lpm r0, Z
+    adiw r30, 9
+    ld r24, X
+       eor r24, r0
+       st X+, r24
+       dec r25
+       brne 25b
+       movw r30, r28
+       sbiw r26, 9
+30:
+       adiw r30, 1
+       lsl r22
+       breq 60f
+       rjmp 20b
+40:
+       sbrs r22, 7
+       rjmp 50f
+       ldi r25, 9
+       movw r28, r30
+45:    lpm r0, Z+
+    ld r24, X
+       eor r24, r0
+       st X+, r24
+       dec r25
+       brne 45b
+       movw r30, r28
+       sbiw r26, 9
+50:
+       adiw r30, 9
+       lsl r22
+       breq 60f
+       rjmp 40b
+60:
+;------ all inputs are consumed, X points at e[0]
+;------ So we finished with obtaining e0 .. e7 and e8
+       movw r28, r26
+       ldd r0, Y+8
+       eor xres, r0
+;---
+
+/*
+   We can look at the bits of e0 .. e7 as a columns of a given matrix. We want to define 8 variables that have the rows
+   of that matrix. The variables need to be 16-bit because we will put into the upper 8 bits the bits of e0 .. e7,
+   and the bits of the variable result will be the Least Significant Bits of a[0] ... a[7].
+*/
+       adiw r28, 9 /* Y points at a[0] */
+       ldi r25, 8
+63:
+       ldi r24, 8
+       clr tmp_0
+65:    ld tmp_1, X
+       lsl tmp_1
+       st X+, tmp_1
+       rol tmp_0
+       dec r24
+       brne 65b
+;---
+       clr tmp_1
+       lsl xres
+       rol tmp_1
+       st Y+, tmp_1
+       st Y+, tmp_0
+       sbiw r26, 8
+       dec r25
+       brne 63b
+;------- First we apply upper triangular transformation
+       sbiw r28, 16  /* Y points at a[0] */
+       movw r30, r28 /* Z points at a[0] */
+
+col = 25
+       ldi r24, 8
+       clr col
+70:
+       mov r1, col
+       ldi tmp_3, 0x80
+       tst r1
+       breq 72f
+71:    lsr tmp_3
+       dec r1
+       brne 71b
+72:
+       clt
+       movw r28, r30 /* Y points at a[row]*/
+73:    ldd tmp_0, Y+1
+       and tmp_0, tmp_3
+       brne 74f
+       set
+       adiw r28, 2
+       rjmp 73b
+74:
+    /* Y points at a[row] */
+       /* if T is set we have to permute [Y] and [Z] */
+       brtc 75f
+       ld tmp_0, Y
+       ld tmp_1, Z
+       st Y, tmp_1
+       st Z, tmp_0
+       ldd tmp_0, Y+1
+       ldd tmp_1, Z+1
+       std Y+1, tmp_1
+       std Z+1, tmp_0
+75: /* permutation done */
+       ldi r26, 7
+       sub r26, col
+       breq 78f
+       movw r28, r30
+76:    adiw r28, 2
+       ldd tmp_0, Y+1
+       and tmp_0, tmp_3
+       breq 77f
+       ld tmp_0, Y
+       ld tmp_1, Z
+       eor tmp_0, tmp_1
+       st Y, tmp_0
+       ldd tmp_0, Y+1
+       ldd tmp_1, Z+1
+       eor tmp_0, tmp_1
+       std Y+1, tmp_0
+77:
+       dec r26
+       brne 76b
+78:
+       adiw r30, 2
+       inc col
+       dec r24
+       brne 70b
+79:
+;------ Then we eliminate 1s above the main diagonal
+
+       ldi col, 7
+       ldi tmp_3, 1
+       sbiw r30, 2
+80:
+       movw r28, r30
+       mov r26, col
+81:
+       sbiw r28, 2
+       ldd tmp_0, Y+1
+       and tmp_0, tmp_3
+       breq 82f
+       ld tmp_0, Y
+       ld tmp_1, Z
+       eor tmp_0, tmp_1
+       st Y, tmp_0
+       ldd tmp_0, Y+1
+       ldd tmp_1, Z+1
+       eor tmp_0, tmp_1
+       std Y+1, tmp_0
+82:
+       dec r26
+       brne 81b
+       sbiw r30, 2
+       lsl tmp_3
+       dec col
+       brne 80b
+89:
+;------ The result is in the Least Significant Bits of a[0] ... a[7]
+       /* Z should point at a[0] */
+       ldi r25, 8
+       clr r24
+90:
+       ld tmp_0, Z
+       adiw r30, 2
+       lsr tmp_0
+       rol r24
+       dec r25
+       brne 90b
+mqq_q_exit:
+;      stack_free 25
+;      pop r29
+;      pop r28
+       ret
+
+/******************************************************************************/
+
+/*
+  param dest:  r24:r25
+  param hash:  r22:r23
+  param key:   r20:r21
+*/
+
+dest_0 =  2
+dest_1 =  3
+xr1_0  =  4
+xr1_1  =  5
+key_0  =  6
+key_1  =  7
+i      =  8
+c      =  9
+qstack_0 = 10
+qstack_1 = 11
+
+.global mqq160_sign_P
+mqq160_sign_P:
+       push_range 2, 11
+       push_range 28, 29
+       stack_alloc 10+20, r26, r27  /* r1[20] + key */
+       adiw r26, 1 /* X points to stack memory */
+       movw key_0, r26
+       /* load key structure */
+       movw r30, r20
+       ldi r18, 10
+10:    lpm r0, Z+
+       st X+, r0
+       dec r18
+       brne 10b
+       movw xr1_0, r26
+       movw dest_0, r24
+       /* call to mqq_inv_affine_transformation(hash, dest, &key); */
+       movw r24, r22
+       movw r22, dest_0
+       movw r20, key_0
+       rcall mqq_inv_affine_transformation
+       /* r1[0]=((uint8_t*)dest)[0]; */
+
+       movw r26, dest_0
+       movw r30, xr1_0
+       ld r0, X
+       st Z, r0
+;----
+       ldi r18, 19
+       mov c, r18
+       clr i
+       inc i
+       stack_alloc 25, r28, r29
+       adiw r28, 1
+       movw qstack_0, r28
+20:    mov r24, i
+       movw r26, xr1_0
+       add r26, i
+       adc r27, r1
+       sbiw r26, 1
+       ld r22, X
+       movw r26, dest_0
+       add r26, i
+       adc r27, r1
+       ld r20, X
+       movw r18, key_0
+       movw r26, qstack_0
+       rcall mqq_q
+       movw r26, xr1_0
+       add r26, i
+       adc r27, r1
+       st X, r24
+       inc i
+       dec c
+       brne 20b
+       stack_free 25
+;-----
+
+
+       movw r28, key_0
+       ldd r30, Y+8
+       ldd r31, Y+9
+       movw r26, xr1_0
+       ldi r18, 20
+30: lpm r20, Z+
+       swap r20
+       andi r20, 0xF0
+       lpm r21, Z+
+       andi r21, 0x0F
+       or r20, r21
+       ld r21, X
+       eor r21, r20
+       st X+, r21
+       dec r18
+       brne 30b
+;----
+
+       movw r24, xr1_0
+       movw r22, dest_0
+       movw r20, key_0
+       rcall mqq_inv_affine_transformation
+       stack_free 30
+       pop_range 28, 29
+       pop_range 2, 11
+       ret
+
+
diff --git a/mqq-sign/mqq160-sign_P-stub.c b/mqq-sign/mqq160-sign_P-stub.c
new file mode 100644 (file)
index 0000000..d8c889f
--- /dev/null
@@ -0,0 +1,158 @@
+/* mqq160-sign.c */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 Danilo Gligoroski, 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/>.
+*/
+/*
+   C code for MQQ160-SIGN suitable for 8-bit smart cards
+
+   It is supposed that the private key is "engraved" in
+   the ROM of the smart card - thus it is here stored as
+   predefined const arrays in "MQQ160-SIGN-PrivateKey.h"
+
+   Programmed by Danilo Gligoroski, 18 Mar 2010.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <avr/pgmspace.h>
+#include "memxor.h"
+#include "mqq160-sign.h"
+
+/*
+This is just for testing purposes.
+It should be programmed in a more flexible way
+in the MQQ160-SIGN C Library.
+*/
+
+
+void mqq_inv_affine_transformation(uint8_t* input_bytes, uint8_t* result, const mqq160_sign_key_t* key);
+uint8_t mqq_q(uint8_t i, uint8_t b1, uint8_t b2, const mqq160_sign_key_t* key);
+
+
+#if 0
+static uint16_t MaskShort[8] = {0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100};
+
+static uint8_t mqq_q(uint8_t i, uint8_t b1, uint8_t b2, const mqq160_sign_key_t* key){
+       uint8_t  e[9];
+       uint16_t a[8];
+       uint8_t result, column, row, k;
+       int8_t j;
+       uint16_t temp;
+       uint8_t *tmp_ptr=key->a;
+       if(i&1){
+               memcpy_P(e, key->cc1, 9);
+               while(b1){
+                       if(b1&0x80){
+                               memxor_idx_P((uint8_t*)e, tmp_ptr, 9, 9);
+                       }
+                       tmp_ptr++;
+                       b1 <<= 1;
+               }
+       }else{
+               memcpy_P(e, key->cc2, 9);
+               while(b1){
+                       if(b1&0x80){
+                               memxor_P((uint8_t*)e, tmp_ptr, 9);
+                       }
+                       tmp_ptr+=9;
+                       b1 <<= 1;
+               }
+       }
+       /* So we finished with obtaining e0 .. e7 and e8 */
+
+       /* We XOR e[8] with b2 and that will be initial value to transform in order to solve a linear system of equations */
+       result=b2 ^ e[8];
+
+       /*
+          We can look at the bits of e0 .. e7 as a columns of a given matrix. We want to define 8 variables that have the rows
+          of that matrix. The variables need to be 16-bit because we will put into the upper 8 bits the bits of e0 .. e7,
+          and the bits of the variable result will be the Least Significant Bits of a[0] ... a[7].
+   */
+       for(j=0; j<8; ++j){
+               row = 0;
+               for(k=0; k<8; ++k){
+                       row |= (e[k]&0x80)>>(k);
+                       e[k]<<=1;
+               }
+               a[j]=(((uint16_t)row)<<8) | (result>>7);
+               result <<= 1;
+       }
+
+       /* Now we finally realize Gausian elimination */
+
+       /* First we apply upper triangular transformation */
+       for(column=0; column<8; column++)
+       {
+               row=column;
+               while ((a[row] & MaskShort[column]) == 0){
+                       row++;
+               }
+               if(row>column)
+               {
+                       temp=a[column];
+                       a[column]=a[row];
+                       a[row]=temp;
+               }
+               for (j=column+1; j<8; j++)
+                       if ((a[j]&MaskShort[column]) !=0)
+                               a[j] ^= a[column];
+       }
+
+       /* Then we eliminate 1s above the main diagonal */
+       for (column=7; column>0; column--){
+               for (j=column-1; j>=0; j--){
+                       if ((a[j]&MaskShort[column]) !=0){
+                               a[j] ^= a[column];
+                       }
+               }
+       }
+       /* The result is in the Least Significant Bits of a[0] ... a[7] */
+       result = 0;
+       for(j=0; j<8; ++j){
+               result <<=1;
+               result |= a[j]&1;
+       }
+       return(result);
+}
+
+#endif
+
+void mqq160_sign_P(void* dest, const void* hash, const mqq160_sign_key_t* key_P){
+       uint8_t i, r1[20], byteindex;
+       mqq160_sign_key_t key;
+
+       memcpy_P(&key, key_P, sizeof(mqq160_sign_key_t));
+
+       mqq_inv_affine_transformation((uint8_t*)hash, (uint8_t*)dest, &key);
+       r1[0]=((uint8_t*)dest)[0];
+       for(i=1; i<20; ++i){
+               r1[i] = mqq_q(i, r1[i-1], ((uint8_t*)dest)[i], &key);
+       }
+       /*
+       Affine transformation is just for the second call. The constant is extracted
+       from the 4 LSBs of the first 40 bytes of RP5[] and xor-ed to input_bytes[].
+       */
+       byteindex = 0;
+       for (i=0; i<20; i++){
+               r1[i] ^=   (uint8_t)(pgm_read_byte(key.rp5+byteindex)<<4)
+                                | (uint8_t)(pgm_read_byte(key.rp5+byteindex+1)&0x0F);
+               byteindex += 2;
+       }
+       mqq_inv_affine_transformation(r1, (uint8_t*)dest, &key);
+}
diff --git a/mqq-sign/mqq160-sign_P.c b/mqq-sign/mqq160-sign_P.c
new file mode 100644 (file)
index 0000000..82c90ea
--- /dev/null
@@ -0,0 +1,217 @@
+/* mqq160-sign.c */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 Danilo Gligoroski, 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/>.
+*/
+/*
+   C code for MQQ160-SIGN suitable for 8-bit smart cards
+
+   It is supposed that the private key is "engraved" in
+   the ROM of the smart card - thus it is here stored as
+   predefined const arrays in "MQQ160-SIGN-PrivateKey.h"
+
+   Programmed by Danilo Gligoroski, 18 Mar 2010.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <avr/pgmspace.h>
+#include "memxor.h"
+#include "mqq160-sign.h"
+
+static uint8_t mod20_table[32] PROGMEM = {
+                4,  5,  6,  7,  8,  9, 10, 11,
+               12, 13, 14, 15, 16, 17, 18, 19,
+                0,  1,  2,  3,  4,  5,  6,  7,
+                8,  9, 10, 11, 12, 13, 14, 15,
+};
+
+static void memxor_P(void* dest, const void* src, uint16_t length){
+       while(length--){
+               *((uint8_t*)dest) ^= pgm_read_byte(src);
+               dest = (uint8_t*)dest +1;
+               src  = (uint8_t*)src  +1;
+       }
+}
+
+static void memxor_idx_P(uint8_t* dest, const uint8_t* src, uint16_t length, uint8_t dist){
+       while(length--){
+                *((uint8_t*)dest) ^= pgm_read_byte((uint8_t*)src);
+               dest = (uint8_t*)dest + 1;
+               src  = (uint8_t*)src  + dist;
+       }
+}
+/*
+This is just for testing purposes.
+It should be programmed in a more flexible way
+in the MQQ160-SIGN C Library.
+*/
+
+static void mqq_inv_affine_transformation(uint8_t* input_bytes, uint8_t* result, const mqq160_sign_key_t* key){
+       /* The matrix SInv is given as two permutations of 160 elements. */
+       uint8_t j, byteindex, bitindex, bitindex_d, byteindex_d, rp1, rp5;
+       uint8_t *r1_ptr, *r5_ptr;
+       uint8_t h1[20];
+
+       /* Initialize H1 and H2 = 0 */
+       memset(h1, 0, 20);
+       memset(result, 0, 20);
+
+       /*
+          Fill H1 with bits of InputBytes accordingly to RP1 permutation
+          and fill H2 with bits of InputBytes accordingly to RP5 permutation
+       */
+       bitindex_d = 0x80;
+       byteindex_d = 0;
+       j=160;
+       r1_ptr = key->rp1;
+       r5_ptr = key->rp5;
+       do{
+               rp1 = pgm_read_byte(r1_ptr++);
+               rp5 = pgm_read_byte(r5_ptr++);
+               byteindex = rp1>>3;
+               bitindex = 0x80 >> (rp1&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       h1[byteindex_d] ^= bitindex_d;
+               }
+
+               byteindex = rp5>>3;
+               bitindex = 0x80 >> (rp5&0x07);
+               if (input_bytes[byteindex] & bitindex){
+                       result[byteindex_d] ^= bitindex_d;
+               }
+               bitindex_d >>= 1;
+               if(bitindex_d==0){
+                       ++byteindex_d;
+                       bitindex_d = 0x80;
+               }
+       }while(--j);
+
+       for (j=0; j<20; j++){
+               result[j] ^= h1[j] ^ h1[pgm_read_byte(j+mod20_table)]
+                                  ^ h1[pgm_read_byte(8+j+mod20_table)]
+                                  ^ h1[pgm_read_byte(12+j+mod20_table)];
+       }
+}
+
+static uint16_t MaskShort[8] = {0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100};
+
+static uint8_t mqq_q(uint8_t i, uint8_t b1, uint8_t b2, const mqq160_sign_key_t* key){
+       uint8_t  e[9];
+       uint16_t a[8];
+       uint8_t result, column, row, k;
+       int8_t j;
+       uint16_t temp;
+       uint8_t *tmp_ptr=key->a;
+       if(i&1){
+               memcpy_P(e, key->cc1, 9);
+               while(b1){
+                       if(b1&0x80){
+                               memxor_idx_P((uint8_t*)e, tmp_ptr, 9, 9);
+                       }
+                       tmp_ptr++;
+                       b1 <<= 1;
+               }
+       }else{
+               memcpy_P(e, key->cc2, 9);
+               while(b1){
+                       if(b1&0x80){
+                               memxor_P((uint8_t*)e, tmp_ptr, 9);
+                       }
+                       tmp_ptr+=9;
+                       b1 <<= 1;
+               }
+       }
+       /* So we finished with obtaining e0 .. e7 and e8 */
+
+       /* We XOR e[8] with b2 and that will be initial value to transform in order to solve a linear system of equations */
+       result=b2 ^ e[8];
+
+       /*
+          We can look at the bits of e0 .. e7 as a columns of a given matrix. We want to define 8 variables that have the rows
+          of that matrix. The variables need to be 16-bit because we will put into the upper 8 bits the bits of e0 .. e7,
+          and the bits of the variable result will be the Least Significant Bits of a[0] ... a[7].
+   */
+       for(j=0; j<8; ++j){
+               row = 0;
+               for(k=0; k<8; ++k){
+                       row |= (e[k]&0x80)>>(k);
+                       e[k]<<=1;
+               }
+               a[j]=(((uint16_t)row)<<8) | (result>>7);
+               result <<= 1;
+       }
+
+       /* Now we finally realize Gausian elimination */
+
+       /* First we apply upper triangular transformation */
+       for(column=0; column<8; column++)
+       {
+               row=column;
+               while ((a[row] & MaskShort[column]) == 0){
+                       row++;
+               }
+               if(row>column)
+               {
+                       temp=a[column];
+                       a[column]=a[row];
+                       a[row]=temp;
+               }
+               for (j=column+1; j<8; j++)
+                       if ((a[j]&MaskShort[column]) !=0)
+                               a[j] ^= a[column];
+       }
+
+       /* Then we eliminate 1s above the main diagonal */
+       for (column=7; column>0; column--){
+               for (j=column-1; j>=0; j--){
+                       if ((a[j]&MaskShort[column]) !=0){
+                               a[j] ^= a[column];
+                       }
+               }
+       }
+       /* The result is in the Least Significant Bits of a[0] ... a[7] */
+       result = 0;
+       for(j=0; j<8; ++j){
+               result <<=1;
+               result |= a[j]&1;
+       }
+       return(result);
+}
+
+void mqq160_sign_P(void* dest, const void* hash, const mqq160_sign_key_t* key_P){
+       uint8_t i, r1[20], byteindex;
+       mqq160_sign_key_t key;
+       memcpy_P(&key, key_P, sizeof(mqq160_sign_key_t));
+       mqq_inv_affine_transformation((uint8_t*)hash, (uint8_t*)dest, &key);
+       r1[0]=((uint8_t*)dest)[0];
+       for(i=1; i<20; ++i){
+               r1[i] = mqq_q(i, r1[i-1], ((uint8_t*)dest)[i], &key);
+       }
+       /*
+       Affine transformation is just for the second call. The constant is extracted
+       from the 4 LSBs of the first 40 bytes of RP5[] and xor-ed to input_bytes[].
+       */
+       byteindex = 0;
+       for (i=0; i<20; i++){
+               r1[i] ^=   (uint8_t)(pgm_read_byte(key.rp5+byteindex)<<4)
+                                | (uint8_t)(pgm_read_byte(key.rp5+byteindex+1)&0x0F);
+               byteindex += 2;
+       }
+       mqq_inv_affine_transformation(r1, (uint8_t*)dest, &key);
+}
diff --git a/mqq-sign/mqq160-sign_P.h b/mqq-sign/mqq160-sign_P.h
new file mode 100644 (file)
index 0000000..19208a2
--- /dev/null
@@ -0,0 +1,27 @@
+/* mqq160-sign.h */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 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/>.
+*/
+
+#ifndef MQQ160SIGN_P_H_
+#define MQQ160SIGN_P_H_
+
+#include "mqq160-sign.h"
+
+void mqq160_sign_P(void* dest, const void* hash, const mqq160_sign_key_t* key_P);
+
+#endif /* MQQ160SIGN_P_H_ */
diff --git a/mqq-sign/mqq160-sign_testkey.c b/mqq-sign/mqq160-sign_testkey.c
new file mode 100644 (file)
index 0000000..8fef41a
--- /dev/null
@@ -0,0 +1,113 @@
+/* mqq160-sign_testkey.c */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 Danilo Gligoroski, 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/>.
+*/
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+#include "mqq160-sign.h"
+#include "mqq160-sign_testkey.h"
+
+/*
+This is the private key of MQQ defined by one
+quadratic quasigroup of order 2^8 given as 81 uint8_ts
+and one nonsingular matrix SInv given as two arrays
+RP1[] and RP5[] of 160 uint8_ts.
+*/
+
+
+static uint8_t a[9*9-1] PROGMEM =
+ { 171, 171, 165,  56, 121, 136,  79, 108,   2,
+   255, 255, 165, 108,  45, 220,  79, 108,  88,
+    54, 108, 103,  21,  74, 119, 141, 204, 221,
+   210, 220,  30, 201, 215, 199,  74,  95, 173,
+   165, 241, 160, 190,  38, 134,  68, 103, 140,
+    84,  84,  68, 157,  81,  65,  30,  11,  48,
+   136, 136,  79,  21, 136, 199,  79,   0, 171,
+   136, 210,  27,  27, 220, 157,  65,  84,  45,
+   225,  61,   8, 232, 235,  49,  22, 146 };
+
+
+static uint8_t cc1[9] PROGMEM = {  2,  88, 221, 173, 140,  48, 171,  45, 252 };
+static uint8_t cc2[9] PROGMEM = {225,  61,   8, 232, 235,  49,  22, 146, 252 };
+
+/* The matrix SInv is stored in ROM as two onedimensional
+arrays RP1[] and RP5[] of 160 uint8_ts */
+static uint8_t rp1[160] PROGMEM = {
+       111, 137,  49, 134,   9, 116,  11,  52,  43,  55,
+        74, 130, 119, 144,  31,   7,  72,  79, 105,  59,
+        57, 120,  50,  94, 141, 135, 149,  44, 109, 100,
+       113,   1, 143, 126, 117,  37,  65,  67, 152, 107,
+        10,  98,  15,  23, 138,  19, 121,  18,  28, 156,
+       123, 106,  48,  29,  97,  34,  85, 157,  64,   3,
+        60,  35,  24,  32, 108, 147, 158,  21, 129,  84,
+         5,  70, 118, 112,  30,  68,  47,  40, 150,  13,
+        61,  73, 132,  22,  95, 153,   4,  76,  87, 114,
+       127,  62,  27,  36, 125,  45, 142,  39, 101,  63,
+        88,  96,  12, 115,  82,  91, 159,  93, 155, 154,
+       148, 110,  25,   0,  41,  20,  54,  26,  14,  83,
+        81,  80, 131,  33,  78,  77, 124, 104, 133,  17,
+       145, 139, 122, 102,  42,  56,  75,  66,   2,  16,
+        86, 140,  71, 136,  69,  99,  58,   6,  92,  90,
+         8, 103, 128,  38,  46, 146,  89, 151,  51,  53 };
+
+static uint8_t rp5[160] PROGMEM = {
+        90, 113, 130, 115, 132,  27,  46,  72,  33,  50,
+        35, 136,  42, 148, 146, 143, 116, 158,  98,  41,
+        39,   5,  54,  86, 106,  56,  30, 138,  80,  44,
+        91,  49,   1, 149, 159, 101,  74,   9, 110, 131,
+        25,  51, 123,  76, 104,  28,  82, 140,   2, 108,
+       120, 144,  10, 145, 124, 119,  62,  57, 117, 121,
+        17,  73, 105,  69, 155,   7, 154,  75, 100, 141,
+       157,  38,  14,  60,  47, 112,  95,  85,  43,  93,
+        24,  12,   4,  71,  81,  13,  94,  68, 107,  67,
+       142, 150,  61,   6, 122,  26, 139,  59, 102, 153,
+       109,  48, 103,  65,  23,  92,  87,  40, 135, 133,
+       129, 134,   8,  55,  83, 125,  31,  96, 147,  36,
+         0, 126,  70,  64,  20,  11, 137,  78,  89,  58,
+        21, 114, 127, 111,  99,  34, 152,  79,  66,  97,
+        22,  15, 151,  32,  84,  37,  77,  88,  16,  29,
+         3, 128, 118,  18, 156,  19,  52,  45,  53,  63 };
+
+mqq160_sign_key_t testkey_P PROGMEM = {a, cc1, cc2, rp1, rp5 };
+
+void mqq_load_pgm_key(void* buffer, mqq160_sign_key_t* key, const mqq160_sign_key_t* key_P){
+       uint8_t *buf_ptr;
+       buf_ptr = buffer;
+       memcpy_P(key, key_P, sizeof(mqq160_sign_key_t));
+
+       memcpy_P(buf_ptr, key->a, MQQ160SIGN_A_SIZE);
+       key->a = buf_ptr;
+       buf_ptr += MQQ160SIGN_A_SIZE;
+
+       memcpy_P(buf_ptr, key->cc1, MQQ160SIGN_CC1_SIZE);
+       key->cc1 = buf_ptr;
+       buf_ptr += MQQ160SIGN_CC1_SIZE;
+
+       memcpy_P(buf_ptr, key->cc2, MQQ160SIGN_CC2_SIZE);
+       key->cc2 = buf_ptr;
+       buf_ptr += MQQ160SIGN_CC2_SIZE;
+
+       memcpy_P(buf_ptr, key->rp1, MQQ160SIGN_RP1_SIZE);
+       key->rp1 = buf_ptr;
+       buf_ptr += MQQ160SIGN_RP1_SIZE;
+
+       memcpy_P(buf_ptr, key->rp5, MQQ160SIGN_RP5_SIZE);
+       key->rp5 = buf_ptr;
+
+}
+
diff --git a/mqq-sign/mqq160-sign_testkey.h b/mqq-sign/mqq160-sign_testkey.h
new file mode 100644 (file)
index 0000000..cd601d9
--- /dev/null
@@ -0,0 +1,42 @@
+/* mqq160-sign_testkey.h */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 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/>.
+*/
+
+#ifndef MQQ160SIGN_TESTKEY_H_
+#define MQQ160SIGN_TESTKEY_H_
+
+#include <stdint.h>
+
+#define MQQ160SIGN_A_SIZE    80
+#define MQQ160SIGN_RP1_SIZE 160
+#define MQQ160SIGN_RP5_SIZE 160
+#define MQQ160SIGN_CC1_SIZE   9
+#define MQQ160SIGN_CC2_SIZE   9
+#define MQQ160SIGN_KEY_SIZE (9+9+160+160+80)
+
+/*
+This is the private key of MQQ defined by one
+quadratic quasigroup of order 2^8 given as 81 uint8_ts
+and one nonsingular matrix SInv given as two arrays
+RP1[] and RP5[] of 160 uint8_ts.
+*/
+extern mqq160_sign_key_t testkey_P;
+
+void mqq_load_pgm_key(void* buffer, mqq160_sign_key_t* key, const mqq160_sign_key_t* key_P);
+
+#endif /* MQQ160SIGN_TESTKEY_H_ */
index 5fb2a1711eaf20d16ef4e5a592ff38a1ff3bb1da..f95f26e84a0f1e4ee82ae1d2c17039d40a372314 100644 (file)
@@ -61,6 +61,7 @@ uint8_t cli_getsn(char* s, uint16_t n);
 uint8_t cli_getsn_cecho(char* s, uint16_t n);
 void cli_putstr(const char* s);
 void cli_putstr_P(PGM_P s);
+void cli_hexdump_byte(uint8_t byte);
 void cli_hexdump(const void* data, uint16_t length);
 void cli_hexdump_rev(const void* data, uint16_t length);
 void cli_hexdump2(const void* data, uint16_t length);
diff --git a/test_src/main-mqq160-sign-test.c b/test_src/main-mqq160-sign-test.c
new file mode 100644 (file)
index 0000000..a5d3f1c
--- /dev/null
@@ -0,0 +1,204 @@
+/* main-mqq160-sign-test.c */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2010 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/>.
+*/
+/*
+ * MQQ160-sign test-suit
+ *
+*/
+
+#include "config.h"
+#include "uart_i.h"
+#include "debug.h"
+
+#include "cli.h"
+#include "mqq160-sign.h"
+#include "mqq160-sign_P.h"
+#include "mqq160-sign_testkey.h"
+#include "performance_test.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <avr/pgmspace.h>
+#include "stack_measuring.h"
+
+char* algo_name = "MQQ160-sign";
+
+
+/*****************************************************************************
+ *  additional validation-functions                                                                                     *
+ *****************************************************************************/
+uint8_t test_hash[20] PROGMEM =
+{
+       (uint8_t)0x64, (uint8_t)0xFE, (uint8_t)0x2A, (uint8_t)0x85,
+       (uint8_t)0xBB, (uint8_t)0x8C, (uint8_t)0x54, (uint8_t)0x5C,
+       (uint8_t)0x65, (uint8_t)0x74, (uint8_t)0xA0, (uint8_t)0xF3,
+       (uint8_t)0xD0, (uint8_t)0xAF, (uint8_t)0x96, (uint8_t)0xB9,
+       (uint8_t)0x0F, (uint8_t)0x17, (uint8_t)0xF3, (uint8_t)0xAD
+};
+
+void performance_mqq(void){
+       uint8_t hash[20];
+       uint8_t signature[20];
+       long t;
+       char str[3*sizeof(long)+2];
+       uint8_t tmp;
+       uint16_t s1, s2;
+       stack_measuring_ctx_t smctx;
+       memcpy_P(hash, test_hash, 20);
+
+       uint8_t key_buffer[MQQ160SIGN_KEY_SIZE];
+       mqq160_sign_key_t key;
+       mqq_load_pgm_key(key_buffer, &key, &testkey_P);
+
+       cli_putstr_P(PSTR("\r\n=== Performance of MQQ160-SIGN ==="));
+       calibrateTimer();
+       startTimer(0);
+       START_TIMER;
+       mqq160_sign_P(signature, hash, &testkey_P);
+       STOP_TIMER;
+       t = stopTimer();
+       ltoa(t, str, 10);
+       cli_putstr_P(PSTR("\r\n cycles for mqq160_sign_P: "));
+       tmp = 12-strlen(str);
+       while(tmp--){
+               cli_putc(' ');
+       }
+       cli_putstr(str);
+
+       calibrateTimer();
+       startTimer(0);
+       START_TIMER;
+       mqq160_sign(signature, hash, &key);
+       STOP_TIMER;
+       t = stopTimer();
+       ltoa(t, str, 10);
+       cli_putstr_P(PSTR("\r\n cycles for mqq160_sign:   "));
+       tmp = 12-strlen(str);
+       while(tmp--){
+               cli_putc(' ');
+       }
+       cli_putstr(str);
+
+       stack_measure_init(&smctx, 0xAA);
+       mqq160_sign_P(signature, hash, &testkey_P);
+       s1 = stack_measure_final(&smctx);
+       stack_measure_init(&smctx, 0x55);
+       mqq160_sign_P(signature, hash, &testkey_P);
+       s2 = stack_measure_final(&smctx);
+       s1 = (s1>s2)?s1:s2;
+       ltoa((long)s1, str, 10);
+       cli_putstr_P(PSTR("\r\n stack for mqq160_sign_P:  "));
+       tmp = 12-strlen(str);
+       while(tmp--){
+               cli_putc(' ');
+       }
+       cli_putstr(str);
+       stack_measure_init(&smctx, 0xAA);
+       mqq160_sign(signature, hash, &key);
+       s1 = stack_measure_final(&smctx);
+       stack_measure_init(&smctx, 0x55);
+       mqq160_sign_P(signature, hash, &testkey_P);
+       s2 = stack_measure_final(&smctx);
+       s1 = (s1>s2)?s1:s2;
+       ltoa((long)s1, str, 10);
+       cli_putstr_P(PSTR("\r\n stack for mqq160_sign:    "));
+       tmp = 12-strlen(str);
+       while(tmp--){
+               cli_putc(' ');
+       }
+       cli_putstr(str);
+
+       cli_putstr_P(PSTR("\r\n=== End of performance figures ==="));
+}
+
+void testrun_mqq_mem(void){
+       uint8_t hash[20];
+       uint8_t signature[20];
+       memcpy_P(hash, test_hash, 20);
+
+       uint8_t key_buffer[MQQ160SIGN_KEY_SIZE];
+       mqq160_sign_key_t key;
+       mqq_load_pgm_key(key_buffer, &key, &testkey_P);
+       mqq160_sign(signature, hash, &key);
+       cli_putstr_P(PSTR("\r\ntest signature (RAM):   "));
+       cli_hexdump(signature, 20);
+}
+
+void testrun_mqq_flash(void){
+       uint8_t hash[20];
+       uint8_t signature[20];
+       memcpy_P(hash, test_hash, 20);
+
+       mqq160_sign_P(signature, hash, &testkey_P);
+       cli_putstr_P(PSTR("\r\ntest signature (FLASH): "));
+       cli_hexdump(signature, 20);
+}
+
+void testrun_mqq(void){
+       uint8_t hash[20];
+       uint8_t signature[20];
+       memcpy_P(hash, test_hash, 20);
+
+       uint8_t key_buffer[MQQ160SIGN_KEY_SIZE];
+       mqq160_sign_key_t key;
+       mqq_load_pgm_key(key_buffer, &key, &testkey_P);
+       mqq160_sign(signature, hash, &key);
+       cli_putstr_P(PSTR("\r\ntest signature (RAM):   "));
+       cli_hexdump(signature, 20);
+
+       mqq160_sign_P(signature, hash, &testkey_P);
+       cli_putstr_P(PSTR("\r\ntest signature (FLASH): "));
+       cli_hexdump(signature, 20);
+}
+
+/*****************************************************************************
+ *  main                                                                                                                                        *
+ *****************************************************************************/
+
+const char test_str[]        PROGMEM = "test";
+const char test_flash_str[]  PROGMEM = "flash";
+const char test_mem_str[]    PROGMEM = "mem";
+const char performance_str[] PROGMEM = "performance";
+const char echo_str[]        PROGMEM = "echo";
+
+cmdlist_entry_t cmdlist[] PROGMEM = {
+       { test_str,                    NULL, testrun_mqq                   },
+       { test_flash_str,              NULL, testrun_mqq_flash             },
+       { test_mem_str,                NULL, testrun_mqq_mem               },
+       { performance_str,             NULL, performance_mqq               },
+       { echo_str,                (void*)1, (void_fpt)echo_ctrl           },
+       { NULL,                        NULL, NULL                          }
+};
+
+int main (void){
+       DEBUG_INIT();
+
+       cli_rx = (cli_rx_fpt)uart0_getc;
+       cli_tx = (cli_tx_fpt)uart0_putc;
+       for(;;){
+               cli_putstr_P(PSTR("\r\n\r\nCrypto-VS ("));
+               cli_putstr(algo_name);
+               cli_putstr_P(PSTR("; "));
+               cli_putstr(__DATE__);
+               cli_putstr_P(PSTR(" "));
+               cli_putstr(__TIME__);
+               cli_putstr_P(PSTR(")\r\nloaded and running\r\n"));
+
+               cmd_interface(cmdlist);
+       }
+}