mirror of
https://github.com/waku-org/nwaku.git
synced 2025-01-28 23:55:43 +00:00
101 lines
3.5 KiB
Nim
101 lines
3.5 KiB
Nim
import
|
|
typetraits,
|
|
./abi/[bearssl_hash, bearssl_rand]
|
|
|
|
export bearssl_rand
|
|
|
|
# About types used in helpers:
|
|
# `bool` types are problematic because because they only use one bit of the
|
|
# entire byte - a similar problem occurs with `object` types with alignment
|
|
# gaps - `supportsCopyMem` is wrong here, we should be using `supportsMemCmp` or
|
|
# something similar that takes into account these issues, but alas, there's no
|
|
# such trait as of now
|
|
|
|
proc init*[S](T: type HmacDrbgContext, seed: openArray[S]): HmacDrbgContext =
|
|
## Create a new randomness context with the given seed - typically, a single
|
|
## instance per thread should be created.
|
|
##
|
|
## The seed can later be topped up with `update`.
|
|
static: doAssert supportsCopyMem(S) and sizeof(S) > 0 and S isnot bool
|
|
|
|
if seed.len == 0:
|
|
hmacDrbgInit(result, addr bearssl_hash.sha256Vtable, nil, 0)
|
|
else:
|
|
# In theory the multiplication can overflow, but practically we can't
|
|
# allocate that much memory, so it won't
|
|
hmacDrbgInit(
|
|
result, addr sha256Vtable, unsafeAddr seed[0], uint seed.len * sizeof(S))
|
|
|
|
proc new*(T: type HmacDrbgContext): ref HmacDrbgContext =
|
|
## Create a new randomness context intended to be shared between randomness
|
|
## consumers - typically, a single instance per thread should be created.
|
|
##
|
|
## The context is seeded with randomness from the OS / system.
|
|
## Returns `nil` if the OS / system has no randomness API.
|
|
let seeder = prngSeederSystem(nil)
|
|
if seeder == nil:
|
|
return nil
|
|
|
|
let rng = (ref HmacDrbgContext)()
|
|
hmacDrbgInit(rng[], addr sha256Vtable, nil, 0)
|
|
|
|
if seeder(addr rng.vtable) == 0:
|
|
return nil
|
|
|
|
rng
|
|
|
|
func generate*(ctx: var HmacDrbgContext, v: var auto) =
|
|
## Fill `v` with random data - `v` must be a simple type
|
|
static: doAssert supportsCopyMem(type v)
|
|
|
|
when sizeof(v) > 0:
|
|
when v is bool:
|
|
# `bool` would result in a heavily biased value because >0 == true
|
|
var tmp: byte
|
|
hmacDrbgGenerate(ctx, addr tmp, uint sizeof(tmp))
|
|
v = (tmp and 1'u8) == 1
|
|
else:
|
|
hmacDrbgGenerate(ctx, addr v, uint sizeof(v))
|
|
|
|
func generate*[V](ctx: var HmacDrbgContext, v: var openArray[V]) =
|
|
## Fill `v` with random data - `T` must be a simple type
|
|
static: doAssert supportsCopyMem(V) and sizeof(V) > 0
|
|
|
|
when V is bool:
|
|
for b in v.mitems:
|
|
ctx.generate(b)
|
|
else:
|
|
if v.len > 0:
|
|
# In theory the multiplication can overflow, but practically we can't
|
|
# allocate that much memory, so it won't
|
|
hmacDrbgGenerate(ctx, addr v[0], uint v.len * sizeof(V))
|
|
|
|
template generate*[V](ctx: var HmacDrbgContext, v: var seq[V]) =
|
|
generate(ctx, v.toOpenArray(0, v.high()))
|
|
|
|
func generateBytes*(ctx: var HmacDrbgContext, n: int): seq[byte] =
|
|
# https://github.com/nim-lang/Nim/issues/19357
|
|
if n > 0:
|
|
result = newSeqUninitialized[byte](n)
|
|
ctx.generate(result)
|
|
|
|
func generate*(ctx: var HmacDrbgContext, T: type): T {.noinit.} =
|
|
## Create a new instance of `T` filled with random data - `T` must be
|
|
## a simple type
|
|
ctx.generate(result)
|
|
|
|
func update*[S](ctx: var HmacDrbgContext, seed: openArray[S]) =
|
|
## Update context with additional seed data
|
|
static: doAssert supportsCopyMem(S) and sizeof(S) > 0 and S isnot bool
|
|
|
|
if seed.len > 0:
|
|
# In theory the multiplication can overflow, but practically we can't
|
|
# allocate that much memory, so it won't
|
|
hmacDrbgUpdate(ctx, unsafeAddr seed[0], uint seed.len * sizeof(S))
|
|
|
|
# Convenience helpers using bearssl naming
|
|
|
|
template hmacDrbgGenerate*(
|
|
ctx: var HmacDrbgContext, output: var openArray[byte]) =
|
|
generate(ctx, output)
|