module By = Digestif_by module Bi = Digestif_bi module Int32 = struct include Int32 let ( lsl ) = Int32.shift_left let ( lsr ) = Int32.shift_right_logical let ( asr ) = Int32.shift_right let ( lor ) = Int32.logor let ( lxor ) = Int32.logxor let ( land ) = Int32.logand let lnot = Int32.lognot let ( + ) = Int32.add let rol32 a n = (a lsl n) lor (a lsr (32 - n)) let ror32 a n = (a lsr n) lor (a lsl (32 - n)) end module Int64 = struct include Int64 let ( land ) = Int64.logand let ( lsl ) = Int64.shift_left end module type S = sig type kind = [ `MD5 ] type ctx = { mutable size : int64; b : Bytes.t; h : int32 array } val init : unit -> ctx val unsafe_feed_bytes : ctx -> By.t -> int -> int -> unit val unsafe_feed_bigstring : ctx -> Bi.t -> int -> int -> unit val unsafe_get : ctx -> By.t val dup : ctx -> ctx end module Unsafe : S = struct type kind = [ `MD5 ] type ctx = { mutable size : int64; b : Bytes.t; h : int32 array } let dup ctx = { size = ctx.size; b = By.copy ctx.b; h = Array.copy ctx.h } let init () = let b = By.make 64 '\x00' in { size = 0L; b; h = [| 0x67452301l; 0xefcdab89l; 0x98badcfel; 0x10325476l |]; } let f1 x y z = Int32.(z lxor (x land (y lxor z))) let f2 x y z = f1 z x y let f3 x y z = Int32.(x lxor y lxor z) let f4 x y z = Int32.(y lxor (x lor lnot z)) let md5_do_chunk : type a. le32_to_cpu:(a -> int -> int32) -> ctx -> a -> int -> unit = fun ~le32_to_cpu ctx buf off -> let a, b, c, d = (ref ctx.h.(0), ref ctx.h.(1), ref ctx.h.(2), ref ctx.h.(3)) in let w = Array.make 16 0l in for i = 0 to 15 do w.(i) <- le32_to_cpu buf (off + (i * 4)) done ; let round f a b c d i k s = let open Int32 in a := !a + f !b !c !d + w.(i) + k ; a := rol32 !a s ; a := !a + !b in round f1 a b c d 0 0xd76aa478l 7 ; round f1 d a b c 1 0xe8c7b756l 12 ; round f1 c d a b 2 0x242070dbl 17 ; round f1 b c d a 3 0xc1bdceeel 22 ; round f1 a b c d 4 0xf57c0fafl 7 ; round f1 d a b c 5 0x4787c62al 12 ; round f1 c d a b 6 0xa8304613l 17 ; round f1 b c d a 7 0xfd469501l 22 ; round f1 a b c d 8 0x698098d8l 7 ; round f1 d a b c 9 0x8b44f7afl 12 ; round f1 c d a b 10 0xffff5bb1l 17 ; round f1 b c d a 11 0x895cd7bel 22 ; round f1 a b c d 12 0x6b901122l 7 ; round f1 d a b c 13 0xfd987193l 12 ; round f1 c d a b 14 0xa679438el 17 ; round f1 b c d a 15 0x49b40821l 22 ; round f2 a b c d 1 0xf61e2562l 5 ; round f2 d a b c 6 0xc040b340l 9 ; round f2 c d a b 11 0x265e5a51l 14 ; round f2 b c d a 0 0xe9b6c7aal 20 ; round f2 a b c d 5 0xd62f105dl 5 ; round f2 d a b c 10 0x02441453l 9 ; round f2 c d a b 15 0xd8a1e681l 14 ; round f2 b c d a 4 0xe7d3fbc8l 20 ; round f2 a b c d 9 0x21e1cde6l 5 ; round f2 d a b c 14 0xc33707d6l 9 ; round f2 c d a b 3 0xf4d50d87l 14 ; round f2 b c d a 8 0x455a14edl 20 ; round f2 a b c d 13 0xa9e3e905l 5 ; round f2 d a b c 2 0xfcefa3f8l 9 ; round f2 c d a b 7 0x676f02d9l 14 ; round f2 b c d a 12 0x8d2a4c8al 20 ; round f3 a b c d 5 0xfffa3942l 4 ; round f3 d a b c 8 0x8771f681l 11 ; round f3 c d a b 11 0x6d9d6122l 16 ; round f3 b c d a 14 0xfde5380cl 23 ; round f3 a b c d 1 0xa4beea44l 4 ; round f3 d a b c 4 0x4bdecfa9l 11 ; round f3 c d a b 7 0xf6bb4b60l 16 ; round f3 b c d a 10 0xbebfbc70l 23 ; round f3 a b c d 13 0x289b7ec6l 4 ; round f3 d a b c 0 0xeaa127fal 11 ; round f3 c d a b 3 0xd4ef3085l 16 ; round f3 b c d a 6 0x04881d05l 23 ; round f3 a b c d 9 0xd9d4d039l 4 ; round f3 d a b c 12 0xe6db99e5l 11 ; round f3 c d a b 15 0x1fa27cf8l 16 ; round f3 b c d a 2 0xc4ac5665l 23 ; round f4 a b c d 0 0xf4292244l 6 ; round f4 d a b c 7 0x432aff97l 10 ; round f4 c d a b 14 0xab9423a7l 15 ; round f4 b c d a 5 0xfc93a039l 21 ; round f4 a b c d 12 0x655b59c3l 6 ; round f4 d a b c 3 0x8f0ccc92l 10 ; round f4 c d a b 10 0xffeff47dl 15 ; round f4 b c d a 1 0x85845dd1l 21 ; round f4 a b c d 8 0x6fa87e4fl 6 ; round f4 d a b c 15 0xfe2ce6e0l 10 ; round f4 c d a b 6 0xa3014314l 15 ; round f4 b c d a 13 0x4e0811a1l 21 ; round f4 a b c d 4 0xf7537e82l 6 ; round f4 d a b c 11 0xbd3af235l 10 ; round f4 c d a b 2 0x2ad7d2bbl 15 ; round f4 b c d a 9 0xeb86d391l 21 ; let open Int32 in ctx.h.(0) <- ctx.h.(0) + !a ; ctx.h.(1) <- ctx.h.(1) + !b ; ctx.h.(2) <- ctx.h.(2) + !c ; ctx.h.(3) <- ctx.h.(3) + !d ; () let feed : type a. blit:(a -> int -> By.t -> int -> int -> unit) -> le32_to_cpu:(a -> int -> int32) -> ctx -> a -> int -> int -> unit = fun ~blit ~le32_to_cpu ctx buf off len -> let idx = ref Int64.(to_int (ctx.size land 0x3FL)) in let len = ref len in let off = ref off in let to_fill = 64 - !idx in ctx.size <- Int64.add ctx.size (Int64.of_int !len) ; if !idx <> 0 && !len >= to_fill then ( blit buf !off ctx.b !idx to_fill ; md5_do_chunk ~le32_to_cpu:By.le32_to_cpu ctx ctx.b 0 ; len := !len - to_fill ; off := !off + to_fill ; idx := 0) ; while !len >= 64 do md5_do_chunk ~le32_to_cpu ctx buf !off ; len := !len - 64 ; off := !off + 64 done ; if !len <> 0 then blit buf !off ctx.b !idx !len ; () let unsafe_feed_bytes = feed ~blit:By.blit ~le32_to_cpu:By.le32_to_cpu let unsafe_feed_bigstring = feed ~blit:By.blit_from_bigstring ~le32_to_cpu:Bi.le32_to_cpu let unsafe_get ctx = let index = Int64.(to_int (ctx.size land 0x3FL)) in let padlen = if index < 56 then 56 - index else 64 + 56 - index in let padding = By.init padlen (function 0 -> '\x80' | _ -> '\x00') in let bits = By.create 8 in By.cpu_to_le64 bits 0 Int64.(ctx.size lsl 3) ; unsafe_feed_bytes ctx padding 0 padlen ; unsafe_feed_bytes ctx bits 0 8 ; let res = By.create (4 * 4) in for i = 0 to 3 do By.cpu_to_le32 res (i * 4) ctx.h.(i) done ; res end