dosyago / floppsy

:baby_chick: floppsy - SMHasher-passing 200Mb/s hash using floating-point ops
https://88e9g.csb.app/
MIT License
12 stars 3 forks source link
continued-fractions cryptography cryptohash egyptian-fractions floating-point hashing hashing-algorithm slow smhasher tiny

:baby_chick: floppsy

200MB/s SMHasher version npm downloads

A tiny, simple and SMHasher-passing slow (200Mb/s) hash designed for floating point hardware. It's also non-deterministic (different values depend on architecture, due to quirks and differences in floating point implementations).

Link to the SUPERCOP ECRYPT benchmark for floppsy

demo

play with a demo online here

construction

constructed using floating point multiplication, division and addition.

based on continued and egyptian fractions.

no bit operations used in the making of this hash.

accolades

passes smhasher

see the results for all tests

also see an independent confirmation of these results

c source

FORCE_INLINE void q ( double * state, double key_val, 
         double numerator, double denominator )
{
  state[0] += numerator / denominator;
  state[0] = 1.0 / state[0];

  state[1] += key_val + M_PI;
  state[1] = numerator / state[1];
}

//---------
// round function : process the message 

FORCE_INLINE void round ( const uint8_t * msg, long len, 
            double * state ) 
{
  double numerator = 1.0;

  // Loop
  for( long i = 0; i < len; i++ ) {
    double val = (double)msg[i];
    double denominator = (M_E * val + i + 1) / state[1];

    q( state, val, numerator, denominator );

    numerator = denominator + 1;
  }
}

//---------
// setup function : setup the state

FORCE_INLINE void setup ( double * state, double init = 0 ) 
{
  state[0] += init != 0 ? pow(init + 1.0/init, 1.0/3) : 3.0;
  state[1] += init != 0 ? pow(init + 1.0/init, 1.0/7) : 1.0/7;
}

//---------
// floppsyhash
// with 64 bit continued egyptian fractions

void floppsyhash_64 ( const void * key, int len,
                   uint32_t seed, void * out )
{
  const uint8_t * data = (const uint8_t *)key;
  uint8_t buf [16];
  double * state = (double*)buf;
  uint32_t * state32 = (uint32_t*)buf;
  double seed32 = (double)seed;

  uint8_t * seedbuf;
  seedbuf = (uint8_t *)&seed;

  setup( state, seed32 );
  round( seedbuf, 4, state );
  round( data, len, state );

  uint8_t output [8];
  uint32_t * h = (uint32_t*)output;

  h[0] = state32[0] + state32[3];
  h[1] = state32[1] + state32[2];

  ((uint32_t*)out)[0] = h[0];
  ((uint32_t*)out)[1] = h[1];
} 

disclaimer

no claims are made regarding the security of this system.

get

npm i --save floppsy

use-cases

include

As a Node ES module:

import floppsy from 'floppsy';

As old style modules:

const floppsy = require('floppsy').default;

Using Snowpack in a web app:

import floppsy from './web_modules/floppsy.js';

api

Can produce digests of 32, 64 or 128 bits.

> f.hash('')
'7f5f8491f0b745bf'
> f.hash('', {bits:32})
'7016ca50'
> f.hash('', {bits:128})
'3f7f508e3fe034033ff0e269b0c66356'

Can also change output format:

  x.hash('',{out_format:'hex'}); // default
  x.hash('',{out_format:'binary'}); // binary string
  x.hash('',{out_format:'bytes'}); // Uint8Array
  x.hash('',{out_format:'uint32s'}); // Uint32Array

play with a demo online here