Generate a (very) large non-repeating integer sequence without prior shuffling

Background

I have a simple media client / server that I wrote, and I want to create a non-obvious time value that I send with each command from the client to the server. Timestamps will have a fair bit of data in them (nano-second resolution, even if it is not really accurate, due to timer sampling restrictions in modern operating systems), etc.

What I'm trying to do (on Linux, on C) is to generate a one-to-one sequence of n-bit values ​​(let it be assumed that the data is stored in 128-bit elements from an int array) without overlapping / colliding values. Then I took the 128-bit / number pseudo-random value as the “salt”, applied it to the timestamp, and then started sending commands to the server, increasing the pre-salted / pre-hashed value.

The reason the timestamp is so large is because the timestamp may take a very long time.


Question

How could I execute such a sequence (without colliding) with the initial salt value? The best approach that sounds in line with my goal is from this post, which notes :

If option 1 is not random enough for you, use the CRC-32 hash of the specified global (32-bit) counter. There is a 1-to-1 mapping (bijection) between N-bit integers and their uniqueness CRC-N will continue to be guaranteed.

However, I do not know:

  • If it can be (effectively) expanded to 128-bit data.
  • If any addition to / multiplying by the value of the salt, in order to provide an initial seed for the sequence, would break it or introduce collisions.

Subsequent

, 128- libssl - , , .

.

+4
3

. [] (.. ).

, random(3) TYPE_0. unsigned int, unsigned int (. ).

, 64 128 . https://en.wikipedia.org/wiki/Linear_congruential_generator, .

wiki, , 128- , 128- .

, "" . .

, .


- , , - :

// _prngstd -- get random number
static inline u32
_prngstd(prng_p prng)
{
    long rhs;
    u32 lhs;

    // NOTE: random is faster and has a _long_ period, but it _only_ produces
    // positive integers but jrand48 produces positive _and_ negative
#if 0
    rhs = jrand48(btc->btc_seed);
    lhs = rhs;
#endif

    // this has collisions
#if 0
    rhs = rand();
    PRNG_FLIP;
#endif

    // this has collisions because it defaults to TYPE_3
#if 0
    rhs = random();
    PRNG_FLIP;
#endif

    // this is random in TYPE_0 (linear congruential) mode
#if 0
    prng->prng_state = ((prng->prng_state * 1103515245) + 12345) & 0x7fffffff;
    rhs = prng->prng_state;
    PRNG_FLIP;
#endif

    // this is random in TYPE_0 (linear congruential) mode with the mask
    // removed to get full range numbers
    // this does _not_ produce overlaps
#if 1
    prng->prng_state = ((prng->prng_state * 1103515245) + 12345);
    rhs = prng->prng_state;
    lhs = rhs;
#endif

    return lhs;
}
+3

- . 128- AES 128- . , .

- , .

, -, , , , ECB, . ECB , , , , .

128 , , . , , . ( ) .

, .

+3

- , .

128- , (, __int128 GCC 64- ) , , SplitMix64. :

uint128_t mix(uint128_t x) {
    uint128_t m0 = (uint128_t)0xecfb1b9bc1f0564f << 64
                 | 0xc68dd22b9302d18d;
    uint128_t m1 = (uint128_t)0x4a4cf0348b717188 << 64
                 | 0xe2aead7d60f8a0df;
    x ^= x >> 59;
    x *= m0;
    x ^= x >> 60;
    x *= m1;
    x ^= x >> 84;
    return x;
}

:

uint128_t unmix(uint128_t x) {
    uint128_t im0 = (uint128_t)0x367ce11aef44b547 << 64
                  | 0x424b0c012b51d945;
    uint128_t im1 = (uint128_t)0xef0323293e8f059d << 64
                  | 0x351690f213b31b1f;
    x ^= x >> 84;
    x *= im1;
    x ^= x >> 60 ^ x >> (2 * 60);
    x *= im0;
    x ^= x >> 59 ^ x >> (2 * 59);
    return x;
}

, ( , , , ), :

uint128_t encode(uint128_t time, uint128_t salt) {
    return mix((time + 1) * salt);
}

uint128_t generate(uint128_t salt) {
    static uint128_t t = 0;
    return encode(t++, salt);
}

static uint128_t inv(uint128_t d) {
    uint128_t i = d;

    while (i * d != 1) {
        i *= 2 - i * d;
    }
    return i;
}

uint128_t decode(uint128_t etime, uint128_t salt) {
    return unmix(etime) * inv(salt) - 1;
}

, salt 2 127 128- ( , salt ), (2 128)! , . , , , , - ( ) .

Obviously, it is uint128_tnot a standard type, so my answer is not C, but you can use either the bignumber library or the compiler extension to do arithmetic work. For clarity, I relied on a compiler extension. All operations are based on C-like unsigned overflow behavior (accept the least significant bits of an arbitrary precision result).

+1
source

Source: https://habr.com/ru/post/1648455/


All Articles