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 u64 t0, t1; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ 1962306a36Sopenharmony_ci t0 = get_unaligned_le64(&raw_key[0]); 2062306a36Sopenharmony_ci t1 = get_unaligned_le64(&raw_key[8]); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci key->key.r64[0] = t0 & 0xffc0fffffffULL; 2362306a36Sopenharmony_ci key->key.r64[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffffULL; 2462306a36Sopenharmony_ci key->key.r64[2] = ((t1 >> 24)) & 0x00ffffffc0fULL; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* s = 20*r */ 2762306a36Sopenharmony_ci key->precomputed_s.r64[0] = key->key.r64[1] * 20; 2862306a36Sopenharmony_ci key->precomputed_s.r64[1] = key->key.r64[2] * 20; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ciEXPORT_SYMBOL(poly1305_core_setkey); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_civoid poly1305_core_blocks(struct poly1305_state *state, 3362306a36Sopenharmony_ci const struct poly1305_core_key *key, const void *src, 3462306a36Sopenharmony_ci unsigned int nblocks, u32 hibit) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci const u8 *input = src; 3762306a36Sopenharmony_ci u64 hibit64; 3862306a36Sopenharmony_ci u64 r0, r1, r2; 3962306a36Sopenharmony_ci u64 s1, s2; 4062306a36Sopenharmony_ci u64 h0, h1, h2; 4162306a36Sopenharmony_ci u64 c; 4262306a36Sopenharmony_ci u128 d0, d1, d2, d; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (!nblocks) 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci hibit64 = ((u64)hibit) << 40; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci r0 = key->key.r64[0]; 5062306a36Sopenharmony_ci r1 = key->key.r64[1]; 5162306a36Sopenharmony_ci r2 = key->key.r64[2]; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci h0 = state->h64[0]; 5462306a36Sopenharmony_ci h1 = state->h64[1]; 5562306a36Sopenharmony_ci h2 = state->h64[2]; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci s1 = key->precomputed_s.r64[0]; 5862306a36Sopenharmony_ci s2 = key->precomputed_s.r64[1]; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci do { 6162306a36Sopenharmony_ci u64 t0, t1; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* h += m[i] */ 6462306a36Sopenharmony_ci t0 = get_unaligned_le64(&input[0]); 6562306a36Sopenharmony_ci t1 = get_unaligned_le64(&input[8]); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci h0 += t0 & 0xfffffffffffULL; 6862306a36Sopenharmony_ci h1 += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL; 6962306a36Sopenharmony_ci h2 += (((t1 >> 24)) & 0x3ffffffffffULL) | hibit64; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* h *= r */ 7262306a36Sopenharmony_ci d0 = (u128)h0 * r0; 7362306a36Sopenharmony_ci d = (u128)h1 * s2; 7462306a36Sopenharmony_ci d0 += d; 7562306a36Sopenharmony_ci d = (u128)h2 * s1; 7662306a36Sopenharmony_ci d0 += d; 7762306a36Sopenharmony_ci d1 = (u128)h0 * r1; 7862306a36Sopenharmony_ci d = (u128)h1 * r0; 7962306a36Sopenharmony_ci d1 += d; 8062306a36Sopenharmony_ci d = (u128)h2 * s2; 8162306a36Sopenharmony_ci d1 += d; 8262306a36Sopenharmony_ci d2 = (u128)h0 * r2; 8362306a36Sopenharmony_ci d = (u128)h1 * r1; 8462306a36Sopenharmony_ci d2 += d; 8562306a36Sopenharmony_ci d = (u128)h2 * r0; 8662306a36Sopenharmony_ci d2 += d; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* (partial) h %= p */ 8962306a36Sopenharmony_ci c = (u64)(d0 >> 44); 9062306a36Sopenharmony_ci h0 = (u64)d0 & 0xfffffffffffULL; 9162306a36Sopenharmony_ci d1 += c; 9262306a36Sopenharmony_ci c = (u64)(d1 >> 44); 9362306a36Sopenharmony_ci h1 = (u64)d1 & 0xfffffffffffULL; 9462306a36Sopenharmony_ci d2 += c; 9562306a36Sopenharmony_ci c = (u64)(d2 >> 42); 9662306a36Sopenharmony_ci h2 = (u64)d2 & 0x3ffffffffffULL; 9762306a36Sopenharmony_ci h0 += c * 5; 9862306a36Sopenharmony_ci c = h0 >> 44; 9962306a36Sopenharmony_ci h0 = h0 & 0xfffffffffffULL; 10062306a36Sopenharmony_ci h1 += c; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci input += POLY1305_BLOCK_SIZE; 10362306a36Sopenharmony_ci } while (--nblocks); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci state->h64[0] = h0; 10662306a36Sopenharmony_ci state->h64[1] = h1; 10762306a36Sopenharmony_ci state->h64[2] = h2; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ciEXPORT_SYMBOL(poly1305_core_blocks); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_civoid poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4], 11262306a36Sopenharmony_ci void *dst) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci u8 *mac = dst; 11562306a36Sopenharmony_ci u64 h0, h1, h2, c; 11662306a36Sopenharmony_ci u64 g0, g1, g2; 11762306a36Sopenharmony_ci u64 t0, t1; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* fully carry h */ 12062306a36Sopenharmony_ci h0 = state->h64[0]; 12162306a36Sopenharmony_ci h1 = state->h64[1]; 12262306a36Sopenharmony_ci h2 = state->h64[2]; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci c = h1 >> 44; 12562306a36Sopenharmony_ci h1 &= 0xfffffffffffULL; 12662306a36Sopenharmony_ci h2 += c; 12762306a36Sopenharmony_ci c = h2 >> 42; 12862306a36Sopenharmony_ci h2 &= 0x3ffffffffffULL; 12962306a36Sopenharmony_ci h0 += c * 5; 13062306a36Sopenharmony_ci c = h0 >> 44; 13162306a36Sopenharmony_ci h0 &= 0xfffffffffffULL; 13262306a36Sopenharmony_ci h1 += c; 13362306a36Sopenharmony_ci c = h1 >> 44; 13462306a36Sopenharmony_ci h1 &= 0xfffffffffffULL; 13562306a36Sopenharmony_ci h2 += c; 13662306a36Sopenharmony_ci c = h2 >> 42; 13762306a36Sopenharmony_ci h2 &= 0x3ffffffffffULL; 13862306a36Sopenharmony_ci h0 += c * 5; 13962306a36Sopenharmony_ci c = h0 >> 44; 14062306a36Sopenharmony_ci h0 &= 0xfffffffffffULL; 14162306a36Sopenharmony_ci h1 += c; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* compute h + -p */ 14462306a36Sopenharmony_ci g0 = h0 + 5; 14562306a36Sopenharmony_ci c = g0 >> 44; 14662306a36Sopenharmony_ci g0 &= 0xfffffffffffULL; 14762306a36Sopenharmony_ci g1 = h1 + c; 14862306a36Sopenharmony_ci c = g1 >> 44; 14962306a36Sopenharmony_ci g1 &= 0xfffffffffffULL; 15062306a36Sopenharmony_ci g2 = h2 + c - (1ULL << 42); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* select h if h < p, or h + -p if h >= p */ 15362306a36Sopenharmony_ci c = (g2 >> ((sizeof(u64) * 8) - 1)) - 1; 15462306a36Sopenharmony_ci g0 &= c; 15562306a36Sopenharmony_ci g1 &= c; 15662306a36Sopenharmony_ci g2 &= c; 15762306a36Sopenharmony_ci c = ~c; 15862306a36Sopenharmony_ci h0 = (h0 & c) | g0; 15962306a36Sopenharmony_ci h1 = (h1 & c) | g1; 16062306a36Sopenharmony_ci h2 = (h2 & c) | g2; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (likely(nonce)) { 16362306a36Sopenharmony_ci /* h = (h + nonce) */ 16462306a36Sopenharmony_ci t0 = ((u64)nonce[1] << 32) | nonce[0]; 16562306a36Sopenharmony_ci t1 = ((u64)nonce[3] << 32) | nonce[2]; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci h0 += t0 & 0xfffffffffffULL; 16862306a36Sopenharmony_ci c = h0 >> 44; 16962306a36Sopenharmony_ci h0 &= 0xfffffffffffULL; 17062306a36Sopenharmony_ci h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL) + c; 17162306a36Sopenharmony_ci c = h1 >> 44; 17262306a36Sopenharmony_ci h1 &= 0xfffffffffffULL; 17362306a36Sopenharmony_ci h2 += (((t1 >> 24)) & 0x3ffffffffffULL) + c; 17462306a36Sopenharmony_ci h2 &= 0x3ffffffffffULL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* mac = h % (2^128) */ 17862306a36Sopenharmony_ci h0 = h0 | (h1 << 44); 17962306a36Sopenharmony_ci h1 = (h1 >> 20) | (h2 << 24); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci put_unaligned_le64(h0, &mac[0]); 18262306a36Sopenharmony_ci put_unaligned_le64(h1, &mac[8]); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ciEXPORT_SYMBOL(poly1305_core_emit); 185