First version
This commit is contained in:
commit
3951521a16
7 changed files with 231 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
**/uuids
|
||||||
|
|
||||||
|
.vscode/.browse.*
|
||||||
|
nimsuggest.log
|
||||||
|
|
||||||
|
**/nimcache/**
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
15
.vscode/settings.json
vendored
Normal file
15
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"**/nimcache/**": true
|
||||||
|
},
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.rulers": [80],
|
||||||
|
"editor.renderIndentGuides": true,
|
||||||
|
"files.autoSave": "afterDelay",
|
||||||
|
"nim.licenseString": "# Copyright 2016 Xored Software, Inc.\n\n",
|
||||||
|
"nim.buildOnSave": false,
|
||||||
|
"nim.lintOnSave": true,
|
||||||
|
"nim.project": ["uuids.nim"]
|
||||||
|
}
|
||||||
20
LICENSE
Normal file
20
LICENSE
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
uuids - UUID library for Nim
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Xored Software Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||||
|
portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||||
|
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
33
README.md
Normal file
33
README.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# uuids
|
||||||
|
|
||||||
|
UUID library for Nim.
|
||||||
|
|
||||||
|
API:
|
||||||
|
```nim
|
||||||
|
type UUID* = object
|
||||||
|
## 128-bit UUID compliant with RFC-4122
|
||||||
|
|
||||||
|
proc `$`*(uuid: UUID): string
|
||||||
|
## Returns a string representation of the UUID in canonical form.
|
||||||
|
|
||||||
|
proc hash*(uuid: UUID): Hash
|
||||||
|
## Computes hash of the specified UUID.
|
||||||
|
|
||||||
|
proc `==`*(x, y: UUID): bool
|
||||||
|
## Returns true when the specified UUIDs are equal, false otherwise.
|
||||||
|
|
||||||
|
proc genUUID*(): UUID =
|
||||||
|
## Returns a random (v4) UUID.
|
||||||
|
## Uses random values obtained from system source (e.g. urandom).
|
||||||
|
## In the future this will use a cryptographically secure PRNG for efficiency.
|
||||||
|
|
||||||
|
proc toUUID*(s: string): UUID {.raises: [ValueError].}
|
||||||
|
## Converts string representation of an UUID to UUID object.
|
||||||
|
## Raises ValueError if invalid format is provided.
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
This library is licensed under the MIT license.
|
||||||
|
Read [LICENSE](https://github.com/pragmagic/uuids/blob/master/LICENSE) file for details.
|
||||||
|
|
||||||
|
Copyright (c) 2016 Xored Software, Inc.
|
||||||
65
src/urandom.nim
Normal file
65
src/urandom.nim
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Source: https://github.com/BlaXpirit/nim-random/blob/master/src/random/urandom.nim
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
import winlean
|
||||||
|
|
||||||
|
type ULONG_PTR = int
|
||||||
|
type HCRYPTPROV = ULONG_PTR
|
||||||
|
var PROV_RSA_FULL {.importc, header: "<windows.h>".}: DWORD
|
||||||
|
var CRYPT_VERIFYCONTEXT {.importc, header: "<windows.h>".}: DWORD
|
||||||
|
|
||||||
|
{.push, stdcall, dynlib: "Advapi32.dll".}
|
||||||
|
|
||||||
|
when useWinUnicode:
|
||||||
|
proc CryptAcquireContext(
|
||||||
|
phProv: ptr HCRYPTPROV, pszContainer: WideCString,
|
||||||
|
pszProvider: WideCString, dwProvType: DWORD, dwFlags: DWORD
|
||||||
|
): WinBool {.importc: "CryptAcquireContextW".}
|
||||||
|
else:
|
||||||
|
proc CryptAcquireContext(
|
||||||
|
phProv: ptr HCRYPTPROV, pszContainer: cstring, pszProvider: cstring,
|
||||||
|
dwProvType: DWORD, dwFlags: DWORD
|
||||||
|
): WinBool {.importc: "CryptAcquireContextA".}
|
||||||
|
|
||||||
|
proc CryptGenRandom(
|
||||||
|
hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: pointer
|
||||||
|
): WinBool {.importc: "CryptGenRandom".}
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
var cryptProv: HCRYPTPROV = 0
|
||||||
|
|
||||||
|
proc urandomInit() =
|
||||||
|
let success = CryptAcquireContext(
|
||||||
|
addr cryptProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT
|
||||||
|
)
|
||||||
|
if success == 0:
|
||||||
|
raise newException(OSError, "Call to CryptAcquireContext failed")
|
||||||
|
|
||||||
|
template urandomImpl() =
|
||||||
|
when defined(windows):
|
||||||
|
if cryptProv == 0:
|
||||||
|
urandomInit()
|
||||||
|
|
||||||
|
let success = CryptGenRandom(cryptProv, DWORD(size), addr result[0])
|
||||||
|
if success == 0:
|
||||||
|
raise newException(OSError, "Call to CryptGenRandom failed")
|
||||||
|
|
||||||
|
else:
|
||||||
|
var file: File
|
||||||
|
if not file.open("/dev/urandom"):
|
||||||
|
raise newException(OSError, "/dev/urandom is not available")
|
||||||
|
try:
|
||||||
|
var index = 0
|
||||||
|
while index < size:
|
||||||
|
let bytesRead = file.readBuffer(addr result[index], size-index)
|
||||||
|
if bytesRead <= 0:
|
||||||
|
raise newException(OSError, "Can't read enough bytes from /dev/urandom")
|
||||||
|
index += bytesRead
|
||||||
|
finally:
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
proc urandom*(size: static[Natural]): array[size, uint8] =
|
||||||
|
## Returns an ``array`` of random integers ``0 <= n < 256`` provided by
|
||||||
|
## the operating system's cryptographic source.
|
||||||
|
urandomImpl()
|
||||||
83
src/uuids.nim
Normal file
83
src/uuids.nim
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
import strutils, hashes
|
||||||
|
import urandom
|
||||||
|
|
||||||
|
type
|
||||||
|
UUID* = object
|
||||||
|
## 128-bit UUID compliant with RFC-4122
|
||||||
|
mostSigBits: int64
|
||||||
|
leastSigBits: int64
|
||||||
|
|
||||||
|
template toHex(s: string, start: Natural,
|
||||||
|
x: BiggestInt, len: Positive) =
|
||||||
|
const HexChars = "0123456789abcdef"
|
||||||
|
var n = x
|
||||||
|
for j in countdown(len - 1, 0):
|
||||||
|
s[start + j] = HexChars[n and 0xF]
|
||||||
|
n = n shr 4
|
||||||
|
# handle negative overflow
|
||||||
|
if n == 0 and x < 0: n = -1
|
||||||
|
|
||||||
|
proc `$`*(uuid: UUID): string =
|
||||||
|
## Returns a string representation of the UUID in canonical form.
|
||||||
|
result = newString(36)
|
||||||
|
toHex(result, 0, uuid.mostSigBits shr 32, 8)
|
||||||
|
result[8] = '-'
|
||||||
|
toHex(result, 9, uuid.mostSigBits shr 16, 4)
|
||||||
|
result[13] = '-'
|
||||||
|
toHex(result, 14, uuid.mostSigBits, 4)
|
||||||
|
result[18] = '-'
|
||||||
|
toHex(result, 19, uuid.leastSigBits shr 48, 4)
|
||||||
|
result[23] = '-'
|
||||||
|
toHex(result, 24, uuid.leastSigBits, 12)
|
||||||
|
|
||||||
|
proc hash*(uuid: UUID): Hash =
|
||||||
|
## Computes hash of the specified UUID.
|
||||||
|
result = uuid.mostSigBits.hash() !& uuid.leastSigBits.hash()
|
||||||
|
result = !$result
|
||||||
|
|
||||||
|
proc `==`*(x, y: UUID): bool =
|
||||||
|
## Returns ``true`` when the specified UUIDs are equal, ``false`` otherwise.
|
||||||
|
x.mostSigBits == y.mostSigBits and x.leastSigBits == y.leastSigBits
|
||||||
|
|
||||||
|
proc genUUID*(): UUID =
|
||||||
|
## Returns a random (v4) UUID.
|
||||||
|
## Uses random values obtained from system source (e.g. urandom).
|
||||||
|
## In the future this will use a cryptographically secure PRNG for efficiency.
|
||||||
|
var randBytes: array[16, uint8] = urandom(16)
|
||||||
|
copyMem(addr result.mostSigBits, addr randBytes[0], 8)
|
||||||
|
copyMem(addr result.leastSigBits, addr randBytes[8], 8)
|
||||||
|
|
||||||
|
# set version to 4
|
||||||
|
result.mostSigBits = (result.mostSigBits and 0xFFFFFFFFFFFF0FFF'i64) or
|
||||||
|
0x0000000000004000'i64
|
||||||
|
# set IETF variant
|
||||||
|
result.leastSigBits = (result.leastSigBits and 0x3FFFFFFFFFFFFFFF'i64) or
|
||||||
|
0x8000000000004000'i64
|
||||||
|
|
||||||
|
proc toUUID*(s: string): UUID {.raises: [ValueError].} =
|
||||||
|
## Converts string representation of an UUID to UUID object.
|
||||||
|
## Raises ``ValueError`` if invalid format is provided.
|
||||||
|
let parts = s.split('-')
|
||||||
|
if parts.len != 5:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"UUID must consist of 5 parts separated with `-`")
|
||||||
|
var mostSigBits: int64 = parseHexInt(parts[0])
|
||||||
|
mostSigBits = mostSigBits shl 16
|
||||||
|
mostSigBits = mostSigBits or parseHexInt(parts[1])
|
||||||
|
mostSigBits = mostSigBits shl 16
|
||||||
|
mostSigBits = mostSigBits or parseHexInt(parts[2])
|
||||||
|
|
||||||
|
var leastSigBits: int64 = parseHexInt(parts[3])
|
||||||
|
leastSigBits = leastSigBits shl 48
|
||||||
|
leastSigBits = leastSigBits or parseHexInt(parts[4])
|
||||||
|
|
||||||
|
result = UUID(mostSigBits: mostSigBits, leastSigBits: leastSigBits)
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
let uuid = genUUID()
|
||||||
|
let uuidStr = $uuid
|
||||||
|
assert(uuidStr.len == 36)
|
||||||
|
assert(uuidStr[14] == '4') # version
|
||||||
|
assert(uuidStr[19] in {'8', '9', 'a', 'b'}) # variant (2 bits)
|
||||||
|
assert(uuidStr.toUUID() == uuid)
|
||||||
|
assert(uuidStr.toUUID().hash() == uuid.hash())
|
||||||
7
uuids.nimble
Normal file
7
uuids.nimble
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[Package]
|
||||||
|
name: "uuids"
|
||||||
|
version: "0.1.0"
|
||||||
|
author: "Xored Software, Inc."
|
||||||
|
description: "UUID library"
|
||||||
|
license: "MIT"
|
||||||
|
srcDir: "src"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue