/*
* Copyright 2017-2023 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2015-2016 Cryptography Research, Inc.
*
* Licensed under the Apache License 2.0 (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 "field.h"
#include "point_448.h"
#include "ed448.h"
#include "crypto/ecx.h"
#include "curve448_local.h"
#define COFACTOR 4
#define C448_WNAF_FIXED_TABLE_BITS 5
#define C448_WNAF_VAR_TABLE_BITS 3
#define EDWARDS_D (-39081)
static const curve448_scalar_t precomputed_scalarmul_adjustment = {
{
{
SC_LIMB(0xc873d6d54a7bb0cfULL), SC_LIMB(0xe933d8d723a70aadULL),
SC_LIMB(0xbb124b65129c96fdULL), SC_LIMB(0x00000008335dc163ULL)
}
}
};
#define TWISTED_D (EDWARDS_D - 1)
#define WBITS C448_WORD_BITS /* NB this may be different from ARCH_WORD_BITS */
/* Inverse. */
static void gf_invert(gf y, const gf x, int assert_nonzero)
{
mask_t ret;
gf t1, t2;
ossl_gf_sqr(t1, x); /* o^2 */
ret = gf_isr(t2, t1); /* +-1/sqrt(o^2) = +-1/o */
(void)ret;
if (assert_nonzero)
assert(ret);
ossl_gf_sqr(t1, t2);
ossl_gf_mul(t2, t1, x); /* not direct to y in case of alias. */
gf_copy(y, t2);
}
/** identity = (0,1) */
const curve448_point_t ossl_curve448_point_identity =
{ {{{{0}}}, {{{1}}}, {{{1}}}, {{{0}}}} };
static void point_double_internal(curve448_point_t p, const curve448_point_t q,
int before_double)
{
gf a, b, c, d;
ossl_gf_sqr(c, q->x);
ossl_gf_sqr(a, q->y);
gf_add_nr(d, c, a); /* 2+e */
gf_add_nr(p->t, q->y, q->x); /* 2+e */
ossl_gf_sqr(b, p->t);
gf_subx_nr(b, b, d, 3); /* 4+e */
gf_sub_nr(p->t, a, c); /* 3+e */
ossl_gf_sqr(p->x, q->z);
gf_add_nr(p->z, p->x, p->x); /* 2+e */
gf_subx_nr(a, p->z, p->t, 4); /* 6+e */
if (GF_HEADROOM == 5)
gf_weak_reduce(a); /* or 1+e */
ossl_gf_mul(p->x, a, b);
ossl_gf_mul(p->z, p->t, a);
ossl_gf_mul(p->y, p->t, d);
if (!before_double)
ossl_gf_mul(p->t, b, d);
}
void ossl_curve448_point_double(curve448_point_t p, const curve448_point_t q)
{
point_double_internal(p, q, 0);
}
/* Operations on [p]niels */
static ossl_inline void cond_neg_niels(niels_t n, mask_t neg)
{
gf_cond_swap(n->a, n->b, neg);
gf_cond_neg(n->c, neg);
}
static void pt_to_pniels(pniels_t b, const curve448_point_t a)
{
gf_sub(b->n->a, a->y, a->x);
gf_add(b->n->b, a->x, a->y);
gf_mulw(b->n->c, a->t, 2 * TWISTED_D);
gf_add(b->z, a->z, a->z);
}
static void pniels_to_pt(curve448_point_t e, const pniels_t d)
{
gf eu;
gf_add(eu, d->n->b, d->n->a);
gf_sub(e->y, d->n->b, d->n->a);
ossl_gf_mul(e->t, e->y, eu);
ossl_gf_mul(e->x, d->z, e->y);
ossl_gf_mul(e->y, d->z, eu);
ossl_gf_sqr(e->z, d->z);
}
static void niels_to_pt(curve448_point_t e, const niels_t n)
{
gf_add(e->y, n->b, n->a);
gf_sub(e->x, n->b, n->a);
ossl_gf_mul(e->t, e->y, e->x);
gf_copy(e->z, ONE);
}
static void add_niels_to_pt(curve448_point_t d, const niels_t e,
int before_double)
{
gf a, b, c;
gf_sub_nr(b, d->y, d->x); /* 3+e */
ossl_gf_mul(a, e->a, b);
gf_add_nr(b, d->x, d->y); /* 2+e */
ossl_gf_mul(d->y, e->b, b);
ossl_gf_mul(d->x, e->c, d->t);
gf_add_nr(c, a, d->y); /* 2+e */
gf_sub_nr(b, d->y, a); /* 3+e */
gf_sub_nr(d->y, d->z, d->x); /* 3+e */
gf_add_nr(a, d->x, d->z); /* 2+e */
ossl_gf_mul(d->z, a, d->y);
ossl_gf_mul(d->x, d->y, b);
ossl_gf_mul(d->y, a, c);
if (!before_double)
ossl_gf_mul(d->t, b, c);
}
static vo