1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright 2015-2016 Cryptography Research, Inc. 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci * 10e1051a39Sopenharmony_ci * Originally written by Mike Hamburg 11e1051a39Sopenharmony_ci */ 12e1051a39Sopenharmony_ci#include "field.h" 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_cistatic const gf MODULUS = { 15e1051a39Sopenharmony_ci FIELD_LITERAL(0xffffffffffffffULL, 0xffffffffffffffULL, 0xffffffffffffffULL, 16e1051a39Sopenharmony_ci 0xffffffffffffffULL, 0xfffffffffffffeULL, 0xffffffffffffffULL, 17e1051a39Sopenharmony_ci 0xffffffffffffffULL, 0xffffffffffffffULL) 18e1051a39Sopenharmony_ci}; 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_ci/* Serialize to wire format. */ 21e1051a39Sopenharmony_civoid gf_serialize(uint8_t *serial, const gf x, int with_hibit) 22e1051a39Sopenharmony_ci{ 23e1051a39Sopenharmony_ci unsigned int j = 0, fill = 0; 24e1051a39Sopenharmony_ci dword_t buffer = 0; 25e1051a39Sopenharmony_ci int i; 26e1051a39Sopenharmony_ci gf red; 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci gf_copy(red, x); 29e1051a39Sopenharmony_ci gf_strong_reduce(red); 30e1051a39Sopenharmony_ci if (!with_hibit) 31e1051a39Sopenharmony_ci assert(gf_hibit(red) == 0); 32e1051a39Sopenharmony_ci 33e1051a39Sopenharmony_ci for (i = 0; i < (with_hibit ? X_SER_BYTES : SER_BYTES); i++) { 34e1051a39Sopenharmony_ci if (fill < 8 && j < NLIMBS) { 35e1051a39Sopenharmony_ci buffer |= ((dword_t) red->limb[LIMBPERM(j)]) << fill; 36e1051a39Sopenharmony_ci fill += LIMB_PLACE_VALUE(LIMBPERM(j)); 37e1051a39Sopenharmony_ci j++; 38e1051a39Sopenharmony_ci } 39e1051a39Sopenharmony_ci serial[i] = (uint8_t)buffer; 40e1051a39Sopenharmony_ci fill -= 8; 41e1051a39Sopenharmony_ci buffer >>= 8; 42e1051a39Sopenharmony_ci } 43e1051a39Sopenharmony_ci} 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_ci/* Return high bit of x = low bit of 2x mod p */ 46e1051a39Sopenharmony_cimask_t gf_hibit(const gf x) 47e1051a39Sopenharmony_ci{ 48e1051a39Sopenharmony_ci gf y; 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_ci gf_add(y, x, x); 51e1051a39Sopenharmony_ci gf_strong_reduce(y); 52e1051a39Sopenharmony_ci return 0 - (y->limb[0] & 1); 53e1051a39Sopenharmony_ci} 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_ci/* Return high bit of x = low bit of 2x mod p */ 56e1051a39Sopenharmony_cimask_t gf_lobit(const gf x) 57e1051a39Sopenharmony_ci{ 58e1051a39Sopenharmony_ci gf y; 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_ci gf_copy(y, x); 61e1051a39Sopenharmony_ci gf_strong_reduce(y); 62e1051a39Sopenharmony_ci return 0 - (y->limb[0] & 1); 63e1051a39Sopenharmony_ci} 64e1051a39Sopenharmony_ci 65e1051a39Sopenharmony_ci/* Deserialize from wire format; return -1 on success and 0 on failure. */ 66e1051a39Sopenharmony_cimask_t gf_deserialize(gf x, const uint8_t serial[SER_BYTES], int with_hibit, 67e1051a39Sopenharmony_ci uint8_t hi_nmask) 68e1051a39Sopenharmony_ci{ 69e1051a39Sopenharmony_ci unsigned int j = 0, fill = 0; 70e1051a39Sopenharmony_ci dword_t buffer = 0; 71e1051a39Sopenharmony_ci dsword_t scarry = 0; 72e1051a39Sopenharmony_ci const unsigned nbytes = with_hibit ? X_SER_BYTES : SER_BYTES; 73e1051a39Sopenharmony_ci unsigned int i; 74e1051a39Sopenharmony_ci mask_t succ; 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ci for (i = 0; i < NLIMBS; i++) { 77e1051a39Sopenharmony_ci while (fill < LIMB_PLACE_VALUE(LIMBPERM(i)) && j < nbytes) { 78e1051a39Sopenharmony_ci uint8_t sj; 79e1051a39Sopenharmony_ci 80e1051a39Sopenharmony_ci sj = serial[j]; 81e1051a39Sopenharmony_ci if (j == nbytes - 1) 82e1051a39Sopenharmony_ci sj &= ~hi_nmask; 83e1051a39Sopenharmony_ci buffer |= ((dword_t) sj) << fill; 84e1051a39Sopenharmony_ci fill += 8; 85e1051a39Sopenharmony_ci j++; 86e1051a39Sopenharmony_ci } 87e1051a39Sopenharmony_ci x->limb[LIMBPERM(i)] = (word_t) 88e1051a39Sopenharmony_ci ((i < NLIMBS - 1) ? buffer & LIMB_MASK(LIMBPERM(i)) : buffer); 89e1051a39Sopenharmony_ci fill -= LIMB_PLACE_VALUE(LIMBPERM(i)); 90e1051a39Sopenharmony_ci buffer >>= LIMB_PLACE_VALUE(LIMBPERM(i)); 91e1051a39Sopenharmony_ci scarry = 92e1051a39Sopenharmony_ci (scarry + x->limb[LIMBPERM(i)] - 93e1051a39Sopenharmony_ci MODULUS->limb[LIMBPERM(i)]) >> (8 * sizeof(word_t)); 94e1051a39Sopenharmony_ci } 95e1051a39Sopenharmony_ci succ = with_hibit ? 0 - (mask_t) 1 : ~gf_hibit(x); 96e1051a39Sopenharmony_ci return succ & word_is_zero((word_t)buffer) & ~word_is_zero((word_t)scarry); 97e1051a39Sopenharmony_ci} 98e1051a39Sopenharmony_ci 99e1051a39Sopenharmony_ci/* Reduce to canonical form. */ 100e1051a39Sopenharmony_civoid gf_strong_reduce(gf a) 101e1051a39Sopenharmony_ci{ 102e1051a39Sopenharmony_ci dsword_t scarry; 103e1051a39Sopenharmony_ci word_t scarry_0; 104e1051a39Sopenharmony_ci dword_t carry = 0; 105e1051a39Sopenharmony_ci unsigned int i; 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_ci /* first, clear high */ 108e1051a39Sopenharmony_ci gf_weak_reduce(a); /* Determined to have negligible perf impact. */ 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_ci /* now the total is less than 2p */ 111e1051a39Sopenharmony_ci 112e1051a39Sopenharmony_ci /* compute total_value - p. No need to reduce mod p. */ 113e1051a39Sopenharmony_ci scarry = 0; 114e1051a39Sopenharmony_ci for (i = 0; i < NLIMBS; i++) { 115e1051a39Sopenharmony_ci scarry = scarry + a->limb[LIMBPERM(i)] - MODULUS->limb[LIMBPERM(i)]; 116e1051a39Sopenharmony_ci a->limb[LIMBPERM(i)] = scarry & LIMB_MASK(LIMBPERM(i)); 117e1051a39Sopenharmony_ci scarry >>= LIMB_PLACE_VALUE(LIMBPERM(i)); 118e1051a39Sopenharmony_ci } 119e1051a39Sopenharmony_ci 120e1051a39Sopenharmony_ci /* 121e1051a39Sopenharmony_ci * uncommon case: it was >= p, so now scarry = 0 and this = x common case: 122e1051a39Sopenharmony_ci * it was < p, so now scarry = -1 and this = x - p + 2^255 so let's add 123e1051a39Sopenharmony_ci * back in p. will carry back off the top for 2^255. 124e1051a39Sopenharmony_ci */ 125e1051a39Sopenharmony_ci assert(scarry == 0 || scarry == -1); 126e1051a39Sopenharmony_ci 127e1051a39Sopenharmony_ci scarry_0 = (word_t)scarry; 128e1051a39Sopenharmony_ci 129e1051a39Sopenharmony_ci /* add it back */ 130e1051a39Sopenharmony_ci for (i = 0; i < NLIMBS; i++) { 131e1051a39Sopenharmony_ci carry = 132e1051a39Sopenharmony_ci carry + a->limb[LIMBPERM(i)] + 133e1051a39Sopenharmony_ci (scarry_0 & MODULUS->limb[LIMBPERM(i)]); 134e1051a39Sopenharmony_ci a->limb[LIMBPERM(i)] = carry & LIMB_MASK(LIMBPERM(i)); 135e1051a39Sopenharmony_ci carry >>= LIMB_PLACE_VALUE(LIMBPERM(i)); 136e1051a39Sopenharmony_ci } 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci assert(carry < 2 && ((word_t)carry + scarry_0) == 0); 139e1051a39Sopenharmony_ci} 140e1051a39Sopenharmony_ci 141e1051a39Sopenharmony_ci/* Subtract two gf elements d=a-b */ 142e1051a39Sopenharmony_civoid gf_sub(gf d, const gf a, const gf b) 143e1051a39Sopenharmony_ci{ 144e1051a39Sopenharmony_ci gf_sub_RAW(d, a, b); 145e1051a39Sopenharmony_ci gf_bias(d, 2); 146e1051a39Sopenharmony_ci gf_weak_reduce(d); 147e1051a39Sopenharmony_ci} 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci/* Add two field elements d = a+b */ 150e1051a39Sopenharmony_civoid gf_add(gf d, const gf a, const gf b) 151e1051a39Sopenharmony_ci{ 152e1051a39Sopenharmony_ci gf_add_RAW(d, a, b); 153e1051a39Sopenharmony_ci gf_weak_reduce(d); 154e1051a39Sopenharmony_ci} 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_ci/* Compare a==b */ 157e1051a39Sopenharmony_cimask_t gf_eq(const gf a, const gf b) 158e1051a39Sopenharmony_ci{ 159e1051a39Sopenharmony_ci gf c; 160e1051a39Sopenharmony_ci mask_t ret = 0; 161e1051a39Sopenharmony_ci unsigned int i; 162e1051a39Sopenharmony_ci 163e1051a39Sopenharmony_ci gf_sub(c, a, b); 164e1051a39Sopenharmony_ci gf_strong_reduce(c); 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_ci for (i = 0; i < NLIMBS; i++) 167e1051a39Sopenharmony_ci ret |= c->limb[LIMBPERM(i)]; 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci return word_is_zero(ret); 170e1051a39Sopenharmony_ci} 171e1051a39Sopenharmony_ci 172e1051a39Sopenharmony_cimask_t gf_isr(gf a, const gf x) 173e1051a39Sopenharmony_ci{ 174e1051a39Sopenharmony_ci gf L0, L1, L2; 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_ci gf_sqr(L1, x); 177e1051a39Sopenharmony_ci gf_mul(L2, x, L1); 178e1051a39Sopenharmony_ci gf_sqr(L1, L2); 179e1051a39Sopenharmony_ci gf_mul(L2, x, L1); 180e1051a39Sopenharmony_ci gf_sqrn(L1, L2, 3); 181e1051a39Sopenharmony_ci gf_mul(L0, L2, L1); 182e1051a39Sopenharmony_ci gf_sqrn(L1, L0, 3); 183e1051a39Sopenharmony_ci gf_mul(L0, L2, L1); 184e1051a39Sopenharmony_ci gf_sqrn(L2, L0, 9); 185e1051a39Sopenharmony_ci gf_mul(L1, L0, L2); 186e1051a39Sopenharmony_ci gf_sqr(L0, L1); 187e1051a39Sopenharmony_ci gf_mul(L2, x, L0); 188e1051a39Sopenharmony_ci gf_sqrn(L0, L2, 18); 189e1051a39Sopenharmony_ci gf_mul(L2, L1, L0); 190e1051a39Sopenharmony_ci gf_sqrn(L0, L2, 37); 191e1051a39Sopenharmony_ci gf_mul(L1, L2, L0); 192e1051a39Sopenharmony_ci gf_sqrn(L0, L1, 37); 193e1051a39Sopenharmony_ci gf_mul(L1, L2, L0); 194e1051a39Sopenharmony_ci gf_sqrn(L0, L1, 111); 195e1051a39Sopenharmony_ci gf_mul(L2, L1, L0); 196e1051a39Sopenharmony_ci gf_sqr(L0, L2); 197e1051a39Sopenharmony_ci gf_mul(L1, x, L0); 198e1051a39Sopenharmony_ci gf_sqrn(L0, L1, 223); 199e1051a39Sopenharmony_ci gf_mul(L1, L2, L0); 200e1051a39Sopenharmony_ci gf_sqr(L2, L1); 201e1051a39Sopenharmony_ci gf_mul(L0, L2, x); 202e1051a39Sopenharmony_ci gf_copy(a, L1); 203e1051a39Sopenharmony_ci return gf_eq(L0, ONE); 204e1051a39Sopenharmony_ci} 205