Skip to content
This repository has been archived by the owner on Feb 27, 2023. It is now read-only.

Commit

Permalink
use slice instead of array pointer for key
Browse files Browse the repository at this point in the history
Change the API to use a slice for the key instead of a pointer to 32 byte array
  • Loading branch information
Andreas Auernhammer committed Feb 21, 2017
1 parent 39175e1 commit aa4c802
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 39 deletions.
45 changes: 29 additions & 16 deletions chacha/chacha.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,36 @@ import (
"errors"
)

// NonceSize is the size of the ChaCha20 nonce in bytes.
const NonceSize = 8
const (
// NonceSize is the size of the ChaCha20 nonce in bytes.
NonceSize = 8

// INonceSize is the size of the IETF-ChaCha20 nonce in bytes.
const INonceSize = 12
// INonceSize is the size of the IETF-ChaCha20 nonce in bytes.
INonceSize = 12

// XNonceSize is the size of the XChaCha20 nonce in bytes.
const XNonceSize = 24
// XNonceSize is the size of the XChaCha20 nonce in bytes.
XNonceSize = 24

// KeySize is the size of the key used by this cipher, in bytes.
KeySize = 32
)

var (
useSSE2 bool
useSSSE3 bool
useAVX2 bool
)

var errInvalidNonce = errors.New("invalid nonce: nonce must be 8, 12 or 24 bytes long")
var (
errKeySize = errors.New("chacha20/chacha: bad key length")
errInvalidNonce = errors.New("chacha20/chacha: bad nonce length")
)

