Coverage for src/lib/cash.py: 73%

77 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2025-03-09 17:37 +0000

1 

2from random import randint 

3from cryptography.hazmat.primitives import hashes 

4 

5 

6class Cash(): 

7 data: str 

8 bits: int 

9 proof: str 

10 nonce: int 

11 

12 def __init__(self, data: str, bits: int): 

13 self.data = data.encode() 

14 self.bits = bits 

15 self.proof = None 

16 self.nonce = None 

17 

18 def __str__(self): # pragma: no cover 

19 return 'Cash(b={})'.format(self.bits) 

20 

21 def __repr__(self): # pragma: no cover 

22 return self.__str__() 

23 

24 def mine(self) -> int: 

25 self.nonce = randint(0, 100000000) 

26 

27 cycle = 0 

28 while True: 

29 cycle += 1 

30 

31 input_data = b'FC:' + str(self.bits).encode() + b':' + self.data + b':' + str(self.nonce).encode() 

32 

33 # print(input_data) 

34 # print(input_data.hex()) 

35 

36 hasher = hashes.Hash(hashes.SHA256()) 

37 hasher.update(input_data) 

38 digest = hasher.finalize() 

39 # print('digest: {} {}'.format(self.nonce, digest.hex())) 

40 

41 found_bits = 0 

42 for c in digest: 

43 if c & 0b10000000: 

44 break 

45 if c & 0b01000000: 

46 found_bits += 1 

47 break 

48 if c & 0b00100000: 

49 found_bits += 2 

50 break 

51 if c & 0b00010000: 

52 found_bits += 3 

53 break 

54 if c & 0b00001000: 

55 found_bits += 4 

56 break 

57 if c & 0b00000100: 

58 found_bits += 5 

59 break 

60 if c & 0b00000010: 

61 found_bits += 6 

62 break 

63 if c & 0b00000001: 

64 found_bits += 7 

65 break 

66 if c == 0: 

67 found_bits += 8 

68 

69 if found_bits >= self.bits: 

70 break 

71 

72 if found_bits >= self.bits: 

73 self.proof = digest.hex() 

74 break 

75 

76 self.nonce += 1 

77 

78 return cycle 

79 

80 def verify(self, proof: str, nonce: int) -> bool: 

81 if len(proof) != 64: 

82 # print('verify, invalid length') 

83 return False 

84 

85 full_bytes = self.bits % 4 == 0 

86 if full_bytes: 

87 if not proof.startswith('0' * (self.bits // 4)): 

88 # print('verify, startswith wrong') 

89 return False 

90 else: 

91 found_bits = 0 

92 for c in bytes.fromhex(proof): 

93 pos = bin(c)[2:].zfill(8).find('1') 

94 if pos == -1: 

95 found_bits += 8 

96 continue 

97 

98 found_bits += pos 

99 break 

100 

101 # print('verify, found_bits: {} {}'.format(found_bits, self.bits)) 

102 if found_bits < self.bits: 

103 # print('verify, found_bits wrong') 

104 return False 

105 

106 input_data = b'FC:' + str(self.bits).encode() + b':' + self.data + b':' + str(nonce).encode() 

107 

108 hasher = hashes.Hash(hashes.SHA256()) 

109 hasher.update(input_data) 

110 digest = hasher.finalize() 

111 

112 return digest.hex() == proof