Merge pull request #829 from aarroyoc/uuidv4

UUIDv4 library
This commit is contained in:
Mark Thom
2021-02-18 14:29:06 -07:00
committed by GitHub
2 changed files with 108 additions and 0 deletions

View File

@@ -519,6 +519,7 @@ The modules that ship with Scryer Prolog are also called
public key signatures and signature verification with Ed25519, public key signatures and signature verification with Ed25519,
ECDH key exchange over Curve25519 (X25519), authenticated symmetric ECDH key exchange over Curve25519 (X25519), authenticated symmetric
encryption with ChaCha20-Poly1305, and reasoning about elliptic curves. encryption with ChaCha20-Poly1305, and reasoning about elliptic curves.
* [`uuid`](src/lib/uuid.pl) UUIDv4 generation and hex representation
To use predicates provided by the `lists` library, write: To use predicates provided by the `lists` library, write:

107
src/lib/uuid.pl Normal file
View File

@@ -0,0 +1,107 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written in February 2021 by Adrián Arroyo (adrian.arroyocalle@gmail.com)
Part of Scryer-Prolog
This library provides reasoning about UUID (only version 4 right now).
There are three predicates:
* uuidv4/1, to generate a new UUIDv4
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
* uuid_string/2, to converte between UUID list of bytes and UUID hex representation
Examples:
?- uuidv4(X).
X = [42,147,248,242,117,196,79,2,129,159|...].
?- uuidv4_string(X).
X = "428499fc-76e3-4240- ...".
?- uuidv4(X), uuid_string(X, S).
X = [173,12,244,152,139,118,64,139,137,4|...], S = "ad0cf498-8b76-408b- ...".
?- uuid_string(X, "61ae692e-eaf6-4199-8dd3-9f01db70a20b").
X = [97,174,105,46,234,246,65,153,141,211|...].
I place this code in the public domain. Use it in any way you want.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(uuid, [
uuidv4/1,
uuidv4_string/1,
uuid_string/2
]).
:- use_module(library(crypto)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
/*
An UUID is made of 16 bytes, composed of 5 sections:
time_low - 4
time_mid - 2
time_hi_and_version - 2
clock_seq_hi_and_res_clock_seq_low - 2
node - 6
UUID v4 can be generated from a set of 16 random bytes: https://www.rfc-archive.org/getrfc.php?rfc=4122#gsc.tab=0 (section 4.4)
*/
uuidv4(Uuid) :-
crypto_n_random_bytes(16, Bytes),
Bytes = [B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16],
byte_bits(B9, BitsClockSeqHi0),
BitsClockSeqHi0 = [_X7, _X6, X5, X4, X3, X2, X1, X0],
NewBitsClockSeqHi0 = [1, 0, X5, X4, X3, X2, X1, X0],
byte_bits(NewClockSeqHi0, NewBitsClockSeqHi0),
byte_bits(B7, BitsTimeHi),
BitsTimeHi = [_Y7, _Y6, _Y5, _Y4, Y3, Y2, Y1, Y0],
NewBitsTimeHi = [0, 1, 0, 0, Y3, Y2, Y1, Y0],
byte_bits(NewTimeHi, NewBitsTimeHi),
Uuid = [B1, B2, B3, B4, B5, B6, NewTimeHi, B8, NewClockSeqHi0, B10, B11, B12, B13, B14, B15, B16].
uuidv4_string(String) :- uuidv4(Uuid), uuid_string(Uuid, String).
uuid_string(Uuid, String) :-
Uuid = [B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16],
phrase(uuid_([S1, S2, S3, S4, S5]), String),
hex_bytes(S1, [B1, B2, B3, B4]),
hex_bytes(S2, [B5, B6]),
hex_bytes(S3, [B7, B8]),
hex_bytes(S4, [B9, B10]),
hex_bytes(S5, [B11, B12, B13, B14, B15, B16]).
uuid_([S1, S2, S3, S4, S5]) -->
{
length(S1, 8),
length(S2, 4),
length(S3, 4),
length(S4, 4),
length(S5, 12)
},
S1,
"-",
S2,
"-",
S3,
"-",
S4,
"-",
S5.
byte_bits(Byte, Bits) :-
\+ var(Byte),
byte_bits_(Byte, Bits),
length(Bits, 8),!.
byte_bits(Byte, Bits) :-
\+ var(Bits),
length(Bits, 8),
byte_bits__(Byte, Bits),!.
byte_bits_(0, [0]).
byte_bits_(1, [1]).
byte_bits_(Byte, Bits) :-
R is Byte // 2,
M is Byte mod 2,
byte_bits_(R, Bits0),
append(Bits0, [M], Bits).
byte_bits__(0, []).
byte_bits__(Byte, Bits) :-
length(Bits, N),
Bits = [Bit|Bits0],
byte_bits__(Byte0, Bits0),
Byte is Byte0 + Bit*(2 ^ (N-1)).