random: integrate the random module into the wizard
[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 <sec/util.h>
52 #include <cfg/compiler.h>
53 #include <cfg/macros.h>
54 #include <string.h>
55
56 typedef uint32_t ub4;
57 typedef uint16_t ub2;
58 typedef uint8_t ub1;
59
60 #define ind(mm,x)  (*(ub4 *)((ub1 *)(mm) + ((x) & ((CONFIG_ISAAC_RANDSIZ-1)<<2))))
61 #define rngstep(mix,a,b,mm,m,m2,r,x) \
62 { \
63   x = *m;  \
64   a = (a^(mix)) + *(m2++); \
65   *(m++) = y = ind(mm,x) + a + b; \
66   *(r++) = b = ind(mm,y>>CONFIG_ISAAC_RANDSIZL) + x; \
67 }
68
69 static void isaac(IsaacContext *ctx)
70 {
71         register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend;
72         mm=ctx->randmem; r=ctx->randrsl;
73         a = ctx->randa; b = ctx->randb + (++ctx->randc);
74         for (m = mm, mend = m2 = m+(CONFIG_ISAAC_RANDSIZ/2); m<mend; )
75         {
76                 rngstep( a<<13, a, b, mm, m, m2, r, x);
77                 rngstep( a>>6 , a, b, mm, m, m2, r, x);
78                 rngstep( a<<2 , a, b, mm, m, m2, r, x);
79                 rngstep( a>>16, a, b, mm, m, m2, r, x);
80         }
81         for (m2 = mm; m2<mend; )
82         {
83                 rngstep( a<<13, a, b, mm, m, m2, r, x);
84                 rngstep( a>>6 , a, b, mm, m, m2, r, x);
85                 rngstep( a<<2 , a, b, mm, m, m2, r, x);
86                 rngstep( a>>16, a, b, mm, m, m2, r, x);
87         }
88         ctx->randb = b; ctx->randa = a;
89 }
90
91
92 #define mix(a,b,c,d,e,f,g,h) \
93 { \
94    a^=b<<11; d+=a; b+=c; \
95    b^=c>>2;  e+=b; c+=d; \
96    c^=d<<8;  f+=c; d+=e; \
97    d^=e>>16; g+=d; e+=f; \
98    e^=f<<10; h+=e; f+=g; \
99    f^=g>>4;  a+=f; g+=h; \
100    g^=h<<8;  b+=g; h+=a; \
101    h^=a>>9;  c+=h; a+=b; \
102 }
103
104 static void isaac_reseed(PRNG *ctx_, const uint8_t *seed)
105 {
106         IsaacContext *ctx = (IsaacContext *)ctx_;
107         int i;
108         ub4 a,b,c,d,e,f,g,h;
109         ub4 *m,*r;
110
111         // XOR the new seed over the current state, so to depend on
112         // the previously-generated output.
113         xor_block(ctx->randrsl, ctx->randrsl, seed, sizeof(ctx->randrsl));
114
115         ctx->randa = ctx->randb = ctx->randc = 0;
116         m=ctx->randmem;
117         r=ctx->randrsl;
118         a=b=c=d=e=f=g=h=0x9e3779b9;  /* the golden ratio */
119
120         for (i=0; i<4; ++i)          /* scramble it */
121         {
122                 mix(a,b,c,d,e,f,g,h);
123         }
124
125         /* initialize using the contents of r[] as the seed */
126         for (i=0; i<CONFIG_ISAAC_RANDSIZ; i+=8)
127         {
128                 a+=r[i  ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
129                 e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
130                 mix(a,b,c,d,e,f,g,h);
131                 m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
132                 m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
133         }
134         /* do a second pass to make all of the seed affect all of m */
135         for (i=0; i<CONFIG_ISAAC_RANDSIZ; i+=8)
136         {
137                 a+=m[i  ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
138                 e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
139                 mix(a,b,c,d,e,f,g,h);
140                 m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
141                 m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
142         }
143 }
144
145 static void isaac_generate(PRNG *ctx_, uint8_t *data, size_t len)
146 {
147         IsaacContext *ctx = (IsaacContext *)ctx_;
148
149         STATIC_ASSERT(sizeof(ctx->randrsl) == CONFIG_ISAAC_RANDSIZ*4);
150
151         while (len)
152         {
153                 ASSERT(ctx->randcnt <= CONFIG_ISAAC_RANDSIZ*4);
154
155                 if (ctx->randcnt == CONFIG_ISAAC_RANDSIZ*4)
156                 {
157                         isaac(ctx);
158                         ctx->randcnt = 0;
159                 }
160
161                 size_t L = MIN(len, CONFIG_ISAAC_RANDSIZ*4 - (size_t)ctx->randcnt);
162                 memcpy(data, (uint8_t*)ctx->randrsl + ctx->randcnt, L);
163                 data += L;
164                 ctx->randcnt += L;
165                 len -= L;
166         }
167 }
168
169
170 /**********************************************************************/
171
172 void isaac_init(IsaacContext *ctx)
173 {
174         ctx->prng.reseed = isaac_reseed;
175         ctx->prng.generate = isaac_generate;
176         ctx->prng.seed_len = sizeof(ctx->randrsl);
177         ctx->prng.seeded = 0;
178
179         ctx->randcnt = CONFIG_ISAAC_RANDSIZ*4;
180         memset(ctx->randrsl, 0, sizeof(ctx->randrsl));
181 }
182
183
184
185
186 #ifdef NEVER
187 int main()
188 {
189   ub4 i,j;
190   randctx ctx;
191   ctx.randa=ctx.randb=ctx.randc=(ub4)0;
192   for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0;
193   randinit(&ctx, TRUE);
194   for (i=0; i<2; ++i)
195   {
196     isaac(&ctx);
197     for (j=0; j<256; ++j)
198     {
199       printf("%.8lx",ctx.randrsl[j]);
200       if ((j&7)==7) printf("\n");
201     }
202   }
203 }
204 #endif