1/* Copyright (c) 1998,2011,2014 Apple Inc.  All Rights Reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
7 * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * FeeRandom.c - generic, portable random number generator object
12 *
13 * Revision History
14 * ----------------
15 * 10/06/98		ap
16 *	Changed to compile with C++.
17 * 19 Jun 97 at Apple
18 *	Eliminated predictability of bytes 4 thru 15 of random data
19 * 18 Jun 97 at Apple
20 *	Reduced size of per-instance giants from 128 to 32 shorts
21 * 23 Aug 96 at NeXT
22 *	Created, based on Blaine Garst's NSRandomNumberGenerator class
23 */
24
25#include "feeRandom.h"
26#include "giantIntegers.h"
27#include "elliptic.h"
28#include "falloc.h"
29#include "feeDebug.h"
30#include "byteRep.h"
31#include <stdlib.h>
32#include "platform.h"
33
34/*
35 * 1 ==> do extra nextNum on feeRandAllocWithSeed()
36 */
37#define EXTRA_NEXT_NUM	0
38
39#define RANDBITS			128		/* must be 0 mod GIANT_BITS_PER_DIGIT */
40#define RAND_GIANT_DIGITS	(RANDBITS/GIANT_BITS_PER_DIGIT)
41
42typedef struct {
43	giant A;
44	giant C;
45	giant SEED;
46	giant x;
47} randInst;
48
49#if		GIANTS_VIA_STACK
50
51/*
52 * Prime the curveParams and giants modules for quick allocs of giants.
53 */
54static int giantsInitd = 0;
55
56static void feeRandInitGiants()
57{
58	if(giantsInitd) {
59		return;
60	}
61	curveParamsInitGiants();
62	giantsInitd = 1;
63}
64#endif
65
66static void pmod(giant x, int bits) {
67	/* Force x to be x (mod 2^bits). */
68	int j;
69	int digits = bits / GIANT_BITS_PER_DIGIT;
70
71	for(j = (digits-1); j >= 0; j--) {
72		if(x->n[j] != 0) break;
73	}
74	x->sign = j+1;
75}
76
77
78feeRand feeRandAllocWithSeed(unsigned seed)
79{
80	randInst *rinst = (randInst *) fmalloc(sizeof(randInst));
81	int digits = RAND_GIANT_DIGITS * 4;
82	unsigned j;
83
84	#if		GIANTS_VIA_STACK
85	feeRandInitGiants();
86	#endif
87	rinst->SEED = newGiant(digits);
88	rinst->C    = newGiant(digits);
89	rinst->A    = newGiant(digits);
90	rinst->x    = newGiant(digits);
91	rinst->C->sign = rinst->A->sign = rinst->SEED->sign = RAND_GIANT_DIGITS;
92	for(j=0; j<RAND_GIANT_DIGITS; j++) {
93	    rinst->C->n[j]    = (giantDigit)(seed + 0xdddddddd - j);
94	    rinst->A->n[j]    = (giantDigit)(seed + 0xfff12223 + j);
95	    rinst->SEED->n[j] = (giantDigit)(seed + j);
96	}
97
98	/*
99	 * on the first feeRandBytes or feeRandNextNum, bytes 4 and 5 of
100	 * the result are duplicated 4.5 times (up to byte 15). Subsequent
101	 * data is indeed random. Thus...
102	 */
103	#if	EXTRA_NEXT_NUM
104	feeRandNextNum(rinst);
105	#endif	// EXTRA_NEXT_NUM
106	return rinst;
107}
108
109feeRand feeRandAlloc(void)
110{
111	return feeRandAllocWithSeed(createRandomSeed());
112}
113
114void feeRandFree(feeRand frand)
115{
116	randInst *rinst = (randInst *) frand;
117
118	clearGiant(rinst->A);
119	freeGiant(rinst->A);
120	clearGiant(rinst->C);
121	freeGiant(rinst->C);
122	clearGiant(rinst->SEED);
123	freeGiant(rinst->SEED);
124	clearGiant(rinst->x);
125	freeGiant(rinst->x);
126	ffree(rinst);
127}
128
129unsigned feeRandNextNum(feeRand frand)
130{
131	randInst *rinst = (randInst *) frand;
132	unsigned rtn;
133
134	mulg(rinst->A, rinst->SEED);
135	addg(rinst->C, rinst->SEED);
136	pmod(rinst->SEED, RANDBITS);
137	gtog(rinst->SEED, rinst->x);
138
139	/*
140	 * FIXME - this is not quite correct; rinst->x only has 4 bytes
141	 * of valid data if RANDBITS is known to be greater than or equal
142	 * to 32.
143	 */
144	rtn = byteRepToInt((unsigned char *)&rinst->x->n);
145	return rtn;
146}
147
148void feeRandBytes(feeRand frand,
149	unsigned char *bytes,		/* must be alloc'd by caller */
150	unsigned numBytes)
151{
152	randInst *rinst = (randInst *) frand;
153	int length;
154   	unsigned toCopy;
155	unsigned char *cp = bytes;
156
157	for (length = numBytes; length > 0; length -= RANDBITS/8) {
158		mulg(rinst->A, rinst->SEED);
159		addg(rinst->C, rinst->SEED);
160		pmod(rinst->SEED, RANDBITS);
161		gtog(rinst->SEED, rinst->x);
162
163		toCopy = RANDBITS/8;
164		if(length < toCopy) {
165			toCopy = length;
166		}
167
168		/*
169		 * FIXME - not 100% platform independent....
170		 */
171		bcopy(rinst->x->n, cp, toCopy);
172		cp += toCopy;
173	}
174}
175
176/* new function, 5 March 1999 - dmitch */
177void feeRandAddEntropy(feeRand frand, unsigned entropy)
178{
179        randInst *rinst = (randInst *) frand;
180        giant tmp = borrowGiant(RAND_GIANT_DIGITS);
181	unsigned i;
182
183	if(entropy == 0) {
184		/* boy would that be a mistake */
185		entropy = 0x12345;
186	}
187	for(i=0; i<RAND_GIANT_DIGITS; i++) {
188		tmp->n[i] = (giantDigit)entropy;
189	}
190	tmp->sign = RAND_GIANT_DIGITS;
191        mulg(tmp, rinst->SEED);
192        addg(rinst->C, rinst->SEED);
193        pmod(rinst->SEED, RANDBITS);
194        entropy ^= 0xff0ff0ff;
195	if(entropy == 0) {
196		entropy = 0x12345;
197	}
198 	for(i=0; i<RAND_GIANT_DIGITS; i++) {
199		tmp->n[i] = (giantDigit)entropy;
200	}
201       	mulg(tmp, rinst->A);
202        addg(rinst->C, rinst->A);
203        pmod(rinst->A, RANDBITS);
204        /* leave C alone */
205       	returnGiant(tmp);
206}
207