Skip to main content

Modules/_sha1module.c

cpython 3.14 @ ab2d84fe1023/Modules/_sha1module.c

Single-type extension module exposing sha1 objects. Prior to CPython 3.13 this module delegated to OpenSSL's SHA-1 implementation; in 3.13 the backend was replaced by the HACL* formally-verified C library under Modules/_hacl/. The Python-visible API is identical to _md5module: update, digest, hexdigest, and copy. Block size is 64 bytes, digest size is 20 bytes.

Map

SymbolKindPurpose
SHA1objectC structHolds sha1_state_s * (opaque HACL* state) plus a lock
SHA1_newfunctionModule-level constructor; accepts initial data and usedforsecurity
sha1_updatemethodFeeds a buffer into Hacl_Hash_SHA1_update
sha1_digestmethodCalls Hacl_Hash_SHA1_digest, returns 20-byte bytes
sha1_hexdigestmethodHex-encodes the 20-byte digest to a 40-char str
sha1_copymethodCalls Hacl_Hash_SHA1_copy, returns independent SHA1object
SHA1TypePyTypeObjectRegistered as _sha1.sha1
_sha1modulePyModuleDefModule definition; single-phase init

Reading

Object lifecycle and HACL* state ownership

SHA1_new allocates the Python object and then calls Hacl_Hash_SHA1_malloc to obtain a heap-allocated, initialised sha1_state_s *. Ownership of that pointer lives on the SHA1object; tp_dealloc is responsible for calling Hacl_Hash_SHA1_free.

// Modules/_sha1module.c:80 SHA1_new
static PyObject *
SHA1_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
SHA1object *new;
...
new = (SHA1object *)type->tp_alloc(type, 0);
if (new == NULL)
return NULL;
new->hash_state = Hacl_Hash_SHA1_malloc();
if (new->hash_state == NULL) {
Py_DECREF(new);
return PyErr_NoMemory();
}
...
}

GIL release during update

Like the MD5 module, sha1_update releases the GIL for large inputs and protects the HACL* state with a per-object lock. The threshold (PY_BUF_LOCK_THRESHOLD, 2048 bytes) is defined in hashlib.h.

// Modules/_sha1module.c:130 sha1_update
static PyObject *
sha1_update(SHA1object *self, PyObject *obj)
{
Py_buffer vw;
if (PyArg_Parse(obj, "y*", &vw) == 0)
return NULL;
if (vw.len >= PY_BUF_LOCK_THRESHOLD) {
ENTER_HASHXOF(self)
Hacl_Hash_SHA1_update(self->hash_state, vw.buf, vw.len);
LEAVE_HASHXOF(self)
} else {
Hacl_Hash_SHA1_update(self->hash_state, vw.buf, vw.len);
}
PyBuffer_Release(&vw);
Py_RETURN_NONE;
}

Digest constants exposed as type attributes

block_size (64) and digest_size (20) are set as integer attributes on SHA1Type at module init time rather than being computed from the HACL* state. They match the values mandated by RFC 3174.

// Modules/_sha1module.c:55 (PyMemberDef)
static PyMemberDef SHA1_members[] = {
{"digest_size", T_INT, offsetof(SHA1object, digestsize), READONLY, NULL},
{"block_size", T_INT, offsetof(SHA1object, blocksize), READONLY, NULL},
{NULL}
};
// blocksize = 64, digestsize = 20 filled in SHA1_new

gopy mirror

Not yet ported. The natural home is module/hashlib/ alongside the other hash types. Go's crypto/sha1 package provides the same block-and-digest semantics and can serve as the backend in place of HACL*.

CPython 3.14 changes

  • The HACL* migration (3.13) removed the OpenSSL dependency from this module entirely. In 3.14 the HACL* version was bumped to pick up upstream security fixes, but the Python-visible API is unchanged.
  • The usedforsecurity keyword is accepted for FIPS-aware callers. SHA-1 is considered cryptographically weak, so callers in security-sensitive paths should pass usedforsecurity=False or switch to SHA-2.
  • No new methods or attributes were added between 3.13 and 3.14.