|
@@ -0,0 +1,175 @@
|
|
|
|
+#define _GNU_SOURCE
|
|
|
|
+#include <assert.h>
|
|
|
|
+#include <limits.h>
|
|
|
|
+#include <stdbool.h>
|
|
|
|
+#include <stdio.h>
|
|
|
|
+#include <stdint.h>
|
|
|
|
+#include <unistd.h>
|
|
|
|
+#include <linux/random.h>
|
|
|
|
+#include <sys/syscall.h>
|
|
|
|
+#include <sys/time.h>
|
|
|
|
+
|
|
|
|
+#include <gmp.h>
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#define INIT_TIMEIT() \
|
|
|
|
+ struct timeval __start, __end; \
|
|
|
|
+ double __sdiff = 0, __udiff = 0
|
|
|
|
+
|
|
|
|
+#define START_TIMEIT() \
|
|
|
|
+ gettimeofday(&__start, NULL)
|
|
|
|
+
|
|
|
|
+#define END_TIMEIT() \
|
|
|
|
+ gettimeofday(&__end, NULL); \
|
|
|
|
+ __sdiff += (__end.tv_sec - __start.tv_sec); \
|
|
|
|
+ __udiff += (__end.tv_usec - __start.tv_usec)
|
|
|
|
+
|
|
|
|
+#define GET_TIMEIT() \
|
|
|
|
+ __sdiff + __udiff * 1e-6
|
|
|
|
+
|
|
|
|
+#define TIMEIT_FORMAT "%lf"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * p is our prime modulus, and is 2^n - g
|
|
|
|
+ * where g is referred to as "gamma" (built-in function in C, so transliterated)
|
|
|
|
+ */
|
|
|
|
+const static char* p_str =
|
|
|
|
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
|
|
+ "505CAF";
|
|
|
|
+const static char* g_str =
|
|
|
|
+ "11510609";
|
|
|
|
+
|
|
|
|
+mpz_t p, g;
|
|
|
|
+uint32_t gg = 11510609;
|
|
|
|
+
|
|
|
|
+static inline ssize_t
|
|
|
|
+getrandom(void *buffer, size_t length, unsigned int flags)
|
|
|
|
+{
|
|
|
|
+ return syscall(SYS_getrandom, buffer, length, flags);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+uint32_t convert(mpz_t n)
|
|
|
|
+{
|
|
|
|
+ uint32_t steps = 0;
|
|
|
|
+ size_t i = 0;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Here we start making a bunch of assumptions.
|
|
|
|
+ * First, we assume the "w" here is 64 bits, which should be the size
|
|
|
|
+ * (in bits) of a mp_limb_t.
|
|
|
|
+ * Secondly, the amount of zeros to check, "d" here is 8.
|
|
|
|
+ */
|
|
|
|
+ assert(sizeof(mp_limb_t) == 8);
|
|
|
|
+ assert(n->_mp_size == 24);
|
|
|
|
+#define mp_size 24
|
|
|
|
+
|
|
|
|
+ uint64_t * restrict nn = n->_mp_d;
|
|
|
|
+
|
|
|
|
+#define distinguished(x) ((x[23] & (ULLONG_MAX << (64-8))) == 0)
|
|
|
|
+
|
|
|
|
+ while (!distinguished(nn)) {
|
|
|
|
+ for (i = 0; i < 64; i+=4) {
|
|
|
|
+ if (((nn[23] | nn[22]) & (0x0F << i)) != 0) break;
|
|
|
|
+ }
|
|
|
|
+ if (i == 64) {
|
|
|
|
+ /**
|
|
|
|
+ * We found no distinguished point for the next 64 steps.
|
|
|
|
+ * Boost it!
|
|
|
|
+ */
|
|
|
|
+ const __int128_t a = nn[23] * gg;
|
|
|
|
+ mpn_lshift(nn, nn, 64, 0);
|
|
|
|
+ mpn_add_n(nn, nn, (mp_limb_t *) &a, 24); // YOLO
|
|
|
|
+ steps += 64;
|
|
|
|
+ } else {
|
|
|
|
+ for (; i < 64; i+=4) {
|
|
|
|
+ if ((nn[23] & (0x0F << i)) != 0) break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (i == 64) {
|
|
|
|
+ /**
|
|
|
|
+ * We found no distinguished point for the next 32 steps.
|
|
|
|
+ * Boost it!
|
|
|
|
+ */
|
|
|
|
+ const uint64_t a = nn[23] >> 32 * gg;
|
|
|
|
+ mpn_lshift(nn, nn, 32, 0);
|
|
|
|
+ mpn_add_1(nn, nn, 24, a);
|
|
|
|
+ steps += 32;
|
|
|
|
+ } else if (i >= 32) {
|
|
|
|
+ /**
|
|
|
|
+ * We found no distinguished point for the next 16 steps.
|
|
|
|
+ * Boost it!
|
|
|
|
+ */
|
|
|
|
+ const uint64_t a = (nn[23] & (ULLONG_MAX << 32)) * gg;
|
|
|
|
+ mpn_lshift(nn, nn, 16, 0);
|
|
|
|
+ mpn_add_1(nn, nn, 24, a);
|
|
|
|
+ steps += 16;
|
|
|
|
+ } else {
|
|
|
|
+ /**
|
|
|
|
+ * If there is nothing else to do, then just multiply by two.
|
|
|
|
+ */
|
|
|
|
+ if (mpn_lshift(nn, nn, 24, 1)) {
|
|
|
|
+ mpn_add_1(nn, nn, 24, gg);
|
|
|
|
+ }
|
|
|
|
+ steps++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return steps;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+uint32_t naif_convert(mpz_t n)
|
|
|
|
+{
|
|
|
|
+ uint32_t i;
|
|
|
|
+ mpz_t t;
|
|
|
|
+ mpz_init_set_ui(t, 1);
|
|
|
|
+ mpz_mul_2exp(t, t, 1536-8);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for (i = 0; mpz_cmp(n, t) > -1; i++) {
|
|
|
|
+ mpz_mul_2exp(n, n, 1);
|
|
|
|
+ mpz_mod(n, n, p);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mpz_clear(t);
|
|
|
|
+ return i;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int main()
|
|
|
|
+{
|
|
|
|
+ mpz_init_set_str(p, p_str, 0);
|
|
|
|
+ mpz_init_set_str(g, g_str, 10);
|
|
|
|
+
|
|
|
|
+ gmp_randstate_t _rstate;
|
|
|
|
+ unsigned long int _rseed;
|
|
|
|
+
|
|
|
|
+ gmp_randinit_default(_rstate);
|
|
|
|
+ getrandom(&_rseed, sizeof(unsigned long int), GRND_RANDOM);
|
|
|
|
+ gmp_randseed_ui(_rstate, _rseed);
|
|
|
|
+
|
|
|
|
+ mpz_t n, n0;
|
|
|
|
+ mpz_inits(n, n0, NULL);
|
|
|
|
+
|
|
|
|
+ INIT_TIMEIT();
|
|
|
|
+ uint32_t converted;
|
|
|
|
+ for (int i=0; i < 1e4; i++) {
|
|
|
|
+ mpz_urandomm(n0, _rstate, p);
|
|
|
|
+ mpz_set(n, n0);
|
|
|
|
+ START_TIMEIT();
|
|
|
|
+ converted = convert(n);
|
|
|
|
+ END_TIMEIT();
|
|
|
|
+ mpz_set(n, n0);
|
|
|
|
+ assert(converted == naif_convert(n));
|
|
|
|
+ }
|
|
|
|
+ printf(TIMEIT_FORMAT "\n", GET_TIMEIT());
|
|
|
|
+
|
|
|
|
+ mpz_clears(n, n0, p, g, NULL);
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+}
|