/* * Written in 2013 by Dmitry Chestnykh * Modified for CPython by Christian Heimes * Updated to use HACL* by Jonathan Protzenko * * To the extent possible under law, the author have dedicated all * copyright and related and neighboring rights to this software to * the public domain worldwide. This software is distributed without * any warranty. http://creativecommons.org/publicdomain/zero/1.0/ */ #ifndef Py_BUILD_CORE_BUILTIN # define Py_BUILD_CORE_MODULE 1 #endif #include "Python.h" #include "hashlib.h" #include "pycore_strhex.h" // _Py_strhex() #include "pycore_typeobject.h" #include "pycore_moduleobject.h" // QUICK CPU AUTODETECTION // // See https://github.com/python/cpython/pull/119316 -- we only enable // vectorized versions for Intel CPUs, even though HACL*'s "vec128" modules also // run on ARM NEON. (We could enable them on POWER -- but I don't have access to // a test machine to see if that speeds anything up.) // // Note that configure.ac and the rest of the build are written in such a way // that if the configure script finds suitable flags to compile HACL's SIMD128 // (resp. SIMD256) files, then Hacl_Hash_Blake2b_Simd128.c (resp. ...) will be // pulled into the build automatically, and then only the CPU autodetection will // need to be updated here. #if defined(__x86_64__) && defined(__GNUC__) #include #elif defined(_M_X64) #include #endif #include // SIMD256 can't be compiled on macOS ARM64, and performance of SIMD128 isn't // great; but when compiling a universal2 binary, autoconf will set // HACL_CAN_COMPILE_SIMD128 and HACL_CAN_COMPILE_SIMD256 because they *can* be // compiled on x86_64. If we're on macOS ARM64, disable these preprocessor // symbols. #if defined(__APPLE__) && defined(__arm64__) # undef HACL_CAN_COMPILE_SIMD128 # undef HACL_CAN_COMPILE_SIMD256 #endif // Small mismatch between the variable names Python defines as part of configure // at the ones HACL* expects to be set in order to enable those headers. #define HACL_CAN_COMPILE_VEC128 HACL_CAN_COMPILE_SIMD128 #define HACL_CAN_COMPILE_VEC256 HACL_CAN_COMPILE_SIMD256 #include "_hacl/Hacl_Hash_Blake2s.h" #include "_hacl/Hacl_Hash_Blake2b.h" #if HACL_CAN_COMPILE_SIMD128 #include "_hacl/Hacl_Hash_Blake2s_Simd128.h" #endif #if HACL_CAN_COMPILE_SIMD256 #include "_hacl/Hacl_Hash_Blake2b_Simd256.h" #endif // MODULE TYPE SLOTS static PyType_Spec blake2b_type_spec; static PyType_Spec blake2s_type_spec; PyDoc_STRVAR(blake2mod__doc__, "_blake2 provides BLAKE2b and BLAKE2s for hashlib\n"); typedef struct { PyTypeObject *blake2b_type; PyTypeObject *blake2s_type; bool can_run_simd128; bool can_run_simd256; } Blake2State; static inline Blake2State * blake2_get_state(PyObject *module) { void *state = _PyModule_GetState(module); assert(state != NULL); return (Blake2State *)state; } #if defined(HACL_CAN_COMPILE_SIMD128) || defined(HACL_CAN_COMPILE_SIMD256) static inline Blake2State * blake2_get_state_from_type(PyTypeObject *module) { void *state = _PyType_GetModuleState(module); assert(state != NULL); return (Blake2State *)state; } #endif static struct PyMethodDef blake2mod_functions[] = { {NULL, NULL} }; static int _blake2_traverse(PyObject *module, visitproc visit, void *arg) { Blake2State *state = blake2_get_state(module); Py_VISIT(state->blake2b_type); Py_VISIT(state->blake2s_type); return 0; } static int _blake2_clear(PyObject *module) { Blake2State *state = blake2_get_state(module); Py_CLEAR(state->blake2b_type); Py_CLEAR(state->blake2s_type); return 0; } static void _blake2_free(void *module) { (void)_blake2_clear((PyObject *)module); } static void blake2module_init_cpu_features(Blake2State *state) { /* This must be kept in sync with hmacmodule_init_cpu_features() * in hmacmodule.c */ int eax1 = 0, ebx1 = 0, ecx1 = 0, edx1 = 0; int eax7 = 0, ebx7 = 0, ecx7 = 0, edx7 = 0; #if defined(__x86_64__) && defined(__GNUC__) __cpuid_count(1, 0, eax1, ebx1, ecx1, edx1); __cpuid_count(7, 0, eax7, ebx7, ecx7, edx7); #elif defined(_M_X64) int info1[4] = {0}; __cpuidex(info1, 1, 0); eax1 = info1[0], ebx1 = info1[1], ecx1 = info1[2], edx1 = info1[3]; int info7[4] = {0}; __cpuidex(info7, 7, 0); eax7 = info7[0], ebx7 = info7[1], ecx7 = info7[2], edx7 = info7[3]; #endif // fmt: off (void)eax1; (void)ebx1; (void)ecx1; (void)edx1; (void)eax7; (void)ebx7; (void)ecx7; (void)edx7; // fmt: on #define EBX_AVX2 (1 << 5) #define ECX_SSE3 (1 << 0) #define ECX_SSSE3 (1 << 9) #define ECX_SSE4_1 (1 << 19) #define ECX_SSE4_2 (1 << 20) #define ECX_AVX (1 << 28) #define EDX_SSE (1 << 25) #define EDX_SSE2 (1 << 26) #define EDX_CMOV (1 << 15) bool avx = (ecx1 & ECX_AVX) != 0; bool avx2 = (ebx7 & EBX_AVX2) != 0; bool sse = (edx1 & EDX_SSE) != 0; bool sse2 = (edx1 & EDX_SSE2) != 0; bool cmov = (edx1 & EDX_CMOV) != 0; bool sse3 = (ecx1 & ECX_SSE3) != 0; bool sse41 = (ecx1 & ECX_SSE4_1) != 0; bool sse42 = (ecx1 & ECX_SSE4_2) != 0; #undef EDX_CMOV #undef EDX_SSE2 #undef EDX_SSE #undef ECX_AVX #undef ECX_SSE4_2 #undef ECX_SSE4_1 #undef ECX_SSSE3 #undef ECX_SSE3 #undef EBX_AVX2 #if HACL_CAN_COMPILE_SIMD128 // TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection state->can_run_simd128 = sse && sse2 && sse3 && sse41 && sse42 && cmov; #else // fmt: off (void)sse; (void)sse2; (void)sse3; (void)sse41; (void)sse42; (void)cmov; // fmt: on state->can_run_simd128 = false; #endif #if HACL_CAN_COMPILE_SIMD256 // TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection state->can_run_simd256 = state->can_run_simd128 && avx && avx2; #else // fmt: off (void)avx; (void)avx2; // fmt: on state->can_run_simd256 = false; #endif } static int blake2_exec(PyObject *m) { Blake2State *st = blake2_get_state(m); blake2module_init_cpu_features(st); #define ADD_INT(DICT, NAME, VALUE) \ do { \ PyObject *x = PyLong_FromLong(VALUE); \ if (x == NULL) { \ return -1; \ } \ int rc = PyDict_SetItemString(DICT, NAME, x); \ Py_DECREF(x); \ if (rc < 0) { \ return -1; \ } \ } while(0) #define ADD_INT_CONST(NAME, VALUE) \ do { \ if (PyModule_AddIntConstant(m, NAME, VALUE) < 0) { \ return -1; \ } \ } while (0) ADD_INT_CONST("_GIL_MINSIZE", HASHLIB_GIL_MINSIZE); st->blake2b_type = (PyTypeObject *)PyType_FromModuleAndSpec( m, &blake2b_type_spec, NULL); if (st->blake2b_type == NULL) { return -1; } if (PyModule_AddType(m, st->blake2b_type) < 0) { return -1; } PyObject *d = st->blake2b_type->tp_dict; ADD_INT(d, "SALT_SIZE", HACL_HASH_BLAKE2B_SALT_BYTES); ADD_INT(d, "PERSON_SIZE", HACL_HASH_BLAKE2B_PERSONAL_BYTES); ADD_INT(d, "MAX_KEY_SIZE", HACL_HASH_BLAKE2B_KEY_BYTES); ADD_INT(d, "MAX_DIGEST_SIZE", HACL_HASH_BLAKE2B_OUT_BYTES); ADD_INT_CONST("BLAKE2B_SALT_SIZE", HACL_HASH_BLAKE2B_SALT_BYTES); ADD_INT_CONST("BLAKE2B_PERSON_SIZE", HACL_HASH_BLAKE2B_PERSONAL_BYTES); ADD_INT_CONST("BLAKE2B_MAX_KEY_SIZE", HACL_HASH_BLAKE2B_KEY_BYTES); ADD_INT_CONST("BLAKE2B_MAX_DIGEST_SIZE", HACL_HASH_BLAKE2B_OUT_BYTES); /* BLAKE2s */ st->blake2s_type = (PyTypeObject *)PyType_FromModuleAndSpec( m, &blake2s_type_spec, NULL); if (st->blake2s_type == NULL) { return -1; } if (PyModule_AddType(m, st->blake2s_type) < 0) { return -1; } d = st->blake2s_type->tp_dict; ADD_INT(d, "SALT_SIZE", HACL_HASH_BLAKE2S_SALT_BYTES); ADD_INT(d, "PERSON_SIZE", HACL_HASH_BLAKE2S_PERSONAL_BYTES); ADD_INT(d, "MAX_KEY_SIZE", HACL_HASH_BLAKE2S_KEY_BYTES); ADD_INT(d, "MAX_DIGEST_SIZE", HACL_HASH_BLAKE2S_OUT_BYTES); ADD_INT_CONST("BLAKE2S_SALT_SIZE", HACL_HASH_BLAKE2S_SALT_BYTES); ADD_INT_CONST("BLAKE2S_PERSON_SIZE", HACL_HASH_BLAKE2S_PERSONAL_BYTES); ADD_INT_CONST("BLAKE2S_MAX_KEY_SIZE", HACL_HASH_BLAKE2S_KEY_BYTES); ADD_INT_CONST("BLAKE2S_MAX_DIGEST_SIZE", HACL_HASH_BLAKE2S_OUT_BYTES); #undef ADD_INT_CONST #undef ADD_INT return 0; } static PyModuleDef_Slot _blake2_slots[] = { {Py_mod_exec, blake2_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; static struct PyModuleDef blake2_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_blake2", .m_doc = blake2mod__doc__, .m_size = sizeof(Blake2State), .m_methods = blake2mod_functions, .m_slots = _blake2_slots, .m_traverse = _blake2_traverse, .m_clear = _blake2_clear, .m_free = _blake2_free, }; PyMODINIT_FUNC PyInit__blake2(void) { return PyModuleDef_Init(&blake2_module); } // IMPLEMENTATION OF METHODS // The HACL* API does not offer an agile API that can deal with either Blake2S // or Blake2B -- the reason is that the underlying states are optimized (uint32s // for S, uint64s for B). Therefore, we use a tagged union in this module to // correctly dispatch. Note that the previous incarnation of this code // transformed the Blake2b implementation into the Blake2s one using a script, // so this is an improvement. // // The 128 and 256 versions are only available if i) we were able to compile // them, and ii) if the CPU we run on also happens to have the right instruction // set. typedef enum { Blake2s, Blake2b, Blake2s_128, Blake2b_256 } blake2_impl; static inline bool is_blake2b(blake2_impl impl) { return impl == Blake2b || impl == Blake2b_256; } static inline bool is_blake2s(blake2_impl impl) { return impl == Blake2s || impl == Blake2s_128; } static inline blake2_impl type_to_impl(PyTypeObject *type) { #if defined(HACL_CAN_COMPILE_SIMD128) || defined(HACL_CAN_COMPILE_SIMD256) Blake2State *st = blake2_get_state_from_type(type); #endif if (!strcmp(type->tp_name, blake2b_type_spec.name)) { #if HACL_CAN_COMPILE_SIMD256 return st->can_run_simd256 ? Blake2b_256 : Blake2b; #else return Blake2b; #endif } else if (!strcmp(type->tp_name, blake2s_type_spec.name)) { #if HACL_CAN_COMPILE_SIMD128 return st->can_run_simd128 ? Blake2s_128 : Blake2s; #else return Blake2s; #endif } Py_UNREACHABLE(); } typedef struct { PyObject_HEAD union { Hacl_Hash_Blake2s_state_t *blake2s_state; Hacl_Hash_Blake2b_state_t *blake2b_state; #if HACL_CAN_COMPILE_SIMD128 Hacl_Hash_Blake2s_Simd128_state_t *blake2s_128_state; #endif #if HACL_CAN_COMPILE_SIMD256 Hacl_Hash_Blake2b_Simd256_state_t *blake2b_256_state; #endif }; blake2_impl impl; bool use_mutex; PyMutex mutex; } Blake2Object; #define _Blake2Object_CAST(op) ((Blake2Object *)(op)) #include "clinic/blake2module.c.h" /*[clinic input] module _blake2 class _blake2.blake2b "Blake2Object *" "&PyBlake2_BLAKE2bType" class _blake2.blake2s "Blake2Object *" "&PyBlake2_BLAKE2sType" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=b7526666bd18af83]*/ static Blake2Object * new_Blake2Object(PyTypeObject *type) { Blake2Object *self = PyObject_GC_New(Blake2Object, type); if (self == NULL) { return NULL; } HASHLIB_INIT_MUTEX(self); PyObject_GC_Track(self); return self; } /* HACL* takes a uint32_t for the length of its parameter, but Py_ssize_t can be * 64 bits so we loop in <4gig chunks when needed. */ #if PY_SSIZE_T_MAX > UINT32_MAX # define HACL_UPDATE_LOOP(UPDATE_FUNC, STATE, BUF, LEN) \ do { \ while (LEN > UINT32_MAX) { \ (void)UPDATE_FUNC(STATE, BUF, UINT32_MAX); \ LEN -= UINT32_MAX; \ BUF += UINT32_MAX; \ } \ } while (0) #else # define HACL_UPDATE_LOOP(...) #endif /* * Note: we explicitly ignore the error code on the basis that it would take * more than 1 billion years to overflow the maximum admissible length for * blake2b/2s (2^64 - 1). */ #define HACL_UPDATE(UPDATE_FUNC, STATE, BUF, LEN) \ do { \ HACL_UPDATE_LOOP(UPDATE_FUNC, STATE, BUF, LEN); \ /* cast to uint32_t is now safe */ \ (void)UPDATE_FUNC(STATE, BUF, (uint32_t)LEN); \ } while (0) static void update(Blake2Object *self, uint8_t *buf, Py_ssize_t len) { switch (self->impl) { // blake2b_256_state and blake2s_128_state must be if'd since // otherwise this results in an unresolved symbol at link-time. #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: HACL_UPDATE(Hacl_Hash_Blake2b_Simd256_update, self->blake2b_256_state, buf, len); return; #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: HACL_UPDATE(Hacl_Hash_Blake2s_Simd128_update, self->blake2s_128_state, buf, len); return; #endif case Blake2b: HACL_UPDATE(Hacl_Hash_Blake2b_update, self->blake2b_state, buf, len); return; case Blake2s: HACL_UPDATE(Hacl_Hash_Blake2s_update, self->blake2s_state, buf, len); return; default: Py_UNREACHABLE(); } } #define BLAKE2_IMPLNAME(SELF) \ (is_blake2b((SELF)->impl) ? "blake2b" : "blake2s") #define GET_BLAKE2_CONST(SELF, NAME) \ (is_blake2b((SELF)->impl) \ ? HACL_HASH_BLAKE2B_ ## NAME \ : HACL_HASH_BLAKE2S_ ## NAME) #define MAX_OUT_BYTES(SELF) GET_BLAKE2_CONST(SELF, OUT_BYTES) #define MAX_SALT_LENGTH(SELF) GET_BLAKE2_CONST(SELF, SALT_BYTES) #define MAX_KEY_BYTES(SELF) GET_BLAKE2_CONST(SELF, KEY_BYTES) #define MAX_PERSONAL_BYTES(SELF) GET_BLAKE2_CONST(SELF, PERSONAL_BYTES) static int py_blake2_validate_params(Blake2Object *self, int digest_size, Py_buffer *key, Py_buffer *salt, Py_buffer *person, int fanout, int depth, unsigned long leaf_size, unsigned long long node_offset, int node_depth, int inner_size) { /* Validate digest size. */ if (digest_size <= 0 || (unsigned int)digest_size > MAX_OUT_BYTES(self)) { PyErr_Format( PyExc_ValueError, "digest_size for %s must be between 1 and %d bytes, got %d", BLAKE2_IMPLNAME(self), MAX_OUT_BYTES(self), digest_size ); goto error; } #define CHECK_LENGTH(NAME, VALUE, MAX) \ do { \ if ((size_t)(VALUE) > (size_t)(MAX)) { \ PyErr_Format(PyExc_ValueError, \ "maximum %s length is %zu bytes, got %zd", \ (NAME), (size_t)(MAX), (Py_ssize_t)(VALUE)); \ goto error; \ } \ } while (0) /* Validate key parameter. */ if (key->obj && key->len) { CHECK_LENGTH("key", key->len, MAX_KEY_BYTES(self)); } /* Validate salt parameter. */ if (salt->obj && salt->len) { CHECK_LENGTH("salt", salt->len, MAX_SALT_LENGTH(self)); } /* Validate personalization parameter. */ if (person->obj && person->len) { CHECK_LENGTH("person", person->len, MAX_PERSONAL_BYTES(self)); } #undef CHECK_LENGTH #define CHECK_TREE(NAME, VALUE, MIN, MAX) \ do { \ if ((VALUE) < (MIN) || (size_t)(VALUE) > (size_t)(MAX)) { \ PyErr_Format(PyExc_ValueError, \ "'%s' must be between %zu and %zu", \ (NAME), (size_t)(MIN), (size_t)(MAX)); \ goto error; \ } \ } while (0) /* Validate tree parameters. */ CHECK_TREE("fanout", fanout, 0, 255); CHECK_TREE("depth", depth, 1, 255); CHECK_TREE("node_depth", node_depth, 0, 255); CHECK_TREE("inner_size", inner_size, 0, MAX_OUT_BYTES(self)); #undef CHECK_TREE if (leaf_size > 0xFFFFFFFFU) { /* maximum: 2**32 - 1 */ PyErr_SetString(PyExc_OverflowError, "'leaf_size' is too large"); goto error; } if (is_blake2s(self->impl) && node_offset > 0xFFFFFFFFFFFFULL) { /* maximum: 2**48 - 1 */ PyErr_SetString(PyExc_OverflowError, "'node_offset' is too large"); goto error; } return 0; error: return -1; } static PyObject * py_blake2_new(PyTypeObject *type, PyObject *data, int digest_size, Py_buffer *key, Py_buffer *salt, Py_buffer *person, int fanout, int depth, unsigned long leaf_size, unsigned long long node_offset, int node_depth, int inner_size, int last_node, int usedforsecurity) { Blake2Object *self = NULL; self = new_Blake2Object(type); if (self == NULL) { goto error; } self->impl = type_to_impl(type); // Ensure that the states are NULL-initialized in case of an error. // See: py_blake2_clear() for more details. switch (self->impl) { #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: self->blake2b_256_state = NULL; break; #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: self->blake2s_128_state = NULL; break; #endif case Blake2b: self->blake2b_state = NULL; break; case Blake2s: self->blake2s_state = NULL; break; default: Py_UNREACHABLE(); } // Unlike the state types, the parameters share a single (client-friendly) // structure. if (py_blake2_validate_params(self, digest_size, key, salt, person, fanout, depth, leaf_size, node_offset, node_depth, inner_size) < 0) { goto error; } // Using Blake2b because we statically know that these are greater than the // Blake2s sizes -- this avoids a VLA. uint8_t salt_buffer[HACL_HASH_BLAKE2B_SALT_BYTES] = {0}; uint8_t personal_buffer[HACL_HASH_BLAKE2B_PERSONAL_BYTES] = {0}; if (salt->obj != NULL) { assert(salt->buf != NULL); memcpy(salt_buffer, salt->buf, salt->len); } if (person->obj != NULL) { assert(person->buf != NULL); memcpy(personal_buffer, person->buf, person->len); } Hacl_Hash_Blake2b_blake2_params params = { .digest_length = digest_size, .key_length = (uint8_t)key->len, .fanout = fanout, .depth = depth, .leaf_length = leaf_size, .node_offset = node_offset, .node_depth = node_depth, .inner_length = inner_size, .salt = salt_buffer, .personal = personal_buffer }; #define BLAKE2_MALLOC(TYPE, STATE) \ do { \ STATE = Hacl_Hash_ ## TYPE ## _malloc_with_params_and_key( \ ¶ms, last_node, key->buf); \ if (STATE == NULL) { \ (void)PyErr_NoMemory(); \ goto error; \ } \ } while (0) switch (self->impl) { #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: BLAKE2_MALLOC(Blake2b_Simd256, self->blake2b_256_state); break; #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: BLAKE2_MALLOC(Blake2s_Simd128, self->blake2s_128_state); break; #endif case Blake2b: BLAKE2_MALLOC(Blake2b, self->blake2b_state); break; case Blake2s: BLAKE2_MALLOC(Blake2s, self->blake2s_state); break; default: Py_UNREACHABLE(); } #undef BLAKE2_MALLOC /* Process initial data if any. */ if (data != NULL) { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error); if (buf.len >= HASHLIB_GIL_MINSIZE) { Py_BEGIN_ALLOW_THREADS update(self, buf.buf, buf.len); Py_END_ALLOW_THREADS } else { update(self, buf.buf, buf.len); } PyBuffer_Release(&buf); } return (PyObject *)self; error: Py_XDECREF(self); return NULL; } /*[clinic input] @classmethod _blake2.blake2b.__new__ as py_blake2b_new data as data_obj: object(c_default="NULL") = b'' * digest_size: int(c_default="HACL_HASH_BLAKE2B_OUT_BYTES") = _blake2.blake2b.MAX_DIGEST_SIZE key: Py_buffer(c_default="NULL", py_default="b''") = None salt: Py_buffer(c_default="NULL", py_default="b''") = None person: Py_buffer(c_default="NULL", py_default="b''") = None fanout: int = 1 depth: int = 1 leaf_size: unsigned_long = 0 node_offset: unsigned_long_long = 0 node_depth: int = 0 inner_size: int = 0 last_node: bool = False usedforsecurity: bool = True string: object(c_default="NULL") = None Return a new BLAKE2b hash object. [clinic start generated code]*/ static PyObject * py_blake2b_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size, Py_buffer *key, Py_buffer *salt, Py_buffer *person, int fanout, int depth, unsigned long leaf_size, unsigned long long node_offset, int node_depth, int inner_size, int last_node, int usedforsecurity, PyObject *string) /*[clinic end generated code: output=de64bd850606b6a0 input=78cf60a2922d2f90]*/ { PyObject *data; if (_Py_hashlib_data_argument(&data, data_obj, string) < 0) { return NULL; } return py_blake2_new(type, data, digest_size, key, salt, person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity); } /*[clinic input] @classmethod _blake2.blake2s.__new__ as py_blake2s_new data as data_obj: object(c_default="NULL") = b'' * digest_size: int(c_default="HACL_HASH_BLAKE2S_OUT_BYTES") = _blake2.blake2s.MAX_DIGEST_SIZE key: Py_buffer(c_default="NULL", py_default="b''") = None salt: Py_buffer(c_default="NULL", py_default="b''") = None person: Py_buffer(c_default="NULL", py_default="b''") = None fanout: int = 1 depth: int = 1 leaf_size: unsigned_long = 0 node_offset: unsigned_long_long = 0 node_depth: int = 0 inner_size: int = 0 last_node: bool = False usedforsecurity: bool = True string: object(c_default="NULL") = None Return a new BLAKE2s hash object. [clinic start generated code]*/ static PyObject * py_blake2s_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size, Py_buffer *key, Py_buffer *salt, Py_buffer *person, int fanout, int depth, unsigned long leaf_size, unsigned long long node_offset, int node_depth, int inner_size, int last_node, int usedforsecurity, PyObject *string) /*[clinic end generated code: output=582a0c4295cc3a3c input=6843d6332eefd295]*/ { PyObject *data; if (_Py_hashlib_data_argument(&data, data_obj, string) < 0) { return NULL; } return py_blake2_new(type, data, digest_size, key, salt, person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity); } static int blake2_blake2b_copy_locked(Blake2Object *self, Blake2Object *cpy) { assert(cpy != NULL); #define BLAKE2_COPY(TYPE, STATE_ATTR) \ do { \ cpy->STATE_ATTR = Hacl_Hash_ ## TYPE ## _copy(self->STATE_ATTR); \ if (cpy->STATE_ATTR == NULL) { \ goto error; \ } \ } while (0) switch (self->impl) { #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: BLAKE2_COPY(Blake2b_Simd256, blake2b_256_state); break; #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: BLAKE2_COPY(Blake2s_Simd128, blake2s_128_state); break; #endif case Blake2b: BLAKE2_COPY(Blake2b, blake2b_state); break; case Blake2s: BLAKE2_COPY(Blake2s, blake2s_state); break; default: Py_UNREACHABLE(); } #undef BLAKE2_COPY cpy->impl = self->impl; return 0; error: (void)PyErr_NoMemory(); return -1; } /*[clinic input] _blake2.blake2b.copy Return a copy of the hash object. [clinic start generated code]*/ static PyObject * _blake2_blake2b_copy_impl(Blake2Object *self) /*[clinic end generated code: output=622d1c56b91c50d8 input=e383c2d199fd8a2e]*/ { int rc; Blake2Object *cpy; if ((cpy = new_Blake2Object(Py_TYPE(self))) == NULL) { return NULL; } ENTER_HASHLIB(self); rc = blake2_blake2b_copy_locked(self, cpy); LEAVE_HASHLIB(self); if (rc < 0) { Py_DECREF(cpy); return NULL; } return (PyObject *)cpy; } /*[clinic input] _blake2.blake2b.update data: object / Update this hash object's state with the provided bytes-like object. [clinic start generated code]*/ static PyObject * _blake2_blake2b_update_impl(Blake2Object *self, PyObject *data) /*[clinic end generated code: output=99330230068e8c99 input=ffc4aa6a6a225d31]*/ { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROUT(data, &buf); if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) { self->use_mutex = true; } if (self->use_mutex) { Py_BEGIN_ALLOW_THREADS PyMutex_Lock(&self->mutex); update(self, buf.buf, buf.len); PyMutex_Unlock(&self->mutex); Py_END_ALLOW_THREADS } else { update(self, buf.buf, buf.len); } PyBuffer_Release(&buf); Py_RETURN_NONE; } static uint8_t blake2_blake2b_compute_digest(Blake2Object *self, uint8_t *digest) { switch (self->impl) { #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: return Hacl_Hash_Blake2b_Simd256_digest( self->blake2b_256_state, digest); #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: return Hacl_Hash_Blake2s_Simd128_digest( self->blake2s_128_state, digest); #endif case Blake2b: return Hacl_Hash_Blake2b_digest(self->blake2b_state, digest); case Blake2s: return Hacl_Hash_Blake2s_digest(self->blake2s_state, digest); default: Py_UNREACHABLE(); } } /*[clinic input] _blake2.blake2b.digest Return the digest value as a bytes object. [clinic start generated code]*/ static PyObject * _blake2_blake2b_digest_impl(Blake2Object *self) /*[clinic end generated code: output=31ab8ad477f4a2f7 input=7d21659e9c5fff02]*/ { uint8_t digest_length = 0, digest[HACL_HASH_BLAKE2B_OUT_BYTES]; ENTER_HASHLIB(self); digest_length = blake2_blake2b_compute_digest(self, digest); LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, digest_length); } /*[clinic input] _blake2.blake2b.hexdigest Return the digest value as a string of hexadecimal digits. [clinic start generated code]*/ static PyObject * _blake2_blake2b_hexdigest_impl(Blake2Object *self) /*[clinic end generated code: output=5ef54b138db6610a input=76930f6946351f56]*/ { uint8_t digest_length = 0, digest[HACL_HASH_BLAKE2B_OUT_BYTES]; ENTER_HASHLIB(self); digest_length = blake2_blake2b_compute_digest(self, digest); LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, digest_length); } static PyMethodDef py_blake2b_methods[] = { _BLAKE2_BLAKE2B_COPY_METHODDEF _BLAKE2_BLAKE2B_DIGEST_METHODDEF _BLAKE2_BLAKE2B_HEXDIGEST_METHODDEF _BLAKE2_BLAKE2B_UPDATE_METHODDEF {NULL, NULL} }; static PyObject * py_blake2b_get_name(PyObject *op, void *Py_UNUSED(closure)) { Blake2Object *self = _Blake2Object_CAST(op); return PyUnicode_FromString(BLAKE2_IMPLNAME(self)); } static PyObject * py_blake2b_get_block_size(PyObject *op, void *Py_UNUSED(closure)) { Blake2Object *self = _Blake2Object_CAST(op); return PyLong_FromLong(GET_BLAKE2_CONST(self, BLOCK_BYTES)); } static Hacl_Hash_Blake2b_index hacl_get_blake2_info(Blake2Object *self) { switch (self->impl) { #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: return Hacl_Hash_Blake2b_Simd256_info(self->blake2b_256_state); #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: return Hacl_Hash_Blake2s_Simd128_info(self->blake2s_128_state); #endif case Blake2b: return Hacl_Hash_Blake2b_info(self->blake2b_state); case Blake2s: return Hacl_Hash_Blake2s_info(self->blake2s_state); default: Py_UNREACHABLE(); } } static PyObject * py_blake2b_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) { Blake2Object *self = _Blake2Object_CAST(op); Hacl_Hash_Blake2b_index info = hacl_get_blake2_info(self); return PyLong_FromLong(info.digest_length); } static PyGetSetDef py_blake2b_getsetters[] = { {"name", py_blake2b_get_name, NULL, NULL, NULL}, {"block_size", py_blake2b_get_block_size, NULL, NULL, NULL}, {"digest_size", py_blake2b_get_digest_size, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; static int py_blake2_clear(PyObject *op) { Blake2Object *self = (Blake2Object *)op; // The initialization function uses PyObject_GC_New() but explicitly // initializes the HACL* internal state to NULL before allocating // it. If an error occurs in the constructor, we should only free // states that were allocated (i.e. that are not NULL). #define BLAKE2_FREE(TYPE, STATE) \ do { \ if (STATE != NULL) { \ Hacl_Hash_ ## TYPE ## _free(STATE); \ STATE = NULL; \ } \ } while (0) switch (self->impl) { #if HACL_CAN_COMPILE_SIMD256 case Blake2b_256: BLAKE2_FREE(Blake2b_Simd256, self->blake2b_256_state); break; #endif #if HACL_CAN_COMPILE_SIMD128 case Blake2s_128: BLAKE2_FREE(Blake2s_Simd128, self->blake2s_128_state); break; #endif case Blake2b: BLAKE2_FREE(Blake2b, self->blake2b_state); break; case Blake2s: BLAKE2_FREE(Blake2s, self->blake2s_state); break; default: Py_UNREACHABLE(); } #undef BLAKE2_FREE return 0; } static void py_blake2_dealloc(PyObject *self) { PyTypeObject *type = Py_TYPE(self); PyObject_GC_UnTrack(self); (void)py_blake2_clear(self); type->tp_free(self); Py_DECREF(type); } static int py_blake2_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); return 0; } static PyType_Slot blake2b_type_slots[] = { {Py_tp_clear, py_blake2_clear}, {Py_tp_dealloc, py_blake2_dealloc}, {Py_tp_traverse, py_blake2_traverse}, {Py_tp_doc, (char *)py_blake2b_new__doc__}, {Py_tp_methods, py_blake2b_methods}, {Py_tp_getset, py_blake2b_getsetters}, {Py_tp_new, py_blake2b_new}, {0, 0} }; static PyType_Slot blake2s_type_slots[] = { {Py_tp_clear, py_blake2_clear}, {Py_tp_dealloc, py_blake2_dealloc}, {Py_tp_traverse, py_blake2_traverse}, {Py_tp_doc, (char *)py_blake2s_new__doc__}, {Py_tp_methods, py_blake2b_methods}, {Py_tp_getset, py_blake2b_getsetters}, // only the constructor differs, so that it can receive a clinic-generated // default digest length suitable for blake2s {Py_tp_new, py_blake2s_new}, {0, 0} }; static PyType_Spec blake2b_type_spec = { .name = "_blake2.blake2b", .basicsize = sizeof(Blake2Object), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE, .slots = blake2b_type_slots }; static PyType_Spec blake2s_type_spec = { .name = "_blake2.blake2s", .basicsize = sizeof(Blake2Object), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HEAPTYPE, .slots = blake2s_type_slots };