Created
May 10, 2024 15:49
-
-
Save ncruces/f0d7eb7432a5854271be4e5b7b5eee17 to your computer and use it in GitHub Desktop.
Adiantum coverage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<!-- saved from url=(0047)file:///tmp/cover1217815835/coverage.html#file3 --> | |
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<title>adiantum: Go Coverage Report</title> | |
<style> | |
body { | |
background: black; | |
color: rgb(80, 80, 80); | |
} | |
body, pre, #legend span { | |
font-family: Menlo, monospace; | |
font-weight: bold; | |
} | |
#topbar { | |
background: black; | |
position: fixed; | |
top: 0; left: 0; right: 0; | |
height: 42px; | |
border-bottom: 1px solid rgb(80, 80, 80); | |
} | |
#content { | |
margin-top: 50px; | |
} | |
#nav, #legend { | |
float: left; | |
margin-left: 10px; | |
} | |
#legend { | |
margin-top: 12px; | |
} | |
#nav { | |
margin-top: 10px; | |
} | |
#legend span { | |
margin: 0 5px; | |
} | |
.cov0 { color: rgb(192, 0, 0) } | |
.cov1 { color: rgb(128, 128, 128) } | |
.cov2 { color: rgb(116, 140, 131) } | |
.cov3 { color: rgb(104, 152, 134) } | |
.cov4 { color: rgb(92, 164, 137) } | |
.cov5 { color: rgb(80, 176, 140) } | |
.cov6 { color: rgb(68, 188, 143) } | |
.cov7 { color: rgb(56, 200, 146) } | |
.cov8 { color: rgb(44, 212, 149) } | |
.cov9 { color: rgb(32, 224, 152) } | |
.cov10 { color: rgb(20, 236, 155) } | |
</style> | |
</head> | |
<body> | |
<div id="topbar"> | |
<div id="nav"> | |
<select id="files"> | |
<option value="file0">lukechampine.com/adiantum/adiantum.go (98.0%)</option> | |
<option value="file1">lukechampine.com/adiantum/hbsh/hbsh.go (100.0%)</option> | |
<option value="file2">lukechampine.com/adiantum/hpolyc/hpolyc.go (96.0%)</option> | |
<option value="file3">lukechampine.com/adiantum/internal/chacha/chacha.go (46.2%)</option> | |
<option value="file4">lukechampine.com/adiantum/internal/chacha/chacha_generic.go (98.8%)</option> | |
<option value="file5">lukechampine.com/adiantum/internal/chacha/chacha_ref.go (100.0%)</option> | |
<option value="file6">lukechampine.com/adiantum/internal/xchacha/chacha.go (100.0%)</option> | |
<option value="file7">lukechampine.com/adiantum/nh/nh.go (60.0%)</option> | |
<option value="file8">lukechampine.com/adiantum/nh/nh_little.go (100.0%)</option> | |
</select> | |
</div> | |
<div id="legend"> | |
<span>not tracked</span> | |
<span class="cov0">not covered</span> | |
<span class="cov8">covered</span> | |
</div> | |
</div> | |
<div id="content"> | |
<pre class="file" id="file0" style="display: none;">package adiantum // import "lukechampine.com/adiantum" | |
import ( | |
"bytes" | |
"crypto/aes" | |
"crypto/cipher" | |
"encoding/binary" | |
"math/bits" | |
"golang.org/x/crypto/poly1305" | |
"lukechampine.com/adiantum/hbsh" | |
"lukechampine.com/adiantum/internal/xchacha" | |
"lukechampine.com/adiantum/nh" | |
) | |
// hashNHPoly1305 implements hbsh.Hash with NH and Poly1305. | |
type hashNHPoly1305 struct { | |
keyT [32]byte | |
keyM [32]byte | |
keyNH [1072]byte | |
} | |
// Sum implements hbsh.Hash. | |
func (h *hashNHPoly1305) Sum(dst, msg, tweak []byte) []byte <span class="cov8" title="1">{ | |
// poly1305 hash 8*len(msg) and tweak with keyT | |
tweakBuf := make([]byte, 16+24) | |
binary.LittleEndian.PutUint64(tweakBuf[:8], uint64(8*len(msg))) | |
var outT [16]byte | |
poly1305.Sum(&outT, append(tweakBuf[:16], tweak...), &h.keyT) | |
// NH hash message in chunks of up to 1024 bytes, then poly1305 those hashes | |
// with keyM | |
mac := poly1305.New(&h.keyM) | |
var outNH [32]byte | |
for len(msg) >= 1024 </span><span class="cov8" title="1">{ | |
nh.Sum(&outNH, msg[:1024], h.keyNH[:]) | |
mac.Write(outNH[:]) | |
msg = msg[1024:] | |
}</span> | |
// handle final (incomplete) chunk, if it exists | |
<span class="cov8" title="1">if len(msg) > 0 </span><span class="cov8" title="1">{ | |
// if necessary, pad to multiple of 16 bytes | |
if len(msg)%16 != 0 </span><span class="cov8" title="1">{ | |
var pad [1024]byte | |
n := copy(pad[:], msg) | |
n += 16 - (n % 16) | |
msg = pad[:n] | |
}</span> | |
<span class="cov8" title="1">nh.Sum(&outNH, msg, h.keyNH[:]) | |
mac.Write(outNH[:])</span> | |
} | |
<span class="cov8" title="1">var outM [16]byte | |
mac.Sum(outM[:0]) | |
// return the sum of the hashes | |
sum := addHashes(outT, outM) | |
return append(dst[:0], sum[:]...)</span> | |
} | |
type chachaStream struct { | |
key []byte | |
rounds int | |
} | |
func (s *chachaStream) XORKeyStream(msg, nonce []byte) <span class="cov8" title="1">{ | |
nonceBuf := make([]byte, 24) | |
n := copy(nonceBuf, nonce) | |
nonceBuf[n] = 1 | |
xchacha.XORKeyStream(msg, msg, nonceBuf, s.key, s.rounds) | |
}</span> | |
func makeAdiantum(key []byte, chachaRounds int) (hbsh.StreamCipher, cipher.Block, hbsh.TweakableHash) <span class="cov8" title="1">{ | |
if len(key) != xchacha.KeySize </span><span class="cov0" title="0">{ | |
panic("adiantum: key must be 32 bytes long")</span> | |
} | |
// create stream cipher and derive block+hash keys | |
<span class="cov8" title="1">stream := &chachaStream{key, chachaRounds} | |
keyBuf := bytes.NewBuffer(make([]byte, 32+16+16+1072)) | |
stream.XORKeyStream(keyBuf.Bytes(), nil) | |
block, _ := aes.NewCipher(keyBuf.Next(32)) | |
hash := new(hashNHPoly1305) | |
copy(hash.keyT[:16], keyBuf.Next(16)) | |
copy(hash.keyM[:16], keyBuf.Next(16)) | |
copy(hash.keyNH[:], keyBuf.Next(1072)) // enough to hash a 1024-byte message | |
return stream, block, hash</span> | |
} | |
// New8 returns an Adiantum cipher with the specified key, using XChaCha8 as the | |
// stream cipher. The key must be 32 bytes. | |
func New8(key []byte) *hbsh.HBSH <span class="cov8" title="1">{ | |
return hbsh.New(makeAdiantum(key, 8)) | |
}</span> | |
// New returns an Adiantum cipher with the specified key. The key must be 32 | |
// bytes. | |
func New(key []byte) *hbsh.HBSH <span class="cov8" title="1">{ | |
return hbsh.New(makeAdiantum(key, 12)) | |
}</span> | |
// New20 returns an Adiantum cipher with the specified key, using XChaCha20 as | |
// the stream cipher. The key must be 32 bytes. | |
func New20(key []byte) *hbsh.HBSH <span class="cov8" title="1">{ | |
return hbsh.New(makeAdiantum(key, 20)) | |
}</span> | |
func addHashes(x, y [16]byte) [16]byte <span class="cov8" title="1">{ | |
x1 := binary.LittleEndian.Uint64(x[:8]) | |
x2 := binary.LittleEndian.Uint64(x[8:16]) | |
y1 := binary.LittleEndian.Uint64(y[:8]) | |
y2 := binary.LittleEndian.Uint64(y[8:16]) | |
r1, c := bits.Add64(x1, y1, 0) | |
r2, _ := bits.Add64(x2, y2, c) | |
binary.LittleEndian.PutUint64(x[:8], r1) | |
binary.LittleEndian.PutUint64(x[8:], r2) | |
return x | |
}</span> | |
</pre> | |
<pre class="file" id="file1" style="display: none">package hbsh // import "lukechampine.com/adiantum/hbsh" | |
import ( | |
"crypto/cipher" | |
"encoding/binary" | |
"math/bits" | |
) | |
// A StreamCipher xors msg with a keystream, modified by a nonce. | |
type StreamCipher interface { | |
XORKeyStream(msg, nonce []byte) | |
} | |
// TweakableHash is a tweakable cryptographic hash function. It appends the hash | |
// of src to dst and returns it. | |
type TweakableHash interface { | |
Sum(dst, src, tweak []byte) []byte | |
} | |
// HBSH is a cipher using the HBSH encryption mode. | |
type HBSH struct { | |
stream StreamCipher | |
block cipher.Block | |
thash TweakableHash | |
hashBuf [32]byte | |
} | |
func (h *HBSH) streamXOR(nonce, msg []byte) []byte <span class="cov8" title="1">{ | |
h.stream.XORKeyStream(msg, nonce) | |
return msg | |
}</span> | |
func (h *HBSH) hash(tweak, msg []byte) []byte <span class="cov8" title="1">{ | |
return h.thash.Sum(h.hashBuf[:0], msg, tweak) | |
}</span> | |
func (h *HBSH) encryptBlock(src []byte) []byte <span class="cov8" title="1">{ | |
h.block.Encrypt(src, src) | |
return src | |
}</span> | |
func (h *HBSH) decryptBlock(src []byte) []byte <span class="cov8" title="1">{ | |
h.block.Decrypt(src, src) | |
return src | |
}</span> | |
// Encrypt encrypts block using the specified tweak. The block must be at least | |
// 16 bytes. The size of the tweak is restricted by the underlying primitives. | |
func (h *HBSH) Encrypt(block, tweak []byte) []byte <span class="cov8" title="1">{ | |
pl, pr := block[:len(block)-16], block[len(block)-16:] | |
pm := blockAdd(pr, h.hash(tweak, pl)) | |
cm := h.encryptBlock(pm) | |
cl := h.streamXOR(cm, pl) | |
cr := blockSub(cm, h.hash(tweak, cl)) | |
return append(cl, cr...) | |
}</span> | |
// Decrypt decrypts block using the specified tweak. The block must be at least | |
// 16 bytes. The size of the tweak is restricted by the underlying primitives. | |
func (h *HBSH) Decrypt(block, tweak []byte) []byte <span class="cov8" title="1">{ | |
cl, cr := block[:len(block)-16], block[len(block)-16:] | |
cm := blockAdd(cr, h.hash(tweak, cl)) | |
pl := h.streamXOR(cm, cl) | |
pm := h.decryptBlock(cm) | |
pr := blockSub(pm, h.hash(tweak, pl)) | |
return append(pl, pr...) | |
}</span> | |
// New returns an HBSH cipher using the specified primitives. | |
func New(stream StreamCipher, block cipher.Block, hash TweakableHash) *HBSH <span class="cov8" title="1">{ | |
return &HBSH{ | |
stream: stream, | |
block: block, | |
thash: hash, | |
} | |
}</span> | |
func blockAdd(x []byte, y []byte) []byte <span class="cov8" title="1">{ | |
x1 := binary.LittleEndian.Uint64(x[:8]) | |
x2 := binary.LittleEndian.Uint64(x[8:16]) | |
y1 := binary.LittleEndian.Uint64(y[:8]) | |
y2 := binary.LittleEndian.Uint64(y[8:16]) | |
r1, c := bits.Add64(x1, y1, 0) | |
r2, _ := bits.Add64(x2, y2, c) | |
binary.LittleEndian.PutUint64(x[:8], r1) | |
binary.LittleEndian.PutUint64(x[8:], r2) | |
return x | |
}</span> | |
func blockSub(x []byte, y []byte) []byte <span class="cov8" title="1">{ | |
x1 := binary.LittleEndian.Uint64(x[:8]) | |
x2 := binary.LittleEndian.Uint64(x[8:16]) | |
y1 := binary.LittleEndian.Uint64(y[:8]) | |
y2 := binary.LittleEndian.Uint64(y[8:16]) | |
r1, c := bits.Sub64(x1, y1, 0) | |
r2, _ := bits.Sub64(x2, y2, c) | |
binary.LittleEndian.PutUint64(x[:8], r1) | |
binary.LittleEndian.PutUint64(x[8:], r2) | |
return x | |
}</span> | |
</pre> | |
<pre class="file" id="file2" style="display: none">package hpolyc // import "lukechampine.com/adiantum/hpolyc" | |
import ( | |
"crypto/aes" | |
"crypto/cipher" | |
"encoding/binary" | |
"golang.org/x/crypto/poly1305" | |
"lukechampine.com/adiantum/hbsh" | |
"lukechampine.com/adiantum/internal/xchacha" | |
) | |
type hpolycHash struct { | |
key [32]byte | |
} | |
func (h *hpolycHash) Sum(dst, msg, tweak []byte) []byte <span class="cov8" title="1">{ | |
lenbuf := make([]byte, 4) | |
binary.LittleEndian.PutUint32(lenbuf, uint32(8*len(tweak))) | |
padding := make([]byte, 16)[(4+len(tweak))%16:] | |
mac := poly1305.New(&h.key) | |
mac.Write(lenbuf) | |
mac.Write(tweak) | |
mac.Write(padding) | |
mac.Write(msg) | |
return mac.Sum(dst) | |
}</span> | |
type chachaStream struct { | |
key []byte | |
rounds int | |
} | |
func (s *chachaStream) XORKeyStream(msg, nonce []byte) <span class="cov8" title="1">{ | |
nonceBuf := make([]byte, 24) | |
n := copy(nonceBuf, nonce) | |
nonceBuf[n] = 1 | |
xchacha.XORKeyStream(msg, msg, nonceBuf, s.key, s.rounds) | |
}</span> | |
func makeHPolyC(key []byte, chachaRounds int) (hbsh.StreamCipher, cipher.Block, hbsh.TweakableHash) <span class="cov8" title="1">{ | |
if len(key) != xchacha.KeySize </span><span class="cov0" title="0">{ | |
panic("hpolyc: key must be 32 bytes long")</span> | |
} | |
// create stream cipher and derive block+hash keys | |
<span class="cov8" title="1">stream := &chachaStream{key, chachaRounds} | |
keyBuf := make([]byte, 48) | |
stream.XORKeyStream(keyBuf, nil) | |
block, _ := aes.NewCipher(keyBuf[:32]) | |
hash := new(hpolycHash) | |
copy(hash.key[:16], keyBuf[32:]) | |
return stream, block, hash</span> | |
} | |
// New8 returns an HPolyC cipher with the specified key, using XChaCha8 as the | |
// stream cipher. The key must be 32 bytes long. | |
func New8(key []byte) *hbsh.HBSH <span class="cov8" title="1">{ | |
return hbsh.New(makeHPolyC(key, 8)) | |
}</span> | |
// New returns an HPolyC cipher with the specified key. The key must be 32 bytes | |
// long. | |
func New(key []byte) *hbsh.HBSH <span class="cov8" title="1">{ | |
return hbsh.New(makeHPolyC(key, 12)) | |
}</span> | |
// New20 returns an HPolyC cipher with the specified key, using XChaCha20 as the | |
// stream cipher. The key must be 32 bytes long. | |
func New20(key []byte) *hbsh.HBSH <span class="cov8" title="1">{ | |
return hbsh.New(makeHPolyC(key, 20)) | |
}</span> | |
</pre> | |
<pre class="file" id="file3" style="display: block;">// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. | |
// Use of this source code is governed by a license that can be | |
// found in the LICENSE file. | |
// Originally from: | |
// https://github.com/aead/chacha20/tree/master/chacha | |
// Package chacha implements some low-level functions of the | |
// ChaCha cipher family. | |
package chacha | |
import ( | |
"errors" | |
"golang.org/x/crypto/chacha20" | |
) | |
const ( | |
// NonceSize is the size of the ChaCha20 nonce in bytes. | |
NonceSize = 8 | |
// INonceSize is the size of the IETF-ChaCha20 nonce in bytes. | |
INonceSize = 12 | |
// XNonceSize is the size of the XChaCha20 nonce in bytes. | |
XNonceSize = 24 | |
// KeySize is the size of the key in bytes. | |
KeySize = 32 | |
) | |
var ( | |
useSSE2 bool | |
useSSSE3 bool | |
useAVX bool | |
useAVX2 bool | |
useVX bool | |
) | |
var ( | |
errKeySize = errors.New("chacha20/chacha: bad key length") | |
errInvalidNonce = errors.New("chacha20/chacha: bad nonce length") | |
) | |
func setup(state *[64]byte, nonce, key []byte) (err error) <span class="cov8" title="1">{ | |
if len(key) != KeySize </span><span class="cov0" title="0">{ | |
err = errKeySize | |
return | |
}</span> | |
<span class="cov8" title="1">var Nonce [16]byte | |
switch len(nonce) </span>{ | |
case NonceSize:<span class="cov8" title="1"> | |
copy(Nonce[8:], nonce) | |
initialize(state, key, &Nonce)</span> | |
case INonceSize:<span class="cov0" title="0"> | |
copy(Nonce[4:], nonce) | |
initialize(state, key, &Nonce)</span> | |
case XNonceSize:<span class="cov0" title="0"> | |
tmpKey, err := chacha20.HChaCha20(key, nonce[:16]) | |
if err != nil </span><span class="cov0" title="0">{ | |
panic(err)</span> | |
} | |
<span class="cov0" title="0">copy(Nonce[8:], nonce[16:]) | |
initialize(state, tmpKey, &Nonce)</span> | |
default:<span class="cov0" title="0"> | |
err = errInvalidNonce</span> | |
} | |
<span class="cov8" title="1">return</span> | |
} | |
// XORKeyStream crypts bytes from src to dst using the given nonce and key. | |
// The length of the nonce determinds the version of ChaCha20: | |
// - NonceSize: ChaCha20/r with a 64 bit nonce and a 2^64 * 64 byte period. | |
// - 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. | |
// The rounds argument specifies the number of rounds performed for keystream | |
// 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, key []byte, rounds int) <span class="cov8" title="1">{ | |
if rounds != 20 && rounds != 12 && rounds != 8 </span><span class="cov0" title="0">{ | |
panic("chacha20/chacha: bad number of rounds")</span> | |
} | |
<span class="cov8" title="1">if len(dst) < len(src) </span><span class="cov0" title="0">{ | |
panic("chacha20/chacha: dst buffer is to small")</span> | |
} | |
<span class="cov8" title="1">if len(nonce) == INonceSize && uint64(len(src)) > (1<<38) </span><span class="cov0" title="0">{ | |
panic("chacha20/chacha: src is too large")</span> | |
} | |
<span class="cov8" title="1">var block, state [64]byte | |
if err := setup(&state, nonce, key); err != nil </span><span class="cov0" title="0">{ | |
panic(err)</span> | |
} | |
<span class="cov8" title="1">xorKeyStream(dst, src, &block, &state, rounds)</span> | |
} | |
</pre> | |
<pre class="file" id="file4" style="display: none;">// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. | |
// Use of this source code is governed by a license that can be | |
// found in the LICENSE file. | |
package chacha | |
import "encoding/binary" | |
func initializeGeneric(state *[64]byte, key []byte, nonce *[16]byte) <span class="cov8" title="1">{ | |
const ( | |
sigma0 uint32 = 0x61707865 | |
sigma1 uint32 = 0x3320646e | |
sigma2 uint32 = 0x79622d32 | |
sigma3 uint32 = 0x6b206574 | |
) | |
binary.LittleEndian.PutUint32(state[0:], sigma0) | |
binary.LittleEndian.PutUint32(state[4:], sigma1) | |
binary.LittleEndian.PutUint32(state[8:], sigma2) | |
binary.LittleEndian.PutUint32(state[12:], sigma3) | |
copy(state[16:], key[:]) | |
copy(state[48:], nonce[:]) | |
}</span> | |
func xorKeyStreamGeneric(dst, src []byte, block, state *[64]byte, rounds int) int <span class="cov8" title="1">{ | |
for len(src) >= 64 </span><span class="cov8" title="1">{ | |
chachaGeneric(block, state, rounds) | |
for i, v := range block </span><span class="cov8" title="1">{ | |
dst[i] = src[i] ^ v | |
}</span> | |
<span class="cov8" title="1">src = src[64:] | |
dst = dst[64:]</span> | |
} | |
<span class="cov8" title="1">n := len(src) | |
if n > 0 </span><span class="cov8" title="1">{ | |
chachaGeneric(block, state, rounds) | |
for i, v := range src </span><span class="cov8" title="1">{ | |
dst[i] = v ^ block[i] | |
}</span> | |
} | |
<span class="cov8" title="1">return n</span> | |
} | |
func chachaGeneric(dst *[64]byte, state *[64]byte, rounds int) <span class="cov8" title="1">{ | |
v00 := binary.LittleEndian.Uint32(state[0:]) | |
v01 := binary.LittleEndian.Uint32(state[4:]) | |
v02 := binary.LittleEndian.Uint32(state[8:]) | |
v03 := binary.LittleEndian.Uint32(state[12:]) | |
v04 := binary.LittleEndian.Uint32(state[16:]) | |
v05 := binary.LittleEndian.Uint32(state[20:]) | |
v06 := binary.LittleEndian.Uint32(state[24:]) | |
v07 := binary.LittleEndian.Uint32(state[28:]) | |
v08 := binary.LittleEndian.Uint32(state[32:]) | |
v09 := binary.LittleEndian.Uint32(state[36:]) | |
v10 := binary.LittleEndian.Uint32(state[40:]) | |
v11 := binary.LittleEndian.Uint32(state[44:]) | |
v12 := binary.LittleEndian.Uint32(state[48:]) | |
v13 := binary.LittleEndian.Uint32(state[52:]) | |
v14 := binary.LittleEndian.Uint32(state[56:]) | |
v15 := binary.LittleEndian.Uint32(state[60:]) | |
s00, s01, s02, s03, s04, s05, s06, s07 := v00, v01, v02, v03, v04, v05, v06, v07 | |
s08, s09, s10, s11, s12, s13, s14, s15 := v08, v09, v10, v11, v12, v13, v14, v15 | |
for i := 0; i < rounds; i += 2 </span><span class="cov8" title="1">{ | |
v00 += v04 | |
v12 ^= v00 | |
v12 = (v12 << 16) | (v12 >> 16) | |
v08 += v12 | |
v04 ^= v08 | |
v04 = (v04 << 12) | (v04 >> 20) | |
v00 += v04 | |
v12 ^= v00 | |
v12 = (v12 << 8) | (v12 >> 24) | |
v08 += v12 | |
v04 ^= v08 | |
v04 = (v04 << 7) | (v04 >> 25) | |
v01 += v05 | |
v13 ^= v01 | |
v13 = (v13 << 16) | (v13 >> 16) | |
v09 += v13 | |
v05 ^= v09 | |
v05 = (v05 << 12) | (v05 >> 20) | |
v01 += v05 | |
v13 ^= v01 | |
v13 = (v13 << 8) | (v13 >> 24) | |
v09 += v13 | |
v05 ^= v09 | |
v05 = (v05 << 7) | (v05 >> 25) | |
v02 += v06 | |
v14 ^= v02 | |
v14 = (v14 << 16) | (v14 >> 16) | |
v10 += v14 | |
v06 ^= v10 | |
v06 = (v06 << 12) | (v06 >> 20) | |
v02 += v06 | |
v14 ^= v02 | |
v14 = (v14 << 8) | (v14 >> 24) | |
v10 += v14 | |
v06 ^= v10 | |
v06 = (v06 << 7) | (v06 >> 25) | |
v03 += v07 | |
v15 ^= v03 | |
v15 = (v15 << 16) | (v15 >> 16) | |
v11 += v15 | |
v07 ^= v11 | |
v07 = (v07 << 12) | (v07 >> 20) | |
v03 += v07 | |
v15 ^= v03 | |
v15 = (v15 << 8) | (v15 >> 24) | |
v11 += v15 | |
v07 ^= v11 | |
v07 = (v07 << 7) | (v07 >> 25) | |
v00 += v05 | |
v15 ^= v00 | |
v15 = (v15 << 16) | (v15 >> 16) | |
v10 += v15 | |
v05 ^= v10 | |
v05 = (v05 << 12) | (v05 >> 20) | |
v00 += v05 | |
v15 ^= v00 | |
v15 = (v15 << 8) | (v15 >> 24) | |
v10 += v15 | |
v05 ^= v10 | |
v05 = (v05 << 7) | (v05 >> 25) | |
v01 += v06 | |
v12 ^= v01 | |
v12 = (v12 << 16) | (v12 >> 16) | |
v11 += v12 | |
v06 ^= v11 | |
v06 = (v06 << 12) | (v06 >> 20) | |
v01 += v06 | |
v12 ^= v01 | |
v12 = (v12 << 8) | (v12 >> 24) | |
v11 += v12 | |
v06 ^= v11 | |
v06 = (v06 << 7) | (v06 >> 25) | |
v02 += v07 | |
v13 ^= v02 | |
v13 = (v13 << 16) | (v13 >> 16) | |
v08 += v13 | |
v07 ^= v08 | |
v07 = (v07 << 12) | (v07 >> 20) | |
v02 += v07 | |
v13 ^= v02 | |
v13 = (v13 << 8) | (v13 >> 24) | |
v08 += v13 | |
v07 ^= v08 | |
v07 = (v07 << 7) | (v07 >> 25) | |
v03 += v04 | |
v14 ^= v03 | |
v14 = (v14 << 16) | (v14 >> 16) | |
v09 += v14 | |
v04 ^= v09 | |
v04 = (v04 << 12) | (v04 >> 20) | |
v03 += v04 | |
v14 ^= v03 | |
v14 = (v14 << 8) | (v14 >> 24) | |
v09 += v14 | |
v04 ^= v09 | |
v04 = (v04 << 7) | (v04 >> 25) | |
}</span> | |
<span class="cov8" title="1">v00 += s00 | |
v01 += s01 | |
v02 += s02 | |
v03 += s03 | |
v04 += s04 | |
v05 += s05 | |
v06 += s06 | |
v07 += s07 | |
v08 += s08 | |
v09 += s09 | |
v10 += s10 | |
v11 += s11 | |
v12 += s12 | |
v13 += s13 | |
v14 += s14 | |
v15 += s15 | |
s12++ | |
binary.LittleEndian.PutUint32(state[48:], s12) | |
if s12 == 0 </span><span class="cov0" title="0">{ // indicates overflow | |
s13++ | |
binary.LittleEndian.PutUint32(state[52:], s13) | |
}</span> | |
<span class="cov8" title="1">binary.LittleEndian.PutUint32(dst[0:], v00) | |
binary.LittleEndian.PutUint32(dst[4:], v01) | |
binary.LittleEndian.PutUint32(dst[8:], v02) | |
binary.LittleEndian.PutUint32(dst[12:], v03) | |
binary.LittleEndian.PutUint32(dst[16:], v04) | |
binary.LittleEndian.PutUint32(dst[20:], v05) | |
binary.LittleEndian.PutUint32(dst[24:], v06) | |
binary.LittleEndian.PutUint32(dst[28:], v07) | |
binary.LittleEndian.PutUint32(dst[32:], v08) | |
binary.LittleEndian.PutUint32(dst[36:], v09) | |
binary.LittleEndian.PutUint32(dst[40:], v10) | |
binary.LittleEndian.PutUint32(dst[44:], v11) | |
binary.LittleEndian.PutUint32(dst[48:], v12) | |
binary.LittleEndian.PutUint32(dst[52:], v13) | |
binary.LittleEndian.PutUint32(dst[56:], v14) | |
binary.LittleEndian.PutUint32(dst[60:], v15)</span> | |
} | |
</pre> | |
<pre class="file" id="file5" style="display: none;">// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. | |
// Use of this source code is governed by a license that can be | |
// found in the LICENSE file. | |
//go:build !(gc && (386 || amd64 || arm64)) | |
package chacha | |
func initialize(state *[64]byte, key []byte, nonce *[16]byte) <span class="cov8" title="1">{ | |
initializeGeneric(state, key, nonce) | |
}</span> | |
func xorKeyStream(dst, src []byte, block, state *[64]byte, rounds int) int <span class="cov8" title="1">{ | |
return xorKeyStreamGeneric(dst, src, block, state, rounds) | |
}</span> | |
</pre> | |
<pre class="file" id="file6" style="display: none;">package xchacha | |
import ( | |
"encoding/binary" | |
"lukechampine.com/adiantum/internal/chacha" | |
) | |
// KeySize is the size of an XChaCha key. | |
const KeySize = chacha.KeySize | |
// NonceSize is the size of an XChaCha nonce. | |
const NonceSize = chacha.XNonceSize | |
// XORKeyStream xors the bytes of src with the key stream derived from the key | |
// and nonce. | |
func XORKeyStream(dst, src, nonce, key []byte, rounds int) <span class="cov8" title="1">{ | |
// expand nonce with HChaCha | |
var tmpKey [32]byte | |
var hNonce [16]byte | |
copy(hNonce[:], nonce[:16]) | |
copy(tmpKey[:], key) | |
hChaCha(&tmpKey, &hNonce, &tmpKey, rounds) | |
chacha.XORKeyStream(dst, src, nonce[16:], tmpKey[:], rounds) | |
}</span> | |
// NOTE: Don't bother trying to optimize hChaCha; it contributes very little to | |
// the total runtime of XORKeyStream. I tried swapping in an asm version and it | |
// only shaved off about 30ns. | |
func hChaCha(out *[32]byte, nonce *[16]byte, key *[32]byte, rounds int) <span class="cov8" title="1">{ | |
const ( | |
sigma0 uint32 = 0x61707865 | |
sigma1 uint32 = 0x3320646e | |
sigma2 uint32 = 0x79622d32 | |
sigma3 uint32 = 0x6b206574 | |
) | |
v00 := sigma0 | |
v01 := sigma1 | |
v02 := sigma2 | |
v03 := sigma3 | |
v04 := binary.LittleEndian.Uint32(key[0:]) | |
v05 := binary.LittleEndian.Uint32(key[4:]) | |
v06 := binary.LittleEndian.Uint32(key[8:]) | |
v07 := binary.LittleEndian.Uint32(key[12:]) | |
v08 := binary.LittleEndian.Uint32(key[16:]) | |
v09 := binary.LittleEndian.Uint32(key[20:]) | |
v10 := binary.LittleEndian.Uint32(key[24:]) | |
v11 := binary.LittleEndian.Uint32(key[28:]) | |
v12 := binary.LittleEndian.Uint32(nonce[0:]) | |
v13 := binary.LittleEndian.Uint32(nonce[4:]) | |
v14 := binary.LittleEndian.Uint32(nonce[8:]) | |
v15 := binary.LittleEndian.Uint32(nonce[12:]) | |
for i := 0; i < rounds; i += 2 </span><span class="cov8" title="1">{ | |
v00 += v04 | |
v12 ^= v00 | |
v12 = (v12 << 16) | (v12 >> 16) | |
v08 += v12 | |
v04 ^= v08 | |
v04 = (v04 << 12) | (v04 >> 20) | |
v00 += v04 | |
v12 ^= v00 | |
v12 = (v12 << 8) | (v12 >> 24) | |
v08 += v12 | |
v04 ^= v08 | |
v04 = (v04 << 7) | (v04 >> 25) | |
v01 += v05 | |
v13 ^= v01 | |
v13 = (v13 << 16) | (v13 >> 16) | |
v09 += v13 | |
v05 ^= v09 | |
v05 = (v05 << 12) | (v05 >> 20) | |
v01 += v05 | |
v13 ^= v01 | |
v13 = (v13 << 8) | (v13 >> 24) | |
v09 += v13 | |
v05 ^= v09 | |
v05 = (v05 << 7) | (v05 >> 25) | |
v02 += v06 | |
v14 ^= v02 | |
v14 = (v14 << 16) | (v14 >> 16) | |
v10 += v14 | |
v06 ^= v10 | |
v06 = (v06 << 12) | (v06 >> 20) | |
v02 += v06 | |
v14 ^= v02 | |
v14 = (v14 << 8) | (v14 >> 24) | |
v10 += v14 | |
v06 ^= v10 | |
v06 = (v06 << 7) | (v06 >> 25) | |
v03 += v07 | |
v15 ^= v03 | |
v15 = (v15 << 16) | (v15 >> 16) | |
v11 += v15 | |
v07 ^= v11 | |
v07 = (v07 << 12) | (v07 >> 20) | |
v03 += v07 | |
v15 ^= v03 | |
v15 = (v15 << 8) | (v15 >> 24) | |
v11 += v15 | |
v07 ^= v11 | |
v07 = (v07 << 7) | (v07 >> 25) | |
v00 += v05 | |
v15 ^= v00 | |
v15 = (v15 << 16) | (v15 >> 16) | |
v10 += v15 | |
v05 ^= v10 | |
v05 = (v05 << 12) | (v05 >> 20) | |
v00 += v05 | |
v15 ^= v00 | |
v15 = (v15 << 8) | (v15 >> 24) | |
v10 += v15 | |
v05 ^= v10 | |
v05 = (v05 << 7) | (v05 >> 25) | |
v01 += v06 | |
v12 ^= v01 | |
v12 = (v12 << 16) | (v12 >> 16) | |
v11 += v12 | |
v06 ^= v11 | |
v06 = (v06 << 12) | (v06 >> 20) | |
v01 += v06 | |
v12 ^= v01 | |
v12 = (v12 << 8) | (v12 >> 24) | |
v11 += v12 | |
v06 ^= v11 | |
v06 = (v06 << 7) | (v06 >> 25) | |
v02 += v07 | |
v13 ^= v02 | |
v13 = (v13 << 16) | (v13 >> 16) | |
v08 += v13 | |
v07 ^= v08 | |
v07 = (v07 << 12) | (v07 >> 20) | |
v02 += v07 | |
v13 ^= v02 | |
v13 = (v13 << 8) | (v13 >> 24) | |
v08 += v13 | |
v07 ^= v08 | |
v07 = (v07 << 7) | (v07 >> 25) | |
v03 += v04 | |
v14 ^= v03 | |
v14 = (v14 << 16) | (v14 >> 16) | |
v09 += v14 | |
v04 ^= v09 | |
v04 = (v04 << 12) | (v04 >> 20) | |
v03 += v04 | |
v14 ^= v03 | |
v14 = (v14 << 8) | (v14 >> 24) | |
v09 += v14 | |
v04 ^= v09 | |
v04 = (v04 << 7) | (v04 >> 25) | |
}</span> | |
<span class="cov8" title="1">binary.LittleEndian.PutUint32(out[0:], v00) | |
binary.LittleEndian.PutUint32(out[4:], v01) | |
binary.LittleEndian.PutUint32(out[8:], v02) | |
binary.LittleEndian.PutUint32(out[12:], v03) | |
binary.LittleEndian.PutUint32(out[16:], v12) | |
binary.LittleEndian.PutUint32(out[20:], v13) | |
binary.LittleEndian.PutUint32(out[24:], v14) | |
binary.LittleEndian.PutUint32(out[28:], v15)</span> | |
} | |
</pre> | |
<pre class="file" id="file7" style="display: none;">package nh // import "lukechampine.com/adiantum/nh" | |
// Sum computes the NH hash of m with the specified key and places the result in | |
// out. The key must be at least 48 bytes larger than the message. | |
func Sum(out *[32]byte, m []byte, key []byte) <span class="cov8" title="1">{ | |
if len(m)%16 != 0 </span><span class="cov0" title="0">{ | |
panic("nh: Message must be a multiple of 16 bytes")</span> | |
} else<span class="cov8" title="1"> if len(key) < len(m)+48 </span><span class="cov0" title="0">{ | |
panic("nh: Key must be at least 48 bytes longer than message")</span> | |
} | |
<span class="cov8" title="1">sum(out, m, key)</span> | |
} | |
</pre> | |
<pre class="file" id="file8" style="display: none;">//go:build (amd64 && !gc) || 386 || arm || arm64 || mipsle || mips64le || ppc64le || riscv || riscv64 || wasm | |
package nh | |
import "unsafe" | |
func sum(out *[32]byte, m, k []byte) <span class="cov8" title="1">{ | |
sumLittleEndian( | |
(*[4]uint64)(unsafe.Pointer(out)), | |
unsafe.Slice((*uint32)(unsafe.Pointer(unsafe.SliceData(m))), len(m)/4), | |
unsafe.Slice((*uint32)(unsafe.Pointer(unsafe.SliceData(k))), len(k)/4)) | |
}</span> | |
func sumLittleEndian(out *[4]uint64, m, k []uint32) <span class="cov8" title="1">{ | |
out[0] = 0 | |
out[1] = 0 | |
out[2] = 0 | |
out[3] = 0 | |
for len(m) >= 4 && len(k) >= 16 </span><span class="cov8" title="1">{ | |
m0 := m[0] | |
m1 := m[1] | |
m2 := m[2] | |
m3 := m[3] | |
out[0] += uint64(m0+k[0]) * uint64(m2+k[2]) | |
out[1] += uint64(m0+k[4]) * uint64(m2+k[6]) | |
out[2] += uint64(m0+k[8]) * uint64(m2+k[10]) | |
out[3] += uint64(m0+k[12]) * uint64(m2+k[14]) | |
out[0] += uint64(m1+k[1]) * uint64(m3+k[3]) | |
out[1] += uint64(m1+k[5]) * uint64(m3+k[7]) | |
out[2] += uint64(m1+k[9]) * uint64(m3+k[11]) | |
out[3] += uint64(m1+k[13]) * uint64(m3+k[15]) | |
k = k[4:] | |
m = m[4:] | |
}</span> | |
} | |
</pre> | |
</div> | |
<script> | |
(function() { | |
var files = document.getElementById('files'); | |
var visible; | |
files.addEventListener('change', onChange, false); | |
function select(part) { | |
if (visible) | |
visible.style.display = 'none'; | |
visible = document.getElementById(part); | |
if (!visible) | |
return; | |
files.value = part; | |
visible.style.display = 'block'; | |
location.hash = part; | |
} | |
function onChange() { | |
select(files.value); | |
window.scrollTo(0, 0); | |
} | |
if (location.hash != "") { | |
select(location.hash.substr(1)); | |
} | |
if (!visible) { | |
select("file0"); | |
} | |
})(); | |
</script> | |
</body></html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment