starting inner keccak explanation
This commit is contained in:
+96
-1
@@ -25,13 +25,15 @@ special cases of Keccak.
|
|||||||
- [Erlang code (fast)](https://github.com/pharpend/kek/blob/8a8a655a80c26ae32763cc25f1e0df8ab0653c82/kek_fast.erl)
|
- [Erlang code (fast)](https://github.com/pharpend/kek/blob/8a8a655a80c26ae32763cc25f1e0df8ab0653c82/kek_fast.erl)
|
||||||
- [erlang-sha3 library (uses fast version of kek)](https://github.com/zxq9/erlang-sha3/blob/63193654e3c05d8031300ffcd52092f75e8b5c2f/src/sha3.erl#L85-L112)
|
- [erlang-sha3 library (uses fast version of kek)](https://github.com/zxq9/erlang-sha3/blob/63193654e3c05d8031300ffcd52092f75e8b5c2f/src/sha3.erl#L85-L112)
|
||||||
|
|
||||||
#### References
|
### References
|
||||||
|
|
||||||
1. [Helpful lecture][german-lecture]
|
1. [Helpful lecture][german-lecture]
|
||||||
2. [Notes for that lecture][german-lecture-notes]
|
2. [Notes for that lecture][german-lecture-notes]
|
||||||
3. [NIST standard][nist-standard] (btw: the double bar notation means "concatenate")
|
3. [NIST standard][nist-standard] (btw: the double bar notation means "concatenate")
|
||||||
4. [SHA-3 Wikipedia](https://en.wikipedia.org/wiki/SHA-3)
|
4. [SHA-3 Wikipedia](https://en.wikipedia.org/wiki/SHA-3)
|
||||||
|
|
||||||
|
### Pitfalls
|
||||||
|
|
||||||
#### Pitfall: "fast keccak" versus "clear keccak"
|
#### Pitfall: "fast keccak" versus "clear keccak"
|
||||||
|
|
||||||
The main reference is the "clear" Erlang code. The "fast" version is the
|
The main reference is the "clear" Erlang code. The "fast" version is the
|
||||||
@@ -126,6 +128,37 @@ shake(ShakeNumber, Message, OutputBitLength) ->
|
|||||||
keccak(Capacity, ShakeMessage, OutputBitLength).
|
keccak(Capacity, ShakeMessage, OutputBitLength).
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Pitfall: Greek letter steps require two copies of the sponge to compute
|
||||||
|
|
||||||
|
This is the pitfall I ran into, and it stalled this project for months. I
|
||||||
|
couldn't figure out what the issue was, and the project was only saved because
|
||||||
|
Hans took the time to figure out the issue and fix it. The nature of hashing
|
||||||
|
algorithms is that they are all-or-nothing and are hard to decompose. Usually
|
||||||
|
when your code doesn't work, you can do some trial and error to figure out
|
||||||
|
which part of the code is wrong. Not so with hashing.
|
||||||
|
|
||||||
|
This requires a lot of context to explain, and it will make sense when you get
|
||||||
|
to the point in the document. This algorithm has state, which is a 1600-bit
|
||||||
|
bit array. And that state gets updated a lot. The updating procedure involves
|
||||||
|
a lot of `xor`ing this bit against that bit, and computing the parity of this
|
||||||
|
string of bits, etc.
|
||||||
|
|
||||||
|
A lot of it involves crawling down the bit array one bit at a time, and xoring
|
||||||
|
the current bit against certain bits from *the original bit array*, and then
|
||||||
|
keeping a separate copy that has the modifications.
|
||||||
|
|
||||||
|
The mistake I was making was as follows. Let's say that the update to bit 55
|
||||||
|
requires xoring it against bit 30. It generally requires xoring against the
|
||||||
|
**un-updated** bit 30. I didn't catch that detail, and was xoring against the
|
||||||
|
adulterated bit 30.
|
||||||
|
|
||||||
|
There's simply no way to find this mistake from trial and error. It's too
|
||||||
|
subtle.
|
||||||
|
|
||||||
|
You can see the commit where Hans fixed my mistake
|
||||||
|
[here](https://github.com/pharpend/kek/commit/7d67c40e6e1280f4abd4fce9122a71034ebcc142).
|
||||||
|
|
||||||
|
|
||||||
## SHA-s and SHAKE-s
|
## SHA-s and SHAKE-s
|
||||||
|
|
||||||
These are the "porcelain" functions that we show to the outside world. These
|
These are the "porcelain" functions that we show to the outside world. These
|
||||||
@@ -525,7 +558,69 @@ really_squeeze(WetSponge, OutputBitLength, BitRate, ResultAcc)->
|
|||||||
|
|
||||||
## Inner Keccak: the kek operation
|
## Inner Keccak: the kek operation
|
||||||
|
|
||||||
|
This is the `f` function that you see in all the documentation. In inner
|
||||||
|
keccak, the 1600-bit sponge is now thought of as a 5x5x64 3-dimensional array.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- The input is the 1600-bit sponge.
|
||||||
|
- The output is a new 1600-bit sponge.
|
||||||
|
- The sponge is sent through 24 "rounds".
|
||||||
|
- Each round consists of the 5 greek letter steps.
|
||||||
|
- Each Greek letter which is a fairly straightforward transformation to the
|
||||||
|
input bit array.
|
||||||
|
- The Greek letter steps are called theta, rho, pi, chi, and iota.
|
||||||
|
- The iota step depends on which round we are in (indexed `0..23`)
|
||||||
|
|
||||||
|
```erlang
|
||||||
|
%% https://github.com/pharpend/kek/blob/8a8a655a80c26ae32763cc25f1e0df8ab0653c82/kek.erl#L324-L368
|
||||||
|
|
||||||
|
-spec inner_keccak(Sponge) -> NewSponge
|
||||||
|
when Sponge :: <<_:1600>>,
|
||||||
|
NewSponge :: <<_:1600>>.
|
||||||
|
%% @private
|
||||||
|
%% the "inner keccak" function, or the 'f' function
|
||||||
|
%% a bunch of bit bullshit
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
inner_keccak(Sponge) ->
|
||||||
|
rounds(Sponge, 24).
|
||||||
|
|
||||||
|
|
||||||
|
-spec rounds(Sponge, NumRoundsLeft) -> ResultSponge
|
||||||
|
when Sponge :: <<_:1600>>,
|
||||||
|
NumRoundsLeft :: non_neg_integer(),
|
||||||
|
ResultSponge :: <<_:1600>>.
|
||||||
|
%% @private
|
||||||
|
%% do however many rounds
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
% no rounds left
|
||||||
|
rounds(FinalSponge, 0) ->
|
||||||
|
FinalSponge;
|
||||||
|
rounds(Sponge, NumRoundsLeft) ->
|
||||||
|
% NRoundsLeft = 24
|
||||||
|
% idx0 = 0
|
||||||
|
% NRoundsLeft = 1
|
||||||
|
% idx0 = 23
|
||||||
|
RoundIdx0 = 24 - NumRoundsLeft,
|
||||||
|
NewSponge = rnd(RoundIdx0, Sponge),
|
||||||
|
NewNumRoundsLeft = NumRoundsLeft - 1,
|
||||||
|
rounds(NewSponge, NewNumRoundsLeft).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec rnd(RoundIdx0, Sponge) -> NewSponge
|
||||||
|
when RoundIdx0 :: 0..23,
|
||||||
|
Sponge :: <<_:1600>>,
|
||||||
|
NewSponge :: <<_:1600>>.
|
||||||
|
%% @private
|
||||||
|
%% do a single round
|
||||||
|
%% @private
|
||||||
|
|
||||||
|
rnd(RoundIdx0, Sponge) ->
|
||||||
|
iota(RoundIdx0, chi(pi(rho(theta(Sponge))))).
|
||||||
|
```
|
||||||
|
|
||||||
[german-lecture]: https://www.youtube.com/watch?v=JWskjzgiIa4
|
[german-lecture]: https://www.youtube.com/watch?v=JWskjzgiIa4
|
||||||
[german-lecture-notes]: https://www.crypto-textbook.com/download/Understanding-Cryptography-Keccak.pdf
|
[german-lecture-notes]: https://www.crypto-textbook.com/download/Understanding-Cryptography-Keccak.pdf
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Reference in New Issue
Block a user