more mqq stuff

This commit is contained in:
bg 2010-03-29 09:27:25 +00:00
parent c9c11514d9
commit 056b130e81
17 changed files with 2196 additions and 11 deletions

View 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);

View 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

12
mkfiles/mqq160-sign.mk Normal file
View File

@ -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

12
mkfiles/mqq160-sign_c.mk Normal file
View File

@ -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

66
mqq-sign/memxor.S Normal file
View File

@ -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

7
mqq-sign/memxor.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef MEMXOR_H_
#define MEMXOR_H_
#include <stdint.h>
void memxor(void* dest, const void* src, uint16_t n);
#endif

540
mqq-sign/mqq160-sign-asm.S Normal file
View File

@ -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

199
mqq-sign/mqq160-sign.c Normal file
View File

@ -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);
}

33
mqq-sign/mqq160-sign.h Normal file
View File

@ -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_ */

View File

@ -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

View File

@ -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);
}

217
mqq-sign/mqq160-sign_P.c Normal file
View File

@ -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);
}

27
mqq-sign/mqq160-sign_P.h Normal file
View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View 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);

View File

@ -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);
}
}