mp-modsqrt: Always return the smaller possible square root.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 1 Feb 2006 18:26:33 +0000 (18:26 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 1 Feb 2006 18:26:33 +0000 (18:26 +0000)
This makes the function more predictable in its behaviour, and therefore
easier to test.

mp-modsqrt.c
mp.h
tests/mp

index f9e4b0f..1cacacd 100644 (file)
@@ -51,6 +51,9 @@
  *             work if %$p$% is composite: you must factor the modulus, take
  *             a square root mod each factor, and recombine the results
  *             using the Chinese Remainder Theorem.
+ *
+ *             We guarantee that the square root returned is the smallest
+ *             one (i.e., the `positive' square root).
  */
 
 mp *mp_modsqrt(mp *d, mp *a, mp *p)
@@ -131,9 +134,14 @@ mp *mp_modsqrt(mp *d, mp *a, mp *p)
     c = mpmont_reduce(&mm, c, c);
   }
 
-  /* --- Done, so tidy up --- */
+  /* --- Done, so tidy up --- *
+   *
+   * Canonify the answer.
+   */
 
   d = mpmont_reduce(&mm, d, r);
+  r = mp_sub(r, p, d);
+  if (MP_CMP(r, <, d)) { mp *tt = r; r = d; d = tt; }
   mp_drop(ainv);
   mp_drop(r); mp_drop(c);
   mp_drop(dd);
@@ -161,11 +169,6 @@ static int verify(dstr *v)
     ok = 0;
   else if (MP_EQ(r, rr))
     ok = 1;
-  else {
-    r = mp_sub(r, p, r);
-    if (MP_EQ(r, rr))
-      ok = 1;
-  }
 
   if (!ok) {
     fputs("\n*** fail\n", stderr);
diff --git a/mp.h b/mp.h
index aa9bbac..74b6473 100644 (file)
--- a/mp.h
+++ b/mp.h
@@ -968,6 +968,9 @@ extern int mp_jacobi(mp */*a*/, mp */*n*/);
  *             work if %$p$% is composite: you must factor the modulus, take
  *             a square root mod each factor, and recombine the results
  *             using the Chinese Remainder Theorem.
+ *
+ *             We guarantee that the square root returned is the smallest
+ *             one (i.e., the `positive' square root).
  */
 
 extern mp *mp_modsqrt(mp */*d*/, mp */*a*/, mp */*p*/);
index e232f62..ab2e775 100644 (file)
--- a/tests/mp
+++ b/tests/mp
@@ -212,15 +212,15 @@ jacobi {
 
 modsqrt {
   1 3 1;
-  4 5 3;
+  4 5 2;
   9775592058107450692 13391974640168007623 3264570455655810730;
   8155671698868891620 10189552848261357803 2073812183305821596;
   3248339460720824413 8976233780911635437 1220523478429582717;
   3447751741648956439 10155704720805654949 2812971608818169892;
   1453601744816463433 3095659104519735473 1260511572497628526;
   3366261317119810224 3756232416311497601 610261287187759737;
-  3869491397135339653 5762828162167967567 2974328005712882420;
-  660864223630638896 1729533840094059799 1058197842375219723;
+  3869491397135339653 5762828162167967567 2788500156455085147;
+  660864223630638896 1729533840094059799 671335997718840076;
 }
 
 factorial {