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
+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
}