summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/Makefile3
-rw-r--r--src/lib/libcrypto/bn/bn_internal.h4
-rw-r--r--src/lib/libcrypto/bn/bn_mont.c71
-rw-r--r--src/lib/libcrypto/ec/ec_field.c189
-rw-r--r--src/lib/libcrypto/ec/ec_internal.h63
5 files changed, 299 insertions, 31 deletions
diff --git a/src/lib/libcrypto/Makefile b/src/lib/libcrypto/Makefile
index dd64f07f48..7564001961 100644
--- a/src/lib/libcrypto/Makefile
+++ b/src/lib/libcrypto/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.233 2025/05/25 04:58:32 jsing Exp $ 1# $OpenBSD: Makefile,v 1.234 2025/05/25 05:12:05 jsing Exp $
2 2
3LIB= crypto 3LIB= crypto
4LIBREBUILD=y 4LIBREBUILD=y
@@ -283,6 +283,7 @@ SRCS+= ec_asn1.c
283SRCS+= ec_convert.c 283SRCS+= ec_convert.c
284SRCS+= ec_curve.c 284SRCS+= ec_curve.c
285SRCS+= ec_err.c 285SRCS+= ec_err.c
286SRCS+= ec_field.c
286SRCS+= ec_key.c 287SRCS+= ec_key.c
287SRCS+= ec_lib.c 288SRCS+= ec_lib.c
288SRCS+= ec_mult.c 289SRCS+= ec_mult.c
diff --git a/src/lib/libcrypto/bn/bn_internal.h b/src/lib/libcrypto/bn/bn_internal.h
index b6e903553f..a1f1515b57 100644
--- a/src/lib/libcrypto/bn/bn_internal.h
+++ b/src/lib/libcrypto/bn/bn_internal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: bn_internal.h,v 1.18 2025/05/25 04:58:32 jsing Exp $ */ 1/* $OpenBSD: bn_internal.h,v 1.19 2025/05/25 05:12:05 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2023 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2023 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -45,6 +45,8 @@ void bn_mod_mul_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
45void bn_montgomery_multiply_words(BN_ULONG *rp, const BN_ULONG *ap, 45void bn_montgomery_multiply_words(BN_ULONG *rp, const BN_ULONG *ap,
46 const BN_ULONG *bp, const BN_ULONG *np, BN_ULONG *tp, BN_ULONG n0, 46 const BN_ULONG *bp, const BN_ULONG *np, BN_ULONG *tp, BN_ULONG n0,
47 int n_len); 47 int n_len);
48void bn_montgomery_reduce_words(BN_ULONG *r, BN_ULONG *a, const BN_ULONG *n,
49 BN_ULONG n0, int n_len);
48 50
49#ifndef HAVE_BN_CT_NE_ZERO 51#ifndef HAVE_BN_CT_NE_ZERO
50static inline int 52static inline int
diff --git a/src/lib/libcrypto/bn/bn_mont.c b/src/lib/libcrypto/bn/bn_mont.c
index ce88b23ca9..950846fa5b 100644
--- a/src/lib/libcrypto/bn/bn_mont.c
+++ b/src/lib/libcrypto/bn/bn_mont.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: bn_mont.c,v 1.67 2025/05/25 04:58:32 jsing Exp $ */ 1/* $OpenBSD: bn_mont.c,v 1.68 2025/05/25 05:12:05 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -316,6 +316,44 @@ BN_MONT_CTX_set_locked(BN_MONT_CTX **pmctx, int lock, const BIGNUM *mod,
316LCRYPTO_ALIAS(BN_MONT_CTX_set_locked); 316LCRYPTO_ALIAS(BN_MONT_CTX_set_locked);
317 317
318/* 318/*
319 * bn_montgomery_reduce_words() performs Montgomery reduction, reducing the input
320 * from its Montgomery form aR to a, returning the result in r. a must be twice
321 * the length of the modulus. Note that the input is mutated in the process of
322 * performing the reduction.
323 */
324void
325bn_montgomery_reduce_words(BN_ULONG *r, BN_ULONG *a, const BN_ULONG *n,
326 BN_ULONG n0, int n_len)
327{
328 BN_ULONG v, mask;
329 BN_ULONG carry = 0;
330 int i;
331
332 /* Add multiples of the modulus, so that it becomes divisible by R. */
333 for (i = 0; i < n_len; i++) {
334 v = bn_mul_add_words(&a[i], n, n_len, a[i] * n0);
335 bn_addw_addw(v, a[i + n_len], carry, &carry, &a[i + n_len]);
336 }
337
338 /* Divide by R (this is the equivalent of right shifting by n_len). */
339 a = &a[n_len];
340
341 /*
342 * The output is now in the range of [0, 2N). Attempt to reduce once by
343 * subtracting the modulus. If the reduction was necessary then the
344 * result is already in r, otherwise copy the value prior to reduction
345 * from the top half of a.
346 */
347 mask = carry - bn_sub_words(r, a, n, n_len);
348
349 for (i = 0; i < n_len; i++) {
350 *r = (*r & ~mask) | (*a & mask);
351 r++;
352 a++;
353 }
354}
355
356/*
319 * bn_montgomery_reduce() performs Montgomery reduction, reducing the input 357 * bn_montgomery_reduce() performs Montgomery reduction, reducing the input
320 * from its Montgomery form aR to a, returning the result in r. Note that the 358 * from its Montgomery form aR to a, returning the result in r. Note that the
321 * input is mutated in the process of performing the reduction, destroying its 359 * input is mutated in the process of performing the reduction, destroying its
@@ -325,7 +363,6 @@ static int
325bn_montgomery_reduce(BIGNUM *r, BIGNUM *a, BN_MONT_CTX *mctx) 363bn_montgomery_reduce(BIGNUM *r, BIGNUM *a, BN_MONT_CTX *mctx)
326{ 364{
327 BIGNUM *n; 365 BIGNUM *n;
328 BN_ULONG *ap, *rp, n0, v, carry, mask;
329 int i, max, n_len; 366 int i, max, n_len;
330 367
331 n = &mctx->N; 368 n = &mctx->N;
@@ -341,7 +378,8 @@ bn_montgomery_reduce(BIGNUM *r, BIGNUM *a, BN_MONT_CTX *mctx)
341 378
342 /* 379 /*
343 * Expand a to twice the length of the modulus, zero if necessary. 380 * Expand a to twice the length of the modulus, zero if necessary.
344 * XXX - make this a requirement of the caller. 381 * XXX - make this a requirement of the caller or use a temporary
382 * allocation.
345 */ 383 */
346 if ((max = 2 * n_len) < n_len) 384 if ((max = 2 * n_len) < n_len)
347 return 0; 385 return 0;
@@ -350,33 +388,8 @@ bn_montgomery_reduce(BIGNUM *r, BIGNUM *a, BN_MONT_CTX *mctx)
350 for (i = a->top; i < max; i++) 388 for (i = a->top; i < max; i++)
351 a->d[i] = 0; 389 a->d[i] = 0;
352 390
353 carry = 0; 391 bn_montgomery_reduce_words(r->d, a->d, n->d, mctx->n0[0], n_len);
354 n0 = mctx->n0[0];
355
356 /* Add multiples of the modulus, so that it becomes divisible by R. */
357 for (i = 0; i < n_len; i++) {
358 v = bn_mul_add_words(&a->d[i], n->d, n_len, a->d[i] * n0);
359 bn_addw_addw(v, a->d[i + n_len], carry, &carry,
360 &a->d[i + n_len]);
361 }
362
363 /* Divide by R (this is the equivalent of right shifting by n_len). */
364 ap = &a->d[n_len];
365
366 /*
367 * The output is now in the range of [0, 2N). Attempt to reduce once by
368 * subtracting the modulus. If the reduction was necessary then the
369 * result is already in r, otherwise copy the value prior to reduction
370 * from the top half of a.
371 */
372 mask = carry - bn_sub_words(r->d, ap, n->d, n_len);
373 392
374 rp = r->d;
375 for (i = 0; i < n_len; i++) {
376 *rp = (*rp & ~mask) | (*ap & mask);
377 rp++;
378 ap++;
379 }
380 r->top = n_len; 393 r->top = n_len;
381 394
382 bn_correct_top(r); 395 bn_correct_top(r);
diff --git a/src/lib/libcrypto/ec/ec_field.c b/src/lib/libcrypto/ec/ec_field.c
new file mode 100644
index 0000000000..ec1c7d11e0
--- /dev/null
+++ b/src/lib/libcrypto/ec/ec_field.c
@@ -0,0 +1,189 @@
1/* $OpenBSD: ec_field.c,v 1.1 2025/05/25 05:12:05 jsing Exp $ */
2/*
3 * Copyright (c) 2024 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <string.h>
19
20#include <openssl/ec.h>
21
22#include "bn_local.h"
23#include "bn_internal.h"
24#include "ec_local.h"
25#include "ec_internal.h"
26
27int
28ec_field_modulus_from_bn(EC_FIELD_MODULUS *fm, const BIGNUM *bn, BN_CTX *ctx)
29{
30 BN_MONT_CTX *mctx = NULL;
31 size_t i;
32 int ret = 0;
33
34 if (BN_is_negative(bn))
35 goto err;
36 if (BN_num_bits(bn) > EC_FIELD_ELEMENT_MAX_BITS)
37 goto err;
38
39 memset(fm, 0, sizeof(*fm));
40
41 fm->n = (BN_num_bits(bn) + BN_BITS2 - 1) / BN_BITS2;
42
43 for (i = 0; i < bn->top; i++)
44 fm->m.w[i] = bn->d[i];
45
46 /* XXX - implement this without BN_MONT_CTX. */
47 if ((mctx = BN_MONT_CTX_new()) == NULL)
48 goto err;
49 if (!BN_MONT_CTX_set(mctx, bn, ctx))
50 goto err;
51
52 for (i = 0; i < mctx->RR.top; i++)
53 fm->rr.w[i] = mctx->RR.d[i];
54
55 fm->minv0 = mctx->n0[0];
56
57 ret = 1;
58
59 err:
60 BN_MONT_CTX_free(mctx);
61
62 return ret;
63}
64
65int
66ec_field_element_from_bn(const EC_FIELD_MODULUS *fm, const EC_GROUP *group,
67 EC_FIELD_ELEMENT *fe, const BIGNUM *bn, BN_CTX *ctx)
68{
69 BN_ULONG t[EC_FIELD_ELEMENT_MAX_WORDS * 2 + 2];
70 BIGNUM *tmp;
71 size_t i;
72 int ret = 0;
73
74 BN_CTX_start(ctx);
75
76 if ((tmp = BN_CTX_get(ctx)) == NULL)
77 goto err;
78
79 /* XXX - enforce 0 <= n < p. */
80
81 if (BN_num_bits(bn) > EC_FIELD_ELEMENT_MAX_BITS)
82 goto err;
83
84 /* XXX - do this without BN. */
85 if (!BN_nnmod(tmp, bn, group->p, ctx))
86 goto err;
87
88 if (BN_num_bits(tmp) > EC_FIELD_ELEMENT_MAX_BITS)
89 abort();
90
91 memset(fe->w, 0, sizeof(fe->w));
92
93 for (i = 0; i < tmp->top; i++)
94 fe->w[i] = tmp->d[i];
95
96 bn_mod_mul_words(fe->w, fe->w, fm->rr.w, fm->m.w, t, fm->minv0, fm->n);
97
98 ret = 1;
99
100 err:
101 BN_CTX_end(ctx);
102
103 return ret;
104}
105
106int
107ec_field_element_to_bn(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *fe,
108 BIGNUM *bn, BN_CTX *ctx)
109{
110 BN_ULONG t[EC_FIELD_ELEMENT_MAX_WORDS * 2 + 2];
111 size_t i;
112
113 if (!bn_wexpand(bn, fm->n))
114 return 0;
115
116 memset(t, 0, sizeof(t));
117 for (i = 0; i < fm->n; i++)
118 t[i] = fe->w[i];
119
120 bn_montgomery_reduce_words(bn->d, t, fm->m.w, fm->minv0, fm->n);
121
122 bn->top = fm->n;
123 bn_correct_top(bn);
124
125 return 1;
126}
127
128void
129ec_field_element_copy(EC_FIELD_ELEMENT *dst, const EC_FIELD_ELEMENT *src)
130{
131 memcpy(dst, src, sizeof(EC_FIELD_ELEMENT));
132}
133
134int
135ec_field_element_equal(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *a,
136 const EC_FIELD_ELEMENT *b)
137{
138 BN_ULONG v = 0;
139 int i;
140
141 for (i = 0; i < fm->n; i++)
142 v |= a->w[i] ^ b->w[i];
143
144 return bn_ct_eq_zero(v);
145}
146
147int
148ec_field_element_is_zero(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *fe)
149{
150 BN_ULONG v = 0;
151 int i;
152
153 for (i = 0; i < fm->n; i++)
154 v |= fe->w[i];
155
156 return bn_ct_eq_zero(v);
157}
158
159void
160ec_field_element_add(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
161 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b)
162{
163 bn_mod_add_words(r->w, a->w, b->w, m->m.w, m->n);
164}
165
166void
167ec_field_element_sub(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
168 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b)
169{
170 bn_mod_sub_words(r->w, a->w, b->w, m->m.w, m->n);
171}
172
173void
174ec_field_element_mul(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
175 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b)
176{
177 BN_ULONG t[EC_FIELD_ELEMENT_MAX_WORDS * 2 + 2];
178
179 bn_mod_mul_words(r->w, a->w, b->w, m->m.w, t, m->minv0, m->n);
180}
181
182void
183ec_field_element_sqr(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
184 const EC_FIELD_ELEMENT *a)
185{
186 BN_ULONG t[EC_FIELD_ELEMENT_MAX_WORDS * 2 + 2];
187
188 bn_mod_mul_words(r->w, a->w, a->w, m->m.w, t, m->minv0, m->n);
189}
diff --git a/src/lib/libcrypto/ec/ec_internal.h b/src/lib/libcrypto/ec/ec_internal.h
new file mode 100644
index 0000000000..29b447e8c9
--- /dev/null
+++ b/src/lib/libcrypto/ec/ec_internal.h
@@ -0,0 +1,63 @@
1/* $OpenBSD: ec_internal.h,v 1.1 2025/05/25 05:12:05 jsing Exp $ */
2/*
3 * Copyright (c) 2024 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <openssl/bn.h>
19
20#ifndef HEADER_EC_INTERNAL_H
21#define HEADER_EC_INTERNAL_H
22
23#define EC_FIELD_ELEMENT_MAX_BITS 521
24#define EC_FIELD_ELEMENT_MAX_BYTES \
25 (EC_FIELD_ELEMENT_MAX_BITS + 7) / 8
26#define EC_FIELD_ELEMENT_MAX_WORDS \
27 ((EC_FIELD_ELEMENT_MAX_BYTES + BN_BYTES - 1) / BN_BYTES)
28
29typedef struct {
30 BN_ULONG w[EC_FIELD_ELEMENT_MAX_WORDS];
31} EC_FIELD_ELEMENT;
32
33typedef struct {
34 size_t n;
35 EC_FIELD_ELEMENT m;
36 EC_FIELD_ELEMENT rr;
37 BN_ULONG minv0;
38} EC_FIELD_MODULUS;
39
40int ec_field_modulus_from_bn(EC_FIELD_MODULUS *fm, const BIGNUM *bn,
41 BN_CTX *ctx);
42
43int ec_field_element_from_bn(const EC_FIELD_MODULUS *fm, const EC_GROUP *group,
44 EC_FIELD_ELEMENT *fe, const BIGNUM *bn, BN_CTX *ctx);
45int ec_field_element_to_bn(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *fe,
46 BIGNUM *bn, BN_CTX *ctx);
47
48void ec_field_element_copy(EC_FIELD_ELEMENT *dst, const EC_FIELD_ELEMENT *src);
49
50int ec_field_element_equal(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *a,
51 const EC_FIELD_ELEMENT *b);
52int ec_field_element_is_zero(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *fe);
53
54void ec_field_element_add(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
55 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b);
56void ec_field_element_sub(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
57 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b);
58void ec_field_element_mul(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
59 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b);
60void ec_field_element_sqr(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
61 const EC_FIELD_ELEMENT *a);
62
63#endif