0

I'm trying to get the hang of Rust lifetimes. While I seem to understand them, I don't seem to know the best way to fix it. Here is a function where I am using the *ring* package to generate a SHA256 HMAC. Here is a simplified version of the function that reproduced the problem:

fn sign<'b>(data: &[u8], key: &[u8]) -> &'b [u8] {
    let hmac_key = hmac::SigningKey::new(&digest::SHA256, key);
    let signature = hmac::sign(&hmac_key, data);
    let data = signature.as_ref();
    data
}

This doesn't work because signature doesn't live long enough. That makes sense; as_ref has a reference to signature, and signature doesn't live past the end of the function.

as_ref is the recommended way in *ring* to get a &[u8] from its Digest structure as seen in the documentation.

How do I correct the issue where signature does not live long enough without copying the entire contents of the byte array?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
vcsjones
  • 138,677
  • 31
  • 291
  • 286
  • 5
    Why do you want to return a `&[u8]`? It seems completely natural for a function called `sign` to return a `Digest`. –  Sep 27 '16 at 22:46

1 Answers1

2

signature binds to a resource that, as it is, will only live in the scope of that function. Naturally, it would only be wrong to lend the signature's array, also living in the function, to something living outside the function. Therefore, expanding its lifetime, as you intended, is out of the question.

With that in mind, there are two ways to go around this, ordered by preference:

  • We can just pass the ownership of signature to the outside, by making the function return the Digest. Note that this doesn't mean that there will be deep copies of the content. Return-value optimization can take place, which will produce the returned object in-place if it's larger than a pointer. On the other hand, this seems to be more of an implementation detail rather than a guarantee of the language. I would look into the compiled assembly if this is a true concern.
  • Alternatively, the library could be rewritten (or modified with an expanded API) to accept a mutable reference to a buffer (which might need to support resizing, such as &mut Vec<u8>). Of course, this implies proposing and implementing acceptable changes to this library, but the former approach to your problem might just suffice.
Community
  • 1
  • 1
E_net4
  • 27,810
  • 13
  • 101
  • 139