init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
package cpu
//go:noescape
func cpuid() uint64
+7
View File
@@ -0,0 +1,7 @@
#include "textflag.h"
// __asm__("mrs %0, MIDR_EL1" : "=r"(arm_cpuid));
TEXT ·cpuid(SB), NOSPLIT, $0
MRS MIDR_EL1, R0
MOVD R0, res+0(FP)
RET
+10
View File
@@ -0,0 +1,10 @@
package cpu
import (
"fmt"
"testing"
)
func TestCPUID(t *testing.T) {
fmt.Println(cpuid())
}
+142
View File
@@ -0,0 +1,142 @@
package entropy
import (
"fmt"
"math"
)
func MarkovTests(data []byte, verbose bool) float64 {
// 将data转换为0,1比特串表示
epsilon := make([]byte, 0, len(data)*8)
for _, b := range data {
epsilon = append(epsilon, (b>>7)&1)
epsilon = append(epsilon, (b>>6)&1)
epsilon = append(epsilon, (b>>5)&1)
epsilon = append(epsilon, (b>>4)&1)
epsilon = append(epsilon, (b>>3)&1)
epsilon = append(epsilon, (b>>2)&1)
epsilon = append(epsilon, (b>>1)&1)
epsilon = append(epsilon, (b>>0)&1)
}
// double markov_test(byte* data, long len, const int verbose, const char *label){
var i, C_0, C_1, C_00, C_10 int64
var H_min, tmp_min_entropy, P_0, P_1, P_00, P_01, P_10, P_11, entEst float64
C_0 = 0
C_00 = 0
C_10 = 0
dataLen := int64(len(epsilon))
// get counts for unconditional and transition probabilities
for i = 0; i < dataLen-1; i++ {
if epsilon[i] == 0 {
C_0++
if epsilon[i+1] == 0 {
C_00++
}
} else if epsilon[i+1] == 0 {
C_10++
}
}
//C_0 is now the number of 0 bits from S[0] to S[len-2]
C_1 = dataLen - 1 - C_0 //C_1 is the number of 1 bits from S[0] to S[len-2]
//Note that P_X1 = C_X1 / C_X = (C_X - C_X0)/C_X = 1.0 - C_X0/C_X = 1.0 - P_X0
if C_0 > 0 {
P_00 = float64(C_00) / float64(C_0)
P_01 = 1.0 - P_00
} else {
P_00 = 0.0
P_01 = 0.0
}
if C_1 > 0 {
P_10 = float64(C_10) / float64(C_1)
P_11 = 1.0 - P_10
} else {
P_10 = 0.0
P_11 = 0.0
}
// account for the last symbol
if epsilon[dataLen-1] == 0 {
C_0++
}
//C_0 is now the number of 0 bits from S[0] to S[len-1]
P_0 = float64(C_0) / float64(dataLen)
P_1 = 1.0 - P_0
if verbose {
fmt.Printf("P_0 = %.17g\n", P_0)
fmt.Printf("P_1 = %.17g\n", P_1)
fmt.Printf("P_{0,0} = %.17g\n", P_00)
fmt.Printf("P_{0,1} = %.17g\n", P_01)
fmt.Printf("P_{1,0} = %.17g\n", P_10)
fmt.Printf("P_{1,1} = %.17g\n", P_11)
}
H_min = 128.0
//In the next block, note that if P_0X > 0.0, then P_0 > 0.0
//and similarly if P_1X > 0.0, then P_1 > 0.0
// Sequence 00...0
if P_00 > 0.0 {
tmp_min_entropy = -math.Log2(P_0) - 127.0*math.Log2(P_00)
if tmp_min_entropy < H_min {
H_min = tmp_min_entropy
}
}
// Sequence 0101...01
if (P_01 > 0.0) && (P_10 > 0.0) {
tmp_min_entropy = -math.Log2(P_0) - 64.0*math.Log2(P_01) - 63.0*math.Log2(P_10)
if tmp_min_entropy < H_min {
H_min = tmp_min_entropy
}
}
// Sequence 011...1
if (P_01 > 0.0) && (P_11 > 0.0) {
tmp_min_entropy = -math.Log2(P_0) - math.Log2(P_01) - 126.0*math.Log2(P_11)
if tmp_min_entropy < H_min {
H_min = tmp_min_entropy
}
}
// Sequence 100...0
if (P_10 > 0.0) && (P_00 > 0.0) {
tmp_min_entropy = -math.Log2(P_1) - math.Log2(P_10) - 126.0*math.Log2(P_00)
if tmp_min_entropy < H_min {
H_min = tmp_min_entropy
}
}
// Sequence 1010...10
if (P_10 > 0.0) && (P_01 > 0.0) {
tmp_min_entropy = -math.Log2(P_1) - 64.0*math.Log2(P_10) - 63.0*math.Log2(P_01)
if tmp_min_entropy < H_min {
H_min = tmp_min_entropy
}
}
// Sequence 11...1
if P_11 > 0.0 {
tmp_min_entropy = -math.Log2(P_1) - 127.0*math.Log2(P_11)
if tmp_min_entropy < H_min {
H_min = tmp_min_entropy
}
}
entEst = math.Min(H_min/128.0, 1.0)
if verbose {
fmt.Printf("p_max = %.17g\n", math.Pow(2.0, -H_min))
fmt.Printf("min entropy = %.17g\n", entEst)
}
return entEst
}
+179
View File
@@ -0,0 +1,179 @@
package entropy
import (
"crypto/rand"
"encoding/binary"
"errors"
"sync"
"time"
"xdx.jelly/xgcl/grand/drng/internal"
)
var OutOfEntropyErr = errors.New("out of entropy")
// Read reads at most 32 bytes into p.
// For efficiency, reads bytes are always multiples of 4.
func (e *EntropyPool) Read(p []byte) (int, error) {
entropyPool.mu.Lock()
if entropyPool.entropySize <= 0 {
return 0, OutOfEntropyErr
}
// n = min(8, entropyPool.entropySize, len(p) / 4)
n := 8
if entropyPool.entropySize < 8 {
n = entropyPool.entropySize
}
if (len(p) / 4) < n {
n = len(p) / 4
}
for i := 0; i < n; i++ {
x, _ := entropyPool.get() // err should not happen
binary.BigEndian.PutUint32(p[4*i:], x)
}
entropyPool.mu.Unlock()
go e.update() // update the entropy pool for next reading.
return 4 * n, nil
}
// EntropyPool 系统熵池
type EntropyPool struct {
mu sync.Mutex //使用互斥锁保证独占性
pool [128]uint32 //熵池,128个字(512字节)
// i - j 之间是未取的熵(mod 128)
i int //熵索引开始
j int //熵索引结束
entropySize int //熵池中可用熵值
source []EntropySource
}
// entropySource 熵源
type EntropySource interface {
GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error)
}
var entropyPool *EntropyPool
var initEntropyPool sync.Once
func init() {
initEntropyPool.Do(
func() {
entropyPool = newEntropyPool()
})
go func() {
// 定时从系统中获取
tickle := time.NewTicker(10 * time.Second)
for {
select {
case <-tickle.C:
entropyPool.update()
}
}
}()
}
func GetEntropyPool() *EntropyPool {
return entropyPool
}
func newEntropyPool() *EntropyPool {
// FIXME: SysTimeEntropySource
p := &EntropyPool{
source: []EntropySource{&OSEntropySource{}, &SysTimeEntropySource{}},
// source: []drng.EntropySource{&OSEntropySource{}},
}
buf := make([]byte, 128*4)
_, _ = rand.Reader.Read(buf)
for i := 0; i < 128; i++ {
p.pool[i] = binary.BigEndian.Uint32(buf[4*i:])
}
// 从每个熵源获取至少256比特
p.update()
// 对buf置0
for i := range buf {
buf[i] = 0
}
// for i := range e {
// e[i] = 0
// }
return p
}
func (e *EntropyPool) get() (uint32, error) {
if e.entropySize <= 0 {
return 0, OutOfEntropyErr
}
n := e.pool[e.i]
e.i = (e.i + 1) & 127
e.entropySize--
return n, nil
}
// lshr 添加新的熵数据g到熵池中。按照GM/T 0105 A.3的方式
func (e *EntropyPool) lshr(g uint32) {
var table = [8]uint32{0, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278}
temp := g ^ e.pool[e.j]
for _, i := range []int{1, 25, 51, 76, 103} {
temp ^= e.pool[(e.j+i)&127]
}
temp = (temp >> 3) ^ table[temp&7]
e.pool[e.j] = temp
e.j = (e.j + 1) & 127
// 置0
temp = 0
_ = temp
}
// Update 熵池更新
func (e *EntropyPool) update() {
e.mu.Lock()
defer e.mu.Unlock()
// 设置超时时间
tickle := time.NewTicker(100 * time.Millisecond)
defer tickle.Stop()
for i := 0; e.entropySize < 128; i = (i + 1) % len(e.source) {
select {
case <-tickle.C:
break
default:
s := e.source[i]
b, _ := s.GetEntropy(4, 4, internal.MaxEntropyInputLength)
if len(b) >= 4 {
e.lshr(binary.BigEndian.Uint32(b))
e.entropySize++
}
}
}
}
func (e *EntropyPool) GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error) {
e.mu.Lock()
defer e.mu.Unlock()
if minEntropyInputLength < internal.MinEntropyInputLength || maxEntropyInputLength > internal.MaxEntropyInputLength {
return nil, internal.ErrEntropyLength
}
entropy := make([]byte, minEntropyInputLength)
buf := make([]byte, 4)
var i int
for i = 0; int64(i) < minEntropyInputLength && e.entropySize > 0; i += 4 {
binary.BigEndian.PutUint32(buf, e.pool[e.i])
copy(entropy[i:], buf)
e.i = (e.i + 1) & 127
e.entropySize--
}
return entropy[:i], nil
}
+27
View File
@@ -0,0 +1,27 @@
package entropy
import (
"crypto/rand"
"sync"
)
type OSEntropySource struct {
mu sync.Mutex
}
func (e *OSEntropySource) GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error) {
//使用互斥锁保证熵源的独占性
e.mu.Lock()
defer e.mu.Unlock()
n := minEntropy
if n < minEntropyInputLength {
n = minEntropyInputLength
}
entropy := make([]byte, n)
if _, err := rand.Reader.Read(entropy); err != nil {
return nil, err
}
return entropy, nil
}
+41
View File
@@ -0,0 +1,41 @@
package entropy
import (
"sync"
"xdx.jelly/xgcl/grand/drng/entropy/rdtsc"
)
// SysTimeEntropySource 系统时间熵源
type SysTimeEntropySource struct {
mu sync.Mutex
}
// GetEntropy
func (e *SysTimeEntropySource) GetEntropy(minEntropy int64, minEntropyInputLength int64, maxEntropyInputLength int64) ([]byte, error) {
//使用互斥锁保证熵源的独占性
e.mu.Lock()
defer e.mu.Unlock()
// SysTimeEntropySource熵源的Markov测试min entropy ~ 0.58
// 因此向熵源最少要取minEntropy / 0.58 ~ 2*minEntropy
n := minEntropy << 1
if n < minEntropyInputLength {
n = minEntropyInputLength
}
entropy := make([]byte, n)
for i := int64(0); i < n; i++ {
// var b byte
// for j := 0; j < 8; j++ {
// t := rdtsc.GetCPUTimeStamp()
// // xor of the the last two bits are used.
// // for a rdtsc usually used 20~50 cycles.
// // b |= byte((t^(t>>1)^(t>>2)^(t>>3))&1) << j
// b |= byte(t&1) << j
// }
// entropy[i] = b
entropy[i] = byte(rdtsc.GetCPUTimeStamp())
}
return entropy, nil
}
+28
View File
@@ -0,0 +1,28 @@
package entropy
import (
"testing"
)
func TestMarkovSimple(t *testing.T) {
data := []byte{0b10001110, 0b01010101, 0b11001100, 0b01110010, 0b10101110}
h := MarkovTests(data, false)
if h-0.761 > 0.01 {
t.Fatal()
}
}
func TestMarkov(t *testing.T) {
// 系统熵源
// entropy := OSEntropySource{}
entropy := SysTimeEntropySource{}
data, _ := entropy.GetEntropy(1000000/8, 1000000/8, 1000000/8)
MarkovTests(data, false)
}
func TestEntropyPoll(t *testing.T) {
pool := &EntropyPool{}
for i := 0; i < 100; i++ {
pool.lshr(0)
}
}
+7
View File
@@ -0,0 +1,7 @@
#include "textflag.h"
TEXT ·RDSeed(SB), NOSPLIT, $0
MRS RNDR, R0
MOVD R0, res+0(FP)
RET
+9
View File
@@ -0,0 +1,9 @@
//go:build amd64 || arm64
// +build amd64 arm64
package rdseed
const SupportRDSEED = true
//go:noescape
func RDSeed() uint64
+12
View File
@@ -0,0 +1,12 @@
package rdseed
import (
"fmt"
"testing"
)
func TestRDSEED(t *testing.T) {
for i := 0; i < 10; i++ {
fmt.Printf("%x\n", RDSeed())
}
}
+17
View File
@@ -0,0 +1,17 @@
# In linux
```
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>
static long long GetThreadCpuTimeNs() {
struct timespec t;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t)) {
perror("clock_gettime");
return 0;
}
return t.tv_nsec;
}
```
Makov测试熵估计0.5-0.6
+10
View File
@@ -0,0 +1,10 @@
#include "textflag.h"
TEXT ·GetCPUTimeStamp(SB), NOSPLIT, $0
RDTSCP // save time stamp counter in DX:AX
SHLQ $32, DX
ORQ DX, AX
MOVQ AX, res+0(FP)
RET
+9
View File
@@ -0,0 +1,9 @@
#include "textflag.h"
TEXT ·GetCPUTimeStamp(SB), NOSPLIT, $0
MRS CNTVCT_EL0, R0
MOVD R0, res+0(FP)
RET
+9
View File
@@ -0,0 +1,9 @@
//go:build amd64 || arm64
// +build amd64 arm64
package rdtsc
const SupportRDTSC = true
//go:noescape
func GetCPUTimeStamp() uint64
+9
View File
@@ -0,0 +1,9 @@
//go:build !amd64 && !arm64
package rdtsc
const SupportRDTSC = false
func GetCPUTimeStamp() uint64 {
panic("unsupported")
}
+12
View File
@@ -0,0 +1,12 @@
package rdtsc
import (
"fmt"
"testing"
)
func TestRDTSC(t *testing.T) {
for i := 0; i < 10; i++ {
fmt.Printf("%x\n", GetCPUTimeStamp())
}
}