1*e8337330SNina Schoetterl-Glausch // SPDX-License-Identifier: GPL-2.0-only
2*e8337330SNina Schoetterl-Glausch /*
3*e8337330SNina Schoetterl-Glausch * (pseudo) random functions
4*e8337330SNina Schoetterl-Glausch * Currently uses SHA-256 to scramble the PRNG state.
5*e8337330SNina Schoetterl-Glausch *
6*e8337330SNina Schoetterl-Glausch * Copyright IBM Corp. 2024
7*e8337330SNina Schoetterl-Glausch */
8*e8337330SNina Schoetterl-Glausch
9*e8337330SNina Schoetterl-Glausch #include "libcflat.h"
10*e8337330SNina Schoetterl-Glausch #include "rand.h"
11*e8337330SNina Schoetterl-Glausch #include <string.h>
12*e8337330SNina Schoetterl-Glausch
13*e8337330SNina Schoetterl-Glausch /* Begin SHA-256 related definitions */
14*e8337330SNina Schoetterl-Glausch
15*e8337330SNina Schoetterl-Glausch #define INITAL_HASH { \
16*e8337330SNina Schoetterl-Glausch 0x6a09e667, \
17*e8337330SNina Schoetterl-Glausch 0xbb67ae85, \
18*e8337330SNina Schoetterl-Glausch 0x3c6ef372, \
19*e8337330SNina Schoetterl-Glausch 0xa54ff53a, \
20*e8337330SNina Schoetterl-Glausch 0x510e527f, \
21*e8337330SNina Schoetterl-Glausch 0x9b05688c, \
22*e8337330SNina Schoetterl-Glausch 0x1f83d9ab, \
23*e8337330SNina Schoetterl-Glausch 0x5be0cd19, \
24*e8337330SNina Schoetterl-Glausch }
25*e8337330SNina Schoetterl-Glausch
26*e8337330SNina Schoetterl-Glausch static const uint32_t K[] = {
27*e8337330SNina Schoetterl-Glausch 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
28*e8337330SNina Schoetterl-Glausch 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
29*e8337330SNina Schoetterl-Glausch 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
30*e8337330SNina Schoetterl-Glausch 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
31*e8337330SNina Schoetterl-Glausch 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
32*e8337330SNina Schoetterl-Glausch 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
33*e8337330SNina Schoetterl-Glausch 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
34*e8337330SNina Schoetterl-Glausch 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
35*e8337330SNina Schoetterl-Glausch };
36*e8337330SNina Schoetterl-Glausch
ch(uint32_t x,uint32_t y,uint32_t z)37*e8337330SNina Schoetterl-Glausch static inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z)
38*e8337330SNina Schoetterl-Glausch {
39*e8337330SNina Schoetterl-Glausch return (x & y) ^ ((~x) & z);
40*e8337330SNina Schoetterl-Glausch }
41*e8337330SNina Schoetterl-Glausch
maj(uint32_t x,uint32_t y,uint32_t z)42*e8337330SNina Schoetterl-Glausch static inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
43*e8337330SNina Schoetterl-Glausch {
44*e8337330SNina Schoetterl-Glausch return (x & y) ^ (x & z) ^ (y & z);
45*e8337330SNina Schoetterl-Glausch }
46*e8337330SNina Schoetterl-Glausch
rot(uint32_t value,unsigned int count)47*e8337330SNina Schoetterl-Glausch static inline uint32_t rot(uint32_t value, unsigned int count)
48*e8337330SNina Schoetterl-Glausch {
49*e8337330SNina Schoetterl-Glausch return value >> count | value << (32 - count);
50*e8337330SNina Schoetterl-Glausch }
51*e8337330SNina Schoetterl-Glausch
upper_sig0(uint32_t x)52*e8337330SNina Schoetterl-Glausch static inline uint32_t upper_sig0(uint32_t x)
53*e8337330SNina Schoetterl-Glausch {
54*e8337330SNina Schoetterl-Glausch return rot(x, 2) ^ rot(x, 13) ^ rot(x, 22);
55*e8337330SNina Schoetterl-Glausch }
56*e8337330SNina Schoetterl-Glausch
upper_sig1(uint32_t x)57*e8337330SNina Schoetterl-Glausch static inline uint32_t upper_sig1(uint32_t x)
58*e8337330SNina Schoetterl-Glausch {
59*e8337330SNina Schoetterl-Glausch return rot(x, 6) ^ rot(x, 11) ^ rot(x, 25);
60*e8337330SNina Schoetterl-Glausch }
61*e8337330SNina Schoetterl-Glausch
lower_sig0(uint32_t x)62*e8337330SNina Schoetterl-Glausch static inline uint32_t lower_sig0(uint32_t x)
63*e8337330SNina Schoetterl-Glausch {
64*e8337330SNina Schoetterl-Glausch return rot(x, 7) ^ rot(x, 18) ^ (x >> 3);
65*e8337330SNina Schoetterl-Glausch }
66*e8337330SNina Schoetterl-Glausch
lower_sig1(uint32_t x)67*e8337330SNina Schoetterl-Glausch static inline uint32_t lower_sig1(uint32_t x)
68*e8337330SNina Schoetterl-Glausch {
69*e8337330SNina Schoetterl-Glausch return rot(x, 17) ^ rot(x, 19) ^ (x >> 10);
70*e8337330SNina Schoetterl-Glausch }
71*e8337330SNina Schoetterl-Glausch
72*e8337330SNina Schoetterl-Glausch enum alphabet { A, B, C, D, E, F, G, H, };
73*e8337330SNina Schoetterl-Glausch
sha256_chunk(const uint32_t (* chunk)[16],uint32_t (* hash)[8])74*e8337330SNina Schoetterl-Glausch static void sha256_chunk(const uint32_t (*chunk)[16], uint32_t (*hash)[8])
75*e8337330SNina Schoetterl-Glausch {
76*e8337330SNina Schoetterl-Glausch uint32_t w[64];
77*e8337330SNina Schoetterl-Glausch uint32_t w_hash[8];
78*e8337330SNina Schoetterl-Glausch
79*e8337330SNina Schoetterl-Glausch memcpy(w, chunk, sizeof(*chunk));
80*e8337330SNina Schoetterl-Glausch
81*e8337330SNina Schoetterl-Glausch for (int i = 16; i < 64; i++)
82*e8337330SNina Schoetterl-Glausch w[i] = lower_sig1(w[i - 2]) + w[i - 7] + lower_sig0(w[i - 15]) + w[i - 16];
83*e8337330SNina Schoetterl-Glausch
84*e8337330SNina Schoetterl-Glausch memcpy(w_hash, hash, sizeof(*hash));
85*e8337330SNina Schoetterl-Glausch
86*e8337330SNina Schoetterl-Glausch for (int i = 0; i < 64; i++) {
87*e8337330SNina Schoetterl-Glausch uint32_t t1, t2;
88*e8337330SNina Schoetterl-Glausch
89*e8337330SNina Schoetterl-Glausch t1 = w_hash[H] +
90*e8337330SNina Schoetterl-Glausch upper_sig1(w_hash[E]) +
91*e8337330SNina Schoetterl-Glausch ch(w_hash[E], w_hash[F], w_hash[G]) +
92*e8337330SNina Schoetterl-Glausch K[i] +
93*e8337330SNina Schoetterl-Glausch w[i];
94*e8337330SNina Schoetterl-Glausch
95*e8337330SNina Schoetterl-Glausch t2 = upper_sig0(w_hash[A]) + maj(w_hash[A], w_hash[B], w_hash[C]);
96*e8337330SNina Schoetterl-Glausch
97*e8337330SNina Schoetterl-Glausch w_hash[H] = w_hash[G];
98*e8337330SNina Schoetterl-Glausch w_hash[G] = w_hash[F];
99*e8337330SNina Schoetterl-Glausch w_hash[F] = w_hash[E];
100*e8337330SNina Schoetterl-Glausch w_hash[E] = w_hash[D] + t1;
101*e8337330SNina Schoetterl-Glausch w_hash[D] = w_hash[C];
102*e8337330SNina Schoetterl-Glausch w_hash[C] = w_hash[B];
103*e8337330SNina Schoetterl-Glausch w_hash[B] = w_hash[A];
104*e8337330SNina Schoetterl-Glausch w_hash[A] = t1 + t2;
105*e8337330SNina Schoetterl-Glausch }
106*e8337330SNina Schoetterl-Glausch
107*e8337330SNina Schoetterl-Glausch for (int i = 0; i < 8; i++)
108*e8337330SNina Schoetterl-Glausch (*hash)[i] += w_hash[i];
109*e8337330SNina Schoetterl-Glausch }
110*e8337330SNina Schoetterl-Glausch
111*e8337330SNina Schoetterl-Glausch /**
112*e8337330SNina Schoetterl-Glausch * sha256_hash - Calculate SHA-256 of input. Only a limited subset of inputs supported.
113*e8337330SNina Schoetterl-Glausch * @n: Number of words to hash, must be <= 13
114*e8337330SNina Schoetterl-Glausch * @input: Input data to hash
115*e8337330SNina Schoetterl-Glausch * @hash: Output hash as a word array, ordered such that the first word contains
116*e8337330SNina Schoetterl-Glausch * the first/leftmost bits of the 256 bit hash
117*e8337330SNina Schoetterl-Glausch *
118*e8337330SNina Schoetterl-Glausch * Calculate the SHA-256 hash of the input where the input must be a multiple of
119*e8337330SNina Schoetterl-Glausch * 4 bytes and at most 52 long. The input is used without any adjustment, so,
120*e8337330SNina Schoetterl-Glausch * should the caller want to hash bytes it needs to interpret the bytes in the
121*e8337330SNina Schoetterl-Glausch * ordering as defined by the specification, that is big endian.
122*e8337330SNina Schoetterl-Glausch * The same applies to interpreting the output array as bytes.
123*e8337330SNina Schoetterl-Glausch * The function computes the same as: printf "%08x" ${input[@]} | xxd -r -p | sha256sum .
124*e8337330SNina Schoetterl-Glausch */
sha256_hash(unsigned int n,const uint32_t (* input)[n],uint32_t (* hash)[8])125*e8337330SNina Schoetterl-Glausch static void sha256_hash(unsigned int n, const uint32_t (*input)[n], uint32_t (*hash)[8])
126*e8337330SNina Schoetterl-Glausch {
127*e8337330SNina Schoetterl-Glausch /*
128*e8337330SNina Schoetterl-Glausch * Pad according to SHA-2 specification.
129*e8337330SNina Schoetterl-Glausch * First set up length in bits.
130*e8337330SNina Schoetterl-Glausch */
131*e8337330SNina Schoetterl-Glausch uint32_t chunk[16] = {
132*e8337330SNina Schoetterl-Glausch [15] = sizeof(*input) * 8,
133*e8337330SNina Schoetterl-Glausch };
134*e8337330SNina Schoetterl-Glausch
135*e8337330SNina Schoetterl-Glausch memcpy(chunk, input, sizeof(*input));
136*e8337330SNina Schoetterl-Glausch /* Then add separator */
137*e8337330SNina Schoetterl-Glausch chunk[n] = 1 << 31;
138*e8337330SNina Schoetterl-Glausch memcpy(hash, (uint32_t[])INITAL_HASH, sizeof(*hash));
139*e8337330SNina Schoetterl-Glausch sha256_chunk(&chunk, hash);
140*e8337330SNina Schoetterl-Glausch }
141*e8337330SNina Schoetterl-Glausch
142*e8337330SNina Schoetterl-Glausch /* End SHA-256 related definitions */
143*e8337330SNina Schoetterl-Glausch
prng_init(uint64_t seed)144*e8337330SNina Schoetterl-Glausch prng_state prng_init(uint64_t seed)
145*e8337330SNina Schoetterl-Glausch {
146*e8337330SNina Schoetterl-Glausch prng_state state = { .next_word = 0 };
147*e8337330SNina Schoetterl-Glausch uint32_t seed_arr[2] = { seed >> 32, seed };
148*e8337330SNina Schoetterl-Glausch
149*e8337330SNina Schoetterl-Glausch sha256_hash(ARRAY_SIZE(seed_arr), &seed_arr, &state.hash);
150*e8337330SNina Schoetterl-Glausch return state;
151*e8337330SNina Schoetterl-Glausch }
152*e8337330SNina Schoetterl-Glausch
prng_scramble(prng_state * state)153*e8337330SNina Schoetterl-Glausch static void prng_scramble(prng_state *state)
154*e8337330SNina Schoetterl-Glausch {
155*e8337330SNina Schoetterl-Glausch uint32_t input[8];
156*e8337330SNina Schoetterl-Glausch
157*e8337330SNina Schoetterl-Glausch memcpy(input, state->hash, sizeof(state->hash));
158*e8337330SNina Schoetterl-Glausch sha256_hash(ARRAY_SIZE(input), &input, &state->hash);
159*e8337330SNina Schoetterl-Glausch state->next_word = 0;
160*e8337330SNina Schoetterl-Glausch }
161*e8337330SNina Schoetterl-Glausch
prng32(prng_state * state)162*e8337330SNina Schoetterl-Glausch uint32_t prng32(prng_state *state)
163*e8337330SNina Schoetterl-Glausch {
164*e8337330SNina Schoetterl-Glausch if (state->next_word < ARRAY_SIZE(state->hash))
165*e8337330SNina Schoetterl-Glausch return state->hash[state->next_word++];
166*e8337330SNina Schoetterl-Glausch
167*e8337330SNina Schoetterl-Glausch prng_scramble(state);
168*e8337330SNina Schoetterl-Glausch return prng32(state);
169*e8337330SNina Schoetterl-Glausch }
170*e8337330SNina Schoetterl-Glausch
prng64(prng_state * state)171*e8337330SNina Schoetterl-Glausch uint64_t prng64(prng_state *state)
172*e8337330SNina Schoetterl-Glausch {
173*e8337330SNina Schoetterl-Glausch /* explicitly evaluate the high word first */
174*e8337330SNina Schoetterl-Glausch uint64_t high = prng32(state);
175*e8337330SNina Schoetterl-Glausch
176*e8337330SNina Schoetterl-Glausch return high << 32 | prng32(state);
177*e8337330SNina Schoetterl-Glausch }
178