/* umac-poly128.c */ /* nettle, low-level cryptographics library * * Copyright (C) 2013 Niels Möller * * The nettle library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * The nettle library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the nettle library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02111-1301, USA. */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include "umac.h" #define HI(x) (x >> 32) #define LO(x) (x & 0xffffffffUL) static void poly128_mul (const uint32_t *k, uint64_t *y) { uint64_t y0,y1,y2,y3,p0,p1,p2,p3,m0,m1,m2; y0 = LO (y[1]); y1 = HI (y[1]); y2 = LO (y[0]); y3 = HI (y[0]); p0 = y0 * k[3]; m0 = y0 * k[2] + y1 * k[3]; p1 = y0 * k[1] + y1 * k[2] + y2 * k[3]; m1 = y0 * k[0] + y1 * k[1] + y2 * k[2] + y3 * k[3]; p2 = y1 * k[0] + y2 * k[1] + y3 * k[2]; m2 = y2 * k[0] + y3 * k[1]; p3 = y3 * k[0]; /* Collaps to 4 64-bit words, +---+---+---+---+ | p3| p2| p1| p0| +-+-+-+-+-+-+-+-+ + | m2| m1| m0| -+-+-+-+-+-+-+-+-+ */ /* But it's convenient to reduce (p3,p2,p1,p0) and (m2,m1,m0) mod p first.*/ m1 += UMAC_P128_OFFSET * HI(p3); p1 += UMAC_P128_OFFSET * (LO(p3) + HI(m2)); m0 += UMAC_P128_OFFSET * (HI(p2) + LO(m2)); p0 += UMAC_P128_OFFSET * (LO(p2) + HI(m1)); /* Left to add +---+---+ | p1| p0| +-+-+-+-+ m1| m0| +-+---+ */ /* First add high parts, with no possibilities for carries */ p1 += m0 >> 32; m0 <<= 32; m1 <<= 32; /* Remains: +---+---+ | p1| p0| +-+-+---+ +| m1| m0| -+---+---+ */ p0 += m0; p1 += (p0 < m0); p1 += m1; if (p1 < m1) { p0 += UMAC_P128_OFFSET; p1 += (p0 < UMAC_P128_OFFSET); } y[0] = p1; y[1] = p0; } void _umac_poly128 (const uint32_t *k, uint64_t *y, uint64_t mh, uint64_t ml) { uint64_t yh, yl, cy; if ( (mh >> 32) == 0xffffffff) { poly128_mul (k, y); if (y[1] > 0) y[1]--; else if (y[0] > 0) { y[0]--; y[1] = UMAC_P128_HI; } else { y[0] = UMAC_P128_HI; y[1] = UMAC_P128_LO-1; } mh -= (ml < UMAC_P128_OFFSET); ml -= UMAC_P128_OFFSET; } assert (mh < UMAC_P128_HI || ml < UMAC_P128_LO); poly128_mul (k, y); yl = y[1] + ml; cy = (yl < ml); yh = y[0] + cy; cy = (yh < cy); yh += mh; cy += (yh < mh); assert (cy <= 1); if (cy) { yl += UMAC_P128_OFFSET; yh += yl < UMAC_P128_OFFSET; } y[0] = yh; y[1] = yl; }