-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
embedded source compatibility #4
Comments
One solution here would be a special feature enabling an alternative mode: #[cfg(feature = "getrandom_custom")]
extern "C" {
fn getrandom_custom(dest: *mut u8, len: usize) -> u32;
}
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
#[cfg(feature = "getrandom_custom")] {
use core::num::NonZeroU32;
let ret = unsafe { getrandom_custom(dest.as_mut_ptr(), dest.len()) };
return if let Some(err) = NonZeroU32::new(ret) {
Err(Error::from(err))
} else {
Ok(())
};
}
getrandom_inner(dest)
} This would allow any single crate in the build to replace the entropy source, which has both advantages (easier testing with dummy entropy, easy of usage of other randomness source libs) and disadvantages (relatively easy to accidentally or possibly even maliciously mess this up; no single place to check whether the alternative is enabled). Another solution (which doesn't need any support here) would be to make a replacement crate with the same API (copy error types, provide [patch.crates-io]
getrandom = { path = "my/replacement/getrandom" } |
There is another issue with In contrast, |
Note: there is a long discussion on this topic in rand#579 with several sub-topics:
At any rate, development appears to be stalled due to lack of demand. |
@dhardy I opened an issue on the embedded WG to call attention to the issue of |
Some of the ideas aired above may still be relevant in the future, e.g. use of an entropy pool (via another crate). This issue is too broad I guess, ranging from |
This comment has been minimized.
This comment has been minimized.
@mati865 |
@newpavlov I totally missed that gate and couldn't find default features field for this crate. I haven't thought about other rand crates enabling it. |
@josephlr I think both of those PRs are irrelevant to the embedded use case, as none of them cover embedded targets. Per the discussion on rust-embedded/wg#353 I’m wondering of the getrandom API is fundamentally incompatible with I think the existing |
#109 (in addition to dealing with WASM targets) also adds a generic way for an external crate to register a custom getrandom implementation. This concept of an externally defined hook was specifically intended to work with embedded targets. For example, if there was some external device that you want to get randomness from, you would write a custom crate which would depend on name = "mydevice-getrandom"
[dependencies]
getrandom = { version = "0.2", features = ["custom"] } And your code would then specify a function to be called. A sample use spin::Mutex;
use getrandom::{register_custom_getrandom, Error};
struct Device{ /* device specific state */ }
impl Device {
fn new() -> Result<Self, Error> {
/* Initialize and Create the device */
}
fn read(&mut self, buf: &mut [u8]) -> Result<(), Error> {
/* Read randomness from the device */
}
}
// Global instance of device
static DEVICE: Mutex<Option<Device>> = Mutex::new(None);
fn my_getrandom(buf: &mut[u8]) -> Result<(), Error> {
let mut guard = DEVICE.lock();
let dev: &mut Device = guard.get_or_insert(Device::new()?);
dev.read(buf)
}
register_custom_getrandom!(my_getrandom); The above code uses the @tarcieri, Is there a reason that wouldn't work for your use case? |
While the embedded-hal crate specifically seems to encourage Global Singletons (per their example code), I realize that this does not map onto all workflows. Alternatively, if you had some device-specific struct RNGDevice{/* private */}
impl RNGDevice {
fn get_mut() -> Result<&mut Self, Error>;
fn read(&mut self, buf: &mut [u8]) -> Result<(), Error>;
} You could implement a use mydevice::RNGDevice;
use getrandom::{register_custom_getrandom, Error};
fn my_getrandom(buf: &mut[u8]) -> Result<(), Error> {
RNGDevice::get_mut()?.read(buf)
}
register_custom_getrandom!(my_getrandom); |
Well first, the I suppose this accomplishes the goal of having something that potentially works for embedded, however I think it’s complex solution as opposed to passing a I’d probably still choose to use One nit here: &mut Device = guard.get_or_insert(Device::new()?); This is assuming device initialization as a side effect, which isn’t how the To make that work with what you’ve proposed, you’d need a more |
I'd agree that's the best bet if you're using something directly. The main reason for the custom impl is to handle cases where |
Appologies for the late reply. @josephlr's example above can certainly be adapted to keep the global singleton but perform initialisation via a user-called function — it just means that However, granted, this is a lot more complexity than strictly required. Should we then close this issue as not-worth-delivering? |
#109 seems good enough to address the immediate issue |
Guess I'll close this then. |
This crate requires
std::io
code on many platforms to read from special devices, therefore will normally requirestd
. Ideally we should provide a smooth route tono_std
compatibility however, possibly by allowing users to defineextern
functions. (We've discussed using "lang items" but these are restricted to Rust's core libraries; we may or may not integrate this code intostd
in the future and use that option, but ideally should have ano_std
option now.)The text was updated successfully, but these errors were encountered: