Chromium Code Reviews| Index: runtime/lib/math_patch.dart |
| diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart |
| index e9cc0838082b2add865d93fa326e09ecdce43f88..285b99abe2c9a6e8b69578c90f2452b72796e254 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,30 +110,30 @@ 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 ArgumentError("max must be positive and < 2^32: $max"); |
| } |
| 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); |
| return result; |
| @@ -143,9 +147,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 +166,44 @@ 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) { |
| + // No local optimizations needed for this rather slow call. |
|
Lasse Reichstein Nielsen
2015/10/14 11:08:45
Really?
How about only asking for the number of b
regis
2015/10/14 20:22:35
By "slow", I meant it is a call to the runtime, so
|
| + if ((max <= 0) || (max > _POW2_32)) { |
| + throw new ArgumentError("max must be positive and < 2^32: $max"); |
|
Lasse Reichstein Nielsen
2015/10/14 11:08:45
< 2^32 should be <= 2^32
Use a range error for th
regis
2015/10/14 20:22:35
Done here and in class _Random above.
The inclusiv
|
| + } |
| + var rnd32; |
| + var result; |
| + do { |
| + rnd32 = _getBytes(4); |
| + result = rnd32 % max; |
| + } while ((rnd32 - result + max) >= _POW2_32); |
|
Lasse Reichstein Nielsen
2015/10/14 11:08:45
Should >= be > ?
If max is a power of 2 and rnd32
regis
2015/10/14 20:22:35
Agreed.
Actually, it made it impossible to use a m
|
| + 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); |
| +} |
| + |