f_generic.c 5.2 KB
Newer Older
1 2 3
/*
 * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2015-2016 Cryptography Research, Inc.
M
Matt Caswell 已提交
4
 *
5 6 7 8
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
M
Matt Caswell 已提交
9
 *
10
 * Originally written by Mike Hamburg
M
Matt Caswell 已提交
11 12 13
 */
#include "field.h"

14 15 16 17
static const gf MODULUS = {
    FIELD_LITERAL(0xffffffffffffff, 0xffffffffffffff, 0xffffffffffffff,
                  0xffffffffffffff, 0xfffffffffffffe, 0xffffffffffffff,
                  0xffffffffffffff, 0xffffffffffffff)
18
};
M
Matt Caswell 已提交
19

M
Matt Caswell 已提交
20
/* Serialize to wire format. */
21 22 23
void gf_serialize(uint8_t serial[SER_BYTES], const gf x, int with_hibit)
{
    unsigned int j = 0, fill = 0;
M
Matt Caswell 已提交
24 25
    dword_t buffer = 0;
    unsigned int i;
M
Matt Caswell 已提交
26
    gf red;
M
Matt Caswell 已提交
27

M
Matt Caswell 已提交
28 29
    gf_copy(red, x);
    gf_strong_reduce(red);
30
    if (!with_hibit)
31
        assert(gf_hibit(red) == 0);
M
Matt Caswell 已提交
32

33
    UNROLL for (i = 0; i < (with_hibit ? X_SER_BYTES : SER_BYTES); i++) {
M
Matt Caswell 已提交
34
        if (fill < 8 && j < NLIMBS) {
35
            buffer |= ((dword_t) red->limb[LIMBPERM(j)]) << fill;
M
Matt Caswell 已提交
36 37 38 39 40 41 42 43 44
            fill += LIMB_PLACE_VALUE(LIMBPERM(j));
            j++;
        }
        serial[i] = buffer;
        fill -= 8;
        buffer >>= 8;
    }
}

45
/* Return high bit of x = low bit of 2x mod p */
46 47
mask_t gf_hibit(const gf x)
{
M
Matt Caswell 已提交
48
    gf y;
49
    gf_add(y, x, x);
M
Matt Caswell 已提交
50
    gf_strong_reduce(y);
51
    return -(y->limb[0] & 1);
M
Matt Caswell 已提交
52 53
}

54
/* Return high bit of x = low bit of 2x mod p */
55 56
mask_t gf_lobit(const gf x)
{
M
Matt Caswell 已提交
57
    gf y;
58
    gf_copy(y, x);
M
Matt Caswell 已提交
59
    gf_strong_reduce(y);
60
    return -(y->limb[0] & 1);
M
Matt Caswell 已提交
61 62
}

63
/* Deserialize from wire format; return -1 on success and 0 on failure. */
64 65 66 67
mask_t gf_deserialize(gf x, const uint8_t serial[SER_BYTES], int with_hibit,
                      uint8_t hi_nmask)
{
    unsigned int j = 0, fill = 0;
M
Matt Caswell 已提交
68 69 70
    dword_t buffer = 0;
    dsword_t scarry = 0;
    const unsigned nbytes = with_hibit ? X_SER_BYTES : SER_BYTES;
M
Matt Caswell 已提交
71 72 73
    unsigned int i;
    mask_t succ;

74
    UNROLL for (i = 0; i < NLIMBS; i++) {
M
Matt Caswell 已提交
75 76
        UNROLL while (fill < LIMB_PLACE_VALUE(LIMBPERM(i)) && j < nbytes) {
            uint8_t sj = serial[j];
77 78 79
            if (j == nbytes - 1)
                sj &= ~hi_nmask;
            buffer |= ((dword_t) sj) << fill;
M
Matt Caswell 已提交
80 81 82
            fill += 8;
            j++;
        }
83 84
        x->limb[LIMBPERM(i)] =
            (i < NLIMBS - 1) ? buffer & LIMB_MASK(LIMBPERM(i)) : buffer;
M
Matt Caswell 已提交
85 86
        fill -= LIMB_PLACE_VALUE(LIMBPERM(i));
        buffer >>= LIMB_PLACE_VALUE(LIMBPERM(i));
87 88 89
        scarry =
            (scarry + x->limb[LIMBPERM(i)] -
             MODULUS->limb[LIMBPERM(i)]) >> (8 * sizeof(word_t));
M
Matt Caswell 已提交
90
    }
91
    succ = with_hibit ? -(mask_t) 1 : ~gf_hibit(x);
M
Matt Caswell 已提交
92 93 94
    return succ & word_is_zero(buffer) & ~word_is_zero(scarry);
}

