pylibswarm

Python3 wrapper for libswarm-ng
git clone git://git.defalsify.org/pylibswarm.git
Log | Files | Refs | Submodules | README | LICENSE

python_swarm.c (6332B)


      1 #define PY_SSIZE_T_CLEAN
      2 #include <Python.h>
      3 #include <stdio.h>
      4 #include <fcntl.h>
      5 #include <sys/stat.h>
      6 #include <unistd.h>
      7 
      8 #include "bmt.h"
      9 #include "swarmfile.h"
     10 #include "soc.h"
     11 
     12 
     13 static void client_callback_do(const unsigned char *hash, const unsigned char *data, size_t data_length, void *callback_static) {
     14 	PyObject *callback = (PyObject*)callback_static;
     15 
     16 	PyObject_CallFunction(callback, "y#y#", hash, SWARM_WORD_SIZE, data, data_length);
     17 }
     18 
     19 
     20 static void soc_sign_callback(char *z, const unsigned char *address, const unsigned char *data, void *callback_static) {
     21 	PyObject *callback = (PyObject*)callback_static;
     22 	PyObject *r;
     23 	unsigned char *signature_bytes;
     24 
     25 
     26 	r = PyObject_CallFunction(callback, "y#y#", address, SWARM_ADDRESS_SIZE, data, SWARM_WORD_SIZE);
     27 	signature_bytes =  PyBytes_AsString(r);
     28 
     29 	memcpy(z, signature_bytes, SWARM_SIGNATURE_SIZE);
     30 }
     31 
     32 
     33 static bmt_spansize_t filehash_path(filehash_t *fctx, const unsigned char *filepath) {
     34 	int fd;
     35 	int r;
     36 	int c;
     37 	size_t l;
     38 	struct stat st;
     39 	unsigned char buf[SWARM_BLOCK_SIZE];
     40 
     41 	fd = open(filepath, O_RDONLY);
     42 	if (fd == -1) {
     43 		return -1;
     44 	}
     45 
     46 	r = fstat(fd, &st);
     47 	if (r == -1) {
     48 		return -1;
     49 	}
     50 	
     51 	// TODO: Return hardcoded zero-hash
     52 	if (st.st_size == 0) {
     53 		close(fd);
     54 		return -1;
     55 	}
     56 
     57 	c = 0;
     58 	while (1) {
     59 		l = read(fd, buf, SWARM_BLOCK_SIZE);
     60 		if (l == 0) {
     61 			break;
     62 		}
     63 		c += l;
     64 		filehash_write(fctx, buf, l);
     65 	}
     66 
     67 	close(fd);
     68 
     69 	if (st.st_size != c) {
     70 		return -1;
     71 	}
     72 
     73 	return filehash_sum(fctx);
     74 }
     75 
     76 
     77 static PyObject* method_bmt_hash(PyObject *self, PyObject *args) {
     78 	bmt_t bctx;
     79 	const unsigned char *input;
     80 	Py_ssize_t input_length;
     81 	bmt_spansize_t data_length;
     82 	int r;
     83 
     84 	r = PyArg_ParseTuple(args, "yIL", &input, &input_length, &data_length);
     85 	if (r != 1) {
     86 		PyErr_SetString(PyExc_ValueError, "could not build values");
     87 		return NULL;
     88 	}
     89 
     90 	bmt_init(&bctx, (char*)input, input_length, data_length);
     91 	r = bmt_sum(&bctx);
     92 	if (r != 0) {
     93 		PyErr_SetString(PyExc_RuntimeError, "bmt hashing failed");
     94 		return NULL;
     95 	}
     96 
     97 	return Py_BuildValue("y#", &bctx.buf, SWARM_WORD_SIZE);
     98 }
     99 
    100 
    101 static PyObject* method_filehash_path(PyObject *self, PyObject *args) {
    102 	filehash_t fctx;
    103 	const unsigned char *inpath;
    104 	PyObject *client_callback;
    105 
    106 	int r;
    107 	r = PyArg_ParseTuple(args, "s|O", &inpath, &client_callback);
    108 	if (r != 1) {
    109 		PyErr_SetString(PyExc_ValueError, "could not build values");
    110 		return NULL;
    111 	}
    112 
    113 	if (client_callback == NULL) {
    114 		filehash_init(&fctx);
    115 	} else {
    116 		filehash_init_callback(&fctx, client_callback_do, client_callback);
    117 	}
    118 	r = filehash_path(&fctx, inpath);
    119 	if (r == -1) {
    120 		PyErr_Format(PyExc_RuntimeError, "file hashing failed for path %s", inpath);
    121 		return NULL;
    122 	}
    123 
    124 	return Py_BuildValue("y#", &fctx.buf, SWARM_WORD_SIZE);
    125 }
    126 
    127 
    128 static PyObject* method_soc_identifier(PyObject *self, PyObject *args) {
    129 	int r;
    130 	const PyBytesObject *topic;
    131 	const PyBytesObject *index;
    132 	const unsigned char *topic_bytes;
    133 	const unsigned char *index_bytes;
    134 	char out[128];
    135 
    136 	r = PyArg_ParseTuple(args, "SS", &topic, &index);
    137 	if (r != 1) {
    138 		PyErr_SetString(PyExc_ValueError, "could not build values");
    139 		return NULL;
    140 	}
    141 
    142 	topic_bytes = PyBytes_AsString((PyObject*)topic);
    143 	index_bytes = PyBytes_AsString((PyObject*)index);
    144 	r = soc_identifier(out, topic_bytes, index_bytes);
    145 	if (r != 0) {
    146 		PyErr_SetString(PyExc_RuntimeError, "could not build identifier");
    147 		return NULL;
    148 	}
    149 
    150 	return Py_BuildValue("y#", &out, SWARM_WORD_SIZE);
    151 }
    152 
    153 
    154 static PyObject* method_soc_create(PyObject *self, PyObject *args) {
    155 	int r;
    156 	bmt_t bctx;
    157 	const PyBytesObject *identifier;
    158 	unsigned char *identifier_bytes;
    159 	const PyBytesObject *input;
    160 	const PyBytesObject *address;
    161 	unsigned char *address_bytes;
    162 	size_t input_length;
    163 	unsigned char *p;
    164 	unsigned char soc_hash[128];
    165 	bmt_spansize_t data_length;
    166 	unsigned char soc_serialized[SWARM_DATA_LENGTH_TYPESIZE + SWARM_BLOCK_SIZE];
    167 	soc_chunk_t chunk;
    168 	PyObject *client_callback;
    169 	PyObject *keystore_callback;
    170 
    171 	client_callback = NULL;
    172 
    173 	r = PyArg_ParseTuple(args, "SSSILO|O", &identifier, &address, &input, &input_length, &data_length, &keystore_callback, &client_callback);
    174 	if (r != 1) {
    175 		PyErr_SetString(PyExc_ValueError, "could not build values");
    176 		return NULL;
    177 	}
    178 	memcpy(&chunk.data.payload_sz, &input_length, sizeof(input_length));
    179 	memcpy(chunk.data.span, &data_length, SWARM_DATA_LENGTH_TYPESIZE);
    180 	if (data_length > SWARM_BLOCK_SIZE) {
    181 		PyErr_Format(PyExc_ValueError, "data payload size %d exceeds maximum of %d bytes", chunk.data.payload_sz, SWARM_BLOCK_SIZE);
    182 		return NULL;
    183 	}
    184 	chunk.data.payload = PyBytes_AsString((PyObject*)input);
    185 	identifier_bytes = PyBytes_AsString((PyObject*)identifier);
    186 	address_bytes = PyBytes_AsString((PyObject*)address);
    187 	memcpy(chunk.identifier, identifier_bytes, SWARM_SOC_IDENTIFIER_SIZE);
    188 	bmt_init(&bctx, (char*)chunk.data.payload, data_length, data_length);
    189 	r = bmt_sum(&bctx);
    190 	if (r != 0) {
    191 		PyErr_SetString(PyExc_RuntimeError, "bmt hashing failed");
    192 		return NULL;
    193 	}
    194 	memcpy(chunk.data.hash, bctx.buf, SWARM_WORD_SIZE);
    195 	r = soc_digest(&chunk, soc_hash);
    196 	if (r != 0) {
    197 		PyErr_SetString(PyExc_RuntimeError, "soc digest failed");
    198 		return NULL;
    199 	}
    200 	soc_sign_callback(&chunk.signature, address_bytes, soc_hash, keystore_callback);
    201 
    202 	p = soc_serialize(&chunk, soc_serialized, &input_length);
    203 	if (p == NULL) {
    204 		PyErr_SetString(PyExc_RuntimeError, "soc serialize failed");
    205 		return NULL;
    206 	}
    207 
    208 	if (client_callback != NULL) {
    209 		client_callback_do(soc_hash, soc_serialized, input_length, client_callback);
    210 	}
    211 
    212 	return Py_BuildValue("y#y#y#", chunk.signature, SWARM_SIGNATURE_SIZE, soc_hash, SWARM_WORD_SIZE, soc_serialized, input_length);
    213 
    214 }
    215 
    216 
    217 static PyMethodDef SwarmMethods[] = {
    218 	{"bmt_hash", method_bmt_hash, METH_VARARGS, "Calculate the BMT hash of the given data"},
    219 	{"filehash_path", method_filehash_path, METH_VARARGS, "Calculate the Swarm file hash of the data from the given file path, with optional callback to receive chunks"},
    220 	{"soc_identifier", method_soc_identifier, METH_VARARGS, "Build an SOC identifier from given topic and index"},
    221 	{"soc_create", method_soc_create, METH_VARARGS, "Build an SOC chunk from given data and identifier"},
    222 	{NULL, NULL, 0, NULL},
    223 };
    224 
    225 
    226 static struct PyModuleDef swarmmodule = {
    227 	PyModuleDef_HEAD_INIT,
    228 	"swarm",
    229 	NULL,
    230 	-1,
    231 	SwarmMethods,
    232 };
    233 
    234 
    235 PyMODINIT_FUNC PyInit_swarm(void) {
    236 	return PyModule_Create(&swarmmodule);
    237 }