%% @doc %% this module exists to check that the table on pp. 12 of %% https://www.crypto-textbook.com/download/Understanding-Cryptography-Keccak.pdf %% is correct -module(rc). -compile(export_all). -spec little_rc(T) -> Bit when T :: non_neg_integer(), Bit :: 0 | 1. %% copying from pp. 16 of https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf little_rc(T) when (T rem 255) =:= 0 -> 1; little_rc(T) -> R = <<(2#1000):4, (2#0000):4>>, %% could make this 8 but splitting into 4 is clearer InitI = 1, TMod255 = T rem 255, NewR = little_rc(InitI, TMod255, R), <> = NewR, Result. -spec little_rc(I, MaxI, R) -> NewR when I :: pos_integer(), MaxI :: pos_integer(), R :: <<_:8>>, NewR :: <<_:8>>. little_rc(I, MaxI, R) when I =< MaxI -> R_ = <<0:1, R/bitstring>>, % need R_[0], R_[4], R_[5], R_[6], and R_[8] <> = R_, NewR_0 = R_0 bxor R_8, NewR_4 = R_4 bxor R_8, NewR_5 = R_5 bxor R_8, NewR_6 = R_6 bxor R_8, NewR = <>, NewI = I + 1, little_rc(NewI, MaxI, NewR); little_rc(I, MaxI, R) when I > MaxI -> R. % Table from pp. 12 of https://www.crypto-textbook.com/download/Understanding-Cryptography-Keccak.pdf % % RC[ 0] = 0x0000000000000001 % RC[ 1] = 0x0000000000008082 % RC[ 2] = 0x800000000000808A % RC[ 3] = 0x8000000080008000 % RC[ 4] = 0x000000000000808B % RC[ 5] = 0x0000000080000001 % RC[ 6] = 0x8000000080008081 % RC[ 7] = 0x8000000000008009 % RC[ 8] = 0x000000000000008A % RC[ 9] = 0x0000000000000088 % RC[10] = 0x0000000080008009 % RC[11] = 0x000000008000000A % RC[12] = 0x000000008000808B % RC[13] = 0x800000000000008B % RC[14] = 0x8000000000008089 % RC[15] = 0x8000000000008003 % RC[16] = 0x8000000000008002 % RC[17] = 0x8000000000000080 % RC[18] = 0x000000000000800A % RC[19] = 0x800000008000000A % RC[20] = 0x8000000080008081 % RC[21] = 0x8000000000008080 % RC[22] = 0x0000000080000001 % RC[23] = 0x8000000080008008 -spec big_rc(RoundIndex) -> BigRC when RoundIndex :: 0..23, BigRC :: <<_:64>>. %% from pp. 16 of the NIST doc: %% > 2. Let RC = 0w. %% > 3. For j from 0 to l, let RC[2^j – 1] = rc(j + 7*ir). %% %% In this case, 0w = <<0:64>>, l = 6, ir ranges between 0..23 %% %% > 2. Let RC = 0w. %% > 3. For j from 0 to 6, let RC[2^j – 1] = rc(j + 7*ir). big_rc(RoundIndex) -> InitJ = 0, InitBigRC = <<0:64>>, big_rc(RoundIndex, InitJ, InitBigRC). -spec big_rc(RoundIndex, J, BigRCAcc) -> BigRC when RoundIndex :: 0..23, J :: 0..6, BigRCAcc :: BigRC, BigRC :: <<_:64>>. %% > 3. For j from 0 to 6, let RC[2^j – 1] = rc(j + 7ir). big_rc(RoundIndex, J, BigRCAcc) when 0 =< J, J =< 6 -> Idx0WeAreModifying = two_to_the(J) - 1, NewBit = little_rc(J + 7*RoundIndex), NumSkipBits = Idx0WeAreModifying, <> = BigRCAcc, NewJ = J + 1, NewBigRCAcc = <>, big_rc(RoundIndex, NewJ, NewBigRCAcc); big_rc(_RoundIndex, J, BigRCAcc) when J > 6 -> BigRCAcc. two_to_the(N) when 0 =< N -> 1 bsl N. %% expected values xrc( 0) -> <<( 16#0000000000000001 ):64>>; xrc( 1) -> <<( 16#0000000000008082 ):64>>; xrc( 2) -> <<( 16#800000000000808A ):64>>; xrc( 3) -> <<( 16#8000000080008000 ):64>>; xrc( 4) -> <<( 16#000000000000808B ):64>>; xrc( 5) -> <<( 16#0000000080000001 ):64>>; xrc( 6) -> <<( 16#8000000080008081 ):64>>; xrc( 7) -> <<( 16#8000000000008009 ):64>>; xrc( 8) -> <<( 16#000000000000008A ):64>>; xrc( 9) -> <<( 16#0000000000000088 ):64>>; xrc(10) -> <<( 16#0000000080008009 ):64>>; xrc(11) -> <<( 16#000000008000000A ):64>>; xrc(12) -> <<( 16#000000008000808B ):64>>; xrc(13) -> <<( 16#800000000000008B ):64>>; xrc(14) -> <<( 16#8000000000008089 ):64>>; xrc(15) -> <<( 16#8000000000008003 ):64>>; xrc(16) -> <<( 16#8000000000008002 ):64>>; xrc(17) -> <<( 16#8000000000000080 ):64>>; xrc(18) -> <<( 16#000000000000800A ):64>>; xrc(19) -> <<( 16#800000008000000A ):64>>; xrc(20) -> <<( 16#8000000080008081 ):64>>; xrc(21) -> <<( 16#8000000000008080 ):64>>; xrc(22) -> <<( 16#0000000080000001 ):64>>; xrc(23) -> <<( 16#8000000080008008 ):64>>. check() -> CheckI = fun(I) -> io:format("I = ~p: ~p~n", [I, big_rc(I) =:= xrc(I)]) end, lists:foreach(CheckI, lists:seq(0, 23)).