src/Pure/General/sha1.ML
author wenzelm
Sat, 22 Feb 2014 20:52:43 +0100
changeset 55672 5e25cc741ab9
parent 41954 fb94df4505a0
child 57638 ed58e740a699
permissions -rw-r--r--
support for completion within the formal context; tuned signature;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     1
(*  Title:      Pure/General/sha1.ML
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     3
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     4
Digesting strings according to SHA-1 (see RFC 3174) -- relatively slow
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     5
version in pure ML.
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     6
*)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     7
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     8
signature SHA1 =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
     9
sig
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    10
  eqtype digest
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    11
  val digest: string -> digest
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    12
  val rep: digest -> string
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    13
end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    14
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    15
structure SHA1: SHA1 =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    16
struct
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    17
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    18
(* 32bit words *)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    19
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    20
infix 4 << >>;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    21
infix 3 andb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    22
infix 2 orb xorb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    23
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    24
val op << = Word32.<<;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    25
val op >> = Word32.>>;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    26
val op andb = Word32.andb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    27
val op orb = Word32.orb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    28
val op xorb = Word32.xorb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    29
val notb = Word32.notb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    30
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    31
fun rotate k w = w << k orb w >> (0w32 - k);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    32
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    33
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    34
(* hexadecimal words *)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    35
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    36
fun hex_digit (text, w: Word32.word) =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    37
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    38
    val d = Word32.toInt (w andb 0wxf);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    39
    val dig = if d < 10 then chr (ord "0" + d) else chr (ord "a" + d - 10);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    40
  in (dig ^ text, w >> 0w4) end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    41
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    42
fun hex_word w = #1 (funpow 8 hex_digit ("", w));
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    43
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    44
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    45
(* padding *)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    46
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    47
fun pack_bytes 0 n = ""
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    48
  | pack_bytes k n = pack_bytes (k - 1) (n div 256) ^ chr (n mod 256);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    49
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    50
fun padded_text str =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    51
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    52
    val len = size str;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    53
    val padding = chr 128 ^ replicate_string (~ (len + 9) mod 64) (chr 0) ^ pack_bytes 8 (len * 8);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    54
    fun byte i = Char.ord (String.sub (if i < len then (str, i) else (padding, (i - len))));
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    55
    fun word i =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    56
      Word32.fromInt (byte (4 * i)) << 0w24 orb
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    57
      Word32.fromInt (byte (4 * i + 1)) << 0w16 orb
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    58
      Word32.fromInt (byte (4 * i + 2)) << 0w8 orb
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    59
      Word32.fromInt (byte (4 * i + 3));
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    60
  in ((len + size padding) div 4, word) end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    61
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    62
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    63
(* digest_string *)
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    64
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    65
fun digest_word (i, w, {a, b, c, d, e}) =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    66
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    67
    val {f, k} =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    68
      if i < 20 then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    69
        {f = (b andb c) orb (notb b andb d),
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    70
         k = 0wx5A827999}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    71
      else if i < 40 then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    72
        {f = b xorb c xorb d,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    73
         k = 0wx6ED9EBA1}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    74
      else if i < 60 then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    75
        {f = (b andb c) orb (b andb d) orb (c andb d),
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    76
         k = 0wx8F1BBCDC}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    77
      else
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    78
        {f = b xorb c xorb d,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    79
         k = 0wxCA62C1D6};
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    80
    val op + = Word32.+;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    81
  in
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    82
    {a = rotate 0w5 a + f + e + w + k,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    83
     b = a,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    84
     c = rotate 0w30 b,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    85
     d = c,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    86
     e = d}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    87
  end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    88
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    89
fun digest_string str =
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    90
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    91
    val (text_len, text) = padded_text str;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    92
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    93
    (*hash result -- 5 words*)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    94
    val hash_array : Word32.word Array.array =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    95
      Array.fromList [0wx67452301, 0wxEFCDAB89, 0wx98BADCFE, 0wx10325476, 0wxC3D2E1F0];
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    96
    fun hash i = Array.sub (hash_array, i);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    97
    fun add_hash x i = Array.update (hash_array, i, hash i + x);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    98
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    99
    (*current chunk -- 80 words*)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   100
    val chunk_array = Array.array (80, 0w0: Word32.word);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   101
    fun chunk i = Array.sub (chunk_array, i);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   102
    fun init_chunk pos =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   103
      Array.modifyi (fn (i, _) =>
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   104
        if i < 16 then text (pos + i)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   105
        else rotate 0w1 (chunk (i - 3) xorb chunk (i - 8) xorb chunk (i - 14) xorb chunk (i - 16)))
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   106
      chunk_array;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   107
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   108
    fun digest_chunks pos =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   109
      if pos < text_len then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   110
        let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   111
          val _ = init_chunk pos;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   112
          val {a, b, c, d, e} = Array.foldli digest_word
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   113
            {a = hash 0,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   114
             b = hash 1,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   115
             c = hash 2,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   116
             d = hash 3,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   117
             e = hash 4}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   118
            chunk_array;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   119
          val _ = add_hash a 0;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   120
          val _ = add_hash b 1;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   121
          val _ = add_hash c 2;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   122
          val _ = add_hash d 3;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   123
          val _ = add_hash e 4;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   124
        in digest_chunks (pos + 16) end
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   125
      else ();
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   126
    val _  = digest_chunks 0;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   127
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   128
    val hex = hex_word o hash;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   129
  in hex 0 ^ hex 1 ^ hex 2 ^ hex 3 ^ hex 4 end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   130
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   131
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   132
(* type digest *)
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   133
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   134
datatype digest = Digest of string;
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   135
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   136
val digest = Digest o digest_string;
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   137
fun rep (Digest s) = s;
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   138
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   139
end;