diff options
author | tb <> | 2022-06-20 19:32:35 +0000 |
---|---|---|
committer | tb <> | 2022-06-20 19:32:35 +0000 |
commit | c0609115dd28ab28056f1c6333df2819501cb6e5 (patch) | |
tree | 8c877056095481645ea7ae0c264035aa7db9a566 /src/lib | |
parent | f61f94aad9d44721a1a98c8fea235d8c2ac50cc9 (diff) | |
download | openbsd-c0609115dd28ab28056f1c6333df2819501cb6e5.tar.gz openbsd-c0609115dd28ab28056f1c6333df2819501cb6e5.tar.bz2 openbsd-c0609115dd28ab28056f1c6333df2819501cb6e5.zip |
Clean up BN_kronecker()
Instead of "Cohen's step N" explain in words what is being done. Things
such as (A & B & 2) != 0 being equivalent to (-1)^((A-1)(B-1)/4) being
negative are not entirely obvious... Remove the strange error dance and
adjust variable names to what Cohen's book uses. Simplify various curly
bits.
ok jsing
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/bn/bn_kron.c | 161 |
1 files changed, 88 insertions, 73 deletions
diff --git a/src/lib/libcrypto/bn/bn_kron.c b/src/lib/libcrypto/bn/bn_kron.c index 274da5d186..c7bc53535e 100644 --- a/src/lib/libcrypto/bn/bn_kron.c +++ b/src/lib/libcrypto/bn/bn_kron.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: bn_kron.c,v 1.6 2015/02/09 15:49:22 jsing Exp $ */ | 1 | /* $OpenBSD: bn_kron.c,v 1.7 2022/06/20 19:32:35 tb Exp $ */ |
2 | /* ==================================================================== | 2 | /* ==================================================================== |
3 | * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. | 3 | * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. |
4 | * | 4 | * |
@@ -58,128 +58,143 @@ | |||
58 | /* least significant word */ | 58 | /* least significant word */ |
59 | #define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0]) | 59 | #define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0]) |
60 | 60 | ||
61 | /* Returns -2 for errors because both -1 and 0 are valid results. */ | 61 | /* |
62 | * Kronecker symbol, implemented according to Henri Cohen, "A Course in | ||
63 | * Computational Algebraic Number Theory", Algorithm 1.4.10. | ||
64 | * | ||
65 | * Returns -1, 0, or 1 on success and -2 on error. | ||
66 | */ | ||
67 | |||
62 | int | 68 | int |
63 | BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) | 69 | BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) |
64 | { | 70 | { |
65 | int i; | 71 | /* tab[BN_lsw(n) & 7] = (-1)^((n^2 - 1)) / 8) for odd values of n. */ |
66 | int ret = -2; /* avoid 'uninitialized' warning */ | ||
67 | int err = 0; | ||
68 | BIGNUM *A, *B, *tmp; | ||
69 | |||
70 | /* In 'tab', only odd-indexed entries are relevant: | ||
71 | * For any odd BIGNUM n, | ||
72 | * tab[BN_lsw(n) & 7] | ||
73 | * is $(-1)^{(n^2-1)/8}$ (using TeX notation). | ||
74 | * Note that the sign of n does not matter. | ||
75 | */ | ||
76 | static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1}; | 72 | static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1}; |
73 | BIGNUM *A, *B, *tmp; | ||
74 | int k, v; | ||
75 | int ret = -2; | ||
77 | 76 | ||
78 | bn_check_top(a); | 77 | bn_check_top(a); |
79 | bn_check_top(b); | 78 | bn_check_top(b); |
80 | 79 | ||
81 | BN_CTX_start(ctx); | 80 | BN_CTX_start(ctx); |
81 | |||
82 | if ((A = BN_CTX_get(ctx)) == NULL) | 82 | if ((A = BN_CTX_get(ctx)) == NULL) |
83 | goto end; | 83 | goto end; |
84 | if ((B = BN_CTX_get(ctx)) == NULL) | 84 | if ((B = BN_CTX_get(ctx)) == NULL) |
85 | goto end; | 85 | goto end; |
86 | 86 | ||
87 | err = !BN_copy(A, a); | 87 | if (BN_copy(A, a) == NULL) |
88 | if (err) | ||
89 | goto end; | 88 | goto end; |
90 | err = !BN_copy(B, b); | 89 | if (BN_copy(B, b) == NULL) |
91 | if (err) | ||
92 | goto end; | 90 | goto end; |
93 | 91 | ||
94 | /* | 92 | /* |
95 | * Kronecker symbol, imlemented according to Henri Cohen, | 93 | * Cohen's step 1: |
96 | * "A Course in Computational Algebraic Number Theory" | ||
97 | * (algorithm 1.4.10). | ||
98 | */ | 94 | */ |
99 | 95 | ||
100 | /* Cohen's step 1: */ | 96 | /* If B is zero, output 1 if |A| is 1, otherwise output 0. */ |
101 | |||
102 | if (BN_is_zero(B)) { | 97 | if (BN_is_zero(B)) { |
103 | ret = BN_abs_is_word(A, 1); | 98 | ret = BN_abs_is_word(A, 1); |
104 | goto end; | 99 | goto end; |
105 | } | 100 | } |
106 | 101 | ||
107 | /* Cohen's step 2: */ | 102 | /* |
103 | * Cohen's step 2: | ||
104 | */ | ||
108 | 105 | ||
106 | /* If both are even, they have a factor in common, so output 0. */ | ||
109 | if (!BN_is_odd(A) && !BN_is_odd(B)) { | 107 | if (!BN_is_odd(A) && !BN_is_odd(B)) { |
110 | ret = 0; | 108 | ret = 0; |
111 | goto end; | 109 | goto end; |
112 | } | 110 | } |
113 | 111 | ||
114 | /* now B is non-zero */ | 112 | /* Factorize B = 2^v * u with odd u and replace B with u. */ |
115 | i = 0; | 113 | v = 0; |
116 | while (!BN_is_bit_set(B, i)) | 114 | while (!BN_is_bit_set(B, v)) |
117 | i++; | 115 | v++; |
118 | err = !BN_rshift(B, B, i); | 116 | if (!BN_rshift(B, B, v)) |
119 | if (err) | ||
120 | goto end; | 117 | goto end; |
121 | if (i & 1) { | ||
122 | /* i is odd */ | ||
123 | /* (thus B was even, thus A must be odd!) */ | ||
124 | |||
125 | /* set 'ret' to $(-1)^{(A^2-1)/8}$ */ | ||
126 | ret = tab[BN_lsw(A) & 7]; | ||
127 | } else { | ||
128 | /* i is even */ | ||
129 | ret = 1; | ||
130 | } | ||
131 | 118 | ||
132 | if (B->neg) { | 119 | /* If v is even set k = 1, otherwise set it to (-1)^((A^2 - 1) / 8). */ |
133 | B->neg = 0; | 120 | k = 1; |
134 | if (A->neg) | 121 | if (v % 2 != 0) |
135 | ret = -ret; | 122 | k = tab[BN_lsw(A) & 7]; |
123 | |||
124 | /* | ||
125 | * If B is negative, replace it with -B and if A is also negative | ||
126 | * replace k with -k. | ||
127 | */ | ||
128 | if (BN_is_negative(B)) { | ||
129 | BN_set_negative(B, 0); | ||
130 | |||
131 | if (BN_is_negative(A)) | ||
132 | k = -k; | ||
136 | } | 133 | } |
137 | 134 | ||
138 | /* now B is positive and odd, so what remains to be done is | 135 | /* |
139 | * to compute the Jacobi symbol (A/B) and multiply it by 'ret' */ | 136 | * Now B is positive and odd, so compute the Jacobi symbol (A/B) |
137 | * and multiply it by k. | ||
138 | */ | ||
140 | 139 | ||
141 | while (1) { | 140 | while (1) { |
142 | /* Cohen's step 3: */ | 141 | /* |
142 | * Cohen's step 3: | ||
143 | */ | ||
143 | 144 | ||
144 | /* B is positive and odd */ | 145 | /* B is positive and odd. */ |
145 | 146 | ||
147 | /* If A is zero output k if B is one, otherwise output 0. */ | ||
146 | if (BN_is_zero(A)) { | 148 | if (BN_is_zero(A)) { |
147 | ret = BN_is_one(B) ? ret : 0; | 149 | ret = BN_is_one(B) ? k : 0; |
148 | goto end; | 150 | goto end; |
149 | } | 151 | } |
150 | 152 | ||
151 | /* now A is non-zero */ | 153 | /* Factorize A = 2^v * u with odd u and replace A with u. */ |
152 | i = 0; | 154 | v = 0; |
153 | while (!BN_is_bit_set(A, i)) | 155 | while (!BN_is_bit_set(A, v)) |
154 | i++; | 156 | v++; |
155 | err = !BN_rshift(A, A, i); | 157 | if (!BN_rshift(A, A, v)) |
156 | if (err) | ||
157 | goto end; | 158 | goto end; |
158 | if (i & 1) { | ||
159 | /* i is odd */ | ||
160 | /* multiply 'ret' by $(-1)^{(B^2-1)/8}$ */ | ||
161 | ret = ret * tab[BN_lsw(B) & 7]; | ||
162 | } | ||
163 | |||
164 | /* Cohen's step 4: */ | ||
165 | /* multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ */ | ||
166 | if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) | ||
167 | ret = -ret; | ||
168 | 159 | ||
169 | /* (A, B) := (B mod |A|, |A|) */ | 160 | /* If v is odd, multiply k with (-1)^((B^2 - 1) / 8). */ |
170 | err = !BN_nnmod(B, B, A, ctx); | 161 | if (v % 2 != 0) |
171 | if (err) | 162 | k *= tab[BN_lsw(B) & 7]; |
163 | |||
164 | /* | ||
165 | * Cohen's step 4: | ||
166 | */ | ||
167 | |||
168 | /* | ||
169 | * Apply the reciprocity law: multiply k by (-1)^((A-1)(B-1)/4). | ||
170 | * | ||
171 | * This expression is -1 if and only if A and B are 3 (mod 4). | ||
172 | * In turn, this is the case if and only if their two's | ||
173 | * complement representations have the second bit set. | ||
174 | * A could be negative in the first iteration, B is positive. | ||
175 | */ | ||
176 | if ((BN_is_negative(A) ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) | ||
177 | k = -k; | ||
178 | |||
179 | /* | ||
180 | * (A, B) := (B mod |A|, |A|) | ||
181 | * | ||
182 | * Once this is done, we know that 0 < A < B at the start of the | ||
183 | * loop. Since B is strictly decreasing, the loop terminates. | ||
184 | */ | ||
185 | |||
186 | if (!BN_nnmod(B, B, A, ctx)) | ||
172 | goto end; | 187 | goto end; |
188 | |||
173 | tmp = A; | 189 | tmp = A; |
174 | A = B; | 190 | A = B; |
175 | B = tmp; | 191 | B = tmp; |
176 | tmp->neg = 0; | 192 | |
193 | BN_set_negative(B, 0); | ||
177 | } | 194 | } |
178 | 195 | ||
179 | end: | 196 | end: |
180 | BN_CTX_end(ctx); | 197 | BN_CTX_end(ctx); |
181 | if (err) | 198 | |
182 | return -2; | 199 | return ret; |
183 | else | ||
184 | return ret; | ||
185 | } | 200 | } |