Skip to content

Commit

Permalink
Add support for BLAKE2 hashing. (#217)
Browse files Browse the repository at this point in the history
Next, on this stream, I'm planning on adding benchmarks (via
google-benchmarks for micro benchmarking and hyperfine for large scale
benchmarking). But I'll focus on the manifest for the next few PRs,
currently just splitting up parallel work.

Signed-off-by: Mihai Maruseac <[email protected]>
  • Loading branch information
mihaimaruseac authored Jun 21, 2024
1 parent 96e52b4 commit f67fc1e
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 3 deletions.
37 changes: 35 additions & 2 deletions model_signing/hashing/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,38 @@ def digest_name(self) -> str:
@override
@property
def digest_size(self) -> int:
"""The size, in bytes, of the digests produced by the engine."""
return 32
return self._hasher.digest_size


class BLAKE2(hashing.StreamingHashEngine):
"""A wrapper around `hashlib.blake2b`."""

def __init__(self, initial_data: bytes = b""):
"""Initializes an instance of a BLAKE2 hash engine.
Args:
initial_data: Optional initial data to hash.
"""
self._hasher = hashlib.blake2b(initial_data)

@override
def update(self, data: bytes) -> None:
self._hasher.update(data)

@override
def reset(self, data: bytes = b"") -> None:
self._hasher = hashlib.blake2b(data)

@override
def compute(self) -> hashing.Digest:
return hashing.Digest(self.digest_name, self._hasher.digest())

@override
@property
def digest_name(self) -> str:
return "blake2b"

@override
@property
def digest_size(self) -> int:
return self._hasher.digest_size
59 changes: 58 additions & 1 deletion model_signing/hashing/memory_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from model_signing.hashing import memory


class TestPrecomputedDigest:
class TestSHA256:

def test_hash_known_value(self):
hasher = memory.SHA256(b"Test string")
Expand Down Expand Up @@ -69,3 +69,60 @@ def test_digest_size(self):

digest = hasher.compute()
assert digest.digest_size == 32


class TestBLAKE2:

def test_hash_known_value(self):
hasher = memory.BLAKE2(b"Test string")
digest = hasher.compute()
expected = (
"3f1b20a13e94ef2a12c50f40de256e0eb444f274b8e2e04e5fb3f572242c858a"
"f600a06a0c350eef1645307a9bf2fa1fcb65445a0b3b2b44d0602ab95f4fb802"
)
assert digest.digest_hex == expected

def test_hash_update_twice_is_the_same_as_update_with_concatenation(self):
str1 = "Test "
str2 = "string"

hasher1 = memory.BLAKE2()
hasher1.update(str1.encode("utf-8"))
hasher1.update(str2.encode("utf-8"))
digest1 = hasher1.compute()

str_all = str1 + str2
hasher2 = memory.BLAKE2()
hasher2.update(str_all.encode("utf-8"))
digest2 = hasher2.compute()

assert digest1.digest_hex == digest2.digest_hex
assert digest1.digest_value == digest2.digest_value

def test_hash_update_empty(self):
hasher1 = memory.BLAKE2(b"Test string")
hasher1.update(b"")
digest1 = hasher1.compute()

hasher2 = memory.BLAKE2(b"Test string")
digest2 = hasher2.compute()

assert digest1.digest_hex == digest2.digest_hex
assert digest1.digest_value == digest2.digest_value

def test_update_after_reset(self):
hasher = memory.BLAKE2(b"Test string")
digest1 = hasher.compute()
hasher.reset()
hasher.update(b"Test string")
digest2 = hasher.compute()

assert digest1.digest_hex == digest2.digest_hex
assert digest1.digest_value == digest2.digest_value

def test_digest_size(self):
hasher = memory.BLAKE2(b"Test string")
assert hasher.digest_size == 64

digest = hasher.compute()
assert digest.digest_size == 64

0 comments on commit f67fc1e

Please sign in to comment.