func setup(state *[64]byte, nonce []byte, key *[32]byte) (err error) {
func setup(state *[64]byte, nonce, key []byte) (err error) {
if len(key) != KeySize {
err = errKeySize
return
}
var Nonce [16]byte
switch len(nonce) {
case NonceSize:
Expand All @@ -42,9 +54,10 @@ func setup(state *[64]byte, nonce []byte, key *[32]byte) (err error) {
var hNonce [16]byte

copy(hNonce[:], nonce[:16])
hChaCha20(&tmpKey, &hNonce, key)
copy(tmpKey[:], key)
hChaCha20(&tmpKey, &hNonce, &tmpKey)
copy(Nonce[8:], nonce[16:])
initialize(state, &tmpKey, &Nonce)
initialize(state, tmpKey[:], &Nonce)

// BUG(aead): A "good" compiler will remove this (optimizations)
// But using the provided key instead of tmpKey,
Expand All @@ -67,9 +80,9 @@ func setup(state *[64]byte, nonce []byte, key *[32]byte) (err error) {
// generation - valid values are 8, 12 or 20. The src and dst may be the same slice
// but otherwise should not overlap. If len(dst) < len(src) this function panics.
// If the nonce is neither 64, 96 nor 192 bits long, this function panics.
func XORKeyStream(dst, src, nonce []byte, key *[32]byte, rounds int) {
func XORKeyStream(dst, src, nonce, key []byte, rounds int) {
if rounds != 20 && rounds != 12 && rounds != 8 {
panic("chacha20/chacha: rounds must be a 8, 12, or 20")
panic("chacha20/chacha: bad number of rounds")
}
if len(dst) < len(src) {
panic("chacha20/chacha: dst buffer is to small")
Expand All @@ -79,8 +92,8 @@ func XORKeyStream(dst, src, nonce []byte, key *[32]byte, rounds int) {
}

var block, state [64]byte
if setup(&state, nonce, key) != nil {
panic("chacha20/chacha: nonce must be 8, 12 or 24 bytes long")
if err := setup(&state, nonce, key); err != nil {
panic(err)
}
xorKeyStream(dst, src, &block, &state, rounds)
}
Expand All @@ -100,9 +113,9 @@ type Cipher struct {
// - INonceSize: ChaCha20/r as defined in RFC 7539 and a 2^32 * 64 byte period.
// - XNonceSize: XChaCha20/r with a 192 bit nonce and a 2^64 * 64 byte period.
// If the nonce is neither 64, 96 nor 192 bits long, a non-nil error is returned.
func NewCipher(nonce []byte, key *[32]byte, rounds int) (*Cipher, error) {
func NewCipher(nonce, key []byte, rounds int) (*Cipher, error) {
if rounds != 20 && rounds != 12 && rounds != 8 {
panic("chacha20/chacha: rounds must be a 8, 12, or 20")
panic("chacha20/chacha: bad number of rounds")
}

c := new(Cipher)
Expand Down
2 changes: 1 addition & 1 deletion chacha/chacha_386.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func init() {
useAVX2 = false
}

func initialize(state *[64]byte, key *[32]byte, nonce *[16]byte) {
func initialize(state *[64]byte, key []byte, nonce *[16]byte) {
binary.LittleEndian.PutUint32(state[0:], sigma[0])
binary.LittleEndian.PutUint32(state[4:], sigma[1])
binary.LittleEndian.PutUint32(state[8:], sigma[2])
Expand Down
6 changes: 3 additions & 3 deletions chacha/chacha_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -706,11 +706,11 @@ TEXT ·supportsSSSE3(SB), NOSPLIT, $0-1
MOVB CX, ret+0(FP)
RET

// func initialize(state *[64]byte, key *[32]byte, nonce *[16]byte)
TEXT ·initialize(SB), 4, $0-24
// func initialize(state *[64]byte, key []byte, nonce *[16]byte)
TEXT ·initialize(SB), 4, $0-40
MOVQ state+0(FP), DI
MOVQ key+8(FP), AX
MOVQ nonce+16(FP), BX
MOVQ nonce+32(FP), BX

MOVOU ·sigma<>(SB), X0
MOVOU 0(AX), X1
Expand Down
2 changes: 1 addition & 1 deletion chacha/chacha_go16_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func init() {

// This function is implemented in chacha_amd64.s
//go:noescape
func initialize(state *[64]byte, key *[32]byte, nonce *[16]byte)
func initialize(state *[64]byte, key []byte, nonce *[16]byte)

// This function is implemented in chacha_amd64.s
//go:noescape
Expand Down
2 changes: 1 addition & 1 deletion chacha/chacha_go17_amd64.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func init() {

// This function is implemented in chacha_amd64.s
//go:noescape
func initialize(state *[64]byte, key *[32]byte, nonce *[16]byte)
func initialize(state *[64]byte, key []byte, nonce *[16]byte)

// This function is implemented in chacha_amd64.s
//go:noescape
Expand Down
2 changes: 1 addition & 1 deletion chacha/chacha_ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package chacha

import "encoding/binary"

func initialize(state *[64]byte, key *[32]byte, nonce *[16]byte) {
func initialize(state *[64]byte, key []byte, nonce *[16]byte) {
binary.LittleEndian.PutUint32(state[0:], sigma[0])
binary.LittleEndian.PutUint32(state[4:], sigma[1])
binary.LittleEndian.PutUint32(state[8:], sigma[2])
Expand Down
14 changes: 6 additions & 8 deletions chacha/chacha_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,13 @@ func testVectors(t *testing.T) {
}

dst := make([]byte, len(v.ciphertext))
var key [32]byte
copy(key[:], v.key)

XORKeyStream(dst, v.plaintext, v.nonce, &key, v.rounds)
XORKeyStream(dst, v.plaintext, v.nonce, v.key, v.rounds)
if !bytes.Equal(dst, v.ciphertext) {
t.Errorf("Test %d: ciphertext mismatch:\n \t got: %s\n \t want: %s", i, toHex(dst), toHex(v.ciphertext))
}

c, err := NewCipher(v.nonce, &key, v.rounds)
c, err := NewCipher(v.nonce, v.key, v.rounds)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -157,21 +155,21 @@ func testIncremental(t *testing.T, iter int, size int) {

for j := 0; j <= len(msg); j++ {
useSSE2, useSSSE3, useAVX2 = false, false, false
XORKeyStream(ref[:j], msg[:j], nonce, &key, 20)
XORKeyStream(ref[:j], msg[:j], nonce, key[:], 20)

useSSE2, useSSSE3, useAVX2 = sse2, ssse3, avx2
XORKeyStream(stream[:j], msg[:j], nonce, &key, 20)
XORKeyStream(stream[:j], msg[:j], nonce, key[:], 20)

if !bytes.Equal(ref[:j], stream[:j]) {
t.Fatalf("Iteration %d failed:\n Message length: %d\n\n got: %s\nwant: %s", i, j, toHex(stream[:j]), toHex(ref[:j]))
}

useSSE2, useSSSE3, useAVX2 = false, false, false
c, _ := NewCipher(nonce, &key, 20)
c, _ := NewCipher(nonce, key[:], 20)
c.XORKeyStream(stream[:j], msg[:j])

useSSE2, useSSSE3, useAVX2 = sse2, ssse3, avx2
c, _ = NewCipher(nonce, &key, 20)
c, _ = NewCipher(nonce, key[:], 20)
c.XORKeyStream(stream[:j], msg[:j])

if !bytes.Equal(ref[:j], stream[:j]) {
Expand Down
4 changes: 2 additions & 2 deletions chacha20.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
// Src and dst may be the same slice but otherwise should not overlap.
// If len(dst) < len(src) this function panics.
// If the nonce is neither 64, 96 nor 192 bits long, this function panics.
func XORKeyStream(dst, src, nonce []byte, key *[32]byte) {
func XORKeyStream(dst, src, nonce, key []byte) {
chacha.XORKeyStream(dst, src, nonce, key, 20)
}

Expand All @@ -36,6 +36,6 @@ func XORKeyStream(dst, src, nonce []byte, key *[32]byte) {
// - 12 bytes: ChaCha20 as defined in RFC 7539 and a 2^32 * 64 byte period.
// - 24 bytes: XChaCha20 with a 192 bit nonce and a 2^64 * 64 byte period.
// If the nonce is neither 64, 96 nor 192 bits long, a non-nil error is returned.
func NewCipher(nonce []byte, key *[32]byte) (cipher.Stream, error) {
func NewCipher(nonce, key []byte) (cipher.Stream, error) {
return chacha.NewCipher(nonce, key, 20)
}
10 changes: 4 additions & 6 deletions chacha20_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,13 @@ func TestVectors(t *testing.T) {
}

dst := make([]byte, len(v.ciphertext))
var key [32]byte
copy(key[:], v.key)

XORKeyStream(dst, v.plaintext, v.nonce, &key)
XORKeyStream(dst, v.plaintext, v.nonce, v.key)
if !bytes.Equal(dst, v.ciphertext) {
t.Errorf("Test %d: ciphertext mismatch:\n \t got: %s\n \t want: %s", i, toHex(dst), toHex(v.ciphertext))
}

c, err := NewCipher(v.nonce, &key)
c, err := NewCipher(v.nonce, v.key)
if err != nil {
t.Fatal(err)
}
Expand All @@ -54,7 +52,7 @@ func TestVectors(t *testing.T) {
func benchmarkCipher(b *testing.B, size int, nonceSize int) {
var key [32]byte
nonce := make([]byte, nonceSize)
c, _ := NewCipher(nonce, &key)
c, _ := NewCipher(nonce, key[:])
buf := make([]byte, size)

b.SetBytes(int64(len(buf)))
Expand All @@ -71,7 +69,7 @@ func benchmarkXORKeyStream(b *testing.B, size int, nonceSize int) {
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
XORKeyStream(buf, buf, nonce[:], &key)
XORKeyStream(buf, buf, nonce[:], key[:])
}
}

Expand Down

0 comments on commit aa4c802

Please sign in to comment.