Skip to main content

Modules/_hashopenssl.c / Lib/hashlib.py (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_hashopenssl.c

This annotation covers variable-length digests and the Python-level hashlib dispatch. See modules_hashlib_detail for md5, sha1, sha256, sha512, update, digest, hexdigest, and copy.

Map

LinesSymbolRole
1-100SHAKE digest objectsVariable-length output: shake_128.digest(length)
101-250BLAKE2b / BLAKE2skeyed hashing, personalization, tree hashing
251-400hashlib.newDispatch by name to OpenSSL or built-in implementation
401-600hmac.new / HMACHMAC construction using hashlib digest objects
601-800hashlib.file_digestHash entire file efficiently
801-900algorithms_available / algorithms_guaranteedRuntime discovery of available hash names

Reading

SHAKE variable-length output

// CPython: Modules/_hashopenssl.c:580 SHAKE_digest
static PyObject *
SHAKE_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
Py_ssize_t length;
if (!_PyArg_ParseStack(args, nargs, "n", &length)) return NULL;
if (length < 0) {
PyErr_SetString(PyExc_ValueError, "length must be non-negative");
return NULL;
}
unsigned char *digest = PyMem_Malloc(length);
EVP_DigestFinalXOF(self->ctx, digest, length); /* XOF = extendable output */
PyObject *result = PyBytes_FromStringAndSize((char *)digest, length);
PyMem_Free(digest);
return result;
}

SHAKE-128 and SHAKE-256 are XOFs (extendable output functions) from SHA-3. The length parameter to digest() is variable, unlike fixed-length SHA-2 digests.

BLAKE2b

// CPython: Modules/_hashopenssl.c:720 blake2b_new
/* BLAKE2b parameters:
data -- initial data to hash
digest_size -- output length in bytes (1-64 for BLAKE2b, 1-32 for BLAKE2s)
key -- optional key (up to 64 bytes) for keyed hashing
salt -- optional 16-byte personalization salt
person -- optional 16-byte personalization string
fanout/depth/leaf_size/node_offset/node_depth/inner_size -- tree hashing
*/

BLAKE2b accepts a key of up to 64 bytes, turning it into a MAC (message authentication code) without a separate HMAC construction. digest_size allows truncated output.

hashlib.new

# CPython: Lib/hashlib.py:162 new
def new(name, data=b'', **kwargs):
"""Create a new hash object using the named algorithm.

Tries OpenSSL first, falls back to built-in implementations
(_md5, _sha1, _sha256, _sha512, _blake2, _sha3).
"""
try:
return __get_openssl_constructor(name)(data, **kwargs)
except ValueError:
pass
return __get_builtin_constructor(name)(data, **kwargs)

hashlib.new('sha256') is equivalent to hashlib.sha256(). The registry of built-in constructors covers the guaranteed algorithms (md5, sha1, sha2 family, sha3 family, blake2).

hashlib.file_digest

# CPython: Lib/hashlib.py:280 file_digest
def file_digest(fileobj, digest, /, *, _bufsize=2**18):
"""Hash the contents of a file-like object.

digest -- a hash name string or a callable returning a hash object
"""
if isinstance(digest, str):
digestobj = new(digest)
else:
digestobj = digest()
buf = bytearray(_bufsize)
view = memoryview(buf)
while True:
size = fileobj.readinto(buf)
if size == 0:
break
digestobj.update(view[:size])
return digestobj

file_digest uses readinto with a reusable bytearray to avoid allocation on each read. The default buffer size is 256 KiB.

algorithms_guaranteed

# CPython: Lib/hashlib.py:80 algorithms_guaranteed
algorithms_guaranteed = {
'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
'shake_128', 'shake_256',
'blake2b', 'blake2s',
}

algorithms_available includes everything OpenSSL provides on the current platform. algorithms_guaranteed is the portable subset that every conforming Python installation must include.

gopy notes

hashlib is in module/hashlib/module.go. SHAKE.digest uses Go's golang.org/x/crypto/sha3.ShakeHash. BLAKE2b/BLAKE2s use golang.org/x/crypto/blake2b and blake2s. file_digest uses Go's io.ReadFull loop. algorithms_guaranteed is a constant frozenset in module/hashlib.