Why the ChaCha20 - IETF algorithm that generates 512 bit keystream per 32 bit counter (that gets incremented), considers "the input words" that form the internal state as little endian ? What will happen if it was considered "big endian" ?

Moreover, we read the byte strings for key, nonce, etc in such a way that we get little endian integers. For example, if I have a 32 byte key in hex like : 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f

we get

uint32_t key[8] = {
      0x03020100, 0x07060504 0x0b0a0908, 0x0f0e0d0c
                0x13121110 ,0x17161514, 0x1b1a1918, 0x1f1e1d1c

I was writing a C++ implementation of ChaCha20 that requires this array to be copied to the right positions in the internal state. Specifically speaking I'm more interested in using XChaCha20 - Poly1305 - IETF (as it supports a 192 bit nonce) and for that I have to use a separate function HChaCha20 to generate a 256 bit subkey to be passed to the normal ChaCha20 . But these quotes from the IETF documents (Sec 2.2.1 ) confused me :

After setting up the HChaCha state, it looks like this:

                61707865 3320646e 79622d32 6b206574
                03020100 07060504 0b0a0908 0f0e0d0c
                13121110 17161514 1b1a1918 1f1e1d1c
                09000000 4a000000 00000000 27594131

                 ChaCha state with the key setup.

After running 20 rounds (10 column rounds interleaved with 10 "diagonal rounds"), the HChaCha state looks like this:

                423b4182 fe7bb227 50420ed3 737d878a
                0aa76448 7954cdf3 846acd37 7b3c58ad
                77e35583 83e77c12 e0076a2d bc6cd0e5
                d5e4f9a0 53a8748a 13c42ec1 dcecd326

                   HChaCha state after 20 rounds

HChaCha20 will then return only the first and last rows, in little endian, resulting in the following 256-bit key:

                82413b42 27b27bfe d30e4250 8a877d73
                a0f9e4d5 8a74a853 c12ec413 26d3ecdc

                    Resultant HChaCha20 subkey

From the above example it looks like what HChaCha20 should return is an array of little endian integers, but why is it swapped in the end ? Didn't we consider the nonce, key, counter everything as little endian in the first place !? Why do we again make it little endian again if we are returning an array of uint32_t integers (which are by default little endian on my platform), or is the author referring to converting the array to byte string (unsigned char array) ? Please do clarify where I went wrong... Every help will be appreciated!

  • 3
    $\begingroup$ Intel CPU's? The final permutation that effect the next calls? $\endgroup$ – kelalaka Mar 22 at 19:19
  • 3
    $\begingroup$ To expand a little on kelakaka's response, little endian is the most common integer format today because it's used on Intel and compatible CPUs, so using that format provides the best performance for the most people. A lot of Bernstein's work is about having good performance on commonly used hardware. $\endgroup$ – Swashbuckler Mar 22 at 20:46
  • $\begingroup$ @Swashbuckler If the result HChaCha20 after all the permutations is an array of little endian integers, why do we "again" make it little endian when returning the subkey. Is the author of the IETF reference document referring to serializing the array to a byte string ? $\endgroup$ – Vivekanand V Mar 22 at 21:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.