From 1c7950443c4a9e904b84a1f2aca29fce9e21adea Mon Sep 17 00:00:00 2001 From: flashultra Date: Mon, 18 May 2020 14:45:50 +0300 Subject: [PATCH] Replace PCG32 with built-in RNG - Xorshift128+ --- README.md | 19 ++++++++++-- haxelib.json | 12 ++++---- Uuid.hx => src/uuid/Uuid.hx | 59 +++++++++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 23 deletions(-) rename Uuid.hx => src/uuid/Uuid.hx (65%) diff --git a/README.md b/README.md index 6733d80..00d420a 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,25 @@ Cross-platform generation of UUID based on [RFC-4122](https://tools.ietf.org/html/rfc4122) . Support for 1, 3, 4 and 5 versions of UUID. -Port from [node-uuid](https://github.com/kelektiv/node-uuid) and using [PCG32](https://github.com/flashultra/hxprng) for random generator. +Port from [node-uuid](https://github.com/kelektiv/node-uuid) and using built-in Xorshift128+ for random generator. Version 3 use Md5 for hash and version 5 use Sha1. -## Installation -Require [PCG32](https://github.com/flashultra/hxprng) . If you won't want to use it can replace it with ```Std.random(256)``` or any other prng library. +## Random generator +For Uuid.v1() and Uuid.v4() you can pass any random function which return value between 0 and 255 . The default random generator is Xorshift128+ . Here is example for custom random function using Std.random +```haxe +public function secureRandom():Int +{ + return Std.random(256); +} + +var uuid = Uuid.v1(secureRandom); + +``` +You can use Uuid to get any random number between some range, based on Xorshift128+ RNG, using the following code: +```haxe + var dice:Int = Uuid.randomFromRange(1,6); +``` ## Usage Version 1 (timestamp): diff --git a/haxelib.json b/haxelib.json index 1b7871c..68a7774 100644 --- a/haxelib.json +++ b/haxelib.json @@ -1,13 +1,11 @@ { "name": "uuid", + "url": "https://github.com/flashultra/uuid", "license": "MIT", "tags": ["cross","haxe","uuid","game"], "description": "Cross platform, simple Uuid generation based on RFC4122 . Support versions are v1, v3, v4 and v5", - "contributors": ["flashultra"], - "releasenote": "Simple Uuid generation for v1, v3, v4 and v5", - "version": "1.0.0", - "url": "https://github.com/flashultra/uuid", - "dependencies": { - "hxprng": "" - } + "version": "2.0.0", + "releasenote": "Add build-in random generator Xorshift128+", + "contributors": [ "flashultra" ], + "classPath": "src" } \ No newline at end of file diff --git a/Uuid.hx b/src/uuid/Uuid.hx similarity index 65% rename from Uuid.hx rename to src/uuid/Uuid.hx index 4b226ac..5d68cf4 100644 --- a/Uuid.hx +++ b/src/uuid/Uuid.hx @@ -1,3 +1,5 @@ +package uuid; + import haxe.Timer; import haxe.Int64; import haxe.io.Bytes; @@ -9,23 +11,48 @@ class Uuid { inline static var URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; inline static var ISO_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; inline static var X500_DN = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; - - static var rng:PCG32 = new PCG32(); - + static var lastMSecs:Float = 0; static var lastNSecs = 0; static var clockSequenceBuffer:Int = -1; - public static function v1(node:Bytes = null, optClockSequence:Int = -1, msecs:Float = -1, optNsecs:Int = -1):String { + static var rndSeed:Int = Std.int(Timer.stamp() * 1000); + static var state0 = splitmix64_seed(rndSeed); + static var state1 = splitmix64_seed(rndSeed + 1); + + private static function splitmix64_seed(index:Int):Int64 { + var result:Int64 = (index + Int64.make(0x9E3779B9, 0x7F4A7C15)); + result = (result ^ (result >> 30)) * Int64.make(0xBF58476D, 0x1CE4E5B9); + result = (result ^ (result >> 27)) * Int64.make(0x94D049BB, 0x133111EB); + return result ^ (result >> 31); + } + + public static function randomFromRange(min:Int, max:Int):Int { + var s1:Int64 = state0; + var s0:Int64 = state1; + state0 = s0; + s1 ^= s1 << 23; + state1 = s1 ^ s0 ^ (s1 >>> 18) ^ (s0 >>> 5); + var result:Int = ((state1 + s0) % (max - min + 1)).low; + result = (result < 0) ? -result : result; + return result + min; + } + + public static function randomByte():Int { + return randomFromRange(0, 255); + } + + public static function v1(node:Bytes = null, optClockSequence:Int = -1, msecs:Float = -1, optNsecs:Int = -1, ?randomFunc:Void->Int):String { + if ( randomFunc == null) randomFunc = randomByte; var buffer:Bytes = Bytes.alloc(16); if (node == null) { node = Bytes.alloc(6); for (i in 0...6) - node.set(i, rng.randomFromRange(0, 255)); + node.set(i, randomFunc()); node.set(0, node.get(0) | 0x01); } if (clockSequenceBuffer == -1) { - clockSequenceBuffer = (rng.randomFromRange(0, 255) << 8 | rng.randomFromRange(0, 255)) & 0x3fff; + clockSequenceBuffer = (randomFunc() << 8 | randomFunc()) & 0x3fff; } var clockSeq = optClockSequence; if (optClockSequence == -1) { @@ -77,7 +104,7 @@ class Uuid { return uuid; } - public static function v3(name:String, namespace:String=""):String { + public static function v3(name:String, namespace:String = ""):String { namespace = StringTools.replace(namespace, '-', ''); var buffer = Md5.make(Bytes.ofHex(namespace + Bytes.ofString(name).toHex())); buffer.set(6, (buffer.get(6) & 0x0f) | 0x30); @@ -86,10 +113,16 @@ class Uuid { return uuid; } - public static function v4(randBytes:Bytes = null):String { - var buffer:Bytes = Bytes.alloc(16); - for (i in 0...16) { - buffer.set(i, rng.randomFromRange(0, 255)); + public static function v4(randBytes:Bytes = null, ?randomFunc:Void->Int):String { + if ( randomFunc == null) randomFunc = randomByte; + var buffer:Bytes = randBytes; + if ( buffer == null ) { + buffer = Bytes.alloc(16); + for (i in 0...16) { + buffer.set(i, randomFunc()); + } + } else { + if ( buffer.length < 16) throw "Random bytes should be at least 16 bytes"; } buffer.set(6, (buffer.get(6) & 0x0f) | 0x40); buffer.set(8, (buffer.get(8) & 0x3f) | 0x80); @@ -97,7 +130,7 @@ class Uuid { return uuid; } - public static function v5(name:String, namespace:String=""):String { + public static function v5(name:String, namespace:String = ""):String { namespace = StringTools.replace(namespace, '-', ''); var buffer = Sha1.make(Bytes.ofHex(namespace + Bytes.ofString(name).toHex())); buffer.set(6, (buffer.get(6) & 0x0f) | 0x50); @@ -115,4 +148,4 @@ class Uuid { public static function parse(data:String):Bytes { return Bytes.ofHex(StringTools.replace(data, '-', '')); } -} \ No newline at end of file +}