Skip to content

Commit

Permalink
Added UUID v7 generated based on current system date and time as well…
Browse files Browse the repository at this point in the history
… as Fixed Bit-Length Dedicated Counter (Method 1).

Added UUID v7 generated based on current system date and time as well as Replace Leftmost Random Bits with Increased Clock Precision (Method 3).
  • Loading branch information
amsga committed Jun 5, 2024
1 parent e39b5f6 commit 97393a5
Show file tree
Hide file tree
Showing 11 changed files with 357 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
dotnet: [ '6.0.x' ]
dotnet: [ '6.0.x', '8.0.x' ]
name: .NET ${{ matrix.dotnet }}

steps:
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]


## [v2.1.0-beta] - 2024-06-05
[v2.1.0-beta](https://github.com/TensionDev/UUIDUtil/releases/tag/v2.1.0-beta)

### Changed
- Added UUID v7 generated based on current system date and time as well as Fixed Bit-Length Dedicated Counter (Method 1).
- Added UUID v7 generated based on current system date and time as well as Replace Leftmost Random Bits with Increased Clock Precision (Method 3).


## [v2.1.0-alpha] - 2023-06-15
[v2.1.0-alpha](https://github.com/TensionDev/UUIDUtil/releases/tag/v2.1.0-alpha)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ This project references the following documents for implementation.
- [Universally unique identifier - Wikipedia](https://en.wikipedia.org/wiki/Universally_unique_identifier)
- [MySQL :: MySQL 8.0 Reference Manual :: 12.24 Miscellaneous Functions](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid)
- [rfc4122](https://datatracker.ietf.org/doc/html/rfc4122)
- [draft-ietf-uuidrev-rfc4122bis-14](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis)
- [rfc9562](https://datatracker.ietf.org/doc/html/rfc9562)
10 changes: 5 additions & 5 deletions UUIDUtil/UUIDNamespace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ namespace TensionDev.UUID
/// <summary>
/// Class Library to generate Universally Unique Identifier (UUID) / Globally Unique Identifier (GUID) based on Version 3 (MD5 namespace name-based).
/// </summary>
public class UUIDNamespace
public static class UUIDNamespace
{
/// <summary>
/// Namespace for Domain Name System
/// </summary>
public static Uuid DNS = new Uuid(0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
public static readonly Uuid DNS = new Uuid(0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
/// <summary>
/// Namespace for URLs
/// </summary>
public static Uuid URL = new Uuid(0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
public static readonly Uuid URL = new Uuid(0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
/// <summary>
/// Namespace for ISO Object IDs (OIDs)
/// </summary>
public static Uuid OID = new Uuid(0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
public static readonly Uuid OID = new Uuid(0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
/// <summary>
/// Namespace for X.500 Distinguished Names(DNs)
/// </summary>
public static Uuid X500 = new Uuid(0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
public static readonly Uuid X500 = new Uuid(0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
}
}
4 changes: 2 additions & 2 deletions UUIDUtil/UUIDUtil.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageId>TensionDev.UUID</PackageId>
<Version>2.1.0-alpha</Version>
<Version>2.1.0-beta</Version>
<Authors>TensionDev amsga</Authors>
<Company>TensionDev</Company>
<Product>TensionDev.UUID</Product>
<Description>A project to store various UUID functions within a library for future use.</Description>
<Copyright>Copyright (c) TensionDev 2021 - 2023</Copyright>
<Copyright>Copyright (c) TensionDev 2021</Copyright>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/TensionDev/UUIDUtil</PackageProjectUrl>
<RepositoryUrl>https://github.com/TensionDev/UUIDUtil</RepositoryUrl>
Expand Down
136 changes: 68 additions & 68 deletions UUIDUtil/UUIDv1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public class UUIDv1
{
protected internal static System.Net.NetworkInformation.PhysicalAddress s_physicalAddress = System.Net.NetworkInformation.PhysicalAddress.None;
protected internal static Int32 s_clock = Int32.MinValue;
protected internal static DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
protected internal static readonly DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);

protected internal static Object s_initLock = new Object();
protected internal static Object s_clockLock = new Object();
protected internal static readonly Object s_initLock = new Object();
protected internal static readonly Object s_clockLock = new Object();

/// <summary>
/// Initialises a new GUID/UUID based on Version 1 (date-time and MAC address)
Expand All @@ -39,68 +39,6 @@ public static Uuid NewUUIDv1()
return NewUUIDv1(DateTime.UtcNow);
}

/// <summary>
/// Initialises the 48-bit Node ID and returns it.<br />
/// Returns the MAC Address of a Network Interface Card, if available.
/// Otherwise, returns a randomly genrated 48-bit Node ID.
/// </summary>
/// <returns>A byte-array representing the 48-bit Node ID</returns>
public static Byte[] GetNodeID()
{
if (System.Net.NetworkInformation.PhysicalAddress.None.Equals(s_physicalAddress))
{
System.Net.NetworkInformation.NetworkInterface[] networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
if (networkInterfaces.Length > 0)
{
s_physicalAddress = networkInterfaces[0].GetPhysicalAddress();
}
else
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] fakeNode = new Byte[6];
cryptoServiceProvider.GetBytes(fakeNode);
fakeNode[0] = (Byte)(fakeNode[0] | 0x01);
s_physicalAddress = new System.Net.NetworkInformation.PhysicalAddress(fakeNode);
}
}
}

return s_physicalAddress.GetAddressBytes();
}

/// <summary>
/// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.<br />
/// Will return an incremented Clock Sequence on each call, modulo 14-bit.
/// </summary>
/// <returns>A byte-array representing the 14-bit Clock Sequence, together with the Variant</returns>
public static Byte[] GetClockSequence()
{
lock (s_initLock)
{
if (s_clock < 0)
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] clockInit = new Byte[4];
cryptoServiceProvider.GetBytes(clockInit);
s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
s_clock |= 0x8000;
}
}
}

Int32 result;
lock (s_clockLock)
{
result = s_clock++;
if (s_clock >= 0xC000)
s_clock = 0x8000;
}

return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
}

/// <summary>
/// Initialises a new GUID/UUID based on Version 1 (date-time and MAC address), based on the given date and time.
/// </summary>
Expand Down Expand Up @@ -146,10 +84,10 @@ public static Uuid NewUUIDv1(DateTime dateTime, Byte[] clockSequence, Byte[] nod
if (nodeID.Length < 6)
throw new ArgumentException(String.Format("Node ID contains less than 48-bit: {0} bytes", nodeID.Length), nameof(nodeID));

TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
Int64 timeinterval = timesince.Ticks;
TimeSpan timeSince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
Int64 timeInterval = timeSince.Ticks;

Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeInterval));

Byte[] hex = new Byte[16];

Expand Down Expand Up @@ -178,5 +116,67 @@ public static Uuid NewUUIDv1(DateTime dateTime, Byte[] clockSequence, Byte[] nod

return Id;
}

/// <summary>
/// Initialises the 48-bit Node ID and returns it.<br />
/// Returns the MAC Address of a Network Interface Card, if available.
/// Otherwise, returns a randomly genrated 48-bit Node ID.
/// </summary>
/// <returns>A byte-array representing the 48-bit Node ID</returns>
public static Byte[] GetNodeID()
{
if (System.Net.NetworkInformation.PhysicalAddress.None.Equals(s_physicalAddress))
{
System.Net.NetworkInformation.NetworkInterface[] networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
if (networkInterfaces.Length > 0)
{
s_physicalAddress = networkInterfaces[0].GetPhysicalAddress();
}
else
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] fakeNode = new Byte[6];
cryptoServiceProvider.GetBytes(fakeNode);
fakeNode[0] = (Byte)(fakeNode[0] | 0x01);
s_physicalAddress = new System.Net.NetworkInformation.PhysicalAddress(fakeNode);
}
}
}

return s_physicalAddress.GetAddressBytes();
}

/// <summary>
/// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.<br />
/// Will return an incremented Clock Sequence on each call, modulo 14-bit.
/// </summary>
/// <returns>A byte-array representing the 14-bit Clock Sequence, together with the Variant</returns>
public static Byte[] GetClockSequence()
{
lock (s_initLock)
{
if (s_clock < 0)
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] clockInit = new Byte[4];
cryptoServiceProvider.GetBytes(clockInit);
s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
s_clock |= 0x8000;
}
}
}

Int32 result;
lock (s_clockLock)
{
result = s_clock++;
if (s_clock >= 0xC000)
s_clock = 0x8000;
}

return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
}
}
}
106 changes: 53 additions & 53 deletions UUIDUtil/UUIDv6.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ namespace TensionDev.UUID
public class UUIDv6
{
protected internal static Int32 s_clock = Int32.MinValue;
protected internal static DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
protected internal static readonly DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);

protected internal static Object s_initLock = new Object();
protected internal static Object s_clockLock = new Object();
protected internal static readonly Object s_initLock = new Object();
protected internal static readonly Object s_clockLock = new Object();

/// <summary>
/// Initialises a new GUID/UUID based on Version 6 (date-time)
Expand All @@ -38,53 +38,6 @@ public static Uuid NewUUIDv6()
return NewUUIDv6(DateTime.UtcNow);
}

/// <summary>
/// Initialises the 48-bit Node ID and returns it.<br />
/// Returns a randomly genrated 48-bit Node ID.
/// </summary>
/// <returns>A byte-array representing the 48-bit Node ID</returns>
public static Byte[] GetNodeID()
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] fakeNode = new Byte[6];
cryptoServiceProvider.GetBytes(fakeNode);
return fakeNode;
}
}

/// <summary>
/// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.<br />
/// Will return an incremented Clock Sequence on each call, modulo 14-bit.
/// </summary>
/// <returns>A byte-array representing the 14-bit Clock Sequence, together with the Variant</returns>
public static Byte[] GetClockSequence()
{
lock (s_initLock)
{
if (s_clock < 0)
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] clockInit = new Byte[4];
cryptoServiceProvider.GetBytes(clockInit);
s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
s_clock |= 0x8000;
}
}
}

