Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This Rust example seems like it misses the point? Rune detects that you're working with data that is marked as secret, and gives you a compiler guarantee that it's defending against some set of known attacks.

The Rust code above depends on the programmer to consistently remember to enforce safety, and to do so correctly every time.

Sure, you could probably implement that as a library. But, "We don't see much value in compiler help with this, a combination of libraries and being careful gets the job done," would be a peculiar position for a rustacean to defend.



Great callout, I haven't had my coffee yet. Here is a version that better shows what I intended

    pub struct Secret<T>(T);

    impl<T> Secret<T> {
        pub fn map<U>(&self, func: impl FnOnce(&T) -> U) -> Secret<U> {
            Secret(func(&self.0))
        }
    }
    
    impl<T: AsRef<[u8]>> PartialEq<&[u8]> for Secret<T> {
        fn eq(&self, other: &&[u8]) -> bool {
            constant_time_eq(self.0.as_ref(), other)
        }
    }

    /* Some other file */

    use secret::Secret;
    
    // Translated from the example
    fn check_mac<T: AsRef<[u8]>>(mac_secret: Secret<T>, message: &[u8], mac: &[u8]) -> bool {
        // This returns a new Secret<[u8; 32]>
        let computed_mac = mac_secret.map(|secret| hmac_sha_256(secret.as_ref(), message));

        // This uses the `constant_time_eq` impl from above
        computed_mac == mac
    }


I think the interesting part of the example is what you _can't_ do in the other file. It's pretty hard to misuse because the return type of `Secret::map` is a new `Secret`, the only way to do `==` on a `Secret<T>` uses a constant time compare.

I guess my main point is that when you have a instead of having to add new things at the language _level_, if I have something as powerful as the rust type system I can implement the same functionality in not much of code.


That covers the one case in the example, but the language goes even further than that in ensuring constant-time processing of secrets, including ensuring speculative execution in the CPU won't expose the data to timing attacks.

I don't know enough about the subject to really evaluate this in detail, but I am more than willing to at least entertain the notion that the problem space is thorny enough that a language-level solution really can do some things that can't be as effectively accomplished with a library solution. Even in a language with a strong compiler like Rust.

Rune also has an interesting approach to pointer safety that's significantly different from Rust's: https://github.com/google/rune/blob/main/doc/index.md#runes-...


It all gets more complicated when you want to pass more than one secret parameter, or the function already returns a Secret - now you need a monad. The key feature seems to be that the code does not need 'map' or anything, the secrecy flag is propagated regardless.


> now you need a Monad

"need a Monad" sounds scary but in practice it looks like this

    impl<T> Secret<T> {
        pub fn map<U>(&self, func: impl FnOnce(&T) -> U) -> Secret<U> {
            Secret(func(&self.0))
        }

        pub fn flat_map<U>(&self, func: impl FnOnce(&T) -> Secret<U>) -> Secret<U> {
            func(&self.0)
        }
    }
If you need an escape hatch for something more complicated, you could provide an api to that

    impl<T> Secret<T> {
        pub unsafe fn reveal(&self) -> &T {
            &self.0
        }
    }


My point, which I didn’t express well there, was about the call side: How do you call

    func(param1: A, param2: B) -> C
with both parameters being secrets (secret1: Secret<A>, secret2: Secret<B>)? In Rust, it‘s

    flat_map(secret1, |param1|
      map(secret2, |param2|
        func(param1, param2)
      )
    )
or with do_notation at least a bit cleaner

    do! {
      param1 <- secret1;
      param2 <- secret2;
      Secret(func(param1, param2));
    }
whereas Rune manages it with

    func(secret1, secret2)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: