-/**************************************************************
- *
- * tools.c
- *
- * Number-theoretical algorithm implementations
- *
- * Updates:
- * 30 Apr 99 REC Modified init_tools type to void.
- * 3 Apr 98 REC Creation
- *
- *
- * c. 1998 Perfectly Scientific, Inc.
- * All Rights Reserved.
- *
- *
- *************************************************************/
-
-/* include files */
-
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-#include <time.h>
-#ifdef _WIN32
-
-#include <process.h>
-
-#endif
-
-#include <string.h>
-#include "giants.h"
-#include "tools.h"
-
-/* definitions */
-
-#define STACK_COUNT 20
-
-/* global variables */
-
-int pr[NUM_PRIMES]; /* External use allowed. */
-static giant tmp[STACK_COUNT];
-static int stack = 0;
-static giant popg();
-static void pushg();
-
-/**************************************************************
- *
- * Maintenance functions
- *
- **************************************************************/
-
-
-void
-init_tools(int shorts)
-{
- int j;
-
- for(j = 0; j < STACK_COUNT; j++) {
- tmp[j] = newgiant(shorts);
- }
- make_primes(); /* Create table of all primes < 2^16,
- to be used by other programs as array
- pr[0..NUM_PRIMES]. */
-}
-
-static giant
-popg() {
- return(tmp[stack++]);
-}
-
-static void
-pushg(int n) {
- stack -= n;
-}
-
-/**************************************************************
- *
- * Number-theoretical functions
- *
- **************************************************************/
-
-int
-prime_literal(
- unsigned int p
-)
-/* Primality test via small, literal sieve.
- After init, one should use primeq() instead.
- */
-{
- unsigned int j=3;
-
- if ((p & 1)==0)
- return ((p == 2)?1:0);
- if (j >= p)
- return (1);
- while ((p%j)!=0)
- {
- j += 2;
- if (j*j > p)
- return(1);
- }
- return(0);
-}
-
-int
-primeq(
- unsigned int odd
-)
-/* Faster primality test, using preset array pr[] of primes.
- This test is valid for all unsigned, 32-bit integers odd.
- */
-{
- unsigned int p;
- unsigned int j;
-
- if(odd < 2) return (0);
- if ((odd & 1)==0)
- return ((odd == 2)?1:0);
- for (j=1; ;j++)
- {
- p = pr[j];
- if (p*p > odd)
- return(1);
- if (odd % p == 0)
- return(0);
- }
-}
-
-void
-make_primes()
-{ int k, npr;
- pr[0] = 2;
- for (k=0, npr=1;; k++)
- {
- if (prime_literal(3+2*k))
- {
- pr[npr++] = 3+2*k;
- if (npr >= NUM_PRIMES)
- break;
- }
- }
-}
-
-int
-prime_probable(giant p)
-/* Invoke Miller-Rabin test of given security depth.
- For MILLER_RABIN_DEPTH == 8, this is an ironclad primality
- test for suspected primes p < 3.4 x 10^{14}.
-*/
-{
- giant t1 = popg(), t2 = popg(), t3 = popg();
- int j, ct, s;
-
- if((p->n[0] & 1) == 0) { /* Evenness test. */
- pushg(3); return(0);
- }
- if(bitlen(p) < 32) { /* Single-word case. */
- pushg(3);
- return(primeq((unsigned int)gtoi(p)));
- }
- itog(-1, t1);
- addg(p, t1); /* t1 := p-1. */
- gtog(t1, t2);
- s = 1;
- gshiftright(1, t2);
- while(t2->n[0] & 1 == 0) {
- gshiftright(1, t2);
- ++s;
- }
- /* Now, p-1 = 2^s * t2. */
- for(j = 0; j < MILLER_RABIN_DEPTH; j++) {
- itog(pr[j+1], t3);
- powermodg(t3, t2, p);
- ct = 1;
- if(isone(t3)) continue;
- if(gcompg(t3, t1) == 0) continue;
- while((ct < s) && (gcompg(t1, t3) != 0)) {
- squareg(t3); modg(p, t3);
- if(isone(t3)) {
- goto composite;
- }
- ++ct;
- }
- if(gcompg(t1, t3) != 0) goto composite;
- }
- goto prime;
-
-composite:
- pushg(3); return(0);
-prime: pushg(3); return(1);
-}
-
-int
-jacobi_symbol(giant a, giant n)
-/* Standard Jacobi symbol (a/n). Parameter n must be odd, positive. */
-{ int t = 1, u;
- giant t5 = popg(), t6 = popg(), t7 = popg();
-
- gtog(a, t5); modg(n, t5);
- gtog(n, t6);
- while(!isZero(t5)) {
- u = (t6->n[0]) & 7;
- while((t5->n[0] & 1) == 0) {
- gshiftright(1, t5);
- if((u==3) || (u==5)) t = -t;
- }
- gtog(t5, t7); gtog(t6, t5); gtog(t7, t6);
- u = (t6->n[0]) & 3;
- if(((t5->n[0] & 3) == 3) && ((u & 3) == 3)) t = -t;
- modg(t6, t5);
- }
- if(isone(t6)) {
- pushg(3);
- return(t);
- }
- pushg(3);
- return(0);
-}
-
-int
-pseudoq(giant a, giant p)
-/* Query whether a^(p-1) = 1 (mod p). */
-{
- int x;
- giant t1 = popg(), t2 = popg();
-
- gtog(p, t1); itog(1, t2); subg(t2, t1);
- gtog(a, t2);
- powermodg(t2, t1, p);
- x = isone(t2);
- pushg(2);
- return(x);
-}
-
-int
-pseudointq(int a, giant p)
-/* Query whether a^(p-1) = 1 (mod p). */
-{
- int x;
- giant t4 = popg();
-
- itog(a, t4);
- x = pseudoq(t4, p);
- pushg(1);
- return(x);
-}
-
-
-void
-powFp2(giant a, giant b, giant w2, giant n, giant p)
-/* Perform powering in the field F_p^2:
- a + b w := (a + b w)^n (mod p), where parameter w2 is a quadratic
- nonresidue (formally equal to w^2).
- */
-{ int j;
- giant t6 = popg(), t7 = popg(), t8 = popg(), t9 = popg();
-
- if(isZero(n)) {
- itog(1,a);
- itog(0,b);
- pushg(4);
- return;
- }
- gtog(a, t8); gtog(b, t9);
- for(j = bitlen(n)-2; j >= 0; j--) {
- gtog(b, t6);
- mulg(a, b); addg(b,b); modg(p, b); /* b := 2 a b. */
- squareg(t6); modg(p, t6);
- mulg(w2, t6); modg(p, t6);
- squareg(a); addg(t6, a); modg(p, a); /* a := a^2 + b^2 w2. */
- if(bitval(n, j)) {
- gtog(b, t6); mulg(t8, b); modg(p, b);
- gtog(a, t7); mulg(t9, a); addg(a, b); modg(p, b);
- mulg(t9, t6); modg(p, t6); mulg(w2, t6); modg(p, t6);
- mulg(t8, a); addg(t6, a); modg(p, a);
- }
- }
- pushg(4);
- return;
-}
-
-int
-sqrtmod(giant p, giant x)
-/* If Sqrt[x] (mod p) exists, function returns 1, else 0.
- In either case x is modified, but if 1 is returned,
- x:= Sqrt[x] (mod p).
- */
-{ giant t0 = popg(), t1 = popg(), t2 = popg(), t3 = popg(),
- t4 = popg();
-
- modg(p, x); /* Justify the argument. */
- gtog(x, t0); /* Store x for eventual validity check on square root. */
- if((p->n[0] & 3) == 3) { /* The case p = 3 (mod 4). */
- gtog(p, t1);
- iaddg(1, t1); gshiftright(2, t1);
- powermodg(x, t1, p);
- goto resolve;
- }
-/* Next, handle case p = 5 (mod 8). */
- if((p->n[0] & 7) == 5) {
- gtog(p, t1); itog(1, t2);
- subg(t2, t1); gshiftright(2, t1);
- gtog(x, t2);
- powermodg(t2, t1, p); /* t2 := x^((p-1)/4) % p. */
- iaddg(1, t1);
- gshiftright(1, t1); /* t1 := (p+3)/8. */
- if(isone(t2)) {
- powermodg(x, t1, p); /* x^((p+3)/8) is root. */
- goto resolve;
- } else {
- itog(1, t2); subg(t2, t1); /* t1 := (p-5)/8. */
- gshiftleft(2,x);
- powermodg(x, t1, p);
- mulg(t0, x); addg(x, x); modg(p, x); /* 2x (4x)^((p-5)/8. */
- goto resolve;
- }
- }
-
-/* Next, handle tougher case: p = 1 (mod 8). */
- itog(2, t1);
- while(1) { /* Find appropriate nonresidue. */
- gtog(t1, t2);
- squareg(t2); subg(x, t2); modg(p, t2);
- if(jacobi_symbol(t2, p) == -1) break;
- iaddg(1, t1);
- } /* t2 is now w^2 in F_p^2. */
- itog(1, t3);
- gtog(p, t4); iaddg(1, t4); gshiftright(1, t4);
- powFp2(t1, t3, t2, t4, p);
- gtog(t1, x);
-
-resolve:
- gtog(x,t1); squareg(t1); modg(p, t1);
- if(gcompg(t0, t1) == 0) {
- pushg(5);
- return(1); /* Success. */
- }
- pushg(5);
- return(0); /* No square root. */
-}
-
-void
-sqrtg(giant n)
-/* n:= Floor[Sqrt[n]]. */
-{ giant t5 = popg(), t6 = popg();
-
- itog(1, t5); gshiftleft(1 + bitlen(n)/2, t5);
- while(1) {
- gtog(n, t6);
- divg(t5, t6);
- addg(t5, t6); gshiftright(1, t6);
- if(gcompg(t6, t5) >= 0) break;
- gtog(t6, t5);
- }
- gtog(t5, n);
- pushg(2);
-}
-
-int
-cornacchia4(giant n, int d, giant u, giant v)
-/* Seek representation 4n = u^2 + |d| v^2,
- for (negative) discriminant d and n > |D|/4.
- Parameter u := 0 and 0 is returned, if no representation is found;
- else 1 is returned and u, v properly set.
- */
-{ int r = n->n[0] & 7, sym;
- giant t1 = popg(), t2 = popg(), t3 = popg(), t4 = popg();
-
- itog(d, t1);
- if((n->n[0]) & 7 == 1) { /* n = 1 (mod 8). */
- sym = jacobi_symbol(t1,n);
- if(sym != 1) {
- itog(0,u);
- pushg(4);
- return(0);
- }
- gtog(t1, t2);
- sqrtmod(n, t2); /* t2 := Sqrt[d] (mod n). */
- } else { /* Avoid separate Jacobi/Legendre test. */
- gtog(t1, t2);
- if(sqrtmod(n, t2) == 0) {
- itog(0, u);
- pushg(4);
- return(0);
- }
- }
-/* t2 is now a valid square root of d (mod n). */
- gtog(t2, t3);
- subg(t1, t3); /* t3 := t2 - d. */
- if((t3->n[0] & 1) == 1) {
- negg(t2);
- addg(n, t2);
- }
- gtog(n, t3); addg(t3, t3); /* t3 := 2n. */
- gtog(n, t4); gshiftleft(2, t4); sqrtg(t4); /* t4 = [Sqrt[4 p]]. */
- while(gcompg(t2, t4) > 0) {
- gtog(t3, t1);
- gtog(t2, t3);
- gtog(t1, t2);
- modg(t3, t2);
- }
- gtog(n, t4); gshiftleft(2, t4);
- gtog(t2, t3); squareg(t3);
- subg(t3, t4); /* t4 := 4n - t2^2. */
- gtog(t4, t3);
- itog(d, t1); absg(t1);
- modg(t1, t3);
- if(!isZero(t3)) {
- itog(0,u);
- pushg(4);
- return(0);
- }
- divg(t1, t4);
- gtog(t4, t1);
- sqrtg(t4); /* t4 := [Sqrt[t4/Abs[d]]]. */
- gtog(t4, t3);
- squareg(t3);
- if(gcompg(t3, t1) != 0) {
- itog(0, u);
- pushg(4);
- return(0);
- }
- gtog(t2, u);
- gtog(t4, v);
- pushg(4);
- return(1);
-}
-
-/*
-rep[p_, d_] := Module[{t, x0, a, b, c},
- If[JacobiSymbol[d,p] != 1, Return[{0,0}]];
- x0 = sqrt[d, p];
- If[Mod[x0-d,2] == 1, x0 = p-x0];
- a = 2p; b = x0; c = sqrtint[4 p];
- While[b > c, {a,b} = {b, Mod[a,b]}];
- t = 4p - b^2;
- If[Mod[t,Abs[d]] !=0, Return[{0,0}]];
- v = t/Abs[d];
- u = sqrtint[v];
- If[u^2 != v, Return[{0,0}]];
- Return[{b, u}]
- ];
-*/
-
-