Skip to content

Instantly share code, notes, and snippets.

@LiosK
Created September 26, 2021 06:31
Show Gist options
  • Save LiosK/af9ba49a7e20d10f8611c1b739b08f0f to your computer and use it in GitHub Desktop.
Save LiosK/af9ba49a7e20d10f8611c1b739b08f0f to your computer and use it in GitHub Desktop.
from datetime import datetime
from secrets import randbits
from typing import Tuple
# In general, the layered approach demonstrates much better collision resistance than
# the naive approach when the per-second randomness field is sufficiently large to
# accommodate a possible number of concurrent generators. Otherwise, the layered
# approach tends to cause burst collisions when the per-second randomness collides.
LEN_PER_SEC = 16
LEN_PER_GEN = 4
N_GENERATOR = 8
Element = Tuple[int, int]
class Generator:
def __init__(self) -> None:
self.ts_sec = 0
self.rand_sec = 0
def generate(self, ts_now: int) -> Tuple[Element, Element]:
if ts_now - self.ts_sec > 1000:
self.ts_sec = ts_now
self.rand_sec = randbits(LEN_PER_SEC)
per_gen = randbits(LEN_PER_GEN)
naive = (randbits(LEN_PER_SEC), per_gen)
layered = (self.rand_sec, per_gen)
return (naive, layered)
def main() -> None:
generators = [Generator() for _ in range(N_GENERATOR)]
n_col = 0
l_col = 0
while True:
# This emulates a situation where multiple generators generate IDs with the same
# timestamp and counter.
n_set = set()
l_set = set()
ts_now = int(datetime.now().timestamp() * 1000)
for g in generators:
(n, l) = g.generate(ts_now)
if n in n_set:
n_col += 1
print(f"Collision detected: naive: {n_col}, layered: {l_col}")
else:
n_set.add(n)
if l in l_set:
l_col += 1
print(f"Collision detected: naive: {n_col}, layered: {l_col}")
else:
l_set.add(l)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment