src/Pure/General/sha1.scala
author wenzelm
Wed, 12 Mar 2025 11:39:00 +0100
changeset 82265 4b875a4c83b0
parent 82158 7d579158d186
permissions -rw-r--r--
update for release;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
38473
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/General/sha1.scala
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     3
75309
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
     4
SHA-1 message digest according to RFC 3174.
38473
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     5
*/
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     6
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     7
package isabelle
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     8
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
     9
48409
0d2114eb412a more explicit java.io.{File => JFile};
wenzelm
parents: 48343
diff changeset
    10
import java.io.{File => JFile, FileInputStream}
38473
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
    11
import java.security.MessageDigest
82158
7d579158d186 clarified signature: more explicit operations;
wenzelm
parents: 80360
diff changeset
    12
import java.util.HexFormat
75309
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    13
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    14
import isabelle.setup.{Build => Setup_Build}
38473
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
    15
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
    16
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 75382
diff changeset
    17
object SHA1 {
77207
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    18
  /* digest */
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    19
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 75382
diff changeset
    20
  final class Digest private[SHA1](rep: String) {
75310
42baf7ffa088 tuned signature;
wenzelm
parents: 75309
diff changeset
    21
    override def toString: String = rep
55802
f7ceebe2f1b5 prefer abstract datatype -- in accordance to ML version;
wenzelm
parents: 54440
diff changeset
    22
    override def hashCode: Int = rep.hashCode
f7ceebe2f1b5 prefer abstract datatype -- in accordance to ML version;
wenzelm
parents: 54440
diff changeset
    23
    override def equals(that: Any): Boolean =
f7ceebe2f1b5 prefer abstract datatype -- in accordance to ML version;
wenzelm
parents: 54440
diff changeset
    24
      that match {
75310
42baf7ffa088 tuned signature;
wenzelm
parents: 75309
diff changeset
    25
        case other: Digest => rep == other.toString
55802
f7ceebe2f1b5 prefer abstract datatype -- in accordance to ML version;
wenzelm
parents: 54440
diff changeset
    26
        case _ => false
f7ceebe2f1b5 prefer abstract datatype -- in accordance to ML version;
wenzelm
parents: 54440
diff changeset
    27
      }
82158
7d579158d186 clarified signature: more explicit operations;
wenzelm
parents: 80360
diff changeset
    28
    def base64: String = Base64.encode(HexFormat.of().parseHex(rep))
41954
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 38473
diff changeset
    29
  }
fb94df4505a0 explicit type SHA1.digest;
wenzelm
parents: 38473
diff changeset
    30
75309
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    31
  def fake_digest(rep: String): Digest = new Digest(rep)
38473
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
    32
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 75382
diff changeset
    33
  def make_digest(body: MessageDigest => Unit): Digest = {
75309
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    34
    val digest_body = new Setup_Build.Digest_Body { def apply(sha: MessageDigest): Unit = body(sha)}
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    35
    new Digest(Setup_Build.make_digest(digest_body))
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    36
  }
62702
e29f47e04180 tuned signature;
wenzelm
parents: 57638
diff changeset
    37
80359
bb4e95d19ecb minor performance tuning;
wenzelm
parents: 78236
diff changeset
    38
  val digest_empty: Digest = make_digest(_ => ())
bb4e95d19ecb minor performance tuning;
wenzelm
parents: 78236
diff changeset
    39
  def digest_length: Int = digest_empty.toString.length
bb4e95d19ecb minor performance tuning;
wenzelm
parents: 78236
diff changeset
    40
48409
0d2114eb412a more explicit java.io.{File => JFile};
wenzelm
parents: 48343
diff changeset
    41
  def digest(file: JFile): Digest =
75394
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    42
    make_digest(sha => using(new FileInputStream(file)) { stream =>
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    43
      val buf = new Array[Byte](65536)
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    44
      var m = 0
75709
a068fb7346ef clarified while-loops;
wenzelm
parents: 75394
diff changeset
    45
      while ({
75394
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    46
        m = stream.read(buf, 0, buf.length)
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    47
        if (m != -1) sha.update(buf, 0, m)
75709
a068fb7346ef clarified while-loops;
wenzelm
parents: 75394
diff changeset
    48
        m != -1
a068fb7346ef clarified while-loops;
wenzelm
parents: 75394
diff changeset
    49
      }) ()
75394
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    50
    })
48343
3060e6343953 more SHA1.digest operations;
wenzelm
parents: 45673
diff changeset
    51
62704
478b49f0d726 proper SHA1 digest as annex to heap file: Poly/ML reads precise segment length;
wenzelm
parents: 62702
diff changeset
    52
  def digest(path: Path): Digest = digest(path.file)
75309
216c2ac23a84 clarified signature;
wenzelm
parents: 75307
diff changeset
    53
  def digest(bytes: Array[Byte]): Digest = make_digest(_.update(bytes))
80360
6ea999f55c2d tuned signature;
wenzelm
parents: 80359
diff changeset
    54
  def digest(bytes: Array[Byte], offset: Int, length: Int): Digest =
6ea999f55c2d tuned signature;
wenzelm
parents: 80359
diff changeset
    55
    make_digest(_.update(bytes, offset, length))
54440
2c4940d2edf7 tuned signature;
wenzelm
parents: 50203
diff changeset
    56
  def digest(bytes: Bytes): Digest = bytes.sha1_digest
2c4940d2edf7 tuned signature;
wenzelm
parents: 50203
diff changeset
    57
  def digest(string: String): Digest = digest(Bytes(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: 55802
diff changeset
    58
77207
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    59
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    60
  /* shasum */
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    61
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    62
  final class Shasum private[SHA1](private[SHA1] val rep: List[String]) {
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    63
    override def equals(other: Any): Boolean =
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    64
      other match {
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    65
        case that: Shasum => rep.equals(that.rep)
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    66
        case _ => false
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    67
      }
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    68
    override def hashCode: Int = rep.hashCode
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    69
    override def toString: String = Library.terminate_lines(rep)
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    70
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    71
    def is_empty: Boolean = rep.isEmpty
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    72
78236
f3a6140fa3b1 tuned signature: more operations;
wenzelm
parents: 77675
diff changeset
    73
    def - (other: Shasum): Shasum = new Shasum(rep.filterNot(other.rep.toSet.contains))
f3a6140fa3b1 tuned signature: more operations;
wenzelm
parents: 77675
diff changeset
    74
77214
df8d71edbc79 clarified signature, using right-associative operation;
wenzelm
parents: 77213
diff changeset
    75
    def :::(other: Shasum): Shasum = new Shasum(other.rep ::: rep)
df8d71edbc79 clarified signature, using right-associative operation;
wenzelm
parents: 77213
diff changeset
    76
77675
9e5f8f6e58a0 more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
wenzelm
parents: 77215
diff changeset
    77
    def filter(pred: String => Boolean): Shasum = new Shasum(rep.filter(pred))
9e5f8f6e58a0 more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
wenzelm
parents: 77215
diff changeset
    78
77207
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    79
    def digest: Digest = {
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    80
      rep match {
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    81
        case List(s)
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    82
        if s.length == digest_length && s.forall(Symbol.is_ascii_hex) => fake_digest(s)
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    83
        case _ => SHA1.digest(toString)
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    84
      }
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    85
    }
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    86
  }
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    87
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    88
  val no_shasum: Shasum = new Shasum(Nil)
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    89
  def flat_shasum(list: List[Shasum]): Shasum = new Shasum(list.flatMap(_.rep))
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    90
  def fake_shasum(text: String): Shasum = new Shasum(Library.trim_split_lines(text))
d98a99e4eea9 proper Shasum.digest, to emulate old form from build_history database;
wenzelm
parents: 77204
diff changeset
    91
77213
05a4ce3f6b0c tuned whitespace;
wenzelm
parents: 77212
diff changeset
    92
  def shasum(digest: Digest, name: String): Shasum =
05a4ce3f6b0c tuned whitespace;
wenzelm
parents: 77212
diff changeset
    93
    new Shasum(List(digest.toString + " " + name))
05a4ce3f6b0c tuned whitespace;
wenzelm
parents: 77212
diff changeset
    94
  def shasum_meta_info(digest: Digest): Shasum =
05a4ce3f6b0c tuned whitespace;
wenzelm
parents: 77212
diff changeset
    95
    shasum(digest, isabelle.setup.Build.META_INFO)
77211
a917f580a107 clarified signature;
wenzelm
parents: 77209
diff changeset
    96
  def shasum_sorted(args: List[(Digest, String)]): Shasum =
77212
a7c4510ae251 tuned --- implicit split;
wenzelm
parents: 77211
diff changeset
    97
    flat_shasum(args.sortBy(_._2).map(shasum))
38473
bd96f2a5beb0 digesting strings according to SHA-1 -- Scala version;
wenzelm
parents:
diff changeset
    98
}