Advanced EOS Series — Part 1 — Cryptographic Hashes

Welcome to the Advanced EOS development series where I’ll be touching on techniques and functionality which is rarely covered by tutorials and courses. The purpose of this series is to bring together the missing pieces you’ll need to complete your skills as an application developer on the EOS network. Each post is ordered by difficulty, so if you’d like a general overview I’d recommend starting right here and working your way up. The full code for these examples can be found here on GitHub.

As these are advanced or extended topics, I’m dangerously assuming you already know the basics and are looking to further your knowledge. For that reason, the code shared in these articles will be concise to the topic being discussed.

The Cryptographic Hash Function

Let’s begin by looking at hashes, all resources for this example can be found here on GitHub. In cryptography, a hashing algorithm takes an input and generates a fixed sized jumble known as the output digest. The digest is deterministic and irreversible, meaning the same input will always generate the same output and the output can’t be reversed to obtain the original input. A good hashing algorithm minimizes output collision by using a ‘high degree of difficulty’ in the shortest amount of computation time. Collision or clashing being the likelihood of two different inputs producing the same output.

Application of Hashes

Typically we will use a hash function for authentication and indexing data, I like to think of it as a method of compressing uniqueness. For example, comparing two arbitrarily sized files or users emails would be time intensive and expose vulnerable user data. We could instead generate a fingerprint by hashing the files contents or users email and more efficiently index and compare the data using the hash result.

This is as about as much as we need to know at this point, but if you’d like to itch your curiosity then I’d encourage some proactive Googling or take a look at Blockgeeks article on The In’s and Outs of Cryptographic Hash Functions.

Coding Our Hash Function

Now that we have a very basic understanding of hashes, we can look into how to generate our very own within our EOS smart contract. We’re going to create an action which takes an input string and outputs a checksum256 hash digest, then for the purpose of this example, print the result.

Let’s start by including the crypto.h library and the EOS print.h wrapper from the EOS framework.

include <eosiolib/crypto.h>
Notice the .h extension on our crypto.h filename? This means we're using a C library and not C++, so our methods will be expecting C type inputs.

Now we can define our action and allocate a reference for our checksum256 output like so.

checksum256 sum{};

The EOS framework provides a set of methods for various hashing algorithms. We’ll use the sha256 for this example because it’s fast, secure and typical used in most cases.

sha256(const_cast<char*>(str.c_str()), str.size(), &sum);

Our sha256 method expects C type inputs, so we first need to convert our string to a char set, then pass the size of the string and a checksum256 reference which will be updated with the output digest. Now all that remains is printing the hashed output result.

printhex(&sum, sizeof(sum));

We could also return the checksum256 here and use it as a private internal action.

Taking it Further — Checksum to String

Credit for this implementation goes to Miguel Mota for developing a solution to convert checksum256 too a hexadecimal string.

So what happens if we want to convert our digest back into a string? For this we will need a new method. To begin with, let’s define a template for our input argument and define the method itself. This template is defined outside of our method definition, typically at the top of our file. Templates simply allow us to define the variable type at the time we call the function, then the compiler will take care of substitution and making it all work.

template <typename CharT>
string to_hex(const CharT* data, uint32_t length) {
// Method Body

Now we can start working on the body of our method. To start with we will create a string for our result, a char set to draw characters from later, and force our data to a uint8_t.

string result;
const char* hex_chars = "0123456789abcdef";
uint8_t* c = (uint8_t*)data;

Finally we will iterate over each char in our input data, match the corresponding hexadecimal character, and append it to our resulting string.

for (uint32_t i = 0; i < length; ++i) {
(result += hex_chars[(c[i] >> 4)]) += hex_chars[(c[i] & 0x0f)];
return result;

And that’s it! We now have a method to create a checksum256 from a char set, and a method to convert that checksum256 into a string. In the next article we will be looking at singletons and how we can utilize them to store application state and configuration.

What’s next?

Make sure you click the follow button if you would like to be notified when I share more examples in this series. Part 2 will be covering how we can utilize Singletons in EOS to store contract state and configuration.

Click to read today’s top story