Skip to content

Commit

Permalink
math/rand/v2: implement io.Reader for ChaCha8
Browse files Browse the repository at this point in the history
Fixes [reserved]
  • Loading branch information
mauri870 committed May 17, 2024
1 parent 69105d7 commit 5415959
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 0 deletions.
1 change: 1 addition & 0 deletions api/next/67059.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pkg math/rand/v2, method (*ChaCha8) Read(p []byte) (n int, err error) #67059
20 changes: 20 additions & 0 deletions src/internal/chacha8rand/chacha8.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,23 @@ func Unmarshal(s *State, data []byte) error {
}
return nil
}

// Read reads random bytes from the state into p.
func Read(s *State, p []byte) (n int, err error) {
for n = 0; n < len(p); n++ {
if n == len(p) {
return n, nil
}

for {
x, ok := s.Next()
if ok {
p[n] = byte(x)
n++
break
}
s.Refill()
}
}
return n, nil
}
5 changes: 5 additions & 0 deletions src/math/rand/v2/chacha8.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,8 @@ func (c *ChaCha8) UnmarshalBinary(data []byte) error {
func (c *ChaCha8) MarshalBinary() ([]byte, error) {
return chacha8rand.Marshal(&c.state), nil
}

// Read generates len(p) random bytes and writes them into p.
func (c *ChaCha8) Read(p []byte) (n int, err error) {
return chacha8rand.Read(&c.state, p)
}
79 changes: 79 additions & 0 deletions src/math/rand/v2/chacha8_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
package rand_test

import (
"bytes"
"io"
. "math/rand/v2"
"testing"
"testing/iotest"
)

func TestChaCha8(t *testing.T) {
Expand Down Expand Up @@ -529,3 +532,79 @@ var chacha8marshal = []string{
"chacha8:\x00\x00\x00\x00\x00\x00\x00zK3\x9bB!,\x94\x9d\x975\xce'O_t\xee|\xb21\x87\xbb\xbb\xfd)\x8f\xe52\x01\vP\fk",
"chacha8:\x00\x00\x00\x00\x00\x00\x00{K3\x9bB!,\x94\x9d\x975\xce'O_t\xee|\xb21\x87\xbb\xbb\xfd)\x8f\xe52\x01\vP\fk",
}

func TestReadEmpty(t *testing.T) {
r := NewChaCha8(chacha8seed)
buf := make([]byte, 0)
n, err := r.Read(buf)
if err != nil {
t.Errorf("Read err into empty buffer; %v", err)
}
if n != 0 {
t.Errorf("Read into empty buffer returned unexpected n of %d", n)
}
}

func TestReadSeedReset(t *testing.T) {
r := NewChaCha8(chacha8seed)
b1 := make([]byte, 128)
_, err := r.Read(b1)
if err != nil {
t.Errorf("read: %v", err)
}

r.Seed(chacha8seed)
b2 := make([]byte, 128)
_, err = r.Read(b2)
if err != nil {
t.Errorf("read: %v", err)
}
if !bytes.Equal(b1, b2) {
t.Errorf("mismatch after re-seed:\n%x\n%x", b1, b2)
}
}

func TestReadByOneByte(t *testing.T) {
r := NewChaCha8(chacha8seed)
b1 := make([]byte, 100)
_, err := io.ReadFull(iotest.OneByteReader(r), b1)
if err != nil {
t.Errorf("read by one byte: %v", err)
}
r = NewChaCha8(chacha8seed)
b2 := make([]byte, 100)
_, err = r.Read(b2)
if err != nil {
t.Errorf("read: %v", err)
}
if !bytes.Equal(b1, b2) {
t.Errorf("read by one byte vs single read:\n%x\n%x", b1, b2)
}
}

func BenchmarkRead3(b *testing.B) {
r := NewChaCha8(chacha8seed)
buf := make([]byte, 3)
b.ResetTimer()
for n := b.N; n > 0; n-- {
r.Read(buf)
}
}

func BenchmarkRead64(b *testing.B) {
r := NewChaCha8(chacha8seed)
buf := make([]byte, 64)
b.ResetTimer()
for n := b.N; n > 0; n-- {
r.Read(buf)
}
}

func BenchmarkRead1000(b *testing.B) {
r := NewChaCha8(chacha8seed)
buf := make([]byte, 1000)
b.ResetTimer()
for n := b.N; n > 0; n-- {
r.Read(buf)
}
}

0 comments on commit 5415959

Please sign in to comment.