95
/* Reduce to canonical form. */
96 97
void gf_strong_reduce(gf a)
{
M
Matt Caswell 已提交
98 99 100 101 102
    dsword_t scarry;
    word_t scarry_0;
    dword_t carry = 0;
    unsigned int i;

M
Matt Caswell 已提交
103
    /* first, clear high */
104
    gf_weak_reduce(a);          /* Determined to have negligible perf impact. */
M
Matt Caswell 已提交
105 106 107 108

    /* now the total is less than 2p */

    /* compute total_value - p.  No need to reduce mod p. */
M
Matt Caswell 已提交
109
    scarry = 0;
110
    for (i = 0; i < NLIMBS; i++) {
M
Matt Caswell 已提交
111 112 113 114 115
        scarry = scarry + a->limb[LIMBPERM(i)] - MODULUS->limb[LIMBPERM(i)];
        a->limb[LIMBPERM(i)] = scarry & LIMB_MASK(LIMBPERM(i));
        scarry >>= LIMB_PLACE_VALUE(LIMBPERM(i));
    }

116 117 118 119
    /*
     * uncommon case: it was >= p, so now scarry = 0 and this = x common case:
     * it was < p, so now scarry = -1 and this = x - p + 2^255 so let's add
     * back in p.  will carry back off the top for 2^255.
M
Matt Caswell 已提交
120
     */
121
    assert(word_is_zero(scarry) | word_is_zero(scarry + 1));
M
Matt Caswell 已提交
122

M
Matt Caswell 已提交
123
    scarry_0 = scarry;
M
Matt Caswell 已提交
124 125

    /* add it back */
126 127 128 129
    for (i = 0; i < NLIMBS; i++) {
        carry =
            carry + a->limb[LIMBPERM(i)] +
            (scarry_0 & MODULUS->limb[LIMBPERM(i)]);
M
Matt Caswell 已提交
130 131 132 133 134 135 136
        a->limb[LIMBPERM(i)] = carry & LIMB_MASK(LIMBPERM(i));
        carry >>= LIMB_PLACE_VALUE(LIMBPERM(i));
    }

    assert(word_is_zero(carry + scarry_0));
}

137
/* Subtract two gf elements d=a-b */
138 139 140 141 142
void gf_sub(gf d, const gf a, const gf b)
{
    gf_sub_RAW(d, a, b);
    gf_bias(d, 2);
    gf_weak_reduce(d);
M
Matt Caswell 已提交
143 144
}

145
/* Add two field elements d = a+b */
146 147 148 149
void gf_add(gf d, const gf a, const gf b)
{
    gf_add_RAW(d, a, b);
    gf_weak_reduce(d);
M
Matt Caswell 已提交
150 151
}

152
/* Compare a==b */
153 154
mask_t gf_eq(const gf a, const gf b)
{
M
Matt Caswell 已提交
155
    gf c;
156
    mask_t ret = 0;
M
Matt Caswell 已提交
157 158
    unsigned int i;

159
    gf_sub(c, a, b);
M
Matt Caswell 已提交
160
    gf_strong_reduce(c);
M
Matt Caswell 已提交
161

162
    for (i = 0; i < NLIMBS; i++) {
M
Matt Caswell 已提交
163 164 165 166 167
        ret |= c->limb[LIMBPERM(i)];
    }

    return word_is_zero(ret);
}
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200

mask_t gf_isr(gf a, const gf x)
{
    gf L0, L1, L2;
    gf_sqr(L1, x);
    gf_mul(L2, x, L1);
    gf_sqr(L1, L2);
    gf_mul(L2, x, L1);
    gf_sqrn(L1, L2, 3);
    gf_mul(L0, L2, L1);
    gf_sqrn(L1, L0, 3);
    gf_mul(L0, L2, L1);
    gf_sqrn(L2, L0, 9);
    gf_mul(L1, L0, L2);
    gf_sqr(L0, L1);
    gf_mul(L2, x, L0);
    gf_sqrn(L0, L2, 18);
    gf_mul(L2, L1, L0);
    gf_sqrn(L0, L2, 37);
    gf_mul(L1, L2, L0);
    gf_sqrn(L0, L1, 37);
    gf_mul(L1, L2, L0);
    gf_sqrn(L0, L1, 111);
    gf_mul(L2, L1, L0);
    gf_sqr(L0, L2);
    gf_mul(L1, x, L0);
    gf_sqrn(L0, L1, 223);
    gf_mul(L1, L2, L0);
    gf_sqr(L2, L1);
    gf_mul(L0, L2, x);
    gf_copy(a, L1);
    return gf_eq(L0, ONE);
}