init: v1.0.0
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
package cpu
|
||||
|
||||
//go:noescape
|
||||
func cpuid() uint64
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCPUID(t *testing.T) {
|
||||
fmt.Println(cpuid())
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
TEXT ·RDSeed(SB), NOSPLIT, $0
|
||||
MRS RNDR, R0
|
||||
MOVD R0, res+0(FP)
|
||||
RET
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build amd64 || arm64
|
||||
// +build amd64 arm64
|
||||
|
||||
package rdseed
|
||||
|
||||
const SupportRDSEED = true
|
||||
|
||||
//go:noescape
|
||||
func RDSeed() uint64
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
TEXT ·GetCPUTimeStamp(SB), NOSPLIT, $0
|
||||
MRS CNTVCT_EL0, R0
|
||||
MOVD R0, res+0(FP)
|
||||
RET
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build amd64 || arm64
|
||||
// +build amd64 arm64
|
||||
|
||||
package rdtsc
|
||||
|
||||
const SupportRDTSC = true
|
||||
|
||||
//go:noescape
|
||||
func GetCPUTimeStamp() uint64
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build !amd64 && !arm64
|
||||
|
||||
package rdtsc
|
||||
|
||||
const SupportRDTSC = false
|
||||
|
||||
func GetCPUTimeStamp() uint64 {
|
||||
panic("unsupported")
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user