From ca420a9d9c23ec3d22ba00f5f446b21d3051b645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:00:57 +0200 Subject: [PATCH] rewrite SHA-3 with macros --- Modules/clinic/sha3module.c.h | 554 ++++++++++++++++++--- Modules/sha3module.c | 886 ++++++++++++++++++++-------------- 2 files changed, 996 insertions(+), 444 deletions(-) diff --git a/Modules/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h index d6d44bf4c514c0..f4f0e2262a0590 100644 --- a/Modules/clinic/sha3module.c.h +++ b/Modules/clinic/sha3module.c.h @@ -6,21 +6,21 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif -#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_long.h" // _PyLong_UInt32_Converter() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() -PyDoc_STRVAR(py_sha3_new__doc__, +PyDoc_STRVAR(SHA3_224_object_new__doc__, "sha3_224(data=b\'\', *, usedforsecurity=True, string=None)\n" "--\n" "\n" -"Return a new SHA3 hash object."); +"Return a new SHA-3-224 hash object."); static PyObject * -py_sha3_new_impl(PyTypeObject *type, PyObject *data_obj, int usedforsecurity, - PyObject *string); +SHA3_224_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string); static PyObject * -py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +SHA3_224_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -54,7 +54,7 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; - PyObject *data_obj = NULL; + PyObject *data = NULL; int usedforsecurity = 1; PyObject *string = NULL; @@ -67,7 +67,7 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto skip_optional_pos; } if (fastargs[0]) { - data_obj = fastargs[0]; + data = fastargs[0]; if (!--noptargs) { goto skip_optional_pos; } @@ -87,102 +87,522 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) } string = fastargs[2]; skip_optional_kwonly: - return_value = py_sha3_new_impl(type, data_obj, usedforsecurity, string); + return_value = SHA3_224_object_new_impl(type, data, usedforsecurity, string); exit: return return_value; } -PyDoc_STRVAR(_sha3_sha3_224_copy__doc__, -"copy($self, /)\n" +PyDoc_STRVAR(SHA3_256_object_new__doc__, +"sha3_256(data=b\'\', *, usedforsecurity=True, string=None)\n" "--\n" "\n" -"Return a copy of the hash object."); +"Return a new SHA-3-256 hash object."); + +static PyObject * +SHA3_256_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string); + +static PyObject * +SHA3_256_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "sha3_256", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *data = NULL; + int usedforsecurity = 1; + PyObject *string = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + data = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + usedforsecurity = PyObject_IsTrue(fastargs[1]); + if (usedforsecurity < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + string = fastargs[2]; +skip_optional_kwonly: + return_value = SHA3_256_object_new_impl(type, data, usedforsecurity, string); -#define _SHA3_SHA3_224_COPY_METHODDEF \ - {"copy", (PyCFunction)_sha3_sha3_224_copy, METH_NOARGS, _sha3_sha3_224_copy__doc__}, +exit: + return return_value; +} + +PyDoc_STRVAR(SHA3_384_object_new__doc__, +"sha3_384(data=b\'\', *, usedforsecurity=True, string=None)\n" +"--\n" +"\n" +"Return a new SHA-3-384 hash object."); static PyObject * -_sha3_sha3_224_copy_impl(SHA3object *self); +SHA3_384_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string); static PyObject * -_sha3_sha3_224_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) +SHA3_384_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - return _sha3_sha3_224_copy_impl((SHA3object *)self); + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "sha3_384", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *data = NULL; + int usedforsecurity = 1; + PyObject *string = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + data = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + usedforsecurity = PyObject_IsTrue(fastargs[1]); + if (usedforsecurity < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + string = fastargs[2]; +skip_optional_kwonly: + return_value = SHA3_384_object_new_impl(type, data, usedforsecurity, string); + +exit: + return return_value; } -PyDoc_STRVAR(_sha3_sha3_224_digest__doc__, -"digest($self, /)\n" +PyDoc_STRVAR(SHA3_512_object_new__doc__, +"sha3_512(data=b\'\', *, usedforsecurity=True, string=None)\n" "--\n" "\n" -"Return the digest value as a bytes object."); +"Return a new SHA-3-512 hash object."); + +static PyObject * +SHA3_512_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string); + +static PyObject * +SHA3_512_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "sha3_512", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *data = NULL; + int usedforsecurity = 1; + PyObject *string = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + data = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + usedforsecurity = PyObject_IsTrue(fastargs[1]); + if (usedforsecurity < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + string = fastargs[2]; +skip_optional_kwonly: + return_value = SHA3_512_object_new_impl(type, data, usedforsecurity, string); + +exit: + return return_value; +} -#define _SHA3_SHA3_224_DIGEST_METHODDEF \ - {"digest", (PyCFunction)_sha3_sha3_224_digest, METH_NOARGS, _sha3_sha3_224_digest__doc__}, +PyDoc_STRVAR(SHAKE128_object_new__doc__, +"shake128(data=b\'\', *, usedforsecurity=True, string=None)\n" +"--\n" +"\n" +"Return a new SHAKE-128 hash object."); static PyObject * -_sha3_sha3_224_digest_impl(SHA3object *self); +SHAKE128_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string); static PyObject * -_sha3_sha3_224_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) +SHAKE128_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - return _sha3_sha3_224_digest_impl((SHA3object *)self); + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "shake128", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *data = NULL; + int usedforsecurity = 1; + PyObject *string = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + data = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + usedforsecurity = PyObject_IsTrue(fastargs[1]); + if (usedforsecurity < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + string = fastargs[2]; +skip_optional_kwonly: + return_value = SHAKE128_object_new_impl(type, data, usedforsecurity, string); + +exit: + return return_value; } -PyDoc_STRVAR(_sha3_sha3_224_hexdigest__doc__, -"hexdigest($self, /)\n" +PyDoc_STRVAR(SHAKE256_object_new__doc__, +"shake256(data=b\'\', *, usedforsecurity=True, string=None)\n" "--\n" "\n" -"Return the digest value as a string of hexadecimal digits."); +"Return a new SHAKE-256 hash object."); -#define _SHA3_SHA3_224_HEXDIGEST_METHODDEF \ - {"hexdigest", (PyCFunction)_sha3_sha3_224_hexdigest, METH_NOARGS, _sha3_sha3_224_hexdigest__doc__}, +static PyObject * +SHAKE256_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string); static PyObject * -_sha3_sha3_224_hexdigest_impl(SHA3object *self); +SHAKE256_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(data), &_Py_ID(usedforsecurity), &_Py_ID(string), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"data", "usedforsecurity", "string", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "shake256", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *data = NULL; + int usedforsecurity = 1; + PyObject *string = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + data = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + usedforsecurity = PyObject_IsTrue(fastargs[1]); + if (usedforsecurity < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + string = fastargs[2]; +skip_optional_kwonly: + return_value = SHAKE256_object_new_impl(type, data, usedforsecurity, string); + +exit: + return return_value; +} + +PyDoc_STRVAR(_sha3_agile_copy__doc__, +"copy($self, /)\n" +"--\n" +"\n" +"Return a copy of the hash object."); + +#define _SHA3_AGILE_COPY_METHODDEF \ + {"copy", (PyCFunction)_sha3_agile_copy, METH_NOARGS, _sha3_agile_copy__doc__}, + +static PyObject * +_sha3_agile_copy_impl(SHA3object *self); static PyObject * -_sha3_sha3_224_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) +_sha3_agile_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _sha3_sha3_224_hexdigest_impl((SHA3object *)self); + return _sha3_agile_copy_impl((SHA3object *)self); } -PyDoc_STRVAR(_sha3_sha3_224_update__doc__, +PyDoc_STRVAR(_sha3_agile_update__doc__, "update($self, data, /)\n" "--\n" "\n" "Update this hash object\'s state with the provided bytes-like object."); -#define _SHA3_SHA3_224_UPDATE_METHODDEF \ - {"update", (PyCFunction)_sha3_sha3_224_update, METH_O, _sha3_sha3_224_update__doc__}, +#define _SHA3_AGILE_UPDATE_METHODDEF \ + {"update", (PyCFunction)_sha3_agile_update, METH_O, _sha3_agile_update__doc__}, static PyObject * -_sha3_sha3_224_update_impl(SHA3object *self, PyObject *data); +_sha3_agile_update_impl(SHA3object *self, PyObject *data); static PyObject * -_sha3_sha3_224_update(PyObject *self, PyObject *data) +_sha3_agile_update(PyObject *self, PyObject *data) { PyObject *return_value = NULL; - return_value = _sha3_sha3_224_update_impl((SHA3object *)self, data); + return_value = _sha3_agile_update_impl((SHA3object *)self, data); return return_value; } -PyDoc_STRVAR(_sha3_shake_128_digest__doc__, +PyDoc_STRVAR(_sha3_agile_sha3_digest__doc__, +"digest($self, /)\n" +"--\n" +"\n" +"Return the digest value as a bytes object."); + +#define _SHA3_AGILE_SHA3_DIGEST_METHODDEF \ + {"digest", (PyCFunction)_sha3_agile_sha3_digest, METH_NOARGS, _sha3_agile_sha3_digest__doc__}, + +static PyObject * +_sha3_agile_sha3_digest_impl(SHA3object *self); + +static PyObject * +_sha3_agile_sha3_digest(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _sha3_agile_sha3_digest_impl((SHA3object *)self); +} + +PyDoc_STRVAR(_sha3_agile_sha3_hexdigest__doc__, +"hexdigest($self, /)\n" +"--\n" +"\n" +"Return the digest value as a string of hexadecimal digits."); + +#define _SHA3_AGILE_SHA3_HEXDIGEST_METHODDEF \ + {"hexdigest", (PyCFunction)_sha3_agile_sha3_hexdigest, METH_NOARGS, _sha3_agile_sha3_hexdigest__doc__}, + +static PyObject * +_sha3_agile_sha3_hexdigest_impl(SHA3object *self); + +static PyObject * +_sha3_agile_sha3_hexdigest(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _sha3_agile_sha3_hexdigest_impl((SHA3object *)self); +} + +PyDoc_STRVAR(_sha3_agile_shake_digest__doc__, "digest($self, /, length)\n" "--\n" "\n" "Return the digest value as a bytes object."); -#define _SHA3_SHAKE_128_DIGEST_METHODDEF \ - {"digest", _PyCFunction_CAST(_sha3_shake_128_digest), METH_FASTCALL|METH_KEYWORDS, _sha3_shake_128_digest__doc__}, +#define _SHA3_AGILE_SHAKE_DIGEST_METHODDEF \ + {"digest", _PyCFunction_CAST(_sha3_agile_shake_digest), METH_FASTCALL|METH_KEYWORDS, _sha3_agile_shake_digest__doc__}, static PyObject * -_sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length); +_sha3_agile_shake_digest_impl(SHA3object *self, uint32_t length); static PyObject * -_sha3_shake_128_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_sha3_agile_shake_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -213,45 +633,36 @@ _sha3_shake_128_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, }; #undef KWTUPLE PyObject *argsbuf[1]; - Py_ssize_t length; + uint32_t length; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - { - Py_ssize_t ival = -1; - PyObject *iobj = _PyNumber_Index(args[0]); - if (iobj != NULL) { - ival = PyLong_AsSsize_t(iobj); - Py_DECREF(iobj); - } - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - length = ival; + if (!_PyLong_UInt32_Converter(args[0], &length)) { + goto exit; } - return_value = _sha3_shake_128_digest_impl((SHA3object *)self, length); + return_value = _sha3_agile_shake_digest_impl((SHA3object *)self, length); exit: return return_value; } -PyDoc_STRVAR(_sha3_shake_128_hexdigest__doc__, +PyDoc_STRVAR(_sha3_agile_shake_hexdigest__doc__, "hexdigest($self, /, length)\n" "--\n" "\n" "Return the digest value as a string of hexadecimal digits."); -#define _SHA3_SHAKE_128_HEXDIGEST_METHODDEF \ - {"hexdigest", _PyCFunction_CAST(_sha3_shake_128_hexdigest), METH_FASTCALL|METH_KEYWORDS, _sha3_shake_128_hexdigest__doc__}, +#define _SHA3_AGILE_SHAKE_HEXDIGEST_METHODDEF \ + {"hexdigest", _PyCFunction_CAST(_sha3_agile_shake_hexdigest), METH_FASTCALL|METH_KEYWORDS, _sha3_agile_shake_hexdigest__doc__}, static PyObject * -_sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length); +_sha3_agile_shake_hexdigest_impl(SHA3object *self, uint32_t length); static PyObject * -_sha3_shake_128_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_sha3_agile_shake_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -282,28 +693,19 @@ _sha3_shake_128_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t narg }; #undef KWTUPLE PyObject *argsbuf[1]; - Py_ssize_t length; + uint32_t length; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - { - Py_ssize_t ival = -1; - PyObject *iobj = _PyNumber_Index(args[0]); - if (iobj != NULL) { - ival = PyLong_AsSsize_t(iobj); - Py_DECREF(iobj); - } - if (ival == -1 && PyErr_Occurred()) { - goto exit; - } - length = ival; + if (!_PyLong_UInt32_Converter(args[0], &length)) { + goto exit; } - return_value = _sha3_shake_128_hexdigest_impl((SHA3object *)self, length); + return_value = _sha3_agile_shake_hexdigest_impl((SHA3object *)self, length); exit: return return_value; } -/*[clinic end generated code: output=c17e3ec670afe253 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=690bb1a3b6455262 input=a9049054013a1b77]*/ diff --git a/Modules/sha3module.c b/Modules/sha3module.c index 68b239352769a1..d772925a0b60a8 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -9,6 +9,7 @@ * Greg Stein (gstein@lyra.org) * Trevor Perrin (trevp@trevp.net) * Gregory P. Smith (greg@krypto.org) + * Bénédikt Tran (10796600+picnixz@users.noreply.github.com) * * Copyright (C) 2012-2022 Christian Heimes (christian@python.org) * Licensed to PSF under a Contributor Agreement. @@ -24,6 +25,8 @@ #include "pycore_typeobject.h" // _PyType_GetModuleState() #include "hashlib.h" +#include "_hacl/Hacl_Hash_SHA3.h" + /* * Assert that 'LEN' can be safely casted to uint32_t. * @@ -35,72 +38,147 @@ #define CHECK_HACL_UINT32_T_LENGTH(LEN) #endif -#define SHA3_MAX_DIGESTSIZE 64 /* 64 Bytes (512 Bits) for 224 to 512 */ +/* + * Call a macro with all SHA-3 known digest sizes. + * + * The macro MACRO takes as input a SHA-3 digest size + * and produces *syntactally correct* code. + */ +#define SHA3N_EXPAND_MACRO(MACRO) \ + MACRO(224); \ + MACRO(256); \ + MACRO(384); \ + MACRO(512); + +/* + * Call a macro with all SHAKE known block sizes. + * + * The macro MACRO takes as input a SHAKE block size + * and produces *syntactally correct* code. + */ +#define SHAKE_EXPAND_MACRO(MACRO) \ + MACRO(128); \ + MACRO(256); + +// SHA-3 and SHAKE are implemented similarly but their interface +// may differ. To distinguish the underlying interface, we use +// the following naming convention: +// +// * methods for SHA-3 or SHAKE _sha3_agile_[_getter] +// * methods for SHA-3 _sha3_agile_sha3_[_getter] +// * methods for SHAKE _sha3_agile_shake_[_getter] +// +// * methods for SHA-3-N _sha3_sha3__[_getter] +// * methods for SHAKE-N _sha3_shake_[_getter] +// +// Local helpers follow the same convention as above but do not +// start with an underscore in their names. +// +// Functions and variables associated with the type itself (slots, specs, +// docs, etc) are named after "SHA3_object_" if they are independent +// of the object type or "__". + +/* The state attribute name holding the corresponding (PyTypeObject *). */ +#define SHA3N_T(N) sha3_ ## N ## _type +#define SHAKE_T(N) shake ## N ## _type + +/* Name of a local (static) helper acting on Python objects. */ +#define SHA3_HELPER(NAME) sha3_agile_ ## NAME +#define SHA3_SHA3_HELPER(NAME) sha3_agile_sha3_ ## NAME +#define SHA3_SHAKE_HELPER(NAME) sha3_agile_shake_ ## NAME + +/* Name of a SHA-3 object getter. */ +#define SHA3N_SHA3_GETTER(N, NAME) _sha3_sha3_ ## N ## _ ## NAME ## _getter +#define SHA3N_SHAKE_GETTER(N, NAME) _sha3_shake ## N ## _ ## NAME ## _getter + +#define SHA3_GETTER(NAME) _sha3_agile_ ## NAME ## _getter +#define SHA3_SHA3_GETTER(NAME) _sha3_agile_sha3_ ## NAME ## _getter +#define SHA3_SHAKE_GETTER(NAME) _sha3_agile_shake_ ## NAME ## _getter + +/* The function implementing a SHA-3 type slot. */ +#define SHA3_TYPE_SLOT(NAME) SHA3object_ ## NAME +#define SHA3_SHA3_TYPE_SLOT(NAME) SHA3N_object_ ## NAME +#define SHA3_SHAKE_TYPE_SLOT(NAME) SHAKE_object_ ## NAME +/* The name of variables holding a SHA-3 type slot. */ +#define SHA3N_SHA3_TYPE_SLOT(N, NAME) SHA3_ ## N ## _object_ ## NAME +#define SHA3N_SHAKE_TYPE_SLOT(N, NAME) SHAKE ## N ## _object_ ## NAME +/* The name of the array holding the different SHA-3 type slots. */ +#define SHA3N_SHA3_TYPE_SLOT_ARRAY(N) SHA3_ ## N ## _type_slots +#define SHA3N_SHAKE_TYPE_SLOT_ARRAY(N) SHAKE ## N ## _type_slots +/* The name of the global variable holding the SHA-3 type spec. */ +#define SHA3N_SHA3_TYPE_SPEC(N) SHA3_ ## N ## _type_spec +#define SHA3N_SHAKE_TYPE_SPEC(N) SHAKE ## N ## _type_spec + +/* The SHA-3 message digest sizes, in bytes. */ +#define SHA3_224_DIGEST_SIZE 28 +#define SHA3_256_DIGEST_SIZE 32 +#define SHA3_384_DIGEST_SIZE 48 +#define SHA3_512_DIGEST_SIZE 64 + +#define SHA3_MAX_DIGEST_SIZE 64 +#define SHA3N_DIGEST_SIZE(N) SHA3_ ## N ## _ ## DIGEST_SIZE + +// --- SHA-3 module state ----------------------------------------------------- typedef struct { - PyTypeObject *sha3_224_type; - PyTypeObject *sha3_256_type; - PyTypeObject *sha3_384_type; - PyTypeObject *sha3_512_type; - PyTypeObject *shake_128_type; - PyTypeObject *shake_256_type; -} SHA3State; - -static inline SHA3State* -sha3_get_state(PyObject *module) +#define SHA3N_TYPE_DECL(N) PyTypeObject *SHA3N_T(N); + SHA3N_EXPAND_MACRO(SHA3N_TYPE_DECL) +#undef SHAKE_TYPE_DECL + +#define SHAKE_TYPE_DECL(N) PyTypeObject *SHAKE_T(N); + SHAKE_EXPAND_MACRO(SHAKE_TYPE_DECL) +#undef SHA3N_TYPE_DECL +} sha3module_state; + +static inline sha3module_state * +get_sha3module_state(PyObject *module) { void *state = PyModule_GetState(module); assert(state != NULL); - return (SHA3State *)state; + return (sha3module_state *)state; } -/*[clinic input] -module _sha3 -class _sha3.sha3_224 "SHA3object *" "&SHA3_224typ" -class _sha3.sha3_256 "SHA3object *" "&SHA3_256typ" -class _sha3.sha3_384 "SHA3object *" "&SHA3_384typ" -class _sha3.sha3_512 "SHA3object *" "&SHA3_512typ" -class _sha3.shake_128 "SHA3object *" "&SHAKE128type" -class _sha3.shake_256 "SHA3object *" "&SHAKE256type" -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b8a53680f370285a]*/ - -/* The structure for storing SHA3 info */ - -#include "_hacl/Hacl_Hash_SHA3.h" +// --- SHA-3 object ----------------------------------------------------------- typedef struct { HASHLIB_OBJECT_HEAD - Hacl_Hash_SHA3_state_t *hash_state; + Hacl_Hash_SHA3_state_t *state; } SHA3object; -#define _SHA3object_CAST(op) ((SHA3object *)(op)) +#define SHA3object_CAST(op) ((SHA3object *)(op)) -#include "clinic/sha3module.c.h" +// --- SHA-3 module clinic configuration -------------------------------------- +// +// The underlying type object for the different classes is explicitly 'void *' +// as we do not need it for now. If this is needed, a `clinic_state()` macro +// should be created. -static SHA3object * -newSHA3object(PyTypeObject *type) -{ - SHA3object *newobj = PyObject_GC_New(SHA3object, type); - if (newobj == NULL) { - return NULL; - } - HASHLIB_INIT_MUTEX(newobj); +/*[clinic input] +module _sha3 - PyObject_GC_Track(newobj); - return newobj; -} +class _sha3.sha3_224 "SHA3object *" "void *" +class _sha3.sha3_256 "SHA3object *" "void *" +class _sha3.sha3_384 "SHA3object *" "void *" +class _sha3.sha3_512 "SHA3object *" "void *" + +class _sha3.shake128 "SHA3object *" "void *" +class _sha3.shake256 "SHA3object *" "void *" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c4a65a163a43876c]*/ + +#include "clinic/sha3module.c.h" static void -sha3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *buf, Py_ssize_t len) +hacl_sha3_state_update(Hacl_Hash_SHA3_state_t *state, + uint8_t *buf, Py_ssize_t len) { - /* - * 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 SHA-3 (2^64 - 1). - */ + /* + * 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 SHA-3 (2^64 - 1). + */ #if PY_SSIZE_T_MAX > UINT32_MAX - while (len > UINT32_MAX) { + while (len > (Py_ssize_t)UINT32_MAX) { (void)Hacl_Hash_SHA3_update(state, buf, UINT32_MAX); len -= UINT32_MAX; buf += UINT32_MAX; @@ -110,115 +188,177 @@ sha3_update(Hacl_Hash_SHA3_state_t *state, uint8_t *buf, Py_ssize_t len) (void)Hacl_Hash_SHA3_update(state, buf, (uint32_t)len); } -/*[clinic input] -@classmethod -_sha3.sha3_224.__new__ as py_sha3_new - - data as data_obj: object(c_default="NULL") = b'' - * - usedforsecurity: bool = True - string: object(c_default="NULL") = None - -Return a new SHA3 hash object. -[clinic start generated code]*/ +static SHA3object * +SHA3_HELPER(gc_new)(PyTypeObject *type) +{ + SHA3object *self = PyObject_GC_New(SHA3object, type); + if (self == NULL) { + return NULL; + } + HASHLIB_INIT_MUTEX(self); + PyObject_GC_Track(self); + return self; +} static PyObject * -py_sha3_new_impl(PyTypeObject *type, PyObject *data_obj, int usedforsecurity, - PyObject *string) -/*[clinic end generated code: output=dcec1eca20395f2a input=c106e0b4e2d67d58]*/ +SHA3_HELPER(new)(PyTypeObject *type, + PyObject *data, int usedforsecurity, PyObject *string, + Spec_Hash_Definitions_hash_alg algorithm) { - PyObject *data; - if (_Py_hashlib_data_argument(&data, data_obj, string) < 0) { + PyObject *msg = NULL; + if (_Py_hashlib_data_argument(&msg, data, string) < 0) { return NULL; } Py_buffer buf = {NULL, NULL}; - SHA3State *state = _PyType_GetModuleState(type); - SHA3object *self = newSHA3object(type); - if (self == NULL) { - goto error; + if (msg) { + GET_BUFFER_VIEW_OR_ERROUT(msg, &buf); } - assert(state != NULL); - - if (type == state->sha3_224_type) { - self->hash_state = Hacl_Hash_SHA3_malloc(Spec_Hash_Definitions_SHA3_224); - } - else if (type == state->sha3_256_type) { - self->hash_state = Hacl_Hash_SHA3_malloc(Spec_Hash_Definitions_SHA3_256); - } - else if (type == state->sha3_384_type) { - self->hash_state = Hacl_Hash_SHA3_malloc(Spec_Hash_Definitions_SHA3_384); - } - else if (type == state->sha3_512_type) { - self->hash_state = Hacl_Hash_SHA3_malloc(Spec_Hash_Definitions_SHA3_512); - } - else if (type == state->shake_128_type) { - self->hash_state = Hacl_Hash_SHA3_malloc(Spec_Hash_Definitions_Shake128); - } - else if (type == state->shake_256_type) { - self->hash_state = Hacl_Hash_SHA3_malloc(Spec_Hash_Definitions_Shake256); - } - else { - PyErr_BadInternalCall(); + SHA3object *self = SHA3_HELPER(gc_new)(type); + if (self == NULL) { goto error; } - - if (self->hash_state == NULL) { + self->state = Hacl_Hash_SHA3_malloc(algorithm); + if (self->state == NULL) { (void)PyErr_NoMemory(); goto error; } - if (data) { - GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error); - /* Do not use self->mutex here as this is the constructor - * where it is not yet possible to have concurrent access. */ - HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED( - buf.len, - sha3_update(self->hash_state, buf.buf, buf.len) - ); + if (msg) { + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* Do not use self->mutex here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + hacl_sha3_state_update(self->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } + else { + hacl_sha3_state_update(self->state, buf.buf, buf.len); + } } PyBuffer_Release(&buf); - return (PyObject *)self; error: - if (self) { - Py_DECREF(self); - } - if (data && buf.obj) { + Py_XDECREF(self); + if (msg && buf.obj) { PyBuffer_Release(&buf); } return NULL; } +#define SHA3N_OBJECT_NEW_IMPL_BODY(S, TYPE, DATA, USEDFORSECURITY, STRING) \ + { \ + return SHA3_HELPER(new)(TYPE, DATA, USEDFORSECURITY, STRING, \ + Spec_Hash_Definitions_ ## S); \ + } + +/*[clinic input] +@classmethod +_sha3.sha3_224.__new__ as SHA3_224_object_new + + data: object(c_default="NULL") = b'' + * + usedforsecurity: bool = True + string: object(c_default="NULL") = None + +Return a new SHA-3-224 hash object. +[clinic start generated code]*/ + +static PyObject * +SHA3_224_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=453146861e0bbe87 input=be111b1025d11e76]*/ +SHA3N_OBJECT_NEW_IMPL_BODY(SHA3_224, type, data, usedforsecurity, string) + +/*[clinic input] +@classmethod +_sha3.sha3_256.__new__ as SHA3_256_object_new = _sha3.sha3_224.__new__ +Return a new SHA-3-256 hash object. +[clinic start generated code]*/ + +static PyObject * +SHA3_256_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=6a739ccabbaa895c input=8e5ba0b0f72100bf]*/ +SHA3N_OBJECT_NEW_IMPL_BODY(SHA3_256, type, data, usedforsecurity, string) + +/*[clinic input] +@classmethod +_sha3.sha3_384.__new__ as SHA3_384_object_new = _sha3.sha3_224.__new__ +Return a new SHA-3-384 hash object. +[clinic start generated code]*/ + +static PyObject * +SHA3_384_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=61b3717e66f48a79 input=2f32d672d8a7f1fa]*/ +SHA3N_OBJECT_NEW_IMPL_BODY(SHA3_384, type, data, usedforsecurity, string) + +/*[clinic input] +@classmethod +_sha3.sha3_512.__new__ as SHA3_512_object_new = _sha3.sha3_224.__new__ +Return a new SHA-3-512 hash object. +[clinic start generated code]*/ + +static PyObject * +SHA3_512_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=8f7717c5eae41a16 input=0e8c3dc698b54421]*/ +SHA3N_OBJECT_NEW_IMPL_BODY(SHA3_512, type, data, usedforsecurity, string) + +/*[clinic input] +@classmethod +_sha3.shake128.__new__ as SHAKE128_object_new = _sha3.sha3_224.__new__ +Return a new SHAKE-128 hash object. +[clinic start generated code]*/ + +static PyObject * +SHAKE128_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=6dbd7b1df6e73e73 input=12dfc70bf291a2ed]*/ +SHA3N_OBJECT_NEW_IMPL_BODY(Shake128, type, data, usedforsecurity, string) + +/*[clinic input] +@classmethod +_sha3.shake256.__new__ as SHAKE256_object_new = _sha3.shake128.__new__ +Return a new SHAKE-256 hash object. +[clinic start generated code]*/ + +static PyObject * +SHAKE256_object_new_impl(PyTypeObject *type, PyObject *data, + int usedforsecurity, PyObject *string) +/*[clinic end generated code: output=bed954e644635da0 input=c5285e663ab1c1d5]*/ +SHA3N_OBJECT_NEW_IMPL_BODY(Shake256, type, data, usedforsecurity, string) +#undef SHA3N_OBJECT_NEW_IMPL_BODY /* Internal methods for a hash object */ static int -SHA3_clear(PyObject *op) +SHA3_TYPE_SLOT(clear)(PyObject *op) { - SHA3object *self = _SHA3object_CAST(op); - if (self->hash_state != NULL) { - Hacl_Hash_SHA3_free(self->hash_state); - self->hash_state = NULL; + SHA3object *self = SHA3object_CAST(op); + if (self->state != NULL) { + Hacl_Hash_SHA3_free(self->state); + self->state = NULL; } return 0; } static void -SHA3_dealloc(PyObject *self) +SHA3_TYPE_SLOT(dealloc)(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); - (void)SHA3_clear(self); + (void)SHA3object_clear(self); tp->tp_free(self); Py_DECREF(tp); } static int -SHA3_traverse(PyObject *self, visitproc visit, void *arg) +SHA3_TYPE_SLOT(traverse)(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); return 0; @@ -226,75 +366,32 @@ SHA3_traverse(PyObject *self, visitproc visit, void *arg) /* External methods for a hash object */ - /*[clinic input] -_sha3.sha3_224.copy +_sha3.sha3_224.copy as _sha3_agile_copy Return a copy of the hash object. [clinic start generated code]*/ static PyObject * -_sha3_sha3_224_copy_impl(SHA3object *self) -/*[clinic end generated code: output=6c537411ecdcda4c input=93a44aaebea51ba8]*/ +_sha3_agile_copy_impl(SHA3object *self) +/*[clinic end generated code: output=c6247c0f9c646612 input=26603628b6677295]*/ { - SHA3object *newobj; - - if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) { + SHA3object *copy = SHA3_HELPER(gc_new)(Py_TYPE(self)); + if (copy == NULL) { return NULL; } HASHLIB_ACQUIRE_LOCK(self); - newobj->hash_state = Hacl_Hash_SHA3_copy(self->hash_state); + copy->state = Hacl_Hash_SHA3_copy(self->state); HASHLIB_RELEASE_LOCK(self); - if (newobj->hash_state == NULL) { - Py_DECREF(newobj); + if (copy->state == NULL) { + Py_DECREF(copy); return PyErr_NoMemory(); } - return (PyObject *)newobj; -} - - -/*[clinic input] -_sha3.sha3_224.digest - -Return the digest value as a bytes object. -[clinic start generated code]*/ - -static PyObject * -_sha3_sha3_224_digest_impl(SHA3object *self) -/*[clinic end generated code: output=fd531842e20b2d5b input=5b2a659536bbd248]*/ -{ - unsigned char digest[SHA3_MAX_DIGESTSIZE]; - // This function errors out if the algorithm is SHAKE. Here, we know this - // not to be the case, and therefore do not perform error checking. - HASHLIB_ACQUIRE_LOCK(self); - (void)Hacl_Hash_SHA3_digest(self->hash_state, digest); - HASHLIB_RELEASE_LOCK(self); - return PyBytes_FromStringAndSize((const char *)digest, - Hacl_Hash_SHA3_hash_len(self->hash_state)); + return (PyObject *)copy; } - /*[clinic input] -_sha3.sha3_224.hexdigest - -Return the digest value as a string of hexadecimal digits. -[clinic start generated code]*/ - -static PyObject * -_sha3_sha3_224_hexdigest_impl(SHA3object *self) -/*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/ -{ - unsigned char digest[SHA3_MAX_DIGESTSIZE]; - HASHLIB_ACQUIRE_LOCK(self); - (void)Hacl_Hash_SHA3_digest(self->hash_state, digest); - HASHLIB_RELEASE_LOCK(self); - return _Py_strhex((const char *)digest, - Hacl_Hash_SHA3_hash_len(self->hash_state)); -} - - -/*[clinic input] -_sha3.sha3_224.update +_sha3.sha3_224.update as _sha3_agile_update data: object / @@ -303,167 +400,175 @@ Update this hash object's state with the provided bytes-like object. [clinic start generated code]*/ static PyObject * -_sha3_sha3_224_update_impl(SHA3object *self, PyObject *data) -/*[clinic end generated code: output=390b7abf7c9795a5 input=a887f54dcc4ae227]*/ +_sha3_agile_update_impl(SHA3object *self, PyObject *data) +/*[clinic end generated code: output=7b2130fbe25c54db input=cfad7cd01a7bfd14]*/ { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROUT(data, &buf); HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED( self, buf.len, - sha3_update(self->hash_state, buf.buf, buf.len) + hacl_sha3_state_update(self->state, buf.buf, buf.len) ); PyBuffer_Release(&buf); Py_RETURN_NONE; } +static uint32_t +SHA3_SHA3_HELPER(compute_digest_locked)(SHA3object *self, uint8_t *buf) +{ + assert(!Hacl_Hash_SHA3_is_shake(self->state)); + HASHLIB_ACQUIRE_LOCK(self); + (void)Hacl_Hash_SHA3_digest(self->state, buf); + HASHLIB_RELEASE_LOCK(self); + return Hacl_Hash_SHA3_hash_len(self->state); +} -static PyMethodDef SHA3_methods[] = { - _SHA3_SHA3_224_COPY_METHODDEF - _SHA3_SHA3_224_DIGEST_METHODDEF - _SHA3_SHA3_224_HEXDIGEST_METHODDEF - _SHA3_SHA3_224_UPDATE_METHODDEF - {NULL, NULL} /* sentinel */ -}; +/*[clinic input] +_sha3.sha3_224.digest as _sha3_agile_sha3_digest +Return the digest value as a bytes object. +[clinic start generated code]*/ static PyObject * -SHA3_get_block_size(PyObject *op, void *Py_UNUSED(closure)) +_sha3_agile_sha3_digest_impl(SHA3object *self) +/*[clinic end generated code: output=17dea352d9229999 input=3eb6a9331ba803a6]*/ { - SHA3object *self = _SHA3object_CAST(op); - uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state); - return PyLong_FromLong(rate); + assert(!Hacl_Hash_SHA3_is_shake(self->state)); + uint8_t digest[SHA3_MAX_DIGEST_SIZE]; + uint32_t digestlen = SHA3_SHA3_HELPER(compute_digest_locked)(self, digest); + assert(digestlen <= SHA3_MAX_DIGEST_SIZE); + return PyBytes_FromStringAndSize((const char *)digest, digestlen); } +/*[clinic input] +_sha3.sha3_224.hexdigest as _sha3_agile_sha3_hexdigest + +Return the digest value as a string of hexadecimal digits. +[clinic start generated code]*/ static PyObject * -SHA3_get_name(PyObject *self, void *Py_UNUSED(closure)) +_sha3_agile_sha3_hexdigest_impl(SHA3object *self) +/*[clinic end generated code: output=39d34160ce921cf6 input=dbec3b195ff5d2cd]*/ { - PyTypeObject *type = Py_TYPE(self); - - SHA3State *state = _PyType_GetModuleState(type); - assert(state != NULL); + assert(!Hacl_Hash_SHA3_is_shake(self->state)); + uint8_t digest[SHA3_MAX_DIGEST_SIZE]; + uint32_t digestlen = SHA3_SHA3_HELPER(compute_digest_locked)(self, digest); + assert(digestlen <= SHA3_MAX_DIGEST_SIZE); + return _Py_strhex((const char *)digest, digestlen); +} - if (type == state->sha3_224_type) { - return PyUnicode_FromString("sha3_224"); - } else if (type == state->sha3_256_type) { - return PyUnicode_FromString("sha3_256"); - } else if (type == state->sha3_384_type) { - return PyUnicode_FromString("sha3_384"); - } else if (type == state->sha3_512_type) { - return PyUnicode_FromString("sha3_512"); - } else if (type == state->shake_128_type) { - return PyUnicode_FromString("shake_128"); - } else if (type == state->shake_256_type) { - return PyUnicode_FromString("shake_256"); - } else { - PyErr_BadInternalCall(); - return NULL; - } +static PyObject * +SHA3_GETTER(block_size)(PyObject *op, void *Py_UNUSED(closure)) +{ + SHA3object *self = SHA3object_CAST(op); + return PyLong_FromLong(Hacl_Hash_SHA3_block_len(self->state)); } +#define SHA3N_NAME_GETTER_DECL(N) \ + static inline PyObject * \ + SHA3N_SHA3_GETTER(N, name) (PyObject *Py_UNUSED(op), \ + void *Py_UNUSED(closure)) \ + { \ + assert(strlen("sha3_" # N) == 8); \ + return PyUnicode_FromStringAndSize("sha3_" # N, 8); \ + } +SHA3N_EXPAND_MACRO(SHA3N_NAME_GETTER_DECL) +#undef SHA3N_NAME_GETTER_DECL static PyObject * -SHA3_get_digest_size(PyObject *op, void *Py_UNUSED(closure)) +SHA3_SHA3_GETTER(digest_size)(PyObject *op, void *Py_UNUSED(closure)) { - // Preserving previous behavior: variable-length algorithms return 0 - SHA3object *self = _SHA3object_CAST(op); - if (Hacl_Hash_SHA3_is_shake(self->hash_state)) - return PyLong_FromLong(0); - else - return PyLong_FromLong(Hacl_Hash_SHA3_hash_len(self->hash_state)); + SHA3object *self = SHA3object_CAST(op); + assert(!Hacl_Hash_SHA3_is_shake(self->state)); + return PyLong_FromLong(Hacl_Hash_SHA3_hash_len(self->state)); } - static PyObject * -SHA3_get_capacity_bits(PyObject *op, void *Py_UNUSED(closure)) +SHA3_GETTER(_capacity_bits)(PyObject *op, void *Py_UNUSED(closure)) { - SHA3object *self = _SHA3object_CAST(op); - uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8; + SHA3object *self = SHA3object_CAST(op); + uint32_t rate = Hacl_Hash_SHA3_block_len(self->state) * 8; assert(rate <= 1600); - int capacity = 1600 - rate; - return PyLong_FromLong(capacity); + return PyLong_FromLong(1600 - rate); } - static PyObject * -SHA3_get_rate_bits(PyObject *op, void *Py_UNUSED(closure)) +SHA3_GETTER(_rate_bits)(PyObject *op, void *Py_UNUSED(closure)) { - SHA3object *self = _SHA3object_CAST(op); - uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8; + SHA3object *self = SHA3object_CAST(op); + uint32_t rate = Hacl_Hash_SHA3_block_len(self->state) * 8; return PyLong_FromLong(rate); } static PyObject * -SHA3_get_suffix(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) +SHA3_SHA3_GETTER(_suffix)(PyObject *op, void *Py_UNUSED(closure)) { +#ifndef NDEBUG + SHA3object *self = SHA3object_CAST(op); + assert(!Hacl_Hash_SHA3_is_shake(self->state)); +#endif unsigned char suffix[2] = {0x06, 0}; return PyBytes_FromStringAndSize((const char *)suffix, 1); } -static PyGetSetDef SHA3_getseters[] = { - {"block_size", SHA3_get_block_size, NULL, NULL, NULL}, - {"name", SHA3_get_name, NULL, NULL, NULL}, - {"digest_size", SHA3_get_digest_size, NULL, NULL, NULL}, - {"_capacity_bits", SHA3_get_capacity_bits, NULL, NULL, NULL}, - {"_rate_bits", SHA3_get_rate_bits, NULL, NULL, NULL}, - {"_suffix", SHA3_get_suffix, NULL, NULL, NULL}, - {NULL} /* Sentinel */ +static PyMethodDef SHA3_SHA3_TYPE_SLOT(methods)[] = { + _SHA3_AGILE_COPY_METHODDEF + _SHA3_AGILE_UPDATE_METHODDEF + _SHA3_AGILE_SHA3_DIGEST_METHODDEF + _SHA3_AGILE_SHA3_HEXDIGEST_METHODDEF + {NULL, NULL} /* sentinel */ }; -#define SHA3_TYPE_SLOTS(type_slots_obj, type_doc, type_methods, type_getseters) \ - static PyType_Slot type_slots_obj[] = { \ - {Py_tp_clear, SHA3_clear}, \ - {Py_tp_dealloc, SHA3_dealloc}, \ - {Py_tp_traverse, SHA3_traverse}, \ - {Py_tp_doc, (char*)type_doc}, \ - {Py_tp_methods, type_methods}, \ - {Py_tp_getset, type_getseters}, \ - {Py_tp_new, py_sha3_new}, \ - {0, NULL} \ - } +#define SHA3N_TYPE_OBJECT_GETSETS_DEF_DECL(N) \ + static PyGetSetDef SHA3N_SHA3_TYPE_SLOT(N, getsets)[] = { \ + {"name", SHA3N_SHA3_GETTER(N, name), NULL, NULL, NULL}, \ + {"block_size", SHA3_GETTER(block_size), NULL, NULL, NULL}, \ + {"digest_size", SHA3_SHA3_GETTER(digest_size), NULL, NULL, NULL}, \ + {"_capacity_bits", SHA3_GETTER(_capacity_bits), NULL, NULL, NULL}, \ + {"_rate_bits", SHA3_GETTER(_rate_bits), NULL, NULL, NULL}, \ + {"_suffix", SHA3_SHA3_GETTER(_suffix), NULL, NULL, NULL}, \ + {NULL} /* sentinel */ \ + }; +SHA3N_EXPAND_MACRO(SHA3N_TYPE_OBJECT_GETSETS_DEF_DECL) +#undef SHA3N_TYPE_OBJECT_GETSETS_DEF_DECL + +#define SHA3N_TYPE_OBJECT_SLOT_DOC(N) \ + PyDoc_STR( \ + "sha3_" #N "([data], *, usedforsecurity=True) -> SHA3 object\n" \ + "\n" \ + "Return a new SHA3 hash object with a digest length of " \ + Py_STRINGIFY(SHA3N_DIGEST_SIZE(N)) " bytes." \ + ) +#define SHA3N_TYPE_OBJECT_SLOTS_DECL(N) \ + static PyType_Slot SHA3N_SHA3_TYPE_SLOT_ARRAY(N)[] = { \ + {Py_tp_clear, SHA3_TYPE_SLOT(clear)}, \ + {Py_tp_dealloc, SHA3_TYPE_SLOT(dealloc)}, \ + {Py_tp_traverse, SHA3_TYPE_SLOT(traverse)}, \ + {Py_tp_doc, SHA3N_TYPE_OBJECT_SLOT_DOC(N)}, \ + {Py_tp_methods, SHA3_SHA3_TYPE_SLOT(methods)}, \ + {Py_tp_getset, SHA3N_SHA3_TYPE_SLOT(N, getsets)}, \ + {Py_tp_new, SHA3N_SHA3_TYPE_SLOT(N, new)}, \ + {0, NULL} \ + }; +SHA3N_EXPAND_MACRO(SHA3N_TYPE_OBJECT_SLOTS_DECL) +#undef SHA3N_TYPE_OBJECT_SLOTS_DECL +#undef SHA3N_TYPE_OBJECT_SLOT_DOC // Using _PyType_GetModuleState() on these types is safe since they -// cannot be subclassed: it does not have the Py_TPFLAGS_BASETYPE flag. -#define SHA3_TYPE_SPEC(type_spec_obj, type_name, type_slots) \ - static PyType_Spec type_spec_obj = { \ - .name = "_sha3." type_name, \ - .basicsize = sizeof(SHA3object), \ - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE \ - | Py_TPFLAGS_HAVE_GC, \ - .slots = type_slots \ - } - -PyDoc_STRVAR(sha3_224__doc__, -"sha3_224([data], *, usedforsecurity=True) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 28 bytes."); - -PyDoc_STRVAR(sha3_256__doc__, -"sha3_256([data], *, usedforsecurity=True) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 32 bytes."); - -PyDoc_STRVAR(sha3_384__doc__, -"sha3_384([data], *, usedforsecurity=True) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 48 bytes."); - -PyDoc_STRVAR(sha3_512__doc__, -"sha3_512([data], *, usedforsecurity=True) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 64 bytes."); - -SHA3_TYPE_SLOTS(sha3_224_slots, sha3_224__doc__, SHA3_methods, SHA3_getseters); -SHA3_TYPE_SPEC(sha3_224_spec, "sha3_224", sha3_224_slots); - -SHA3_TYPE_SLOTS(sha3_256_slots, sha3_256__doc__, SHA3_methods, SHA3_getseters); -SHA3_TYPE_SPEC(sha3_256_spec, "sha3_256", sha3_256_slots); - -SHA3_TYPE_SLOTS(sha3_384_slots, sha3_384__doc__, SHA3_methods, SHA3_getseters); -SHA3_TYPE_SPEC(sha3_384_spec, "sha3_384", sha3_384_slots); - -SHA3_TYPE_SLOTS(sha3_512_slots, sha3_512__doc__, SHA3_methods, SHA3_getseters); -SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots); +// cannot be subclassed: they don't have the Py_TPFLAGS_BASETYPE flag. +#define SHA3N_TYPE_OBJECT_TYPE_SPEC_DECL(N) \ + static PyType_Spec SHA3N_SHA3_TYPE_SPEC(N) = { \ + .name = "_sha3.sha3_" # N, \ + .basicsize = sizeof(SHA3object), \ + .flags = ( \ + Py_TPFLAGS_DEFAULT \ + | Py_TPFLAGS_IMMUTABLETYPE \ + | Py_TPFLAGS_HAVE_GC \ + ), \ + .slots = SHA3N_SHA3_TYPE_SLOT_ARRAY(N) \ + }; +SHA3N_EXPAND_MACRO(SHA3N_TYPE_OBJECT_TYPE_SPEC_DECL) +#undef SHA3N_TYPE_OBJECT_SLOTS_DECL static int sha3_shake_check_digest_length(Py_ssize_t length) @@ -484,18 +589,17 @@ sha3_shake_check_digest_length(Py_ssize_t length) return 0; } - /*[clinic input] -_sha3.shake_128.digest +_sha3.shake128.digest as _sha3_agile_shake_digest - length: Py_ssize_t + length: uint32 Return the digest value as a bytes object. [clinic start generated code]*/ static PyObject * -_sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length) -/*[clinic end generated code: output=6c53fb71a6cff0a0 input=be03ade4b31dd54c]*/ +_sha3_agile_shake_digest_impl(SHA3object *self, uint32_t length) +/*[clinic end generated code: output=795e48b14dc14d6f input=99119839b7a66f75]*/ { if (sha3_shake_check_digest_length(length) < 0) { return NULL; @@ -514,23 +618,22 @@ _sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length) PyObject *digest = PyBytes_FromStringAndSize(NULL, length); uint8_t *buffer = (uint8_t *)PyBytes_AS_STRING(digest); HASHLIB_ACQUIRE_LOCK(self); - (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length); + (void)Hacl_Hash_SHA3_squeeze(self->state, buffer, (uint32_t)length); HASHLIB_RELEASE_LOCK(self); return digest; } - /*[clinic input] -_sha3.shake_128.hexdigest +_sha3.shake128.hexdigest as _sha3_agile_shake_hexdigest - length: Py_ssize_t + length: uint32 Return the digest value as a string of hexadecimal digits. [clinic start generated code]*/ static PyObject * -_sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length) -/*[clinic end generated code: output=a27412d404f64512 input=0d84d05d7a8ccd37]*/ +_sha3_agile_shake_hexdigest_impl(SHA3object *self, uint32_t length) +/*[clinic end generated code: output=1be85b774c2eec80 input=438e17f72e53d0a2]*/ { if (sha3_shake_check_digest_length(length) < 0) { return NULL; @@ -548,151 +651,198 @@ _sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length) } HASHLIB_ACQUIRE_LOCK(self); - (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length); + (void)Hacl_Hash_SHA3_squeeze(self->state, buffer, (uint32_t)length); HASHLIB_RELEASE_LOCK(self); PyObject *digest = _Py_strhex((const char *)buffer, length); PyMem_Free(buffer); return digest; } -static PyObject * -SHAKE_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) +#define SHAKE_NAME_GETTER_DECL(N) \ + static inline PyObject * \ + SHA3N_SHAKE_GETTER(N, name) (PyObject *Py_UNUSED(op), \ + void *Py_UNUSED(closure)) \ + { \ + assert(strlen("shake_" # N) == 9); \ + return PyUnicode_FromStringAndSize("shake_" # N, 9); \ + } +SHAKE_EXPAND_MACRO(SHAKE_NAME_GETTER_DECL) +#undef SHAKE_NAME_GETTER_DECL + +static inline PyObject * +SHA3_SHAKE_GETTER(digest_size)(PyObject *op, void *Py_UNUSED(closure)) { +#ifndef NDEBUG + SHA3object *self = SHA3object_CAST(op); + assert(Hacl_Hash_SHA3_is_shake(self->state)); +#endif + // preserving legacy behavior: variable-length algorithms return 0 return PyLong_FromLong(0); } static PyObject * -SHAKE_get_suffix(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure)) +SHA3_SHAKE_GETTER(_suffix)(PyObject *Py_UNUSED(op), void *Py_UNUSED(closure)) { unsigned char suffix[2] = {0x1f, 0}; return PyBytes_FromStringAndSize((const char *)suffix, 1); } - -static PyGetSetDef SHAKE_getseters[] = { - {"block_size", SHA3_get_block_size, NULL, NULL, NULL}, - {"name", SHA3_get_name, NULL, NULL, NULL}, - {"digest_size", SHAKE_get_digest_size, NULL, NULL, NULL}, - {"_capacity_bits", SHA3_get_capacity_bits, NULL, NULL, NULL}, - {"_rate_bits", SHA3_get_rate_bits, NULL, NULL, NULL}, - {"_suffix", SHAKE_get_suffix, NULL, NULL, NULL}, - {NULL} /* Sentinel */ -}; - - -static PyMethodDef SHAKE_methods[] = { - _SHA3_SHA3_224_COPY_METHODDEF - _SHA3_SHAKE_128_DIGEST_METHODDEF - _SHA3_SHAKE_128_HEXDIGEST_METHODDEF - _SHA3_SHA3_224_UPDATE_METHODDEF - {NULL, NULL} /* sentinel */ +static PyMethodDef SHA3_SHAKE_TYPE_SLOT(methods)[] = { + _SHA3_AGILE_COPY_METHODDEF + _SHA3_AGILE_UPDATE_METHODDEF + _SHA3_AGILE_SHAKE_DIGEST_METHODDEF + _SHA3_AGILE_SHAKE_HEXDIGEST_METHODDEF + {NULL, NULL} /* sentinel */ }; -PyDoc_STRVAR(shake_128__doc__, -"shake_128([data], *, usedforsecurity=True) -> SHAKE object\n\ -\n\ -Return a new SHAKE hash object."); - -PyDoc_STRVAR(shake_256__doc__, -"shake_256([data], *, usedforsecurity=True) -> SHAKE object\n\ -\n\ -Return a new SHAKE hash object."); - -SHA3_TYPE_SLOTS(SHAKE128slots, shake_128__doc__, SHAKE_methods, SHAKE_getseters); -SHA3_TYPE_SPEC(SHAKE128_spec, "shake_128", SHAKE128slots); - -SHA3_TYPE_SLOTS(SHAKE256slots, shake_256__doc__, SHAKE_methods, SHAKE_getseters); -SHA3_TYPE_SPEC(SHAKE256_spec, "shake_256", SHAKE256slots); +#define SHAKE_TYPE_OBJECT_GETSETS_DEF_DECL(N) \ + static PyGetSetDef SHA3N_SHAKE_TYPE_SLOT(N, getsets)[] = { \ + {"name", SHA3N_SHAKE_GETTER(N, name), NULL, NULL, NULL}, \ + {"block_size", SHA3_GETTER(block_size), NULL, NULL, NULL}, \ + {"digest_size", SHA3_SHAKE_GETTER(digest_size), NULL, NULL, NULL}, \ + {"_capacity_bits", SHA3_GETTER(_capacity_bits), NULL, NULL, NULL}, \ + {"_rate_bits", SHA3_GETTER(_rate_bits), NULL, NULL, NULL}, \ + {"_suffix", SHA3_SHAKE_GETTER(_suffix), NULL, NULL, NULL}, \ + {NULL} /* sentinel */ \ + }; +SHAKE_EXPAND_MACRO(SHAKE_TYPE_OBJECT_GETSETS_DEF_DECL) +#undef SHAKE_TYPE_OBJECT_GETSETS_DEF_DECL + +#define SHAKE_TYPE_OBJECT_SLOT_DOC(N) \ + PyDoc_STR( \ + "shake_" #N "([data], *, usedforsecurity=True) -> SHAKE object\n" \ + "\n" \ + "Return a new SHAKE hash object." \ + ) +#define SHAKE_TYPE_OBJECT_SLOTS_DECL(N) \ + static PyType_Slot SHA3N_SHAKE_TYPE_SLOT_ARRAY(N)[] = { \ + {Py_tp_clear, SHA3_TYPE_SLOT(clear)}, \ + {Py_tp_dealloc, SHA3_TYPE_SLOT(dealloc)}, \ + {Py_tp_traverse, SHA3_TYPE_SLOT(traverse)}, \ + {Py_tp_doc, SHAKE_TYPE_OBJECT_SLOT_DOC(N)}, \ + {Py_tp_methods, SHA3_SHAKE_TYPE_SLOT(methods)}, \ + {Py_tp_getset, SHA3N_SHAKE_TYPE_SLOT(N, getsets)}, \ + {Py_tp_new, SHA3N_SHAKE_TYPE_SLOT(N, new)}, \ + {0, NULL} \ + }; +SHAKE_EXPAND_MACRO(SHAKE_TYPE_OBJECT_SLOTS_DECL) +#undef SHAKE_TYPE_OBJECT_SLOTS_DECL +#undef SHAKE_TYPE_OBJECT_SLOT_DOC +// Using _PyType_GetModuleState() on these types is safe since they +// cannot be subclassed: they don't have the Py_TPFLAGS_BASETYPE flag. +#define SHAKE_TYPE_OBJECT_TYPE_SPEC_DECL(N) \ + static PyType_Spec SHA3N_SHAKE_TYPE_SPEC(N) = { \ + .name = "_sha3.shake_" # N, \ + .basicsize = sizeof(SHA3object), \ + .flags = ( \ + Py_TPFLAGS_DEFAULT \ + | Py_TPFLAGS_IMMUTABLETYPE \ + | Py_TPFLAGS_HAVE_GC \ + ), \ + .slots = SHA3N_SHAKE_TYPE_SLOT_ARRAY(N) \ + }; +SHAKE_EXPAND_MACRO(SHAKE_TYPE_OBJECT_TYPE_SPEC_DECL) +#undef SHAKE_TYPE_OBJECT_TYPE_SPEC_DECL static int -_sha3_traverse(PyObject *module, visitproc visit, void *arg) +sha3module_traverse(PyObject *module, visitproc visit, void *arg) { - SHA3State *state = sha3_get_state(module); + sha3module_state *state = get_sha3module_state(module); Py_VISIT(state->sha3_224_type); Py_VISIT(state->sha3_256_type); Py_VISIT(state->sha3_384_type); Py_VISIT(state->sha3_512_type); - Py_VISIT(state->shake_128_type); - Py_VISIT(state->shake_256_type); + Py_VISIT(state->shake128_type); + Py_VISIT(state->shake256_type); return 0; } static int -_sha3_clear(PyObject *module) +sha3module_clear(PyObject *module) { - SHA3State *state = sha3_get_state(module); + sha3module_state *state = get_sha3module_state(module); Py_CLEAR(state->sha3_224_type); Py_CLEAR(state->sha3_256_type); Py_CLEAR(state->sha3_384_type); Py_CLEAR(state->sha3_512_type); - Py_CLEAR(state->shake_128_type); - Py_CLEAR(state->shake_256_type); + Py_CLEAR(state->shake128_type); + Py_CLEAR(state->shake256_type); return 0; } static void -_sha3_free(void *module) +sha3module_free(void *module) { - (void)_sha3_clear((PyObject *)module); + (void)sha3module_clear((PyObject *)module); } static int -_sha3_exec(PyObject *m) +sha3module_set_type(PyTypeObject **type, PyObject *module, PyType_Spec *spec) { - SHA3State *st = sha3_get_state(m); - -#define init_sha3type(type, typespec) \ - do { \ - st->type = (PyTypeObject *)PyType_FromModuleAndSpec( \ - m, &typespec, NULL); \ - if (st->type == NULL) { \ - return -1; \ - } \ - if (PyModule_AddType(m, st->type) < 0) { \ - return -1; \ - } \ + *type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, NULL); + if (*type == NULL) { + return -1; + } + if (PyModule_AddType(module, *type) < 0) { + return -1; + } + return 0; +} + +static int +sha3module_exec(PyObject *module) +{ + sha3module_state *state = get_sha3module_state(module); + +#define SHA3_MAKE_TYPE(TYPE, TYPE_SPEC) \ + do { \ + if (sha3module_set_type(&TYPE, module, &TYPE_SPEC) < 0) { \ + return -1; \ + } \ } while(0) - init_sha3type(sha3_224_type, sha3_224_spec); - init_sha3type(sha3_256_type, sha3_256_spec); - init_sha3type(sha3_384_type, sha3_384_spec); - init_sha3type(sha3_512_type, sha3_512_spec); - init_sha3type(shake_128_type, SHAKE128_spec); - init_sha3type(shake_256_type, SHAKE256_spec); -#undef init_sha3type + SHA3_MAKE_TYPE(state->sha3_224_type, SHA3N_SHA3_TYPE_SPEC(224)); + SHA3_MAKE_TYPE(state->sha3_256_type, SHA3N_SHA3_TYPE_SPEC(256)); + SHA3_MAKE_TYPE(state->sha3_384_type, SHA3N_SHA3_TYPE_SPEC(384)); + SHA3_MAKE_TYPE(state->sha3_512_type, SHA3N_SHA3_TYPE_SPEC(512)); - if (PyModule_AddStringConstant(m, "implementation", "HACL") < 0) { + SHA3_MAKE_TYPE(state->shake128_type, SHA3N_SHAKE_TYPE_SPEC(128)); + SHA3_MAKE_TYPE(state->shake256_type, SHA3N_SHAKE_TYPE_SPEC(256)); +#undef SHA3_MAKE_TYPE + + if (PyModule_AddStringConstant(module, "implementation", "HACL") < 0) { return -1; } - if (PyModule_AddIntConstant(m, "_GIL_MINSIZE", HASHLIB_GIL_MINSIZE) < 0) { + if (PyModule_AddIntConstant(module, + "_GIL_MINSIZE", + HASHLIB_GIL_MINSIZE) < 0) { return -1; } return 0; } -static PyModuleDef_Slot _sha3_slots[] = { - {Py_mod_exec, _sha3_exec}, +static PyModuleDef_Slot sha3module_slots[] = { + {Py_mod_exec, sha3module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; /* Initialize this module. */ -static struct PyModuleDef _sha3module = { +static struct PyModuleDef sha3module_def = { PyModuleDef_HEAD_INIT, .m_name = "_sha3", - .m_size = sizeof(SHA3State), - .m_slots = _sha3_slots, - .m_traverse = _sha3_traverse, - .m_clear = _sha3_clear, - .m_free = _sha3_free, + .m_size = sizeof(sha3module_state), + .m_slots = sha3module_slots, + .m_traverse = sha3module_traverse, + .m_clear = sha3module_clear, + .m_free = sha3module_free, }; - PyMODINIT_FUNC PyInit__sha3(void) { - return PyModuleDef_Init(&_sha3module); + return PyModuleDef_Init(&sha3module_def); }