162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This is based in part on Andrew Moon's poly1305-donna, which is in the 662306a36Sopenharmony_ci * public domain. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <asm/unaligned.h> 1162306a36Sopenharmony_ci#include <crypto/internal/poly1305.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_civoid poly1305_core_setkey(struct poly1305_core_key *key, 1462306a36Sopenharmony_ci const u8 raw_key[POLY1305_BLOCK_SIZE]) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ 1762306a36Sopenharmony_ci key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff; 1862306a36Sopenharmony_ci key->key.r[1] = (get_unaligned_le32(&raw_key[3]) >> 2) & 0x3ffff03; 1962306a36Sopenharmony_ci key->key.r[2] = (get_unaligned_le32(&raw_key[6]) >> 4) & 0x3ffc0ff; 2062306a36Sopenharmony_ci key->key.r[3] = (get_unaligned_le32(&raw_key[9]) >> 6) & 0x3f03fff; 2162306a36Sopenharmony_ci key->key.r[4] = (get_unaligned_le32(&raw_key[12]) >> 8) & 0x00fffff; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci /* s = 5*r */ 2462306a36Sopenharmony_ci key->precomputed_s.r[0] = key->key.r[1] * 5; 2562306a36Sopenharmony_ci key->precomputed_s.r[1] = key->key.r[2] * 5; 2662306a36Sopenharmony_ci key->precomputed_s.r[2] = key->key.r[3] * 5; 2762306a36Sopenharmony_ci key->precomputed_s.r[3] = key->key.r[4] * 5; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ciEXPORT_SYMBOL(poly1305_core_setkey); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_civoid poly1305_core_blocks(struct poly1305_state *state, 3262306a36Sopenharmony_ci const struct poly1305_core_key *key, const void *src, 3362306a36Sopenharmony_ci unsigned int nblocks, u32 hibit) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci const u8 *input = src; 3662306a36Sopenharmony_ci u32 r0, r1, r2, r3, r4; 3762306a36Sopenharmony_ci u32 s1, s2, s3, s4; 3862306a36Sopenharmony_ci u32 h0, h1, h2, h3, h4; 3962306a36Sopenharmony_ci u64 d0, d1, d2, d3, d4; 4062306a36Sopenharmony_ci u32 c; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!nblocks) 4362306a36Sopenharmony_ci return; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci hibit <<= 24; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci r0 = key->key.r[0]; 4862306a36Sopenharmony_ci r1 = key->key.r[1]; 4962306a36Sopenharmony_ci r2 = key->key.r[2]; 5062306a36Sopenharmony_ci r3 = key->key.r[3]; 5162306a36Sopenharmony_ci r4 = key->key.r[4]; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci s1 = key->precomputed_s.r[0]; 5462306a36Sopenharmony_ci s2 = key->precomputed_s.r[1]; 5562306a36Sopenharmony_ci s3 = key->precomputed_s.r[2]; 5662306a36Sopenharmony_ci s4 = key->precomputed_s.r[3]; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci h0 = state->h[0]; 5962306a36Sopenharmony_ci h1 = state->h[1]; 6062306a36Sopenharmony_ci h2 = state->h[2]; 6162306a36Sopenharmony_ci h3 = state->h[3]; 6262306a36Sopenharmony_ci h4 = state->h[4]; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci do { 6562306a36Sopenharmony_ci /* h += m[i] */ 6662306a36Sopenharmony_ci h0 += (get_unaligned_le32(&input[0])) & 0x3ffffff; 6762306a36Sopenharmony_ci h1 += (get_unaligned_le32(&input[3]) >> 2) & 0x3ffffff; 6862306a36Sopenharmony_ci h2 += (get_unaligned_le32(&input[6]) >> 4) & 0x3ffffff; 6962306a36Sopenharmony_ci h3 += (get_unaligned_le32(&input[9]) >> 6) & 0x3ffffff; 7062306a36Sopenharmony_ci h4 += (get_unaligned_le32(&input[12]) >> 8) | hibit; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* h *= r */ 7362306a36Sopenharmony_ci d0 = ((u64)h0 * r0) + ((u64)h1 * s4) + 7462306a36Sopenharmony_ci ((u64)h2 * s3) + ((u64)h3 * s2) + 7562306a36Sopenharmony_ci ((u64)h4 * s1); 7662306a36Sopenharmony_ci d1 = ((u64)h0 * r1) + ((u64)h1 * r0) + 7762306a36Sopenharmony_ci ((u64)h2 * s4) + ((u64)h3 * s3) + 7862306a36Sopenharmony_ci ((u64)h4 * s2); 7962306a36Sopenharmony_ci d2 = ((u64)h0 * r2) + ((u64)h1 * r1) + 8062306a36Sopenharmony_ci ((u64)h2 * r0) + ((u64)h3 * s4) + 8162306a36Sopenharmony_ci ((u64)h4 * s3); 8262306a36Sopenharmony_ci d3 = ((u64)h0 * r3) + ((u64)h1 * r2) + 8362306a36Sopenharmony_ci ((u64)h2 * r1) + ((u64)h3 * r0) + 8462306a36Sopenharmony_ci ((u64)h4 * s4); 8562306a36Sopenharmony_ci d4 = ((u64)h0 * r4) + ((u64)h1 * r3) + 8662306a36Sopenharmony_ci ((u64)h2 * r2) + ((u64)h3 * r1) + 8762306a36Sopenharmony_ci ((u64)h4 * r0); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* (partial) h %= p */ 9062306a36Sopenharmony_ci c = (u32)(d0 >> 26); 9162306a36Sopenharmony_ci h0 = (u32)d0 & 0x3ffffff; 9262306a36Sopenharmony_ci d1 += c; 9362306a36Sopenharmony_ci c = (u32)(d1 >> 26); 9462306a36Sopenharmony_ci h1 = (u32)d1 & 0x3ffffff; 9562306a36Sopenharmony_ci d2 += c; 9662306a36Sopenharmony_ci c = (u32)(d2 >> 26); 9762306a36Sopenharmony_ci h2 = (u32)d2 & 0x3ffffff; 9862306a36Sopenharmony_ci d3 += c; 9962306a36Sopenharmony_ci c = (u32)(d3 >> 26); 10062306a36Sopenharmony_ci h3 = (u32)d3 & 0x3ffffff; 10162306a36Sopenharmony_ci d4 += c; 10262306a36Sopenharmony_ci c = (u32)(d4 >> 26); 10362306a36Sopenharmony_ci h4 = (u32)d4 & 0x3ffffff; 10462306a36Sopenharmony_ci h0 += c * 5; 10562306a36Sopenharmony_ci c = (h0 >> 26); 10662306a36Sopenharmony_ci h0 = h0 & 0x3ffffff; 10762306a36Sopenharmony_ci h1 += c; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci input += POLY1305_BLOCK_SIZE; 11062306a36Sopenharmony_ci } while (--nblocks); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci state->h[0] = h0; 11362306a36Sopenharmony_ci state->h[1] = h1; 11462306a36Sopenharmony_ci state->h[2] = h2; 11562306a36Sopenharmony_ci state->h[3] = h3; 11662306a36Sopenharmony_ci state->h[4] = h4; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ciEXPORT_SYMBOL(poly1305_core_blocks); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_civoid poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4], 12162306a36Sopenharmony_ci void *dst) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci u8 *mac = dst; 12462306a36Sopenharmony_ci u32 h0, h1, h2, h3, h4, c; 12562306a36Sopenharmony_ci u32 g0, g1, g2, g3, g4; 12662306a36Sopenharmony_ci u64 f; 12762306a36Sopenharmony_ci u32 mask; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* fully carry h */ 13062306a36Sopenharmony_ci h0 = state->h[0]; 13162306a36Sopenharmony_ci h1 = state->h[1]; 13262306a36Sopenharmony_ci h2 = state->h[2]; 13362306a36Sopenharmony_ci h3 = state->h[3]; 13462306a36Sopenharmony_ci h4 = state->h[4]; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci c = h1 >> 26; 13762306a36Sopenharmony_ci h1 = h1 & 0x3ffffff; 13862306a36Sopenharmony_ci h2 += c; 13962306a36Sopenharmony_ci c = h2 >> 26; 14062306a36Sopenharmony_ci h2 = h2 & 0x3ffffff; 14162306a36Sopenharmony_ci h3 += c; 14262306a36Sopenharmony_ci c = h3 >> 26; 14362306a36Sopenharmony_ci h3 = h3 & 0x3ffffff; 14462306a36Sopenharmony_ci h4 += c; 14562306a36Sopenharmony_ci c = h4 >> 26; 14662306a36Sopenharmony_ci h4 = h4 & 0x3ffffff; 14762306a36Sopenharmony_ci h0 += c * 5; 14862306a36Sopenharmony_ci c = h0 >> 26; 14962306a36Sopenharmony_ci h0 = h0 & 0x3ffffff; 15062306a36Sopenharmony_ci h1 += c; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* compute h + -p */ 15362306a36Sopenharmony_ci g0 = h0 + 5; 15462306a36Sopenharmony_ci c = g0 >> 26; 15562306a36Sopenharmony_ci g0 &= 0x3ffffff; 15662306a36Sopenharmony_ci g1 = h1 + c; 15762306a36Sopenharmony_ci c = g1 >> 26; 15862306a36Sopenharmony_ci g1 &= 0x3ffffff; 15962306a36Sopenharmony_ci g2 = h2 + c; 16062306a36Sopenharmony_ci c = g2 >> 26; 16162306a36Sopenharmony_ci g2 &= 0x3ffffff; 16262306a36Sopenharmony_ci g3 = h3 + c; 16362306a36Sopenharmony_ci c = g3 >> 26; 16462306a36Sopenharmony_ci g3 &= 0x3ffffff; 16562306a36Sopenharmony_ci g4 = h4 + c - (1UL << 26); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* select h if h < p, or h + -p if h >= p */ 16862306a36Sopenharmony_ci mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; 16962306a36Sopenharmony_ci g0 &= mask; 17062306a36Sopenharmony_ci g1 &= mask; 17162306a36Sopenharmony_ci g2 &= mask; 17262306a36Sopenharmony_ci g3 &= mask; 17362306a36Sopenharmony_ci g4 &= mask; 17462306a36Sopenharmony_ci mask = ~mask; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci h0 = (h0 & mask) | g0; 17762306a36Sopenharmony_ci h1 = (h1 & mask) | g1; 17862306a36Sopenharmony_ci h2 = (h2 & mask) | g2; 17962306a36Sopenharmony_ci h3 = (h3 & mask) | g3; 18062306a36Sopenharmony_ci h4 = (h4 & mask) | g4; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* h = h % (2^128) */ 18362306a36Sopenharmony_ci h0 = ((h0) | (h1 << 26)) & 0xffffffff; 18462306a36Sopenharmony_ci h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; 18562306a36Sopenharmony_ci h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; 18662306a36Sopenharmony_ci h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (likely(nonce)) { 18962306a36Sopenharmony_ci /* mac = (h + nonce) % (2^128) */ 19062306a36Sopenharmony_ci f = (u64)h0 + nonce[0]; 19162306a36Sopenharmony_ci h0 = (u32)f; 19262306a36Sopenharmony_ci f = (u64)h1 + nonce[1] + (f >> 32); 19362306a36Sopenharmony_ci h1 = (u32)f; 19462306a36Sopenharmony_ci f = (u64)h2 + nonce[2] + (f >> 32); 19562306a36Sopenharmony_ci h2 = (u32)f; 19662306a36Sopenharmony_ci f = (u64)h3 + nonce[3] + (f >> 32); 19762306a36Sopenharmony_ci h3 = (u32)f; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci put_unaligned_le32(h0, &mac[0]); 20162306a36Sopenharmony_ci put_unaligned_le32(h1, &mac[4]); 20262306a36Sopenharmony_ci put_unaligned_le32(h2, &mac[8]); 20362306a36Sopenharmony_ci put_unaligned_le32(h3, &mac[12]); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ciEXPORT_SYMBOL(poly1305_core_emit); 206