1# Copyright 2024 The Sigstore Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Digests for memory objects.
16
17These can only compute hashes of objects residing in memory, after they get
18converted to bytes.
19
20Example usage:
21```python
22>>> hasher = SHA256()
23>>> hasher.update(b"abcd")
24>>> digest = hasher.compute()
25>>> digest.digest_hex
26'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'
27```
28
29Or, passing the data directly in the constructor:
30```python
31>>> hasher = SHA256(b"abcd")
32>>> digest = hasher.compute()
33>>> digest.digest_hex
34'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'
35```
36"""
37
38import hashlib
39
40from typing_extensions import override
41
42from model_signing._hashing import hashing
43
44
45class SHA256(hashing.StreamingHashEngine):
46 """A wrapper around `hashlib.sha256`."""
47
48 def __init__(self, initial_data: bytes = b""):
49 """Initializes an instance of a SHA256 hash engine.
50
51 Args:
52 initial_data: Optional initial data to hash.
53 """
54 self._hasher = hashlib.sha256(initial_data)
55
56 @override
57 def update(self, data: bytes) -> None:
58 self._hasher.update(data)
59
60 @override
61 def reset(self, data: bytes = b"") -> None:
62 self._hasher = hashlib.sha256(data)
63
64 @override
65 def compute(self) -> hashing.Digest:
66 return hashing.Digest(self.digest_name, self._hasher.digest())
67
68 @property
69 @override
70 def digest_name(self) -> str:
71 return "sha256"
72
73 @property
74 @override
75 def digest_size(self) -> int:
76 return self._hasher.digest_size
77
78
79class BLAKE2(hashing.StreamingHashEngine):
80 """A wrapper around `hashlib.blake2b`."""
81
82 def __init__(self, initial_data: bytes = b""):
83 """Initializes an instance of a BLAKE2 hash engine.
84
85 Args:
86 initial_data: Optional initial data to hash.
87 """
88 self._hasher = hashlib.blake2b(initial_data)
89
90 @override
91 def update(self, data: bytes) -> None:
92 self._hasher.update(data)
93
94 @override
95 def reset(self, data: bytes = b"") -> None:
96 self._hasher = hashlib.blake2b(data)
97
98 @override
99 def compute(self) -> hashing.Digest:
100 return hashing.Digest(self.digest_name, self._hasher.digest())
101
102 @property
103 @override
104 def digest_name(self) -> str:
105 return "blake2b"
106
107 @property
108 @override
109 def digest_size(self) -> int:
110 return self._hasher.digest_size