xref: /openbsd/usr.bin/ssh/xmss_wots.c (revision 27a1722d)
1*27a1722dSdjm /* $OpenBSD: xmss_wots.c,v 1.3 2018/04/10 00:10:49 djm Exp $ */
2a6be8e7cSmarkus /*
3a6be8e7cSmarkus wots.c version 20160722
4a6be8e7cSmarkus Andreas Hülsing
5a6be8e7cSmarkus Joost Rijneveld
6a6be8e7cSmarkus Public domain.
7a6be8e7cSmarkus */
8a6be8e7cSmarkus 
9a6be8e7cSmarkus #include <stdlib.h>
10a6be8e7cSmarkus #include <stdint.h>
11a6be8e7cSmarkus #include <limits.h>
12a6be8e7cSmarkus #include "xmss_commons.h"
13a6be8e7cSmarkus #include "xmss_hash.h"
14a6be8e7cSmarkus #include "xmss_wots.h"
15a6be8e7cSmarkus #include "xmss_hash_address.h"
16a6be8e7cSmarkus 
17a6be8e7cSmarkus 
18a6be8e7cSmarkus /* libm-free version of log2() for wots */
19a6be8e7cSmarkus static inline int
wots_log2(uint32_t v)20a6be8e7cSmarkus wots_log2(uint32_t v)
21a6be8e7cSmarkus {
22a6be8e7cSmarkus   int      b;
23a6be8e7cSmarkus 
24a6be8e7cSmarkus   for (b = sizeof (v) * CHAR_BIT - 1; b >= 0; b--) {
25a6be8e7cSmarkus     if ((1U << b) & v) {
26a6be8e7cSmarkus       return b;
27a6be8e7cSmarkus     }
28a6be8e7cSmarkus   }
29a6be8e7cSmarkus   return 0;
30a6be8e7cSmarkus }
31a6be8e7cSmarkus 
32a6be8e7cSmarkus void
wots_set_params(wots_params * params,int n,int w)33a6be8e7cSmarkus wots_set_params(wots_params *params, int n, int w)
34a6be8e7cSmarkus {
35a6be8e7cSmarkus   params->n = n;
36a6be8e7cSmarkus   params->w = w;
37a6be8e7cSmarkus   params->log_w = wots_log2(params->w);
38a6be8e7cSmarkus   params->len_1 = (CHAR_BIT * n) / params->log_w;
39a6be8e7cSmarkus   params->len_2 = (wots_log2(params->len_1 * (w - 1)) / params->log_w) + 1;
40a6be8e7cSmarkus   params->len = params->len_1 + params->len_2;
41a6be8e7cSmarkus   params->keysize = params->len * params->n;
42a6be8e7cSmarkus }
43a6be8e7cSmarkus 
44a6be8e7cSmarkus /**
45a6be8e7cSmarkus  * Helper method for pseudorandom key generation
46a6be8e7cSmarkus  * Expands an n-byte array into a len*n byte array
47a6be8e7cSmarkus  * this is done using PRF
48a6be8e7cSmarkus  */
expand_seed(unsigned char * outseeds,const unsigned char * inseed,const wots_params * params)49a6be8e7cSmarkus static void expand_seed(unsigned char *outseeds, const unsigned char *inseed, const wots_params *params)
50a6be8e7cSmarkus {
51a6be8e7cSmarkus   uint32_t i = 0;
52a6be8e7cSmarkus   unsigned char ctr[32];
53a6be8e7cSmarkus   for(i = 0; i < params->len; i++){
54a6be8e7cSmarkus     to_byte(ctr, i, 32);
55a6be8e7cSmarkus     prf((outseeds + (i*params->n)), ctr, inseed, params->n);
56a6be8e7cSmarkus   }
57a6be8e7cSmarkus }
58a6be8e7cSmarkus 
59a6be8e7cSmarkus /**
60a6be8e7cSmarkus  * Computes the chaining function.
61a6be8e7cSmarkus  * out and in have to be n-byte arrays
62a6be8e7cSmarkus  *
63*27a1722dSdjm  * interprets in as start-th value of the chain
64a6be8e7cSmarkus  * addr has to contain the address of the chain
65a6be8e7cSmarkus  */
gen_chain(unsigned char * out,const unsigned char * in,unsigned int start,unsigned int steps,const wots_params * params,const unsigned char * pub_seed,uint32_t addr[8])66a6be8e7cSmarkus static void gen_chain(unsigned char *out, const unsigned char *in, unsigned int start, unsigned int steps, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
67a6be8e7cSmarkus {
68a6be8e7cSmarkus   uint32_t i, j;
69a6be8e7cSmarkus   for (j = 0; j < params->n; j++)
70a6be8e7cSmarkus     out[j] = in[j];
71a6be8e7cSmarkus 
72a6be8e7cSmarkus   for (i = start; i < (start+steps) && i < params->w; i++) {
73a6be8e7cSmarkus     setHashADRS(addr, i);
74a6be8e7cSmarkus     hash_f(out, out, pub_seed, addr, params->n);
75a6be8e7cSmarkus   }
76a6be8e7cSmarkus }
77a6be8e7cSmarkus 
78a6be8e7cSmarkus /**
79a6be8e7cSmarkus  * base_w algorithm as described in draft.
80a6be8e7cSmarkus  *
81a6be8e7cSmarkus  *
82a6be8e7cSmarkus  */
base_w(int * output,const int out_len,const unsigned char * input,const wots_params * params)83a6be8e7cSmarkus static void base_w(int *output, const int out_len, const unsigned char *input, const wots_params *params)
84a6be8e7cSmarkus {
85a6be8e7cSmarkus   int in = 0;
86a6be8e7cSmarkus   int out = 0;
87a6be8e7cSmarkus   uint32_t total = 0;
88a6be8e7cSmarkus   int bits = 0;
89a6be8e7cSmarkus   int consumed = 0;
90a6be8e7cSmarkus 
91a6be8e7cSmarkus   for (consumed = 0; consumed < out_len; consumed++) {
92a6be8e7cSmarkus     if (bits == 0) {
93a6be8e7cSmarkus       total = input[in];
94a6be8e7cSmarkus       in++;
95a6be8e7cSmarkus       bits += 8;
96a6be8e7cSmarkus     }
97a6be8e7cSmarkus     bits -= params->log_w;
98a6be8e7cSmarkus     output[out] = (total >> bits) & (params->w - 1);
99a6be8e7cSmarkus     out++;
100a6be8e7cSmarkus   }
101a6be8e7cSmarkus }
102a6be8e7cSmarkus 
wots_pkgen(unsigned char * pk,const unsigned char * sk,const wots_params * params,const unsigned char * pub_seed,uint32_t addr[8])103a6be8e7cSmarkus void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
104a6be8e7cSmarkus {
105a6be8e7cSmarkus   uint32_t i;
106a6be8e7cSmarkus   expand_seed(pk, sk, params);
107a6be8e7cSmarkus   for (i=0; i < params->len; i++) {
108a6be8e7cSmarkus     setChainADRS(addr, i);
109a6be8e7cSmarkus     gen_chain(pk+i*params->n, pk+i*params->n, 0, params->w-1, params, pub_seed, addr);
110a6be8e7cSmarkus   }
111a6be8e7cSmarkus }
112a6be8e7cSmarkus 
113a6be8e7cSmarkus 
wots_sign(unsigned char * sig,const unsigned char * msg,const unsigned char * sk,const wots_params * params,const unsigned char * pub_seed,uint32_t addr[8])114a6be8e7cSmarkus int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
115a6be8e7cSmarkus {
116a6be8e7cSmarkus   //int basew[params->len];
117a6be8e7cSmarkus   int csum = 0;
118a6be8e7cSmarkus   uint32_t i = 0;
119a6be8e7cSmarkus   int *basew = calloc(params->len, sizeof(int));
120a6be8e7cSmarkus   if (basew == NULL)
121a6be8e7cSmarkus     return -1;
122a6be8e7cSmarkus 
123a6be8e7cSmarkus   base_w(basew, params->len_1, msg, params);
124a6be8e7cSmarkus 
125a6be8e7cSmarkus   for (i=0; i < params->len_1; i++) {
126a6be8e7cSmarkus     csum += params->w - 1 - basew[i];
127a6be8e7cSmarkus   }
128a6be8e7cSmarkus 
129a6be8e7cSmarkus   csum = csum << (8 - ((params->len_2 * params->log_w) % 8));
130a6be8e7cSmarkus 
131a6be8e7cSmarkus   int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8;
132a6be8e7cSmarkus 
133a6be8e7cSmarkus   unsigned char csum_bytes[len_2_bytes];
134a6be8e7cSmarkus   to_byte(csum_bytes, csum, len_2_bytes);
135a6be8e7cSmarkus 
136a6be8e7cSmarkus   int csum_basew[params->len_2];
137a6be8e7cSmarkus   base_w(csum_basew, params->len_2, csum_bytes, params);
138a6be8e7cSmarkus 
139a6be8e7cSmarkus   for (i = 0; i < params->len_2; i++) {
140a6be8e7cSmarkus     basew[params->len_1 + i] = csum_basew[i];
141a6be8e7cSmarkus   }
142a6be8e7cSmarkus 
143a6be8e7cSmarkus   expand_seed(sig, sk, params);
144a6be8e7cSmarkus 
145a6be8e7cSmarkus   for (i = 0; i < params->len; i++) {
146a6be8e7cSmarkus     setChainADRS(addr, i);
147a6be8e7cSmarkus     gen_chain(sig+i*params->n, sig+i*params->n, 0, basew[i], params, pub_seed, addr);
148a6be8e7cSmarkus   }
149a6be8e7cSmarkus   free(basew);
150a6be8e7cSmarkus   return 0;
151a6be8e7cSmarkus }
152a6be8e7cSmarkus 
wots_pkFromSig(unsigned char * pk,const unsigned char * sig,const unsigned char * msg,const wots_params * params,const unsigned char * pub_seed,uint32_t addr[8])153a6be8e7cSmarkus int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
154a6be8e7cSmarkus {
155a6be8e7cSmarkus   int csum = 0;
156a6be8e7cSmarkus   uint32_t i = 0;
157a6be8e7cSmarkus   int *basew = calloc(params->len, sizeof(int));
158a6be8e7cSmarkus   if (basew == NULL)
159a6be8e7cSmarkus     return -1;
160a6be8e7cSmarkus 
161a6be8e7cSmarkus   base_w(basew, params->len_1, msg, params);
162a6be8e7cSmarkus 
163a6be8e7cSmarkus   for (i=0; i < params->len_1; i++) {
164a6be8e7cSmarkus     csum += params->w - 1 - basew[i];
165a6be8e7cSmarkus   }
166a6be8e7cSmarkus 
167a6be8e7cSmarkus   csum = csum << (8 - ((params->len_2 * params->log_w) % 8));
168a6be8e7cSmarkus 
169a6be8e7cSmarkus   int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8;
170a6be8e7cSmarkus 
171a6be8e7cSmarkus   unsigned char csum_bytes[len_2_bytes];
172a6be8e7cSmarkus   to_byte(csum_bytes, csum, len_2_bytes);
173a6be8e7cSmarkus 
174a6be8e7cSmarkus   int csum_basew[params->len_2];
175a6be8e7cSmarkus   base_w(csum_basew, params->len_2, csum_bytes, params);
176a6be8e7cSmarkus 
177a6be8e7cSmarkus   for (i = 0; i < params->len_2; i++) {
178a6be8e7cSmarkus     basew[params->len_1 + i] = csum_basew[i];
179a6be8e7cSmarkus   }
180a6be8e7cSmarkus   for (i=0; i < params->len; i++) {
181a6be8e7cSmarkus     setChainADRS(addr, i);
182a6be8e7cSmarkus     gen_chain(pk+i*params->n, sig+i*params->n, basew[i], params->w-1-basew[i], params, pub_seed, addr);
183a6be8e7cSmarkus   }
184a6be8e7cSmarkus   free(basew);
185a6be8e7cSmarkus   return 0;
186a6be8e7cSmarkus }
187