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 }