Code change:
The nonce can just be opaque bytes. The block counter is tricky, as noted in the issue. The "obvious" choice is little-endian, as that is consistent with the philosophy of the designer (as I understand it), but that is not anything more than a guess. Absent strong evidence that big-endian is a better choice, I'm going to err on the side of not making a substantive change here. But I think that we need a consensus call to support that viewpoint.
Here's what 5.4.4 says However, RFC 8439 says: This is a little confusing, but I think the correct way to read this is that the ChaCha function takes the nonce as a 96-bit opaque quantity, and the fact that it's little-endian is an internal detail irrelevant to our purposes, so we should just replace the second sentence with "The remaining 12 bytes are used as the 96-bit ChaCha nonce". This is reinforced by the fact that the test vectors have the nonce as a byte block. The situation with the counter is more complicated because we are told it is both a counter and 32-bits (which might make you think it's an integer parameter), but it is also treated as a little-endian integer, which makes one think it's a bitstring. And then the test vectors treat it as a value, rather than as a bitstring. If you look at code it typically thinks of this as an integer: See, for instance: URL So, I think the right answer here is to think of ChaCha as having the following API: Note that because the value on the wire is in big-endian format, this would invert the nonce, but I think it's the right answer anyway. Otherwise, you're having to pass in the counter in the wrong format on big-endian platforms.
As a completely general note, I don't think it is right to change endianness of crypto wire formats. AES-GCM has a completely backwards neither little nor big endian encoding (byte and bit swapped so no platform wins) this remains so on the wire. Especially for HW processing this is significant. But little endian is also more performant on nearly all relevant platforms today so there is no need to go over board forcing big endian if it can be avoided without insulting RFC's.
Yeah, this should simplify that text some.
I like the proposed change, the text had somewhat confused me when implementing this in a previous life.
I don't think that the reinterpretation of the little-endian thing is safe, as per NAME comment. The takes a byte buffer as input rather than a . That is to allow for different block counter sizes. I'll make the editorial change, but leave the suggestion there alone.
I have a question out to the editor of the PKCS spec. It appears like there are no solid rules in the spec to support any particular position here. I'm going with my best guess at WWDJBD here, but I'm happy to make a change if there is a strong case made for something else.
NAME NAME can we flip this to please? I don't think that we need to change the substance here, but I want to confirm the little-endian/big-endian choice here. I hope to have more information to share on the question soon, but that might not be definitive. We might just have to make a call ourselves. Absent better information, I'm going to suggest that we continue with little-endian, but I this is far from an obvious conclusion.
The API I'm using for ChaCha20 takes a const uint8_t nonce[12], and I currently pass in a pointer (offset by 4 bytes) to the sample as the nonce, without doing any endianness conversions. I'm in favor of clarifying the language for this input. (Given that this has the design label instead of the editorial label, my design opinion is to keep with the simple thing of passing the bytes directly from the sample to the nonce input of ChaCha20 and not do any endianness conversions. I'm assuming that other crypto libraries have similar APIs though.)
The API I have takes . PKCS takes pointers just like the API NAME refers to (but it fails to specify the endianness, which is a critical oversight, compounded by the fact that the size of the counter can vary). I suspect that - as NAME says - the right idea is to note that ChaCha20 will interpret the nonce as three little-endian integers and that the counter might be expressed as a byte sequence that is then (probably) interpreted as a little-endian integer.
I understand and appreciate this being marked as “design”, though I consider the text that landed in master as editorial, as it (in my view) ended as adding practical advice while retaining the definition we have had.
Yes, but as a design issue, we want to confirm that "no action" is the correct outcome. It's cheap enough to do so.
I like the updated text. It reads good as it gives the practical advice first, then amends that with the formal definition.

Related discussion:
text: ChaCha20 function as defined in Section 2.4 of CHACHA.  This uses a 256-bit key and 16 bytes sampled from the packet protection output. <del> The first 4 bytes of the sampled ciphertext are interpreted as a 32-bit number in little-endian order and are used as the block count. The remaining 12 bytes are interpreted as three concatenated 32-bit numbers in little-endian order and used as the nonce. </del> <ins> The first 4 bytes of the sampled ciphertext are the block counter.  A ChaCha20 implementation could take a 32-bit integer in place of a byte sequence, in which case the byte sequence is interpreted as a little-endian value. The remaining 12 bytes are used as the nonce.  A ChaCha20 implementation might take an array of three 32-bit integers in place of a byte sequence, in which case the nonce bytes are interpreted as a sequence of 32-bit little-endian integers. </ins> The encryption mask is produced by invoking ChaCha20 to protect 5 zero bytes.  In pseudocode: