<p>In the following, I try to minimize the background knowledge needed to understand the answer. If you need more details, I suggest taking a look at section 12.2 of <a href="http://williamstallings.com/Crypto/Crypto4e.html" rel="nofollow">Cryptography and Network Security Principles and Practices, Fourth Edition</a>. (Though it requires a fair knowledge of crypto.)</p>

<hr>

<p>First take a look at <a href="http://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction" rel="nofollow">Merkle–Damgård construction</a>. Virtually all hash functions follow such construction. Informally, it applies a <em>compression function</em> iteratively to reduce the input size to get some fixed-length output. For instance, you can hash a whole DVD (~ 4.3 GB) and get a 128-bit code.</p>

<p>Let $M$ be the input to an MD-based hash function. The MD construction appends a pad and the length of $M$ to it, so as to prevent several attacks.</p>

<p>Whirlpool uses a compression function named $W$. $W$ is similar to a block cipher named <a href="http://en.wikipedia.org/wiki/Rijndael" rel="nofollow">Rijndael</a>, which is now standardized under the name AES (Advanced Encryption Standard). Rijndael has 3 variants: 128-bit, 192-bit, and 256-bit. The inventors of Whirlpool decided that no Rijndael variant is secure enough to be used as the compression function for a hash. Thus, $W$ is designed so as it accepts 512-bit inputs, and produces 512-bit outputs. The key size of $W$ is 512 bits as well.</p>

<p>Whirlpool works as follows. Let $M$ be the input. $M$ is divided into 512-bit segments: $M=(M_0,M_1,\ldots,M_t)$. Let $h_0$ be some initial value (fixed by Whirlpool standard). </p>

<p>For $i=1,2,\ldots,t$, apply $W$ iteratively as follows:</p>

<p>$h_i = W(h_{i-1},m_i) \oplus h_{i-1} \oplus m_i$</p>

<p>where the first input to $W$ is a <strong>block-to-be-encrypted</strong>, and its second input is the <strong>encryption key</strong>. $\oplus$ denotes the XOR operation.</p>

<p>$h_t$ is considered as the output of the Whirlpool hash function.</p>

<p>The whole complexity lies in designing $W$. As pointed out before, it is similar to Rijndael, so you can understand it if you get familiar with Rijndael, on which I have designed a <a href="http://ce.sharif.edu/courses/88-89/2/ce442-1/resources/root/AES/Slides.pptx" rel="nofollow">set of slides</a>. The slides are self-contained and do not assume any math background beyond high school.</p>

CC BY-SA 2.5
2010-11-06T14:47:58.190Z
That certainly made things a lot clearer, thank you for your efforts. Yuval also gets a +1 for helping to understand how to use the code
Oystein
CC BY-SA 2.5
2010-11-06T07:28:59.830Z
2010-11-06T07:28:59.830Z
Sadeq Dousti
<p>The API for using Whirlpool consists of the functions NESSIEInit, NESSIEadd and NESSIEFinalize.</p>

<p>The first function initializes an instance of NESSIEstruct (in the C version). You the enter the data using NESSIEadd. You get the hash using NESSIEfinalize.</p>

<p>The only non-trivial part is how to add the data. The function that adds data gets a vector of bytes and its length in bits; the last byte can be partial, but I guess you have no need for that.</p>

<p>You can add data as many times as you want; adding $d_1$ then $d_2$ then $d_3$ is the same as adding $d_1d_2d_3$, i.e. it doesn't matter how you break the input. It's like an input stream then gets a vector of bits and takes care of everything else.</p>

<p>Internally, it's a pretty standard hash function built around an AES variant. The hash function works on chunks of 512 bits - you have to be careful about padding if your input isn't an integer multiple of this (if you do this improperly, there are some simple attacks).</p>

<p>The internal state S is also 512 bits, and is init with zero. To process a block B, first encrypt S using some constant round keys; the intermediate results are used as round keys for an encryption of B. Xor the result (B encrypted with round keys generated from S) to S and to B to get the new S. The hash itself is the value of S after the last input block.</p>

<p>All encryptions are with respect to the AES-like cipher, which is pretty similar to AES but uses for example a different S-box and a different MDS (there are other small differences).</p>

