+++ /dev/null
-* Increase performance
-* Randomize ports usage
--- /dev/null
+doc/todo.texi
\ No newline at end of file
@node Client part
@section Client part
-Except for common @code{-mtu}, @code{-stats} options client has the
-following ones:
+Except for common @code{-mtu}, @code{-stats}, @code{-egd} options client
+has the following ones:
@table @code
@item -timeout
@ref{Timeout} setting in seconds.
-@item -noncediff
-Allowable @ref{Nonce difference}.
-
@item -noise
Enable @ref{Noise}.
@table @asis
@item Nonce and identity encryption
-@url{http://143.53.36.235:8080/tea.htm, XTEA}
+@url{http://143.53.36.235:8080/tea.htm, XTEA}.
@item Data encryption
-@url{http://cr.yp.to/snuffle.html, Salsa20}
+@url{http://cr.yp.to/snuffle.html, Salsa20}.
@item Message authentication
-@url{http://cr.yp.to/mac.html, Poly1305}
+@url{http://cr.yp.to/mac.html, Poly1305}.
@item Password authenticated key agreement
DH-A-EKE powered by @url{http://cr.yp.to/ecdh.html, Curve25519}
-and @url{http://ed25519.cr.yp.to/, Ed25519}
+and @url{http://ed25519.cr.yp.to/, Ed25519}.
@item DH elliptic-curve point encoding for public keys
-@url{http://elligator.cr.yp.to/, Elligator}
+@url{http://elligator.cr.yp.to/, Elligator}.
@item Key derivation function for verifier generation
@url{https://en.wikipedia.org/wiki/PBKDF2, PBKDF2} based on
-@url{https://en.wikipedia.org/wiki/SHA-2, SHA-512}
+@url{https://en.wikipedia.org/wiki/SHA-2, SHA-512}.
@item Packet overhead
-26 bytes per packet
+26 bytes per packet.
@item Handshake overhead
-4 UDP (2 from client, 2 from server) packets, 264 bytes total payload
+4 UDP (2 from client, 2 from server) packets, 264 bytes total payload.
+@item Entropy required
+832 bits in average on client, 832 bits in average on server side per
+handshake.
@end table
@menu
@tab @url{download/govpn-3.2.tar.xz, link} @url{download/govpn-3.2.tar.xz.sig, sign}
@tab @code{388e98d6adef5ebf3431b0d48419f54d2e2064c657de67e23c669ebcf273126d}
+@item 3.3 @tab 175 KiB
+@tab @url{download/govpn-3.3.tar.xz, link} @url{download/govpn-3.3.tar.xz.sig, sign}
+@tab @code{1834a057215324f49d6272b2beb89f1532105156f7e853eae855659992ac0c84}
+
@end multitable
Also you can try its @ref{Contacts, .onion} version.
--- /dev/null
+@node EGD
+@section EGD
+
+Overall security mainly depends on client side:
+@ref{PAKE, good passphrase} and cryprographically good pseudo random
+number generator.
+
+Some operating systems do not have good enough quality PRNG, bad
+@code{/dev/urandom}. You should use separate PRNG with them. GoVPN
+communicates with them using
+@url{http://egd.sourceforge.net/, Entropy Gathering Daemon} protocol.
+
+To switch using EGD-compatible daemons instead of @code{crypto/rand}
+library you provide @code{-egd PATH} command line option, where
+@code{PATH} is the domain socket.
+
+@example
+% ./govpn-server [...] -egd /var/run/egd.sock
+@end example
* Contacts::
* Copying conditions::
* Thanks::
+* TODO::
@end menu
@include overview.texi
@verbatiminclude fdl.txt
@include thanks.texi
+@include todo.texi
@bye
exchange, EKE, Diffie-Hellman, DH, DH-EKE, Augmented EKE, A-EKE,
security, encrypted key exchange, 128-bit margin, DPI, censorship,
resistance, free software, GPLv3+, reviewability, easy, simple,
-Curve25519, Ed25519, Elligator, SHA-512, Salsa20, Poly1305, AEAD, XTEA, PBKDF2,
-PRP, signatures, asymmetric cryptography, zero-knowledge password proof,
-PAKE, password, passphrase, password authenticated key exchange, perfect
-forward secrecy, PFS, MAC, nonce, verifier, rehandshake, heartbeat,
-replay attack, MiTM, length hiding, timestamps hiding, noise, constant
-traffic, constant packet rate, CPR, TAP, TAP, VPN, GNU, Linux, FreeBSD,
-IPv6, dictionary attack, mutual authentication, simultaneous clients,
-JSON, HTTP-server, statistics, PRNG, traffic analysis, Go, golang.
+Curve25519, Ed25519, Elligator, SHA-512, Salsa20, Poly1305, AEAD, XTEA,
+PBKDF2, PRP, signatures, asymmetric cryptography, zero-knowledge
+password proof, PAKE, password, passphrase, password authenticated key
+exchange, perfect forward secrecy, PFS, MAC, nonce, verifier,
+rehandshake, heartbeat, replay attack, MiTM, length hiding, timestamps
+hiding, noise, constant traffic, constant packet rate, CPR, EGD,
+entropy, TAP, TAP, VPN, GNU, Linux, FreeBSD, IPv6, dictionary attack,
+mutual authentication, simultaneous clients, JSON, HTTP-server,
+statistics, PRNG, traffic analysis, Go, golang.
@table @strong
+@item Release 3.4
+@itemize @bullet
+@item Ability to use external @ref{EGD}-compatible PRNGs. Now you are
+able to use GoVPN even on systems with the bad @code{/dev/random},
+providing higher quality entropy from external sources.
+@item Removed @code{-noncediff} option. It is replaced with in-memory
+storage of seen nonces, thus eliminating possible replay attacks at all
+without performance degradation related to inbound packets reordering.
+@end itemize
+
@item Release 3.3
@itemize @bullet
@item Compatibility with an old GNU Make 3.x. Previously only BSD Make
+++ /dev/null
-@node Nonce difference
-@section Nonce difference
-
-GoVPN prevents replay attacks by remembering the last used nonce in
-messages from the remote peer. All incoming messages must have higher
-nonce number (technically it is counter), otherwise they are dropped.
-
-Because of UDP nature that does not guarantee packet ordering during
-transmission, GoVPN will drop valid non-replayed UDP packets. That leads
-to performance decrease.
-
-In most cases there is no need in so strict nonce boundaries and
-@code{-noncediff} command line option allows to create the window of
-allowable nonce differences. This is trade-off between highest security
-and possible performance degradation. For example @code{-noncediff 128}
-works rather well (no packet drops) with 1 Gbps link with two switches.
-By default no nonce differences are allowed (highest security).
implementations in software are too complex to be reviewed, analyzed and
modified.
-State off art cryptography technologies includes:
-@url{http://cr.yp.to/snuffle.html, Salsa20} stream encryption,
-@url{http://143.53.36.235:8080/tea.htm, XTEA} PRP,
-@url{http://cr.yp.to/mac.html, Poly1305} message authentication,
-@url{https://en.wikipedia.org/wiki/PBKDF2} password-based key derivation
-function based on @url{https://en.wikipedia.org/wiki/SHA-2, SHA-512}
-hash function,
-@url{https://en.wikipedia.org/wiki/Encrypted_key_exchange,
-Diffie-Hellman Augmented Encrypted Key Exchange}
-(DH-A-EKE) powered by @url{http://cr.yp.to/ecdh.html, Curve25519},
-@url{http://ed25519.cr.yp.to/, Ed25519} signatures and
-@url{http://elligator.cr.yp.to/, Elligator} curve-point encoding.
-Strong
-@url{https://en.wikipedia.org/wiki/Zero-knowledge_password_proof, zero-knowledge}
-mutual authentication with key exchange stage is invulnerable
-to man-in-the-middle attacks.
+@ref{Developer manual, State off art cryptography technologies}. Strong
+mutual authenticated key exchange is invulnerable to man-in-the middle
+attachs.
@url{https://en.wikipedia.org/wiki/Forward_secrecy, Perfect forward secrecy}
-property guarantee that compromising of long-term authentication
-pre-shared key can not lead to previously captured traffic decrypting.
-Compromising of peers password file on server side won't allow attacker
+property guarantees that compromising of long-term authentication keys
+does not lead to previously captured traffic decrypting.
+Compromising of peers password files on server side won't allow attacker
to masquerade as the client, because of asymmetric @strong{verifiers}
usage, resistant to dictionary attacks. Rehandshaking ensures session
-keys rotation. MAC authentication with one-time keys protects against
+keys rotation. One-time keys MAC authentication protects against
@url{https://en.wikipedia.org/wiki/Replay_attack, replay attacks}.
Server can work with several clients simultaneously. Each client is
network interfaces on top of UDP entirely
@item
@url{https://www.gnu.org/, GNU}/Linux and
-@url{http://www.freebsd.org/, FreeBSD} support
-@item IPv6 compatible
-@item Encrypted and authenticated payload transport
-@item Relatively fast handshake
-@item Password-authenticated key exchange
-@item Server-side password verifiers are secure against dictionary attacks
-@item Attacker can not masquerade a client even with password files compromising
-@item Replay attack protection
-@item Perfect forward secrecy property
-@item Mutual two-side authentication
-@item Zero knowledge authentication
-@item Built-in rehandshake and heartbeat features
-@item Several simultaneous clients support
-@item Per-client configuration options
-@item Hiding of payload packets length with noise
-@item Hiding of payload packets timestamps with constant packet rate traffic
+@url{http://www.freebsd.org/, FreeBSD} support.
+@item IPv6 compatible.
+@item Encrypted and authenticated payload transport.
+@item Relatively fast handshake.
+@item Password-authenticated key exchange.
+@item Server-side password verifiers are secure against dictionary
+attacks.
+@item Attacker can not masquerade a client even with password files
+compromising.
+@item Replay attack protection.
+@item Perfect forward secrecy property.
+@item Mutual two-side authentication.
+@item Zero knowledge authentication.
+@item Built-in rehandshake and heartbeat features.
+@item Several simultaneous clients support.
+@item Per-client configuration options.
+@item Hiding of payload packets length with noise.
+@item Hiding of payload packets timestamps with constant packet rate
+traffic.
@item Optional built-in HTTP-server for retrieving information about
-known connected peers in @url{http://json.org/, JSON} format
+known connected peers in @url{http://json.org/, JSON} format.
+@item Compatibility with @url{http://egd.sourceforge.net/, EGD} PRNGs.
@end itemize
@node Precautions
@unnumbered Precautions
-The very important precaution is the @strong{cryptographically good}
-pseudo random number generator. GoVPN uses native operating system PRNG
-as entropy source. You have no way to check its quality in closed
-source code operating systems, so it is recommended not to use them if
-you really needs security. Moreover it is possible that those OS leaks
-information about possible PRNG states. And at least Apple OS X and
-Microsoft Windows are already known to have weak CSPRNGs.
-
-GoVPN could use its own PRNG implementation like
-@url{https://www.schneier.com/fortuna.html, Fortuna}, but it is
-much easier to use the right OS, to use free software.
+@enumerate
+@item
+We use password (passphrase) authentication, so overall security fully
+depends on its strength. You @strong{should} use long, high-entropy
+passphrases. Also remember to keep passphrase in temporary file and read
+it securely as described in @ref{Verifier}.
-Also you should @strong{never} use one key for multiple clients. Salsa20
-encryption is randomized in each session, but it depends again on PRNG.
-If it fails, produces equal values at least once, then all you traffic
-related to that key could be decrypted.
+@item
+You must @strong{never} use one key for multiple clients.
-We use password (passphrase) authentication, so overall security fully
-depends on its strength. So you should use long, high-entropy
-passphrases. Also remember to keep passphrase on temporary file as
-described in @ref{Verifier}.
+@item
+You must use @strong{cryptographically good} pseudo random number
+generator. By default we use default @code{crypto/rand} library that
+reads @code{/dev/urandom} source. Some GNU/Linux and FreeBSD systems
+are rather good with this entropy source. Closed proprietary ones are
+always not and you must use optional @ref{EGD} feature with them.
+@end enumerate
@node Server part
@section Server part
-Except for common @code{-mtu}, @code{-stats} options server has the
-following ones:
+Except for common @code{-mtu}, @code{-stats}, @code{-egd} options server
+has the following ones:
@table @code
@item -bind
Optional. Contains @ref{Timeout} setting (decimal notation) in seconds.
Otherwise default minute timeout will be used.
-@item noncediff
-Optional. Contains allowable @ref{Nonce difference} setting (decimal
-notation).
-
@item noise
Optional. Contains either "1" (enable @ref{Noise} adding), or "0".
--- /dev/null
+@node TODO
+@unnumbered TODO
+
+@itemize
+@item Ability to tunnel only specified TCP connections, without full
+ featured VPN solution. Similar to ssh -R.
+@item Ability to work over HTTP, WebSockets and something similar.
+@item Ability to noise handshake packets sizes.
+@item Increase performance.
+@item Randomize ports usage.
+@end itemize
of Salsa20 are ignored. All remaining output is XORed with the data,
encrypting it.
-To prevent replay attacks we remember latest @code{SERIAL} from the
-remote peer. If received message's @code{SERIAL} is not greater that the
-saved one, then drop it. Optionally, because some UDP packets can be
-reordered during transmission, we can allow some window for valid
-serials with the @code{-noncediff} option. @code{-noncediff 10} with
-current saved serial state equals to 78 allows messages with 68…78
-serials. That time window can be used by attacker to replay packets, so
-by default it equals to 1. However it can improve performance because of
-rearranged UDP packets.
+To prevent replay attacks we must remember received @code{SERIAL}s and
+if meet one, then drop it. Basically we could just store latest number
+and check if received one is greater, but because of UDP packets
+reordering this can lead to valid packets dropping and overall
+performance degradation. We store up to 256 seen nonces in hash
+structure, in two swapping buckets.
automate it using up and down shell scripts.
@menu
+* EGD:: Entropy gathering daemon
* Identity::
* PAKE:: Password Authenticated Key Agreement
* Timeout::
-* Nonce difference::
* MTU:: Maximum Transmission Unit
* Stats::
* Noise::
* Example usage::
@end menu
+@include egd.texi
@include identity.texi
@include pake.texi
@include timeout.texi
-@include noncediff.texi
@include mtu.texi
@include stats.texi
@include noise.texi
PUB, PRIV = Ed25519.Generate(SOURCE)
@end verbatim
-Verifier is public key of Ed25519 generated from the PBKDF2 of the
-passphrase in hexadecimal encoding. @code{PeerId} is used as a 128-bit
-salt. Server stores and knows only verifier. Client can compute the
-whole keypair every time he makes handshake.
+Verifier is @code{PUB} public key of Ed25519 generated from the PBKDF2
+of the passphrase in hexadecimal encoding. @code{PeerId} is used as a
+128-bit salt. Server stores and knows only verifier. Client can compute
+the whole keypair every time he makes handshake.
downPath = flag.String("down", "", "Path to down-script")
stats = flag.String("stats", "", "Enable stats retrieving on host:port")
mtu = flag.Int("mtu", 1452, "MTU for outgoing packets")
- nonceDiff = flag.Int("noncediff", 1, "Allow nonce difference")
timeoutP = flag.Int("timeout", 60, "Timeout seconds")
noisy = flag.Bool("noise", false, "Enable noise appending")
cpr = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate")
+ egdPath = flag.String("egd", "", "Optional path to EGD socket")
)
func main() {
log.Fatalln(err)
}
+ if *egdPath != "" {
+ log.Println("Using", *egdPath, "EGD")
+ govpn.EGDInit(*egdPath)
+ }
+
pub, priv := govpn.NewVerifier(id, govpn.StringFromFile(*keyPath))
conf := &govpn.PeerConf{
Id: id,
Timeout: time.Second * time.Duration(timeout),
- Noncediff: *nonceDiff,
NoiseEnable: *noisy,
CPR: *cpr,
DSAPub: pub,
peersPath = flag.String("peers", "peers", "Path to peers keys directory")
stats = flag.String("stats", "", "Enable stats retrieving on host:port")
mtu = flag.Int("mtu", 1452, "MTU for outgoing packets")
+ egdPath = flag.String("egd", "", "Optional path to EGD socket")
)
type PeerReadyEvent struct {
govpn.MTU = *mtu
govpn.PeersInit(*peersPath)
+ if *egdPath != "" {
+ log.Println("Using", *egdPath, "EGD")
+ govpn.EGDInit(*egdPath)
+ }
+
bind, err := net.ResolveUDPAddr("udp", *bindAddr)
if err != nil {
log.Fatalln("Can not resolve bind address:", err)
--- /dev/null
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package govpn
+
+import (
+ "errors"
+ "net"
+)
+
+var (
+ egdPath string
+)
+
+func EGDInit(path string) {
+ egdPath = path
+}
+
+// Read n bytes from EGD, blocking mode.
+func EGDRead(b []byte) error {
+ c, err := net.Dial("unix", egdPath)
+ if err != nil {
+ return err
+ }
+ defer c.Close()
+ c.Write([]byte{0x02, byte(len(b))})
+ r, err := c.Read(b)
+ if err != nil {
+ return err
+ }
+ if r != len(b) {
+ return errors.New("Got less bytes than expected from EGD")
+ }
+ return nil
+}
return nonce
}
+func randRead(b []byte) error {
+ var err error
+ if egdPath == "" {
+ _, err = rand.Read(b)
+ } else {
+ err = EGDRead(b)
+ }
+ return err
+}
+
func dhKeypairGen() (*[32]byte, *[32]byte) {
priv := new([32]byte)
pub := new([32]byte)
repr := new([32]byte)
reprFound := false
for !reprFound {
- if _, err := rand.Read(priv[:]); err != nil {
+ if err := randRead(priv[:]); err != nil {
log.Fatalln("Error reading random for DH private key:", err)
}
reprFound = extra25519.ScalarBaseMult(pub, repr, priv)
state.dhPriv, dhPubRepr = dhKeypairGen()
state.rNonce = new([RSize]byte)
- if _, err := rand.Read(state.rNonce[:]); err != nil {
+ if err := randRead(state.rNonce[:]); err != nil {
log.Fatalln("Error reading random for nonce:", err)
}
enc := make([]byte, 32)
// Generate R* and encrypt them
h.rServer = new([RSize]byte)
- if _, err := rand.Read(h.rServer[:]); err != nil {
+ if err := randRead(h.rServer[:]); err != nil {
log.Fatalln("Error reading random for R:", err)
}
h.sServer = new([SSize]byte)
- if _, err := rand.Read(h.sServer[:]); err != nil {
+ if err := randRead(h.sServer[:]); err != nil {
log.Fatalln("Error reading random for S:", err)
}
encRs := make([]byte, RSize+SSize)
// Generate R* and signature and encrypt them
h.rClient = new([RSize]byte)
- if _, err := rand.Read(h.rClient[:]); err != nil {
+ if err := randRead(h.rClient[:]); err != nil {
log.Fatalln("Error reading random for R:", err)
}
h.sClient = new([SSize]byte)
- if _, err := rand.Read(h.sClient[:]); err != nil {
+ if err := randRead(h.sClient[:]); err != nil {
log.Fatalln("Error reading random for S:", err)
}
sign := ed25519.Sign(h.Conf.DSAPriv, h.key[:])
type PeerConf struct {
Id *PeerId
Timeout time.Duration
- Noncediff int
NoiseEnable bool
CPR int
// This is passphrase verifier
if dummyConf != nil {
return dummyConf
}
- conf := PeerConf{Id: id, Noncediff: 1, NoiseEnable: false, CPR: 0}
+ conf := PeerConf{Id: id, NoiseEnable: false, CPR: 0}
peerPath := path.Join(PeersPath, id.String())
verPath := path.Join(peerPath, "verifier")
}
conf.Timeout = time.Second * time.Duration(timeout)
- if val, err := readIntFromFile(path.Join(peerPath, "noncediff")); err == nil {
- conf.Noncediff = val
- }
if val, err := readIntFromFile(path.Join(peerPath, "noise")); err == nil && val == 1 {
conf.NoiseEnable = true
}
)
const (
- NonceSize = 8
+ NonceSize = 8
+ NonceBucketSize = 128
// S20BS is Salsa20's internal blocksize in bytes
S20BS = 64
// Maximal amount of bytes transfered with single key (4 GiB)
CPRCycle time.Duration `json:"-"`
// Cryptography related
- Key *[SSize]byte `json:"-"`
- Noncediff int
- NonceOur uint64 `json:"-"`
- NonceRecv uint64 `json:"-"`
- NonceCipher *xtea.Cipher `json:"-"`
+ Key *[SSize]byte `json:"-"`
+ NonceOur uint64 `json:"-"`
+ NonceRecv uint64 `json:"-"`
+ NonceCipher *xtea.Cipher `json:"-"`
+ nonceBucket0 map[uint64]struct{}
+ nonceBucket1 map[uint64]struct{}
+ nonceFound bool
+ nonceBucketN int32
// Timers
Timeout time.Duration `json:"-"`
timeout = timeout / TimeoutHeartbeat
}
peer := Peer{
- Addr: addr,
- Timeout: timeout,
- Established: now,
- LastPing: now,
- Id: conf.Id,
- NoiseEnable: noiseEnable,
- CPR: conf.CPR,
- CPRCycle: cprCycle,
- Noncediff: conf.Noncediff,
- NonceOur: uint64(conf.Noncediff + nonce),
- NonceRecv: uint64(conf.Noncediff + 0),
- Key: key,
- NonceCipher: newNonceCipher(key),
- buf: make([]byte, MTU+S20BS),
- tag: new([poly1305.TagSize]byte),
- keyAuth: new([SSize]byte),
- nonce: make([]byte, NonceSize),
+ Addr: addr,
+ Timeout: timeout,
+ Established: now,
+ LastPing: now,
+ Id: conf.Id,
+ NoiseEnable: noiseEnable,
+ CPR: conf.CPR,
+ CPRCycle: cprCycle,
+ NonceOur: uint64(nonce),
+ NonceRecv: uint64(0),
+ nonceBucket0: make(map[uint64]struct{}, NonceBucketSize),
+ nonceBucket1: make(map[uint64]struct{}, NonceBucketSize),
+ Key: key,
+ NonceCipher: newNonceCipher(key),
+ buf: make([]byte, MTU+S20BS),
+ tag: new([poly1305.TagSize]byte),
+ keyAuth: new([SSize]byte),
+ nonce: make([]byte, NonceSize),
}
return &peer
}
p.FramesUnauth++
return false
}
+
+ // Check if received nonce is known to us in either of two buckets.
+ // If yes, then this is ignored duplicate.
+ // Check from the oldest bucket, as in most cases this will result
+ // in constant time check.
+ // If Bucket0 is filled, then it becomes Bucket1.
p.NonceCipher.Decrypt(p.buf, udpPkt[:NonceSize])
+ ready <- struct{}{}
p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
- if int(p.NonceRecv)-p.Noncediff >= 0 && int(p.nonceRecv) < int(p.NonceRecv)-p.Noncediff {
- ready <- struct{}{}
+ if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
p.FramesDup++
return false
}
- ready <- struct{}{}
+ if _, p.nonceFound = p.nonceBucket0[p.NonceRecv]; p.nonceFound {
+ p.FramesDup++
+ return false
+ }
+ p.nonceBucket0[p.NonceRecv] = struct{}{}
+ p.nonceBucketN++
+ if p.nonceBucketN == NonceBucketSize {
+ p.nonceBucket1 = p.nonceBucket0
+ p.nonceBucket0 = make(map[uint64]struct{}, NonceBucketSize)
+ p.nonceBucketN = 0
+ }
+
p.FramesIn++
p.BytesIn += int64(p.size)
p.LastPing = time.Now()
conf = &PeerConf{
Id: peerId,
Timeout: time.Second * time.Duration(TimeoutDefault),
- Noncediff: 1,
NoiseEnable: false,
CPR: 0,
}
peer = newPeer(addr, conf, 128, new([SSize]byte))
b.ResetTimer()
for i := 0; i < b.N; i++ {
+ peer.nonceBucket0 = make(map[uint64]struct{}, 1)
+ peer.nonceBucket1 = make(map[uint64]struct{}, 1)
if !peer.UDPProcess(ciphertext, dummy, ready) {
b.Fail()
}