blob: dbe99ed439ad7ce8cb3f74f64b828b272782d483 [file] [log] [blame]
Robert Sloanab8b8882018-03-26 11:39:51 -07001/*
2 * Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright (c) 2014, Intel Corporation. All Rights Reserved.
Adam Langleyfad63272015-11-12 12:15:39 -08004 *
Robert Sloanab8b8882018-03-26 11:39:51 -07005 * 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
Adam Langleyfad63272015-11-12 12:15:39 -08009 *
Robert Sloanab8b8882018-03-26 11:39:51 -070010 * Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
11 * (1) Intel Corporation, Israel Development Center, Haifa, Israel
12 * (2) University of Haifa, Israel
13 *
14 * Reference:
15 * S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with
16 * 256 Bit Primes"
17 */
Adam Langleyfad63272015-11-12 12:15:39 -080018
19#include <openssl/ec.h>
20
Adam Langley4139edb2016-01-13 15:00:54 -080021#include <assert.h>
Adam Langleyfad63272015-11-12 12:15:39 -080022#include <stdint.h>
23#include <string.h>
24
25#include <openssl/bn.h>
26#include <openssl/crypto.h>
27#include <openssl/err.h>
28
29#include "../bn/internal.h"
Robert Sloan8ff03552017-06-14 12:40:58 -070030#include "../delocate.h"
31#include "../../internal.h"
Steven Valdez909b19f2016-11-21 15:35:44 -050032#include "internal.h"
33#include "p256-x86_64.h"
Adam Langleyfad63272015-11-12 12:15:39 -080034
35
36#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
37 !defined(OPENSSL_SMALL)
38
Adam Langleyfad63272015-11-12 12:15:39 -080039typedef P256_POINT_AFFINE PRECOMP256_ROW[64];
40
Robert Sloan8f860b12017-08-28 07:37:06 -070041// One converted into the Montgomery domain
Adam Langleyfad63272015-11-12 12:15:39 -080042static const BN_ULONG ONE[P256_LIMBS] = {
43 TOBN(0x00000000, 0x00000001), TOBN(0xffffffff, 0x00000000),
44 TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0xfffffffe),
45};
46
Robert Sloan8f860b12017-08-28 07:37:06 -070047// Precomputed tables for the default generator
Adam Langleyfad63272015-11-12 12:15:39 -080048#include "p256-x86_64-table.h"
49
Robert Sloan8f860b12017-08-28 07:37:06 -070050// Recode window to a signed digit, see util-64.c for details
Adam Langleyfad63272015-11-12 12:15:39 -080051static unsigned booth_recode_w5(unsigned in) {
52 unsigned s, d;
53
54 s = ~((in >> 5) - 1);
55 d = (1 << 6) - in - 1;
56 d = (d & s) | (in & ~s);
57 d = (d >> 1) + (d & 1);
58
59 return (d << 1) + (s & 1);
60}
61
62static unsigned booth_recode_w7(unsigned in) {
63 unsigned s, d;
64
65 s = ~((in >> 7) - 1);
66 d = (1 << 8) - in - 1;
67 d = (d & s) | (in & ~s);
68 d = (d >> 1) + (d & 1);
69
70 return (d << 1) + (s & 1);
71}
72
Robert Sloan8f860b12017-08-28 07:37:06 -070073// copy_conditional copies |src| to |dst| if |move| is one and leaves it as-is
74// if |move| is zero.
75//
76// WARNING: this breaks the usual convention of constant-time functions
77// returning masks.
Adam Langleyfad63272015-11-12 12:15:39 -080078static void copy_conditional(BN_ULONG dst[P256_LIMBS],
79 const BN_ULONG src[P256_LIMBS], BN_ULONG move) {
80 BN_ULONG mask1 = ((BN_ULONG)0) - move;
81 BN_ULONG mask2 = ~mask1;
82
83 dst[0] = (src[0] & mask1) ^ (dst[0] & mask2);
84 dst[1] = (src[1] & mask1) ^ (dst[1] & mask2);
85 dst[2] = (src[2] & mask1) ^ (dst[2] & mask2);
86 dst[3] = (src[3] & mask1) ^ (dst[3] & mask2);
87 if (P256_LIMBS == 8) {
88 dst[4] = (src[4] & mask1) ^ (dst[4] & mask2);
89 dst[5] = (src[5] & mask1) ^ (dst[5] & mask2);
90 dst[6] = (src[6] & mask1) ^ (dst[6] & mask2);
91 dst[7] = (src[7] & mask1) ^ (dst[7] & mask2);
92 }
93}
94
Robert Sloan8f860b12017-08-28 07:37:06 -070095// is_not_zero returns one iff in != 0 and zero otherwise.
96//
97// WARNING: this breaks the usual convention of constant-time functions
98// returning masks.
99//
100// (define-fun is_not_zero ((in (_ BitVec 64))) (_ BitVec 64)
101// (bvlshr (bvor in (bvsub #x0000000000000000 in)) #x000000000000003f)
102// )
103//
104// (declare-fun x () (_ BitVec 64))
105//
106// (assert (and (= x #x0000000000000000) (= (is_not_zero x) #x0000000000000001)))
107// (check-sat)
108//
109// (assert (and (not (= x #x0000000000000000)) (= (is_not_zero x) #x0000000000000000)))
110// (check-sat)
111//
Steven Valdez909b19f2016-11-21 15:35:44 -0500112static BN_ULONG is_not_zero(BN_ULONG in) {
113 in |= (0 - in);
114 in >>= BN_BITS2 - 1;
115 return in;
116}
Adam Langleyfad63272015-11-12 12:15:39 -0800117
Robert Sloan8f860b12017-08-28 07:37:06 -0700118// ecp_nistz256_mod_inverse_mont sets |r| to (|in| * 2^-256)^-1 * 2^256 mod p.
119// That is, |r| is the modular inverse of |in| for input and output in the
120// Montgomery domain.
Steven Valdez909b19f2016-11-21 15:35:44 -0500121static void ecp_nistz256_mod_inverse_mont(BN_ULONG r[P256_LIMBS],
122 const BN_ULONG in[P256_LIMBS]) {
Adam Langleyfad63272015-11-12 12:15:39 -0800123 /* The poly is ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff
124 ffffffff
125 We use FLT and used poly-2 as exponent */
126 BN_ULONG p2[P256_LIMBS];
127 BN_ULONG p4[P256_LIMBS];
128 BN_ULONG p8[P256_LIMBS];
129 BN_ULONG p16[P256_LIMBS];
130 BN_ULONG p32[P256_LIMBS];
131 BN_ULONG res[P256_LIMBS];
132 int i;
133
134 ecp_nistz256_sqr_mont(res, in);
Robert Sloan8f860b12017-08-28 07:37:06 -0700135 ecp_nistz256_mul_mont(p2, res, in); // 3*p
Adam Langleyfad63272015-11-12 12:15:39 -0800136
137 ecp_nistz256_sqr_mont(res, p2);
138 ecp_nistz256_sqr_mont(res, res);
Robert Sloan8f860b12017-08-28 07:37:06 -0700139 ecp_nistz256_mul_mont(p4, res, p2); // f*p
Adam Langleyfad63272015-11-12 12:15:39 -0800140
141 ecp_nistz256_sqr_mont(res, p4);
142 ecp_nistz256_sqr_mont(res, res);
143 ecp_nistz256_sqr_mont(res, res);
144 ecp_nistz256_sqr_mont(res, res);
Robert Sloan8f860b12017-08-28 07:37:06 -0700145 ecp_nistz256_mul_mont(p8, res, p4); // ff*p
Adam Langleyfad63272015-11-12 12:15:39 -0800146
147 ecp_nistz256_sqr_mont(res, p8);
148 for (i = 0; i < 7; i++) {
149 ecp_nistz256_sqr_mont(res, res);
150 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700151 ecp_nistz256_mul_mont(p16, res, p8); // ffff*p
Adam Langleyfad63272015-11-12 12:15:39 -0800152
153 ecp_nistz256_sqr_mont(res, p16);
154 for (i = 0; i < 15; i++) {
155 ecp_nistz256_sqr_mont(res, res);
156 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700157 ecp_nistz256_mul_mont(p32, res, p16); // ffffffff*p
Adam Langleyfad63272015-11-12 12:15:39 -0800158
159 ecp_nistz256_sqr_mont(res, p32);
160 for (i = 0; i < 31; i++) {
161 ecp_nistz256_sqr_mont(res, res);
162 }
163 ecp_nistz256_mul_mont(res, res, in);
164
165 for (i = 0; i < 32 * 4; i++) {
166 ecp_nistz256_sqr_mont(res, res);
167 }
168 ecp_nistz256_mul_mont(res, res, p32);
169
170 for (i = 0; i < 32; i++) {
171 ecp_nistz256_sqr_mont(res, res);
172 }
173 ecp_nistz256_mul_mont(res, res, p32);
174
175 for (i = 0; i < 16; i++) {
176 ecp_nistz256_sqr_mont(res, res);
177 }
178 ecp_nistz256_mul_mont(res, res, p16);
179
180 for (i = 0; i < 8; i++) {
181 ecp_nistz256_sqr_mont(res, res);
182 }
183 ecp_nistz256_mul_mont(res, res, p8);
184
185 ecp_nistz256_sqr_mont(res, res);
186 ecp_nistz256_sqr_mont(res, res);
187 ecp_nistz256_sqr_mont(res, res);
188 ecp_nistz256_sqr_mont(res, res);
189 ecp_nistz256_mul_mont(res, res, p4);
190
191 ecp_nistz256_sqr_mont(res, res);
192 ecp_nistz256_sqr_mont(res, res);
193 ecp_nistz256_mul_mont(res, res, p2);
194
195 ecp_nistz256_sqr_mont(res, res);
196 ecp_nistz256_sqr_mont(res, res);
David Benjamin4969cc92016-04-22 15:02:23 -0400197 ecp_nistz256_mul_mont(r, res, in);
Adam Langleyfad63272015-11-12 12:15:39 -0800198}
199
Robert Sloan8f860b12017-08-28 07:37:06 -0700200// ecp_nistz256_bignum_to_field_elem copies the contents of |in| to |out| and
201// returns one if it fits. Otherwise it returns zero.
Adam Langleyfad63272015-11-12 12:15:39 -0800202static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS],
203 const BIGNUM *in) {
Robert Sloan8542c082018-02-05 09:07:34 -0800204 return bn_copy_words(out, P256_LIMBS, in);
Adam Langleyfad63272015-11-12 12:15:39 -0800205}
206
Robert Sloan8f860b12017-08-28 07:37:06 -0700207// r = p * p_scalar
Adam Langley4139edb2016-01-13 15:00:54 -0800208static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
Robert Sloan99319a12017-11-27 10:32:46 -0800209 const EC_POINT *p,
210 const EC_SCALAR *p_scalar) {
Adam Langley4139edb2016-01-13 15:00:54 -0800211 assert(p != NULL);
212 assert(p_scalar != NULL);
213
Adam Langleyfad63272015-11-12 12:15:39 -0800214 static const unsigned kWindowSize = 5;
215 static const unsigned kMask = (1 << (5 /* kWindowSize */ + 1)) - 1;
216
Robert Sloan8f860b12017-08-28 07:37:06 -0700217 // A |P256_POINT| is (3 * 32) = 96 bytes, and the 64-byte alignment should
218 // add no more than 63 bytes of overhead. Thus, |table| should require
219 // ~1599 ((96 * 16) + 63) bytes of stack space.
David Benjamin4969cc92016-04-22 15:02:23 -0400220 alignas(64) P256_POINT table[16];
Adam Langley4139edb2016-01-13 15:00:54 -0800221 uint8_t p_str[33];
Robert Sloan99319a12017-11-27 10:32:46 -0800222 OPENSSL_memcpy(p_str, p_scalar->bytes, 32);
223 p_str[32] = 0;
Adam Langley4139edb2016-01-13 15:00:54 -0800224
Robert Sloan8f860b12017-08-28 07:37:06 -0700225 // table[0] is implicitly (0,0,0) (the point at infinity), therefore it is
226 // not stored. All other values are actually stored with an offset of -1 in
227 // table.
Adam Langley4139edb2016-01-13 15:00:54 -0800228 P256_POINT *row = table;
229
230 if (!ecp_nistz256_bignum_to_field_elem(row[1 - 1].X, &p->X) ||
231 !ecp_nistz256_bignum_to_field_elem(row[1 - 1].Y, &p->Y) ||
232 !ecp_nistz256_bignum_to_field_elem(row[1 - 1].Z, &p->Z)) {
233 OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
Robert Sloan99319a12017-11-27 10:32:46 -0800234 return 0;
Adam Langleyfad63272015-11-12 12:15:39 -0800235 }
236
Adam Langley4139edb2016-01-13 15:00:54 -0800237 ecp_nistz256_point_double(&row[2 - 1], &row[1 - 1]);
238 ecp_nistz256_point_add(&row[3 - 1], &row[2 - 1], &row[1 - 1]);
239 ecp_nistz256_point_double(&row[4 - 1], &row[2 - 1]);
240 ecp_nistz256_point_double(&row[6 - 1], &row[3 - 1]);
241 ecp_nistz256_point_double(&row[8 - 1], &row[4 - 1]);
242 ecp_nistz256_point_double(&row[12 - 1], &row[6 - 1]);
243 ecp_nistz256_point_add(&row[5 - 1], &row[4 - 1], &row[1 - 1]);
244 ecp_nistz256_point_add(&row[7 - 1], &row[6 - 1], &row[1 - 1]);
245 ecp_nistz256_point_add(&row[9 - 1], &row[8 - 1], &row[1 - 1]);
246 ecp_nistz256_point_add(&row[13 - 1], &row[12 - 1], &row[1 - 1]);
247 ecp_nistz256_point_double(&row[14 - 1], &row[7 - 1]);
248 ecp_nistz256_point_double(&row[10 - 1], &row[5 - 1]);
249 ecp_nistz256_point_add(&row[15 - 1], &row[14 - 1], &row[1 - 1]);
250 ecp_nistz256_point_add(&row[11 - 1], &row[10 - 1], &row[1 - 1]);
David Benjaminc895d6b2016-08-11 13:26:41 -0400251 ecp_nistz256_point_double(&row[16 - 1], &row[8 - 1]);
Adam Langleyfad63272015-11-12 12:15:39 -0800252
253 BN_ULONG tmp[P256_LIMBS];
David Benjamin4969cc92016-04-22 15:02:23 -0400254 alignas(32) P256_POINT h;
Adam Langleyfad63272015-11-12 12:15:39 -0800255 unsigned index = 255;
Adam Langley4139edb2016-01-13 15:00:54 -0800256 unsigned wvalue = p_str[(index - 1) / 8];
Adam Langleyfad63272015-11-12 12:15:39 -0800257 wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
258
Adam Langley4139edb2016-01-13 15:00:54 -0800259 ecp_nistz256_select_w5(r, table, booth_recode_w5(wvalue) >> 1);
Adam Langleyfad63272015-11-12 12:15:39 -0800260
261 while (index >= 5) {
Adam Langley4139edb2016-01-13 15:00:54 -0800262 if (index != 255) {
Adam Langleyfad63272015-11-12 12:15:39 -0800263 unsigned off = (index - 1) / 8;
264
Adam Langley4139edb2016-01-13 15:00:54 -0800265 wvalue = p_str[off] | p_str[off + 1] << 8;
Adam Langleyfad63272015-11-12 12:15:39 -0800266 wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
267
268 wvalue = booth_recode_w5(wvalue);
269
Adam Langley4139edb2016-01-13 15:00:54 -0800270 ecp_nistz256_select_w5(&h, table, wvalue >> 1);
Adam Langleyfad63272015-11-12 12:15:39 -0800271
272 ecp_nistz256_neg(tmp, h.Y);
273 copy_conditional(h.Y, tmp, (wvalue & 1));
274
275 ecp_nistz256_point_add(r, r, &h);
276 }
277
278 index -= kWindowSize;
279
280 ecp_nistz256_point_double(r, r);
281 ecp_nistz256_point_double(r, r);
282 ecp_nistz256_point_double(r, r);
283 ecp_nistz256_point_double(r, r);
284 ecp_nistz256_point_double(r, r);
285 }
286
Robert Sloan8f860b12017-08-28 07:37:06 -0700287 // Final window
Adam Langley4139edb2016-01-13 15:00:54 -0800288 wvalue = p_str[0];
289 wvalue = (wvalue << 1) & kMask;
Adam Langleyfad63272015-11-12 12:15:39 -0800290
Adam Langley4139edb2016-01-13 15:00:54 -0800291 wvalue = booth_recode_w5(wvalue);
Adam Langleyfad63272015-11-12 12:15:39 -0800292
Adam Langley4139edb2016-01-13 15:00:54 -0800293 ecp_nistz256_select_w5(&h, table, wvalue >> 1);
Adam Langleyfad63272015-11-12 12:15:39 -0800294
Adam Langley4139edb2016-01-13 15:00:54 -0800295 ecp_nistz256_neg(tmp, h.Y);
296 copy_conditional(h.Y, tmp, wvalue & 1);
Adam Langleyfad63272015-11-12 12:15:39 -0800297
Adam Langley4139edb2016-01-13 15:00:54 -0800298 ecp_nistz256_point_add(r, r, &h);
299
Robert Sloan99319a12017-11-27 10:32:46 -0800300 return 1;
Adam Langleyfad63272015-11-12 12:15:39 -0800301}
302
Robert Sloan99319a12017-11-27 10:32:46 -0800303static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
304 const EC_SCALAR *g_scalar,
305 const EC_POINT *p_,
306 const EC_SCALAR *p_scalar, BN_CTX *ctx) {
Adam Langley4139edb2016-01-13 15:00:54 -0800307 assert((p_ != NULL) == (p_scalar != NULL));
308
Adam Langleyfad63272015-11-12 12:15:39 -0800309 static const unsigned kWindowSize = 7;
310 static const unsigned kMask = (1 << (7 /* kWindowSize */ + 1)) - 1;
311
David Benjamin4969cc92016-04-22 15:02:23 -0400312 alignas(32) union {
Adam Langleyfad63272015-11-12 12:15:39 -0800313 P256_POINT p;
314 P256_POINT_AFFINE a;
315 } t, p;
316
Adam Langley4139edb2016-01-13 15:00:54 -0800317 if (g_scalar != NULL) {
Robert Sloan99319a12017-11-27 10:32:46 -0800318 uint8_t p_str[33];
319 OPENSSL_memcpy(p_str, g_scalar->bytes, 32);
320 p_str[32] = 0;
Adam Langleyfad63272015-11-12 12:15:39 -0800321
Robert Sloan8f860b12017-08-28 07:37:06 -0700322 // First window
Adam Langley4139edb2016-01-13 15:00:54 -0800323 unsigned wvalue = (p_str[0] << 1) & kMask;
324 unsigned index = kWindowSize;
Adam Langleyfad63272015-11-12 12:15:39 -0800325
Adam Langley4139edb2016-01-13 15:00:54 -0800326 wvalue = booth_recode_w7(wvalue);
Adam Langleyfad63272015-11-12 12:15:39 -0800327
Adam Langley4139edb2016-01-13 15:00:54 -0800328 const PRECOMP256_ROW *const precomputed_table =
329 (const PRECOMP256_ROW *)ecp_nistz256_precomputed;
330 ecp_nistz256_select_w7(&p.a, precomputed_table[0], wvalue >> 1);
331
332 ecp_nistz256_neg(p.p.Z, p.p.Y);
333 copy_conditional(p.p.Y, p.p.Z, wvalue & 1);
334
Robert Sloan8f860b12017-08-28 07:37:06 -0700335 // Convert |p| from affine to Jacobian coordinates. We set Z to zero if |p|
336 // is infinity and |ONE| otherwise. |p| was computed from the table, so it
337 // is infinity iff |wvalue >> 1| is zero.
Robert Sloan69939df2017-01-09 10:53:07 -0800338 OPENSSL_memset(p.p.Z, 0, sizeof(p.p.Z));
Steven Valdez909b19f2016-11-21 15:35:44 -0500339 copy_conditional(p.p.Z, ONE, is_not_zero(wvalue >> 1));
Adam Langley4139edb2016-01-13 15:00:54 -0800340
Robert Sloan99319a12017-11-27 10:32:46 -0800341 for (int i = 1; i < 37; i++) {
Adam Langley4139edb2016-01-13 15:00:54 -0800342 unsigned off = (index - 1) / 8;
343 wvalue = p_str[off] | p_str[off + 1] << 8;
344 wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
345 index += kWindowSize;
Adam Langleyfad63272015-11-12 12:15:39 -0800346
347 wvalue = booth_recode_w7(wvalue);
348
Adam Langley4139edb2016-01-13 15:00:54 -0800349 ecp_nistz256_select_w7(&t.a, precomputed_table[i], wvalue >> 1);
Adam Langleyfad63272015-11-12 12:15:39 -0800350
Adam Langley4139edb2016-01-13 15:00:54 -0800351 ecp_nistz256_neg(t.p.Z, t.a.Y);
352 copy_conditional(t.a.Y, t.p.Z, wvalue & 1);
Adam Langleyfad63272015-11-12 12:15:39 -0800353
Adam Langley4139edb2016-01-13 15:00:54 -0800354 ecp_nistz256_point_add_affine(&p.p, &p.p, &t.a);
Adam Langleyfad63272015-11-12 12:15:39 -0800355 }
Adam Langleyfad63272015-11-12 12:15:39 -0800356 }
357
Adam Langley4139edb2016-01-13 15:00:54 -0800358 const int p_is_infinity = g_scalar == NULL;
359 if (p_scalar != NULL) {
Adam Langleyfad63272015-11-12 12:15:39 -0800360 P256_POINT *out = &t.p;
361 if (p_is_infinity) {
362 out = &p.p;
363 }
364
Robert Sloan99319a12017-11-27 10:32:46 -0800365 if (!ecp_nistz256_windowed_mul(group, out, p_, p_scalar)) {
366 return 0;
Adam Langley4139edb2016-01-13 15:00:54 -0800367 }
Adam Langleyfad63272015-11-12 12:15:39 -0800368
369 if (!p_is_infinity) {
370 ecp_nistz256_point_add(&p.p, &p.p, out);
371 }
372 }
373
Robert Sloan8f860b12017-08-28 07:37:06 -0700374 // Not constant-time, but we're only operating on the public output.
David Benjamin4969cc92016-04-22 15:02:23 -0400375 if (!bn_set_words(&r->X, p.p.X, P256_LIMBS) ||
376 !bn_set_words(&r->Y, p.p.Y, P256_LIMBS) ||
377 !bn_set_words(&r->Z, p.p.Z, P256_LIMBS)) {
378 return 0;
379 }
Adam Langleyfad63272015-11-12 12:15:39 -0800380
Robert Sloan99319a12017-11-27 10:32:46 -0800381 return 1;
Adam Langleyfad63272015-11-12 12:15:39 -0800382}
383
384static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
385 BIGNUM *x, BIGNUM *y, BN_CTX *ctx) {
386 BN_ULONG z_inv2[P256_LIMBS];
387 BN_ULONG z_inv3[P256_LIMBS];
Adam Langleyfad63272015-11-12 12:15:39 -0800388 BN_ULONG point_x[P256_LIMBS], point_y[P256_LIMBS], point_z[P256_LIMBS];
389
390 if (EC_POINT_is_at_infinity(group, point)) {
391 OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
392 return 0;
393 }
394
395 if (!ecp_nistz256_bignum_to_field_elem(point_x, &point->X) ||
396 !ecp_nistz256_bignum_to_field_elem(point_y, &point->Y) ||
397 !ecp_nistz256_bignum_to_field_elem(point_z, &point->Z)) {
398 OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
399 return 0;
400 }
401
Steven Valdez909b19f2016-11-21 15:35:44 -0500402 ecp_nistz256_mod_inverse_mont(z_inv3, point_z);
Adam Langleyfad63272015-11-12 12:15:39 -0800403 ecp_nistz256_sqr_mont(z_inv2, z_inv3);
David Benjamin4969cc92016-04-22 15:02:23 -0400404
Robert Sloan8f860b12017-08-28 07:37:06 -0700405 // Instead of using |ecp_nistz256_from_mont| to convert the |x| coordinate
406 // and then calling |ecp_nistz256_from_mont| again to convert the |y|
407 // coordinate below, convert the common factor |z_inv2| once now, saving one
408 // reduction.
Steven Valdezb0b45c62017-01-17 16:23:54 -0500409 ecp_nistz256_from_mont(z_inv2, z_inv2);
Adam Langleyfad63272015-11-12 12:15:39 -0800410
411 if (x != NULL) {
David Benjaminc895d6b2016-08-11 13:26:41 -0400412 BN_ULONG x_aff[P256_LIMBS];
413 ecp_nistz256_mul_mont(x_aff, z_inv2, point_x);
David Benjaminc895d6b2016-08-11 13:26:41 -0400414 if (!bn_set_words(x, x_aff, P256_LIMBS)) {
Adam Langley4139edb2016-01-13 15:00:54 -0800415 OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
416 return 0;
417 }
Adam Langleyfad63272015-11-12 12:15:39 -0800418 }
419
420 if (y != NULL) {
David Benjaminc895d6b2016-08-11 13:26:41 -0400421 BN_ULONG y_aff[P256_LIMBS];
Adam Langleyfad63272015-11-12 12:15:39 -0800422 ecp_nistz256_mul_mont(z_inv3, z_inv3, z_inv2);
David Benjaminc895d6b2016-08-11 13:26:41 -0400423 ecp_nistz256_mul_mont(y_aff, z_inv3, point_y);
David Benjaminc895d6b2016-08-11 13:26:41 -0400424 if (!bn_set_words(y, y_aff, P256_LIMBS)) {
Adam Langley4139edb2016-01-13 15:00:54 -0800425 OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
426 return 0;
427 }
Adam Langleyfad63272015-11-12 12:15:39 -0800428 }
429
430 return 1;
431}
432
Robert Sloan8ff03552017-06-14 12:40:58 -0700433DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) {
434 out->group_init = ec_GFp_mont_group_init;
435 out->group_finish = ec_GFp_mont_group_finish;
Robert Sloan8ff03552017-06-14 12:40:58 -0700436 out->group_set_curve = ec_GFp_mont_group_set_curve;
437 out->point_get_affine_coordinates = ecp_nistz256_get_affine;
438 out->mul = ecp_nistz256_points_mul;
Robert Sloan55818102017-12-18 11:26:17 -0800439 out->mul_public = ecp_nistz256_points_mul;
Robert Sloan8ff03552017-06-14 12:40:58 -0700440 out->field_mul = ec_GFp_mont_field_mul;
441 out->field_sqr = ec_GFp_mont_field_sqr;
442 out->field_encode = ec_GFp_mont_field_encode;
443 out->field_decode = ec_GFp_mont_field_decode;
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400444};
Adam Langleyfad63272015-11-12 12:15:39 -0800445
446#endif /* !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
447 !defined(OPENSSL_SMALL) */