Using crates.io dependencies
It is highly likely that your crate depends (directly or transitively) on crates published on crates.io.
Oftentimes, compiling your dependencies for the x86_64-fortanix-unknown-sgx
target will just work.
Sometimes, you may see that a dependency doesn't compile due to a missing implementation for this target.
This can happen if the crate uses platform-specific functionality or links to code written in other languages.
You will need to add an implementation for the SGX target to the crate in question.
Example: rand
Let's understand this with the help of an example, an old version of the rand
crate.
(The rand
crate has already been ported to SGX, the latest 0.4 and 0.6 versions will work out of the box.)
-
Create a new crate
cargo new port_test
-
Add
rand (v0.4.5)
as dependency to this crateAppend following lines to
Cargo.toml
:[dependencies] rand = "=0.4.5"
-
Compile the crate
cargo build
-
Realize the compilation failure reason
You may see following output (or something similar) for
cargo build
Compiling rand v0.4.5 (<path>/rand) error[E0433]: failed to resolve: use of undeclared type or module `imp` --> <path>/rand/src/os.rs:35:18 | 35 | pub struct OsRng(imp::OsRng); | ^^^ use of undeclared type or module `imp` error[E0433]: failed to resolve: use of undeclared type or module `imp` --> <path>/rand/src/os.rs:40:9 | 40 | imp::OsRng::new().map(OsRng) | ^^^ use of undeclared type or module `imp`
The output states that module
imp
is missing for SGX target. The typeOsRng
is missing as well.
Implement
To add an implementation for a specific target, you can use conditional compilation.
The proper way to conditionally compile for x86_64-fortanix-unknown-sgx
is with cfg(all(target_env = "sgx", target_vendor = "fortanix"))
.
Let's take a look at the implementation needed for rand
.
Setup a copy of the rand source. Checkout the relevant branch, 0.4
in this case.
Append following lines in src/lib.rs
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#[cfg(all(target_env = "sgx", target_vendor = "fortanix"))]
mod imp {
use rdrand::RdRand;
use std::io;
use rand_core::RngCore;
pub struct OsRng{
gen: RdRand
}
impl OsRng {
pub fn new() -> io::Result<OsRng> {
match RdRand::new() {
Ok(rng) => Ok(OsRng { gen: rng }),
Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
}
}
pub(crate) fn next_u32(&mut self) -> u32 {
match self.gen.try_next_u32() {
Some(n) => n,
None => panic!("Non-recoverable hardware failure has occurred")
}
}
pub(crate) fn next_u64(&mut self) -> u64 {
match self.gen.try_next_u64() {
Some(n) => n,
None => panic!("Non-recoverable hardware failure has occurred")
}
}
pub(crate) fn fill_bytes(&mut self, v: &mut [u8]) {
match self.gen.try_fill_bytes(v) {
Ok(_) => {},
Err(_) => panic!("Non-recoverable hardware failure has occurred")
}
}
}
}
Here's the link to actual implementation.
Test
You can test your changes by overriding the dependency with your copy. Append following lines to Cargo.toml:
1
2
[patch.crates-io]
rand = { path = "<path-to-your-copy-of-dependency>" }
Alternatively, you can add below lines if you want to pick changes from a git repo:
1
2
[patch.crates-io]
rand = { git="<git-repo-name>", branch="<branch-name>" }
You should be able to compile successfully (assuming your changes are correct and sufficient):
cargo build
Push changes to upstream
It is highly recommended that you push your changes to upstream.
Create a Pull Request in the original repo for your changes
Create a Pull Request on the relevant branch in the original repo for your changes. Add a meaningful title to the PR, e.g. "Add support for x86_64-fortanix-unknown-sgx target"
Ask us to review
You can always ping us to review your changes. We highly appreciate your contribution.
Note: Once your changes get merged in original dependency git repo, you should remove the patch section from Cargo.toml .