1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * This module is meant to be used as template for base 2^44 assembly
12e1051a39Sopenharmony_ci * implementation[s]. On side note compiler-generated code is not
13e1051a39Sopenharmony_ci * slower than compiler-generated base 2^64 code on [high-end] x86_64,
14e1051a39Sopenharmony_ci * even though amount of multiplications is 50% higher. Go figure...
15e1051a39Sopenharmony_ci */
16e1051a39Sopenharmony_ci#include <stdlib.h>
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_citypedef unsigned char u8;
19e1051a39Sopenharmony_citypedef unsigned int u32;
20e1051a39Sopenharmony_citypedef unsigned long u64;
21e1051a39Sopenharmony_citypedef uint128_t u128;
22e1051a39Sopenharmony_ci
23e1051a39Sopenharmony_citypedef struct {
24e1051a39Sopenharmony_ci    u64 h[3];
25e1051a39Sopenharmony_ci    u64 s[2];
26e1051a39Sopenharmony_ci    u64 r[3];
27e1051a39Sopenharmony_ci} poly1305_internal;
28e1051a39Sopenharmony_ci
29e1051a39Sopenharmony_ci#define POLY1305_BLOCK_SIZE 16
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci/* pick 64-bit unsigned integer in little endian order */
32e1051a39Sopenharmony_cistatic u64 U8TOU64(const unsigned char *p)
33e1051a39Sopenharmony_ci{
34e1051a39Sopenharmony_ci    return (((u64)(p[0] & 0xff)) |
35e1051a39Sopenharmony_ci            ((u64)(p[1] & 0xff) << 8) |
36e1051a39Sopenharmony_ci            ((u64)(p[2] & 0xff) << 16) |
37e1051a39Sopenharmony_ci            ((u64)(p[3] & 0xff) << 24) |
38e1051a39Sopenharmony_ci            ((u64)(p[4] & 0xff) << 32) |
39e1051a39Sopenharmony_ci            ((u64)(p[5] & 0xff) << 40) |
40e1051a39Sopenharmony_ci            ((u64)(p[6] & 0xff) << 48) |
41e1051a39Sopenharmony_ci            ((u64)(p[7] & 0xff) << 56));
42e1051a39Sopenharmony_ci}
43e1051a39Sopenharmony_ci
44e1051a39Sopenharmony_ci/* store a 64-bit unsigned integer in little endian */
45e1051a39Sopenharmony_cistatic void U64TO8(unsigned char *p, u64 v)
46e1051a39Sopenharmony_ci{
47e1051a39Sopenharmony_ci    p[0] = (unsigned char)((v) & 0xff);
48e1051a39Sopenharmony_ci    p[1] = (unsigned char)((v >> 8) & 0xff);
49e1051a39Sopenharmony_ci    p[2] = (unsigned char)((v >> 16) & 0xff);
50e1051a39Sopenharmony_ci    p[3] = (unsigned char)((v >> 24) & 0xff);
51e1051a39Sopenharmony_ci    p[4] = (unsigned char)((v >> 32) & 0xff);
52e1051a39Sopenharmony_ci    p[5] = (unsigned char)((v >> 40) & 0xff);
53e1051a39Sopenharmony_ci    p[6] = (unsigned char)((v >> 48) & 0xff);
54e1051a39Sopenharmony_ci    p[7] = (unsigned char)((v >> 56) & 0xff);
55e1051a39Sopenharmony_ci}
56e1051a39Sopenharmony_ci
57e1051a39Sopenharmony_ciint poly1305_init(void *ctx, const unsigned char key[16])
58e1051a39Sopenharmony_ci{
59e1051a39Sopenharmony_ci    poly1305_internal *st = (poly1305_internal *)ctx;
60e1051a39Sopenharmony_ci    u64 r0, r1;
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_ci    /* h = 0 */
63e1051a39Sopenharmony_ci    st->h[0] = 0;
64e1051a39Sopenharmony_ci    st->h[1] = 0;
65e1051a39Sopenharmony_ci    st->h[2] = 0;
66e1051a39Sopenharmony_ci
67e1051a39Sopenharmony_ci    r0 = U8TOU64(&key[0]) & 0x0ffffffc0fffffff;
68e1051a39Sopenharmony_ci    r1 = U8TOU64(&key[8]) & 0x0ffffffc0ffffffc;
69e1051a39Sopenharmony_ci
70e1051a39Sopenharmony_ci    /* break r1:r0 to three 44-bit digits, masks are 1<<44-1 */
71e1051a39Sopenharmony_ci    st->r[0] = r0 & 0x0fffffffffff;
72e1051a39Sopenharmony_ci    st->r[1] = ((r0 >> 44) | (r1 << 20))  & 0x0fffffffffff;
73e1051a39Sopenharmony_ci    st->r[2] = (r1 >> 24);
74e1051a39Sopenharmony_ci
75e1051a39Sopenharmony_ci    st->s[0] = (st->r[1] + (st->r[1] << 2)) << 2;
76e1051a39Sopenharmony_ci    st->s[1] = (st->r[2] + (st->r[2] << 2)) << 2;
77e1051a39Sopenharmony_ci
78e1051a39Sopenharmony_ci    return 0;
79e1051a39Sopenharmony_ci}
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_civoid poly1305_blocks(void *ctx, const unsigned char *inp, size_t len,
82e1051a39Sopenharmony_ci                     u32 padbit)
83e1051a39Sopenharmony_ci{
84e1051a39Sopenharmony_ci    poly1305_internal *st = (poly1305_internal *)ctx;
85e1051a39Sopenharmony_ci    u64 r0, r1, r2;
86e1051a39Sopenharmony_ci    u64 s1, s2;
87e1051a39Sopenharmony_ci    u64 h0, h1, h2, c;
88e1051a39Sopenharmony_ci    u128 d0, d1, d2;
89e1051a39Sopenharmony_ci    u64 pad = (u64)padbit << 40;
90e1051a39Sopenharmony_ci
91e1051a39Sopenharmony_ci    r0 = st->r[0];
92e1051a39Sopenharmony_ci    r1 = st->r[1];
93e1051a39Sopenharmony_ci    r2 = st->r[2];
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci    s1 = st->s[0];
96e1051a39Sopenharmony_ci    s2 = st->s[1];
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    h0 = st->h[0];
99e1051a39Sopenharmony_ci    h1 = st->h[1];
100e1051a39Sopenharmony_ci    h2 = st->h[2];
101e1051a39Sopenharmony_ci
102e1051a39Sopenharmony_ci    while (len >= POLY1305_BLOCK_SIZE) {
103e1051a39Sopenharmony_ci        u64 m0, m1;
104e1051a39Sopenharmony_ci
105e1051a39Sopenharmony_ci        m0 = U8TOU64(inp + 0);
106e1051a39Sopenharmony_ci        m1 = U8TOU64(inp + 8);
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_ci        /* h += m[i], m[i] is broken to 44-bit digits */
109e1051a39Sopenharmony_ci        h0 += m0 & 0x0fffffffffff;
110e1051a39Sopenharmony_ci        h1 += ((m0 >> 44) | (m1 << 20))  & 0x0fffffffffff;
111e1051a39Sopenharmony_ci        h2 +=  (m1 >> 24) + pad;
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_ci        /* h *= r "%" p, where "%" stands for "partial remainder" */
114e1051a39Sopenharmony_ci        d0 = ((u128)h0 * r0) + ((u128)h1 * s2) + ((u128)h2 * s1);
115e1051a39Sopenharmony_ci        d1 = ((u128)h0 * r1) + ((u128)h1 * r0) + ((u128)h2 * s2);
116e1051a39Sopenharmony_ci        d2 = ((u128)h0 * r2) + ((u128)h1 * r1) + ((u128)h2 * r0);
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ci        /* "lazy" reduction step */
119e1051a39Sopenharmony_ci        h0 = (u64)d0 & 0x0fffffffffff;
120e1051a39Sopenharmony_ci        h1 = (u64)(d1 += (u64)(d0 >> 44)) & 0x0fffffffffff;
121e1051a39Sopenharmony_ci        h2 = (u64)(d2 += (u64)(d1 >> 44)) & 0x03ffffffffff; /* last 42 bits */
122e1051a39Sopenharmony_ci
123e1051a39Sopenharmony_ci        c = (d2 >> 42);
124e1051a39Sopenharmony_ci        h0 += c + (c << 2);
125e1051a39Sopenharmony_ci
126e1051a39Sopenharmony_ci        inp += POLY1305_BLOCK_SIZE;
127e1051a39Sopenharmony_ci        len -= POLY1305_BLOCK_SIZE;
128e1051a39Sopenharmony_ci    }
129e1051a39Sopenharmony_ci
130e1051a39Sopenharmony_ci    st->h[0] = h0;
131e1051a39Sopenharmony_ci    st->h[1] = h1;
132e1051a39Sopenharmony_ci    st->h[2] = h2;
133e1051a39Sopenharmony_ci}
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_civoid poly1305_emit(void *ctx, unsigned char mac[16], const u32 nonce[4])
136e1051a39Sopenharmony_ci{
137e1051a39Sopenharmony_ci    poly1305_internal *st = (poly1305_internal *) ctx;
138e1051a39Sopenharmony_ci    u64 h0, h1, h2;
139e1051a39Sopenharmony_ci    u64 g0, g1, g2;
140e1051a39Sopenharmony_ci    u128 t;
141e1051a39Sopenharmony_ci    u64 mask;
142e1051a39Sopenharmony_ci
143e1051a39Sopenharmony_ci    h0 = st->h[0];
144e1051a39Sopenharmony_ci    h1 = st->h[1];
145e1051a39Sopenharmony_ci    h2 = st->h[2];
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ci    /* after "lazy" reduction, convert 44+bit digits to 64-bit ones */
148e1051a39Sopenharmony_ci    h0 = (u64)(t = (u128)h0 + (h1 << 44));              h1 >>= 20;
149e1051a39Sopenharmony_ci    h1 = (u64)(t = (u128)h1 + (h2 << 24) + (t >> 64));  h2 >>= 40;
150e1051a39Sopenharmony_ci    h2 += (u64)(t >> 64);
151e1051a39Sopenharmony_ci
152e1051a39Sopenharmony_ci    /* compare to modulus by computing h + -p */
153e1051a39Sopenharmony_ci    g0 = (u64)(t = (u128)h0 + 5);
154e1051a39Sopenharmony_ci    g1 = (u64)(t = (u128)h1 + (t >> 64));
155e1051a39Sopenharmony_ci    g2 = h2 + (u64)(t >> 64);
156e1051a39Sopenharmony_ci
157e1051a39Sopenharmony_ci    /* if there was carry into 131st bit, h1:h0 = g1:g0 */
158e1051a39Sopenharmony_ci    mask = 0 - (g2 >> 2);
159e1051a39Sopenharmony_ci    g0 &= mask;
160e1051a39Sopenharmony_ci    g1 &= mask;
161e1051a39Sopenharmony_ci    mask = ~mask;
162e1051a39Sopenharmony_ci    h0 = (h0 & mask) | g0;
163e1051a39Sopenharmony_ci    h1 = (h1 & mask) | g1;
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_ci    /* mac = (h + nonce) % (2^128) */
166e1051a39Sopenharmony_ci    h0 = (u64)(t = (u128)h0 + nonce[0] + ((u64)nonce[1]<<32));
167e1051a39Sopenharmony_ci    h1 = (u64)(t = (u128)h1 + nonce[2] + ((u64)nonce[3]<<32) + (t >> 64));
168e1051a39Sopenharmony_ci
169e1051a39Sopenharmony_ci    U64TO8(mac + 0, h0);
170e1051a39Sopenharmony_ci    U64TO8(mac + 8, h1);
171e1051a39Sopenharmony_ci}
172