Include prototyping steps #1

Merged
foefl merged 15 commits from native_hashing into main 2025-12-16 12:50:07 +00:00
4 changed files with 2585 additions and 1003 deletions
Showing only changes of commit e5ca60919e - Show all commits

View File

@ -60,8 +60,8 @@ linker_args: list[str] = []
if sys.platform.startswith("win") and not DEBUG: if sys.platform.startswith("win") and not DEBUG:
c_args = ("/O2", "/GL", "/Gy") c_args = ("/O2", "/GL", "/Gy", "/openmp:llvm")
l_args = ("/LTCG", "/OPT:REF", "/OPT:ICF") l_args = ("/LTCG", "/OPT:REF", "/OPT:ICF", "/openmp:llvm")
else: else:
c_args = tuple() c_args = tuple()
l_args = tuple() l_args = tuple()

View File

@ -4,12 +4,11 @@ cdef extern from "openssl/evp.h":
pass pass
ctypedef struct EVP_MD: ctypedef struct EVP_MD:
pass pass
EVP_MD_CTX *EVP_MD_CTX_new() EVP_MD_CTX *EVP_MD_CTX_new() nogil
void EVP_MD_CTX_free(EVP_MD_CTX *) void EVP_MD_CTX_free(EVP_MD_CTX *) nogil
const EVP_MD *EVP_sha256() const EVP_MD *EVP_sha256() nogil
int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, void *impl) int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, void *impl) nogil
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt) int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt) nogil
int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s) nogil
unsigned int *s) int EVP_MD_size(const EVP_MD *md) nogil
int EVP_MD_size(const EVP_MD *md) int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) nogil
int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ from libc.stdlib cimport malloc, free
from libc.string cimport memcpy from libc.string cimport memcpy
from cython.operator import postincrement, dereference from cython.operator import postincrement, dereference
cimport polluck_blockchain.openssl_evp as ossl cimport polluck_blockchain.openssl_evp as ossl
from cython.parallel cimport prange
ctypedef unsigned long ULong ctypedef unsigned long ULong
@ -57,14 +58,35 @@ cdef int serialize_uint64(unsigned char* out, unsigned long long v) except -1 no
# unsigned char *ptr # unsigned char *ptr
# size_t size # size_t size
cdef const size_t NONCE_OFFSET = <size_t>16
cdef inline bint has_leading_zero_bits(const unsigned char *digest, int num_bits) nogil:
cdef int i, full_bytes = num_bits // 8
cdef int rem_bits = num_bits % 8
for i in range(full_bytes):
if digest[i] != 0:
return False
if rem_bits:
if digest[full_bytes] >> (8 - rem_bits) != 0:
return False
return True
cdef inline bint has_leading_zero_bytes(const unsigned char *digest, int num_bytes) nogil:
cdef int i, full_bytes = num_bytes // 8
cdef int rem_bits = num_bytes % 8
for i in range(num_bytes):
if digest[i] != 0:
return False
return True
cdef class PyBlock: cdef class PyBlock:
cdef: cdef:
# ULong _index
# double _timestamp
# string _data
# string _prev_hash
# ULong _nonce
# string _hash
Block *BlockC Block *BlockC
bint ptr_owner bint ptr_owner
@ -164,7 +186,7 @@ cdef class PyBlock:
def hash(self): def hash(self):
return self.BlockC.hash.decode("UTF-8") return self.BlockC.hash.decode("UTF-8")
cdef unsigned char* bytes_serialize_c(self, size_t *size): cdef unsigned char* bytes_serialize_c(self, size_t *size) nogil:
cdef: cdef:
size_t total_len size_t total_len
unsigned char* buf unsigned char* buf
@ -179,7 +201,7 @@ cdef class PyBlock:
buf = <unsigned char*>malloc(size[0] * sizeof(unsigned char)) buf = <unsigned char*>malloc(size[0] * sizeof(unsigned char))
if buf == NULL: if buf == NULL:
raise MemoryError() return NULL
serialize_uint64(buf + pos, self.BlockC.index) serialize_uint64(buf + pos, self.BlockC.index)
pos += 8 pos += 8
@ -204,21 +226,13 @@ cdef class PyBlock:
return buf return buf
def bytes_serialize(self): cdef unsigned char* digest(self, unsigned char *data, size_t data_size, size_t *digest_size) nogil:
cdef:
unsigned char *serialize_res
size_t serialize_size
try:
serialize_res = self.bytes_serialize_c(&serialize_size)
return serialize_res[:serialize_size]
finally:
free(serialize_res)
cdef unsigned char* digest(self, unsigned char *data, size_t data_size, size_t *digest_size):
cdef ossl.EVP_MD_CTX *ctx = ossl.EVP_MD_CTX_new() cdef ossl.EVP_MD_CTX *ctx = ossl.EVP_MD_CTX_new()
if ctx == NULL: if ctx == NULL:
raise MemoryError() return NULL
cdef const ossl.EVP_MD *algo = ossl.EVP_sha256() cdef const ossl.EVP_MD *algo = ossl.EVP_sha256()
if algo == NULL:
return NULL
cdef: cdef:
unsigned char* digest unsigned char* digest
@ -237,14 +251,74 @@ cdef class PyBlock:
return digest return digest
cdef unsigned char* perform_hash_c(self, size_t *digest_size): def bytes_serialize(self):
cdef:
unsigned char *serialize_res
size_t serialize_size
try:
serialize_res = self.bytes_serialize_c(&serialize_size)
return serialize_res[:serialize_size]
finally:
free(serialize_res)
cpdef mine(self, unsigned int difficulty, unsigned int max_nonce=0xFFFFFFFF):
cdef:
unsigned char *serial_buf
size_t serialize_size
unsigned char *digest
size_t digest_size
bint nonce_found = False
int nonce, nonce_solution = 0
bint *p_nonce_found = &nonce_found
int *p_nonce_solution = &nonce_solution
serial_buf = self.bytes_serialize_c(&serialize_size)
# for nonce in prange(max_nonce, nogil=True, schedule="static", num_threads=16):
# if p_nonce_found[0]:
# break
# serialize_uint64(serial_buf + NONCE_OFFSET, <uint64_t>nonce)
# digest = self.digest(serial_buf, serialize_size, &digest_size)
# if has_leading_zero_bits(digest, difficulty):
# p_nonce_found[0] = True
# p_nonce_solution[0] = nonce
# break
# free(digest)
with nogil:
for nonce in range(max_nonce):
serialize_uint64(serial_buf + NONCE_OFFSET, <uint64_t>nonce)
digest = self.digest(serial_buf, serialize_size, &digest_size)
if has_leading_zero_bits(digest, difficulty):
nonce_found = True
nonce_solution = nonce
break
free(digest)
if not nonce_found:
raise RuntimeError("No valid nonce found")
self.BlockC.nonce = <uint64_t>nonce_solution
cdef unsigned char* perform_hash_c(self, size_t *digest_size) nogil:
cdef: cdef:
unsigned char *serialize_res unsigned char *serialize_res
size_t serialize_size size_t serialize_size
unsigned char *digest unsigned char *digest
serialize_res = self.bytes_serialize_c(&serialize_size) serialize_res = self.bytes_serialize_c(&serialize_size)
if serialize_res == NULL:
return NULL
digest = self.digest(serialize_res, serialize_size, digest_size) digest = self.digest(serialize_res, serialize_size, digest_size)
if digest == NULL:
return NULL
free(serialize_res)
return digest return digest
@ -255,6 +329,8 @@ cdef class PyBlock:
try: try:
digest = self.perform_hash_c(&digest_size) digest = self.perform_hash_c(&digest_size)
if digest == NULL:
raise MemoryError()
self.BlockC.hash = bytes(digest[:digest_size]).hex().encode("UTF-8") self.BlockC.hash = bytes(digest[:digest_size]).hex().encode("UTF-8")
finally: finally:
free(digest) free(digest)