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);
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
--- /dev/null
+# 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
+
--- /dev/null
+# 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
+
--- /dev/null
+/* 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+#ifndef MEMXOR_H_
+#define MEMXOR_H_
+#include <stdint.h>
+
+void memxor(void* dest, const void* src, uint16_t n);
+
+#endif
--- /dev/null
+/* 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
+
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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
+
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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;
+
+}
+
--- /dev/null
+/* 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_ */
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);
--- /dev/null
+/* 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);
+ }
+}