So, Season 5 of New Girl just came out on Netflix. I think you know where this is going, but effectively I sat in the Lovesac and watched TV all day. To feel a little bit better, I thought I should exercise my fingers a bit. Anyway here goes, back by popular demand, an F# implementation of SHA1. Now, before you look at my crap code and start asking questions. This is pretty much my first time ever using F#. Anyway, it compiles, and I've tested it a few times, so it seems 100% ready to ship.

` ````
// Converts an ascii string into a byte sequence
let getBytes (input: string) = seq {for c in input -> (byte)c}
// Get a uint32 from a sequence of 4 bytes in big endian
let bytesToUi (input: seq<byte>) =
let i = ref 3
// My decrementor function because I didnt realize value assignment don't return a value
let dec value =
let t = !value
value := (!value - 1)
t
// Fold the 4 bytes into a uint
Seq.fold (fun (acc : uint32) (b : byte) -> acc ||| (uint32(b) <<< (dec i) * 8)) 0u input
// Rotate left
let rotl (input: uint32) (amount) =
(input <<< amount) ||| (input >>> (32 - amount))
// Runs SHA1 on a string
let sha1 (input: string) =
// Get length of input in bytes
let messageLen = uint32(input.Length)
// Get length of input in bits
let bitlen = uint64(8u * messageLen)
// Get the amount we need to pad. Include the bit (0x80) we append to the message and the ulong at the end of the message for length
let padlen =
match ((messageLen + 9u) % 64u) with
| 0u -> 0
| _ -> int(64u - ((messageLen + 9u) % 64u))
// Append the bit to the end of the message
let asciibytes = Seq.append (getBytes(input)) (Seq.singleton 0x80uy)
// Pad with 0s. Assume the length is not going to be larger than uint32, so set the highest order 4 bytes to zero as well
let asciibytes = Seq.append asciibytes (seq {for i in 1.. (padlen+4) -> 0uy})
// Append 64 bits of message length
let messageBytes = Seq.append asciibytes (seq {for i in (List.rev [0..7]) -> ((byte)(bitlen >>> (i * 8)))})
// Constants
let mutable h0 = 0x67452301u
let mutable h1 = 0xEFCDAB89u
let mutable h2 = 0x98BADCFEu
let mutable h3 = 0x10325476u
let mutable h4 = 0xC3D2E1F0u
// Get the total message length
let totalBytes = Seq.length messageBytes
// For each 64 byte chunk
for chunk = 0 to ((totalBytes / 64)-1) do
let w = [| for i in 1 .. 80 -> 0u|]
// Populate the array
for i = 0 to 15 do
w.[i] <- bytesToUi (Seq.take 4 (Seq.skip (i*4 + chunk * 64) messageBytes))
for i = 16 to 79 do
w.[i] <- rotl ((w.[i-3]) ^^^ (w.[i-8]) ^^^ (w.[i-14]) ^^^ (w.[i-16])) 1
// Set up the locals
let mutable a, b, c, d, e = h0, h1, h2, h3, h4
let mutable k = 0u
let mutable f = 0u
for i in 0 .. 79 do
let round = match i with
| m when m < 20 -> (0x5A827999u, ((b &&& c) ||| ((~~~b) &&& d)))
| m when m < 40 -> (0x6ED9EBA1u, (b ^^^ c ^^^ d))
| m when m < 60 -> (0x8F1BBCDCu, ((b &&& c) ||| (b &&& d) ||| (c &&& d)))
| _ -> (0xCA62C1D6u, (b ^^^ c ^^^ d))
let temp = (rotl a 5) + (snd round) + e + (fst round) + w.[i]
e <- d
d <- c
c <- rotl b 30
b <- a
a <- temp
h0 <- h0 + a
h1 <- h1 + b
h2 <- h2 + c
h3 <- h3 + d
h4 <- h4 + e
[h0; h1; h2; h3; h4]
```