Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

@@ -0,0 +1,15 @@
import crypto.rand
fn test_reading() {
a := rand.read(32)!
// dump(a.hex())
assert a.len == 32
mut histogram := [256]int{}
for b in a {
histogram[b]++
}
// dump(histogram)
for h in histogram {
assert h < 10
}
}
+24
View File
@@ -0,0 +1,24 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
struct ReadError {
Error
}
// msg returns the error message.
pub fn (err ReadError) msg() string {
return 'crypto.rand.read() error reading random bytes'
}
// bytes returns an array of `bytes_needed` random bytes.
// Note: this call can block your program for a long period of time,
// if your system does not have access to enough entropy.
// See also rand.bytes(), if you do not need really random bytes,
// but instead pseudo random ones, from a pseudo random generator
// that can be seeded, and that is usually faster.
pub fn bytes(bytes_needed int) ![]u8 {
return read(bytes_needed)
}
+19
View File
@@ -0,0 +1,19 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
#include <sys/random.h>
fn C.getentropy(buf voidptr, buflen usize) i32
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
mut buffer := []u8{len: bytes_needed}
status := C.getentropy(buffer.data, bytes_needed)
if status != 0 {
return &ReadError{}
}
return buffer
}
@@ -0,0 +1,9 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
return error('rand.read is not implemented on this platform')
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) 2022 John Lloyd. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
#include <stdlib.h>
fn C.arc4random_buf(p &u8, n usize)
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
mut buffer := unsafe { malloc_noscan(bytes_needed) }
C.arc4random_buf(buffer, bytes_needed)
return unsafe { buffer.vbytes(bytes_needed) }
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
#include <sys/syscall.h>
pub const C.SYS_getrandom int
const read_batch_size = 256
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
mut buffer := unsafe { vcalloc_noscan(bytes_needed) }
mut bytes_read := 0
mut remaining_bytes := bytes_needed
// getrandom syscall wont block if requesting <= 256 bytes
for bytes_read < bytes_needed {
batch_size := if remaining_bytes > read_batch_size {
read_batch_size
} else {
remaining_bytes
}
rbytes := unsafe { getrandom(batch_size, buffer + bytes_read) }
if rbytes == -1 {
unsafe { free(buffer) }
return &ReadError{}
}
bytes_read += rbytes
remaining_bytes -= rbytes
}
return unsafe { buffer.vbytes(bytes_needed) }
}
fn getrandom(bytes_needed int, buffer voidptr) int {
if bytes_needed > read_batch_size {
panic('getrandom() dont request more than ${read_batch_size} bytes at once.')
}
return unsafe { C.syscall(C.SYS_getrandom, buffer, bytes_needed, 0) }
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) 2022 John Lloyd. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
#include <stdlib.h>
fn C.arc4random_buf(p &u8, n usize)
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
mut buffer := unsafe { malloc_noscan(bytes_needed) }
C.arc4random_buf(buffer, bytes_needed)
return unsafe { buffer.vbytes(bytes_needed) }
}
+41
View File
@@ -0,0 +1,41 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
#include <sys/random.h>
fn C.getrandom(p &u8, n usize, flags u32) i32
const read_batch_size = 256
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
mut buffer := unsafe { malloc_noscan(bytes_needed) }
mut bytes_read := 0
mut remaining_bytes := bytes_needed
// getrandom syscall wont block if requesting <= 256 bytes
for bytes_read < bytes_needed {
batch_size := if remaining_bytes > read_batch_size {
read_batch_size
} else {
remaining_bytes
}
rbytes := unsafe { getrandom(batch_size, buffer + bytes_read) }
if rbytes == -1 {
unsafe { free(buffer) }
return &ReadError{}
}
bytes_read += rbytes
remaining_bytes -= rbytes
}
return unsafe { buffer.vbytes(bytes_needed) }
}
fn v_getrandom(bytes_needed int, buffer voidptr) int {
if bytes_needed > read_batch_size {
panic('getrandom() dont request more than ${read_batch_size} bytes at once.')
}
return C.getrandom(buffer, bytes_needed, 0)
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
#flag windows -Llibraries/bcrypt
#flag windows -lbcrypt
#include <bcrypt.h>
const status_success = 0x00000000
const bcrypt_use_system_preferred_rng = 0x00000002
// read returns an array of `bytes_needed` random bytes read from the OS.
pub fn read(bytes_needed int) ![]u8 {
mut buffer := []u8{len: bytes_needed}
// use bcrypt_use_system_preferred_rng because we passed null as algo
status := C.BCryptGenRandom(0, buffer.data, bytes_needed, bcrypt_use_system_preferred_rng)
if status != status_success {
return &ReadError{}
}
return buffer
}
+95
View File
@@ -0,0 +1,95 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module rand
import math.bits
import math.big
import encoding.binary
// int_u64 returns a random unsigned 64-bit integer `u64` read from a real OS source of entropy.
pub fn int_u64(max u64) !u64 {
bitlen := bits.len_64(max)
if bitlen == 0 {
return u64(0)
}
k := (bitlen + 7) / 8
mut b := u64(bitlen % 8)
if b == u64(0) {
b = u64(8)
}
mut n := u64(0)
for {
mut buf := read(k)!
buf[0] &= u8(int(u64(1) << b) - 1)
x := bytes_to_u64(buf)
n = x[0]
// NOTE: maybe until we have bigint could do it another way?
// if x.len > 1 {
// n = u64(u32(x[1])<<u32(32)) | n
// }
if n < max {
return n
}
}
return n
}
fn bytes_to_u64(b []u8) []u64 {
ws := 64 / 8
mut z := []u64{len: ((b.len + ws - 1) / ws)}
mut i := b.len
for k := 0; i >= ws; k++ {
z[k] = binary.big_endian_u64(b[i - ws..i])
i -= ws
}
if i > 0 {
mut d := u64(0)
for s := u64(0); i > 0; s += u64(8) {
d |= u64(b[i - 1]) << s
i--
}
z[z.len - 1] = d
}
return z
}
// int_big creates a random `big.Integer` with range [0, n)
// returns an error if `n` is 0 or negative.
pub fn int_big(n big.Integer) !big.Integer {
if n.signum < 1 {
return error('`n` cannot be 0 or negative.')
}
max := n - big.integer_from_int(1)
len := max.bit_len()
if len == 0 {
// max = n - 1, if max = 0 then return max, as it is the only valid integer in [0, 1)
return max
}
// k is the maximum byte length needed to encode a value < n
k := (len + 7) / 8
// b is the number of bits in the most significant byte of n-1
mut b := u8(len % 8)
if b == 0 {
b = 8
}
mut result := big.Integer{}
for {
mut buf := read(k)!
// Clear bits in the first byte to increase the probability that the result is < max
buf[0] &= u8(int(1 << b) - 1)
result = big.integer_from_bytes(buf)
if result < max {
break
}
}
return result
}
+23
View File
@@ -0,0 +1,23 @@
import math.big
import crypto.rand
fn test_int_big() {
z := big.integer_from_int(0)
if _ := rand.int_big(z) {
assert false
} else {
assert true
}
n := big.integer_from_int(-1)
if _ := rand.int_big(n) {
assert false
} else {
assert true
}
m := big.integer_from_int(1).left_shift(128)
l := rand.int_big(m)! // actual large number
assert l < m
assert l > n
}