init: v1.0.0
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
)
|
||||
|
||||
var defaultConfig1 = &internal.DrngConfig{
|
||||
Seedlen: 440 >> 3,
|
||||
Outlen: 256 >> 3,
|
||||
ReseedIntervalInTime: time.Second * 600,
|
||||
ReseedIntervalInCounter: 1 << 20,
|
||||
MinEntropy: 256 >> 3,
|
||||
MinEntropyInputLength: 256 >> 3,
|
||||
MaxEntropyInputLength: (1 << 35) >> 3,
|
||||
}
|
||||
|
||||
// 安全级别2的配置
|
||||
var defaultConfig2 = &internal.DrngConfig{
|
||||
Seedlen: 440 >> 3,
|
||||
Outlen: 256 >> 3,
|
||||
ReseedIntervalInTime: time.Second * 60,
|
||||
ReseedIntervalInCounter: 1 << 10,
|
||||
MinEntropy: 256 >> 3,
|
||||
MinEntropyInputLength: 256 >> 3,
|
||||
MaxEntropyInputLength: (1 << 35) >> 3,
|
||||
}
|
||||
|
||||
func Config(level internal.SecureLevel) *internal.DrngConfig {
|
||||
switch level {
|
||||
case internal.SecureLevel1:
|
||||
return defaultConfig1
|
||||
case internal.SecureLevel2:
|
||||
return defaultConfig2
|
||||
default:
|
||||
panic("unsupported secure level")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
|
||||
"xdx.jelly/xgcl/sm"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
var _ = sm3.BlockSize // import sm3
|
||||
|
||||
// 内部状态
|
||||
type internalState struct {
|
||||
v []byte
|
||||
c []byte
|
||||
|
||||
reseedCounter uint32
|
||||
lastReseedTime time.Time
|
||||
}
|
||||
|
||||
// zeromize 对内部状态置0
|
||||
func (s *internalState) zeromize() {
|
||||
for i := 0; i < len(s.v); i++ {
|
||||
s.v[i] = 0
|
||||
}
|
||||
|
||||
for i := 0; i < len(s.c); i++ {
|
||||
s.c[i] = 0
|
||||
}
|
||||
|
||||
s.reseedCounter = 0
|
||||
}
|
||||
|
||||
type HashDrng struct {
|
||||
// mu sync.Mutex
|
||||
config internal.DrngConfig
|
||||
hash sm.Hash
|
||||
df func(input []byte, n int) []byte
|
||||
state internalState
|
||||
personalizationString []byte //个性化字符串,来自应用的比特串
|
||||
}
|
||||
|
||||
// Read implements internal.internal.
|
||||
// func (hd *HashDrng) Read(p []byte) (n int, err error) {
|
||||
// return len(p), hd.Generate(p, nil)
|
||||
// }
|
||||
|
||||
// var SM3_df = newDF(sm.SM3)
|
||||
|
||||
// newDF 返回一个使用hash作为杂凑的df函数
|
||||
// 例:SM3_df = newDF(sm.SM3)
|
||||
func newDF(hash sm.Hash) func(input []byte, n int) []byte {
|
||||
h := hash.New()
|
||||
return func(input []byte, n int) []byte {
|
||||
out := make([]byte, 0, n+hash.Size()-1)
|
||||
len := (n + hash.Size() - 1) / hash.Size()
|
||||
counter := uint32(1)
|
||||
buf := make([]byte, 8)
|
||||
for i := 0; i < len; i++ {
|
||||
binary.BigEndian.PutUint32(buf, counter)
|
||||
binary.BigEndian.PutUint32(buf[4:], uint32(n<<3))
|
||||
h.Write(buf)
|
||||
h.Write(input)
|
||||
out = h.Sum(out)
|
||||
h.Reset()
|
||||
counter += 1
|
||||
}
|
||||
return out[:n]
|
||||
}
|
||||
}
|
||||
|
||||
// func New(hash sm.Hash, config *internal.DrngConfig) (internal.Drng, error) {
|
||||
// raw, _ := NewHashDrng(hash, config)
|
||||
// pool := entropy.GetEntropyPool()
|
||||
// d, err := raw.Instantiate([]byte(internal.PERSONALIZATIONSTRING), internal.Nonce(), pool)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return &drng.DrngUtil{
|
||||
// Drng: d,
|
||||
// ReseedSource: pool,
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
func NewHashDrng(hash sm.Hash, config *internal.DrngConfig) (internal.RawDrng, error) {
|
||||
hd := &HashDrng{
|
||||
hash: hash,
|
||||
df: newDF(hash),
|
||||
config: *config,
|
||||
}
|
||||
|
||||
// HashDrng 析构时对内部状态置0
|
||||
runtime.SetFinalizer(hd, func(hd *HashDrng) {
|
||||
hd.state.zeromize()
|
||||
})
|
||||
return hd, nil
|
||||
}
|
||||
|
||||
func (hd *HashDrng) OutLen() int {
|
||||
return hd.config.Outlen
|
||||
}
|
||||
|
||||
func (hd *HashDrng) Config() *internal.DrngConfig {
|
||||
return &hd.config
|
||||
}
|
||||
|
||||
// Instantiate 初始化HashDrng
|
||||
func (hd *HashDrng) Instantiate(personalizationString []byte, nonce []byte, entropySource io.Reader) (internal.Drng, error) {
|
||||
// hd.mu.Lock()
|
||||
// defer hd.mu.Unlock()
|
||||
|
||||
cfg := hd.config
|
||||
hd.personalizationString = personalizationString
|
||||
|
||||
seedMaterial := make([]byte, 2*cfg.MinEntropyInputLength, int(2*cfg.MinEntropyInputLength)+len(nonce)+len(personalizationString))
|
||||
var m, n int
|
||||
var err error
|
||||
var errCount int
|
||||
for n < int(cfg.MinEntropyInputLength) {
|
||||
m, err = entropySource.Read(seedMaterial[n:])
|
||||
n += m
|
||||
if err != nil {
|
||||
errCount++
|
||||
}
|
||||
if errCount > 3 {
|
||||
return hd, err
|
||||
}
|
||||
}
|
||||
seedMaterial = append(seedMaterial, nonce...)
|
||||
seedMaterial = append(seedMaterial, personalizationString...)
|
||||
seed := hd.df(seedMaterial, cfg.Seedlen)
|
||||
|
||||
//初始化内部状态变量
|
||||
hd.state.v = append(hd.state.v[:0], seed...)
|
||||
hd.state.c = append(hd.state.c[:0], hd.df(append([]byte{0}, seed...), cfg.Seedlen)...)
|
||||
hd.state.reseedCounter = 1
|
||||
hd.state.lastReseedTime = time.Now()
|
||||
|
||||
// seed和seedMaterial置0
|
||||
for i := 0; i < len(seed); i++ {
|
||||
seed[i] = 0
|
||||
}
|
||||
for i := 0; i < len(seedMaterial); i++ {
|
||||
seedMaterial[i] = 0
|
||||
}
|
||||
return hd, nil
|
||||
}
|
||||
|
||||
// Reseed 更新HashDrng的内部状态
|
||||
func (hd *HashDrng) Reseed(entropyInput, additionalInput []byte) {
|
||||
// hd.mu.Lock()
|
||||
// defer hd.mu.Unlock()
|
||||
|
||||
seedMaterial := make([]byte, 1, 1+len(entropyInput)+len(hd.state.v)+len(additionalInput))
|
||||
seedMaterial[0] = 1
|
||||
seedMaterial = append(seedMaterial, entropyInput...)
|
||||
seedMaterial = append(seedMaterial, hd.state.v...)
|
||||
seedMaterial = append(seedMaterial, additionalInput...)
|
||||
|
||||
seed := hd.df(seedMaterial, hd.config.Seedlen)
|
||||
copy(hd.state.v, seed)
|
||||
hd.state.c = append(hd.state.c[:0], hd.df(append([]byte{0}, seed...), hd.config.Seedlen)...)
|
||||
hd.state.reseedCounter = 1
|
||||
hd.state.lastReseedTime = time.Now()
|
||||
|
||||
// seed和seedMaterial置0
|
||||
for i := 0; i < len(seed); i++ {
|
||||
seed[i] = 0
|
||||
}
|
||||
for i := 0; i < len(seedMaterial); i++ {
|
||||
seedMaterial[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Generate 输出函数
|
||||
func (hd *HashDrng) Generate(b []byte, additionalInput []byte) error {
|
||||
// hd.mu.Lock()
|
||||
// defer hd.mu.Unlock()
|
||||
|
||||
if len(b) > hd.config.Outlen {
|
||||
return internal.ErrReturnedBitsTooLong
|
||||
}
|
||||
|
||||
// 需要重播种
|
||||
if hd.state.reseedCounter > uint32(hd.config.ReseedIntervalInCounter) ||
|
||||
time.Since(hd.state.lastReseedTime) > hd.config.ReseedIntervalInTime {
|
||||
return internal.ErrNeedReseed
|
||||
}
|
||||
hash := hd.hash.New()
|
||||
if len(additionalInput) > 0 {
|
||||
hash.Write([]byte{2})
|
||||
hash.Write(hd.state.v)
|
||||
hash.Write(additionalInput)
|
||||
W := hash.Sum(nil)
|
||||
internal.AddModBytes(hd.state.v, W)
|
||||
}
|
||||
hash.Reset()
|
||||
_, _ = hash.Write(hd.state.v)
|
||||
temp := hash.Sum(nil)
|
||||
copy(b, temp)
|
||||
hash.Reset()
|
||||
hash.Write([]byte{3})
|
||||
hash.Write(hd.state.v)
|
||||
H := hash.Sum(nil)
|
||||
|
||||
reseedCounterBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(reseedCounterBytes, hd.state.reseedCounter)
|
||||
|
||||
internal.AddModBytes(hd.state.v, H[:])
|
||||
internal.AddModBytes(hd.state.v, hd.state.c)
|
||||
internal.AddModBytes(hd.state.v, reseedCounterBytes)
|
||||
hd.state.reseedCounter++
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
_ "crypto/sha256"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/entropy"
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
func TestSysEntropySource(t *testing.T) {
|
||||
e := entropy.GetEntropyPool()
|
||||
b, err := e.GetEntropy(128, 128, 128)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%x\n", b)
|
||||
}
|
||||
|
||||
func TestSm3Df(t *testing.T) {
|
||||
input := make([]byte, 10)
|
||||
for n := 0; n < 100; n++ {
|
||||
output := newDF(sm.SM3)(input, n)
|
||||
if len(output) != n {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0.03GBps, 主要是internal.Outlen太小
|
||||
func TestDrngSpeed(t *testing.T) {
|
||||
raw, _ := NewHashDrng(sm.SM3, Config(internal.SecureLevel2))
|
||||
rng, _ := raw.Instantiate(nil, internal.Nonce(), entropy.GetEntropyPool())
|
||||
msg := make([]byte, rng.OutLen())
|
||||
|
||||
start := time.Now()
|
||||
times := 10000
|
||||
buf := make([]byte, 32)
|
||||
for i := 0; i < times; i++ {
|
||||
if err := rng.Generate(msg, nil); err == internal.ErrNeedReseed {
|
||||
entropy.GetEntropyPool().Read(buf)
|
||||
rng.Reseed(buf, nil)
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
t.Logf("Generate Random speed: %.2f MBps\n", float64(times*len(msg))/float64(1024*1024)/elapsed.Seconds())
|
||||
}
|
||||
|
||||
// func TestSm3DrngRandomness(t *testing.T) {
|
||||
// // 测试Sm3Drng的随机性测试通过率
|
||||
// total := 10
|
||||
// pass := 0
|
||||
// for i := 0; i < total; i++ {
|
||||
// fmt.Println("======================================", i)
|
||||
// if statistics.SampleSelfTests(Reader) {
|
||||
// fmt.Printf("%d-th test: [O]\n", i)
|
||||
// pass += 1
|
||||
// } else {
|
||||
// fmt.Printf("%d-th test: [X]\n", i)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fmt.Printf("Pass Rate: %d/%d\n", pass, total)
|
||||
// }
|
||||
@@ -0,0 +1,24 @@
|
||||
package hashrng
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
|
||||
"xdx.jelly/xgcl/grand/drng/internal"
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
// 随机数发生器的已知答案检测
|
||||
func KAT() bool {
|
||||
raw, _ := NewHashDrng(sm.SM3, Config(internal.SecureLevel2))
|
||||
nonce, _ := hex.DecodeString("0001020304050607")
|
||||
entropy, _ := hex.DecodeString("C4F7D581BEFEF25C8BBB6DAD52A6AB8234FA7DB7A988592BC592DAF2BE630647")
|
||||
rng, _ := raw.Instantiate(nil, nonce, bytes.NewReader(entropy))
|
||||
additionalInput, _ := hex.DecodeString("00010203040506")
|
||||
|
||||
rand := make([]byte, 32)
|
||||
rng.Generate(rand, additionalInput)
|
||||
|
||||
wanted, _ := hex.DecodeString("a6e3c0ad539fa0c211b23e3aa7c3b92482bfc77fcb9864690e832bcda4357046")
|
||||
return bytes.Compare(rand, wanted) == 0
|
||||
}
|
||||
Reference in New Issue
Block a user