diff options
| author | tb <> | 2024-11-02 09:21:04 +0000 |
|---|---|---|
| committer | tb <> | 2024-11-02 09:21:04 +0000 |
| commit | b5e79cb0c7e63e52ff53937b6156d4525d360b34 (patch) | |
| tree | 21c0cdcf944a9def5acf5c52f126ad2b8e696828 /src | |
| parent | 5567406332339692172e16ae341f814c8f5e76f1 (diff) | |
| download | openbsd-b5e79cb0c7e63e52ff53937b6156d4525d360b34.tar.gz openbsd-b5e79cb0c7e63e52ff53937b6156d4525d360b34.tar.bz2 openbsd-b5e79cb0c7e63e52ff53937b6156d4525d360b34.zip | |
Rewrite/clean up ec_GFp_simple_set_compressed_coordinates()
The biggest change here is that the computation is now performed in the
Montgomery domain if we have a Montgomery curve. This avoids constant
checking whether need to use plain field operations or whether we can
use curve-specific ones.
Use a few better variable names and stop attempting to figure out whether
the operation failed due to an error in BN_mod_sqrt() or a bad point. All
in all this only shaves off 10 lines, but it is astounding what a few tweaks
can do to code that looked like Rome in 455 AD.
with/ok jsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/ec/ecp_oct.c | 110 |
1 files changed, 48 insertions, 62 deletions
diff --git a/src/lib/libcrypto/ec/ecp_oct.c b/src/lib/libcrypto/ec/ecp_oct.c index 6daab41870..85467a4143 100644 --- a/src/lib/libcrypto/ec/ecp_oct.c +++ b/src/lib/libcrypto/ec/ecp_oct.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: ecp_oct.c,v 1.31 2024/10/31 05:47:37 tb Exp $ */ | 1 | /* $OpenBSD: ecp_oct.c,v 1.32 2024/11/02 09:21:04 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. |
| @@ -72,21 +72,17 @@ | |||
| 72 | 72 | ||
| 73 | int | 73 | int |
| 74 | ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, | 74 | ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, |
| 75 | EC_POINT *point, const BIGNUM *x_, int y_bit, BN_CTX *ctx) | 75 | EC_POINT *point, const BIGNUM *in_x, int y_bit, BN_CTX *ctx) |
| 76 | { | 76 | { |
| 77 | BIGNUM *tmp1, *tmp2, *x, *y; | 77 | const BIGNUM *p = &group->field, *a = &group->a, *b = &group->b; |
| 78 | BIGNUM *w, *x, *y; | ||
| 78 | int ret = 0; | 79 | int ret = 0; |
| 79 | 80 | ||
| 80 | /* clear error queue */ | ||
| 81 | ERR_clear_error(); | ||
| 82 | |||
| 83 | y_bit = (y_bit != 0); | 81 | y_bit = (y_bit != 0); |
| 84 | 82 | ||
| 85 | BN_CTX_start(ctx); | 83 | BN_CTX_start(ctx); |
| 86 | 84 | ||
| 87 | if ((tmp1 = BN_CTX_get(ctx)) == NULL) | 85 | if ((w = BN_CTX_get(ctx)) == NULL) |
| 88 | goto err; | ||
| 89 | if ((tmp2 = BN_CTX_get(ctx)) == NULL) | ||
| 90 | goto err; | 86 | goto err; |
| 91 | if ((x = BN_CTX_get(ctx)) == NULL) | 87 | if ((x = BN_CTX_get(ctx)) == NULL) |
| 92 | goto err; | 88 | goto err; |
| @@ -94,83 +90,73 @@ ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, | |||
| 94 | goto err; | 90 | goto err; |
| 95 | 91 | ||
| 96 | /* | 92 | /* |
| 97 | * Recover y. We have a Weierstrass equation y^2 = x^3 + a*x + b, so | 93 | * Weierstrass equation: y^2 = x^3 + ax + b, so y is one of the |
| 98 | * y is one of the square roots of x^3 + a*x + b. | 94 | * square roots of x^3 + ax + b. The y-bit indicates which one. |
| 99 | */ | 95 | */ |
| 100 | 96 | ||
| 101 | /* tmp1 := x^3 */ | 97 | /* XXX - should we not insist on 0 <= x < p instead? */ |
| 102 | if (!BN_nnmod(x, x_, &group->field, ctx)) | 98 | if (!BN_nnmod(x, in_x, p, ctx)) |
| 103 | goto err; | 99 | goto err; |
| 104 | if (group->meth->field_decode == NULL) { | 100 | |
| 105 | /* field_{sqr,mul} work on standard representation */ | 101 | if (group->meth->field_encode != NULL) { |
| 106 | if (!group->meth->field_sqr(group, tmp2, x_, ctx)) | 102 | if (!group->meth->field_encode(group, x, x, ctx)) |
| 107 | goto err; | ||
| 108 | if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) | ||
| 109 | goto err; | ||
| 110 | } else { | ||
| 111 | if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) | ||
| 112 | goto err; | ||
| 113 | if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) | ||
| 114 | goto err; | 103 | goto err; |
| 115 | } | 104 | } |
| 116 | 105 | ||
| 117 | /* tmp1 := tmp1 + a*x */ | 106 | /* y = x^3 */ |
| 107 | if (!group->meth->field_sqr(group, y, x, ctx)) | ||
| 108 | goto err; | ||
| 109 | if (!group->meth->field_mul(group, y, y, x, ctx)) | ||
| 110 | goto err; | ||
| 111 | |||
| 112 | /* y += ax */ | ||
| 118 | if (group->a_is_minus3) { | 113 | if (group->a_is_minus3) { |
| 119 | if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) | 114 | if (!BN_mod_lshift1_quick(w, x, p)) |
| 120 | goto err; | 115 | goto err; |
| 121 | if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) | 116 | if (!BN_mod_add_quick(w, w, x, p)) |
| 122 | goto err; | 117 | goto err; |
| 123 | if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) | 118 | if (!BN_mod_sub_quick(y, y, w, p)) |
| 124 | goto err; | 119 | goto err; |
| 125 | } else { | 120 | } else { |
| 126 | if (group->meth->field_decode) { | 121 | if (!group->meth->field_mul(group, w, a, x, ctx)) |
| 127 | if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) | 122 | goto err; |
| 128 | goto err; | 123 | if (!BN_mod_add_quick(y, y, w, p)) |
| 129 | if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) | ||
| 130 | goto err; | ||
| 131 | } else { | ||
| 132 | /* field_mul works on standard representation */ | ||
| 133 | if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) | ||
| 134 | goto err; | ||
| 135 | } | ||
| 136 | |||
| 137 | if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) | ||
| 138 | goto err; | 124 | goto err; |
| 139 | } | 125 | } |
| 140 | 126 | ||
| 141 | /* tmp1 := tmp1 + b */ | 127 | /* y += b */ |
| 128 | if (!BN_mod_add_quick(y, y, b, p)) | ||
| 129 | goto err; | ||
| 130 | |||
| 142 | if (group->meth->field_decode != NULL) { | 131 | if (group->meth->field_decode != NULL) { |
| 143 | if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) | 132 | if (!group->meth->field_decode(group, x, x, ctx)) |
| 144 | goto err; | 133 | goto err; |
| 145 | if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) | 134 | if (!group->meth->field_decode(group, y, y, ctx)) |
| 146 | goto err; | ||
| 147 | } else { | ||
| 148 | if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) | ||
| 149 | goto err; | 135 | goto err; |
| 150 | } | 136 | } |
| 151 | 137 | ||
| 152 | if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { | 138 | if (!BN_mod_sqrt(y, y, p, ctx)) { |
| 153 | unsigned long err = ERR_peek_last_error(); | 139 | ECerror(EC_R_INVALID_COMPRESSED_POINT); |
| 140 | goto err; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (y_bit == BN_is_odd(y)) | ||
| 144 | goto done; | ||
| 154 | 145 | ||
| 155 | if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { | 146 | if (BN_is_zero(y)) { |
| 156 | ERR_clear_error(); | 147 | ECerror(EC_R_INVALID_COMPRESSION_BIT); |
| 157 | ECerror(EC_R_INVALID_COMPRESSED_POINT); | ||
| 158 | } else | ||
| 159 | ECerror(ERR_R_BN_LIB); | ||
| 160 | goto err; | 148 | goto err; |
| 161 | } | 149 | } |
| 150 | if (!BN_usub(y, &group->field, y)) | ||
| 151 | goto err; | ||
| 152 | |||
| 162 | if (y_bit != BN_is_odd(y)) { | 153 | if (y_bit != BN_is_odd(y)) { |
| 163 | if (BN_is_zero(y)) { | 154 | /* Can only happen if p is even and should not be reachable. */ |
| 164 | ECerror(EC_R_INVALID_COMPRESSION_BIT); | 155 | ECerror(ERR_R_INTERNAL_ERROR); |
| 165 | goto err; | 156 | goto err; |
| 166 | } | ||
| 167 | if (!BN_usub(y, &group->field, y)) | ||
| 168 | goto err; | ||
| 169 | if (y_bit != BN_is_odd(y)) { | ||
| 170 | ECerror(ERR_R_INTERNAL_ERROR); | ||
| 171 | goto err; | ||
| 172 | } | ||
| 173 | } | 157 | } |
| 158 | |||
| 159 | done: | ||
| 174 | if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) | 160 | if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) |
| 175 | goto err; | 161 | goto err; |
| 176 | 162 | ||
