summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/ec
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/ec')
-rw-r--r--src/lib/libcrypto/ec/ec_convert.c6
-rw-r--r--src/lib/libcrypto/ec/ec_curve.c7
-rw-r--r--src/lib/libcrypto/ec/ec_field.c202
-rw-r--r--src/lib/libcrypto/ec/ec_internal.h65
-rw-r--r--src/lib/libcrypto/ec/ec_lib.c61
-rw-r--r--src/lib/libcrypto/ec/ec_local.h22
-rw-r--r--src/lib/libcrypto/ec/ec_mult.c76
-rw-r--r--src/lib/libcrypto/ec/ecp_hp_methods.c943
-rw-r--r--src/lib/libcrypto/ec/ecp_methods.c21
9 files changed, 1315 insertions, 88 deletions
diff --git a/src/lib/libcrypto/ec/ec_convert.c b/src/lib/libcrypto/ec/ec_convert.c
index 84641a4e72..3b88bd20ba 100644
--- a/src/lib/libcrypto/ec/ec_convert.c
+++ b/src/lib/libcrypto/ec/ec_convert.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_convert.c,v 1.15 2025/05/10 05:54:38 tb Exp $ */ 1/* $OpenBSD: ec_convert.c,v 1.16 2025/12/26 18:44:19 tb Exp $ */
2/* 2/*
3 * Originally written by Bodo Moeller for the OpenSSL project. 3 * Originally written by Bodo Moeller for the OpenSSL project.
4 */ 4 */
@@ -452,7 +452,7 @@ EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
452 if (ctx == NULL) 452 if (ctx == NULL)
453 goto err; 453 goto err;
454 454
455 if (group->meth != point->meth) { 455 if (!ec_group_and_point_compatible(group, point)) {
456 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 456 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
457 goto err; 457 goto err;
458 } 458 }
@@ -478,7 +478,7 @@ EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
478 if (ctx == NULL) 478 if (ctx == NULL)
479 goto err; 479 goto err;
480 480
481 if (group->meth != point->meth) { 481 if (!ec_group_and_point_compatible(group, point)) {
482 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 482 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
483 goto err; 483 goto err;
484 } 484 }
diff --git a/src/lib/libcrypto/ec/ec_curve.c b/src/lib/libcrypto/ec/ec_curve.c
index 2cfb219b50..fda2681704 100644
--- a/src/lib/libcrypto/ec/ec_curve.c
+++ b/src/lib/libcrypto/ec/ec_curve.c
@@ -1,7 +1,4 @@
1/* $OpenBSD: ec_curve.c,v 1.58 2025/05/10 05:54:38 tb Exp $ */ 1/* $OpenBSD: ec_curve.c,v 1.60 2025/12/15 12:09:46 tb Exp $ */
2/*
3 * Written by Nils Larsch for the OpenSSL project.
4 */
5/* ==================================================================== 2/* ====================================================================
6 * Copyright (c) 1998-2010 The OpenSSL Project. All rights reserved. 3 * Copyright (c) 1998-2010 The OpenSSL Project. All rights reserved.
7 * 4 *
@@ -1395,7 +1392,7 @@ ec_curve_from_group(const EC_GROUP *group)
1395 if ((cofactor = EC_GROUP_get0_cofactor(group)) != NULL) { 1392 if ((cofactor = EC_GROUP_get0_cofactor(group)) != NULL) {
1396 BN_ULONG cofactor_word; 1393 BN_ULONG cofactor_word;
1397 1394
1398 if ((cofactor_word = BN_get_word(cofactor)) == BN_MASK2) 1395 if ((cofactor_word = BN_get_word(cofactor)) == (BN_ULONG)-1)
1399 goto err; 1396 goto err;
1400 if (cofactor_word > INT_MAX) 1397 if (cofactor_word > INT_MAX)
1401 goto err; 1398 goto err;
diff --git a/src/lib/libcrypto/ec/ec_field.c b/src/lib/libcrypto/ec/ec_field.c
new file mode 100644
index 0000000000..6576526e77
--- /dev/null
+++ b/src/lib/libcrypto/ec/ec_field.c
@@ -0,0 +1,202 @@
1/* $OpenBSD: ec_field.c,v 1.3 2025/08/02 16:20:00 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
134void
135ec_field_element_select(const EC_FIELD_MODULUS *fm, EC_FIELD_ELEMENT *r,
136 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b, int conditional)
137{
138 BN_ULONG mask;
139 int i;
140
141 mask = bn_ct_eq_zero_mask(conditional);
142
143 for (i = 0; i < fm->n; i++)
144 r->w[i] = (a->w[i] & mask) | (b->w[i] & ~mask);
145}
146
147int
148ec_field_element_equal(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *a,
149 const EC_FIELD_ELEMENT *b)
150{
151 BN_ULONG v = 0;
152 int i;
153
154 for (i = 0; i < fm->n; i++)
155 v |= a->w[i] ^ b->w[i];
156
157 return bn_ct_eq_zero(v);
158}
159
160int
161ec_field_element_is_zero(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *fe)
162{
163 BN_ULONG v = 0;
164 int i;
165
166 for (i = 0; i < fm->n; i++)
167 v |= fe->w[i];
168
169 return bn_ct_eq_zero(v);
170}
171
172void
173ec_field_element_add(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
174 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b)
175{
176 bn_mod_add_words(r->w, a->w, b->w, m->m.w, m->n);
177}
178
179void
180ec_field_element_sub(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
181 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b)
182{
183 bn_mod_sub_words(r->w, a->w, b->w, m->m.w, m->n);
184}
185
186void
187ec_field_element_mul(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
188 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b)
189{
190 BN_ULONG t[EC_FIELD_ELEMENT_MAX_WORDS * 2 + 2];
191
192 bn_mod_mul_words(r->w, a->w, b->w, m->m.w, t, m->minv0, m->n);
193}
194
195void
196ec_field_element_sqr(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
197 const EC_FIELD_ELEMENT *a)
198{
199 BN_ULONG t[EC_FIELD_ELEMENT_MAX_WORDS * 2 + 2];
200
201 bn_mod_sqr_words(r->w, a->w, m->m.w, t, m->minv0, m->n);
202}
diff --git a/src/lib/libcrypto/ec/ec_internal.h b/src/lib/libcrypto/ec/ec_internal.h
new file mode 100644
index 0000000000..de0affa206
--- /dev/null
+++ b/src/lib/libcrypto/ec/ec_internal.h
@@ -0,0 +1,65 @@
1/* $OpenBSD: ec_internal.h,v 1.3 2025/12/05 14:12:32 tb 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 + sizeof(BN_ULONG) - 1) / sizeof(BN_ULONG))
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);
49void ec_field_element_select(const EC_FIELD_MODULUS *fm, EC_FIELD_ELEMENT *r,
50 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b, int conditional);
51
52int ec_field_element_equal(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *a,
53 const EC_FIELD_ELEMENT *b);
54int ec_field_element_is_zero(const EC_FIELD_MODULUS *fm, const EC_FIELD_ELEMENT *fe);
55
56void ec_field_element_add(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
57 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b);
58void ec_field_element_sub(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
59 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b);
60void ec_field_element_mul(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
61 const EC_FIELD_ELEMENT *a, const EC_FIELD_ELEMENT *b);
62void ec_field_element_sqr(const EC_FIELD_MODULUS *m, EC_FIELD_ELEMENT *r,
63 const EC_FIELD_ELEMENT *a);
64
65#endif
diff --git a/src/lib/libcrypto/ec/ec_lib.c b/src/lib/libcrypto/ec/ec_lib.c
index d760ecfb95..30b2cf95b8 100644
--- a/src/lib/libcrypto/ec/ec_lib.c
+++ b/src/lib/libcrypto/ec/ec_lib.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_lib.c,v 1.124 2025/05/10 05:54:38 tb Exp $ */ 1/* $OpenBSD: ec_lib.c,v 1.131 2025/12/26 18:49:13 tb Exp $ */
2/* 2/*
3 * Originally written by Bodo Moeller for the OpenSSL project. 3 * Originally written by Bodo Moeller for the OpenSSL project.
4 */ 4 */
@@ -165,6 +165,10 @@ EC_GROUP_copy(EC_GROUP *dst, const EC_GROUP *src)
165 165
166 dst->a_is_minus3 = src->a_is_minus3; 166 dst->a_is_minus3 = src->a_is_minus3;
167 167
168 memcpy(&dst->fm, &src->fm, sizeof(src->fm));
169 memcpy(&dst->fe_a, &src->fe_a, sizeof(src->fe_a));
170 memcpy(&dst->fe_b, &src->fe_b, sizeof(src->fe_b));
171
168 BN_MONT_CTX_free(dst->mont_ctx); 172 BN_MONT_CTX_free(dst->mont_ctx);
169 dst->mont_ctx = NULL; 173 dst->mont_ctx = NULL;
170 if (src->mont_ctx != NULL) { 174 if (src->mont_ctx != NULL) {
@@ -788,6 +792,16 @@ EC_GROUP_cmp(const EC_GROUP *group1, const EC_GROUP *group2, BN_CTX *ctx_in)
788} 792}
789LCRYPTO_ALIAS(EC_GROUP_cmp); 793LCRYPTO_ALIAS(EC_GROUP_cmp);
790 794
795int
796ec_group_and_point_compatible(const EC_GROUP *group, const EC_POINT *point)
797{
798 if (group->meth != point->meth)
799 return 0;
800 if (group->nid == NID_undef || point->nid == NID_undef)
801 return 1;
802 return group->nid == point->nid;
803}
804
791EC_POINT * 805EC_POINT *
792EC_POINT_new(const EC_GROUP *group) 806EC_POINT_new(const EC_GROUP *group)
793{ 807{
@@ -811,6 +825,7 @@ EC_POINT_new(const EC_GROUP *group)
811 goto err; 825 goto err;
812 826
813 point->meth = group->meth; 827 point->meth = group->meth;
828 point->nid = group->nid;
814 829
815 return point; 830 return point;
816 831
@@ -852,6 +867,8 @@ EC_POINT_copy(EC_POINT *dst, const EC_POINT *src)
852 if (dst == src) 867 if (dst == src)
853 return 1; 868 return 1;
854 869
870 dst->nid = src->nid;
871
855 if (!bn_copy(dst->X, src->X)) 872 if (!bn_copy(dst->X, src->X))
856 return 0; 873 return 0;
857 if (!bn_copy(dst->Y, src->Y)) 874 if (!bn_copy(dst->Y, src->Y))
@@ -860,6 +877,10 @@ EC_POINT_copy(EC_POINT *dst, const EC_POINT *src)
860 return 0; 877 return 0;
861 dst->Z_is_one = src->Z_is_one; 878 dst->Z_is_one = src->Z_is_one;
862 879
880 memcpy(&dst->fe_x, &src->fe_x, sizeof(dst->fe_x));
881 memcpy(&dst->fe_y, &src->fe_y, sizeof(dst->fe_y));
882 memcpy(&dst->fe_z, &src->fe_z, sizeof(dst->fe_z));
883
863 return 1; 884 return 1;
864} 885}
865LCRYPTO_ALIAS(EC_POINT_copy); 886LCRYPTO_ALIAS(EC_POINT_copy);
@@ -890,15 +911,11 @@ LCRYPTO_ALIAS(EC_POINT_dup);
890int 911int
891EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) 912EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
892{ 913{
893 if (group->meth != point->meth) { 914 if (!ec_group_and_point_compatible(group, point)) {
894 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 915 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
895 return 0; 916 return 0;
896 } 917 }
897 918 return group->meth->point_set_to_infinity(group, point);
898 BN_zero(point->Z);
899 point->Z_is_one = 0;
900
901 return 1;
902} 919}
903LCRYPTO_ALIAS(EC_POINT_set_to_infinity); 920LCRYPTO_ALIAS(EC_POINT_set_to_infinity);
904 921
@@ -918,7 +935,7 @@ EC_POINT_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point,
918 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 935 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
919 goto err; 936 goto err;
920 } 937 }
921 if (group->meth != point->meth) { 938 if (!ec_group_and_point_compatible(group, point)) {
922 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 939 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
923 goto err; 940 goto err;
924 } 941 }
@@ -969,7 +986,7 @@ EC_POINT_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point,
969 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 986 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
970 goto err; 987 goto err;
971 } 988 }
972 if (group->meth != point->meth) { 989 if (!ec_group_and_point_compatible(group, point)) {
973 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 990 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
974 goto err; 991 goto err;
975 } 992 }
@@ -1119,8 +1136,9 @@ EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
1119 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1136 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1120 goto err; 1137 goto err;
1121 } 1138 }
1122 if (group->meth != r->meth || group->meth != a->meth || 1139 if (!ec_group_and_point_compatible(group, r) ||
1123 group->meth != b->meth) { 1140 !ec_group_and_point_compatible(group, a) ||
1141 !ec_group_and_point_compatible(group, b)) {
1124 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1142 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1125 goto err; 1143 goto err;
1126 } 1144 }
@@ -1150,7 +1168,8 @@ EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
1150 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1168 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1151 goto err; 1169 goto err;
1152 } 1170 }
1153 if (group->meth != r->meth || r->meth != a->meth) { 1171 if (!ec_group_and_point_compatible(group, r) ||
1172 !ec_group_and_point_compatible(group, a)) {
1154 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1173 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1155 goto err; 1174 goto err;
1156 } 1175 }
@@ -1179,7 +1198,7 @@ EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx_in)
1179 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1198 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1180 goto err; 1199 goto err;
1181 } 1200 }
1182 if (group->meth != a->meth) { 1201 if (!ec_group_and_point_compatible(group, a)) {
1183 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1202 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1184 goto err; 1203 goto err;
1185 } 1204 }
@@ -1196,12 +1215,11 @@ LCRYPTO_ALIAS(EC_POINT_invert);
1196int 1215int
1197EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) 1216EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
1198{ 1217{
1199 if (group->meth != point->meth) { 1218 if (!ec_group_and_point_compatible(group, point)) {
1200 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1219 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1201 return 0; 1220 return 0;
1202 } 1221 }
1203 1222 return group->meth->point_is_at_infinity(group, point);
1204 return BN_is_zero(point->Z);
1205} 1223}
1206LCRYPTO_ALIAS(EC_POINT_is_at_infinity); 1224LCRYPTO_ALIAS(EC_POINT_is_at_infinity);
1207 1225
@@ -1221,7 +1239,7 @@ EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
1221 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1239 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1222 goto err; 1240 goto err;
1223 } 1241 }
1224 if (group->meth != point->meth) { 1242 if (!ec_group_and_point_compatible(group, point)) {
1225 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1243 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1226 goto err; 1244 goto err;
1227 } 1245 }
@@ -1251,7 +1269,8 @@ EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
1251 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1269 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1252 goto err; 1270 goto err;
1253 } 1271 }
1254 if (group->meth != a->meth || a->meth != b->meth) { 1272 if (!ec_group_and_point_compatible(group, a) ||
1273 !ec_group_and_point_compatible(group, b)) {
1255 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1274 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1256 goto err; 1275 goto err;
1257 } 1276 }
@@ -1324,6 +1343,12 @@ EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
1324 goto err; 1343 goto err;
1325 } 1344 }
1326 1345
1346 if (!ec_group_and_point_compatible(group, r) ||
1347 (point != NULL && !ec_group_and_point_compatible(group, point))) {
1348 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1349 goto err;
1350 }
1351
1327 if (g_scalar != NULL && point == NULL && p_scalar == NULL) { 1352 if (g_scalar != NULL && point == NULL && p_scalar == NULL) {
1328 /* 1353 /*
1329 * In this case we want to compute g_scalar * GeneratorPoint: 1354 * In this case we want to compute g_scalar * GeneratorPoint:
diff --git a/src/lib/libcrypto/ec/ec_local.h b/src/lib/libcrypto/ec/ec_local.h
index c7a54d3a2b..d84e92767c 100644
--- a/src/lib/libcrypto/ec/ec_local.h
+++ b/src/lib/libcrypto/ec/ec_local.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ec_local.h,v 1.67 2025/03/24 13:07:04 jsing Exp $ */ 1/* $OpenBSD: ec_local.h,v 1.73 2025/12/26 18:42:33 tb Exp $ */
2/* 2/*
3 * Originally written by Bodo Moeller for the OpenSSL project. 3 * Originally written by Bodo Moeller for the OpenSSL project.
4 */ 4 */
@@ -69,6 +69,9 @@
69 * 69 *
70 */ 70 */
71 71
72#ifndef HEADER_EC_LOCAL_H
73#define HEADER_EC_LOCAL_H
74
72#include <stdlib.h> 75#include <stdlib.h>
73 76
74#include <openssl/bn.h> 77#include <openssl/bn.h>
@@ -76,6 +79,7 @@
76#include <openssl/objects.h> 79#include <openssl/objects.h>
77 80
78#include "bn_local.h" 81#include "bn_local.h"
82#include "ec_internal.h"
79 83
80__BEGIN_HIDDEN_DECLS 84__BEGIN_HIDDEN_DECLS
81 85
@@ -85,6 +89,9 @@ typedef struct ec_method_st {
85 int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, 89 int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
86 BIGNUM *b, BN_CTX *); 90 BIGNUM *b, BN_CTX *);
87 91
92 int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *);
93 int (*point_is_at_infinity)(const EC_GROUP *, const EC_POINT *);
94
88 int (*point_is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *); 95 int (*point_is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *);
89 int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, 96 int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b,
90 BN_CTX *); 97 BN_CTX *);
@@ -155,10 +162,15 @@ struct ec_group_st {
155 162
156 /* Montgomery context used by EC_GFp_mont_method. */ 163 /* Montgomery context used by EC_GFp_mont_method. */
157 BN_MONT_CTX *mont_ctx; 164 BN_MONT_CTX *mont_ctx;
165
166 EC_FIELD_MODULUS fm;
167 EC_FIELD_ELEMENT fe_a;
168 EC_FIELD_ELEMENT fe_b;
158} /* EC_GROUP */; 169} /* EC_GROUP */;
159 170
160struct ec_point_st { 171struct ec_point_st {
161 const EC_METHOD *meth; 172 const EC_METHOD *meth;
173 int nid;
162 174
163 /* 175 /*
164 * Jacobian projective coordinates: (X, Y, Z) represents (X/Z^2, Y/Z^3) 176 * Jacobian projective coordinates: (X, Y, Z) represents (X/Z^2, Y/Z^3)
@@ -168,10 +180,15 @@ struct ec_point_st {
168 BIGNUM *Y; 180 BIGNUM *Y;
169 BIGNUM *Z; 181 BIGNUM *Z;
170 int Z_is_one; /* enable optimized point arithmetics for special case */ 182 int Z_is_one; /* enable optimized point arithmetics for special case */
183
184 EC_FIELD_ELEMENT fe_x;
185 EC_FIELD_ELEMENT fe_y;
186 EC_FIELD_ELEMENT fe_z;
171} /* EC_POINT */; 187} /* EC_POINT */;
172 188
173const EC_METHOD *EC_GFp_simple_method(void); 189const EC_METHOD *EC_GFp_simple_method(void);
174const EC_METHOD *EC_GFp_mont_method(void); 190const EC_METHOD *EC_GFp_mont_method(void);
191const EC_METHOD *EC_GFp_homogeneous_projective_method(void);
175 192
176/* Compute r = scalar1 * point1 + scalar2 * point2 in non-constant time. */ 193/* Compute r = scalar1 * point1 + scalar2 * point2 in non-constant time. */
177int ec_wnaf_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1, 194int ec_wnaf_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1,
@@ -179,6 +196,7 @@ int ec_wnaf_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1,
179 BN_CTX *ctx); 196 BN_CTX *ctx);
180 197
181int ec_group_is_builtin_curve(const EC_GROUP *group, int *out_nid); 198int ec_group_is_builtin_curve(const EC_GROUP *group, int *out_nid);
199int ec_group_and_point_compatible(const EC_GROUP *group, const EC_POINT *point);
182 200
183/* 201/*
184 * Wrappers around the unergonomic EC_POINT_{oct2point,point2oct}(). 202 * Wrappers around the unergonomic EC_POINT_{oct2point,point2oct}().
@@ -252,3 +270,5 @@ int ecdh_KDF_X9_63(unsigned char *out, size_t outlen, const unsigned char *Z,
252 size_t Zlen, const unsigned char *sinfo, size_t sinfolen, const EVP_MD *md); 270 size_t Zlen, const unsigned char *sinfo, size_t sinfolen, const EVP_MD *md);
253 271
254__END_HIDDEN_DECLS 272__END_HIDDEN_DECLS
273
274#endif /* HEADER_EC_LOCAL_H */
diff --git a/src/lib/libcrypto/ec/ec_mult.c b/src/lib/libcrypto/ec/ec_mult.c
index d74c89cfe2..067df9a2a2 100644
--- a/src/lib/libcrypto/ec/ec_mult.c
+++ b/src/lib/libcrypto/ec/ec_mult.c
@@ -1,64 +1,19 @@
1/* $OpenBSD: ec_mult.c,v 1.59 2025/05/10 05:54:38 tb Exp $ */ 1/* $OpenBSD: ec_mult.c,v 1.61 2025/12/26 18:44:19 tb Exp $ */
2
2/* 3/*
3 * Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. 4 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
4 */
5/* ====================================================================
6 * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgment:
22 * "This product includes software developed by the OpenSSL Project
23 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24 * 5 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 6 * Permission to use, copy, modify, and distribute this software for any
26 * endorse or promote products derived from this software without 7 * purpose with or without fee is hereby granted, provided that the above
27 * prior written permission. For written permission, please contact 8 * copyright notice and this permission notice appear in all copies.
28 * openssl-core@openssl.org.
29 * 9 *
30 * 5. Products derived from this software may not be called "OpenSSL" 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
31 * nor may "OpenSSL" appear in their names without prior written 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
32 * permission of the OpenSSL Project. 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
33 * 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
34 * 6. Redistributions of any form whatsoever must retain the following 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
35 * acknowledgment: 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
36 * "This product includes software developed by the OpenSSL Project 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
37 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 * This product includes cryptographic software written by Eric Young
54 * (eay@cryptsoft.com). This product includes software written by Tim
55 * Hudson (tjh@cryptsoft.com).
56 *
57 */
58/* ====================================================================
59 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60 * Portions of this software developed by SUN MICROSYSTEMS, INC.,
61 * and contributed to the OpenSSL project.
62 */ 17 */
63 18
64#include <stdint.h> 19#include <stdint.h>
@@ -332,8 +287,9 @@ ec_wnaf_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1,
332 ECerror(ERR_R_PASSED_NULL_PARAMETER); 287 ECerror(ERR_R_PASSED_NULL_PARAMETER);
333 goto err; 288 goto err;
334 } 289 }
335 if (group->meth != r->meth || group->meth != point1->meth || 290 if (!ec_group_and_point_compatible(group, r) ||
336 group->meth != point2->meth) { 291 !ec_group_and_point_compatible(group, point1) ||
292 !ec_group_and_point_compatible(group, point2)) {
337 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 293 ECerror(EC_R_INCOMPATIBLE_OBJECTS);
338 goto err; 294 goto err;
339 } 295 }
diff --git a/src/lib/libcrypto/ec/ecp_hp_methods.c b/src/lib/libcrypto/ec/ecp_hp_methods.c
new file mode 100644
index 0000000000..0b34a55b9d
--- /dev/null
+++ b/src/lib/libcrypto/ec/ecp_hp_methods.c
@@ -0,0 +1,943 @@
1/* $OpenBSD: ecp_hp_methods.c,v 1.5 2025/08/03 15:44:00 jsing Exp $ */
2/*
3 * Copyright (c) 2024-2025 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/bn.h>
21#include <openssl/ec.h>
22#include <openssl/err.h>
23
24#include "bn_internal.h"
25#include "crypto_internal.h"
26#include "ec_local.h"
27#include "ec_internal.h"
28#include "err_local.h"
29
30static int
31ec_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a,
32 const BIGNUM *b, BN_CTX *ctx)
33{
34 BIGNUM *t;
35 int ret = 0;
36
37 BN_CTX_start(ctx);
38
39 /* XXX - p must be a prime > 3. */
40
41 if (!bn_copy(group->p, p))
42 goto err;
43 if (!bn_copy(group->a, a))
44 goto err;
45 if (!bn_copy(group->b, b))
46 goto err;
47
48 /* XXX */
49 BN_set_negative(group->p, 0);
50
51 /* XXX */
52 if (!BN_nnmod(group->a, group->a, group->p, ctx))
53 goto err;
54 if (!BN_nnmod(group->b, group->b, group->p, ctx))
55 goto err;
56
57 if ((t = BN_CTX_get(ctx)) == NULL)
58 goto err;
59 if (!BN_set_word(t, 3))
60 goto err;
61 if (!BN_mod_add(t, t, a, group->p, ctx))
62 goto err;
63
64 group->a_is_minus3 = BN_is_zero(t);
65
66 if (!ec_field_modulus_from_bn(&group->fm, group->p, ctx))
67 goto err;
68 if (!ec_field_element_from_bn(&group->fm, group, &group->fe_a, group->a, ctx))
69 goto err;
70 if (!ec_field_element_from_bn(&group->fm, group, &group->fe_b, group->b, ctx))
71 goto err;
72
73 ret = 1;
74
75 err:
76 BN_CTX_end(ctx);
77
78 return ret;
79}
80
81static int
82ec_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
83 BIGNUM *b, BN_CTX *ctx)
84{
85 if (p != NULL) {
86 if (!bn_copy(p, group->p))
87 return 0;
88 }
89 if (a != NULL) {
90 if (!bn_copy(a, group->a))
91 return 0;
92 }
93 if (b != NULL) {
94 if (!bn_copy(b, group->b))
95 return 0;
96 }
97 return 1;
98}
99
100static int
101ec_point_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
102{
103 /* Check if Z is equal to zero. */
104 return ec_field_element_is_zero(&group->fm, &point->fe_z);
105}
106
107static int
108ec_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
109{
110 /* Infinity is (x = 0, y = 1, z = 0). */
111
112 memset(&point->fe_x, 0, sizeof(point->fe_x));
113 memset(&point->fe_y, 0, sizeof(point->fe_y));
114 memset(&point->fe_z, 0, sizeof(point->fe_z));
115
116 point->fe_y.w[0] = 1;
117
118 return 1;
119}
120
121static int
122ec_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point,
123 const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
124{
125 if (x == NULL || y == NULL) {
126 ECerror(ERR_R_PASSED_NULL_PARAMETER);
127 return 0;
128 }
129
130 if (!bn_copy(point->X, x))
131 return 0;
132 if (!bn_copy(point->Y, y))
133 return 0;
134 if (!BN_one(point->Z))
135 return 0;
136
137 /* XXX */
138 if (!BN_nnmod(point->X, point->X, group->p, ctx))
139 return 0;
140 if (!BN_nnmod(point->Y, point->Y, group->p, ctx))
141 return 0;
142
143 if (!ec_field_element_from_bn(&group->fm, group, &point->fe_x, point->X, ctx))
144 return 0;
145 if (!ec_field_element_from_bn(&group->fm, group, &point->fe_y, point->Y, ctx))
146 return 0;
147 if (!ec_field_element_from_bn(&group->fm, group, &point->fe_z, point->Z, ctx))
148 return 0;
149
150 return 1;
151}
152
153static int
154ec_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point,
155 BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
156{
157 BIGNUM *zinv;
158 int ret = 0;
159
160 /*
161 * Convert homogeneous projective coordinates (XZ, YZ, Z) to affine
162 * coordinates (x = X/Z, y = Y/Z).
163 */
164 if (!ec_field_element_to_bn(&group->fm, &point->fe_x, point->X, ctx))
165 return 0;
166 if (!ec_field_element_to_bn(&group->fm, &point->fe_y, point->Y, ctx))
167 return 0;
168 if (!ec_field_element_to_bn(&group->fm, &point->fe_z, point->Z, ctx))
169 return 0;
170
171 BN_CTX_start(ctx);
172
173 if ((zinv = BN_CTX_get(ctx)) == NULL)
174 goto err;
175
176 if (BN_mod_inverse_ct(zinv, point->Z, group->p, ctx) == NULL)
177 goto err;
178
179 if (x != NULL) {
180 if (!BN_mod_mul(x, point->X, zinv, group->p, ctx))
181 goto err;
182 }
183 if (y != NULL) {
184 if (!BN_mod_mul(y, point->Y, zinv, group->p, ctx))
185 goto err;
186 }
187
188 ret = 1;
189
190 err:
191 BN_CTX_end(ctx);
192
193 return ret;
194}
195
196static int
197ec_point_add_a1(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
198 const EC_POINT *b, BN_CTX *ctx)
199{
200 EC_FIELD_ELEMENT X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3;
201 EC_FIELD_ELEMENT b3, t0, t1, t2, t3, t4, t5;
202 EC_FIELD_ELEMENT ga, gb;
203
204 /*
205 * Complete, projective point addition for arbitrary prime order short
206 * Weierstrass curves with arbitrary a - see
207 * https://eprint.iacr.org/2015/1060, algorithm 1 and appendix A.1.
208 */
209
210 ec_field_element_copy(&ga, &group->fe_a);
211 ec_field_element_copy(&gb, &group->fe_b);
212
213 ec_field_element_copy(&X1, &a->fe_x);
214 ec_field_element_copy(&Y1, &a->fe_y);
215 ec_field_element_copy(&Z1, &a->fe_z);
216
217 ec_field_element_copy(&X2, &b->fe_x);
218 ec_field_element_copy(&Y2, &b->fe_y);
219 ec_field_element_copy(&Z2, &b->fe_z);
220
221 /* b3 := 3 * b ; */
222 ec_field_element_add(&group->fm, &b3, &gb, &gb);
223 ec_field_element_add(&group->fm, &b3, &b3, &gb);
224
225 /* t0 := X1 * X2 ; t1 := Y1 * Y2 ; t2 := Z1 * Z2 ; */
226 ec_field_element_mul(&group->fm, &t0, &X1, &X2);
227 ec_field_element_mul(&group->fm, &t1, &Y1, &Y2);
228 ec_field_element_mul(&group->fm, &t2, &Z1, &Z2);
229
230 /* t3 := X1 + Y1 ; t4 := X2 + Y2 ; t3 := t3 * t4 ; */
231 ec_field_element_add(&group->fm, &t3, &X1, &Y1);
232 ec_field_element_add(&group->fm, &t4, &X2, &Y2);
233 ec_field_element_mul(&group->fm, &t3, &t3, &t4);
234
235 /* t4 := t0 + t1 ; t3 := t3 - t4 ; t4 := X1 + Z1 ; */
236 ec_field_element_add(&group->fm, &t4, &t0, &t1);
237 ec_field_element_sub(&group->fm, &t3, &t3, &t4);
238 ec_field_element_add(&group->fm, &t4, &X1, &Z1);
239
240 /* t5 := X2 + Z2 ; t4 := t4 * t5 ; t5 := t0 + t2 ; */
241 ec_field_element_add(&group->fm, &t5, &X2, &Z2);
242 ec_field_element_mul(&group->fm, &t4, &t4, &t5);
243 ec_field_element_add(&group->fm, &t5, &t0, &t2);
244
245 /* t4 := t4 - t5 ; t5 := Y1 + Z1 ; X3 := Y2 + Z2 ; */
246 ec_field_element_sub(&group->fm, &t4, &t4, &t5);
247 ec_field_element_add(&group->fm, &t5, &Y1, &Z1);
248 ec_field_element_add(&group->fm, &X3, &Y2, &Z2);
249
250 /* t5 := t5 * X3 ; X3 := t1 + t2 ; t5 := t5 - X3 ; */
251 ec_field_element_mul(&group->fm, &t5, &t5, &X3);
252 ec_field_element_add(&group->fm, &X3, &t1, &t2);
253 ec_field_element_sub(&group->fm, &t5, &t5, &X3);
254
255 /* Z3 := a * t4 ; X3 := b3 * t2 ; Z3 := X3 + Z3 ; */
256 ec_field_element_mul(&group->fm, &Z3, &ga, &t4);
257 ec_field_element_mul(&group->fm, &X3, &b3, &t2);
258 ec_field_element_add(&group->fm, &Z3, &X3, &Z3);
259
260 /* X3 := t1 - Z3 ; Z3 := t1 + Z3 ; Y3 := X3 * Z3 ; */
261 ec_field_element_sub(&group->fm, &X3, &t1, &Z3);
262 ec_field_element_add(&group->fm, &Z3, &t1, &Z3);
263 ec_field_element_mul(&group->fm, &Y3, &X3, &Z3);
264
265 /* t1 := t0 + t0 ; t1 := t1 + t0 ; t2 := a * t2 ; */
266 ec_field_element_add(&group->fm, &t1, &t0, &t0);
267 ec_field_element_add(&group->fm, &t1, &t1, &t0);
268 ec_field_element_mul(&group->fm, &t2, &ga, &t2);
269
270 /* t4 := b3 * t4 ; t1 := t1 + t2 ; t2 := t0 - t2 ; */
271 ec_field_element_mul(&group->fm, &t4, &b3, &t4);
272 ec_field_element_add(&group->fm, &t1, &t1, &t2);
273 ec_field_element_sub(&group->fm, &t2, &t0, &t2);
274
275 /* t2 := a * t2 ; t4 := t4 + t2 ; t0 := t1 * t4 ; */
276 ec_field_element_mul(&group->fm, &t2, &ga, &t2);
277 ec_field_element_add(&group->fm, &t4, &t4, &t2);
278 ec_field_element_mul(&group->fm, &t0, &t1, &t4);
279
280 /* Y3 := Y3 + t0 ; t0 := t5 * t4 ; X3 := t3 * X3 ; */
281 ec_field_element_add(&group->fm, &Y3, &Y3, &t0);
282 ec_field_element_mul(&group->fm, &t0, &t5, &t4);
283 ec_field_element_mul(&group->fm, &X3, &t3, &X3);
284
285 /* X3 := X3 - t0 ; t0 := t3 * t1 ; Z3 := t5 * Z3 ; */
286 ec_field_element_sub(&group->fm, &X3, &X3, &t0);
287 ec_field_element_mul(&group->fm, &t0, &t3, &t1);
288 ec_field_element_mul(&group->fm, &Z3, &t5, &Z3);
289
290 /* Z3 := Z3 + t0 ; */
291 ec_field_element_add(&group->fm, &Z3, &Z3, &t0);
292
293 ec_field_element_copy(&r->fe_x, &X3);
294 ec_field_element_copy(&r->fe_y, &Y3);
295 ec_field_element_copy(&r->fe_z, &Z3);
296
297 return 1;
298}
299
300static int
301ec_point_add_a2(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
302 const EC_POINT *b, BN_CTX *ctx)
303{
304 EC_FIELD_ELEMENT X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3;
305 EC_FIELD_ELEMENT t0, t1, t2, t3, t4;
306 EC_FIELD_ELEMENT gb;
307
308 /*
309 * Complete, projective point addition for arbitrary prime order short
310 * Weierstrass curves with a = -3 - see https://eprint.iacr.org/2015/1060,
311 * algorithm 4 and appendix A.2.
312 */
313
314 ec_field_element_copy(&gb, &group->fe_b);
315
316 ec_field_element_copy(&X1, &a->fe_x);
317 ec_field_element_copy(&Y1, &a->fe_y);
318 ec_field_element_copy(&Z1, &a->fe_z);
319
320 ec_field_element_copy(&X2, &b->fe_x);
321 ec_field_element_copy(&Y2, &b->fe_y);
322 ec_field_element_copy(&Z2, &b->fe_z);
323
324 /* t0 := X1 * X2 ; t1 := Y1 * Y2 ; t2 := Z1 * Z2 ; */
325 ec_field_element_mul(&group->fm, &t0, &X1, &X2);
326 ec_field_element_mul(&group->fm, &t1, &Y1, &Y2);
327 ec_field_element_mul(&group->fm, &t2, &Z1, &Z2);
328
329 /* t3 := X1 + Y1 ; t4 := X2 + Y2 ; t3 := t3 * t4 ; */
330 ec_field_element_add(&group->fm, &t3, &X1, &Y1);
331 ec_field_element_add(&group->fm, &t4, &X2, &Y2);
332 ec_field_element_mul(&group->fm, &t3, &t3, &t4);
333
334 /* t4 := t0 + t1 ; t3 := t3 - t4 ; t4 := Y1 + Z1 ; */
335 ec_field_element_add(&group->fm, &t4, &t0, &t1);
336 ec_field_element_sub(&group->fm, &t3, &t3, &t4);
337 ec_field_element_add(&group->fm, &t4, &Y1, &Z1);
338
339 /* X3 := Y2 + Z2 ; t4 := t4 * X3 ; X3 := t1 + t2 ; */
340 ec_field_element_add(&group->fm, &X3, &Y2, &Z2);
341 ec_field_element_mul(&group->fm, &t4, &t4, &X3);
342 ec_field_element_add(&group->fm, &X3, &t1, &t2);
343
344 /* t4 := t4 - X3 ; X3 := X1 + Z1 ; Y3 := X2 + Z2 ; */
345 ec_field_element_sub(&group->fm, &t4, &t4, &X3);
346 ec_field_element_add(&group->fm, &X3, &X1, &Z1);
347 ec_field_element_add(&group->fm, &Y3, &X2, &Z2);
348
349 /* X3 := X3 * Y3 ; Y3 := t0 + t2 ; Y3 := X3 - Y3 ; */
350 ec_field_element_mul(&group->fm, &X3, &X3, &Y3);
351 ec_field_element_add(&group->fm, &Y3, &t0, &t2);
352 ec_field_element_sub(&group->fm, &Y3, &X3, &Y3);
353
354 /* Z3 := b * t2 ; X3 := Y3 - Z3 ; Z3 := X3 + X3 ; */
355 ec_field_element_mul(&group->fm, &Z3, &gb, &t2);
356 ec_field_element_sub(&group->fm, &X3, &Y3, &Z3);
357 ec_field_element_add(&group->fm, &Z3, &X3, &X3);
358
359 /* X3 := X3 + Z3 ; Z3 := t1 - X3 ; X3 := t1 + X3 ; */
360 ec_field_element_add(&group->fm, &X3, &X3, &Z3);
361 ec_field_element_sub(&group->fm, &Z3, &t1, &X3);
362 ec_field_element_add(&group->fm, &X3, &t1, &X3);
363
364 /* Y3 := b * Y3 ; t1 := t2 + t2 ; t2 := t1 + t2 ; */
365 ec_field_element_mul(&group->fm, &Y3, &gb, &Y3);
366 ec_field_element_add(&group->fm, &t1, &t2, &t2);
367 ec_field_element_add(&group->fm, &t2, &t1, &t2);
368
369 /* Y3 := Y3 - t2 ; Y3 := Y3 - t0 ; t1 := Y3 + Y3 ; */
370 ec_field_element_sub(&group->fm, &Y3, &Y3, &t2);
371 ec_field_element_sub(&group->fm, &Y3, &Y3, &t0);
372 ec_field_element_add(&group->fm, &t1, &Y3, &Y3);
373
374 /* Y3 := t1 + Y3 ; t1 := t0 + t0 ; t0 := t1 + t0 ; */
375 ec_field_element_add(&group->fm, &Y3, &t1, &Y3);
376 ec_field_element_add(&group->fm, &t1, &t0, &t0);
377 ec_field_element_add(&group->fm, &t0, &t1, &t0);
378
379 /* t0 := t0 - t2 ; t1 := t4 * Y3 ; t2 := t0 * Y3 ; */
380 ec_field_element_sub(&group->fm, &t0, &t0, &t2);
381 ec_field_element_mul(&group->fm, &t1, &t4, &Y3);
382 ec_field_element_mul(&group->fm, &t2, &t0, &Y3);
383
384 /* Y3 := X3 * Z3 ; Y3 := Y3 + t2 ; X3 := t3 * X3 ; */
385 ec_field_element_mul(&group->fm, &Y3, &X3, &Z3);
386 ec_field_element_add(&group->fm, &Y3, &Y3, &t2);
387 ec_field_element_mul(&group->fm, &X3, &t3, &X3);
388
389 /* X3 := X3 - t1 ; Z3 := t4 * Z3 ; t1 := t3 * t0 ; */
390 ec_field_element_sub(&group->fm, &X3, &X3, &t1);
391 ec_field_element_mul(&group->fm, &Z3, &t4, &Z3);
392 ec_field_element_mul(&group->fm, &t1, &t3, &t0);
393
394 /* Z3 := Z3 + t1 ; */
395 ec_field_element_add(&group->fm, &Z3, &Z3, &t1);
396
397 ec_field_element_copy(&r->fe_x, &X3);
398 ec_field_element_copy(&r->fe_y, &Y3);
399 ec_field_element_copy(&r->fe_z, &Z3);
400
401 return 1;
402}
403
404static int
405ec_point_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
406 const EC_POINT *b, BN_CTX *ctx)
407{
408 if (group->a_is_minus3)
409 return ec_point_add_a2(group, r, a, b, ctx);
410
411 return ec_point_add_a1(group, r, a, b, ctx);
412}
413
414static int
415ec_point_dbl_a1(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
416{
417 EC_FIELD_ELEMENT X1, Y1, Z1, X3, Y3, Z3;
418 EC_FIELD_ELEMENT b3, t0, t1, t2, t3;
419 EC_FIELD_ELEMENT ga, gb;
420
421 /*
422 * Exception-free point doubling for arbitrary prime order short
423 * Weierstrass curves with arbitrary a - see
424 * https://eprint.iacr.org/2015/1060, algorithm 3 and appendix A.1.
425 */
426
427 ec_field_element_copy(&ga, &group->fe_a);
428 ec_field_element_copy(&gb, &group->fe_b);
429
430 ec_field_element_copy(&X1, &a->fe_x);
431 ec_field_element_copy(&Y1, &a->fe_y);
432 ec_field_element_copy(&Z1, &a->fe_z);
433
434 /* b3 := 3 * b ; */
435 ec_field_element_add(&group->fm, &b3, &gb, &gb);
436 ec_field_element_add(&group->fm, &b3, &b3, &gb);
437
438 /* t0 := X^2; t1 := Y^2; t2 := Z^2 ; */
439 ec_field_element_sqr(&group->fm, &t0, &X1);
440 ec_field_element_sqr(&group->fm, &t1, &Y1);
441 ec_field_element_sqr(&group->fm, &t2, &Z1);
442
443 /* t3 := X * Y ; t3 := t3 + t3 ; Z3 := X * Z ; */
444 ec_field_element_mul(&group->fm, &t3, &X1, &Y1);
445 ec_field_element_add(&group->fm, &t3, &t3, &t3);
446 ec_field_element_mul(&group->fm, &Z3, &X1, &Z1);
447
448 /* Z3 := Z3 + Z3 ; X3 := a * Z3 ; Y3 := b3 * t2 ; */
449 ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
450 ec_field_element_mul(&group->fm, &X3, &ga, &Z3);
451 ec_field_element_mul(&group->fm, &Y3, &b3, &t2);
452
453 /* Y3 := X3 + Y3 ; X3 := t1 - Y3 ; Y3 := t1 + Y3 ; */
454 ec_field_element_add(&group->fm, &Y3, &X3, &Y3);
455 ec_field_element_sub(&group->fm, &X3, &t1, &Y3);
456 ec_field_element_add(&group->fm, &Y3, &t1, &Y3);
457
458 /* Y3 := X3 * Y3 ; X3 := t3 * X3 ; Z3 := b3 * Z3 ; */
459 ec_field_element_mul(&group->fm, &Y3, &X3, &Y3);
460 ec_field_element_mul(&group->fm, &X3, &t3, &X3);
461 ec_field_element_mul(&group->fm, &Z3, &b3, &Z3);
462
463 /* t2 := a * t2 ; t3 := t0 - t2 ; t3 := a * t3 ; */
464 ec_field_element_mul(&group->fm, &t2, &ga, &t2);
465 ec_field_element_sub(&group->fm, &t3, &t0, &t2);
466 ec_field_element_mul(&group->fm, &t3, &ga, &t3);
467
468 /* t3 := t3 + Z3 ; Z3 := t0 + t0 ; t0 := Z3 + t0 ; */
469 ec_field_element_add(&group->fm, &t3, &t3, &Z3);
470 ec_field_element_add(&group->fm, &Z3, &t0, &t0);
471 ec_field_element_add(&group->fm, &t0, &Z3, &t0);
472
473 /* t0 := t0 + t2 ; t0 := t0 * t3 ; Y3 := Y3 + t0 ; */
474 ec_field_element_add(&group->fm, &t0, &t0, &t2);
475 ec_field_element_mul(&group->fm, &t0, &t0, &t3);
476 ec_field_element_add(&group->fm, &Y3, &Y3, &t0);
477
478 /* t2 := Y * Z ; t2 := t2 + t2 ; t0 := t2 * t3 ; */
479 ec_field_element_mul(&group->fm, &t2, &Y1, &Z1);
480 ec_field_element_add(&group->fm, &t2, &t2, &t2);
481 ec_field_element_mul(&group->fm, &t0, &t2, &t3);
482
483 /* X3 := X3 - t0 ; Z3 := t2 * t1 ; Z3 := Z3 + Z3 ; */
484 ec_field_element_sub(&group->fm, &X3, &X3, &t0);
485 ec_field_element_mul(&group->fm, &Z3, &t2, &t1);
486 ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
487
488 /* Z3 := Z3 + Z3 ; */
489 ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
490
491 ec_field_element_copy(&r->fe_x, &X3);
492 ec_field_element_copy(&r->fe_y, &Y3);
493 ec_field_element_copy(&r->fe_z, &Z3);
494
495 return 1;
496}
497
498static int
499ec_point_dbl_a2(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
500{
501 EC_FIELD_ELEMENT X1, Y1, Z1, X3, Y3, Z3;
502 EC_FIELD_ELEMENT t0, t1, t2, t3;
503 EC_FIELD_ELEMENT ga, gb;
504
505 /*
506 * Exception-free point doubling for arbitrary prime order short
507 * Weierstrass curves with a = -3 - see https://eprint.iacr.org/2015/1060,
508 * algorithm 6 and appendix A.2.
509 */
510
511 ec_field_element_copy(&ga, &group->fe_a);
512 ec_field_element_copy(&gb, &group->fe_b);
513
514 ec_field_element_copy(&X1, &a->fe_x);
515 ec_field_element_copy(&Y1, &a->fe_y);
516 ec_field_element_copy(&Z1, &a->fe_z);
517
518 /* t0 := X^2; t1 := Y^2; t2 := Z^2 ; */
519 ec_field_element_sqr(&group->fm, &t0, &X1);
520 ec_field_element_sqr(&group->fm, &t1, &Y1);
521 ec_field_element_sqr(&group->fm, &t2, &Z1);
522
523 /* t3 := X * Y ; t3 := t3 + t3 ; Z3 := X * Z ; */
524 ec_field_element_mul(&group->fm, &t3, &X1, &Y1);
525 ec_field_element_add(&group->fm, &t3, &t3, &t3);
526 ec_field_element_mul(&group->fm, &Z3, &X1, &Z1);
527
528 /* Z3 := Z3 + Z3 ; Y3 := b * t2 ; Y3 := Y3 - Z3 ; */
529 ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
530 ec_field_element_mul(&group->fm, &Y3, &gb, &t2);
531 ec_field_element_sub(&group->fm, &Y3, &Y3, &Z3);
532
533 /* X3 := Y3 + Y3 ; Y3 := X3 + Y3 ; X3 := t1 - Y3 ; */
534 ec_field_element_add(&group->fm, &X3, &Y3, &Y3);
535 ec_field_element_add(&group->fm, &Y3, &X3, &Y3);
536 ec_field_element_sub(&group->fm, &X3, &t1, &Y3);
537
538 /* Y3 := t1 + Y3 ; Y3 := X3 * Y3 ; X3 := X3 * t3 ; */
539 ec_field_element_add(&group->fm, &Y3, &t1, &Y3);
540 ec_field_element_mul(&group->fm, &Y3, &X3, &Y3);
541 ec_field_element_mul(&group->fm, &X3, &X3, &t3);
542
543 /* t3 := t2 + t2 ; t2 := t2 + t3 ; Z3 := b * Z3 ; */
544 ec_field_element_add(&group->fm, &t3, &t2, &t2);
545 ec_field_element_add(&group->fm, &t2, &t2, &t3);
546 ec_field_element_mul(&group->fm, &Z3, &gb, &Z3);
547
548 /* Z3 := Z3 - t2 ; Z3 := Z3 - t0 ; t3 := Z3 + Z3 ; */
549 ec_field_element_sub(&group->fm, &Z3, &Z3, &t2);
550 ec_field_element_sub(&group->fm, &Z3, &Z3, &t0);
551 ec_field_element_add(&group->fm, &t3, &Z3, &Z3);
552
553 /* Z3 := Z3 + t3 ; t3 := t0 + t0 ; t0 := t3 + t0 ; */
554 ec_field_element_add(&group->fm, &Z3, &Z3, &t3);
555 ec_field_element_add(&group->fm, &t3, &t0, &t0);
556 ec_field_element_add(&group->fm, &t0, &t3, &t0);
557
558 /* t0 := t0 - t2 ; t0 := t0 * Z3 ; Y3 := Y3 + t0 ; */
559 ec_field_element_sub(&group->fm, &t0, &t0, &t2);
560 ec_field_element_mul(&group->fm, &t0, &t0, &Z3);
561 ec_field_element_add(&group->fm, &Y3, &Y3, &t0);
562
563 /* t0 := Y * Z ; t0 := t0 + t0 ; Z3 := t0 * Z3 ; */
564 ec_field_element_mul(&group->fm, &t0, &Y1, &Z1);
565 ec_field_element_add(&group->fm, &t0, &t0, &t0);
566 ec_field_element_mul(&group->fm, &Z3, &t0, &Z3);
567
568 /* X3 := X3 - Z3 ; Z3 := t0 * t1 ; Z3 := Z3 + Z3 ; */
569 ec_field_element_sub(&group->fm, &X3, &X3, &Z3);
570 ec_field_element_mul(&group->fm, &Z3, &t0, &t1);
571 ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
572
573 /* Z3 := Z3 + Z3 ; */
574 ec_field_element_add(&group->fm, &Z3, &Z3, &Z3);
575
576 ec_field_element_copy(&r->fe_x, &X3);
577 ec_field_element_copy(&r->fe_y, &Y3);
578 ec_field_element_copy(&r->fe_z, &Z3);
579
580 return 1;
581}
582
583static int
584ec_point_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
585{
586 if (group->a_is_minus3)
587 return ec_point_dbl_a2(group, r, a, ctx);
588
589 return ec_point_dbl_a1(group, r, a, ctx);
590}
591
592static int
593ec_point_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
594{
595 EC_FIELD_ELEMENT y;
596 BN_ULONG mask;
597 int i;
598
599 /*
600 * Invert the point by setting Y = p - Y, if Y is non-zero and the point
601 * is not at infinity.
602 */
603
604 mask = ~(0 - (ec_point_is_at_infinity(group, point) |
605 ec_field_element_is_zero(&group->fm, &point->fe_y)));
606
607 /* XXX - masked/conditional subtraction? */
608 ec_field_element_sub(&group->fm, &y, &group->fm.m, &point->fe_y);
609
610 for (i = 0; i < group->fm.n; i++)
611 point->fe_y.w[i] = (point->fe_y.w[i] & ~mask) | (y.w[i] & mask);
612
613 return 1;
614}
615
616static int
617ec_point_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
618{
619 EC_FIELD_ELEMENT sum, axz2, bz3, x3, y2z, z2;
620
621 /*
622 * Curve is defined by a Weierstrass equation y^2 = x^3 + a*x + b.
623 * The given point is in homogeneous projective coordinates
624 * (x = X/Z, y = Y/Z). Substitute and multiply by Z^3 in order to
625 * evaluate as zy^2 = x^3 + axz^2 + bz^3.
626 */
627
628 ec_field_element_sqr(&group->fm, &z2, &point->fe_z);
629
630 ec_field_element_sqr(&group->fm, &y2z, &point->fe_y);
631 ec_field_element_mul(&group->fm, &y2z, &y2z, &point->fe_z);
632
633 ec_field_element_sqr(&group->fm, &x3, &point->fe_x);
634 ec_field_element_mul(&group->fm, &x3, &x3, &point->fe_x);
635
636 ec_field_element_mul(&group->fm, &axz2, &group->fe_a, &point->fe_x);
637 ec_field_element_mul(&group->fm, &axz2, &axz2, &z2);
638
639 ec_field_element_mul(&group->fm, &bz3, &group->fe_b, &point->fe_z);
640 ec_field_element_mul(&group->fm, &bz3, &bz3, &z2);
641
642 ec_field_element_add(&group->fm, &sum, &x3, &axz2);
643 ec_field_element_add(&group->fm, &sum, &sum, &bz3);
644
645 return ec_field_element_equal(&group->fm, &y2z, &sum) |
646 ec_point_is_at_infinity(group, point);
647}
648
649static int
650ec_point_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
651{
652 EC_FIELD_ELEMENT ax, ay, bx, by;
653
654 /*
655 * Compare two points that have homogeneous projection coordinates, that
656 * is (X_a/Z_a, Y_a/Z_a) == (X_b/Z_b, Y_b/Z_b). Return -1 on error, 0 on
657 * equality and 1 on inequality.
658 *
659 * If a and b are both at infinity, Z_a and Z_b will both be zero,
660 * resulting in all values becoming zero, resulting in equality. If a is
661 * at infinity and b is not, then Y_a will be one and Z_b will be
662 * non-zero, hence Y_a * Z_b will be non-zero. Z_a will be zero, hence
663 * Y_b * Z_a will be zero, resulting in inequality. The same applies if
664 * b is at infinity and a is not.
665 */
666
667 ec_field_element_mul(&group->fm, &ax, &a->fe_x, &b->fe_z);
668 ec_field_element_mul(&group->fm, &ay, &a->fe_y, &b->fe_z);
669 ec_field_element_mul(&group->fm, &bx, &b->fe_x, &a->fe_z);
670 ec_field_element_mul(&group->fm, &by, &b->fe_y, &a->fe_z);
671
672 return 1 - (ec_field_element_equal(&group->fm, &ax, &bx) &
673 ec_field_element_equal(&group->fm, &ay, &by));
674}
675
676#if 0
677static int
678ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
679 BN_CTX *ctx)
680{
681 size_t i;
682
683 /* XXX */
684 for (i = 0; i < num; i++) {
685 if (!EC_POINT_make_affine(group, points[0], ctx))
686 return 0;
687 }
688
689 return 1;
690}
691#else
692
693static int
694ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
695 BN_CTX *ctx)
696{
697 BIGNUM **prod_Z = NULL;
698 BIGNUM *tmp, *tmp_Z;
699 size_t i;
700 int ret = 0;
701
702 if (num == 0)
703 return 1;
704
705 BN_CTX_start(ctx);
706
707 if ((tmp = BN_CTX_get(ctx)) == NULL)
708 goto err;
709 if ((tmp_Z = BN_CTX_get(ctx)) == NULL)
710 goto err;
711
712 if ((prod_Z = calloc(num, sizeof *prod_Z)) == NULL)
713 goto err;
714 for (i = 0; i < num; i++) {
715 if ((prod_Z[i] = BN_CTX_get(ctx)) == NULL)
716 goto err;
717 }
718
719 if (!BN_is_zero(points[0]->Z)) {
720 if (!bn_copy(prod_Z[0], points[0]->Z))
721 goto err;
722 } else {
723 if (!BN_one(prod_Z[0]))
724 goto err;
725 }
726
727 for (i = 1; i < num; i++) {
728 if (!BN_is_zero(points[i]->Z)) {
729 if (!BN_mod_mul(prod_Z[i], prod_Z[i - 1], points[i]->Z,
730 group->p, ctx))
731 goto err;
732 } else {
733 if (!bn_copy(prod_Z[i], prod_Z[i - 1]))
734 goto err;
735 }
736 }
737
738 if (!BN_mod_inverse_nonct(tmp, prod_Z[num - 1], group->p, ctx)) {
739 ECerror(ERR_R_BN_LIB);
740 goto err;
741 }
742
743 for (i = num - 1; i > 0; i--) {
744 if (BN_is_zero(points[i]->Z))
745 continue;
746
747 if (!BN_mod_mul(tmp_Z, prod_Z[i - 1], tmp, group->p, ctx))
748 goto err;
749 if (!BN_mod_mul(tmp, tmp, points[i]->Z, group->p, ctx))
750 goto err;
751 if (!bn_copy(points[i]->Z, tmp_Z))
752 goto err;
753 }
754
755 for (i = 0; i < num; i++) {
756 EC_POINT *p = points[i];
757
758 if (BN_is_zero(p->Z))
759 continue;
760
761 if (!BN_mod_mul(p->X, p->X, p->Z, group->p, ctx))
762 goto err;
763 if (!BN_mod_mul(p->Y, p->Y, p->Z, group->p, ctx))
764 goto err;
765
766 if (!BN_one(p->Z))
767 goto err;
768 }
769
770 ret = 1;
771
772 err:
773 BN_CTX_end(ctx);
774 free(prod_Z);
775
776 return ret;
777}
778#endif
779
780static void
781ec_point_select(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
782 const EC_POINT *b, int conditional)
783{
784 ec_field_element_select(&group->fm, &r->fe_x, &a->fe_x, &b->fe_x, conditional);
785 ec_field_element_select(&group->fm, &r->fe_y, &a->fe_y, &b->fe_y, conditional);
786 ec_field_element_select(&group->fm, &r->fe_z, &a->fe_z, &b->fe_z, conditional);
787}
788
789static int
790ec_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, const EC_POINT *point,
791 BN_CTX *ctx)
792{
793 BIGNUM *cardinality;
794 EC_POINT *multiples[15];
795 EC_POINT *rr = NULL, *t = NULL;
796 uint8_t *scalar_bytes = NULL;
797 int scalar_len = 0;
798 uint8_t j, wv;
799 int conditional, i;
800 int ret = 0;
801
802 memset(multiples, 0, sizeof(multiples));
803
804 BN_CTX_start(ctx);
805
806 /* XXX - consider blinding. */
807
808 if ((cardinality = BN_CTX_get(ctx)) == NULL)
809 goto err;
810 if (!BN_mul(cardinality, group->order, group->cofactor, ctx))
811 goto err;
812
813 /* XXX - handle scalar > cardinality and/or negative. */
814
815 /* Convert scalar into big endian bytes. */
816 scalar_len = BN_num_bytes(cardinality);
817 if ((scalar_bytes = calloc(1, scalar_len)) == NULL)
818 goto err;
819 if (!BN_bn2binpad(scalar, scalar_bytes, scalar_len))
820 goto err;
821
822 /* Compute multiples of point. */
823 if ((multiples[0] = EC_POINT_dup(point, group)) == NULL)
824 goto err;
825 for (i = 1; i < 15; i += 2) {
826 if ((multiples[i] = EC_POINT_new(group)) == NULL)
827 goto err;
828 if (!EC_POINT_dbl(group, multiples[i], multiples[i / 2], ctx))
829 goto err;
830 if ((multiples[i + 1] = EC_POINT_new(group)) == NULL)
831 goto err;
832 if (!EC_POINT_add(group, multiples[i + 1], multiples[i], point, ctx))
833 goto err;
834 }
835
836 if ((rr = EC_POINT_new(group)) == NULL)
837 goto err;
838 if ((t = EC_POINT_new(group)) == NULL)
839 goto err;
840
841 if (!EC_POINT_set_to_infinity(group, rr))
842 goto err;
843
844 for (i = 0; i < scalar_len; i++) {
845 if (i != 0) {
846 if (!EC_POINT_dbl(group, rr, rr, ctx))
847 goto err;
848 if (!EC_POINT_dbl(group, rr, rr, ctx))
849 goto err;
850 if (!EC_POINT_dbl(group, rr, rr, ctx))
851 goto err;
852 if (!EC_POINT_dbl(group, rr, rr, ctx))
853 goto err;
854 }
855
856 if (!EC_POINT_set_to_infinity(group, t))
857 goto err;
858
859 wv = scalar_bytes[i] >> 4;
860 for (j = 1; j < 16; j++) {
861 conditional = crypto_ct_eq_u8(j, wv);
862 ec_point_select(group, t, t, multiples[j - 1], conditional);
863 }
864 if (!EC_POINT_add(group, rr, rr, t, ctx))
865 goto err;
866
867 if (!EC_POINT_dbl(group, rr, rr, ctx))
868 goto err;
869 if (!EC_POINT_dbl(group, rr, rr, ctx))
870 goto err;
871 if (!EC_POINT_dbl(group, rr, rr, ctx))
872 goto err;
873 if (!EC_POINT_dbl(group, rr, rr, ctx))
874 goto err;
875
876 if (!EC_POINT_set_to_infinity(group, t))
877 goto err;
878
879 wv = scalar_bytes[i] & 0xf;
880 for (j = 1; j < 16; j++) {
881 conditional = crypto_ct_eq_u8(j, wv);
882 ec_point_select(group, t, t, multiples[j - 1], conditional);
883 }
884 if (!EC_POINT_add(group, rr, rr, t, ctx))
885 goto err;
886 }
887
888 if (!EC_POINT_copy(r, rr))
889 goto err;
890
891 ret = 1;
892
893 err:
894 for (i = 0; i < 15; i++)
895 EC_POINT_free(multiples[i]);
896
897 EC_POINT_free(rr);
898 EC_POINT_free(t);
899
900 freezero(scalar_bytes, scalar_len);
901
902 BN_CTX_end(ctx);
903
904 return ret;
905}
906
907static int
908ec_mul_single_ct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
909 const EC_POINT *point, BN_CTX *ctx)
910{
911 return ec_mul(group, r, scalar, point, ctx);
912}
913
914static int
915ec_mul_double_nonct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar1,
916 const EC_POINT *point1, const BIGNUM *scalar2, const EC_POINT *point2,
917 BN_CTX *ctx)
918{
919 return ec_wnaf_mul(group, r, scalar1, point1, scalar2, point2, ctx);
920}
921
922static const EC_METHOD ec_GFp_homogeneous_projective_method = {
923 .group_set_curve = ec_group_set_curve,
924 .group_get_curve = ec_group_get_curve,
925 .point_set_to_infinity = ec_point_set_to_infinity,
926 .point_is_at_infinity = ec_point_is_at_infinity,
927 .point_set_affine_coordinates = ec_point_set_affine_coordinates,
928 .point_get_affine_coordinates = ec_point_get_affine_coordinates,
929 .add = ec_point_add,
930 .dbl = ec_point_dbl,
931 .invert = ec_point_invert,
932 .point_is_on_curve = ec_point_is_on_curve,
933 .point_cmp = ec_point_cmp,
934 .points_make_affine = ec_points_make_affine,
935 .mul_single_ct = ec_mul_single_ct,
936 .mul_double_nonct = ec_mul_double_nonct,
937};
938
939const EC_METHOD *
940EC_GFp_homogeneous_projective_method(void)
941{
942 return &ec_GFp_homogeneous_projective_method;
943}
diff --git a/src/lib/libcrypto/ec/ecp_methods.c b/src/lib/libcrypto/ec/ecp_methods.c
index 5adc049ab7..fcb48d9e33 100644
--- a/src/lib/libcrypto/ec/ecp_methods.c
+++ b/src/lib/libcrypto/ec/ecp_methods.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ecp_methods.c,v 1.46 2025/05/10 05:54:38 tb Exp $ */ 1/* $OpenBSD: ecp_methods.c,v 1.47 2025/05/24 08:25:58 jsing Exp $ */
2/* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> 2/* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
3 * for the OpenSSL project. 3 * for the OpenSSL project.
4 * Includes code written by Bodo Moeller for the OpenSSL project. 4 * Includes code written by Bodo Moeller for the OpenSSL project.
@@ -180,6 +180,21 @@ ec_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b,
180} 180}
181 181
182static int 182static int
183ec_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
184{
185 BN_zero(point->Z);
186 point->Z_is_one = 0;
187
188 return 1;
189}
190
191static int
192ec_point_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
193{
194 return BN_is_zero(point->Z);
195}
196
197static int
183ec_point_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) 198ec_point_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
184{ 199{
185 BIGNUM *rh, *tmp, *Z4, *Z6; 200 BIGNUM *rh, *tmp, *Z4, *Z6;
@@ -1281,6 +1296,8 @@ ec_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1281static const EC_METHOD ec_GFp_simple_method = { 1296static const EC_METHOD ec_GFp_simple_method = {
1282 .group_set_curve = ec_group_set_curve, 1297 .group_set_curve = ec_group_set_curve,
1283 .group_get_curve = ec_group_get_curve, 1298 .group_get_curve = ec_group_get_curve,
1299 .point_set_to_infinity = ec_point_set_to_infinity,
1300 .point_is_at_infinity = ec_point_is_at_infinity,
1284 .point_is_on_curve = ec_point_is_on_curve, 1301 .point_is_on_curve = ec_point_is_on_curve,
1285 .point_cmp = ec_point_cmp, 1302 .point_cmp = ec_point_cmp,
1286 .point_set_affine_coordinates = ec_point_set_affine_coordinates, 1303 .point_set_affine_coordinates = ec_point_set_affine_coordinates,
@@ -1304,6 +1321,8 @@ EC_GFp_simple_method(void)
1304static const EC_METHOD ec_GFp_mont_method = { 1321static const EC_METHOD ec_GFp_mont_method = {
1305 .group_set_curve = ec_mont_group_set_curve, 1322 .group_set_curve = ec_mont_group_set_curve,
1306 .group_get_curve = ec_group_get_curve, 1323 .group_get_curve = ec_group_get_curve,
1324 .point_set_to_infinity = ec_point_set_to_infinity,
1325 .point_is_at_infinity = ec_point_is_at_infinity,
1307 .point_is_on_curve = ec_point_is_on_curve, 1326 .point_is_on_curve = ec_point_is_on_curve,
1308 .point_cmp = ec_point_cmp, 1327 .point_cmp = ec_point_cmp,
1309 .point_set_affine_coordinates = ec_point_set_affine_coordinates, 1328 .point_set_affine_coordinates = ec_point_set_affine_coordinates,