Implement BlockRngCore ISAAC and ISAAC-64 #325
Conversation
rand-core/src/impls.rs
Outdated
| /// | ||
| /// This is similar to [`BlockRng`], but specialized for algorithms that operate | ||
| /// on `u64` values (rare). Hopefully specialization will one day allow | ||
| /// `BlockRng` to support both, so that this wrapper can be removed. |
There was a problem hiding this comment.
The "rare" part may change... I also don't know that it's worth talking about this future direction here. Also since all the implementations are different, is there any point making BlockRng support both?
There was a problem hiding this comment.
I'll remove the speculation...
The idea was once that things like ReseedingRng can then be used for both 32- and 64-bit RNGs.
There was a problem hiding this comment.
Which is a problem in itself. I wonder whether many people will complain about the new ReseedingRng being incompatible with many PRNGs... maybe not: I'm struggling to find any references which are not simply copies of the source
There was a problem hiding this comment.
The servo one is little more than a reshuffle of Rand code, so more like one, and that's reseeding ChaCha, so we're fine.
|
Is ISAAC going to be deprecated over HC128? |
|
In my opinion it already is, with |
|
Well, at least it's not yet official according to the documentation. |
|
Good point, I'll make a reference to HC-128 in the documentation |
|
Have you tried just deriving Serialize and Deserialize on Block Core? It should automagically only derive where |
c43e348 to
6912a12
Compare
|
@LinearZoetrope I have pushed my (unsuccessful) attempt to derive Serialize and Deserialize on Are you interested in taking a look? |
6912a12 to
c48e4cc
Compare
23d85d5 to
8a2deb0
Compare
8a2deb0 to
58fd61d
Compare
|
🎉 Finally have Serde re-implemented and a green bill from the CI. Updated the description in the first post. |
58fd61d to
4d09662
Compare
(and relative links are really inconsistent)
4d09662 to
bbd1b38
Compare
src/prng/isaac_array.rs
Outdated
| #[derive(Copy, Clone)] | ||
| #[allow(missing_debug_implementations)] | ||
| #[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))] | ||
| pub struct IsaacArray<T> where T: Default + Copy { |
There was a problem hiding this comment.
Default and Copy should never be used in trait bounds on a data structure -- only on impls and methods. The only code that requires these bounds are the Deserialize and Default impls, so the bounds should be on those impls.
There was a problem hiding this comment.
Thank you for reviewing, I hope I got them right now. It compiles...
rand_core/src/lib.rs
Outdated
|
|
||
| #[cfg(feature="std")] extern crate core; | ||
| #[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; | ||
| #[cfg(feature="serde-1")] extern crate serde; |
There was a problem hiding this comment.
I have a weak preference for serde1 as the name of the Serde feature instead of serde-1, to be consistent with crates that enable optional Serde support through an optional dependency on the serde1 shim.
There was a problem hiding this comment.
From what I see serde-1 seems to be used by a couple of crates to add the optional dependency. serde1 does not seem to have any reverse dependencies?
I don't like serde-1, and serde1 also does not seem ideal compared to just serde.
For rand_core, we could name the feature just serde with:
serde = { version = "1", optional = true, features = ["derive"] }.
For rand I see the serde feature as temporary, until we split of the PRNGs into a separate crate. There seems to be some movement in rust-lang/cargo#1286.
@dhardy What do you think? Does it make sense to use serde as the feature name in rand_core, and at some point in the future both crates can use that name?
There was a problem hiding this comment.
Well if serde never has another breaking release we don't need to append any number, but since it had quite a few before 1.0 appending a number seemed prudent. If @dtolnay prefers serde1 that is fine, except that it's a breaking change (we added the serde-1 feature for the Rand 0.4 release).
There was a problem hiding this comment.
except that it's a breaking change (we added the
serde-1feature for the Rand 0.4 release).
I don't think we did? https://github.com/rust-lang-nursery/rand/blob/0.4/Cargo.toml
There was a problem hiding this comment.
Okay, then we aren't constrained and can use serde1 as suggested.
dhardy
left a comment
There was a problem hiding this comment.
What do you think about making the public fields private? I think the only accessors actually needed should be to core and a "reset" function (for ChaCha::set_counter).
rand_core/src/impls.rs
Outdated
| serialize = "R::Results: Serialize", | ||
| deserialize = "R::Results: Deserialize<'de>")))] | ||
| pub results: R::Results, | ||
| pub index: usize, |
There was a problem hiding this comment.
Comment that 0 is never stored? next_u32 relies on this.
rand_core/src/impls.rs
Outdated
| #[cfg_attr(feature="serde-1", serde(bound( | ||
| serialize = "R::Results: Serialize", | ||
| deserialize = "R::Results: Deserialize<'de>")))] | ||
| pub results: R::Results, |
There was a problem hiding this comment.
Public fields should be documented — but I think perhaps we should not make these public (just add necessary accessor fns and a "reset" function).
There was a problem hiding this comment.
But than I have to do things properly... But it really cleans things up, so good idea.
rand_core/src/impls.rs
Outdated
| deserialize = "R::Results: Deserialize<'de>")))] | ||
| pub results: R::Results, | ||
| pub index: usize, | ||
| pub half_used: bool, // true if only half of the previous result is used |
There was a problem hiding this comment.
I think fill_bytes should reset half_used = false ? In fact I think the x86 version could also use the left-over bytes easily (because LE means the bytes are contiguous); the other version could also but would need an extra copy.
There was a problem hiding this comment.
Good catch. I think it only happened to pass the tests because it then it generates a new set of results in-between, which resets half_used.
I don't like to change the logic at the moment t.b.h.
There was a problem hiding this comment.
I don't think tests could catch this anyway; there's no memory unsafety, just the possibility of skipping one word of output and using another twice.
There was a problem hiding this comment.
Oops, I though we tested for it in test_isaac64_true_values_mixed, but that tests only mixing next_u64 and next_u32.
rand_core/src/lib.rs
Outdated
|
|
||
| #[cfg(feature="std")] extern crate core; | ||
| #[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; | ||
| #[cfg(feature="serde-1")] extern crate serde; |
There was a problem hiding this comment.
Okay, then we aren't constrained and can use serde1 as suggested.
a2f85ec to
1d6cd6c
Compare
1d6cd6c to
35ddc87
Compare
|
|
||
| /// Return a mutable reference the wrapped `BlockRngCore`. | ||
| pub fn inner(&mut self) -> &mut R { | ||
| &mut self.core |
There was a problem hiding this comment.
Really we should have mutable and immutable accessors, i.e. fn inner(&self) -> &R and fn inner_mut.
I'm surprised you didn't call this core though (you can shadow the name).
There was a problem hiding this comment.
I did initially, but I then thought this would make more sense for users, who don't see the field name.
There was a problem hiding this comment.
I just thought it aligned well with BlockRngCore but doesn't matter.
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
| fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
| let mut filled = 0; | ||
| self.half_used = false; |
There was a problem hiding this comment.
You need this in the other implementation of fill_bytes too!
| index: RAND_SIZE, // generate on first use | ||
| half_used: false, | ||
| }) | ||
| Isaac64Rng(BlockRng64::new(Isaac64Core::new_from_u64(seed))) |
There was a problem hiding this comment.
You don't need the separate Isaac64Core::new_from_u64 function, but if you do want it you don't need key on the line above.
There was a problem hiding this comment.
Sloppy work... I am sorry. Modified the commit.
35ddc87 to
f9f0ea6
Compare
|
Looks good 👍 |
Implement `BlockRngCore` ISAAC and ISAAC-64
Updated description:
This is the part I left out of #281.
This PR implements
BlockRngCorefor ISAAC and ISAAC-64. This meant changes in bothrandandrand_core.rand_core:BlockRng64wrapper, becauseBlockRngonly works foru32. The implementation is mostly just of copy of the one inIsaac64Rng. Only thefill_bytespart uses the same direct filling trick asBlockRng. This does not have any advantage at all forIsaac64Rng, because it generates 2kb at a time, and the copy cost is negligible compared to the time that takes. But as this is supposed to be a generic wrapper, it seems to make sense.serde-1feature to deriveSerializeandDeserializefor theBlockRngwrappers.rand:IsaacArraywrapper to supportAsRefand other traits on theBlockRng::Resultstype ofIsaac{64}Rng.isaac_serdetoisaac_array, because both deal with the problem of bad support for large arrays.IsaacRngandIsaac64Rngis as much as possible just a refactor of existing functionality. I believe the only small intended change is that the results type does not useWrapping<T>.First I thought this PR had problems that would take me forever to figure out, but thanks to help from @dtolnay they vanished overnight 😄. Now I think it would be very nice to get this in the 0.5 release, for three reasons:
BlockRng. We recommend RNGs to implement Serde, then we should also make it possible to do so.Isaac{64}Rng.BlockRngCorePR by implementing it for ISAAC (making it possible to also use it withReseedingRngetc.).Original post:
This is the part I left out of #281.
There are a few things which make implementing
BlockRngCorenot straight-forward.BlockRng64wrapper, becauseBlockRngonly works foru32.Asref()is not implemented for arrays with more than 32 elements. This adds anIsaacArrayas work-around.BlockRnginrand-coreserialisable? I did some effort, but implementing serialize, and especially deserialize, by hand becomes ugly quickly. cc @LinearZoetropeSo this is not yet mergeable, but I am hoping for some input 😄.