Skip to content

Cryptographic Hashing without Double limitation (Pull Request as issue) #489

Description

@Reptorian1125

I decided to implement a hashing method that bypass the inherent limitation of double-type for G'MIC by doing the following method: Treat double as unsigned long long, then do math operations within unsigned, then return the double modulo 16777216. Intended to work with G'MIC hash table irrespective of how big or small the number is. I'm doing a pull request this way because for some reason I see 14000+ difference within clone of mine, so I don't know how to fix that. Also, I don't really know what I'm doing, but so far tests do work, but I'll let you decide on the changes, and doing two seed leads to beautiful randomness.

            if (!std::strncmp(ss, "hash(", 5)) { // hash(value_or_vector [,seed1 [,seed2]])
                _cimg_mp_op("Function 'hash()'");
                s0 = ss + 5;
                s1 = s0;

                // First argument: the value or vector to hash.
                s1 = s0; while (s1 < se1 && (*s1 != ',' || level[s1 - expr._data] != clevel1)) ++s1;
                arg2 = compile(s0, s1, depth1, 0, block_flags);

                // Optional trailing seed1, seed2 (both scalars, both default to 0 if omitted).
                arg3 = ~0U; arg4 = ~0U;
                if (s1 < se1) {
                    s0 = ++s1; while (s0 < se1 && (*s0 != ',' || level[s0 - expr._data] != clevel1)) ++s0;
                    arg3 = compile(s1, s0, depth1, 0, block_flags);
                    _cimg_mp_check_type(arg3, 2, 1, 0);
                    if (s0 < se1) {
                        s1 = ++s0; while (s1 < se1 && (*s1 != ',' || level[s1 - expr._data] != clevel1)) ++s1;
                        arg4 = compile(s0, s1, depth1, 0, block_flags);
                        _cimg_mp_check_type(arg4, 3, 1, 0);
                    }
                }

                const unsigned int seed1 = arg3 == ~0U ? const_scalar(0) : arg3;
                const unsigned int seed2 = arg4 == ~0U ? const_scalar(0) : arg4;

                // Constant-folding: fold when the data (element-wise if a vector) and both seeds are constant.
                bool arg2_const = is_const_scalar(arg2);
                if (is_vector(arg2)) {
                    arg2_const = true;
                    for (unsigned int i = 1; i <= size(arg2) && arg2_const; ++i) arg2_const &= is_const_scalar(arg2 + i);
                }
                if (arg2_const && is_const_scalar(seed1) && is_const_scalar(seed2)) {
                    CImg<ulongT>::vector((ulongT)mp_hash, 0, arg2, size(arg2), seed1, seed2).move_to(opcode);
                    _cimg_mp_const_scalar(mp_hash(*this));
                }

                _cimg_mp_scalar4(hash, arg2, size(arg2), seed1, seed2);
            }
      static double mp_hash(_cimg_math_parser& mp) {
          unsigned int seed1_bits, seed2_bits, h, mult;
          unsigned long long bits64;

          std::memcpy(&bits64, &_mp_arg(4), sizeof(bits64)); // seed1 reg = opcode[4]
          seed1_bits = (unsigned int)(bits64 ^ (bits64 >> 32));
          std::memcpy(&bits64, &_mp_arg(5), sizeof(bits64)); // seed2 reg = opcode[5]
          seed2_bits = (unsigned int)(bits64 ^ (bits64 >> 32));

          mult = seed2_bits | 1U;
          h = 2166136261U ^ seed1_bits;

          const ulongT siz = (ulongT)mp.opcode[3]; // 0 = scalar, else vector length
          const double
              * const ptrb = siz ? &_mp_arg(2) + 1 : &_mp_arg(2), // vector data starts past the NaN sentinel
              * const ptre = ptrb + (siz ? siz : 1),
              * ptr = ptrb;

          while (ptr < ptre) {
              std::memcpy(&bits64, ptr++, sizeof(bits64));
              h = h * mult + (unsigned int)(bits64 & 0xFFFFFFFFU); // low 32 bits
              h = h * mult + (unsigned int)(bits64 >> 32);         // high 32 bits
          }

          // Avalanche finalizer (Murmur3 fmix32).
          h ^= h >> 16; h *= 0x85ebca6bU;
          h ^= h >> 13; h *= 0xc2b2ae35U;
          h ^= h >> 16;

          return (double)(h & 0xFFFFFFU);
      }

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions