2 * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright 2015-2016 Cryptography Research, Inc.
5 * Licensed under the OpenSSL license (the "License"). You may not use
6 * this file except in compliance with the License. You can obtain a copy
7 * in the file LICENSE in the source distribution or at
8 * https://www.openssl.org/source/license.html
10 * Originally written by Mike Hamburg
14 static const gf MODULUS =
15 { FIELD_LITERAL(0xffffffffffffff, 0xffffffffffffff, 0xffffffffffffff,
16 0xffffffffffffff, 0xfffffffffffffe, 0xffffffffffffff,
17 0xffffffffffffff, 0xffffffffffffff)
20 /** Serialize to wire format. */
21 void gf_serialize(uint8_t serial[SER_BYTES], const gf x, int with_hibit)
23 unsigned int j = 0, fill = 0;
29 gf_strong_reduce(red);
31 assert(gf_hibit(red) == 0);
34 UNROLL for (i = 0; i < (with_hibit ? X_SER_BYTES : SER_BYTES); i++) {
35 if (fill < 8 && j < NLIMBS) {
36 buffer |= ((dword_t) red->limb[LIMBPERM(j)]) << fill;
37 fill += LIMB_PLACE_VALUE(LIMBPERM(j));
46 /** Return high bit of x = low bit of 2x mod p */
47 mask_t gf_hibit(const gf x)
52 return -(y->limb[0] & 1);
55 /** Return high bit of x = low bit of 2x mod p */
56 mask_t gf_lobit(const gf x)
61 return -(y->limb[0] & 1);
64 /** Deserialize from wire format; return -1 on success and 0 on failure. */
65 mask_t gf_deserialize(gf x, const uint8_t serial[SER_BYTES], int with_hibit,
68 unsigned int j = 0, fill = 0;
71 const unsigned nbytes = with_hibit ? X_SER_BYTES : SER_BYTES;
75 UNROLL for (i = 0; i < NLIMBS; i++) {
76 UNROLL while (fill < LIMB_PLACE_VALUE(LIMBPERM(i)) && j < nbytes) {
77 uint8_t sj = serial[j];
80 buffer |= ((dword_t) sj) << fill;
84 x->limb[LIMBPERM(i)] =
85 (i < NLIMBS - 1) ? buffer & LIMB_MASK(LIMBPERM(i)) : buffer;
86 fill -= LIMB_PLACE_VALUE(LIMBPERM(i));
87 buffer >>= LIMB_PLACE_VALUE(LIMBPERM(i));
89 (scarry + x->limb[LIMBPERM(i)] -
90 MODULUS->limb[LIMBPERM(i)]) >> (8 * sizeof(word_t));
92 succ = with_hibit ? -(mask_t) 1 : ~gf_hibit(x);
93 return succ & word_is_zero(buffer) & ~word_is_zero(scarry);
96 /** Reduce to canonical form. */
97 void gf_strong_reduce(gf a)
104 /* first, clear high */
105 gf_weak_reduce(a); /* Determined to have negligible perf impact. */
107 /* now the total is less than 2p */
109 /* compute total_value - p. No need to reduce mod p. */
111 for (i = 0; i < NLIMBS; i++) {
112 scarry = scarry + a->limb[LIMBPERM(i)] - MODULUS->limb[LIMBPERM(i)];
113 a->limb[LIMBPERM(i)] = scarry & LIMB_MASK(LIMBPERM(i));
114 scarry >>= LIMB_PLACE_VALUE(LIMBPERM(i));
118 * uncommon case: it was >= p, so now scarry = 0 and this = x common case:
119 * it was < p, so now scarry = -1 and this = x - p + 2^255 so let's add
120 * back in p. will carry back off the top for 2^255.
122 assert(word_is_zero(scarry) | word_is_zero(scarry + 1));
127 for (i = 0; i < NLIMBS; i++) {
129 carry + a->limb[LIMBPERM(i)] +
130 (scarry_0 & MODULUS->limb[LIMBPERM(i)]);
131 a->limb[LIMBPERM(i)] = carry & LIMB_MASK(LIMBPERM(i));
132 carry >>= LIMB_PLACE_VALUE(LIMBPERM(i));
135 assert(word_is_zero(carry + scarry_0));
138 /** Subtract two gf elements d=a-b */
139 void gf_sub(gf d, const gf a, const gf b)
146 /** Add two field elements d = a+b */
147 void gf_add(gf d, const gf a, const gf b)
154 mask_t gf_eq(const gf a, const gf b)
163 for (i = 0; i < NLIMBS; i++) {
164 ret |= c->limb[LIMBPERM(i)];
167 return word_is_zero(ret);