summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--TODO2
-rw-r--r--cipher/ChangeLog12
-rw-r--r--cipher/random-daemon.c70
-rw-r--r--cipher/random.c15
-rw-r--r--cipher/random.h12
-rw-r--r--mpi/ChangeLog12
-rw-r--r--mpi/mpi-bit.c127
-rw-r--r--mpi/mpiutil.c21
-rw-r--r--tests/ChangeLog4
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/t-mpi-bit.c241
12 files changed, 446 insertions, 76 deletions
diff --git a/NEWS b/NEWS
index e4bbad4f..ca293d8e 100644
--- a/NEWS
+++ b/NEWS
@@ -12,9 +12,11 @@ Noteworthy changes in version 1.3.0 (unreleased)
* Support for SHA-224 and HMAC using SHA-384 and SHA-512.
+ * gcry_mpi_rshift does not anymore truncate the shift count.
+
* Interface changes relative to the 1.2.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- gcry_fast_random_poll NEW
+ gcry_fast_random_poll NEW
gcry_pk_algo_name CHANGED (minor change in respect to return value)
gcry_cipher_algo_name CHANGED (minor change in respect to return value)
GCRY_MD_SHA224 NEW
diff --git a/TODO b/TODO
index 365d8f7c..1cfc6dc1 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,7 @@
What's left to do -*- outline -*-
+* Updated the FSF's directory.
+
* Add more tests.
* udiv-qrnbd.o should get build as *.lo [HPUX]
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index a6cb45b4..c921a1a5 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,15 @@
+2006-08-03 Werner Koch <wk@g10code.com>
+
+ * random-daemon.c (_gcry_daemon_initialize_basics): Don't
+ initialize the socket. Remove arg SOCKETNAME.
+ (connect_to_socket): Make sure that daemon is set to -1 on error.
+ (call_daemon): Initialize the socket on the first call.
+ (_gcry_daemon_randomize, _gcry_daemon_get_random_bytes)
+ (_gcry_daemon_create_nonce): New arg SOCKETNAME.
+ * random.c (initialize): Call new daemon initializator.
+ (get_random_bytes, gcry_randomize, gcry_create_nonce): Pass socket
+ name to daemon call and reset allow_daemon on failure.
+
2006-07-26 Werner Koch <wk@g10code.com>
* rmd160.c (_gcry_rmd160_mixblock): Add cast to transform call.
diff --git a/cipher/random-daemon.c b/cipher/random-daemon.c
index 6a42d551..95d76f7d 100644
--- a/cipher/random-daemon.c
+++ b/cipher/random-daemon.c
@@ -24,7 +24,7 @@
gcryptrnd. Such a daemon is useful to keep a persistent pool in
memory over invocations of a single application and to allow
prioritizing access to the actual entropy sources. The drawback is
- that we need to use IPC (i.e. unxi domain socket) to convey
+ that we need to use IPC (i.e. unix domain socket) to convey
sensitive data.
*/
@@ -111,20 +111,22 @@ connect_to_socket (const char *socketname, int *sock)
out:
- *sock = fd;
gcry_free (srvr_addr);
-
if (err)
- close (fd);
+ {
+ close (fd);
+ fd = -1;
+ }
+ *sock = fd;
return err;
}
/* Initialize basics of this module. This should be viewed as a
- constroctur to prepare locking. */
+ constructor to prepare locking. */
void
-_gcry_daemon_initialize_basics (const char *socketname)
+_gcry_daemon_initialize_basics (void)
{
static int initialized;
int err;
@@ -135,15 +137,10 @@ _gcry_daemon_initialize_basics (const char *socketname)
err = ath_mutex_init (&daemon_lock);
if (err)
log_fatal ("failed to create the daemon lock: %s\n", strerror (err) );
-
- err = connect_to_socket (socketname ? socketname : RANDOM_DAEMON_SOCKET,
- &daemon_socket);
- if (err)
- log_info ("not using random daemon\n");
}
}
-
+
/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on
success or another value on write error. */
@@ -201,22 +198,47 @@ readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
data of random level LEVEL will be generated. The retrieved random
data will be stored in BUFFER. Returns error code. */
static gcry_error_t
-call_daemon (void *buffer, size_t req_nbytes, int nonce,
+call_daemon (const char *socketname,
+ void *buffer, size_t req_nbytes, int nonce,
enum gcry_random_level level)
{
+ static int initialized;
unsigned char buf[255];
- gcry_error_t err;
+ gcry_error_t err = 0;
size_t nbytes;
size_t nread;
int rc;
- err = 0;
-
- if (! req_nbytes)
+ if (!req_nbytes)
return 0;
ath_mutex_lock (&daemon_lock);
+ /* Open the socket if that has not been done. */
+ if (!initialized)
+ {
+ initialized = 1;
+ err = connect_to_socket (socketname ? socketname : RANDOM_DAEMON_SOCKET,
+ &daemon_socket);
+ if (err)
+ {
+ daemon_socket = -1;
+ log_info ("not using random daemon\n");
+ ath_mutex_unlock (&daemon_lock);
+ return err;
+ }
+ }
+
+ /* Check that we have a valid socket descriptor. */
+ if ( daemon_socket == -1 )
+ {
+ ath_mutex_unlock (&daemon_lock);
+ return gcry_error (GPG_ERR_INTERNAL);
+ }
+
+
+ /* Do the real work. */
+
do
{
/* Process in chunks. */
@@ -311,12 +333,13 @@ call_daemon (void *buffer, size_t req_nbytes, int nonce,
support GCRY_STRONG_RANDOM and GCRY_VERY_STRONG_RANDOM here.
Return 0 on success. */
int
-_gcry_daemon_randomize (void *buffer, size_t length,
+_gcry_daemon_randomize (const char *socketname,
+ void *buffer, size_t length,
enum gcry_random_level level)
{
gcry_error_t err;
- err = call_daemon (buffer, length, 0, level);
+ err = call_daemon (socketname, buffer, length, 0, level);
return err ? -1 : 0;
}
@@ -327,7 +350,8 @@ _gcry_daemon_randomize (void *buffer, size_t length,
that the IPC mechanism might have not stored it there. Return a
pointer to a newly alloced memory or NULL if it failed. */
void *
-_gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure)
+_gcry_daemon_get_random_bytes (const char *socketname,
+ size_t nbytes, int level, int secure)
{
gcry_error_t err;
void *p;
@@ -336,7 +360,7 @@ _gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure)
if (err)
goto out;
- err = call_daemon (p, nbytes, 0, level);
+ err = call_daemon (socketname, p, nbytes, 0, level);
out:
@@ -353,11 +377,11 @@ _gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure)
/* Internal function to fill BUFFER with NBYTES of data usable for a
nonce. Returns 0 on success. */
int
-_gcry_daemon_create_nonce (void *buffer, size_t length)
+_gcry_daemon_create_nonce (const char *socketname, void *buffer, size_t length)
{
gcry_error_t err;
- err = call_daemon (buffer, length, 1, 0);
+ err = call_daemon (socketname, buffer, length, 1, 0);
return err ? -1 : 0;
}
diff --git a/cipher/random.c b/cipher/random.c
index e38b8773..528111af 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -161,7 +161,7 @@ initialize_basics(void)
if (err)
log_fatal ("failed to create the nonce buffer lock: %s\n",
strerror (err) );
- _gcry_daemon_initialize_basics (daemon_socket_name);
+ _gcry_daemon_initialize_basics ();
}
}
@@ -304,8 +304,11 @@ get_random_bytes ( size_t nbytes, int level, int secure)
/* Make sure the requested level is in range. */
MASK_LEVEL(level);
- if (allow_daemon && (p=_gcry_daemon_get_random_bytes (nbytes, level,secure)))
+ if (allow_daemon &&
+ (p=_gcry_daemon_get_random_bytes (daemon_socket_name,
+ nbytes, level,secure)))
return p; /* The daemon succeeded. */
+ allow_daemon = 0; /* Daemon failed - switch off. */
/* Lock the pool. */
err = ath_mutex_lock (&pool_lock);
@@ -417,8 +420,10 @@ gcry_randomize (byte *buffer, size_t length, enum gcry_random_level level)
/* Make sure the level is okay. */
MASK_LEVEL(level);
- if (allow_daemon && !_gcry_daemon_randomize (buffer, length, level))
+ if (allow_daemon
+ && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level))
return; /* The daemon succeeded. */
+ allow_daemon = 0; /* Daemon failed - switch off. */
/* Acquire the pool lock. */
err = ath_mutex_lock (&pool_lock);
@@ -1233,8 +1238,10 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
if (!is_initialized)
initialize ();
- if (allow_daemon && !_gcry_daemon_create_nonce (buffer, length))
+ if (allow_daemon
+ && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length))
return; /* The daemon succeeded. */
+ allow_daemon = 0; /* Daemon failed - switch off. */
/* Acquire the nonce buffer lock. */
err = ath_mutex_lock (&nonce_buffer_lock);
diff --git a/cipher/random.h b/cipher/random.h
index afed64c7..3c9c75f3 100644
--- a/cipher/random.h
+++ b/cipher/random.h
@@ -37,12 +37,14 @@ byte *_gcry_get_random_bits( size_t nbits, int level, int secure );
void _gcry_fast_random_poll( void );
/*-- random-daemon.c (only used from random.c) --*/
-void _gcry_set_random_daemon_socket (const char *socketname);
-void _gcry_daemon_initialize_basics (const char *socketname);
-int _gcry_daemon_randomize (void *buffer, size_t length,
+void _gcry_daemon_initialize_basics (void);
+int _gcry_daemon_randomize (const char *socketname,
+ void *buffer, size_t length,
enum gcry_random_level level);
-void *_gcry_daemon_get_random_bytes (size_t nbytes, int level, int secure);
-int _gcry_daemon_create_nonce (void *buffer, size_t length);
+void *_gcry_daemon_get_random_bytes (const char *socketname,
+ size_t nbytes, int level, int secure);
+int _gcry_daemon_create_nonce (const char *socketname,
+ void *buffer, size_t length);
#endif /*G10_RANDOM_H*/
diff --git a/mpi/ChangeLog b/mpi/ChangeLog
index c82cc6c6..176ccf22 100644
--- a/mpi/ChangeLog
+++ b/mpi/ChangeLog
@@ -1,3 +1,15 @@
+2006-08-04 Werner Koch <wk@g10code.com>
+
+ * mpi-bit.c (gcry_mpi_rshift): Rewritten to remove the limitation
+ on N (which used to be less than BITS_PER_MPI_LIMB).
+
+2006-08-03 Werner Koch <wk@g10code.com>
+
+ * mpi-bit.c (gcry_mpi_set_bit, gcry_mpi_set_highbit): Fixed
+ allocation. Reported by bpgcrypt at itaparica.org.
+ * mpiutil.c (_gcry_mpi_resize): Clear the new part of the resized
+ limb space.
+
2006-07-26 Werner Koch <wk@g10code.com>
* mpiutil.c (gcry_mpi_randomize): Changed P to unsigned char*.
diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c
index 2d917995..d16eaae1 100644
--- a/mpi/mpi-bit.c
+++ b/mpi/mpi-bit.c
@@ -1,5 +1,5 @@
/* mpi-bit.c - MPI bit level fucntions
- * Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2001, 2002, 2006 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -116,17 +116,17 @@ gcry_mpi_test_bit( gcry_mpi_t a, unsigned int n )
void
gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
{
- unsigned int limbno, bitno;
+ unsigned int limbno, bitno;
- limbno = n / BITS_PER_MPI_LIMB;
- bitno = n % BITS_PER_MPI_LIMB;
+ limbno = n / BITS_PER_MPI_LIMB;
+ bitno = n % BITS_PER_MPI_LIMB;
- if( limbno >= a->nlimbs ) { /* resize */
- if( a->alloced >= limbno )
- mpi_resize(a, limbno+1 );
- a->nlimbs = limbno+1;
+ if ( limbno >= a->nlimbs )
+ {
+ mpi_resize (a, limbno+1 );
+ a->nlimbs = limbno+1;
}
- a->d[limbno] |= (A_LIMB_1<<bitno);
+ a->d[limbno] |= (A_LIMB_1<<bitno);
}
/****************
@@ -135,20 +135,20 @@ gcry_mpi_set_bit( gcry_mpi_t a, unsigned int n )
void
gcry_mpi_set_highbit( gcry_mpi_t a, unsigned int n )
{
- unsigned int limbno, bitno;
-
- limbno = n / BITS_PER_MPI_LIMB;
- bitno = n % BITS_PER_MPI_LIMB;
-
- if( limbno >= a->nlimbs ) { /* resize */
- if( a->alloced >= limbno )
- mpi_resize(a, limbno+1 );
- a->nlimbs = limbno+1;
+ unsigned int limbno, bitno;
+
+ limbno = n / BITS_PER_MPI_LIMB;
+ bitno = n % BITS_PER_MPI_LIMB;
+
+ if ( limbno >= a->nlimbs )
+ {
+ mpi_resize (a, limbno+1 );
+ a->nlimbs = limbno+1;
}
- a->d[limbno] |= (A_LIMB_1<<bitno);
- for( bitno++; bitno < BITS_PER_MPI_LIMB; bitno++ )
- a->d[limbno] &= ~(A_LIMB_1 << bitno);
- a->nlimbs = limbno+1;
+ a->d[limbno] |= (A_LIMB_1<<bitno);
+ for ( bitno++; bitno < BITS_PER_MPI_LIMB; bitno++ )
+ a->d[limbno] &= ~(A_LIMB_1 << bitno);
+ a->nlimbs = limbno+1;
}
/****************
@@ -188,26 +188,77 @@ gcry_mpi_clear_bit( gcry_mpi_t a, unsigned int n )
}
-/****************
- * Shift A by N bits to the right
- * FIXME: should use alloc_limb if X and A are same.
+/*
+ * Shift A by N bits to the right.
*/
void
-gcry_mpi_rshift( gcry_mpi_t x, gcry_mpi_t a, unsigned n )
+gcry_mpi_rshift ( gcry_mpi_t x, gcry_mpi_t a, unsigned int n )
{
- mpi_ptr_t xp;
- mpi_size_t xsize;
-
- xsize = a->nlimbs;
- x->sign = a->sign;
- RESIZE_IF_NEEDED(x, xsize);
- xp = x->d;
-
- if( xsize ) {
- _gcry_mpih_rshift( xp, a->d, xsize, n);
- MPN_NORMALIZE( xp, xsize);
+ mpi_size_t xsize;
+ unsigned int i;
+ unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
+ unsigned int nbits = (n%BITS_PER_MPI_LIMB);
+
+ if ( x == a )
+ {
+ /* In-place operation. */
+ if ( nlimbs >= x->nlimbs )
+ {
+ x->nlimbs = 0;
+ return;
+ }
+
+ if (nlimbs)
+ {
+ for (i=0; i < x->nlimbs - nlimbs; i++ )
+ x->d[i] = x->d[i+nlimbs];
+ x->d[i] = 0;
+ x->nlimbs -= nlimbs;
+
+ }
+ if ( x->nlimbs && nbits )
+ _gcry_mpih_rshift ( x->d, x->d, x->nlimbs, nbits );
+ }
+ else if ( nlimbs )
+ {
+ /* Copy and shift by more or equal bits than in a limb. */
+ xsize = a->nlimbs;
+ x->sign = a->sign;
+ RESIZE_IF_NEEDED (x, xsize);
+ x->nlimbs = xsize;
+ for (i=0; i < a->nlimbs; i++ )
+ x->d[i] = a->d[i];
+ x->nlimbs = i;
+
+ if ( nlimbs >= x->nlimbs )
+ {
+ x->nlimbs = 0;
+ return;
+ }
+
+ if (nlimbs)
+ {
+ for (i=0; i < x->nlimbs - nlimbs; i++ )
+ x->d[i] = x->d[i+nlimbs];
+ x->d[i] = 0;
+ x->nlimbs -= nlimbs;
+ }
+
+ if ( x->nlimbs && nbits )
+ _gcry_mpih_rshift ( x->d, x->d, x->nlimbs, nbits );
+ }
+ else
+ {
+ /* Copy and shift by less than bits in a limb. */
+ xsize = a->nlimbs;
+ x->sign = a->sign;
+ RESIZE_IF_NEEDED (x, xsize);
+ x->nlimbs = xsize;
+
+ if ( xsize )
+ _gcry_mpih_rshift (x->d, a->d, x->nlimbs, nbits );
}
- x->nlimbs = xsize;
+ MPN_NORMALIZE (x->d, x->nlimbs);
}
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index f6f9a8b2..fe1b7617 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -115,17 +115,30 @@ _gcry_mpi_assign_limb_space( gcry_mpi_t a, mpi_ptr_t ap, unsigned int nlimbs )
/****************
- * Resize the array of A to NLIMBS. the additional space is cleared
- * (set to 0) [done by gcry_realloc()]
+ * Resize the array of A to NLIMBS. The additional space is cleared
+ * (set to 0).
*/
void
_gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs)
{
+ size_t i;
+
if (nlimbs <= a->alloced)
- return; /* no need to do it */
+ {
+ /* We only need to clear the new space (this is a nop if the
+ limb space is already of the correct size. */
+ for (i=a->nlimbs; i < a->alloced; i++)
+ a->d[i] = 0;
+ return;
+ }
+ /* Actually resize the limb space. */
if (a->d)
- a->d = gcry_xrealloc (a->d, nlimbs * sizeof (mpi_limb_t));
+ {
+ a->d = gcry_xrealloc (a->d, nlimbs * sizeof (mpi_limb_t));
+ for (i=a->alloced; i < nlimbs; i++)
+ a->d[i] = 0;
+ }
else
{
if (a->flags & 1)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 154bd5e2..af66e6ed 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,7 @@
+2006-08-03 Werner Koch <wk@g10code.com>
+
+ * t-mpi-bit.c: New.
+
2006-07-06 Werner Koch <wk@g10code.com>
* benchmark.c (main): New option --use-random-daemon. New command
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 945ce5d0..e4a922ac 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -18,7 +18,7 @@
## Process this file with automake to produce Makefile.in
-TESTS = prime register ac ac-schemes ac-data basic \
+TESTS = t-mpi-bit prime register ac ac-schemes ac-data basic \
tsexp keygen pubkey benchmark pkbench hmac keygrip
INCLUDES = -I$(top_srcdir)/src
diff --git a/tests/t-mpi-bit.c b/tests/t-mpi-bit.c
new file mode 100644
index 00000000..2465a8fd
--- /dev/null
+++ b/tests/t-mpi-bit.c
@@ -0,0 +1,241 @@
+/* t-mpi-bit.c - Tests for bit level functions
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "../src/gcrypt.h"
+
+#define PGM "t-mpi-bit"
+
+static const char *wherestr;
+static int verbose;
+static int error_count;
+
+#define xmalloc(a) gcry_xmalloc ((a))
+#define xcalloc(a,b) gcry_xcalloc ((a),(b))
+#define xfree(a) gcry_free ((a))
+#define pass() do { ; } while (0)
+
+static void
+show (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ if (!verbose)
+ return;
+ fprintf (stderr, "%s: ", PGM);
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+}
+
+static void
+fail (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ fflush (stdout);
+ fprintf (stderr, "%s: ", PGM);
+ if (wherestr)
+ fprintf (stderr, "%s: ", wherestr);
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ error_count++;
+}
+
+static void
+die (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ fflush (stdout);
+ fprintf (stderr, "%s: ", PGM);
+ if (wherestr)
+ fprintf (stderr, "%s: ", wherestr);
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ exit (1);
+}
+
+/* Allocate a bit string consisting of '0' and '1' from the MPI
+ A. Return the LENGTH least significant bits. Caller needs to xfree
+ the result. */
+static char *
+mpi2bitstr (gcry_mpi_t a, size_t length)
+{
+ char *p, *buf;
+
+ buf = p = xmalloc (length+1);
+ while (length--)
+ *p++ = gcry_mpi_test_bit (a, length) ? '1':'0';
+ *p = 0;
+
+ return buf;
+}
+
+/* Shift a bit string to the right. */
+static void
+rshiftbitstring (char *string, size_t n)
+{
+ size_t len = strlen (string);
+
+ if (n > len)
+ n = len;
+
+ memmove (string+n, string, len-n);
+ memset (string, '0', n);
+}
+
+
+/* This is to check a bug reported by bpgcrypt at itaparica.org on
+ 2006-07-31 against libgcrypt 1.2.2. */
+static void
+one_bit_only (int highbit)
+{
+ gcry_mpi_t a;
+ char *result;
+ int i;
+
+ wherestr = "one_bit_only";
+ show ("checking that set_%sbit does only set one bit\n", highbit?"high":"");
+
+ a = gcry_mpi_new (0);
+ gcry_mpi_randomize (a, 70, GCRY_WEAK_RANDOM);
+ gcry_mpi_set_ui (a, 0);
+
+ if (highbit)
+ gcry_mpi_set_highbit (a, 42);
+ else
+ gcry_mpi_set_bit (a, 42);
+ if (!gcry_mpi_test_bit (a, 42))
+ fail ("failed to set a bit\n");
+ gcry_mpi_clear_bit (a, 42);
+ if (gcry_mpi_test_bit (a, 42))
+ fail ("failed to clear a bit\n");
+ result = mpi2bitstr (a, 70);
+ assert (strlen (result) == 70);
+ show ("r=%s\n", result);
+ for (i=0; result[i]; i++)
+ if ( result[i] != '0' )
+ break;
+ if (result[i])
+ fail ("spurious bits detected\n");
+ xfree (result);
+ gcry_mpi_release (a);
+}
+
+/* Check that the shifting actually works for an amount larger than
+ the number of bits per limb. */
+static void
+test_rshift (int pass)
+{
+ gcry_mpi_t a, b;
+ char *result, *result2;
+ int i;
+
+ wherestr = "test_rshift";
+ show ("checking that rshift works as expected (pass %d)\n", pass);
+
+ a = gcry_mpi_new (0);
+ b = gcry_mpi_new (0);
+ gcry_mpi_randomize (a, 70, GCRY_WEAK_RANDOM);
+
+ for (i=0; i < 75; i++)
+ {
+ gcry_mpi_rshift (b, a, i);
+
+ result = mpi2bitstr (b, 72);
+ result2 = mpi2bitstr (a, 72);
+ rshiftbitstring (result2, i);
+ if (strcmp (result, result2))
+ {
+ show ("got =%s\n", result);
+ show ("want=%s\n", result2);
+ fail ("rshift by %d failed\n", i);
+ }
+ xfree (result);
+ xfree (result2);
+ }
+
+ /* Again. This time using in-place operation. */
+ gcry_mpi_randomize (a, 70, GCRY_WEAK_RANDOM);
+
+ for (i=0; i < 75; i++)
+ {
+ gcry_mpi_release (b);
+ b = gcry_mpi_copy (a);
+ gcry_mpi_rshift (b, b, i);
+
+ result = mpi2bitstr (b, 72);
+ result2 = mpi2bitstr (a, 72);
+ rshiftbitstring (result2, i);
+ if (strcmp (result, result2))
+ {
+ show ("got =%s\n", result);
+ show ("want=%s\n", result2);
+ fail ("in-place rshift by %d failed\n", i);
+ }
+ xfree (result2);
+ xfree (result);
+ }
+
+ gcry_mpi_release (b);
+ gcry_mpi_release (a);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int debug = 0;
+ int i;
+
+ if (argc > 1 && !strcmp (argv[1], "--verbose"))
+ verbose = 1;
+ else if (argc > 1 && !strcmp (argv[1], "--debug"))
+ verbose = debug = 1;
+
+ if (!gcry_check_version (GCRYPT_VERSION))
+ die ("version mismatch\n");
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (debug)
+ gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
+ one_bit_only (0);
+ one_bit_only (1);
+ for (i=0; i < 5; i++)
+ test_rshift (i); /* Run several times due to random initializations. */
+
+ show ("All tests completed. Errors: %d\n", error_count);
+ return error_count ? 1 : 0;
+}