diff options
Diffstat (limited to 'rand/rand_isaac')
| -rw-r--r-- | rand/rand_isaac/CHANGELOG.md | 8 | ||||
| -rw-r--r-- | rand/rand_isaac/COPYRIGHT | 12 | ||||
| -rw-r--r-- | rand/rand_isaac/Cargo.toml | 31 | ||||
| -rw-r--r-- | rand/rand_isaac/LICENSE-APACHE | 201 | ||||
| -rw-r--r-- | rand/rand_isaac/LICENSE-MIT | 26 | ||||
| -rw-r--r-- | rand/rand_isaac/README.md | 47 | ||||
| -rw-r--r-- | rand/rand_isaac/src/isaac.rs | 484 | ||||
| -rw-r--r-- | rand/rand_isaac/src/isaac64.rs | 481 | ||||
| -rw-r--r-- | rand/rand_isaac/src/isaac_array.rs | 136 | ||||
| -rw-r--r-- | rand/rand_isaac/src/lib.rs | 36 | 
10 files changed, 1462 insertions, 0 deletions
diff --git a/rand/rand_isaac/CHANGELOG.md b/rand/rand_isaac/CHANGELOG.md new file mode 100644 index 0000000..d0c4a2f --- /dev/null +++ b/rand/rand_isaac/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/rand/rand_isaac/COPYRIGHT b/rand/rand_isaac/COPYRIGHT new file mode 100644 index 0000000..468d907 --- /dev/null +++ b/rand/rand_isaac/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand/rand_isaac/Cargo.toml b/rand/rand_isaac/Cargo.toml new file mode 100644 index 0000000..07c4a36 --- /dev/null +++ b/rand/rand_isaac/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rand_isaac" +version = "0.1.0" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-random/rand" +documentation = "https://rust-random.github.io/rand/rand_isaac" +homepage = "https://crates.io/crates/rand_isaac" +description = """ +ISAAC random number generator +""" +keywords = ["random", "rng", "isaac"] +categories = ["algorithms", "no-std"] + +[badges] +travis-ci = { repository = "rust-random/rand" } +appveyor = { repository = "rust-random/rand" } + +[features] +serde1 = ["serde", "serde_derive", "rand_core/serde1"] + +[dependencies] +rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false } +serde = { version = "1", optional = true } +serde_derive = { version = "^1.0.38", optional = true } + +[dev-dependencies] +# This is for testing serde, unfortunately we can't specify feature-gated dev +# deps yet, see: https://github.com/rust-lang/cargo/issues/1596 +bincode = "1" diff --git a/rand/rand_isaac/LICENSE-APACHE b/rand/rand_isaac/LICENSE-APACHE new file mode 100644 index 0000000..17d7468 --- /dev/null +++ b/rand/rand_isaac/LICENSE-APACHE @@ -0,0 +1,201 @@ +                              Apache License +                        Version 2.0, January 2004 +                     https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +   "License" shall mean the terms and conditions for use, reproduction, +   and distribution as defined by Sections 1 through 9 of this document. + +   "Licensor" shall mean the copyright owner or entity authorized by +   the copyright owner that is granting the License. + +   "Legal Entity" shall mean the union of the acting entity and all +   other entities that control, are controlled by, or are under common +   control with that entity. For the purposes of this definition, +   "control" means (i) the power, direct or indirect, to cause the +   direction or management of such entity, whether by contract or +   otherwise, or (ii) ownership of fifty percent (50%) or more of the +   outstanding shares, or (iii) beneficial ownership of such entity. + +   "You" (or "Your") shall mean an individual or Legal Entity +   exercising permissions granted by this License. + +   "Source" form shall mean the preferred form for making modifications, +   including but not limited to software source code, documentation +   source, and configuration files. + +   "Object" form shall mean any form resulting from mechanical +   transformation or translation of a Source form, including but +   not limited to compiled object code, generated documentation, +   and conversions to other media types. + +   "Work" shall mean the work of authorship, whether in Source or +   Object form, made available under the License, as indicated by a +   copyright notice that is included in or attached to the work +   (an example is provided in the Appendix below). + +   "Derivative Works" shall mean any work, whether in Source or Object +   form, that is based on (or derived from) the Work and for which the +   editorial revisions, annotations, elaborations, or other modifications +   represent, as a whole, an original work of authorship. For the purposes +   of this License, Derivative Works shall not include works that remain +   separable from, or merely link (or bind by name) to the interfaces of, +   the Work and Derivative Works thereof. + +   "Contribution" shall mean any work of authorship, including +   the original version of the Work and any modifications or additions +   to that Work or Derivative Works thereof, that is intentionally +   submitted to Licensor for inclusion in the Work by the copyright owner +   or by an individual or Legal Entity authorized to submit on behalf of +   the copyright owner. For the purposes of this definition, "submitted" +   means any form of electronic, verbal, or written communication sent +   to the Licensor or its representatives, including but not limited to +   communication on electronic mailing lists, source code control systems, +   and issue tracking systems that are managed by, or on behalf of, the +   Licensor for the purpose of discussing and improving the Work, but +   excluding communication that is conspicuously marked or otherwise +   designated in writing by the copyright owner as "Not a Contribution." + +   "Contributor" shall mean Licensor and any individual or Legal Entity +   on behalf of whom a Contribution has been received by Licensor and +   subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +   this License, each Contributor hereby grants to You a perpetual, +   worldwide, non-exclusive, no-charge, royalty-free, irrevocable +   copyright license to reproduce, prepare Derivative Works of, +   publicly display, publicly perform, sublicense, and distribute the +   Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +   this License, each Contributor hereby grants to You a perpetual, +   worldwide, non-exclusive, no-charge, royalty-free, irrevocable +   (except as stated in this section) patent license to make, have made, +   use, offer to sell, sell, import, and otherwise transfer the Work, +   where such license applies only to those patent claims licensable +   by such Contributor that are necessarily infringed by their +   Contribution(s) alone or by combination of their Contribution(s) +   with the Work to which such Contribution(s) was submitted. If You +   institute patent litigation against any entity (including a +   cross-claim or counterclaim in a lawsuit) alleging that the Work +   or a Contribution incorporated within the Work constitutes direct +   or contributory patent infringement, then any patent licenses +   granted to You under this License for that Work shall terminate +   as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +   Work or Derivative Works thereof in any medium, with or without +   modifications, and in Source or Object form, provided that You +   meet the following conditions: + +   (a) You must give any other recipients of the Work or +       Derivative Works a copy of this License; and + +   (b) You must cause any modified files to carry prominent notices +       stating that You changed the files; and + +   (c) You must retain, in the Source form of any Derivative Works +       that You distribute, all copyright, patent, trademark, and +       attribution notices from the Source form of the Work, +       excluding those notices that do not pertain to any part of +       the Derivative Works; and + +   (d) If the Work includes a "NOTICE" text file as part of its +       distribution, then any Derivative Works that You distribute must +       include a readable copy of the attribution notices contained +       within such NOTICE file, excluding those notices that do not +       pertain to any part of the Derivative Works, in at least one +       of the following places: within a NOTICE text file distributed +       as part of the Derivative Works; within the Source form or +       documentation, if provided along with the Derivative Works; or, +       within a display generated by the Derivative Works, if and +       wherever such third-party notices normally appear. The contents +       of the NOTICE file are for informational purposes only and +       do not modify the License. You may add Your own attribution +       notices within Derivative Works that You distribute, alongside +       or as an addendum to the NOTICE text from the Work, provided +       that such additional attribution notices cannot be construed +       as modifying the License. + +   You may add Your own copyright statement to Your modifications and +   may provide additional or different license terms and conditions +   for use, reproduction, or distribution of Your modifications, or +   for any such Derivative Works as a whole, provided Your use, +   reproduction, and distribution of the Work otherwise complies with +   the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +   any Contribution intentionally submitted for inclusion in the Work +   by You to the Licensor shall be under the terms and conditions of +   this License, without any additional terms or conditions. +   Notwithstanding the above, nothing herein shall supersede or modify +   the terms of any separate license agreement you may have executed +   with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +   names, trademarks, service marks, or product names of the Licensor, +   except as required for reasonable and customary use in describing the +   origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +   agreed to in writing, Licensor provides the Work (and each +   Contributor provides its Contributions) on an "AS IS" BASIS, +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +   implied, including, without limitation, any warranties or conditions +   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +   PARTICULAR PURPOSE. You are solely responsible for determining the +   appropriateness of using or redistributing the Work and assume any +   risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +   whether in tort (including negligence), contract, or otherwise, +   unless required by applicable law (such as deliberate and grossly +   negligent acts) or agreed to in writing, shall any Contributor be +   liable to You for damages, including any direct, indirect, special, +   incidental, or consequential damages of any character arising as a +   result of this License or out of the use or inability to use the +   Work (including but not limited to damages for loss of goodwill, +   work stoppage, computer failure or malfunction, or any and all +   other commercial damages or losses), even if such Contributor +   has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +   the Work or Derivative Works thereof, You may choose to offer, +   and charge a fee for, acceptance of support, warranty, indemnity, +   or other liability obligations and/or rights consistent with this +   License. However, in accepting such obligations, You may act only +   on Your own behalf and on Your sole responsibility, not on behalf +   of any other Contributor, and only if You agree to indemnify, +   defend, and hold each Contributor harmless for any liability +   incurred by, or claims asserted against, such Contributor by reason +   of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +   To apply the Apache License to your work, attach the following +   boilerplate notice, with the fields enclosed by brackets "[]" +   replaced with your own identifying information. (Don't include +   the brackets!)  The text should be enclosed in the appropriate +   comment syntax for the file format. We also recommend that a +   file or class name and description of purpose be included on the +   same "printed page" as the copyright notice for easier +   identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +	https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand/rand_isaac/LICENSE-MIT b/rand/rand_isaac/LICENSE-MIT new file mode 100644 index 0000000..d93b5ba --- /dev/null +++ b/rand/rand_isaac/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand/rand_isaac/README.md b/rand/rand_isaac/README.md new file mode 100644 index 0000000..02d1230 --- /dev/null +++ b/rand/rand_isaac/README.md @@ -0,0 +1,47 @@ +# rand_isaac + +[](https://travis-ci.org/rust-random/rand) +[](https://ci.appveyor.com/project/rust-random/rand) +[](https://crates.io/crates/rand_isaac) +[](https://rust-random.github.io/book/) +[](https://rust-random.github.io/rand/rand_isaac) +[](https://docs.rs/rand_isaac) +[](https://github.com/rust-random/rand#rust-version-requirements) + +Implements the ISAAC and ISAAC-64 random number generators. + +ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +the principal bitwise operations employed. It is the most advanced of a +series of array based random number generator designed by Robert Jenkins +in 1996[^1][^2]. + +ISAAC is notably fast and produces excellent quality random numbers for +non-cryptographic applications. + +Links: + +-   [API documentation (master)](https://rust-random.github.io/rand/rand_isaac) +-   [API documentation (docs.rs)](https://docs.rs/rand_isaac) +-   [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](http://burtleburtle.net/bob/rand/isaacafa.html) +[^2]: Bob Jenkins, [*ISAAC and RC4*](http://burtleburtle.net/bob/rand/isaac.html) + + +## Crate Features + +`rand_isaac` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + + +# License + +`rand_isaac` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand/rand_isaac/src/isaac.rs b/rand/rand_isaac/src/isaac.rs new file mode 100644 index 0000000..2bfdd94 --- /dev/null +++ b/rand/rand_isaac/src/isaac.rs @@ -0,0 +1,484 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; +use isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w32 = w<u32>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses the ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1][^2]. +/// +/// ISAAC is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson, +/// named ISAAC+[^3]. But because the specification is not complete, because +/// there is no good implementation, and because the suggested bias may not +/// exist, it is not implemented here. +/// +/// ## Overview of the ISAAC algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256]         // results +/// +/// mix(a,i) = a ^ a << 13   if i = 0 mod 4 +///            a ^ a >>  6   if i = 1 mod 4 +///            a ^ a <<  2   if i = 2 mod 4 +///            a ^ a >> 16   if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +///     x = s_[i] +///     a = f(a,i) + s[i+128 mod 256] +///     y = a + b + s[x>>2 mod 256] +///     s[i] = y +///     b = x + s[y>>10 mod 256] +///     r[i] = b +/// } +/// ``` +/// +/// Numbers are generated in blocks of 256. This means the function above only +/// runs once every 256 times you ask for a next random number. In all other +/// circumstances the last element of the results array is returned. +/// +/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs. +/// 2 * 256 * 4 = 2 kb to hold the state and results. +/// +/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*]( +///       http://burtleburtle.net/bob/rand/isaacafa.html) +/// +/// [^2]: Bob Jenkins, [*ISAAC and RC4*]( +///       http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]( +///       https://eprint.iacr.org/2006/438) +/// +/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html +/// [`BlockRng`]: ../../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacRng(BlockRng<IsaacCore>); + +impl RngCore for IsaacRng { +    #[inline(always)] +    fn next_u32(&mut self) -> u32 { +        self.0.next_u32() +    } + +    #[inline(always)] +    fn next_u64(&mut self) -> u64 { +        self.0.next_u64() +    } + +    fn fill_bytes(&mut self, dest: &mut [u8]) { +        self.0.fill_bytes(dest) +    } + +    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { +        self.0.try_fill_bytes(dest) +    } +} + +impl SeedableRng for IsaacRng { +    type Seed = <IsaacCore as SeedableRng>::Seed; + +    fn from_seed(seed: Self::Seed) -> Self { +        IsaacRng(BlockRng::<IsaacCore>::from_seed(seed)) +    } +     +    /// Create an ISAAC random number generator using an `u64` as seed. +    /// If `seed == 0` this will produce the same stream of random numbers as +    /// the reference implementation when used unseeded. +    fn seed_from_u64(seed: u64) -> Self { +        IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed)) +    } + +    fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { +        BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng)) +    } +} + +impl IsaacRng { +    /// Create an ISAAC random number generator using an `u64` as seed. +    /// If `seed == 0` this will produce the same stream of random numbers as +    /// the reference implementation when used unseeded. +    #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] +    pub fn new_from_u64(seed: u64) -> Self { +        Self::seed_from_u64(seed) +    } +} + +/// The core of `IsaacRng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacCore { +    #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] +    mem: [w32; RAND_SIZE], +    a: w32, +    b: w32, +    c: w32, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for IsaacCore { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        write!(f, "IsaacCore {{}}") +    } +} + +impl BlockRngCore for IsaacCore { +    type Item = u32; +    type Results = IsaacArray<Self::Item>; + +    /// Refills the output buffer, `results`. See also the pseudocode desciption +    /// of the algorithm in the [`IsaacRng`] documentation. +    /// +    /// Optimisations used (similar to the reference implementation): +    ///  +    /// - The loop is unrolled 4 times, once for every constant of mix(). +    /// - The contents of the main loop are moved to a function `rngstep`, to +    ///   reduce code duplication. +    /// - We use local variables for a and b, which helps with optimisations. +    /// - We split the main loop in two, one that operates over 0..128 and one +    ///   over 128..256. This way we can optimise out the addition and modulus +    ///   from `s[i+128 mod 256]`. +    /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the +    ///   `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer +    ///   arithmetic. +    /// - We fill `results` backwards. The reference implementation reads values +    ///   from `results` in reverse. We read them in the normal direction, to +    ///   make `fill_bytes` a memcopy. To maintain compatibility we fill in +    ///   reverse. +    ///  +    /// [`IsaacRng`]: struct.IsaacRng.html +    fn generate(&mut self, results: &mut IsaacArray<Self::Item>) { +        self.c += w(1); +        // abbreviations +        let mut a = self.a; +        let mut b = self.b + self.c; +        const MIDPOINT: usize = RAND_SIZE / 2; + +        #[inline] +        fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 { +            let index = (v >> amount).0 as usize % RAND_SIZE; +            mem[index] +        } + +        #[inline] +        fn rngstep(mem: &mut [w32; RAND_SIZE], +                   results: &mut [u32; RAND_SIZE], +                   mix: w32, +                   a: &mut w32, +                   b: &mut w32, +                   base: usize, +                   m: usize, +                   m2: usize) { +            let x = mem[base + m]; +            *a = mix + mem[base + m2]; +            let y = *a + *b + ind(&mem, x, 2); +            mem[base + m] = y; +            *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN); +            results[RAND_SIZE - 1 - base - m] = (*b).0; +        } + +        let mut m = 0; +        let mut m2 = MIDPOINT; +        for i in (0..MIDPOINT/4).map(|i| i * 4) { +            rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); +            rngstep(&mut self.mem, results, a ^ (a >> 6 ),  &mut a, &mut b, i + 1, m, m2); +            rngstep(&mut self.mem, results, a ^ (a << 2 ),  &mut a, &mut b, i + 2, m, m2); +            rngstep(&mut self.mem, results, a ^ (a >> 16),  &mut a, &mut b, i + 3, m, m2); +        } + +        m = MIDPOINT; +        m2 = 0; +        for i in (0..MIDPOINT/4).map(|i| i * 4) { +            rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); +            rngstep(&mut self.mem, results, a ^ (a >> 6 ),  &mut a, &mut b, i + 1, m, m2); +            rngstep(&mut self.mem, results, a ^ (a << 2 ),  &mut a, &mut b, i + 2, m, m2); +            rngstep(&mut self.mem, results, a ^ (a >> 16),  &mut a, &mut b, i + 3, m, m2); +        } + +        self.a = a; +        self.b = b; +    } +} + +impl IsaacCore { +    /// Create a new ISAAC random number generator. +    /// +    /// The author Bob Jenkins describes how to best initialize ISAAC here: +    /// <https://rt.cpan.org/Public/Bug/Display.html?id=64324> +    /// The answer is included here just in case: +    /// +    /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will +    /// do fine, and they should have their expected strength (eg a 40-bit key +    /// will take as much time to brute force as 40-bit keys usually will). You +    /// could fill the remainder with 0, but set the last array element to the +    /// length of the key provided (to distinguish keys that differ only by +    /// different amounts of 0 padding). You do still need to call `randinit()` +    /// to make sure the initial state isn't uniform-looking." +    /// "After publishing ISAAC, I wanted to limit the key to half the size of +    /// `r[]`, and repeat it twice. That would have made it hard to provide a +    /// key that sets the whole internal state to anything convenient. But I'd +    /// already published it." +    /// +    /// And his answer to the question "For my code, would repeating the key +    /// over and over to fill 256 integers be a better solution than +    /// zero-filling, or would they essentially be the same?": +    /// "If the seed is under 32 bytes, they're essentially the same, otherwise +    /// repeating the seed would be stronger. randinit() takes a chunk of 32 +    /// bytes, mixes it, and combines that with the next 32 bytes, et cetera. +    /// Then loops over all the elements the same way a second time." +    #[inline] +    fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self { +        fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32, +               e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) { +            *a ^= *b << 11; *d += *a; *b += *c; +            *b ^= *c >> 2;  *e += *b; *c += *d; +            *c ^= *d << 8;  *f += *c; *d += *e; +            *d ^= *e >> 16; *g += *d; *e += *f; +            *e ^= *f << 10; *h += *e; *f += *g; +            *f ^= *g >> 4;  *a += *f; *g += *h; +            *g ^= *h << 8;  *b += *g; *h += *a; +            *h ^= *a >> 9;  *c += *h; *a += *b; +        } + +        // These numbers are the result of initializing a...h with the +        // fractional part of the golden ratio in binary (0x9e3779b9) +        // and applying mix() 4 times. +        let mut a = w(0x1367df5a); +        let mut b = w(0x95d90059); +        let mut c = w(0xc3163e4b); +        let mut d = w(0x0f421ad8); +        let mut e = w(0xd92a4a78); +        let mut f = w(0xa51a3c49); +        let mut g = w(0xc4efea1b); +        let mut h = w(0x30609119); + +        // Normally this should do two passes, to make all of the seed effect +        // all of `mem` +        for _ in 0..rounds { +            for i in (0..RAND_SIZE/8).map(|i| i * 8) { +                a += mem[i  ]; b += mem[i+1]; +                c += mem[i+2]; d += mem[i+3]; +                e += mem[i+4]; f += mem[i+5]; +                g += mem[i+6]; h += mem[i+7]; +                mix(&mut a, &mut b, &mut c, &mut d, +                    &mut e, &mut f, &mut g, &mut h); +                mem[i  ] = a; mem[i+1] = b; +                mem[i+2] = c; mem[i+3] = d; +                mem[i+4] = e; mem[i+5] = f; +                mem[i+6] = g; mem[i+7] = h; +            } +        } + +        Self { mem, a: w(0), b: w(0), c: w(0) } +    } +} + +impl SeedableRng for IsaacCore { +    type Seed = [u8; 32]; + +    fn from_seed(seed: Self::Seed) -> Self { +        let mut seed_u32 = [0u32; 8]; +        le::read_u32_into(&seed, &mut seed_u32); +        // Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`. +        let mut seed_extended = [w(0); RAND_SIZE]; +        for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) { +            *x = w(*y); +        } +        Self::init(seed_extended, 2) +    } +     +    /// Create an ISAAC random number generator using an `u64` as seed. +    /// If `seed == 0` this will produce the same stream of random numbers as +    /// the reference implementation when used unseeded. +    fn seed_from_u64(seed: u64) -> Self { +        let mut key = [w(0); RAND_SIZE]; +        key[0] = w(seed as u32); +        key[1] = w((seed >> 32) as u32); +        // Initialize with only one pass. +        // A second pass does not improve the quality here, because all of the +        // seed was already available in the first round. +        // Not doing the second pass has the small advantage that if +        // `seed == 0` this method produces exactly the same state as the +        // reference implementation when used unseeded. +        Self::init(key, 1) +    } + +    fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { +        // Custom `from_rng` implementation that fills a seed with the same size +        // as the entire state. +        let mut seed = [w(0u32); RAND_SIZE]; +        unsafe { +            let ptr = seed.as_mut_ptr() as *mut u8; + +            let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4); +            rng.try_fill_bytes(slice)?; +        } +        for i in seed.iter_mut() { +            *i = w(i.0.to_le()); +        } + +        Ok(Self::init(seed, 2)) +    } +} + +#[cfg(test)] +mod test { +    use rand_core::{RngCore, SeedableRng}; +    use super::IsaacRng; + +    #[test] +    fn test_isaac_construction() { +        // Test that various construction techniques produce a working RNG. +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng1 = IsaacRng::from_seed(seed); +        assert_eq!(rng1.next_u32(), 2869442790); + +        let mut rng2 = IsaacRng::from_rng(rng1).unwrap(); +        assert_eq!(rng2.next_u32(), 3094074039); +    } + +    #[test] +    fn test_isaac_true_values_32() { +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                     57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng1 = IsaacRng::from_seed(seed); +        let mut results = [0u32; 10]; +        for i in results.iter_mut() { *i = rng1.next_u32(); } +        let expected = [ +            2558573138, 873787463, 263499565, 2103644246, 3595684709, +            4203127393, 264982119, 2765226902, 2737944514, 3900253796]; +        assert_eq!(results, expected); + +        let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0, +                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng2 = IsaacRng::from_seed(seed); +        // skip forward to the 10000th number +        for _ in 0..10000 { rng2.next_u32(); } + +        for i in results.iter_mut() { *i = rng2.next_u32(); } +        let expected = [ +            3676831399, 3183332890, 2834741178, 3854698763, 2717568474, +            1576568959, 3507990155, 179069555, 141456972, 2478885421]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac_true_values_64() { +        // As above, using little-endian versions of above values +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                    57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng = IsaacRng::from_seed(seed); +        let mut results = [0u64; 5]; +        for i in results.iter_mut() { *i = rng.next_u64(); } +        let expected = [ +            3752888579798383186, 9035083239252078381,18052294697452424037, +            11876559110374379111, 16751462502657800130]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac_true_bytes() { +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                     57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng = IsaacRng::from_seed(seed); +        let mut results = [0u8; 32]; +        rng.fill_bytes(&mut results); +        // Same as first values in test_isaac_true_values as bytes in LE order +        let expected = [82, 186, 128, 152, 71, 240, 20, 52, +                        45, 175, 180, 15, 86, 16, 99, 125, +                        101, 203, 81, 214, 97, 162, 134, 250, +                        103, 78, 203, 15, 150, 3, 210, 164]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac_new_uninitialized() { +        // Compare the results from initializing `IsaacRng` with +        // `seed_from_u64(0)`, to make sure it is the same as the reference +        // implementation when used uninitialized. +        // Note: We only test the first 16 integers, not the full 256 of the +        // first block. +        let mut rng = IsaacRng::seed_from_u64(0); +        let mut results = [0u32; 16]; +        for i in results.iter_mut() { *i = rng.next_u32(); } +        let expected: [u32; 16] = [ +            0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA, +            0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD, +            0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846, +            0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac_clone() { +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                     57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng1 = IsaacRng::from_seed(seed); +        let mut rng2 = rng1.clone(); +        for _ in 0..16 { +            assert_eq!(rng1.next_u32(), rng2.next_u32()); +        } +    } + +    #[test] +    #[cfg(feature="serde1")] +    fn test_isaac_serde() { +        use bincode; +        use std::io::{BufWriter, BufReader}; + +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                     57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng = IsaacRng::from_seed(seed); + +        let buf: Vec<u8> = Vec::new(); +        let mut buf = BufWriter::new(buf); +        bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + +        let buf = buf.into_inner().unwrap(); +        let mut read = BufReader::new(&buf[..]); +        let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + +        for _ in 0..300 { // more than the 256 buffered results +            assert_eq!(rng.next_u32(), deserialized.next_u32()); +        } +    } +} diff --git a/rand/rand_isaac/src/isaac64.rs b/rand/rand_isaac/src/isaac64.rs new file mode 100644 index 0000000..2712762 --- /dev/null +++ b/rand/rand_isaac/src/isaac64.rs @@ -0,0 +1,481 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC-64 random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng64}; +use isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w64 = w<u64>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses ISAAC-64, the 64-bit variant of the +/// ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1]. +/// +/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers +/// instead of 32-bit, it uses twice as much memory to hold its state and +/// results. Also it uses different constants for shifts and indirect indexing, +/// optimized to give good results for 64bit arithmetic. +/// +/// ISAAC-64 is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// ## Overview of the ISAAC-64 algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = !(a ^ a << 21)  if i = 0 mod 4 +///              a ^ a >>  5   if i = 1 mod 4 +///              a ^ a << 12   if i = 2 mod 4 +///              a ^ a >> 33   if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +///     x = s_[i] +///     a = mix(a,i) + s[i+128 mod 256] +///     y = a + b + s[x>>3 mod 256] +///     s[i] = y +///     b = x + s[y>>11 mod 256] +///     r[i] = b +/// } +/// ``` +/// +/// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods. +/// +/// See for more information the documentation of [`IsaacRng`]. +/// +/// [^1]: Bob Jenkins, [*ISAAC and RC4*]( +///       http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html +/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html +/// [`BlockRng64`]: ../../rand_core/block/struct.BlockRng64.html +/// [`RngCore`]: ../../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Rng(BlockRng64<Isaac64Core>); + +impl RngCore for Isaac64Rng { +    #[inline(always)] +    fn next_u32(&mut self) -> u32 { +        self.0.next_u32() +    } + +    #[inline(always)] +    fn next_u64(&mut self) -> u64 { +        self.0.next_u64() +    } + +    fn fill_bytes(&mut self, dest: &mut [u8]) { +        self.0.fill_bytes(dest) +    } + +    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { +        self.0.try_fill_bytes(dest) +    } +} + +impl SeedableRng for Isaac64Rng { +    type Seed = <Isaac64Core as SeedableRng>::Seed; + +    fn from_seed(seed: Self::Seed) -> Self { +        Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed)) +    } + +    /// Create an ISAAC random number generator using an `u64` as seed. +    /// If `seed == 0` this will produce the same stream of random numbers as +    /// the reference implementation when used unseeded. +    fn seed_from_u64(seed: u64) -> Self { +        Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed)) +    } + +    fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { +        BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng)) +    } +} + +impl Isaac64Rng { +    /// Create an ISAAC-64 random number generator using an `u64` as seed. +    /// If `seed == 0` this will produce the same stream of random numbers as +    /// the reference implementation when used unseeded. +    #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] +    pub fn new_from_u64(seed: u64) -> Self { +        Self::seed_from_u64(seed) +    } +} + +/// The core of `Isaac64Rng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Core { +    #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] +    mem: [w64; RAND_SIZE], +    a: w64, +    b: w64, +    c: w64, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Isaac64Core { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        write!(f, "Isaac64Core {{}}") +    } +} + +impl BlockRngCore for Isaac64Core { +    type Item = u64; +    type Results = IsaacArray<Self::Item>; + +    /// Refills the output buffer, `results`. See also the pseudocode desciption +    /// of the algorithm in the [`Isaac64Rng`] documentation. +    /// +    /// Optimisations used (similar to the reference implementation): +    ///  +    /// - The loop is unrolled 4 times, once for every constant of mix(). +    /// - The contents of the main loop are moved to a function `rngstep`, to +    ///   reduce code duplication. +    /// - We use local variables for a and b, which helps with optimisations. +    /// - We split the main loop in two, one that operates over 0..128 and one +    ///   over 128..256. This way we can optimise out the addition and modulus +    ///   from `s[i+128 mod 256]`. +    /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the +    ///   `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer +    ///   arithmetic. +    /// - We fill `results` backwards. The reference implementation reads values +    ///   from `results` in reverse. We read them in the normal direction, to +    ///   make `fill_bytes` a memcopy. To maintain compatibility we fill in +    ///   reverse. +    ///  +    /// [`Isaac64Rng`]: struct.Isaac64Rng.html +    fn generate(&mut self, results: &mut IsaacArray<Self::Item>) { +        self.c += w(1); +        // abbreviations +        let mut a = self.a; +        let mut b = self.b + self.c; +        const MIDPOINT: usize = RAND_SIZE / 2; + +        #[inline] +        fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 { +            let index = (v >> amount).0 as usize % RAND_SIZE; +            mem[index] +        } + +        #[inline] +        fn rngstep(mem: &mut [w64; RAND_SIZE], +                   results: &mut [u64; RAND_SIZE], +                   mix: w64, +                   a: &mut w64, +                   b: &mut w64, +                   base: usize, +                   m: usize, +                   m2: usize) { +            let x = mem[base + m]; +            *a = mix + mem[base + m2]; +            let y = *a + *b + ind(&mem, x, 3); +            mem[base + m] = y; +            *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN); +            results[RAND_SIZE - 1 - base - m] = (*b).0; +        } + +        let mut m = 0; +        let mut m2 = MIDPOINT; +        for i in (0..MIDPOINT/4).map(|i| i * 4) { +            rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); +            rngstep(&mut self.mem, results,   a ^ (a >> 5 ),  &mut a, &mut b, i + 1, m, m2); +            rngstep(&mut self.mem, results,   a ^ (a << 12),  &mut a, &mut b, i + 2, m, m2); +            rngstep(&mut self.mem, results,   a ^ (a >> 33),  &mut a, &mut b, i + 3, m, m2); +        } + +        m = MIDPOINT; +        m2 = 0; +        for i in (0..MIDPOINT/4).map(|i| i * 4) { +            rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); +            rngstep(&mut self.mem, results,   a ^ (a >> 5 ),  &mut a, &mut b, i + 1, m, m2); +            rngstep(&mut self.mem, results,   a ^ (a << 12),  &mut a, &mut b, i + 2, m, m2); +            rngstep(&mut self.mem, results,   a ^ (a >> 33),  &mut a, &mut b, i + 3, m, m2); +        } + +        self.a = a; +        self.b = b; +    } +} + +impl Isaac64Core { +    /// Create a new ISAAC-64 random number generator. +    fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self { +        fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64, +               e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) { +            *a -= *e; *f ^= *h >> 9;  *h += *a; +            *b -= *f; *g ^= *a << 9;  *a += *b; +            *c -= *g; *h ^= *b >> 23; *b += *c; +            *d -= *h; *a ^= *c << 15; *c += *d; +            *e -= *a; *b ^= *d >> 14; *d += *e; +            *f -= *b; *c ^= *e << 20; *e += *f; +            *g -= *c; *d ^= *f >> 17; *f += *g; +            *h -= *d; *e ^= *g << 14; *g += *h; +        } + +        // These numbers are the result of initializing a...h with the +        // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13) +        // and applying mix() 4 times. +        let mut a = w(0x647c4677a2884b7c); +        let mut b = w(0xb9f8b322c73ac862); +        let mut c = w(0x8c0ea5053d4712a0); +        let mut d = w(0xb29b2e824a595524); +        let mut e = w(0x82f053db8355e0ce); +        let mut f = w(0x48fe4a0fa5a09315); +        let mut g = w(0xae985bf2cbfc89ed); +        let mut h = w(0x98f5704f6c44c0ab); + +        // Normally this should do two passes, to make all of the seed effect +        // all of `mem` +        for _ in 0..rounds { +            for i in (0..RAND_SIZE/8).map(|i| i * 8) { +                a += mem[i  ]; b += mem[i+1]; +                c += mem[i+2]; d += mem[i+3]; +                e += mem[i+4]; f += mem[i+5]; +                g += mem[i+6]; h += mem[i+7]; +                mix(&mut a, &mut b, &mut c, &mut d, +                    &mut e, &mut f, &mut g, &mut h); +                mem[i  ] = a; mem[i+1] = b; +                mem[i+2] = c; mem[i+3] = d; +                mem[i+4] = e; mem[i+5] = f; +                mem[i+6] = g; mem[i+7] = h; +            } +        } + +        Self { mem, a: w(0), b: w(0), c: w(0) } +    } + +    /// Create an ISAAC-64 random number generator using an `u64` as seed. +    /// If `seed == 0` this will produce the same stream of random numbers as +    /// the reference implementation when used unseeded. +    #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] +    pub fn new_from_u64(seed: u64) -> Self { +        Self::seed_from_u64(seed) +    } +} + +impl SeedableRng for Isaac64Core { +    type Seed = [u8; 32]; + +    fn from_seed(seed: Self::Seed) -> Self { +        let mut seed_u64 = [0u64; 4]; +        le::read_u64_into(&seed, &mut seed_u64); +        // Convert the seed to `Wrapping<u64>` and zero-extend to `RAND_SIZE`. +        let mut seed_extended = [w(0); RAND_SIZE]; +        for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) { +            *x = w(*y); +        } +        Self::init(seed_extended, 2) +    } +     +    fn seed_from_u64(seed: u64) -> Self { +        let mut key = [w(0); RAND_SIZE]; +        key[0] = w(seed); +        // Initialize with only one pass. +        // A second pass does not improve the quality here, because all of the +        // seed was already available in the first round. +        // Not doing the second pass has the small advantage that if +        // `seed == 0` this method produces exactly the same state as the +        // reference implementation when used unseeded. +        Self::init(key, 1) +    } + +    fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { +        // Custom `from_rng` implementation that fills a seed with the same size +        // as the entire state. +        let mut seed = [w(0u64); RAND_SIZE]; +        unsafe { +            let ptr = seed.as_mut_ptr() as *mut u8; +            let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8); +            rng.try_fill_bytes(slice)?; +        } +        for i in seed.iter_mut() { +            *i = w(i.0.to_le()); +        } + +        Ok(Self::init(seed, 2)) +    } +} + +#[cfg(test)] +mod test { +    use rand_core::{RngCore, SeedableRng}; +    use super::Isaac64Rng; + +    #[test] +    fn test_isaac64_construction() { +        // Test that various construction techniques produce a working RNG. +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                    0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng1 = Isaac64Rng::from_seed(seed); +        assert_eq!(rng1.next_u64(), 14964555543728284049); + +        let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap(); +        assert_eq!(rng2.next_u64(), 919595328260451758); +    } + +    #[test] +    fn test_isaac64_true_values_64() { +        let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, +                    200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; +        let mut rng1 = Isaac64Rng::from_seed(seed); +        let mut results = [0u64; 10]; +        for i in results.iter_mut() { *i = rng1.next_u64(); } +        let expected = [ +                   15071495833797886820, 7720185633435529318, +                   10836773366498097981, 5414053799617603544, +                   12890513357046278984, 17001051845652595546, +                   9240803642279356310, 12558996012687158051, +                   14673053937227185542, 1677046725350116783]; +        assert_eq!(results, expected); + +        let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0, +                    49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0]; +        let mut rng2 = Isaac64Rng::from_seed(seed); +        // skip forward to the 10000th number +        for _ in 0..10000 { rng2.next_u64(); } + +        for i in results.iter_mut() { *i = rng2.next_u64(); } +        let expected = [ +            18143823860592706164, 8491801882678285927, 2699425367717515619, +            17196852593171130876, 2606123525235546165, 15790932315217671084, +            596345674630742204, 9947027391921273664, 11788097613744130851, +            10391409374914919106]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac64_true_values_32() { +        let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, +                    200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; +        let mut rng = Isaac64Rng::from_seed(seed); +        let mut results = [0u32; 12]; +        for i in results.iter_mut() { *i = rng.next_u32(); } +        // Subset of above values, as an LE u32 sequence +        let expected = [ +                    3477963620, 3509106075, +                    687845478, 1797495790, +                    227048253, 2523132918, +                    4044335064, 1260557630, +                    4079741768, 3001306521, +                    69157722, 3958365844]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac64_true_values_mixed() { +        let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, +                    200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; +        let mut rng = Isaac64Rng::from_seed(seed); +        // Test alternating between `next_u64` and `next_u32` works as expected. +        // Values are the same as `test_isaac64_true_values` and +        // `test_isaac64_true_values_32`. +        assert_eq!(rng.next_u64(), 15071495833797886820); +        assert_eq!(rng.next_u32(), 687845478); +        assert_eq!(rng.next_u32(), 1797495790); +        assert_eq!(rng.next_u64(), 10836773366498097981); +        assert_eq!(rng.next_u32(), 4044335064); +        // Skip one u32 +        assert_eq!(rng.next_u64(), 12890513357046278984); +        assert_eq!(rng.next_u32(), 69157722); +    } + +    #[test] +    fn test_isaac64_true_bytes() { +        let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, +                    200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; +        let mut rng = Isaac64Rng::from_seed(seed); +        let mut results = [0u8; 32]; +        rng.fill_bytes(&mut results); +        // Same as first values in test_isaac64_true_values as bytes in LE order +        let expected = [100, 131, 77, 207, 155, 181, 40, 209, +                        102, 176, 255, 40, 238, 155, 35, 107, +                        61, 123, 136, 13, 246, 243, 99, 150, +                        216, 167, 15, 241, 62, 149, 34, 75]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac64_new_uninitialized() { +        // Compare the results from initializing `IsaacRng` with +        // `seed_from_u64(0)`, to make sure it is the same as the reference +        // implementation when used uninitialized. +        // Note: We only test the first 16 integers, not the full 256 of the +        // first block. +        let mut rng = Isaac64Rng::seed_from_u64(0); +        let mut results = [0u64; 16]; +        for i in results.iter_mut() { *i = rng.next_u64(); } +        let expected: [u64; 16] = [ +            0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB, +            0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49, +            0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F, +            0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF, +            0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD, +            0xB9090F3D42D2D2EA]; +        assert_eq!(results, expected); +    } + +    #[test] +    fn test_isaac64_clone() { +        let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, +                    200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; +        let mut rng1 = Isaac64Rng::from_seed(seed); +        let mut rng2 = rng1.clone(); +        for _ in 0..16 { +            assert_eq!(rng1.next_u64(), rng2.next_u64()); +        } +    } + +    #[test] +    #[cfg(feature="serde1")] +    fn test_isaac64_serde() { +        use bincode; +        use std::io::{BufWriter, BufReader}; + +        let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, +                     57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; +        let mut rng = Isaac64Rng::from_seed(seed); + +        let buf: Vec<u8> = Vec::new(); +        let mut buf = BufWriter::new(buf); +        bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + +        let buf = buf.into_inner().unwrap(); +        let mut read = BufReader::new(&buf[..]); +        let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + +        for _ in 0..300 { // more than the 256 buffered results +            assert_eq!(rng.next_u64(), deserialized.next_u64()); +        } +    } +} diff --git a/rand/rand_isaac/src/isaac_array.rs b/rand/rand_isaac/src/isaac_array.rs new file mode 100644 index 0000000..0fa6147 --- /dev/null +++ b/rand/rand_isaac/src/isaac_array.rs @@ -0,0 +1,136 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ISAAC helper functions for 256-element arrays. + +// Terrible workaround because arrays with more than 32 elements do not +// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other +// traits for that matter. + +#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + +#[derive(Copy, Clone)] +#[allow(missing_debug_implementations)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacArray<T> { +    #[cfg_attr(feature="serde1",serde(with="isaac_array_serde"))] +    #[cfg_attr(feature="serde1", serde(bound( +        serialize = "T: Serialize", +        deserialize = "T: Deserialize<'de> + Copy + Default")))] +    inner: [T; RAND_SIZE] +} + +impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> { +    #[inline(always)] +    fn as_ref(&self) -> &[T] { +        &self.inner[..] +    } +} + +impl<T> ::core::convert::AsMut<[T]> for IsaacArray<T> { +    #[inline(always)] +    fn as_mut(&mut self) -> &mut [T] { +        &mut self.inner[..] +    } +} + +impl<T> ::core::ops::Deref for IsaacArray<T> { +    type Target = [T; RAND_SIZE]; +    #[inline(always)] +    fn deref(&self) -> &Self::Target { +        &self.inner +    } +} + +impl<T> ::core::ops::DerefMut for IsaacArray<T> { +    #[inline(always)] +    fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] { +        &mut self.inner +    } +} + +impl<T> ::core::default::Default for IsaacArray<T> where T: Copy + Default { +    fn default() -> IsaacArray<T> { +        IsaacArray { inner: [T::default(); RAND_SIZE] } +    } +} + + +#[cfg(feature="serde1")] +pub(super) mod isaac_array_serde { +    const RAND_SIZE_LEN: usize = 8; +    const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +    use serde::{Deserialize, Deserializer, Serialize, Serializer}; +    use serde::de::{Visitor,SeqAccess}; +    use serde::de; + +    use core::fmt; + +    pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error> +    where +        T: Serialize, +        S: Serializer +    { +        use serde::ser::SerializeTuple; + +        let mut seq = ser.serialize_tuple(RAND_SIZE)?; + +        for e in arr.iter() { +            seq.serialize_element(&e)?; +        } + +        seq.end() +    } + +    #[inline] +    pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error> +    where +        T: Deserialize<'de>+Default+Copy, +        D: Deserializer<'de>, +    { +        use core::marker::PhantomData; +        struct ArrayVisitor<T> { +            _pd: PhantomData<T>, +        }; +        impl<'de,T> Visitor<'de> for ArrayVisitor<T> +        where +            T: Deserialize<'de>+Default+Copy +        { +            type Value = [T; RAND_SIZE]; + +            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +                formatter.write_str("Isaac state array") +            } + +            #[inline] +            fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error> +            where +                A: SeqAccess<'de>, +            { +                let mut out = [Default::default();RAND_SIZE]; + +                for i in 0..RAND_SIZE { +                    match seq.next_element()? { +                        Some(val) => out[i] = val, +                        None => return Err(de::Error::invalid_length(i, &self)), +                    }; +                } + +                Ok(out) +            } +        } + +        de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData}) +    } +} diff --git a/rand/rand_isaac/src/lib.rs b/rand/rand_isaac/src/lib.rs new file mode 100644 index 0000000..ec82d8e --- /dev/null +++ b/rand/rand_isaac/src/lib.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC and ISAAC-64 random number generators. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", +       html_favicon_url = "https://www.rust-lang.org/favicon.ico", +       html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(all(feature="serde1", test)), no_std)] + +extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +// To test serialization we need bincode and the standard library +#[cfg(all(feature="serde1", test))] extern crate bincode; +#[cfg(all(feature="serde1", test))] extern crate std as core; + +pub mod isaac; +pub mod isaac64; + +mod isaac_array; + +pub use self::isaac::IsaacRng; +pub use self::isaac64::Isaac64Rng;  | 
