66// Licensed under the Apache License, Version 2.0 (the "License");
77// you may not use this file except in compliance with the License.
88// You may obtain a copy of the License at
9- //
9+ //
1010// http://www.apache.org/licenses/LICENSE-2.0
11- //
11+ //
1212// Unless required by applicable law or agreed to in writing, software
1313// distributed under the License is distributed on an "AS IS" BASIS,
1414// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515// See the License for the specific language governing permissions and
1616// limitations under the License.
1717
1818#include < kernel/rng.hpp>
19- #include < kernel/rdrand.hpp>
2019#include < kernel/cpuid.hpp>
20+ #include < kernel/os.hpp>
21+ #include < kernel/rdrand.hpp>
2122#include < algorithm>
2223#include < cstring>
24+ #include < smp>
2325
24- static uint64_t rng_state[25 ];
26+ struct rng_state
27+ {
28+ uint64_t state[25 ];
29+ };
30+ static SMP_ARRAY<rng_state> rng;
2531
2632static inline uint64_t rotate_left (uint64_t input, size_t rot) {
2733 return (input << rot) | (input >> (64 -rot));
@@ -125,10 +131,10 @@ void rng_absorb(const void* input, size_t bytes)
125131 size_t absorbing = std::min<size_t >(bytes - absorbed, SHAKE_128_RATE);
126132
127133 xor_bytes (static_cast <const uint8_t *>(input) + absorbed,
128- reinterpret_cast <uint8_t *>(rng_state ),
134+ reinterpret_cast <uint8_t *>(PER_CPU (rng). state ),
129135 absorbing);
130136
131- keccak_1600_p (rng_state );
137+ keccak_1600_p (PER_CPU (rng). state );
132138 absorbed += absorbing;
133139 }
134140 }
@@ -140,8 +146,32 @@ void rng_extract(void* output, size_t bytes)
140146 while (copied < bytes)
141147 {
142148 size_t copying = std::min<size_t >(bytes - copied, SHAKE_128_RATE);
143- memcpy (static_cast <uint8_t *>(output) + copied, rng_state , copying);
144- keccak_1600_p (rng_state );
149+ memcpy (static_cast <uint8_t *>(output) + copied, PER_CPU (rng). state , copying);
150+ keccak_1600_p (PER_CPU (rng). state );
145151 copied += copying;
146152 }
147153 }
154+
155+ void RNG::init ()
156+ {
157+ // initialize random seed based on cycles since start
158+ if (CPUID::has_feature (CPUID::Feature::RDRAND)) {
159+ uint32_t rdrand_output[32 ];
160+
161+ for (size_t i = 0 ; i != 32 ; ++i) {
162+ while (!rdrand32 (&rdrand_output[i])) {}
163+ }
164+
165+ rng_absorb (rdrand_output, sizeof (rdrand_output));
166+ }
167+ else {
168+ // this is horrible, better solution needed here
169+ for (size_t i = 0 ; i != 32 ; ++i) {
170+ uint64_t clock = OS::cycles_since_boot ();
171+ // maybe additionally call something which will take
172+ // variable time depending in some way on the processor
173+ // state (clflush?) or a HAVEGE-like approach.
174+ rng_absorb (&clock, sizeof (clock));
175+ }
176+ }
177+ }
0 commit comments