Skip to content

Commit

Permalink
Update sha256 and bit
Browse files Browse the repository at this point in the history
  • Loading branch information
reverse.hash committed May 6, 2023
1 parent 5ca2cea commit f0265d9
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 27 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/200b67d3924c40e38479efdcd9b04aac)](https://www.codacy.com/gh/reverse-hash/understanding-bitcoin/dashboard?utm_source=github.com&utm_medium=referral&utm_content=reverse-hash/understanding-bitcoin&utm_campaign=Badge_Grade)
![test workflow](https://github.com/reverse-hash/understanding-bitcoin/actions/workflows/tests.yml/badge.svg)
![format workflow](https://github.com/reverse-hash/understanding-bitcoin/actions/workflows/format.yml/badge.svg)
![coverage workflow](https://github.com/reverse-hash/understanding-bitcoin/actions/workflows/coverage.yml/badge.svg)
![coverage workflow](https://github.com/reverse-hash/understanding-bitcoin/actions/workflows/coverage.yml/badge.svg)

## First steps

```commandline
python -m pip install --upgrade pip
pip install -r requirements.txt
```
9 changes: 6 additions & 3 deletions understandingbitcoin/common/bit.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ def from_bytes(cls, byte_value: bytes) -> BitStream:
:param byte_value: The array of bytes to convert
:return: The binary sequence representation
"""
return BitStream.from_unsigned_int(int.from_bytes(byte_value, byteorder='big'))
return BitStream.from_unsigned_int(int.from_bytes(byte_value,
byteorder='big'))

@classmethod
def from_char(cls, char: str) -> BitStream:
Expand Down Expand Up @@ -142,9 +143,11 @@ def __add__(self, other: BitStream | str | int) -> BitStream:
if isinstance(other, (BitStream, str)):
result: int = int(str(self) or self.BIT_0, 2) \
+ int(str(other) or self.BIT_0, 2)
return BitStream.from_unsigned_int(result, max(len(self), len(other)))
return BitStream.from_unsigned_int(result, max(len(self),
len(other)))

return BitStream.from_unsigned_int(int(self._value or self.BIT_0, 2) + other)
return BitStream.from_unsigned_int(int(self._value or self.BIT_0, 2)
+ other)

def __and__(self, other: BitStream):
"""
Expand Down
55 changes: 32 additions & 23 deletions understandingbitcoin/hash/sha256.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ def hash(cls, message: bytes) -> bytes:
# words
words: tuple[64] = cls._expand_block(block)

# words are processed through a series of rounds and hash values
# are updated using the output of each block
cls._compute_hash(hash_values, words)
# words are processed through a series of rounds
block_output: tuple[8] = cls._compress_words(hash_values, words)

# hash values are updated using the output of each block
cls._update_hash(hash_values, block_output)

# final hash output is generated once all blocks of the message have
# been processed
Expand Down Expand Up @@ -125,10 +127,11 @@ def _init_hash(cls) -> list[8]:

@classmethod
def _expand_block(cls, block: ByteBuffer) -> tuple[64]:
# create a 64 entry list of 64 i
# create a 64 entry list
words: list[64] = [None] * 64

# w[0..15] is a copy of the block
i: int
for i in range(16):
words[i] = block.get_word32()

Expand All @@ -140,7 +143,7 @@ def _expand_block(cls, block: ByteBuffer) -> tuple[64]:
return tuple(words)

@classmethod
def _compute_hash(cls, hash_values: list[8], words: tuple[64]) -> None:
def _compress_words(cls, hash_values: list[8], words: tuple[64]) -> tuple:
# unpack and copy current hash values
(a, b, c, d, e, f, g, h) = hash_values

Expand All @@ -157,24 +160,7 @@ def _compute_hash(cls, hash_values: list[8], words: tuple[64]) -> None:
b = a
a = (t1 + t2).mod(cls._WORD_SIZE_BITS)

# update hash values with the compressed chunk
hash_values[0] = (hash_values[0] + a).mod(cls._WORD_SIZE_BITS)
hash_values[1] = (hash_values[1] + b).mod(cls._WORD_SIZE_BITS)
hash_values[2] = (hash_values[2] + c).mod(cls._WORD_SIZE_BITS)
hash_values[3] = (hash_values[3] + d).mod(cls._WORD_SIZE_BITS)
hash_values[4] = (hash_values[4] + e).mod(cls._WORD_SIZE_BITS)
hash_values[5] = (hash_values[5] + f).mod(cls._WORD_SIZE_BITS)
hash_values[6] = (hash_values[6] + g).mod(cls._WORD_SIZE_BITS)
hash_values[7] = (hash_values[7] + h).mod(cls._WORD_SIZE_BITS)

@staticmethod
def _generate_digest(hash_values: list[8]) -> bytes:
digest: ByteBuffer = ByteBuffer()
value: BitStream
for value in hash_values:
digest.put_word32(value)

return digest.bytes()
return a, b, c, d, e, f, g, h

@staticmethod
def _σ0(x: BitStream) -> BitStream:
Expand All @@ -199,3 +185,26 @@ def _choice(x: BitStream, y: BitStream, z: BitStream) -> BitStream:
@staticmethod
def _majority(x: BitStream, y: BitStream, z: BitStream) -> BitStream:
return (x & y) ^ (x & z) ^ (y & z)

@classmethod
def _update_hash(cls, hash_values: list[8], block_output: tuple):
(a, b, c, d, e, f, g, h) = block_output

# update hash values with the compressed chuck
hash_values[0] = (hash_values[0] + a).mod(cls._WORD_SIZE_BITS)
hash_values[1] = (hash_values[1] + b).mod(cls._WORD_SIZE_BITS)
hash_values[2] = (hash_values[2] + c).mod(cls._WORD_SIZE_BITS)
hash_values[3] = (hash_values[3] + d).mod(cls._WORD_SIZE_BITS)
hash_values[4] = (hash_values[4] + e).mod(cls._WORD_SIZE_BITS)
hash_values[5] = (hash_values[5] + f).mod(cls._WORD_SIZE_BITS)
hash_values[6] = (hash_values[6] + g).mod(cls._WORD_SIZE_BITS)
hash_values[7] = (hash_values[7] + h).mod(cls._WORD_SIZE_BITS)

@staticmethod
def _generate_digest(hash_values: list[8]) -> bytes:
digest: ByteBuffer = ByteBuffer(order=ByteOrder.BIG_ENDIAN)
value: BitStream
for value in hash_values:
digest.put_word32(value)

return digest.bytes()

0 comments on commit f0265d9

Please sign in to comment.