scalar.c 6.9 KB
Newer Older
C
code4lala 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
/*
 * Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2015-2016 Cryptography Research, Inc.
 *
 * 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
 *
 * Originally written by Mike Hamburg
 */
#include <openssl/crypto.h>

#include "word.h"
#include "point_448.h"

static const c448_word_t MONTGOMERY_FACTOR = (c448_word_t) 0x3bd440fae918bc5ULL;
static const curve448_scalar_t sc_p = {
    {
        {
            SC_LIMB(0x2378c292ab5844f3ULL), SC_LIMB(0x216cc2728dc58f55ULL),
            SC_LIMB(0xc44edb49aed63690ULL), SC_LIMB(0xffffffff7cca23e9ULL),
            SC_LIMB(0xffffffffffffffffULL), SC_LIMB(0xffffffffffffffffULL),
            SC_LIMB(0x3fffffffffffffffULL)
        }
    }
}, sc_r2 = {
    {
        {

            SC_LIMB(0xe3539257049b9b60ULL), SC_LIMB(0x7af32c4bc1b195d9ULL),
            SC_LIMB(0x0d66de2388ea1859ULL), SC_LIMB(0xae17cf725ee4d838ULL),
            SC_LIMB(0x1a9cc14ba3c47c44ULL), SC_LIMB(0x2052bcb7e4d070afULL),
            SC_LIMB(0x3402a939f823b729ULL)
        }
    }
};

#define WBITS C448_WORD_BITS   /* NB this may be different from ARCH_WORD_BITS */

const curve448_scalar_t curve448_scalar_one = {{{1}}};
const curve448_scalar_t curve448_scalar_zero = {{{0}}};

/*
 * {extra,accum} - sub +? p
 * Must have extra <= 1
 */
static void sc_subx(curve448_scalar_t out,
                    const c448_word_t accum[C448_SCALAR_LIMBS],
                    const curve448_scalar_t sub,
                    const curve448_scalar_t p, c448_word_t extra)
{
    c448_dsword_t chain = 0;
    unsigned int i;
    c448_word_t borrow;

    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        chain = (chain + accum[i]) - sub->limb[i];
        out->limb[i] = (c448_word_t)chain;
        chain >>= WBITS;
    }
    borrow = (c448_word_t)chain + extra;     /* = 0 or -1 */

    chain = 0;
    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        chain = (chain + out->limb[i]) + (p->limb[i] & borrow);
        out->limb[i] = (c448_word_t)chain;
        chain >>= WBITS;
    }
}

static void sc_montmul(curve448_scalar_t out, const curve448_scalar_t a,
                       const curve448_scalar_t b)
{
    unsigned int i, j;
    c448_word_t accum[C448_SCALAR_LIMBS + 1] = { 0 };
    c448_word_t hi_carry = 0;

    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        c448_word_t mand = a->limb[i];
        const c448_word_t *mier = b->limb;

        c448_dword_t chain = 0;
        for (j = 0; j < C448_SCALAR_LIMBS; j++) {
            chain += ((c448_dword_t) mand) * mier[j] + accum[j];
            accum[j] = (c448_word_t)chain;
            chain >>= WBITS;
        }
        accum[j] = (c448_word_t)chain;

        mand = accum[0] * MONTGOMERY_FACTOR;
        chain = 0;
        mier = sc_p->limb;
        for (j = 0; j < C448_SCALAR_LIMBS; j++) {
            chain += (c448_dword_t) mand *mier[j] + accum[j];
            if (j)
                accum[j - 1] = (c448_word_t)chain;
            chain >>= WBITS;
        }
        chain += accum[j];
        chain += hi_carry;
        accum[j - 1] = (c448_word_t)chain;
        hi_carry = chain >> WBITS;
    }

    sc_subx(out, accum, sc_p, sc_p, hi_carry);
}

void curve448_scalar_mul(curve448_scalar_t out, const curve448_scalar_t a,
                         const curve448_scalar_t b)
{
    sc_montmul(out, a, b);
    sc_montmul(out, out, sc_r2);
}

