Skip to content

Instantly share code, notes, and snippets.

@borovan
Created December 15, 2021 08:05
Show Gist options
  • Save borovan/64814cdb6f1aa06483545bab2ea20565 to your computer and use it in GitHub Desktop.
Save borovan/64814cdb6f1aa06483545bab2ea20565 to your computer and use it in GitHub Desktop.
import Buffer "mo:base/Buffer";
import Debug "mo:base/Debug";
import Iter "mo:base/Iter";
import Nat "mo:base/Nat";
import Nat8 "mo:base/Nat8";
import Nat16 "mo:base/Nat16";
import Nat32 "mo:base/Nat32";
import Nat64 "mo:base/Nat64";
import RandomB "mo:base/Random";
import SHA256 "mo:sha256/SHA256";
import Time "mo:base/Time";
import T "Types";
module {
// Random
// it's a service so we can instantiate it at the top
// level and pass it via dependencies, otherwise we have
// inter-canister calls
public class Random() {
// Current sha data
// it gets rebuit with a new SHA256 when ever the
// wrapping byte counter is zero
var sha : [Nat8] = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
// byte
// the current read position of the sha array, 0 to 31
var byte : Nat = 0;
// getBytes
// returns b bytes of pseudorandom data
func getBytes(b : Nat) : [Nat8] {
var buf = Buffer.Buffer<Nat8>(b);
// iterate per byte
for (i in Iter.range(0, b-1)) {
// reset
if (byte == 0) {
sha := newSha();
};
// add byte and increment the counter
buf.add(sha[byte]);
byte += 1;
if (byte >= 32) {
byte := 0;
};
};
buf.toArray();
};
// timeToBytes
public func timeToBytes() : [Nat8] {
let time : Nat64 = Nat64.fromIntWrap(Time.now());
let buf = Buffer.Buffer<Nat8>(8);
for (i in Iter.range(0, 7)) {
let b = Nat64.fromNat(i*8);
let n = Nat8.fromNat(Nat64.toNat((time >> b) & 255));
buf.add(n);
};
buf.toArray();
};
// dice
// max 256*256 so Nat16
public func dice(n : Nat8, d : Nat8) : Nat {
var t : Nat = 0;
for (i in Iter.range(0, Nat8.toNat(n)-1)) {
let b = getBytes(1);
t += Nat8.toNat(b[0] % d) + 1;
};
t;
};
// nat8
public func nat8() : Nat8 { Nat8.fromNat(bytesToNat(1)) };
public func nat8n() : Nat { bytesToNat(1) };
// nat16
public func nat16() : Nat16 { Nat16.fromNat(bytesToNat(2)) };
public func nat16n() : Nat { bytesToNat(2) };
// nat32
public func nat32() : Nat32 { Nat32.fromNat(bytesToNat(4)) };
public func nat32n() : Nat { bytesToNat(4) };
// nat64
public func nat64() : Nat64 { Nat64.fromNat(bytesToNat(8)) };
public func nat64n() : Nat { bytesToNat(8) };
// bytesToNat
// creates a Nat from b bytes of sha data
func bytesToNat(b : Nat) : Nat {
let bytes = getBytes(b);
var sum : Nat64 = 0;
for (i in Iter.range(0, b-1)) {
var bnat = Nat64.fromNat(Nat8.toNat(bytes[i]));
bnat <<= Nat64.fromNat(i*8);
sum += bnat;
};
// Convert to Nat
let n = Nat64.toNat(sum);
// Debug.print("randNat generated (random) - " # Nat.toText(n));
n;
};
// newSha
func newSha() : [Nat8] {
let buf = Buffer.Buffer<Nat8>(40);
// current SHA
if (sha.size() > 0) {
for (i in Iter.range(0, 31)) {
buf.add(sha[i]);
};
};
// time
let ttb = timeToBytes();
for (i in Iter.range(0, 7)) {
buf.add(ttb[i]);
};
// update sha to new sum
let dig = SHA256.Digest();
dig.write(buf.toArray());
dig.sum();
};
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment