How do I convert a string to hex in Rust?

14,012

Solution 1

I will go out on a limb here, and suggest that the solution is for hash to be of type Vec<u8>.


The issue is that while you can indeed convert a String to a &[u8] using as_bytes and then use to_hex, you first need to have a valid String object to start with.

While any String object can be converted to a &[u8], the reverse is not true. A String object is solely meant to hold a valid UTF-8 encoded Unicode string: not all bytes pattern qualify.

Therefore, it is incorrect for gen_sha256 to produce a String. A more correct type would be Vec<u8> which can, indeed, accept any bytes pattern. And from then on, invoking to_hex is easy enough:

hash.as_slice().to_hex()

Solution 2

It appears the source for ToHex has the solution I'm looking for. It contains a test:

#[test]
pub fn test_to_hex() {
    assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172");
}

My revised code is:

let hash = gen_sha256("example");

hash.as_bytes().to_hex()

This appears to work. I will take some time before I accept this solution if anyone has an alternative answer.

Solution 3

A hexadecimal representation can be generated with a function like this:

pub fn hex_push(buf: &mut String, blob: &[u8]) {
    for ch in blob {
        fn hex_from_digit(num: u8) -> char {
            if num < 10 {
                (b'0' + num) as char
            } else {
                (b'A' + num - 10) as char
            }
        }
        buf.push(hex_from_digit(ch / 16));
        buf.push(hex_from_digit(ch % 16));
    }
}

This is a tad more efficient than the generic radix formatting implemented currently in the language.

Here's a benchmark:

test bench_specialized_hex_push   ... bench:          12 ns/iter (+/- 0) = 250 MB/s
test bench_specialized_fomat      ... bench:          42 ns/iter (+/- 12) = 71 MB/s
test bench_specialized_format     ... bench:          47 ns/iter (+/- 2) = 63 MB/s
test bench_specialized_hex_string ... bench:          76 ns/iter (+/- 9) = 39 MB/s
test bench_to_hex                 ... bench:          82 ns/iter (+/- 12) = 36 MB/s
test bench_format                 ... bench:          97 ns/iter (+/- 8) = 30 MB/s

Solution 4

Thanks to the user jey in the ##rust irc channel in freenode. You can just use the hex representation fmt provides,

>> let mut s = String::new();
>> use std::fmt::Write as FmtWrite; // renaming import to avoid collision
>> for b in "hello world".as_bytes() { write!(s, "{:02x}", b); }
()
>> s
"68656c6c6f20776f726c64"
>> 

or a bit silly one,

>> "hello world".as_bytes().iter().map(|x| format!("{:02x}", x)).collect::<String>()
"68656c6c6f20776f726c64"
Share:
14,012
leshow
Author by

leshow

Updated on July 22, 2022

Comments

  • leshow
    leshow over 1 year

    I want to convert a string of characters (a SHA256 hash) to hex in Rust:

    extern crate crypto;
    extern crate rustc_serialize;
    
    use rustc_serialize::hex::ToHex;
    use crypto::digest::Digest;
    use crypto::sha2::Sha256;
    
    fn gen_sha256(hashme: &str) -> String {
        let mut sh = Sha256::new();
        sh.input_str(hashme);
    
        sh.result_str()
    }
    
    fn main() {
        let hash = gen_sha256("example");
    
        hash.to_hex()
    }
    

    The compiler says:

    error[E0599]: no method named `to_hex` found for type `std::string::String` in the current scope
      --> src/main.rs:18:10
       |
    18 |     hash.to_hex()
       |          ^^^^^^
    

    I can see this is true; it looks like it's only implemented for [u8].

    What am I to do? Is there no method implemented to convert from a string to hex in Rust?

    My Cargo.toml dependencies:

    [dependencies]
    rust-crypto = "0.2.36"
    rustc-serialize = "0.3.24"
    

    edit I just realized the string is already in hex format from the rust-crypto library. D'oh.

  • Levans
    Levans over 9 years
    Well, this clarified your problem, and is probably the simplest way to achieve it.
  • Shepmaster
    Shepmaster over 9 years
    This is absolutely the correct solution. rustc itself does this for the sha256 it generates, in fact.
  • leshow
    leshow over 9 years
    I'm new to rust, therefore I'm not too familiar with conversion between types. I returned the 'String' type because the library I'm using returns that type for the hash. How might I rewrite this gen_sha256 so it returns a Vec<u8>? (posted function in OP)
  • Matthieu M.
    Matthieu M. over 9 years
    Which library do you use? And if it does use a String, are you sure it is not already HEX encoded? From String to Vec<u8> you can use as_bytes().collect(), but I am worried that there might be a deeper issue. (For example, in the rustc library linked above by Shepmaster, to return a String it actually calls the version that returns a Vec<u8> and then hex encode it: self.result_bytes().to_hex().to_string(), where result_bytes returns Vec<u8>)
  • leshow
    leshow over 9 years
    the library actually does return it as a hex encoded string. in the code that I was writing I actually wanted to convert a regular string into a hex string, but I just used the sha256 hash as my test string... forgetting that a sha256 hash is already in hex format lol.
  • leshow
    leshow over 9 years
    I'm actually converting this string to hex format: let random_chars: Vec<u8> = task_rng().gen_iter::<u8>().take(take_num).collect(); I took your advice and made it a Vec<u8>
  • Shepmaster
    Shepmaster about 6 years
    Presumably this is already implemented in a crate and every person who want to convert doesn't need to copy/paste this...
  • Shepmaster
    Shepmaster about 6 years
    I'm sorry, I didn't mean to cause offense. I'm genuinely curious — why is this code better than the crate which has the sole purpose of converting byte slices to hex?
  • ArtemGr
    ArtemGr about 6 years
    @Shepmaster, This code is simple enough to be educational and can be easily adopted to anyone's needs, easily fit into unanticipated abstractions. Benchmark is educational as well. On the other hand, spawning a third hex crate for something that simple would only bring namespace pollution and distract me from doing things that are more important. Hopefully this explains why it should be there and not in a crate. A question for you to consider: why giving other people advice they haven't asked for is better for you than getting more time for yourself and your own projects?
  • Shepmaster
    Shepmaster about 6 years
    I truly apologize for insulting/offending you, it was not my intent. However, I'm not talking to just you, but also to everyone else who comes to this answer later, so I'll state my point plainly and move on: this code is accurate, works and understanding it is useful. However, I believe that no one should use it because by copy-and-pasting it locally you are increasing your own maintenance burden. Instead, one should use the hex crate. In addition to having a maintainer, based on some quick benchmarks I did, the crate is faster than this code.
  • Stargateur
    Stargateur about 6 years
    @ArtemGr "A question for you to consider: why giving other people advice they haven't asked for is better for you than getting more time for yourself and your own projects?", a question for you, did you forget that you are on stackoverflow ? It's a collaborative site ! Comments are exactly here for "giving other people advice they haven't asked".
  • ArtemGr
    ArtemGr about 6 years
    I'd like to similarly warn "everyone else who comes to this answer later" from spamming their code with unnecessary crates and abstractions. The more top-level abstractions you have, the more complex and less maintainable you project becomes. This is called over-design. Copying is fine when it's practical, see Rule of three. And you can learn more about the benefits of inline code at youtube.com/watch?v=5Nc68IdNKdg.
  • ArtemGr
    ArtemGr about 6 years
    You're missing the point, @Stargateur. Shepmaster tries to get in my head and tell me how I should spend my personal time (by making new crates or advertising the existing ones, etc). I gave him a personal question in return. The question was not about Stackoverflow, it was about Shepmaster specifically. As for the comments and advice, no-one likes it when it's presumptuous. I make everyone's life better by reminding Shepmaster that people need some personal space.
  • misnomer___
    misnomer___ almost 6 years
    I get this error "no method named to_hex found for type &[u8] in the current scope" when using to_hex. What am I doing wrong here?
  • Matthieu M.
    Matthieu M. almost 6 years
    @misnomer___: Most likely, you forgot to bring the trait into scope. In Rust, inherent methods can be used without any further fuss, but trait methods require that the trait be in scope (otherwise, it's unclear which trait they came from). Insert use rustc_serialize::hex::ToHex; and it should work.
  • leshow
    leshow over 5 years
    @ArtemGr you're violating the 'rule of three' by putting this function verbatim in your code though. There are surely more than three people who need this function, therefore it should be refactored and moved to a single place. The code is very informational though, so thank you for that.
  • ArtemGr
    ArtemGr over 5 years
    It might be a dangerous rationalization, @leshow. Next time you're writing a function you might think "but surely there are more than three people who need this", which in turn might prevent you from enjoying the flexibility of the Rule of three and YAGNI.