blob: ca5690f355110c8413edcf442c498da54516cccb [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* Copyright 2013-2015 Free Software Foundation, Inc.
2
3This file is part of the GNU MP Library test suite.
4
5The GNU MP Library test suite is free software; you can redistribute it
6and/or modify it under the terms of the GNU General Public License as
7published by the Free Software Foundation; either version 3 of the License,
8or (at your option) any later version.
9
10The GNU MP Library test suite is distributed in the hope that it will be
11useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
17
18#include <stdio.h>
19#include <stdlib.h> /* for strtol */
20
21#include "gmp-impl.h"
22#include "longlong.h"
23#include "tests/tests.h"
24
25#define MAX_SIZE 50
26
27#define COUNT 200
28
29static void
30mpz_to_mpn (mp_ptr ap, mp_size_t an, const mpz_t b)
31{
32 mp_size_t bn = mpz_size (b);
33 ASSERT_ALWAYS (bn <= an);
34 MPN_COPY_INCR (ap, mpz_limbs_read (b), bn);
35 MPN_ZERO (ap + bn, an - bn);
36}
37
38int
39mpz_eq_mpn (mp_ptr ap, mp_size_t an, const mpz_t b)
40{
41 mp_size_t bn = mpz_size (b);
42
43 return (bn >= 0 && bn <= an
44 && mpn_cmp (ap, mpz_limbs_read (b), bn) == 0
45 && (an == bn || mpn_zero_p (ap + bn, an - bn)));
46}
47
48static mp_bitcnt_t
49bit_size (mp_srcptr xp, mp_size_t n)
50{
51 MPN_NORMALIZE (xp, n);
52 return n > 0 ? mpn_sizeinbase (xp, n, 2) : 0;
53}
54
55int
56main (int argc, char **argv)
57{
58 gmp_randstate_ptr rands;
59 long count = COUNT;
60 mp_ptr mp;
61 mp_ptr ap;
62 mp_ptr tp;
63 mp_ptr scratch;
64 mpz_t m, a, r, g;
65 int test;
66 mp_limb_t ran;
67 mp_size_t itch;
68 TMP_DECL;
69
70 tests_start ();
71 rands = RANDS;
72
73
74 TMP_MARK;
75 mpz_init (m);
76 mpz_init (a);
77 mpz_init (r);
78 mpz_init (g);
79
80 TESTS_REPS (count, argv, argc);
81
82 mp = TMP_ALLOC_LIMBS (MAX_SIZE);
83 ap = TMP_ALLOC_LIMBS (MAX_SIZE);
84 tp = TMP_ALLOC_LIMBS (MAX_SIZE);
85 scratch = TMP_ALLOC_LIMBS (mpn_sec_invert_itch (MAX_SIZE) + 1);
86
87 for (test = 0; test < count; test++)
88 {
89 mp_bitcnt_t bits;
90 int rres, tres;
91 mp_size_t n;
92
93 bits = urandom () % (GMP_NUMB_BITS * MAX_SIZE) + 1;
94
95 if (test & 1)
96 mpz_rrandomb (m, rands, bits);
97 else
98 mpz_urandomb (m, rands, bits);
99 if (test & 2)
100 mpz_rrandomb (a, rands, bits);
101 else
102 mpz_urandomb (a, rands, bits);
103
104 mpz_setbit (m, 0);
105 if (test & 4)
106 {
107 /* Ensure it really is invertible */
108 if (mpz_sgn (a) == 0)
109 mpz_set_ui (a, 1);
110 else
111 for (;;)
112 {
113 mpz_gcd (g, a, m);
114 if (mpz_cmp_ui (g, 1) == 0)
115 break;
116 mpz_remove (a, a, g);
117 }
118 }
119
120 rres = mpz_invert (r, a, m);
121 if ( (test & 4) && !rres)
122 {
123 gmp_fprintf (stderr, "test %d: Not invertible!\n"
124 "m = %Zd\n"
125 "a = %Zd\n", test, m, a);
126 abort ();
127 }
128 ASSERT_ALWAYS (! (test & 4) || rres);
129
130 n = (bits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
131 ASSERT_ALWAYS (n <= MAX_SIZE);
132 itch = mpn_sec_invert_itch (n);
133 scratch[itch] = ran = urandom ();
134
135 mpz_to_mpn (ap, n, a);
136 mpz_to_mpn (mp, n, m);
137 tres = mpn_sec_invert (tp, ap, mp, n,
138 bit_size (ap, n) + bit_size (mp, n),
139 scratch);
140
141 if (rres != tres || (rres == 1 && !mpz_eq_mpn (tp, n, r)) || ran != scratch[itch])
142 {
143 gmp_fprintf (stderr, "Test %d failed.\n"
144 "m = %Zd\n"
145 "a = %Zd\n", test, m, a);
146 fprintf (stderr, "ref ret: %d\n"
147 "got ret: %d\n", rres, tres);
148 if (rres)
149 gmp_fprintf (stderr, "ref: %Zd\n", r);
150 if (tres)
151 gmp_fprintf (stderr, "got: %Nd\n", tp, n);
152 if (ran != scratch[itch])
153 fprintf (stderr, "scratch[itch] changed.\n");
154 abort ();
155 }
156 }
157
158 TMP_FREE;
159
160 mpz_clear (m);
161 mpz_clear (a);
162 mpz_clear (r);
163 mpz_clear (g);
164
165 tests_end ();
166 return 0;
167}