2 * c_pmodm127 - calculate q mod 2^(2^127-1)
4 * Copyright (C) 2004-2007 Landon Curt Noll
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.1 $
21 * @(#) $Id: c_pmodm127.c,v 30.1 2007/03/16 11:10:04 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/custom/RCS/c_pmodm127.c,v $
24 * Under source code control: 2004/07/28 22:12:25
25 * File existed as early as: 2004
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
35 #include "have_const.h"
40 #include "have_unused.h"
43 STATIC HALF h255
[] = {
45 (HALF
)0x00000000, (HALF
)0x00000000, (HALF
)0x00000000, (HALF
)0x00000000,
46 (HALF
)0x00000000, (HALF
)0x00000000, (HALF
)0x00000000, (HALF
)0x80000000
47 #else /* BASEB == 32 */
48 (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000,
49 (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000,
50 (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000,
51 (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x0000, (HALF
)0x8000
52 #endif /* BASEB == 32 */
59 /* static declarations */
60 S_FUNC
void zmod5_or_zmod(ZVALUE
*zp
);
61 STATIC BOOL havelastmod
= FALSE
;
62 STATIC ZVALUE lastmod
[1];
63 STATIC ZVALUE lastmodinv
[1];
67 * c_pmodm127 - calculate q mod 2^(2^127-1)
71 * vals[0] real number; (q - potential factor)
74 * result real number; (q mod 2^(2^127-1))
78 c_pmodm127(char UNUSED
*name
, int UNUSED count
, VALUE
**vals
)
80 VALUE result
; /* what we will return */
81 ZVALUE q
; /* test factor */
82 ZVALUE temp
; /* temp calculation value */
83 int i
; /* exponent value */
88 result
.v_type
= V_NULL
;
89 if (vals
[0]->v_type
!= V_NUM
) {
90 math_error("Non-numeric argument for pmodm127");
93 if (qisfrac(vals
[0]->v_num
)) {
94 math_error("Non-integer argument for pmodm127");
97 if (qisneg(vals
[0]->v_num
) || qiszero(vals
[0]->v_num
)) {
98 math_error("argument for pmodm127 <= 0");
103 * look at the numerator
105 q
= vals
[0]->v_num
->num
;
108 * setup lastmod with q
110 if (havelastmod
&& zcmp(q
, *lastmod
)) {
117 zbitvalue(2 * q
.len
* BASEB
, &temp
);
118 zquo(temp
, q
, lastmodinv
, 0);
126 result
.v_num
= qalloc();
127 zcopy(p255
, &result
.v_num
->num
);
128 result
.v_type
= V_NUM
;
131 * compute 2^(2^127-1) mod q by modular exponentation
133 * We implement the following calc code in C:
135 * (* given q, our test factor, as the arg to this function *)
137 * for (i=8; i < 127; ++i) {
138 * result %= q; (* mod *)
139 * result *= result; (* square *)
140 * result <<= 1; (* times 2 *)
142 * result %= q; (* result is now 2^(2^127-1) % q *)
144 for (i
=8; i
<127; ++i
) {
146 /* use of zmod is a bit slower than zmod5_or_zmod */
147 (void) zmod(result
.v_num
->num
, *lastmod
, &temp
, 0);
148 zfree(result
.v_num
->num
);
149 result
.v_num
->num
= temp
;
151 zmod5_or_zmod(&result
.v_num
->num
); /* mod */
154 /* use of zmul is slightly slower than zsquare */
155 zmul(result
.v_num
->num
, result
.v_num
->num
, &temp
); /* square */
157 zsquare(result
.v_num
->num
, &temp
); /* square */
160 * We could manually shift here, but this would o speed
161 * up the operation only a very tiny bit at the expense
162 * of a bunch of special code.
164 zfree(result
.v_num
->num
);
165 zshift(temp
, 1, &result
.v_num
->num
); /* times 2 */
168 zmod5_or_zmod(&result
.v_num
->num
); /* result = 2^(2^127-1) % q */
171 * cleanup and return result
178 * zmod5_or_zmod - fast integer modulo the modulus computation
180 * "borrowed" from ../zmod.c
182 * Given the address of a positive integer whose word count does not
183 * exceed twice that of the modulus stored at lastmod, to evaluate and store
184 * at that address the value of the integer modulo the modulus.
186 * Unlike the static routine in ../zmod.c, we will call the zmod and return
187 * the result of the zmod5_or_zmod conditions do not apply to the argument
191 zmod5_or_zmod(ZVALUE
*zp
)
202 if (zrel(*zp
, *lastmod
) < 0)
204 modlen
= lastmod
->len
;
206 z1
.v
= zp
->v
+ modlen
- 1;
207 z1
.len
= len
- modlen
+ 1;
208 z1
.sign
= z2
.sign
= z3
.sign
= 0;
209 if (z1
.len
> modlen
+ 1) {
210 /* in ../zmod.c we did a math_error("Bad call to zmod5!!!"); */
211 /* here we just call the slower zmod and return the result */
212 (void) zmod(*zp
, *lastmod
, &tmp1
, 0);
213 /* replace zp with tmp1 mod result */
218 z2
.v
= lastmodinv
->v
+ modlen
+ 1 - z1
.len
;
219 z2
.len
= lastmodinv
->len
- modlen
- 1 + z1
.len
;
221 z3
.v
= tmp1
.v
+ z1
.len
;
222 z3
.len
= tmp1
.len
- z1
.len
;
224 zmul(z3
, *lastmod
, &tmp2
);
231 f
= (FULL
) *a
- (FULL
) *b
++ - (FULL
) u
;
233 u
= - (HALF
) (f
>> BASEB
);
237 if (tmp2
.len
> modlen
)
238 f
= (FULL
) *a
- (FULL
) *b
- (FULL
) u
;
240 f
= (FULL
) *a
- (FULL
) u
;
243 while (len
> 0 && *--a
== 0)
249 while (len
> 0 && zrel(*zp
, *lastmod
) >= 0) {
252 math_error("Too many subtractions in zmod5_or_zmod");
260 f
= (FULL
) *a
- (FULL
) *b
++ - (FULL
) u
;
262 u
= - (HALF
) (f
>> BASEB
);
265 f
= (FULL
) *a
- (FULL
) u
;
268 while (len
> 0 && *--a
== 0)