Join our public slack channel for support, discussions and more...
Contents

Using crates.io dependencies

It is highly likely that your crate depends (directly or transitively) on crates published on crates.io. Often times, 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.)

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 occured")
            }
        }

        pub(crate) fn next_u64(&mut self) -> u64 {
            match self.gen.try_next_u64() {
                Some(n) => n,
                None => panic!("Non-recoverable hardware failure has occured")
            }
        }

        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 occured")
            }
        }
    }
}

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 .

Contents