lib/crypto/poly1305-donna32.c

Source file repositories/reference/linux-study-clean/lib/crypto/poly1305-donna32.c

File Facts

System
Linux kernel
Corpus path
lib/crypto/poly1305-donna32.c
Extension
.c
Size
4875 bytes
Lines
207
Domain
Kernel Services
Bucket
lib
Inferred role
Kernel Services: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Shared kernel service surface used by multiple subsystems, including helpers, cryptography, virtualization support, and async I/O infrastructure.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
 * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 *
 * This is based in part on Andrew Moon's poly1305-donna, which is in the
 * public domain.
 */

#include <crypto/internal/poly1305.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/unaligned.h>

void poly1305_core_setkey(struct poly1305_core_key *key,
			  const u8 raw_key[POLY1305_BLOCK_SIZE])
{
	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
	key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff;
	key->key.r[1] = (get_unaligned_le32(&raw_key[3]) >> 2) & 0x3ffff03;
	key->key.r[2] = (get_unaligned_le32(&raw_key[6]) >> 4) & 0x3ffc0ff;
	key->key.r[3] = (get_unaligned_le32(&raw_key[9]) >> 6) & 0x3f03fff;
	key->key.r[4] = (get_unaligned_le32(&raw_key[12]) >> 8) & 0x00fffff;

	/* s = 5*r */
	key->precomputed_s.r[0] = key->key.r[1] * 5;
	key->precomputed_s.r[1] = key->key.r[2] * 5;
	key->precomputed_s.r[2] = key->key.r[3] * 5;
	key->precomputed_s.r[3] = key->key.r[4] * 5;
}
EXPORT_SYMBOL(poly1305_core_setkey);

void poly1305_core_blocks(struct poly1305_state *state,
			  const struct poly1305_core_key *key, const void *src,
			  unsigned int nblocks, u32 hibit)
{
	const u8 *input = src;
	u32 r0, r1, r2, r3, r4;
	u32 s1, s2, s3, s4;
	u32 h0, h1, h2, h3, h4;
	u64 d0, d1, d2, d3, d4;
	u32 c;

	if (!nblocks)
		return;

	hibit <<= 24;

	r0 = key->key.r[0];
	r1 = key->key.r[1];
	r2 = key->key.r[2];
	r3 = key->key.r[3];
	r4 = key->key.r[4];

	s1 = key->precomputed_s.r[0];
	s2 = key->precomputed_s.r[1];
	s3 = key->precomputed_s.r[2];
	s4 = key->precomputed_s.r[3];

	h0 = state->h[0];
	h1 = state->h[1];
	h2 = state->h[2];
	h3 = state->h[3];
	h4 = state->h[4];

	do {
		/* h += m[i] */
		h0 += (get_unaligned_le32(&input[0])) & 0x3ffffff;
		h1 += (get_unaligned_le32(&input[3]) >> 2) & 0x3ffffff;
		h2 += (get_unaligned_le32(&input[6]) >> 4) & 0x3ffffff;
		h3 += (get_unaligned_le32(&input[9]) >> 6) & 0x3ffffff;
		h4 += (get_unaligned_le32(&input[12]) >> 8) | hibit;

		/* h *= r */
		d0 = ((u64)h0 * r0) + ((u64)h1 * s4) +
		     ((u64)h2 * s3) + ((u64)h3 * s2) +
		     ((u64)h4 * s1);
		d1 = ((u64)h0 * r1) + ((u64)h1 * r0) +
		     ((u64)h2 * s4) + ((u64)h3 * s3) +
		     ((u64)h4 * s2);
		d2 = ((u64)h0 * r2) + ((u64)h1 * r1) +
		     ((u64)h2 * r0) + ((u64)h3 * s4) +
		     ((u64)h4 * s3);
		d3 = ((u64)h0 * r3) + ((u64)h1 * r2) +
		     ((u64)h2 * r1) + ((u64)h3 * r0) +
		     ((u64)h4 * s4);
		d4 = ((u64)h0 * r4) + ((u64)h1 * r3) +
		     ((u64)h2 * r2) + ((u64)h3 * r1) +
		     ((u64)h4 * r0);

		/* (partial) h %= p */

Annotation

Implementation Notes