runtime: add runtime.rand function

This function is needed for Go 1.22, and is used from various packages
like math/rand.

When there is no random number generator available, it falls back to a
static sequence of numbers. I think this is fine, because as far as I
can see it is only used for non-cryptographic needs.
Этот коммит содержится в:
Ayke van Laethem 2024-01-18 21:27:08 +01:00
родитель 204659bdcd
коммит e9003e2deb
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
11 изменённых файлов: 102 добавлений и 1 удалений

Просмотреть файл

@ -838,6 +838,7 @@ endif
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src

Просмотреть файл

@ -119,6 +119,7 @@ var Musl = Library{
"internal/syscall_ret.c",
"internal/vdso.c",
"legacy/*.c",
"linux/*.c",
"malloc/*.c",
"malloc/mallocng/*.c",
"mman/*.c",

Просмотреть файл

@ -1,4 +1,7 @@
//go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x) || esp32c3
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3
// If you update the above build constraint, you'll probably also need to update
// src/runtime/rand_hwrng.go.
package rand

Просмотреть файл

@ -16,6 +16,8 @@ func rand_fastrand64() uint64 {
}
// This function is used by hash/maphash.
// This function isn't required anymore since Go 1.22, so should be removed once
// that becomes the minimum requirement.
func fastrand() uint32 {
xorshift32State = xorshift32(xorshift32State)
return xorshift32State
@ -34,6 +36,8 @@ func xorshift32(x uint32) uint32 {
}
// This function is used by hash/maphash.
// This function isn't required anymore since Go 1.22, so should be removed once
// that becomes the minimum requirement.
func fastrand64() uint64 {
xorshift64State = xorshiftMult64(xorshift64State)
return xorshift64State
@ -56,3 +60,16 @@ func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
}
return uintptr(hash32(p, s, seed))
}
// Function that's called from various packages starting with Go 1.22.
func rand() uint64 {
// Return a random number from hardware, falling back to software if
// unavailable.
n, ok := hardwareRand()
if !ok {
// Fallback to static random number.
// Not great, but we can't do much better than this.
n = fastrand64()
}
return n
}

Просмотреть файл

@ -112,3 +112,14 @@ func findGlobals(found func(start, end uintptr)) {
cmd = (*segmentLoadCommand)(unsafe.Add(unsafe.Pointer(cmd), cmd.cmdsize))
}
}
func hardwareRand() (n uint64, ok bool) {
n |= uint64(libc_arc4random())
n |= uint64(libc_arc4random()) << 32
return n, true
}
// uint32_t arc4random(void);
//
//export arc4random
func libc_arc4random() uint32

Просмотреть файл

@ -120,3 +120,16 @@ func libc_getpagesize() int
func syscall_Getpagesize() int {
return libc_getpagesize()
}
func hardwareRand() (n uint64, ok bool) {
read := libc_getrandom(unsafe.Pointer(&n), 8, 0)
if read != 8 {
return 0, false
}
return n, true
}
// ssize_t getrandom(void buf[.buflen], size_t buflen, unsigned int flags);
//
//export getrandom
func libc_getrandom(buf unsafe.Pointer, buflen uintptr, flags uint32) uint32

16
src/runtime/rand_hwrng.go Обычный файл
Просмотреть файл

@ -0,0 +1,16 @@
//go:build baremetal && (nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3)
// If you update the above build constraint, you'll probably also need to update
// src/crypto/rand/rand_baremetal.go.
package runtime
import "machine"
func hardwareRand() (n uint64, ok bool) {
n1, err1 := machine.GetRNG()
n2, err2 := machine.GetRNG()
n = uint64(n1)<<32 | uint64(n2)
ok = err1 == nil && err2 == nil
return
}

7
src/runtime/rand_norng.go Обычный файл
Просмотреть файл

@ -0,0 +1,7 @@
//go:build baremetal && !(nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3)
package runtime
func hardwareRand() (n uint64, ok bool) {
return 0, false // no RNG available
}

Просмотреть файл

@ -308,3 +308,8 @@ func svcOutputDebugString(str *uint8, size uint64) uint64
//
//export svcGetInfo
func svcGetInfo(output *uint64, id0 uint32, handle uint32, id1 uint64) uint64
func hardwareRand() (n uint64, ok bool) {
// TODO: see whether there is a RNG and use it.
return 0, false
}

Просмотреть файл

@ -85,3 +85,14 @@ func procPin() {
//go:linkname procUnpin sync/atomic.runtime_procUnpin
func procUnpin() {
}
func hardwareRand() (n uint64, ok bool) {
n |= uint64(libc_arc4random())
n |= uint64(libc_arc4random()) << 32
return n, true
}
// uint32_t arc4random(void);
//
//export arc4random
func libc_arc4random() uint32

Просмотреть файл

@ -228,3 +228,19 @@ func procPin() {
//go:linkname procUnpin sync/atomic.runtime_procUnpin
func procUnpin() {
}
func hardwareRand() (n uint64, ok bool) {
var n1, n2 uint32
errCode1 := libc_rand_s(&n1)
errCode2 := libc_rand_s(&n2)
n = uint64(n1)<<32 | uint64(n2)
ok = errCode1 == 0 && errCode2 == 0
return
}
// Cryptographically secure random number generator.
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rand-s?view=msvc-170
// errno_t rand_s(unsigned int* randomValue);
//
//export rand_s
func libc_rand_s(randomValue *uint32) int32