src/Pure/General/sha1.ML
author wenzelm
Fri, 18 Mar 2016 16:26:35 +0100
changeset 62663 bea354f6ff21
parent 57638 ed58e740a699
child 62666 00aff1da05ae
permissions -rw-r--r--
clarified modules; 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
57638
ed58e740a699 less authentic SHA1.digest: trust Scala side on blobs and avoid re-calculation via Foreign Language Interface, which might be a cause of problems;
wenzelm
parents: 41954
diff changeset
    13
  val fake: string -> digest
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    14
end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    15
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    16
structure SHA1: SHA1 =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    17
struct
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    18
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    19
(* 32bit words *)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    20
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    21
infix 4 << >>;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    22
infix 3 andb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    23
infix 2 orb xorb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    24
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 >> = Word32.>>;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    27
val op andb = Word32.andb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    28
val op orb = Word32.orb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    29
val op xorb = Word32.xorb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    30
val notb = Word32.notb;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    31
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    32
fun rotate k w = w << k orb w >> (0w32 - k);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    33
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    34
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    35
(* hexadecimal words *)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    36
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    37
fun hex_digit (text, w: Word32.word) =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    38
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    39
    val d = Word32.toInt (w andb 0wxf);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    40
    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
    41
  in (dig ^ text, w >> 0w4) end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    42
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    43
fun hex_word w = #1 (funpow 8 hex_digit ("", w));
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    44
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    45
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    46
(* padding *)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    47
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    48
fun pack_bytes 0 n = ""
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    49
  | 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
    50
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    51
fun padded_text str =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    52
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    53
    val len = size str;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    54
    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
    55
    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
    56
    fun word i =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    57
      Word32.fromInt (byte (4 * i)) << 0w24 orb
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    58
      Word32.fromInt (byte (4 * i + 1)) << 0w16 orb
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    59
      Word32.fromInt (byte (4 * i + 2)) << 0w8 orb
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    60
      Word32.fromInt (byte (4 * i + 3));
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    61
  in ((len + size padding) div 4, word) end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    62
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    63
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    64
(* digest_string *)
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    65
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    66
fun digest_word (i, w, {a, b, c, d, e}) =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    67
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    68
    val {f, k} =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    69
      if i < 20 then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    70
        {f = (b andb c) orb (notb b andb d),
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    71
         k = 0wx5A827999}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    72
      else if i < 40 then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    73
        {f = b xorb c xorb d,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    74
         k = 0wx6ED9EBA1}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    75
      else if i < 60 then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    76
        {f = (b andb c) orb (b andb d) orb (c andb d),
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    77
         k = 0wx8F1BBCDC}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    78
      else
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    79
        {f = b xorb c xorb d,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    80
         k = 0wxCA62C1D6};
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    81
    val op + = Word32.+;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    82
  in
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    83
    {a = rotate 0w5 a + f + e + w + k,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    84
     b = a,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    85
     c = rotate 0w30 b,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    86
     d = c,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    87
     e = d}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    88
  end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    89
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
    90
fun digest_string str =
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    91
  let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    92
    val (text_len, text) = padded_text str;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    93
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    94
    (*hash result -- 5 words*)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    95
    val hash_array : Word32.word Array.array =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    96
      Array.fromList [0wx67452301, 0wxEFCDAB89, 0wx98BADCFE, 0wx10325476, 0wxC3D2E1F0];
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    97
    fun hash i = Array.sub (hash_array, i);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    98
    fun add_hash x i = Array.update (hash_array, i, hash i + x);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
    99
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   100
    (*current chunk -- 80 words*)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   101
    val chunk_array = Array.array (80, 0w0: Word32.word);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   102
    fun chunk i = Array.sub (chunk_array, i);
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   103
    fun init_chunk pos =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   104
      Array.modifyi (fn (i, _) =>
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   105
        if i < 16 then text (pos + i)
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   106
        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
   107
      chunk_array;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   108
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   109
    fun digest_chunks pos =
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   110
      if pos < text_len then
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   111
        let
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   112
          val _ = init_chunk pos;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   113
          val {a, b, c, d, e} = Array.foldli digest_word
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   114
            {a = hash 0,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   115
             b = hash 1,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   116
             c = hash 2,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   117
             d = hash 3,
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   118
             e = hash 4}
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   119
            chunk_array;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   120
          val _ = add_hash a 0;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   121
          val _ = add_hash b 1;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   122
          val _ = add_hash c 2;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   123
          val _ = add_hash d 3;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   124
          val _ = add_hash e 4;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   125
        in digest_chunks (pos + 16) end
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   126
      else ();
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   127
    val _  = digest_chunks 0;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   128
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   129
    val hex = hex_word o hash;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   130
  in hex 0 ^ hex 1 ^ hex 2 ^ hex 3 ^ hex 4 end;
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   131
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   132
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   133
(* type digest *)
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   134
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   135
datatype digest = Digest of string;
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   136
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   137
val digest = Digest o digest_string;
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   138
fun rep (Digest s) = s;
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 35628
diff changeset
   139
57638
ed58e740a699 less authentic SHA1.digest: trust Scala side on blobs and avoid re-calculation via Foreign Language Interface, which might be a cause of problems;
wenzelm
parents: 41954
diff changeset
   140
val fake = Digest;
ed58e740a699 less authentic SHA1.digest: trust Scala side on blobs and avoid re-calculation via Foreign Language Interface, which might be a cause of problems;
wenzelm
parents: 41954
diff changeset
   141
62663
bea354f6ff21 clarified modules;
wenzelm
parents: 57638
diff changeset
   142
val _ = PolyML.addPrettyPrinter (fn _ => fn _ => Pretty.to_polyml o Pretty.str o quote o rep);
bea354f6ff21 clarified modules;
wenzelm
parents: 57638
diff changeset
   143
35628
f1456d045151 Digesting strings according to SHA-1.
wenzelm
parents:
diff changeset
   144
end;