scripts/crypto/gen-hash-testvecs.py

Source file repositories/reference/linux-study-clean/scripts/crypto/gen-hash-testvecs.py

File Facts

System
Linux kernel
Corpus path
scripts/crypto/gen-hash-testvecs.py
Extension
.py
Size
12804 bytes
Lines
365
Domain
Support Tooling And Documentation
Bucket
scripts
Inferred role
Support Tooling And Documentation: scripts
Status
atlas-only

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Script that generates test vectors for the given hash function.
#
# Requires that python-cryptography be installed.
#
# Copyright 2025 Google LLC

import cryptography.hazmat.primitives.ciphers
import cryptography.hazmat.primitives.cmac
import hashlib
import hmac
import sys

DATA_LENS = [0, 1, 2, 3, 16, 32, 48, 49, 63, 64, 65, 127, 128, 129, 256, 511,
             513, 1000, 3333, 4096, 4128, 4160, 4224, 16384]

# Generate the given number of random bytes, using the length itself as the seed
# for a simple linear congruential generator (LCG).  The C test code uses the
# same LCG with the same seeding strategy to reconstruct the data, ensuring
# reproducibility without explicitly storing the data in the test vectors.
def rand_bytes(length):
    seed = length
    out = []
    for _ in range(length):
        seed = (seed * 25214903917 + 11) % 2**48
        out.append((seed >> 16) % 256)
    return bytes(out)

AES_256_KEY_SIZE = 32

# AES-CMAC.  Just wraps the implementation from python-cryptography.
class AesCmac:
    def __init__(self, key):
        aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(key)
        self.cmac = cryptography.hazmat.primitives.cmac.CMAC(aes)

    def update(self, data):
        self.cmac.update(data)

    def digest(self):
        return self.cmac.finalize()

POLY1305_KEY_SIZE = 32

# A straightforward, unoptimized implementation of Poly1305.
# Reference: https://cr.yp.to/mac/poly1305-20050329.pdf
class Poly1305:
    def __init__(self, key):
        assert len(key) == POLY1305_KEY_SIZE
        self.h = 0
        rclamp = 0x0ffffffc0ffffffc0ffffffc0fffffff
        self.r = int.from_bytes(key[:16], byteorder='little') & rclamp
        self.s = int.from_bytes(key[16:], byteorder='little')

    # Note: this supports partial blocks only at the end.
    def update(self, data):
        for i in range(0, len(data), 16):
            chunk = data[i:i+16]
            c = int.from_bytes(chunk, byteorder='little') + 2**(8 * len(chunk))
            self.h = ((self.h + c) * self.r) % (2**130 - 5)
        return self

    # Note: gen_additional_poly1305_testvecs() relies on this being
    # nondestructive, i.e. not changing any field of self.
    def digest(self):
        m = (self.h + self.s) % 2**128
        return m.to_bytes(16, byteorder='little')

Annotation

Implementation Notes