Skip to content

Hash Generator — Python source

Compute SHA-1, SHA-256, SHA-384 and SHA-512 hashes of any text at once, using the browser's native SubtleCrypto. Copy each digest. 100% client-side.

This is the Python implementation — the same logic the interactive tool runs, in a shareable, citable form.

"""hash — SHA-1 / SHA-256 / SHA-384 / SHA-512 digest of a UTF-8 string.

Language: Python
CosmoDev polyglot showcase port of the ``hash`` tool.
Ported from src/tools/HashGenerator.tsx — display source, part of CosmoDev's
polyglot tool pages.

Unkeyed SHA digests via Python's standard-library ``hashlib`` module (backed
by OpenSSL). ``hashlib`` supplies the vetted, constant-time hash constructors
and returns lowercase hex via ``hexdigest()``. No third-party packages are
required.

Behavior mirrors the TypeScript reference: UTF-8 input, lowercase hex output,
and rejection of unknown algorithm names.
"""

from __future__ import annotations

import hashlib
from typing import Final

# Canonical algorithm names. The spellings match the TypeScript union so the
# same string works across every port. Each maps to a hashlib constructor.
SHA1: Final[str] = "SHA-1"
SHA256: Final[str] = "SHA-256"  # default algorithm
SHA384: Final[str] = "SHA-384"
SHA512: Final[str] = "SHA-512"

DEFAULT_ALGORITHM: Final[str] = SHA256

# Dispatch table: canonical name -> hashlib constructor. Module-level so the
# supported set is visible in one place and easy to extend.
_HASH_CONSTRUCTORS = {
    SHA1: hashlib.sha1,
    SHA256: hashlib.sha256,
    SHA384: hashlib.sha384,
    SHA512: hashlib.sha512,
}


def _digest_for(algorithm: str):
    """Return the hashlib constructor for the canonical algorithm name.

    Raises ValueError (not KeyError) so callers get a clear, domain-specific
    message rather than a leaky lookup error.
    """
    try:
        return _HASH_CONSTRUCTORS[algorithm]
    except KeyError:
        raise ValueError(f"Unsupported hash algorithm: {algorithm}") from None


def digest(text: str, algorithm: str = SHA256) -> str:
    """Compute the digest of ``text`` and return it as lowercase hex.

    ``text`` is UTF-8 encoded before hashing, so the result is correct for
    arbitrary Unicode (emoji, accents, CJK). An empty ``algorithm`` selects
    SHA-256, standing in for the optional-parameter default the TypeScript
    reference declares.

    Passing the constructor (rather than the algorithm name string) as
    ``digestmod`` makes an unknown algorithm fail fast here instead of deep
    inside ``hashlib.new``.
    """
    if algorithm == "":
        algorithm = DEFAULT_ALGORITHM

    constructor = _digest_for(algorithm)

    # text -> UTF-8 bytes; hexdigest() returns the lowercase hex string the
    # TypeScript reference produces.
    return constructor(text.encode("utf-8")).hexdigest()


def hash_all(text: str) -> dict[str, str]:
    """Compute every supported digest of ``text``.

    Returns a dict keyed by the canonical algorithm name — the Python
    equivalent of the Record the React island renders. Each hash is
    independent.
    """
    return {alg: digest(text, alg) for alg in (SHA1, SHA256, SHA384, SHA512)}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →