149 lines
3.1 KiB
Go
149 lines
3.1 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"encoding/binary"
|
||
|
"encoding/hex"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
)
|
||
|
|
||
|
type SHISHUA struct {
|
||
|
state [16]uint64
|
||
|
output [16]uint64
|
||
|
counter [4]uint64
|
||
|
}
|
||
|
|
||
|
var phi = [16]uint64{
|
||
|
0x9E3779B97F4A7C15, 0xF39CC0605CEDC834, 0x1082276BF3A27251, 0xF86C6A11D0C18E95,
|
||
|
0x2767F0B153D27B7F, 0x0347045B5BF1827F, 0x01886F0928403002, 0xC1D64BA40F335E36,
|
||
|
0xF06AD7AE9717877E, 0x85839D6EFFBD7DC6, 0x64D325D1C5371682, 0xCADD0CCCFDFFBBE1,
|
||
|
0x626E33B8D04B4331, 0xBBF73C790D94F79D, 0x471C4AB3ED3D82A5, 0xFEC507705E4AE6E5,
|
||
|
}
|
||
|
|
||
|
func (srng *SHISHUA) shuffle() {
|
||
|
for j := 0; j < 2; j++ {
|
||
|
s := srng.state[j*8 : (j+1)*8]
|
||
|
o := srng.output[j*4 : (j+1)*4]
|
||
|
var t [8]uint64
|
||
|
|
||
|
for k := 0; k < 4; k++ {
|
||
|
s[k+4] += srng.counter[k]
|
||
|
}
|
||
|
|
||
|
shufOffsets := []uint8{2, 3, 0, 1, 5, 6, 7, 4, 3, 0, 1, 2, 6, 7, 4, 5}
|
||
|
for k := 0; k < 8; k++ {
|
||
|
t[k] = (s[shufOffsets[k]] >> 32) | (s[shufOffsets[k+8]] << 32)
|
||
|
}
|
||
|
|
||
|
for k := 0; k < 4; k++ {
|
||
|
uLo := s[k] >> 1
|
||
|
uHi := s[k+4] >> 3
|
||
|
s[k] = uLo + t[k]
|
||
|
s[k+4] = uHi + t[k+4]
|
||
|
o[k] = uLo ^ t[k+4]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for j := 0; j < 4; j++ {
|
||
|
srng.output[j+8] = srng.state[j] ^ srng.state[j+12]
|
||
|
srng.output[j+12] = srng.state[j+8] ^ srng.state[j+4]
|
||
|
srng.counter[j] += 7 - uint64(j*2)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (srng *SHISHUA) Uint64() uint64 {
|
||
|
out := srng.output[0]
|
||
|
srng.shuffle()
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
func (srng *SHISHUA) Seed(seed int64) {
|
||
|
srng.Seed64(uint64(seed))
|
||
|
}
|
||
|
*/
|
||
|
func (srng *SHISHUA) prngGen(buf []byte, size int) []byte {
|
||
|
if buf == nil {
|
||
|
panic("buf is nil")
|
||
|
}
|
||
|
for i := 0; i < size; i += 128 {
|
||
|
for j := 0; j < 16; j++ {
|
||
|
binary.LittleEndian.PutUint64(buf[i+j*8:], srng.Uint64())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return buf
|
||
|
}
|
||
|
|
||
|
func (srng *SHISHUA) Read(buf []byte) (n int, err error) {
|
||
|
size := cap(buf)
|
||
|
if size%128 != 0 {
|
||
|
panic("buf's size must be a multiple of 128 bytes.")
|
||
|
}
|
||
|
return copy(buf, srng.prngGen(buf, size)), nil
|
||
|
}
|
||
|
|
||
|
func NewSHISHUA() *SHISHUA {
|
||
|
srng := &SHISHUA{}
|
||
|
|
||
|
buf := make([]byte, 64)
|
||
|
if n, e := rand.Read(buf); n != 64 || e != nil {
|
||
|
panic("rand.Read failed")
|
||
|
}
|
||
|
|
||
|
var seed [4]uint64
|
||
|
for i := 0; i < 4; i++ {
|
||
|
seed[i] = uint64(buf[i*8+0]) | uint64(buf[i*8+1])<<8 | uint64(buf[i*8+2])<<16 | uint64(buf[i*8+3])<<24
|
||
|
}
|
||
|
|
||
|
copy(srng.state[:], phi[:])
|
||
|
for i := 0; i < 4; i++ {
|
||
|
srng.state[i*2+0] ^= seed[i]
|
||
|
srng.state[i*2+8] ^= seed[(i+2)%4]
|
||
|
}
|
||
|
|
||
|
const rounds = 13
|
||
|
for i := 0; i < rounds; i++ {
|
||
|
srng.shuffle()
|
||
|
for j := 0; j < 4; j++ {
|
||
|
srng.state[j] = srng.output[j+12]
|
||
|
srng.state[j+4] = srng.output[j+8]
|
||
|
srng.state[j+8] = srng.output[j+4]
|
||
|
srng.state[j+12] = srng.output[j]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return srng
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
s := NewSHISHUA()
|
||
|
|
||
|
buf := make([]byte, 128)
|
||
|
|
||
|
var occurrences = make(map[string]struct{})
|
||
|
|
||
|
for i := 0; i < 100; i++ {
|
||
|
n, _ := s.Read(buf)
|
||
|
if n != cap(buf) {
|
||
|
panic("n != cap(buf)")
|
||
|
}
|
||
|
// spew.Dump(buf[:n])
|
||
|
str := hex.EncodeToString(buf)
|
||
|
if _, ok := occurrences[str]; ok {
|
||
|
panic("duplicate hex")
|
||
|
}
|
||
|
occurrences[str] = struct{}{}
|
||
|
_, _ = os.Stdout.WriteString(str)
|
||
|
_, _ = os.Stdout.WriteString("\n")
|
||
|
}
|
||
|
|
||
|
for i := 0; i < 5000; i++ {
|
||
|
str := fmt.Sprintf("%x", s.Uint64())
|
||
|
if _, ok := occurrences[str]; ok {
|
||
|
panic("duplicate uint64")
|
||
|
}
|
||
|
}
|
||
|
}
|