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