Secure random bytes and unbiased sampling for MoonBit; never a seeded generator.
test "draw" {
let key = @moonseed.bytes(32, @system.source) // 32 uniform bytes
let n = @moonseed.below(b"\x03\xe8", @system.source) // in [0, 1000)
let d = @moonseed.scalar(b"\x05", @system.source) // in [1, 4)
ignore((key, n, d))
}| Package | What it holds | Depends on |
|---|---|---|
| moonseed | Source, Unavailable, bytes, below, scalar, Replay | nothing |
| moonseed/system | source, the platform's entropy | core env |
| Source | Where the bytes come from |
|---|---|
| @system.source | crypto.getRandomValues on JavaScript, WASI random_get on wasm and wasm-gc, the runtime on native |
| Replay::new(bytes) | the bytes given, in order; exhausted after |
| your own | anything that implements Source |
priv struct Device {}
impl @moonseed.Source for Device with fn fill(_self, _buf) {
raise Failed("the device is unplugged")
}
test "a source of my own" {
let refused = try {
ignore(@moonseed.bytes(4, Device::{ }))
""
} catch {
e => e.to_string()
}
assert_eq(refused, "the device is unplugged")
}test "the three refusals" {
assert_eq(
@moonseed.Unavailable::Platform.to_string(),
"the platform has no entropy source",
)
assert_eq(
@moonseed.Unavailable::Exhausted.to_string(),
"the replay source is exhausted",
)
assert_eq(
@moonseed.Unavailable::Failed("the device is unplugged").to_string(),
"the device is unplugged",
)
}test "replay" {
let source = @moonseed.Replay::new(b"\x07\xff\x02")
assert_eq(@moonseed.below(b"\x0a", source), b"\x07")
// 0xff keeps its low four bits, which is 15: at or above the bound, so the
// next byte is drawn instead.
assert_eq(@moonseed.below(b"\x0a", source), b"\x02")
assert_eq(source.remaining(), 0)
}test "a short replay gives nothing" {
let source = @moonseed.Replay::new(b"\x01\x02\x03")
let buf = FixedArray::make(4, b'\x00')
let refused = try {
source.fill(buf)
false
} catch {
@moonseed.Unavailable::Exhausted => true
_ => false
}
assert_true(refused)
assert_eq(buf, [b'\x00', b'\x00', b'\x00', b'\x00'])
assert_eq(source.remaining(), 3)
}test "below 1000" {
let source = @moonseed.Replay::new(b"\x17\x90\x37\xdd")
assert_eq(@moonseed.below(b"\x03\xe8", source), b"\x03\x90")
assert_eq(@moonseed.below(b"\x03\xe8", source), b"\x03\xdd")
assert_eq(source.remaining(), 0)
}test "a P-256 scalar" {
let order = b"\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xbc\xe6\xfa\xad\xa7\x17\x9e\x84\xf3\xb9\xca\xc2\xfc\x63\x25\x51"
let source = @moonseed.Replay::new(b"\xe4\xb8\x51\x7f\x20\xec\x48\x11\xf7\xd9\xe0\xcf\xa2\xec\x7e\x28\x19\x8a\x34\x1d\xec\xe5\xf7\x7a\x8d\x98\x88\x59\xb9\x44\x62\x41")
assert_eq(
@moonseed.scalar(order, source),
b"\xe4\xb8\x51\x7f\x20\xec\x48\x11\xf7\xd9\xe0\xcf\xa2\xec\x7e\x28\x19\x8a\x34\x1d\xec\xe5\xf7\x7a\x8d\x98\x88\x59\xb9\x44\x62\x41",
)
assert_eq(source.remaining(), 0)
}pub struct Replay {
// private fields
}test {
let source = @moonseed.Replay::new(b"\x0a")
let buf = FixedArray::make(1, b'\x00')
source.fill(buf)
assert_eq(buf, [b'\x0a'])
}test {
let source = @moonseed.Replay::new(b"\x17\x90")
assert_eq(@moonseed.below(b"\x03\xe8", source), b"\x03\x90")
}test {
let source = @moonseed.Replay::new(b"\x01\x02\x03")
assert_eq(@moonseed.bytes(2, source), b"\x01\x02")
}test {
let source = @moonseed.Replay::new(b"\xc0\x80")
assert_eq(@moonseed.scalar(b"\x05", source), b"\x04")
}Install
Download zipSecure random bytes and unbiased sampling for MoonBit; never a seeded generator.