cpython/Modules/blake2module.c

/*
 * 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 =;