reorganizing/commenting code
This commit is contained in:
@@ -3,38 +3,130 @@
|
|||||||
%% 1. Helpful lecture: https://www.youtube.com/watch?v=JWskjzgiIa4
|
%% 1. Helpful lecture: https://www.youtube.com/watch?v=JWskjzgiIa4
|
||||||
%% 2. NIST standard: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
%% 2. NIST standard: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
||||||
%% (btw: the double bar notation means "concatenate")
|
%% (btw: the double bar notation means "concatenate")
|
||||||
|
%% 3. https://en.wikipedia.org/wiki/SHA-3
|
||||||
%% @end
|
%% @end
|
||||||
-module(kek).
|
-module(kek).
|
||||||
|
|
||||||
% theta and rho steps are done
|
% theta and rho steps are done
|
||||||
% weird syntax errors
|
|
||||||
|
|
||||||
-compile(export_all).
|
-compile(export_all).
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%% TOP LEVEL API
|
||||||
|
%%%
|
||||||
|
%%% sha*s and shake*s
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
-spec sha3_224(Message) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
Digest :: <<_:224>>.
|
||||||
|
%% @doc
|
||||||
|
%% SHA-3 with an output bit length of 224 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
sha3_224(Message) ->
|
sha3_224(Message) ->
|
||||||
sha3(224, Message).
|
sha3(224, Message).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec sha3_256(Message) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
Digest :: <<_:256>>.
|
||||||
|
%% @doc
|
||||||
|
%% SHA-3 with an output bit length of 256 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
sha3_256(Message) ->
|
sha3_256(Message) ->
|
||||||
sha3(256, Message).
|
sha3(256, Message).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec sha3_384(Message) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
Digest :: <<_:384>>.
|
||||||
|
%% @doc
|
||||||
|
%% SHA-3 with an output bit length of 384 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
sha3_384(Message) ->
|
sha3_384(Message) ->
|
||||||
sha3(384, Message).
|
sha3(384, Message).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec sha3_512(Message) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
Digest :: <<_:512>>.
|
||||||
|
%% @doc
|
||||||
|
%% SHA-3 with an output bit length of 512 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
sha3_512(Message) ->
|
sha3_512(Message) ->
|
||||||
sha3(512, Message).
|
sha3(512, Message).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec sha3(OutputBitLength, Message) -> Digest
|
||||||
|
when OutputBitLength :: pos_integer(),
|
||||||
|
Message :: bitstring(),
|
||||||
|
Digest :: <<_:OutputBitLength>>.
|
||||||
|
%% @doc
|
||||||
|
%% SHA-3 with an arbitrary output bit length.
|
||||||
|
%%
|
||||||
|
%% This means Keccak with Capacity = 2*OutputBitLength. Additionally, SHA3
|
||||||
|
%% concatenates the bits 01 onto the end of the input, before sending the
|
||||||
|
%% Message to keccak/3.
|
||||||
|
%% @end
|
||||||
|
|
||||||
sha3(OutputBitLength, Message) ->
|
sha3(OutputBitLength, Message) ->
|
||||||
Capacity = 2*OutputBitLength,
|
Capacity = 2*OutputBitLength,
|
||||||
ShaMessage = <<Message/bitstring, (2#01):2>>,
|
ShaMessage = <<Message/bitstring, (2#01):2>>,
|
||||||
keccak(Capacity, ShaMessage, OutputBitLength).
|
keccak(Capacity, ShaMessage, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec shake128(Message, OutputBitLength) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: <<_:OutputBitLength>>.
|
||||||
|
%% @doc
|
||||||
|
%% This is the SHAKE variable-length hash with Capacity 256 = 2*128 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
shake128(Message, OutputBitLength) ->
|
shake128(Message, OutputBitLength) ->
|
||||||
shake(128, Message, OutputBitLength).
|
shake(128, Message, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec shake256(Message, OutputBitLength) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: <<_:OutputBitLength>>.
|
||||||
|
%% @doc
|
||||||
|
%% This is the SHAKE variable-length hash with Capacity 512 = 2*256 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
shake256(Message, OutputBitLength) ->
|
shake256(Message, OutputBitLength) ->
|
||||||
shake(256, Message, OutputBitLength).
|
shake(256, Message, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec shake256(ShakeNumber, Message, OutputBitLength) -> Digest
|
||||||
|
when ShakeNumber :: pos_integer(),
|
||||||
|
Message :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: <<_:OutputBitLength>>.
|
||||||
|
%% @doc
|
||||||
|
%% This is the SHAKE variable-length hash with Capacity 512 = 2*ShakeNumber bits.
|
||||||
|
%%
|
||||||
|
%% This concatenates the bitstring 1111 onto the end of the Message before
|
||||||
|
%% sending the message to keccak/3.
|
||||||
|
%% @end
|
||||||
|
|
||||||
shake(ShakeNumber, Message, OutputBitLength) ->
|
shake(ShakeNumber, Message, OutputBitLength) ->
|
||||||
Capacity = 2*ShakeNumber,
|
Capacity = 2*ShakeNumber,
|
||||||
ShakeMessage = <<Message, (2#1111):4>>,
|
ShakeMessage = <<Message, (2#1111):4>>,
|
||||||
@@ -42,11 +134,28 @@ shake(ShakeNumber, Message, OutputBitLength) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%% OUTER KECCAK
|
||||||
|
%%%
|
||||||
|
%%% Keccak pads the input, absorbs it into the sponge, and squeezes the bits out
|
||||||
|
%%% of the sponge. The absorption and squeezing phases invoke "inner keccak",
|
||||||
|
%%% which is the heart of the algorithm.
|
||||||
|
%%%
|
||||||
|
%%% - keccak/3
|
||||||
|
%%% - pad/2
|
||||||
|
%%% - absorb/4
|
||||||
|
%%% - squeeze/3
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec keccak(Capacity, Message, OutputBitLength) -> Digest
|
-spec keccak(Capacity, Message, OutputBitLength) -> Digest
|
||||||
when Capacity :: pos_integer(),
|
when Capacity :: pos_integer(),
|
||||||
Message :: bitstring(),
|
Message :: bitstring(),
|
||||||
OutputBitLength :: pos_integer(),
|
OutputBitLength :: pos_integer(),
|
||||||
Digest :: bitstring().
|
Digest :: <<_:OutputBitLength>>.
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Note: this is Keccak 1600, the only one used in practice
|
%% Note: this is Keccak 1600, the only one used in practice
|
||||||
%%
|
%%
|
||||||
@@ -190,6 +299,26 @@ really_squeeze(WetSponge, OutputBitLength, BitRate, ResultAcc)->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%% THE DREADED INNER KECCAK
|
||||||
|
%%%
|
||||||
|
%%% This is the "f" function that appears in all the documentation.
|
||||||
|
%%%
|
||||||
|
%%% The input is the 1600-bit sponge array. inner_keccak/1 sends the input
|
||||||
|
%%% through 24 "rounds". Each round consists of the 5 Greek letter steps, each of
|
||||||
|
%%% which is a weird transformation on the array.
|
||||||
|
%%%
|
||||||
|
%%% In "inner keccak", the input array is thought of as a 5x5x64 3D array. The
|
||||||
|
%%% coordinate system is described in its own section.
|
||||||
|
%%%
|
||||||
|
%%% TODO: iota depends on the round index, so this code may need to be altered
|
||||||
|
%%% slightly.
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec inner_keccak(Sponge) -> NewSponge
|
-spec inner_keccak(Sponge) -> NewSponge
|
||||||
when Sponge :: <<_:1600>>,
|
when Sponge :: <<_:1600>>,
|
||||||
NewSponge :: <<_:1600>>.
|
NewSponge :: <<_:1600>>.
|
||||||
@@ -231,6 +360,21 @@ rnd(Sponge) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% THETA STEP
|
||||||
|
%%
|
||||||
|
%% For each bit in the input array,
|
||||||
|
%% 1. take
|
||||||
|
%% - the bit
|
||||||
|
%% - the 5-bit column to the left
|
||||||
|
%% - the 5-bit column to the front right
|
||||||
|
%% 2. compute the parity of their concatenation (0 if even# of 1s, 1 if odd# of
|
||||||
|
%% 1s)
|
||||||
|
%% 3. set the bit to that parity value
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec theta(Array) -> NewArray
|
-spec theta(Array) -> NewArray
|
||||||
when Array :: <<_:1600>>,
|
when Array :: <<_:1600>>,
|
||||||
NewArray :: <<_:1600>>.
|
NewArray :: <<_:1600>>.
|
||||||
@@ -277,6 +421,33 @@ theta(ArrayBits, ThisIdx0) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec parity(Bits) -> Parity
|
||||||
|
when Bits :: bitstring(),
|
||||||
|
Parity :: 0 | 1.
|
||||||
|
%% @private
|
||||||
|
%% Count the number of 1s in the given bitstring. Return 0 if even, 1 if odd.
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
parity(Bits) ->
|
||||||
|
parity(Bits, 0).
|
||||||
|
|
||||||
|
parity(<<0:1, Rest/bitstring>>, NOnes) -> parity(Rest, NOnes);
|
||||||
|
parity(<<1:1, Rest/bitstring>>, NOnes) -> parity(Rest, NOnes + 1);
|
||||||
|
parity(<<>> , NOnes) -> NOnes rem 2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% RHO STEP
|
||||||
|
%%
|
||||||
|
%% This step applies an affine shift to each 64-bit "lane" (fixed X,Y; Z ranges
|
||||||
|
%% from 0 to 63).
|
||||||
|
%%
|
||||||
|
%% The amount of the shift is given by the "offset" table.
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec rho(Array) -> NewArray
|
-spec rho(Array) -> NewArray
|
||||||
when Array :: <<_:1600>>,
|
when Array :: <<_:1600>>,
|
||||||
NewArray :: <<_:1600>>.
|
NewArray :: <<_:1600>>.
|
||||||
@@ -337,35 +508,6 @@ rhoxy(Array, ThisXY = {xy, ThisX, ThisY}) ->
|
|||||||
NewArray = replace_lane(Array, ThisXY, NewLane),
|
NewArray = replace_lane(Array, ThisXY, NewLane),
|
||||||
NewArray.
|
NewArray.
|
||||||
|
|
||||||
xyth(_, _) -> error(nyi).
|
|
||||||
|
|
||||||
-spec replace_lane(OriginalArray, LaneXY, NewLane) -> NewArray
|
|
||||||
when OriginalArray :: <<_:1600>>,
|
|
||||||
LaneXY :: {xy, 0..4, 0..4},
|
|
||||||
NewLane :: <<_:64>>,
|
|
||||||
NewArray :: <<_:1600>>.
|
|
||||||
%% @private
|
|
||||||
%% take the original array, and swap out the lane at the given x,y coordinate
|
|
||||||
%% with the new given lane. the lane will be represented continuously so we
|
|
||||||
%% can do a hack
|
|
||||||
%% @end
|
|
||||||
|
|
||||||
% special case when it's the last lane
|
|
||||||
% grab the final 64 bits off the original array and replace them with the new lane
|
|
||||||
replace_lane(<<Pre:(1600 - 64), _:64>>, _LaneXY = {xy, 4, 4}, NewLane) ->
|
|
||||||
<<Pre:(1600 - 64), NewLane/bitstring>>;
|
|
||||||
% general case, grab the shit before the lane, grab the shit after the lane
|
|
||||||
% replace the shit in the middle
|
|
||||||
replace_lane(OriginalArray, _LaneXY = {xy, LaneX, LaneY}, NewLane) ->
|
|
||||||
FirstBitOfLane_Idx0 = xyz_to_idx0({xyz, LaneX, LaneY, 0}),
|
|
||||||
FirstBitAfterLane_Idx0 = xyz_to_idx0({xyz, LaneX, LaneY, 63}) + 1,
|
|
||||||
NumberOfBitsBeforeTheLane = FirstBitOfLane_Idx0,
|
|
||||||
NumberOfBitsIncludingTheLane = FirstBitAfterLane_Idx0,
|
|
||||||
<<PreLane:NumberOfBitsBeforeTheLane , _/bitstring>> = OriginalArray,
|
|
||||||
<< _:NumberOfBitsIncludingTheLane, AfterLane/bitstring>> = OriginalArray,
|
|
||||||
Result = <<PreLane:NumberOfBitsBeforeTheLane, NewLane/bitstring, AfterLane/bitstring>>,
|
|
||||||
Result.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-spec offset(X, Y) -> Offset
|
-spec offset(X, Y) -> Offset
|
||||||
@@ -409,17 +551,112 @@ offset(2, 3) -> 15 rem 64.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% PI STEP
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
pi(_Sponge) ->
|
pi(_Sponge) ->
|
||||||
error(nyi).
|
error(nyi).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% CHI STEP
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
chi(_Sponge) ->
|
chi(_Sponge) ->
|
||||||
error(nyi).
|
error(nyi).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% IOTA STEP
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
iota(_Sponge) ->
|
iota(_Sponge) ->
|
||||||
error(nyi).
|
error(nyi).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%% INNER KECCAK COORDINATE SYSTEM
|
||||||
|
%%%
|
||||||
|
%%% Inner Keccak thinks of the 1600-bit input array as a 5x5x64 3D array
|
||||||
|
%%% (5*5*64). This section provides a variety of helper functions to talk about
|
||||||
|
%%% the array using the X,Y,Z coordinate system.
|
||||||
|
%%%
|
||||||
|
%%% The coordinate system is toroidal, meaning that each coordinate is "modded
|
||||||
|
%%% down" to be in the approprate range. For instance, the X-coordinate "to the
|
||||||
|
%%% right" of X=4 is X=0. And likewise, the coordinate "behind" Z=63 is Z=0. See
|
||||||
|
%%% the section on directionality conventions.
|
||||||
|
%%%
|
||||||
|
%%% VOCABULARY:
|
||||||
|
%%%
|
||||||
|
%%% 3D state:
|
||||||
|
%%% - The [state] is the entire 5x5x24 array
|
||||||
|
%%%
|
||||||
|
%%% 0D subsets of the state:
|
||||||
|
%%% - A [bit] is a single bit in the array given by an X,Y,Z coordinate triple
|
||||||
|
%%% (see xyzth/3).
|
||||||
|
%%%
|
||||||
|
%%% 1D subsets of the state:
|
||||||
|
%%% - a [row]
|
||||||
|
%%% - is a 5-bit array
|
||||||
|
%%% - given by a Y,Z coordinate pair in range {0..4, 0..63} (see yzth/2)
|
||||||
|
%%% - you should think of a row as being internally indexed with an X
|
||||||
|
%%% coordinate ranging in 0..4
|
||||||
|
%%% - a [column]
|
||||||
|
%%% - is a 5-bit array
|
||||||
|
%%% - given by an X,Z coordinate pair in range {0..4, 0..63} (see xzth/2)
|
||||||
|
%%% - you should think of a column as being internally indexed with a Y
|
||||||
|
%%% coordinate ranging in 0..4
|
||||||
|
%%% - a [lane]
|
||||||
|
%%% - is a 64-bit array
|
||||||
|
%%% - given by an X,Y coordinate pair in range {0..4, 0..4} (see xyth/2)
|
||||||
|
%%% - you should think of a lane as being internally indexed with a Z
|
||||||
|
%%% coordinate ranging in 0..63.
|
||||||
|
%%%
|
||||||
|
%%% 2D subsets of the state:
|
||||||
|
%%% - a [sheet]
|
||||||
|
%%% - is a 5x64 array
|
||||||
|
%%% - given by a single X coordinate ranging in 0..4 (see xth/2)
|
||||||
|
%%% - you should think of a sheet as being internally indexed by a Y,Z
|
||||||
|
%%% coordinate pair ranging in {0..4, 0..63}.
|
||||||
|
%%% - a [plane]
|
||||||
|
%%% - is a 5x64 array
|
||||||
|
%%% - given by a single Y coordinate ranging in 0..4 (see yth/2)
|
||||||
|
%%% - you should think of a plane as being internally indexed by a X,Z
|
||||||
|
%%% coordinate pair ranging in {0..4, 0..63}.
|
||||||
|
%%% - a [slice]
|
||||||
|
%%% - is a 5x5 array
|
||||||
|
%%% - given by a single Z coordinate ranging in 0..63 (see zth/2)
|
||||||
|
%%% - you should think of a sheet as being internally indexed by a X,Y
|
||||||
|
%%% coordinate pair ranging in {0..4, 0..4}.
|
||||||
|
%%%
|
||||||
|
%%% PACKING CONVENTION:
|
||||||
|
%%%
|
||||||
|
%%% Each lane (64-bit long bitstring given by an {X,Y} <- {0..4, 0..4} coordinate
|
||||||
|
%%% pair and indexed by a Z <- 0..63 coordinate.
|
||||||
|
%%%
|
||||||
|
%%% DIRECTIONALITY CONVENTION:
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% CONVERTING BETWEEN XYZ-INDICES AND 0-INDICES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec idx0_to_xyz(Idx0) -> XYZ
|
-spec idx0_to_xyz(Idx0) -> XYZ
|
||||||
when Idx0 :: 0..1599,
|
when Idx0 :: 0..1599,
|
||||||
XYZ :: {xyz, X :: 0..4, Y :: 0..4, Z :: 0..63}.
|
XYZ :: {xyz, X :: 0..4, Y :: 0..4, Z :: 0..63}.
|
||||||
@@ -459,6 +696,13 @@ xyz_to_idx0({xyz, X, Y, Z}) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% DIRECTIONAL TRANSFORMATIONS ON SINGLE COORDINATE VALUES
|
||||||
|
%%
|
||||||
|
%% For instance, if you have an X-value and want to get the X-value "to the
|
||||||
|
%% left", this section contains functions that compute such things.
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec left(X) -> XToTheLeft
|
-spec left(X) -> XToTheLeft
|
||||||
when X :: 0..4,
|
when X :: 0..4,
|
||||||
XToTheLeft :: 0..4.
|
XToTheLeft :: 0..4.
|
||||||
@@ -549,12 +793,57 @@ behind(63) -> 0.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% 0D BIT ACCESSORS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
-spec xyzth(XYZ, Array1600) -> Bit
|
||||||
|
when XYZ :: {xyz, X, Y, Z},
|
||||||
|
Bits :: <<_:1600>>,
|
||||||
|
Bit :: 0 | 1,
|
||||||
|
X :: 0..4,
|
||||||
|
Y :: 0..4,
|
||||||
|
Z :: 0..63.
|
||||||
|
%% @private
|
||||||
|
%% Fetch the bit at the given X, Y, Z coordinate triple
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
xyzth(_XYZ, _Array1600) ->
|
||||||
|
error(nyi).
|
||||||
|
%Idx0 = xyz_to_idx0(XYZ),
|
||||||
|
%<<_Skip:Idx0.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec xyzset(XYZ, Array1600, Bit) -> NewArray1600
|
||||||
|
when XYZ :: {xyz, X, Y, Z},
|
||||||
|
Bits :: <<_:1600>>,
|
||||||
|
Bit :: 0 | 1,
|
||||||
|
X :: 0..4,
|
||||||
|
Y :: 0..4,
|
||||||
|
Z :: 0..63.
|
||||||
|
%% @private
|
||||||
|
%% Set the bit at the given X, Y, Z coordinate triple to the given value
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
xyzset(_XYZ, _Array1600, _NewBit) ->
|
||||||
|
error(nyi).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% 1D SUBSET ACCESSORS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
-spec xzth(XZ, Bits) -> Column
|
-spec xzth(XZ, Bits) -> Column
|
||||||
when XZ :: {xz, X, Z},
|
when XZ :: {xz, X, Z},
|
||||||
X :: 0..4,
|
X :: 0..4,
|
||||||
Z :: 0..63,
|
Z :: 0..63,
|
||||||
Bits :: <<_:1600>>,
|
Bits :: <<_:1600>>,
|
||||||
Column :: <<_:5>>.
|
Column :: <<_:5>>.
|
||||||
|
%% @private
|
||||||
|
%% Fetch the column at the given X, Z coordinate pair
|
||||||
|
%% @end
|
||||||
|
|
||||||
xzth({xz, X, Z}, Bits) ->
|
xzth({xz, X, Z}, Bits) ->
|
||||||
% just grab them one at a time
|
% just grab them one at a time
|
||||||
@@ -562,18 +851,49 @@ xzth({xz, X, Z}, Bits) ->
|
|||||||
|| Y <- lists:seq(0, 4)
|
|| Y <- lists:seq(0, 4)
|
||||||
>>.
|
>>.
|
||||||
|
|
||||||
xyzth(_, _) -> error(nyi).
|
|
||||||
|
|
||||||
|
|
||||||
-spec parity(bitstring()) -> 0 | 1.
|
-spec xyth(XY, Array1600) -> Lane
|
||||||
|
when XY :: {xy, X, Y},
|
||||||
|
Array1600 :: <<_:1600>>,
|
||||||
|
Lane :: <<_:64>>,
|
||||||
|
X :: 0..4,
|
||||||
|
Y :: 0..4.
|
||||||
%% @private
|
%% @private
|
||||||
%% count the number of 1s in the bitstring (is it even or odd?)
|
%% Grab the lane at the given X, Y coordinate pair.
|
||||||
%% @end
|
%% @end
|
||||||
|
|
||||||
parity(Bits) ->
|
xyth({xy, X, Y}, Array1600) ->
|
||||||
parity(Bits, 0).
|
<< <<( xyzth({xyz, X, Y, Z}, Array1600) ):1>>
|
||||||
|
|| Z <- lists:seq(0, 63)
|
||||||
|
>>.
|
||||||
|
|
||||||
parity(<<0:1, Rest/bitstring>>, NOnes) -> parity(Rest, NOnes);
|
|
||||||
parity(<<1:1, Rest/bitstring>>, NOnes) -> parity(Rest, NOnes + 1);
|
|
||||||
parity(<<>> , NOnes) -> NOnes rem 2.
|
-spec xyset(LaneXY, OriginalArray1600, NewLane) -> NewArray1600
|
||||||
|
when OriginalArray :: <<_:1600>>,
|
||||||
|
LaneXY :: {xy, 0..4, 0..4},
|
||||||
|
NewLane :: <<_:64>>,
|
||||||
|
NewArray :: <<_:1600>>.
|
||||||
|
%% @private
|
||||||
|
%% Take the original array, and swap out the lane at the given x,y coordinate
|
||||||
|
%% with the new given lane.
|
||||||
|
%%
|
||||||
|
%% The lane will be represented continuously so we can do a hack
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
% special case when it's the last lane
|
||||||
|
% grab the final 64 bits off the original array and replace them with the new lane
|
||||||
|
xyset(_LaneXY = {xy, 4, 4}, <<Pre:(1600 - 64), _:64>>, NewLane) ->
|
||||||
|
<<Pre:(1600 - 64), NewLane/bitstring>>;
|
||||||
|
% general case, grab the shit before the lane, grab the shit after the lane
|
||||||
|
% replace the shit in the middle
|
||||||
|
xyset(_LaneXY = {xy, LaneX, LaneY}, OriginalArray, NewLane) ->
|
||||||
|
FirstBitOfLane_Idx0 = xyz_to_idx0({xyz, LaneX, LaneY, 0}),
|
||||||
|
FirstBitAfterLane_Idx0 = xyz_to_idx0({xyz, LaneX, LaneY, 63}) + 1,
|
||||||
|
NumberOfBitsBeforeTheLane = FirstBitOfLane_Idx0,
|
||||||
|
NumberOfBitsIncludingTheLane = FirstBitAfterLane_Idx0,
|
||||||
|
<<PreLane:NumberOfBitsBeforeTheLane , _/bitstring>> = OriginalArray,
|
||||||
|
<< _:NumberOfBitsIncludingTheLane, AfterLane/bitstring>> = OriginalArray,
|
||||||
|
Result = <<PreLane:NumberOfBitsBeforeTheLane, NewLane/bitstring, AfterLane/bitstring>>,
|
||||||
|
Result.
|
||||||
|
|||||||
Reference in New Issue
Block a user