From f8b82a6eed6ae9d8706b34a893dc02595aa2539a Mon Sep 17 00:00:00 2001 From: "kayos@tcp.direct" Date: Sat, 11 Nov 2023 14:00:52 -0800 Subject: [PATCH] init --- go.mod | 3 ++ go.sum | 0 shishua.go | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 shishua.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..77a27af --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.tcp.direct/kayos/shishua-go + +go 1.21.2 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/shishua.go b/shishua.go new file mode 100644 index 0000000..347751f --- /dev/null +++ b/shishua.go @@ -0,0 +1,148 @@ +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") + } + } +}