Skip to content

Commit

Permalink
Add urand() for cryptographically safe RNG
Browse files Browse the repository at this point in the history
  • Loading branch information
thesephist committed Dec 22, 2019
1 parent 64aa053 commit 861c9df
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 1 deletion.
1 change: 1 addition & 0 deletions SPEC.md
Expand Up @@ -161,6 +161,7 @@ These are the right primitives, but we can build much more sophisticated systems
- `req(composite, callback) => callback`: Send an HTTP client request. `url` is required, `method`, `headers`, `body` are optional and default to their sensible zero values.
- `wait(number, callback)`: Call the callback function after at least the given number of seconds has elapsed.
- `rand() => number`: a pseudorandom floating point number in interval `[0, 1)`.
- `urand(length) => string`: a string of given length containing random bits, safe for cryptography work
- `time() => number`: number of seconds in floating point in UNIX epoch.
- `exec(string, [list], string, callback) => callback`: Exec the command at a given path with given arguments, with a given stdin, call given callback with stdout when exited.

Expand Down
27 changes: 27 additions & 0 deletions pkg/ink/runtime.go
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"context"
crand "crypto/rand"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -59,6 +60,7 @@ func (ctx *Context) LoadEnvironment() {
ctx.LoadFunc("listen", inkListen)
ctx.LoadFunc("req", inkReq)
ctx.LoadFunc("rand", inkRand)
ctx.LoadFunc("urand", inkUrand)
ctx.LoadFunc("time", inkTime)
ctx.LoadFunc("wait", inkWait)
ctx.LoadFunc("exec", inkExec)
Expand Down Expand Up @@ -1093,6 +1095,31 @@ func inkRand(ctx *Context, in []Value) (Value, error) {
return NumberValue(rand.Float64()), nil
}

func inkUrand(ctx *Context, in []Value) (Value, error) {
if len(in) != 1 {
return nil, Err{
ErrRuntime,
fmt.Sprintf("urand() expects one argument: length, but got %d", len(in)),
}
}

bufLength, isNum := in[0].(NumberValue)
if !isNum || bufLength < 0 {
return nil, Err{
ErrRuntime,
"unsupported combination of argument types in urand()",
}
}

buf := make([]byte, int64(float64(bufLength)))
_, err := crand.Read(buf)
if err != nil {
return NullValue{}, nil
}

return StringValue(buf), nil
}

func inkTime(ctx *Context, in []Value) (Value, error) {
unixSeconds := float64(time.Now().UnixNano()) / 1e9
return NumberValue(unixSeconds), nil
Expand Down
2 changes: 1 addition & 1 deletion samples/uuid.ink
Expand Up @@ -8,7 +8,7 @@ map := std.map

uuid := () => (
` generate 16 random bytes `
r := map(range(0, 16, 1), () => floor(rand() * 256))
r := map(urand(16), b => point(b))

` helper to map numbers to uniform hexadecimals `
x := i => (
Expand Down
1 change: 1 addition & 0 deletions utils/ink.vim
Expand Up @@ -72,6 +72,7 @@ syntax keyword inkBuiltin delete contained
syntax keyword inkBuiltin listen contained
syntax keyword inkBuiltin req contained
syntax keyword inkBuiltin rand contained
syntax keyword inkBuiltin urand contained
syntax keyword inkBuiltin time contained
syntax keyword inkBuiltin wait contained
syntax keyword inkBuiltin exec contained
Expand Down

0 comments on commit 861c9df

Please sign in to comment.