Răsfoiți Sursa

hash raw bytes of integers, not their string representations

Malte Kraus 8 ani în urmă
părinte
comite
bd2d844afe
2 a modificat fișierele cu 19 adăugiri și 6 ștergeri
  1. 18 3
      src/block.py
  2. 1 3
      src/proof_of_work.py

+ 18 - 3
src/block.py

@@ -4,6 +4,7 @@ from datetime import datetime
 from binascii import hexlify, unhexlify
 from binascii import hexlify, unhexlify
 import json
 import json
 import logging
 import logging
+import math
 
 
 from .merkle import merkle_tree
 from .merkle import merkle_tree
 from .crypto import get_hasher
 from .crypto import get_hasher
@@ -91,24 +92,38 @@ class Block:
         """ Verify that the merkle root hash is correct for the transactions in this block. """
         """ Verify that the merkle root hash is correct for the transactions in this block. """
         return merkle_tree(self.transactions).get_hash() == self.merkle_root_hash
         return merkle_tree(self.transactions).get_hash() == self.merkle_root_hash
 
 
+    def _int_to_bytes(self, val: int):
+        l = val.bit_length()
+        l = (0 if l % 8 == 0 or l == 0 else 1) + l // 8;
+        return val.to_bytes(l, 'little')
+
     def get_partial_hash(self):
     def get_partial_hash(self):
         """
         """
         Computes a hash over the contents of this block, except for the nonce. The proof of
         Computes a hash over the contents of this block, except for the nonce. The proof of
         work can use this partial hash to efficiently try different nonces. Other uses should
         work can use this partial hash to efficiently try different nonces. Other uses should
         use :any:`get_hash` to get the complete hash.
         use :any:`get_hash` to get the complete hash.
         """
         """
+        # TODO: the dynamically sized values here could in theory allow two different objects
+        # to hash to the same value (e.g. ('ab', 'c') has same hash as ('a', 'bc') )
         hasher = get_hasher()
         hasher = get_hasher()
         hasher.update(self.prev_block_hash)
         hasher.update(self.prev_block_hash)
         hasher.update(self.merkle_root_hash)
         hasher.update(self.merkle_root_hash)
         hasher.update(str(self.time.timestamp()).encode())
         hasher.update(str(self.time.timestamp()).encode())
-        hasher.update(str(self.difficulty).encode())
+        hasher.update(self._int_to_bytes(self.difficulty))
         return hasher
         return hasher
+    def finish_hash(self, hasher):
+        """
+        Finishes the hash in `hasher` with the nonce in this block. The proof of
+        work can use this function to efficiently try different nonces. Other uses should
+        use :any:`get_hash` to get the complete hash in one step.
+        """
+        hasher.update(self._int_to_bytes(self.nonce))
+        return hasher.digest()
 
 
     def get_hash(self):
     def get_hash(self):
         """ Compute the hash of the header data. This is not necessarily the received hash value for this block! """
         """ Compute the hash of the header data. This is not necessarily the received hash value for this block! """
         hasher = self.get_partial_hash()
         hasher = self.get_partial_hash()
-        hasher.update(str(self.nonce).encode()) # for mining we want to get a copy of hasher here
-        return hasher.digest()
+        return self.finish_hash(hasher)
 
 
     def verify_difficulty(self):
     def verify_difficulty(self):
         """ Verify that the hash value is correct and fulfills its difficulty promise. """
         """ Verify that the hash value is correct and fulfills its difficulty promise. """

+ 1 - 3
src/proof_of_work.py

@@ -43,9 +43,7 @@ class ProofOfWork:
         hasher = self.block.get_partial_hash()
         hasher = self.block.get_partial_hash()
         while not self.stopped:
         while not self.stopped:
             for _ in range(1000):
             for _ in range(1000):
-                h = hasher.copy()
-                h.update(str(self.block.nonce).encode())
-                self.block.hash = h.digest()
+                self.block.hash = self.block.finish_hash(hasher.copy())
                 if verify_proof_of_work(self.block):
                 if verify_proof_of_work(self.block):
                     return self.block
                     return self.block
                 self.block.nonce += 1
                 self.block.nonce += 1