Int32 result;
lock (s_clockLock)
{
result = s_clock++;
if (s_clock >= 0xC000)
s_clock = 0x8000;
}

return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
}

/// <summary>
/// Initialises a new GUID/UUID based on Version 6 (date-time), based on the given date and time.
/// </summary>
Expand Down Expand Up @@ -130,10 +83,10 @@ public static Uuid NewUUIDv6(DateTime dateTime, Byte[] clockSequence, Byte[] nod
if (nodeID.Length < 6)
throw new ArgumentException(String.Format("Node ID contains less than 48-bit: {0} bytes", nodeID.Length), nameof(nodeID));

TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
Int64 timeinterval = timesince.Ticks << 4;
TimeSpan timeSince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
Int64 timeInterval = timeSince.Ticks << 4;

Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeInterval));

Byte[] hex = new Byte[16];

Expand Down Expand Up @@ -162,5 +115,52 @@ public static Uuid NewUUIDv6(DateTime dateTime, Byte[] clockSequence, Byte[] nod

return Id;
}

/// <summary>
/// Initialises the 48-bit Node ID and returns it.<br />
/// Returns a randomly genrated 48-bit Node ID.
/// </summary>
/// <returns>A byte-array representing the 48-bit Node ID</returns>
public static Byte[] GetNodeID()
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] fakeNode = new Byte[6];
cryptoServiceProvider.GetBytes(fakeNode);
return fakeNode;
}
}

/// <summary>
/// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.<br />
/// Will return an incremented Clock Sequence on each call, modulo 14-bit.
/// </summary>
/// <returns>A byte-array representing the 14-bit Clock Sequence, together with the Variant</returns>
public static Byte[] GetClockSequence()
{
lock (s_initLock)
{
if (s_clock < 0)
{
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
{
Byte[] clockInit = new Byte[4];
cryptoServiceProvider.GetBytes(clockInit);
s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
s_clock |= 0x8000;
}
}
}

Int32 result;
lock (s_clockLock)
{
result = s_clock++;
if (s_clock >= 0xC000)
s_clock = 0x8000;
}

return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
}
}
}
Loading

0 comments on commit 97393a5

Please sign in to comment.