Revert "Remove gmp from AOS"

This reverts commit f37c97684f0910a3f241394549392f00145ab0f7.

We need gmp for SymEngine for symbolicmanipultion in C++

Change-Id: Ia13216d1715cf96944f7b4f422b7a799f921d4a4
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/third_party/gmp/mini-gmp/tests/Makefile b/third_party/gmp/mini-gmp/tests/Makefile
new file mode 100644
index 0000000..7cc4485
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/Makefile
@@ -0,0 +1,65 @@
+# Note: Requires GNU make
+
+# Copyright 2011, 2012, 2014, 2016, 2018 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite 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 General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+srcdir=.
+MINI_GMP_DIR=..
+
+CC = gcc
+CFLAGS = -O -Wall -g
+CPPFLAGS =
+LDFLAGS =
+
+LIBS = -lgmp -lm -lmcheck
+
+CHECK_PROGRAMS = t-add t-sub t-mul t-invert t-div t-div_2exp \
+	t-double t-cmp_d t-gcd t-lcm t-import t-comb t-signed \
+	t-sqrt t-root t-powm t-logops t-bitops t-scan t-str \
+	t-reuse t-aorsmul t-limbs t-cong t-pprime_p t-lucm \
+	t-mpq_addsub t-mpq_muldiv t-mpq_muldiv_2exp t-mpq_str \
+	t-mpq_double
+# Default TESTS to all tests, allowing overriding TESTS for building tests
+# without running them.
+TESTS = $(CHECK_PROGRAMS)
+
+MISC_OBJS = hex-random.o mini-random.o testutils.o
+
+all:
+
+clean:
+	rm -f *.o $(CHECK_PROGRAMS)
+
+%: %.c
+.c:
+
+# Keep object files
+.PRECIOUS: %.o
+
+%.o: %.c $(MINI_GMP_DIR)/mini-gmp.h $(MINI_GMP_DIR)/mini-mpq.h hex-random.h mini-random.h
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
+testutils.o: $(MINI_GMP_DIR)/mini-gmp.c $(MINI_GMP_DIR)/mini-mpq.c
+
+%: %.o $(MISC_OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@
+
+# Missing tests include:
+#   mpz_cmp_d, mpz_popcount, mpz_hamdist, mpz_ui_pow_ui
+
+check: $(CHECK_PROGRAMS)
+	$(srcdir)/run-tests $(TESTS)
diff --git a/third_party/gmp/mini-gmp/tests/hex-random.c b/third_party/gmp/mini-gmp/tests/hex-random.c
new file mode 100644
index 0000000..a5b405b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/hex-random.c
@@ -0,0 +1,573 @@
+/*
+
+Copyright 2011, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+
+#ifdef __unix__
+# include <unistd.h>
+# include <sys/time.h>
+#endif
+
+#include "gmp.h"
+
+#include "hex-random.h"
+
+/* FIXME: gmp-impl.h included only for mpz_lucas_mod */
+/* #include "gmp-impl.h" */
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#define mpz_lucas_mod  __gmpz_lucas_mod
+__GMP_DECLSPEC int mpz_lucas_mod (mpz_ptr, mpz_ptr, long, mp_bitcnt_t, mpz_srcptr, mpz_ptr, mpz_ptr);
+
+#if defined (__cplusplus)
+}
+#endif
+
+static gmp_randstate_t state;
+
+static void
+mkseed (mpz_t seed)
+{
+  FILE *f = fopen ("/dev/urandom", "rb");
+  if (f)
+    {
+      unsigned char buf[6];
+      size_t res;
+
+      setbuf (f, NULL);
+      res = fread (buf, sizeof(buf), 1, f);
+      fclose (f);
+
+      if (res == 1)
+	{
+	  mpz_import (seed, sizeof(buf), 1, 1, 0, 0, buf);
+	  return;
+	}
+    }
+
+#ifdef __unix__
+  {
+    struct timeval tv;
+    mpz_t usec;
+    mpz_init (usec);
+
+    gettimeofday (&tv, NULL);
+    mpz_set_ui (seed, tv.tv_sec);
+    mpz_set_ui (usec, tv.tv_usec);
+    /* usec fits in 20 bits, shift left to make it 48 bits. */
+    mpz_mul_2exp (usec, usec, 28);
+    mpz_xor (seed, seed, usec);
+
+    mpz_clear (usec);
+  }
+#else
+  mpz_set_ui (seed, time (NULL));
+#endif
+}
+
+void
+hex_random_init (void)
+{
+  mpz_t seed;
+  char *env_seed;
+
+  mpz_init (seed);
+
+  env_seed = getenv ("GMP_CHECK_RANDOMIZE");
+  if (env_seed && env_seed[0])
+    {
+      mpz_set_str (seed, env_seed, 0);
+      if (mpz_cmp_ui (seed, 0) != 0)
+	gmp_printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%Zd\n", seed);
+      else
+	{
+	  mkseed (seed);
+	  gmp_printf ("Seed GMP_CHECK_RANDOMIZE=%Zd (include this in bug reports)\n", seed);
+	}
+      fflush (stdout);
+    }
+  else
+    mpz_set_ui (seed, 4711);
+
+  gmp_randinit_default (state);
+  gmp_randseed (state, seed);
+
+  mpz_clear (seed);
+}
+
+char *
+hex_urandomb (unsigned long bits)
+{
+  char *res;
+  mpz_t x;
+
+  mpz_init (x);
+  mpz_urandomb (x, state, bits);
+  gmp_asprintf (&res, "%Zx", x);
+  mpz_clear (x);
+  return res;
+}
+
+char *
+hex_rrandomb (unsigned long bits)
+{
+  char *res;
+  mpz_t x;
+
+  mpz_init (x);
+  mpz_rrandomb (x, state, bits);
+  gmp_asprintf (&res, "%Zx", x);
+  mpz_clear (x);
+  return res;
+}
+
+char *
+hex_rrandomb_export (void *dst, size_t *countp,
+		     int order, size_t size, int endian, unsigned long bits)
+{
+  char *res;
+  mpz_t x;
+  mpz_init (x);
+  mpz_rrandomb (x, state, bits);
+  gmp_asprintf (&res, "%Zx", x);
+  mpz_export (dst, countp, order, size, endian, 0, x);
+  mpz_clear (x);
+  return res;
+}
+
+void hex_random_op2 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **rp)
+{
+  mpz_t a, r;
+  unsigned long abits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (r);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 1);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  switch (op)
+    {
+    default:
+      abort ();
+    case OP_SQR:
+      mpz_mul (r, a, a);
+      break;
+    }
+
+  gmp_asprintf (ap, "%Zx", a);
+  gmp_asprintf (rp, "%Zx", r);
+
+  mpz_clear (a);
+  mpz_clear (r);
+}
+
+void
+hex_random_op3 (enum hex_random_op op,  unsigned long maxbits,
+		char **ap, char **bp, char **rp)
+{
+  mpz_t a, b, r;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (r);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+  bbits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (a, state, abits);
+  mpz_rrandomb (b, state, bbits);
+
+  signs = gmp_urandomb_ui (state, 3);
+  if (signs & 1)
+    mpz_neg (a, a);
+  if (signs & 2)
+    mpz_neg (b, b);
+
+  switch (op)
+    {
+    default:
+      abort ();
+    case OP_ADD:
+      mpz_add (r, a, b);
+      break;
+    case OP_SUB:
+      mpz_sub (r, a, b);
+      break;
+    case OP_MUL:
+      mpz_mul (r, a, b);
+      break;
+    case OP_GCD:
+      if (signs & 4)
+	{
+	  /* Produce a large gcd */
+	  unsigned long gbits = gmp_urandomb_ui (state, 32) % maxbits;
+	  mpz_rrandomb (r, state, gbits);
+	  mpz_mul (a, a, r);
+	  mpz_mul (b, b, r);
+	}
+      mpz_gcd (r, a, b);
+      break;
+    case OP_LCM:
+      if (signs & 4)
+	{
+	  /* Produce a large gcd */
+	  unsigned long gbits = gmp_urandomb_ui (state, 32) % maxbits;
+	  mpz_rrandomb (r, state, gbits);
+	  mpz_mul (a, a, r);
+	  mpz_mul (b, b, r);
+	}
+      mpz_lcm (r, a, b);
+      break;
+    case OP_AND:
+      mpz_and (r, a, b);
+      break;
+    case OP_IOR:
+      mpz_ior (r, a, b);
+      break;
+    case OP_XOR:
+      mpz_xor (r, a, b);
+      break;
+    }
+
+  gmp_asprintf (ap, "%Zx", a);
+  gmp_asprintf (bp, "%Zx", b);
+  gmp_asprintf (rp, "%Zx", r);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (r);
+}
+
+void
+hex_random_op4 (enum hex_random_op op, unsigned long maxbits,
+		char **ap, char **bp, char **cp, char **dp)
+{
+  mpz_t a, b, c, d;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (c);
+  mpz_init (d);
+
+  if (op == OP_POWM)
+    {
+      unsigned long cbits;
+      abits = gmp_urandomb_ui (state, 32) % maxbits;
+      bbits = 1 + gmp_urandomb_ui (state, 32) % maxbits;
+      cbits = 2 + gmp_urandomb_ui (state, 32) % maxbits;
+
+      mpz_rrandomb (a, state, abits);
+      mpz_rrandomb (b, state, bbits);
+      mpz_rrandomb (c, state, cbits);
+
+      signs = gmp_urandomb_ui (state, 3);
+      if (signs & 1)
+	mpz_neg (a, a);
+      if (signs & 2)
+	{
+	  mpz_t g;
+
+	  /* If we negate the exponent, must make sure that gcd(a, c) = 1 */
+	  if (mpz_sgn (a) == 0)
+	    mpz_set_ui (a, 1);
+	  else
+	    {
+	      mpz_init (g);
+
+	      for (;;)
+		{
+		  mpz_gcd (g, a, c);
+		  if (mpz_cmp_ui (g, 1) == 0)
+		    break;
+		  mpz_divexact (a, a, g);
+		}
+	      mpz_clear (g);
+	    }
+	  mpz_neg (b, b);
+	}
+      if (signs & 4)
+	mpz_neg (c, c);
+
+      mpz_powm (d, a, b, c);
+    }
+  else
+    {
+      unsigned long qbits;
+      bbits = 1 + gmp_urandomb_ui (state, 32) % maxbits;
+      qbits = gmp_urandomb_ui (state, 32) % maxbits;
+      abits = bbits + qbits;
+      if (abits > 30)
+	abits -= 30;
+      else
+	abits = 0;
+
+      mpz_rrandomb (a, state, abits);
+      mpz_rrandomb (b, state, bbits);
+
+      signs = gmp_urandomb_ui (state, 2);
+      if (signs & 1)
+	mpz_neg (a, a);
+      if (signs & 2)
+	mpz_neg (b, b);
+
+      switch (op)
+	{
+	default:
+	  abort ();
+	case OP_CDIV:
+	  mpz_cdiv_qr (c, d, a, b);
+	  break;
+	case OP_FDIV:
+	  mpz_fdiv_qr (c, d, a, b);
+	  break;
+	case OP_TDIV:
+	  mpz_tdiv_qr (c, d, a, b);
+	  break;
+	}
+    }
+  gmp_asprintf (ap, "%Zx", a);
+  gmp_asprintf (bp, "%Zx", b);
+  gmp_asprintf (cp, "%Zx", c);
+  gmp_asprintf (dp, "%Zx", d);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (c);
+  mpz_clear (d);
+}
+
+void
+hex_random_bit_op (enum hex_random_op op, unsigned long maxbits,
+		   char **ap, unsigned long *b, char **rp)
+{
+  mpz_t a, r;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (r);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+  bbits = gmp_urandomb_ui (state, 32) % (maxbits + 100);
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 1);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  switch (op)
+    {
+    default:
+      abort ();
+
+    case OP_SETBIT:
+      mpz_set (r, a);
+      mpz_setbit (r, bbits);
+      break;
+    case OP_CLRBIT:
+      mpz_set (r, a);
+      mpz_clrbit (r, bbits);
+      break;
+    case OP_COMBIT:
+      mpz_set (r, a);
+      mpz_combit (r, bbits);
+      break;
+    case OP_CDIV_Q_2:
+      mpz_cdiv_q_2exp (r, a, bbits);
+      break;
+    case OP_CDIV_R_2:
+      mpz_cdiv_r_2exp (r, a, bbits);
+      break;
+    case OP_FDIV_Q_2:
+      mpz_fdiv_q_2exp (r, a, bbits);
+      break;
+    case OP_FDIV_R_2:
+      mpz_fdiv_r_2exp (r, a, bbits);
+      break;
+    case OP_TDIV_Q_2:
+      mpz_tdiv_q_2exp (r, a, bbits);
+      break;
+    case OP_TDIV_R_2:
+      mpz_tdiv_r_2exp (r, a, bbits);
+      break;
+    }
+
+  gmp_asprintf (ap, "%Zx", a);
+  *b = bbits;
+  gmp_asprintf (rp, "%Zx", r);
+
+  mpz_clear (a);
+  mpz_clear (r);
+}
+
+void
+hex_random_scan_op (enum hex_random_op op, unsigned long maxbits,
+		    char **ap, unsigned long *b, unsigned long *r)
+{
+  mpz_t a;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+  bbits = gmp_urandomb_ui (state, 32) % (maxbits + 100);
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 1);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  switch (op)
+    {
+    default:
+      abort ();
+
+    case OP_SCAN0:
+      *r = mpz_scan0 (a, bbits);
+      break;
+    case OP_SCAN1:
+      *r = mpz_scan1 (a, bbits);
+      break;
+    }
+  gmp_asprintf (ap, "%Zx", a);
+  *b = bbits;
+
+  mpz_clear (a);
+}
+
+void
+hex_random_str_op (unsigned long maxbits,
+		   int base, char **ap, char **rp)
+{
+  mpz_t a;
+  unsigned long abits;
+  unsigned signs;
+
+  mpz_init (a);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 2);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  *ap = mpz_get_str (NULL, 16, a);
+  *rp = mpz_get_str (NULL, base, a);
+
+  mpz_clear (a);
+}
+
+void hex_random_lucm_op (unsigned long maxbits,
+			 char **vp, char **qp, char **mp,
+			 long *Q, unsigned long *b0, int *res)
+{
+  mpz_t m, v, q, t1, t2;
+  unsigned long mbits;
+
+  mpz_init (m);
+  mpz_init (v);
+  mpz_init (q);
+  mpz_init (t1);
+  mpz_init (t2);
+
+  *Q = gmp_urandomb_ui (state, 14) + 1;
+
+  do
+    {
+      mbits = gmp_urandomb_ui (state, 32) % maxbits + 5;
+
+      mpz_rrandomb (m, state, mbits);
+      *b0 = gmp_urandomb_ui (state, 32) % (mbits - 3) + 2;
+      /* The GMP  implementation uses the exponent (m >> b0) + 1. */
+      /* mini-gmp implementation uses the exponent (m >> b0) | 1. */
+      /* They are the same (and are used) only when (m >> b0) is even */
+      mpz_clrbit (m, *b0);
+      /* mini-gmp implementation only works if the modulus is odd. */
+      mpz_setbit (m, 0);
+    }
+  while (mpz_gcd_ui (NULL, m, *Q) != 1);
+
+  if (*Q == 1 || gmp_urandomb_ui (state, 1))
+    *Q = - *Q;
+
+#if (__GNU_MP_VERSION == 6 && (__GNU_MP_VERSION_MINOR > 1 || __GNU_MP_VERSION_PATCHLEVEL > 9))
+  *res = mpz_lucas_mod (v, q, *Q, *b0, m, t1, t2);
+#else
+  *b0 = 0;
+#endif
+
+  gmp_asprintf (vp, "%Zx", v);
+  gmp_asprintf (qp, "%Zx", q);
+  gmp_asprintf (mp, "%Zx", m);
+
+  mpz_clear (m);
+  mpz_clear (v);
+  mpz_clear (q);
+  mpz_clear (t1);
+  mpz_clear (t2);
+}
+
+void
+hex_mpq_random_str_op (unsigned long maxbits,
+		       int base, char **ap, char **rp)
+{
+  mpq_t a;
+  unsigned long abits;
+  unsigned signs;
+
+  mpq_init (a);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (mpq_numref (a), state, abits);
+  mpz_rrandomb (mpq_denref (a), state, abits);
+  mpz_add_ui (mpq_denref (a), mpq_denref (a), 1);
+
+  mpq_canonicalize (a);
+  signs = gmp_urandomb_ui (state, 2);
+  if (signs & 1)
+    mpq_neg (a, a);
+
+  *ap = mpq_get_str (NULL, 16, a);
+  *rp = mpq_get_str (NULL, base, a);
+
+  mpq_clear (a);
+}
diff --git a/third_party/gmp/mini-gmp/tests/hex-random.h b/third_party/gmp/mini-gmp/tests/hex-random.h
new file mode 100644
index 0000000..da44347
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/hex-random.h
@@ -0,0 +1,55 @@
+/*
+
+Copyright 2011, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+enum hex_random_op
+  {
+    OP_ADD, OP_SUB, OP_MUL, OP_SQR,
+    OP_CDIV, OP_FDIV, OP_TDIV,
+    OP_CDIV_Q_2, OP_CDIV_R_2,
+    OP_FDIV_Q_2, OP_FDIV_R_2,
+    OP_TDIV_Q_2,  OP_TDIV_R_2,
+    OP_GCD, OP_LCM, OP_POWM, OP_AND, OP_IOR, OP_XOR,
+    OP_SETBIT, OP_CLRBIT, OP_COMBIT,
+    OP_SCAN0, OP_SCAN1,
+  };
+
+void hex_random_init (void);
+char *hex_urandomb (unsigned long bits);
+char *hex_rrandomb (unsigned long bits);
+char *hex_rrandomb_export (void *dst, size_t *countp,
+			   int order, size_t size, int endian,
+			   unsigned long bits);
+
+void hex_random_op2 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **rp);
+void hex_random_op3 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **bp, char **rp);
+void hex_random_op4 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **bp, char **rp, char **qp);
+void hex_random_bit_op (enum hex_random_op op, unsigned long maxbits,
+			char **ap, unsigned long *b, char **rp);
+void hex_random_scan_op (enum hex_random_op op, unsigned long maxbits,
+			char **ap, unsigned long *b, unsigned long *r);
+void hex_random_str_op (unsigned long maxbits,
+			int base, char **ap, char **rp);
+void hex_random_lucm_op (unsigned long maxbits,
+			 char **vp, char **qp, char **mp,
+			 long *Q, unsigned long *b0, int *res);
+void hex_mpq_random_str_op (unsigned long maxbits,
+			    int base, char **ap, char **rp);
diff --git a/third_party/gmp/mini-gmp/tests/mini-random.c b/third_party/gmp/mini-gmp/tests/mini-random.c
new file mode 100644
index 0000000..7504af3
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/mini-random.c
@@ -0,0 +1,160 @@
+/*
+
+Copyright 2011, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mini-random.h"
+
+static void
+set_str (mpz_t r, const char *s)
+{
+  if (mpz_set_str (r, s, 16) != 0)
+    {
+      fprintf (stderr, "mpz_set_str failed on input %s\n", s);
+      abort ();
+    }
+}
+
+void
+mini_urandomb (mpz_t r, unsigned long bits)
+{
+  char *s;
+  s = hex_urandomb (bits);
+  set_str (r, s);
+  free (s);
+}
+
+void
+mini_rrandomb (mpz_t r, unsigned long bits)
+{
+  char *s;
+  s = hex_rrandomb (bits);
+  set_str (r, s);
+  free (s);
+}
+
+void
+mini_rrandomb_export (mpz_t r, void *dst, size_t *countp,
+		      int order, size_t size, int endian, unsigned long bits)
+{
+  char *s;
+  s = hex_rrandomb_export (dst, countp, order, size, endian, bits);
+  set_str (r, s);
+  free (s);
+}
+
+void
+mini_random_op2 (enum hex_random_op op, unsigned long maxbits,
+		 mpz_t a, mpz_t r)
+{
+  char *ap;
+  char *rp;
+
+  hex_random_op2 (op, maxbits, &ap, &rp);
+  set_str (a, ap);
+  set_str (r, rp);
+
+  free (ap);
+  free (rp);
+}
+
+void
+mini_random_op3 (enum hex_random_op op, unsigned long maxbits,
+		 mpz_t a, mpz_t b, mpz_t r)
+{
+  char *ap;
+  char *bp;
+  char *rp;
+
+  hex_random_op3 (op, maxbits, &ap, &bp, &rp);
+  set_str (a, ap);
+  set_str (b, bp);
+  set_str (r, rp);
+
+  free (ap);
+  free (bp);
+  free (rp);
+}
+
+void
+mini_random_op4 (enum hex_random_op op, unsigned long maxbits,
+		 mpz_t a, mpz_t b, mpz_t c, mpz_t d)
+{
+  char *ap;
+  char *bp;
+  char *cp;
+  char *dp;
+
+  hex_random_op4 (op, maxbits, &ap, &bp, &cp, &dp);
+  set_str (a, ap);
+  set_str (b, bp);
+  set_str (c, cp);
+  set_str (d, dp);
+
+  free (ap);
+  free (bp);
+  free (cp);
+  free (dp);
+}
+
+void
+mini_random_bit_op (enum hex_random_op op, unsigned long maxbits,
+			 mpz_t a, mp_bitcnt_t *b, mpz_t r)
+{
+  char *ap;
+  char *rp;
+
+  hex_random_bit_op (op, maxbits, &ap, b, &rp);
+  set_str (a, ap);
+  set_str (r, rp);
+
+  free (ap);
+  free (rp);
+}
+
+void
+mini_random_scan_op (enum hex_random_op op, unsigned long maxbits,
+		     mpz_t a, mp_bitcnt_t *b, mp_bitcnt_t *r)
+{
+  char *ap;
+
+  hex_random_scan_op (op, maxbits, &ap, b, r);
+  set_str (a, ap);
+
+  free (ap);
+}
+
+void
+mini_random_lucm_op (unsigned long maxbits, mpz_t v, mpz_t q, mpz_t m,
+			  long *Q, unsigned long *b0, int *res)
+{
+  char *vp;
+  char *qp;
+  char *mp;
+
+  hex_random_lucm_op (maxbits, &vp, &qp, &mp, Q, b0, res);
+  set_str (v, vp);
+  set_str (q, qp);
+  set_str (m, mp);
+
+  free (vp);
+  free (qp);
+  free (mp);
+}
diff --git a/third_party/gmp/mini-gmp/tests/mini-random.h b/third_party/gmp/mini-gmp/tests/mini-random.h
new file mode 100644
index 0000000..2f54749
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/mini-random.h
@@ -0,0 +1,35 @@
+/*
+
+Copyright 2011, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "../mini-gmp.h"
+#include "hex-random.h"
+
+void mini_urandomb (mpz_t, unsigned long);
+void mini_rrandomb (mpz_t, unsigned long);
+void mini_rrandomb_export (mpz_t r, void *dst, size_t *countp,
+			   int order, size_t size, int endian,
+			   unsigned long bits);
+
+void mini_random_op2 (enum hex_random_op,  unsigned long, mpz_t, mpz_t);
+void mini_random_op3 (enum hex_random_op,  unsigned long, mpz_t, mpz_t, mpz_t);
+void mini_random_op4 (enum hex_random_op, unsigned long, mpz_t, mpz_t, mpz_t, mpz_t);
+void mini_random_scan_op (enum hex_random_op, unsigned long, mpz_t, mp_bitcnt_t *, mp_bitcnt_t *);
+void mini_random_bit_op (enum hex_random_op, unsigned long, mpz_t, mp_bitcnt_t *, mpz_t);
+void mini_random_lucm_op (unsigned long, mpz_t, mpz_t, mpz_t,
+			  long *, unsigned long *, int *);
diff --git a/third_party/gmp/mini-gmp/tests/run-tests b/third_party/gmp/mini-gmp/tests/run-tests
new file mode 100755
index 0000000..5d452d6
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/run-tests
@@ -0,0 +1,135 @@
+#! /bin/sh
+
+# Copyright (C) 2000-2002, 2004, 2005, 2011, 2012, 2016  Niels Möller
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU 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.
+
+failed=0
+all=0
+
+debug='no'
+testflags=''
+
+if [ -z "$srcdir" ] ; then
+  srcdir=`pwd`
+fi
+
+export srcdir
+
+# When used in make rules, we sometimes get the filenames VPATH
+# expanded, but usually not.
+find_program () {
+    case "$1" in
+	*/*)
+	  echo "$1"
+	  ;;
+	*)
+	  if [ -x "$1" ] ; then
+	      echo "./$1"
+	  else
+	      echo "$srcdir/$1"
+	  fi
+	  ;;
+    esac
+}
+
+env_program () {
+  if [ -x "$1" ] ; then
+    if "$1"; then : ; else
+      echo FAIL: $1
+      exit 1
+    fi
+  fi
+}
+
+TEST_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+TEST_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH"
+
+if [ "$TEST_LIBRARY_PATH" ] ; then
+  TEST_LD_LIBRARY_PATH="$TEST_LIBRARY_PATH:$TEST_LD_LIBRARY_PATH"
+  TEST_DYLD_LIBRARY_PATH="$TEST_LIBRARY_PATH:$TEST_DYLD_LIBRARY_PATH"
+fi
+
+test_program () {
+  testname=`basename "$1" .exe`
+  testname=`basename "$testname" -test`
+  if [ -z "$EMULATOR" ] || head -1 "$1" | grep '^#!' > /dev/null; then
+    LD_LIBRARY_PATH="$TEST_LD_LIBRARY_PATH" \
+    DYLD_LIBRARY_PATH="$TEST_DYLD_LIBRARY_PATH" \
+    "$1" $testflags
+  else
+    $EMULATOR "$1" $testflags
+  fi
+  case "$?" in
+      0)
+	echo PASS: $testname
+	all=`expr $all + 1`
+	;;
+      77)
+	echo SKIP: $testname
+      ;;
+      *)
+	echo FAIL: $testname
+	failed=`expr $failed + 1`
+	all=`expr $all + 1`
+	;;
+  esac
+}
+
+env_program `find_program setup-env`
+
+while test $# != 0
+do
+  case "$1" in
+  --debug)
+    debug=yes
+    ;;
+  -v)
+    testflags='-v'
+    ;;
+  -*)
+    echo >&2 'Unknown option `'"$1'"
+    exit 1
+    ;;
+  *)
+    break
+    ;;
+  esac
+  shift
+done
+
+# Comment out special handling for zero arguments to support separate
+# tests-build/tests-run.
+#if [ $# -eq 0 ] ; then
+#  for f in *-test; do test_program "./$f"; done
+#else
+  for f in "$@" ; do test_program `find_program "$f"`; done
+#fi
+
+if [ $failed -eq 0 ] ; then
+  banner="All $all tests passed"
+else
+  banner="$failed of $all tests failed"
+fi
+dashes=`echo "$banner" | sed s/./=/g`
+echo "$dashes"
+echo "$banner"
+echo "$dashes"
+
+if [ "x$debug" = xno ] ; then
+  env_program `find_program teardown-env`
+fi
+
+[ "$failed" -eq 0 ]
diff --git a/third_party/gmp/mini-gmp/tests/t-add.c b/third_party/gmp/mini-gmp/tests/t-add.c
new file mode 100644
index 0000000..0a093ef
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-add.c
@@ -0,0 +1,57 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_ADD, MAXBITS, a, b, ref);
+      mpz_add (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_add failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-aorsmul.c b/third_party/gmp/mini-gmp/tests/t-aorsmul.c
new file mode 100644
index 0000000..eb275a8
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-aorsmul.c
@@ -0,0 +1,77 @@
+/*
+
+Copyright 2012, 2014, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init_set_ui (res, 5);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
+      if (i & 1) {
+	mpz_add (ref, ref, res);
+	if (mpz_fits_ulong_p (b))
+	  mpz_addmul_ui (res, a, mpz_get_ui (b));
+	else
+	  mpz_addmul (res, a, b);
+      } else {
+	mpz_sub (ref, res, ref);
+	if (mpz_fits_ulong_p (b))
+	  mpz_submul_ui (res, a, mpz_get_ui (b));
+	else
+	  mpz_submul (res, a, b);
+      }
+      if (mpz_cmp (res, ref))
+	{
+	  if (i & 1)
+	    fprintf (stderr, "mpz_addmul failed:\n");
+	  else
+	    fprintf (stderr, "mpz_submul failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-bitops.c b/third_party/gmp/mini-gmp/tests/t-bitops.c
new file mode 100644
index 0000000..27d87ca
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-bitops.c
@@ -0,0 +1,104 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, res, ref;
+  mp_bitcnt_t b;
+
+  mpz_init (a);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_bit_op (OP_SETBIT, MAXBITS, a, &b, ref);
+      mpz_set (res, a);
+      mpz_setbit (res, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_setbit failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (!mpz_tstbit (res, b))
+	{
+	  fprintf (stderr, "mpz_tstbit failed (after mpz_setbit):\n");
+	  dump ("res", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  abort ();
+	}
+      mini_random_bit_op (OP_CLRBIT, MAXBITS, a, &b, ref);
+      mpz_set (res, a);
+      mpz_clrbit (res, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_clrbit failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_tstbit (res, b))
+	{
+	  fprintf (stderr, "mpz_tstbit failed (after mpz_clrbit):\n");
+	  dump ("res", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  abort ();
+	}
+      mini_random_bit_op (OP_COMBIT, MAXBITS, a, &b, ref);
+      mpz_set (res, a);
+      mpz_com (a, a);
+      mpz_combit (res, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_combit failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_tstbit (res, b) != mpz_tstbit (a, b))
+	{
+	  fprintf (stderr, "mpz_tstbit failed (after mpz_combit):\n");
+	  dump ("res", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-cmp_d.c b/third_party/gmp/mini-gmp/tests/t-cmp_d.c
new file mode 100644
index 0000000..09ca810
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-cmp_d.c
@@ -0,0 +1,283 @@
+/* Test mpz_cmp_d and mpz_cmpabs_d.
+
+Copyright 2001-2003, 2005, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <math.h>
+
+#include "testutils.h"
+
+/* FIXME: Not sure if the tests here are exhaustive.  Ought to try to get
+   each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised.  */
+
+
+#define SGN(n)  ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
+
+
+void
+check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs)
+{
+  int   got;
+
+  got = mpz_cmp_d (x, y);
+  if (SGN(got) != cmp)
+    {
+      unsigned i;
+      printf    ("mpz_cmp_d wrong (from %s)\n", name);
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmp);
+    fail:
+      printf ("  x=");
+      mpz_out_str (stdout, 10, x);
+      printf    ("\n  y %g\n", y);
+      printf ("  x=0x");
+      mpz_out_str (stdout, -16, x);
+      printf    ("\n  y %g\n", y);
+      printf    ("  y");
+      for (i = 0; i < sizeof(y); i++)
+        printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
+      printf ("\n");
+      abort ();
+    }
+
+  got = mpz_cmpabs_d (x, y);
+  if (SGN(got) != cmpabs)
+    {
+      printf    ("mpz_cmpabs_d wrong\n");
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmpabs);
+      goto fail;
+    }
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *x;
+    double      y;
+    int         cmp, cmpabs;
+
+  } data[] = {
+
+    {  "0",  0.0,  0,  0 },
+
+    {  "1",  0.0,  1,  1 },
+    { "-1",  0.0, -1,  1 },
+
+    {  "1",  0.5,  1,  1 },
+    { "-1", -0.5, -1,  1 },
+
+    {  "0",  1.0, -1, -1 },
+    {  "0", -1.0,  1, -1 },
+
+    {  "0x1000000000000000000000000000000000000000000000000", 1.0,  1, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 },
+
+    {  "0",  1e100, -1, -1 },
+    {  "0", -1e100,  1, -1 },
+
+    {  "2",  1.5,   1,  1 },
+    {  "2", -1.5,   1,  1 },
+    { "-2",  1.5,  -1,  1 },
+    { "-2", -1.5,  -1,  1 },
+  };
+
+  mpz_t    x;
+  unsigned i;
+
+  mpz_init (x);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (x, data[i].x, 0);
+      check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs);
+    }
+
+  mpz_clear (x);
+}
+
+
+/* Equality of integers with up to 53 bits */
+void
+check_onebits (void)
+{
+  mpz_t   x, x2;
+  double  y;
+  int     i;
+
+  mpz_init_set_ui (x, 0L);
+  mpz_init (x2);
+
+  for (i = 0; i < 512; i++)
+    {
+      mpz_mul_2exp (x, x, 1);
+      mpz_add_ui (x, x, 1L);
+
+      y = mpz_get_d (x);
+      mpz_set_d (x2, y);
+
+      /* stop if any truncation is occurring */
+      if (mpz_cmp (x, x2) != 0)
+        break;
+
+      check_one ("check_onebits", x, y, 0, 0);
+      check_one ("check_onebits", x, -y, 1, 0);
+      mpz_neg (x, x);
+      check_one ("check_onebits", x, y, -1, 0);
+      check_one ("check_onebits", x, -y, 0, 0);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+  mpz_clear (x2);
+}
+
+
+/* With the mpz differing by 1, in a limb position possibly below the double */
+void
+check_low_z_one (void)
+{
+  mpz_t          x;
+  double         y;
+  unsigned long  i;
+
+  mpz_init (x);
+
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+#define LIM 127			/* vax fp numbers have limited range */
+#else
+#define LIM 512
+#endif
+
+  for (i = 1; i < LIM; i++)
+    {
+      mpz_set_ui (x, 1L);
+      mpz_mul_2exp (x, x, i);
+      y = mpz_get_d (x);
+
+      check_one ("check_low_z_one", x, y,   0, 0);
+      check_one ("check_low_z_one", x, -y,  1, 0);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 0);
+      check_one ("check_low_z_one", x, -y,  0, 0);
+      mpz_neg (x, x);
+
+      mpz_sub_ui (x, x, 1);
+
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+
+      mpz_add_ui (x, x, 2);
+
+      check_one ("check_low_z_one", x, y,   1, 1);
+      check_one ("check_low_z_one", x, -y,  1, 1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 1);
+      check_one ("check_low_z_one", x, -y, -1, 1);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+}
+
+/* Comparing 1 and 1+2^-n.  "y" is volatile to make gcc store and fetch it,
+   which forces it to a 64-bit double, whereas on x86 it would otherwise
+   remain on the float stack as an 80-bit long double.  */
+void
+check_one_2exp (void)
+{
+  double           e;
+  mpz_t            x;
+  volatile double  y;
+  int              i;
+
+  mpz_init (x);
+
+  e = 1.0;
+  for (i = 0; i < 128; i++)
+    {
+      e /= 2.0;
+      y = 1.0 + e;
+      if (y == 1.0)
+        break;
+
+      mpz_set_ui (x, 1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+
+      mpz_set_si (x, -1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+    }
+
+  mpz_clear (x);
+}
+
+void
+check_infinity (void)
+{
+  mpz_t   x;
+  double  y = HUGE_VAL;
+  if (y != 2*y)
+    return;
+
+  mpz_init (x);
+
+  /* 0 cmp inf */
+  mpz_set_ui (x, 0L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 123 cmp inf */
+  mpz_set_ui (x, 123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -123 cmp inf */
+  mpz_set_si (x, -123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 2^5000 cmp inf */
+  mpz_set_ui (x, 1L);
+  mpz_mul_2exp (x, x, 5000L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -2^5000 cmp inf */
+  mpz_neg (x, x);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  mpz_clear (x);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  check_data ();
+  check_onebits ();
+  check_low_z_one ();
+  check_one_2exp ();
+  check_infinity ();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-comb.c b/third_party/gmp/mini-gmp/tests/t-comb.c
new file mode 100644
index 0000000..652bfcb
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-comb.c
@@ -0,0 +1,175 @@
+/* Exercise mpz_fac_ui and mpz_bin_uiui.
+
+Copyright 2000-2002, 2012, 2013, 2017-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testutils.h"
+
+/* Usage: t-fac_ui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+void
+try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+  mpz_bin_uiui (got, n, k);
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_bin_uiui wrong\n");
+      printf ("  n=%lu\n", n);
+      printf ("  k=%lu\n", k);
+      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
+      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
+      abort();
+    }
+  mpz_clear (got);
+}
+
+/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count.  */
+void
+bin_smallexaustive (unsigned int count)
+{
+  mpz_t          want;
+  unsigned long  n, k;
+
+  mpz_init (want);
+
+  for (n = 0; n < count; n++)
+    {
+      mpz_set_ui (want, 1);
+      for (k = 0; k <= n; k++)
+	{
+	  try_mpz_bin_uiui (want, n, k);
+	  mpz_mul_ui (want, want, n - k);
+	  mpz_fdiv_q_ui (want, want, k + 1);
+	}
+      try_mpz_bin_uiui (want, n, k);
+    }
+
+  mpz_clear (want);
+}
+
+/* Test all fac(n) cases, with 0 <= n <= limit.  */
+void
+fac_smallexaustive (unsigned int limit)
+{
+  mpz_t          f, r;
+  unsigned long  n;
+  mpz_init_set_si (f, 1);  /* 0! = 1 */
+  mpz_init (r);
+
+  for (n = 0; n < limit; n++)
+    {
+      mpz_fac_ui (r, n);
+
+      if (mpz_cmp (f, r) != 0)
+        {
+          printf ("mpz_fac_ui(%lu) wrong\n", n);
+          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+          abort ();
+        }
+
+      mpz_mul_ui (f, f, n+1);  /* (n+1)! = n! * (n+1) */
+    }
+
+  mpz_clear (f);
+  mpz_clear (r);
+}
+
+void checkWilson (mpz_t f, unsigned long n)
+{
+  unsigned long m, a;
+
+  mpz_2fac_ui (f, 2 * n - 1);
+
+  a = mpz_fdiv_q_ui (f, f, n);
+  m = mpz_fdiv_ui (f, n);
+  if ((m != n - 1) || (a != 0))
+    {
+      printf ("mpz_2fac_ui(%lu) wrong\n", 2 * n - 1);
+      printf ("  Wilson's theorem not verified: got (%lu, %lu), expected (0, %lu).\n", a, m, n - 1);
+      abort ();
+    }
+
+  mpz_fac_ui (f, n - 1);
+  m = mpz_fdiv_ui (f, n);
+  if ( m != n - 1)
+    {
+      printf ("mpz_fac_ui(%lu) wrong\n", n - 1);
+      printf ("  Wilson's theorem not verified: got %lu, expected %lu.\n",m ,n - 1);
+      abort ();
+    }
+}
+
+void
+checkprimes (unsigned long p1, unsigned long p2, unsigned long p3)
+{
+  mpz_t          b, f;
+
+  if (p1 - 1 != p2 - 1 + p3 - 1)
+    {
+      printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3);
+      printf (" %lu - 1 != %lu - 1 + %lu - 1 \n", p1, p2, p3);
+      abort ();
+    }
+
+  mpz_init (b);
+  mpz_init (f);
+
+  checkWilson (b, p1); /* b = (p1-1)! */
+  checkWilson (f, p2); /* f = (p2-1)! */
+  mpz_divexact (b, b, f);
+  checkWilson (f, p3); /* f = (p3-1)! */
+  mpz_divexact (b, b, f); /* b = (p1-1)!/((p2-1)!(p3-1)!) */
+  mpz_bin_uiui (f, p1 - 1, p2 - 1);
+  if (mpz_cmp (f, b) != 0)
+    {
+      printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3);
+      printf ("  got  "); mpz_out_str (stdout, 10, b); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+      abort ();
+    }
+
+  mpz_clear (b);
+  mpz_clear (f);
+
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  unsigned long  limit = 128;
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ~ limit;
+  else if (argc > 1)
+    limit = atoi (argv[1]);
+
+  checkprimes(1009, 733, 277);
+  fac_smallexaustive (limit);
+  bin_smallexaustive (limit);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-cong.c b/third_party/gmp/mini-gmp/tests/t-cong.c
new file mode 100644
index 0000000..92b6930
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-cong.c
@@ -0,0 +1,212 @@
+/* test mpz_congruent_p
+
+Copyright 2001, 2002, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "testutils.h"
+
+#define MPZ_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mpz_srcptr __mpz_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mpz_srcptr_swap__tmp;					\
+  } while (0)
+
+void
+check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want)
+{
+  int   got;
+  int   swap;
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      got = (mpz_congruent_p (a, c, d) != 0);
+      if (want != got)
+	{
+	  printf ("mpz_congruent_p wrong\n");
+	  printf ("   expected %d got %d\n", want, got);
+	  dump ("	 a", a);
+	  dump ("	 c", c);
+	  dump ("	 d", d);
+	  abort ();
+	}
+
+#if 0
+      if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d))
+	{
+	  unsigned long	 uc = mpz_get_ui (c);
+	  unsigned long	 ud = mpz_get_ui (d);
+	  got = (mpz_congruent_ui_p (a, uc, ud) != 0);
+	  if (want != got)
+	    {
+	      printf	("mpz_congruent_ui_p wrong\n");
+	      printf	("   expected %d got %d\n", want, got);
+	      dump ("   a", a);
+	      printf	("   c=%lu\n", uc);
+	      printf	("   d=%lu\n", ud);
+	      abort ();
+	    }
+	}
+#endif
+      MPZ_SRCPTR_SWAP (a, c);
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *c;
+    const char *d;
+    int        want;
+
+  } data[] = {
+
+    /* strict equality mod 0 */
+    { "0", "0", "0", 1 },
+    { "11", "11", "0", 1 },
+    { "3", "11", "0", 0 },
+
+    /* anything congruent mod 1 */
+    { "0", "0", "1", 1 },
+    { "1", "0", "1", 1 },
+    { "0", "1", "1", 1 },
+    { "123", "456", "1", 1 },
+    { "0x123456789123456789", "0x987654321987654321", "1", 1 },
+
+    /* csize==1, dsize==2 changing to 1 after stripping 2s */
+    { "0x3333333333333333",  "0x33333333",
+      "0x180000000", 1 },
+    { "0x33333333333333333333333333333333", "0x3333333333333333",
+      "0x18000000000000000", 1 },
+
+    /* another dsize==2 becoming 1, with opposite signs this time */
+    {  "0x444444441",
+      "-0x22222221F",
+       "0x333333330", 1 },
+    {  "0x44444444444444441",
+      "-0x2222222222222221F",
+       "0x33333333333333330", 1 },
+  };
+
+  mpz_t   a, c, d;
+  unsigned   i;
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (c, data[i].c, 0);
+      mpz_set_str_or_abort (d, data[i].d, 0);
+      check_one (a, c, d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  mpz_t   a, c, d, ra, rc;
+  int     i;
+  int     want;
+  int     reps = 10000;
+  mpz_t bs;
+  unsigned long size_range, size;
+
+  if (argc >= 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (bs);
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+  mpz_init (ra);
+  mpz_init (rc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mini_urandomb (bs, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (a, size);
+
+      mini_urandomb (bs, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (c, size);
+
+      do
+	{
+	  mini_urandomb (bs, 32);
+	  size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+	  mini_urandomb (bs, size_range);
+	  size = mpz_get_ui (bs);
+	  mini_rrandomb (d, size);
+	}
+      while (mpz_sgn(d) == 0);
+
+      mini_urandomb (bs, 3);
+      if (mpz_tstbit (bs, 0))
+	mpz_neg (a, a);
+      if (mpz_tstbit (bs, 1))
+	mpz_neg (c, c);
+      if (mpz_tstbit (bs, 2))
+	mpz_neg (d, d);
+
+      mpz_fdiv_r (ra, a, d);
+      mpz_fdiv_r (rc, c, d);
+
+      want = (mpz_cmp (ra, rc) == 0);
+      check_one (a, c, d, want);
+
+      mpz_sub (ra, ra, rc);
+      mpz_sub (a, a, ra);
+      check_one (a, c, d, 1);
+
+    }
+
+  mpz_clear (bs);
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+  mpz_clear (ra);
+  mpz_clear (rc);
+}
+
+
+void
+testmain (int argc, char *argv[])
+{
+  check_data ();
+  check_random (argc, argv);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-div.c b/third_party/gmp/mini-gmp/tests/t-div.c
new file mode 100644
index 0000000..be2f6b1
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-div.c
@@ -0,0 +1,258 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+typedef void div_qr_func (mpz_t, mpz_t, const mpz_t, const mpz_t);
+typedef unsigned long div_qr_ui_func (mpz_t, mpz_t, const mpz_t, unsigned long);
+typedef void div_func (mpz_t, const mpz_t, const mpz_t);
+typedef unsigned long div_x_ui_func (mpz_t, const mpz_t, unsigned long);
+typedef unsigned long div_ui_func (const mpz_t, unsigned long);
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, q, r, rq, rr;
+  int div_p;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (r);
+  mpz_init (q);
+  mpz_init (rr);
+  mpz_init (rq);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      unsigned j;
+      for (j = 0; j < 3; j++)
+	{
+	  static const enum hex_random_op ops[3] = { OP_CDIV, OP_FDIV, OP_TDIV };
+	  static const char name[3] = { 'c', 'f', 't'};
+	  static div_qr_func * const div_qr [3] =
+	    {
+	      mpz_cdiv_qr, mpz_fdiv_qr, mpz_tdiv_qr
+	    };
+	  static div_qr_ui_func * const div_qr_ui[3] =
+	    {
+	      mpz_cdiv_qr_ui, mpz_fdiv_qr_ui, mpz_tdiv_qr_ui
+	    };
+	  static div_func * const div_q [3] =
+	    {
+	      mpz_cdiv_q, mpz_fdiv_q, mpz_tdiv_q
+	    };
+	  static div_x_ui_func * const div_q_ui[3] =
+	    {
+	      mpz_cdiv_q_ui, mpz_fdiv_q_ui, mpz_tdiv_q_ui
+	    };
+	  static div_func * const div_r [3] =
+	    {
+	      mpz_cdiv_r, mpz_fdiv_r, mpz_tdiv_r
+	    };
+	  static div_x_ui_func * const div_r_ui[3] =
+	    {
+	      mpz_cdiv_r_ui, mpz_fdiv_r_ui, mpz_tdiv_r_ui
+	    };
+	  static div_ui_func * const div_ui[3] =
+	    {
+	      mpz_cdiv_ui, mpz_fdiv_ui, mpz_tdiv_ui
+	    };
+
+	  mini_random_op4 (ops[j], MAXBITS, a, b, rq, rr);
+	  div_qr[j] (q, r, a, b);
+	  if (mpz_cmp (r, rr) || mpz_cmp (q, rq))
+	    {
+	      fprintf (stderr, "mpz_%cdiv_qr failed:\n", name[j]);
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r   ", r);
+	      dump ("rref", rr);
+	      dump ("q   ", q);
+	      dump ("qref", rq);
+	      abort ();
+	    }
+	  mpz_set_si (q, -5);
+	  div_q[j] (q, a, b);
+	  if (mpz_cmp (q, rq))
+	    {
+	      fprintf (stderr, "mpz_%cdiv_q failed:\n", name[j]);
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("q   ", q);
+	      dump ("qref", rq);
+	      abort ();
+	    }
+	  mpz_set_ui (r, ~5);
+	  div_r[j] (r, a, b);
+	  if (mpz_cmp (r, rr))
+	    {
+	      fprintf (stderr, "mpz_%cdiv_r failed:\n", name[j]);
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r   ", r);
+	      dump ("rref", rr);
+	      abort ();
+	    }
+
+	  if (j == 0)		/* do this once, not for all roundings */
+	    {
+	      div_p = mpz_divisible_p (a, b);
+	      if ((mpz_sgn (r) == 0) ^ (div_p != 0))
+		{
+		  fprintf (stderr, "mpz_divisible_p failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("r   ", r);
+		  abort ();
+		}
+	    }
+
+	  mpz_set_si (r, -6);
+	  if (j == 0 && mpz_sgn (b) < 0)  /* ceil, negative divisor */
+	    {
+	      mpz_mod (r, a, b);
+	      if (mpz_cmp (r, rr))
+		{
+		  fprintf (stderr, "mpz_mod failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  abort ();
+		}
+	    }
+
+	  if (j == 1 && mpz_sgn (b) > 0) /* floor, positive divisor */
+	    {
+	      mpz_mod (r, a, b);
+	      if (mpz_cmp (r, rr))
+		{
+		  fprintf (stderr, "mpz_mod failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  abort ();
+		}
+	    }
+
+	  if (mpz_fits_ulong_p (b))
+	    {
+	      unsigned long rl;
+
+	      mpz_set_si (r, -7);
+	      mpz_set_ui (q, ~7);
+	      rl = div_qr_ui[j] (q, r, a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr)
+		  || mpz_cmp (r, rr) || mpz_cmp (q, rq))
+		{
+		  fprintf (stderr, "mpz_%cdiv_qr_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  dump ("q   ", q);
+		  dump ("qref", rq);
+		  abort ();
+		}
+
+	      mpz_set_si (q, 3);
+	      rl = div_q_ui[j] (q, a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr) || mpz_cmp (q, rq))
+		{
+		  fprintf (stderr, "mpz_%cdiv_q_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("rref", rr);
+		  dump ("q   ", q);
+		  dump ("qref", rq);
+		  abort ();
+		}
+
+	      mpz_set_ui (r, 7);
+	      rl = div_r_ui[j] (r, a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr) || mpz_cmp (r, rr))
+		{
+		  fprintf (stderr, "mpz_%cdiv_r_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  abort ();
+		}
+
+	      rl = div_ui[j] (a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr))
+		{
+		  fprintf (stderr, "mpz_%cdiv_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("rref", rr);
+		  abort ();
+		}
+
+	      if (j == 0)	/* do this once, not for all roundings */
+		{
+		  div_p = mpz_divisible_ui_p (a, mpz_get_ui (b));
+		  if ((mpz_sgn (r) == 0) ^ (div_p != 0))
+		    {
+		      fprintf (stderr, "mpz_divisible_ui_p failed:\n");
+		      dump ("a", a);
+		      dump ("b", b);
+		      dump ("r   ", r);
+		      abort ();
+		    }
+		}
+
+	      if (j == 1)	/* floor */
+		{
+		  mpz_set_si (r, -2);
+		  mpz_mod_ui (r, a, mpz_get_ui (b));
+		  if (mpz_cmp (r, rr))
+		    {
+		      fprintf (stderr, "mpz_mod failed:\n");
+		      dump ("a", a);
+		      dump ("b", b);
+		      dump ("r   ", r);
+		      dump ("rref", rr);
+		      abort ();
+		    }
+		}
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (r);
+  mpz_clear (q);
+  mpz_clear (rr);
+  mpz_clear (rq);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-div_2exp.c b/third_party/gmp/mini-gmp/tests/t-div_2exp.c
new file mode 100644
index 0000000..53d3f2b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-div_2exp.c
@@ -0,0 +1,82 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+typedef void div_func (mpz_t, const mpz_t, mp_bitcnt_t);
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, res, ref;
+  mp_bitcnt_t b;
+
+  mpz_init (a);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      unsigned j;
+      for (j = 0; j < 6; j++)
+	{
+	  static const enum hex_random_op ops[6] =
+	    {
+	      OP_CDIV_Q_2, OP_CDIV_R_2,
+	      OP_FDIV_Q_2, OP_FDIV_R_2,
+	      OP_TDIV_Q_2, OP_TDIV_R_2
+	    };
+	  static const char *name[6] =
+	    {
+	      "cdiv_q", "cdiv_r",
+	      "fdiv_q", "fdiv_r",
+	      "tdiv_q", "tdiv_r"
+	    };
+	  static div_func * const div [6] =
+	    {
+	      mpz_cdiv_q_2exp, mpz_cdiv_r_2exp,
+	      mpz_fdiv_q_2exp, mpz_fdiv_r_2exp,
+	      mpz_tdiv_q_2exp, mpz_tdiv_r_2exp
+	    };
+
+	  mini_random_bit_op (ops[j], MAXBITS, a, &b, ref);
+	  div[j] (res, a, b);
+	  if (mpz_cmp (ref, res))
+	    {
+	      fprintf (stderr, "mpz_%s_2exp failed:\n", name[j]);
+	      dump ("a", a);
+	      fprintf (stderr, "b: %lu\n", b);
+	      dump ("r", res);
+	      dump ("ref", ref);
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-double.c b/third_party/gmp/mini-gmp/tests/t-double.c
new file mode 100644
index 0000000..9a1aa8f
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-double.c
@@ -0,0 +1,228 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+
+#include "testutils.h"
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+mp_bitcnt_t
+mpz_mantissasizeinbits (const mpz_t z)
+{
+  return ! mpz_cmp_ui (z, 0) ? 0 :
+    mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
+}
+
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+int
+mpz_get_d_exact_p (const mpz_t z)
+{
+  return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
+}
+#define HAVE_EXACT_P 1
+#endif
+
+#define COUNT 10000
+
+void
+test_matissa (void)
+{
+  mpz_t x, y;
+  int i, c;
+
+  mpz_init (x);
+  mpz_init (y);
+
+  mini_urandomb (y, 4);
+  c = i = mpz_get_ui (y);
+
+  do {
+    double d;
+    int cmp;
+
+    mpz_setbit (x, c);
+    d = mpz_get_d (x);
+    mpz_set_d (y, d);
+    if (mpz_cmp_d (y, d) != 0)
+      {
+	fprintf (stderr, "mpz_cmp_d (y, d) failed:\n"
+		 "d = %.20g\n"
+		 "i = %i\n"
+		 "c = %i\n",
+		 d, i, c);
+	abort ();
+      }
+
+    cmp = mpz_cmp (x, y);
+
+#if defined(HAVE_EXACT_P)
+    if ((mpz_get_d_exact_p (x) != 0) != (cmp == 0))
+      {
+	fprintf (stderr, "Not all bits converted:\n"
+		 "d = %.20g\n"
+		 "i = %i\n"
+		 "c = %i\n",
+		 d, i, c);
+	abort ();
+      }
+#endif
+
+    if (cmp < 0)
+      {
+	fprintf (stderr, "mpz_get_d failed:\n"
+		 "d = %.20g\n"
+		 "i = %i\n"
+		 "c = %i\n",
+		 d, i, c);
+	abort ();
+      }
+    else if (cmp > 0)
+      {
+	if (mpz_cmp_d (x, d) <= 0)
+	  {
+	    fprintf (stderr, "mpz_cmp_d (x, d) failed:\n"
+		     "d = %.20g\n"
+		     "i = %i\n"
+		     "c = %i\n",
+		     d, i, c);
+	    abort ();
+	  }
+	break;
+      }
+    ++c;
+  } while (1);
+
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+static const struct
+{
+  double d;
+  const char *s;
+} values[] = {
+  { 0.0, "0" },
+  { 0.3, "0" },
+  { -0.3, "0" },
+  { M_PI, "3" },
+  { M_PI*1e15, "b29430a256d21" },
+  { -M_PI*1e15, "-b29430a256d21" },
+  /* 17 * 2^{200} =
+     27317946752402834684213355569799764242877450894307478200123392 */
+  {0.2731794675240283468421335556979976424288e62,
+    "1100000000000000000000000000000000000000000000000000" },
+  { 0.0, NULL }
+};
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t x;
+
+  for (i = 0; values[i].s; i++)
+    {
+      char *s;
+      mpz_init_set_d (x, values[i].d);
+      s = mpz_get_str (NULL, 16, x);
+      if (strcmp (s, values[i].s) != 0)
+	{
+	  fprintf (stderr, "mpz_set_d failed:\n"
+		   "d = %.20g\n"
+		   "s = %s\n"
+		   "r = %s\n",
+		   values[i].d, s, values[i].s);
+	  abort ();
+	}
+      testfree (s);
+      mpz_clear (x);
+    }
+
+  mpz_init (x);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      /* Use volatile, to avoid extended precision in floating point
+	 registers, e.g., on m68k and 80387. */
+      volatile double d, f;
+      unsigned long m;
+      int e;
+
+      mini_rrandomb (x, GMP_LIMB_BITS);
+      m = mpz_get_ui (x);
+      mini_urandomb (x, 8);
+      e = mpz_get_ui (x) - 100;
+
+      d = ldexp ((double) m, e);
+      mpz_set_d (x, d);
+      f = mpz_get_d (x);
+      if (f != floor (d))
+	{
+	  fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
+	  goto dumperror;
+	}
+      if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) >= 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
+	  goto dumperror;
+	}
+      f = d + 1.0;
+      if (f > d && ! (mpz_cmp_d (x, f) < 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
+	  goto dumperror;
+	}
+
+      d = - d;
+
+      mpz_set_d (x, d);
+      f = mpz_get_d (x);
+      if (f != ceil (d))
+	{
+	  fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
+	dumperror:
+	  dump ("x", x);
+	  fprintf (stderr, "m = %lx, e = %i\n", m, e);
+	  fprintf (stderr, "d = %.15g\n", d);
+	  fprintf (stderr, "f = %.15g\n", f);
+	  fprintf (stderr, "f - d = %.5g\n", f - d);
+	  abort ();
+	}
+      if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) <= 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
+	  goto dumperror;
+	}
+      f = d - 1.0;
+      if (f < d && ! (mpz_cmp_d (x, f) > 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
+	  goto dumperror;
+	}
+    }
+
+  mpz_clear (x);
+  test_matissa();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-gcd.c b/third_party/gmp/mini-gmp/tests/t-gcd.c
new file mode 100644
index 0000000..64f90f4
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-gcd.c
@@ -0,0 +1,178 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+/* Called when g is supposed to be gcd(a,b), and g = s a + t b. */
+static int
+gcdext_valid_p (const mpz_t a, const mpz_t b,
+		const mpz_t g, const mpz_t s, const mpz_t t)
+{
+  mpz_t ta, tb, r;
+
+  /* It's not clear that gcd(0,0) is well defined, but we allow it and
+     require that gcd(0,0) = 0. */
+  if (mpz_sgn (g) < 0)
+    return 0;
+
+  if (mpz_sgn (a) == 0)
+    {
+      /* Must have g == abs (b). Any value for s is in some sense "correct",
+	 but it makes sense to require that s == 0, t = sgn (b)*/
+      return mpz_cmpabs (g, b) == 0
+	&& mpz_sgn (s) == 0 && mpz_cmp_si (t, mpz_sgn (b)) == 0;
+    }
+  else if (mpz_sgn (b) == 0)
+    {
+      /* Must have g == abs (a), s == sign (a), t = 0 */
+      return mpz_cmpabs (g, a) == 0
+	&& mpz_cmp_si (s, mpz_sgn (a)) == 0 && mpz_sgn (t) == 0;
+    }
+
+  if (mpz_sgn (g) <= 0)
+    return 0;
+
+  mpz_init (ta);
+  mpz_init (tb);
+  mpz_init (r);
+
+  mpz_mul (ta, s, a);
+  mpz_mul (tb, t, b);
+  mpz_add (ta, ta, tb);
+
+  if (mpz_cmp (ta, g) != 0)
+    {
+    fail:
+      mpz_clear (ta);
+      mpz_clear (tb);
+      mpz_clear (r);
+      return 0;
+    }
+  mpz_tdiv_qr (ta, r, a, g);
+  if (mpz_sgn (r) != 0)
+    goto fail;
+
+  mpz_tdiv_qr (tb, r, b, g);
+  if (mpz_sgn (r) != 0)
+    goto fail;
+
+  /* Require that 2 |s| < |b/g|, or |s| == 1. */
+  if (mpz_cmpabs_ui (s, 1) > 0)
+    {
+      mpz_mul_2exp (r, s, 1);
+      if (mpz_cmpabs (r, tb) > 0)
+	goto fail;
+    }
+
+  /* Require that 2 |t| < |a/g| or |t| == 1*/
+  if (mpz_cmpabs_ui (t, 1) > 0)
+    {
+      mpz_mul_2exp (r, t, 1);
+      if (mpz_cmpabs (r, ta) > 0)
+	return 0;
+    }
+
+  mpz_clear (ta);
+  mpz_clear (tb);
+  mpz_clear (r);
+
+  return 1;
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, g, s, t;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (g);
+  mpz_init (s);
+  mpz_init (t);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_GCD, MAXBITS, a, b, s);
+      mpz_gcd (g, a, b);
+      if (mpz_cmp (g, s))
+	{
+	  fprintf (stderr, "mpz_gcd failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", g);
+	  dump ("ref", s);
+	  abort ();
+	}
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      unsigned flags;
+      mini_urandomb (a, 32);
+      flags = mpz_get_ui (a);
+      mini_rrandomb (a, MAXBITS);
+      mini_rrandomb (b, MAXBITS);
+
+      if (flags % 37 == 0)
+	mpz_mul (a, a, b);
+      if (flags % 37 == 1)
+	mpz_mul (b, a, b);
+
+      if (flags & 1)
+	mpz_neg (a, a);
+      if (flags & 2)
+	mpz_neg (b, b);
+
+      mpz_gcdext (g, s, t, a, b);
+      if (!gcdext_valid_p (a, b, g, s, t))
+	{
+	  fprintf (stderr, "mpz_gcdext failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("g", g);
+	  dump ("s", s);
+	  dump ("t", t);
+	  abort ();
+	}
+
+      mpz_gcd (s, a, b);
+      if (mpz_cmp (g, s))
+	{
+	  fprintf (stderr, "mpz_gcd failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", g);
+	  dump ("ref", s);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (g);
+  mpz_clear (s);
+  mpz_clear (t);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-import.c b/third_party/gmp/mini-gmp/tests/t-import.c
new file mode 100644
index 0000000..66c9d5e
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-import.c
@@ -0,0 +1,99 @@
+/*
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAX_WORDS 20
+#define MAX_WORD_SIZE 10
+
+static void
+dump_bytes (const char *label, const unsigned char *s, size_t n)
+{
+  size_t i;
+  fprintf (stderr, "%s:", label);
+  for (i = 0; i < n; i++)
+    {
+      if (i && (i % 16) == 0)
+	fprintf (stderr, "\n");
+      fprintf (stderr, " %02x", s[i]);
+    }
+  fprintf (stderr, "\n");
+}
+
+/* Tests both mpz_import and mpz_export. */
+void
+testmain (int argc, char **argv)
+{
+  unsigned char input[MAX_WORDS * MAX_WORD_SIZE];
+  unsigned char output[MAX_WORDS * MAX_WORD_SIZE + 2];
+  size_t count, in_count, out_count, size;
+  int endian, order;
+
+  mpz_t a, res;
+
+  mpz_init (a);
+  mpz_init (res);
+
+  for (size = 0; size <= MAX_WORD_SIZE; size++)
+    for (count = 0; count <= MAX_WORDS; count++)
+      for (endian = -1; endian <= 1; endian++)
+	for (order = -1; order <= 1; order += 2)
+	  {
+	    mini_rrandomb_export (a, input, &in_count,
+				  order, size, endian, size*count * 8);
+	    mpz_import (res, in_count, order, size, endian, 0, input);
+	    if (mpz_cmp (a, res))
+	      {
+		fprintf (stderr, "mpz_import failed:\n"
+			 "in_count %lu, out_count %lu, endian = %d, order = %d\n",
+			 (unsigned long) in_count, (unsigned long) out_count, endian, order);
+		dump ("a", a);
+		dump ("res", res);
+		abort ();
+	      }
+	    output[0] = 17;
+	    output[1+in_count*size] = 17;
+
+	    mpz_export (output+1, &out_count, order, size, endian, 0, a);
+	    if (out_count != in_count
+		|| memcmp (output+1, input, in_count * size)
+		|| output[0] != 17
+		|| output[1+in_count*size] != 17)
+	      {
+		fprintf (stderr, "mpz_export failed:\n"
+			 "in_count %lu, out_count %lu, endian = %d, order = %d\n",
+			 (unsigned long) in_count, (unsigned long) out_count, endian, order);
+		dump_bytes ("input", input, in_count * size);
+		dump_bytes ("output", output+1, out_count * size);
+		if (output[0] != 17)
+		  fprintf (stderr, "Overwrite at -1, value %02x\n", output[0]);
+		if (output[1+in_count*size] != 17)
+		  fprintf (stderr, "Overwrite at %lu, value %02x\n",
+			   (unsigned long) (in_count*size), output[1+in_count*size]);
+
+		abort ();
+	      }
+	  }
+  mpz_clear (a);
+  mpz_clear (res);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-invert.c b/third_party/gmp/mini-gmp/tests/t-invert.c
new file mode 100644
index 0000000..843002b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-invert.c
@@ -0,0 +1,139 @@
+/*
+
+Copyright 2012, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+#define COUNT 10000
+
+static void
+test_2by1(const mpz_t u)
+{
+  mpz_t m, p, t;
+
+  mpz_init (m);
+  mpz_init (p);
+  mpz_init (t);
+
+  assert (mpz_size (u) == 1);
+
+  mpz_set_ui (m, mpn_invert_limb (u->_mp_d[0]));
+  mpz_setbit (m, GMP_LIMB_BITS);
+
+  mpz_mul (p, m, u);
+
+  mpz_set_ui (t, 0);
+  mpz_setbit (t, 2* GMP_LIMB_BITS);
+  mpz_sub (t, t, p);
+
+  /* Should have 0 < B^2 - m u <= u */
+  if (mpz_sgn (t) <= 0 || mpz_cmp (t, u) > 0)
+    {
+      fprintf (stderr, "mpn_invert_limb failed:\n");
+      dump ("u", u);
+      dump ("m", m);
+      dump ("p", p);
+      dump ("t", t);
+      abort ();
+    }
+  mpz_clear (m);
+  mpz_clear (p);
+  mpz_clear (t);
+}
+
+static void
+test_3by2(const mpz_t u)
+{
+  mpz_t m, p, t;
+
+  mpz_init (m);
+  mpz_init (p);
+  mpz_init (t);
+
+  assert (mpz_size (u) == 2);
+
+  mpz_set_ui (m, mpn_invert_3by2 (u->_mp_d[1], u[0]._mp_d[0]));
+
+  mpz_setbit (m, GMP_LIMB_BITS);
+
+  mpz_mul (p, m, u);
+
+  mpz_set_ui (t, 0);
+  mpz_setbit (t, 3 * GMP_LIMB_BITS);
+  mpz_sub (t, t, p);
+
+  /* Should have 0 < B^3 - m u <= u */
+  if (mpz_sgn (t) <= 0 || mpz_cmp (t, u) > 0)
+    {
+      fprintf (stderr, "mpn_invert_3by2 failed:\n");
+      dump ("u", u);
+      dump ("m", m);
+      dump ("p", p);
+      dump ("t", t);
+      abort ();
+    }
+  mpz_clear (m);
+  mpz_clear (p);
+  mpz_clear (t);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t u, m, p, t;
+
+  mpz_init (u);
+  mpz_init (m);
+  mpz_init (p);
+  mpz_init (t);
+
+  /* These values trigger 32-bit overflow of ql in mpn_invert_3by2. */
+  if (GMP_LIMB_BITS == 64)
+    {
+      mpz_set_str (u, "80007fff3ffe0000", 16);
+      test_2by1 (u);
+      mpz_set_str (u, "80007fff3ffe000000000000000003ff", 16);
+      test_3by2 (u);
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_urandomb (u, GMP_LIMB_BITS);
+      mpz_setbit (u, GMP_LIMB_BITS -1);
+
+      test_2by1 (u);
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_urandomb (u, 2*GMP_LIMB_BITS);
+      mpz_setbit (u, 2*GMP_LIMB_BITS -1);
+
+      test_3by2 (u);
+    }
+
+  mpz_clear (u);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-lcm.c b/third_party/gmp/mini-gmp/tests/t-lcm.c
new file mode 100644
index 0000000..f21a39a
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-lcm.c
@@ -0,0 +1,73 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, g, s;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (g);
+  mpz_init (s);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_LCM, MAXBITS, a, b, s);
+      mpz_lcm (g, a, b);
+      if (mpz_cmp (g, s))
+	{
+	  fprintf (stderr, "mpz_lcm failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", g);
+	  dump ("ref", s);
+	  abort ();
+	}
+      if (mpz_fits_ulong_p (b))
+	{
+	  mpz_set_si (g, 0);
+	  mpz_lcm_ui (g, a, mpz_get_ui (b));
+	  if (mpz_cmp (g, s))
+	    {
+	      fprintf (stderr, "mpz_lcm_ui failed:\n");
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r", g);
+	      dump ("ref", s);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (g);
+  mpz_clear (s);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-limbs.c b/third_party/gmp/mini-gmp/tests/t-limbs.c
new file mode 100644
index 0000000..f4e57dd
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-limbs.c
@@ -0,0 +1,111 @@
+/*
+
+Copyright 2012, 2014, 2016, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 100
+
+void
+my_mpz_mul (mpz_t r, mpz_srcptr a,  mpz_srcptr b)
+{
+  mp_limb_t *tp;
+  mp_size_t tn, an, bn;
+
+  an = mpz_size (a);
+  bn = mpz_size (b);
+
+  assert (an > 0);
+  assert (bn > 0);
+
+  tn = an + bn;
+  tp = mpz_limbs_write (r, tn);
+  if (an > bn)
+    mpn_mul (tp, mpz_limbs_read (a), an, mpz_limbs_read (b), bn);
+  else
+    mpn_mul (tp, mpz_limbs_read (b), bn, mpz_limbs_read (a), an);
+
+  if (mpz_sgn (a) != mpz_sgn(b))
+    tn = - tn;
+
+  mpz_limbs_finish (r, tn);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
+      if (mpz_sgn(ref) == 0)
+	/* my_mpz_mul requires a != 0, b != 0 */
+	continue;
+      my_mpz_mul (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "my_mpz_mul failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      /* The following test exploits a side-effect of my_mpz_mul: res
+	 points to a buffer with at least an+bn limbs, and the limbs
+	 above the result are zeroed. */
+      if (mpz_size (b) > 0 && mpz_getlimbn (res, mpz_size(a)) != mpz_limbs_read (res) [mpz_size(a)])
+	{
+	  fprintf (stderr, "getlimbn - limbs_read differ.\n");
+	  abort ();
+	}
+      if ((i % 4 == 0) && mpz_size (res) > 1)
+	{
+	  mpz_realloc2 (res, 1);
+	  if (mpz_cmp_ui (res, 0))
+	    {
+	      fprintf (stderr, "mpz_realloc2 did not clear res.\n");
+	      abort ();
+	    }
+	  mpz_limbs_finish (ref, 0);
+	  if (mpz_cmp_d (ref, 0))
+	    {
+	      fprintf (stderr, "mpz_limbs_finish did not clear res.\n");
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-logops.c b/third_party/gmp/mini-gmp/tests/t-logops.c
new file mode 100644
index 0000000..b4e0239
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-logops.c
@@ -0,0 +1,112 @@
+/*
+
+Copyright 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testlogops (int count)
+{
+  int i;
+  mpz_t a, b, res, ref;
+  mp_bitcnt_t c;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < count; i++)
+    {
+      mini_random_op3 (OP_AND, MAXBITS, a, b, ref);
+      mpz_and (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_and failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+
+      mini_random_op3 (OP_IOR, MAXBITS, a, b, ref);
+      mpz_ior (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_ior failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+
+      mini_random_op3 (OP_XOR, MAXBITS, a, b, ref);
+      mpz_xor (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_xor failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+
+      if (i % 8) {
+	c = 0;
+	mpz_mul_2exp (res, res, i % 8);
+      } else if (mpz_sgn (res) >= 0) {
+	c = mpz_odd_p (res) != 0;
+	mpz_tdiv_q_2exp (res, res, 1);
+      } else {
+	c = (~ (mp_bitcnt_t) 0) - 3;
+	mpz_set_ui (res, 11 << ((i >> 3)%4)); /* set 3 bits */
+      }
+
+      if (mpz_popcount (res) + c != mpz_hamdist (a, b))
+	{
+	  fprintf (stderr, "mpz_popcount(r) + %lu and mpz_hamdist(a,b) differ:\n", c);
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  fprintf (stderr, "mpz_popcount(r) = %lu:\n", mpz_popcount (res));
+	  fprintf (stderr, "mpz_hamdist(a,b) = %lu:\n", mpz_hamdist (a, b));
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  testhalves (COUNT*2/3, testlogops);
+  testlogops (COUNT/3);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-lucm.c b/third_party/gmp/mini-gmp/tests/t-lucm.c
new file mode 100644
index 0000000..22ad575
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-lucm.c
@@ -0,0 +1,98 @@
+/* Tests the (internal) function mpz_lucas_mod
+
+Copyright 2018, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 100
+#define COUNT 1000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t m, vr, qr, vm, qm, vt;
+  int resm, resr;
+  long Q;
+  unsigned long b0;
+
+  mpz_init (m);
+  mpz_init (vr);
+  mpz_init (qr);
+  mpz_init (vm);
+  mpz_init (qm);
+  mpz_init (vt);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_lucm_op (MAXBITS, vr, qr, m, &Q, &b0, &resr);
+      if (b0 == 0)
+	{
+	  fprintf (stderr, "lucas_mod: test disabled (%u tests done).\n", i);
+	  break;
+	}
+      resm = mpz_lucas_mod (vm, qm, Q, b0, m);
+
+      if (resr != resm)
+	{
+	  if (resm != 0 || mpz_cmp_ui (vm, 0) != 0)
+	    {
+	      fprintf (stderr, "mpz_lucas_mod wrong return value (%d != %d):\n", resr, resm);
+	      fprintf (stderr, "Q = %ld , b0 = %lu\n", Q, b0);
+	      dump ("m", m);
+	      dump ("vm", vm);
+	      dump ("qm", qm);
+	      abort ();
+	    }
+	}
+      else if (resm == 0)
+	{
+	  mpz_abs (vr, vr);
+	  mpz_sub (vt, m, vr);
+	  mpz_abs (vm, vm);
+	  mpz_mod (qm, qm, m);
+	  if (mpz_cmp_ui (qr, 0) < 0)
+	    mpz_add (qr, qr, m);
+	  if (mpz_cmp (qm, qr) != 0 ||
+	      (mpz_cmp (vm, vr) != 0 && mpz_cmp (vm, vt) != 0))
+	    {
+	      fprintf (stderr, "mpz_lucas_mod error:\n");
+	      fprintf (stderr, "Q = %ld , b0 = %lu\n", Q, b0);
+	      dump ("m", m);
+	      dump ("vm", vm);
+	      dump ("vr", vr);
+	      dump ("vt", vt);
+	      dump ("qm", qm);
+	      dump ("qr", qr);
+	      abort ();
+	    }
+
+	}
+    }
+  mpz_clear (m);
+  mpz_clear (vr);
+  mpz_clear (qr);
+  mpz_clear (vm);
+  mpz_clear (qm);
+  mpz_clear (vt);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_addsub.c b/third_party/gmp/mini-gmp/tests/t-mpq_addsub.c
new file mode 100644
index 0000000..de1461f
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_addsub.c
@@ -0,0 +1,204 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 300
+#define COUNT 10000
+
+static void
+_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
+{
+  if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
+    {
+      mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
+    }
+  else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
+    {
+      mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
+    }
+  else
+    {
+      mpq_set_num (q, n);
+      mpq_set_den (q, d);
+    }
+  mpq_canonicalize (q);
+}
+
+void
+testcmpui ()
+{
+  unsigned d1, d2, n1, n2;
+  mpq_t q1, q2;
+
+  mpq_init (q1);
+  mpq_init (q2);
+
+  for (d1 = 1; d1 < 6; d1 += 2)
+    for (n1 = 1; n1 < 6; n1 *= 2)
+      {
+	mpq_set_ui (q1, n1, d1);
+	for (d2 = 1; d2 < 6; d2 += 2)
+	  for (n2 = 1; n2 < 6; n2 *= 2)
+	    {
+	      int fres = mpq_cmp_ui (q1, n2, d2);
+	      int ref = (d1*n2 < d2*n1) - (d1*n2 > d2*n1);
+
+	      mpq_set_ui (q2, n2, d2);
+
+	      if ((!ref) != mpq_equal (q1, q2))
+		{
+		  fprintf (stderr, "mpz_equal failed: %i / %i = %i / %i ? %i\n", n1, d1, n2, d2, ref);
+		  abort ();
+		}
+
+	      if (ref != fres)
+		{
+		  fprintf (stderr, "mpz_cmp_ui failed: %i / %i = %i / %i ? %i != %i\n", n1, d1, n2, d2, ref, fres);
+		  abort ();
+		}
+	    }
+      }
+
+  mpq_clear (q1);
+  mpq_clear (q2);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, q, r, c;
+  mpq_t rr, ii, ff;
+  int tst;
+
+  testcmpui ();
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (r);
+  mpz_init (q);
+  mpz_init (c);
+  mpq_init (rr);
+  mpq_init (ff);
+  mpq_init (ii);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op4 (OP_TDIV, MAXBITS, a, b, q, r);
+
+      _mpq_set_zz (rr, a, b);
+      _mpq_set_zz (ff, r, b);
+
+      mpq_set_z (ii, q);
+
+      mpz_set_q (c, rr);
+      if (mpz_cmp (c, q))
+	{
+	  fprintf (stderr, "mpz_set_q failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("c", c);
+	  dump ("q", q);
+	  abort ();
+	}
+
+      if ((mpz_sgn (r) != 0) ^ (mpz_cmp_ui (mpq_denref (rr), 1) != 0))
+	{
+	  fprintf (stderr, "mpq_canonicalize failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", r);
+	  dump ("D", mpq_denref (rr));
+	  abort ();
+	}
+
+      if (i & 1)
+	{
+	  if (mpz_fits_slong_p (q))
+	    tst = mpq_cmp_si (rr, mpz_get_si (q), 1);
+	  else if (mpz_fits_ulong_p (q))
+	    tst = mpq_cmp_ui (rr, mpz_get_ui (q), 1);
+	  else
+	    tst = mpq_cmp_z (rr, q);
+	  if (mpz_sgn (b) < 0)
+	    tst = - tst;
+	  if ((tst != mpz_sgn (r)) && ((tst < 0 && mpz_sgn (r) >= 0) || (tst > 0 && mpz_sgn (r) <= 0)))
+	    {
+	      fprintf (stderr, "mpq_cmp ii failed: %i %i\n", tst, mpz_sgn (r));
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r", r);
+	      dump ("q", q);
+	      abort ();
+	    }
+	}
+      else
+	{
+	  if (mpz_fits_ulong_p (b) && mpz_fits_slong_p (r))
+	    tst = mpq_cmp_si (rr, mpz_get_si (r), mpz_get_ui (b));
+	  else if (mpz_fits_ulong_p (b) && mpz_fits_ulong_p (r))
+	    tst = mpq_cmp_ui (rr, mpz_get_ui (r), mpz_get_ui (b));
+	  else
+	    tst = mpq_cmp (rr, ff);
+	  if ((tst != mpz_sgn (q)) && ((tst < 0 && mpz_sgn (q) >= 0) || (tst > 0 && mpz_sgn (q) <= 0)))
+	    {
+	      fprintf (stderr, "mpq_cmp ff failed: %i %i\n", tst, mpz_sgn (q));
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r", r);
+	      dump ("q", q);
+	      abort ();
+	    }
+	}
+
+      if (i & 1)
+	{
+	  mpq_sub (rr, rr, ff);
+	}
+      else
+	{
+	  mpq_neg (ff, ff);
+	  mpq_add (rr, ff, rr);
+	}
+
+      if (!mpq_equal (ii, rr))
+	{
+	  fprintf (stderr, "mpq_%s failed:\n", (i & 1) ? "sub" : "add");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", r);
+	  dump ("q", q);
+	  abort ();
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (r);
+  mpz_clear (q);
+  mpz_clear (c);
+  mpq_clear (rr);
+  mpq_clear (ff);
+  mpq_clear (ii);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_double.c b/third_party/gmp/mini-gmp/tests/t-mpq_double.c
new file mode 100644
index 0000000..1bd6c92
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_double.c
@@ -0,0 +1,214 @@
+/* Test mpq_set_d.
+
+Copyright 2001-2003, 2005, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define COUNT 2000
+
+mp_bitcnt_t
+mpz_mantissasizeinbits (const mpz_t z)
+{
+  return ! mpz_cmp_ui (z, 0) ? 0 :
+    mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
+}
+
+int
+mpz_abspow2_p (const mpz_t z)
+{
+  return mpz_mantissasizeinbits (z) == 1;
+}
+
+mp_bitcnt_t
+mpq_mantissasizeinbits (const mpq_t q)
+{
+  if (! mpz_abspow2_p (mpq_denref (q)))
+    return ~ (mp_bitcnt_t) 0;
+
+  return mpz_mantissasizeinbits (mpq_numref (q));
+}
+
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+int
+mpz_get_d_exact_p (const mpz_t z)
+{
+  return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
+}
+
+int
+mpq_get_d_exact_p (const mpq_t q)
+{
+  /* return mpq_mantissasizeinbits (q) <= DBL_MANT_DIG; */
+  return
+    (mpz_sizeinbase (mpq_denref (q), 2) -
+     mpz_scan1 (mpq_denref (q), 0) == 1) &&
+    (mpz_sizeinbase (mpq_numref (q), 2) -
+     mpz_scan1 (mpq_numref (q), 0) <= DBL_MANT_DIG);
+  /* mpz_sizeinbase (zero, 2) - mpz_scan1 (zero, 0) == 2 */
+}
+#define HAVE_EXACT_P 1
+#endif
+
+void
+check_random (void)
+{
+  unsigned i;
+  mpz_t x;
+  mpq_t y, z;
+
+  mpz_init (x);
+  mpq_init (y);
+  mpq_init (z);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      /* Use volatile, to avoid extended precision in floating point
+	 registers, e.g., on m68k and 80387. */
+      volatile double d, f;
+      unsigned long m;
+      int e, c;
+
+      mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
+      m = mpz_get_ui (x);
+      mini_urandomb (x, 8);
+      e = mpz_get_ui (x) - 128;
+
+      d = ldexp ((double) m, e);
+      mpq_set_d (y, d);
+      f = mpq_get_d (y);
+      if (f != d)
+	{
+	  fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
+	  goto dumperror;
+	}
+
+      d = - d;
+      mpq_neg (y, y);
+
+      mpq_set_d (z, d);
+      f = mpq_get_d (z);
+      if (f != d || !mpq_equal (y, z))
+	{
+	  fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
+	dumperror:
+	  dump ("ny", mpq_numref (y));
+	  dump ("dy", mpq_denref (y));
+	  fprintf (stderr, "m = %lx, e = %i\n", m, e);
+	  fprintf (stderr, "d = %.35g\n", d);
+	  fprintf (stderr, "f = %.35g\n", f);
+	  fprintf (stderr, "f - d = %.35g\n", f - d);
+	  abort ();
+	}
+
+      mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
+      m = mpz_get_ui (x);
+      mini_urandomb (x, 8);
+      e = mpz_get_ui (x) - 128;
+
+      d = ldexp ((double) m, e);
+      mpq_set_d (y, d);
+
+      mpq_add (y, y, z);
+      mpq_set_d (z, mpq_get_d (y));
+      f = mpq_get_d (z);
+      c = mpq_cmp (y, z);
+
+#if defined(HAVE_EXACT_P)
+      if (mpq_get_d_exact_p (y) ? c != 0 : (f > 0 ? c <= 0 : c >= 0))
+#else
+      if (f > 0 ? c < 0 : c > 0)
+#endif
+	{
+	  fprintf (stderr, "mpq_get_d/mpq_set_d failed: %i %i\n", i, c);
+	  goto dumperror;
+	}
+    }
+
+  mpz_clear (x);
+  mpq_clear (y);
+  mpq_clear (z);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    double        y;
+    long int      n;
+    unsigned long d;
+  } data[] = {
+    {  0.0,  0, 1 },
+    {  1.0,  1, 1 },
+    { -1.0, -1, 1 },
+    { -1.5, -3, 2 },
+    {-1.25, -5, 4 },
+    {0.125,  1, 8 },
+
+    {24685,24685,1},
+    {-9876,-9876,1},
+    {463.5,  927,2},
+
+    {1234.5/8192,  2469, 16384 },
+    {-543.0/1024,  -543,  1024 },
+    {9876.5/ 512, 19753,  1024 },
+    {9753.0/ 128,  9753,   128 },
+    {-789.0/  32,  -789,    32 },
+    {4.580078125,  2345,   512 },
+  };
+
+  mpq_t    x, r;
+  unsigned i;
+  double d;
+
+  mpq_init (x);
+  mpq_init (r);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_d (x, data[i].y);
+      mpq_set_si (r, data[i].n, data[i].d);
+      mpq_canonicalize (r);
+      if (!mpq_equal (x, r))
+	{
+	  fprintf (stderr, "mpq_set_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
+	  abort ();
+	}
+      d = mpq_get_d (r);
+      if (d != data[i].y)
+	{
+	  fprintf (stderr, "mpq_get_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
+	  abort ();
+	}
+    }
+
+  mpq_clear (x);
+  mpq_clear (r);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  check_data ();
+  check_random ();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_muldiv.c b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv.c
new file mode 100644
index 0000000..8e7de8b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv.c
@@ -0,0 +1,176 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 300
+#define COUNT 10000
+
+static void
+_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
+{
+  if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
+    {
+      mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
+    }
+  else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
+    {
+      mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
+    }
+  else
+    {
+      mpq_set_num (q, n);
+      mpq_set_den (q, d);
+    }
+  mpq_canonicalize (q);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t an, bn, rn, ad, bd, rd;
+  mpq_t aq, bq, refq, resq;
+
+  mpz_init (an);
+  mpz_init (bn);
+  mpz_init (rn);
+  mpz_init (ad);
+  mpz_init (bd);
+  mpz_init (rd);
+  mpq_init (aq);
+  mpq_init (bq);
+  mpq_init (refq);
+  mpq_init (resq);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, an, bn, rn);
+      do {
+	mini_random_op3 (OP_MUL, MAXBITS, ad, bd, rd);
+      } while (mpz_sgn (rd) == 0);
+
+      _mpq_set_zz (aq, an, ad);
+      _mpq_set_zz (bq, bn, bd);
+      _mpq_set_zz (refq, rn, rd);
+
+      mpq_mul (resq, aq, bq);
+      if (!mpq_equal (resq, refq))
+	{
+	  fprintf (stderr, "mpq_mul failed [%i]:\n", i);
+	  dump ("an", an);
+	  dump ("ad", ad);
+	  dump ("bn", bn);
+	  dump ("bd", bd);
+	  dump ("refn", rn);
+	  dump ("refd", rd);
+	  dump ("resn", mpq_numref (resq));
+	  dump ("resd", mpq_denref (resq));
+	  abort ();
+	}
+
+      if (mpq_sgn (refq) != 0)
+	{
+	  mpq_set_ui (resq, ~6, 8);
+	  mpq_inv (aq, aq);
+	  mpq_div (resq, aq, bq);
+	  mpq_inv (resq, resq);
+	  if (!mpq_equal (resq, refq))
+	    {
+	      fprintf (stderr, "mpq_div failed [%i]:\n", i);
+	      dump ("an", an);
+	      dump ("ad", ad);
+	      dump ("bn", bn);
+	      dump ("bd", bd);
+	      dump ("refn", rn);
+	      dump ("refd", rd);
+	      dump ("resn", mpq_numref (resq));
+	      dump ("resd", mpq_denref (resq));
+	      abort ();
+	    }
+
+	  mpq_swap (bq, aq);
+	  mpq_div (resq, aq, bq);
+	  if (!mpq_equal (resq, refq))
+	    {
+	      fprintf (stderr, "mpq_swap failed [%i]:\n", i);
+	      dump ("an", an);
+	      dump ("ad", ad);
+	      dump ("bn", bn);
+	      dump ("bd", bd);
+	      dump ("refn", rn);
+	      dump ("refd", rd);
+	      dump ("resn", mpq_numref (resq));
+	      dump ("resd", mpq_denref (resq));
+	      abort ();
+	    }
+	}
+
+      mpq_set (resq, aq);
+      mpq_neg (bq, aq);
+      mpq_abs (refq, aq);
+      if (mpq_equal (refq, resq))
+	mpq_add (resq, refq, bq);
+      else
+	mpq_add (resq, refq, resq);
+      mpq_set_ui (refq, 0, 1);
+      if (!mpq_equal (resq, refq))
+	{
+	  fprintf (stderr, "mpq_abs failed [%i]:\n", i);
+	      dump ("an", an);
+	      dump ("ad", ad);
+	      dump ("resn", mpq_numref (resq));
+	      dump ("resd", mpq_denref (resq));
+	      abort ();
+	}
+
+      mpq_mul (resq, aq, aq);
+      mpq_mul (refq, aq, bq); /* now bq = - aq */
+      mpq_neg (refq, refq);
+      if (!mpq_equal (resq, refq))
+	{
+	  fprintf (stderr, "mpq_mul(sqr) failed [%i]:\n", i);
+	  dump ("an", an);
+	  dump ("ad", ad);
+	  dump ("bn", bn);
+	  dump ("bd", bd);
+	  dump ("refn", rn);
+	  dump ("refd", rd);
+	  dump ("resn", mpq_numref (resq));
+	  dump ("resd", mpq_denref (resq));
+	  abort ();
+	}
+    }
+
+  mpz_clear (an);
+  mpz_clear (bn);
+  mpz_clear (rn);
+  mpz_clear (ad);
+  mpz_clear (bd);
+  mpz_clear (rd);
+  mpq_clear (aq);
+  mpq_clear (bq);
+  mpq_clear (refq);
+  mpq_clear (resq);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_muldiv_2exp.c b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv_2exp.c
new file mode 100644
index 0000000..46b2c0c
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv_2exp.c
@@ -0,0 +1,138 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 300
+#define COUNT 10000
+
+static void
+_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
+{
+  if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
+    {
+      mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
+    }
+  else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
+    {
+      mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
+    }
+  else
+    {
+      mpq_set_num (q, n);
+      mpq_set_den (q, d);
+    }
+  mpq_canonicalize (q);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, t;
+  mpq_t aq, rq, tq;
+  mp_bitcnt_t e;
+  long int e2, t1, t2;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (t);
+  mpq_init (aq);
+  mpq_init (rq);
+  mpq_init (tq);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      do {
+	mini_random_bit_op (OP_COMBIT, MAXBITS, a, &e, b);
+      } while (mpz_sgn (a) == 0 || mpz_sgn (b) == 0);
+
+      _mpq_set_zz (aq, a, b);
+      e2 = mpz_scan1 (a, 0);
+      e2-= mpz_scan1 (b, 0);
+
+      mpq_mul_2exp (rq, aq, e);
+      t1 = mpz_scan1 (mpq_numref (rq), 0);
+      t2 = mpz_scan1 (mpq_denref (rq), 0);
+      mpq_neg (tq, rq);
+      mpq_div (tq, aq, tq);
+      mpq_get_den (t, tq);
+
+      if (e2 + e != t1 - t2 || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e
+	  || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_si (mpq_numref (tq), -1) != 0)
+	{
+	  fprintf (stderr, "mpq_mul_2exp failed: %lu\n", e);
+	  dump ("na", a);
+	  dump ("da", b);
+	  dump ("nr", mpq_numref (rq));
+	  dump ("dr", mpq_denref (rq));
+	  abort ();
+	}
+
+      mpq_div_2exp (rq, aq, e);
+      t1 = mpz_scan1 (mpq_numref (rq), 0);
+      t2 = mpz_scan1 (mpq_denref (rq), 0);
+      mpq_div (aq, aq, rq);
+      mpq_get_num (t, aq);
+
+      if (e2 != t1 - t2 + e || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e
+	  || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_ui (mpq_denref (aq), 1) != 0)
+	{
+	  fprintf (stderr, "mpq_div_2exp failed: %lu\n", e);
+	  fprintf (stderr, "%li %li %lu %zu\n", e2, t2, mpz_scan1 (t, 0), mpz_sizeinbase (t, 2));
+	  dump ("na", a);
+	  dump ("da", b);
+	  dump ("nr", mpq_numref (rq));
+	  dump ("dr", mpq_denref (rq));
+	  abort ();
+	}
+
+      mpq_set_ui (aq, 0, 1);
+      mpq_set_ui (rq, 6, 7);
+      mpq_set (tq, aq);
+      mpq_div_2exp (rq, aq, e);
+
+      if (!mpq_equal (tq, rq))
+	{
+	  fprintf (stderr, "mpq_div_2exp failed on zero: %lu\n", e);
+	  abort ();
+	}
+
+      mpq_set_ui (rq, 7, 6);
+      mpq_mul_2exp (rq, aq, e);
+
+      if (!mpq_equal (rq, tq))
+	{
+	  fprintf (stderr, "mpq_mul_2exp failed on zero: %lu\n", e);
+	  abort ();
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (t);
+  mpq_clear (aq);
+  mpq_clear (rq);
+  mpq_clear (tq);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_str.c b/third_party/gmp/mini-gmp/tests/t-mpq_str.c
new file mode 100644
index 0000000..7c69153
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_str.c
@@ -0,0 +1,252 @@
+/*
+
+Copyright 2012-2014, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 400
+#define COUNT 2000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+static void
+test_small (void)
+{
+  struct {
+    const char *input;
+    const char *decimal;
+  } data[] = {
+    { "1832407/3", "1832407/3" },
+    { " 2763959/6", "2763959/6 " },
+    { "4 981 999 / 1 8", "4981999/18" },
+    { "10\t73981/30 ", "1073981/30" },
+    { "958 544 /1", "00958544/01" },
+    { "-0", "0000" },
+    { " -000  ", "0/ 1" },
+    { "0704436/011", "231710/9" },
+    /* Check the case of large number of leading zeros. */
+    { "0000000000000000000000000/1", "0/0000000000000000000000001" },
+    { "000000000000000704436/000011", "0000000000000000231710/00009" },
+    { " 012/ 02503517", "10/689999" },
+    { "0b 10/0 1312143", "2/365667" },
+    { "-03 274062/0x1", "-882738/1" },
+    { "012\t242", "005282" },
+    { "9/0b11010111110010001111", "9/883855" },
+    { "022/ 0b11001010010100001", "18/103585" },
+    { "-0b101010110011101111/0x12", "-175343/18" },
+    { "-05/0b 111 1111 0110 1110 0110", "-5/521958" },
+    { "0b 011 111 110 111 001 000 011/0b00110", "1044035/6" },
+    { " 0x53dfc", "343548" },
+    { "-0x00012/0x000fA019", "-18/1024025" },
+    { "0x 642d1", "410321" },
+    { "0x5 8067/0Xa", "360551/10" },
+    { "-0xd6Be6/3", "-879590/3" },
+    { "\t0B1110000100000000011", "460803" },
+    { "0B\t1111110010010100101", "517285" },
+    { "-0x 00 2d/0B1\t010111101101110100", "-45/359284" },
+    { "-0B101\t1001101111111001", "-367609" },
+    { "0B10001001010111110000/0xf", "562672/15" },
+    { "0Xe4B7e/1", "936830" },
+    { "0X1E4bf/0X1", "124095" },
+    { "-0Xfdb90/05", "-1039248/5" },
+    { "0b010/0X7fc47", "2/523335" },
+    { "15/0X8167c", "15/530044" },
+    /* Some invalid inputs */
+    { "", NULL },
+    { "0x", NULL },
+    { "0b", NULL },
+    { "0z", NULL },
+    { "-", NULL },
+    { "/0x ", NULL },
+    { "0|1", NULL },
+    { "/", NULL },
+    { "0ab", NULL },
+    { "10x0", NULL },
+    { "1/0xxab", NULL },
+    { "0/ab", NULL },
+    { "0/#", NULL },
+    { "$foo/1", NULL },
+    { NULL, NULL }
+  };
+  unsigned i;
+  mpq_t a, b;
+  mpq_init (a);
+  mpq_init (b);
+
+  for (i = 0; data[i].input; i++)
+    {
+      int res = mpq_set_str (a, data[i].input, 0);
+      if (data[i].decimal)
+	{
+	  if (res != 0)
+	    {
+	      fprintf (stderr, "mpq_set_str returned -1, input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (mpq_set_str (b, data[i].decimal, 10) != 0)
+	    {
+	      fprintf (stderr, "mpq_set_str returned -1, decimal input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (!mpq_equal (a, b))
+	    {
+	      fprintf (stderr, "mpq_set_str failed for input: %s\n",
+		       data[i].input);
+
+	      dump ("got_num", mpq_numref (a));
+	      dump ("got_den", mpq_denref (a));
+	      dump ("ref_num", mpq_numref (b));
+	      dump ("ref_den", mpq_denref (b));
+	      abort ();
+	    }
+	}
+      else if (res != -1)
+	{
+	  fprintf (stderr, "mpq_set_str returned %d, invalid input: %s\n",
+		   res, data[i].input);
+	  abort ();
+	}
+    }
+
+  mpq_clear (a);
+  mpq_clear (b);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  char *ap;
+  char *bp;
+  char *rp;
+  size_t rn, arn;
+
+  mpq_t a, b;
+
+  FILE *tmp;
+
+  test_small ();
+
+  mpq_init (a);
+  mpq_init (b);
+
+  tmp = tmpfile ();
+  if (!tmp)
+    fprintf (stderr,
+	     "Failed to create temporary file. Skipping mpq_out_str tests.\n");
+
+  for (i = 0; i < COUNT/60; i++)
+    {
+      int base;
+      for (base = 2; base <= 62; ++base)
+	{
+	  hex_mpq_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp);
+	  if (mpq_set_str (a, ap, 16) != 0)
+	    {
+	      fprintf (stderr, "mpq_set_str failed on input %s\n", ap);
+	      abort ();
+	    }
+
+	  rn = strlen (rp);
+	  arn = rn - (rp[0] == '-');
+
+	  bp = mpq_get_str (NULL, (i&1 || base > 36) ? base: -base, a);
+	  if (strcmp (bp, rp))
+	    {
+	      fprintf (stderr, "mpz_get_str failed:\n");
+	      dump ("a_num", mpq_numref (a));
+	      dump ("a_den", mpq_denref (a));
+	      fprintf (stderr, "b = %s\n", bp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", rp);
+	      abort ();
+	    }
+
+	  /* Just a few tests with file i/o. */
+	  if (tmp && i < 20)
+	    {
+	      size_t tn;
+	      rewind (tmp);
+	      tn = mpq_out_str (tmp, (i&1 || base > 36) ? base: -base, a);
+	      if (tn != rn)
+		{
+		  fprintf (stderr, "mpq_out_str, bad return value:\n");
+		  dump ("a_num", mpq_numref (a));
+		  dump ("a_den", mpq_denref (a));
+		  fprintf (stderr, "r = %s\n", rp);
+		  fprintf (stderr, "  base %d, correct size %u, got %u\n",
+			   base, (unsigned) rn, (unsigned)tn);
+		  abort ();
+		}
+	      rewind (tmp);
+	      memset (bp, 0, rn);
+	      tn = fread (bp, 1, rn, tmp);
+	      if (tn != rn)
+		{
+		  fprintf (stderr,
+			   "fread failed, expected %lu bytes, got only %lu.\n",
+			   (unsigned long) rn, (unsigned long) tn);
+		  abort ();
+		}
+
+	      if (memcmp (bp, rp, rn) != 0)
+		{
+		  fprintf (stderr, "mpq_out_str failed:\n");
+		  dump ("a_num", mpq_numref (a));
+		  dump ("a_den", mpq_denref (a));
+		  fprintf (stderr, "b = %s\n", bp);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", rp);
+		  abort ();
+		}
+	    }
+
+	  mpq_set_str (b, rp, base);
+
+	  if (!mpq_equal (a, b))
+	    {
+	      fprintf (stderr, "mpq_set_str failed:\n");
+	      fprintf (stderr, "r = %s\n", rp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", ap);
+	      fprintf (stderr, "  base = 16\n");
+	      dump ("b_num", mpq_numref (b));
+	      dump ("b_den", mpq_denref (b));
+	      dump ("r_num", mpq_numref (a));
+	      dump ("r_den", mpq_denref (a));
+	      abort ();
+	    }
+
+	  free (ap);
+	  free (rp);
+	  testfree (bp);
+	}
+    }
+  mpq_clear (a);
+  mpq_clear (b);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mul.c b/third_party/gmp/mini-gmp/tests/t-mul.c
new file mode 100644
index 0000000..57ec4ed
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mul.c
@@ -0,0 +1,113 @@
+/*
+
+Copyright 2012, 2014, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, res_ui, ref, tz;
+  mp_limb_t t[2*MAXLIMBS];
+  mp_size_t an;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (res_ui);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
+      mpz_mul (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_mul failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_size (a) == mpz_size (b))
+	{
+	  memset (t, 0x55, sizeof(t));
+	  an = mpz_size (a);
+	  if (an > 0)
+	    {
+	      mpn_mul_n (t, a->_mp_d, b->_mp_d, an);
+
+	      mpz_roinit_n (tz, t, 2*an);
+	      if (mpz_cmpabs (tz, ref))
+		{
+		  fprintf (stderr, "mpn_mul_n failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("ref", ref);
+		  abort ();
+		}
+	    }
+	}
+      if (mpz_fits_slong_p (b)) {
+	mpz_mul_si (res_ui, a, mpz_get_si (b));
+	if (mpz_cmp (res_ui, ref))
+	  {
+	    fprintf (stderr, "mpz_mul_si failed:\n");
+	    dump ("a", a);
+	    dump ("b", b);
+	    dump ("r", res_ui);
+	    dump ("ref", ref);
+	    abort ();
+	  }
+      }
+      mini_random_op2 (OP_SQR, MAXBITS, a, ref);
+      an = mpz_size (a);
+      if (an > 0)
+	{
+	  memset (t, 0x33, sizeof(t));
+	  mpn_sqr (t, mpz_limbs_read (a), an);
+
+	  mpz_roinit_n (tz, t, 2*an);
+	  if (mpz_cmp (tz, ref))
+	    {
+	      fprintf (stderr, "mpn (squaring) failed:\n");
+	      dump ("a", a);
+	      dump ("ref", ref);
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (res_ui);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-powm.c b/third_party/gmp/mini-gmp/tests/t-powm.c
new file mode 100644
index 0000000..d6c108d
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-powm.c
@@ -0,0 +1,61 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 1000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t b, e, m, res, ref;
+
+  mpz_init (b);
+  mpz_init (e);
+  mpz_init (m);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op4 (OP_POWM, MAXBITS, b, e, m, ref);
+      mpz_powm (res, b, e, m);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_powm failed:\n");
+	  dump ("b", b);
+	  dump ("e", e);
+	  dump ("m", m);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (b);
+  mpz_clear (e);
+  mpz_clear (m);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-pprime_p.c b/third_party/gmp/mini-gmp/tests/t-pprime_p.c
new file mode 100644
index 0000000..6cf9b18
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-pprime_p.c
@@ -0,0 +1,183 @@
+/* test mpz_probab_prime_p
+
+Copyright 2001, 2002, 2004, 2011, 2012, 2014, 2016 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "testutils.h"
+
+static int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  if (t < 32)
+    return (0xa08a28acUL >> t) & 1;
+  if ((t & 1) == 0)
+    return 0;
+
+  if (t % 3 == 0)
+    return 0;
+  if (t % 5 == 0)
+    return 0;
+  if (t % 7 == 0)
+    return 0;
+
+  for (d = 11;;)
+    {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 2;
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 4;
+    }
+  return 0;
+}
+
+static void
+check_one (mpz_srcptr n, int want)
+{
+  int  got;
+
+  got = mpz_probab_prime_p (n, 25);
+
+  /* "definitely prime" is fine if we only wanted "probably prime" */
+  if (got == 2 && want == 1)
+    want = 2;
+
+  if (got != want)
+    {
+      printf ("mpz_probab_prime_p\n");
+      dump   ("  n    ", n);
+      printf ("  got =%d", got);
+      printf ("  want=%d\n", want);
+      abort ();
+    }
+}
+
+static void
+check_pn (mpz_ptr n, int want)
+{
+  check_one (n, want);
+  mpz_neg (n, n);
+  check_one (n, want);
+}
+
+static void
+check_small (void)
+{
+  mpz_t  n;
+  long   i;
+
+  mpz_init (n);
+
+  for (i = 0; i < 1700; i++)
+    {
+      mpz_set_si (n, i);
+      check_pn (n, isprime (i));
+    }
+
+  mpz_clear (n);
+}
+
+void
+check_composites (void)
+{
+  int i;
+  int reps = 1000;
+  mpz_t a, b, n, bs;
+  unsigned long size_range, size;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (n);
+  mpz_init (bs);
+
+  for (i = 0; i < reps; i++)
+    {
+      mini_urandomb (bs, 16);
+      size_range = mpz_get_ui (bs) % 10 + 1; /* 0..1024 bit operands */
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (a, size);
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (b, size);
+
+      /* Exclude trivial factors */
+      if (mpz_cmp_ui (a, 1) == 0)
+	mpz_set_ui (a, 2);
+      if (mpz_cmp_ui (b, 1) == 0)
+	mpz_set_ui (b, 2);
+
+      mpz_mul (n, a, b);
+
+      check_pn (n, 0);
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (n);
+  mpz_clear (bs);
+}
+
+static void
+check_primes (void)
+{
+  static const char * const primes[] = {
+    "2", "17", "65537",
+    /* diffie-hellman-group1-sha1, also "Well known group 2" in RFC
+       2412, 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */
+    "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+    "FFFFFFFFFFFFFFFF",
+    NULL
+  };
+
+  mpz_t n;
+  int i;
+
+  mpz_init (n);
+
+  for (i = 0; primes[i]; i++)
+    {
+      mpz_set_str_or_abort (n, primes[i], 0);
+      check_one (n, 1);
+    }
+  mpz_clear (n);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  check_small ();
+  check_composites ();
+  check_primes ();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-reuse.c b/third_party/gmp/mini-gmp/tests/t-reuse.c
new file mode 100644
index 0000000..5ac9e11
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-reuse.c
@@ -0,0 +1,663 @@
+/* Test that routines allow reusing a source variable as destination.
+
+Copyright 1996, 1999-2002, 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define COUNT 100
+
+void dump3 (const char *, mpz_t, mpz_t, mpz_t);
+void mpz_check_format (const mpz_t);
+
+typedef void (*dss_func) (mpz_t, const mpz_t, const mpz_t);
+typedef void (*dsi_func) (mpz_t, const mpz_t, unsigned long int);
+typedef unsigned long int (*dsi_div_func) (mpz_t, const mpz_t, unsigned long int);
+typedef unsigned long int (*ddsi_div_func) (mpz_t, mpz_t, const mpz_t, unsigned long int);
+typedef void (*ddss_div_func) (mpz_t, mpz_t, const mpz_t, const mpz_t);
+typedef void (*ds_func) (mpz_t, const mpz_t);
+
+
+void
+mpz_xinvert (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  int res;
+  res = mpz_invert (r, a, b);
+  if (res == 0)
+    mpz_set_ui (r, 0);
+}
+
+dss_func dss_funcs[] =
+{
+  mpz_add, mpz_sub, mpz_mul,
+  mpz_cdiv_q, mpz_cdiv_r, mpz_fdiv_q, mpz_fdiv_r, mpz_tdiv_q, mpz_tdiv_r,
+  mpz_xinvert,
+  mpz_gcd, mpz_lcm, mpz_and, mpz_ior, mpz_xor
+};
+const char *dss_func_names[] =
+{
+  "mpz_add", "mpz_sub", "mpz_mul",
+  "mpz_cdiv_q", "mpz_cdiv_r", "mpz_fdiv_q", "mpz_fdiv_r", "mpz_tdiv_q", "mpz_tdiv_r",
+  "mpz_xinvert",
+  "mpz_gcd", "mpz_lcm", "mpz_and", "mpz_ior", "mpz_xor"
+};
+char dss_func_division[] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
+
+dsi_func dsi_funcs[] =
+{
+  /* Don't change order here without changing the code in main(). */
+  mpz_add_ui, mpz_mul_ui, mpz_sub_ui,
+  mpz_fdiv_q_2exp, mpz_fdiv_r_2exp,
+  mpz_cdiv_q_2exp, mpz_cdiv_r_2exp,
+  mpz_tdiv_q_2exp, mpz_tdiv_r_2exp,
+  mpz_mul_2exp,
+  mpz_pow_ui
+};
+const char *dsi_func_names[] =
+{
+  "mpz_add_ui", "mpz_mul_ui", "mpz_sub_ui",
+  "mpz_fdiv_q_2exp", "mpz_fdiv_r_2exp",
+  "mpz_cdiv_q_2exp", "mpz_cdiv_r_2exp",
+  "mpz_tdiv_q_2exp", "mpz_tdiv_r_2exp",
+  "mpz_mul_2exp",
+  "mpz_pow_ui"
+};
+
+dsi_div_func dsi_div_funcs[] =
+{
+  mpz_cdiv_q_ui, mpz_cdiv_r_ui,
+  mpz_fdiv_q_ui, mpz_fdiv_r_ui,
+  mpz_tdiv_q_ui, mpz_tdiv_r_ui
+};
+const char *dsi_div_func_names[] =
+{
+  "mpz_cdiv_q_ui", "mpz_cdiv_r_ui",
+  "mpz_fdiv_q_ui", "mpz_fdiv_r_ui",
+  "mpz_tdiv_q_ui", "mpz_tdiv_r_ui"
+};
+
+ddsi_div_func ddsi_div_funcs[] =
+{
+  mpz_cdiv_qr_ui,
+  mpz_fdiv_qr_ui,
+  mpz_tdiv_qr_ui
+};
+const char *ddsi_div_func_names[] =
+{
+  "mpz_cdiv_qr_ui",
+  "mpz_fdiv_qr_ui",
+  "mpz_tdiv_qr_ui"
+};
+
+ddss_div_func ddss_div_funcs[] =
+{
+  mpz_cdiv_qr,
+  mpz_fdiv_qr,
+  mpz_tdiv_qr
+};
+const char *ddss_div_func_names[] =
+{
+  "mpz_cdiv_qr",
+  "mpz_fdiv_qr",
+  "mpz_tdiv_qr"
+};
+
+ds_func ds_funcs[] =
+{
+  mpz_abs, mpz_com, mpz_neg, mpz_sqrt
+};
+const char *ds_func_names[] =
+{
+  "mpz_abs", "mpz_com", "mpz_neg", "mpz_sqrt"
+};
+
+
+#define FAIL(class,indx,op1,op2,op3) \
+  do {									\
+  class##_funcs[indx] = 0;						\
+  dump3 (class##_func_names[indx], op1, op2, op3);			\
+  failures++;								\
+  } while (0)
+#define FAIL2(fname,op1,op2,op3) \
+  do {									\
+  dump3 (#fname, op1, op2, op3);						\
+  failures++;								\
+  } while (0)
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  int pass, reps = COUNT;
+  mpz_t in1, in2, in3;
+  unsigned long int in2i;
+  mp_size_t size;
+  mpz_t res1, res2, res3;
+  mpz_t ref1, ref2, ref3;
+  mpz_t t;
+  unsigned long int r1, r2;
+  long failures = 0;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  mpz_init (bs);
+
+  mpz_init (in1);
+  mpz_init (in2);
+  mpz_init (in3);
+  mpz_init (ref1);
+  mpz_init (ref2);
+  mpz_init (ref3);
+  mpz_init (res1);
+  mpz_init (res2);
+  mpz_init (res3);
+  mpz_init (t);
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+      mini_urandomb (bs, 32);
+      size_range = mpz_get_ui (bs) % 12 + 2;
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (in1, size);
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (in2, size);
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (in3, size);
+
+      mini_urandomb (bs, 3);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (in1, in1);
+      if ((bsi & 2) != 0)
+	mpz_neg (in2, in2);
+      if ((bsi & 4) != 0)
+	mpz_neg (in3, in3);
+
+      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
+	{
+	  if (dss_funcs[i] == 0)
+	    continue;
+	  if (dss_func_division[i] && mpz_sgn (in2) == 0)
+	    continue;
+
+	  (dss_funcs[i]) (ref1, in1, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  (dss_funcs[i]) (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  (dss_funcs[i]) (res1, in1, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < sizeof (ddss_div_funcs) / sizeof (ddss_div_func); i++)
+	{
+	  if (ddss_div_funcs[i] == 0)
+	    continue;
+	  if (mpz_sgn (in2) == 0)
+	    continue;
+
+	  (ddss_div_funcs[i]) (ref1, ref2, in1, in2);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+
+	  mpz_set (res1, in1);
+	  (ddss_div_funcs[i]) (res1, res2, res1, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  (ddss_div_funcs[i]) (res1, res2, res2, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  (ddss_div_funcs[i]) (res1, res2, in1, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res2, in2);
+	  (ddss_div_funcs[i]) (res1, res2, in1, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < sizeof (ds_funcs) / sizeof (ds_func); i++)
+	{
+	  if (ds_funcs[i] == 0)
+	    continue;
+	  if (strcmp (ds_func_names[i], "mpz_sqrt") == 0
+	      && mpz_sgn (in1) < 0)
+	    continue;
+
+	  (ds_funcs[i]) (ref1, in1);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  (ds_funcs[i]) (res1, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (ds, i, in1, in2, NULL);
+	}
+
+      in2i = mpz_get_ui (in2);
+
+      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
+	{
+	  if (dsi_funcs[i] == 0)
+	    continue;
+	  if (strcmp (dsi_func_names[i], "mpz_fdiv_q_2exp") == 0)
+	    /* Limit exponent to something reasonable for the division
+	       functions.  Without this, we'd  normally shift things off
+	       the end and just generate the trivial values 1, 0, -1.  */
+	    in2i %= 0x1000;
+	  if (strcmp (dsi_func_names[i], "mpz_mul_2exp") == 0)
+	    /* Limit exponent more for mpz_mul_2exp to save time.  */
+	    in2i %= 0x100;
+	  if (strcmp (dsi_func_names[i], "mpz_pow_ui") == 0)
+	    /* Limit exponent yet more for mpz_pow_ui to save time.  */
+	    in2i %= 0x10;
+
+	  (dsi_funcs[i]) (ref1, in1, in2i);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  (dsi_funcs[i]) (res1, res1, in2i);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dsi, i, in1, in2, NULL);
+	}
+
+      if (in2i != 0)	  /* Don't divide by 0.  */
+	{
+	  for (i = 0; i < sizeof (dsi_div_funcs) / sizeof (dsi_div_funcs); i++)
+	    {
+	      r1 = (dsi_div_funcs[i]) (ref1, in1, in2i);
+	      mpz_check_format (ref1);
+
+	      mpz_set (res1, in1);
+	      r2 = (dsi_div_funcs[i]) (res1, res1, in2i);
+	      mpz_check_format (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || r1 != r2)
+		FAIL (dsi_div, i, in1, in2, NULL);
+	    }
+
+	  for (i = 0; i < sizeof (ddsi_div_funcs) / sizeof (ddsi_div_funcs); i++)
+	    {
+	      r1 = (ddsi_div_funcs[i]) (ref1, ref2, in1, in2i);
+	      mpz_check_format (ref1);
+
+	      mpz_set (res1, in1);
+	      r2 = (ddsi_div_funcs[i]) (res1, res2, res1, in2i);
+	      mpz_check_format (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+
+	      mpz_set (res2, in1);
+	      (ddsi_div_funcs[i]) (res1, res2, res2, in2i);
+	      mpz_check_format (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+	    }
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_sqrtrem (ref1, ref2, in1);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_sqrtrem (res1, res2, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_sqrtrem (res1, res2, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_root (ref1, in1, in2i % 0x1000 + 1);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_root (res1, res1, in2i % 0x1000 + 1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_root, in1, in2, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_rootrem (ref1, ref2, in1, in2i % 0x1000 + 1);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_rootrem (res1, res2, res1, in2i % 0x1000 + 1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_rootrem (res1, res2, res2, in2i % 0x1000 + 1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+	}
+
+      if (pass < reps / 2)	/* run fewer tests since gcdext lots of time */
+	{
+	  mpz_gcdext (ref1, ref2, ref3, in1, in2);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+	  mpz_check_format (ref3);
+
+	  mpz_set (res1, in1);
+	  mpz_gcdext (res1, res2, res3, res1, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_gcdext (res1, res2, res3, res2, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res3, in1);
+	  mpz_gcdext (res1, res2, res3, res3, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_gcdext (res1, res2, res3, in1, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in2);
+	  mpz_gcdext (res1, res2, res3, in1, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res3, in2);
+	  mpz_gcdext (res1, res2, res3, in1, res3);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res1, in1);
+	  mpz_gcdext (res1, res2, NULL, res1, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_gcdext (res1, res2, NULL, res2, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_gcdext (res1, res2, NULL, in1, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in2);
+	  mpz_gcdext (res1, res2, NULL, in1, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+	}
+
+      /* Don't run mpz_powm for huge exponents or when undefined.  */
+      if (mpz_sizeinbase (in2, 2) < 250 && mpz_sgn (in3) != 0
+	  && (mpz_sgn (in2) >= 0 || mpz_invert (t, in1, in3)))
+	{
+	  mpz_powm (ref1, in1, in2, in3);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm (res1, res1, in2, in3);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in2);
+	  mpz_powm (res1, in1, res1, in3);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm (res1, in1, in2, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+	}
+
+      /* Don't run mpz_powm_ui when undefined.  */
+      if (mpz_sgn (in3) != 0)
+	{
+	  mpz_powm_ui (ref1, in1, in2i, in3);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm_ui (res1, res1, in2i, in3);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm_ui (res1, in1, in2i, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+	}
+
+      {
+	r1 = mpz_gcd_ui (ref1, in1, in2i);
+	mpz_check_format (ref1);
+
+	mpz_set (res1, in1);
+	r2 = mpz_gcd_ui (res1, res1, in2i);
+	mpz_check_format (res1);
+	if (mpz_cmp (ref1, res1) != 0)
+	  FAIL2 (mpz_gcd_ui, in1, in2, NULL);
+      }
+#if 0
+      if (mpz_cmp_ui (in2, 1L) > 0 && mpz_sgn (in1) != 0)
+	{
+	  /* Test mpz_remove */
+	  mpz_remove (ref1, in1, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_remove (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_remove (res1, in1, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+	}
+#endif
+      if (mpz_sgn (in2) != 0)
+	{
+	  /* Test mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact (ref1, t, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact (res1, t, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+	}
+
+#if 0
+      if (mpz_sgn (in2) > 0)
+	{
+	  /* Test mpz_divexact_gcd, same as mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact_gcd (ref1, t, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact_gcd (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact_gcd (res1, t, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+	}
+#endif
+    }
+
+  if (failures != 0)
+    {
+      fprintf (stderr, "mpz/reuse: %ld error%s\n", failures, "s" + (failures == 1));
+      exit (1);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (in1);
+  mpz_clear (in2);
+  mpz_clear (in3);
+  mpz_clear (ref1);
+  mpz_clear (ref2);
+  mpz_clear (ref3);
+  mpz_clear (res1);
+  mpz_clear (res2);
+  mpz_clear (res3);
+  mpz_clear (t);
+}
+
+void
+dump3 (const char *name, mpz_t in1, mpz_t in2, mpz_t in3)
+{
+  printf ("failure in %s (", name);
+  mpz_out_str (stdout, -16, in1);
+  if (in2 != NULL)
+    {
+      printf (" ");
+      mpz_out_str (stdout, -16, in2);
+    }
+  if (in3 != NULL)
+    {
+      printf (" ");
+      mpz_out_str (stdout, -16, in3);
+    }
+  printf (")\n");
+}
+
+void
+mpz_check_format (const mpz_t x)
+{
+  mp_size_t n = x ->_mp_size;
+  if (n < 0)
+    n = - n;
+
+  if (n > x->_mp_alloc)
+    {
+      fprintf (stderr, "mpz_t size exceeds allocation!\n");
+      abort ();
+    }
+
+  if (n > 0 && x->_mp_d[n-1] == 0)
+    {
+      fprintf (stderr, "Unnormalized mpz_t!\n");
+      abort ();
+    }
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-root.c b/third_party/gmp/mini-gmp/tests/t-root.c
new file mode 100644
index 0000000..1f46c43
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-root.c
@@ -0,0 +1,95 @@
+/*
+
+Copyright 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+/* Called when s is supposed to be floor(root(u,z)), and r = u - s^z */
+static int
+rootrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r, unsigned long z)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  if (mpz_fits_ulong_p (s))
+    mpz_ui_pow_ui (t, mpz_get_ui (s), z);
+  else
+    mpz_pow_ui (t, s, z);
+  mpz_sub (t, u, t);
+  if ((mpz_sgn (t) != mpz_sgn(u) && mpz_sgn (t) != 0) || mpz_cmp (t, r) != 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+  if (mpz_sgn (s) > 0)
+    mpz_add_ui (t, s, 1);
+  else
+    mpz_sub_ui (t, s, 1);
+  mpz_pow_ui (t, t, z);
+  if (mpz_cmpabs (t, u) <= 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+
+  mpz_clear (t);
+  return 1;
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  unsigned long e;
+  mpz_t u, s, r, bs;
+
+  mpz_init (u);
+  mpz_init (s);
+  mpz_init (r);
+  mpz_init (bs);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_rrandomb (u, MAXBITS);
+      mini_rrandomb (bs, 12);
+      e = mpz_getlimbn (bs, 0) % mpz_sizeinbase (u, 2) + 1;
+      if ((e & 1) && (mpz_getlimbn (bs, 0) & (1L<<10)))
+	mpz_neg (u, u);
+      mpz_rootrem (s, r, u, e);
+
+      if (!rootrem_valid_p (u, s, r, e))
+	{
+	  fprintf (stderr, "mpz_rootrem(%lu-th) failed:\n", e);
+	  dump ("u", u);
+	  dump ("root", s);
+	  dump ("rem", r);
+	  abort ();
+	}
+    }
+  mpz_clear (bs);
+  mpz_clear (u);
+  mpz_clear (s);
+  mpz_clear (r);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-scan.c b/third_party/gmp/mini-gmp/tests/t-scan.c
new file mode 100644
index 0000000..39b1f35
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-scan.c
@@ -0,0 +1,90 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a;
+  mp_bitcnt_t b, res, ref;
+
+  mpz_init (a);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_scan_op (OP_SCAN0, MAXBITS, a, &b, &ref);
+      res = mpz_scan0 (a, b);
+      if (res != ref)
+	{
+	  fprintf (stderr, "mpz_scan0 failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  fprintf (stderr, "r: %lu\n", res);
+	  fprintf (stderr, "ref: %lu\n", ref);
+	  abort ();
+	}
+      if (mpz_sgn (a) > 0 && ref < mpz_sizeinbase (a, 2))
+	{
+	  res = mpn_scan0 (a->_mp_d, b);
+	  if (res != ref)
+	    {
+	      fprintf (stderr, "mpn_scan0 failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "b: %lu\n", b);
+	      fprintf (stderr, "r: %lu\n", res);
+	      fprintf (stderr, "ref: %lu\n", ref);
+	      abort ();
+	    }
+	}
+      mini_random_scan_op (OP_SCAN1, MAXBITS, a, &b, &ref);
+      res = mpz_scan1 (a, b);
+      if (res != ref)
+	{
+	  fprintf (stderr, "mpz_scan1 failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  fprintf (stderr, "r: %lu\n", res);
+	  fprintf (stderr, "ref: %lu\n", ref);
+	  abort ();
+	}
+      if (mpz_sgn (a) > 0 && ref != ~ (mp_bitcnt_t) 0)
+	{
+	  res = mpn_scan1 (a->_mp_d, b);
+	  if (res != ref)
+	    {
+	      fprintf (stderr, "mpn_scan1 failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "b: %lu\n", b);
+	      fprintf (stderr, "r: %lu\n", res);
+	      fprintf (stderr, "ref: %lu\n", ref);
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-signed.c b/third_party/gmp/mini-gmp/tests/t-signed.c
new file mode 100644
index 0000000..e183944
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-signed.c
@@ -0,0 +1,205 @@
+/* Exercise some mpz_..._si functions.
+
+Copyright 2013, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testutils.h"
+
+/* Always called with sz fitting in a signed long, and si is the
+   corresponding value. */
+int
+check_si (const mpz_t sz, long si)
+{
+  mpz_t t;
+
+  /* Checks on sz/si */
+  if ((mpz_cmp_si (sz, si)) != 0)
+    {
+      printf ("mpz_cmp_si (sz, %ld) != 0.\n", si);
+      return 0;
+    }
+  if (mpz_get_si (sz) != si)
+    {
+      printf ("mpz_get_si (sz) != %ld.\n", si);
+      return 0;
+    }
+
+  mpz_init_set_si (t, si);
+
+  if (mpz_cmp (t, sz) != 0)
+    {
+      printf ("mpz_init_set_si (%ld) failed.\n", si);
+      printf (" got="); mpz_out_str (stdout, 10, t); printf ("\n");
+      return 0;
+    }
+
+  mpz_clear (t);
+  return 1;
+}
+
+/* Called with mpz_cmp (sz, oz) == c. If sz fits in a signed long,
+   si is the coresponding value, and similarly for oz and oi. */
+void
+check_si_cmp (const mpz_t sz, const mpz_t oz, long si, long oi, int c)
+{
+  if (mpz_cmp (sz, oz) != c)
+    {
+      printf ("mpz_cmp (sz, oz) != %i.\n", c);
+      goto fail;
+    }
+
+  if (mpz_fits_slong_p (sz))
+    {
+      if (!check_si (sz, si))
+	goto fail;
+      if (mpz_cmp_si (oz, si) != -c)
+	{
+	  printf ("mpz_cmp_si (oz, %ld) != %i.\n", si, -c);
+	  goto fail;
+	}
+    }
+  else
+    {
+      if (mpz_cmp_si (sz, si) != c)
+	{
+	  printf ("mpz_cmp_si (sz, %ld) != %i.\n", si, c);
+	  goto fail;
+	}
+      if (mpz_cmp_si (sz, -c) != c)
+	{
+	  printf ("mpz_cmp_si (sz, %i) != %i.\n", -c, c);
+	  goto fail;
+	}
+    }
+  if (mpz_fits_slong_p (oz))
+    {
+      if (!check_si (oz, oi))
+	goto fail;
+      if (mpz_cmp_si (sz, oi) != c)
+	{
+	  printf ("mpz_cmp_si (sz, %ld) != %i.\n", oi, c);
+	  goto fail;
+	}
+    }
+  return;
+
+ fail:
+  printf (" sz="); mpz_out_str (stdout, 10, sz); printf ("\n");
+  printf (" si=%ld\n", si);
+  printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
+  printf (" oi=%ld\n", si);
+  abort ();
+}
+
+void
+try_op_si (int c)
+{
+  long  si, oi;
+  mpz_t sz, oz;
+  unsigned overflow_count;
+
+  si = c;
+  mpz_init_set_si (sz, si);
+
+  oi = si;
+  mpz_init_set (oz, sz);
+
+  /* To get a few tests with operands straddling the border, don't
+     stop at the very first operand exceeding a signed long. */
+  for (overflow_count = 0; overflow_count < 10; )
+    {
+      /* c * 2^k */
+      mpz_mul_2exp (sz, sz, 1);
+      if (mpz_fits_slong_p (sz))
+	si *= 2;
+      else
+	overflow_count++;
+
+      check_si_cmp (sz, oz, si, oi, c);
+
+      /* c * (2^k + 1) */
+      if (c == -1)
+	mpz_sub_ui (oz, sz, 1);
+      else
+	mpz_add_ui (oz, sz, 1);
+      if (mpz_fits_slong_p (oz))
+	oi = si + c;
+      else
+	overflow_count++;
+      check_si_cmp (oz, sz, oi, si, c);
+
+      /* c * (2^K - 1) */
+      mpz_mul_si (oz, sz, 2*c);
+      if (c == -1)
+	mpz_ui_sub (oz, 1, oz); /* oz = sz * 2 + 1 */
+      else
+	mpz_sub_ui (oz, oz, 1); /* oz = sz * 2 - 1 */
+      if (mpz_fits_slong_p (oz))
+	oi = (si - c) * 2 + c;
+      else
+	overflow_count++;
+
+      check_si_cmp (oz, sz, oi, si, c);
+    };
+
+  mpz_clear (sz);
+  mpz_clear (oz);
+}
+
+void
+try_fits_slong_p (void)
+{
+  mpz_t x;
+  mpz_init_set_si (x, LONG_MAX);
+  if (!mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MAX) false!\n");
+      abort ();
+    }
+  mpz_add_ui (x, x, 1);
+  if (mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MAX + 1) true!\n");
+      abort ();
+    }
+  mpz_set_si (x, LONG_MIN);
+  if (!mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MIN) false!\n");
+      abort ();
+    }
+  mpz_sub_ui (x, x, 1);
+  if (mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MIN - 1) true!\n");
+      abort ();
+    }
+
+  mpz_clear (x);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  try_fits_slong_p ();
+  try_op_si (-1);
+  try_op_si (1);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-sqrt.c b/third_party/gmp/mini-gmp/tests/t-sqrt.c
new file mode 100644
index 0000000..dd4c83a
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-sqrt.c
@@ -0,0 +1,181 @@
+/*
+
+Copyright 2012, 2014, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 9000
+
+/* Called when s is supposed to be floor(sqrt(u)), and r = u - s^2 */
+static int
+sqrtrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpz_mul (t, s, s);
+  mpz_sub (t, u, t);
+  if (mpz_sgn (t) < 0 || mpz_cmp (t, r) != 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+  mpz_add_ui (t, s, 1);
+  mpz_mul (t, t, t);
+  if (mpz_cmp (t, u) <= 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+
+  mpz_clear (t);
+  return 1;
+}
+
+void
+mpz_mpn_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+  mp_limb_t *sp, *rp;
+  mp_size_t un, sn, ret;
+
+  un = mpz_size (u);
+
+  mpz_xor (s, s, u);
+  sn = (un + 1) / 2;
+  sp = mpz_limbs_write (s, sn + 1);
+  sp [sn] = 11;
+
+  if (un & 1)
+    rp = NULL; /* Exploits the fact that r already is correct. */
+  else {
+    mpz_add (r, u, s);
+    rp = mpz_limbs_write (r, un + 1);
+    rp [un] = 19;
+  }
+
+  ret = mpn_sqrtrem (sp, rp, mpz_limbs_read (u), un);
+
+  if (sp [sn] != 11)
+    {
+      fprintf (stderr, "mpn_sqrtrem buffer overrun on sp.\n");
+      abort ();
+    }
+  if (un & 1) {
+    if ((ret != 0) != (mpz_size (r) != 0)) {
+      fprintf (stderr, "mpn_sqrtrem wrong return value with NULL.\n");
+      abort ();
+    }
+  } else {
+    mpz_limbs_finish (r, ret);
+    if ((size_t) ret != mpz_size (r)) {
+      fprintf (stderr, "mpn_sqrtrem wrong return value.\n");
+      abort ();
+    }
+    if (rp [un] != 19)
+      {
+	fprintf (stderr, "mpn_sqrtrem buffer overrun on rp.\n");
+	abort ();
+      }
+  }
+
+  mpz_limbs_finish (s, (un + 1) / 2);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t u, s, r;
+
+  mpz_init (s);
+  mpz_init (r);
+
+  mpz_init_set_si (u, -1);
+  if (mpz_perfect_square_p (u))
+    {
+      fprintf (stderr, "mpz_perfect_square_p failed on -1.\n");
+      abort ();
+    }
+
+  if (!mpz_perfect_square_p (s))
+    {
+      fprintf (stderr, "mpz_perfect_square_p failed on 0.\n");
+      abort ();
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_rrandomb (u, MAXBITS - (i & 0xFF));
+      mpz_sqrtrem (s, r, u);
+
+      if (!sqrtrem_valid_p (u, s, r))
+	{
+	  fprintf (stderr, "mpz_sqrtrem failed:\n");
+	  dump ("u", u);
+	  dump ("sqrt", s);
+	  dump ("rem", r);
+	  abort ();
+	}
+
+      mpz_mpn_sqrtrem (s, r, u);
+
+      if (!sqrtrem_valid_p (u, s, r))
+	{
+	  fprintf (stderr, "mpn_sqrtrem failed:\n");
+	  dump ("u", u);
+	  dump ("sqrt", s);
+	  dump ("rem", r);
+	  abort ();
+	}
+
+      if (mpz_sgn (r) == 0) {
+	mpz_neg (u, u);
+	mpz_sub_ui (u, u, 1);
+      }
+
+      if ((mpz_sgn (u) <= 0 || (i & 1)) ?
+	  mpz_perfect_square_p (u) :
+	  mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u)))
+	{
+	  fprintf (stderr, "mp%s_perfect_square_p failed on non square:\n",
+		   (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n");
+	  dump ("u", u);
+	  abort ();
+	}
+
+      mpz_mul (u, s, s);
+      if (!((mpz_sgn (u) <= 0 || (i & 1)) ?
+	    mpz_perfect_square_p (u) :
+	    mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u))))
+	{
+	  fprintf (stderr, "mp%s_perfect_square_p failed on square:\n",
+		   (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n");
+	  dump ("u", u);
+	  abort ();
+	}
+
+    }
+  mpz_clear (u);
+  mpz_clear (s);
+  mpz_clear (r);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-str.c b/third_party/gmp/mini-gmp/tests/t-str.c
new file mode 100644
index 0000000..1e78676
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-str.c
@@ -0,0 +1,319 @@
+/*
+
+Copyright 2012-2014, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 2000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+static void
+test_small (void)
+{
+  struct {
+    const char *input;
+    const char *decimal;
+  } data[] = {
+    { "183407", "183407" },
+    { " 763959", "763959 " },
+    { "9 81999", "981999" },
+    { "10\t7398 ", "107398" },
+    { "-9585 44", "-00958544" },
+    { "-0", "0000" },
+    { " -000  ", "0" },
+    { "0704436", "231710" },
+    /* Check the case of large number of leading zeros. */
+    { "0000000000000000000000000", "0000000000000000000000000" },
+    { "000000000000000000000000704436", "000000000000000000000000231710" },
+    { " 02503517", "689999" },
+    { "0 1312143", "365667" },
+    { "-03 274062", "-882738" },
+    { "012\t242", "005282" },
+    { "0b11010111110010001111", "883855" },
+    { " 0b11001010010100001", "103585" },
+    { "-0b101010110011101111", "-175343" },
+    { "0b 1111111011011100110", "521958" },
+    { "0b1 1111110111001000011", "1044035" },
+    { " 0x53dfc", "343548" },
+    { "0xfA019", "1024025" },
+    { "0x 642d1", "410321" },
+    { "0x5 8067", "360551" },
+    { "-0xd6Be6", "-879590" },
+    { "\t0B1110000100000000011", "460803" },
+    { "0B\t1111110010010100101", "517285" },
+    { "0B1\t010111101101110100", "359284" },
+    { "-0B101\t1001101111111001", "-367609" },
+    { "0B10001001010111110000", "562672" },
+    { "0Xe4B7e", "936830" },
+    { "0X1E4bf", "124095" },
+    { "-0Xfdb90", "-1039248" },
+    { "0X7fc47", "523335" },
+    { "0X8167c", "530044" },
+    /* Some invalid inputs */
+    { "", NULL },
+    { "0x", NULL },
+    { "0b", NULL },
+    { "0z", NULL },
+    { "-", NULL },
+    { "-0x ", NULL },
+    { "0|1", NULL },
+    { "4+4", NULL },
+    { "0ab", NULL },
+    { "10x0", NULL },
+    { "0xxab", NULL },
+    { "ab", NULL },
+    { "0%#", NULL },
+    { "$foo", NULL },
+    { NULL, NULL }
+  };
+  unsigned i;
+  mpz_t a, b;
+  mpz_init (b);
+
+  for (i = 0; data[i].input; i++)
+    {
+      int res = mpz_init_set_str (a, data[i].input, 0);
+      if (data[i].decimal)
+	{
+	  if (res != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str returned -1, input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (mpz_set_str (b, data[i].decimal, 10) != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str returned -1, decimal input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (mpz_cmp (a, b) != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str failed for input: %s\n",
+		       data[i].input);
+
+	      dump ("got", a);
+	      dump ("ref", b);
+	      abort ();
+	    }
+	}
+      else if (res != -1)
+	{
+	  fprintf (stderr, "mpz_set_str returned %d, invalid input: %s\n",
+		   res, data[i].input);
+	  abort ();
+	}
+      mpz_clear (a);
+    }
+
+  mpz_clear (b);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  char *ap;
+  char *bp;
+  char *rp;
+  size_t bn, rn, arn;
+
+  mpz_t a, b;
+
+  FILE *tmp;
+
+  test_small ();
+
+  mpz_init (a);
+  mpz_init (b);
+
+  tmp = tmpfile ();
+  if (!tmp)
+    fprintf (stderr,
+	     "Failed to create temporary file. Skipping mpz_out_str tests.\n");
+
+  for (i = 0; i < COUNT; i++)
+    {
+      int base;
+      for (base = 0; base <= 62; base += 1 + (base == 0))
+	{
+	  hex_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp);
+	  if (mpz_set_str (a, ap, 16) != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str failed on input %s\n", ap);
+	      abort ();
+	    }
+
+	  rn = strlen (rp);
+	  arn = rn - (rp[0] == '-');
+
+	  bn = mpz_sizeinbase (a, base ? base : 10);
+	  if (bn < arn || bn > (arn + 1))
+	    {
+	      fprintf (stderr, "mpz_sizeinbase failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "r = %s\n", rp);
+	      fprintf (stderr, "  base %d, correct size %u, got %u\n",
+		       base, (unsigned) arn, (unsigned)bn);
+	      abort ();
+	    }
+	  bp = mpz_get_str (NULL, (i&1 || base > 36) ? base: -base, a);
+	  if (strcmp (bp, rp))
+	    {
+	      fprintf (stderr, "mpz_get_str failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "b = %s\n", bp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", rp);
+	      abort ();
+	    }
+
+	  /* Just a few tests with file i/o. */
+	  if (tmp && i < 20)
+	    {
+	      size_t tn;
+	      rewind (tmp);
+	      tn = mpz_out_str (tmp, (i&1 || base > 36) ? base: -base, a);
+	      if (tn != rn)
+		{
+		  fprintf (stderr, "mpz_out_str, bad return value:\n");
+		  dump ("a", a);
+		  fprintf (stderr, "r = %s\n", rp);
+		  fprintf (stderr, "  base %d, correct size %u, got %u\n",
+			   base, (unsigned) rn, (unsigned)tn);
+		  abort ();
+		}
+	      rewind (tmp);
+	      memset (bp, 0, rn);
+	      tn = fread (bp, 1, rn, tmp);
+	      if (tn != rn)
+		{
+		  fprintf (stderr,
+			   "fread failed, expected %lu bytes, got only %lu.\n",
+			   (unsigned long) rn, (unsigned long) tn);
+		  abort ();
+		}
+
+	      if (memcmp (bp, rp, rn) != 0)
+		{
+		  fprintf (stderr, "mpz_out_str failed:\n");
+		  dump ("a", a);
+		  fprintf (stderr, "b = %s\n", bp);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", rp);
+		  abort ();
+		}
+	    }
+
+	  mpz_set_str (b, rp, base);
+
+	  if (mpz_cmp (a, b))
+	    {
+	      fprintf (stderr, "mpz_set_str failed:\n");
+	      fprintf (stderr, "r = %s\n", rp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", ap);
+	      fprintf (stderr, "  base = 16\n");
+	      dump ("b", b);
+	      dump ("r", a);
+	      abort ();
+	    }
+
+	  /* Test mpn interface */
+	  if (base && mpz_sgn (a))
+	    {
+	      size_t i;
+	      const char *absr;
+	      mp_limb_t t[MAXLIMBS];
+	      size_t tn = mpz_size (a);
+
+	      assert (tn <= MAXLIMBS);
+	      mpn_copyi (t, a->_mp_d, tn);
+
+	      bn = mpn_get_str ((unsigned char *) bp, base, t, tn);
+	      if (bn != arn)
+		{
+		  fprintf (stderr, "mpn_get_str failed:\n");
+		  fprintf (stderr, "returned length: %lu (bad)\n", (unsigned long) bn);
+		  fprintf (stderr, "expected: %lu\n", (unsigned long) arn);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", ap);
+		  fprintf (stderr, "  base = 16\n");
+		  dump ("b", b);
+		  dump ("r", a);
+		  abort ();
+		}
+	      absr = rp + (rp[0] == '-');
+
+	      for (i = 0; i < bn; i++)
+		{
+		  unsigned char digit = absr[i];
+		  char value;
+		  if (digit >= '0' && digit <= '9')
+		    value = digit - '0';
+		  else if (digit >= 'a' && digit <= 'z')
+		    value = digit - 'a' + ((base > 36) ? 36 : 10);
+		  else if (digit >= 'A' && digit <= 'Z')
+		    value = digit - 'A' + 10;
+		  else
+		    {
+		      fprintf (stderr, "Internal error in test.\n");
+		      abort();
+		    }
+		  if (bp[i] != value)
+		    {
+		      fprintf (stderr, "mpn_get_str failed:\n");
+		      fprintf (stderr, "digit %lu: %d (bad)\n", (unsigned long) i, bp[i]);
+		      fprintf (stderr, "expected: %d\n", value);
+		      fprintf (stderr, "  base = %d\n", base);
+		      fprintf (stderr, "r = %s\n", ap);
+		      fprintf (stderr, "  base = 16\n");
+		      dump ("b", b);
+		      dump ("r", a);
+		      abort ();
+		    }
+		}
+	      tn = mpn_set_str (t, (unsigned char *) bp, bn, base);
+	      if (tn != mpz_size (a) || mpn_cmp (t, a->_mp_d, tn))
+		{
+		  fprintf (stderr, "mpn_set_str failed:\n");
+		  fprintf (stderr, "r = %s\n", rp);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", ap);
+		  fprintf (stderr, "  base = 16\n");
+		  dump ("r", a);
+		  abort ();
+		}
+	    }
+	  free (ap);
+	  free (rp);
+	  testfree (bp);
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-sub.c b/third_party/gmp/mini-gmp/tests/t-sub.c
new file mode 100644
index 0000000..e230fda
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-sub.c
@@ -0,0 +1,71 @@
+/*
+
+Copyright 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, res_ui, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (res_ui);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_SUB, MAXBITS, a, b, ref);
+      mpz_sub (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_sub failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_fits_ulong_p (a)) {
+	mpz_ui_sub (res_ui, mpz_get_ui (a), b);
+	if (mpz_cmp (res_ui, ref))
+	  {
+	    fprintf (stderr, "mpz_ui_sub failed:\n");
+	    dump ("a", a);
+	    dump ("b", b);
+	    dump ("r", res_ui);
+	    dump ("ref", ref);
+	    abort ();
+	  }
+      }
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (res_ui);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/testutils.c b/third_party/gmp/mini-gmp/tests/testutils.c
new file mode 100644
index 0000000..b131a9e
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/testutils.c
@@ -0,0 +1,181 @@
+/*
+
+Copyright 2013-2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "testutils.h"
+
+/* Include it here, so we we could tweak, e.g., how MPZ_REALLOC
+   works. */
+#include "../mini-gmp.c"
+#include "../mini-mpq.c"
+
+static size_t total_alloc = 0;
+
+/* Custom memory allocation to track memory usage, and add a small red
+   zone.
+
+   About alignment: In general, getting a block from malloc, and
+   incrementing it by sizeof(size_t), like we do here, might give a
+   pointer which is not properly aligned for all types. But the
+   largest type we allocate space for is unsigned long (mp_limb_t),
+   which shouldn't have stricter alignment requirements than
+   size_t. */
+
+static unsigned char block_end[8] =
+  { 0x7c, 0x37, 0xd6, 0x12, 0xa8, 0x6c, 0x01, 0xd1 };
+
+static void *
+block_init (size_t *block, size_t size)
+{
+  char *p;
+  *block++ = size;
+
+  p = (char *) block;
+  memcpy (p + size, block_end, sizeof(block_end));
+
+  total_alloc += size;
+  return p;
+}
+
+/* Check small redzone, return pointer to malloced block. */
+static size_t *
+block_check  (void *p)
+{
+  size_t *block = (size_t *) p - 1;
+  size_t size = block[0];
+
+  if (memcmp ((char *)p + size, block_end, sizeof(block_end)) != 0)
+    {
+      fprintf (stderr, "red zone overwritten.\n");
+      abort ();
+    }
+  total_alloc -= size;
+  return block;
+}
+
+static void *
+tu_alloc (size_t size)
+{
+  size_t *block = (size_t *) malloc (sizeof(size_t) + size + sizeof(block_end));
+  if (!block)
+    {
+      fprintf (stderr, "Virtual memory exhausted.\n");
+      abort ();
+    }
+
+  return block_init (block, size);
+}
+
+static void *
+tu_realloc (void *p, size_t old_size, size_t new_size)
+{
+  size_t *block = block_check (p);
+  block = (size_t *) realloc (block, sizeof(size_t) + new_size + sizeof(block_end));
+  if (!block)
+    {
+      fprintf (stderr, "Virtual memory exhausted.\n");
+      abort ();
+    }
+
+  return block_init (block, new_size);
+}
+
+static void
+tu_free (void *p, size_t old_size)
+{
+  free (block_check (p));
+}
+
+/* Free memory allocated via mini-gmp allocation function. */
+void
+testfree (void *p)
+{
+  void (*freefunc) (void *, size_t);
+  mp_get_memory_functions (NULL, NULL, &freefunc);
+
+  freefunc (p, 0);
+}
+
+int
+main (int argc, char **argv)
+{
+  hex_random_init ();
+
+  mp_set_memory_functions (tu_alloc, tu_realloc, tu_free);
+
+  /* Currently, t-comb seems to be the only program accepting any
+     arguments. It might make sense to parse common arguments here. */
+  testmain (argc, argv);
+
+  if (total_alloc != 0)
+    {
+      fprintf (stderr, "Memory leaked: %lu bytes.\n",
+	       (unsigned long) total_alloc);
+      abort ();
+    }
+  return 0;
+}
+
+void
+testhalves (int count, void (*tested_fun) (int))
+{
+  void (*freefunc) (void *, size_t);
+  void *(*reallocfunc) (void *, size_t, size_t);
+  void *(*allocfunc) (size_t);
+  size_t initial_alloc;
+
+  mp_get_memory_functions (&allocfunc, &reallocfunc, &freefunc);
+  initial_alloc = total_alloc;
+  (*tested_fun) (count / 2);
+  if (initial_alloc != total_alloc)
+    {
+      fprintf (stderr, "First half, memory leaked: %lu bytes.\n",
+	       (unsigned long) total_alloc - initial_alloc);
+      abort ();
+    }
+  mp_set_memory_functions (NULL, NULL, NULL);
+  (*tested_fun) (count / 2);
+  mp_set_memory_functions (allocfunc, reallocfunc, freefunc);
+}
+
+void
+dump (const char *label, const mpz_t x)
+{
+  char *buf = mpz_get_str (NULL, 16, x);
+  fprintf (stderr, "%s: %s\n", label, buf);
+  testfree (buf);
+}
+
+void
+mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
+{
+  if (mpz_set_str (z, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR: mpz_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+int
+mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q,
+	       mp_bitcnt_t b0, const mpz_t n)
+{
+  return gmp_lucas_mod (V, Qk, Q, b0, n);
+}
diff --git a/third_party/gmp/mini-gmp/tests/testutils.h b/third_party/gmp/mini-gmp/tests/testutils.h
new file mode 100644
index 0000000..e565ac3
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/testutils.h
@@ -0,0 +1,42 @@
+/*
+
+Copyright 2013, 2014, 2018, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite 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 General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mini-random.h"
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+void testmain (int argc, char **argv);
+
+void testhalves (int count, void (*tested_fun) (int));
+
+void testfree (void *p);
+
+void
+dump (const char *label, const mpz_t x);
+
+void
+mpz_set_str_or_abort (mpz_ptr z, const char *str, int base);
+
+/* Prototype for wrappers to internal functions to be tested. */
+int
+mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q,
+	       mp_bitcnt_t b0, const mpz_t n);