void curve448_scalar_sub(curve448_scalar_t out, const curve448_scalar_t a,
                         const curve448_scalar_t b)
{
    sc_subx(out, a->limb, b, sc_p, 0);
}

void curve448_scalar_add(curve448_scalar_t out, const curve448_scalar_t a,
                         const curve448_scalar_t b)
{
    c448_dword_t chain = 0;
    unsigned int i;

    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        chain = (chain + a->limb[i]) + b->limb[i];
        out->limb[i] = (c448_word_t)chain;
        chain >>= WBITS;
    }
    sc_subx(out, out->limb, sc_p, sc_p, (c448_word_t)chain);
}

static ossl_inline void scalar_decode_short(curve448_scalar_t s,
                                            const unsigned char *ser,
                                            size_t nbytes)
{
    size_t i, j, k = 0;

    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        c448_word_t out = 0;

        for (j = 0; j < sizeof(c448_word_t) && k < nbytes; j++, k++)
            out |= ((c448_word_t) ser[k]) << (8 * j);
        s->limb[i] = out;
    }
}

c448_error_t curve448_scalar_decode(
                                curve448_scalar_t s,
                                const unsigned char ser[C448_SCALAR_BYTES])
{
    unsigned int i;
    c448_dsword_t accum = 0;

    scalar_decode_short(s, ser, C448_SCALAR_BYTES);
    for (i = 0; i < C448_SCALAR_LIMBS; i++)
        accum = (accum + s->limb[i] - sc_p->limb[i]) >> WBITS;
    /* Here accum == 0 or -1 */

    curve448_scalar_mul(s, s, curve448_scalar_one); /* ham-handed reduce */

    return c448_succeed_if(~word_is_zero((uint32_t)accum));
}

void curve448_scalar_destroy(curve448_scalar_t scalar)
{
    OPENSSL_cleanse(scalar, sizeof(curve448_scalar_t));
}

void curve448_scalar_decode_long(curve448_scalar_t s,
                                 const unsigned char *ser, size_t ser_len)
{
    size_t i;
    curve448_scalar_t t1, t2;

    if (ser_len == 0) {
        curve448_scalar_copy(s, curve448_scalar_zero);
        return;
    }

    i = ser_len - (ser_len % C448_SCALAR_BYTES);
    if (i == ser_len)
        i -= C448_SCALAR_BYTES;

    scalar_decode_short(t1, &ser[i], ser_len - i);

    if (ser_len == sizeof(curve448_scalar_t)) {
        assert(i == 0);
        /* ham-handed reduce */
        curve448_scalar_mul(s, t1, curve448_scalar_one);
        curve448_scalar_destroy(t1);
        return;
    }

    while (i) {
        i -= C448_SCALAR_BYTES;
        sc_montmul(t1, t1, sc_r2);
        (void)curve448_scalar_decode(t2, ser + i);
        curve448_scalar_add(t1, t1, t2);
    }

    curve448_scalar_copy(s, t1);
    curve448_scalar_destroy(t1);
    curve448_scalar_destroy(t2);
}

void curve448_scalar_encode(unsigned char ser[C448_SCALAR_BYTES],
                            const curve448_scalar_t s)
{
    unsigned int i, j, k = 0;

    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        for (j = 0; j < sizeof(c448_word_t); j++, k++)
            ser[k] = s->limb[i] >> (8 * j);
    }
}

void curve448_scalar_halve(curve448_scalar_t out, const curve448_scalar_t a)
{
    c448_word_t mask = 0 - (a->limb[0] & 1);
    c448_dword_t chain = 0;
    unsigned int i;

    for (i = 0; i < C448_SCALAR_LIMBS; i++) {
        chain = (chain + a->limb[i]) + (sc_p->limb[i] & mask);
        out->limb[i] = (c448_word_t)chain;
        chain >>= C448_WORD_BITS;
    }
    for (i = 0; i < C448_SCALAR_LIMBS - 1; i++)
        out->limb[i] = out->limb[i] >> 1 | out->limb[i + 1] << (WBITS - 1);
    out->limb[i] = out->limb[i] >> 1 | (c448_word_t)(chain << (WBITS - 1));
}