2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include "tommath_private.h"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#ifdef BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* LibTomMath, multiple-precision integer library -- Tom St Denis
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * LibTomMath is a library that provides multiple-precision
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * integer arithmetic as well as number theoretic functionality.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * The library was designed directly after the MPI library by
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Michael Fromberger but has been written from scratch with
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * additional optimizations in place.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * The library is free for all purposes without any express
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * guarantee it works.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-26 01:39:03 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#ifndef LTM_USE_FIPS_ONLY
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:54:55 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  8-bit is just too small. You can try the Frobenius test
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  but that frobenius test can fail, too, for the same reason.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 15:15:13 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#ifndef MP_8BIT
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:54:55 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * multiply bigint a with int d and put the result in c
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Like mp_mul_d() but with a signed long as the small input
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-12 00:14:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int s_mp_mul_si(const mp_int *a, long d, mp_int *c)
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:54:55 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   mp_int t;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   int err, neg = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   if ((err = mp_init(&t)) != MP_OKAY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   if (d < 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      neg = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      d = -d;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * mp_digit might be smaller than a long, which excludes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * the use of mp_mul_d() here.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   if ((err = mp_set_long(&t, (unsigned long) d)) != MP_OKAY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      goto LBL_MPMULSI_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   if ((err = mp_mul(a, &t, c)) != MP_OKAY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      goto LBL_MPMULSI_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   if (neg ==  1) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      c->sign = (a->sign == MP_NEG) ? MP_ZPOS: MP_NEG;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								LBL_MPMULSI_ERR:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   mp_clear(&t);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   return err;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Strong Lucas-Selfridge test.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    returns MP_YES if it is a strong L-S prime, MP_NO if it is composite
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Code ported from  Thomas Ray Nicely's implementation of the BPSW test
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    at http://www.trnicely.net/misc/bpsw.html
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Released into the public domain by the author, who disclaims any legal
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    liability arising from its use
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    The multi-line comments are made by Thomas R. Nicely and are copied verbatim.
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:17:48 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    Additional comments marked "CZ" (without the quotes) are by the code-portist.
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    (If that name sounds familiar, he is the guy who found the fdiv bug in the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								     Pentium (P5x, I think) Intel processor)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								*/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								int mp_prime_strong_lucas_selfridge(const mp_int *a, int *result)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:17:48 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   /* CZ TODO: choose better variable names! */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz;
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:17:48 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits;
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:06:23 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   int e;
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   int isset;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   *result = MP_NO;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   Find the first element D in the sequence {5, -7, 9, -11, 13, ...}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   indicates that, if N is not a perfect square, D will "nearly
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   always" be "small." Just in case, an overflow trap for D is
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   included.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   if ((e = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz,
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                          NULL)) != MP_OKAY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return e;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   D = 5;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   sign = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   for (;;) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Ds   = sign * D;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      sign = -sign;
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_set_long(&Dz, (unsigned long)D)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      /* if 1 < GCD < N then N is composite with factor "D", and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         Jacobi(D,N) is technically undefined (but often returned
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         as zero). */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:21:51 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if (Ds < 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         Dz.sign = MP_NEG;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_kronecker(&Dz, a, &J)) != MP_OKAY) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if (J == -1) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      D += 2;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:33:43 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if (D > (INT_MAX - 2)) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         e = MP_VAL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   P = 1;              /* Selfridge's choice */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   Q = (1 - Ds) / 4;   /* Required so D = P*P - 4*Q */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* NOTE: The conditions (a) N does not divide Q, and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (b) D is square-free or not a perfect square, are included by
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      some authors; e.g., "Prime numbers and computer methods for
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      p. 130. For this particular application of Lucas sequences,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      these conditions were found to be immaterial. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      odd positive integer d and positive integer s for which
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test).
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      The strong Lucas-Selfridge test then returns N as a strong
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Lucas probable prime (slprp) if any of the following
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (all equalities mod N). Thus d is the highest index of U that
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      must be computed (since V_2m is independent of U), compared
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      to U_{N+1} for the standard Lucas-Selfridge test; and no
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      index of V beyond (N+1)/2 is required, just as in the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      standard Lucas-Selfridge test. However, the quantity Q^d must
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      be computed for use (if necessary) in the latter stages of
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      the test. The result is that the strong Lucas-Selfridge test
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      has a running time only slightly greater (order of 10 %) than
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      that of the standard Lucas-Selfridge test, while producing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      only (roughly) 30 % as many pseudoprimes (and every strong
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Lucas pseudoprime is also a standard Lucas pseudoprime). Thus
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      the evidence indicates that the strong Lucas-Selfridge test is
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      more effective than the standard Lucas-Selfridge test, and a
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Baillie-PSW test based on the strong Lucas-Selfridge test
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      should be more reliable. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:21:51 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   if ((e = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   s = mp_cnt_lsb(&Np1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:17:48 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   /* CZ
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * This should round towards zero because
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * and mp_div_2d() is equivalent. Additionally:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * dividing an even number by two does not produce
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    * any leftovers.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   if ((e = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* We must now compute U_d and V_d. Since d is odd, the accumulated
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      values U and V are initialized to U_1 and V_1 (if the target
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      index were even, U and V would be initialized instead to U_0=0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      and V_0=2). The values of U_2m and V_2m are also initialized to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      U_1 and V_1; the FOR loop calculates in succession U_2 and V_2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      U_4 and V_4, U_8 and V_8, etc. If the corresponding bits
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (1, 2, 3, ...) of t are on (the zero bit having been accounted
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      for in the initialization of U and V), these values are then
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      combined with the previous totals for U and V, using the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      composition formulas for addition of indices. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:21:51 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   mp_set(&Uz, 1uL);    /* U=U_1 */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   mp_set(&Vz, (mp_digit)P);    /* V=V_1 */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:21:51 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   mp_set(&U2mz, 1uL);  /* U_1 */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   mp_set(&V2mz, (mp_digit)P);  /* V_1 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   if (Q < 0) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Q = -Q;
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      /* Initializes calculation of Q^d */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      Qmz.sign = MP_NEG;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Q2mz.sign = MP_NEG;
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Qkdz.sign = MP_NEG;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Q = -Q;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   } else {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      /* Initializes calculation of Q^d */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   Nbits = mp_count_bits(&Dz);
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      /* Formulas for doubling of indices (carried out mod N). Note that
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       * the indices denoted as "2m" are actually powers of 2, specifically
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       * 2^(ul-1) beginning each loop and 2^ul ending each loop.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       * U_2m = U_m*V_m
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       * V_2m = V_m*V_m - 2*Q^m
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      /* Must calculate powers of Q for use in V_2m, also for Q^d later */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:17:48 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      /* prevents overflow */ /* CZ  still necessary without a fixed prealloc'd mem.? */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((isset = mp_get_bit(&Dz, u)) == MP_VAL) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         e = isset;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (isset == MP_YES) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         /* Formulas for addition of indices (carried out mod N);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          * U_(m+n) = (U_m*V_n + U_n*V_m)/2
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          * Be careful with division by 2 (mod N)!
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = s_mp_mul_si(&T4z, (long)Ds, &T4z)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:24:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if (mp_isodd(&Uz) != MP_NO) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if ((e = mp_add(&Uz, a, &Uz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-21 22:17:48 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         /* CZ
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          * This should round towards negative infinity because
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp().
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          * But mp_div_2() does not do so, it is truncating instead.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_div_2(&Uz, &Uz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:24:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((Uz.sign == MP_NEG) && (mp_isodd(&Uz) != MP_NO)) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:21:51 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if ((e = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:24:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if (mp_isodd(&Vz) != MP_NO) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if ((e = mp_add(&Vz, a, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_div_2(&Vz, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:24:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((Vz.sign == MP_NEG) && (mp_isodd(&Vz) != MP_NO)) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:21:51 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if ((e = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mod(&Uz, a, &Uz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         /* Calculating Q^d for later use */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      strong Lucas pseudoprime. */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:24:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   if ((mp_iszero(&Uz) != MP_NO) || (mp_iszero(&Vz) != MP_NO)) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      *result = MP_YES;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed.,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      1995/6) omits the condition V0 on p.142, but includes it on
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      p. 130. The condition is NECESSARY; otherwise the test will
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return false negatives---e.g., the primes 29 and 2000029 will be
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      returned as composite. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      these are congruent to 0 mod N, then N is a prime or a strong
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      Lucas pseudoprime. */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   /* Initialize 2*Q^(d*2^r) for V_2m */
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   for (r = 1; r < s; r++) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_sqr(&Vz, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:24:49 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if (mp_iszero(&Vz) != MP_NO) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         *result = MP_YES;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-05 15:07:22 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      if (r < (s - 1)) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-26 08:47:47 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								         if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) {
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            goto LBL_LS_ERR;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								         }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								LBL_LS_ERR:
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-25 14:04:02 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								   mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL);
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								   return e;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 15:15:13 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-04 00:01:45 +02:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							
								
									
										
										
										
											2018-05-26 01:39:03 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							
								
									
										
										
										
											2018-12-12 00:14:05 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* ref:         $Format:%D$ */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* git commit:  $Format:%H$ */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/* commit time: $Format:%ai$ */
							 |