Skip to content

Commit

Permalink
add capability to do incremental hash digests (#4)
Browse files Browse the repository at this point in the history
* add capability to do incremental hash digests

* add ability to copy digests

* change to use  and
  • Loading branch information
pipermerriam committed Feb 21, 2018
1 parent 2955411 commit 1fc4879
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 4 deletions.
26 changes: 26 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,32 @@ Compute a Keccak256 Hash
>>> keccak(b'')
b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p"


You may also compute hashes incrementally

.. doctest::

>>> from eth_hash.auto import keccak
>>> preimage = keccak.new(b'part-a')
>>> preimage.update(b'part-b')
>>> preimage.digest()
b'6\x91l\xdd50\xd6[\x7f\xf9B\xff\xc9SW\x98\xc3\xaal\xd9\xde\xdd6I\xb7\x91\x9e\xf4`pl\x08'

The preimage object returned may be copied as well.

.. doctest::

>>> from eth_hash.auto import keccak
>>> preimage = keccak.new(b'part-a')
>>> preimage_copy = preimage.copy()
>>> preimage.update(b'part-b')
>>> preimage.digest()
b'6\x91l\xdd50\xd6[\x7f\xf9B\xff\xc9SW\x98\xc3\xaal\xd9\xde\xdd6I\xb7\x91\x9e\xf4`pl\x08'
>>> preimage_copy.update(b'part-c')
>>> preimage_copy.digest()
b'\xffcy45\xea\xdd\xdf\x8e(\x1c\xfcF\xf3\xd4\xa1S\x0f\xdf\xd8\x01!\xb2(\xe1\xc7\xc6\xa3\x08\xc3\n\x0b'


Select one of many installed backends
---------------------------------------

Expand Down
4 changes: 2 additions & 2 deletions eth_hash/backends/pysha3.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from sha3 import (
keccak_256,
keccak_256 as _keccak_256,
)


def keccak256(prehash: bytes) -> bytes:
return keccak_256(prehash).digest()
return _keccak_256(prehash).digest()
25 changes: 24 additions & 1 deletion eth_hash/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,33 @@ class Keccak256:
def __init__(self, backend):
self.hasher = backend.keccak256

assert self.hasher(b'') == b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p" # noqa: E501
assert self.hasher(b'') == b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';\x7b\xfa\xd8\x04]\x85\xa4p" # noqa: E501

def __call__(self, preimage):
if not isinstance(preimage, bytes):
raise TypeError("Can only compute the hash of a `bytes` value, not %r" % preimage)

return self.hasher(preimage)

def new(self, part):
if not isinstance(part, bytes):
raise TypeError("Can only compute the hash of a `bytes` value, not %r" % part)
return PreImage(part, keccak_fn=self.hasher)


class PreImage:
def __init__(self, *parts, keccak_fn):
self.preimage_parts = list(parts)
self.keccak_fn = keccak_fn

def update(self, part):
if not isinstance(part, bytes):
raise TypeError("Can only compute the hash of a `bytes` value, not %r" % part)
self.preimage_parts.append(part)

def digest(self):
return self.keccak_fn(b''.join(self.preimage_parts))

def copy(self):
digest = type(self)(*self.preimage_parts, keccak_fn=self.keccak_fn)
return digest
36 changes: 35 additions & 1 deletion tests/backends/test_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,43 @@ def keccak_auto():
(
(
b'',
b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", # noqa: E501
b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';\x7b\xfa\xd8\x04]\x85\xa4p", # noqa: E501
),
),
)
def test_keccak_256(keccak, prehash, expected_result):
assert keccak(prehash) == expected_result


@pytest.mark.parametrize(
'parts, expected_result',
(
(
[b''],
b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';\x7b\xfa\xd8\x04]\x85\xa4p", # noqa: E501
),
(
[b'', b'', b''],
b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';\x7b\xfa\xd8\x04]\x85\xa4p", # noqa: E501
),
(
[b'arst', b'tsra'],
b"\xb1\xf3T\xb2\x8f\xf2\x84R\xd6\xb9\xd6\x1fA\x06\x1b\xbe\x82\xbe\xb1\xfc\x98\xf33d\xa8\x05\x8d\x1a]\x16M\x05", # noqa: E501
),
),
)
def test_keccak_256_preimage(keccak, parts, expected_result):
preimage = keccak.new(parts[0])
for part in parts[1:]:
preimage.update(part)
assert preimage.digest() == expected_result


def test_copy_keccak_256_preimage(keccak):
preimage_origin = keccak.new(b'')
preimage_copy = preimage_origin.copy()

preimage_origin.update(b'arsttsra')

assert preimage_origin.digest() == b"\xb1\xf3T\xb2\x8f\xf2\x84R\xd6\xb9\xd6\x1fA\x06\x1b\xbe\x82\xbe\xb1\xfc\x98\xf33d\xa8\x05\x8d\x1a]\x16M\x05" # noqa: E501
assert preimage_copy.digest() == b"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';\x7b\xfa\xd8\x04]\x85\xa4p" # noqa: E501

0 comments on commit 1fc4879

Please sign in to comment.