summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authortb <>2022-06-20 19:32:35 +0000
committertb <>2022-06-20 19:32:35 +0000
commitc0609115dd28ab28056f1c6333df2819501cb6e5 (patch)
tree8c877056095481645ea7ae0c264035aa7db9a566 /src/lib
parentf61f94aad9d44721a1a98c8fea235d8c2ac50cc9 (diff)
downloadopenbsd-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.c161
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
62int 68int
63BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) 69BN_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
179end: 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}