CC BY-SA 2.5
2010-11-05T23:50:50.650Z
Aha. But why three functions instead of one? Also I notice some of the code has an `#ifdef OBSOLETE` wrapping - what is that for? Can I remove it to reduce file size?
Oystein
CC BY-SA 2.5
2010-11-06T00:01:10.483Z
Also when you say that you have to be careful with the padding, do you mean that the user (me) of the API should pad the input data, or were you talking about the inner workings of the API? The way I understand it, padding is a part of the hash function?
Oystein
CC BY-SA 2.5
2010-11-06T01:21:14.597Z
@oystein, while this site is a great place to ask about an algorithm - it's less good of a place to ask about specific code. That said (without looking at the code), #ifdef is normally used for conditional compilation. If you're working with "good" code, it's probably there to save space/time rather than the opposite (and could even have an effect of the correctness of the code).
Daniel Apon
CC BY-SA 2.5
2010-11-06T23:06:12.643Z
Padding is taken care of by the API. If you use the API, you don't have to pad - it probably won't hurt, but there's no reason for you to.
Yuval Filmus
CC BY-SA 2.5
2010-11-06T23:06:57.043Z
Re the OBSOLETE parts, I don't know why it's there, but this code doesn't get compiled, so all that happens when you remove it is that the source code gets smaller; the compiled code remains the same.
Yuval Filmus
CC BY-SA 2.5
2010-11-06T23:50:16.417Z
Re why three functions, this is for flexibility. If you always want to deliver the data in one piece, you can write a function for that. In many applications data comes streaming it and you want to calculate its hash on-the-fly so that you can check it once the stream is complete (communication is slower than computing, so you have extra time to calculate the hash).
Yuval Filmus
CC BY-SA 2.5
2010-11-05T23:27:39.843Z
2010-11-05T23:27:39.843Z
Yuval Filmus
<p>Note: Question originally asked on <a href="https://stackoverflow.com/questions/4108595/an-explanation-of-whirlpool-c-implementation-or-the-general-algorithm">StackOverflow</a> - was directed here</p>

<p>Anyone got a tutorial on the designers concept implementation of Whirlpool in C, or the Whirlpool algorithm in general? I find the source code hard to understand, mostly because I do not know anything about the algorithm. I am not a cryptographer, nor am I a good mathematician, so their documentation kind of went over my head...</p>

<p>The implementation and other documentation can be found <a href="http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html" rel="nofollow noreferrer">here</a>.</p>

<p>Initially I was just searching for a free (public domain) implementation to use in a project, but I figured I better know something about it as well... Currently I do not even know how to use it.</p>

CC BY-SA 2.5
2010-11-05T22:25:46.107Z
Also, it would be good if somebody with enough rep could retag the question to something more sane.. Any attempt from me to tag it caused an error because the tags did not exist
Oystein
CC BY-SA 2.5
2010-11-05T22:36:18.407Z
Next time please include the link to your specific question instead of the link to the top page of stackoverflow.com.
Tsuyoshi Ito
CC BY-SA 2.5
2010-11-05T22:37:34.033Z
Good point. Fixed. EDIT: You fixed it.
Oystein
CC BY-SA 2.5
2010-11-05T23:26:50.183Z
I don't know of any tutorial.  You might find useful information at http://en.wikipedia.org/wiki/One-way_compression_function, and specifically in the "Construction from block ciphers" and "Miyaguchi–Preneel" sections.  Whirlpool is a special case of the Miyagushi-Preneel method for building hash functions from block ciphers.

If those don't help, can you be more specific in what you hope to learn?
David Cash
CC BY-SA 2.5
2010-11-05T23:32:13.177Z
I don't think you need to know anything about the internal workings of the algorithm in this case, as long as you use the provided API. On the other hand, you can certainly misuse hash functions in a generic way.
Yuval Filmus
<ds.algorithms><cr.crypto-security>
An explanation of Whirlpool C implementation - or the general algorithm
Oystein
# An explanation of Whirlpool C implementation - or the general algorithm

(Asked by: username_0 on 2010-11-05)

