diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/ec/ecp_methods.c | 212 |
1 files changed, 93 insertions, 119 deletions
diff --git a/src/lib/libcrypto/ec/ecp_methods.c b/src/lib/libcrypto/ec/ecp_methods.c index 65dfd5ef00..a4713bdcdc 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.9 2024/11/17 08:19:08 tb Exp $ */ | 1 | /* $OpenBSD: ecp_methods.c,v 1.10 2024/11/30 16:18:01 tb 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. |
| @@ -1123,9 +1123,8 @@ static int | |||
| 1123 | ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], | 1123 | ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], |
| 1124 | BN_CTX *ctx) | 1124 | BN_CTX *ctx) |
| 1125 | { | 1125 | { |
| 1126 | BIGNUM *tmp0, *tmp1; | 1126 | BIGNUM **prod_Z = NULL; |
| 1127 | size_t pow2 = 0; | 1127 | BIGNUM *tmp, *tmp_Z; |
| 1128 | BIGNUM **heap = NULL; | ||
| 1129 | size_t i; | 1128 | size_t i; |
| 1130 | int ret = 0; | 1129 | int ret = 0; |
| 1131 | 1130 | ||
| @@ -1134,141 +1133,120 @@ ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], | |||
| 1134 | 1133 | ||
| 1135 | BN_CTX_start(ctx); | 1134 | BN_CTX_start(ctx); |
| 1136 | 1135 | ||
| 1137 | if ((tmp0 = BN_CTX_get(ctx)) == NULL) | 1136 | if ((tmp = BN_CTX_get(ctx)) == NULL) |
| 1138 | goto err; | 1137 | goto err; |
| 1139 | if ((tmp1 = BN_CTX_get(ctx)) == NULL) | 1138 | if ((tmp_Z = BN_CTX_get(ctx)) == NULL) |
| 1140 | goto err; | 1139 | goto err; |
| 1141 | 1140 | ||
| 1142 | /* | 1141 | if ((prod_Z = calloc(num, sizeof *prod_Z)) == NULL) |
| 1143 | * Before converting the individual points, compute inverses of all Z | ||
| 1144 | * values. Modular inversion is rather slow, but luckily we can do | ||
| 1145 | * with a single explicit inversion, plus about 3 multiplications per | ||
| 1146 | * input value. | ||
| 1147 | */ | ||
| 1148 | |||
| 1149 | pow2 = 1; | ||
| 1150 | while (num > pow2) | ||
| 1151 | pow2 <<= 1; | ||
| 1152 | /* | ||
| 1153 | * Now pow2 is the smallest power of 2 satifsying pow2 >= num. We | ||
| 1154 | * need twice that. | ||
| 1155 | */ | ||
| 1156 | pow2 <<= 1; | ||
| 1157 | |||
| 1158 | heap = reallocarray(NULL, pow2, sizeof heap[0]); | ||
| 1159 | if (heap == NULL) | ||
| 1160 | goto err; | 1142 | goto err; |
| 1143 | for (i = 0; i < num; i++) { | ||
| 1144 | if ((prod_Z[i] = BN_new()) == NULL) | ||
| 1145 | goto err; | ||
| 1146 | } | ||
| 1161 | 1147 | ||
| 1162 | /* | 1148 | /* |
| 1163 | * The array is used as a binary tree, exactly as in heapsort: | 1149 | * Set prod_Z[i] to the product of points[0]->Z, ..., points[i]->Z, |
| 1164 | * | 1150 | * skipping any zero-valued inputs (pretend that they're 1). |
| 1165 | * heap[1] heap[2] heap[3] heap[4] heap[5] | ||
| 1166 | * heap[6] heap[7] heap[8]heap[9] heap[10]heap[11] | ||
| 1167 | * heap[12]heap[13] heap[14] heap[15] | ||
| 1168 | * | ||
| 1169 | * We put the Z's in the last line; then we set each other node to the | ||
| 1170 | * product of its two child-nodes (where empty or 0 entries are | ||
| 1171 | * treated as ones); then we invert heap[1]; then we invert each | ||
| 1172 | * other node by replacing it by the product of its parent (after | ||
| 1173 | * inversion) and its sibling (before inversion). | ||
| 1174 | */ | 1151 | */ |
| 1175 | heap[0] = NULL; | ||
| 1176 | for (i = pow2 / 2 - 1; i > 0; i--) | ||
| 1177 | heap[i] = NULL; | ||
| 1178 | for (i = 0; i < num; i++) | ||
| 1179 | heap[pow2 / 2 + i] = &points[i]->Z; | ||
| 1180 | for (i = pow2 / 2 + num; i < pow2; i++) | ||
| 1181 | heap[i] = NULL; | ||
| 1182 | |||
| 1183 | /* set each node to the product of its children */ | ||
| 1184 | for (i = pow2 / 2 - 1; i > 0; i--) { | ||
| 1185 | heap[i] = BN_new(); | ||
| 1186 | if (heap[i] == NULL) | ||
| 1187 | goto err; | ||
| 1188 | 1152 | ||
| 1189 | if (heap[2 * i] != NULL) { | 1153 | if (!BN_is_zero(&points[0]->Z)) { |
| 1190 | if ((heap[2 * i + 1] == NULL) || BN_is_zero(heap[2 * i + 1])) { | 1154 | if (!bn_copy(prod_Z[0], &points[0]->Z)) |
| 1191 | if (!bn_copy(heap[i], heap[2 * i])) | 1155 | goto err; |
| 1192 | goto err; | 1156 | } else { |
| 1193 | } else { | 1157 | if (group->meth->field_set_to_one != NULL) { |
| 1194 | if (BN_is_zero(heap[2 * i])) { | 1158 | if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) |
| 1195 | if (!bn_copy(heap[i], heap[2 * i + 1])) | 1159 | goto err; |
| 1196 | goto err; | 1160 | } else { |
| 1197 | } else { | 1161 | if (!BN_one(prod_Z[0])) |
| 1198 | if (!group->meth->field_mul(group, heap[i], | 1162 | goto err; |
| 1199 | heap[2 * i], heap[2 * i + 1], ctx)) | ||
| 1200 | goto err; | ||
| 1201 | } | ||
| 1202 | } | ||
| 1203 | } | 1163 | } |
| 1204 | } | 1164 | } |
| 1205 | 1165 | ||
| 1206 | /* invert heap[1] */ | 1166 | for (i = 1; i < num; i++) { |
| 1207 | if (!BN_is_zero(heap[1])) { | 1167 | if (!BN_is_zero(&points[i]->Z)) { |
| 1208 | if (BN_mod_inverse_ct(heap[1], heap[1], &group->field, ctx) == NULL) { | 1168 | if (!group->meth->field_mul(group, prod_Z[i], |
| 1209 | ECerror(ERR_R_BN_LIB); | 1169 | prod_Z[i - 1], &points[i]->Z, ctx)) |
| 1210 | goto err; | 1170 | goto err; |
| 1171 | } else { | ||
| 1172 | if (!bn_copy(prod_Z[i], prod_Z[i - 1])) | ||
| 1173 | goto err; | ||
| 1211 | } | 1174 | } |
| 1212 | } | 1175 | } |
| 1176 | |||
| 1177 | /* | ||
| 1178 | * Now use a single explicit inversion to replace every non-zero | ||
| 1179 | * points[i]->Z by its inverse. | ||
| 1180 | */ | ||
| 1181 | if (!BN_mod_inverse_nonct(tmp, prod_Z[num - 1], &group->field, ctx)) { | ||
| 1182 | ECerror(ERR_R_BN_LIB); | ||
| 1183 | goto err; | ||
| 1184 | } | ||
| 1185 | |||
| 1213 | if (group->meth->field_encode != NULL) { | 1186 | if (group->meth->field_encode != NULL) { |
| 1214 | /* | 1187 | /* |
| 1215 | * in the Montgomery case, we just turned R*H (representing | 1188 | * In the Montgomery case we just turned R*H (representing H) |
| 1216 | * H) into 1/(R*H), but we need R*(1/H) (representing | 1189 | * into 1/(R*H), but we need R*(1/H) (representing 1/H); i.e., |
| 1217 | * 1/H); i.e. we have need to multiply by the Montgomery | 1190 | * we need to multiply by the Montgomery factor twice. |
| 1218 | * factor twice | ||
| 1219 | */ | 1191 | */ |
| 1220 | if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) | 1192 | if (!group->meth->field_encode(group, tmp, tmp, ctx)) |
| 1221 | goto err; | 1193 | goto err; |
| 1222 | if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) | 1194 | if (!group->meth->field_encode(group, tmp, tmp, ctx)) |
| 1223 | goto err; | 1195 | goto err; |
| 1224 | } | 1196 | } |
| 1225 | /* set other heap[i]'s to their inverses */ | 1197 | |
| 1226 | for (i = 2; i < pow2 / 2 + num; i += 2) { | 1198 | for (i = num - 1; i > 0; i--) { |
| 1227 | /* i is even */ | 1199 | /* |
| 1228 | if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1])) { | 1200 | * Loop invariant: tmp is the product of the inverses of |
| 1229 | if (!group->meth->field_mul(group, tmp0, heap[i / 2], heap[i + 1], ctx)) | 1201 | * points[0]->Z, ..., points[i]->Z (zero-valued inputs skipped). |
| 1230 | goto err; | 1202 | */ |
| 1231 | if (!group->meth->field_mul(group, tmp1, heap[i / 2], heap[i], ctx)) | 1203 | if (BN_is_zero(&points[i]->Z)) |
| 1232 | goto err; | 1204 | continue; |
| 1233 | if (!bn_copy(heap[i], tmp0)) | 1205 | |
| 1234 | goto err; | 1206 | /* Set tmp_Z to the inverse of points[i]->Z. */ |
| 1235 | if (!bn_copy(heap[i + 1], tmp1)) | 1207 | if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx)) |
| 1236 | goto err; | 1208 | goto err; |
| 1237 | } else { | 1209 | /* Adjust tmp to satisfy loop invariant. */ |
| 1238 | if (!bn_copy(heap[i], heap[i / 2])) | 1210 | if (!group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx)) |
| 1239 | goto err; | 1211 | goto err; |
| 1240 | } | 1212 | /* Replace points[i]->Z by its inverse. */ |
| 1213 | if (!bn_copy(&points[i]->Z, tmp_Z)) | ||
| 1214 | goto err; | ||
| 1241 | } | 1215 | } |
| 1242 | 1216 | ||
| 1243 | /* | 1217 | if (!BN_is_zero(&points[0]->Z)) { |
| 1244 | * we have replaced all non-zero Z's by their inverses, now fix up | 1218 | /* Replace points[0]->Z by its inverse. */ |
| 1245 | * all the points | 1219 | if (!bn_copy(&points[0]->Z, tmp)) |
| 1246 | */ | 1220 | goto err; |
| 1221 | } | ||
| 1222 | |||
| 1223 | /* Finally, fix up the X and Y coordinates for all points. */ | ||
| 1247 | for (i = 0; i < num; i++) { | 1224 | for (i = 0; i < num; i++) { |
| 1248 | EC_POINT *p = points[i]; | 1225 | EC_POINT *p = points[i]; |
| 1249 | 1226 | ||
| 1250 | if (!BN_is_zero(&p->Z)) { | 1227 | if (BN_is_zero(&p->Z)) |
| 1251 | /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ | 1228 | continue; |
| 1252 | 1229 | ||
| 1253 | if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx)) | 1230 | /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ |
| 1254 | goto err; | 1231 | |
| 1255 | if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx)) | 1232 | if (!group->meth->field_sqr(group, tmp, &p->Z, ctx)) |
| 1256 | goto err; | 1233 | goto err; |
| 1234 | if (!group->meth->field_mul(group, &p->X, &p->X, tmp, ctx)) | ||
| 1235 | goto err; | ||
| 1257 | 1236 | ||
| 1258 | if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx)) | 1237 | if (!group->meth->field_mul(group, tmp, tmp, &p->Z, ctx)) |
| 1238 | goto err; | ||
| 1239 | if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) | ||
| 1240 | goto err; | ||
| 1241 | |||
| 1242 | if (group->meth->field_set_to_one != NULL) { | ||
| 1243 | if (!group->meth->field_set_to_one(group, &p->Z, ctx)) | ||
| 1259 | goto err; | 1244 | goto err; |
| 1260 | if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx)) | 1245 | } else { |
| 1246 | if (!BN_one(&p->Z)) | ||
| 1261 | goto err; | 1247 | goto err; |
| 1262 | |||
| 1263 | if (group->meth->field_set_to_one != NULL) { | ||
| 1264 | if (!group->meth->field_set_to_one(group, &p->Z, ctx)) | ||
| 1265 | goto err; | ||
| 1266 | } else { | ||
| 1267 | if (!BN_one(&p->Z)) | ||
| 1268 | goto err; | ||
| 1269 | } | ||
| 1270 | p->Z_is_one = 1; | ||
| 1271 | } | 1248 | } |
| 1249 | p->Z_is_one = 1; | ||
| 1272 | } | 1250 | } |
| 1273 | 1251 | ||
| 1274 | ret = 1; | 1252 | ret = 1; |
| @@ -1276,16 +1254,12 @@ ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], | |||
| 1276 | err: | 1254 | err: |
| 1277 | BN_CTX_end(ctx); | 1255 | BN_CTX_end(ctx); |
| 1278 | 1256 | ||
| 1279 | if (heap != NULL) { | 1257 | if (prod_Z != NULL) { |
| 1280 | /* | 1258 | for (i = 0; i < num; i++) |
| 1281 | * heap[pow2/2] .. heap[pow2-1] have not been allocated | 1259 | BN_free(prod_Z[i]); |
| 1282 | * locally! | 1260 | free(prod_Z); |
| 1283 | */ | ||
| 1284 | for (i = pow2 / 2 - 1; i > 0; i--) { | ||
| 1285 | BN_free(heap[i]); | ||
| 1286 | } | ||
| 1287 | free(heap); | ||
| 1288 | } | 1261 | } |
| 1262 | |||
| 1289 | return ret; | 1263 | return ret; |
| 1290 | } | 1264 | } |
| 1291 | 1265 | ||
