Skip to content

Instantly share code, notes, and snippets.

@ncruces
Created May 10, 2024 15:49
Show Gist options
  • Save ncruces/f0d7eb7432a5854271be4e5b7b5eee17 to your computer and use it in GitHub Desktop.
Save ncruces/f0d7eb7432a5854271be4e5b7b5eee17 to your computer and use it in GitHub Desktop.
Adiantum coverage
<!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(&amp;outT, append(tweakBuf[:16], tweak...), &amp;h.keyT)
// NH hash message in chunks of up to 1024 bytes, then poly1305 those hashes
// with keyM
mac := poly1305.New(&amp;h.keyM)
var outNH [32]byte
for len(msg) &gt;= 1024 </span><span class="cov8" title="1">{
nh.Sum(&amp;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) &gt; 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(&amp;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 := &amp;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 &amp;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(&amp;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 := &amp;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, &amp;Nonce)</span>
case INonceSize:<span class="cov0" title="0">
copy(Nonce[4:], nonce)
initialize(state, key, &amp;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, &amp;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) &lt; 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 &amp;&amp; rounds != 12 &amp;&amp; rounds != 8 </span><span class="cov0" title="0">{
panic("chacha20/chacha: bad number of rounds")</span>
}
<span class="cov8" title="1">if len(dst) &lt; 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 &amp;&amp; uint64(len(src)) &gt; (1&lt;&lt;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(&amp;state, nonce, key); err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov8" title="1">xorKeyStream(dst, src, &amp;block, &amp;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) &gt;= 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 &gt; 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 &lt; rounds; i += 2 </span><span class="cov8" title="1">{
v00 += v04
v12 ^= v00
v12 = (v12 &lt;&lt; 16) | (v12 &gt;&gt; 16)
v08 += v12
v04 ^= v08
v04 = (v04 &lt;&lt; 12) | (v04 &gt;&gt; 20)
v00 += v04
v12 ^= v00
v12 = (v12 &lt;&lt; 8) | (v12 &gt;&gt; 24)
v08 += v12
v04 ^= v08
v04 = (v04 &lt;&lt; 7) | (v04 &gt;&gt; 25)
v01 += v05
v13 ^= v01
v13 = (v13 &lt;&lt; 16) | (v13 &gt;&gt; 16)
v09 += v13
v05 ^= v09
v05 = (v05 &lt;&lt; 12) | (v05 &gt;&gt; 20)
v01 += v05
v13 ^= v01
v13 = (v13 &lt;&lt; 8) | (v13 &gt;&gt; 24)
v09 += v13
v05 ^= v09
v05 = (v05 &lt;&lt; 7) | (v05 &gt;&gt; 25)
v02 += v06
v14 ^= v02
v14 = (v14 &lt;&lt; 16) | (v14 &gt;&gt; 16)
v10 += v14
v06 ^= v10
v06 = (v06 &lt;&lt; 12) | (v06 &gt;&gt; 20)
v02 += v06
v14 ^= v02
v14 = (v14 &lt;&lt; 8) | (v14 &gt;&gt; 24)
v10 += v14
v06 ^= v10
v06 = (v06 &lt;&lt; 7) | (v06 &gt;&gt; 25)
v03 += v07
v15 ^= v03
v15 = (v15 &lt;&lt; 16) | (v15 &gt;&gt; 16)
v11 += v15
v07 ^= v11
v07 = (v07 &lt;&lt; 12) | (v07 &gt;&gt; 20)
v03 += v07
v15 ^= v03
v15 = (v15 &lt;&lt; 8) | (v15 &gt;&gt; 24)
v11 += v15
v07 ^= v11
v07 = (v07 &lt;&lt; 7) | (v07 &gt;&gt; 25)
v00 += v05
v15 ^= v00
v15 = (v15 &lt;&lt; 16) | (v15 &gt;&gt; 16)
v10 += v15
v05 ^= v10
v05 = (v05 &lt;&lt; 12) | (v05 &gt;&gt; 20)
v00 += v05
v15 ^= v00
v15 = (v15 &lt;&lt; 8) | (v15 &gt;&gt; 24)
v10 += v15
v05 ^= v10
v05 = (v05 &lt;&lt; 7) | (v05 &gt;&gt; 25)
v01 += v06
v12 ^= v01
v12 = (v12 &lt;&lt; 16) | (v12 &gt;&gt; 16)
v11 += v12
v06 ^= v11
v06 = (v06 &lt;&lt; 12) | (v06 &gt;&gt; 20)
v01 += v06
v12 ^= v01
v12 = (v12 &lt;&lt; 8) | (v12 &gt;&gt; 24)
v11 += v12
v06 ^= v11
v06 = (v06 &lt;&lt; 7) | (v06 &gt;&gt; 25)
v02 += v07
v13 ^= v02
v13 = (v13 &lt;&lt; 16) | (v13 &gt;&gt; 16)
v08 += v13
v07 ^= v08
v07 = (v07 &lt;&lt; 12) | (v07 &gt;&gt; 20)
v02 += v07
v13 ^= v02
v13 = (v13 &lt;&lt; 8) | (v13 &gt;&gt; 24)
v08 += v13
v07 ^= v08
v07 = (v07 &lt;&lt; 7) | (v07 &gt;&gt; 25)
v03 += v04
v14 ^= v03
v14 = (v14 &lt;&lt; 16) | (v14 &gt;&gt; 16)
v09 += v14
v04 ^= v09
v04 = (v04 &lt;&lt; 12) | (v04 &gt;&gt; 20)
v03 += v04
v14 ^= v03
v14 = (v14 &lt;&lt; 8) | (v14 &gt;&gt; 24)
v09 += v14
v04 ^= v09
v04 = (v04 &lt;&lt; 7) | (v04 &gt;&gt; 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 &amp;&amp; (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(&amp;tmpKey, &amp;hNonce, &amp;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 &lt; rounds; i += 2 </span><span class="cov8" title="1">{
v00 += v04
v12 ^= v00
v12 = (v12 &lt;&lt; 16) | (v12 &gt;&gt; 16)
v08 += v12
v04 ^= v08
v04 = (v04 &lt;&lt; 12) | (v04 &gt;&gt; 20)
v00 += v04
v12 ^= v00
v12 = (v12 &lt;&lt; 8) | (v12 &gt;&gt; 24)
v08 += v12
v04 ^= v08
v04 = (v04 &lt;&lt; 7) | (v04 &gt;&gt; 25)
v01 += v05
v13 ^= v01
v13 = (v13 &lt;&lt; 16) | (v13 &gt;&gt; 16)
v09 += v13
v05 ^= v09
v05 = (v05 &lt;&lt; 12) | (v05 &gt;&gt; 20)
v01 += v05
v13 ^= v01
v13 = (v13 &lt;&lt; 8) | (v13 &gt;&gt; 24)
v09 += v13
v05 ^= v09
v05 = (v05 &lt;&lt; 7) | (v05 &gt;&gt; 25)
v02 += v06
v14 ^= v02
v14 = (v14 &lt;&lt; 16) | (v14 &gt;&gt; 16)
v10 += v14
v06 ^= v10
v06 = (v06 &lt;&lt; 12) | (v06 &gt;&gt; 20)
v02 += v06
v14 ^= v02
v14 = (v14 &lt;&lt; 8) | (v14 &gt;&gt; 24)
v10 += v14
v06 ^= v10
v06 = (v06 &lt;&lt; 7) | (v06 &gt;&gt; 25)
v03 += v07
v15 ^= v03
v15 = (v15 &lt;&lt; 16) | (v15 &gt;&gt; 16)
v11 += v15
v07 ^= v11
v07 = (v07 &lt;&lt; 12) | (v07 &gt;&gt; 20)
v03 += v07
v15 ^= v03
v15 = (v15 &lt;&lt; 8) | (v15 &gt;&gt; 24)
v11 += v15
v07 ^= v11
v07 = (v07 &lt;&lt; 7) | (v07 &gt;&gt; 25)
v00 += v05
v15 ^= v00
v15 = (v15 &lt;&lt; 16) | (v15 &gt;&gt; 16)
v10 += v15
v05 ^= v10
v05 = (v05 &lt;&lt; 12) | (v05 &gt;&gt; 20)
v00 += v05
v15 ^= v00
v15 = (v15 &lt;&lt; 8) | (v15 &gt;&gt; 24)
v10 += v15
v05 ^= v10
v05 = (v05 &lt;&lt; 7) | (v05 &gt;&gt; 25)
v01 += v06
v12 ^= v01
v12 = (v12 &lt;&lt; 16) | (v12 &gt;&gt; 16)
v11 += v12
v06 ^= v11
v06 = (v06 &lt;&lt; 12) | (v06 &gt;&gt; 20)
v01 += v06
v12 ^= v01
v12 = (v12 &lt;&lt; 8) | (v12 &gt;&gt; 24)
v11 += v12
v06 ^= v11
v06 = (v06 &lt;&lt; 7) | (v06 &gt;&gt; 25)
v02 += v07
v13 ^= v02
v13 = (v13 &lt;&lt; 16) | (v13 &gt;&gt; 16)
v08 += v13
v07 ^= v08
v07 = (v07 &lt;&lt; 12) | (v07 &gt;&gt; 20)
v02 += v07
v13 ^= v02
v13 = (v13 &lt;&lt; 8) | (v13 &gt;&gt; 24)
v08 += v13
v07 ^= v08
v07 = (v07 &lt;&lt; 7) | (v07 &gt;&gt; 25)
v03 += v04
v14 ^= v03
v14 = (v14 &lt;&lt; 16) | (v14 &gt;&gt; 16)
v09 += v14
v04 ^= v09
v04 = (v04 &lt;&lt; 12) | (v04 &gt;&gt; 20)
v03 += v04
v14 ^= v03
v14 = (v14 &lt;&lt; 8) | (v14 &gt;&gt; 24)
v09 += v14
v04 ^= v09
v04 = (v04 &lt;&lt; 7) | (v04 &gt;&gt; 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) &lt; 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 &amp;&amp; !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) &gt;= 4 &amp;&amp; len(k) &gt;= 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