SEC: make sure PRNGs are seeded before generating data. This allows
[bertos.git] / bertos / sec / prng / isaac.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief ISAAC implementation
34  * \author Giovanni Bajo <rasky@develer.com>
35  *
36  */
37
38 /*
39 ------------------------------------------------------------------------------
40 rand.c: By Bob Jenkins.  My random number generator, ISAAC.  Public Domain.
41 MODIFIED:
42   960327: Creation (addition of randinit, really)
43   970719: use context, not global variables, for internal state
44   980324: added main (ifdef'ed out), also rearranged randinit()
45   010626: Note that this is public domain
46 ------------------------------------------------------------------------------
47 */
48
49 #include "isaac.h"
50 #include <sec/prng.h>
51 #include <cfg/compiler.h>
52 #include <cfg/macros.h>
53 #include <string.h>
54
55 typedef uint32_t ub4;
56 typedef uint16_t ub2;
57 typedef uint8_t ub1;
58
59 #define ind(mm,x)  (*(ub4 *)((ub1 *)(mm) + ((x) & ((CONFIG_ISAAC_RANDSIZ-1)<<2))))
60 #define rngstep(mix,a,b,mm,m,m2,r,x) \
61 { \
62   x = *m;  \
63   a = (a^(mix)) + *(m2++); \
64   *(m++) = y = ind(mm,x) + a + b; \
65   *(r++) = b = ind(mm,y>>CONFIG_ISAAC_RANDSIZL) + x; \
66 }
67
68 static void isaac(IsaacContext *ctx)
69 {
70         register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend;
71         mm=ctx->randmem; r=ctx->randrsl;
72         a = ctx->randa; b = ctx->randb + (++ctx->randc);
73         for (m = mm, mend = m2 = m+(CONFIG_ISAAC_RANDSIZ/2); m<mend; )
74         {
75                 rngstep( a<<13, a, b, mm, m, m2, r, x);
76                 rngstep( a>>6 , a, b, mm, m, m2, r, x);
77                 rngstep( a<<2 , a, b, mm, m, m2, r, x);
78                 rngstep( a>>16, a, b, mm, m, m2, r, x);
79         }
80         for (m2 = mm; m2<mend; )
81         {
82                 rngstep( a<<13, a, b, mm, m, m2, r, x);
83                 rngstep( a>>6 , a, b, mm, m, m2, r, x);
84                 rngstep( a<<2 , a, b, mm, m, m2, r, x);
85                 rngstep( a>>16, a, b, mm, m, m2, r, x);
86         }
87         ctx->randb = b; ctx->randa = a;
88 }
89
90
91 #define mix(a,b,c,d,e,f,g,h) \
92 { \
93    a^=b<<11; d+=a; b+=c; \
94    b^=c>>2;  e+=b; c+=d; \
95    c^=d<<8;  f+=c; d+=e; \
96    d^=e>>16; g+=d; e+=f; \
97    e^=f<<10; h+=e; f+=g; \
98    f^=g>>4;  a+=f; g+=h; \
99    g^=h<<8;  b+=g; h+=a; \
100    h^=a>>9;  c+=h; a+=b; \
101 }
102
103 static void isaac_reseed(PRNG *ctx_, const uint8_t *seed)
104 {
105         IsaacContext *ctx = (IsaacContext *)ctx_;
106         int i;
107         ub4 a,b,c,d,e,f,g,h;
108         ub4 *m,*r;
109
110         // Copy seed over half of randrsl, to reuse half of last-generated
111         // data as seed.
112         memcpy(ctx->randrsl, seed, sizeof(ctx->randrsl)/2);
113
114         ctx->randa = ctx->randb = ctx->randc = 0;
115         m=ctx->randmem;
116         r=ctx->randrsl;
117         a=b=c=d=e=f=g=h=0x9e3779b9;  /* the golden ratio */
118
119         for (i=0; i<4; ++i)          /* scramble it */
120         {
121                 mix(a,b,c,d,e,f,g,h);
122         }
123
124         /* initialize using the contents of r[] as the seed */
125         for (i=0; i<CONFIG_ISAAC_RANDSIZ; i+=8)
126         {
127                 a+=r[i  ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
128                 e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
129                 mix(a,b,c,d,e,f,g,h);
130                 m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
131                 m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
132         }
133         /* do a second pass to make all of the seed affect all of m */
134         for (i=0; i<CONFIG_ISAAC_RANDSIZ; i+=8)
135         {
136                 a+=m[i  ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
137                 e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
138                 mix(a,b,c,d,e,f,g,h);
139                 m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
140                 m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
141         }
142 }
143
144 static void isaac_generate(PRNG *ctx_, uint8_t *data, size_t len)
145 {
146         IsaacContext *ctx = (IsaacContext *)ctx_;
147
148         STATIC_ASSERT(sizeof(ctx->randrsl) == CONFIG_ISAAC_RANDSIZ*4);
149
150         while (len)
151         {
152                 ASSERT(ctx->randcnt <= CONFIG_ISAAC_RANDSIZ*4);
153
154                 if (ctx->randcnt == CONFIG_ISAAC_RANDSIZ*4)
155                 {
156                         isaac(ctx);
157                         ctx->randcnt = 0;
158                 }
159
160                 size_t L = MIN(len, CONFIG_ISAAC_RANDSIZ*4 - (size_t)ctx->randcnt);
161                 memcpy(data, (uint8_t*)ctx->randrsl + ctx->randcnt, L);
162                 data += L;
163                 ctx->randcnt += L;
164                 len -= L;
165         }
166 }
167
168
169 /**********************************************************************/
170
171 void isaac_init(IsaacContext *ctx)
172 {
173         ctx->prng.reseed = isaac_reseed;
174         ctx->prng.generate = isaac_generate;
175         ctx->prng.seed_len = sizeof(ctx->randrsl) / 2;
176         ctx->prng.seeded = 0;
177
178         ctx->randcnt = CONFIG_ISAAC_RANDSIZ*4;
179         memset(ctx->randrsl, 0, sizeof(ctx->randrsl));
180 }
181
182
183
184
185 #ifdef NEVER
186 int main()
187 {
188   ub4 i,j;
189   randctx ctx;
190   ctx.randa=ctx.randb=ctx.randc=(ub4)0;
191   for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0;
192   randinit(&ctx, TRUE);
193   for (i=0; i<2; ++i)
194   {
195     isaac(&ctx);
196     for (j=0; j<256; ++j)
197     {
198       printf("%.8lx",ctx.randrsl[j]);
199       if ((j&7)==7) printf("\n");
200     }
201   }
202 }
203 #endif