Index: runtime/lib/math_patch.dart |
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart |
index e9cc0838082b2add865d93fa326e09ecdce43f88..667174cc61d2c13d1595c0bcf6c0f1689938d09c 100644 |
--- a/runtime/lib/math_patch.dart |
+++ b/runtime/lib/math_patch.dart |
@@ -90,14 +90,18 @@ patch class Random { |
.._nextState() |
.._nextState(); |
} |
+ |
+ /*patch*/ factory Random.secure() { |
+ return new _SecureRandom(); |
+ } |
} |
class _Random implements Random { |
// Internal state of the random number generator. |
final _state; |
- static const kSTATE_LO = 0; |
- static const kSTATE_HI = 1; |
+ static const _kSTATE_LO = 0; |
+ static const _kSTATE_HI = 1; // Unused in Dart code. |
_Random._withState(Uint32List this._state); |
@@ -106,32 +110,33 @@ class _Random implements Random { |
// The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1. |
// Implements: |
- // var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64; |
- // _state[kSTATE_LO] = state & _MASK_32; |
- // _state[kSTATE_HI] = state >> 32; |
+ // var state = |
+ // ((_A * (_state[_kSTATE_LO])) + _state[_kSTATE_HI]) & ((1 << 64) - 1); |
+ // _state[_kSTATE_LO] = state & ((1 << 32) - 1); |
+ // _state[_kSTATE_HI] = state >> 32; |
// This is a native to prevent 64-bit operations in Dart, which |
// fail with --throw_on_javascript_int_overflow. |
void _nextState() native "Random_nextState"; |
int nextInt(int max) { |
const limit = 0x3FFFFFFF; |
- if (max <= 0 || ((max > limit) && (max > _POW2_32))) { |
- throw new ArgumentError("max must be positive and < 2^32:" |
- " $max"); |
+ if ((max <= 0) || ((max > limit) && (max > _POW2_32))) { |
+ throw new RangeError.range(max, 1, _POW2_32, "max", |
+ "Must be positive and <= 2^32"); |
} |
if ((max & -max) == max) { |
// Fast case for powers of two. |
_nextState(); |
- return _state[kSTATE_LO] & (max - 1); |
+ return _state[_kSTATE_LO] & (max - 1); |
} |
var rnd32; |
var result; |
do { |
_nextState(); |
- rnd32 = _state[kSTATE_LO]; |
+ rnd32 = _state[_kSTATE_LO]; |
result = rnd32 % max; |
- } while ((rnd32 - result + max) >= _POW2_32); |
+ } while ((rnd32 - result + max) > _POW2_32); |
return result; |
} |
@@ -143,9 +148,7 @@ class _Random implements Random { |
return nextInt(2) == 0; |
} |
- // Constants used by the algorithm or masking. |
- static const _MASK_32 = (1 << 32) - 1; |
- static const _MASK_64 = (1 << 64) - 1; |
+ // Constants used by the algorithm. |
static const _POW2_32 = 1 << 32; |
static const _POW2_53_D = 1.0 * (1 << 53); |
static const _POW2_27_D = 1.0 * (1 << 27); |
@@ -164,6 +167,46 @@ class _Random implements Random { |
static int _nextSeed() { |
// Trigger the PRNG once to change the internal state. |
_prng._nextState(); |
- return _prng._state[kSTATE_LO]; |
+ return _prng._state[_kSTATE_LO]; |
+ } |
+} |
+ |
+ |
+class _SecureRandom implements Random { |
+ _SecureRandom() { |
+ // Throw early in constructor if entropy source is not hooked up. |
+ _getBytes(1); |
+ } |
+ |
+ // Return count bytes of entropy as a positive integer; count <= 8. |
+ static int _getBytes(int count) native "SecureRandom_getBytes"; |
+ |
+ int nextInt(int max) { |
+ RangeError.checkValueInInterval( |
+ max, 1, _POW2_32, "max", "Must be positive and <= 2^32"); |
+ final byteCount = ((max - 1).bitLength + 7) >> 3; |
+ if (byteCount == 0) { |
+ return 0; // Not random if max == 1. |
+ } |
+ var rnd; |
+ var result; |
+ do { |
+ rnd = _getBytes(byteCount); |
+ result = rnd % max; |
+ } while ((rnd - result + max) > (1 << (byteCount << 3))); |
+ return result; |
+ } |
+ |
+ double nextDouble() { |
+ return (_getBytes(7) >> 3) / _POW2_53_D; |
+ } |
+ |
+ bool nextBool() { |
+ return _getBytes(1).isEven; |
} |
+ |
+ // Constants used by the algorithm. |
+ static const _POW2_32 = 1 << 32; |
+ static const _POW2_53_D = 1.0 * (1 << 53); |
} |
+ |