Note: Question originally asked on [StackOverflow](https://stackoverflow.com/questions/4108595/an-explanation-of-whirlpool-c-implementation-or-the-general-algorithm) - was directed here

Anyone got a tutorial on the designers concept implementation of Whirlpool in C, or the Whirlpool algorithm in general? I find the source code hard to understand, mostly because I do not know anything about the algorithm. I am not a cryptographer, nor am I a good mathematician, so their documentation kind of went over my head...

The implementation and other documentation can be found [here](http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html).

Initially I was just searching for a free (public domain) implementation to use in a project, but I figured I better know something about it as well... Currently I do not even know how to use it.

**Tags:** ds.algorithms, cr.crypto-security
> **Comments:**
> **username_0**: Also, it would be good if somebody with enough rep could retag the question to something more sane.. Any attempt from me to tag it caused an error because the tags did not exist  
> **username_1**: Next time please include the link to your specific question instead of the link to the top page of stackoverflow.com.  
> **username_0**: Good point. Fixed. EDIT: You fixed it.  
> **username_2**: I don't know of any tutorial.  You might find useful information at http://en.wikipedia.org/wiki/One-way_compression_function, and specifically in the "Construction from block ciphers" and "Miyaguchi–Preneel" sections.  Whirlpool is a special case of the Miyagushi-Preneel method for building hash functions from block ciphers.  If those don't help, can you be more specific in what you hope to learn?  
> **username_3**: I don't think you need to know anything about the internal workings of the algorithm in this case, as long as you use the provided API. On the other hand, you can certainly misuse hash functions in a generic way.  

---

## 2 answers

### Answer by username_4 on 2010-11-06. Score: 5 | Accepted answer

In the following, I try to minimize the background knowledge needed to understand the answer. If you need more details, I suggest taking a look at section 12.2 of [Cryptography and Network Security Principles and Practices, Fourth Edition](http://williamstallings.com/Crypto/Crypto4e.html). (Though it requires a fair knowledge of crypto.)

---

First take a look at [Merkle–Damgård construction](http://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction). Virtually all hash functions follow such construction. Informally, it applies a *compression function* iteratively to reduce the input size to get some fixed-length output. For instance, you can hash a whole DVD (~ 4.3 GB) and get a 128-bit code.

Let $M$ be the input to an MD-based hash function. The MD construction appends a pad and the length of $M$ to it, so as to prevent several attacks.

Whirlpool uses a compression function named $W$. $W$ is similar to a block cipher named [Rijndael](http://en.wikipedia.org/wiki/Rijndael), which is now standardized under the name AES (Advanced Encryption Standard). Rijndael has 3 variants: 128-bit, 192-bit, and 256-bit. The inventors of Whirlpool decided that no Rijndael variant is secure enough to be used as the compression function for a hash. Thus, $W$ is designed so as it accepts 512-bit inputs, and produces 512-bit outputs. The key size of $W$ is 512 bits as well.

Whirlpool works as follows. Let $M$ be the input. $M$ is divided into 512-bit segments: $M=(M\_0,M\_1,\ldots,M\_t)$. Let $h\_0$ be some initial value (fixed by Whirlpool standard).

For $i=1,2,\ldots,t$, apply $W$ iteratively as follows:

$h\_i = W(h\_{i-1},m\_i) \oplus h\_{i-1} \oplus m\_i$

where the first input to $W$ is a **block-to-be-encrypted**, and its second input is the **encryption key**. $\oplus$ denotes the XOR operation.

$h\_t$ is considered as the output of the Whirlpool hash function.

The whole complexity lies in designing $W$. As pointed out before, it is similar to Rijndael, so you can understand it if you get familiar with Rijndael, on which I have designed a [set of slides](http://ce.sharif.edu/courses/88-89/2/ce442-1/resources/root/AES/Slides.pptx). The slides are self-contained and do not assume any math background beyond high school.

> **Comments:**
> **username_0**: That certainly made things a lot clearer, thank you for your efforts. Yuval also gets a +1 for helping to understand how to use the code  

---

### Answer by username_3 on 2010-11-05. Score: 3

The API for using Whirlpool consists of the functions NESSIEInit, NESSIEadd and NESSIEFinalize.

The first function initializes an instance of NESSIEstruct (in the C version). You the enter the data using NESSIEadd. You get the hash using NESSIEfinalize.

The only non-trivial part is how to add the data. The function that adds data gets a vector of bytes and its length in bits; the last byte can be partial, but I guess you have no need for that.

You can add data as many times as you want; adding $d\_1$ then $d\_2$ then $d\_3$ is the same as adding $d\_1d\_2d\_3$, i.e. it doesn't matter how you break the input. It's like an input stream then gets a vector of bits and takes care of everything else.

Internally, it's a pretty standard hash function built around an AES variant. The hash function works on chunks of 512 bits - you have to be careful about padding if your input isn't an integer multiple of this (if you do this improperly, there are some simple attacks).

The internal state S is also 512 bits, and is init with zero. To process a block B, first encrypt S using some constant round keys; the intermediate results are used as round keys for an encryption of B. Xor the result (B encrypted with round keys generated from S) to S and to B to get the new S. The hash itself is the value of S after the last input block.

All encryptions are with respect to the AES-like cipher, which is pretty similar to AES but uses for example a different S-box and a different MDS (there are other small differences).

> **Comments:**
> **username_0**: Aha. But why three functions instead of one? Also I notice some of the code has an `#ifdef OBSOLETE` wrapping - what is that for? Can I remove it to reduce file size?  
> **username_0**: Also when you say that you have to be careful with the padding, do you mean that the user (me) of the API should pad the input data, or were you talking about the inner workings of the API? The way I understand it, padding is a part of the hash function?  
> **username_5**: @oystein, while this site is a great place to ask about an algorithm - it's less good of a place to ask about specific code. That said (without looking at the code), #ifdef is normally used for conditional compilation. If you're working with "good" code, it's probably there to save space/time rather than the opposite (and could even have an effect of the correctness of the code).  
> **username_3**: Padding is taken care of by the API. If you use the API, you don't have to pad - it probably won't hurt, but there's no reason for you to.  
> **username_3**: Re the OBSOLETE parts, I don't know why it's there, but this code doesn't get compiled, so all that happens when you remove it is that the source code gets smaller; the compiled code remains the same.  
> **username_3**: Re why three functions, this is for flexibility. If you always want to deliver the data in one piece, you can write a function for that. In many applications data comes streaming it and you want to calculate its hash on-the-fly so that you can check it once the stream is complete (communication is slower than computing, so you have extra time to calculate the hash).  

---

