2 | import Control.Monad.State
6 | import Data.Fin.Extra
7 | import Data.Nat.Order.Properties
18 | ChaChaState = Vect 16 Bits32
22 | constants : Vect 4 Bits32
23 | constants = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]
26 | quarter_rotate : Fin 16 -> Fin 16 -> Fin 16 -> Fin 16 -> State ChaChaState ()
27 | quarter_rotate a b c d = do
28 | modify (\s => updateAt a (+ index b s) s)
29 | modify (\s => updateAt d (`xor` index a s) s)
30 | modify (\s => updateAt d (rotl 16) s)
32 | modify (\s => updateAt c (+ index d s) s)
33 | modify (\s => updateAt b (`xor` index c s) s)
34 | modify (\s => updateAt b (rotl 12) s)
36 | modify (\s => updateAt a (+ index b s) s)
37 | modify (\s => updateAt d (`xor` index a s) s)
38 | modify (\s => updateAt d (rotl 8) s)
40 | modify (\s => updateAt c (+ index d s) s)
41 | modify (\s => updateAt b (`xor` index c s) s)
42 | modify (\s => updateAt b (rotl 7) s)
45 | double_rotate : State ChaChaState ()
47 | quarter_rotate 0 4 8 12
48 | quarter_rotate 1 5 9 13
49 | quarter_rotate 2 6 10 14
50 | quarter_rotate 3 7 11 15
52 | quarter_rotate 0 5 10 15
53 | quarter_rotate 1 6 11 12
54 | quarter_rotate 2 7 8 13
55 | quarter_rotate 3 4 9 14
58 | run2x : (n_double_rounds : Nat) -> ChaChaState -> ChaChaState
59 | run2x n_double_rounds s =
63 | modify (zipWith (+) original)
65 | go : Fin (S n_double_rounds) -> State ChaChaState ()
67 | go (FS wit) = double_rotate *> go (weaken wit)
71 | chacha_rfc8439_block : Nat -> (counter : Bits32) -> Key -> Vect 3 Bits32 -> Vect 64 Bits8
72 | chacha_rfc8439_block rounds counter key nonce = concat $
map (to_le {n = 4}) $
run2x rounds $
constants ++ key ++ [counter] ++ nonce
76 | chacha_original_block : Nat -> (counter : Bits64) -> Key -> Vect 2 Bits32 -> Vect 64 Bits8
77 | chacha_original_block rounds counter key nonce = concat $
map (to_le {n = 4}) $
run2x rounds $
constants ++ key ++ split_word counter ++ nonce
79 | split_word : Bits64 -> Vect 2 Bits32
80 | split_word a = [ cast a, cast (shiftR a 32) ]