working serialization

This commit is contained in:
Florian Förster 2025-12-15 10:46:21 +01:00
parent 357347c30c
commit b3324182f7
4 changed files with 1225 additions and 565 deletions

View File

@ -1,25 +1,44 @@
import os import os
import sys import sys
from pathlib import Path
from Cython.Build import cythonize from Cython.Build import cythonize
from Cython.Compiler import Options from Cython.Compiler import Options
from setuptools import setup from setuptools import Extension, setup
# Cython compilation options
Options.docstrings = False Options.docstrings = False
Options.embed_pos_in_docstring = False Options.embed_pos_in_docstring = False
Options.annotate = False Options.annotate = False
Options.fast_fail = True Options.fast_fail = True
DEBUG = bool(os.getenv("DOPT_DEBUG", None)) DEBUG = bool(os.getenv("DOPT_DEBUG", None))
linetrace_opt: bool = False linetrace_opt: bool = False
if DEBUG: if DEBUG:
linetrace_opt = True linetrace_opt = True
# includes
OPENSSL_DIR = (Path(__file__).parent / "openssl").resolve()
assert OPENSSL_DIR.exists()
openssl_include = OPENSSL_DIR / "include"
assert openssl_include.exists()
openssl_lib = OPENSSL_DIR / "lib"
assert openssl_lib.exists()
ext = Extension(
name="polluck_blockchain.placeholder_native",
sources=["src/polluck_blockchain/placeholder_native.pyx"],
include_dirs=[str(openssl_include)],
library_dirs=[str(openssl_lib)],
libraries=["libssl", "libcrypto"],
)
ext_modules = cythonize( ext_modules = cythonize(
[ [
ext,
# "src/polluck_blockchain/placeholder.py", # "src/polluck_blockchain/placeholder.py",
"src/polluck_blockchain/placeholder_native.pyx", # "src/polluck_blockchain/placeholder_native.pyx",
# "src/polluck_blockchain/python_translate.py", # "src/polluck_blockchain/python_translate.py",
], ],
compiler_directives={ compiler_directives={

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@ from libc.stdint cimport uint64_t
from libc.stdlib cimport malloc, free 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
ctypedef unsigned long ULong ctypedef unsigned long ULong
@ -48,9 +49,13 @@ cdef int serialize_uint64(unsigned char* out, unsigned long long v) except -1 no
out[6] = (v >> 8) & 0xFF out[6] = (v >> 8) & 0xFF
out[7] = v & 0xFF out[7] = v & 0xFF
cdef struct SerializeResult: # cdef struct SerializeResult:
unsigned char *ptr # unsigned char *ptr
size_t size # size_t size
# cdef struct DigestResult:
# unsigned char *ptr
# size_t size
cdef class PyBlock: cdef class PyBlock:
cdef: cdef:
@ -159,19 +164,19 @@ cdef class PyBlock:
def hash(self): def hash(self):
return self.BlockC.hash.decode("UTF-8") return self.BlockC.hash.decode("UTF-8")
cdef SerializeResult bytes_serialize_c(self): cdef unsigned char* bytes_serialize_c(self, size_t *size):
cdef: cdef:
size_t total_len size_t total_len
unsigned char* buf unsigned char* buf
size_t pos = 0 size_t pos = 0
# index (8), timestamp (8), nonce (8), data, prev_hash # index (8), timestamp (8), nonce (8), data, prev_hash
total_len = ( size[0] = (
<size_t>(8 * 3) + <size_t>(8 * 3) +
self.BlockC.data.size() + self.BlockC.data.size() +
self.BlockC.prev_hash.size() self.BlockC.prev_hash.size()
) )
buf = <unsigned char*>malloc(total_len * sizeof(unsigned char)) buf = <unsigned char*>malloc(size[0] * sizeof(unsigned char))
if buf == NULL: if buf == NULL:
raise MemoryError() raise MemoryError()
@ -197,15 +202,65 @@ cdef class PyBlock:
) )
pos += self.BlockC.prev_hash.size() pos += self.BlockC.prev_hash.size()
return SerializeResult(buf, total_len) return buf
def bytes_serialize(self): def bytes_serialize(self):
cdef SerializeResult serialize_res cdef:
unsigned char *serialize_res
size_t serialize_size
try: try:
serialize_res = self.bytes_serialize_c() serialize_res = self.bytes_serialize_c(&serialize_size)
return serialize_res.ptr[:serialize_res.size] return serialize_res[:serialize_size]
finally: finally:
free(serialize_res.ptr) 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()
if ctx == NULL:
raise MemoryError()
cdef const ossl.EVP_MD *algo = ossl.EVP_sha256()
cdef:
unsigned char* digest
size_t dig_buff_len
unsigned int digest_len
dig_buff_len = <size_t>ossl.EVP_MD_size(algo)
digest = <unsigned char*>malloc(dig_buff_len * sizeof(unsigned char))
ossl.EVP_DigestInit_ex(ctx, algo, NULL)
ossl.EVP_DigestUpdate(ctx, data, data_size)
ossl.EVP_DigestFinal_ex(ctx, digest, &digest_len)
digest_size[0] = dig_buff_len
ossl.EVP_MD_CTX_free(ctx)
return digest
cdef unsigned char* perform_hash_c(self, size_t *digest_size):
cdef:
unsigned char *serialize_res
size_t serialize_size
unsigned char *digest
serialize_res = self.bytes_serialize_c(&serialize_size)
digest = self.digest(serialize_res, serialize_size, digest_size)
return digest
cpdef perform_hash(self):
cdef:
unsigned char *digest
size_t digest_size
try:
digest = self.perform_hash_c(&digest_size)
self.BlockC.hash = bytes(digest[:digest_size]).hex().encode("UTF-8")
finally:
free(digest)
return self.hash
@ -234,7 +289,7 @@ cdef class Blockchain:
self._chain = new unordered_map[uint64_t, Block*]() self._chain = new unordered_map[uint64_t, Block*]()
if self._chain is NULL: if self._chain is NULL:
raise MemoryError("Could not allocate hasmap") raise MemoryError("Could not allocate hasmap")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
pass pass