/* * Written in 2013 by Dmitry Chestnykh <[email protected]> * Modified for CPython by Christian Heimes <[email protected]> * Updated to use HACL* by Jonathan Protzenko <[email protected]> * * 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 … #endif #include "pyconfig.h" #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 <cpuid.h> #elif defined(_M_X64) #include <intrin.h> #endif #include <stdbool.h> // 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 // ECX #define ECX_SSE3 … #define ECX_SSSE3 … #define ECX_SSE4_1 … #define ECX_SSE4_2 … #define ECX_AVX … // EBX #define EBX_AVX2 … // EDX #define EDX_SSE … #define EDX_SSE2 … #define EDX_CMOV … // zero-initialized by default cpu_flags; void detect_cpu_features(cpu_flags *flags) { … } #ifdef HACL_CAN_COMPILE_SIMD128 static inline bool has_simd128(cpu_flags *flags) { … } #endif #ifdef HACL_CAN_COMPILE_SIMD256 static inline bool has_simd256(cpu_flags *flags) { … } #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 … #define HACL_CAN_COMPILE_VEC256 … #include "_hacl/Hacl_Hash_Blake2b.h" #include "_hacl/Hacl_Hash_Blake2s.h" #if HACL_CAN_COMPILE_SIMD256 #include "_hacl/Hacl_Hash_Blake2b_Simd256.h" #endif #if HACL_CAN_COMPILE_SIMD128 #include "_hacl/Hacl_Hash_Blake2s_Simd128.h" #endif // MODULE TYPE SLOTS static PyType_Spec blake2b_type_spec; static PyType_Spec blake2s_type_spec; PyDoc_STRVAR(blake2mod__doc__, "_blake2b provides BLAKE2b for hashlib\n" ); Blake2State; static inline Blake2State* blake2_get_state(PyObject *module) { … } #if defined(HACL_CAN_COMPILE_SIMD128) || defined(HACL_CAN_COMPILE_SIMD256) static inline Blake2State* blake2_get_state_from_type(PyTypeObject *module) { … } #endif static struct PyMethodDef blake2mod_functions[] = …; static int _blake2_traverse(PyObject *module, visitproc visit, void *arg) { … } static int _blake2_clear(PyObject *module) { … } static void _blake2_free(void *module) { … } #define ADD_INT … #define ADD_INT_CONST … static int blake2_exec(PyObject *m) { … } #undef ADD_INT #undef ADD_INT_CONST static PyModuleDef_Slot _blake2_slots[] = …; static struct PyModuleDef blake2_module = …; PyMODINIT_FUNC PyInit__blake2(void) { … } // 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. blake2_impl; static inline bool is_blake2b(blake2_impl impl) { … } static inline bool is_blake2s(blake2_impl impl) { … } static inline blake2_impl type_to_impl(PyTypeObject *type) { … } Blake2Object; #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) { … } /* 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,state,buf,len) … #else #define HACL_UPDATE_LOOP … #endif #define HACL_UPDATE(update,state,buf,len) … static void update(Blake2Object *self, uint8_t *buf, Py_ssize_t len) { … } static PyObject * py_blake2b_or_s_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) { … } /*[clinic input] @classmethod _blake2.blake2b.__new__ as py_blake2b_new data: 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 Return a new BLAKE2b hash object. [clinic start generated code]*/ static PyObject * py_blake2b_new_impl(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) /*[clinic end generated code: output=32bfd8f043c6896f input=8fee2b7b11428b2d]*/ { … } /*[clinic input] @classmethod _blake2.blake2s.__new__ as py_blake2s_new data: 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 Return a new BLAKE2s hash object. [clinic start generated code]*/ static PyObject * py_blake2s_new_impl(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) /*[clinic end generated code: output=556181f73905c686 input=8165a11980eac7f3]*/ { … } /*[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]*/ { … } /*[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(Blake2Object *self, PyObject *data) /*[clinic end generated code: output=e6d1ac88471df308 input=ffc4aa6a6a225d31]*/ { … } /*[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]*/ { … } /*[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]*/ { … } static PyMethodDef py_blake2b_methods[] = …; static PyObject * py_blake2b_get_name(Blake2Object *self, void *closure) { … } static PyObject * py_blake2b_get_block_size(Blake2Object *self, void *closure) { … } static PyObject * py_blake2b_get_digest_size(Blake2Object *self, void *closure) { … } static PyGetSetDef py_blake2b_getsetters[] = …; static void py_blake2b_dealloc(Blake2Object *self) { … } static PyType_Slot blake2b_type_slots[] = …; static PyType_Slot blake2s_type_slots[] = …; static PyType_Spec blake2b_type_spec = …; static PyType_Spec blake2s_type_spec = …;