Files
2026-05-27 23:03:00 +08:00

220 lines
5.3 KiB
Go

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
}