/src/boringssl/crypto/fipsmodule/bn/jacobi.cc.inc
Line | Count | Source |
1 | | // Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/bn.h> |
16 | | |
17 | | #include <openssl/err.h> |
18 | | |
19 | | #include "internal.h" |
20 | | |
21 | | |
22 | | using namespace bssl; |
23 | | |
24 | | // least significant word |
25 | 112k | #define BN_lsw(n) (((n)->width == 0) ? (BN_ULONG)0 : (n)->d[0]) |
26 | | |
27 | 28.9k | int bssl::bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { |
28 | | // In 'tab', only odd-indexed entries are relevant: |
29 | | // For any odd BIGNUM n, |
30 | | // tab[BN_lsw(n) & 7] |
31 | | // is $(-1)^{(n^2-1)/8}$ (using TeX notation). |
32 | | // Note that the sign of n does not matter. |
33 | 28.9k | static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1}; |
34 | | |
35 | | // The Jacobi symbol is only defined for odd modulus. |
36 | 28.9k | if (!BN_is_odd(b)) { |
37 | 0 | OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); |
38 | 0 | return -2; |
39 | 0 | } |
40 | | |
41 | | // Require b be positive. |
42 | 28.9k | if (BN_is_negative(b)) { |
43 | 0 | OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); |
44 | 0 | return -2; |
45 | 0 | } |
46 | | |
47 | 28.9k | BN_CTXScope scope(ctx); |
48 | 28.9k | BIGNUM *A = BN_CTX_get(ctx); |
49 | 28.9k | BIGNUM *B = BN_CTX_get(ctx); |
50 | 28.9k | if (B == nullptr) { |
51 | 0 | return -2; |
52 | 0 | } |
53 | | |
54 | 28.9k | if (!BN_copy(A, a) || |
55 | 28.9k | !BN_copy(B, b)) { |
56 | 0 | return -2; |
57 | 0 | } |
58 | | |
59 | | // Adapted from logic to compute the Kronecker symbol, originally implemented |
60 | | // according to Henri Cohen, "A Course in Computational Algebraic Number |
61 | | // Theory" (algorithm 1.4.10). |
62 | | |
63 | 28.9k | int ret = 1; |
64 | 78.1k | while (1) { |
65 | | // Cohen's step 3: |
66 | | |
67 | | // B is positive and odd |
68 | 78.1k | if (BN_is_zero(A)) { |
69 | 28.9k | return BN_is_one(B) ? ret : 0; |
70 | 28.9k | } |
71 | | |
72 | | // now A is non-zero |
73 | 49.1k | int i = 0; |
74 | 92.5k | while (!BN_is_bit_set(A, i)) { |
75 | 43.3k | i++; |
76 | 43.3k | } |
77 | 49.1k | if (!BN_rshift(A, A, i)) { |
78 | 0 | return -2; |
79 | 0 | } |
80 | 49.1k | if (i & 1) { |
81 | | // i is odd |
82 | | // multiply 'ret' by $(-1)^{(B^2-1)/8}$ |
83 | 14.4k | ret = ret * tab[BN_lsw(B) & 7]; |
84 | 14.4k | } |
85 | | |
86 | | // Cohen's step 4: |
87 | | // multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ |
88 | 49.1k | if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) { |
89 | 0 | ret = -ret; |
90 | 0 | } |
91 | | |
92 | | // (A, B) := (B mod |A|, |A|) |
93 | 49.1k | if (!BN_nnmod(B, B, A, ctx)) { |
94 | 0 | return -2; |
95 | 0 | } |
96 | 49.1k | BIGNUM *tmp = A; |
97 | 49.1k | A = B; |
98 | 49.1k | B = tmp; |
99 | 49.1k | tmp->neg = 0; |
100 | 49.1k | } |
101 | 28.9k | } |