You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
41 lines
1.8 KiB
41 lines
1.8 KiB
import hashlib |
|
from .support import bintohex |
|
|
|
def get_pow(data, noncelen=10, hashfn=hashlib.sha512, |
|
hashlen=64, nbits=1, truncate=0, maxiterations=10**8): |
|
""" Arguments: |
|
data - a string of bytes. |
|
noncelen - an int, the number of additional bytes to be appended |
|
to the bytestring `data` which will be used for grinding. |
|
hashfn - a function that outputs a finalized hash state that can |
|
be converted to a bytestring with .digest() (see hashlib). |
|
hashlen - the length of the bytestring created with the .digest() |
|
call just mentioned. |
|
nbits - an integer, the number of bits of proof of work required. |
|
truncate - an integer number of bytes to be truncated from the end |
|
of the hash digest created. |
|
maxiterations - an integer, how many grinding attempts maximum allowed |
|
to attempt to reach the target, before giving up. |
|
Returns: |
|
(nonceval, pow-preimage, niterations) |
|
where pow-preimage is data+nonce-in-bytes |
|
or |
|
(None, failure-reason, None) |
|
""" |
|
maxbits = (hashlen-truncate)*8 |
|
pow_target = 2 ** (maxbits - nbits) |
|
# note since we are using a trivial counter, two |
|
# elements of returned tuple are the same, this needn't be the case. |
|
for nonceval in range(maxiterations): |
|
x = data + bintohex(nonceval.to_bytes(noncelen, "big")).encode( |
|
"utf-8") |
|
pow_candidate = hashfn(x).digest()[:truncate] |
|
if int.from_bytes(pow_candidate, "big") < pow_target: |
|
return (nonceval, x, nonceval) |
|
return (None, "exceeded max-iterations: {}".format(maxiterations), None) |
|
|
|
def verify_pow(data, hashfn=hashlib.sha512, hashlen=64, nbits=1, truncate=0): |
|
return int.from_bytes(hashfn(data).digest()[:truncate], |
|
"big") < 2 ** ((hashlen - truncate) * 8 - nbits) |
|
|
|
|