Merge pull request #505 from urazoff/develop Add FNV-1a hash function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
diff --git a/demo/test.c b/demo/test.c
index b9ef509..c87f97c 100644
--- a/demo/test.c
+++ b/demo/test.c
@@ -153,6 +153,56 @@ LBL_ERR:
return EXIT_FAILURE;
}
+static int test_mp_hash(void)
+{
+ mp_int a;
+ mp_hval hash;
+ int i;
+ int len = 5;
+
+ const char *input[] = {
+ "0",
+ "///////////////////////////////////////////////////////////////////",
+ "4n9cbk886QtLQmofprid3l2Q0GD8Yv979Lh8BdZkFE8g2pDUUSMBET/+M/YFyVZ3mBp",
+ "5NlgzHhmIX05O5YoW5yW5reAlVNtRAlIcN2dfoATnNdc1Cw5lHZUTwNthmK6/ZLKfY6",
+ "3gweiHDX+ji5utraSe46IJX+uuh7iggs63xIpMP5MriU4Np+LpHI5are8RzS9pKh9xP"
+ };
+ const mp_hval hvals[] = {
+#if (MP_DIGIT_BIT == 15)
+ 0x50c5d1f,
+ 0x51b3ba04,
+ 0xf83febd7,
+ 0x2dc8624c,
+ 0xf5c2996b
+#elif (MP_DIGIT_BIT == 60)
+ 0xaf63bd4c8601b7df,
+ 0xdb090f8a5cd75210,
+ 0xabae35c7872c107d,
+ 0xfec74888bcef5fcd,
+ 0x27ba96030abceda5
+#else
+ 0xaf63bd4c8601b7df,
+ 0x7e868fbf541faf44,
+ 0x420cca3a4cb623bb,
+ 0x16636d996304ee7f,
+ 0x33afc9f1b274fa67
+#endif
+ };
+
+ DOR(mp_init(&a));
+ for (i = 0; i < len; ++i) {
+ DO(mp_read_radix(&a, input[i], 64));
+ DO(mp_hash(&a, &hash));
+ EXPECT(hash == hvals[i]);
+ }
+
+ mp_clear(&a);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear(&a);
+ return EXIT_FAILURE;
+}
+
static int check_get_set_i32(mp_int *a, int32_t b)
{
mp_clear(a);
@@ -2164,6 +2214,7 @@ static int unit_tests(int argc, char **argv)
#define T3(n, o1, o2, o3) { #n, (MP_HAS(o1) && MP_HAS(o2) && MP_HAS(o3)) ? test_##n : NULL }
T0(feature_detection),
T0(trivial_stuff),
+ T1(mp_hash, MP_HASH),
T2(mp_get_set_i32, MP_GET_I32, MP_GET_MAG_U32),
T2(mp_get_set_i64, MP_GET_I64, MP_GET_MAG_U64),
T1(mp_and, MP_AND),
diff --git a/doc/bn.tex b/doc/bn.tex
index 1dfb34d..3e01e32 100644
--- a/doc/bn.tex
+++ b/doc/bn.tex
@@ -1444,6 +1444,20 @@ This divides $a$ by $b$ and stores the quotient in $c$ and $d$. The signed quot
such that $bc + d = a$. Note that either of $c$ or $d$ can be set to \texttt{NULL} if their value
is not required. If $b$ is zero the function returns \texttt{MP\_VAL}.
+\section{Hashing}
+To get a non-cryptographic hash of an \texttt{mp\_int} use the following function.
+
+\index{mp\_hash}
+\begin{alltt}
+mp_err mp_hash (mp_int *a, mp_hval *hash);
+\end{alltt}
+
+This will create the hash of $a$ following the \mbox{FNV-1a} algorithm as described on
+\url{http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-1a}. With the
+help of this function one can use an \texttt{mp\_int} as a key in a hash table.
+
+NB: The hashing is not stable over different widths of an \texttt{mp\_digit}.
+
\chapter{Multiplication and Squaring}
\section{Multiplication}
A full signed integer multiplication can be performed with the following.
diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj
index 1bf2f6b..e27aa98 100644
--- a/libtommath_VS2008.vcproj
+++ b/libtommath_VS2008.vcproj
@@ -481,6 +481,10 @@
>
</File>
<File
+ RelativePath="mp_hash.c"
+ >
+ </File>
+ <File
RelativePath="mp_init.c"
>
</File>
diff --git a/makefile b/makefile
index a5e5bf1..7fa04d2 100644
--- a/makefile
+++ b/makefile
@@ -31,9 +31,9 @@ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count
mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \
mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \
mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \
-mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o mp_init_l.o \
-mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o mp_invmod.o \
-mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
+mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \
+mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \
+mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
diff --git a/makefile.mingw b/makefile.mingw
index a0192d6..7aeb564 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -33,9 +33,9 @@ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count
mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \
mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \
mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \
-mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o mp_init_l.o \
-mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o mp_invmod.o \
-mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
+mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \
+mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \
+mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
diff --git a/makefile.msvc b/makefile.msvc
index df886e9..59a365e 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -29,9 +29,9 @@ mp_cmp.obj mp_cmp_d.obj mp_cmp_mag.obj mp_cnt_lsb.obj mp_complement.obj mp_copy.
mp_div.obj mp_div_2.obj mp_div_2d.obj mp_div_d.obj mp_dr_is_modulus.obj mp_dr_reduce.obj mp_dr_setup.obj \
mp_error_to_string.obj mp_exch.obj mp_expt_n.obj mp_exptmod.obj mp_exteuclid.obj mp_fread.obj mp_from_sbin.obj \
mp_from_ubin.obj mp_fwrite.obj mp_gcd.obj mp_get_double.obj mp_get_i32.obj mp_get_i64.obj mp_get_l.obj mp_get_mag_u32.obj \
-mp_get_mag_u64.obj mp_get_mag_ul.obj mp_grow.obj mp_init.obj mp_init_copy.obj mp_init_i32.obj mp_init_i64.obj mp_init_l.obj \
-mp_init_multi.obj mp_init_set.obj mp_init_size.obj mp_init_u32.obj mp_init_u64.obj mp_init_ul.obj mp_invmod.obj \
-mp_is_square.obj mp_kronecker.obj mp_lcm.obj mp_log_n.obj mp_lshd.obj mp_mod.obj mp_mod_2d.obj \
+mp_get_mag_u64.obj mp_get_mag_ul.obj mp_grow.obj mp_hash.obj mp_init.obj mp_init_copy.obj mp_init_i32.obj mp_init_i64.obj \
+mp_init_l.obj mp_init_multi.obj mp_init_set.obj mp_init_size.obj mp_init_u32.obj mp_init_u64.obj mp_init_ul.obj \
+mp_invmod.obj mp_is_square.obj mp_kronecker.obj mp_lcm.obj mp_log_n.obj mp_lshd.obj mp_mod.obj mp_mod_2d.obj \
mp_montgomery_calc_normalization.obj mp_montgomery_reduce.obj mp_montgomery_setup.obj mp_mul.obj mp_mul_2.obj \
mp_mul_2d.obj mp_mul_d.obj mp_mulmod.obj mp_neg.obj mp_or.obj mp_pack.obj mp_pack_count.obj mp_prime_fermat.obj \
mp_prime_frobenius_underwood.obj mp_prime_is_prime.obj mp_prime_miller_rabin.obj mp_prime_next_prime.obj \
diff --git a/makefile.shared b/makefile.shared
index 9319e65..41a0cd2 100644
--- a/makefile.shared
+++ b/makefile.shared
@@ -28,9 +28,9 @@ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count
mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \
mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \
mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \
-mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o mp_init_l.o \
-mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o mp_invmod.o \
-mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
+mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \
+mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \
+mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
diff --git a/makefile.unix b/makefile.unix
index 64fb580..be04674 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -34,9 +34,9 @@ mp_cmp.o mp_cmp_d.o mp_cmp_mag.o mp_cnt_lsb.o mp_complement.o mp_copy.o mp_count
mp_div.o mp_div_2.o mp_div_2d.o mp_div_d.o mp_dr_is_modulus.o mp_dr_reduce.o mp_dr_setup.o \
mp_error_to_string.o mp_exch.o mp_expt_n.o mp_exptmod.o mp_exteuclid.o mp_fread.o mp_from_sbin.o \
mp_from_ubin.o mp_fwrite.o mp_gcd.o mp_get_double.o mp_get_i32.o mp_get_i64.o mp_get_l.o mp_get_mag_u32.o \
-mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o mp_init_l.o \
-mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o mp_invmod.o \
-mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
+mp_get_mag_u64.o mp_get_mag_ul.o mp_grow.o mp_hash.o mp_init.o mp_init_copy.o mp_init_i32.o mp_init_i64.o \
+mp_init_l.o mp_init_multi.o mp_init_set.o mp_init_size.o mp_init_u32.o mp_init_u64.o mp_init_ul.o \
+mp_invmod.o mp_is_square.o mp_kronecker.o mp_lcm.o mp_log_n.o mp_lshd.o mp_mod.o mp_mod_2d.o \
mp_montgomery_calc_normalization.o mp_montgomery_reduce.o mp_montgomery_setup.o mp_mul.o mp_mul_2.o \
mp_mul_2d.o mp_mul_d.o mp_mulmod.o mp_neg.o mp_or.o mp_pack.o mp_pack_count.o mp_prime_fermat.o \
mp_prime_frobenius_underwood.o mp_prime_is_prime.o mp_prime_miller_rabin.o mp_prime_next_prime.o \
diff --git a/mp_hash.c b/mp_hash.c
new file mode 100644
index 0000000..2add757
--- /dev/null
+++ b/mp_hash.c
@@ -0,0 +1,36 @@
+#include "tommath_private.h"
+#ifdef MP_HASH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#if defined(MP_16BIT)
+#define FNV_1A_INIT ((uint32_t)0x811c9dc5)
+#define FNV_1A_PRIME ((uint32_t)0x01000193)
+#else
+#define FNV_1A_INIT ((uint64_t)0xcbf29ce484222325ULL)
+#define FNV_1A_PRIME ((uint64_t)0x100000001b3ULL)
+#endif
+
+/* computes hash of mp_int. */
+mp_err mp_hash(mp_int *a, mp_hval *hash)
+{
+ int x;
+ mp_hval hval = FNV_1A_INIT;
+ mp_digit r, mask, shift;
+
+ /* FNV-1a algorithm */
+ mask = ((mp_digit)1 << 8) - 1uL;
+ shift = (mp_digit)(MP_DIGIT_BIT - 8);
+ r = 0;
+ for (x = a->used; x --> 0;) {
+ mp_digit rr = a->dp[x] & mask;
+ hval ^= (mp_hval)(a->dp[x] >> 8) | (r << shift);
+ hval *= FNV_1A_PRIME;
+ r = rr;
+ }
+ hval ^= mp_isneg(a) ? (mp_hval)1 : (mp_hval)0;
+ *hash = hval * FNV_1A_PRIME;
+
+ return MP_OKAY;
+}
+#endif
diff --git a/tommath.def b/tommath.def
index f0a9703..1af4e9e 100644
--- a/tommath.def
+++ b/tommath.def
@@ -47,6 +47,7 @@ EXPORTS
mp_get_mag_u64
mp_get_mag_ul
mp_grow
+ mp_hash
mp_init
mp_init_copy
mp_init_i32
diff --git a/tommath.h b/tommath.h
index 25a166e..44c92b2 100644
--- a/tommath.h
+++ b/tommath.h
@@ -488,6 +488,15 @@ mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) MP_WUR;
/* Y = G**X (mod P) */
mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) MP_WUR;
+#if defined(MP_16BIT)
+typedef uint32_t mp_hval;
+#else
+typedef uint64_t mp_hval;
+#endif
+
+/* computes hash */
+mp_err mp_hash(mp_int *a, mp_hval *hash) MP_WUR;
+
/* ---> Primes <--- */
/* performs one Fermat test of "a" using base "b".
diff --git a/tommath_class.h b/tommath_class.h
index da9c5ea..becbcb1 100644
--- a/tommath_class.h
+++ b/tommath_class.h
@@ -53,6 +53,7 @@
# define MP_GET_MAG_U64_C
# define MP_GET_MAG_UL_C
# define MP_GROW_C
+# define MP_HASH_C
# define MP_INIT_C
# define MP_INIT_COPY_C
# define MP_INIT_I32_C
@@ -386,6 +387,9 @@
# define S_MP_ZERO_DIGS_C
#endif
+#if defined(MP_HASH_C)
+#endif
+
#if defined(MP_INIT_C)
#endif