Pigweed
 
Loading...
Searching...
No Matches
xor_shift.h
1// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <algorithm>
17#include <cstdint>
18#include <cstring>
19
20#include "pw_assert/check.h"
21#include "pw_bytes/span.h"
22#include "pw_random/random.h"
23#include "pw_span/span.h"
24#include "pw_status/status_with_size.h"
25
26namespace pw::random {
27
50 public:
51 XorShiftStarRng64(uint64_t initial_seed) : state_(initial_seed) {}
52
57 void Get(ByteSpan dest) final {
58 while (!dest.empty()) {
59 uint64_t random = Regenerate();
60 size_t copy_size = std::min(dest.size_bytes(), sizeof(state_));
61 std::memcpy(dest.data(), &random, copy_size);
62 dest = dest.subspan(copy_size);
63 }
64 }
65
71 void InjectEntropyBits(uint32_t data, uint_fast8_t num_bits) final {
72 if (num_bits == 0) {
73 return;
74 } else if (num_bits > 32) {
75 num_bits = 32;
76 }
77
78 // Rotate state.
79 uint64_t untouched_state = state_ >> (kNumStateBits - num_bits);
80 state_ = untouched_state | (state_ << num_bits);
81 // Zero-out all irrelevant bits, then XOR entropy into state.
82 uint32_t mask =
83 static_cast<uint32_t>((static_cast<uint64_t>(1) << num_bits) - 1);
84 state_ ^= (data & mask);
85 }
86
87 private:
88 // Calculate and return the next value based on the "xorshift*" algorithm
89 uint64_t Regenerate() {
90 // State must be nonzero, or the algorithm will get stuck and always return
91 // zero.
92 if (state_ == 0) {
93 state_--;
94 }
95 state_ ^= state_ >> 12;
96 state_ ^= state_ << 25;
97 state_ ^= state_ >> 27;
98 return state_ * kMultConst;
99 }
100 uint64_t state_;
101 static constexpr uint8_t kNumStateBits = sizeof(state_) * 8;
102
103 // For information on why this constant was selected, see:
104 // https://www.jstatsoft.org/article/view/v008i14
105 // http://vigna.di.unimi.it/ftp/papers/xorshift.pdf
106 static constexpr uint64_t kMultConst = 0x2545F4914F6CDD1D;
107};
108
109} // namespace pw::random
Definition: random.h:34
Definition: xor_shift.h:49
void InjectEntropyBits(uint32_t data, uint_fast8_t num_bits) final
Definition: xor_shift.h:71
void Get(ByteSpan dest) final
Definition: xor_shift.h:57