runtimejs / runtime

[not maintained] Lightweight JavaScript library operating system for the cloud
http://runtimejs.org
Apache License 2.0
1.93k stars 128 forks source link

Add RNG driver #73

Closed facekapow closed 9 years ago

facekapow commented 9 years ago

This PR adds a VirtioRNG driver. Exposes getRand(cb) and getRandLength(length, cb) in runtime.driver.rng (though, i'm pretty sure you'll want to change that, seems like a bad place for it). I had to remove the PCI debug info iterator, because for some reason, having it there prevented the PCI lister function from reading the RNG device (in fact, it hung the system and didn't even load the shell). I know that's a bug, but for now that's the alternative I could find. Now someone just needs to provide an interface for libsodium 😄. I'm working on a custom (no libsodium) randomBytes implementation.

kesla commented 9 years ago

Cool!

kesla commented 9 years ago

Maybe it would make sense to create a runtime-node-crypto that extends https://github.com/dominictarr/sodium-browserify?

facekapow commented 9 years ago

sodium-browserify does have a lot of useful functions already done, so... i'll see how to add some more functionality to it and use it.

facekapow commented 9 years ago

Since I only place one buffer, I made the runtime.driver.rng functions synchronous by using getBuffer(). Plus, I added a Node compatible randomBytes() function (which accepts an optional asynchronous callback, just like Node).

facekapow commented 9 years ago

Ok, i'll fix this.

facekapow commented 9 years ago

OK! I've merged getRand and getRandLength, so now it's getRand([length], [callback]) (the parameters can switch places, and they're both optional). I've added getHybridRand, which works exactly the same as getRand, EXCEPT when the result of getting the buffer is null, in which case it falls back to the Multiply-With-Carry RNG algorithm (with a few tweaks in order to return a number less than 256 but not a negative) and returns a UInt8Array like normal. getHybridRand is recommended since it works like /dev/random and /dev/urandom. I've also removed randomBytes and i've put it into runtime-node-crypto (which will only work with runtime if this PR merges, and if it gets mapped to crypto by runtimeify).

iefserge commented 9 years ago

@ArielAbreu hey, sorry for the delay, I'll review this PR in a little while.

facekapow commented 9 years ago

Hmm, odd. I'm getting merge conflicts remotely on github.com, but locally, the Github app shows absolutely no conflicts, and neither does the command line.

iefserge commented 9 years ago

@ArielAbreu you might need to refetch upstream and rebase your branch

facekapow commented 9 years ago

I've fixed the merge conflict, and added isaac.js (with the necessary changes in order to be used + it's license), but I still haven't used it.

iefserge commented 9 years ago

@ArielAbreu nice, I'm going to fix Math.random() because now it uses the same seed everytime (isaac.js uses Math.random() for the initial seed). We can re-seed isaac.js using bytes from virtio-rng after that (when/if available). This way we can ensure getPseudoRandomBytes works even if virtio-rng is not available.

facekapow commented 9 years ago

@iefserge You could also just isaac.reset(). It clears the seed and everything. Then seed it using virtio-rng (like you said).

facekapow commented 9 years ago

Just pushed a commit containing a new interface supporting multiple sources of randomness for runtime.random, which is used by the VirtioRNG driver to add itself and set itself as the default. I tested it and both runtime.random.rand() and runtime.random.urand() work as expected. rand() always accepts (and expects) a callback, and urand() returns immediately and generates randomness if there is not enough.

EDIT: I take that back, I need to fix runtime.random.rand(), it loops forever when there is not enough randomness.

facekapow commented 9 years ago

OK, now everything should work as expected.

facekapow commented 9 years ago

Correction: now it should work. I made VirtioRNG use Math.random() if u8 is null when VirtioRNG is requested for a seed.

facekapow commented 9 years ago

@iefserge I've fixed a couple of things. I renamed rand to getRandomValues and urand to getPseudoRandomValues. Now getRandomValues loads a Uint8Array into the method's queue and calls the method's fillQueue, which fills up the Uint8Array with randomness. Also, since now randomness is not stored, getPseudoRandomValues asks for a seed and generates all the randomness from isaac.js using the seed. getPseudoRandomValues also accepts a Uint8Array variable from the user instead of a length (but a length can still be provided instead of a variable) and returns it in case they did getPseudoRandomValues(new Uint8Array(10)). And I also moved the default 'none' source to a separate file.

facekapow commented 9 years ago

I've removed the fillRequestQueue() function code in favor of using it directly.

facekapow commented 9 years ago

Pushed a commit that makes fillQueue() use an IRQ callback and makes init() in every source return a one-time seed to use for isaac.js instead of requesting one every time getPseudoRandomValues() is called.

facekapow commented 9 years ago

New commit made that has a cbqueue for callbacks and calls irq.on once.

facekapow commented 9 years ago

I've fixed the stuff in the comments. Only the default method is used, one generic argument (for getRandomValues, too), use U8 directly, remove done, no queue for buffers (fillQueue is now fillBuffer, which accepts a buffer directly), callback queue is not exposed either, and isaac.js inits itself and is seeded with the first value of the buffer from every successful getRandomValues call.

iefserge commented 9 years ago

Thanks, I'm going to add few improvements and will try to resolve pciscan issue, then it should be good to merge.

facekapow commented 9 years ago

Sounds good! Maybe the pciscan issue only happens with the virtio-rng device. I haven't tested this theory yet, just a hunch.