Skip to content

Commit de09602

Browse files
committed
optimize calls to PyMem_Malloc in SHAKE digest computation
1 parent 2dbada1 commit de09602

File tree

3 files changed

+58
-31
lines changed

3 files changed

+58
-31
lines changed

Lib/test/test_hashlib.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,15 @@ def test_hexdigest(self):
376376
self.assertIsInstance(h.digest(), bytes)
377377
self.assertEqual(hexstr(h.digest()), h.hexdigest())
378378

379-
def test_digest_length_overflow(self):
379+
def test_shakes_digest_zero_length(self):
380+
for shake_name in self.shakes:
381+
for constructor in self.hash_constructors[shake_name]:
382+
with self.subTest(constructor=constructor):
383+
h = constructor(b'abcdef', usedforsecurity=False)
384+
self.assertEqual(h.digest(0), b'')
385+
self.assertEqual(h.hexdigest(0), '')
386+
387+
def test_shakes_digest_length_overflow(self):
380388
# See issue #34922
381389
large_sizes = (2**29, 2**32-10, 2**32+10, 2**61, 2**64-10, 2**64+10)
382390
for cons in self.hash_constructors:

Modules/clinic/sha3module.c.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/sha3module.c

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -472,29 +472,48 @@ SHA3_TYPE_SPEC(sha3_384_spec, "sha3_384", sha3_384_slots);
472472
SHA3_TYPE_SLOTS(sha3_512_slots, sha3_512__doc__, SHA3_methods, SHA3_getseters);
473473
SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots);
474474

475+
/*
476+
* Compute the digest of SHAKE object.
477+
*
478+
* If 'hex' is false, the output is the raw binary digest as bytes.
479+
* Otherwise, the output is its hexadecimal (string) representation.
480+
*/
475481
static PyObject *
476-
_SHAKE_digest(PyObject *op, unsigned long digestlen, int hex)
482+
_sha3_shake_compute_digest(SHA3object *self, uint32_t digestlen, bool hex)
477483
{
478-
unsigned char *digest = NULL;
484+
uint8_t *digest = NULL;
479485
PyObject *result = NULL;
480-
SHA3object *self = _SHA3object_CAST(op);
481-
482-
if (digestlen >= (1 << 29)) {
483-
PyErr_SetString(PyExc_ValueError, "length is too large");
486+
#define MAX_SHAKE_DIGESTSIZE (1 << 29)
487+
if (digestlen >= MAX_SHAKE_DIGESTSIZE) {
488+
PyErr_Format(PyExc_ValueError,
489+
"SHAKE digest length must be < %" PRIu32,
490+
MAX_SHAKE_DIGESTSIZE);
484491
return NULL;
485492
}
486-
digest = (unsigned char*)PyMem_Malloc(digestlen);
493+
#undef MAX_SHAKE_DIGESTSIZE
494+
495+
/*
496+
* The HACL* function fails if the algorithm is not SHAKE, which is not
497+
* the case as the caller is _sha3_shake_{128,256}[hex]digest_impl(),
498+
* or if the output length is zero.
499+
*
500+
* In the latter case, we follow the existing behavior
501+
* and return an empty digest, without raising an error.
502+
*/
503+
if (digestlen == 0) {
504+
return Py_GetConstant(
505+
hex ? Py_CONSTANT_EMPTY_STR : Py_CONSTANT_EMPTY_BYTES
506+
);
507+
}
508+
509+
digest = PyMem_Malloc(digestlen);
487510
if (digest == NULL) {
488511
return PyErr_NoMemory();
489512
}
490513

491-
/* Get the raw (binary) digest value. The HACL functions errors out if:
492-
* - the algorithm is not shake -- not the case here
493-
* - the output length is zero -- we follow the existing behavior and return
494-
* an empty digest, without raising an error */
495-
if (digestlen > 0) {
496-
(void)Hacl_Hash_SHA3_squeeze(self->hash_state, digest, digestlen);
497-
}
514+
ENTER_HASHLIB(self);
515+
(void)Hacl_Hash_SHA3_squeeze(self->hash_state, digest, digestlen);
516+
LEAVE_HASHLIB(self);
498517
if (hex) {
499518
result = _Py_strhex((const char *)digest, digestlen);
500519
}
@@ -509,32 +528,32 @@ _SHAKE_digest(PyObject *op, unsigned long digestlen, int hex)
509528
/*[clinic input]
510529
_sha3.shake_128.digest
511530
512-
length: unsigned_long
531+
length: uint32
513532
514533
Return the digest value as a bytes object.
515534
[clinic start generated code]*/
516535

517536
static PyObject *
518-
_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length)
519-
/*[clinic end generated code: output=2313605e2f87bb8f input=93d6d6ff32904f18]*/
537+
_sha3_shake_128_digest_impl(SHA3object *self, uint32_t length)
538+
/*[clinic end generated code: output=b8be6cd55400959c input=8a6901d3d699ee26]*/
520539
{
521-
return _SHAKE_digest((PyObject *)self, length, 0);
540+
return _sha3_shake_compute_digest(self, length, false);
522541
}
523542

524543

525544
/*[clinic input]
526545
_sha3.shake_128.hexdigest
527546
528-
length: unsigned_long
547+
length: uint32
529548
530549
Return the digest value as a string of hexadecimal digits.
531550
[clinic start generated code]*/
532551

533552
static PyObject *
534-
_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length)
535-
/*[clinic end generated code: output=bf8e2f1e490944a8 input=562d74e7060b56ab]*/
553+
_sha3_shake_128_hexdigest_impl(SHA3object *self, uint32_t length)
554+
/*[clinic end generated code: output=cc1abb908d8ac614 input=acab18f97f8af822]*/
536555
{
537-
return _SHAKE_digest((PyObject *)self, length, 1);
556+
return _sha3_shake_compute_digest(self, length, true);
538557
}
539558

540559
static PyObject *

0 commit comments

Comments
 (0)