Advertisement
franji

Untitled

Jan 28th, 2018
1,131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.28 KB | None | 0 0
  1. import hashlib
  2. import struct
  3. import random
  4.  
  5. def Log2(n):
  6.     """Log2(n) - how many times n can be be divided by2 before it is zero.
  7.    >>> Log2(0)
  8.    0
  9.    >>> Log2(5)
  10.    3
  11.    """
  12.     for i in xrange(32):
  13.         # mask is i ones in binary
  14.         # i==0  => mask==0b0
  15.         # i==1  => mask==0b1
  16.         # i==2  => mask==0b11
  17.         mask = (1L << i) - 1
  18.         if (n & mask) == n:
  19.             return i
  20.     return 99
  21.  
  22. g_puzzle_bits0 = 20  # put in a variable so we can make it lower for testing
  23. def NumberOfZerosForPuzzle(block_serial_number):
  24.     """Given a block serial number - how many zeros should be at the end of its signature
  25.    >>> NumberOfZerosForPuzzle(1000)
  26.    30
  27.    """
  28.     return g_puzzle_bits0 + Log2(block_serial_number)
  29.  
  30.  
  31. def WalletCode(member_names_list):
  32.     """Given list of the names of wallet owners - return a 32 bit number - wallet number.
  33.    >>> WalletCode(["Foo Bar", "Bar Vaz"])
  34.    3622990312
  35.    """
  36.     member_names_str = ",".join(sorted(member_names_list))
  37.     m = hashlib.md5()
  38.     m.update(member_names_str.lower())
  39.     data = m.digest()
  40.     # take lower 32 bit of member's name digest
  41.     # Note - unpack returns a tuple of size 1 - we use [0] to get the number
  42.     return struct.unpack(">L", data[:4])[0]
  43.  
  44. # Block is 32 byte/256bit long.
  45. # record/block format:
  46. # 32 bit serial number
  47. # 32 bit wallet number
  48. # 64 bit prev_sig[:8]highest bits  (first half ) of previous block's signature (including all the block)
  49. # 32 bit puzzle answer
  50. # 96 bit sig[:12] - md5 - the first 12 bytes of md5 of above fields. need to make last N bits zero
  51.  
  52. def CreateBlock0_TestStage():
  53.     block0 = [0, 0, "BLOCKNUM", 2016330331, ""]
  54.     m = hashlib.md5()
  55.     block0_bin = struct.pack(">LL8sL", *block0[:4])
  56.     m.update(block0_bin)
  57.     block0_bin += m.digest()[:12]
  58.     return block0_bin
  59.  
  60.  
  61.  
  62. def CheckSignature(sig, n_zeros):
  63.     # check tha last n_zeros bits of signature.
  64.     # look at them byte by bye (8 bits together)
  65.     sig_index = 15  # look at last byte
  66.     while n_zeros >= 8:
  67.         b = ord(sig[sig_index])
  68.         if b != 0:
  69.             return False  # bad signature
  70.         sig_index -= 1
  71.         n_zeros -= 8 # we checked one byte
  72.     if n_zeros == 0:
  73.         return True  # this happens when n_zeros was divisible by 8
  74.     mask = (1L << n_zeros) - 1
  75.     b = ord(sig[sig_index])
  76.     return (b & mask) == 0
  77.  
  78.  
  79. def CheckBlockSignature(serial, wallet, prev_sig, puzzle, block_sig):
  80.     """Given a block fields - check that signature is valid and puzzle is solved.
  81.    return 0 if OK, reason for erro if not.
  82.    """
  83.     block_data = struct.pack(">LL8sL", serial, wallet, prev_sig, puzzle)
  84.     m = hashlib.md5()
  85.     m.update(block_data)
  86.     sig = m.digest()
  87.     # check sig has right number of zeros at the end
  88.     n_zeros = NumberOfZerosForPuzzle(serial)
  89.     if not CheckSignature(sig, n_zeros):
  90.         return 4
  91.     # check that the signature is part of the block
  92.     if block_sig != sig[:12]:
  93.         return 5
  94.     return 0
  95.  
  96. def unpack_clock_to_tuple(block_bin):
  97.     return struct.unpack(">LL8sL12s", block_bin)
  98.  
  99. def IsValidBlock(prev_block_bin, block_bin):
  100.     """Check if block_bin is valid given the previous block.
  101.    return 0 if Block ok, a reason number if not.
  102.    """
  103.     prev_block = unpack_clock_to_tuple(prev_block_bin)
  104.     block = unpack_clock_to_tuple(block_bin)
  105.     return IsValidBlockUnpacked(prev_block, block)
  106.  
  107.  
  108. def IsValidBlockUnpacked(prev_block_tuple, block_tuple):
  109.     # check serial number
  110.     if block_tuple[0] != prev_block_tuple[0] + 1:
  111.         return 1
  112.     # check that not same wallet number
  113.     if block_tuple[1] == prev_block_tuple[1]:
  114.         return 2
  115.     # check that new block contins part of prev block signature
  116.     if block_tuple[2] != prev_block_tuple[4][:8]:
  117.         return 3
  118.     #calculate the signature for the block
  119.     return CheckBlockSignature(*block_tuple)
  120.  
  121.  
  122. def MineCoinAttempts(my_wallet, prev_block_bin, attempts_count):
  123.     prev_block = struct.unpack(">LL8sL12s", prev_block_bin)
  124.     serial, w, prev_prev_sig, prev_puzzle, prev_sig  = prev_block
  125.     new_serial = serial + 1
  126.     prev_half = prev_sig[:8]
  127.     n_zeros = NumberOfZerosForPuzzle(new_serial)
  128.     for _ in xrange(attempts_count):
  129.         puzzle = random.randint(0, 1<<32 - 1)
  130.         #print new_serial, my_wallet, prev_half, puzzle
  131.         block_bin = struct.pack(">LL8sL", new_serial, my_wallet, prev_half, puzzle)
  132.         m = hashlib.md5()
  133.         m.update(block_bin)
  134.         sig = m.digest()
  135.         if CheckSignature(sig, n_zeros):
  136.             block_bin += sig[:12]
  137.             return block_bin # new block
  138.     return None # could not find block in attempts_count
  139.  
  140. def MineCoin(my_wallet, prev_block_bin):
  141.     new_block = None
  142.     while not new_block:
  143.         new_block = MineCoinAttempts(my_wallet, prev_block_bin, 10000)
  144.     return new_block
  145.  
  146.  
  147. def TestMining():
  148.     prev_block = CreateBlock0_TestStage()
  149.     wallet1 = WalletCode(["Tal Franji"])
  150.     wallet2 = WalletCode(["Foo Bar"])
  151.     for _ in xrange(1000):
  152.         new_block = MineCoin(wallet1, prev_block)
  153.         if IsValidBlock(prev_block, new_block) != 0:
  154.             print "BAD"
  155.             break
  156.         print repr(prev_block)
  157.         prev_block = new_block
  158.         wallet1, wallet2 = wallet2, wallet1
  159.  
  160. #To test this module:
  161. #TestMining()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement