Revision 8a7e1b7f7f7dda7d9ac75c7adbb915b5c7db208f authored by Dzomo the everest Yak on 09 January 2020, 09:25:31 UTC, committed by Dzomo the everest Yak on 09 January 2020, 09:25:31 UTC
1 parent 9cd0bde
Raw File
Spec.Gimli.fst
module Spec.Gimli

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


let size_state : size_nat = 12
let rate : size_nat = 16

let column = i:size_nat{i < size_state}
let state = lseq uint32 size_state

let column_looped (c:column{c < 4}) (st:state) =
  let x = st.[c] <<<. 24ul in
  let y = st.[c + 4] <<<. 9ul in
  let z = st.[c + 8] in
  let st : state = upd st (c + 8) ((x ^. (z <<. 1ul)) ^. ((y &. z) <<. 2ul)) in
  let st : state = upd st (c + 4) (y ^. x ^. ((x |. z) <<. 1ul)) in
  let st : state = upd st (c) (z ^. y ^. ((x &. y) <<. 3ul)) in
  st

let small_swap (st:state) : state =
  let x = st.[0] in
  let y = st.[1] in
  let st = st.[1] <- x in
  let st = st.[0] <- y in
  let x = st.[2] in
  let y = st.[3] in
  let st = st.[2] <- y in
  let st = st.[3] <- x in
  st

let big_swap (st:state) : state =
  let x = st.[0] in
  let y = st.[2] in
  let st = st.[2] <- x in
  let st = st.[0] <- y in
  let x = st.[1] in
  let y = st.[3] in
  let st = st.[1] <- y in
  let st = st.[3] <- x in
  st

let c0 = u32 0x9e377800

let round_add (r:size_nat) (st:state) : state =
  let x = st.[0] in
  st.[0] <- x ^. (c0 ^. u32 r)

let inner_loop (st:state) : state =
  repeati 4 (fun i st -> column_looped i st) st

assume val nat_and: size_nat -> size_nat -> Tot size_nat

let round (r:size_nat{r <= 24}) (st:state) : state =
  let st = inner_loop st in
  let st = if (nat_and r 3) = 0 then small_swap st else st in
  let st = if (nat_and r 3) = 2 then big_swap st else st in
  let st = if (nat_and r 3) = 0 then round_add r st else st in
  st

let gimli (st:state) : state =
  repeati 24 (fun i st -> round (24 - i) st) st

///
/// Hash Function
///

let vsize_block = 16

let update_block (block: lbytes vsize_block) (st:state): Tot state =
  let st8 = uints_to_bytes_be st in
  let x = map2 (fun a b -> a ^. b) block (sub st8 0 vsize_block) in
  let st8 = update_sub st8 0 vsize_block x in
  let st32 = uints_from_bytes_be #U32 #SEC st8 in
  gimli st

let update_last (last:bytes{length last < vsize_block}) (st:state): Tot state =
  let len = length last in
  let block = create 48 (u8 0) in
  let block = update_sub block 0 len last in
  let block = block.[len] <- (u8 1) in
  let block = block.[47] <- (u8 1) in
  let st8 = uints_to_bytes_be st in
  let st8 = map2 (fun a b -> a ^. b) block st8 in
  let st32 = uints_from_bytes_be #U32 #SEC #size_state st8 in
  gimli st

let hash (input: bytes) : Tot (lbytes 32) =
  let n = (length input) / vsize_block in
  let rem = length input % vsize_block in
  let output = create 32 (u8 0) in
  let st0 = create size_state (u32 0) in
  let st = repeati_blocks vsize_block input
    (fun i block st -> update_block block st)
    (fun i rem block st -> update_last block st) st0
  in
  let w3 = sub st 0 3 in
  let w3 = uints_to_bytes_be #U32 #SEC w3 in
  let output = update_sub output 0 (3 * numbytes U32) w3 in
  let st = gimli st in

  let w3 = sub st 0 3 in
  let w3 = uints_to_bytes_be #U32 #SEC w3 in
  let output = update_sub output (3 * numbytes U32) (3 * numbytes U32) w3 in
  output
back to top