Revision 1990ae634d0602ff022afc946ef66933e4e4a2dc authored by Santiago Zanella-Beguelin on 09 December 2019, 17:48:55 UTC, committed by Santiago Zanella-Beguelin on 09 December 2019, 17:50:10 UTC
1 parent ae8e182
Raw File
Spec.SHA3.fst
module Spec.SHA3

open Lib.IntTypes
open Lib.Sequence
open Lib.ByteSequence
open FStar.Mul
open Lib.LoopCombinators

open Spec.SHA3.Constants

#reset-options "--z3rlimit 50 --max_fuel 0 --max_ifuel 0"

unfold
type state = lseq uint64 25

unfold
type index = n:size_nat{n < 5}

let readLane (s:state) (x:index) (y:index) : Tot uint64 =
  s.[x + 5 * y]

let writeLane (s:state) (x:index) (y:index) (v:uint64) : Tot state =
  s.[x + 5 * y] <- v

let rotl (a:uint64) (b:size_t{0 < uint_v b /\ uint_v b < 64}) : Tot uint64 =
  rotate_left a b

let state_theta_inner_C (s:state) (i:size_nat{i < 5}) (_C:lseq uint64 5) : Tot (lseq uint64 5) =
  _C.[i] <- readLane s i 0 ^. readLane s i 1 ^. readLane s i 2 ^. readLane s i 3 ^. readLane s i 4

let state_theta0 (s:state) (_C:lseq uint64 5) =
  repeati 5 (state_theta_inner_C s) _C

let state_theta_inner_s_inner (x:index) (_D:uint64) (y:index) (s:state) : Tot state =
  writeLane s x y (readLane s x y ^. _D)

let state_theta_inner_s (_C:lseq uint64 5) (x:index) (s:state) : Tot state =
  let _D = _C.[(x + 4) % 5] ^. (rotl _C.[(x + 1) % 5] (size 1)) in
  repeati 5 (state_theta_inner_s_inner x _D) s

let state_theta1 (s:state) (_C:lseq uint64 5) : Tot state =
  repeati 5 (state_theta_inner_s _C) s

let state_theta (s:state) : Tot state =
  let _C = create 5 (u64 0) in
  let _C = state_theta0 s _C in
  state_theta1 s _C

let state_pi_rho_inner (i:size_nat{i < 24}) (current, s) : (uint64 & state) =
  let r = keccak_rotc.[i] in
  let _Y = v keccak_piln.[i] in
  let temp = s.[_Y] in
  let s = s.[_Y] <- rotl current r in
  let current = temp in
  current, s

val state_pi_rho_s: i:size_nat{i <= 24} -> Type0
let state_pi_rho_s i = uint64 & state

let state_pi_rho (s_theta:state) : Tot state =
  let current = readLane s_theta 1 0 in
  let _, s_pi_rho = repeat_gen 24 state_pi_rho_s
    state_pi_rho_inner (current, s_theta) in
  s_pi_rho

let state_chi_inner (s_pi_rho:state) (y:index) (x:index) (s:state) : Tot state =
  writeLane s x y
    (readLane s_pi_rho x y ^.
     ((lognot (readLane s_pi_rho ((x + 1) % 5) y)) &.
      readLane s_pi_rho ((x + 2) % 5) y))

let state_chi_inner1 (s_pi_rho:state) (y:index) (s:state) : Tot state =
  repeati 5 (state_chi_inner s_pi_rho y) s

let state_chi (s_pi_rho:state) : Tot state  =
  repeati 5 (state_chi_inner1 s_pi_rho) s_pi_rho

let state_iota (s:state) (round:size_nat{round < 24}) : Tot state =
  writeLane s 0 0 (readLane s 0 0 ^. secret keccak_rndc.[round])

let state_permute1 (round:size_nat{round < 24}) (s:state) : Tot state =
  let s_theta = state_theta s in
  let s_pi_rho = state_pi_rho s_theta in
  let s_chi = state_chi s_pi_rho in
  let s_iota = state_iota s_chi round in
  s_iota

let state_permute (s:state) : Tot state =
  repeati 24 state_permute1 s

let loadState_inner (block:lbytes 200) (j:size_nat{j < 25}) (s:state) : Tot state =
  s.[j] <- s.[j] ^. uint_from_bytes_le #U64 (sub block (j * 8) 8)

let loadState
  (rateInBytes:size_nat{rateInBytes <= 200})
  (input:lbytes rateInBytes)
  (s:state) :
  Tot state =

  let block = create 200 (u8 0) in
  let block = update_sub block 0 rateInBytes input in
  repeati 25 (loadState_inner block) s

let storeState_inner (s:state) (j:size_nat{j < 25}) (block:lbytes 200) : Tot (lbytes 200) =
  update_sub block (j * 8) 8 (uint_to_bytes_le #U64 s.[j])

let storeState (rateInBytes:size_nat{rateInBytes <= 200}) (s:state) : Tot (lbytes rateInBytes) =
  let block = create 200 (u8 0) in
  let block = repeati 25 (storeState_inner s) block in
  sub block 0 rateInBytes

let absorb_next (s:state) (rateInBytes:size_nat{rateInBytes > 0 /\ rateInBytes <= 200}) : Tot state =
  let nextBlock = create rateInBytes (u8 0) in
  let nextBlock = nextBlock.[rateInBytes - 1] <- u8 0x80 in
  let s = loadState rateInBytes nextBlock s in
  state_permute s

val absorb_last:
    delimitedSuffix:byte_t
  -> rateInBytes:size_nat{0 < rateInBytes /\ rateInBytes <= 200}
  -> rem:size_nat{rem < rateInBytes}
  -> input:lbytes rem
  -> s:state ->
  Tot state

let absorb_last delimitedSuffix rateInBytes rem input s =
  let lastBlock = create rateInBytes (u8 0) in
  let lastBlock = update_sub lastBlock 0 rem input in
  let lastBlock = lastBlock.[rem] <- byte_to_uint8 delimitedSuffix in
  let s = loadState rateInBytes lastBlock s in
  let s =
    if not ((delimitedSuffix &. byte 0x80) =. byte 0) &&
       (rem = rateInBytes - 1)
    then state_permute s else s in
  absorb_next s rateInBytes

let absorb_inner
  (rateInBytes:size_nat{0 < rateInBytes /\ rateInBytes <= 200})
  (block:lbytes rateInBytes)
  (s:state) :
  Tot state =

  let s = loadState rateInBytes block s in
  state_permute s

let absorb
  (s:state)
  (rateInBytes:size_nat{0 < rateInBytes /\ rateInBytes <= 200})
  (inputByteLen:nat)
  (input:bytes{length input == inputByteLen})
  (delimitedSuffix:byte_t) :
  Tot state =

  repeat_blocks rateInBytes input
  (absorb_inner rateInBytes)
  (absorb_last delimitedSuffix rateInBytes) s

let squeeze_inner
  (rateInBytes:size_nat{0 < rateInBytes /\ rateInBytes <= 200})
  (outputByteLen:size_nat)
  (i:size_nat{i < outputByteLen / rateInBytes})
  (s:state) :
  Tot (state & lbytes rateInBytes) =

  let block = storeState rateInBytes s in
  let s = state_permute s in
  s, block

let squeeze
  (s:state)
  (rateInBytes:size_nat{0 < rateInBytes /\ rateInBytes <= 200})
  (outputByteLen:size_nat):
  Tot (lbytes outputByteLen) =

  let outBlocks = outputByteLen / rateInBytes in
  let a (i:nat{i <= outBlocks}) = state in
  let s, output =
    generate_blocks rateInBytes outBlocks outBlocks a
      (squeeze_inner rateInBytes outputByteLen) s
  in
  let remOut = outputByteLen % rateInBytes in
  let block = storeState remOut s in
  (to_lseq output) @| block


val keccak:
    rate:size_nat{rate % 8 == 0 /\ rate / 8 > 0 /\ rate <= 1600}
  -> capacity:size_nat{capacity + rate == 1600}
  -> inputByteLen:nat
  -> input:bytes{length input == inputByteLen}
  -> delimitedSuffix:byte_t
  -> outputByteLen:size_nat ->
  Tot (lbytes outputByteLen)

let keccak rate capacity inputByteLen input delimitedSuffix outputByteLen =
  let rateInBytes = rate / 8 in
  let s = create 25 (u64 0) in
  let s = absorb s rateInBytes inputByteLen input delimitedSuffix in
  squeeze s rateInBytes outputByteLen

let shake128
  (inputByteLen:nat)
  (input:bytes{length input == inputByteLen})
  (outputByteLen:size_nat) :
  Tot (lbytes outputByteLen) =

  keccak 1344 256 inputByteLen input (byte 0x1F) outputByteLen

let shake256
  (inputByteLen:nat)
  (input:bytes{length input == inputByteLen})
  (outputByteLen:size_nat) :
  Tot (lbytes outputByteLen) =

  keccak 1088 512 inputByteLen input (byte 0x1F) outputByteLen

let sha3_224 (inputByteLen:nat) (input:bytes{length input == inputByteLen}) : lbytes 28 =
  keccak 1152 448 inputByteLen input (byte 0x06) 28

let sha3_256 (inputByteLen:nat) (input:bytes{length input == inputByteLen}) : lbytes 32 =
  keccak 1088 512 inputByteLen input (byte 0x06) 32

let sha3_384 (inputByteLen:nat) (input:bytes{length input == inputByteLen}) : lbytes 48 =
  keccak 832 768 inputByteLen input (byte 0x06) 48

let sha3_512 (inputByteLen:nat) (input:bytes{length input == inputByteLen}) : lbytes 64 =
  keccak 576 1024 inputByteLen input (byte 0x06) 64


val cshake128_frodo:
    input_len:nat
  -> input:bytes{length input == input_len}
  -> cstm:uint16
  -> output_len:size_nat ->
  Tot (lbytes output_len)

let cshake128_frodo input_len input cstm output_len =
  let s = create 25 (u64 0) in
  let s = s.[0] <- u64 0x10010001a801 |. shift_left (to_u64 cstm) (size 48) in
  let s = state_permute s in
  let s = absorb s 168 input_len input (byte 0x04) in
  squeeze s 168 output_len


val cshake256_frodo:
    input_len:nat
  -> input:bytes{length input == input_len}
  -> cstm:uint16
  -> output_len:size_nat ->
  Tot (lbytes output_len)

let cshake256_frodo input_len input cstm output_len =
  let s = create 25 (u64 0) in
  let s = s.[0] <- u64 0x100100018801 |. shift_left (to_u64 cstm) (size 48) in
  let s = state_permute s in
  let s = absorb s 136 input_len input (byte 0x04) in
  squeeze s 136 output_len
back to top