Hacker News new | past | comments | ask | show | jobs | submit login

Like this:

  use sha2::{Sha256, Digest};

  fn main() {
    let mut hasher = Sha256::new();
    hasher.input(b"hello world");
    let result = hasher.result();
    ??
  }
How do I get a string with the hash value? Which chapter of which book should I read?



Ah, I see! So yeah, this isn't something the book covers, so that would not be helpful.

In this case, the hash ends up being raw bytes. So the question is, what are you trying to do with this hash? Being a bunch of bytes, this may not be valid UTF-8 (and in this case, is not ASCII, let alone UTF-8). One option is to encode to base64:

  use sha2::{Sha256, Digest};
  use base64;
  
  fn main() {
      let mut hasher = Sha256::new();
      hasher.input(b"hello world");
      let result = hasher.result();
      let encoded = base64::encode(&result);
    
      assert_eq!("uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=", encoded);
  }
But yeah, you can't exactly "get a string" out of a random bag of bytes unless you know how you want that bag of bytes to be represented, encoding wise. That's not exactly a satisfying answer, but such are strings!


This seems to be a conceptual mistake that often happens when coming from high level languages, I have seen similar confusion on stack overflow relating to packet based network protocols.

What many low-level data formats deal with are raw bytes ("byte strings" in some contexts). The output of a hasher is random binary data.

What most humans are accustomed to are some form of encoding that makes it easier to spell out the octets. Hex and base64 are common. But they are not the native representation that the machine deals with.

With almost everything being explicit in rust you need an explicit conversion from bytes to hex, base64, urlencode or some other format.

Those conversion methods (with their contract often expressed as a separate trait) may be provided by the same crate or you may have to pull them in from a different crate.

A hasher does not need to provide this itself because its output types can be enhanced by foreign traits.


The hash value is a bunch of bytes. A "string" would need to be some encoded version of those bytes, commonly hexadecimal representation.


I think you can use format!() to format the byte array as a hex string.

The result of a hash is never a string, so it makes sense that you'd need another step to print it as one.


As mentioned by others, you need to convert the bytes to a String. `Sha2` provides a helper function for that: `hasher.result_str()`.

EDIT: sorry I don't know which docs I was looking at, I can't find it in the current version.


This is helpful but in general what is a problem of having strings and trivial functions to convert something (like bytes) to strings? Maybe I am missing the point.


Because converting a type to a string isn't trivial. It needs to be defined for that type.

Rust does have a pair of traits that can be used, Display [1] and Debug [2]. Display must be implemented manually by the author of a type, while Debug can be automatically derived if all the members of a type implement Debug. Like this:

    #[derive(Debug)]
    struct Foo {

    }
[1] https://doc.rust-lang.org/std/fmt/trait.Display.html

[2] https://doc.rust-lang.org/std/fmt/trait.Debug.html


The process of "functions to convert bytes to a string" is called "encoding". The problem is, there's no universal way to do it, so you need to choose one. You need to know what the bytes mean, and then convert them into whatever representation that you need.

It is unfortunate that you’ve been downvoted for asking a question.


Thank you very much. I am going to read up this because I think I am missing out on crucial details.

It is unfortunate how HN is nowadays but I don’t care if I can still learn a lot from people like you.


Happy to help. Feel free to post questions on users.rust-lang.org as well; people are super happy to elaborate on any question, no matter how big or small.


Rust doesn't have varargs, so formatting functions tend to be macros (allowing to pass in multiple arguments, compile time parsing the format string to allow type checking etc) so they are generally not that trivial.

There are some examples of printing output using formatting strings in the RustCrypto readme:

    let hash = Blake2b::digest(b"my message");
    println!("Result: {:x}", hash);
https://github.com/RustCrypto/hashes#usage

If you're looking to get the actual string value rather than just print it out, then take a look at the format macro. It uses the same format strings / traits etc as println, so wherever you see println you could drop in format instead:

    let hash = Blake2b::digest(b"my message");
    let text = format!("{:x}", hash);
https://doc.rust-lang.org/std/macro.format.html


It sounds like you're coming from a language (like C) where a string is just an array of bytes or a language (like Ruby or Javascript) where strings are seriously overloaded.

In Rust a string is a UTF-8 sequence. Typically human readable. A byte is generally represented by the u8 type, and a collection of bytes is either an array or vector (e.g. [u8] or Vec<u8>). To create a human readable form of an object in Rust you'd typically use the Display ({} format specifier) and/or Debug traits ({:?}). A string (e.g. &str or String) is NOT a collection of bytes. There are exceptions however with OsString/OsStr representing something closer to a collection of bytes and CString/CStr representing a bag of bytes.

Your comments seem a bit XY-ish to me. What are you trying to solve by converting things to strings? For debugging or human readable output Array, Vec, and u8 all implement the Debug trait. u8 also implements UpperHex and LowerHex so you can get a hex formatted version as well (e.g. format!("{:02X}", bytes)).

For the (MD5) hash case, as others have pointed out you're looking at a base 64 encoding which you'll often have to do on your own depending on the library you're using.

Now if you're struggling with owned vs borrowed strings that's a whole other matter. You can insert some magic into your functions with generics and trait constraints and into your structures with the Cow type (clone on write).


since we know that Sha256::new() will always produce 'valid' characters for utf8 you can just do

    let my_rust_string = str::from_utf8(result).unwarp() 

If there is a possibility of an error, (you read it from file, network ...) you can do:

    let my_rust_string = match str::from_utf8(result) {
        Ok(str) => str,
        Err(err) => panic!("Invalid utf8: {}", err),
    };
 
Or you can do lossy conversion (will have that question mark on chars that it cant decode)

    let my_rust_string = String::from_utf8_lossy(result);

edit: Ok so i read sha2 api wrong. result() is raw bytes and result_str() is hex encoded string. Above wont be much use for either. And others have already explained what to use.

I just stared programming in rust several months ago, and that was my pain also, since where i live we still have some other encoding in use.


I'm well versed in Rust but I think you might need to use

str::from_utf8(result.as_slice())

https://docs.rs/generic-array/0.8.2/generic_array/struct.Gen...

https://doc.rust-lang.org/std/str/fn.from_utf8.html


That would be correct if the bytes were a string encoded in utf-8, but that's probably not the case for the output of a hash function.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: