Explorar el Código

分布式抽取

zhangjinkun hace 6 años
padre
commit
c2ec32148d
Se han modificado 100 ficheros con 27039 adiciones y 4 borrados
  1. 27 4
      src/config.json
  2. 10 0
      src/golang.org/x/crypto/.gitattributes
  3. 2 0
      src/golang.org/x/crypto/.gitignore
  4. 3 0
      src/golang.org/x/crypto/AUTHORS
  5. 26 0
      src/golang.org/x/crypto/CONTRIBUTING.md
  6. 3 0
      src/golang.org/x/crypto/CONTRIBUTORS
  7. 27 0
      src/golang.org/x/crypto/LICENSE
  8. 22 0
      src/golang.org/x/crypto/PATENTS
  9. 21 0
      src/golang.org/x/crypto/README.md
  10. 926 0
      src/golang.org/x/crypto/acme/acme.go
  11. 1313 0
      src/golang.org/x/crypto/acme/acme_test.go
  12. 1139 0
      src/golang.org/x/crypto/acme/autocert/autocert.go
  13. 1189 0
      src/golang.org/x/crypto/acme/autocert/autocert_test.go
  14. 130 0
      src/golang.org/x/crypto/acme/autocert/cache.go
  15. 58 0
      src/golang.org/x/crypto/acme/autocert/cache_test.go
  16. 34 0
      src/golang.org/x/crypto/acme/autocert/example_test.go
  17. 416 0
      src/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go
  18. 157 0
      src/golang.org/x/crypto/acme/autocert/listener.go
  19. 141 0
      src/golang.org/x/crypto/acme/autocert/renewal.go
  20. 329 0
      src/golang.org/x/crypto/acme/autocert/renewal_test.go
  21. 281 0
      src/golang.org/x/crypto/acme/http.go
  22. 209 0
      src/golang.org/x/crypto/acme/http_test.go
  23. 156 0
      src/golang.org/x/crypto/acme/jws.go
  24. 394 0
      src/golang.org/x/crypto/acme/jws_test.go
  25. 329 0
      src/golang.org/x/crypto/acme/types.go
  26. 63 0
      src/golang.org/x/crypto/acme/types_test.go
  27. 285 0
      src/golang.org/x/crypto/argon2/argon2.go
  28. 233 0
      src/golang.org/x/crypto/argon2/argon2_test.go
  29. 53 0
      src/golang.org/x/crypto/argon2/blake2b.go
  30. 60 0
      src/golang.org/x/crypto/argon2/blamka_amd64.go
  31. 243 0
      src/golang.org/x/crypto/argon2/blamka_amd64.s
  32. 163 0
      src/golang.org/x/crypto/argon2/blamka_generic.go
  33. 15 0
      src/golang.org/x/crypto/argon2/blamka_ref.go
  34. 35 0
      src/golang.org/x/crypto/bcrypt/base64.go
  35. 295 0
      src/golang.org/x/crypto/bcrypt/bcrypt.go
  36. 243 0
      src/golang.org/x/crypto/bcrypt/bcrypt_test.go
  37. 289 0
      src/golang.org/x/crypto/blake2b/blake2b.go
  38. 37 0
      src/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go
  39. 750 0
      src/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
  40. 24 0
      src/golang.org/x/crypto/blake2b/blake2b_amd64.go
  41. 281 0
      src/golang.org/x/crypto/blake2b/blake2b_amd64.s
  42. 179 0
      src/golang.org/x/crypto/blake2b/blake2b_generic.go
  43. 11 0
      src/golang.org/x/crypto/blake2b/blake2b_ref.go
  44. 847 0
      src/golang.org/x/crypto/blake2b/blake2b_test.go
  45. 177 0
      src/golang.org/x/crypto/blake2b/blake2x.go
  46. 32 0
      src/golang.org/x/crypto/blake2b/register.go
  47. 244 0
      src/golang.org/x/crypto/blake2s/blake2s.go
  48. 32 0
      src/golang.org/x/crypto/blake2s/blake2s_386.go
  49. 435 0
      src/golang.org/x/crypto/blake2s/blake2s_386.s
  50. 37 0
      src/golang.org/x/crypto/blake2s/blake2s_amd64.go
  51. 438 0
      src/golang.org/x/crypto/blake2s/blake2s_amd64.s
  52. 174 0
      src/golang.org/x/crypto/blake2s/blake2s_generic.go
  53. 17 0
      src/golang.org/x/crypto/blake2s/blake2s_ref.go
  54. 1050 0
      src/golang.org/x/crypto/blake2s/blake2s_test.go
  55. 178 0
      src/golang.org/x/crypto/blake2s/blake2x.go
  56. 21 0
      src/golang.org/x/crypto/blake2s/register.go
  57. 159 0
      src/golang.org/x/crypto/blowfish/block.go
  58. 274 0
      src/golang.org/x/crypto/blowfish/blowfish_test.go
  59. 91 0
      src/golang.org/x/crypto/blowfish/cipher.go
  60. 199 0
      src/golang.org/x/crypto/blowfish/const.go
  61. 416 0
      src/golang.org/x/crypto/bn256/bn256.go
  62. 304 0
      src/golang.org/x/crypto/bn256/bn256_test.go
  63. 44 0
      src/golang.org/x/crypto/bn256/constants.go
  64. 287 0
      src/golang.org/x/crypto/bn256/curve.go
  65. 43 0
      src/golang.org/x/crypto/bn256/example_test.go
  66. 200 0
      src/golang.org/x/crypto/bn256/gfp12.go
  67. 219 0
      src/golang.org/x/crypto/bn256/gfp2.go
  68. 296 0
      src/golang.org/x/crypto/bn256/gfp6.go
  69. 395 0
      src/golang.org/x/crypto/bn256/optate.go
  70. 258 0
      src/golang.org/x/crypto/bn256/twist.go
  71. 526 0
      src/golang.org/x/crypto/cast5/cast5.go
  72. 106 0
      src/golang.org/x/crypto/cast5/cast5_test.go
  73. 101 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
  74. 86 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
  75. 2695 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
  76. 81 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
  77. 15 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
  78. 255 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
  79. 101 0
      src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
  80. 104 0
      src/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
  81. 1 0
      src/golang.org/x/crypto/codereview.cfg
  82. 751 0
      src/golang.org/x/crypto/cryptobyte/asn1.go
  83. 46 0
      src/golang.org/x/crypto/cryptobyte/asn1/asn1.go
  84. 333 0
      src/golang.org/x/crypto/cryptobyte/asn1_test.go
  85. 337 0
      src/golang.org/x/crypto/cryptobyte/builder.go
  86. 516 0
      src/golang.org/x/crypto/cryptobyte/cryptobyte_test.go
  87. 154 0
      src/golang.org/x/crypto/cryptobyte/example_test.go
  88. 166 0
      src/golang.org/x/crypto/cryptobyte/string.go
  89. 8 0
      src/golang.org/x/crypto/curve25519/const_amd64.h
  90. 20 0
      src/golang.org/x/crypto/curve25519/const_amd64.s
  91. 65 0
      src/golang.org/x/crypto/curve25519/cswap_amd64.s
  92. 834 0
      src/golang.org/x/crypto/curve25519/curve25519.go
  93. 39 0
      src/golang.org/x/crypto/curve25519/curve25519_test.go
  94. 23 0
      src/golang.org/x/crypto/curve25519/doc.go
  95. 73 0
      src/golang.org/x/crypto/curve25519/freeze_amd64.s
  96. 1377 0
      src/golang.org/x/crypto/curve25519/ladderstep_amd64.s
  97. 240 0
      src/golang.org/x/crypto/curve25519/mont25519_amd64.go
  98. 169 0
      src/golang.org/x/crypto/curve25519/mul_amd64.s
  99. 132 0
      src/golang.org/x/crypto/curve25519/square_amd64.s
  100. 217 0
      src/golang.org/x/crypto/ed25519/ed25519.go

+ 27 - 4
src/config.json

@@ -1,10 +1,33 @@
 {
     "port": "9090",
     "mgodb": "192.168.3.207:27082",
-    "dbsize": 5,
-    "dbname": "extract_kf",
-	"redis":"buyer=192.168.3.18:6379,winner=192.168.3.18:6379",
+    "dbsize": 10,
+    "dbname": "extract_v3",
+    "redis": "buyer=192.168.3.18:6379,winner=192.168.3.18:6379",
     "saveresult": true,
     "fieldscore": true,
-	"buyerwinner": false
+    "buyerwinner": false,
+    "udptaskid": "5be107e600746bf92debf080",
+    "udpip": "127.0.0.1",
+    "udpport": "1484",
+    "nextNode": [
+        {
+            "addr": "127.0.0.1",
+            "port": 1480,
+            "memo": "生中标企业"
+        },
+        {
+            "addr": "127.0.0.1",
+            "port": 1481,
+            "stype": "hangye",
+            "memo": "行业分类"
+        }
+    ],
+    "esconfig": {
+        "available": false,
+        "AccessID": "",
+        "AccessSecret": "",
+        "LaunchTemplateId": "lt-2zeidqiydzusn7hw7lt8",
+        "VSwitchId": "vsw-2ze23am2bl9e3v6rnyhfb"
+    }
 } 

+ 10 - 0
src/golang.org/x/crypto/.gitattributes

@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text

+ 2 - 0
src/golang.org/x/crypto/.gitignore

@@ -0,0 +1,2 @@
+# Add no patterns to .hgignore except for files generated by the build.
+last-change

+ 3 - 0
src/golang.org/x/crypto/AUTHORS

@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at https://tip.golang.org/AUTHORS.

+ 26 - 0
src/golang.org/x/crypto/CONTRIBUTING.md

@@ -0,0 +1,26 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1.  What version of Go are you using (`go version`)?
+2.  What operating system and processor architecture are you using?
+3.  What did you do?
+4.  What did you expect to see?
+5.  What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.

+ 3 - 0
src/golang.org/x/crypto/CONTRIBUTORS

@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at https://tip.golang.org/CONTRIBUTORS.

+ 27 - 0
src/golang.org/x/crypto/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 22 - 0
src/golang.org/x/crypto/PATENTS

@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go.  This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation.  If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.

+ 21 - 0
src/golang.org/x/crypto/README.md

@@ -0,0 +1,21 @@
+# Go Cryptography
+
+This repository holds supplementary Go cryptography libraries.
+
+## Download/Install
+
+The easiest way to install is to run `go get -u golang.org/x/crypto/...`. You
+can also manually git clone the repository to `$GOPATH/src/golang.org/x/crypto`.
+
+## Report Issues / Send Patches
+
+This repository uses Gerrit for code changes. To learn how to submit changes to
+this repository, see https://golang.org/doc/contribute.html.
+
+The main issue tracker for the crypto repository is located at
+https://github.com/golang/go/issues. Prefix your issue with "x/crypto:" in the
+subject line, so it is easy to find.
+
+Note that contributions to the cryptography package receive additional scrutiny
+due to their sensitive nature. Patches may take longer than normal to receive
+feedback.

+ 926 - 0
src/golang.org/x/crypto/acme/acme.go

@@ -0,0 +1,926 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package acme provides an implementation of the
+// Automatic Certificate Management Environment (ACME) spec.
+// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details.
+//
+// Most common scenarios will want to use autocert subdirectory instead,
+// which provides automatic access to certificates from Let's Encrypt
+// and any other ACME-based CA.
+//
+// This package is a work in progress and makes no API stability promises.
+package acme
+
+import (
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/sha256"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"math/big"
+	"net/http"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
+	LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
+
+	// ALPNProto is the ALPN protocol name used by a CA server when validating
+	// tls-alpn-01 challenges.
+	//
+	// Package users must ensure their servers can negotiate the ACME ALPN in
+	// order for tls-alpn-01 challenge verifications to succeed.
+	// See the crypto/tls package's Config.NextProtos field.
+	ALPNProto = "acme-tls/1"
+)
+
+// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge.
+var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
+
+const (
+	maxChainLen = 5       // max depth and breadth of a certificate chain
+	maxCertSize = 1 << 20 // max size of a certificate, in bytes
+
+	// Max number of collected nonces kept in memory.
+	// Expect usual peak of 1 or 2.
+	maxNonces = 100
+)
+
+// Client is an ACME client.
+// The only required field is Key. An example of creating a client with a new key
+// is as follows:
+//
+// 	key, err := rsa.GenerateKey(rand.Reader, 2048)
+// 	if err != nil {
+// 		log.Fatal(err)
+// 	}
+// 	client := &Client{Key: key}
+//
+type Client struct {
+	// Key is the account key used to register with a CA and sign requests.
+	// Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey.
+	//
+	// The following algorithms are supported:
+	// RS256, ES256, ES384 and ES512.
+	// See RFC7518 for more details about the algorithms.
+	Key crypto.Signer
+
+	// HTTPClient optionally specifies an HTTP client to use
+	// instead of http.DefaultClient.
+	HTTPClient *http.Client
+
+	// DirectoryURL points to the CA directory endpoint.
+	// If empty, LetsEncryptURL is used.
+	// Mutating this value after a successful call of Client's Discover method
+	// will have no effect.
+	DirectoryURL string
+
+	// RetryBackoff computes the duration after which the nth retry of a failed request
+	// should occur. The value of n for the first call on failure is 1.
+	// The values of r and resp are the request and response of the last failed attempt.
+	// If the returned value is negative or zero, no more retries are done and an error
+	// is returned to the caller of the original method.
+	//
+	// Requests which result in a 4xx client error are not retried,
+	// except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests.
+	//
+	// If RetryBackoff is nil, a truncated exponential backoff algorithm
+	// with the ceiling of 10 seconds is used, where each subsequent retry n
+	// is done after either ("Retry-After" + jitter) or (2^n seconds + jitter),
+	// preferring the former if "Retry-After" header is found in the resp.
+	// The jitter is a random value up to 1 second.
+	RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
+
+	dirMu sync.Mutex // guards writes to dir
+	dir   *Directory // cached result of Client's Discover method
+
+	noncesMu sync.Mutex
+	nonces   map[string]struct{} // nonces collected from previous responses
+}
+
+// Discover performs ACME server discovery using c.DirectoryURL.
+//
+// It caches successful result. So, subsequent calls will not result in
+// a network round-trip. This also means mutating c.DirectoryURL after successful call
+// of this method will have no effect.
+func (c *Client) Discover(ctx context.Context) (Directory, error) {
+	c.dirMu.Lock()
+	defer c.dirMu.Unlock()
+	if c.dir != nil {
+		return *c.dir, nil
+	}
+
+	dirURL := c.DirectoryURL
+	if dirURL == "" {
+		dirURL = LetsEncryptURL
+	}
+	res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK))
+	if err != nil {
+		return Directory{}, err
+	}
+	defer res.Body.Close()
+	c.addNonce(res.Header)
+
+	var v struct {
+		Reg    string `json:"new-reg"`
+		Authz  string `json:"new-authz"`
+		Cert   string `json:"new-cert"`
+		Revoke string `json:"revoke-cert"`
+		Meta   struct {
+			Terms   string   `json:"terms-of-service"`
+			Website string   `json:"website"`
+			CAA     []string `json:"caa-identities"`
+		}
+	}
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return Directory{}, err
+	}
+	c.dir = &Directory{
+		RegURL:    v.Reg,
+		AuthzURL:  v.Authz,
+		CertURL:   v.Cert,
+		RevokeURL: v.Revoke,
+		Terms:     v.Meta.Terms,
+		Website:   v.Meta.Website,
+		CAA:       v.Meta.CAA,
+	}
+	return *c.dir, nil
+}
+
+// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
+// The exp argument indicates the desired certificate validity duration. CA may issue a certificate
+// with a different duration.
+// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain.
+//
+// In the case where CA server does not provide the issued certificate in the response,
+// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips.
+// In such a scenario, the caller can cancel the polling with ctx.
+//
+// CreateCert returns an error if the CA's response or chain was unreasonably large.
+// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
+func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) {
+	if _, err := c.Discover(ctx); err != nil {
+		return nil, "", err
+	}
+
+	req := struct {
+		Resource  string `json:"resource"`
+		CSR       string `json:"csr"`
+		NotBefore string `json:"notBefore,omitempty"`
+		NotAfter  string `json:"notAfter,omitempty"`
+	}{
+		Resource: "new-cert",
+		CSR:      base64.RawURLEncoding.EncodeToString(csr),
+	}
+	now := timeNow()
+	req.NotBefore = now.Format(time.RFC3339)
+	if exp > 0 {
+		req.NotAfter = now.Add(exp).Format(time.RFC3339)
+	}
+
+	res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated))
+	if err != nil {
+		return nil, "", err
+	}
+	defer res.Body.Close()
+
+	curl := res.Header.Get("Location") // cert permanent URL
+	if res.ContentLength == 0 {
+		// no cert in the body; poll until we get it
+		cert, err := c.FetchCert(ctx, curl, bundle)
+		return cert, curl, err
+	}
+	// slurp issued cert and CA chain, if requested
+	cert, err := c.responseCert(ctx, res, bundle)
+	return cert, curl, err
+}
+
+// FetchCert retrieves already issued certificate from the given url, in DER format.
+// It retries the request until the certificate is successfully retrieved,
+// context is cancelled by the caller or an error response is received.
+//
+// The returned value will also contain the CA (issuer) certificate if the bundle argument is true.
+//
+// FetchCert returns an error if the CA's response or chain was unreasonably large.
+// Callers are encouraged to parse the returned value to ensure the certificate is valid
+// and has expected features.
+func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
+	res, err := c.get(ctx, url, wantStatus(http.StatusOK))
+	if err != nil {
+		return nil, err
+	}
+	return c.responseCert(ctx, res, bundle)
+}
+
+// RevokeCert revokes a previously issued certificate cert, provided in DER format.
+//
+// The key argument, used to sign the request, must be authorized
+// to revoke the certificate. It's up to the CA to decide which keys are authorized.
+// For instance, the key pair of the certificate may be authorized.
+// If the key is nil, c.Key is used instead.
+func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
+	if _, err := c.Discover(ctx); err != nil {
+		return err
+	}
+
+	body := &struct {
+		Resource string `json:"resource"`
+		Cert     string `json:"certificate"`
+		Reason   int    `json:"reason"`
+	}{
+		Resource: "revoke-cert",
+		Cert:     base64.RawURLEncoding.EncodeToString(cert),
+		Reason:   int(reason),
+	}
+	if key == nil {
+		key = c.Key
+	}
+	res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK))
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	return nil
+}
+
+// AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service
+// during account registration. See Register method of Client for more details.
+func AcceptTOS(tosURL string) bool { return true }
+
+// Register creates a new account registration by following the "new-reg" flow.
+// It returns the registered account. The account is not modified.
+//
+// The registration may require the caller to agree to the CA's Terms of Service (TOS).
+// If so, and the account has not indicated the acceptance of the terms (see Account for details),
+// Register calls prompt with a TOS URL provided by the CA. Prompt should report
+// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS.
+func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) {
+	if _, err := c.Discover(ctx); err != nil {
+		return nil, err
+	}
+
+	var err error
+	if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil {
+		return nil, err
+	}
+	var accept bool
+	if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms {
+		accept = prompt(a.CurrentTerms)
+	}
+	if accept {
+		a.AgreedTerms = a.CurrentTerms
+		a, err = c.UpdateReg(ctx, a)
+	}
+	return a, err
+}
+
+// GetReg retrieves an existing registration.
+// The url argument is an Account URI.
+func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
+	a, err := c.doReg(ctx, url, "reg", nil)
+	if err != nil {
+		return nil, err
+	}
+	a.URI = url
+	return a, nil
+}
+
+// UpdateReg updates an existing registration.
+// It returns an updated account copy. The provided account is not modified.
+func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) {
+	uri := a.URI
+	a, err := c.doReg(ctx, uri, "reg", a)
+	if err != nil {
+		return nil, err
+	}
+	a.URI = uri
+	return a, nil
+}
+
+// Authorize performs the initial step in an authorization flow.
+// The caller will then need to choose from and perform a set of returned
+// challenges using c.Accept in order to successfully complete authorization.
+//
+// If an authorization has been previously granted, the CA may return
+// a valid authorization (Authorization.Status is StatusValid). If so, the caller
+// need not fulfill any challenge and can proceed to requesting a certificate.
+func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) {
+	if _, err := c.Discover(ctx); err != nil {
+		return nil, err
+	}
+
+	type authzID struct {
+		Type  string `json:"type"`
+		Value string `json:"value"`
+	}
+	req := struct {
+		Resource   string  `json:"resource"`
+		Identifier authzID `json:"identifier"`
+	}{
+		Resource:   "new-authz",
+		Identifier: authzID{Type: "dns", Value: domain},
+	}
+	res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+
+	var v wireAuthz
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	if v.Status != StatusPending && v.Status != StatusValid {
+		return nil, fmt.Errorf("acme: unexpected status: %s", v.Status)
+	}
+	return v.authorization(res.Header.Get("Location")), nil
+}
+
+// GetAuthorization retrieves an authorization identified by the given URL.
+//
+// If a caller needs to poll an authorization until its status is final,
+// see the WaitAuthorization method.
+func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
+	res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	var v wireAuthz
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	return v.authorization(url), nil
+}
+
+// RevokeAuthorization relinquishes an existing authorization identified
+// by the given URL.
+// The url argument is an Authorization.URI value.
+//
+// If successful, the caller will be required to obtain a new authorization
+// using the Authorize method before being able to request a new certificate
+// for the domain associated with the authorization.
+//
+// It does not revoke existing certificates.
+func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
+	req := struct {
+		Resource string `json:"resource"`
+		Status   string `json:"status"`
+		Delete   bool   `json:"delete"`
+	}{
+		Resource: "authz",
+		Status:   "deactivated",
+		Delete:   true,
+	}
+	res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK))
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	return nil
+}
+
+// WaitAuthorization polls an authorization at the given URL
+// until it is in one of the final states, StatusValid or StatusInvalid,
+// the ACME CA responded with a 4xx error code, or the context is done.
+//
+// It returns a non-nil Authorization only if its Status is StatusValid.
+// In all other cases WaitAuthorization returns an error.
+// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
+func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
+	for {
+		res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
+		if err != nil {
+			return nil, err
+		}
+
+		var raw wireAuthz
+		err = json.NewDecoder(res.Body).Decode(&raw)
+		res.Body.Close()
+		switch {
+		case err != nil:
+			// Skip and retry.
+		case raw.Status == StatusValid:
+			return raw.authorization(url), nil
+		case raw.Status == StatusInvalid:
+			return nil, raw.error(url)
+		}
+
+		// Exponential backoff is implemented in c.get above.
+		// This is just to prevent continuously hitting the CA
+		// while waiting for a final authorization status.
+		d := retryAfter(res.Header.Get("Retry-After"))
+		if d == 0 {
+			// Given that the fastest challenges TLS-SNI and HTTP-01
+			// require a CA to make at least 1 network round trip
+			// and most likely persist a challenge state,
+			// this default delay seems reasonable.
+			d = time.Second
+		}
+		t := time.NewTimer(d)
+		select {
+		case <-ctx.Done():
+			t.Stop()
+			return nil, ctx.Err()
+		case <-t.C:
+			// Retry.
+		}
+	}
+}
+
+// GetChallenge retrieves the current status of an challenge.
+//
+// A client typically polls a challenge status using this method.
+func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
+	res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	v := wireChallenge{URI: url}
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	return v.challenge(), nil
+}
+
+// Accept informs the server that the client accepts one of its challenges
+// previously obtained with c.Authorize.
+//
+// The server will then perform the validation asynchronously.
+func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) {
+	auth, err := keyAuth(c.Key.Public(), chal.Token)
+	if err != nil {
+		return nil, err
+	}
+
+	req := struct {
+		Resource string `json:"resource"`
+		Type     string `json:"type"`
+		Auth     string `json:"keyAuthorization"`
+	}{
+		Resource: "challenge",
+		Type:     chal.Type,
+		Auth:     auth,
+	}
+	res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus(
+		http.StatusOK,       // according to the spec
+		http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
+	))
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+
+	var v wireChallenge
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	return v.challenge(), nil
+}
+
+// DNS01ChallengeRecord returns a DNS record value for a dns-01 challenge response.
+// A TXT record containing the returned value must be provisioned under
+// "_acme-challenge" name of the domain being validated.
+//
+// The token argument is a Challenge.Token value.
+func (c *Client) DNS01ChallengeRecord(token string) (string, error) {
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return "", err
+	}
+	b := sha256.Sum256([]byte(ka))
+	return base64.RawURLEncoding.EncodeToString(b[:]), nil
+}
+
+// HTTP01ChallengeResponse returns the response for an http-01 challenge.
+// Servers should respond with the value to HTTP requests at the URL path
+// provided by HTTP01ChallengePath to validate the challenge and prove control
+// over a domain name.
+//
+// The token argument is a Challenge.Token value.
+func (c *Client) HTTP01ChallengeResponse(token string) (string, error) {
+	return keyAuth(c.Key.Public(), token)
+}
+
+// HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge
+// should be provided by the servers.
+// The response value can be obtained with HTTP01ChallengeResponse.
+//
+// The token argument is a Challenge.Token value.
+func (c *Client) HTTP01ChallengePath(token string) string {
+	return "/.well-known/acme-challenge/" + token
+}
+
+// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
+// Servers can present the certificate to validate the challenge and prove control
+// over a domain name.
+//
+// The implementation is incomplete in that the returned value is a single certificate,
+// computed only for Z0 of the key authorization. ACME CAs are expected to update
+// their implementations to use the newer version, TLS-SNI-02.
+// For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3.
+//
+// The token argument is a Challenge.Token value.
+// If a WithKey option is provided, its private part signs the returned cert,
+// and the public part is used to specify the signee.
+// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
+//
+// The returned certificate is valid for the next 24 hours and must be presented only when
+// the server name of the TLS ClientHello matches exactly the returned name value.
+func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	b := sha256.Sum256([]byte(ka))
+	h := hex.EncodeToString(b[:])
+	name = fmt.Sprintf("%s.%s.acme.invalid", h[:32], h[32:])
+	cert, err = tlsChallengeCert([]string{name}, opt)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	return cert, name, nil
+}
+
+// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
+// Servers can present the certificate to validate the challenge and prove control
+// over a domain name. For more details on TLS-SNI-02 see
+// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3.
+//
+// The token argument is a Challenge.Token value.
+// If a WithKey option is provided, its private part signs the returned cert,
+// and the public part is used to specify the signee.
+// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
+//
+// The returned certificate is valid for the next 24 hours and must be presented only when
+// the server name in the TLS ClientHello matches exactly the returned name value.
+func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
+	b := sha256.Sum256([]byte(token))
+	h := hex.EncodeToString(b[:])
+	sanA := fmt.Sprintf("%s.%s.token.acme.invalid", h[:32], h[32:])
+
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	b = sha256.Sum256([]byte(ka))
+	h = hex.EncodeToString(b[:])
+	sanB := fmt.Sprintf("%s.%s.ka.acme.invalid", h[:32], h[32:])
+
+	cert, err = tlsChallengeCert([]string{sanA, sanB}, opt)
+	if err != nil {
+		return tls.Certificate{}, "", err
+	}
+	return cert, sanA, nil
+}
+
+// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
+// Servers can present the certificate to validate the challenge and prove control
+// over a domain name. For more details on TLS-ALPN-01 see
+// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3
+//
+// The token argument is a Challenge.Token value.
+// If a WithKey option is provided, its private part signs the returned cert,
+// and the public part is used to specify the signee.
+// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
+//
+// The returned certificate is valid for the next 24 hours and must be presented only when
+// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol
+// has been specified.
+func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) {
+	ka, err := keyAuth(c.Key.Public(), token)
+	if err != nil {
+		return tls.Certificate{}, err
+	}
+	shasum := sha256.Sum256([]byte(ka))
+	extValue, err := asn1.Marshal(shasum[:])
+	if err != nil {
+		return tls.Certificate{}, err
+	}
+	acmeExtension := pkix.Extension{
+		Id:       idPeACMEIdentifierV1,
+		Critical: true,
+		Value:    extValue,
+	}
+
+	tmpl := defaultTLSChallengeCertTemplate()
+
+	var newOpt []CertOption
+	for _, o := range opt {
+		switch o := o.(type) {
+		case *certOptTemplate:
+			t := *(*x509.Certificate)(o) // shallow copy is ok
+			tmpl = &t
+		default:
+			newOpt = append(newOpt, o)
+		}
+	}
+	tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
+	newOpt = append(newOpt, WithTemplate(tmpl))
+	return tlsChallengeCert([]string{domain}, newOpt)
+}
+
+// doReg sends all types of registration requests.
+// The type of request is identified by typ argument, which is a "resource"
+// in the ACME spec terms.
+//
+// A non-nil acct argument indicates whether the intention is to mutate data
+// of the Account. Only Contact and Agreement of its fields are used
+// in such cases.
+func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) {
+	req := struct {
+		Resource  string   `json:"resource"`
+		Contact   []string `json:"contact,omitempty"`
+		Agreement string   `json:"agreement,omitempty"`
+	}{
+		Resource: typ,
+	}
+	if acct != nil {
+		req.Contact = acct.Contact
+		req.Agreement = acct.AgreedTerms
+	}
+	res, err := c.post(ctx, c.Key, url, req, wantStatus(
+		http.StatusOK,       // updates and deletes
+		http.StatusCreated,  // new account creation
+		http.StatusAccepted, // Let's Encrypt divergent implementation
+	))
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+
+	var v struct {
+		Contact        []string
+		Agreement      string
+		Authorizations string
+		Certificates   string
+	}
+	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+		return nil, fmt.Errorf("acme: invalid response: %v", err)
+	}
+	var tos string
+	if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 {
+		tos = v[0]
+	}
+	var authz string
+	if v := linkHeader(res.Header, "next"); len(v) > 0 {
+		authz = v[0]
+	}
+	return &Account{
+		URI:            res.Header.Get("Location"),
+		Contact:        v.Contact,
+		AgreedTerms:    v.Agreement,
+		CurrentTerms:   tos,
+		Authz:          authz,
+		Authorizations: v.Authorizations,
+		Certificates:   v.Certificates,
+	}, nil
+}
+
+// popNonce returns a nonce value previously stored with c.addNonce
+// or fetches a fresh one from the given URL.
+func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
+	c.noncesMu.Lock()
+	defer c.noncesMu.Unlock()
+	if len(c.nonces) == 0 {
+		return c.fetchNonce(ctx, url)
+	}
+	var nonce string
+	for nonce = range c.nonces {
+		delete(c.nonces, nonce)
+		break
+	}
+	return nonce, nil
+}
+
+// clearNonces clears any stored nonces
+func (c *Client) clearNonces() {
+	c.noncesMu.Lock()
+	defer c.noncesMu.Unlock()
+	c.nonces = make(map[string]struct{})
+}
+
+// addNonce stores a nonce value found in h (if any) for future use.
+func (c *Client) addNonce(h http.Header) {
+	v := nonceFromHeader(h)
+	if v == "" {
+		return
+	}
+	c.noncesMu.Lock()
+	defer c.noncesMu.Unlock()
+	if len(c.nonces) >= maxNonces {
+		return
+	}
+	if c.nonces == nil {
+		c.nonces = make(map[string]struct{})
+	}
+	c.nonces[v] = struct{}{}
+}
+
+func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
+	r, err := http.NewRequest("HEAD", url, nil)
+	if err != nil {
+		return "", err
+	}
+	resp, err := c.doNoRetry(ctx, r)
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+	nonce := nonceFromHeader(resp.Header)
+	if nonce == "" {
+		if resp.StatusCode > 299 {
+			return "", responseError(resp)
+		}
+		return "", errors.New("acme: nonce not found")
+	}
+	return nonce, nil
+}
+
+func nonceFromHeader(h http.Header) string {
+	return h.Get("Replay-Nonce")
+}
+
+func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) {
+	b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
+	if err != nil {
+		return nil, fmt.Errorf("acme: response stream: %v", err)
+	}
+	if len(b) > maxCertSize {
+		return nil, errors.New("acme: certificate is too big")
+	}
+	cert := [][]byte{b}
+	if !bundle {
+		return cert, nil
+	}
+
+	// Append CA chain cert(s).
+	// At least one is required according to the spec:
+	// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1
+	up := linkHeader(res.Header, "up")
+	if len(up) == 0 {
+		return nil, errors.New("acme: rel=up link not found")
+	}
+	if len(up) > maxChainLen {
+		return nil, errors.New("acme: rel=up link is too large")
+	}
+	for _, url := range up {
+		cc, err := c.chainCert(ctx, url, 0)
+		if err != nil {
+			return nil, err
+		}
+		cert = append(cert, cc...)
+	}
+	return cert, nil
+}
+
+// chainCert fetches CA certificate chain recursively by following "up" links.
+// Each recursive call increments the depth by 1, resulting in an error
+// if the recursion level reaches maxChainLen.
+//
+// First chainCert call starts with depth of 0.
+func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) {
+	if depth >= maxChainLen {
+		return nil, errors.New("acme: certificate chain is too deep")
+	}
+
+	res, err := c.get(ctx, url, wantStatus(http.StatusOK))
+	if err != nil {
+		return nil, err
+	}
+	defer res.Body.Close()
+	b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
+	if err != nil {
+		return nil, err
+	}
+	if len(b) > maxCertSize {
+		return nil, errors.New("acme: certificate is too big")
+	}
+	chain := [][]byte{b}
+
+	uplink := linkHeader(res.Header, "up")
+	if len(uplink) > maxChainLen {
+		return nil, errors.New("acme: certificate chain is too large")
+	}
+	for _, up := range uplink {
+		cc, err := c.chainCert(ctx, up, depth+1)
+		if err != nil {
+			return nil, err
+		}
+		chain = append(chain, cc...)
+	}
+
+	return chain, nil
+}
+
+// linkHeader returns URI-Reference values of all Link headers
+// with relation-type rel.
+// See https://tools.ietf.org/html/rfc5988#section-5 for details.
+func linkHeader(h http.Header, rel string) []string {
+	var links []string
+	for _, v := range h["Link"] {
+		parts := strings.Split(v, ";")
+		for _, p := range parts {
+			p = strings.TrimSpace(p)
+			if !strings.HasPrefix(p, "rel=") {
+				continue
+			}
+			if v := strings.Trim(p[4:], `"`); v == rel {
+				links = append(links, strings.Trim(parts[0], "<>"))
+			}
+		}
+	}
+	return links
+}
+
+// keyAuth generates a key authorization string for a given token.
+func keyAuth(pub crypto.PublicKey, token string) (string, error) {
+	th, err := JWKThumbprint(pub)
+	if err != nil {
+		return "", err
+	}
+	return fmt.Sprintf("%s.%s", token, th), nil
+}
+
+// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges.
+func defaultTLSChallengeCertTemplate() *x509.Certificate {
+	return &x509.Certificate{
+		SerialNumber:          big.NewInt(1),
+		NotBefore:             time.Now(),
+		NotAfter:              time.Now().Add(24 * time.Hour),
+		BasicConstraintsValid: true,
+		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+	}
+}
+
+// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
+// with the given SANs and auto-generated public/private key pair.
+// The Subject Common Name is set to the first SAN to aid debugging.
+// To create a cert with a custom key pair, specify WithKey option.
+func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
+	var key crypto.Signer
+	tmpl := defaultTLSChallengeCertTemplate()
+	for _, o := range opt {
+		switch o := o.(type) {
+		case *certOptKey:
+			if key != nil {
+				return tls.Certificate{}, errors.New("acme: duplicate key option")
+			}
+			key = o.key
+		case *certOptTemplate:
+			t := *(*x509.Certificate)(o) // shallow copy is ok
+			tmpl = &t
+		default:
+			// package's fault, if we let this happen:
+			panic(fmt.Sprintf("unsupported option type %T", o))
+		}
+	}
+	if key == nil {
+		var err error
+		if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil {
+			return tls.Certificate{}, err
+		}
+	}
+	tmpl.DNSNames = san
+	if len(san) > 0 {
+		tmpl.Subject.CommonName = san[0]
+	}
+
+	der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key)
+	if err != nil {
+		return tls.Certificate{}, err
+	}
+	return tls.Certificate{
+		Certificate: [][]byte{der},
+		PrivateKey:  key,
+	}, nil
+}
+
+// encodePEM returns b encoded as PEM with block of type typ.
+func encodePEM(typ string, b []byte) []byte {
+	pb := &pem.Block{Type: typ, Bytes: b}
+	return pem.EncodeToMemory(pb)
+}
+
+// timeNow is useful for testing for fixed current time.
+var timeNow = time.Now

+ 1313 - 0
src/golang.org/x/crypto/acme/acme_test.go

@@ -0,0 +1,1313 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"bytes"
+	"context"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"math/big"
+	"net/http"
+	"net/http/httptest"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+	"time"
+)
+
+// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
+// interface.
+func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
+	// Decode request
+	var req struct{ Payload string }
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		t.Fatal(err)
+	}
+	payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = json.Unmarshal(payload, v)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+type jwsHead struct {
+	Alg   string
+	Nonce string
+	JWK   map[string]string `json:"jwk"`
+}
+
+func decodeJWSHead(r *http.Request) (*jwsHead, error) {
+	var req struct{ Protected string }
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		return nil, err
+	}
+	b, err := base64.RawURLEncoding.DecodeString(req.Protected)
+	if err != nil {
+		return nil, err
+	}
+	var head jwsHead
+	if err := json.Unmarshal(b, &head); err != nil {
+		return nil, err
+	}
+	return &head, nil
+}
+
+func TestDiscover(t *testing.T) {
+	const (
+		reg    = "https://example.com/acme/new-reg"
+		authz  = "https://example.com/acme/new-authz"
+		cert   = "https://example.com/acme/new-cert"
+		revoke = "https://example.com/acme/revoke-cert"
+	)
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/json")
+		fmt.Fprintf(w, `{
+			"new-reg": %q,
+			"new-authz": %q,
+			"new-cert": %q,
+			"revoke-cert": %q
+		}`, reg, authz, cert, revoke)
+	}))
+	defer ts.Close()
+	c := Client{DirectoryURL: ts.URL}
+	dir, err := c.Discover(context.Background())
+	if err != nil {
+		t.Fatal(err)
+	}
+	if dir.RegURL != reg {
+		t.Errorf("dir.RegURL = %q; want %q", dir.RegURL, reg)
+	}
+	if dir.AuthzURL != authz {
+		t.Errorf("dir.AuthzURL = %q; want %q", dir.AuthzURL, authz)
+	}
+	if dir.CertURL != cert {
+		t.Errorf("dir.CertURL = %q; want %q", dir.CertURL, cert)
+	}
+	if dir.RevokeURL != revoke {
+		t.Errorf("dir.RevokeURL = %q; want %q", dir.RevokeURL, revoke)
+	}
+}
+
+func TestRegister(t *testing.T) {
+	contacts := []string{"mailto:admin@example.com"}
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "test-nonce")
+			return
+		}
+		if r.Method != "POST" {
+			t.Errorf("r.Method = %q; want POST", r.Method)
+		}
+
+		var j struct {
+			Resource  string
+			Contact   []string
+			Agreement string
+		}
+		decodeJWSRequest(t, &j, r)
+
+		// Test request
+		if j.Resource != "new-reg" {
+			t.Errorf("j.Resource = %q; want new-reg", j.Resource)
+		}
+		if !reflect.DeepEqual(j.Contact, contacts) {
+			t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
+		}
+
+		w.Header().Set("Location", "https://ca.tld/acme/reg/1")
+		w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
+		w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
+		w.Header().Add("Link", `<https://ca.tld/acme/terms>;rel="terms-of-service"`)
+		w.WriteHeader(http.StatusCreated)
+		b, _ := json.Marshal(contacts)
+		fmt.Fprintf(w, `{"contact": %s}`, b)
+	}))
+	defer ts.Close()
+
+	prompt := func(url string) bool {
+		const terms = "https://ca.tld/acme/terms"
+		if url != terms {
+			t.Errorf("prompt url = %q; want %q", url, terms)
+		}
+		return false
+	}
+
+	c := Client{Key: testKeyEC, dir: &Directory{RegURL: ts.URL}}
+	a := &Account{Contact: contacts}
+	var err error
+	if a, err = c.Register(context.Background(), a, prompt); err != nil {
+		t.Fatal(err)
+	}
+	if a.URI != "https://ca.tld/acme/reg/1" {
+		t.Errorf("a.URI = %q; want https://ca.tld/acme/reg/1", a.URI)
+	}
+	if a.Authz != "https://ca.tld/acme/new-authz" {
+		t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
+	}
+	if a.CurrentTerms != "https://ca.tld/acme/terms" {
+		t.Errorf("a.CurrentTerms = %q; want https://ca.tld/acme/terms", a.CurrentTerms)
+	}
+	if !reflect.DeepEqual(a.Contact, contacts) {
+		t.Errorf("a.Contact = %v; want %v", a.Contact, contacts)
+	}
+}
+
+func TestUpdateReg(t *testing.T) {
+	const terms = "https://ca.tld/acme/terms"
+	contacts := []string{"mailto:admin@example.com"}
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "test-nonce")
+			return
+		}
+		if r.Method != "POST" {
+			t.Errorf("r.Method = %q; want POST", r.Method)
+		}
+
+		var j struct {
+			Resource  string
+			Contact   []string
+			Agreement string
+		}
+		decodeJWSRequest(t, &j, r)
+
+		// Test request
+		if j.Resource != "reg" {
+			t.Errorf("j.Resource = %q; want reg", j.Resource)
+		}
+		if j.Agreement != terms {
+			t.Errorf("j.Agreement = %q; want %q", j.Agreement, terms)
+		}
+		if !reflect.DeepEqual(j.Contact, contacts) {
+			t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
+		}
+
+		w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
+		w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
+		w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, terms))
+		w.WriteHeader(http.StatusOK)
+		b, _ := json.Marshal(contacts)
+		fmt.Fprintf(w, `{"contact":%s, "agreement":%q}`, b, terms)
+	}))
+	defer ts.Close()
+
+	c := Client{Key: testKeyEC}
+	a := &Account{URI: ts.URL, Contact: contacts, AgreedTerms: terms}
+	var err error
+	if a, err = c.UpdateReg(context.Background(), a); err != nil {
+		t.Fatal(err)
+	}
+	if a.Authz != "https://ca.tld/acme/new-authz" {
+		t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
+	}
+	if a.AgreedTerms != terms {
+		t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
+	}
+	if a.CurrentTerms != terms {
+		t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, terms)
+	}
+	if a.URI != ts.URL {
+		t.Errorf("a.URI = %q; want %q", a.URI, ts.URL)
+	}
+}
+
+func TestGetReg(t *testing.T) {
+	const terms = "https://ca.tld/acme/terms"
+	const newTerms = "https://ca.tld/acme/new-terms"
+	contacts := []string{"mailto:admin@example.com"}
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "test-nonce")
+			return
+		}
+		if r.Method != "POST" {
+			t.Errorf("r.Method = %q; want POST", r.Method)
+		}
+
+		var j struct {
+			Resource  string
+			Contact   []string
+			Agreement string
+		}
+		decodeJWSRequest(t, &j, r)
+
+		// Test request
+		if j.Resource != "reg" {
+			t.Errorf("j.Resource = %q; want reg", j.Resource)
+		}
+		if len(j.Contact) != 0 {
+			t.Errorf("j.Contact = %v", j.Contact)
+		}
+		if j.Agreement != "" {
+			t.Errorf("j.Agreement = %q", j.Agreement)
+		}
+
+		w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
+		w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
+		w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, newTerms))
+		w.WriteHeader(http.StatusOK)
+		b, _ := json.Marshal(contacts)
+		fmt.Fprintf(w, `{"contact":%s, "agreement":%q}`, b, terms)
+	}))
+	defer ts.Close()
+
+	c := Client{Key: testKeyEC}
+	a, err := c.GetReg(context.Background(), ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if a.Authz != "https://ca.tld/acme/new-authz" {
+		t.Errorf("a.AuthzURL = %q; want https://ca.tld/acme/new-authz", a.Authz)
+	}
+	if a.AgreedTerms != terms {
+		t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
+	}
+	if a.CurrentTerms != newTerms {
+		t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, newTerms)
+	}
+	if a.URI != ts.URL {
+		t.Errorf("a.URI = %q; want %q", a.URI, ts.URL)
+	}
+}
+
+func TestAuthorize(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "test-nonce")
+			return
+		}
+		if r.Method != "POST" {
+			t.Errorf("r.Method = %q; want POST", r.Method)
+		}
+
+		var j struct {
+			Resource   string
+			Identifier struct {
+				Type  string
+				Value string
+			}
+		}
+		decodeJWSRequest(t, &j, r)
+
+		// Test request
+		if j.Resource != "new-authz" {
+			t.Errorf("j.Resource = %q; want new-authz", j.Resource)
+		}
+		if j.Identifier.Type != "dns" {
+			t.Errorf("j.Identifier.Type = %q; want dns", j.Identifier.Type)
+		}
+		if j.Identifier.Value != "example.com" {
+			t.Errorf("j.Identifier.Value = %q; want example.com", j.Identifier.Value)
+		}
+
+		w.Header().Set("Location", "https://ca.tld/acme/auth/1")
+		w.WriteHeader(http.StatusCreated)
+		fmt.Fprintf(w, `{
+			"identifier": {"type":"dns","value":"example.com"},
+			"status":"pending",
+			"challenges":[
+				{
+					"type":"http-01",
+					"status":"pending",
+					"uri":"https://ca.tld/acme/challenge/publickey/id1",
+					"token":"token1"
+				},
+				{
+					"type":"tls-sni-01",
+					"status":"pending",
+					"uri":"https://ca.tld/acme/challenge/publickey/id2",
+					"token":"token2"
+				}
+			],
+			"combinations":[[0],[1]]}`)
+	}))
+	defer ts.Close()
+
+	cl := Client{Key: testKeyEC, dir: &Directory{AuthzURL: ts.URL}}
+	auth, err := cl.Authorize(context.Background(), "example.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if auth.URI != "https://ca.tld/acme/auth/1" {
+		t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
+	}
+	if auth.Status != "pending" {
+		t.Errorf("Status = %q; want pending", auth.Status)
+	}
+	if auth.Identifier.Type != "dns" {
+		t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
+	}
+	if auth.Identifier.Value != "example.com" {
+		t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
+	}
+
+	if n := len(auth.Challenges); n != 2 {
+		t.Fatalf("len(auth.Challenges) = %d; want 2", n)
+	}
+
+	c := auth.Challenges[0]
+	if c.Type != "http-01" {
+		t.Errorf("c.Type = %q; want http-01", c.Type)
+	}
+	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
+	}
+	if c.Token != "token1" {
+		t.Errorf("c.Token = %q; want token1", c.Token)
+	}
+
+	c = auth.Challenges[1]
+	if c.Type != "tls-sni-01" {
+		t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
+	}
+	if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
+		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
+	}
+	if c.Token != "token2" {
+		t.Errorf("c.Token = %q; want token2", c.Token)
+	}
+
+	combs := [][]int{{0}, {1}}
+	if !reflect.DeepEqual(auth.Combinations, combs) {
+		t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
+	}
+}
+
+func TestAuthorizeValid(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "nonce")
+			return
+		}
+		w.WriteHeader(http.StatusCreated)
+		w.Write([]byte(`{"status":"valid"}`))
+	}))
+	defer ts.Close()
+	client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
+	_, err := client.Authorize(context.Background(), "example.com")
+	if err != nil {
+		t.Errorf("err = %v", err)
+	}
+}
+
+func TestGetAuthorization(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != "GET" {
+			t.Errorf("r.Method = %q; want GET", r.Method)
+		}
+
+		w.WriteHeader(http.StatusOK)
+		fmt.Fprintf(w, `{
+			"identifier": {"type":"dns","value":"example.com"},
+			"status":"pending",
+			"challenges":[
+				{
+					"type":"http-01",
+					"status":"pending",
+					"uri":"https://ca.tld/acme/challenge/publickey/id1",
+					"token":"token1"
+				},
+				{
+					"type":"tls-sni-01",
+					"status":"pending",
+					"uri":"https://ca.tld/acme/challenge/publickey/id2",
+					"token":"token2"
+				}
+			],
+			"combinations":[[0],[1]]}`)
+	}))
+	defer ts.Close()
+
+	cl := Client{Key: testKeyEC}
+	auth, err := cl.GetAuthorization(context.Background(), ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if auth.Status != "pending" {
+		t.Errorf("Status = %q; want pending", auth.Status)
+	}
+	if auth.Identifier.Type != "dns" {
+		t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
+	}
+	if auth.Identifier.Value != "example.com" {
+		t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
+	}
+
+	if n := len(auth.Challenges); n != 2 {
+		t.Fatalf("len(set.Challenges) = %d; want 2", n)
+	}
+
+	c := auth.Challenges[0]
+	if c.Type != "http-01" {
+		t.Errorf("c.Type = %q; want http-01", c.Type)
+	}
+	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
+	}
+	if c.Token != "token1" {
+		t.Errorf("c.Token = %q; want token1", c.Token)
+	}
+
+	c = auth.Challenges[1]
+	if c.Type != "tls-sni-01" {
+		t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
+	}
+	if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
+		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
+	}
+	if c.Token != "token2" {
+		t.Errorf("c.Token = %q; want token2", c.Token)
+	}
+
+	combs := [][]int{{0}, {1}}
+	if !reflect.DeepEqual(auth.Combinations, combs) {
+		t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
+	}
+}
+
+func TestWaitAuthorization(t *testing.T) {
+	t.Run("wait loop", func(t *testing.T) {
+		var count int
+		authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+			count++
+			w.Header().Set("Retry-After", "0")
+			if count > 1 {
+				fmt.Fprintf(w, `{"status":"valid"}`)
+				return
+			}
+			fmt.Fprintf(w, `{"status":"pending"}`)
+		})
+		if err != nil {
+			t.Fatalf("non-nil error: %v", err)
+		}
+		if authz == nil {
+			t.Fatal("authz is nil")
+		}
+	})
+	t.Run("invalid status", func(t *testing.T) {
+		_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+			fmt.Fprintf(w, `{"status":"invalid"}`)
+		})
+		if _, ok := err.(*AuthorizationError); !ok {
+			t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
+		}
+	})
+	t.Run("non-retriable error", func(t *testing.T) {
+		const code = http.StatusBadRequest
+		_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+			w.WriteHeader(code)
+		})
+		res, ok := err.(*Error)
+		if !ok {
+			t.Fatalf("err is %v (%T); want a non-nil *Error", err, err)
+		}
+		if res.StatusCode != code {
+			t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
+		}
+	})
+	for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} {
+		t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) {
+			var count int
+			authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
+				count++
+				w.Header().Set("Retry-After", "0")
+				if count > 1 {
+					fmt.Fprintf(w, `{"status":"valid"}`)
+					return
+				}
+				w.WriteHeader(code)
+			})
+			if err != nil {
+				t.Fatalf("non-nil error: %v", err)
+			}
+			if authz == nil {
+				t.Fatal("authz is nil")
+			}
+		})
+	}
+	t.Run("context cancel", func(t *testing.T) {
+		ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
+		defer cancel()
+		_, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) {
+			w.Header().Set("Retry-After", "60")
+			fmt.Fprintf(w, `{"status":"pending"}`)
+		})
+		if err == nil {
+			t.Error("err is nil")
+		}
+	})
+}
+func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) {
+	t.Helper()
+	ts := httptest.NewServer(h)
+	defer ts.Close()
+	type res struct {
+		authz *Authorization
+		err   error
+	}
+	ch := make(chan res, 1)
+	go func() {
+		var client Client
+		a, err := client.WaitAuthorization(ctx, ts.URL)
+		ch <- res{a, err}
+	}()
+	select {
+	case <-time.After(3 * time.Second):
+		t.Fatal("WaitAuthorization took too long to return")
+	case v := <-ch:
+		return v.authz, v.err
+	}
+	panic("runWaitAuthorization: out of select")
+}
+
+func TestRevokeAuthorization(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "nonce")
+			return
+		}
+		switch r.URL.Path {
+		case "/1":
+			var req struct {
+				Resource string
+				Status   string
+				Delete   bool
+			}
+			decodeJWSRequest(t, &req, r)
+			if req.Resource != "authz" {
+				t.Errorf("req.Resource = %q; want authz", req.Resource)
+			}
+			if req.Status != "deactivated" {
+				t.Errorf("req.Status = %q; want deactivated", req.Status)
+			}
+			if !req.Delete {
+				t.Errorf("req.Delete is false")
+			}
+		case "/2":
+			w.WriteHeader(http.StatusBadRequest)
+		}
+	}))
+	defer ts.Close()
+	client := &Client{Key: testKey}
+	ctx := context.Background()
+	if err := client.RevokeAuthorization(ctx, ts.URL+"/1"); err != nil {
+		t.Errorf("err = %v", err)
+	}
+	if client.RevokeAuthorization(ctx, ts.URL+"/2") == nil {
+		t.Error("nil error")
+	}
+}
+
+func TestPollChallenge(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != "GET" {
+			t.Errorf("r.Method = %q; want GET", r.Method)
+		}
+
+		w.WriteHeader(http.StatusOK)
+		fmt.Fprintf(w, `{
+			"type":"http-01",
+			"status":"pending",
+			"uri":"https://ca.tld/acme/challenge/publickey/id1",
+			"token":"token1"}`)
+	}))
+	defer ts.Close()
+
+	cl := Client{Key: testKeyEC}
+	chall, err := cl.GetChallenge(context.Background(), ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if chall.Status != "pending" {
+		t.Errorf("Status = %q; want pending", chall.Status)
+	}
+	if chall.Type != "http-01" {
+		t.Errorf("c.Type = %q; want http-01", chall.Type)
+	}
+	if chall.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", chall.URI)
+	}
+	if chall.Token != "token1" {
+		t.Errorf("c.Token = %q; want token1", chall.Token)
+	}
+}
+
+func TestAcceptChallenge(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "test-nonce")
+			return
+		}
+		if r.Method != "POST" {
+			t.Errorf("r.Method = %q; want POST", r.Method)
+		}
+
+		var j struct {
+			Resource string
+			Type     string
+			Auth     string `json:"keyAuthorization"`
+		}
+		decodeJWSRequest(t, &j, r)
+
+		// Test request
+		if j.Resource != "challenge" {
+			t.Errorf(`resource = %q; want "challenge"`, j.Resource)
+		}
+		if j.Type != "http-01" {
+			t.Errorf(`type = %q; want "http-01"`, j.Type)
+		}
+		keyAuth := "token1." + testKeyECThumbprint
+		if j.Auth != keyAuth {
+			t.Errorf(`keyAuthorization = %q; want %q`, j.Auth, keyAuth)
+		}
+
+		// Respond to request
+		w.WriteHeader(http.StatusAccepted)
+		fmt.Fprintf(w, `{
+			"type":"http-01",
+			"status":"pending",
+			"uri":"https://ca.tld/acme/challenge/publickey/id1",
+			"token":"token1",
+			"keyAuthorization":%q
+		}`, keyAuth)
+	}))
+	defer ts.Close()
+
+	cl := Client{Key: testKeyEC}
+	c, err := cl.Accept(context.Background(), &Challenge{
+		URI:   ts.URL,
+		Token: "token1",
+		Type:  "http-01",
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if c.Type != "http-01" {
+		t.Errorf("c.Type = %q; want http-01", c.Type)
+	}
+	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
+	}
+	if c.Token != "token1" {
+		t.Errorf("c.Token = %q; want token1", c.Token)
+	}
+}
+
+func TestNewCert(t *testing.T) {
+	notBefore := time.Now()
+	notAfter := notBefore.AddDate(0, 2, 0)
+	timeNow = func() time.Time { return notBefore }
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "test-nonce")
+			return
+		}
+		if r.Method != "POST" {
+			t.Errorf("r.Method = %q; want POST", r.Method)
+		}
+
+		var j struct {
+			Resource  string `json:"resource"`
+			CSR       string `json:"csr"`
+			NotBefore string `json:"notBefore,omitempty"`
+			NotAfter  string `json:"notAfter,omitempty"`
+		}
+		decodeJWSRequest(t, &j, r)
+
+		// Test request
+		if j.Resource != "new-cert" {
+			t.Errorf(`resource = %q; want "new-cert"`, j.Resource)
+		}
+		if j.NotBefore != notBefore.Format(time.RFC3339) {
+			t.Errorf(`notBefore = %q; wanted %q`, j.NotBefore, notBefore.Format(time.RFC3339))
+		}
+		if j.NotAfter != notAfter.Format(time.RFC3339) {
+			t.Errorf(`notAfter = %q; wanted %q`, j.NotAfter, notAfter.Format(time.RFC3339))
+		}
+
+		// Respond to request
+		template := x509.Certificate{
+			SerialNumber: big.NewInt(int64(1)),
+			Subject: pkix.Name{
+				Organization: []string{"goacme"},
+			},
+			NotBefore: notBefore,
+			NotAfter:  notAfter,
+
+			KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+			ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+			BasicConstraintsValid: true,
+		}
+
+		sampleCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &testKeyEC.PublicKey, testKeyEC)
+		if err != nil {
+			t.Fatalf("Error creating certificate: %v", err)
+		}
+
+		w.Header().Set("Location", "https://ca.tld/acme/cert/1")
+		w.WriteHeader(http.StatusCreated)
+		w.Write(sampleCert)
+	}))
+	defer ts.Close()
+
+	csr := x509.CertificateRequest{
+		Version: 0,
+		Subject: pkix.Name{
+			CommonName:   "example.com",
+			Organization: []string{"goacme"},
+		},
+	}
+	csrb, err := x509.CreateCertificateRequest(rand.Reader, &csr, testKeyEC)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	c := Client{Key: testKeyEC, dir: &Directory{CertURL: ts.URL}}
+	cert, certURL, err := c.CreateCert(context.Background(), csrb, notAfter.Sub(notBefore), false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if cert == nil {
+		t.Errorf("cert is nil")
+	}
+	if certURL != "https://ca.tld/acme/cert/1" {
+		t.Errorf("certURL = %q; want https://ca.tld/acme/cert/1", certURL)
+	}
+}
+
+func TestFetchCert(t *testing.T) {
+	var count byte
+	var ts *httptest.Server
+	ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		count++
+		if count < 3 {
+			up := fmt.Sprintf("<%s>;rel=up", ts.URL)
+			w.Header().Set("Link", up)
+		}
+		w.Write([]byte{count})
+	}))
+	defer ts.Close()
+	res, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
+	if err != nil {
+		t.Fatalf("FetchCert: %v", err)
+	}
+	cert := [][]byte{{1}, {2}, {3}}
+	if !reflect.DeepEqual(res, cert) {
+		t.Errorf("res = %v; want %v", res, cert)
+	}
+}
+
+func TestFetchCertRetry(t *testing.T) {
+	var count int
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if count < 1 {
+			w.Header().Set("Retry-After", "0")
+			w.WriteHeader(http.StatusTooManyRequests)
+			count++
+			return
+		}
+		w.Write([]byte{1})
+	}))
+	defer ts.Close()
+	res, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
+	if err != nil {
+		t.Fatalf("FetchCert: %v", err)
+	}
+	cert := [][]byte{{1}}
+	if !reflect.DeepEqual(res, cert) {
+		t.Errorf("res = %v; want %v", res, cert)
+	}
+}
+
+func TestFetchCertCancel(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Retry-After", "0")
+		w.WriteHeader(http.StatusAccepted)
+	}))
+	defer ts.Close()
+	ctx, cancel := context.WithCancel(context.Background())
+	done := make(chan struct{})
+	var err error
+	go func() {
+		_, err = (&Client{}).FetchCert(ctx, ts.URL, false)
+		close(done)
+	}()
+	cancel()
+	<-done
+	if err != context.Canceled {
+		t.Errorf("err = %v; want %v", err, context.Canceled)
+	}
+}
+
+func TestFetchCertDepth(t *testing.T) {
+	var count byte
+	var ts *httptest.Server
+	ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		count++
+		if count > maxChainLen+1 {
+			t.Errorf("count = %d; want at most %d", count, maxChainLen+1)
+			w.WriteHeader(http.StatusInternalServerError)
+		}
+		w.Header().Set("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
+		w.Write([]byte{count})
+	}))
+	defer ts.Close()
+	_, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
+	if err == nil {
+		t.Errorf("err is nil")
+	}
+}
+
+func TestFetchCertBreadth(t *testing.T) {
+	var ts *httptest.Server
+	ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		for i := 0; i < maxChainLen+1; i++ {
+			w.Header().Add("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
+		}
+		w.Write([]byte{1})
+	}))
+	defer ts.Close()
+	_, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
+	if err == nil {
+		t.Errorf("err is nil")
+	}
+}
+
+func TestFetchCertSize(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		b := bytes.Repeat([]byte{1}, maxCertSize+1)
+		w.Write(b)
+	}))
+	defer ts.Close()
+	_, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
+	if err == nil {
+		t.Errorf("err is nil")
+	}
+}
+
+func TestRevokeCert(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "HEAD" {
+			w.Header().Set("Replay-Nonce", "nonce")
+			return
+		}
+
+		var req struct {
+			Resource    string
+			Certificate string
+			Reason      int
+		}
+		decodeJWSRequest(t, &req, r)
+		if req.Resource != "revoke-cert" {
+			t.Errorf("req.Resource = %q; want revoke-cert", req.Resource)
+		}
+		if req.Reason != 1 {
+			t.Errorf("req.Reason = %d; want 1", req.Reason)
+		}
+		// echo -n cert | base64 | tr -d '=' | tr '/+' '_-'
+		cert := "Y2VydA"
+		if req.Certificate != cert {
+			t.Errorf("req.Certificate = %q; want %q", req.Certificate, cert)
+		}
+	}))
+	defer ts.Close()
+	client := &Client{
+		Key: testKeyEC,
+		dir: &Directory{RevokeURL: ts.URL},
+	}
+	ctx := context.Background()
+	if err := client.RevokeCert(ctx, nil, []byte("cert"), CRLReasonKeyCompromise); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestNonce_add(t *testing.T) {
+	var c Client
+	c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
+	c.addNonce(http.Header{"Replay-Nonce": {}})
+	c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
+
+	nonces := map[string]struct{}{"nonce": {}}
+	if !reflect.DeepEqual(c.nonces, nonces) {
+		t.Errorf("c.nonces = %q; want %q", c.nonces, nonces)
+	}
+}
+
+func TestNonce_addMax(t *testing.T) {
+	c := &Client{nonces: make(map[string]struct{})}
+	for i := 0; i < maxNonces; i++ {
+		c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
+	}
+	c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
+	if n := len(c.nonces); n != maxNonces {
+		t.Errorf("len(c.nonces) = %d; want %d", n, maxNonces)
+	}
+}
+
+func TestNonce_fetch(t *testing.T) {
+	tests := []struct {
+		code  int
+		nonce string
+	}{
+		{http.StatusOK, "nonce1"},
+		{http.StatusBadRequest, "nonce2"},
+		{http.StatusOK, ""},
+	}
+	var i int
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != "HEAD" {
+			t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
+		}
+		w.Header().Set("Replay-Nonce", tests[i].nonce)
+		w.WriteHeader(tests[i].code)
+	}))
+	defer ts.Close()
+	for ; i < len(tests); i++ {
+		test := tests[i]
+		c := &Client{}
+		n, err := c.fetchNonce(context.Background(), ts.URL)
+		if n != test.nonce {
+			t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
+		}
+		switch {
+		case err == nil && test.nonce == "":
+			t.Errorf("%d: n=%q, err=%v; want non-nil error", i, n, err)
+		case err != nil && test.nonce != "":
+			t.Errorf("%d: n=%q, err=%v; want %q", i, n, err, test.nonce)
+		}
+	}
+}
+
+func TestNonce_fetchError(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusTooManyRequests)
+	}))
+	defer ts.Close()
+	c := &Client{}
+	_, err := c.fetchNonce(context.Background(), ts.URL)
+	e, ok := err.(*Error)
+	if !ok {
+		t.Fatalf("err is %T; want *Error", err)
+	}
+	if e.StatusCode != http.StatusTooManyRequests {
+		t.Errorf("e.StatusCode = %d; want %d", e.StatusCode, http.StatusTooManyRequests)
+	}
+}
+
+func TestNonce_postJWS(t *testing.T) {
+	var count int
+	seen := make(map[string]bool)
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		count++
+		w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
+		if r.Method == "HEAD" {
+			// We expect the client do a HEAD request
+			// but only to fetch the first nonce.
+			return
+		}
+		// Make client.Authorize happy; we're not testing its result.
+		defer func() {
+			w.WriteHeader(http.StatusCreated)
+			w.Write([]byte(`{"status":"valid"}`))
+		}()
+
+		head, err := decodeJWSHead(r)
+		if err != nil {
+			t.Errorf("decodeJWSHead: %v", err)
+			return
+		}
+		if head.Nonce == "" {
+			t.Error("head.Nonce is empty")
+			return
+		}
+		if seen[head.Nonce] {
+			t.Errorf("nonce is already used: %q", head.Nonce)
+		}
+		seen[head.Nonce] = true
+	}))
+	defer ts.Close()
+
+	client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
+	if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
+		t.Errorf("client.Authorize 1: %v", err)
+	}
+	// The second call should not generate another extra HEAD request.
+	if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
+		t.Errorf("client.Authorize 2: %v", err)
+	}
+
+	if count != 3 {
+		t.Errorf("total requests count: %d; want 3", count)
+	}
+	if n := len(client.nonces); n != 1 {
+		t.Errorf("len(client.nonces) = %d; want 1", n)
+	}
+	for k := range seen {
+		if _, exist := client.nonces[k]; exist {
+			t.Errorf("used nonce %q in client.nonces", k)
+		}
+	}
+}
+
+func TestLinkHeader(t *testing.T) {
+	h := http.Header{"Link": {
+		`<https://example.com/acme/new-authz>;rel="next"`,
+		`<https://example.com/acme/recover-reg>; rel=recover`,
+		`<https://example.com/acme/terms>; foo=bar; rel="terms-of-service"`,
+		`<dup>;rel="next"`,
+	}}
+	tests := []struct {
+		rel string
+		out []string
+	}{
+		{"next", []string{"https://example.com/acme/new-authz", "dup"}},
+		{"recover", []string{"https://example.com/acme/recover-reg"}},
+		{"terms-of-service", []string{"https://example.com/acme/terms"}},
+		{"empty", nil},
+	}
+	for i, test := range tests {
+		if v := linkHeader(h, test.rel); !reflect.DeepEqual(v, test.out) {
+			t.Errorf("%d: linkHeader(%q): %v; want %v", i, test.rel, v, test.out)
+		}
+	}
+}
+
+func TestTLSSNI01ChallengeCert(t *testing.T) {
+	const (
+		token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
+		// echo -n <token.testKeyECThumbprint> | shasum -a 256
+		san = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.acme.invalid"
+	)
+
+	client := &Client{Key: testKeyEC}
+	tlscert, name, err := client.TLSSNI01ChallengeCert(token)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if n := len(tlscert.Certificate); n != 1 {
+		t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
+	}
+	cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(cert.DNSNames) != 1 || cert.DNSNames[0] != san {
+		t.Fatalf("cert.DNSNames = %v; want %q", cert.DNSNames, san)
+	}
+	if cert.DNSNames[0] != name {
+		t.Errorf("cert.DNSNames[0] != name: %q vs %q", cert.DNSNames[0], name)
+	}
+	if cn := cert.Subject.CommonName; cn != san {
+		t.Errorf("cert.Subject.CommonName = %q; want %q", cn, san)
+	}
+}
+
+func TestTLSSNI02ChallengeCert(t *testing.T) {
+	const (
+		token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
+		// echo -n evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA | shasum -a 256
+		sanA = "7ea0aaa69214e71e02cebb18bb867736.09b730209baabf60e43d4999979ff139.token.acme.invalid"
+		// echo -n <token.testKeyECThumbprint> | shasum -a 256
+		sanB = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.ka.acme.invalid"
+	)
+
+	client := &Client{Key: testKeyEC}
+	tlscert, name, err := client.TLSSNI02ChallengeCert(token)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if n := len(tlscert.Certificate); n != 1 {
+		t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
+	}
+	cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+	if err != nil {
+		t.Fatal(err)
+	}
+	names := []string{sanA, sanB}
+	if !reflect.DeepEqual(cert.DNSNames, names) {
+		t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
+	}
+	sort.Strings(cert.DNSNames)
+	i := sort.SearchStrings(cert.DNSNames, name)
+	if i >= len(cert.DNSNames) || cert.DNSNames[i] != name {
+		t.Errorf("%v doesn't have %q", cert.DNSNames, name)
+	}
+	if cn := cert.Subject.CommonName; cn != sanA {
+		t.Errorf("CommonName = %q; want %q", cn, sanA)
+	}
+}
+
+func TestTLSALPN01ChallengeCert(t *testing.T) {
+	const (
+		token   = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
+		keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint
+		// echo -n <token.testKeyECThumbprint> | shasum -a 256
+		h      = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0"
+		domain = "example.com"
+	)
+
+	extValue, err := hex.DecodeString(h)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	client := &Client{Key: testKeyEC}
+	tlscert, err := client.TLSALPN01ChallengeCert(token, domain)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if n := len(tlscert.Certificate); n != 1 {
+		t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
+	}
+	cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+	if err != nil {
+		t.Fatal(err)
+	}
+	names := []string{domain}
+	if !reflect.DeepEqual(cert.DNSNames, names) {
+		t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
+	}
+	if cn := cert.Subject.CommonName; cn != domain {
+		t.Errorf("CommonName = %q; want %q", cn, domain)
+	}
+	acmeExts := []pkix.Extension{}
+	for _, ext := range cert.Extensions {
+		if idPeACMEIdentifierV1.Equal(ext.Id) {
+			acmeExts = append(acmeExts, ext)
+		}
+	}
+	if len(acmeExts) != 1 {
+		t.Errorf("acmeExts = %v; want exactly one", acmeExts)
+	}
+	if !acmeExts[0].Critical {
+		t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical)
+	}
+	if bytes.Compare(acmeExts[0].Value, extValue) != 0 {
+		t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue)
+	}
+
+}
+
+func TestTLSChallengeCertOpt(t *testing.T) {
+	key, err := rsa.GenerateKey(rand.Reader, 512)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tmpl := &x509.Certificate{
+		SerialNumber: big.NewInt(2),
+		Subject:      pkix.Name{Organization: []string{"Test"}},
+		DNSNames:     []string{"should-be-overwritten"},
+	}
+	opts := []CertOption{WithKey(key), WithTemplate(tmpl)}
+
+	client := &Client{Key: testKeyEC}
+	cert1, _, err := client.TLSSNI01ChallengeCert("token", opts...)
+	if err != nil {
+		t.Fatal(err)
+	}
+	cert2, _, err := client.TLSSNI02ChallengeCert("token", opts...)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for i, tlscert := range []tls.Certificate{cert1, cert2} {
+		// verify generated cert private key
+		tlskey, ok := tlscert.PrivateKey.(*rsa.PrivateKey)
+		if !ok {
+			t.Errorf("%d: tlscert.PrivateKey is %T; want *rsa.PrivateKey", i, tlscert.PrivateKey)
+			continue
+		}
+		if tlskey.D.Cmp(key.D) != 0 {
+			t.Errorf("%d: tlskey.D = %v; want %v", i, tlskey.D, key.D)
+		}
+		// verify generated cert public key
+		x509Cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+		if err != nil {
+			t.Errorf("%d: %v", i, err)
+			continue
+		}
+		tlspub, ok := x509Cert.PublicKey.(*rsa.PublicKey)
+		if !ok {
+			t.Errorf("%d: x509Cert.PublicKey is %T; want *rsa.PublicKey", i, x509Cert.PublicKey)
+			continue
+		}
+		if tlspub.N.Cmp(key.N) != 0 {
+			t.Errorf("%d: tlspub.N = %v; want %v", i, tlspub.N, key.N)
+		}
+		// verify template option
+		sn := big.NewInt(2)
+		if x509Cert.SerialNumber.Cmp(sn) != 0 {
+			t.Errorf("%d: SerialNumber = %v; want %v", i, x509Cert.SerialNumber, sn)
+		}
+		org := []string{"Test"}
+		if !reflect.DeepEqual(x509Cert.Subject.Organization, org) {
+			t.Errorf("%d: Subject.Organization = %+v; want %+v", i, x509Cert.Subject.Organization, org)
+		}
+		for _, v := range x509Cert.DNSNames {
+			if !strings.HasSuffix(v, ".acme.invalid") {
+				t.Errorf("%d: invalid DNSNames element: %q", i, v)
+			}
+		}
+	}
+}
+
+func TestHTTP01Challenge(t *testing.T) {
+	const (
+		token = "xxx"
+		// thumbprint is precomputed for testKeyEC in jws_test.go
+		value   = token + "." + testKeyECThumbprint
+		urlpath = "/.well-known/acme-challenge/" + token
+	)
+	client := &Client{Key: testKeyEC}
+	val, err := client.HTTP01ChallengeResponse(token)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if val != value {
+		t.Errorf("val = %q; want %q", val, value)
+	}
+	if path := client.HTTP01ChallengePath(token); path != urlpath {
+		t.Errorf("path = %q; want %q", path, urlpath)
+	}
+}
+
+func TestDNS01ChallengeRecord(t *testing.T) {
+	// echo -n xxx.<testKeyECThumbprint> | \
+	//      openssl dgst -binary -sha256 | \
+	//      base64 | tr -d '=' | tr '/+' '_-'
+	const value = "8DERMexQ5VcdJ_prpPiA0mVdp7imgbCgjsG4SqqNMIo"
+
+	client := &Client{Key: testKeyEC}
+	val, err := client.DNS01ChallengeRecord("xxx")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if val != value {
+		t.Errorf("val = %q; want %q", val, value)
+	}
+}

+ 1139 - 0
src/golang.org/x/crypto/acme/autocert/autocert.go

@@ -0,0 +1,1139 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package autocert provides automatic access to certificates from Let's Encrypt
+// and any other ACME-based CA.
+//
+// This package is a work in progress and makes no API stability promises.
+package autocert
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	mathrand "math/rand"
+	"net"
+	"net/http"
+	"path"
+	"strings"
+	"sync"
+	"time"
+
+	"golang.org/x/crypto/acme"
+)
+
+// createCertRetryAfter is how much time to wait before removing a failed state
+// entry due to an unsuccessful createCert call.
+// This is a variable instead of a const for testing.
+// TODO: Consider making it configurable or an exp backoff?
+var createCertRetryAfter = time.Minute
+
+// pseudoRand is safe for concurrent use.
+var pseudoRand *lockedMathRand
+
+func init() {
+	src := mathrand.NewSource(time.Now().UnixNano())
+	pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
+}
+
+// AcceptTOS is a Manager.Prompt function that always returns true to
+// indicate acceptance of the CA's Terms of Service during account
+// registration.
+func AcceptTOS(tosURL string) bool { return true }
+
+// HostPolicy specifies which host names the Manager is allowed to respond to.
+// It returns a non-nil error if the host should be rejected.
+// The returned error is accessible via tls.Conn.Handshake and its callers.
+// See Manager's HostPolicy field and GetCertificate method docs for more details.
+type HostPolicy func(ctx context.Context, host string) error
+
+// HostWhitelist returns a policy where only the specified host names are allowed.
+// Only exact matches are currently supported. Subdomains, regexp or wildcard
+// will not match.
+func HostWhitelist(hosts ...string) HostPolicy {
+	whitelist := make(map[string]bool, len(hosts))
+	for _, h := range hosts {
+		whitelist[h] = true
+	}
+	return func(_ context.Context, host string) error {
+		if !whitelist[host] {
+			return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host)
+		}
+		return nil
+	}
+}
+
+// defaultHostPolicy is used when Manager.HostPolicy is not set.
+func defaultHostPolicy(context.Context, string) error {
+	return nil
+}
+
+// Manager is a stateful certificate manager built on top of acme.Client.
+// It obtains and refreshes certificates automatically using "tls-alpn-01",
+// "tls-sni-01", "tls-sni-02" and "http-01" challenge types,
+// as well as providing them to a TLS server via tls.Config.
+//
+// You must specify a cache implementation, such as DirCache,
+// to reuse obtained certificates across program restarts.
+// Otherwise your server is very likely to exceed the certificate
+// issuer's request rate limits.
+type Manager struct {
+	// Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS).
+	// The registration may require the caller to agree to the CA's TOS.
+	// If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report
+	// whether the caller agrees to the terms.
+	//
+	// To always accept the terms, the callers can use AcceptTOS.
+	Prompt func(tosURL string) bool
+
+	// Cache optionally stores and retrieves previously-obtained certificates
+	// and other state. If nil, certs will only be cached for the lifetime of
+	// the Manager. Multiple Managers can share the same Cache.
+	//
+	// Using a persistent Cache, such as DirCache, is strongly recommended.
+	Cache Cache
+
+	// HostPolicy controls which domains the Manager will attempt
+	// to retrieve new certificates for. It does not affect cached certs.
+	//
+	// If non-nil, HostPolicy is called before requesting a new cert.
+	// If nil, all hosts are currently allowed. This is not recommended,
+	// as it opens a potential attack where clients connect to a server
+	// by IP address and pretend to be asking for an incorrect host name.
+	// Manager will attempt to obtain a certificate for that host, incorrectly,
+	// eventually reaching the CA's rate limit for certificate requests
+	// and making it impossible to obtain actual certificates.
+	//
+	// See GetCertificate for more details.
+	HostPolicy HostPolicy
+
+	// RenewBefore optionally specifies how early certificates should
+	// be renewed before they expire.
+	//
+	// If zero, they're renewed 30 days before expiration.
+	RenewBefore time.Duration
+
+	// Client is used to perform low-level operations, such as account registration
+	// and requesting new certificates.
+	//
+	// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
+	// as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is
+	// generated and, if Cache is not nil, stored in cache.
+	//
+	// Mutating the field after the first call of GetCertificate method will have no effect.
+	Client *acme.Client
+
+	// Email optionally specifies a contact email address.
+	// This is used by CAs, such as Let's Encrypt, to notify about problems
+	// with issued certificates.
+	//
+	// If the Client's account key is already registered, Email is not used.
+	Email string
+
+	// ForceRSA used to make the Manager generate RSA certificates. It is now ignored.
+	//
+	// Deprecated: the Manager will request the correct type of certificate based
+	// on what each client supports.
+	ForceRSA bool
+
+	// ExtraExtensions are used when generating a new CSR (Certificate Request),
+	// thus allowing customization of the resulting certificate.
+	// For instance, TLS Feature Extension (RFC 7633) can be used
+	// to prevent an OCSP downgrade attack.
+	//
+	// The field value is passed to crypto/x509.CreateCertificateRequest
+	// in the template's ExtraExtensions field as is.
+	ExtraExtensions []pkix.Extension
+
+	clientMu sync.Mutex
+	client   *acme.Client // initialized by acmeClient method
+
+	stateMu sync.Mutex
+	state   map[certKey]*certState
+
+	// renewal tracks the set of domains currently running renewal timers.
+	renewalMu sync.Mutex
+	renewal   map[certKey]*domainRenewal
+
+	// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
+	tokensMu sync.RWMutex
+	// tryHTTP01 indicates whether the Manager should try "http-01" challenge type
+	// during the authorization flow.
+	tryHTTP01 bool
+	// httpTokens contains response body values for http-01 challenges
+	// and is keyed by the URL path at which a challenge response is expected
+	// to be provisioned.
+	// The entries are stored for the duration of the authorization flow.
+	httpTokens map[string][]byte
+	// certTokens contains temporary certificates for tls-sni and tls-alpn challenges
+	// and is keyed by token domain name, which matches server name of ClientHello.
+	// Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names
+	// for tls-alpn.
+	// The entries are stored for the duration of the authorization flow.
+	certTokens map[string]*tls.Certificate
+	// nowFunc, if not nil, returns the current time. This may be set for
+	// testing purposes.
+	nowFunc func() time.Time
+}
+
+// certKey is the key by which certificates are tracked in state, renewal and cache.
+type certKey struct {
+	domain  string // without trailing dot
+	isRSA   bool   // RSA cert for legacy clients (as opposed to default ECDSA)
+	isToken bool   // tls-based challenge token cert; key type is undefined regardless of isRSA
+}
+
+func (c certKey) String() string {
+	if c.isToken {
+		return c.domain + "+token"
+	}
+	if c.isRSA {
+		return c.domain + "+rsa"
+	}
+	return c.domain
+}
+
+// TLSConfig creates a new TLS config suitable for net/http.Server servers,
+// supporting HTTP/2 and the tls-alpn-01 ACME challenge type.
+func (m *Manager) TLSConfig() *tls.Config {
+	return &tls.Config{
+		GetCertificate: m.GetCertificate,
+		NextProtos: []string{
+			"h2", "http/1.1", // enable HTTP/2
+			acme.ALPNProto, // enable tls-alpn ACME challenges
+		},
+	}
+}
+
+// GetCertificate implements the tls.Config.GetCertificate hook.
+// It provides a TLS certificate for hello.ServerName host, including answering
+// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges.
+// All other fields of hello are ignored.
+//
+// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
+// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
+// The error is propagated back to the caller of GetCertificate and is user-visible.
+// This does not affect cached certs. See HostPolicy field description for more details.
+//
+// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will
+// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler
+// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers
+// due to security issues in the ecosystem.)
+func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
+	if m.Prompt == nil {
+		return nil, errors.New("acme/autocert: Manager.Prompt not set")
+	}
+
+	name := hello.ServerName
+	if name == "" {
+		return nil, errors.New("acme/autocert: missing server name")
+	}
+	if !strings.Contains(strings.Trim(name, "."), ".") {
+		return nil, errors.New("acme/autocert: server name component count invalid")
+	}
+	if strings.ContainsAny(name, `+/\`) {
+		return nil, errors.New("acme/autocert: server name contains invalid character")
+	}
+
+	// In the worst-case scenario, the timeout needs to account for caching, host policy,
+	// domain ownership verification and certificate issuance.
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
+	defer cancel()
+
+	// Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge.
+	if wantsTokenCert(hello) {
+		m.tokensMu.RLock()
+		defer m.tokensMu.RUnlock()
+		// It's ok to use the same token cert key for both tls-sni and tls-alpn
+		// because there's always at most 1 token cert per on-going domain authorization.
+		// See m.verify for details.
+		if cert := m.certTokens[name]; cert != nil {
+			return cert, nil
+		}
+		if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil {
+			return cert, nil
+		}
+		// TODO: cache error results?
+		return nil, fmt.Errorf("acme/autocert: no token cert for %q", name)
+	}
+
+	// regular domain
+	ck := certKey{
+		domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
+		isRSA:  !supportsECDSA(hello),
+	}
+	cert, err := m.cert(ctx, ck)
+	if err == nil {
+		return cert, nil
+	}
+	if err != ErrCacheMiss {
+		return nil, err
+	}
+
+	// first-time
+	if err := m.hostPolicy()(ctx, name); err != nil {
+		return nil, err
+	}
+	cert, err = m.createCert(ctx, ck)
+	if err != nil {
+		return nil, err
+	}
+	m.cachePut(ctx, ck, cert)
+	return cert, nil
+}
+
+// wantsTokenCert reports whether a TLS request with SNI is made by a CA server
+// for a challenge verification.
+func wantsTokenCert(hello *tls.ClientHelloInfo) bool {
+	// tls-alpn-01
+	if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
+		return true
+	}
+	// tls-sni-xx
+	return strings.HasSuffix(hello.ServerName, ".acme.invalid")
+}
+
+func supportsECDSA(hello *tls.ClientHelloInfo) bool {
+	// The "signature_algorithms" extension, if present, limits the key exchange
+	// algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
+	if hello.SignatureSchemes != nil {
+		ecdsaOK := false
+	schemeLoop:
+		for _, scheme := range hello.SignatureSchemes {
+			const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10
+			switch scheme {
+			case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256,
+				tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512:
+				ecdsaOK = true
+				break schemeLoop
+			}
+		}
+		if !ecdsaOK {
+			return false
+		}
+	}
+	if hello.SupportedCurves != nil {
+		ecdsaOK := false
+		for _, curve := range hello.SupportedCurves {
+			if curve == tls.CurveP256 {
+				ecdsaOK = true
+				break
+			}
+		}
+		if !ecdsaOK {
+			return false
+		}
+	}
+	for _, suite := range hello.CipherSuites {
+		switch suite {
+		case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
+			return true
+		}
+	}
+	return false
+}
+
+// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
+// It returns an http.Handler that responds to the challenges and must be
+// running on port 80. If it receives a request that is not an ACME challenge,
+// it delegates the request to the optional fallback handler.
+//
+// If fallback is nil, the returned handler redirects all GET and HEAD requests
+// to the default TLS port 443 with 302 Found status code, preserving the original
+// request path and query. It responds with 400 Bad Request to all other HTTP methods.
+// The fallback is not protected by the optional HostPolicy.
+//
+// Because the fallback handler is run with unencrypted port 80 requests,
+// the fallback should not serve TLS-only requests.
+//
+// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
+// challenge for domain verification.
+func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	m.tryHTTP01 = true
+
+	if fallback == nil {
+		fallback = http.HandlerFunc(handleHTTPRedirect)
+	}
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") {
+			fallback.ServeHTTP(w, r)
+			return
+		}
+		// A reasonable context timeout for cache and host policy only,
+		// because we don't wait for a new certificate issuance here.
+		ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
+		defer cancel()
+		if err := m.hostPolicy()(ctx, r.Host); err != nil {
+			http.Error(w, err.Error(), http.StatusForbidden)
+			return
+		}
+		data, err := m.httpToken(ctx, r.URL.Path)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusNotFound)
+			return
+		}
+		w.Write(data)
+	})
+}
+
+func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
+	if r.Method != "GET" && r.Method != "HEAD" {
+		http.Error(w, "Use HTTPS", http.StatusBadRequest)
+		return
+	}
+	target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
+	http.Redirect(w, r, target, http.StatusFound)
+}
+
+func stripPort(hostport string) string {
+	host, _, err := net.SplitHostPort(hostport)
+	if err != nil {
+		return hostport
+	}
+	return net.JoinHostPort(host, "443")
+}
+
+// cert returns an existing certificate either from m.state or cache.
+// If a certificate is found in cache but not in m.state, the latter will be filled
+// with the cached value.
+func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
+	m.stateMu.Lock()
+	if s, ok := m.state[ck]; ok {
+		m.stateMu.Unlock()
+		s.RLock()
+		defer s.RUnlock()
+		return s.tlscert()
+	}
+	defer m.stateMu.Unlock()
+	cert, err := m.cacheGet(ctx, ck)
+	if err != nil {
+		return nil, err
+	}
+	signer, ok := cert.PrivateKey.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("acme/autocert: private key cannot sign")
+	}
+	if m.state == nil {
+		m.state = make(map[certKey]*certState)
+	}
+	s := &certState{
+		key:  signer,
+		cert: cert.Certificate,
+		leaf: cert.Leaf,
+	}
+	m.state[ck] = s
+	go m.renew(ck, s.key, s.leaf.NotAfter)
+	return cert, nil
+}
+
+// cacheGet always returns a valid certificate, or an error otherwise.
+// If a cached certificate exists but is not valid, ErrCacheMiss is returned.
+func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) {
+	if m.Cache == nil {
+		return nil, ErrCacheMiss
+	}
+	data, err := m.Cache.Get(ctx, ck.String())
+	if err != nil {
+		return nil, err
+	}
+
+	// private
+	priv, pub := pem.Decode(data)
+	if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
+		return nil, ErrCacheMiss
+	}
+	privKey, err := parsePrivateKey(priv.Bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	// public
+	var pubDER [][]byte
+	for len(pub) > 0 {
+		var b *pem.Block
+		b, pub = pem.Decode(pub)
+		if b == nil {
+			break
+		}
+		pubDER = append(pubDER, b.Bytes)
+	}
+	if len(pub) > 0 {
+		// Leftover content not consumed by pem.Decode. Corrupt. Ignore.
+		return nil, ErrCacheMiss
+	}
+
+	// verify and create TLS cert
+	leaf, err := validCert(ck, pubDER, privKey, m.now())
+	if err != nil {
+		return nil, ErrCacheMiss
+	}
+	tlscert := &tls.Certificate{
+		Certificate: pubDER,
+		PrivateKey:  privKey,
+		Leaf:        leaf,
+	}
+	return tlscert, nil
+}
+
+func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error {
+	if m.Cache == nil {
+		return nil
+	}
+
+	// contains PEM-encoded data
+	var buf bytes.Buffer
+
+	// private
+	switch key := tlscert.PrivateKey.(type) {
+	case *ecdsa.PrivateKey:
+		if err := encodeECDSAKey(&buf, key); err != nil {
+			return err
+		}
+	case *rsa.PrivateKey:
+		b := x509.MarshalPKCS1PrivateKey(key)
+		pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b}
+		if err := pem.Encode(&buf, pb); err != nil {
+			return err
+		}
+	default:
+		return errors.New("acme/autocert: unknown private key type")
+	}
+
+	// public
+	for _, b := range tlscert.Certificate {
+		pb := &pem.Block{Type: "CERTIFICATE", Bytes: b}
+		if err := pem.Encode(&buf, pb); err != nil {
+			return err
+		}
+	}
+
+	return m.Cache.Put(ctx, ck.String(), buf.Bytes())
+}
+
+func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
+	b, err := x509.MarshalECPrivateKey(key)
+	if err != nil {
+		return err
+	}
+	pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+	return pem.Encode(w, pb)
+}
+
+// createCert starts the domain ownership verification and returns a certificate
+// for that domain upon success.
+//
+// If the domain is already being verified, it waits for the existing verification to complete.
+// Either way, createCert blocks for the duration of the whole process.
+func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
+	// TODO: maybe rewrite this whole piece using sync.Once
+	state, err := m.certState(ck)
+	if err != nil {
+		return nil, err
+	}
+	// state may exist if another goroutine is already working on it
+	// in which case just wait for it to finish
+	if !state.locked {
+		state.RLock()
+		defer state.RUnlock()
+		return state.tlscert()
+	}
+
+	// We are the first; state is locked.
+	// Unblock the readers when domain ownership is verified
+	// and we got the cert or the process failed.
+	defer state.Unlock()
+	state.locked = false
+
+	der, leaf, err := m.authorizedCert(ctx, state.key, ck)
+	if err != nil {
+		// Remove the failed state after some time,
+		// making the manager call createCert again on the following TLS hello.
+		time.AfterFunc(createCertRetryAfter, func() {
+			defer testDidRemoveState(ck)
+			m.stateMu.Lock()
+			defer m.stateMu.Unlock()
+			// Verify the state hasn't changed and it's still invalid
+			// before deleting.
+			s, ok := m.state[ck]
+			if !ok {
+				return
+			}
+			if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil {
+				return
+			}
+			delete(m.state, ck)
+		})
+		return nil, err
+	}
+	state.cert = der
+	state.leaf = leaf
+	go m.renew(ck, state.key, state.leaf.NotAfter)
+	return state.tlscert()
+}
+
+// certState returns a new or existing certState.
+// If a new certState is returned, state.exist is false and the state is locked.
+// The returned error is non-nil only in the case where a new state could not be created.
+func (m *Manager) certState(ck certKey) (*certState, error) {
+	m.stateMu.Lock()
+	defer m.stateMu.Unlock()
+	if m.state == nil {
+		m.state = make(map[certKey]*certState)
+	}
+	// existing state
+	if state, ok := m.state[ck]; ok {
+		return state, nil
+	}
+
+	// new locked state
+	var (
+		err error
+		key crypto.Signer
+	)
+	if ck.isRSA {
+		key, err = rsa.GenerateKey(rand.Reader, 2048)
+	} else {
+		key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	state := &certState{
+		key:    key,
+		locked: true,
+	}
+	state.Lock() // will be unlocked by m.certState caller
+	m.state[ck] = state
+	return state, nil
+}
+
+// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
+// The key argument is the certificate private key.
+func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) {
+	client, err := m.acmeClient(ctx)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if err := m.verify(ctx, client, ck.domain); err != nil {
+		return nil, nil, err
+	}
+	csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
+	if err != nil {
+		return nil, nil, err
+	}
+	der, _, err = client.CreateCert(ctx, csr, 0, true)
+	if err != nil {
+		return nil, nil, err
+	}
+	leaf, err = validCert(ck, der, key, m.now())
+	if err != nil {
+		return nil, nil, err
+	}
+	return der, leaf, nil
+}
+
+// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice.
+// It ignores revocation errors.
+func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) {
+	client, err := m.acmeClient(ctx)
+	if err != nil {
+		return
+	}
+	for _, u := range uri {
+		client.RevokeAuthorization(ctx, u)
+	}
+}
+
+// verify runs the identifier (domain) authorization flow
+// using each applicable ACME challenge type.
+func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
+	// The list of challenge types we'll try to fulfill
+	// in this specific order.
+	challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"}
+	m.tokensMu.RLock()
+	if m.tryHTTP01 {
+		challengeTypes = append(challengeTypes, "http-01")
+	}
+	m.tokensMu.RUnlock()
+
+	// Keep track of pending authzs and revoke the ones that did not validate.
+	pendingAuthzs := make(map[string]bool)
+	defer func() {
+		var uri []string
+		for k, pending := range pendingAuthzs {
+			if pending {
+				uri = append(uri, k)
+			}
+		}
+		if len(uri) > 0 {
+			// Use "detached" background context.
+			// The revocations need not happen in the current verification flow.
+			go m.revokePendingAuthz(context.Background(), uri)
+		}
+	}()
+
+	// errs accumulates challenge failure errors, printed if all fail
+	errs := make(map[*acme.Challenge]error)
+	var nextTyp int // challengeType index of the next challenge type to try
+	for {
+		// Start domain authorization and get the challenge.
+		authz, err := client.Authorize(ctx, domain)
+		if err != nil {
+			return err
+		}
+		// No point in accepting challenges if the authorization status
+		// is in a final state.
+		switch authz.Status {
+		case acme.StatusValid:
+			return nil // already authorized
+		case acme.StatusInvalid:
+			return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
+		}
+
+		pendingAuthzs[authz.URI] = true
+
+		// Pick the next preferred challenge.
+		var chal *acme.Challenge
+		for chal == nil && nextTyp < len(challengeTypes) {
+			chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges)
+			nextTyp++
+		}
+		if chal == nil {
+			errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain)
+			for chal, err := range errs {
+				errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err)
+			}
+			return errors.New(errorMsg)
+		}
+		cleanup, err := m.fulfill(ctx, client, chal, domain)
+		if err != nil {
+			errs[chal] = err
+			continue
+		}
+		defer cleanup()
+		if _, err := client.Accept(ctx, chal); err != nil {
+			errs[chal] = err
+			continue
+		}
+
+		// A challenge is fulfilled and accepted: wait for the CA to validate.
+		if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil {
+			errs[chal] = err
+			continue
+		}
+		delete(pendingAuthzs, authz.URI)
+		return nil
+	}
+}
+
+// fulfill provisions a response to the challenge chal.
+// The cleanup is non-nil only if provisioning succeeded.
+func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) {
+	switch chal.Type {
+	case "tls-alpn-01":
+		cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain)
+		if err != nil {
+			return nil, err
+		}
+		m.putCertToken(ctx, domain, &cert)
+		return func() { go m.deleteCertToken(domain) }, nil
+	case "tls-sni-01":
+		cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
+		if err != nil {
+			return nil, err
+		}
+		m.putCertToken(ctx, name, &cert)
+		return func() { go m.deleteCertToken(name) }, nil
+	case "tls-sni-02":
+		cert, name, err := client.TLSSNI02ChallengeCert(chal.Token)
+		if err != nil {
+			return nil, err
+		}
+		m.putCertToken(ctx, name, &cert)
+		return func() { go m.deleteCertToken(name) }, nil
+	case "http-01":
+		resp, err := client.HTTP01ChallengeResponse(chal.Token)
+		if err != nil {
+			return nil, err
+		}
+		p := client.HTTP01ChallengePath(chal.Token)
+		m.putHTTPToken(ctx, p, resp)
+		return func() { go m.deleteHTTPToken(p) }, nil
+	}
+	return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
+}
+
+func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
+	for _, c := range chal {
+		if c.Type == typ {
+			return c
+		}
+	}
+	return nil
+}
+
+// putCertToken stores the token certificate with the specified name
+// in both m.certTokens map and m.Cache.
+func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	if m.certTokens == nil {
+		m.certTokens = make(map[string]*tls.Certificate)
+	}
+	m.certTokens[name] = cert
+	m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
+}
+
+// deleteCertToken removes the token certificate with the specified name
+// from both m.certTokens map and m.Cache.
+func (m *Manager) deleteCertToken(name string) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	delete(m.certTokens, name)
+	if m.Cache != nil {
+		ck := certKey{domain: name, isToken: true}
+		m.Cache.Delete(context.Background(), ck.String())
+	}
+}
+
+// httpToken retrieves an existing http-01 token value from an in-memory map
+// or the optional cache.
+func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) {
+	m.tokensMu.RLock()
+	defer m.tokensMu.RUnlock()
+	if v, ok := m.httpTokens[tokenPath]; ok {
+		return v, nil
+	}
+	if m.Cache == nil {
+		return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath)
+	}
+	return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath))
+}
+
+// putHTTPToken stores an http-01 token value using tokenPath as key
+// in both in-memory map and the optional Cache.
+//
+// It ignores any error returned from Cache.Put.
+func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	if m.httpTokens == nil {
+		m.httpTokens = make(map[string][]byte)
+	}
+	b := []byte(val)
+	m.httpTokens[tokenPath] = b
+	if m.Cache != nil {
+		m.Cache.Put(ctx, httpTokenCacheKey(tokenPath), b)
+	}
+}
+
+// deleteHTTPToken removes an http-01 token value from both in-memory map
+// and the optional Cache, ignoring any error returned from the latter.
+//
+// If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout.
+func (m *Manager) deleteHTTPToken(tokenPath string) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	delete(m.httpTokens, tokenPath)
+	if m.Cache != nil {
+		m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath))
+	}
+}
+
+// httpTokenCacheKey returns a key at which an http-01 token value may be stored
+// in the Manager's optional Cache.
+func httpTokenCacheKey(tokenPath string) string {
+	return path.Base(tokenPath) + "+http-01"
+}
+
+// renew starts a cert renewal timer loop, one per domain.
+//
+// The loop is scheduled in two cases:
+// - a cert was fetched from cache for the first time (wasn't in m.state)
+// - a new cert was created by m.createCert
+//
+// The key argument is a certificate private key.
+// The exp argument is the cert expiration time (NotAfter).
+func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) {
+	m.renewalMu.Lock()
+	defer m.renewalMu.Unlock()
+	if m.renewal[ck] != nil {
+		// another goroutine is already on it
+		return
+	}
+	if m.renewal == nil {
+		m.renewal = make(map[certKey]*domainRenewal)
+	}
+	dr := &domainRenewal{m: m, ck: ck, key: key}
+	m.renewal[ck] = dr
+	dr.start(exp)
+}
+
+// stopRenew stops all currently running cert renewal timers.
+// The timers are not restarted during the lifetime of the Manager.
+func (m *Manager) stopRenew() {
+	m.renewalMu.Lock()
+	defer m.renewalMu.Unlock()
+	for name, dr := range m.renewal {
+		delete(m.renewal, name)
+		dr.stop()
+	}
+}
+
+func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
+	const keyName = "acme_account+key"
+
+	// Previous versions of autocert stored the value under a different key.
+	const legacyKeyName = "acme_account.key"
+
+	genKey := func() (*ecdsa.PrivateKey, error) {
+		return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	}
+
+	if m.Cache == nil {
+		return genKey()
+	}
+
+	data, err := m.Cache.Get(ctx, keyName)
+	if err == ErrCacheMiss {
+		data, err = m.Cache.Get(ctx, legacyKeyName)
+	}
+	if err == ErrCacheMiss {
+		key, err := genKey()
+		if err != nil {
+			return nil, err
+		}
+		var buf bytes.Buffer
+		if err := encodeECDSAKey(&buf, key); err != nil {
+			return nil, err
+		}
+		if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil {
+			return nil, err
+		}
+		return key, nil
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	priv, _ := pem.Decode(data)
+	if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
+		return nil, errors.New("acme/autocert: invalid account key found in cache")
+	}
+	return parsePrivateKey(priv.Bytes)
+}
+
+func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
+	m.clientMu.Lock()
+	defer m.clientMu.Unlock()
+	if m.client != nil {
+		return m.client, nil
+	}
+
+	client := m.Client
+	if client == nil {
+		client = &acme.Client{DirectoryURL: acme.LetsEncryptURL}
+	}
+	if client.Key == nil {
+		var err error
+		client.Key, err = m.accountKey(ctx)
+		if err != nil {
+			return nil, err
+		}
+	}
+	var contact []string
+	if m.Email != "" {
+		contact = []string{"mailto:" + m.Email}
+	}
+	a := &acme.Account{Contact: contact}
+	_, err := client.Register(ctx, a, m.Prompt)
+	if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict {
+		// conflict indicates the key is already registered
+		m.client = client
+		err = nil
+	}
+	return m.client, err
+}
+
+func (m *Manager) hostPolicy() HostPolicy {
+	if m.HostPolicy != nil {
+		return m.HostPolicy
+	}
+	return defaultHostPolicy
+}
+
+func (m *Manager) renewBefore() time.Duration {
+	if m.RenewBefore > renewJitter {
+		return m.RenewBefore
+	}
+	return 720 * time.Hour // 30 days
+}
+
+func (m *Manager) now() time.Time {
+	if m.nowFunc != nil {
+		return m.nowFunc()
+	}
+	return time.Now()
+}
+
+// certState is ready when its mutex is unlocked for reading.
+type certState struct {
+	sync.RWMutex
+	locked bool              // locked for read/write
+	key    crypto.Signer     // private key for cert
+	cert   [][]byte          // DER encoding
+	leaf   *x509.Certificate // parsed cert[0]; always non-nil if cert != nil
+}
+
+// tlscert creates a tls.Certificate from s.key and s.cert.
+// Callers should wrap it in s.RLock() and s.RUnlock().
+func (s *certState) tlscert() (*tls.Certificate, error) {
+	if s.key == nil {
+		return nil, errors.New("acme/autocert: missing signer")
+	}
+	if len(s.cert) == 0 {
+		return nil, errors.New("acme/autocert: missing certificate")
+	}
+	return &tls.Certificate{
+		PrivateKey:  s.key,
+		Certificate: s.cert,
+		Leaf:        s.leaf,
+	}, nil
+}
+
+// certRequest generates a CSR for the given common name cn and optional SANs.
+func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) {
+	req := &x509.CertificateRequest{
+		Subject:         pkix.Name{CommonName: cn},
+		DNSNames:        san,
+		ExtraExtensions: ext,
+	}
+	return x509.CreateCertificateRequest(rand.Reader, req, key)
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+//
+// Inspired by parsePrivateKey in crypto/tls/tls.go.
+func parsePrivateKey(der []byte) (crypto.Signer, error) {
+	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+		return key, nil
+	}
+	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+		switch key := key.(type) {
+		case *rsa.PrivateKey:
+			return key, nil
+		case *ecdsa.PrivateKey:
+			return key, nil
+		default:
+			return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping")
+		}
+	}
+	if key, err := x509.ParseECPrivateKey(der); err == nil {
+		return key, nil
+	}
+
+	return nil, errors.New("acme/autocert: failed to parse private key")
+}
+
+// validCert parses a cert chain provided as der argument and verifies the leaf and der[0]
+// correspond to the private key, the domain and key type match, and expiration dates
+// are valid. It doesn't do any revocation checking.
+//
+// The returned value is the verified leaf cert.
+func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) {
+	// parse public part(s)
+	var n int
+	for _, b := range der {
+		n += len(b)
+	}
+	pub := make([]byte, n)
+	n = 0
+	for _, b := range der {
+		n += copy(pub[n:], b)
+	}
+	x509Cert, err := x509.ParseCertificates(pub)
+	if err != nil || len(x509Cert) == 0 {
+		return nil, errors.New("acme/autocert: no public key found")
+	}
+	// verify the leaf is not expired and matches the domain name
+	leaf = x509Cert[0]
+	if now.Before(leaf.NotBefore) {
+		return nil, errors.New("acme/autocert: certificate is not valid yet")
+	}
+	if now.After(leaf.NotAfter) {
+		return nil, errors.New("acme/autocert: expired certificate")
+	}
+	if err := leaf.VerifyHostname(ck.domain); err != nil {
+		return nil, err
+	}
+	// ensure the leaf corresponds to the private key and matches the certKey type
+	switch pub := leaf.PublicKey.(type) {
+	case *rsa.PublicKey:
+		prv, ok := key.(*rsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("acme/autocert: private key type does not match public key type")
+		}
+		if pub.N.Cmp(prv.N) != 0 {
+			return nil, errors.New("acme/autocert: private key does not match public key")
+		}
+		if !ck.isRSA && !ck.isToken {
+			return nil, errors.New("acme/autocert: key type does not match expected value")
+		}
+	case *ecdsa.PublicKey:
+		prv, ok := key.(*ecdsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("acme/autocert: private key type does not match public key type")
+		}
+		if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
+			return nil, errors.New("acme/autocert: private key does not match public key")
+		}
+		if ck.isRSA && !ck.isToken {
+			return nil, errors.New("acme/autocert: key type does not match expected value")
+		}
+	default:
+		return nil, errors.New("acme/autocert: unknown public key algorithm")
+	}
+	return leaf, nil
+}
+
+type lockedMathRand struct {
+	sync.Mutex
+	rnd *mathrand.Rand
+}
+
+func (r *lockedMathRand) int63n(max int64) int64 {
+	r.Lock()
+	n := r.rnd.Int63n(max)
+	r.Unlock()
+	return n
+}
+
+// For easier testing.
+var (
+	// Called when a state is removed.
+	testDidRemoveState = func(certKey) {}
+)

+ 1189 - 0
src/golang.org/x/crypto/acme/autocert/autocert_test.go

@@ -0,0 +1,1189 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"html/template"
+	"io"
+	"io/ioutil"
+	"math/big"
+	"net/http"
+	"net/http/httptest"
+	"reflect"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"golang.org/x/crypto/acme"
+	"golang.org/x/crypto/acme/autocert/internal/acmetest"
+)
+
+var (
+	exampleDomain     = "example.org"
+	exampleCertKey    = certKey{domain: exampleDomain}
+	exampleCertKeyRSA = certKey{domain: exampleDomain, isRSA: true}
+)
+
+var discoTmpl = template.Must(template.New("disco").Parse(`{
+	"new-reg": "{{.}}/new-reg",
+	"new-authz": "{{.}}/new-authz",
+	"new-cert": "{{.}}/new-cert"
+}`))
+
+var authzTmpl = template.Must(template.New("authz").Parse(`{
+	"status": "pending",
+	"challenges": [
+		{
+			"uri": "{{.}}/challenge/1",
+			"type": "tls-sni-01",
+			"token": "token-01"
+		},
+		{
+			"uri": "{{.}}/challenge/2",
+			"type": "tls-sni-02",
+			"token": "token-02"
+		},
+		{
+			"uri": "{{.}}/challenge/dns-01",
+			"type": "dns-01",
+			"token": "token-dns-01"
+		},
+		{
+			"uri": "{{.}}/challenge/http-01",
+			"type": "http-01",
+			"token": "token-http-01"
+		}
+	]
+}`))
+
+type memCache struct {
+	t       *testing.T
+	mu      sync.Mutex
+	keyData map[string][]byte
+}
+
+func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	v, ok := m.keyData[key]
+	if !ok {
+		return nil, ErrCacheMiss
+	}
+	return v, nil
+}
+
+// filenameSafe returns whether all characters in s are printable ASCII
+// and safe to use in a filename on most filesystems.
+func filenameSafe(s string) bool {
+	for _, c := range s {
+		if c < 0x20 || c > 0x7E {
+			return false
+		}
+		switch c {
+		case '\\', '/', ':', '*', '?', '"', '<', '>', '|':
+			return false
+		}
+	}
+	return true
+}
+
+func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
+	if !filenameSafe(key) {
+		m.t.Errorf("invalid characters in cache key %q", key)
+	}
+
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	m.keyData[key] = data
+	return nil
+}
+
+func (m *memCache) Delete(ctx context.Context, key string) error {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	delete(m.keyData, key)
+	return nil
+}
+
+func newMemCache(t *testing.T) *memCache {
+	return &memCache{
+		t:       t,
+		keyData: make(map[string][]byte),
+	}
+}
+
+func (m *memCache) numCerts() int {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	res := 0
+	for key := range m.keyData {
+		if strings.HasSuffix(key, "+token") ||
+			strings.HasSuffix(key, "+key") ||
+			strings.HasSuffix(key, "+http-01") {
+			continue
+		}
+		res++
+	}
+	return res
+}
+
+func dummyCert(pub interface{}, san ...string) ([]byte, error) {
+	return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
+}
+
+func dateDummyCert(pub interface{}, start, end time.Time, san ...string) ([]byte, error) {
+	// use EC key to run faster on 386
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		return nil, err
+	}
+	t := &x509.Certificate{
+		SerialNumber:          big.NewInt(1),
+		NotBefore:             start,
+		NotAfter:              end,
+		BasicConstraintsValid: true,
+		KeyUsage:              x509.KeyUsageKeyEncipherment,
+		DNSNames:              san,
+	}
+	if pub == nil {
+		pub = &key.PublicKey
+	}
+	return x509.CreateCertificate(rand.Reader, t, t, pub, key)
+}
+
+func decodePayload(v interface{}, r io.Reader) error {
+	var req struct{ Payload string }
+	if err := json.NewDecoder(r).Decode(&req); err != nil {
+		return err
+	}
+	payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
+	if err != nil {
+		return err
+	}
+	return json.Unmarshal(payload, v)
+}
+
+func clientHelloInfo(sni string, ecdsaSupport bool) *tls.ClientHelloInfo {
+	hello := &tls.ClientHelloInfo{
+		ServerName:   sni,
+		CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+	}
+	if ecdsaSupport {
+		hello.CipherSuites = append(hello.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
+	}
+	return hello
+}
+
+func TestGetCertificate(t *testing.T) {
+	man := &Manager{Prompt: AcceptTOS}
+	defer man.stopRenew()
+	hello := clientHelloInfo("example.org", true)
+	testGetCertificate(t, man, "example.org", hello)
+}
+
+func TestGetCertificate_trailingDot(t *testing.T) {
+	man := &Manager{Prompt: AcceptTOS}
+	defer man.stopRenew()
+	hello := clientHelloInfo("example.org.", true)
+	testGetCertificate(t, man, "example.org", hello)
+}
+
+func TestGetCertificate_ForceRSA(t *testing.T) {
+	man := &Manager{
+		Prompt:   AcceptTOS,
+		Cache:    newMemCache(t),
+		ForceRSA: true,
+	}
+	defer man.stopRenew()
+	hello := clientHelloInfo(exampleDomain, true)
+	testGetCertificate(t, man, exampleDomain, hello)
+
+	// ForceRSA was deprecated and is now ignored.
+	cert, err := man.cacheGet(context.Background(), exampleCertKey)
+	if err != nil {
+		t.Fatalf("man.cacheGet: %v", err)
+	}
+	if _, ok := cert.PrivateKey.(*ecdsa.PrivateKey); !ok {
+		t.Errorf("cert.PrivateKey is %T; want *ecdsa.PrivateKey", cert.PrivateKey)
+	}
+}
+
+func TestGetCertificate_nilPrompt(t *testing.T) {
+	man := &Manager{}
+	defer man.stopRenew()
+	url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
+	defer finish()
+	man.Client = &acme.Client{DirectoryURL: url}
+	hello := clientHelloInfo("example.org", true)
+	if _, err := man.GetCertificate(hello); err == nil {
+		t.Error("got certificate for example.org; wanted error")
+	}
+}
+
+func TestGetCertificate_expiredCache(t *testing.T) {
+	// Make an expired cert and cache it.
+	pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tmpl := &x509.Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject:      pkix.Name{CommonName: exampleDomain},
+		NotAfter:     time.Now(),
+	}
+	pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tlscert := &tls.Certificate{
+		Certificate: [][]byte{pub},
+		PrivateKey:  pk,
+	}
+
+	man := &Manager{Prompt: AcceptTOS, Cache: newMemCache(t)}
+	defer man.stopRenew()
+	if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
+		t.Fatalf("man.cachePut: %v", err)
+	}
+
+	// The expired cached cert should trigger a new cert issuance
+	// and return without an error.
+	hello := clientHelloInfo(exampleDomain, true)
+	testGetCertificate(t, man, exampleDomain, hello)
+}
+
+func TestGetCertificate_failedAttempt(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusBadRequest)
+	}))
+	defer ts.Close()
+
+	d := createCertRetryAfter
+	f := testDidRemoveState
+	defer func() {
+		createCertRetryAfter = d
+		testDidRemoveState = f
+	}()
+	createCertRetryAfter = 0
+	done := make(chan struct{})
+	testDidRemoveState = func(ck certKey) {
+		if ck != exampleCertKey {
+			t.Errorf("testDidRemoveState: domain = %v; want %v", ck, exampleCertKey)
+		}
+		close(done)
+	}
+
+	man := &Manager{
+		Prompt: AcceptTOS,
+		Client: &acme.Client{
+			DirectoryURL: ts.URL,
+		},
+	}
+	defer man.stopRenew()
+	hello := clientHelloInfo(exampleDomain, true)
+	if _, err := man.GetCertificate(hello); err == nil {
+		t.Error("GetCertificate: err is nil")
+	}
+	select {
+	case <-time.After(5 * time.Second):
+		t.Errorf("took too long to remove the %q state", exampleCertKey)
+	case <-done:
+		man.stateMu.Lock()
+		defer man.stateMu.Unlock()
+		if v, exist := man.state[exampleCertKey]; exist {
+			t.Errorf("state exists for %v: %+v", exampleCertKey, v)
+		}
+	}
+}
+
+// testGetCertificate_tokenCache tests the fallback of token certificate fetches
+// to cache when Manager.certTokens misses. ecdsaSupport refers to the CA when
+// verifying the certificate token.
+func testGetCertificate_tokenCache(t *testing.T, ecdsaSupport bool) {
+	man1 := &Manager{
+		Cache:  newMemCache(t),
+		Prompt: AcceptTOS,
+	}
+	defer man1.stopRenew()
+	man2 := &Manager{
+		Cache:  man1.Cache,
+		Prompt: AcceptTOS,
+	}
+	defer man2.stopRenew()
+
+	// Send the verification request to a different Manager from the one that
+	// initiated the authorization, when they share caches.
+	url, finish := startACMEServerStub(t, getCertificateFromManager(man2, ecdsaSupport), "example.org")
+	defer finish()
+	man1.Client = &acme.Client{DirectoryURL: url}
+	hello := clientHelloInfo("example.org", true)
+	if _, err := man1.GetCertificate(hello); err != nil {
+		t.Error(err)
+	}
+	if _, err := man2.GetCertificate(hello); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestGetCertificate_tokenCache(t *testing.T) {
+	t.Run("ecdsaSupport=true", func(t *testing.T) {
+		testGetCertificate_tokenCache(t, true)
+	})
+	t.Run("ecdsaSupport=false", func(t *testing.T) {
+		testGetCertificate_tokenCache(t, false)
+	})
+}
+
+func TestGetCertificate_ecdsaVsRSA(t *testing.T) {
+	cache := newMemCache(t)
+	man := &Manager{Prompt: AcceptTOS, Cache: cache}
+	defer man.stopRenew()
+	url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
+	defer finish()
+	man.Client = &acme.Client{DirectoryURL: url}
+
+	cert, err := man.GetCertificate(clientHelloInfo("example.org", true))
+	if err != nil {
+		t.Error(err)
+	}
+	if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
+		t.Error("an ECDSA client was served a non-ECDSA certificate")
+	}
+
+	cert, err = man.GetCertificate(clientHelloInfo("example.org", false))
+	if err != nil {
+		t.Error(err)
+	}
+	if _, ok := cert.Leaf.PublicKey.(*rsa.PublicKey); !ok {
+		t.Error("a RSA client was served a non-RSA certificate")
+	}
+
+	if _, err := man.GetCertificate(clientHelloInfo("example.org", true)); err != nil {
+		t.Error(err)
+	}
+	if _, err := man.GetCertificate(clientHelloInfo("example.org", false)); err != nil {
+		t.Error(err)
+	}
+	if numCerts := cache.numCerts(); numCerts != 2 {
+		t.Errorf("found %d certificates in cache; want %d", numCerts, 2)
+	}
+}
+
+func TestGetCertificate_wrongCacheKeyType(t *testing.T) {
+	cache := newMemCache(t)
+	man := &Manager{Prompt: AcceptTOS, Cache: cache}
+	defer man.stopRenew()
+	url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), exampleDomain)
+	defer finish()
+	man.Client = &acme.Client{DirectoryURL: url}
+
+	// Make an RSA cert and cache it without suffix.
+	pk, err := rsa.GenerateKey(rand.Reader, 512)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tmpl := &x509.Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject:      pkix.Name{CommonName: exampleDomain},
+		NotAfter:     time.Now().Add(90 * 24 * time.Hour),
+	}
+	pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
+	if err != nil {
+		t.Fatal(err)
+	}
+	rsaCert := &tls.Certificate{
+		Certificate: [][]byte{pub},
+		PrivateKey:  pk,
+	}
+	if err := man.cachePut(context.Background(), exampleCertKey, rsaCert); err != nil {
+		t.Fatalf("man.cachePut: %v", err)
+	}
+
+	// The RSA cached cert should be silently ignored and replaced.
+	cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, true))
+	if err != nil {
+		t.Error(err)
+	}
+	if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
+		t.Error("an ECDSA client was served a non-ECDSA certificate")
+	}
+	if numCerts := cache.numCerts(); numCerts != 1 {
+		t.Errorf("found %d certificates in cache; want %d", numCerts, 1)
+	}
+}
+
+func getCertificateFromManager(man *Manager, ecdsaSupport bool) func(string) error {
+	return func(sni string) error {
+		_, err := man.GetCertificate(clientHelloInfo(sni, ecdsaSupport))
+		return err
+	}
+}
+
+// startACMEServerStub runs an ACME server
+// The domain argument is the expected domain name of a certificate request.
+// TODO: Drop this in favour of x/crypto/acme/autocert/internal/acmetest.
+func startACMEServerStub(t *testing.T, getCertificate func(string) error, domain string) (url string, finish func()) {
+	// echo token-02 | shasum -a 256
+	// then divide result in 2 parts separated by dot
+	tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
+	verifyTokenCert := func() {
+		if err := getCertificate(tokenCertName); err != nil {
+			t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
+			return
+		}
+	}
+
+	// ACME CA server stub
+	var ca *httptest.Server
+	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Replay-Nonce", "nonce")
+		if r.Method == "HEAD" {
+			// a nonce request
+			return
+		}
+
+		switch r.URL.Path {
+		// discovery
+		case "/":
+			if err := discoTmpl.Execute(w, ca.URL); err != nil {
+				t.Errorf("discoTmpl: %v", err)
+			}
+		// client key registration
+		case "/new-reg":
+			w.Write([]byte("{}"))
+		// domain authorization
+		case "/new-authz":
+			w.Header().Set("Location", ca.URL+"/authz/1")
+			w.WriteHeader(http.StatusCreated)
+			if err := authzTmpl.Execute(w, ca.URL); err != nil {
+				t.Errorf("authzTmpl: %v", err)
+			}
+		// accept tls-sni-02 challenge
+		case "/challenge/2":
+			verifyTokenCert()
+			w.Write([]byte("{}"))
+		// authorization status
+		case "/authz/1":
+			w.Write([]byte(`{"status": "valid"}`))
+		// cert request
+		case "/new-cert":
+			var req struct {
+				CSR string `json:"csr"`
+			}
+			decodePayload(&req, r.Body)
+			b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
+			csr, err := x509.ParseCertificateRequest(b)
+			if err != nil {
+				t.Errorf("new-cert: CSR: %v", err)
+			}
+			if csr.Subject.CommonName != domain {
+				t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain)
+			}
+			der, err := dummyCert(csr.PublicKey, domain)
+			if err != nil {
+				t.Errorf("new-cert: dummyCert: %v", err)
+			}
+			chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
+			w.Header().Set("Link", chainUp)
+			w.WriteHeader(http.StatusCreated)
+			w.Write(der)
+		// CA chain cert
+		case "/ca-cert":
+			der, err := dummyCert(nil, "ca")
+			if err != nil {
+				t.Errorf("ca-cert: dummyCert: %v", err)
+			}
+			w.Write(der)
+		default:
+			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+		}
+	}))
+	finish = func() {
+		ca.Close()
+
+		// make sure token cert was removed
+		cancel := make(chan struct{})
+		done := make(chan struct{})
+		go func() {
+			defer close(done)
+			tick := time.NewTicker(100 * time.Millisecond)
+			defer tick.Stop()
+			for {
+				if err := getCertificate(tokenCertName); err != nil {
+					return
+				}
+				select {
+				case <-tick.C:
+				case <-cancel:
+					return
+				}
+			}
+		}()
+		select {
+		case <-done:
+		case <-time.After(5 * time.Second):
+			close(cancel)
+			t.Error("token cert was not removed")
+			<-done
+		}
+	}
+	return ca.URL, finish
+}
+
+// tests man.GetCertificate flow using the provided hello argument.
+// The domain argument is the expected domain name of a certificate request.
+func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) {
+	url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), domain)
+	defer finish()
+	man.Client = &acme.Client{DirectoryURL: url}
+
+	// simulate tls.Config.GetCertificate
+	var tlscert *tls.Certificate
+	var err error
+	done := make(chan struct{})
+	go func() {
+		tlscert, err = man.GetCertificate(hello)
+		close(done)
+	}()
+	select {
+	case <-time.After(time.Minute):
+		t.Fatal("man.GetCertificate took too long to return")
+	case <-done:
+	}
+	if err != nil {
+		t.Fatalf("man.GetCertificate: %v", err)
+	}
+
+	// verify the tlscert is the same we responded with from the CA stub
+	if len(tlscert.Certificate) == 0 {
+		t.Fatal("len(tlscert.Certificate) is 0")
+	}
+	cert, err := x509.ParseCertificate(tlscert.Certificate[0])
+	if err != nil {
+		t.Fatalf("x509.ParseCertificate: %v", err)
+	}
+	if len(cert.DNSNames) == 0 || cert.DNSNames[0] != domain {
+		t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
+	}
+
+}
+
+func TestVerifyHTTP01(t *testing.T) {
+	var (
+		http01 http.Handler
+
+		authzCount      int // num. of created authorizations
+		didAcceptHTTP01 bool
+	)
+
+	verifyHTTPToken := func() {
+		r := httptest.NewRequest("GET", "/.well-known/acme-challenge/token-http-01", nil)
+		w := httptest.NewRecorder()
+		http01.ServeHTTP(w, r)
+		if w.Code != http.StatusOK {
+			t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK)
+		}
+		if v := w.Body.String(); !strings.HasPrefix(v, "token-http-01.") {
+			t.Errorf("http token value = %q; want 'token-http-01.' prefix", v)
+		}
+	}
+
+	// ACME CA server stub, only the needed bits.
+	// TODO: Replace this with x/crypto/acme/autocert/internal/acmetest.
+	var ca *httptest.Server
+	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Replay-Nonce", "nonce")
+		if r.Method == "HEAD" {
+			// a nonce request
+			return
+		}
+
+		switch r.URL.Path {
+		// Discovery.
+		case "/":
+			if err := discoTmpl.Execute(w, ca.URL); err != nil {
+				t.Errorf("discoTmpl: %v", err)
+			}
+		// Client key registration.
+		case "/new-reg":
+			w.Write([]byte("{}"))
+		// New domain authorization.
+		case "/new-authz":
+			authzCount++
+			w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount))
+			w.WriteHeader(http.StatusCreated)
+			if err := authzTmpl.Execute(w, ca.URL); err != nil {
+				t.Errorf("authzTmpl: %v", err)
+			}
+		// Accept tls-sni-02.
+		case "/challenge/2":
+			w.Write([]byte("{}"))
+		// Reject tls-sni-01.
+		case "/challenge/1":
+			http.Error(w, "won't accept tls-sni-01", http.StatusBadRequest)
+		// Should not accept dns-01.
+		case "/challenge/dns-01":
+			t.Errorf("dns-01 challenge was accepted")
+			http.Error(w, "won't accept dns-01", http.StatusBadRequest)
+		// Accept http-01.
+		case "/challenge/http-01":
+			didAcceptHTTP01 = true
+			verifyHTTPToken()
+			w.Write([]byte("{}"))
+		// Authorization statuses.
+		// Make tls-sni-xxx invalid.
+		case "/authz/1", "/authz/2":
+			w.Write([]byte(`{"status": "invalid"}`))
+		case "/authz/3", "/authz/4":
+			w.Write([]byte(`{"status": "valid"}`))
+		default:
+			http.NotFound(w, r)
+			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+		}
+	}))
+	defer ca.Close()
+
+	m := &Manager{
+		Client: &acme.Client{
+			DirectoryURL: ca.URL,
+		},
+	}
+	http01 = m.HTTPHandler(nil)
+	ctx := context.Background()
+	client, err := m.acmeClient(ctx)
+	if err != nil {
+		t.Fatalf("m.acmeClient: %v", err)
+	}
+	if err := m.verify(ctx, client, "example.org"); err != nil {
+		t.Errorf("m.verify: %v", err)
+	}
+	// Only tls-sni-01, tls-sni-02 and http-01 must be accepted
+	// The dns-01 challenge is unsupported.
+	if authzCount != 3 {
+		t.Errorf("authzCount = %d; want 3", authzCount)
+	}
+	if !didAcceptHTTP01 {
+		t.Error("did not accept http-01 challenge")
+	}
+}
+
+func TestRevokeFailedAuthz(t *testing.T) {
+	// Prefill authorization URIs expected to be revoked.
+	// The challenges are selected in a specific order,
+	// each tried within a newly created authorization.
+	// This means each authorization URI corresponds to a different challenge type.
+	revokedAuthz := map[string]bool{
+		"/authz/0": false, // tls-sni-02
+		"/authz/1": false, // tls-sni-01
+		"/authz/2": false, // no viable challenge, but authz is created
+	}
+
+	var authzCount int          // num. of created authorizations
+	var revokeCount int         // num. of revoked authorizations
+	done := make(chan struct{}) // closed when revokeCount is 3
+
+	// ACME CA server stub, only the needed bits.
+	// TODO: Replace this with x/crypto/acme/autocert/internal/acmetest.
+	var ca *httptest.Server
+	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Replay-Nonce", "nonce")
+		if r.Method == "HEAD" {
+			// a nonce request
+			return
+		}
+
+		switch r.URL.Path {
+		// Discovery.
+		case "/":
+			if err := discoTmpl.Execute(w, ca.URL); err != nil {
+				t.Errorf("discoTmpl: %v", err)
+			}
+		// Client key registration.
+		case "/new-reg":
+			w.Write([]byte("{}"))
+		// New domain authorization.
+		case "/new-authz":
+			w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount))
+			w.WriteHeader(http.StatusCreated)
+			if err := authzTmpl.Execute(w, ca.URL); err != nil {
+				t.Errorf("authzTmpl: %v", err)
+			}
+			authzCount++
+		// tls-sni-02 challenge "accept" request.
+		case "/challenge/2":
+			// Refuse.
+			http.Error(w, "won't accept tls-sni-02 challenge", http.StatusBadRequest)
+		// tls-sni-01 challenge "accept" request.
+		case "/challenge/1":
+			// Accept but the authorization will be "expired".
+			w.Write([]byte("{}"))
+		// Authorization requests.
+		case "/authz/0", "/authz/1", "/authz/2":
+			// Revocation requests.
+			if r.Method == "POST" {
+				var req struct{ Status string }
+				if err := decodePayload(&req, r.Body); err != nil {
+					t.Errorf("%s: decodePayload: %v", r.URL, err)
+				}
+				switch req.Status {
+				case "deactivated":
+					revokedAuthz[r.URL.Path] = true
+					revokeCount++
+					if revokeCount >= 3 {
+						// Last authorization is revoked.
+						defer close(done)
+					}
+				default:
+					t.Errorf("%s: req.Status = %q; want 'deactivated'", r.URL, req.Status)
+				}
+				w.Write([]byte(`{"status": "invalid"}`))
+				return
+			}
+			// Authorization status requests.
+			// Simulate abandoned authorization, deleted by the CA.
+			w.WriteHeader(http.StatusNotFound)
+		default:
+			http.NotFound(w, r)
+			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+		}
+	}))
+	defer ca.Close()
+
+	m := &Manager{
+		Client: &acme.Client{DirectoryURL: ca.URL},
+	}
+	// Should fail and revoke 3 authorizations.
+	// The first 2 are tsl-sni-02 and tls-sni-01 challenges.
+	// The third time an authorization is created but no viable challenge is found.
+	// See revokedAuthz above for more explanation.
+	if _, err := m.createCert(context.Background(), exampleCertKey); err == nil {
+		t.Errorf("m.createCert returned nil error")
+	}
+	select {
+	case <-time.After(3 * time.Second):
+		t.Error("revocations took too long")
+	case <-done:
+		// revokeCount is at least 3.
+	}
+	for uri, ok := range revokedAuthz {
+		if !ok {
+			t.Errorf("%q authorization was not revoked", uri)
+		}
+	}
+}
+
+func TestHTTPHandlerDefaultFallback(t *testing.T) {
+	tt := []struct {
+		method, url  string
+		wantCode     int
+		wantLocation string
+	}{
+		{"GET", "http://example.org", 302, "https://example.org/"},
+		{"GET", "http://example.org/foo", 302, "https://example.org/foo"},
+		{"GET", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"},
+		{"GET", "http://example.org/?a=b", 302, "https://example.org/?a=b"},
+		{"GET", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"},
+		{"GET", "http://example.org:80/foo?a=b", 302, "https://example.org:443/foo?a=b"},
+		{"GET", "http://example.org:80/foo%20bar", 302, "https://example.org:443/foo%20bar"},
+		{"GET", "http://[2602:d1:xxxx::c60a]:1234", 302, "https://[2602:d1:xxxx::c60a]:443/"},
+		{"GET", "http://[2602:d1:xxxx::c60a]", 302, "https://[2602:d1:xxxx::c60a]/"},
+		{"GET", "http://[2602:d1:xxxx::c60a]/foo?a=b", 302, "https://[2602:d1:xxxx::c60a]/foo?a=b"},
+		{"HEAD", "http://example.org", 302, "https://example.org/"},
+		{"HEAD", "http://example.org/foo", 302, "https://example.org/foo"},
+		{"HEAD", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"},
+		{"HEAD", "http://example.org/?a=b", 302, "https://example.org/?a=b"},
+		{"HEAD", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"},
+		{"POST", "http://example.org", 400, ""},
+		{"PUT", "http://example.org", 400, ""},
+		{"GET", "http://example.org/.well-known/acme-challenge/x", 404, ""},
+	}
+	var m Manager
+	h := m.HTTPHandler(nil)
+	for i, test := range tt {
+		r := httptest.NewRequest(test.method, test.url, nil)
+		w := httptest.NewRecorder()
+		h.ServeHTTP(w, r)
+		if w.Code != test.wantCode {
+			t.Errorf("%d: w.Code = %d; want %d", i, w.Code, test.wantCode)
+			t.Errorf("%d: body: %s", i, w.Body.Bytes())
+		}
+		if v := w.Header().Get("Location"); v != test.wantLocation {
+			t.Errorf("%d: Location = %q; want %q", i, v, test.wantLocation)
+		}
+	}
+}
+
+func TestAccountKeyCache(t *testing.T) {
+	m := Manager{Cache: newMemCache(t)}
+	ctx := context.Background()
+	k1, err := m.accountKey(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	k2, err := m.accountKey(ctx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(k1, k2) {
+		t.Errorf("account keys don't match: k1 = %#v; k2 = %#v", k1, k2)
+	}
+}
+
+func TestCache(t *testing.T) {
+	ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	cert, err := dummyCert(ecdsaKey.Public(), exampleDomain)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ecdsaCert := &tls.Certificate{
+		Certificate: [][]byte{cert},
+		PrivateKey:  ecdsaKey,
+	}
+
+	rsaKey, err := rsa.GenerateKey(rand.Reader, 512)
+	if err != nil {
+		t.Fatal(err)
+	}
+	cert, err = dummyCert(rsaKey.Public(), exampleDomain)
+	if err != nil {
+		t.Fatal(err)
+	}
+	rsaCert := &tls.Certificate{
+		Certificate: [][]byte{cert},
+		PrivateKey:  rsaKey,
+	}
+
+	man := &Manager{Cache: newMemCache(t)}
+	defer man.stopRenew()
+	ctx := context.Background()
+
+	if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil {
+		t.Fatalf("man.cachePut: %v", err)
+	}
+	if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil {
+		t.Fatalf("man.cachePut: %v", err)
+	}
+
+	res, err := man.cacheGet(ctx, exampleCertKey)
+	if err != nil {
+		t.Fatalf("man.cacheGet: %v", err)
+	}
+	if res == nil || !bytes.Equal(res.Certificate[0], ecdsaCert.Certificate[0]) {
+		t.Errorf("man.cacheGet = %+v; want %+v", res, ecdsaCert)
+	}
+
+	res, err = man.cacheGet(ctx, exampleCertKeyRSA)
+	if err != nil {
+		t.Fatalf("man.cacheGet: %v", err)
+	}
+	if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) {
+		t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert)
+	}
+}
+
+func TestHostWhitelist(t *testing.T) {
+	policy := HostWhitelist("example.com", "example.org", "*.example.net")
+	tt := []struct {
+		host  string
+		allow bool
+	}{
+		{"example.com", true},
+		{"example.org", true},
+		{"one.example.com", false},
+		{"two.example.org", false},
+		{"three.example.net", false},
+		{"dummy", false},
+	}
+	for i, test := range tt {
+		err := policy(nil, test.host)
+		if err != nil && test.allow {
+			t.Errorf("%d: policy(%q): %v; want nil", i, test.host, err)
+		}
+		if err == nil && !test.allow {
+			t.Errorf("%d: policy(%q): nil; want an error", i, test.host)
+		}
+	}
+}
+
+func TestValidCert(t *testing.T) {
+	key1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	key2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	key3, err := rsa.GenerateKey(rand.Reader, 512)
+	if err != nil {
+		t.Fatal(err)
+	}
+	cert1, err := dummyCert(key1.Public(), "example.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+	cert2, err := dummyCert(key2.Public(), "example.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+	cert3, err := dummyCert(key3.Public(), "example.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+	now := time.Now()
+	early, err := dateDummyCert(key1.Public(), now.Add(time.Hour), now.Add(2*time.Hour), "example.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+	expired, err := dateDummyCert(key1.Public(), now.Add(-2*time.Hour), now.Add(-time.Hour), "example.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tt := []struct {
+		ck   certKey
+		key  crypto.Signer
+		cert [][]byte
+		ok   bool
+	}{
+		{certKey{domain: "example.org"}, key1, [][]byte{cert1}, true},
+		{certKey{domain: "example.org", isRSA: true}, key3, [][]byte{cert3}, true},
+		{certKey{domain: "example.org"}, key1, [][]byte{cert1, cert2, cert3}, true},
+		{certKey{domain: "example.org"}, key1, [][]byte{cert1, {1}}, false},
+		{certKey{domain: "example.org"}, key1, [][]byte{{1}}, false},
+		{certKey{domain: "example.org"}, key1, [][]byte{cert2}, false},
+		{certKey{domain: "example.org"}, key2, [][]byte{cert1}, false},
+		{certKey{domain: "example.org"}, key1, [][]byte{cert3}, false},
+		{certKey{domain: "example.org"}, key3, [][]byte{cert1}, false},
+		{certKey{domain: "example.net"}, key1, [][]byte{cert1}, false},
+		{certKey{domain: "example.org"}, key1, [][]byte{early}, false},
+		{certKey{domain: "example.org"}, key1, [][]byte{expired}, false},
+		{certKey{domain: "example.org", isRSA: true}, key1, [][]byte{cert1}, false},
+		{certKey{domain: "example.org"}, key3, [][]byte{cert3}, false},
+	}
+	for i, test := range tt {
+		leaf, err := validCert(test.ck, test.cert, test.key, now)
+		if err != nil && test.ok {
+			t.Errorf("%d: err = %v", i, err)
+		}
+		if err == nil && !test.ok {
+			t.Errorf("%d: err is nil", i)
+		}
+		if err == nil && test.ok && leaf == nil {
+			t.Errorf("%d: leaf is nil", i)
+		}
+	}
+}
+
+type cacheGetFunc func(ctx context.Context, key string) ([]byte, error)
+
+func (f cacheGetFunc) Get(ctx context.Context, key string) ([]byte, error) {
+	return f(ctx, key)
+}
+
+func (f cacheGetFunc) Put(ctx context.Context, key string, data []byte) error {
+	return fmt.Errorf("unsupported Put of %q = %q", key, data)
+}
+
+func (f cacheGetFunc) Delete(ctx context.Context, key string) error {
+	return fmt.Errorf("unsupported Delete of %q", key)
+}
+
+func TestManagerGetCertificateBogusSNI(t *testing.T) {
+	m := Manager{
+		Prompt: AcceptTOS,
+		Cache: cacheGetFunc(func(ctx context.Context, key string) ([]byte, error) {
+			return nil, fmt.Errorf("cache.Get of %s", key)
+		}),
+	}
+	tests := []struct {
+		name    string
+		wantErr string
+	}{
+		{"foo.com", "cache.Get of foo.com"},
+		{"foo.com.", "cache.Get of foo.com"},
+		{`a\b.com`, "acme/autocert: server name contains invalid character"},
+		{`a/b.com`, "acme/autocert: server name contains invalid character"},
+		{"", "acme/autocert: missing server name"},
+		{"foo", "acme/autocert: server name component count invalid"},
+		{".foo", "acme/autocert: server name component count invalid"},
+		{"foo.", "acme/autocert: server name component count invalid"},
+		{"fo.o", "cache.Get of fo.o"},
+	}
+	for _, tt := range tests {
+		_, err := m.GetCertificate(clientHelloInfo(tt.name, true))
+		got := fmt.Sprint(err)
+		if got != tt.wantErr {
+			t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr)
+		}
+	}
+}
+
+func TestCertRequest(t *testing.T) {
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// An extension from RFC7633. Any will do.
+	ext := pkix.Extension{
+		Id:    asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1},
+		Value: []byte("dummy"),
+	}
+	b, err := certRequest(key, "example.org", []pkix.Extension{ext}, "san.example.org")
+	if err != nil {
+		t.Fatalf("certRequest: %v", err)
+	}
+	r, err := x509.ParseCertificateRequest(b)
+	if err != nil {
+		t.Fatalf("ParseCertificateRequest: %v", err)
+	}
+	var found bool
+	for _, v := range r.Extensions {
+		if v.Id.Equal(ext.Id) {
+			found = true
+			break
+		}
+	}
+	if !found {
+		t.Errorf("want %v in Extensions: %v", ext, r.Extensions)
+	}
+}
+
+func TestSupportsECDSA(t *testing.T) {
+	tests := []struct {
+		CipherSuites     []uint16
+		SignatureSchemes []tls.SignatureScheme
+		SupportedCurves  []tls.CurveID
+		ecdsaOk          bool
+	}{
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+		}, nil, nil, false},
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+		}, nil, nil, true},
+
+		// SignatureSchemes limits, not extends, CipherSuites
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+		}, []tls.SignatureScheme{
+			tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
+		}, nil, false},
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+		}, []tls.SignatureScheme{
+			tls.PKCS1WithSHA256,
+		}, nil, false},
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+		}, []tls.SignatureScheme{
+			tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
+		}, nil, true},
+
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+		}, []tls.SignatureScheme{
+			tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
+		}, []tls.CurveID{
+			tls.CurveP521,
+		}, false},
+		{[]uint16{
+			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+		}, []tls.SignatureScheme{
+			tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
+		}, []tls.CurveID{
+			tls.CurveP256,
+			tls.CurveP521,
+		}, true},
+	}
+	for i, tt := range tests {
+		result := supportsECDSA(&tls.ClientHelloInfo{
+			CipherSuites:     tt.CipherSuites,
+			SignatureSchemes: tt.SignatureSchemes,
+			SupportedCurves:  tt.SupportedCurves,
+		})
+		if result != tt.ecdsaOk {
+			t.Errorf("%d: supportsECDSA = %v; want %v", i, result, tt.ecdsaOk)
+		}
+	}
+}
+
+// TODO: add same end-to-end for http-01 challenge type.
+func TestEndToEnd(t *testing.T) {
+	const domain = "example.org"
+
+	// ACME CA server
+	ca := acmetest.NewCAServer([]string{"tls-alpn-01"}, []string{domain})
+	defer ca.Close()
+
+	// User dummy server.
+	m := &Manager{
+		Prompt: AcceptTOS,
+		Client: &acme.Client{DirectoryURL: ca.URL},
+	}
+	us := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("OK"))
+	}))
+	us.TLS = &tls.Config{
+		NextProtos: []string{"http/1.1", acme.ALPNProto},
+		GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
+			cert, err := m.GetCertificate(hello)
+			if err != nil {
+				t.Errorf("m.GetCertificate: %v", err)
+			}
+			return cert, err
+		},
+	}
+	us.StartTLS()
+	defer us.Close()
+	// In TLS-ALPN challenge verification, CA connects to the domain:443 in question.
+	// Because the domain won't resolve in tests, we need to tell the CA
+	// where to dial to instead.
+	ca.Resolve(domain, strings.TrimPrefix(us.URL, "https://"))
+
+	// A client visiting user dummy server.
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{
+			RootCAs:    ca.Roots,
+			ServerName: domain,
+		},
+	}
+	client := &http.Client{Transport: tr}
+	res, err := client.Get(us.URL)
+	if err != nil {
+		t.Logf("CA errors: %v", ca.Errors())
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	b, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if v := string(b); v != "OK" {
+		t.Errorf("user server response: %q; want 'OK'", v)
+	}
+}

+ 130 - 0
src/golang.org/x/crypto/acme/autocert/cache.go

@@ -0,0 +1,130 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"context"
+	"errors"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+)
+
+// ErrCacheMiss is returned when a certificate is not found in cache.
+var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
+
+// Cache is used by Manager to store and retrieve previously obtained certificates
+// and other account data as opaque blobs.
+//
+// Cache implementations should not rely on the key naming pattern. Keys can
+// include any printable ASCII characters, except the following: \/:*?"<>|
+type Cache interface {
+	// Get returns a certificate data for the specified key.
+	// If there's no such key, Get returns ErrCacheMiss.
+	Get(ctx context.Context, key string) ([]byte, error)
+
+	// Put stores the data in the cache under the specified key.
+	// Underlying implementations may use any data storage format,
+	// as long as the reverse operation, Get, results in the original data.
+	Put(ctx context.Context, key string, data []byte) error
+
+	// Delete removes a certificate data from the cache under the specified key.
+	// If there's no such key in the cache, Delete returns nil.
+	Delete(ctx context.Context, key string) error
+}
+
+// DirCache implements Cache using a directory on the local filesystem.
+// If the directory does not exist, it will be created with 0700 permissions.
+type DirCache string
+
+// Get reads a certificate data from the specified file name.
+func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
+	name = filepath.Join(string(d), name)
+	var (
+		data []byte
+		err  error
+		done = make(chan struct{})
+	)
+	go func() {
+		data, err = ioutil.ReadFile(name)
+		close(done)
+	}()
+	select {
+	case <-ctx.Done():
+		return nil, ctx.Err()
+	case <-done:
+	}
+	if os.IsNotExist(err) {
+		return nil, ErrCacheMiss
+	}
+	return data, err
+}
+
+// Put writes the certificate data to the specified file name.
+// The file will be created with 0600 permissions.
+func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
+	if err := os.MkdirAll(string(d), 0700); err != nil {
+		return err
+	}
+
+	done := make(chan struct{})
+	var err error
+	go func() {
+		defer close(done)
+		var tmp string
+		if tmp, err = d.writeTempFile(name, data); err != nil {
+			return
+		}
+		select {
+		case <-ctx.Done():
+			// Don't overwrite the file if the context was canceled.
+		default:
+			newName := filepath.Join(string(d), name)
+			err = os.Rename(tmp, newName)
+		}
+	}()
+	select {
+	case <-ctx.Done():
+		return ctx.Err()
+	case <-done:
+	}
+	return err
+}
+
+// Delete removes the specified file name.
+func (d DirCache) Delete(ctx context.Context, name string) error {
+	name = filepath.Join(string(d), name)
+	var (
+		err  error
+		done = make(chan struct{})
+	)
+	go func() {
+		err = os.Remove(name)
+		close(done)
+	}()
+	select {
+	case <-ctx.Done():
+		return ctx.Err()
+	case <-done:
+	}
+	if err != nil && !os.IsNotExist(err) {
+		return err
+	}
+	return nil
+}
+
+// writeTempFile writes b to a temporary file, closes the file and returns its path.
+func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
+	// TempFile uses 0600 permissions
+	f, err := ioutil.TempFile(string(d), prefix)
+	if err != nil {
+		return "", err
+	}
+	if _, err := f.Write(b); err != nil {
+		f.Close()
+		return "", err
+	}
+	return f.Name(), f.Close()
+}

+ 58 - 0
src/golang.org/x/crypto/acme/autocert/cache_test.go

@@ -0,0 +1,58 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"context"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"testing"
+)
+
+// make sure DirCache satisfies Cache interface
+var _ Cache = DirCache("/")
+
+func TestDirCache(t *testing.T) {
+	dir, err := ioutil.TempDir("", "autocert")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	dir = filepath.Join(dir, "certs") // a nonexistent dir
+	cache := DirCache(dir)
+	ctx := context.Background()
+
+	// test cache miss
+	if _, err := cache.Get(ctx, "nonexistent"); err != ErrCacheMiss {
+		t.Errorf("get: %v; want ErrCacheMiss", err)
+	}
+
+	// test put/get
+	b1 := []byte{1}
+	if err := cache.Put(ctx, "dummy", b1); err != nil {
+		t.Fatalf("put: %v", err)
+	}
+	b2, err := cache.Get(ctx, "dummy")
+	if err != nil {
+		t.Fatalf("get: %v", err)
+	}
+	if !reflect.DeepEqual(b1, b2) {
+		t.Errorf("b1 = %v; want %v", b1, b2)
+	}
+	name := filepath.Join(dir, "dummy")
+	if _, err := os.Stat(name); err != nil {
+		t.Error(err)
+	}
+
+	// test delete
+	if err := cache.Delete(ctx, "dummy"); err != nil {
+		t.Fatalf("delete: %v", err)
+	}
+	if _, err := cache.Get(ctx, "dummy"); err != ErrCacheMiss {
+		t.Errorf("get: %v; want ErrCacheMiss", err)
+	}
+}

+ 34 - 0
src/golang.org/x/crypto/acme/autocert/example_test.go

@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert_test
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+
+	"golang.org/x/crypto/acme/autocert"
+)
+
+func ExampleNewListener() {
+	mux := http.NewServeMux()
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		fmt.Fprintf(w, "Hello, TLS user! Your config: %+v", r.TLS)
+	})
+	log.Fatal(http.Serve(autocert.NewListener("example.com"), mux))
+}
+
+func ExampleManager() {
+	m := &autocert.Manager{
+		Cache:      autocert.DirCache("secret-dir"),
+		Prompt:     autocert.AcceptTOS,
+		HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"),
+	}
+	s := &http.Server{
+		Addr:      ":https",
+		TLSConfig: m.TLSConfig(),
+	}
+	s.ListenAndServeTLS("", "")
+}

+ 416 - 0
src/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go

@@ -0,0 +1,416 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package acmetest provides types for testing acme and autocert packages.
+//
+// TODO: Consider moving this to x/crypto/acme/internal/acmetest for acme tests as well.
+package acmetest
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"math/big"
+	"net/http"
+	"net/http/httptest"
+	"sort"
+	"strings"
+	"sync"
+	"time"
+)
+
+// CAServer is a simple test server which implements ACME spec bits needed for testing.
+type CAServer struct {
+	URL   string         // server URL after it has been started
+	Roots *x509.CertPool // CA root certificates; initialized in NewCAServer
+
+	rootKey      crypto.Signer
+	rootCert     []byte // DER encoding
+	rootTemplate *x509.Certificate
+
+	server           *httptest.Server
+	challengeTypes   []string // supported challenge types
+	domainsWhitelist []string // only these domains are valid for issuing, unless empty
+
+	mu             sync.Mutex
+	certCount      int                       // number of issued certs
+	domainAddr     map[string]string         // domain name to addr:port resolution
+	authorizations map[string]*authorization // keyed by domain name
+	errors         []error                   // encountered client errors
+}
+
+// NewCAServer creates a new ACME test server and starts serving requests.
+// The returned CAServer issues certs signed with the CA roots
+// available in the Roots field.
+//
+// The challengeTypes argument defines the supported ACME challenge types
+// sent to a client in a response for a domain authorization.
+// If domainsWhitelist is non-empty, the certs will be issued only for the specified
+// list of domains. Otherwise, any domain name is allowed.
+func NewCAServer(challengeTypes []string, domainsWhitelist []string) *CAServer {
+	var whitelist []string
+	for _, name := range domainsWhitelist {
+		whitelist = append(whitelist, name)
+	}
+	sort.Strings(whitelist)
+	ca := &CAServer{
+		challengeTypes:   challengeTypes,
+		domainsWhitelist: whitelist,
+		domainAddr:       make(map[string]string),
+		authorizations:   make(map[string]*authorization),
+	}
+
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		panic(fmt.Sprintf("ecdsa.GenerateKey: %v", err))
+	}
+	tmpl := &x509.Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject: pkix.Name{
+			Organization: []string{"Test Acme Co"},
+			CommonName:   "Root CA",
+		},
+		NotBefore:             time.Now(),
+		NotAfter:              time.Now().Add(365 * 24 * time.Hour),
+		KeyUsage:              x509.KeyUsageCertSign,
+		BasicConstraintsValid: true,
+		IsCA: true,
+	}
+	der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
+	if err != nil {
+		panic(fmt.Sprintf("x509.CreateCertificate: %v", err))
+	}
+	cert, err := x509.ParseCertificate(der)
+	if err != nil {
+		panic(fmt.Sprintf("x509.ParseCertificate: %v", err))
+	}
+	ca.Roots = x509.NewCertPool()
+	ca.Roots.AddCert(cert)
+	ca.rootKey = key
+	ca.rootCert = der
+	ca.rootTemplate = tmpl
+
+	ca.server = httptest.NewServer(http.HandlerFunc(ca.handle))
+	ca.URL = ca.server.URL
+	return ca
+}
+
+// Close shuts down the server and blocks until all outstanding
+// requests on this server have completed.
+func (ca *CAServer) Close() {
+	ca.server.Close()
+}
+
+// Errors returns all client errors.
+func (ca *CAServer) Errors() []error {
+	ca.mu.Lock()
+	defer ca.mu.Unlock()
+	return ca.errors
+}
+
+// Resolve adds a domain to address resolution for the ca to dial to
+// when validating challenges for the domain authorization.
+func (ca *CAServer) Resolve(domain, addr string) {
+	ca.mu.Lock()
+	defer ca.mu.Unlock()
+	ca.domainAddr[domain] = addr
+}
+
+type discovery struct {
+	NewReg   string `json:"new-reg"`
+	NewAuthz string `json:"new-authz"`
+	NewCert  string `json:"new-cert"`
+}
+
+type challenge struct {
+	URI   string `json:"uri"`
+	Type  string `json:"type"`
+	Token string `json:"token"`
+}
+
+type authorization struct {
+	Status     string      `json:"status"`
+	Challenges []challenge `json:"challenges"`
+
+	id     int
+	domain string
+}
+
+func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Replay-Nonce", "nonce")
+	if r.Method == "HEAD" {
+		// a nonce request
+		return
+	}
+
+	// TODO: Verify nonce header for all POST requests.
+
+	switch {
+	default:
+		err := fmt.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+		ca.addError(err)
+		http.Error(w, err.Error(), http.StatusBadRequest)
+
+	// Discovery request.
+	case r.URL.Path == "/":
+		resp := &discovery{
+			NewReg:   ca.serverURL("/new-reg"),
+			NewAuthz: ca.serverURL("/new-authz"),
+			NewCert:  ca.serverURL("/new-cert"),
+		}
+		if err := json.NewEncoder(w).Encode(resp); err != nil {
+			panic(fmt.Sprintf("discovery response: %v", err))
+		}
+
+	// Client key registration request.
+	case r.URL.Path == "/new-reg":
+		// TODO: Check the user account key against a ca.accountKeys?
+		w.Write([]byte("{}"))
+
+	// Domain authorization request.
+	case r.URL.Path == "/new-authz":
+		var req struct {
+			Identifier struct{ Value string }
+		}
+		if err := decodePayload(&req, r.Body); err != nil {
+			ca.addError(err)
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return
+		}
+		ca.mu.Lock()
+		defer ca.mu.Unlock()
+		authz, ok := ca.authorizations[req.Identifier.Value]
+		if !ok {
+			authz = &authorization{
+				domain: req.Identifier.Value,
+				Status: "pending",
+			}
+			for _, typ := range ca.challengeTypes {
+				authz.Challenges = append(authz.Challenges, challenge{
+					Type:  typ,
+					URI:   ca.serverURL("/challenge/%s/%s", typ, authz.domain),
+					Token: challengeToken(authz.domain, typ),
+				})
+			}
+			ca.authorizations[authz.domain] = authz
+		}
+		w.Header().Set("Location", ca.serverURL("/authz/%s", authz.domain))
+		w.WriteHeader(http.StatusCreated)
+		if err := json.NewEncoder(w).Encode(authz); err != nil {
+			panic(fmt.Sprintf("new authz response: %v", err))
+		}
+
+	// Accept tls-alpn-01 challenge type requests.
+	// TODO: Add http-01 and dns-01 handlers.
+	case strings.HasPrefix(r.URL.Path, "/challenge/tls-alpn-01/"):
+		domain := strings.TrimPrefix(r.URL.Path, "/challenge/tls-alpn-01/")
+		ca.mu.Lock()
+		defer ca.mu.Unlock()
+		if _, ok := ca.authorizations[domain]; !ok {
+			err := fmt.Errorf("challenge accept: no authz for %q", domain)
+			ca.addError(err)
+			http.Error(w, err.Error(), http.StatusNotFound)
+			return
+		}
+		go func(domain string) {
+			err := ca.verifyALPNChallenge(domain)
+			ca.mu.Lock()
+			defer ca.mu.Unlock()
+			authz := ca.authorizations[domain]
+			if err != nil {
+				authz.Status = "invalid"
+				return
+			}
+			authz.Status = "valid"
+
+		}(domain)
+		w.Write([]byte("{}"))
+
+	// Get authorization status requests.
+	case strings.HasPrefix(r.URL.Path, "/authz/"):
+		domain := strings.TrimPrefix(r.URL.Path, "/authz/")
+		ca.mu.Lock()
+		defer ca.mu.Unlock()
+		authz, ok := ca.authorizations[domain]
+		if !ok {
+			http.Error(w, fmt.Sprintf("no authz for %q", domain), http.StatusNotFound)
+			return
+		}
+		if err := json.NewEncoder(w).Encode(authz); err != nil {
+			panic(fmt.Sprintf("get authz for %q response: %v", domain, err))
+		}
+
+	// Cert issuance request.
+	case r.URL.Path == "/new-cert":
+		var req struct {
+			CSR string `json:"csr"`
+		}
+		decodePayload(&req, r.Body)
+		b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
+		csr, err := x509.ParseCertificateRequest(b)
+		if err != nil {
+			ca.addError(err)
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return
+		}
+		names := unique(append(csr.DNSNames, csr.Subject.CommonName))
+		if err := ca.matchWhitelist(names); err != nil {
+			ca.addError(err)
+			http.Error(w, err.Error(), http.StatusUnauthorized)
+			return
+		}
+		if err := ca.authorized(names); err != nil {
+			ca.addError(err)
+			http.Error(w, err.Error(), http.StatusUnauthorized)
+			return
+		}
+		der, err := ca.leafCert(csr)
+		if err != nil {
+			err = fmt.Errorf("new-cert response: ca.leafCert: %v", err)
+			ca.addError(err)
+			http.Error(w, err.Error(), http.StatusBadRequest)
+		}
+		w.Header().Set("Link", fmt.Sprintf("<%s>; rel=up", ca.serverURL("/ca-cert")))
+		w.WriteHeader(http.StatusCreated)
+		w.Write(der)
+
+	// CA chain cert request.
+	case r.URL.Path == "/ca-cert":
+		w.Write(ca.rootCert)
+	}
+}
+
+func (ca *CAServer) addError(err error) {
+	ca.mu.Lock()
+	defer ca.mu.Unlock()
+	ca.errors = append(ca.errors, err)
+}
+
+func (ca *CAServer) serverURL(format string, arg ...interface{}) string {
+	return ca.server.URL + fmt.Sprintf(format, arg...)
+}
+
+func (ca *CAServer) matchWhitelist(dnsNames []string) error {
+	if len(ca.domainsWhitelist) == 0 {
+		return nil
+	}
+	var nomatch []string
+	for _, name := range dnsNames {
+		i := sort.SearchStrings(ca.domainsWhitelist, name)
+		if i == len(ca.domainsWhitelist) || ca.domainsWhitelist[i] != name {
+			nomatch = append(nomatch, name)
+		}
+	}
+	if len(nomatch) > 0 {
+		return fmt.Errorf("matchWhitelist: some domains don't match: %q", nomatch)
+	}
+	return nil
+}
+
+func (ca *CAServer) authorized(dnsNames []string) error {
+	ca.mu.Lock()
+	defer ca.mu.Unlock()
+	var noauthz []string
+	for _, name := range dnsNames {
+		authz, ok := ca.authorizations[name]
+		if !ok || authz.Status != "valid" {
+			noauthz = append(noauthz, name)
+		}
+	}
+	if len(noauthz) > 0 {
+		return fmt.Errorf("CAServer: no authz for %q", noauthz)
+	}
+	return nil
+}
+
+func (ca *CAServer) leafCert(csr *x509.CertificateRequest) (der []byte, err error) {
+	ca.mu.Lock()
+	defer ca.mu.Unlock()
+	ca.certCount++ // next leaf cert serial number
+	leaf := &x509.Certificate{
+		SerialNumber:          big.NewInt(int64(ca.certCount)),
+		Subject:               pkix.Name{Organization: []string{"Test Acme Co"}},
+		NotBefore:             time.Now(),
+		NotAfter:              time.Now().Add(90 * 24 * time.Hour),
+		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		DNSNames:              csr.DNSNames,
+		BasicConstraintsValid: true,
+	}
+	if len(csr.DNSNames) == 0 {
+		leaf.DNSNames = []string{csr.Subject.CommonName}
+	}
+	return x509.CreateCertificate(rand.Reader, leaf, ca.rootTemplate, csr.PublicKey, ca.rootKey)
+}
+
+func (ca *CAServer) addr(domain string) (string, error) {
+	ca.mu.Lock()
+	defer ca.mu.Unlock()
+	addr, ok := ca.domainAddr[domain]
+	if !ok {
+		return "", fmt.Errorf("CAServer: no addr resolution for %q", domain)
+	}
+	return addr, nil
+}
+
+func (ca *CAServer) verifyALPNChallenge(domain string) error {
+	const acmeALPNProto = "acme-tls/1"
+
+	addr, err := ca.addr(domain)
+	if err != nil {
+		return err
+	}
+	conn, err := tls.Dial("tcp", addr, &tls.Config{
+		ServerName:         domain,
+		InsecureSkipVerify: true,
+		NextProtos:         []string{acmeALPNProto},
+	})
+	if err != nil {
+		return err
+	}
+	if v := conn.ConnectionState().NegotiatedProtocol; v != acmeALPNProto {
+		return fmt.Errorf("CAServer: verifyALPNChallenge: negotiated proto is %q; want %q", v, acmeALPNProto)
+	}
+	if n := len(conn.ConnectionState().PeerCertificates); n != 1 {
+		return fmt.Errorf("len(PeerCertificates) = %d; want 1", n)
+	}
+	// TODO: verify conn.ConnectionState().PeerCertificates[0]
+	return nil
+}
+
+func decodePayload(v interface{}, r io.Reader) error {
+	var req struct{ Payload string }
+	if err := json.NewDecoder(r).Decode(&req); err != nil {
+		return err
+	}
+	payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
+	if err != nil {
+		return err
+	}
+	return json.Unmarshal(payload, v)
+}
+
+func challengeToken(domain, challType string) string {
+	return fmt.Sprintf("token-%s-%s", domain, challType)
+}
+
+func unique(a []string) []string {
+	seen := make(map[string]bool)
+	var res []string
+	for _, s := range a {
+		if s != "" && !seen[s] {
+			seen[s] = true
+			res = append(res, s)
+		}
+	}
+	return res
+}

+ 157 - 0
src/golang.org/x/crypto/acme/autocert/listener.go

@@ -0,0 +1,157 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"crypto/tls"
+	"log"
+	"net"
+	"os"
+	"path/filepath"
+	"runtime"
+	"time"
+)
+
+// NewListener returns a net.Listener that listens on the standard TLS
+// port (443) on all interfaces and returns *tls.Conn connections with
+// LetsEncrypt certificates for the provided domain or domains.
+//
+// It enables one-line HTTPS servers:
+//
+//     log.Fatal(http.Serve(autocert.NewListener("example.com"), handler))
+//
+// NewListener is a convenience function for a common configuration.
+// More complex or custom configurations can use the autocert.Manager
+// type instead.
+//
+// Use of this function implies acceptance of the LetsEncrypt Terms of
+// Service. If domains is not empty, the provided domains are passed
+// to HostWhitelist. If domains is empty, the listener will do
+// LetsEncrypt challenges for any requested domain, which is not
+// recommended.
+//
+// Certificates are cached in a "golang-autocert" directory under an
+// operating system-specific cache or temp directory. This may not
+// be suitable for servers spanning multiple machines.
+//
+// The returned listener uses a *tls.Config that enables HTTP/2, and
+// should only be used with servers that support HTTP/2.
+//
+// The returned Listener also enables TCP keep-alives on the accepted
+// connections. The returned *tls.Conn are returned before their TLS
+// handshake has completed.
+func NewListener(domains ...string) net.Listener {
+	m := &Manager{
+		Prompt: AcceptTOS,
+	}
+	if len(domains) > 0 {
+		m.HostPolicy = HostWhitelist(domains...)
+	}
+	dir := cacheDir()
+	if err := os.MkdirAll(dir, 0700); err != nil {
+		log.Printf("warning: autocert.NewListener not using a cache: %v", err)
+	} else {
+		m.Cache = DirCache(dir)
+	}
+	return m.Listener()
+}
+
+// Listener listens on the standard TLS port (443) on all interfaces
+// and returns a net.Listener returning *tls.Conn connections.
+//
+// The returned listener uses a *tls.Config that enables HTTP/2, and
+// should only be used with servers that support HTTP/2.
+//
+// The returned Listener also enables TCP keep-alives on the accepted
+// connections. The returned *tls.Conn are returned before their TLS
+// handshake has completed.
+//
+// Unlike NewListener, it is the caller's responsibility to initialize
+// the Manager m's Prompt, Cache, HostPolicy, and other desired options.
+func (m *Manager) Listener() net.Listener {
+	ln := &listener{
+		m:    m,
+		conf: m.TLSConfig(),
+	}
+	ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
+	return ln
+}
+
+type listener struct {
+	m    *Manager
+	conf *tls.Config
+
+	tcpListener  net.Listener
+	tcpListenErr error
+}
+
+func (ln *listener) Accept() (net.Conn, error) {
+	if ln.tcpListenErr != nil {
+		return nil, ln.tcpListenErr
+	}
+	conn, err := ln.tcpListener.Accept()
+	if err != nil {
+		return nil, err
+	}
+	tcpConn := conn.(*net.TCPConn)
+
+	// Because Listener is a convenience function, help out with
+	// this too.  This is not possible for the caller to set once
+	// we return a *tcp.Conn wrapping an inaccessible net.Conn.
+	// If callers don't want this, they can do things the manual
+	// way and tweak as needed. But this is what net/http does
+	// itself, so copy that. If net/http changes, we can change
+	// here too.
+	tcpConn.SetKeepAlive(true)
+	tcpConn.SetKeepAlivePeriod(3 * time.Minute)
+
+	return tls.Server(tcpConn, ln.conf), nil
+}
+
+func (ln *listener) Addr() net.Addr {
+	if ln.tcpListener != nil {
+		return ln.tcpListener.Addr()
+	}
+	// net.Listen failed. Return something non-nil in case callers
+	// call Addr before Accept:
+	return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
+}
+
+func (ln *listener) Close() error {
+	if ln.tcpListenErr != nil {
+		return ln.tcpListenErr
+	}
+	return ln.tcpListener.Close()
+}
+
+func homeDir() string {
+	if runtime.GOOS == "windows" {
+		return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+	}
+	if h := os.Getenv("HOME"); h != "" {
+		return h
+	}
+	return "/"
+}
+
+func cacheDir() string {
+	const base = "golang-autocert"
+	switch runtime.GOOS {
+	case "darwin":
+		return filepath.Join(homeDir(), "Library", "Caches", base)
+	case "windows":
+		for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
+			if v := os.Getenv(ev); v != "" {
+				return filepath.Join(v, base)
+			}
+		}
+		// Worst case:
+		return filepath.Join(homeDir(), base)
+	}
+	if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
+		return filepath.Join(xdg, base)
+	}
+	return filepath.Join(homeDir(), ".cache", base)
+}

+ 141 - 0
src/golang.org/x/crypto/acme/autocert/renewal.go

@@ -0,0 +1,141 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"context"
+	"crypto"
+	"sync"
+	"time"
+)
+
+// renewJitter is the maximum deviation from Manager.RenewBefore.
+const renewJitter = time.Hour
+
+// domainRenewal tracks the state used by the periodic timers
+// renewing a single domain's cert.
+type domainRenewal struct {
+	m   *Manager
+	ck  certKey
+	key crypto.Signer
+
+	timerMu sync.Mutex
+	timer   *time.Timer
+}
+
+// start starts a cert renewal timer at the time
+// defined by the certificate expiration time exp.
+//
+// If the timer is already started, calling start is a noop.
+func (dr *domainRenewal) start(exp time.Time) {
+	dr.timerMu.Lock()
+	defer dr.timerMu.Unlock()
+	if dr.timer != nil {
+		return
+	}
+	dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
+}
+
+// stop stops the cert renewal timer.
+// If the timer is already stopped, calling stop is a noop.
+func (dr *domainRenewal) stop() {
+	dr.timerMu.Lock()
+	defer dr.timerMu.Unlock()
+	if dr.timer == nil {
+		return
+	}
+	dr.timer.Stop()
+	dr.timer = nil
+}
+
+// renew is called periodically by a timer.
+// The first renew call is kicked off by dr.start.
+func (dr *domainRenewal) renew() {
+	dr.timerMu.Lock()
+	defer dr.timerMu.Unlock()
+	if dr.timer == nil {
+		return
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
+	defer cancel()
+	// TODO: rotate dr.key at some point?
+	next, err := dr.do(ctx)
+	if err != nil {
+		next = renewJitter / 2
+		next += time.Duration(pseudoRand.int63n(int64(next)))
+	}
+	dr.timer = time.AfterFunc(next, dr.renew)
+	testDidRenewLoop(next, err)
+}
+
+// updateState locks and replaces the relevant Manager.state item with the given
+// state. It additionally updates dr.key with the given state's key.
+func (dr *domainRenewal) updateState(state *certState) {
+	dr.m.stateMu.Lock()
+	defer dr.m.stateMu.Unlock()
+	dr.key = state.key
+	dr.m.state[dr.ck] = state
+}
+
+// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
+// Instead, it requests a new certificate independently and, upon success,
+// replaces dr.m.state item with a new one and updates cache for the given domain.
+//
+// It may lock and update the Manager.state if the expiration date of the currently
+// cached cert is far enough in the future.
+//
+// The returned value is a time interval after which the renewal should occur again.
+func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
+	// a race is likely unavoidable in a distributed environment
+	// but we try nonetheless
+	if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
+		next := dr.next(tlscert.Leaf.NotAfter)
+		if next > dr.m.renewBefore()+renewJitter {
+			signer, ok := tlscert.PrivateKey.(crypto.Signer)
+			if ok {
+				state := &certState{
+					key:  signer,
+					cert: tlscert.Certificate,
+					leaf: tlscert.Leaf,
+				}
+				dr.updateState(state)
+				return next, nil
+			}
+		}
+	}
+
+	der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
+	if err != nil {
+		return 0, err
+	}
+	state := &certState{
+		key:  dr.key,
+		cert: der,
+		leaf: leaf,
+	}
+	tlscert, err := state.tlscert()
+	if err != nil {
+		return 0, err
+	}
+	if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
+		return 0, err
+	}
+	dr.updateState(state)
+	return dr.next(leaf.NotAfter), nil
+}
+
+func (dr *domainRenewal) next(expiry time.Time) time.Duration {
+	d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
+	// add a bit of randomness to renew deadline
+	n := pseudoRand.int63n(int64(renewJitter))
+	d -= time.Duration(n)
+	if d < 0 {
+		return 0
+	}
+	return d
+}
+
+var testDidRenewLoop = func(next time.Duration, err error) {}

+ 329 - 0
src/golang.org/x/crypto/acme/autocert/renewal_test.go

@@ -0,0 +1,329 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package autocert
+
+import (
+	"context"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/base64"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+	"time"
+
+	"golang.org/x/crypto/acme"
+)
+
+func TestRenewalNext(t *testing.T) {
+	now := time.Now()
+	man := &Manager{
+		RenewBefore: 7 * 24 * time.Hour,
+		nowFunc:     func() time.Time { return now },
+	}
+	defer man.stopRenew()
+	tt := []struct {
+		expiry   time.Time
+		min, max time.Duration
+	}{
+		{now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour},
+		{now.Add(time.Hour), 0, 1},
+		{now, 0, 1},
+		{now.Add(-time.Hour), 0, 1},
+	}
+
+	dr := &domainRenewal{m: man}
+	for i, test := range tt {
+		next := dr.next(test.expiry)
+		if next < test.min || test.max < next {
+			t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max)
+		}
+	}
+}
+
+func TestRenewFromCache(t *testing.T) {
+	// ACME CA server stub
+	var ca *httptest.Server
+	ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Replay-Nonce", "nonce")
+		if r.Method == "HEAD" {
+			// a nonce request
+			return
+		}
+
+		switch r.URL.Path {
+		// discovery
+		case "/":
+			if err := discoTmpl.Execute(w, ca.URL); err != nil {
+				t.Fatalf("discoTmpl: %v", err)
+			}
+		// client key registration
+		case "/new-reg":
+			w.Write([]byte("{}"))
+		// domain authorization
+		case "/new-authz":
+			w.Header().Set("Location", ca.URL+"/authz/1")
+			w.WriteHeader(http.StatusCreated)
+			w.Write([]byte(`{"status": "valid"}`))
+		// cert request
+		case "/new-cert":
+			var req struct {
+				CSR string `json:"csr"`
+			}
+			decodePayload(&req, r.Body)
+			b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
+			csr, err := x509.ParseCertificateRequest(b)
+			if err != nil {
+				t.Fatalf("new-cert: CSR: %v", err)
+			}
+			der, err := dummyCert(csr.PublicKey, exampleDomain)
+			if err != nil {
+				t.Fatalf("new-cert: dummyCert: %v", err)
+			}
+			chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
+			w.Header().Set("Link", chainUp)
+			w.WriteHeader(http.StatusCreated)
+			w.Write(der)
+		// CA chain cert
+		case "/ca-cert":
+			der, err := dummyCert(nil, "ca")
+			if err != nil {
+				t.Fatalf("ca-cert: dummyCert: %v", err)
+			}
+			w.Write(der)
+		default:
+			t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
+		}
+	}))
+	defer ca.Close()
+
+	man := &Manager{
+		Prompt:      AcceptTOS,
+		Cache:       newMemCache(t),
+		RenewBefore: 24 * time.Hour,
+		Client: &acme.Client{
+			DirectoryURL: ca.URL,
+		},
+	}
+	defer man.stopRenew()
+
+	// cache an almost expired cert
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	now := time.Now()
+	cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
+	if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
+		t.Fatal(err)
+	}
+
+	// veriy the renewal happened
+	defer func() {
+		testDidRenewLoop = func(next time.Duration, err error) {}
+	}()
+	done := make(chan struct{})
+	testDidRenewLoop = func(next time.Duration, err error) {
+		defer close(done)
+		if err != nil {
+			t.Errorf("testDidRenewLoop: %v", err)
+		}
+		// Next should be about 90 days:
+		// dummyCert creates 90days expiry + account for man.RenewBefore.
+		// Previous expiration was within 1 min.
+		future := 88 * 24 * time.Hour
+		if next < future {
+			t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
+		}
+
+		// ensure the new cert is cached
+		after := time.Now().Add(future)
+		tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
+		if err != nil {
+			t.Fatalf("man.cacheGet: %v", err)
+		}
+		if !tlscert.Leaf.NotAfter.After(after) {
+			t.Errorf("cache leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
+		}
+
+		// verify the old cert is also replaced in memory
+		man.stateMu.Lock()
+		defer man.stateMu.Unlock()
+		s := man.state[exampleCertKey]
+		if s == nil {
+			t.Fatalf("m.state[%q] is nil", exampleCertKey)
+		}
+		tlscert, err = s.tlscert()
+		if err != nil {
+			t.Fatalf("s.tlscert: %v", err)
+		}
+		if !tlscert.Leaf.NotAfter.After(after) {
+			t.Errorf("state leaf.NotAfter = %v; want > %v", tlscert.Leaf.NotAfter, after)
+		}
+	}
+
+	// trigger renew
+	hello := clientHelloInfo(exampleDomain, true)
+	if _, err := man.GetCertificate(hello); err != nil {
+		t.Fatal(err)
+	}
+
+	// wait for renew loop
+	select {
+	case <-time.After(10 * time.Second):
+		t.Fatal("renew took too long to occur")
+	case <-done:
+	}
+}
+
+func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
+	man := &Manager{
+		Prompt:      AcceptTOS,
+		Cache:       newMemCache(t),
+		RenewBefore: 24 * time.Hour,
+		Client: &acme.Client{
+			DirectoryURL: "invalid",
+		},
+	}
+	defer man.stopRenew()
+
+	// cache a recently renewed cert with a different private key
+	newKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	now := time.Now()
+	newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), exampleDomain)
+	if err != nil {
+		t.Fatal(err)
+	}
+	newLeaf, err := validCert(exampleCertKey, [][]byte{newCert}, newKey, now)
+	if err != nil {
+		t.Fatal(err)
+	}
+	newTLSCert := &tls.Certificate{PrivateKey: newKey, Certificate: [][]byte{newCert}, Leaf: newLeaf}
+	if err := man.cachePut(context.Background(), exampleCertKey, newTLSCert); err != nil {
+		t.Fatal(err)
+	}
+
+	// set internal state to an almost expired cert
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatal(err)
+	}
+	oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
+	if err != nil {
+		t.Fatal(err)
+	}
+	oldLeaf, err := validCert(exampleCertKey, [][]byte{oldCert}, key, now)
+	if err != nil {
+		t.Fatal(err)
+	}
+	man.stateMu.Lock()
+	if man.state == nil {
+		man.state = make(map[certKey]*certState)
+	}
+	s := &certState{
+		key:  key,
+		cert: [][]byte{oldCert},
+		leaf: oldLeaf,
+	}
+	man.state[exampleCertKey] = s
+	man.stateMu.Unlock()
+
+	// veriy the renewal accepted the newer cached cert
+	defer func() {
+		testDidRenewLoop = func(next time.Duration, err error) {}
+	}()
+	done := make(chan struct{})
+	testDidRenewLoop = func(next time.Duration, err error) {
+		defer close(done)
+		if err != nil {
+			t.Errorf("testDidRenewLoop: %v", err)
+		}
+		// Next should be about 90 days
+		// Previous expiration was within 1 min.
+		future := 88 * 24 * time.Hour
+		if next < future {
+			t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
+		}
+
+		// ensure the cached cert was not modified
+		tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
+		if err != nil {
+			t.Fatalf("man.cacheGet: %v", err)
+		}
+		if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) {
+			t.Errorf("cache leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter)
+		}
+
+		// verify the old cert is also replaced in memory
+		man.stateMu.Lock()
+		defer man.stateMu.Unlock()
+		s := man.state[exampleCertKey]
+		if s == nil {
+			t.Fatalf("m.state[%q] is nil", exampleCertKey)
+		}
+		stateKey := s.key.Public().(*ecdsa.PublicKey)
+		if stateKey.X.Cmp(newKey.X) != 0 || stateKey.Y.Cmp(newKey.Y) != 0 {
+			t.Fatalf("state key was not updated from cache x: %v y: %v; want x: %v y: %v", stateKey.X, stateKey.Y, newKey.X, newKey.Y)
+		}
+		tlscert, err = s.tlscert()
+		if err != nil {
+			t.Fatalf("s.tlscert: %v", err)
+		}
+		if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) {
+			t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter)
+		}
+
+		// verify the private key is replaced in the renewal state
+		r := man.renewal[exampleCertKey]
+		if r == nil {
+			t.Fatalf("m.renewal[%q] is nil", exampleCertKey)
+		}
+		renewalKey := r.key.Public().(*ecdsa.PublicKey)
+		if renewalKey.X.Cmp(newKey.X) != 0 || renewalKey.Y.Cmp(newKey.Y) != 0 {
+			t.Fatalf("renewal private key was not updated from cache x: %v y: %v; want x: %v y: %v", renewalKey.X, renewalKey.Y, newKey.X, newKey.Y)
+		}
+
+	}
+
+	// assert the expiring cert is returned from state
+	hello := clientHelloInfo(exampleDomain, true)
+	tlscert, err := man.GetCertificate(hello)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !oldLeaf.NotAfter.Equal(tlscert.Leaf.NotAfter) {
+		t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, oldLeaf.NotAfter)
+	}
+
+	// trigger renew
+	go man.renew(exampleCertKey, s.key, s.leaf.NotAfter)
+
+	// wait for renew loop
+	select {
+	case <-time.After(10 * time.Second):
+		t.Fatal("renew took too long to occur")
+	case <-done:
+		// assert the new cert is returned from state after renew
+		hello := clientHelloInfo(exampleDomain, true)
+		tlscert, err := man.GetCertificate(hello)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !newTLSCert.Leaf.NotAfter.Equal(tlscert.Leaf.NotAfter) {
+			t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newTLSCert.Leaf.NotAfter)
+		}
+	}
+}

+ 281 - 0
src/golang.org/x/crypto/acme/http.go

@@ -0,0 +1,281 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/rand"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"math/big"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// retryTimer encapsulates common logic for retrying unsuccessful requests.
+// It is not safe for concurrent use.
+type retryTimer struct {
+	// backoffFn provides backoff delay sequence for retries.
+	// See Client.RetryBackoff doc comment.
+	backoffFn func(n int, r *http.Request, res *http.Response) time.Duration
+	// n is the current retry attempt.
+	n int
+}
+
+func (t *retryTimer) inc() {
+	t.n++
+}
+
+// backoff pauses the current goroutine as described in Client.RetryBackoff.
+func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error {
+	d := t.backoffFn(t.n, r, res)
+	if d <= 0 {
+		return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n)
+	}
+	wakeup := time.NewTimer(d)
+	defer wakeup.Stop()
+	select {
+	case <-ctx.Done():
+		return ctx.Err()
+	case <-wakeup.C:
+		return nil
+	}
+}
+
+func (c *Client) retryTimer() *retryTimer {
+	f := c.RetryBackoff
+	if f == nil {
+		f = defaultBackoff
+	}
+	return &retryTimer{backoffFn: f}
+}
+
+// defaultBackoff provides default Client.RetryBackoff implementation
+// using a truncated exponential backoff algorithm,
+// as described in Client.RetryBackoff.
+//
+// The n argument is always bounded between 1 and 30.
+// The returned value is always greater than 0.
+func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration {
+	const max = 10 * time.Second
+	var jitter time.Duration
+	if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
+		// Set the minimum to 1ms to avoid a case where
+		// an invalid Retry-After value is parsed into 0 below,
+		// resulting in the 0 returned value which would unintentionally
+		// stop the retries.
+		jitter = (1 + time.Duration(x.Int64())) * time.Millisecond
+	}
+	if v, ok := res.Header["Retry-After"]; ok {
+		return retryAfter(v[0]) + jitter
+	}
+
+	if n < 1 {
+		n = 1
+	}
+	if n > 30 {
+		n = 30
+	}
+	d := time.Duration(1<<uint(n-1))*time.Second + jitter
+	if d > max {
+		return max
+	}
+	return d
+}
+
+// retryAfter parses a Retry-After HTTP header value,
+// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
+// It returns zero value if v cannot be parsed.
+func retryAfter(v string) time.Duration {
+	if i, err := strconv.Atoi(v); err == nil {
+		return time.Duration(i) * time.Second
+	}
+	t, err := http.ParseTime(v)
+	if err != nil {
+		return 0
+	}
+	return t.Sub(timeNow())
+}
+
+// resOkay is a function that reports whether the provided response is okay.
+// It is expected to keep the response body unread.
+type resOkay func(*http.Response) bool
+
+// wantStatus returns a function which reports whether the code
+// matches the status code of a response.
+func wantStatus(codes ...int) resOkay {
+	return func(res *http.Response) bool {
+		for _, code := range codes {
+			if code == res.StatusCode {
+				return true
+			}
+		}
+		return false
+	}
+}
+
+// get issues an unsigned GET request to the specified URL.
+// It returns a non-error value only when ok reports true.
+//
+// get retries unsuccessful attempts according to c.RetryBackoff
+// until the context is done or a non-retriable error is received.
+func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) {
+	retry := c.retryTimer()
+	for {
+		req, err := http.NewRequest("GET", url, nil)
+		if err != nil {
+			return nil, err
+		}
+		res, err := c.doNoRetry(ctx, req)
+		switch {
+		case err != nil:
+			return nil, err
+		case ok(res):
+			return res, nil
+		case isRetriable(res.StatusCode):
+			retry.inc()
+			resErr := responseError(res)
+			res.Body.Close()
+			// Ignore the error value from retry.backoff
+			// and return the one from last retry, as received from the CA.
+			if retry.backoff(ctx, req, res) != nil {
+				return nil, resErr
+			}
+		default:
+			defer res.Body.Close()
+			return nil, responseError(res)
+		}
+	}
+}
+
+// post issues a signed POST request in JWS format using the provided key
+// to the specified URL.
+// It returns a non-error value only when ok reports true.
+//
+// post retries unsuccessful attempts according to c.RetryBackoff
+// until the context is done or a non-retriable error is received.
+// It uses postNoRetry to make individual requests.
+func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) {
+	retry := c.retryTimer()
+	for {
+		res, req, err := c.postNoRetry(ctx, key, url, body)
+		if err != nil {
+			return nil, err
+		}
+		if ok(res) {
+			return res, nil
+		}
+		resErr := responseError(res)
+		res.Body.Close()
+		switch {
+		// Check for bad nonce before isRetriable because it may have been returned
+		// with an unretriable response code such as 400 Bad Request.
+		case isBadNonce(resErr):
+			// Consider any previously stored nonce values to be invalid.
+			c.clearNonces()
+		case !isRetriable(res.StatusCode):
+			return nil, resErr
+		}
+		retry.inc()
+		// Ignore the error value from retry.backoff
+		// and return the one from last retry, as received from the CA.
+		if err := retry.backoff(ctx, req, res); err != nil {
+			return nil, resErr
+		}
+	}
+}
+
+// postNoRetry signs the body with the given key and POSTs it to the provided url.
+// The body argument must be JSON-serializable.
+// It is used by c.post to retry unsuccessful attempts.
+func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) {
+	nonce, err := c.popNonce(ctx, url)
+	if err != nil {
+		return nil, nil, err
+	}
+	b, err := jwsEncodeJSON(body, key, nonce)
+	if err != nil {
+		return nil, nil, err
+	}
+	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
+	if err != nil {
+		return nil, nil, err
+	}
+	req.Header.Set("Content-Type", "application/jose+json")
+	res, err := c.doNoRetry(ctx, req)
+	if err != nil {
+		return nil, nil, err
+	}
+	c.addNonce(res.Header)
+	return res, req, nil
+}
+
+// doNoRetry issues a request req, replacing its context (if any) with ctx.
+func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) {
+	res, err := c.httpClient().Do(req.WithContext(ctx))
+	if err != nil {
+		select {
+		case <-ctx.Done():
+			// Prefer the unadorned context error.
+			// (The acme package had tests assuming this, previously from ctxhttp's
+			// behavior, predating net/http supporting contexts natively)
+			// TODO(bradfitz): reconsider this in the future. But for now this
+			// requires no test updates.
+			return nil, ctx.Err()
+		default:
+			return nil, err
+		}
+	}
+	return res, nil
+}
+
+func (c *Client) httpClient() *http.Client {
+	if c.HTTPClient != nil {
+		return c.HTTPClient
+	}
+	return http.DefaultClient
+}
+
+// isBadNonce reports whether err is an ACME "badnonce" error.
+func isBadNonce(err error) bool {
+	// According to the spec badNonce is urn:ietf:params:acme:error:badNonce.
+	// However, ACME servers in the wild return their versions of the error.
+	// See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
+	// and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66.
+	ae, ok := err.(*Error)
+	return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce")
+}
+
+// isRetriable reports whether a request can be retried
+// based on the response status code.
+//
+// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code.
+// Callers should parse the response and check with isBadNonce.
+func isRetriable(code int) bool {
+	return code <= 399 || code >= 500 || code == http.StatusTooManyRequests
+}
+
+// responseError creates an error of Error type from resp.
+func responseError(resp *http.Response) error {
+	// don't care if ReadAll returns an error:
+	// json.Unmarshal will fail in that case anyway
+	b, _ := ioutil.ReadAll(resp.Body)
+	e := &wireError{Status: resp.StatusCode}
+	if err := json.Unmarshal(b, e); err != nil {
+		// this is not a regular error response:
+		// populate detail with anything we received,
+		// e.Status will already contain HTTP response code value
+		e.Detail = string(b)
+		if e.Detail == "" {
+			e.Detail = resp.Status
+		}
+	}
+	return e.error(resp.Header)
+}

+ 209 - 0
src/golang.org/x/crypto/acme/http_test.go

@@ -0,0 +1,209 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"context"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+)
+
+func TestDefaultBackoff(t *testing.T) {
+	tt := []struct {
+		nretry     int
+		retryAfter string        // Retry-After header
+		out        time.Duration // expected min; max = min + jitter
+	}{
+		{-1, "", time.Second},       // verify the lower bound is 1
+		{0, "", time.Second},        // verify the lower bound is 1
+		{100, "", 10 * time.Second}, // verify the ceiling
+		{1, "3600", time.Hour},      // verify the header value is used
+		{1, "", 1 * time.Second},
+		{2, "", 2 * time.Second},
+		{3, "", 4 * time.Second},
+		{4, "", 8 * time.Second},
+	}
+	for i, test := range tt {
+		r := httptest.NewRequest("GET", "/", nil)
+		resp := &http.Response{Header: http.Header{}}
+		if test.retryAfter != "" {
+			resp.Header.Set("Retry-After", test.retryAfter)
+		}
+		d := defaultBackoff(test.nretry, r, resp)
+		max := test.out + time.Second // + max jitter
+		if d < test.out || max < d {
+			t.Errorf("%d: defaultBackoff(%v) = %v; want between %v and %v", i, test.nretry, d, test.out, max)
+		}
+	}
+}
+
+func TestErrorResponse(t *testing.T) {
+	s := `{
+		"status": 400,
+		"type": "urn:acme:error:xxx",
+		"detail": "text"
+	}`
+	res := &http.Response{
+		StatusCode: 400,
+		Status:     "400 Bad Request",
+		Body:       ioutil.NopCloser(strings.NewReader(s)),
+		Header:     http.Header{"X-Foo": {"bar"}},
+	}
+	err := responseError(res)
+	v, ok := err.(*Error)
+	if !ok {
+		t.Fatalf("err = %+v (%T); want *Error type", err, err)
+	}
+	if v.StatusCode != 400 {
+		t.Errorf("v.StatusCode = %v; want 400", v.StatusCode)
+	}
+	if v.ProblemType != "urn:acme:error:xxx" {
+		t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType)
+	}
+	if v.Detail != "text" {
+		t.Errorf("v.Detail = %q; want text", v.Detail)
+	}
+	if !reflect.DeepEqual(v.Header, res.Header) {
+		t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header)
+	}
+}
+
+func TestPostWithRetries(t *testing.T) {
+	var count int
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		count++
+		w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
+		if r.Method == "HEAD" {
+			// We expect the client to do 2 head requests to fetch
+			// nonces, one to start and another after getting badNonce
+			return
+		}
+
+		head, err := decodeJWSHead(r)
+		switch {
+		case err != nil:
+			t.Errorf("decodeJWSHead: %v", err)
+		case head.Nonce == "":
+			t.Error("head.Nonce is empty")
+		case head.Nonce == "nonce1":
+			// Return a badNonce error to force the call to retry.
+			w.Header().Set("Retry-After", "0")
+			w.WriteHeader(http.StatusBadRequest)
+			w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`))
+			return
+		}
+		// Make client.Authorize happy; we're not testing its result.
+		w.WriteHeader(http.StatusCreated)
+		w.Write([]byte(`{"status":"valid"}`))
+	}))
+	defer ts.Close()
+
+	client := &Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
+	// This call will fail with badNonce, causing a retry
+	if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
+		t.Errorf("client.Authorize 1: %v", err)
+	}
+	if count != 4 {
+		t.Errorf("total requests count: %d; want 4", count)
+	}
+}
+
+func TestRetryErrorType(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Replay-Nonce", "nonce")
+		w.WriteHeader(http.StatusTooManyRequests)
+		w.Write([]byte(`{"type":"rateLimited"}`))
+	}))
+	defer ts.Close()
+
+	client := &Client{
+		Key: testKey,
+		RetryBackoff: func(n int, r *http.Request, res *http.Response) time.Duration {
+			// Do no retries.
+			return 0
+		},
+		dir: &Directory{AuthzURL: ts.URL},
+	}
+
+	t.Run("post", func(t *testing.T) {
+		testRetryErrorType(t, func() error {
+			_, err := client.Authorize(context.Background(), "example.com")
+			return err
+		})
+	})
+	t.Run("get", func(t *testing.T) {
+		testRetryErrorType(t, func() error {
+			_, err := client.GetAuthorization(context.Background(), ts.URL)
+			return err
+		})
+	})
+}
+
+func testRetryErrorType(t *testing.T, callClient func() error) {
+	t.Helper()
+	err := callClient()
+	if err == nil {
+		t.Fatal("client.Authorize returned nil error")
+	}
+	acmeErr, ok := err.(*Error)
+	if !ok {
+		t.Fatalf("err is %v (%T); want *Error", err, err)
+	}
+	if acmeErr.StatusCode != http.StatusTooManyRequests {
+		t.Errorf("acmeErr.StatusCode = %d; want %d", acmeErr.StatusCode, http.StatusTooManyRequests)
+	}
+	if acmeErr.ProblemType != "rateLimited" {
+		t.Errorf("acmeErr.ProblemType = %q; want 'rateLimited'", acmeErr.ProblemType)
+	}
+}
+
+func TestRetryBackoffArgs(t *testing.T) {
+	const resCode = http.StatusInternalServerError
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Replay-Nonce", "test-nonce")
+		w.WriteHeader(resCode)
+	}))
+	defer ts.Close()
+
+	// Canceled in backoff.
+	ctx, cancel := context.WithCancel(context.Background())
+
+	var nretry int
+	backoff := func(n int, r *http.Request, res *http.Response) time.Duration {
+		nretry++
+		if n != nretry {
+			t.Errorf("n = %d; want %d", n, nretry)
+		}
+		if nretry == 3 {
+			cancel()
+		}
+
+		if r == nil {
+			t.Error("r is nil")
+		}
+		if res.StatusCode != resCode {
+			t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, resCode)
+		}
+		return time.Millisecond
+	}
+
+	client := &Client{
+		Key:          testKey,
+		RetryBackoff: backoff,
+		dir:          &Directory{AuthzURL: ts.URL},
+	}
+	if _, err := client.Authorize(ctx, "example.com"); err == nil {
+		t.Error("err is nil")
+	}
+	if nretry != 3 {
+		t.Errorf("nretry = %d; want 3", nretry)
+	}
+}

+ 156 - 0
src/golang.org/x/crypto/acme/jws.go

@@ -0,0 +1,156 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	_ "crypto/sha512" // need for EC keys
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"math/big"
+)
+
+// jwsEncodeJSON signs claimset using provided key and a nonce.
+// The result is serialized in JSON format.
+// See https://tools.ietf.org/html/rfc7515#section-7.
+func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) {
+	jwk, err := jwkEncode(key.Public())
+	if err != nil {
+		return nil, err
+	}
+	alg, sha := jwsHasher(key.Public())
+	if alg == "" || !sha.Available() {
+		return nil, ErrUnsupportedKey
+	}
+	phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce)
+	phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
+	cs, err := json.Marshal(claimset)
+	if err != nil {
+		return nil, err
+	}
+	payload := base64.RawURLEncoding.EncodeToString(cs)
+	hash := sha.New()
+	hash.Write([]byte(phead + "." + payload))
+	sig, err := jwsSign(key, sha, hash.Sum(nil))
+	if err != nil {
+		return nil, err
+	}
+
+	enc := struct {
+		Protected string `json:"protected"`
+		Payload   string `json:"payload"`
+		Sig       string `json:"signature"`
+	}{
+		Protected: phead,
+		Payload:   payload,
+		Sig:       base64.RawURLEncoding.EncodeToString(sig),
+	}
+	return json.Marshal(&enc)
+}
+
+// jwkEncode encodes public part of an RSA or ECDSA key into a JWK.
+// The result is also suitable for creating a JWK thumbprint.
+// https://tools.ietf.org/html/rfc7517
+func jwkEncode(pub crypto.PublicKey) (string, error) {
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		// https://tools.ietf.org/html/rfc7518#section-6.3.1
+		n := pub.N
+		e := big.NewInt(int64(pub.E))
+		// Field order is important.
+		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
+		return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,
+			base64.RawURLEncoding.EncodeToString(e.Bytes()),
+			base64.RawURLEncoding.EncodeToString(n.Bytes()),
+		), nil
+	case *ecdsa.PublicKey:
+		// https://tools.ietf.org/html/rfc7518#section-6.2.1
+		p := pub.Curve.Params()
+		n := p.BitSize / 8
+		if p.BitSize%8 != 0 {
+			n++
+		}
+		x := pub.X.Bytes()
+		if n > len(x) {
+			x = append(make([]byte, n-len(x)), x...)
+		}
+		y := pub.Y.Bytes()
+		if n > len(y) {
+			y = append(make([]byte, n-len(y)), y...)
+		}
+		// Field order is important.
+		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
+		return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`,
+			p.Name,
+			base64.RawURLEncoding.EncodeToString(x),
+			base64.RawURLEncoding.EncodeToString(y),
+		), nil
+	}
+	return "", ErrUnsupportedKey
+}
+
+// jwsSign signs the digest using the given key.
+// The hash is unused for ECDSA keys.
+//
+// Note: non-stdlib crypto.Signer implementations are expected to return
+// the signature in the format as specified in RFC7518.
+// See https://tools.ietf.org/html/rfc7518 for more details.
+func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) {
+	if key, ok := key.(*ecdsa.PrivateKey); ok {
+		// The key.Sign method of ecdsa returns ASN1-encoded signature.
+		// So, we use the package Sign function instead
+		// to get R and S values directly and format the result accordingly.
+		r, s, err := ecdsa.Sign(rand.Reader, key, digest)
+		if err != nil {
+			return nil, err
+		}
+		rb, sb := r.Bytes(), s.Bytes()
+		size := key.Params().BitSize / 8
+		if size%8 > 0 {
+			size++
+		}
+		sig := make([]byte, size*2)
+		copy(sig[size-len(rb):], rb)
+		copy(sig[size*2-len(sb):], sb)
+		return sig, nil
+	}
+	return key.Sign(rand.Reader, digest, hash)
+}
+
+// jwsHasher indicates suitable JWS algorithm name and a hash function
+// to use for signing a digest with the provided key.
+// It returns ("", 0) if the key is not supported.
+func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) {
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		return "RS256", crypto.SHA256
+	case *ecdsa.PublicKey:
+		switch pub.Params().Name {
+		case "P-256":
+			return "ES256", crypto.SHA256
+		case "P-384":
+			return "ES384", crypto.SHA384
+		case "P-521":
+			return "ES512", crypto.SHA512
+		}
+	}
+	return "", 0
+}
+
+// JWKThumbprint creates a JWK thumbprint out of pub
+// as specified in https://tools.ietf.org/html/rfc7638.
+func JWKThumbprint(pub crypto.PublicKey) (string, error) {
+	jwk, err := jwkEncode(pub)
+	if err != nil {
+		return "", err
+	}
+	b := sha256.Sum256([]byte(jwk))
+	return base64.RawURLEncoding.EncodeToString(b[:]), nil
+}

+ 394 - 0
src/golang.org/x/crypto/acme/jws_test.go

@@ -0,0 +1,394 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/json"
+	"encoding/pem"
+	"fmt"
+	"io"
+	"math/big"
+	"testing"
+)
+
+const (
+	testKeyPEM = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
+WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
+Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq
+EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf
+oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy
+KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV
+9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H
+r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm
+ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP
+G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS
+zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6
+9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s
+8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc
+7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL
+qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ
+Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU
+RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o
+JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd
+4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt
+jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q
+YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73
+c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G
+N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7
+EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
+9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx
+-----END RSA PRIVATE KEY-----
+`
+
+	// This thumbprint is for the testKey defined above.
+	testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
+
+	// openssl ecparam -name secp256k1 -genkey -noout
+	testKeyECPEM = `
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIK07hGLr0RwyUdYJ8wbIiBS55CjnkMD23DWr+ccnypWLoAoGCCqGSM49
+AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
+QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
+-----END EC PRIVATE KEY-----
+`
+	// openssl ecparam -name secp384r1 -genkey -noout
+	testKeyEC384PEM = `
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
+Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
+JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
+WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
+-----END EC PRIVATE KEY-----
+`
+	// openssl ecparam -name secp521r1 -genkey -noout
+	testKeyEC512PEM = `
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
+KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
+7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
+FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
+GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
+-----END EC PRIVATE KEY-----
+`
+	// 1. openssl ec -in key.pem -noout -text
+	// 2. remove first byte, 04 (the header); the rest is X and Y
+	// 3. convert each with: echo <val> | xxd -r -p | base64 -w 100 | tr -d '=' | tr '/+' '_-'
+	testKeyECPubX    = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
+	testKeyECPubY    = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
+	testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
+	testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
+	testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
+	testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
+
+	// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
+	// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
+	testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
+)
+
+var (
+	testKey      *rsa.PrivateKey
+	testKeyEC    *ecdsa.PrivateKey
+	testKeyEC384 *ecdsa.PrivateKey
+	testKeyEC512 *ecdsa.PrivateKey
+)
+
+func init() {
+	testKey = parseRSA(testKeyPEM, "testKeyPEM")
+	testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
+	testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
+	testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
+}
+
+func decodePEM(s, name string) []byte {
+	d, _ := pem.Decode([]byte(s))
+	if d == nil {
+		panic("no block found in " + name)
+	}
+	return d.Bytes
+}
+
+func parseRSA(s, name string) *rsa.PrivateKey {
+	b := decodePEM(s, name)
+	k, err := x509.ParsePKCS1PrivateKey(b)
+	if err != nil {
+		panic(fmt.Sprintf("%s: %v", name, err))
+	}
+	return k
+}
+
+func parseEC(s, name string) *ecdsa.PrivateKey {
+	b := decodePEM(s, name)
+	k, err := x509.ParseECPrivateKey(b)
+	if err != nil {
+		panic(fmt.Sprintf("%s: %v", name, err))
+	}
+	return k
+}
+
+func TestJWSEncodeJSON(t *testing.T) {
+	claims := struct{ Msg string }{"Hello JWS"}
+	// JWS signed with testKey and "nonce" as the nonce value
+	// JSON-serialized JWS fields are split for easier testing
+	const (
+		// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
+		protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
+			"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
+			"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
+			"QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
+			"VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
+			"NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
+			"QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
+			"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
+			"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
+			"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
+			"UVEifSwibm9uY2UiOiJub25jZSJ9"
+		// {"Msg":"Hello JWS"}
+		payload   = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
+		signature = "eAGUikStX_UxyiFhxSLMyuyBcIB80GeBkFROCpap2sW3EmkU_ggF" +
+			"knaQzxrTfItICSAXsCLIquZ5BbrSWA_4vdEYrwWtdUj7NqFKjHRa" +
+			"zpLHcoR7r1rEHvkoP1xj49lS5fc3Wjjq8JUhffkhGbWZ8ZVkgPdC" +
+			"4tMBWiQDoth-x8jELP_3LYOB_ScUXi2mETBawLgOT2K8rA0Vbbmx" +
+			"hWNlOWuUf-8hL5YX4IOEwsS8JK_TrTq5Zc9My0zHJmaieqDV0UlP" +
+			"k0onFjPFkGm7MrPSgd0MqRG-4vSAg2O4hDo7rKv4n8POjjXlNQvM" +
+			"9IPLr8qZ7usYBKhEGwX3yq_eicAwBw"
+	)
+
+	b, err := jwsEncodeJSON(claims, testKey, "nonce")
+	if err != nil {
+		t.Fatal(err)
+	}
+	var jws struct{ Protected, Payload, Signature string }
+	if err := json.Unmarshal(b, &jws); err != nil {
+		t.Fatal(err)
+	}
+	if jws.Protected != protected {
+		t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
+	}
+	if jws.Payload != payload {
+		t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
+	}
+	if jws.Signature != signature {
+		t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature)
+	}
+}
+
+func TestJWSEncodeJSONEC(t *testing.T) {
+	tt := []struct {
+		key      *ecdsa.PrivateKey
+		x, y     string
+		alg, crv string
+	}{
+		{testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
+		{testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
+		{testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
+	}
+	for i, test := range tt {
+		claims := struct{ Msg string }{"Hello JWS"}
+		b, err := jwsEncodeJSON(claims, test.key, "nonce")
+		if err != nil {
+			t.Errorf("%d: %v", i, err)
+			continue
+		}
+		var jws struct{ Protected, Payload, Signature string }
+		if err := json.Unmarshal(b, &jws); err != nil {
+			t.Errorf("%d: %v", i, err)
+			continue
+		}
+
+		b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
+		if err != nil {
+			t.Errorf("%d: jws.Protected: %v", i, err)
+		}
+		var head struct {
+			Alg   string
+			Nonce string
+			JWK   struct {
+				Crv string
+				Kty string
+				X   string
+				Y   string
+			} `json:"jwk"`
+		}
+		if err := json.Unmarshal(b, &head); err != nil {
+			t.Errorf("%d: jws.Protected: %v", i, err)
+		}
+		if head.Alg != test.alg {
+			t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
+		}
+		if head.Nonce != "nonce" {
+			t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
+		}
+		if head.JWK.Crv != test.crv {
+			t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
+		}
+		if head.JWK.Kty != "EC" {
+			t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
+		}
+		if head.JWK.X != test.x {
+			t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
+		}
+		if head.JWK.Y != test.y {
+			t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
+		}
+	}
+}
+
+type customTestSigner struct {
+	sig []byte
+	pub crypto.PublicKey
+}
+
+func (s *customTestSigner) Public() crypto.PublicKey { return s.pub }
+func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) {
+	return s.sig, nil
+}
+
+func TestJWSEncodeJSONCustom(t *testing.T) {
+	claims := struct{ Msg string }{"hello"}
+	const (
+		// printf '{"Msg":"hello"}' | base64 | tr -d '=' | tr '/+' '_-'
+		payload = "eyJNc2ciOiJoZWxsbyJ9"
+		// printf 'testsig' | base64 | tr -d '='
+		testsig = "dGVzdHNpZw"
+
+		// printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":<testKeyECPubY>,"y":<testKeyECPubY>,"nonce":"nonce"}' | \
+		// base64 | tr -d '=' | tr '/+' '_-'
+		es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjVsaEV1" +
+			"ZzV4SzR4QkRaMm5BYmF4THRhTGl2ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFH" +
+			"a3YwVGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6Im5vbmNlIn0"
+
+		// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
+		rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
+			"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
+			"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
+			"QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
+			"VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
+			"NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
+			"QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
+			"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
+			"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
+			"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
+			"UVEifSwibm9uY2UiOiJub25jZSJ9"
+	)
+
+	tt := []struct {
+		alg, phead string
+		pub        crypto.PublicKey
+	}{
+		{"RS256", rs256phead, testKey.Public()},
+		{"ES256", es256phead, testKeyEC.Public()},
+	}
+	for _, tc := range tt {
+		tc := tc
+		t.Run(tc.alg, func(t *testing.T) {
+			signer := &customTestSigner{
+				sig: []byte("testsig"),
+				pub: tc.pub,
+			}
+			b, err := jwsEncodeJSON(claims, signer, "nonce")
+			if err != nil {
+				t.Fatal(err)
+			}
+			var j struct{ Protected, Payload, Signature string }
+			if err := json.Unmarshal(b, &j); err != nil {
+				t.Fatal(err)
+			}
+			if j.Protected != tc.phead {
+				t.Errorf("j.Protected = %q\nwant %q", j.Protected, tc.phead)
+			}
+			if j.Payload != payload {
+				t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload)
+			}
+			if j.Signature != testsig {
+				t.Errorf("j.Signature = %q\nwant %q", j.Signature, testsig)
+			}
+		})
+	}
+}
+
+func TestJWKThumbprintRSA(t *testing.T) {
+	// Key example from RFC 7638
+	const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
+		"VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" +
+		"4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" +
+		"W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" +
+		"1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" +
+		"aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
+	const base64E = "AQAB"
+	const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
+
+	b, err := base64.RawURLEncoding.DecodeString(base64N)
+	if err != nil {
+		t.Fatalf("Error parsing example key N: %v", err)
+	}
+	n := new(big.Int).SetBytes(b)
+
+	b, err = base64.RawURLEncoding.DecodeString(base64E)
+	if err != nil {
+		t.Fatalf("Error parsing example key E: %v", err)
+	}
+	e := new(big.Int).SetBytes(b)
+
+	pub := &rsa.PublicKey{N: n, E: int(e.Uint64())}
+	th, err := JWKThumbprint(pub)
+	if err != nil {
+		t.Error(err)
+	}
+	if th != expected {
+		t.Errorf("thumbprint = %q; want %q", th, expected)
+	}
+}
+
+func TestJWKThumbprintEC(t *testing.T) {
+	// Key example from RFC 7520
+	// expected was computed with
+	// echo -n '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \
+	// openssl dgst -binary -sha256 | \
+	// base64 | \
+	// tr -d '=' | tr '/+' '_-'
+	const (
+		base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" +
+			"KqjqvjyekWF-7ytDyRXYgCF5cj0Kt"
+		base64Y = "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUda" +
+			"QkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
+		expected = "dHri3SADZkrush5HU_50AoRhcKFryN-PI6jPBtPL55M"
+	)
+
+	b, err := base64.RawURLEncoding.DecodeString(base64X)
+	if err != nil {
+		t.Fatalf("Error parsing example key X: %v", err)
+	}
+	x := new(big.Int).SetBytes(b)
+
+	b, err = base64.RawURLEncoding.DecodeString(base64Y)
+	if err != nil {
+		t.Fatalf("Error parsing example key Y: %v", err)
+	}
+	y := new(big.Int).SetBytes(b)
+
+	pub := &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y}
+	th, err := JWKThumbprint(pub)
+	if err != nil {
+		t.Error(err)
+	}
+	if th != expected {
+		t.Errorf("thumbprint = %q; want %q", th, expected)
+	}
+}
+
+func TestJWKThumbprintErrUnsupportedKey(t *testing.T) {
+	_, err := JWKThumbprint(struct{}{})
+	if err != ErrUnsupportedKey {
+		t.Errorf("err = %q; want %q", err, ErrUnsupportedKey)
+	}
+}

+ 329 - 0
src/golang.org/x/crypto/acme/types.go

@@ -0,0 +1,329 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"crypto"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+	"time"
+)
+
+// ACME server response statuses used to describe Authorization and Challenge states.
+const (
+	StatusUnknown    = "unknown"
+	StatusPending    = "pending"
+	StatusProcessing = "processing"
+	StatusValid      = "valid"
+	StatusInvalid    = "invalid"
+	StatusRevoked    = "revoked"
+)
+
+// CRLReasonCode identifies the reason for a certificate revocation.
+type CRLReasonCode int
+
+// CRL reason codes as defined in RFC 5280.
+const (
+	CRLReasonUnspecified          CRLReasonCode = 0
+	CRLReasonKeyCompromise        CRLReasonCode = 1
+	CRLReasonCACompromise         CRLReasonCode = 2
+	CRLReasonAffiliationChanged   CRLReasonCode = 3
+	CRLReasonSuperseded           CRLReasonCode = 4
+	CRLReasonCessationOfOperation CRLReasonCode = 5
+	CRLReasonCertificateHold      CRLReasonCode = 6
+	CRLReasonRemoveFromCRL        CRLReasonCode = 8
+	CRLReasonPrivilegeWithdrawn   CRLReasonCode = 9
+	CRLReasonAACompromise         CRLReasonCode = 10
+)
+
+// ErrUnsupportedKey is returned when an unsupported key type is encountered.
+var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
+
+// Error is an ACME error, defined in Problem Details for HTTP APIs doc
+// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
+type Error struct {
+	// StatusCode is The HTTP status code generated by the origin server.
+	StatusCode int
+	// ProblemType is a URI reference that identifies the problem type,
+	// typically in a "urn:acme:error:xxx" form.
+	ProblemType string
+	// Detail is a human-readable explanation specific to this occurrence of the problem.
+	Detail string
+	// Header is the original server error response headers.
+	// It may be nil.
+	Header http.Header
+}
+
+func (e *Error) Error() string {
+	return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
+}
+
+// AuthorizationError indicates that an authorization for an identifier
+// did not succeed.
+// It contains all errors from Challenge items of the failed Authorization.
+type AuthorizationError struct {
+	// URI uniquely identifies the failed Authorization.
+	URI string
+
+	// Identifier is an AuthzID.Value of the failed Authorization.
+	Identifier string
+
+	// Errors is a collection of non-nil error values of Challenge items
+	// of the failed Authorization.
+	Errors []error
+}
+
+func (a *AuthorizationError) Error() string {
+	e := make([]string, len(a.Errors))
+	for i, err := range a.Errors {
+		e[i] = err.Error()
+	}
+	return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
+}
+
+// RateLimit reports whether err represents a rate limit error and
+// any Retry-After duration returned by the server.
+//
+// See the following for more details on rate limiting:
+// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6
+func RateLimit(err error) (time.Duration, bool) {
+	e, ok := err.(*Error)
+	if !ok {
+		return 0, false
+	}
+	// Some CA implementations may return incorrect values.
+	// Use case-insensitive comparison.
+	if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
+		return 0, false
+	}
+	if e.Header == nil {
+		return 0, true
+	}
+	return retryAfter(e.Header.Get("Retry-After")), true
+}
+
+// Account is a user account. It is associated with a private key.
+type Account struct {
+	// URI is the account unique ID, which is also a URL used to retrieve
+	// account data from the CA.
+	URI string
+
+	// Contact is a slice of contact info used during registration.
+	Contact []string
+
+	// The terms user has agreed to.
+	// A value not matching CurrentTerms indicates that the user hasn't agreed
+	// to the actual Terms of Service of the CA.
+	AgreedTerms string
+
+	// Actual terms of a CA.
+	CurrentTerms string
+
+	// Authz is the authorization URL used to initiate a new authz flow.
+	Authz string
+
+	// Authorizations is a URI from which a list of authorizations
+	// granted to this account can be fetched via a GET request.
+	Authorizations string
+
+	// Certificates is a URI from which a list of certificates
+	// issued for this account can be fetched via a GET request.
+	Certificates string
+}
+
+// Directory is ACME server discovery data.
+type Directory struct {
+	// RegURL is an account endpoint URL, allowing for creating new
+	// and modifying existing accounts.
+	RegURL string
+
+	// AuthzURL is used to initiate Identifier Authorization flow.
+	AuthzURL string
+
+	// CertURL is a new certificate issuance endpoint URL.
+	CertURL string
+
+	// RevokeURL is used to initiate a certificate revocation flow.
+	RevokeURL string
+
+	// Term is a URI identifying the current terms of service.
+	Terms string
+
+	// Website is an HTTP or HTTPS URL locating a website
+	// providing more information about the ACME server.
+	Website string
+
+	// CAA consists of lowercase hostname elements, which the ACME server
+	// recognises as referring to itself for the purposes of CAA record validation
+	// as defined in RFC6844.
+	CAA []string
+}
+
+// Challenge encodes a returned CA challenge.
+// Its Error field may be non-nil if the challenge is part of an Authorization
+// with StatusInvalid.
+type Challenge struct {
+	// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
+	Type string
+
+	// URI is where a challenge response can be posted to.
+	URI string
+
+	// Token is a random value that uniquely identifies the challenge.
+	Token string
+
+	// Status identifies the status of this challenge.
+	Status string
+
+	// Error indicates the reason for an authorization failure
+	// when this challenge was used.
+	// The type of a non-nil value is *Error.
+	Error error
+}
+
+// Authorization encodes an authorization response.
+type Authorization struct {
+	// URI uniquely identifies a authorization.
+	URI string
+
+	// Status identifies the status of an authorization.
+	Status string
+
+	// Identifier is what the account is authorized to represent.
+	Identifier AuthzID
+
+	// Challenges that the client needs to fulfill in order to prove possession
+	// of the identifier (for pending authorizations).
+	// For final authorizations, the challenges that were used.
+	Challenges []*Challenge
+
+	// A collection of sets of challenges, each of which would be sufficient
+	// to prove possession of the identifier.
+	// Clients must complete a set of challenges that covers at least one set.
+	// Challenges are identified by their indices in the challenges array.
+	// If this field is empty, the client needs to complete all challenges.
+	Combinations [][]int
+}
+
+// AuthzID is an identifier that an account is authorized to represent.
+type AuthzID struct {
+	Type  string // The type of identifier, e.g. "dns".
+	Value string // The identifier itself, e.g. "example.org".
+}
+
+// wireAuthz is ACME JSON representation of Authorization objects.
+type wireAuthz struct {
+	Status       string
+	Challenges   []wireChallenge
+	Combinations [][]int
+	Identifier   struct {
+		Type  string
+		Value string
+	}
+}
+
+func (z *wireAuthz) authorization(uri string) *Authorization {
+	a := &Authorization{
+		URI:          uri,
+		Status:       z.Status,
+		Identifier:   AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
+		Combinations: z.Combinations, // shallow copy
+		Challenges:   make([]*Challenge, len(z.Challenges)),
+	}
+	for i, v := range z.Challenges {
+		a.Challenges[i] = v.challenge()
+	}
+	return a
+}
+
+func (z *wireAuthz) error(uri string) *AuthorizationError {
+	err := &AuthorizationError{
+		URI:        uri,
+		Identifier: z.Identifier.Value,
+	}
+	for _, raw := range z.Challenges {
+		if raw.Error != nil {
+			err.Errors = append(err.Errors, raw.Error.error(nil))
+		}
+	}
+	return err
+}
+
+// wireChallenge is ACME JSON challenge representation.
+type wireChallenge struct {
+	URI    string `json:"uri"`
+	Type   string
+	Token  string
+	Status string
+	Error  *wireError
+}
+
+func (c *wireChallenge) challenge() *Challenge {
+	v := &Challenge{
+		URI:    c.URI,
+		Type:   c.Type,
+		Token:  c.Token,
+		Status: c.Status,
+	}
+	if v.Status == "" {
+		v.Status = StatusPending
+	}
+	if c.Error != nil {
+		v.Error = c.Error.error(nil)
+	}
+	return v
+}
+
+// wireError is a subset of fields of the Problem Details object
+// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
+type wireError struct {
+	Status int
+	Type   string
+	Detail string
+}
+
+func (e *wireError) error(h http.Header) *Error {
+	return &Error{
+		StatusCode:  e.Status,
+		ProblemType: e.Type,
+		Detail:      e.Detail,
+		Header:      h,
+	}
+}
+
+// CertOption is an optional argument type for the TLS ChallengeCert methods for
+// customizing a temporary certificate for TLS-based challenges.
+type CertOption interface {
+	privateCertOpt()
+}
+
+// WithKey creates an option holding a private/public key pair.
+// The private part signs a certificate, and the public part represents the signee.
+func WithKey(key crypto.Signer) CertOption {
+	return &certOptKey{key}
+}
+
+type certOptKey struct {
+	key crypto.Signer
+}
+
+func (*certOptKey) privateCertOpt() {}
+
+// WithTemplate creates an option for specifying a certificate template.
+// See x509.CreateCertificate for template usage details.
+//
+// In TLS ChallengeCert methods, the template is also used as parent,
+// resulting in a self-signed certificate.
+// The DNSNames field of t is always overwritten for tls-sni challenge certs.
+func WithTemplate(t *x509.Certificate) CertOption {
+	return (*certOptTemplate)(t)
+}
+
+type certOptTemplate x509.Certificate
+
+func (*certOptTemplate) privateCertOpt() {}

+ 63 - 0
src/golang.org/x/crypto/acme/types_test.go

@@ -0,0 +1,63 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+	"errors"
+	"net/http"
+	"testing"
+	"time"
+)
+
+func TestRateLimit(t *testing.T) {
+	now := time.Date(2017, 04, 27, 10, 0, 0, 0, time.UTC)
+	f := timeNow
+	defer func() { timeNow = f }()
+	timeNow = func() time.Time { return now }
+
+	h120, hTime := http.Header{}, http.Header{}
+	h120.Set("Retry-After", "120")
+	hTime.Set("Retry-After", "Tue Apr 27 11:00:00 2017")
+
+	err1 := &Error{
+		ProblemType: "urn:ietf:params:acme:error:nolimit",
+		Header:      h120,
+	}
+	err2 := &Error{
+		ProblemType: "urn:ietf:params:acme:error:rateLimited",
+		Header:      h120,
+	}
+	err3 := &Error{
+		ProblemType: "urn:ietf:params:acme:error:rateLimited",
+		Header:      nil,
+	}
+	err4 := &Error{
+		ProblemType: "urn:ietf:params:acme:error:rateLimited",
+		Header:      hTime,
+	}
+
+	tt := []struct {
+		err error
+		res time.Duration
+		ok  bool
+	}{
+		{nil, 0, false},
+		{errors.New("dummy"), 0, false},
+		{err1, 0, false},
+		{err2, 2 * time.Minute, true},
+		{err3, 0, true},
+		{err4, time.Hour, true},
+	}
+	for i, test := range tt {
+		res, ok := RateLimit(test.err)
+		if ok != test.ok {
+			t.Errorf("%d: RateLimit(%+v): ok = %v; want %v", i, test.err, ok, test.ok)
+			continue
+		}
+		if res != test.res {
+			t.Errorf("%d: RateLimit(%+v) = %v; want %v", i, test.err, res, test.res)
+		}
+	}
+}

+ 285 - 0
src/golang.org/x/crypto/argon2/argon2.go

@@ -0,0 +1,285 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package argon2 implements the key derivation function Argon2.
+// Argon2 was selected as the winner of the Password Hashing Competition and can
+// be used to derive cryptographic keys from passwords.
+//
+// For a detailed specification of Argon2 see [1].
+//
+// If you aren't sure which function you need, use Argon2id (IDKey) and
+// the parameter recommendations for your scenario.
+//
+//
+// Argon2i
+//
+// Argon2i (implemented by Key) is the side-channel resistant version of Argon2.
+// It uses data-independent memory access, which is preferred for password
+// hashing and password-based key derivation. Argon2i requires more passes over
+// memory than Argon2id to protect from trade-off attacks. The recommended
+// parameters (taken from [2]) for non-interactive operations are time=3 and to
+// use the maximum available memory.
+//
+//
+// Argon2id
+//
+// Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining
+// Argon2i and Argon2d. It uses data-independent memory access for the first
+// half of the first iteration over the memory and data-dependent memory access
+// for the rest. Argon2id is side-channel resistant and provides better brute-
+// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
+// parameters for non-interactive operations (taken from [2]) are time=1 and to
+// use the maximum available memory.
+//
+// [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
+// [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3
+package argon2
+
+import (
+	"encoding/binary"
+	"sync"
+
+	"golang.org/x/crypto/blake2b"
+)
+
+// The Argon2 version implemented by this package.
+const Version = 0x13
+
+const (
+	argon2d = iota
+	argon2i
+	argon2id
+)
+
+// Key derives a key from the password, salt, and cost parameters using Argon2i
+// returning a byte slice of length keyLen that can be used as cryptographic
+// key. The CPU cost and parallelism degree must be greater than zero.
+//
+// For example, you can get a derived key for e.g. AES-256 (which needs a
+// 32-byte key) by doing:
+//
+//      key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
+//
+// The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number.
+// If using that amount of memory (32 MB) is not possible in some contexts then
+// the time parameter can be increased to compensate.
+//
+// The time parameter specifies the number of passes over the memory and the
+// memory parameter specifies the size of the memory in KiB. For example
+// memory=32*1024 sets the memory cost to ~32 MB. The number of threads can be
+// adjusted to the number of available CPUs. The cost parameters should be
+// increased as memory latency and CPU parallelism increases. Remember to get a
+// good random salt.
+func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
+	return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
+}
+
+// IDKey derives a key from the password, salt, and cost parameters using
+// Argon2id returning a byte slice of length keyLen that can be used as
+// cryptographic key. The CPU cost and parallelism degree must be greater than
+// zero.
+//
+// For example, you can get a derived key for e.g. AES-256 (which needs a
+// 32-byte key) by doing:
+//
+//      key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
+//
+// The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number.
+// If using that amount of memory (64 MB) is not possible in some contexts then
+// the time parameter can be increased to compensate.
+//
+// The time parameter specifies the number of passes over the memory and the
+// memory parameter specifies the size of the memory in KiB. For example
+// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
+// adjusted to the numbers of available CPUs. The cost parameters should be
+// increased as memory latency and CPU parallelism increases. Remember to get a
+// good random salt.
+func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
+	return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
+}
+
+func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
+	if time < 1 {
+		panic("argon2: number of rounds too small")
+	}
+	if threads < 1 {
+		panic("argon2: parallelism degree too low")
+	}
+	h0 := initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode)
+
+	memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
+	if memory < 2*syncPoints*uint32(threads) {
+		memory = 2 * syncPoints * uint32(threads)
+	}
+	B := initBlocks(&h0, memory, uint32(threads))
+	processBlocks(B, time, memory, uint32(threads), mode)
+	return extractKey(B, memory, uint32(threads), keyLen)
+}
+
+const (
+	blockLength = 128
+	syncPoints  = 4
+)
+
+type block [blockLength]uint64
+
+func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte {
+	var (
+		h0     [blake2b.Size + 8]byte
+		params [24]byte
+		tmp    [4]byte
+	)
+
+	b2, _ := blake2b.New512(nil)
+	binary.LittleEndian.PutUint32(params[0:4], threads)
+	binary.LittleEndian.PutUint32(params[4:8], keyLen)
+	binary.LittleEndian.PutUint32(params[8:12], memory)
+	binary.LittleEndian.PutUint32(params[12:16], time)
+	binary.LittleEndian.PutUint32(params[16:20], uint32(Version))
+	binary.LittleEndian.PutUint32(params[20:24], uint32(mode))
+	b2.Write(params[:])
+	binary.LittleEndian.PutUint32(tmp[:], uint32(len(password)))
+	b2.Write(tmp[:])
+	b2.Write(password)
+	binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt)))
+	b2.Write(tmp[:])
+	b2.Write(salt)
+	binary.LittleEndian.PutUint32(tmp[:], uint32(len(key)))
+	b2.Write(tmp[:])
+	b2.Write(key)
+	binary.LittleEndian.PutUint32(tmp[:], uint32(len(data)))
+	b2.Write(tmp[:])
+	b2.Write(data)
+	b2.Sum(h0[:0])
+	return h0
+}
+
+func initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block {
+	var block0 [1024]byte
+	B := make([]block, memory)
+	for lane := uint32(0); lane < threads; lane++ {
+		j := lane * (memory / threads)
+		binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane)
+
+		binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0)
+		blake2bHash(block0[:], h0[:])
+		for i := range B[j+0] {
+			B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:])
+		}
+
+		binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1)
+		blake2bHash(block0[:], h0[:])
+		for i := range B[j+1] {
+			B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:])
+		}
+	}
+	return B
+}
+
+func processBlocks(B []block, time, memory, threads uint32, mode int) {
+	lanes := memory / threads
+	segments := lanes / syncPoints
+
+	processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) {
+		var addresses, in, zero block
+		if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
+			in[0] = uint64(n)
+			in[1] = uint64(lane)
+			in[2] = uint64(slice)
+			in[3] = uint64(memory)
+			in[4] = uint64(time)
+			in[5] = uint64(mode)
+		}
+
+		index := uint32(0)
+		if n == 0 && slice == 0 {
+			index = 2 // we have already generated the first two blocks
+			if mode == argon2i || mode == argon2id {
+				in[6]++
+				processBlock(&addresses, &in, &zero)
+				processBlock(&addresses, &addresses, &zero)
+			}
+		}
+
+		offset := lane*lanes + slice*segments + index
+		var random uint64
+		for index < segments {
+			prev := offset - 1
+			if index == 0 && slice == 0 {
+				prev += lanes // last block in lane
+			}
+			if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
+				if index%blockLength == 0 {
+					in[6]++
+					processBlock(&addresses, &in, &zero)
+					processBlock(&addresses, &addresses, &zero)
+				}
+				random = addresses[index%blockLength]
+			} else {
+				random = B[prev][0]
+			}
+			newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index)
+			processBlockXOR(&B[offset], &B[prev], &B[newOffset])
+			index, offset = index+1, offset+1
+		}
+		wg.Done()
+	}
+
+	for n := uint32(0); n < time; n++ {
+		for slice := uint32(0); slice < syncPoints; slice++ {
+			var wg sync.WaitGroup
+			for lane := uint32(0); lane < threads; lane++ {
+				wg.Add(1)
+				go processSegment(n, slice, lane, &wg)
+			}
+			wg.Wait()
+		}
+	}
+
+}
+
+func extractKey(B []block, memory, threads, keyLen uint32) []byte {
+	lanes := memory / threads
+	for lane := uint32(0); lane < threads-1; lane++ {
+		for i, v := range B[(lane*lanes)+lanes-1] {
+			B[memory-1][i] ^= v
+		}
+	}
+
+	var block [1024]byte
+	for i, v := range B[memory-1] {
+		binary.LittleEndian.PutUint64(block[i*8:], v)
+	}
+	key := make([]byte, keyLen)
+	blake2bHash(key, block[:])
+	return key
+}
+
+func indexAlpha(rand uint64, lanes, segments, threads, n, slice, lane, index uint32) uint32 {
+	refLane := uint32(rand>>32) % threads
+	if n == 0 && slice == 0 {
+		refLane = lane
+	}
+	m, s := 3*segments, ((slice+1)%syncPoints)*segments
+	if lane == refLane {
+		m += index
+	}
+	if n == 0 {
+		m, s = slice*segments, 0
+		if slice == 0 || lane == refLane {
+			m += index
+		}
+	}
+	if index == 0 || lane == refLane {
+		m--
+	}
+	return phi(rand, uint64(m), uint64(s), refLane, lanes)
+}
+
+func phi(rand, m, s uint64, lane, lanes uint32) uint32 {
+	p := rand & 0xFFFFFFFF
+	p = (p * p) >> 32
+	p = (p * m) >> 32
+	return lane*lanes + uint32((s+m-(p+1))%uint64(lanes))
+}

+ 233 - 0
src/golang.org/x/crypto/argon2/argon2_test.go

@@ -0,0 +1,233 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package argon2
+
+import (
+	"bytes"
+	"encoding/hex"
+	"testing"
+)
+
+var (
+	genKatPassword = []byte{
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	}
+	genKatSalt   = []byte{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}
+	genKatSecret = []byte{0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}
+	genKatAAD    = []byte{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}
+)
+
+func TestArgon2(t *testing.T) {
+	defer func(sse4 bool) { useSSE4 = sse4 }(useSSE4)
+
+	if useSSE4 {
+		t.Log("SSE4.1 version")
+		testArgon2i(t)
+		testArgon2d(t)
+		testArgon2id(t)
+		useSSE4 = false
+	}
+	t.Log("generic version")
+	testArgon2i(t)
+	testArgon2d(t)
+	testArgon2id(t)
+}
+
+func testArgon2d(t *testing.T) {
+	want := []byte{
+		0x51, 0x2b, 0x39, 0x1b, 0x6f, 0x11, 0x62, 0x97,
+		0x53, 0x71, 0xd3, 0x09, 0x19, 0x73, 0x42, 0x94,
+		0xf8, 0x68, 0xe3, 0xbe, 0x39, 0x84, 0xf3, 0xc1,
+		0xa1, 0x3a, 0x4d, 0xb9, 0xfa, 0xbe, 0x4a, 0xcb,
+	}
+	hash := deriveKey(argon2d, genKatPassword, genKatSalt, genKatSecret, genKatAAD, 3, 32, 4, 32)
+	if !bytes.Equal(hash, want) {
+		t.Errorf("derived key does not match - got: %s , want: %s", hex.EncodeToString(hash), hex.EncodeToString(want))
+	}
+}
+
+func testArgon2i(t *testing.T) {
+	want := []byte{
+		0xc8, 0x14, 0xd9, 0xd1, 0xdc, 0x7f, 0x37, 0xaa,
+		0x13, 0xf0, 0xd7, 0x7f, 0x24, 0x94, 0xbd, 0xa1,
+		0xc8, 0xde, 0x6b, 0x01, 0x6d, 0xd3, 0x88, 0xd2,
+		0x99, 0x52, 0xa4, 0xc4, 0x67, 0x2b, 0x6c, 0xe8,
+	}
+	hash := deriveKey(argon2i, genKatPassword, genKatSalt, genKatSecret, genKatAAD, 3, 32, 4, 32)
+	if !bytes.Equal(hash, want) {
+		t.Errorf("derived key does not match - got: %s , want: %s", hex.EncodeToString(hash), hex.EncodeToString(want))
+	}
+}
+
+func testArgon2id(t *testing.T) {
+	want := []byte{
+		0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c,
+		0x08, 0xc0, 0x37, 0xa3, 0x4a, 0x8b, 0x53, 0xc9,
+		0xd0, 0x1e, 0xf0, 0x45, 0x2d, 0x75, 0xb6, 0x5e,
+		0xb5, 0x25, 0x20, 0xe9, 0x6b, 0x01, 0xe6, 0x59,
+	}
+	hash := deriveKey(argon2id, genKatPassword, genKatSalt, genKatSecret, genKatAAD, 3, 32, 4, 32)
+	if !bytes.Equal(hash, want) {
+		t.Errorf("derived key does not match - got: %s , want: %s", hex.EncodeToString(hash), hex.EncodeToString(want))
+	}
+}
+
+func TestVectors(t *testing.T) {
+	password, salt := []byte("password"), []byte("somesalt")
+	for i, v := range testVectors {
+		want, err := hex.DecodeString(v.hash)
+		if err != nil {
+			t.Fatalf("Test %d: failed to decode hash: %v", i, err)
+		}
+		hash := deriveKey(v.mode, password, salt, nil, nil, v.time, v.memory, v.threads, uint32(len(want)))
+		if !bytes.Equal(hash, want) {
+			t.Errorf("Test %d - got: %s want: %s", i, hex.EncodeToString(hash), hex.EncodeToString(want))
+		}
+	}
+}
+
+func benchmarkArgon2(mode int, time, memory uint32, threads uint8, keyLen uint32, b *testing.B) {
+	password := []byte("password")
+	salt := []byte("choosing random salts is hard")
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		deriveKey(mode, password, salt, nil, nil, time, memory, threads, keyLen)
+	}
+}
+
+func BenchmarkArgon2i(b *testing.B) {
+	b.Run(" Time: 3 Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2i, 3, 32*1024, 1, 32, b) })
+	b.Run(" Time: 4 Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2i, 4, 32*1024, 1, 32, b) })
+	b.Run(" Time: 5 Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2i, 5, 32*1024, 1, 32, b) })
+	b.Run(" Time: 3 Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2i, 3, 64*1024, 4, 32, b) })
+	b.Run(" Time: 4 Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2i, 4, 64*1024, 4, 32, b) })
+	b.Run(" Time: 5 Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2i, 5, 64*1024, 4, 32, b) })
+}
+
+func BenchmarkArgon2d(b *testing.B) {
+	b.Run(" Time: 3, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2d, 3, 32*1024, 1, 32, b) })
+	b.Run(" Time: 4, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2d, 4, 32*1024, 1, 32, b) })
+	b.Run(" Time: 5, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2d, 5, 32*1024, 1, 32, b) })
+	b.Run(" Time: 3, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2d, 3, 64*1024, 4, 32, b) })
+	b.Run(" Time: 4, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2d, 4, 64*1024, 4, 32, b) })
+	b.Run(" Time: 5, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2d, 5, 64*1024, 4, 32, b) })
+}
+
+func BenchmarkArgon2id(b *testing.B) {
+	b.Run(" Time: 3, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2id, 3, 32*1024, 1, 32, b) })
+	b.Run(" Time: 4, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2id, 4, 32*1024, 1, 32, b) })
+	b.Run(" Time: 5, Memory: 32 MB, Threads: 1", func(b *testing.B) { benchmarkArgon2(argon2id, 5, 32*1024, 1, 32, b) })
+	b.Run(" Time: 3, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2id, 3, 64*1024, 4, 32, b) })
+	b.Run(" Time: 4, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2id, 4, 64*1024, 4, 32, b) })
+	b.Run(" Time: 5, Memory: 64 MB, Threads: 4", func(b *testing.B) { benchmarkArgon2(argon2id, 5, 64*1024, 4, 32, b) })
+}
+
+// Generated with the CLI of https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
+var testVectors = []struct {
+	mode         int
+	time, memory uint32
+	threads      uint8
+	hash         string
+}{
+	{
+		mode: argon2i, time: 1, memory: 64, threads: 1,
+		hash: "b9c401d1844a67d50eae3967dc28870b22e508092e861a37",
+	},
+	{
+		mode: argon2d, time: 1, memory: 64, threads: 1,
+		hash: "8727405fd07c32c78d64f547f24150d3f2e703a89f981a19",
+	},
+	{
+		mode: argon2id, time: 1, memory: 64, threads: 1,
+		hash: "655ad15eac652dc59f7170a7332bf49b8469be1fdb9c28bb",
+	},
+	{
+		mode: argon2i, time: 2, memory: 64, threads: 1,
+		hash: "8cf3d8f76a6617afe35fac48eb0b7433a9a670ca4a07ed64",
+	},
+	{
+		mode: argon2d, time: 2, memory: 64, threads: 1,
+		hash: "3be9ec79a69b75d3752acb59a1fbb8b295a46529c48fbb75",
+	},
+	{
+		mode: argon2id, time: 2, memory: 64, threads: 1,
+		hash: "068d62b26455936aa6ebe60060b0a65870dbfa3ddf8d41f7",
+	},
+	{
+		mode: argon2i, time: 2, memory: 64, threads: 2,
+		hash: "2089f3e78a799720f80af806553128f29b132cafe40d059f",
+	},
+	{
+		mode: argon2d, time: 2, memory: 64, threads: 2,
+		hash: "68e2462c98b8bc6bb60ec68db418ae2c9ed24fc6748a40e9",
+	},
+	{
+		mode: argon2id, time: 2, memory: 64, threads: 2,
+		hash: "350ac37222f436ccb5c0972f1ebd3bf6b958bf2071841362",
+	},
+	{
+		mode: argon2i, time: 3, memory: 256, threads: 2,
+		hash: "f5bbf5d4c3836af13193053155b73ec7476a6a2eb93fd5e6",
+	},
+	{
+		mode: argon2d, time: 3, memory: 256, threads: 2,
+		hash: "f4f0669218eaf3641f39cc97efb915721102f4b128211ef2",
+	},
+	{
+		mode: argon2id, time: 3, memory: 256, threads: 2,
+		hash: "4668d30ac4187e6878eedeacf0fd83c5a0a30db2cc16ef0b",
+	},
+	{
+		mode: argon2i, time: 4, memory: 4096, threads: 4,
+		hash: "a11f7b7f3f93f02ad4bddb59ab62d121e278369288a0d0e7",
+	},
+	{
+		mode: argon2d, time: 4, memory: 4096, threads: 4,
+		hash: "935598181aa8dc2b720914aa6435ac8d3e3a4210c5b0fb2d",
+	},
+	{
+		mode: argon2id, time: 4, memory: 4096, threads: 4,
+		hash: "145db9733a9f4ee43edf33c509be96b934d505a4efb33c5a",
+	},
+	{
+		mode: argon2i, time: 4, memory: 1024, threads: 8,
+		hash: "0cdd3956aa35e6b475a7b0c63488822f774f15b43f6e6e17",
+	},
+	{
+		mode: argon2d, time: 4, memory: 1024, threads: 8,
+		hash: "83604fc2ad0589b9d055578f4d3cc55bc616df3578a896e9",
+	},
+	{
+		mode: argon2id, time: 4, memory: 1024, threads: 8,
+		hash: "8dafa8e004f8ea96bf7c0f93eecf67a6047476143d15577f",
+	},
+	{
+		mode: argon2i, time: 2, memory: 64, threads: 3,
+		hash: "5cab452fe6b8479c8661def8cd703b611a3905a6d5477fe6",
+	},
+	{
+		mode: argon2d, time: 2, memory: 64, threads: 3,
+		hash: "22474a423bda2ccd36ec9afd5119e5c8949798cadf659f51",
+	},
+	{
+		mode: argon2id, time: 2, memory: 64, threads: 3,
+		hash: "4a15b31aec7c2590b87d1f520be7d96f56658172deaa3079",
+	},
+	{
+		mode: argon2i, time: 3, memory: 1024, threads: 6,
+		hash: "d236b29c2b2a09babee842b0dec6aa1e83ccbdea8023dced",
+	},
+	{
+		mode: argon2d, time: 3, memory: 1024, threads: 6,
+		hash: "a3351b0319a53229152023d9206902f4ef59661cdca89481",
+	},
+	{
+		mode: argon2id, time: 3, memory: 1024, threads: 6,
+		hash: "1640b932f4b60e272f5d2207b9a9c626ffa1bd88d2349016",
+	},
+}

+ 53 - 0
src/golang.org/x/crypto/argon2/blake2b.go

@@ -0,0 +1,53 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package argon2
+
+import (
+	"encoding/binary"
+	"hash"
+
+	"golang.org/x/crypto/blake2b"
+)
+
+// blake2bHash computes an arbitrary long hash value of in
+// and writes the hash to out.
+func blake2bHash(out []byte, in []byte) {
+	var b2 hash.Hash
+	if n := len(out); n < blake2b.Size {
+		b2, _ = blake2b.New(n, nil)
+	} else {
+		b2, _ = blake2b.New512(nil)
+	}
+
+	var buffer [blake2b.Size]byte
+	binary.LittleEndian.PutUint32(buffer[:4], uint32(len(out)))
+	b2.Write(buffer[:4])
+	b2.Write(in)
+
+	if len(out) <= blake2b.Size {
+		b2.Sum(out[:0])
+		return
+	}
+
+	outLen := len(out)
+	b2.Sum(buffer[:0])
+	b2.Reset()
+	copy(out, buffer[:32])
+	out = out[32:]
+	for len(out) > blake2b.Size {
+		b2.Write(buffer[:])
+		b2.Sum(buffer[:0])
+		copy(out, buffer[:32])
+		out = out[32:]
+		b2.Reset()
+	}
+
+	if outLen%blake2b.Size > 0 { // outLen > 64
+		r := ((outLen + 31) / 32) - 2 // ⌈τ /32⌉-2
+		b2, _ = blake2b.New(outLen-32*r, nil)
+	}
+	b2.Write(buffer[:])
+	b2.Sum(out[:0])
+}

+ 60 - 0
src/golang.org/x/crypto/argon2/blamka_amd64.go

@@ -0,0 +1,60 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package argon2
+
+import "golang.org/x/sys/cpu"
+
+func init() {
+	useSSE4 = cpu.X86.HasSSE41
+}
+
+//go:noescape
+func mixBlocksSSE2(out, a, b, c *block)
+
+//go:noescape
+func xorBlocksSSE2(out, a, b, c *block)
+
+//go:noescape
+func blamkaSSE4(b *block)
+
+func processBlockSSE(out, in1, in2 *block, xor bool) {
+	var t block
+	mixBlocksSSE2(&t, in1, in2, &t)
+	if useSSE4 {
+		blamkaSSE4(&t)
+	} else {
+		for i := 0; i < blockLength; i += 16 {
+			blamkaGeneric(
+				&t[i+0], &t[i+1], &t[i+2], &t[i+3],
+				&t[i+4], &t[i+5], &t[i+6], &t[i+7],
+				&t[i+8], &t[i+9], &t[i+10], &t[i+11],
+				&t[i+12], &t[i+13], &t[i+14], &t[i+15],
+			)
+		}
+		for i := 0; i < blockLength/8; i += 2 {
+			blamkaGeneric(
+				&t[i], &t[i+1], &t[16+i], &t[16+i+1],
+				&t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1],
+				&t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1],
+				&t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1],
+			)
+		}
+	}
+	if xor {
+		xorBlocksSSE2(out, in1, in2, &t)
+	} else {
+		mixBlocksSSE2(out, in1, in2, &t)
+	}
+}
+
+func processBlock(out, in1, in2 *block) {
+	processBlockSSE(out, in1, in2, false)
+}
+
+func processBlockXOR(out, in1, in2 *block) {
+	processBlockSSE(out, in1, in2, true)
+}

+ 243 - 0
src/golang.org/x/crypto/argon2/blamka_amd64.s

@@ -0,0 +1,243 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+#include "textflag.h"
+
+DATA ·c40<>+0x00(SB)/8, $0x0201000706050403
+DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
+GLOBL ·c40<>(SB), (NOPTR+RODATA), $16
+
+DATA ·c48<>+0x00(SB)/8, $0x0100070605040302
+DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
+GLOBL ·c48<>(SB), (NOPTR+RODATA), $16
+
+#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \
+	MOVO       v4, t1; \
+	MOVO       v5, v4; \
+	MOVO       t1, v5; \
+	MOVO       v6, t1; \
+	PUNPCKLQDQ v6, t2; \
+	PUNPCKHQDQ v7, v6; \
+	PUNPCKHQDQ t2, v6; \
+	PUNPCKLQDQ v7, t2; \
+	MOVO       t1, v7; \
+	MOVO       v2, t1; \
+	PUNPCKHQDQ t2, v7; \
+	PUNPCKLQDQ v3, t2; \
+	PUNPCKHQDQ t2, v2; \
+	PUNPCKLQDQ t1, t2; \
+	PUNPCKHQDQ t2, v3
+
+#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \
+	MOVO       v4, t1; \
+	MOVO       v5, v4; \
+	MOVO       t1, v5; \
+	MOVO       v2, t1; \
+	PUNPCKLQDQ v2, t2; \
+	PUNPCKHQDQ v3, v2; \
+	PUNPCKHQDQ t2, v2; \
+	PUNPCKLQDQ v3, t2; \
+	MOVO       t1, v3; \
+	MOVO       v6, t1; \
+	PUNPCKHQDQ t2, v3; \
+	PUNPCKLQDQ v7, t2; \
+	PUNPCKHQDQ t2, v6; \
+	PUNPCKLQDQ t1, t2; \
+	PUNPCKHQDQ t2, v7
+
+#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, t0, c40, c48) \
+	MOVO    v0, t0;        \
+	PMULULQ v2, t0;        \
+	PADDQ   v2, v0;        \
+	PADDQ   t0, v0;        \
+	PADDQ   t0, v0;        \
+	PXOR    v0, v6;        \
+	PSHUFD  $0xB1, v6, v6; \
+	MOVO    v4, t0;        \
+	PMULULQ v6, t0;        \
+	PADDQ   v6, v4;        \
+	PADDQ   t0, v4;        \
+	PADDQ   t0, v4;        \
+	PXOR    v4, v2;        \
+	PSHUFB  c40, v2;       \
+	MOVO    v0, t0;        \
+	PMULULQ v2, t0;        \
+	PADDQ   v2, v0;        \
+	PADDQ   t0, v0;        \
+	PADDQ   t0, v0;        \
+	PXOR    v0, v6;        \
+	PSHUFB  c48, v6;       \
+	MOVO    v4, t0;        \
+	PMULULQ v6, t0;        \
+	PADDQ   v6, v4;        \
+	PADDQ   t0, v4;        \
+	PADDQ   t0, v4;        \
+	PXOR    v4, v2;        \
+	MOVO    v2, t0;        \
+	PADDQ   v2, t0;        \
+	PSRLQ   $63, v2;       \
+	PXOR    t0, v2;        \
+	MOVO    v1, t0;        \
+	PMULULQ v3, t0;        \
+	PADDQ   v3, v1;        \
+	PADDQ   t0, v1;        \
+	PADDQ   t0, v1;        \
+	PXOR    v1, v7;        \
+	PSHUFD  $0xB1, v7, v7; \
+	MOVO    v5, t0;        \
+	PMULULQ v7, t0;        \
+	PADDQ   v7, v5;        \
+	PADDQ   t0, v5;        \
+	PADDQ   t0, v5;        \
+	PXOR    v5, v3;        \
+	PSHUFB  c40, v3;       \
+	MOVO    v1, t0;        \
+	PMULULQ v3, t0;        \
+	PADDQ   v3, v1;        \
+	PADDQ   t0, v1;        \
+	PADDQ   t0, v1;        \
+	PXOR    v1, v7;        \
+	PSHUFB  c48, v7;       \
+	MOVO    v5, t0;        \
+	PMULULQ v7, t0;        \
+	PADDQ   v7, v5;        \
+	PADDQ   t0, v5;        \
+	PADDQ   t0, v5;        \
+	PXOR    v5, v3;        \
+	MOVO    v3, t0;        \
+	PADDQ   v3, t0;        \
+	PSRLQ   $63, v3;       \
+	PXOR    t0, v3
+
+#define LOAD_MSG_0(block, off) \
+	MOVOU 8*(off+0)(block), X0;  \
+	MOVOU 8*(off+2)(block), X1;  \
+	MOVOU 8*(off+4)(block), X2;  \
+	MOVOU 8*(off+6)(block), X3;  \
+	MOVOU 8*(off+8)(block), X4;  \
+	MOVOU 8*(off+10)(block), X5; \
+	MOVOU 8*(off+12)(block), X6; \
+	MOVOU 8*(off+14)(block), X7
+
+#define STORE_MSG_0(block, off) \
+	MOVOU X0, 8*(off+0)(block);  \
+	MOVOU X1, 8*(off+2)(block);  \
+	MOVOU X2, 8*(off+4)(block);  \
+	MOVOU X3, 8*(off+6)(block);  \
+	MOVOU X4, 8*(off+8)(block);  \
+	MOVOU X5, 8*(off+10)(block); \
+	MOVOU X6, 8*(off+12)(block); \
+	MOVOU X7, 8*(off+14)(block)
+
+#define LOAD_MSG_1(block, off) \
+	MOVOU 8*off+0*8(block), X0;  \
+	MOVOU 8*off+16*8(block), X1; \
+	MOVOU 8*off+32*8(block), X2; \
+	MOVOU 8*off+48*8(block), X3; \
+	MOVOU 8*off+64*8(block), X4; \
+	MOVOU 8*off+80*8(block), X5; \
+	MOVOU 8*off+96*8(block), X6; \
+	MOVOU 8*off+112*8(block), X7
+
+#define STORE_MSG_1(block, off) \
+	MOVOU X0, 8*off+0*8(block);  \
+	MOVOU X1, 8*off+16*8(block); \
+	MOVOU X2, 8*off+32*8(block); \
+	MOVOU X3, 8*off+48*8(block); \
+	MOVOU X4, 8*off+64*8(block); \
+	MOVOU X5, 8*off+80*8(block); \
+	MOVOU X6, 8*off+96*8(block); \
+	MOVOU X7, 8*off+112*8(block)
+
+#define BLAMKA_ROUND_0(block, off, t0, t1, c40, c48) \
+	LOAD_MSG_0(block, off);                                   \
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \
+	SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1);                  \
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1);              \
+	STORE_MSG_0(block, off)
+
+#define BLAMKA_ROUND_1(block, off, t0, t1, c40, c48) \
+	LOAD_MSG_1(block, off);                                   \
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \
+	SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1);                  \
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48); \
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1);              \
+	STORE_MSG_1(block, off)
+
+// func blamkaSSE4(b *block)
+TEXT ·blamkaSSE4(SB), 4, $0-8
+	MOVQ b+0(FP), AX
+
+	MOVOU ·c40<>(SB), X10
+	MOVOU ·c48<>(SB), X11
+
+	BLAMKA_ROUND_0(AX, 0, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 16, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 32, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 48, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 64, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 80, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 96, X8, X9, X10, X11)
+	BLAMKA_ROUND_0(AX, 112, X8, X9, X10, X11)
+
+	BLAMKA_ROUND_1(AX, 0, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 2, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 4, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 6, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 8, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 10, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 12, X8, X9, X10, X11)
+	BLAMKA_ROUND_1(AX, 14, X8, X9, X10, X11)
+	RET
+
+// func mixBlocksSSE2(out, a, b, c *block)
+TEXT ·mixBlocksSSE2(SB), 4, $0-32
+	MOVQ out+0(FP), DX
+	MOVQ a+8(FP), AX
+	MOVQ b+16(FP), BX
+	MOVQ a+24(FP), CX
+	MOVQ $128, BP
+
+loop:
+	MOVOU 0(AX), X0
+	MOVOU 0(BX), X1
+	MOVOU 0(CX), X2
+	PXOR  X1, X0
+	PXOR  X2, X0
+	MOVOU X0, 0(DX)
+	ADDQ  $16, AX
+	ADDQ  $16, BX
+	ADDQ  $16, CX
+	ADDQ  $16, DX
+	SUBQ  $2, BP
+	JA    loop
+	RET
+
+// func xorBlocksSSE2(out, a, b, c *block)
+TEXT ·xorBlocksSSE2(SB), 4, $0-32
+	MOVQ out+0(FP), DX
+	MOVQ a+8(FP), AX
+	MOVQ b+16(FP), BX
+	MOVQ a+24(FP), CX
+	MOVQ $128, BP
+
+loop:
+	MOVOU 0(AX), X0
+	MOVOU 0(BX), X1
+	MOVOU 0(CX), X2
+	MOVOU 0(DX), X3
+	PXOR  X1, X0
+	PXOR  X2, X0
+	PXOR  X3, X0
+	MOVOU X0, 0(DX)
+	ADDQ  $16, AX
+	ADDQ  $16, BX
+	ADDQ  $16, CX
+	ADDQ  $16, DX
+	SUBQ  $2, BP
+	JA    loop
+	RET

+ 163 - 0
src/golang.org/x/crypto/argon2/blamka_generic.go

@@ -0,0 +1,163 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package argon2
+
+var useSSE4 bool
+
+func processBlockGeneric(out, in1, in2 *block, xor bool) {
+	var t block
+	for i := range t {
+		t[i] = in1[i] ^ in2[i]
+	}
+	for i := 0; i < blockLength; i += 16 {
+		blamkaGeneric(
+			&t[i+0], &t[i+1], &t[i+2], &t[i+3],
+			&t[i+4], &t[i+5], &t[i+6], &t[i+7],
+			&t[i+8], &t[i+9], &t[i+10], &t[i+11],
+			&t[i+12], &t[i+13], &t[i+14], &t[i+15],
+		)
+	}
+	for i := 0; i < blockLength/8; i += 2 {
+		blamkaGeneric(
+			&t[i], &t[i+1], &t[16+i], &t[16+i+1],
+			&t[32+i], &t[32+i+1], &t[48+i], &t[48+i+1],
+			&t[64+i], &t[64+i+1], &t[80+i], &t[80+i+1],
+			&t[96+i], &t[96+i+1], &t[112+i], &t[112+i+1],
+		)
+	}
+	if xor {
+		for i := range t {
+			out[i] ^= in1[i] ^ in2[i] ^ t[i]
+		}
+	} else {
+		for i := range t {
+			out[i] = in1[i] ^ in2[i] ^ t[i]
+		}
+	}
+}
+
+func blamkaGeneric(t00, t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15 *uint64) {
+	v00, v01, v02, v03 := *t00, *t01, *t02, *t03
+	v04, v05, v06, v07 := *t04, *t05, *t06, *t07
+	v08, v09, v10, v11 := *t08, *t09, *t10, *t11
+	v12, v13, v14, v15 := *t12, *t13, *t14, *t15
+
+	v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04))
+	v12 ^= v00
+	v12 = v12>>32 | v12<<32
+	v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12))
+	v04 ^= v08
+	v04 = v04>>24 | v04<<40
+
+	v00 += v04 + 2*uint64(uint32(v00))*uint64(uint32(v04))
+	v12 ^= v00
+	v12 = v12>>16 | v12<<48
+	v08 += v12 + 2*uint64(uint32(v08))*uint64(uint32(v12))
+	v04 ^= v08
+	v04 = v04>>63 | v04<<1
+
+	v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05))
+	v13 ^= v01
+	v13 = v13>>32 | v13<<32
+	v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13))
+	v05 ^= v09
+	v05 = v05>>24 | v05<<40
+
+	v01 += v05 + 2*uint64(uint32(v01))*uint64(uint32(v05))
+	v13 ^= v01
+	v13 = v13>>16 | v13<<48
+	v09 += v13 + 2*uint64(uint32(v09))*uint64(uint32(v13))
+	v05 ^= v09
+	v05 = v05>>63 | v05<<1
+
+	v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06))
+	v14 ^= v02
+	v14 = v14>>32 | v14<<32
+	v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14))
+	v06 ^= v10
+	v06 = v06>>24 | v06<<40
+
+	v02 += v06 + 2*uint64(uint32(v02))*uint64(uint32(v06))
+	v14 ^= v02
+	v14 = v14>>16 | v14<<48
+	v10 += v14 + 2*uint64(uint32(v10))*uint64(uint32(v14))
+	v06 ^= v10
+	v06 = v06>>63 | v06<<1
+
+	v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07))
+	v15 ^= v03
+	v15 = v15>>32 | v15<<32
+	v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15))
+	v07 ^= v11
+	v07 = v07>>24 | v07<<40
+
+	v03 += v07 + 2*uint64(uint32(v03))*uint64(uint32(v07))
+	v15 ^= v03
+	v15 = v15>>16 | v15<<48
+	v11 += v15 + 2*uint64(uint32(v11))*uint64(uint32(v15))
+	v07 ^= v11
+	v07 = v07>>63 | v07<<1
+
+	v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05))
+	v15 ^= v00
+	v15 = v15>>32 | v15<<32
+	v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15))
+	v05 ^= v10
+	v05 = v05>>24 | v05<<40
+
+	v00 += v05 + 2*uint64(uint32(v00))*uint64(uint32(v05))
+	v15 ^= v00
+	v15 = v15>>16 | v15<<48
+	v10 += v15 + 2*uint64(uint32(v10))*uint64(uint32(v15))
+	v05 ^= v10
+	v05 = v05>>63 | v05<<1
+
+	v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06))
+	v12 ^= v01
+	v12 = v12>>32 | v12<<32
+	v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12))
+	v06 ^= v11
+	v06 = v06>>24 | v06<<40
+
+	v01 += v06 + 2*uint64(uint32(v01))*uint64(uint32(v06))
+	v12 ^= v01
+	v12 = v12>>16 | v12<<48
+	v11 += v12 + 2*uint64(uint32(v11))*uint64(uint32(v12))
+	v06 ^= v11
+	v06 = v06>>63 | v06<<1
+
+	v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07))
+	v13 ^= v02
+	v13 = v13>>32 | v13<<32
+	v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13))
+	v07 ^= v08
+	v07 = v07>>24 | v07<<40
+
+	v02 += v07 + 2*uint64(uint32(v02))*uint64(uint32(v07))
+	v13 ^= v02
+	v13 = v13>>16 | v13<<48
+	v08 += v13 + 2*uint64(uint32(v08))*uint64(uint32(v13))
+	v07 ^= v08
+	v07 = v07>>63 | v07<<1
+
+	v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04))
+	v14 ^= v03
+	v14 = v14>>32 | v14<<32
+	v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14))
+	v04 ^= v09
+	v04 = v04>>24 | v04<<40
+
+	v03 += v04 + 2*uint64(uint32(v03))*uint64(uint32(v04))
+	v14 ^= v03
+	v14 = v14>>16 | v14<<48
+	v09 += v14 + 2*uint64(uint32(v09))*uint64(uint32(v14))
+	v04 ^= v09
+	v04 = v04>>63 | v04<<1
+
+	*t00, *t01, *t02, *t03 = v00, v01, v02, v03
+	*t04, *t05, *t06, *t07 = v04, v05, v06, v07
+	*t08, *t09, *t10, *t11 = v08, v09, v10, v11
+	*t12, *t13, *t14, *t15 = v12, v13, v14, v15
+}

+ 15 - 0
src/golang.org/x/crypto/argon2/blamka_ref.go

@@ -0,0 +1,15 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64 appengine gccgo
+
+package argon2
+
+func processBlock(out, in1, in2 *block) {
+	processBlockGeneric(out, in1, in2, false)
+}
+
+func processBlockXOR(out, in1, in2 *block) {
+	processBlockGeneric(out, in1, in2, true)
+}

+ 35 - 0
src/golang.org/x/crypto/bcrypt/base64.go

@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bcrypt
+
+import "encoding/base64"
+
+const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+var bcEncoding = base64.NewEncoding(alphabet)
+
+func base64Encode(src []byte) []byte {
+	n := bcEncoding.EncodedLen(len(src))
+	dst := make([]byte, n)
+	bcEncoding.Encode(dst, src)
+	for dst[n-1] == '=' {
+		n--
+	}
+	return dst[:n]
+}
+
+func base64Decode(src []byte) ([]byte, error) {
+	numOfEquals := 4 - (len(src) % 4)
+	for i := 0; i < numOfEquals; i++ {
+		src = append(src, '=')
+	}
+
+	dst := make([]byte, bcEncoding.DecodedLen(len(src)))
+	n, err := bcEncoding.Decode(dst, src)
+	if err != nil {
+		return nil, err
+	}
+	return dst[:n], nil
+}

+ 295 - 0
src/golang.org/x/crypto/bcrypt/bcrypt.go

@@ -0,0 +1,295 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
+// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
+package bcrypt // import "golang.org/x/crypto/bcrypt"
+
+// The code is a port of Provos and Mazières's C implementation.
+import (
+	"crypto/rand"
+	"crypto/subtle"
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+
+	"golang.org/x/crypto/blowfish"
+)
+
+const (
+	MinCost     int = 4  // the minimum allowable cost as passed in to GenerateFromPassword
+	MaxCost     int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
+	DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
+)
+
+// The error returned from CompareHashAndPassword when a password and hash do
+// not match.
+var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
+
+// The error returned from CompareHashAndPassword when a hash is too short to
+// be a bcrypt hash.
+var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
+
+// The error returned from CompareHashAndPassword when a hash was created with
+// a bcrypt algorithm newer than this implementation.
+type HashVersionTooNewError byte
+
+func (hv HashVersionTooNewError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
+}
+
+// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
+type InvalidHashPrefixError byte
+
+func (ih InvalidHashPrefixError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
+}
+
+type InvalidCostError int
+
+func (ic InvalidCostError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
+}
+
+const (
+	majorVersion       = '2'
+	minorVersion       = 'a'
+	maxSaltSize        = 16
+	maxCryptedHashSize = 23
+	encodedSaltSize    = 22
+	encodedHashSize    = 31
+	minHashSize        = 59
+)
+
+// magicCipherData is an IV for the 64 Blowfish encryption calls in
+// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
+var magicCipherData = []byte{
+	0x4f, 0x72, 0x70, 0x68,
+	0x65, 0x61, 0x6e, 0x42,
+	0x65, 0x68, 0x6f, 0x6c,
+	0x64, 0x65, 0x72, 0x53,
+	0x63, 0x72, 0x79, 0x44,
+	0x6f, 0x75, 0x62, 0x74,
+}
+
+type hashed struct {
+	hash  []byte
+	salt  []byte
+	cost  int // allowed range is MinCost to MaxCost
+	major byte
+	minor byte
+}
+
+// GenerateFromPassword returns the bcrypt hash of the password at the given
+// cost. If the cost given is less than MinCost, the cost will be set to
+// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
+// to compare the returned hashed password with its cleartext version.
+func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
+	p, err := newFromPassword(password, cost)
+	if err != nil {
+		return nil, err
+	}
+	return p.Hash(), nil
+}
+
+// CompareHashAndPassword compares a bcrypt hashed password with its possible
+// plaintext equivalent. Returns nil on success, or an error on failure.
+func CompareHashAndPassword(hashedPassword, password []byte) error {
+	p, err := newFromHash(hashedPassword)
+	if err != nil {
+		return err
+	}
+
+	otherHash, err := bcrypt(password, p.cost, p.salt)
+	if err != nil {
+		return err
+	}
+
+	otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
+	if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
+		return nil
+	}
+
+	return ErrMismatchedHashAndPassword
+}
+
+// Cost returns the hashing cost used to create the given hashed
+// password. When, in the future, the hashing cost of a password system needs
+// to be increased in order to adjust for greater computational power, this
+// function allows one to establish which passwords need to be updated.
+func Cost(hashedPassword []byte) (int, error) {
+	p, err := newFromHash(hashedPassword)
+	if err != nil {
+		return 0, err
+	}
+	return p.cost, nil
+}
+
+func newFromPassword(password []byte, cost int) (*hashed, error) {
+	if cost < MinCost {
+		cost = DefaultCost
+	}
+	p := new(hashed)
+	p.major = majorVersion
+	p.minor = minorVersion
+
+	err := checkCost(cost)
+	if err != nil {
+		return nil, err
+	}
+	p.cost = cost
+
+	unencodedSalt := make([]byte, maxSaltSize)
+	_, err = io.ReadFull(rand.Reader, unencodedSalt)
+	if err != nil {
+		return nil, err
+	}
+
+	p.salt = base64Encode(unencodedSalt)
+	hash, err := bcrypt(password, p.cost, p.salt)
+	if err != nil {
+		return nil, err
+	}
+	p.hash = hash
+	return p, err
+}
+
+func newFromHash(hashedSecret []byte) (*hashed, error) {
+	if len(hashedSecret) < minHashSize {
+		return nil, ErrHashTooShort
+	}
+	p := new(hashed)
+	n, err := p.decodeVersion(hashedSecret)
+	if err != nil {
+		return nil, err
+	}
+	hashedSecret = hashedSecret[n:]
+	n, err = p.decodeCost(hashedSecret)
+	if err != nil {
+		return nil, err
+	}
+	hashedSecret = hashedSecret[n:]
+
+	// The "+2" is here because we'll have to append at most 2 '=' to the salt
+	// when base64 decoding it in expensiveBlowfishSetup().
+	p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
+	copy(p.salt, hashedSecret[:encodedSaltSize])
+
+	hashedSecret = hashedSecret[encodedSaltSize:]
+	p.hash = make([]byte, len(hashedSecret))
+	copy(p.hash, hashedSecret)
+
+	return p, nil
+}
+
+func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
+	cipherData := make([]byte, len(magicCipherData))
+	copy(cipherData, magicCipherData)
+
+	c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
+	if err != nil {
+		return nil, err
+	}
+
+	for i := 0; i < 24; i += 8 {
+		for j := 0; j < 64; j++ {
+			c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
+		}
+	}
+
+	// Bug compatibility with C bcrypt implementations. We only encode 23 of
+	// the 24 bytes encrypted.
+	hsh := base64Encode(cipherData[:maxCryptedHashSize])
+	return hsh, nil
+}
+
+func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
+	csalt, err := base64Decode(salt)
+	if err != nil {
+		return nil, err
+	}
+
+	// Bug compatibility with C bcrypt implementations. They use the trailing
+	// NULL in the key string during expansion.
+	// We copy the key to prevent changing the underlying array.
+	ckey := append(key[:len(key):len(key)], 0)
+
+	c, err := blowfish.NewSaltedCipher(ckey, csalt)
+	if err != nil {
+		return nil, err
+	}
+
+	var i, rounds uint64
+	rounds = 1 << cost
+	for i = 0; i < rounds; i++ {
+		blowfish.ExpandKey(ckey, c)
+		blowfish.ExpandKey(csalt, c)
+	}
+
+	return c, nil
+}
+
+func (p *hashed) Hash() []byte {
+	arr := make([]byte, 60)
+	arr[0] = '$'
+	arr[1] = p.major
+	n := 2
+	if p.minor != 0 {
+		arr[2] = p.minor
+		n = 3
+	}
+	arr[n] = '$'
+	n++
+	copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
+	n += 2
+	arr[n] = '$'
+	n++
+	copy(arr[n:], p.salt)
+	n += encodedSaltSize
+	copy(arr[n:], p.hash)
+	n += encodedHashSize
+	return arr[:n]
+}
+
+func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
+	if sbytes[0] != '$' {
+		return -1, InvalidHashPrefixError(sbytes[0])
+	}
+	if sbytes[1] > majorVersion {
+		return -1, HashVersionTooNewError(sbytes[1])
+	}
+	p.major = sbytes[1]
+	n := 3
+	if sbytes[2] != '$' {
+		p.minor = sbytes[2]
+		n++
+	}
+	return n, nil
+}
+
+// sbytes should begin where decodeVersion left off.
+func (p *hashed) decodeCost(sbytes []byte) (int, error) {
+	cost, err := strconv.Atoi(string(sbytes[0:2]))
+	if err != nil {
+		return -1, err
+	}
+	err = checkCost(cost)
+	if err != nil {
+		return -1, err
+	}
+	p.cost = cost
+	return 3, nil
+}
+
+func (p *hashed) String() string {
+	return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
+}
+
+func checkCost(cost int) error {
+	if cost < MinCost || cost > MaxCost {
+		return InvalidCostError(cost)
+	}
+	return nil
+}

+ 243 - 0
src/golang.org/x/crypto/bcrypt/bcrypt_test.go

@@ -0,0 +1,243 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bcrypt
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+)
+
+func TestBcryptingIsEasy(t *testing.T) {
+	pass := []byte("mypassword")
+	hp, err := GenerateFromPassword(pass, 0)
+	if err != nil {
+		t.Fatalf("GenerateFromPassword error: %s", err)
+	}
+
+	if CompareHashAndPassword(hp, pass) != nil {
+		t.Errorf("%v should hash %s correctly", hp, pass)
+	}
+
+	notPass := "notthepass"
+	err = CompareHashAndPassword(hp, []byte(notPass))
+	if err != ErrMismatchedHashAndPassword {
+		t.Errorf("%v and %s should be mismatched", hp, notPass)
+	}
+}
+
+func TestBcryptingIsCorrect(t *testing.T) {
+	pass := []byte("allmine")
+	salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
+	expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
+
+	hash, err := bcrypt(pass, 10, salt)
+	if err != nil {
+		t.Fatalf("bcrypt blew up: %v", err)
+	}
+	if !bytes.HasSuffix(expectedHash, hash) {
+		t.Errorf("%v should be the suffix of %v", hash, expectedHash)
+	}
+
+	h, err := newFromHash(expectedHash)
+	if err != nil {
+		t.Errorf("Unable to parse %s: %v", string(expectedHash), err)
+	}
+
+	// This is not the safe way to compare these hashes. We do this only for
+	// testing clarity. Use bcrypt.CompareHashAndPassword()
+	if err == nil && !bytes.Equal(expectedHash, h.Hash()) {
+		t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHash)
+	}
+}
+
+func TestVeryShortPasswords(t *testing.T) {
+	key := []byte("k")
+	salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
+	_, err := bcrypt(key, 10, salt)
+	if err != nil {
+		t.Errorf("One byte key resulted in error: %s", err)
+	}
+}
+
+func TestTooLongPasswordsWork(t *testing.T) {
+	salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
+	// One byte over the usual 56 byte limit that blowfish has
+	tooLongPass := []byte("012345678901234567890123456789012345678901234567890123456")
+	tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C")
+	hash, err := bcrypt(tooLongPass, 10, salt)
+	if err != nil {
+		t.Fatalf("bcrypt blew up on long password: %v", err)
+	}
+	if !bytes.HasSuffix(tooLongExpected, hash) {
+		t.Errorf("%v should be the suffix of %v", hash, tooLongExpected)
+	}
+}
+
+type InvalidHashTest struct {
+	err  error
+	hash []byte
+}
+
+var invalidTests = []InvalidHashTest{
+	{ErrHashTooShort, []byte("$2a$10$fooo")},
+	{ErrHashTooShort, []byte("$2a")},
+	{HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
+	{InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
+	{InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
+}
+
+func TestInvalidHashErrors(t *testing.T) {
+	check := func(name string, expected, err error) {
+		if err == nil {
+			t.Errorf("%s: Should have returned an error", name)
+		}
+		if err != nil && err != expected {
+			t.Errorf("%s gave err %v but should have given %v", name, err, expected)
+		}
+	}
+	for _, iht := range invalidTests {
+		_, err := newFromHash(iht.hash)
+		check("newFromHash", iht.err, err)
+		err = CompareHashAndPassword(iht.hash, []byte("anything"))
+		check("CompareHashAndPassword", iht.err, err)
+	}
+}
+
+func TestUnpaddedBase64Encoding(t *testing.T) {
+	original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 32, 30, 109, 243, 30}
+	encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe")
+
+	encoded := base64Encode(original)
+
+	if !bytes.Equal(encodedOriginal, encoded) {
+		t.Errorf("Encoded %v should have equaled %v", encoded, encodedOriginal)
+	}
+
+	decoded, err := base64Decode(encodedOriginal)
+	if err != nil {
+		t.Fatalf("base64Decode blew up: %s", err)
+	}
+
+	if !bytes.Equal(decoded, original) {
+		t.Errorf("Decoded %v should have equaled %v", decoded, original)
+	}
+}
+
+func TestCost(t *testing.T) {
+	suffix := "XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C"
+	for _, vers := range []string{"2a", "2"} {
+		for _, cost := range []int{4, 10} {
+			s := fmt.Sprintf("$%s$%02d$%s", vers, cost, suffix)
+			h := []byte(s)
+			actual, err := Cost(h)
+			if err != nil {
+				t.Errorf("Cost, error: %s", err)
+				continue
+			}
+			if actual != cost {
+				t.Errorf("Cost, expected: %d, actual: %d", cost, actual)
+			}
+		}
+	}
+	_, err := Cost([]byte("$a$a$" + suffix))
+	if err == nil {
+		t.Errorf("Cost, malformed but no error returned")
+	}
+}
+
+func TestCostValidationInHash(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	pass := []byte("mypassword")
+
+	for c := 0; c < MinCost; c++ {
+		p, _ := newFromPassword(pass, c)
+		if p.cost != DefaultCost {
+			t.Errorf("newFromPassword should default costs below %d to %d, but was %d", MinCost, DefaultCost, p.cost)
+		}
+	}
+
+	p, _ := newFromPassword(pass, 14)
+	if p.cost != 14 {
+		t.Errorf("newFromPassword should default cost to 14, but was %d", p.cost)
+	}
+
+	hp, _ := newFromHash(p.Hash())
+	if p.cost != hp.cost {
+		t.Errorf("newFromHash should maintain the cost at %d, but was %d", p.cost, hp.cost)
+	}
+
+	_, err := newFromPassword(pass, 32)
+	if err == nil {
+		t.Fatalf("newFromPassword: should return a cost error")
+	}
+	if err != InvalidCostError(32) {
+		t.Errorf("newFromPassword: should return cost error, got %#v", err)
+	}
+}
+
+func TestCostReturnsWithLeadingZeroes(t *testing.T) {
+	hp, _ := newFromPassword([]byte("abcdefgh"), 7)
+	cost := hp.Hash()[4:7]
+	expected := []byte("07$")
+
+	if !bytes.Equal(expected, cost) {
+		t.Errorf("single digit costs in hash should have leading zeros: was %v instead of %v", cost, expected)
+	}
+}
+
+func TestMinorNotRequired(t *testing.T) {
+	noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
+	h, err := newFromHash(noMinorHash)
+	if err != nil {
+		t.Fatalf("No minor hash blew up: %s", err)
+	}
+	if h.minor != 0 {
+		t.Errorf("Should leave minor version at 0, but was %d", h.minor)
+	}
+
+	if !bytes.Equal(noMinorHash, h.Hash()) {
+		t.Errorf("Should generate hash %v, but created %v", noMinorHash, h.Hash())
+	}
+}
+
+func BenchmarkEqual(b *testing.B) {
+	b.StopTimer()
+	passwd := []byte("somepasswordyoulike")
+	hash, _ := GenerateFromPassword(passwd, DefaultCost)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		CompareHashAndPassword(hash, passwd)
+	}
+}
+
+func BenchmarkDefaultCost(b *testing.B) {
+	b.StopTimer()
+	passwd := []byte("mylongpassword1234")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		GenerateFromPassword(passwd, DefaultCost)
+	}
+}
+
+// See Issue https://github.com/golang/go/issues/20425.
+func TestNoSideEffectsFromCompare(t *testing.T) {
+	source := []byte("passw0rd123456")
+	password := source[:len(source)-6]
+	token := source[len(source)-6:]
+	want := make([]byte, len(source))
+	copy(want, source)
+
+	wantHash := []byte("$2a$10$LK9XRuhNxHHCvjX3tdkRKei1QiCDUKrJRhZv7WWZPuQGRUM92rOUa")
+	_ = CompareHashAndPassword(wantHash, password)
+
+	got := bytes.Join([][]byte{password, token}, []byte(""))
+	if !bytes.Equal(got, want) {
+		t.Errorf("got=%q want=%q", got, want)
+	}
+}

+ 289 - 0
src/golang.org/x/crypto/blake2b/blake2b.go

@@ -0,0 +1,289 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
+// and the extendable output function (XOF) BLAKE2Xb.
+//
+// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
+// and for BLAKE2Xb see https://blake2.net/blake2x.pdf
+//
+// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
+// If you need a secret-key MAC (message authentication code), use the New512
+// function with a non-nil key.
+//
+// BLAKE2X is a construction to compute hash values larger than 64 bytes. It
+// can produce hash values between 0 and 4 GiB.
+package blake2b
+
+import (
+	"encoding/binary"
+	"errors"
+	"hash"
+)
+
+const (
+	// The blocksize of BLAKE2b in bytes.
+	BlockSize = 128
+	// The hash size of BLAKE2b-512 in bytes.
+	Size = 64
+	// The hash size of BLAKE2b-384 in bytes.
+	Size384 = 48
+	// The hash size of BLAKE2b-256 in bytes.
+	Size256 = 32
+)
+
+var (
+	useAVX2 bool
+	useAVX  bool
+	useSSE4 bool
+)
+
+var (
+	errKeySize  = errors.New("blake2b: invalid key size")
+	errHashSize = errors.New("blake2b: invalid hash size")
+)
+
+var iv = [8]uint64{
+	0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
+	0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
+}
+
+// Sum512 returns the BLAKE2b-512 checksum of the data.
+func Sum512(data []byte) [Size]byte {
+	var sum [Size]byte
+	checkSum(&sum, Size, data)
+	return sum
+}
+
+// Sum384 returns the BLAKE2b-384 checksum of the data.
+func Sum384(data []byte) [Size384]byte {
+	var sum [Size]byte
+	var sum384 [Size384]byte
+	checkSum(&sum, Size384, data)
+	copy(sum384[:], sum[:Size384])
+	return sum384
+}
+
+// Sum256 returns the BLAKE2b-256 checksum of the data.
+func Sum256(data []byte) [Size256]byte {
+	var sum [Size]byte
+	var sum256 [Size256]byte
+	checkSum(&sum, Size256, data)
+	copy(sum256[:], sum[:Size256])
+	return sum256
+}
+
+// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
+// key turns the hash into a MAC. The key must between zero and 64 bytes long.
+func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
+
+// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
+// key turns the hash into a MAC. The key must between zero and 64 bytes long.
+func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
+
+// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
+// key turns the hash into a MAC. The key must between zero and 64 bytes long.
+func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
+
+// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
+// A non-nil key turns the hash into a MAC. The key must between zero and 64 bytes long.
+// The hash size can be a value between 1 and 64 but it is highly recommended to use
+// values equal or greater than:
+// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
+// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
+// When the key is nil, the returned hash.Hash implements BinaryMarshaler
+// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
+func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
+
+func newDigest(hashSize int, key []byte) (*digest, error) {
+	if hashSize < 1 || hashSize > Size {
+		return nil, errHashSize
+	}
+	if len(key) > Size {
+		return nil, errKeySize
+	}
+	d := &digest{
+		size:   hashSize,
+		keyLen: len(key),
+	}
+	copy(d.key[:], key)
+	d.Reset()
+	return d, nil
+}
+
+func checkSum(sum *[Size]byte, hashSize int, data []byte) {
+	h := iv
+	h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
+	var c [2]uint64
+
+	if length := len(data); length > BlockSize {
+		n := length &^ (BlockSize - 1)
+		if length == n {
+			n -= BlockSize
+		}
+		hashBlocks(&h, &c, 0, data[:n])
+		data = data[n:]
+	}
+
+	var block [BlockSize]byte
+	offset := copy(block[:], data)
+	remaining := uint64(BlockSize - offset)
+	if c[0] < remaining {
+		c[1]--
+	}
+	c[0] -= remaining
+
+	hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
+
+	for i, v := range h[:(hashSize+7)/8] {
+		binary.LittleEndian.PutUint64(sum[8*i:], v)
+	}
+}
+
+type digest struct {
+	h      [8]uint64
+	c      [2]uint64
+	size   int
+	block  [BlockSize]byte
+	offset int
+
+	key    [BlockSize]byte
+	keyLen int
+}
+
+const (
+	magic         = "b2b"
+	marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+	if d.keyLen != 0 {
+		return nil, errors.New("crypto/blake2b: cannot marshal MACs")
+	}
+	b := make([]byte, 0, marshaledSize)
+	b = append(b, magic...)
+	for i := 0; i < 8; i++ {
+		b = appendUint64(b, d.h[i])
+	}
+	b = appendUint64(b, d.c[0])
+	b = appendUint64(b, d.c[1])
+	// Maximum value for size is 64
+	b = append(b, byte(d.size))
+	b = append(b, d.block[:]...)
+	b = append(b, byte(d.offset))
+	return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
+		return errors.New("crypto/blake2b: invalid hash state identifier")
+	}
+	if len(b) != marshaledSize {
+		return errors.New("crypto/blake2b: invalid hash state size")
+	}
+	b = b[len(magic):]
+	for i := 0; i < 8; i++ {
+		b, d.h[i] = consumeUint64(b)
+	}
+	b, d.c[0] = consumeUint64(b)
+	b, d.c[1] = consumeUint64(b)
+	d.size = int(b[0])
+	b = b[1:]
+	copy(d.block[:], b[:BlockSize])
+	b = b[BlockSize:]
+	d.offset = int(b[0])
+	return nil
+}
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Size() int { return d.size }
+
+func (d *digest) Reset() {
+	d.h = iv
+	d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
+	d.offset, d.c[0], d.c[1] = 0, 0, 0
+	if d.keyLen > 0 {
+		d.block = d.key
+		d.offset = BlockSize
+	}
+}
+
+func (d *digest) Write(p []byte) (n int, err error) {
+	n = len(p)
+
+	if d.offset > 0 {
+		remaining := BlockSize - d.offset
+		if n <= remaining {
+			d.offset += copy(d.block[d.offset:], p)
+			return
+		}
+		copy(d.block[d.offset:], p[:remaining])
+		hashBlocks(&d.h, &d.c, 0, d.block[:])
+		d.offset = 0
+		p = p[remaining:]
+	}
+
+	if length := len(p); length > BlockSize {
+		nn := length &^ (BlockSize - 1)
+		if length == nn {
+			nn -= BlockSize
+		}
+		hashBlocks(&d.h, &d.c, 0, p[:nn])
+		p = p[nn:]
+	}
+
+	if len(p) > 0 {
+		d.offset += copy(d.block[:], p)
+	}
+
+	return
+}
+
+func (d *digest) Sum(sum []byte) []byte {
+	var hash [Size]byte
+	d.finalize(&hash)
+	return append(sum, hash[:d.size]...)
+}
+
+func (d *digest) finalize(hash *[Size]byte) {
+	var block [BlockSize]byte
+	copy(block[:], d.block[:d.offset])
+	remaining := uint64(BlockSize - d.offset)
+
+	c := d.c
+	if c[0] < remaining {
+		c[1]--
+	}
+	c[0] -= remaining
+
+	h := d.h
+	hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
+
+	for i, v := range h {
+		binary.LittleEndian.PutUint64(hash[8*i:], v)
+	}
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+	var a [8]byte
+	binary.BigEndian.PutUint64(a[:], x)
+	return append(b, a[:]...)
+}
+
+func appendUint32(b []byte, x uint32) []byte {
+	var a [4]byte
+	binary.BigEndian.PutUint32(a[:], x)
+	return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+	x := binary.BigEndian.Uint64(b)
+	return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+	x := binary.BigEndian.Uint32(b)
+	return b[4:], x
+}

+ 37 - 0
src/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go

@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+package blake2b
+
+import "golang.org/x/sys/cpu"
+
+func init() {
+	useAVX2 = cpu.X86.HasAVX2
+	useAVX = cpu.X86.HasAVX
+	useSSE4 = cpu.X86.HasSSE41
+}
+
+//go:noescape
+func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+
+//go:noescape
+func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+
+//go:noescape
+func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+
+func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
+	switch {
+	case useAVX2:
+		hashBlocksAVX2(h, c, flag, blocks)
+	case useAVX:
+		hashBlocksAVX(h, c, flag, blocks)
+	case useSSE4:
+		hashBlocksSSE4(h, c, flag, blocks)
+	default:
+		hashBlocksGeneric(h, c, flag, blocks)
+	}
+}

+ 750 - 0
src/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s

@@ -0,0 +1,750 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+#include "textflag.h"
+
+DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
+DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
+DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b
+DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1
+GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32
+
+DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1
+DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
+DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b
+DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179
+GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32
+
+DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403
+DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
+DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403
+DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b
+GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32
+
+DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302
+DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
+DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302
+DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a
+GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32
+
+DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
+DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
+GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16
+
+DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
+DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
+GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16
+
+DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1
+DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
+GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16
+
+DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
+DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
+GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16
+
+DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403
+DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
+GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16
+
+DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302
+DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
+GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
+
+#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39
+#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93
+#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e
+#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93
+#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39
+
+#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
+	VPADDQ  m0, Y0, Y0;   \
+	VPADDQ  Y1, Y0, Y0;   \
+	VPXOR   Y0, Y3, Y3;   \
+	VPSHUFD $-79, Y3, Y3; \
+	VPADDQ  Y3, Y2, Y2;   \
+	VPXOR   Y2, Y1, Y1;   \
+	VPSHUFB c40, Y1, Y1;  \
+	VPADDQ  m1, Y0, Y0;   \
+	VPADDQ  Y1, Y0, Y0;   \
+	VPXOR   Y0, Y3, Y3;   \
+	VPSHUFB c48, Y3, Y3;  \
+	VPADDQ  Y3, Y2, Y2;   \
+	VPXOR   Y2, Y1, Y1;   \
+	VPADDQ  Y1, Y1, t;    \
+	VPSRLQ  $63, Y1, Y1;  \
+	VPXOR   t, Y1, Y1;    \
+	VPERMQ_0x39_Y1_Y1;    \
+	VPERMQ_0x4E_Y2_Y2;    \
+	VPERMQ_0x93_Y3_Y3;    \
+	VPADDQ  m2, Y0, Y0;   \
+	VPADDQ  Y1, Y0, Y0;   \
+	VPXOR   Y0, Y3, Y3;   \
+	VPSHUFD $-79, Y3, Y3; \
+	VPADDQ  Y3, Y2, Y2;   \
+	VPXOR   Y2, Y1, Y1;   \
+	VPSHUFB c40, Y1, Y1;  \
+	VPADDQ  m3, Y0, Y0;   \
+	VPADDQ  Y1, Y0, Y0;   \
+	VPXOR   Y0, Y3, Y3;   \
+	VPSHUFB c48, Y3, Y3;  \
+	VPADDQ  Y3, Y2, Y2;   \
+	VPXOR   Y2, Y1, Y1;   \
+	VPADDQ  Y1, Y1, t;    \
+	VPSRLQ  $63, Y1, Y1;  \
+	VPXOR   t, Y1, Y1;    \
+	VPERMQ_0x39_Y3_Y3;    \
+	VPERMQ_0x4E_Y2_Y2;    \
+	VPERMQ_0x93_Y1_Y1
+
+#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E
+#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26
+#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E
+#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36
+#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E
+
+#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n
+#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n
+#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n
+#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n
+#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n
+
+#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01
+#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01
+#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01
+#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01
+#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01
+
+#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01
+#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01
+#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01
+#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01
+#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01
+
+#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8
+#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01
+
+// load msg: Y12 = (i0, i1, i2, i3)
+// i0, i1, i2, i3 must not be 0
+#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \
+	VMOVQ_SI_X12(i0*8);           \
+	VMOVQ_SI_X11(i2*8);           \
+	VPINSRQ_1_SI_X12(i1*8);       \
+	VPINSRQ_1_SI_X11(i3*8);       \
+	VINSERTI128 $1, X11, Y12, Y12
+
+// load msg: Y13 = (i0, i1, i2, i3)
+// i0, i1, i2, i3 must not be 0
+#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \
+	VMOVQ_SI_X13(i0*8);           \
+	VMOVQ_SI_X11(i2*8);           \
+	VPINSRQ_1_SI_X13(i1*8);       \
+	VPINSRQ_1_SI_X11(i3*8);       \
+	VINSERTI128 $1, X11, Y13, Y13
+
+// load msg: Y14 = (i0, i1, i2, i3)
+// i0, i1, i2, i3 must not be 0
+#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \
+	VMOVQ_SI_X14(i0*8);           \
+	VMOVQ_SI_X11(i2*8);           \
+	VPINSRQ_1_SI_X14(i1*8);       \
+	VPINSRQ_1_SI_X11(i3*8);       \
+	VINSERTI128 $1, X11, Y14, Y14
+
+// load msg: Y15 = (i0, i1, i2, i3)
+// i0, i1, i2, i3 must not be 0
+#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \
+	VMOVQ_SI_X15(i0*8);           \
+	VMOVQ_SI_X11(i2*8);           \
+	VPINSRQ_1_SI_X15(i1*8);       \
+	VPINSRQ_1_SI_X11(i3*8);       \
+	VINSERTI128 $1, X11, Y15, Y15
+
+#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \
+	VMOVQ_SI_X12_0;                   \
+	VMOVQ_SI_X11(4*8);                \
+	VPINSRQ_1_SI_X12(2*8);            \
+	VPINSRQ_1_SI_X11(6*8);            \
+	VINSERTI128 $1, X11, Y12, Y12;    \
+	LOAD_MSG_AVX2_Y13(1, 3, 5, 7);    \
+	LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \
+	LOAD_MSG_AVX2_Y15(9, 11, 13, 15)
+
+#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \
+	LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \
+	LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \
+	VMOVQ_SI_X11(11*8);              \
+	VPSHUFD     $0x4E, 0*8(SI), X14; \
+	VPINSRQ_1_SI_X11(5*8);           \
+	VINSERTI128 $1, X11, Y14, Y14;   \
+	LOAD_MSG_AVX2_Y15(12, 2, 7, 3)
+
+#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \
+	VMOVQ_SI_X11(5*8);              \
+	VMOVDQU     11*8(SI), X12;      \
+	VPINSRQ_1_SI_X11(15*8);         \
+	VINSERTI128 $1, X11, Y12, Y12;  \
+	VMOVQ_SI_X13(8*8);              \
+	VMOVQ_SI_X11(2*8);              \
+	VPINSRQ_1_SI_X13_0;             \
+	VPINSRQ_1_SI_X11(13*8);         \
+	VINSERTI128 $1, X11, Y13, Y13;  \
+	LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \
+	LOAD_MSG_AVX2_Y15(14, 6, 1, 4)
+
+#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \
+	LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \
+	LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \
+	LOAD_MSG_AVX2_Y14(2, 5, 4, 15);  \
+	VMOVQ_SI_X15(6*8);               \
+	VMOVQ_SI_X11_0;                  \
+	VPINSRQ_1_SI_X15(10*8);          \
+	VPINSRQ_1_SI_X11(8*8);           \
+	VINSERTI128 $1, X11, Y15, Y15
+
+#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \
+	LOAD_MSG_AVX2_Y12(9, 5, 2, 10);  \
+	VMOVQ_SI_X13_0;                  \
+	VMOVQ_SI_X11(4*8);               \
+	VPINSRQ_1_SI_X13(7*8);           \
+	VPINSRQ_1_SI_X11(15*8);          \
+	VINSERTI128 $1, X11, Y13, Y13;   \
+	LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \
+	LOAD_MSG_AVX2_Y15(1, 12, 8, 13)
+
+#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \
+	VMOVQ_SI_X12(2*8);                \
+	VMOVQ_SI_X11_0;                   \
+	VPINSRQ_1_SI_X12(6*8);            \
+	VPINSRQ_1_SI_X11(8*8);            \
+	VINSERTI128 $1, X11, Y12, Y12;    \
+	LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \
+	LOAD_MSG_AVX2_Y14(4, 7, 15, 1);   \
+	LOAD_MSG_AVX2_Y15(13, 5, 14, 9)
+
+#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \
+	LOAD_MSG_AVX2_Y12(12, 1, 14, 4);  \
+	LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \
+	VMOVQ_SI_X14_0;                   \
+	VPSHUFD     $0x4E, 8*8(SI), X11;  \
+	VPINSRQ_1_SI_X14(6*8);            \
+	VINSERTI128 $1, X11, Y14, Y14;    \
+	LOAD_MSG_AVX2_Y15(7, 3, 2, 11)
+
+#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \
+	LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \
+	LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \
+	LOAD_MSG_AVX2_Y14(5, 15, 8, 2);  \
+	VMOVQ_SI_X15_0;                  \
+	VMOVQ_SI_X11(6*8);               \
+	VPINSRQ_1_SI_X15(4*8);           \
+	VPINSRQ_1_SI_X11(10*8);          \
+	VINSERTI128 $1, X11, Y15, Y15
+
+#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \
+	VMOVQ_SI_X12(6*8);              \
+	VMOVQ_SI_X11(11*8);             \
+	VPINSRQ_1_SI_X12(14*8);         \
+	VPINSRQ_1_SI_X11_0;             \
+	VINSERTI128 $1, X11, Y12, Y12;  \
+	LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \
+	VMOVQ_SI_X11(1*8);              \
+	VMOVDQU     12*8(SI), X14;      \
+	VPINSRQ_1_SI_X11(10*8);         \
+	VINSERTI128 $1, X11, Y14, Y14;  \
+	VMOVQ_SI_X15(2*8);              \
+	VMOVDQU     4*8(SI), X11;       \
+	VPINSRQ_1_SI_X15(7*8);          \
+	VINSERTI128 $1, X11, Y15, Y15
+
+#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \
+	LOAD_MSG_AVX2_Y12(10, 8, 7, 1);  \
+	VMOVQ_SI_X13(2*8);               \
+	VPSHUFD     $0x4E, 5*8(SI), X11; \
+	VPINSRQ_1_SI_X13(4*8);           \
+	VINSERTI128 $1, X11, Y13, Y13;   \
+	LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \
+	VMOVQ_SI_X15(11*8);              \
+	VMOVQ_SI_X11(12*8);              \
+	VPINSRQ_1_SI_X15(14*8);          \
+	VPINSRQ_1_SI_X11_0;              \
+	VINSERTI128 $1, X11, Y15, Y15
+
+// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment
+	MOVQ h+0(FP), AX
+	MOVQ c+8(FP), BX
+	MOVQ flag+16(FP), CX
+	MOVQ blocks_base+24(FP), SI
+	MOVQ blocks_len+32(FP), DI
+
+	MOVQ SP, DX
+	MOVQ SP, R9
+	ADDQ $31, R9
+	ANDQ $~31, R9
+	MOVQ R9, SP
+
+	MOVQ CX, 16(SP)
+	XORQ CX, CX
+	MOVQ CX, 24(SP)
+
+	VMOVDQU ·AVX2_c40<>(SB), Y4
+	VMOVDQU ·AVX2_c48<>(SB), Y5
+
+	VMOVDQU 0(AX), Y8
+	VMOVDQU 32(AX), Y9
+	VMOVDQU ·AVX2_iv0<>(SB), Y6
+	VMOVDQU ·AVX2_iv1<>(SB), Y7
+
+	MOVQ 0(BX), R8
+	MOVQ 8(BX), R9
+	MOVQ R9, 8(SP)
+
+loop:
+	ADDQ $128, R8
+	MOVQ R8, 0(SP)
+	CMPQ R8, $128
+	JGE  noinc
+	INCQ R9
+	MOVQ R9, 8(SP)
+
+noinc:
+	VMOVDQA Y8, Y0
+	VMOVDQA Y9, Y1
+	VMOVDQA Y6, Y2
+	VPXOR   0(SP), Y7, Y3
+
+	LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15()
+	VMOVDQA Y12, 32(SP)
+	VMOVDQA Y13, 64(SP)
+	VMOVDQA Y14, 96(SP)
+	VMOVDQA Y15, 128(SP)
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3()
+	VMOVDQA Y12, 160(SP)
+	VMOVDQA Y13, 192(SP)
+	VMOVDQA Y14, 224(SP)
+	VMOVDQA Y15, 256(SP)
+
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+	LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0()
+	ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
+
+	ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5)
+	ROUND_AVX2(160(SP), 192(SP), 224(SP), 256(SP), Y10, Y4, Y5)
+
+	VPXOR Y0, Y8, Y8
+	VPXOR Y1, Y9, Y9
+	VPXOR Y2, Y8, Y8
+	VPXOR Y3, Y9, Y9
+
+	LEAQ 128(SI), SI
+	SUBQ $128, DI
+	JNE  loop
+
+	MOVQ R8, 0(BX)
+	MOVQ R9, 8(BX)
+
+	VMOVDQU Y8, 0(AX)
+	VMOVDQU Y9, 32(AX)
+	VZEROUPPER
+
+	MOVQ DX, SP
+	RET
+
+#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA
+#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB
+#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF
+#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD
+#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE
+
+#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7
+#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF
+#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7
+#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF
+#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7
+#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7
+#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF
+#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF
+
+#define SHUFFLE_AVX() \
+	VMOVDQA X6, X13;         \
+	VMOVDQA X2, X14;         \
+	VMOVDQA X4, X6;          \
+	VPUNPCKLQDQ_X13_X13_X15; \
+	VMOVDQA X5, X4;          \
+	VMOVDQA X6, X5;          \
+	VPUNPCKHQDQ_X15_X7_X6;   \
+	VPUNPCKLQDQ_X7_X7_X15;   \
+	VPUNPCKHQDQ_X15_X13_X7;  \
+	VPUNPCKLQDQ_X3_X3_X15;   \
+	VPUNPCKHQDQ_X15_X2_X2;   \
+	VPUNPCKLQDQ_X14_X14_X15; \
+	VPUNPCKHQDQ_X15_X3_X3;   \
+
+#define SHUFFLE_AVX_INV() \
+	VMOVDQA X2, X13;         \
+	VMOVDQA X4, X14;         \
+	VPUNPCKLQDQ_X2_X2_X15;   \
+	VMOVDQA X5, X4;          \
+	VPUNPCKHQDQ_X15_X3_X2;   \
+	VMOVDQA X14, X5;         \
+	VPUNPCKLQDQ_X3_X3_X15;   \
+	VMOVDQA X6, X14;         \
+	VPUNPCKHQDQ_X15_X13_X3;  \
+	VPUNPCKLQDQ_X7_X7_X15;   \
+	VPUNPCKHQDQ_X15_X6_X6;   \
+	VPUNPCKLQDQ_X14_X14_X15; \
+	VPUNPCKHQDQ_X15_X7_X7;   \
+
+#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
+	VPADDQ  m0, v0, v0;   \
+	VPADDQ  v2, v0, v0;   \
+	VPADDQ  m1, v1, v1;   \
+	VPADDQ  v3, v1, v1;   \
+	VPXOR   v0, v6, v6;   \
+	VPXOR   v1, v7, v7;   \
+	VPSHUFD $-79, v6, v6; \
+	VPSHUFD $-79, v7, v7; \
+	VPADDQ  v6, v4, v4;   \
+	VPADDQ  v7, v5, v5;   \
+	VPXOR   v4, v2, v2;   \
+	VPXOR   v5, v3, v3;   \
+	VPSHUFB c40, v2, v2;  \
+	VPSHUFB c40, v3, v3;  \
+	VPADDQ  m2, v0, v0;   \
+	VPADDQ  v2, v0, v0;   \
+	VPADDQ  m3, v1, v1;   \
+	VPADDQ  v3, v1, v1;   \
+	VPXOR   v0, v6, v6;   \
+	VPXOR   v1, v7, v7;   \
+	VPSHUFB c48, v6, v6;  \
+	VPSHUFB c48, v7, v7;  \
+	VPADDQ  v6, v4, v4;   \
+	VPADDQ  v7, v5, v5;   \
+	VPXOR   v4, v2, v2;   \
+	VPXOR   v5, v3, v3;   \
+	VPADDQ  v2, v2, t0;   \
+	VPSRLQ  $63, v2, v2;  \
+	VPXOR   t0, v2, v2;   \
+	VPADDQ  v3, v3, t0;   \
+	VPSRLQ  $63, v3, v3;  \
+	VPXOR   t0, v3, v3
+
+// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7)
+// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0
+#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \
+	VMOVQ_SI_X12(i0*8);     \
+	VMOVQ_SI_X13(i2*8);     \
+	VMOVQ_SI_X14(i4*8);     \
+	VMOVQ_SI_X15(i6*8);     \
+	VPINSRQ_1_SI_X12(i1*8); \
+	VPINSRQ_1_SI_X13(i3*8); \
+	VPINSRQ_1_SI_X14(i5*8); \
+	VPINSRQ_1_SI_X15(i7*8)
+
+// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7)
+#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \
+	VMOVQ_SI_X12_0;        \
+	VMOVQ_SI_X13(4*8);     \
+	VMOVQ_SI_X14(1*8);     \
+	VMOVQ_SI_X15(5*8);     \
+	VPINSRQ_1_SI_X12(2*8); \
+	VPINSRQ_1_SI_X13(6*8); \
+	VPINSRQ_1_SI_X14(3*8); \
+	VPINSRQ_1_SI_X15(7*8)
+
+// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3)
+#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \
+	VPSHUFD $0x4E, 0*8(SI), X12; \
+	VMOVQ_SI_X13(11*8);          \
+	VMOVQ_SI_X14(12*8);          \
+	VMOVQ_SI_X15(7*8);           \
+	VPINSRQ_1_SI_X13(5*8);       \
+	VPINSRQ_1_SI_X14(2*8);       \
+	VPINSRQ_1_SI_X15(3*8)
+
+// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13)
+#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \
+	VMOVDQU 11*8(SI), X12;  \
+	VMOVQ_SI_X13(5*8);      \
+	VMOVQ_SI_X14(8*8);      \
+	VMOVQ_SI_X15(2*8);      \
+	VPINSRQ_1_SI_X13(15*8); \
+	VPINSRQ_1_SI_X14_0;     \
+	VPINSRQ_1_SI_X15(13*8)
+
+// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8)
+#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \
+	VMOVQ_SI_X12(2*8);      \
+	VMOVQ_SI_X13(4*8);      \
+	VMOVQ_SI_X14(6*8);      \
+	VMOVQ_SI_X15_0;         \
+	VPINSRQ_1_SI_X12(5*8);  \
+	VPINSRQ_1_SI_X13(15*8); \
+	VPINSRQ_1_SI_X14(10*8); \
+	VPINSRQ_1_SI_X15(8*8)
+
+// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15)
+#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \
+	VMOVQ_SI_X12(9*8);      \
+	VMOVQ_SI_X13(2*8);      \
+	VMOVQ_SI_X14_0;         \
+	VMOVQ_SI_X15(4*8);      \
+	VPINSRQ_1_SI_X12(5*8);  \
+	VPINSRQ_1_SI_X13(10*8); \
+	VPINSRQ_1_SI_X14(7*8);  \
+	VPINSRQ_1_SI_X15(15*8)
+
+// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3)
+#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \
+	VMOVQ_SI_X12(2*8);      \
+	VMOVQ_SI_X13_0;         \
+	VMOVQ_SI_X14(12*8);     \
+	VMOVQ_SI_X15(11*8);     \
+	VPINSRQ_1_SI_X12(6*8);  \
+	VPINSRQ_1_SI_X13(8*8);  \
+	VPINSRQ_1_SI_X14(10*8); \
+	VPINSRQ_1_SI_X15(3*8)
+
+// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11)
+#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \
+	MOVQ    0*8(SI), X12;        \
+	VPSHUFD $0x4E, 8*8(SI), X13; \
+	MOVQ    7*8(SI), X14;        \
+	MOVQ    2*8(SI), X15;        \
+	VPINSRQ_1_SI_X12(6*8);       \
+	VPINSRQ_1_SI_X14(3*8);       \
+	VPINSRQ_1_SI_X15(11*8)
+
+// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8)
+#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \
+	MOVQ 6*8(SI), X12;      \
+	MOVQ 11*8(SI), X13;     \
+	MOVQ 15*8(SI), X14;     \
+	MOVQ 3*8(SI), X15;      \
+	VPINSRQ_1_SI_X12(14*8); \
+	VPINSRQ_1_SI_X13_0;     \
+	VPINSRQ_1_SI_X14(9*8);  \
+	VPINSRQ_1_SI_X15(8*8)
+
+// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10)
+#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \
+	MOVQ 5*8(SI), X12;      \
+	MOVQ 8*8(SI), X13;      \
+	MOVQ 0*8(SI), X14;      \
+	MOVQ 6*8(SI), X15;      \
+	VPINSRQ_1_SI_X12(15*8); \
+	VPINSRQ_1_SI_X13(2*8);  \
+	VPINSRQ_1_SI_X14(4*8);  \
+	VPINSRQ_1_SI_X15(10*8)
+
+// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5)
+#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \
+	VMOVDQU 12*8(SI), X12;  \
+	MOVQ    1*8(SI), X13;   \
+	MOVQ    2*8(SI), X14;   \
+	VPINSRQ_1_SI_X13(10*8); \
+	VPINSRQ_1_SI_X14(7*8);  \
+	VMOVDQU 4*8(SI), X15
+
+// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0)
+#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \
+	MOVQ 15*8(SI), X12;     \
+	MOVQ 3*8(SI), X13;      \
+	MOVQ 11*8(SI), X14;     \
+	MOVQ 12*8(SI), X15;     \
+	VPINSRQ_1_SI_X12(9*8);  \
+	VPINSRQ_1_SI_X13(13*8); \
+	VPINSRQ_1_SI_X14(14*8); \
+	VPINSRQ_1_SI_X15_0
+
+// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
+	MOVQ h+0(FP), AX
+	MOVQ c+8(FP), BX
+	MOVQ flag+16(FP), CX
+	MOVQ blocks_base+24(FP), SI
+	MOVQ blocks_len+32(FP), DI
+
+	MOVQ SP, BP
+	MOVQ SP, R9
+	ADDQ $15, R9
+	ANDQ $~15, R9
+	MOVQ R9, SP
+
+	VMOVDQU ·AVX_c40<>(SB), X0
+	VMOVDQU ·AVX_c48<>(SB), X1
+	VMOVDQA X0, X8
+	VMOVDQA X1, X9
+
+	VMOVDQU ·AVX_iv3<>(SB), X0
+	VMOVDQA X0, 0(SP)
+	XORQ    CX, 0(SP)          // 0(SP) = ·AVX_iv3 ^ (CX || 0)
+
+	VMOVDQU 0(AX), X10
+	VMOVDQU 16(AX), X11
+	VMOVDQU 32(AX), X2
+	VMOVDQU 48(AX), X3
+
+	MOVQ 0(BX), R8
+	MOVQ 8(BX), R9
+
+loop:
+	ADDQ $128, R8
+	CMPQ R8, $128
+	JGE  noinc
+	INCQ R9
+
+noinc:
+	VMOVQ_R8_X15
+	VPINSRQ_1_R9_X15
+
+	VMOVDQA X10, X0
+	VMOVDQA X11, X1
+	VMOVDQU ·AVX_iv0<>(SB), X4
+	VMOVDQU ·AVX_iv1<>(SB), X5
+	VMOVDQU ·AVX_iv2<>(SB), X6
+
+	VPXOR   X15, X6, X6
+	VMOVDQA 0(SP), X7
+
+	LOAD_MSG_AVX_0_2_4_6_1_3_5_7()
+	VMOVDQA X12, 16(SP)
+	VMOVDQA X13, 32(SP)
+	VMOVDQA X14, 48(SP)
+	VMOVDQA X15, 64(SP)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15)
+	VMOVDQA X12, 80(SP)
+	VMOVDQA X13, 96(SP)
+	VMOVDQA X14, 112(SP)
+	VMOVDQA X15, 128(SP)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6)
+	VMOVDQA X12, 144(SP)
+	VMOVDQA X13, 160(SP)
+	VMOVDQA X14, 176(SP)
+	VMOVDQA X15, 192(SP)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX_1_0_11_5_12_2_7_3()
+	VMOVDQA X12, 208(SP)
+	VMOVDQA X13, 224(SP)
+	VMOVDQA X14, 240(SP)
+	VMOVDQA X15, 256(SP)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX_11_12_5_15_8_0_2_13()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX_2_5_4_15_6_10_0_8()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX_9_5_2_10_0_7_4_15()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX_2_6_0_8_12_10_11_3()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX_0_6_9_8_7_3_2_11()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX_5_15_8_2_0_4_6_10()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX_6_14_11_0_15_9_3_8()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX_12_13_1_10_2_7_4_5()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5)
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX()
+	LOAD_MSG_AVX_15_9_3_13_11_14_12_0()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9)
+	SHUFFLE_AVX()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9)
+	SHUFFLE_AVX()
+	HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9)
+	SHUFFLE_AVX_INV()
+
+	VMOVDQU 32(AX), X14
+	VMOVDQU 48(AX), X15
+	VPXOR   X0, X10, X10
+	VPXOR   X1, X11, X11
+	VPXOR   X2, X14, X14
+	VPXOR   X3, X15, X15
+	VPXOR   X4, X10, X10
+	VPXOR   X5, X11, X11
+	VPXOR   X6, X14, X2
+	VPXOR   X7, X15, X3
+	VMOVDQU X2, 32(AX)
+	VMOVDQU X3, 48(AX)
+
+	LEAQ 128(SI), SI
+	SUBQ $128, DI
+	JNE  loop
+
+	VMOVDQU X10, 0(AX)
+	VMOVDQU X11, 16(AX)
+
+	MOVQ R8, 0(BX)
+	MOVQ R9, 8(BX)
+	VZEROUPPER
+
+	MOVQ BP, SP
+	RET

+ 24 - 0
src/golang.org/x/crypto/blake2b/blake2b_amd64.go

@@ -0,0 +1,24 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.7,amd64,!gccgo,!appengine
+
+package blake2b
+
+import "golang.org/x/sys/cpu"
+
+func init() {
+	useSSE4 = cpu.X86.HasSSE41
+}
+
+//go:noescape
+func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+
+func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
+	if useSSE4 {
+		hashBlocksSSE4(h, c, flag, blocks)
+	} else {
+		hashBlocksGeneric(h, c, flag, blocks)
+	}
+}

+ 281 - 0
src/golang.org/x/crypto/blake2b/blake2b_amd64.s

@@ -0,0 +1,281 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+#include "textflag.h"
+
+DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
+DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
+GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16
+
+DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
+DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
+GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16
+
+DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1
+DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
+GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16
+
+DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
+DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
+GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16
+
+DATA ·c40<>+0x00(SB)/8, $0x0201000706050403
+DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
+GLOBL ·c40<>(SB), (NOPTR+RODATA), $16
+
+DATA ·c48<>+0x00(SB)/8, $0x0100070605040302
+DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
+GLOBL ·c48<>(SB), (NOPTR+RODATA), $16
+
+#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \
+	MOVO       v4, t1; \
+	MOVO       v5, v4; \
+	MOVO       t1, v5; \
+	MOVO       v6, t1; \
+	PUNPCKLQDQ v6, t2; \
+	PUNPCKHQDQ v7, v6; \
+	PUNPCKHQDQ t2, v6; \
+	PUNPCKLQDQ v7, t2; \
+	MOVO       t1, v7; \
+	MOVO       v2, t1; \
+	PUNPCKHQDQ t2, v7; \
+	PUNPCKLQDQ v3, t2; \
+	PUNPCKHQDQ t2, v2; \
+	PUNPCKLQDQ t1, t2; \
+	PUNPCKHQDQ t2, v3
+
+#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \
+	MOVO       v4, t1; \
+	MOVO       v5, v4; \
+	MOVO       t1, v5; \
+	MOVO       v2, t1; \
+	PUNPCKLQDQ v2, t2; \
+	PUNPCKHQDQ v3, v2; \
+	PUNPCKHQDQ t2, v2; \
+	PUNPCKLQDQ v3, t2; \
+	MOVO       t1, v3; \
+	MOVO       v6, t1; \
+	PUNPCKHQDQ t2, v3; \
+	PUNPCKLQDQ v7, t2; \
+	PUNPCKHQDQ t2, v6; \
+	PUNPCKLQDQ t1, t2; \
+	PUNPCKHQDQ t2, v7
+
+#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
+	PADDQ  m0, v0;        \
+	PADDQ  m1, v1;        \
+	PADDQ  v2, v0;        \
+	PADDQ  v3, v1;        \
+	PXOR   v0, v6;        \
+	PXOR   v1, v7;        \
+	PSHUFD $0xB1, v6, v6; \
+	PSHUFD $0xB1, v7, v7; \
+	PADDQ  v6, v4;        \
+	PADDQ  v7, v5;        \
+	PXOR   v4, v2;        \
+	PXOR   v5, v3;        \
+	PSHUFB c40, v2;       \
+	PSHUFB c40, v3;       \
+	PADDQ  m2, v0;        \
+	PADDQ  m3, v1;        \
+	PADDQ  v2, v0;        \
+	PADDQ  v3, v1;        \
+	PXOR   v0, v6;        \
+	PXOR   v1, v7;        \
+	PSHUFB c48, v6;       \
+	PSHUFB c48, v7;       \
+	PADDQ  v6, v4;        \
+	PADDQ  v7, v5;        \
+	PXOR   v4, v2;        \
+	PXOR   v5, v3;        \
+	MOVOU  v2, t0;        \
+	PADDQ  v2, t0;        \
+	PSRLQ  $63, v2;       \
+	PXOR   t0, v2;        \
+	MOVOU  v3, t0;        \
+	PADDQ  v3, t0;        \
+	PSRLQ  $63, v3;       \
+	PXOR   t0, v3
+
+#define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \
+	MOVQ   i0*8(src), m0;     \
+	PINSRQ $1, i1*8(src), m0; \
+	MOVQ   i2*8(src), m1;     \
+	PINSRQ $1, i3*8(src), m1; \
+	MOVQ   i4*8(src), m2;     \
+	PINSRQ $1, i5*8(src), m2; \
+	MOVQ   i6*8(src), m3;     \
+	PINSRQ $1, i7*8(src), m3
+
+// func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
+TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
+	MOVQ h+0(FP), AX
+	MOVQ c+8(FP), BX
+	MOVQ flag+16(FP), CX
+	MOVQ blocks_base+24(FP), SI
+	MOVQ blocks_len+32(FP), DI
+
+	MOVQ SP, BP
+	MOVQ SP, R9
+	ADDQ $15, R9
+	ANDQ $~15, R9
+	MOVQ R9, SP
+
+	MOVOU ·iv3<>(SB), X0
+	MOVO  X0, 0(SP)
+	XORQ  CX, 0(SP)     // 0(SP) = ·iv3 ^ (CX || 0)
+
+	MOVOU ·c40<>(SB), X13
+	MOVOU ·c48<>(SB), X14
+
+	MOVOU 0(AX), X12
+	MOVOU 16(AX), X15
+
+	MOVQ 0(BX), R8
+	MOVQ 8(BX), R9
+
+loop:
+	ADDQ $128, R8
+	CMPQ R8, $128
+	JGE  noinc
+	INCQ R9
+
+noinc:
+	MOVQ R8, X8
+	PINSRQ $1, R9, X8
+
+	MOVO X12, X0
+	MOVO X15, X1
+	MOVOU 32(AX), X2
+	MOVOU 48(AX), X3
+	MOVOU ·iv0<>(SB), X4
+	MOVOU ·iv1<>(SB), X5
+	MOVOU ·iv2<>(SB), X6
+
+	PXOR X8, X6
+	MOVO 0(SP), X7
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7)
+	MOVO X8, 16(SP)
+	MOVO X9, 32(SP)
+	MOVO X10, 48(SP)
+	MOVO X11, 64(SP)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15)
+	MOVO X8, 80(SP)
+	MOVO X9, 96(SP)
+	MOVO X10, 112(SP)
+	MOVO X11, 128(SP)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6)
+	MOVO X8, 144(SP)
+	MOVO X9, 160(SP)
+	MOVO X10, 176(SP)
+	MOVO X11, 192(SP)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3)
+	MOVO X8, 208(SP)
+	MOVO X9, 224(SP)
+	MOVO X10, 240(SP)
+	MOVO X11, 256(SP)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14)
+	SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
+	HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14)
+	SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
+
+	MOVOU 32(AX), X10
+	MOVOU 48(AX), X11
+	PXOR  X0, X12
+	PXOR  X1, X15
+	PXOR  X2, X10
+	PXOR  X3, X11
+	PXOR  X4, X12
+	PXOR  X5, X15
+	PXOR  X6, X10
+	PXOR  X7, X11
+	MOVOU X10, 32(AX)
+	MOVOU X11, 48(AX)
+
+	LEAQ 128(SI), SI
+	SUBQ $128, DI
+	JNE  loop
+
+	MOVOU X12, 0(AX)
+	MOVOU X15, 16(AX)
+
+	MOVQ R8, 0(BX)
+	MOVQ R9, 8(BX)
+
+	MOVQ BP, SP
+	RET

+ 179 - 0
src/golang.org/x/crypto/blake2b/blake2b_generic.go

@@ -0,0 +1,179 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blake2b
+
+import "encoding/binary"
+
+// the precomputed values for BLAKE2b
+// there are 12 16-byte arrays - one for each round
+// the entries are calculated from the sigma constants.
+var precomputed = [12][16]byte{
+	{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
+	{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
+	{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
+	{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
+	{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
+	{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
+	{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
+	{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
+	{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
+	{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
+	{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first
+	{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second
+}
+
+func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
+	var m [16]uint64
+	c0, c1 := c[0], c[1]
+
+	for i := 0; i < len(blocks); {
+		c0 += BlockSize
+		if c0 < BlockSize {
+			c1++
+		}
+
+		v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
+		v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
+		v12 ^= c0
+		v13 ^= c1
+		v14 ^= flag
+
+		for j := range m {
+			m[j] = binary.LittleEndian.Uint64(blocks[i:])
+			i += 8
+		}
+
+		for j := range precomputed {
+			s := &(precomputed[j])
+
+			v0 += m[s[0]]
+			v0 += v4
+			v12 ^= v0
+			v12 = v12<<(64-32) | v12>>32
+			v8 += v12
+			v4 ^= v8
+			v4 = v4<<(64-24) | v4>>24
+			v1 += m[s[1]]
+			v1 += v5
+			v13 ^= v1
+			v13 = v13<<(64-32) | v13>>32
+			v9 += v13
+			v5 ^= v9
+			v5 = v5<<(64-24) | v5>>24
+			v2 += m[s[2]]
+			v2 += v6
+			v14 ^= v2
+			v14 = v14<<(64-32) | v14>>32
+			v10 += v14
+			v6 ^= v10
+			v6 = v6<<(64-24) | v6>>24
+			v3 += m[s[3]]
+			v3 += v7
+			v15 ^= v3
+			v15 = v15<<(64-32) | v15>>32
+			v11 += v15
+			v7 ^= v11
+			v7 = v7<<(64-24) | v7>>24
+
+			v0 += m[s[4]]
+			v0 += v4
+			v12 ^= v0
+			v12 = v12<<(64-16) | v12>>16
+			v8 += v12
+			v4 ^= v8
+			v4 = v4<<(64-63) | v4>>63
+			v1 += m[s[5]]
+			v1 += v5
+			v13 ^= v1
+			v13 = v13<<(64-16) | v13>>16
+			v9 += v13
+			v5 ^= v9
+			v5 = v5<<(64-63) | v5>>63
+			v2 += m[s[6]]
+			v2 += v6
+			v14 ^= v2
+			v14 = v14<<(64-16) | v14>>16
+			v10 += v14
+			v6 ^= v10
+			v6 = v6<<(64-63) | v6>>63
+			v3 += m[s[7]]
+			v3 += v7
+			v15 ^= v3
+			v15 = v15<<(64-16) | v15>>16
+			v11 += v15
+			v7 ^= v11
+			v7 = v7<<(64-63) | v7>>63
+
+			v0 += m[s[8]]
+			v0 += v5
+			v15 ^= v0
+			v15 = v15<<(64-32) | v15>>32
+			v10 += v15
+			v5 ^= v10
+			v5 = v5<<(64-24) | v5>>24
+			v1 += m[s[9]]
+			v1 += v6
+			v12 ^= v1
+			v12 = v12<<(64-32) | v12>>32
+			v11 += v12
+			v6 ^= v11
+			v6 = v6<<(64-24) | v6>>24
+			v2 += m[s[10]]
+			v2 += v7
+			v13 ^= v2
+			v13 = v13<<(64-32) | v13>>32
+			v8 += v13
+			v7 ^= v8
+			v7 = v7<<(64-24) | v7>>24
+			v3 += m[s[11]]
+			v3 += v4
+			v14 ^= v3
+			v14 = v14<<(64-32) | v14>>32
+			v9 += v14
+			v4 ^= v9
+			v4 = v4<<(64-24) | v4>>24
+
+			v0 += m[s[12]]
+			v0 += v5
+			v15 ^= v0
+			v15 = v15<<(64-16) | v15>>16
+			v10 += v15
+			v5 ^= v10
+			v5 = v5<<(64-63) | v5>>63
+			v1 += m[s[13]]
+			v1 += v6
+			v12 ^= v1
+			v12 = v12<<(64-16) | v12>>16
+			v11 += v12
+			v6 ^= v11
+			v6 = v6<<(64-63) | v6>>63
+			v2 += m[s[14]]
+			v2 += v7
+			v13 ^= v2
+			v13 = v13<<(64-16) | v13>>16
+			v8 += v13
+			v7 ^= v8
+			v7 = v7<<(64-63) | v7>>63
+			v3 += m[s[15]]
+			v3 += v4
+			v14 ^= v3
+			v14 = v14<<(64-16) | v14>>16
+			v9 += v14
+			v4 ^= v9
+			v4 = v4<<(64-63) | v4>>63
+
+		}
+
+		h[0] ^= v0 ^ v8
+		h[1] ^= v1 ^ v9
+		h[2] ^= v2 ^ v10
+		h[3] ^= v3 ^ v11
+		h[4] ^= v4 ^ v12
+		h[5] ^= v5 ^ v13
+		h[6] ^= v6 ^ v14
+		h[7] ^= v7 ^ v15
+	}
+	c[0], c[1] = c0, c1
+}

+ 11 - 0
src/golang.org/x/crypto/blake2b/blake2b_ref.go

@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64 appengine gccgo
+
+package blake2b
+
+func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
+	hashBlocksGeneric(h, c, flag, blocks)
+}

+ 847 - 0
src/golang.org/x/crypto/blake2b/blake2b_test.go

@@ -0,0 +1,847 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blake2b
+
+import (
+	"bytes"
+	"encoding"
+	"encoding/hex"
+	"fmt"
+	"hash"
+	"io"
+	"testing"
+)
+
+func fromHex(s string) []byte {
+	b, err := hex.DecodeString(s)
+	if err != nil {
+		panic(err)
+	}
+	return b
+}
+
+func TestHashes(t *testing.T) {
+	defer func(sse4, avx, avx2 bool) {
+		useSSE4, useAVX, useAVX2 = sse4, avx, avx2
+	}(useSSE4, useAVX, useAVX2)
+
+	if useAVX2 {
+		t.Log("AVX2 version")
+		testHashes(t)
+		useAVX2 = false
+	}
+	if useAVX {
+		t.Log("AVX version")
+		testHashes(t)
+		useAVX = false
+	}
+	if useSSE4 {
+		t.Log("SSE4 version")
+		testHashes(t)
+		useSSE4 = false
+	}
+	t.Log("generic version")
+	testHashes(t)
+}
+
+func TestHashes2X(t *testing.T) {
+	defer func(sse4, avx, avx2 bool) {
+		useSSE4, useAVX, useAVX2 = sse4, avx, avx2
+	}(useSSE4, useAVX, useAVX2)
+
+	if useAVX2 {
+		t.Log("AVX2 version")
+		testHashes2X(t)
+		useAVX2 = false
+	}
+	if useAVX {
+		t.Log("AVX version")
+		testHashes2X(t)
+		useAVX = false
+	}
+	if useSSE4 {
+		t.Log("SSE4 version")
+		testHashes2X(t)
+		useSSE4 = false
+	}
+	t.Log("generic version")
+	testHashes2X(t)
+}
+
+func TestMarshal(t *testing.T) {
+	input := make([]byte, 255)
+	for i := range input {
+		input[i] = byte(i)
+	}
+	for _, size := range []int{Size, Size256, Size384, 12, 25, 63} {
+		for i := 0; i < 256; i++ {
+			h, err := New(size, nil)
+			if err != nil {
+				t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
+			}
+			h2, err := New(size, nil)
+			if err != nil {
+				t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
+			}
+
+			h.Write(input[:i/2])
+			halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary()
+			if err != nil {
+				t.Fatalf("size=%d, len(input)=%d: could not marshal: %v", size, i, err)
+			}
+			err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate)
+			if err != nil {
+				t.Fatalf("size=%d, len(input)=%d: could not unmarshal: %v", size, i, err)
+			}
+
+			h.Write(input[i/2 : i])
+			sum := h.Sum(nil)
+			h2.Write(input[i/2 : i])
+			sum2 := h2.Sum(nil)
+
+			if !bytes.Equal(sum, sum2) {
+				t.Fatalf("size=%d, len(input)=%d: results do not match; sum = %v, sum2 = %v", size, i, sum, sum2)
+			}
+
+			h3, err := New(size, nil)
+			if err != nil {
+				t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
+			}
+			h3.Write(input[:i])
+			sum3 := h3.Sum(nil)
+			if !bytes.Equal(sum, sum3) {
+				t.Fatalf("size=%d, len(input)=%d: sum = %v, want %v", size, i, sum, sum3)
+			}
+		}
+	}
+}
+
+func testHashes(t *testing.T) {
+	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
+
+	input := make([]byte, 255)
+	for i := range input {
+		input[i] = byte(i)
+	}
+
+	for i, expectedHex := range hashes {
+		h, err := New512(key)
+		if err != nil {
+			t.Fatalf("#%d: error from New512: %v", i, err)
+		}
+
+		h.Write(input[:i])
+		sum := h.Sum(nil)
+
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+
+		h.Reset()
+		for j := 0; j < i; j++ {
+			h.Write(input[j : j+1])
+		}
+
+		sum = h.Sum(sum[:0])
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+	}
+}
+
+func testHashes2X(t *testing.T) {
+	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
+
+	input := make([]byte, 256)
+	for i := range input {
+		input[i] = byte(i)
+	}
+
+	for i, expectedHex := range hashes2X {
+		length := uint32(len(expectedHex) / 2)
+		sum := make([]byte, int(length))
+
+		h, err := NewXOF(length, key)
+		if err != nil {
+			t.Fatalf("#%d: error from NewXOF: %v", i, err)
+		}
+
+		if _, err := h.Write(input); err != nil {
+			t.Fatalf("#%d (single write): error from Write: %v", i, err)
+		}
+		if _, err := h.Read(sum); err != nil {
+			t.Fatalf("#%d (single write): error from Read: %v", i, err)
+		}
+		if n, err := h.Read(sum); n != 0 || err != io.EOF {
+			t.Fatalf("#%d (single write): Read did not return (0, io.EOF) after exhaustion, got (%v, %v)", i, n, err)
+		}
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+
+		h.Reset()
+		for j := 0; j < len(input); j++ {
+			h.Write(input[j : j+1])
+		}
+		for j := 0; j < len(sum); j++ {
+			h = h.Clone()
+			if _, err := h.Read(sum[j : j+1]); err != nil {
+				t.Fatalf("#%d (byte-by-byte) - Read %d: error from Read: %v", i, j, err)
+			}
+		}
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+	}
+
+	h, err := NewXOF(OutputLengthUnknown, key)
+	if err != nil {
+		t.Fatalf("#unknown length: error from NewXOF: %v", err)
+	}
+	if _, err := h.Write(input); err != nil {
+		t.Fatalf("#unknown length: error from Write: %v", err)
+	}
+
+	var result [64]byte
+	if n, err := h.Read(result[:]); err != nil {
+		t.Fatalf("#unknown length: error from Read: %v", err)
+	} else if n != len(result) {
+		t.Fatalf("#unknown length: Read returned %d bytes, want %d", n, len(result))
+	}
+
+	const expected = "3dbba8516da76bf7330055c66ea36cf1005e92714262b24d9710f51d9e126406e1bcd6497059f9331f1091c3634b695428d475ed432f987040575520a1c29f5e"
+	if fmt.Sprintf("%x", result) != expected {
+		t.Fatalf("#unknown length: bad result %x, wanted %s", result, expected)
+	}
+}
+
+func generateSequence(out []byte, seed uint32) {
+	a := 0xDEAD4BAD * seed // prime
+	b := uint32(1)
+
+	for i := range out { // fill the buf
+		a, b = b, a+b
+		out[i] = byte(b >> 24)
+	}
+}
+
+func computeMAC(msg []byte, hashSize int, key []byte) (sum []byte) {
+	var h hash.Hash
+	switch hashSize {
+	case Size:
+		h, _ = New512(key)
+	case Size384:
+		h, _ = New384(key)
+	case Size256:
+		h, _ = New256(key)
+	case 20:
+		h, _ = newDigest(20, key)
+	default:
+		panic("unexpected hashSize")
+	}
+
+	h.Write(msg)
+	return h.Sum(sum)
+}
+
+func computeHash(msg []byte, hashSize int) (sum []byte) {
+	switch hashSize {
+	case Size:
+		hash := Sum512(msg)
+		return hash[:]
+	case Size384:
+		hash := Sum384(msg)
+		return hash[:]
+	case Size256:
+		hash := Sum256(msg)
+		return hash[:]
+	case 20:
+		var hash [64]byte
+		checkSum(&hash, 20, msg)
+		return hash[:20]
+	default:
+		panic("unexpected hashSize")
+	}
+}
+
+// Test function from RFC 7693.
+func TestSelfTest(t *testing.T) {
+	hashLens := [4]int{20, 32, 48, 64}
+	msgLens := [6]int{0, 3, 128, 129, 255, 1024}
+
+	msg := make([]byte, 1024)
+	key := make([]byte, 64)
+
+	h, _ := New256(nil)
+	for _, hashSize := range hashLens {
+		for _, msgLength := range msgLens {
+			generateSequence(msg[:msgLength], uint32(msgLength)) // unkeyed hash
+
+			md := computeHash(msg[:msgLength], hashSize)
+			h.Write(md)
+
+			generateSequence(key[:], uint32(hashSize)) // keyed hash
+			md = computeMAC(msg[:msgLength], hashSize, key[:hashSize])
+			h.Write(md)
+		}
+	}
+
+	sum := h.Sum(nil)
+	expected := [32]byte{
+		0xc2, 0x3a, 0x78, 0x00, 0xd9, 0x81, 0x23, 0xbd,
+		0x10, 0xf5, 0x06, 0xc6, 0x1e, 0x29, 0xda, 0x56,
+		0x03, 0xd7, 0x63, 0xb8, 0xbb, 0xad, 0x2e, 0x73,
+		0x7f, 0x5e, 0x76, 0x5a, 0x7b, 0xcc, 0xd4, 0x75,
+	}
+	if !bytes.Equal(sum, expected[:]) {
+		t.Fatalf("got %x, wanted %x", sum, expected)
+	}
+}
+
+// Benchmarks
+
+func benchmarkSum(b *testing.B, size int) {
+	data := make([]byte, size)
+	b.SetBytes(int64(size))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		Sum512(data)
+	}
+}
+
+func benchmarkWrite(b *testing.B, size int) {
+	data := make([]byte, size)
+	h, _ := New512(nil)
+	b.SetBytes(int64(size))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		h.Write(data)
+	}
+}
+
+func BenchmarkWrite128(b *testing.B) { benchmarkWrite(b, 128) }
+func BenchmarkWrite1K(b *testing.B)  { benchmarkWrite(b, 1024) }
+
+func BenchmarkSum128(b *testing.B) { benchmarkSum(b, 128) }
+func BenchmarkSum1K(b *testing.B)  { benchmarkSum(b, 1024) }
+
+// These values were taken from https://blake2.net/blake2b-test.txt.
+var hashes = []string{
+	"10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568",
+	"961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd",
+	"da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965",
+	"33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1",
+	"beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac",
+	"098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb",
+	"6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f",
+	"7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52",
+	"380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9",
+	"60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637",
+	"4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd",
+	"f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b",
+	"962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563",
+	"43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355",
+	"dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6",
+	"6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e",
+	"a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93",
+	"f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1",
+	"95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670",
+	"04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9",
+	"ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c",
+	"9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd",
+	"4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152",
+	"64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9",
+	"5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f",
+	"7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b",
+	"f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764",
+	"86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d",
+	"10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55",
+	"b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b",
+	"c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e",
+	"eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7",
+	"86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991",
+	"5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347",
+	"ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82",
+	"7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42",
+	"940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327",
+	"2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760",
+	"d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252",
+	"b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55",
+	"4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1",
+	"258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee",
+	"79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa",
+	"8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7",
+	"c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071",
+	"b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4",
+	"7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf",
+	"a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d",
+	"41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8",
+	"14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487",
+	"d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c",
+	"e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2",
+	"feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa",
+	"462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33",
+	"d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d",
+	"e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e",
+	"f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2",
+	"30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4",
+	"f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2",
+	"0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a",
+	"08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564",
+	"d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f",
+	"dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9",
+	"bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa",
+	"65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022",
+	"939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c",
+	"c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc",
+	"987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f",
+	"ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b",
+	"49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866",
+	"da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d",
+	"d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8",
+	"2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4",
+	"e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3",
+	"dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e",
+	"d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745",
+	"b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545",
+	"6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063",
+	"f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd",
+	"cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a",
+	"fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed",
+	"5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd",
+	"9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275",
+	"af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897",
+	"48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430",
+	"0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab",
+	"06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f",
+	"1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46",
+	"3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29",
+	"04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab",
+	"9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8",
+	"ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a",
+	"8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec",
+	"fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79",
+	"28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24",
+	"ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b",
+	"b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5",
+	"31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463",
+	"bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4",
+	"f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3",
+	"8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9",
+	"c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d",
+	"4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4",
+	"c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a",
+	"ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6",
+	"82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73",
+	"2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6",
+	"16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6",
+	"78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3",
+	"0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa",
+	"f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3",
+	"2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b",
+	"227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f",
+	"1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc",
+	"5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200",
+	"dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6",
+	"02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8",
+	"64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f",
+	"f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a",
+	"e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e",
+	"e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935",
+	"85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74",
+	"aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0",
+	"7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c",
+	"de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145",
+	"aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f",
+	"c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0",
+	"76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb",
+	"72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4",
+	"64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91",
+	"12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89",
+	"60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444",
+	"a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a",
+	"b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414",
+	"fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49",
+	"34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b",
+	"3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0",
+	"ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469",
+	"022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3",
+	"e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd",
+	"94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8",
+	"31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21",
+	"91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989",
+	"d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1",
+	"d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399",
+	"7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0",
+	"58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723",
+	"27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff",
+	"3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc",
+	"eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38",
+	"c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a",
+	"8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051",
+	"24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca",
+	"5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4",
+	"e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677",
+	"bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1",
+	"d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce",
+	"50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347",
+	"0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91",
+	"1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209",
+	"e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659",
+	"b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381",
+	"72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56",
+	"c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7",
+	"c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f",
+	"6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972",
+	"3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe",
+	"c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e",
+	"8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be",
+	"28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8",
+	"2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc",
+	"66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8",
+	"f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0",
+	"8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc",
+	"3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979",
+	"06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29",
+	"c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d",
+	"4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108",
+	"898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45",
+	"ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4",
+	"3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267",
+	"95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d",
+	"227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb",
+	"5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813",
+	"7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc",
+	"062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29",
+	"f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc",
+	"ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16",
+	"c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1",
+	"15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c",
+	"89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7",
+	"e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a",
+	"8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa",
+	"da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e",
+	"f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc",
+	"11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5",
+	"b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a",
+	"ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3",
+	"29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc",
+	"3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d",
+	"3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff",
+	"07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb",
+	"b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4",
+	"7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc",
+	"1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902",
+	"106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e",
+	"0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08",
+	"521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816",
+	"1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406",
+	"5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4",
+	"b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d",
+	"bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d",
+	"65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900",
+	"ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06",
+	"e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01",
+	"3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0",
+	"fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94",
+	"951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02",
+	"8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492",
+	"16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2",
+	"c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c",
+	"72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb",
+	"c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077",
+	"c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727",
+	"f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd",
+	"348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c",
+	"5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0",
+	"2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403",
+	"b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391",
+	"64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8",
+	"0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605",
+	"f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9",
+	"3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d",
+	"d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe",
+	"cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe",
+	"98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1",
+	"771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3",
+	"c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb",
+	"8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b",
+	"1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef",
+	"af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253",
+	"29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec",
+	"a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a",
+	"0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473",
+	"b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837",
+	"74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a",
+	"3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1",
+	"58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d",
+	"9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9",
+	"b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537",
+	"1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7",
+	"4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2",
+	"695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338",
+	"a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15",
+	"d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9",
+	"142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461",
+}
+
+var hashes2X = []string{
+	"64",
+	"f457",
+	"e8c045",
+	"a74c6d0d",
+	"eb02ae482a",
+	"be65b981275e",
+	"8540ccd083a455",
+	"074a02fa58d7c7c0",
+	"da6da05e10db3022b6",
+	"542a5aae2f28f2c3b68c",
+	"ca3af2afc4afe891da78b1",
+	"e0f66b8dcebf4edc85f12c85",
+	"744224d383733b3fa2c53bfcf5",
+	"b09b653e85b72ef5cdf8fcfa95f3",
+	"dd51877f31f1cf7b9f68bbb09064a3",
+	"f5ebf68e7ebed6ad445ffc0c47e82650",
+	"ebdcfe03bcb7e21a9091202c5938c0a1bb",
+	"860fa5a72ff92efafc48a89df1632a4e2809",
+	"0d6d49daa26ae2818041108df3ce0a4db48c8d",
+	"e5d7e1bc5715f5ae991e4043e39533af5d53e47f",
+	"5232028a43b9d4dfa7f37439b49495926481ab8a29",
+	"c118803c922f9ae2397fb676a2ab7603dd9c29c21fe4",
+	"2af924f48b9bd7076bfd68794bba6402e2a7ae048de3ea",
+	"61255ac38231087c79ea1a0fa14538c26be1c851b6f318c0",
+	"f9712b8e42f0532162822f142cb946c40369f2f0e77b6b186e",
+	"76da0b89558df66f9b1e66a61d1e795b178ce77a359087793ff2",
+	"9036fd1eb32061bdecebc4a32aa524b343b8098a16768ee774d93c",
+	"f4ce5a05934e125d159678bea521f585574bcf9572629f155f63efcc",
+	"5e1c0d9fae56393445d3024d6b82692d1339f7b5936f68b062c691d3bf",
+	"538e35f3e11111d7c4bab69f83b30ade4f67addf1f45cdd2ac74bf299509",
+	"17572c4dcbb17faf8785f3bba9f6903895394352eae79b01ebd758377694cc",
+	"29f6bb55de7f8868e053176c878c9fe6c2055c4c5413b51ab0386c277fdbac75",
+	"bad026c8b2bd3d294907f2280a7145253ec2117d76e3800357be6d431b16366e41",
+	"386b7cb6e0fd4b27783125cbe80065af8eb9981fafc3ed18d8120863d972fa7427d9",
+	"06e8e6e26e756fff0b83b226dce974c21f970e44fb5b3e5bbada6e4b12f81cca666f48",
+	"2f9bd300244f5bc093ba6dcdb4a89fa29da22b1de9d2c9762af919b5fedf6998fbda305b",
+	"cf6bdcc46d788074511f9e8f0a4b86704365b2d3f98340b8db53920c385b959a38c8869ae7",
+	"1171e603e5cdeb4cda8fd7890222dd8390ede87b6f3284cac0f0d832d8250c9200715af7913d",
+	"bda7b2ad5d02bd35ffb009bdd72b7d7bc9c28b3a32f32b0ba31d6cbd3ee87c60b7b98c03404621",
+	"2001455324e748503aa08eff2fb2e52ae0170e81a6e9368ada054a36ca340fb779393fb045ac72b3",
+	"45f0761aefafbf87a68f9f1f801148d9bba52616ad5ee8e8ac9207e9846a782f487d5cca8b20355a18",
+	"3a7e05708be62f087f17b41ac9f20e4ef8115c5ab6d08e84d46af8c273fb46d3ce1aabebae5eea14e018",
+	"ea318da9d042ca337ccdfb2bee3e96ecb8f907876c8d143e8e44569178353c2e593e4a82c265931ba1dd79",
+	"e0f7c08f5bd712f87094b04528fadb283d83c9ceb82a3e39ec31c19a42a1a1c3bee5613b5640abe069b0d690",
+	"d35e63fb1f3f52ab8f7c6cd7c8247e9799042e53922fbaea808ab979fa0c096588cfea3009181d2f93002dfc11",
+	"b8b0ab69e3ae55a8699eb481dd665b6a2424c89bc6b7cca02d15fdf1b9854139cab49d34de498b50b2c7e8b910cf",
+	"fb65e3222a2950eae1701d4cdd4736266f65bf2c0d2e77968996eadb60ef74fb786f6234973a2524bdfe32d100aa0e",
+	"f28b4bb3a2e2c4d5c01a23ff134558559a2d3d704b75402983ee4e0f71d273ae056842c4153b18ee5c47e2bfa54313d4",
+	"7bb78794e58a53c3e4b1aeb161e756af051583d14e0a5a3205e094b7c9a8cf62d098fa9ea1db12f330a51ab9852c17f983",
+	"a879a8ebae4d0987789bcc58ec3448e35ba1fa1ee58c668d8295aba4eaeaf2762b053a677e25404f635a53037996974d418a",
+	"695865b353ec701ecc1cb38f3154489eed0d39829fc192bb68db286d20fa0a64235cde5639137819f7e99f86bd89afcef84a0f",
+	"a6ec25f369f71176952fb9b33305dc768589a6070463ee4c35996e1ced4964a865a5c3dc8f0d809eab71366450de702318e4834d",
+	"604749f7bfadb069a036409ffac5ba291fa05be8cba2f141554132f56d9bcb88d1ce12f2004cd3ade1aa66a26e6ef64e327514096d",
+	"daf9fa7dc2464a899533594e7916fc9bc585bd29dd60c930f3bfa78bc47f6c8439448043a45119fc9228c15bce5fd24f46baf9de736b",
+	"943ea5647a8666763084da6a6f15dcf0e8dc24f27fd0d9194805d25180fe3a6d98f4b2b5e0d6a04e9b41869817030f16ae975dd41fc35c",
+	"af4f73cbfc093760dfeb52d57ef45207bbd1a515f5523404e5d95a73c237d97ae65bd195b472de6d514c2c448b12fafc282166da132258e9",
+	"605f4ed72ed7f5046a342fe4cf6808100d4632e610d59f7ebb016e367d0ff0a95cf45b02c727ba71f147e95212f52046804d376c918cadd260",
+	"3750d8ab0a6b13f78e51d321dfd1aa801680e958de45b7b977d05732ee39f856b27cb2bcce8fbf3db6666d35e21244c2881fdcc27fbfea6b1672",
+	"8f1b929e80ab752b58abe9731b7b34eb61369536995abef1c0980d93903c1880da3637d367456895f0cb4769d6de3a979e38ed6f5f6ac4d48e9b32",
+	"d8469b7aa538b36cdc711a591d60dafecca22bd421973a70e2deef72f69d8014a6f0064eabfbebf5383cbb90f452c6e113d2110e4b1092c54a38b857",
+	"7d1f1ad2029f4880e1898af8289c23bc933a40863cc4ab697fead79c58b6b8e25b68cf5324579b0fe879fe7a12e6d03907f0140dfe7b29d33d6109ecf1",
+	"87a77aca6d551642288a0dff66078225ae39d288801607429d6725ca949eed7a6f199dd8a65523b4ee7cfa4187400e96597bfffc3e38ade0ae0ab88536a9",
+	"e101f43179d8e8546e5ce6a96d7556b7e6b9d4a7d00e7aade5579d085d527ce34a9329551ebcaf6ba946949bbe38e30a62ae344c1950b4bde55306b3bac432",
+	"4324561d76c370ef35ac36a4adf8f3773a50d86504bd284f71f7ce9e2bc4c1f1d34a7fb2d67561d101955d448b67577eb30dfee96a95c7f921ef53e20be8bc44",
+	"78f0ed6e220b3da3cc9381563b2f72c8dc830cb0f39a48c6ae479a6a78dcfa94002631dec467e9e9b47cc8f0887eb680e340aec3ec009d4a33d241533c76c8ca8c",
+	"9f6589c31a472e0a736f4eb22b6c70a9d332cc15304ccb66a6b97cd051b6ed82f8990e1d9bee2e4bb1c3c45e550ae0e7b96e93ae23f2fb8f63b309131e72b36cba6a",
+	"c138077ee4ed3d7ffa85ba851dfdf6e9843fc1dc00889d117237bfaad9aa757192f73556b959f98e6d24886ce48869f2a01a48c371785f12b6484eb2078f08c22066e1",
+	"f83e7c9e0954a500576ea1fc90a3db2cbd7994eaef647dab5b34e88ab9dc0b47addbc807b21c8e6dd3d0bd357f008471d4f3e0abb18450e1d4919e03a34545b9643f870e",
+	"3277a11f2628544fc66f50428f1ad56bcba6ee36ba2ca6ecdf7e255effc0c30235c039d13e01f04cf1efe95b5c2033ab72adda30994b62f2851d17c9920eadca9a251752dc",
+	"c2a834281a06fe7b730d3a03f90761daf02714c066e33fc07e1f59ac801ec2f4433486b5a2da8faa51a0cf3c34e29b2960cd0013378938dbd47c3a3d12d70db01d7d06c3e91e",
+	"47680182924a51cabe142a6175c9253e8ba7ea579ece8d9bcb78b1e9ca00db844fa08abcf41702bd758ee2c608d9612fed50e85854469cb4ef3038acf1e35b6ba4390561d8ae82",
+	"cec45830cd71869e83b109a99a3cd7d935f83a95de7c582f3adbd34e4938fa2f3f922f52f14f169c38cc6618d3f306a8a4d607b345b8a9c48017136fbf825aecf7b620e85f837fae",
+	"46fb53c70ab105079d5d78dc60eaa30d938f26e4d0b9df122e21ec85deda94744c1daf8038b8a6652d1ff3e7e15376f5abd30e564784a999f665078340d66b0e939e0c2ef03f9c08bb",
+	"7b0dcb52791a170cc52f2e8b95d8956f325c3751d3ef3b2b83b41d82d4496b46228a750d02b71a96012e56b0720949ca77dc68be9b1ef1ad6d6a5ceb86bf565cb972279039e209dddcdc",
+	"7153fd43e6b05f5e1a4401e0fef954a737ed142ec2f60bc4daeef9ce73ea1b40a0fcaf1a1e03a3513f930dd5335723632f59f7297fe3a98b68e125eadf478eb045ed9fc4ee566d13f537f5",
+	"c7f569c79c801dab50e9d9ca6542f25774b3841e49c83efe0b89109f569509ce7887bc0d2b57b50320eb81fab9017f16c4c870e59edb6c26620d93748500231d70a36f48a7c60747ca2d5986",
+	"0a81e0c547648595adca65623ce783411aac7f7d30c3ad269efafab288e7186f6895261972f5137877669c550f34f5128850ebb50e1884814ea1055ee29a866afd04b2087abed02d9592573428",
+	"6a7b6769e1f1c95314b0c7fe77013567891bd23416374f23e4f43e27bc4c55cfada13b53b1581948e07fb96a50676baa2756db0988077b0f27d36ac088e0ff0fe72eda1e8eb4b8facff3218d9af0",
+	"a399474595cb1ccab6107f18e80f03b1707745c7bf769fc9f260094dc9f8bc6fe09271cb0b131ebb2acd073de4a6521c8368e664278be86be216d1622393f23435fae4fbc6a2e7c961282a777c2d75",
+	"4f0fc590b2755a515ae6b46e9628092369d9c8e589e3239320639aa8f7aa44f8111c7c4b3fdbe6e55e036fbf5ebc9c0aa87a4e66851c11e86f6cbf0bd9eb1c98a378c7a7d3af900f55ee108b59bc9e5c",
+	"ed96a046f08dd675107331d267379c6fce3c352a9f8d7b243008a74cb4e9410836afaabe871dab6038ca94ce5f6d41fa922ce08aba58169f94cfc86d9f688f396abd24c11a6a9b0830572105a477c33e92",
+	"379955f539abf0eb2972ee99ed9546c4bbee363403991833005dc27904c271ef22a799bc32cb39f08d2e4ba6717d55153feb692d7c5efae70890bf29d96df02333c7b05ccc314e4835b018fec9141a82c745",
+	"e16cc8d41b96547ede0d0cf4d908c5fa393399daa4a9696e76a4c1f6a2a9fef70f17fb53551a8145ed88f18db8fe780a079d94732437023f7c1d1849ef69ad536a76204239e8ba5d97e507c36c7d042f87fe0e",
+	"a81de50750ece3f84536728f227208bf01ec5b7721579d007de72c88ee20663318332efe5bc7c09ad1fa8342be51f0609046ccf760a7957a7d8dc88941adb93666a4521ebe76618e5ddc2dd3261493d400b50073",
+	"b72c5fb7c7f60d243928fa41a2d711157b96aef290185c64b4de3dcfa3d644da67a8f37c2ac55caad79ec695a473e8b481f658c497edb8a191526592b11a412282d2a4010c90ef4647bd6ce745ebc9244a71d4876b",
+	"9550703877079c90e200e830f277b605624954c549e729c359ee01ee2b07741ecc4255cb37f96682dafcdbaade1063e2c5ccbd1918fb669926a67744101fb6de3ac016be4c74165a1e5a696b704ba2ebf4a953d44b95",
+	"a17eb44d4de502dc04a80d5a5e9507d17f27c96467f24c79b06bc98a4c410741d4ac2db98ec02c2a976d788531f1a4451b6c6204cef6dae1b6ebbcd0bde23e6fffb02754043c8fd3c783d90a670b16879ce68b5554fe1c",
+	"41d3ea1eaba5be4a206732dbb5b70b79b66a6e5908795ad4fb7cf9e67efb13f06fef8f90acb080ce082aadec6a1b543af759ab63fa6f1d3941186482b0c2b312f1151ea8386253a13ed3708093279b8eb04185636488b226",
+	"5e7cdd8373dc42a243c96013cd29df9283b5f28bb50453a903c85e2ce57f35861bf93f03029072b70dac0804e7d51fd0c578c8d9fa619f1e9ce3d8044f65d55634dba611280c1d5cfb59c836a595c803124f696b07ddfac718",
+	"26a14c4aa168907cb5de0d12a82e1373a128fb21f2ed11feba108b1bebce934ad63ed89f4ed7ea5e0bc8846e4fc10142f82de0bebd39d68f7874f615c3a9c896bab34190e85df05aaa316e14820b5e478d838fa89dfc94a7fc1e",
+	"0211dfc3c35881adc170e4ba6daab1b702dff88933db9a6829a76b8f4a7c2a6d658117132a974f0a0b3a38ceea1efc2488da21905345909e1d859921dc2b5054f09bce8eeb91fa2fc6d048ce00b9cd655e6aafbdaa3a2f19270a16",
+	"ddf015b01b68c4f5f72c3145d54049867d99ee6bef24282abf0eecdb506e295bacf8f23ffa65a4cd891f76a046b9dd82cae43a8d01e18a8dff3b50aeb92672be69d7c087ec1fa2d3b2a39196ea5b49b7baede37a586fea71aded587f",
+	"6ee721f71ca4dd5c9ce7873c5c04c6ce76a2c824b984251c15535afc96adc9a4d48ca314bfeb6b8ee65092f14cf2a7ca9614e1dcf24c2a7f0f0c11207d3d8aed4af92873b56e8b9ba2fbd659c3f4ca90fa24f113f74a37181bf0fdf758",
+	"689bd150e65ac123612524f720f54def78c095eaab8a87b8bcc72b443408e3227f5c8e2bd5af9bcac684d497bc3e41b7a022c28fb5458b95e8dfa2e8caccde0492936ff1902476bb7b4ef2125b19aca2cd3384d922d9f36dddbcd96ae0d6",
+	"3a3c0ef066fa4390ec76ad6be1dc9c31ddf45fef43fbfa1f49b439caa2eb9f3042253a9853e96a9cf86b4f873785a5d2c5d3b05f6501bc876e09031188e05f48937bf3c9b667d14800db62437590b84ce96aa70bb5141ee2ea41b55a6fd944",
+	"741ce384e5e0edaebb136701ce38b3d33215415197758ae81235307a4115777d4dab23891db530c6d28f63a957428391421f742789a0e04c99c828373d9903b64dd57f26b3a38b67df829ae243feef731ead0abfca049924667fdec49d40f665",
+	"a513f450d66cd5a48a115aee862c65b26e836f35a5eb6894a80519e2cd96cc4cad8ed7eb922b4fc9bbc55c973089d627b1da9c3a95f6c019ef1d47143cc545b15e4244424be28199c51a5efc7234dcd94e72d229897c392af85f523c2633427825",
+	"71f1554d2d49bb7bd9e62e71fa049fb54a2c097032f61ebda669b3e1d4593962e47fc62a0ab5d85706aebd6a2f9a192c88aa1ee2f6a46710cf4af6d3c25b7e68ad5c3db23ac009c8f13625ff85dc8e50a9a1b2682d3329330b973ec8cbb7bb73b2bd",
+	"167cc1067bc08a8d2c1a0c10041ebe1fc327b37043f6bd8f1c63569e9d36ded58519e66b162f34b6d8f1107ef1e3de199d97b36b44141a1fc4f49b883f40507ff11f909a017869dc8a2357fc7336ae68703d25f75710b0ff5f9765321c0fa53a51675c",
+	"cb859b35dc70e264efaad2a809fea1e71cd4a3f924be3b5a13f8687a1166b538c40b2ad51d5c3e47b0de482497382673140f547068ff0b3b0fb7501209e1bf36082509ae85f60bb98fd02ac50d883a1a8daa704952d83c1f6da60c9624bc7c99912930bf",
+	"afb1f0c6b7125b04fa2578dd40f60cb411b35ebc7026c702e25b3f0ae3d4695d44cfdf37cb755691dd9c365edadf21ee44245620e6a24d4c2497135b37cd7ac67e3bd0aaee9f63f107746f9b88859ea902bc7d6895406aa2161f480cad56327d0a5bba2836",
+	"13e9c0522587460d90c7cb354604de8f1bf850e75b4b176bda92862d35ec810861f7d5e7ff6ba9302f2c2c8642ff8b7776a2f53665790f570fcef3cac069a90d50db42227331c4affb33d6c040d75b9aeafc9086eb83ced38bb02c759e95ba08c92b17031288",
+	"0549812d62d3ed497307673a4806a21060987a4dbbf43d352b9b170a29240954cf04bc3e1e250476e6800b79e843a8bd8253b7d743de01ab336e978d4bea384eaff700ce020691647411b10a60acacb6f8837fb08ad666b8dcc9eaa87ccb42aef6914a3f3bc30a",
+	"3a263efbe1f2d463f20526e1d0fd735035fd3f808925f058b32c4d8788aeeab9b8ce233b3c34894731cd73361f465bd350395aebcabd2fb63010298ca025d849c1fa3cd573309b74d7f824bbfe383f09db24bcc565f636b877333206a6ad70815c3bef5574c5fc1c",
+	"3c6a7d8a84ef7e3eaa812fc1eb8e85105467230d2c9e4562edbfd808f4d1ac15d16b786cc6a02959c2bc17149c2ce74c6f85ee5ef22a8a96b9be1f197cffd214c1ab02a06a9227f37cd432579f8c28ff2b5ac91cca8ffe6240932739d56788c354e92c591e1dd76499",
+	"b571859294b02af17541a0b5e899a5f67d6f5e36d38255bc417486e69240db56b09cf2607fbf4f95d085a779358a8a8b41f36503438c1860c8f361ce0f2783a08b21bd7232b50ca6d35428335272a5c05b436b2631d8d5c84d60e8040083768ce56a250727fb0579dd5c",
+	"98ee1b7269d2a0dd490ca38d447279870ea55326571a1b430adbb2cf65c492131136f504145df3ab113a13abfb72c33663266b8bc9c458db4bf5d7ef03e1d3b8a99d5de0c024be8fabc8dc4f5dac82a0342d8ed65c329e7018d6997e69e29a01350516c86beaf153da65ac",
+	"41c5c95f088df320d35269e5bf86d10248f17aec6776f0fe653f1c356aae409788c938befeb67c86d1c8870e8099ca0ce61a80fbb5a6654c44529368f70fc9b9c2f912f5092047d0ffc339577d24142300e34948e086f62e23ecaca410d24f8a36b5c8c5a80e0926bc8aa16a",
+	"9f93c41f533b2a82a4df893c78faaaa793c1506974ba2a604cd33101713ca4adfd30819ffd8403402b8d40aff78106f3357f3e2c24312c0d3603a17184d7b999fc9908d14d50192aebabd90d05073da7af4be37dd3d81c90acc80e8333df546f17ab6874f1ec204392d1c0571e",
+	"3da5207245ac270a915fc91cdb314e5a2577c4f8e269c4e701f0d7493ba716de79935918b917a2bd5db98050dbd1eb3894b65fac5abf13e075abebc011e651c03cafb6127147771a5c8418223e1548137a89206635c26ca9c235ccc108dc25cf846e4732444bd0c2782b197b262b",
+	"96011af3965bb941dc8f749932ea484eccb9ba94e34b39f24c1e80410f96ce1d4f6e0aa5be606def4f54301e930493d4b55d484d93ab9dd4dc2c9cfb79345363af31ad42f4bd1aa6c77b8afc9f0d551bef7570b13b927afe3e7ac4de7603a0876d5edb1ad9be05e9ee8b53941e8f59",
+	"51dbbf2a7ca224e524e3454fe82ddc901fafd2120fa8603bc343f129484e9600f688586e040566de0351d1693829045232d04ff31aa6b80125c763faab2a9b233313d931903dcfaba490538b06e4688a35886dc24cdd32a13875e6acf45454a8eb8a315ab95e608ad8b6a49aef0e299a",
+	"5a6a422529e22104681e8b18d64bc0463a45df19ae2633751c7aae412c250f8fb2cd5e1270d3d0cf009c8aa69688ccd4e2b6536f5747a5bc479b20c135bf4e89d33a26118705a614c6be7ecfe766932471ad4ba01c4f045b1abb5070f90ec78439a27a1788db9327d1c32f939e5fb1d5ba",
+	"5d26c983642093cb12ff0afabd87b7c56e211d01844ad6da3f623b9f20a0c968034299f2a65e6673530c5980a532beb831c7d0697d12760445986681076dfb6fae5f3a4d8f17a0db5008ce8619f566d2cfe4cf2a6d6f9c3664e3a48564a351c0b3c945c5ee24587521e4112c57e318be1b6a",
+	"52641dbc6e36be4d905d8d60311e303e8e859cc47901ce30d6f67f152343e3c4030e3a33463793c19effd81fb7c4d631a9479a7505a983a052b1e948ce093b30efa595fab3a00f4cef9a2f664ceeb07ec61719212d58966bca9f00a7d7a8cb4024cf6476bab7fbccee5fd4e7c3f5e2b2975aa2",
+	"a34ce135b37bf3db1c4aaa4878b4499bd2ee17b85578fcaf605d41e1826b45fdaa1b083d8235dc642787f11469a5493e36806504fe2a2063905e821475e2d5ee217057950370492f5024995e77b82aa51b4f5bd8ea24dc71e0a8a640b0592c0d80c24a726169cf0a10b40944747113d03b52708c",
+	"46b3cdf4946e15a5334fc3244d6680f5fc132afa67bf43bfade23d0c9e0ec64e7dab76faaeca1870c05f96b7d019411d8b0873d9fed04fa5057c039d5949a4d592827f619471359d6171691cfa8a5d7cb07ef2804f6ccad4821c56d4988bea7765f660f09ef87405f0a80bcf8559efa111f2a0b419",
+	"8b9fc21691477f11252fca050b121c5334eb4280aa11659e267297de1fec2b2294c7ccee9b59a149b9930b08bd320d3943130930a7d931b71d2f10234f4480c67f1de883d9894ada5ed5071660e221d78ae402f1f05af47761e13fec979f2671e3c63fb0ae7aa1327cf9b8313adab90794a52686bbc4",
+	"cd6598924ce847de7ff45b20ac940aa6292a8a99b56a74eddc24f2cfb45797188614a21d4e8867e23ff75afd7cd324248d58fcf1ddc73fbd115dfa8c09e62022fab540a59f87c989c12a86ded05130939f00cd2f3b512963dfe0289f0e54acad881c1027d2a0292138fdee902d67d9669c0ca1034a9456",
+	"594e1cd7337248704e691854af0fdb021067ddf7832b049ba7b684438c32b029eded2df2c89a6ff5f2f2c311522ae2dc6db5a815afc60637b15ec24ef9541f1550409db2a006da3affffe548a1eaee7bd114e9b805d0756c8e90c4dc33cb05226bc2b393b18d953f8730d4c7ae693159cdba758ad28964e2",
+	"1f0d292453f04406ada8be4c161b82e3cdd69099a8637659e0ee40b8f6da46005cfc6085db9804852decfbe9f7b4dda019a7112612895a144ed430a960c8b2f5458d3d56b7f427cee6358915aee7146278aed2a0296cdd929e4d21ef95a3adf8b7a6beba673cdccdbdcfb2474711732d972ad054b2dc64f38d",
+	"b65a72d4e1f9f9f75911cc46ad0806b9b18c87d105332a3fe183f45f063a746c892dc6c4b9181b1485b3e3a2cc3b453eba2d4c39d6905a774ed3fb755468beb190925ecd8e57ecb0d985125741650c6b6a1b2a3a50e93e3892c21d47ed5884eed83aa94e1602288f2f49fe286624de9d01fcb54433a0dc4ad70b",
+	"705ce0ffa469250782aff725248fc88fe98eb76659e8407edc1c4842c9867d61fe64fb86f74e980598b92bc213d06f337bd5654fc28643c7ba769a4c31563427543c00808b627a19c90d86c322f33566ce020121cc322229c3337943d46f68ef939d613dcef0077269f88151d6398b6b009abb763410b154ad76a3",
+	"7fa881ce87498440ab6af13854f0d851a7e0404de33896999a9b3292a5d2f5b3ad033530c558168fe5d2fdb9b89a2354c46cf32a0e612afc6c6485d789511bfef26800c74bf1a4cfbe30bda310d5f6029c3dccdedb6149e4971274e276dccfabd63bc4b9955e8303feb57f8a688db55ecb4b33d1f9fe1b3a8ba7ac32",
+	"23a98f71c01c0408ae16843dc03be7db0aeaf055f951709d4e0dfdf64fffbffaf900ee592ee10929648e56f6c1e9f5be5793f7df66453eb56502c7c56c0f0c88da77abc8fa371e434104627ef7c663c49f40998dbad63fa6c7aa4fac17ae138d8bbe081f9bd168cd33c1fbc92fa35ed687679f48a64b87db1fe5bae675",
+	"7b8970b6a33237e5a7bcb39272703edb92285c55842b30b9a48834b1b507cc02a6764739f2f7ee6ae02a7b715a1c455e59e8c77a1ae98abb10161853f1234d20da99016588cd8602d6b7ec7e177d4011edfa61e6b3766a3c6f8d6e9eac893c568903eb6e6aba9c4725774f6b4343b7acaa6c031593a36eef6c72806ff309",
+	"f7f4d328ba108b7b1de4443e889a985ed52f485f3ca4e0c246aa5526590cbed344e9f4fe53e4eea0e761c82324649206ca8c2b45152157d4115e68c818644b03b65bb47ad79f94d37cb03c1d953b74c2b8adfa0e1c418bda9c518ddcd7050e0f149044740a2b16479413b63fc13c36144f80c73687513dca761ba8642a8ae0",
+	"2d7dc80c19a1d12d5fe3963569547a5d1d3e821e6f06c5d5e2c09401f946c9f7e13cd019f2f9a878b62dd850453b6294b99ccaa068e542993524b0f63832d48e865be31e8ec1ee103c718340c904b32efb69170b67f038d50a3252794b1b4076c0620621ab3d91215d55ffea99f23d54e161a90d8d4902fda5931d9f6a27146a",
+	"77dff4c7ad30c954338c4b23639dae4b275086cbe654d401a2343528065e4c9f1f2eca22aa025d49ca823e76fdbb35df78b1e5075ff2c82b680bca385c6d57f7ea7d1030bb392527b25dd73e9eeff97bea397cf3b9dda0c817a9c870ed12c006cc054968c64000e0da874e9b7d7d621b0679866912243ea096c7b38a1344e98f74",
+	"83bed0d556798f2b419f7056e6d3ffada06e939b95a688d0ec8c6ac5ea45ab73a4cf01043e0a170766e21395f27ab4b78c435f5f0dfe6e93ab80df38610e41158429ddf20296f53a06a017723359fe22dc08b5da33f0800a4fe50118e8d7eab2f83a85cd764bf8a166903bd0e9dcfeeceba44ff4ca4439846458d31ea2bb564645d1",
+	"ea12cf5a113543e39504123036f15a5bafa9c555562469f99cd29996a4dfaaab2a34b00557ccf15f37fc0cc1b3be427e725f2cd952e50af7970dda9200cd5ce252b1f29c40067fea3027ed686190803b59d834179d1b8f5b55abe55ad174b2a1188f7753ec0ae2fc01316e7d498b68ee3598a0e9baaaa664a60f7fb4f90edbed494ad7",
+	"55266358332d8d9e68bd13432088beadf95833aab67a0eb3b10650414255f299e2670c3e1a5b2976159a46c72a7ce57d59b7be14c15798e09ed50fa312a431b0264d7a1396aa6168bde897e208ece53d2cfc83786113b1e6eac5e9bb98984abb6c8d64eebb991903254abc650c999bb9958a5d7937434b869bc940e21b9dc1cc8982f2ba",
+	"4d6104ded730aefe02873f4c741232c8234a6d66d85393aff57fbf56ba6347666988dfc4d58f3cc895a0da598822edeee4533d24ec0ee292fd5e1ad04898ffbc1ff4bef14dec220babcb0f28fffe32a6e2c28aaaac16442bf4feb02917d18bb3a415d84fa9358d5a9852688d846c92271911f934181c30f82434d915f93f155a1ffbf0b125",
+	"eb5f579a4c476af554aac11e5719d378549497e613b35a929d6f36bb8831d7a466aa76de9be24ebb55543f1c13924f64cfd648a5b3fa90387315c16174dbf1e9a183c196d9bb8f84af65f1f8212429aadc11ef2426d07d4716062b85c8d5d2dff8e21b9e62b7fa7dbd57d72633054b464fb28583a56ca13ccc5ddc74dae942492f31731e7046",
+	"ebddec3dcaf18063e45a76ebeac39af85a1adc2818881ccce48c106288f5988365cca2b4b1d7f037322da46840f42bebdcbc7193838d426e101087d8cea03aaff743d573eb4f4e9a71a2c884390769a6503874125d194bee8d46a3a0d5e4fcf28ff8465887d8e9df771d70157e75df3642b331d2778ceb32ceba868640171ab7a5d22eede1ee44",
+	"26d87ec70b57691e3bb359633d3ddba17f029d62cdfe977f5fd42274d79b444a32494d1c01e9f72d03cce78c806df96e93ea78da3a054209924ed765edc4d570f66168dc25ee3114e4017e387440349c8f0a94804761c3055f88e4fda2a49b860b1486a9609095f6250f268b6a4d1aecc03a505632ebf0b9dc22d0755a736faf7ad7000858b5864b",
+	"3880f5cc2d08fa70ef44b1f263fcf534d062a298c1bd5ee2eee8c3265806c4ce50b004f3a1fc1fa5b024aaac7f528c023c8181f67c6e1c357425dc4d573bd46b93a542afa3a19bdb140a2ce666e1a01f5c4d2dcd681fa9f5839b797813c394738d5ee4971386c12c7c117d17c7bec324b760aa30cda9ab2aa850284ba6fa97946f710f02449d1883c6",
+	"3317d2f452105dd3f4a96f9257af8285a80be58066b50f6f54bd633749b49f6ab9d57d45652d2ae852a2f6940cd5ec3159dd7f333358b12f502325df38843508faf7e246352d201280babd90b14fbf7722641c3601d0e458474439973c611bb5502fd0eb3078f87124ca7e1a016fcb6cfeff65f6a565985aca7122cfa8c5a11da0cb47797c5132333179",
+	"f2c5c955d0224e784a46b9125f8fef8a5e1271e145eb08bbbd07ca8e1cfc848cef14fa3b36221ac62006403dbb7f7d77958ccc54a8566c837858b809f3e310ace8ca682515bc655d2a397cab238a663b464d511f02dc5d033dad4cb5e0e519e94a54b62a3896e460ec70e5716b5921bf8396aa86a60123e6287e34570bb01bdc602e113670bf498af2ff10",
+	"180e275205691a83630cf4b0c7b80e6df8fad6ef1c23ba8013d2f09aef7abade1827f23af230de90676240b4b3b0673f8afdea0327330055041741f65560d90348de696d34ca80dfe8afae582fe4879d4594b80e9408fb53e800e01ca58552b905c365e7f1416e51c080f517d6bbd30e64ae1535d59decdc76c6624d737868f49f2f719da39ba1344d59eab9",
+	"c517a84e4631a7f65ace170d1e5c2fdb259841535d88da323e68c0883e6af7b041cfe05908815a5a9d1b14fa712c2c16fadcf1ca54d3aa954d411240df331b2aebdfb65aced84d0b8aace56ec0aa7c13ec7d75ca883b6bcf6db74c9e98463c484a8262684f29910373430651f90ecffe18b072170e61ee58de20e2a6ff67b3ab00fccbb80af943f20b56b98107",
+	"d1a56a5ee990e02b84b5862fde62f69ec07567be2d7ccb769a461c4989d11fdda6c945d942fb8b2da795ed97e43a5b7dbdde7f8fd2ff7154544336d5c50fb7380341e660d4898c7fbc39b2b782f28defac6873523c7c1de8e52c65e4395c686ba483c35a220b0416d46357a063fa4c33fa9c52d5c207a1304ae141c791e62ba6a7374ed922b8dd94079b72b69302",
+	"4720b88d6bfb1ab43958e26827730d852d9ec30173ebd0fe0d273edcece2e788558984cd9306fe5978086a5cb6d37975755d2a3daeb16f99a8a11544b8247a8b7ed5587afc5bea1daf85dcea5703c5905cf56ae7cc76408ccabb8fcc25cacc5ff456db3f62fa559c45b9c71505eb5073df1f10fc4c9060843f0cd68bbb4e8edfb48d0fd81d9c21e53b28a2aae4f7ba",
+	"f4639b511db9e092823d47d2947efacbaae0e5b912dec3b284d2350b9262f3a51796a0cd9f8bc5a65879d6578ec24a060e293100c2e12ad82d5b2a0e9d22965858030e7cdf2ab3562bfa8ac084c6e8237aa22f54b94c4e92d69f22169ced6c85a293f5e16bfc326153bf629cdd6393675c6627cd949cd367eef02e0f54779f4d5210197698e4754a5fe490a3a7521c1c",
+	"3d9e7a860a718565e3670c29079ce80e381969fea91017cfd5952e0d8a4a79bb08e2cd1e26161f30ee03a24891d1bfa8c212861b51618d07429fb48000ff87ef09c6fca526567777e9c076d58a642d5c521b1caa5fb0fb3a4b8982dc14a444732b72b239b8f01fc8ba8ee86b3013b5d3e98a92b2aeaecd4879fca5d5e9e0bd880dbfffa6f96f94f3998812aac6a714f331",
+	"4d9bf551d7fd531e7482e2ec875c0651b0bcc6caa738f7497befd11e67ae0e036c9d7ae4301cc3c7906f0d0e1ed4738753f414f9b3cd9b8a71176e325c4c74ce020680ecbfb146889597f5b40487e93f974cd866817fb9fb24c7c7c16177e6e120bfe349e83aa82ba40e59e917565788658a2b254f25cf99bc65070b3794cea2259eb10e42bb54852cba3110baa773dcd70c",
+	"b91f65ab5bc059bfa5b43b6ebae243b1c46826f3da061338b5af02b2da76bb5ebad2b426de3c3134a633499c7c36a120369727cb48a0c6cbab0acecdda137057159aa117a5d687c4286868f561a272e0c18966b2fec3e55d75abea818ce2d339e26adc005c2658493fe06271ad0cc33fcb25065e6a2a286af45a518aee5e2532f81ec9256f93ff2d0d41c9b9a2efdb1a2af899",
+	"736f6e387acb9acbee026a6080f8a9eb8dbb5d7c54ac7053ce75dd184b2cb7b942e22a3497419ddb3a04cf9e4eb9340a1a6f9474c06ee1dcfc8513979fee1fc4768087617fd424f4d65f54782c787a1d2de6efc81534343e855f20b3f3589027a5436201eee747d45b9b8375e4294d72ab6a52e04dfbb2914db92ee58f134b026527ed52d4f794459e02a43a17b0d51ea69bd7f3",
+	"9242d3eb31d26d923b99d66954cfade94f25a18912e6356810b63b971ae74bb53bc58b3c01424208ea1e0b1499936daea27e63d904f9ed65fdf69de40780a3027b2e89d94bdf214f585472613ce328f628f4f0d56217dfb53db5f7a07f54c8d71db16e27de7cdb8d23988837b49b65c12f1771d979e8b192c9f4a16b8d9fba917bcf74ce5a82aac2075608ba6c2d485fa59864b9de",
+	"5da68704f4b592d41f08aca08f62d85e2e2466e5f3be010315d11d113db674c4b98764a509a2f5aacc7ae72c9deff2bcc42810b47f64d429b35745b9efff0b18c58653461e968aaa3c2c7fc455bc5771a8f10cd184be831040df767201ab8d32cb9a58c89afbebecb524502c9b940c1b838f8361bbcde90d272715017f67609ea39b20fac985332d82daaa023999e3f8bfa5f3758bb8",
+	"71ea2af9c8ac2e5ae44a176662882e01027ca3cdb41ec2c6785606a07d7231cd4a2bded7155c2feef3d44d8fd42afa73265cef826f6e03aa761c5c51d5b1f129ddc27503ff50d9c2d748322df4b13dd5cdc7d46381528ab22b79b0049011e4d2e57fe2735e0d58d8d56e92c75dbeac8c76c4239d7f3f24fb56697593b3e4afa6671d5bbc96c079a1c154fe20212ade67b05d49ceaa7a84",
+	"1d133170582fa4bff59a21953ebbc01bc202d43cd79c083d1f5c02fa15a43a0f519e36acb710bdabac880f04bc003800641c2487930de9c03c0e0deb347fa815efca0a38c6c5de694db698743bc955581f6a945deec4ae988ef7cdf40498b77796ddea3fae0ea844891ab751c7ee20917c5a4af53cd4ebd82170078f41ada2795e6eea17593fa90cbf5290a1095e299fc7f507f360f187cd",
+	"5ec4ac45d48fc15c72471d795066bdf8e99a483d5fdd599511b9cdc408de7c0616491b73924d0266da34a495331a935c4b8884f57d7ad8cce4cbe586875aa52482215ed39d7626cce55d50349c7767981c8bd6890f132a196184247343566fc972b86fe3c5369d6a6519e9f07942f0522b77ad01c751dcf7defe31e471a0ec00963765dd8518144a3b8c3c978ad108056516a25dbe3092e73c",
+	"0d5e74b78290c689f2b3cfea45fc9b6a84c822639cd438a7f05c07c374adced42cdc12d2a9233a4ffe80307efc1ac13cb04300e165f8d90dd01c0ea955e7657332c6e86ad6b43e78ba4c13c675aed83192d8427866fb6484e6a3071b2369a46fba9005f31232da7ffec7952f831aaaddf63e225263531c2cf387f8cc14fa856c8795137142c3a52ffa69b8e30ebc88ce3bbc227597bcc8dddd89",
+	"a0fe36f983259921dc2fa7d89002b3066241d63bfc2448caf7e10522a35562be0bfedc3dce49cfce2e614a04d4c64cfc0ab898873a7fc26928dc1927c009d12f6f9b7a278205d3d0057604f4ac746f8b9287c3bc6b929832bf253b6586192ac43fdd29ba585dbd9059aab9c6ff6000a7867c67fec1457b733f6b620881166b8fed92bc8d84f0426002e7be7fcd6ee0abf3755e2babfe5636ca0b37",
+	"1d29b6d8eca793bb801becf90b7d7de215b17618ec32340da4bac707cdbb58b951d5036ec02e105d83b5960e2a72002d19b7fa8e1128cc7c5049ed1f76b82a59eac6ed09e56eb73d9ade38a6739f0e07155afa6ec0d9f5cf13c4b30f5f9a465b162a9c3ba04b5a0b3363c2a63f13f2a3b57c590ec6aa7f64f4dcf7f1582d0ca157eb3b3e53b20e306b1f24e9bda87397d413f01b453ceffeca1fb1e7",
+	"6a2860c110cd0fc5a19bcaafcd30762ee10242d34739638e716bd89fd537ea4dc630e6f85d1bd88a25ad3892ca554c232c9830bd56980c9f08d378d28f7fa6fa7df4fcbf6ad98b1adfff3ec1f63310e50f920c99a5200b8e64c2c2ca249399a149942261f737d5d72da949e914c024d57c4b639cb89990fed2b38a37e5bcd24d17ca12dfcd36ce04691fd03c32f6ed5de2a2191ed7c826375ba81f78d0",
+	"7132aa291ddc9210c60dbe7eb3c19f9053f2dd74742cf57fdc5df98312adbf4710a73245de4a0c3b24e21ab8b466a77ae29d15500d5142555ef3088cbccbe685ed9119a10755148f0b9f0dbcf02b2b9bcadc8517c88346ea4e78285e9cbab122f824cc18faf53b742a87c008bb6aa47eed8e1c8709b8c2b9adb4cc4f07fb423e5830a8e503ab4f7945a2a02ab0a019b65d4fd71dc364d07bdc6e637990e3",
+	"3e664da330f2c6007bff0d5101d88288aaacd3c07913c09e871cce16e55a39fde1ce4db6b8379977c46cce08983ca686778afe0a77a41baf447854b9aa286c398c2b83c95a127b053101b6799c1638e5efd67273b2618df6ec0b96d8d040e8c1ee01a99b9b5c8fe63fea2f749e6c90d31f6fae4e1469ac09884c4fe1a8539acb313f42c941224a0e79c059e18affc2bcb6724975c436f7bf949ebdd8aef51c",
+	"7a6ea63a271eb49470f5ce77519ed61ae9b2f1be07a96855726bc3df1d0723af3a703fdfc2e739c9d31d25814daf661a23558b50982e66ee37ad880f5c8f11c8130fac8a5d0250583700d5a324894fae6d61993f6bf9327214f8674649f355b23fd634940b2c467973a839e659169c773119919f5b81ee171edb2e5f6940d7551f9e5a70625d9ea88711ad0ed8ab2da720ad358bef954456cb2d5636425717c2",
+	"c5106bbda114168c449172e49590c7eeb827fa4e1a2a7a87a3c1f721a9047d0c0a50fbf244731be1b7eb1a2ef30f5ae846a9f38f0df44f32af61b68dbdcd0226e741dfb6ef81a2503691af5e4b3171f48c59ba4ef91eba344b5b697f261df7bbbb734ca6e6daebaa4a179feb17002823281b8534d55a6531c59305f6e3fd3fa63b747bcf0deb654c392a02fe687a269effb1238f38bcaea6b208b221c45fe7fbe7",
+	"597716a5ebeebc4bf524c15518816f0b5dcda39cc833c3d66b6368ce39f3fd02ceba8d12072bfe6137c68d3acd50c849873150928b320b4fbc31c1456679ea1d0acaeeabf666d1f1bad3e6b9312c5cbdecf9b799d3e30b0316bed5f41245107b693366accc8b2bcef2a6be54209ffabc0bb6f93377abdcd57d1b25a89e046f16d8fd00f99d1c0cd247aafa72234386ae484510c084ee609f08aad32a005a0a5710cb",
+	"0771ffe789f4135704b6970b617bae41666bc9a6939d47bd04282e140d5a861c44cf05e0aa57190f5b02e298f1431265a365d29e3127d6fccd86ec0df600e26bcdda2d8f487d2e4b38fbb20f1667591f9b5730930788f2691b9ee1564829d1ada15fffc53e785e0c5e5dd11705a5a71e390ca66f4a592785be188fefe89b4bd085b2024b22a210cb7f4a71c2ad215f082ec63746c7367c22aedb5601f513d9f1ffc1f3",
+	"be6556c94313739c115895a7bad2b620c0708e24f0390daa55521c31d2c6782acf41156271238885c367a57c72b4fe999c160e804ad58d8e565edbce14a2dd90e443eb80626b3eab9d7ab75d6f8a062d7ca89b7af8eb292c98eaf87ad1dfd0db103d1bb6188bd7e7a63502153cf3ce23d43b60c5782602bac8ad92fb2324f5a79453898c5de18415639ecc5c7974d3077f76fc1df5b956723bb19a624d7ea3ec13ba3d86",
+	"4bc33729f14cd2f1dc2ff459abee8f6860dda1062845e4adab78b53c835d106bdfa35dd9e77219eaef403d4e80488ca6bd1c93dd76ef9d543fbb7c8904dccc5f71509a6214f73d0f4e467c3e038ea639b29e7fc442ee29f57117740576188ada15a739827c647a46b0271817ab235c023c30c90f2115e5c90cd8501e7b286962fc66ffc3fe7e8978746168314908a41998bd83a1eeffda9d714b864f4d490fdeb9c7a6edfa",
+	"ab12faea205b3d3a803cf6cb32b9698c32301a1e7f7c6c23a20174c95e98b7c3cfe93fffb3c970face8f5751312a261741141b948d777b8a2ea286fe69fc8ac84d34116a4674bb09a1a0b6af90a748e511749de4697908f4acb22be08e96ebc58ab1690acf73914286c198a2b57f1dd70ea8a52325d3045b8bdfe9a09792521526b7564a2a5fcd01e291f1f8894017ce7d3e8a5dba15332fb410fcfc8d62195a48a9e7c86fc4",
+	"7d421e59a567af70594757a49809a9c22e07fe14061090b9a041875bb77933deae36c823a9b47044fa0599187c75426b6b5ed94982ab1af7882d9e952eca399ee80a8903c4bc8ebe7a0fb035b6b26a2a013536e57fa9c94b16f8c2753c9dd79fb568f638966b06da81ce87cd77ac0793b7a36c45b8687c995bf4414d28289dbee977e77bf05d931b4feaa359a397ca41be529910077c8d498e0e8fb06e8e660cc6ebf07b77a02f",
+	"0c18ab727725d62fd3a2714b7185c09faca130438eff1675b38beca7f93a6962d7b98cb300ea33067a2035cdd694348784aa2eda2f16c731eca119a050d3b3ce7d5c0fd6c234354a1da98c0642451922f670984d035f8c6f35031d6188bbeb31a95e99e21b26f6eb5e2af3c7f8eea426357b3b5f83e0029f4c4732bca366c9aa625748297f039327c276cd8d9c9bf692a47af098aa50ca97b99961bef8bc2a7a802e0b8cfdb84319",
+	"92d5909d18a8b2b9971cd1627b461e98a74ba377186a6a9df5bd133635250b300abccb2254cacb775df6d99f7c7d0952653c28e6909b9f9a45adce691f7adc1afffcd9b06e49f775364cc2c62825b9c1a86089080e26b57e732aac98d80d009bfe50df01b95205aa07ed8ec5c873da3b92d00d53af825aa64b3c634c5ece40bff152c331222d3453fd92e0ca17cef19ecb96a6eed4961b627aca48b12fecd091754f770d52ba861546",
+	"802f22e4a388e874927fef24c797408254e03910bab5bf372320207f8067f2b1ea543917d4a27df89f5bf936ba12e04302bde23119533d0976beca9e20cc16b4dbf17a2ddc44b66aba76c61ad59d5e90de02a88327ead0a8b75463a1a68e307a6e2e53ecc1986274b9ee80bc9f3140671d5285bc5fb57b281042a8978a1175900c6073fd7bd740122956602c1aa773dd2896674d0a6beab24454b107f7c847acb31a0d332b4dfc5e3f2f",
+	"3844fe65db11c92fb90bf15e2e0cd216b5b5be91604baf3b84a0ca480e41ecfaca3709b32f8c6e8761406a635b88eec91e075c48799a16ca08f295d9766d74475c47f3f2a274eae8a6ee1d191a7f37ee413a4bf42cad52acd5564a651715ae42ac2cddd52f819c692ecdef52ecb763270322cdca7bd5aef71428fa73e844568b96b43c89bf1ed42a0abf209ffad0eeec286c6f141e8af073ba4adfbbdeda253752ae36c9957dfc905b4c49",
+	"329377f7bf3c8d74991a7d61b0cf39baff5d485d79751b0d5ad017d23bec570fb19810105bab79ab5acb102ab972165224d4ec888ec7de5148077fa9c1bb6820e0d91ae4e2591a21fec2f820606ce4bafc1e377f8dc3a5bd1a9e2772a57abccd0b757164d768872c91d02789545ab5b203f688d71dd08522a3fd2f5bcd7df507aebf1ca27ddff0a82afb7aa9c180008f49d1325adf97d047e77238fc75f56356de4e87d8c961575c9f6362c9",
+	"f7f269929b0d71ea8eef7120e55ccba691c582dd534692abef35c0fe9dec7dae973cd9702e5ad420d278fe0e653fdcb22fdcb63148109ec7e94f2d0750b28157dd1764376ae10fdb0a4aef3b304bd82793e0595f941226a2d72abbc929f53134dc495b0d65ced409914f94c2523f3dfbbdeeac84ae247ab5d1b9ea33dce1a808885a55be1f3683b46f4be73d9b62eec2585f690056858dfc427aabf591cd276724885bcd4c00b93bb51fb7484d",
+	"ac022309aa2c4d7fb628255b8b7fb4c3e3ae64b1cb65e0de711a6def1653d95d8088871cb8905fe8ae76423604988a8f77589f3f776dc1e4b30dbe9dd262b2187db02518a132d219bd1a06ebac13132b5164b6c420b37dd2ccee7d69b3b7fa12e54f0a53b853d490a68379ea1fa2d79762830ffb71bf86aab506b51f85c4b6a41b69325c7d0c7aa85b93b7144489d213e8f33dbb879fce22849865337b620b155cb2d2d36a68832889e30194d36d",
+	"d009c2b78a8f02e5e5dbb586ef71fc324b375092e15913ca1a5bfd22d516baadb96867bee3562e77c4a4852344a1a76c30728be5e22400b4cc41711f66754c246a520498d8c24f0205b9c873748dbeb67fe1ad099ad04cf89f4b517f0aa481136d9f6de2d727df01c6aa4099da59d4382b51e25fd47c33d9842c32b62331e50794bfe8b61b3ba9de1b8b704779c6d65edff3af00f121ab4a7ea384edabe47c6d0098a48991f387ca4444135ec59d46",
+	"c00bab36cce69899817d1425016d222d7303197ed3e3fdcac744705e7f178a1ac745968900f69299163e19b3161f3e0a4cc55aa2e4e71e0ee6ac427d1f4d14e063f68d303ddfbb18118335cfa7a6a90d99c38319ee76f7a884846a9e0b68030bf28e78bfbd56359b9368842814da42b04cb0e307d5d846dc22f049147bae31b9a956d17676a8cc348dafa3cabc2007a30e730e3894dddf9999fb8819086311f0703e141613ed6dcd7af8510e2dc435b0",
+	"c9789152a9fc29698d49ed95f09bd11b75f18a8c5615a73dbe54ae5e550027fd0ae6a8b60667040c1b12de3d1ee3f6bf061c78c951a3210effc912e19f482dd4de152063c588c44903bc11761706fd935afa040df085b08144d83d0dde32b46ab52f4fae98ac116c7ff11d7f553450c2e37b9c5f0b1dd9e0b8640a24cba6f2a5246c41f197f46e3dc8a29131c79bef3351c6e277a0a34442274d546ccd058891277473d668420f121750d19cd684267405",
+	"06a15a0731ce52557e368bcbaa11ef3399299e36fb9f2eda6e5726907c1d29c5c6fc581405ba48c7e2e522206a8f128d7c1c939d1132a00bd7d6366aa82724e968964eb2e373563f607dfa649590dcf5589114df69da5547fef8d1604cc4c6de1ed5783c8746918a4dd31168d6bc8784cd0c769206bd803d6ca8557b66748770402b075ef44b38157d4c0da7c6281725a2065d087b1f7b23455fa673bdeeba45b983311c44eabe9ef4b7bde3420ae9881863",
+	"d08aacef2d7a41aec09473bd8a44f628e15addb7b9e5b77a1e09c8ab4942f379a0bfcb324d580b774666f18ae78dd36710824ff12393f059068fe4b559c53662c2b0e6c69e23785c8f32554e837ec1714bee902e60737b639dd933af4f68cb9d7de77e1f3b28e5b122891afce62b79acd5b1ab4ba411662cc77d806449e69c5a45a143b742d98ac84a0826d68433b9b700ace6cd472ba2d58a90847f42ce9c43f38ffc017db4bf40450b2eee1f4594dc740c0f",
+	"6a6058b0a498b7ea76a93c646eb9b8629f0cba4a0c726420c5f67ba9b0412cade356abdf0a4fb94384bad32ce0d5dd9e23dcaae1d6f28ff8683616b30f1392890c67b3a2c04b360893b801f127e527e4da82e239f4c878da13f4a4f1c76db07190e77ec123995168102fb274434a2d1e12913b9b5cbab4aacaad2bd89d88b3ca2b8e60dacf7c22c9379097ff60880f552e320ca3b571994f52534470feee2b39e0dadb5cd88257a3e459a4cc6f12f17b8d54e1bb",
+	"adeced01fc5671531cbb45679f5ddd42b3a95151677b6125aaf6f5e8f82fbabaa5ecf7c3552c2458587224f0042870f178f5fca5465250e75d71352e652eeed23cdb7f915f5ebb44099b6db116ca1be45530ac8ed32b7f161d60ed4397ad3d7d649ae6bf75ca5bec891d8e595605be9764f3a03965e1fe0eaffbf212e3df4f0fa35e08ff9d0091e6d4ac4748edfe43b611085a6ffec163014655fdd839fd9e81b63b1fa8cae4ec335ec343289758e389a79ceedfae",
+	"d014592f3a83ba40af366f137c674724916c3cdd3f6cf9d4c5c7c8d6d51ebf26e315e2c12b3546be56fb52382904046ecbd2f5b883aa4ff473de6f0c26ab862c3fa34bf3d880cc1911ce39a4088c6617c179dc5faf68a2c488bbde12d67b50f73abcfab0e3b062e68c95363e11f5f1de8ec36ed01ea21442518089045df67d346135283ad5b3fff80cf57f20876849f6db9fa139728358415a90610f69ec720fc92d8234e3e122551e9df2c644c4a2c4e3734d07de8e",
+	"c0d0c37838873ba8757d6e41b409605043bc1635edcd731219587676d94217e9f0ab44b71de25000661ce7303b7015f45e6eaa7b7ebef92b8f4a34c902c908d2172185505fa33aca5a41be83079316cdfdd430fc2c45f505f85d867e6d516f7e1bf19c001d9f43018968aab65ec031b3801399231c83ec9e622dab5629922a6b424cab938c135ff7310501c2c02971bfd2f577e25904d1a618baf0859f77f4e8b1d0cde9544e95ec52ff710c0672fdb3d891feeea2b017",
+	"7022e7f00902219ba97baa0e940e8ac7727f58955aa068c29680fac4a16bcd812c03eeb5adbcfe867a7f7c6b5d89f4641adb9173b76a1a8438866f9b4f640ce2aedf5f1080c890bcf515b4be4e3e512352f1e5323c62ec46cb73f3d71be8235fee55a154763f7c3f9aeb61ffd28f4cd93d3310f608e2133586bf1ab3f102de96f64c68a4668de8acb2a76a7ce0cddddc8fa3df5e9d230823da16ed9ebb402d36e38e6e018795e5a71517ecab5f9ca472b9ced8ff69d2d195",
+	"acaf4baf3681ab865ab9abfae41697141ead9d5e98523c2e0e1eeb6373dd15405242a3393611e19b693cabaa4e45ac866cc66663a6e898dc73095a4132d43fb78ff7166724f06562fc6c546c78f2d5087467fcfb780478ec871ac38d9516c2f62bdb66c00218747e959b24f1f1795fafe39ee4109a1f84e3f82e96436a3f8e2c74ef1a665b0daaa459c7a80757b52c905e2fb4e30c4a3f882e87bce35d70e2925a1671205c28c89886a49e045e31434abaab4a7aed077ff22c",
+	"84cb6ec8a2da4f6c3b15edf77f9af9e44e13d67acc17b24bd4c7a33980f37050c0301ba3aa15ad92efe842cd3ebd3636cf945bb1f199fe0682037b9dacf86f162dadabfa625239c37f8b8db9901df0e618ff56fa62a57499f7ba83baebc085eaf3dda850835520344a67e09419368d81012168e5de5ea45158397af9a5c6a1657b26f319b66f816cd2c28996547d697e8df2bb163ccb9dda4d6691dffd102a13667ab9cde60ffbfb872187d9c425a7f67c1d9fffff9276ed0aeb",
+	"6a52c9bbbba454c14540b2be58230d78ecbeb391646a0c6fcce2f789086a78364b81ae85d5396d7cfa8b46bda41e3083ec5cf7b4c47dc601c8a697df52f557defca248506dbebab25657f5a561d09625b7f4b2f0119a12beeac087efc9d350a735c35d2431c1da7dda99befb17f41a3dc4da0f00bb95366be128538ce27763d81f832fe3c1d4efc07b5b08ad8dc9e65fb5e48546664e18cb2d3bb3fe1f56fa7aae718c5e3bbdeaf70e15023f6a25b72a2d177fcfd04211d40664fe",
+	"c3c4d3b31f1f5f9538923df3478c84fffaef411520a542da9a220ee4132eabb9d718b5076fb2f985485e8ba058330aed27ddfd3afa3db34aa60301088caec3d0053828c0c2bc87e2e61db5ea5a29f62fdad9c8b5fc5063ec4ee865e5b2e35fac0c7a835d5f57a1b1079833c25fc38fcb14311c54f8a3bd251bca19342d69e5785f9c2e43cf189d421c76c8e8db925d70fa0fae5ee3a28c4047c23a2b8a167ce53f35ced33bec822b88b06f41558c47d4fed1bfa3e21eb060df4d8ba1",
+	"8d55e92136992ba23856c1aea109766fc44772477efc932b3194af2265e433ed77d63b44d2a1cff2e8680eff120a430fe012f0f09c6201d546e13ad46fc4ce910eab27bb1569879abed2d9c37fae9f1267c2216ec5debcb20d4de58461a621e6ce8946899de81c0add44d35e27b7982a97f2a5e6314901caebe41dbba35f48bc9244ca6dca2bdde7306435892f287036df088633a070c2e385815ab3e2bfc1a47c05a5b9fe0e80dd6e38e4713a70c8f82bd32475eea8400c7bc67f59cf",
+	"5016284e20362610fa05ca9d789cad25f6d43263787e7e085476764ce4a8908ce99b262b375e9d106170b1bec1f473d5e777e0c1896533040e39c8c1465e07907ef5860e14e4d8310013e35f12090e0bfc687474b1f15f3dd2033a0edac5246102da4deec7e188c3517d84d9c2a0a4497a4c5f82a30f1ba009e45ee6eb3ab4368c720ea6feee428ffd2c4cc52debb8d634a64176572c72368f94a66689f23f8a01218f532117af5a8060d140e7ca435a92882fcb5630ebe14a4805f1dc83",
+	"05456ec59b8d41bbd736727976b96b38c43827f9e16169be673ff37870c2ecd5f0d1ea1a136be4cc7b047a02a4421d484fd2a12ece418e42ee391a13a0b1df5a0162b29ab70d3fe3e04ba6ab26b37d62b7cf05a5e2f033611bf970b8e1f30e198e483e740fa9618c1e8677e07b61296b94a9787a68fba622d7653b5568f4a8628025939b0f74389ea8fced6098c065bf2a869fd8e07d705eadb53006be2abb716a3114ceb0236d7e916f037cb954cf977720855d12be76d900ca124a2a66bb",
+	"eb6f60b83fcee77060ff346aaf6ec34d82a8af469947d3b5074cde8eb26566eb1fa039bcc707738df1e95869bd827c246e88436f0614d9834ead5392ef376105c4a9f370071cdeaaff6ca0f18b74c3a48d19a717253c49bd9009ccbfdd5728a08b7d112a2ed8dbafbbb46d7a75dc9a05e09bfde1a0a92d74a51887f9d123d7896e9f9d0057b660ed7d55454c069d3c5260411db4cdc67e7b74f680d7ac4b9dcc2f8baf72e15e6b3cafebcdf449a6436ed2c398b675f79c644747c57553bf7ea2",
+	"187a88e88514f6c4157c1ba40b442baae1ae563a6c989277443b12a219aa484cb9fa8adbb9a29d429f50155321b15664926317477079c7060dfdaa84c1d74bba78892c34e6f21ad35208d2ae622012401696bff5cd57b6485944b3db7b9071fa5f57fbfb1085d91bb9cff5808d662cdc6c8157249478262c44b7fbc397ed42a4977b202e817717bfccc9f0467294062313f7705251ed09573f16d23429361fada259dfb300369c4198f07341b38e84d02cdb74af5de6aab1fc2026208ea7c418c0",
+	"be31bc96606d0fab007e5caeded2f1c9f747c759777e9b6eef962bed49e45a1d4fc993e279d024915e600865ecb087b960584be18c41114d3c43f92169b9e0e1f85a0ebcd4e196376ccdc920e66103cd3b1c58407d0aafd0e003c4e341a1daddb9f4faba974362a32f35db83384b05ae8e3322d728893861afd8b1c940de5a17f691e763ce4969b6d94f67fb4a0235d100225bd8602f291388f0ca4a568748ad0d6040f1262eac2aede6cd27419bb78a394c1ffad72c262be8c3f9d9619d633e51d0",
+	"4d83d85ca838b4518588f2a90228a4dd18f14dd5b4c012d26298a97d848abbd825d221d02cceb6e8c701b4ad00e1dee4889b5c533e4bb60f1f41a4a61ee5478be2c1b1016c30345afd7a5253668260515e70751f22c8b4022d7fe4877d7bbce90b46531507dd3e89549e7fd58ea28f4cb23d33662bd003c1345ba94cc4b06867f778957901a8c441bee0f3b12e16463a51f7e50690356971dd73a686a49fda1eae46c9d54fba262811d698025d0ee053f1c58591c3bb3cbde69de0b31549ef5b69cf10",
+	"cdeb07d36dc5f9a1cd717a9e9cca37a2ce93caa298eee63571f7d6c5fde2a11c666cf53cf2dcb41ca2ea2319e7230ca68e38c647905928713a13982bf47fe33d7095ebd50b2df976208920a43eb2e29b942f32467403c45cea18bf44e0f6aeb155b48a8e5c471fec972a9d62f7ae093d2758f0aaec7ca50cb4725bfa219f1a3a46ad6bde7361f445f86b94d66b8ece080e56c510250693a5d0ea0ae87b4421860b853bcf0381eae4f1bf7c5c0472a93ad18407bc88475ab8560d344a921d3e86a02da397",
+	"a598fad52852c5d51ae3b10528fc1f722e21d44fbd42ae5acdf20e85a28532e646a223d27fd907bfd38eb8bb75175636892f8242877aab89e8c0824d368f3339ce7a82aa4e5af6db1f3b588a4d667a00f67bee37cfd2724dde06d2909fb9e58d892f4cfd2c4ca85acdf8256f5458b030a6bda151154ff2e6d7a8da90b54a2884c8a99fab5a4ac211ff23dc0975f4f592fd1b6b9dc7783bdcd2d4ca4e68d2902f2013e122cb62e2bff6b0a98ec55ba25837e21f1cfe67739b568d43e6413dab2bd1dc471e5a",
+	"17b68c74c9fe4926e8102070916a4e381b9fe25f5973c9bd4b04ce25749fc18931f37a65a356d3f5e5a1ef125d546f4f0ea797c15fb2efea6fbfcc5739c564693d47adeb12dcb3d98a2830719b13247792cb2491dca159a28138c6cff925aca42f4fdb02e73fbd508ec49b25c60703a7595a3e8f44b155b371d525e48e7e5dc84ac7b17c52bf5e526a67e7187234a2f19f57c548c70fc0b27183df73ffa53fa58b658034c896fa791ae9a7fd2620f5e46ce84c842a6e60e9324ae4db224ffc87d9617cb85ca2",
+	"b9e4267ea39e1de1fed0579f93bb351007c9f8fcdd811053fae33f09e2753d7428f04e1a9efcd45ea701a5d87a35b3afb2e6b65365dee6ead0bbb611b7797b212ac688653f542e604a39df277f12514ddfee3b4e27b98395c2cd97a203f1f1153c50327965770802ec2c9783edc428271762b275471e7ac65ac36523df28b0d7e6e6ccc7674268a132a63411fc82c0738dbb68af003b769a0bf9e6587b36476cb465350fee13f88ea355d47ffac7b0f964f4139db11b7642cb8d75fe1bc74d859b6d9e884f75ac",
+	"8ca704fe7208fe5f9c23110c0b3b4eee0ef632cae82bda68d8db2436ad409aa05cf159223586e1e6d8bdae9f316ea786809fbe7fe81ec61c61552d3a83cd6beaf652d1263862664df6aae321d0323440430f400f291c3efbe5d5c690b0cc6b0bf871b3933befb40bc870e2ee1ebb68025a2dcc11b68daadef6be29b5f21e440374301bde1e80dcfade4c9d681480e65ec494a6af48df232c3d51447b9d06be714949249c44c43cf73ed13ef0d533e770284e51369d94ae241a5fb2f163893071b2b4c118aeaf9eae",
+	"4fd8dd01012bb4df82bf42e0683f998e6f52dd9c5617bae33f867d6c0b69798cead8179346d70acc941abbbdd26e3229d5651361d2252c72ff22db2938d06ff6fc29a42fdf800ae967d06479bc7bbb8e71f40b1190a4b7189ffc9a7096cdb76d40aec424e1388e1eb7ef4ac3b34f3f089da8fda7d1927f5d775c0b2801d22dd1265c973158f640cec93edfed06dc80b20ef8c496b98289d54d46ccd205951cbb0f4e7daeb866b60bacb483411e4382b6f04d472843186bd0e31fbaa93e5c901ec028efafeb45fc551a",
+	"e9ee1b22b04b321a5fdd8301627011f583887d77560fb0f35552e207561f81e38ac58a0d0aeaf832d1ee72d913720d01f75574e9a321864fe95f4d0d8f0b8db97649a53e71e940aede5c40b4b9105daa42a6fb2811b61209247534cbaf830b07abe338d75d2f5f4eb1c3cf151e9edabe2c8d5f6fff08fac1495ef48160b100d30dcb0676700bcceb28723a29980ab0766a93abb8cb3d1963007db8458ed99b689d2a7c28c788743c80e8c1239b20982c81dadd0eed6740c65fbc4ef15c7b5569cb9fc997c6550a34b3b2",
+	"ec01e3a60964360f7f23ab0b22e021815765ad706f242265ebc19a2bb9e4eac94393952dcf61aae47682671a10f9165f0b20adf83a6706bfbdcf04c6faba6114653a35584267267873291c6fe7ff5f7695243143421509502c8875aafa9e9afe5be5ef2c851c7f35d69be5d3896000ccdbbfab5c238bb34d607cfe2d55d748880545b4aa7ca61137992925189025c62654b1f20d49c3ccd75aa73ce99cd7258dabedd6480a9f5185531fc0118beb68cc0a9cd182f6973287cf9252e12be5b619f15c25b65c71b7a316ebfd",
+	"db51a2f84704b78414093aa93708ec5e78573595c6e3a16c9e15744fa0f98ec78a1b3ed1e16f9717c01f6cab1bff0d56367ffc516c2e33261074935e0735ccf0d018744b4d28450f9a4db0dcf7ff504d3183aa967f76a507357948da9018fc38f150db53e2df6cea14466f03792f8bc11bdb5266dd6d508cde9e12ff04305c0295de29de19d491ad86e766774bb517e7e65befb1c5e2c267f013e235d8483e177214f89978b4cdc81aa7eff8b39f2825ad3a1b6ac1424e30edd49b067d770f16e74dd7a9c3af2ad74289a676",
+	"00e40f30ae3746edad0f5dd03d0e640933cf3d1694804c1e1ed6399ac36611d405196ee48f129344a8512feda16a354517871322bd5d9c6a1b592933eab531923efb393ffb23d9109cbe1075cebfa5fb917b40df028a621460ff6783c798792cb1d9635b5a6f84ec13918fa302924649b5c7fcb1f7007f0d2f06e9cfd7c27491e565a96c68a0c3644f92cd8f38857258c33801c5d537a83dfe583cba59d7eec7e394199c0a2660a62fabe3ed2099d57f315a6cd8de1a4ade29d977f15d65759cff433e5ac0c182aef3761163e1",
+	"3c5ea24d0d9b618294a263f062b2414a722be4eb10dfc346a6ec3b821d7396eba61cd6ef33618b04cd087a811f299d4606820227f16000d7c839062b96d3e3f59cd1a082448d13fc8f56b3fa7fb5f66d0350aa3b72dd7c165d590282f7da2e12cfe9e60e1796122bb8c2d40fdc2997af634b9c6b127a893dfb3467909378300db3da911be1d7b616bb8e0572433e65527e15d936500a2c60e9f9909dcf22ab5e4b6700f0238c205b4a813626fac3d945bab2637fb08203044a73d20c9a3fcf7c3fc4eb7807c3276dd5f73ce89597",
+	"9271aeeebfac46f4de85df78f1bfd36136aa8905e15835c9e1941176f71e3aa5b1b131843d40479735e23e182a2bd71f66f6149dccb7ed8c16469079dc8590bbf165374951785f4531f7e7361de62f936cfb23a2b5bdf186632e7042a0dd451fdc9b7208f923f3a5f250ae590ec348c63a16c3aacaf7379f53b5dd4152dcd40d23e683e2156e64c592ffc07e2cd6bbeebef4dd590b2f6b2bcbf08fcd111c079f5c4033adb6c17574f8756ecd87be27eff1d7c8e8d0324438d59ae171d5a17128fbcb5533d921bd044a2038a5046b33",
+	"4e3e533d5bcb15793d1b9d0468aaee801f32fdb486b11027183553a09ddbee8213924296f2815dc61577297459e834bf1c7a53f87d43782209e589b8295219ba7073a8fff18ad647fdb474fa39e1faa69911bf83438d5f64fe52f38ce6a991f25812c8f548de7bf2fdea7e9b4782beb4011d3567184c817521a2ba0ebad75b892f7f8e35d68b099827a1b08a84ec5e8125651d6f260295684d0ab1011a9209d2bdeb75128bf5364774d7df91e0746b7b08bda9185035f4f226e7d0a1946fcaa9c607a66b185d8546aac2800e85b74e67",
+	"b5d89fa2d94531093365d1259cc6fe8827fea48e6374c8b9a8c4d2209c280fa5c44958a1847222a692a59e6aa2696e6cdc8a543dd89b0ce03bc293b4e78d6ef48e1839694ccd5c65661143095c705b07e3ced84a0f5959114dd89deb956ab3fac8130eb4a878278205b801ae41a29e34146192308c4e759b374757b0c3b00319bce92a1b95a4d2ee179fd6714ff96155d26f693a5bc973f84ac8b3b91e3926276297532d98b46992a3f104c08100bf1671c43134bac280c617da711e90a0100137525375ebb12802a428885ae7fce6514a",
+	"40e3d8048fc10650cb8a7fc2e7113e26dec34f9ca2d5129cd10a8e8e44d113d61ee48c7d003e19fd307fc6debd70feb30243f298c510ccc4418355ce143066f067ad7c6de7288c3080e7ad46a23c8d34deb55a43e652fe90444ad3c57d3ec1e1c489d63ef915a24bc74a7925a0a7b1e1523f21ca8fee78df24e3d0a68d0013423db97c280799a0618229c0f2c167289a891e5c8d6661ab21285951c31710e3b5fe55f6347fe16d9b40507948a59252efeb616df83e5c098b07d0a7247cd371daff0e50491c582503fd89f79ba94d6af9ed76",
+	"1fa444de01dd3901e2b4684e3d7a799ffa02d85afd35fb30fe4c9d672837bee6dd8a3b8608b4bb5e589220ad5a854f46b46e41c6d57ad124a46beab4169ff69fee7e3838a6165e19dad8eb5d7bf53d4edd3cd2769daf219510a02fdd2afe0c0e1da3cd30fcd1aa88b68965586f07a25a1720fbd90a096ea30fc8e945e3637d7857c8a9c0ab4154ffb2000e57b5f9adfa4e4eaf8065bc3c2b2e75f495963325588785a6ce417dcddffd299873b15dcccca128d63cd4eeeadb64cda28099a9ad7c80d34844901f26b88b00b9aafeb2f90286d29d",
+	"fde0a0d9d813983bd1f55cf778a003a2023b34a555322ab280584537bc6bdd844d22a7d6066c18da83ec09f3d8d5a1aab4be0d5ce19b436052f6e259a4b49017a1f47f1fe2bf115d5bc8599fb216351c60dd6b1bedb2e6f4dcadf424b833501b6f099cbfad9e2290680fb69c25032b42a6274f7cb9b5c5950401354838a45f7cb77b95bf54718e2f3d3d9fb91eb2311903980277396398d9736d8e92fd838594ac8a537c6c529db5a8a4f89290e6ba6f20ac0e5ed6fef40901d0e0e8e3e502990811f9acaae555dd54eb1bcd96b513e2fe751bec",
+	"9f8e0caec87858599f5ab29bff86da78a841a918a023a111098687ecdf2747612d3f3809d9ca400b878bd4f92c43a1004f1c17c7f19a3cd1ce449bd2b23aff551623c37dd8c0be56bf3fd857b500c2b9f9ccea62481944090a3cf3b6ee81d9af8eeb60f65ef150f9fa4d3ed6ce4762d3d4f174ee8ccd460c25cafac0ea5ec8a6a4b2f9e8c0520cb7061155e532cb65f188b01e4b9086db951f504b060c296b326b3fc1c590498ecce594f828f4a10ea416675720ae505295d38a791bd0e93f428448a8f4c1fc0af53604a9e8255384d29ae5c334e2",
+	"33d1e683a4c97ee6bbaa5f9df1a88cb53b7f3c157b6045d70a56fda0ccbd3a1fa1f049cd564da072b53f415bf5fb843771c1d2551fd075d33377362b2f7c0645f9723123d11975991db8a2b518f02e2c7c30342a044754290bae2c77496d755e5981f12e6b0a0174280b958bf11ed628a9062775993ced04bf752ea8d165e3ac2177d7cd1b9371c44efa98f0b3e68602a839d384eec007979f46429dafb138cbc231ad928a9f65f7d66fac77416395e8f1debaaf76ec2e4e03e8674102cd26f614739f3ec9f949033df1fb97e87c2326d65aef94ed5f",
+	"180048f09d0b480887af7fd548a85abf605440c1ddde6afe4c30c30670233f7bf928f43b4681f59279ebbda5e8f8f2a1abefdee129e18ac60f9224e90b38b0aabd01308e0a27f41b6fb2ee07ee176ec9048c5fe33c3f7c791469c81f30e28170585b9f3e7e3c8c2e9d74370cb4518f13bf2dee048cbd98ffa32d85e43bcc64a626b40efb51ce712925fdd6fee006dc68b88004a81549d2121986dd1966084cd654a7c6686b3bae32afbd9625e09344e85cf9611ea08dfce835a2e5b3726e69ae8a76a97db60fcc539944ba4b1e8449e4d9802ae99fae86",
+	"13c0bc2f5eb887cd90eae426143764cf82b3545998c386007cca871890912217aa143ac4ed4ddb5a7495b704aa4de18419b8664b15bc26cfc6596a4d2ae408f98b47a566476d5802d594ba84c2f538def9d016661f6404bb2337a3932a24f6e30073a6c9c274b940c62c727242e24466084a3ea336365d71ea8fa6499c0ea8d59eea505f1126b99c795023c4963aa0d99323d0391e8701110edf551b2d3799e1063ca443f1add162156e445502ca1a052fe70c289838593b58839fc63de128a03e2bbf389e22ae0cf957fd03315ee407b096cc1cfd92dee6",
+	"6f1eb607d679efef065df08987a1174aab41bdac8aece7726dfa65805d6fff5b3d17a672d96b770dc32165f144f0f7324822a5c87563b7cd9e37a742ae83ef245d09006d91576f435a03476f509ea2936636232f66aa7f6cdf1ac187bbd1fcb8e20f8791866e60ed96c73374c12ac16795e999b891c64507d2dbd97e5fc29fac750ad27f2937cbcd29fdafccf27ab22453834d475f6186eaf975a36fad5c8bd61c21da554e1ded46c4c39765dcf5c8f5ccfb49b6a4dc562c919d0c7d8940ec536ab2448ec3c9a9c8b0e8fd4870cad9de2577c7b0c38563f355",
+	"dcdd993c94d3acbc555f464871a32c5da6f13b3d5bbc3e34429705e8ad2e76393fdd96a69a94acb652f5dc3c120d41187e9aa919669f727c4868013b0cb6acc165c1b7706c52248e15c3bf81eb6c147619467945c7c48fa14a73e7c3d5bec91706c567145342a026c9d97eff97ec672c5debb9df1a998083b0b0081d65c517b3e5634c95e347e781aa30ca1c8af815e2e494d844e847fdcb41622894a518dc36571123a40bfdbe8c4f4cff44d83c61dd9dcd24c464c53b395edb31efee9f3aa080e87cdc3d22d613ae84a53c9249c32c96f9a3bc4629bb126a70",
+	"49971f9823e63c3a72574d977953329e813b22a8387cd13f56d8ea77a5d1a8a20012632d1d8732bbcb9f756b9675aab5db927beacab7ca263e5718b8dfa7b2eed9a91bf5ed163b16139d45f7b8cc7e3f7bdda6202106f67dfb23b7c315ee3e17a09d466b1e6b13e7c7428184a979f5358667b4fa8bd40bcc8ea46058db44587a85377ac46bf155136c09ac58cb6c27f28e17028c91e7e8f74d5b500e56293b316974f02b9d9ea205d9b6ac4cfb74eb8eb0c944577fd2f41316368307beab3e327bf7dbaa0a4428836ec4e895dea635234abeaf113ceeadac33c7a3",
+	"c57a9cc958cee983599b04fe694f15fb470fcbc53e4bfcc00a27351b12d5d2434444253ad4184e87b81b738922ffd7ff1dc1e54f39c5518b49fb8fe50d63e3935f99e4bd125e8dc0ba8a17fd62de709339a43fabe15cf86d96a54010112170c340cfac4132182eed7301402bc7c8276089dec38488af145cb6222525894658f03501204b7a66aba0be1b557b28a2f652d66f7313ed825ecc4d8596c1be7420d4425b86a1a90a5b7f30d0f24e0d1aae0eb619ca457a71699e44be612a4011c597ee80b94d5507e429d7fc6af22579cd6ad642723b05ef169fade526fb",
+	"0568a672cd1ecbaa947045b712e2ac27995392fbef8f9488f79803cbee561c212287f080eca95adb5ba42739d78e3ba667f06045d87850d3a0499358649caa257ad29f1a9c511e7054db20554d15cbb55ff854afa45cae475c729cea72ede953522031865bc02b95589ed4d9841c552a8cc94904a93ed09ed77222f6c178195056be59bc4e96a815adf534e6b466fb47e262ff79c803c157a21b6e2269c2e0abeb494113cd868d8466e82d4b2f6a28b73645853d96bc9242515d803e33294848d3fe42fdff68da53c03491636beede47ff1399dd3d54a5e914d55d7adf",
+	"3f19f61a4cd085796731ac9f85a75a8bce77031932c31762d87d8b8d07b8bd19ff78d6b7d1bd1e87f3a4f41aad03b6c4d17a6cbc86be55f7c8b88ada047bb04f8d49f1c34bcf81cc0f3389ad01a758fc7eeb0072aa9ad1481992bfdde82e438e75590a4423832dfbe3756e2229ea873bc3606e6d72174cb2163bf40b5d49c81009dab85ecc03e311351bbf96e32c030a2b276a7698cb25bc2c967acb3213161a1fdde7d912cd6a804490f8056c47da1333f6e35c41e749c2c23919cb9af5eec5652e6e072b034fb1682e9aaa194a9c0bd456ea0b008d14dbce37967a7a8e",
+	"705f98f632d99d3651793825c38dc4deda56c59eac539da6a0159c83131cf8ab6f2ee0c3b74111fde351f7aa1a8c500a0cecab17c212d2c58ca09eae608c8eefc922b9902ef8d6832f799ba48c3c28aa702b3242107edeba01daafe424406a3822965056cfe8783455a671e93b1e2eae2321364f1871471c82124df33bc09e1b52882bd7e1c4c7d0b2f3dd4a28c2a002a43246768af0700f9659de99d62167be93177aabf19d678e79e9c726ac510d94e74873eda99620a3961930cd91937c88a06d8153d64fd60da7ca38cf26d1d4f04a0df273f52127c53fdc593f0f8df9",
+	"ea6f8e977c954657b45f25480ff42c36c7a10c77caa26eb1c907062e24fbca5aebc65cacca0de10abea8c78322f08672e13d8ac16996eca1aa17402eaea4c1cc6c800b22dc18cb8d620192d74bac02c07b5cfa61e513c7f28b7e29b9700e0e442720bf4c669d4995da19d19f841d9eb68cc74153592591e3bf059ef616b95305aa453b32fe99a91afb35bd482cf2b7aa42702837a53be3c38883d2963020e347556f841254ec6b85854485fe8c520b05f2ea67a9bf3981555c20991e2bacd4db5b418228b6002d8d41c025cb472bf5443aaa885974a408ea7f2e3f932c600deb",
+	"408190134ed06556811b1af808ab2d986aff152a28de2c41a2207c0ccc18125ac20f48384de89ea7c80cda1da14e60cc1599943646b4c0082bbcda2d9fa55a13e9df2934edf15eb4fd41f25fa3dd706ab6de522ed351b106321e494e7a27d5f7caf44ec6fadf1122d227eefc0f57aefc140d2c63d07dcbfd65790b1099745ed042cfd1548242076b98e616b76ff0d53db5179df8dd62c06a36a8b9e95a671e2a9b9dd3fb187a31ae5828d218ec5851913e0b52e2532bd4bf9e7b349f32de2b6d5d3cdf9f372d49617b6220c93c05962327e99a0480488443349f0fd54c1860f7c8",
+	"5f9e5c6f38573a85010a9d84d33f29c057003b2645e3ea6f72cbc7af95d197ce6a06b13fea81722853e6991791b8b15091cd066f5ed913592ed3d3af5370d39ba22beeb2a582a414b16824b77e194a094c2afdcc09aa73ce36f4943cca5ae32c5017dc398801dd92a47382d9327c9f6cffd38ca4167cd836f7855fc5ff048d8efba378cdde224905a0425e6b1de061fc951c5e624a5153b008ad41160a710b3ff2081748d5e02deb9f841f4fc6cf4a15153dd4fe874fd447482696283e79ee0e6bc8c1c0409baa5ab02c5209c319e3169b2476149c0c6e541c6197ca46e004eef533",
+	"218c6b3508aec69574f2b5039b30b942b72a8349d05f48ff945bbbe5c8957d5a6199492a6bf54bab821c9377e2edfa4c908384664d2c80112d5e805d66e0a551b941021be17dd20bd825bea9a3b6afb1b8c605805b3bda58750f03ea5c953a698494b425d8980c69f34d1c3f6b5866e8717031152a127215c256e08873c21b0f5cc85875d0f7c94601659150c04cd5fe5d381ba29983a2d94fcd3a65a94c53c7279cd000dddd4253d8cff8d7f6ace10247fe3bc30d63ba4bb54f557b3d22a3924369430d71ab37b701e9500bda70b5a643704858beed4726a889b6c9c91584194c68f1",
+	"dac26aa7273fc25d6e044c79fc2bfa46e59892a42bbca59a86826c91e76ab03e4bd9f7c0b5f08d1931d88b36ea77d94f7ba67cd4f1d3086e529427201119096ae066ae6f170940830ed7900de7bb9d66e09788287403a4ecc93c6da975d2fb08e918840a236c15f5d3a8f7375c2eeebbf6f01a6e7f29ca2b8d42df158414c320777433663c59fdcd1f39ca68e3473db721be7ce8c6dba5fddc024f94fedb286b0477581d451313ca8c737484daf60d67f9b2d56d4bcc271f7e9ae958c7f258efbc74d25753e0516f28282461941bf2dcc7dd8c7df6173b89760cefcac07190243ff863fb",
+	"c46e6512e6797cc7a54254a1b26b2de29aa83d6c4b1ea5a2786fbcec388270625b12635eae39e1fba013f8a65219421bca8b52a8ddfd431cda60299bdf160734d5a7450ec79620058522702174ae451b9bfa7c4a455fbbee3e1d048c7d4bac5131018228f137c8e130440c7059b4f15eaa34ce872a851a16ce86f982df78a00be4d564da2003a450ddee9ab43ea876b8b4b65c84f0b39265fd5456417afb5bc54997c986e66fc222f2123ba5e719c4d6b9a177b188277df384f1125821cf19d5248cef0be183ccdc84ac194506f740ed2188b2689ea4c9236a9e9e3a2fff85b6af4e9b49a3",
+	"1ccd4d278d67b65cf2564ecd4de1b55fe07adc80e1f735fe2f08ea53fd3977323689122c29c798957abaff6aba09bdcbf661d77f4dc8913ab1fe2bef38846166e3834785e7105d746484eff8c656af5d8c7854abc1c62b7fadb65521dc6f793d978bda9838eb3800417d32e8a24d8c8cb1d18a5de6ca79d9e1b0ff9aa25e6218fe944cf18666fecc1e31334b390260dbe0997539e1b02f6366b2aea4f4a21efe04f4b97568fcb39e59919d5ebac6543d5d0f48fc66b923c34aac377dc95c20329b837b6ed5e8d9a3d2089cd0d8f025658006ff41cbdaccca618822ca590ab155253f8bc1c7f5",
+	"9875209588395ee3c9fdd793fd48717cc84c8c3ea622b2ccc4a1be4448e6034b7810569855255031f10be5ffd714b05f9ce01972d712d40abf03d4d0ce175813a7a668f761324996093fc2aa5912f7fc2abdadd8775d2b4d9ad492216293381460ed8f6db3d641d1525f4242c348bbfe504c704f215dc461de51b5c75c1aae967936963848f16c673eca5e78dfd47eb19001d52d1bcf96c98956dad5ddf594a5da757e7ca35f2f69803b784e66ac5a58b75c228b8266ec592505e5d1ca87d81225738855f15bc0914677e81593fd409e77d159f8a908f67788de9eb06c5561547aada96c47c535",
+	"40c90e375e366f3756d89091eb3eed9fe0fbfc5638700af4617d358812bac53124a2205dd6756456787d49cd6a35e302479a0992288f47532e4ea7ab62fc5ad5adc690a5d9a446f7e035ad4641bd8dae83946aee3338ec984ccb5cc633e1409f2531eeffe05532a8b0062ba99454c9aeabf8ecb94db195af7032bfebc22912f49d39330add47ff8fa5720612d697f0b602738930e060a1bb214efc5e292224cf34e29deaea6b1b1ff847e94ecc997325ac38df61db45d82bf0e74a664d2fe085c20b04c39e90d6a170b68d2f1d373f00c731c524456ada73d659aaac9df3191a7a3865083343fc13",
+	"e8800d82e072210ca6d7fa2472028974780b76aad4bcb9ad362422dd05ae3232668251d164daa375a43b26a38cce28dbeb3dee1a4a579f70d0fe7febb29b5ece8aa836e050fb3d188c63aa9c3c0da6c717d86458a6096b5effceb964efdec7035960c09ccd10dea3c5f1c7f9f478d5887ebbe2e15c5ff85dbacbc444bb951c4eec7abecb89ed80187e409e2972ffe1a5f01562af109f2cf09471cf72cf83a3bb8f4e2ef38ed0e326b698296394e5b2718a5000c01425708e8ad0461e62462d8819c2377f13ab1be2c7c9f33dc06fe23cad27b87569f2ce2e56e4b2c60c7b1b3d370841d89ebdc1f192",
+	"796d6d1447d5b7e8c55cd8b2f8b7010db39f27565f907e3fc0e464ea2d4bb52b37f10e7c6dcfc59231b9cdee12c32aeb4adbc42b86e86eb6defb5b69e6ca75e1f4d0dae3e124e5a1b8b6697f7e10b0403f1f0a5ff848eef3752837a9ba17780f16a9a709188a8d5b89a2fa74adb2e651163b1c2b3d261e225c9158dcd9eb7ac3d6704cee290cdff6bcb3cb90cee030aa0d19d4693655c3c30ac6fc06d2ae37787c47126d57ed9a6bef5f8a6c56859aefc08755739a95aac57a4dd916a92ba9f3afbf969df8085949615033365c751a9a3e1a18cee98a69d22e64009bebf8307169b6c61de0617ecfafdf",
+	"4f9057183566153cf337b07c3f5556006de54c56b2a1e5326c07aaeabd1886ec6f1641358925db232b2f0dbf75229c796a7395b2f934c1f99090bec1123f3c841b1cb3c5b1ec42ed5408f2940f0c48a9470b852c46d6557853d459cecd2c32bbcd8ee21fa11e385eef0857cba4d8545a61b52a484cdd779db4739fbc7aa9860dcabe0488b98fa0b60c3f7d6153db279000a52ffb573dab37d2ab1896a90e5deb7ac6bbe56239085c325d83a917dc6e8a448425b718c2356b9f3066163555ec444f372e184e02c8c4c69b1c1c2ae2b51e45b98f73d933d18750968945ca85d6bbb22014b4c4015262e3c40d",
+	"79dcca7d8b81a61359e4aece21f3df7b99518ce70bd2f57a18bab5e7114af2add0a0cea7f319d69f231f060e0a539d9a23fb3e95451ce8c6340cfb09edf931df84203a39226dd9eb278f11b691ef612585b973daab373e65d11325898badf6732100371fd759960fa8fec373268421d28bffdb9b12a430b92fe4b07566ca0c89e616e49f8fc75ccd9cdc66db820d7c02e109aa5ed86b89770262918a518f90a2292f6b68d68ae03992e4259a17a23c84ec2a417f082b5abf3a26e44d2278ecb8ba9456965303a75f25394d1aaf5544590e74b14d8a4cc4050be2b0ebcfe4d2db6b12a02c68a3bcdda70301f3",
+	"848755dc31e25e9a42f9ec12d847d19f292c14c162c9aba49e972cb123b58b8e57bb263a923929833373858594ff52dbc298dbbc078599194e4c07b0e5fc1e10808bbacdb6e93c72b333685cf961f28eb0d5a395c63266b01f130d25db384b356e5da6d01042fc2359581b89c63b3bb2d1ce897fbc9e83fe85d9666cb60e6a8c657f70caad5387b8a045bf91095606802c8424ea8ac52ef29386dc46183378a5fcb2cb927428b8c070f1c42aafd3bc70ca25437807696a46873cfeb7b80ba2ebc3c4272443d445e46343a1465253a9eebd532a0d1d2c18264b91ff45159f245404ae9335f2af55c802772426b4",
+	"ecaa6e999ef355a0768730edb835db411829a3764f79d764bb5682af6d00f51b313e017b83fffe2e332cd4a3de0a81d6a52084d5748346a1f81eb9b183ff6d93d05edc00e938d001c90872dfe234e8dd085f639af168af4a07e18f1c56ca6c7c1addffc4a70eb4660666dda0321636c3f83479ad3b64e23d749620413a2ecdcc52ad4e6e63f2b817ce99c15b5d2da3792721d7158297cce65e0c04fe810d7e2434b969e4c7892b3840623e153576356e9a696fd9e7a801c25de621a7849da3f99158d3d09bf039f43c510c8ffb00fa3e9a3c12d2c8062dd25b8dabe53d8581e30427e81c3dfc2d455352487e1255",
+	"23a3fe80e3636313fdf922a1359514d9f31775e1adf24285e8001c04dbce866df055edf25b506e18953492a173ba5aa0c1ec758123406a97025ba9b6b7a97eb14734424d1a7841ec0eaeba0051d6e9734263bea1af9895a3b8c83d8c854da2ae7832bdd7c285b73f8113c3821cced38b3656b4e6369a9f8327cd368f04128f1d78b6b4260f55995277feffa15e34532cd0306c1f47354667c17018ee012a791af2dbbc7afc92c388008c601740cccbbe66f1eb06ea657e9d478066c2bd2093ab62cd94abadc002722f50968e8acf361658fc64f50685a5b1b004888b3b4f64a4ddb67bec7e4ac64c9ee8deeda896b9",
+	"758f3567cd992228386a1c01930f7c52a9dcce28fdc1aaa54b0fed97d9a54f1df805f31bac12d559e90a2063cd7df8311a148f6904f78c5440f75e49877c0c0855d59c7f7ee52837e6ef3e54a568a7b38a0d5b896e298c8e46a56d24d8cabda8aeff85a622a3e7c87483ba921f34156defd185f608e2241224286e38121a162c2ba7604f68484717196f6628861a948180e8f06c6cc1ec66d032cf8d16da039cd74277cde31e535bc1692a44046e16881c954af3cd91dc49b443a3680e4bc42a954a46ebd1368b1398edd7580f935514b15c7fbfa9b40048a35122283af731f5e460aa85b66e65f49a9d158699bd2870",
+	"fe511e86971cea2b6af91b2afa898d9b067fa71780790bb409189f5debe719f405e16acf7c4306a6e6ac5cd535290efe088943b9e6c5d25bfc508023c1b105d20d57252fee8cdbddb4d34a6ec2f72e8d55be55afcafd2e922ab8c31888bec4e816d04f0b2cd23df6e04720969c5152b3563c6da37e4608554cc7b8715bc10aba6a2e3b6fbcd35408df0dd73a9076bfad32b741fcdb0edfb563b3f753508b9b26f0a91673255f9bcda2b9a120f6bfa0632b6551ca517d846a747b66ebda1b2170891ece94c19ce8bf682cc94afdf0053fba4e4f0530935c07cdd6f879c999a8c4328ef6d3e0a37974a230ada83910604337",
+	"a6024f5b959698c0de45f4f29e1803f99dc8112989c536e5a1337e281bc856ff721e986de183d7b0ea9eb61166830ae5d6d6bc857dc833ff189b52889b8e2bd3f35b4937624d9b36dc5f19db44f0772508029784c7dac9568d28609058bc437e2f79f95b12307d8a8fb042d7fd6ee910a9e8df609ede3283f958ba918a9925a0b1d0f9f9f232062315f28a52cbd60e71c09d83e0f6600f508f0ae8ad7642c080ffc618fcd2314e26f67f1529342569f6df37017f7e3b2dac32ad88d56d175ab22205ee7e3ee94720d76933a21132e110fefbb0689a3adbaa4c685f43652136d09b3a359b5c671e38f11915cb5612db2ae294",
+	"af6de0e227bd78494acb559ddf34d8a7d55a03912384831be21c38376f39cda8a864aff7a48aed758f6bdf777779a669068a75ce82a06f6b3325c855ed83daf5513a078a61f7dc6c1622a633367e5f3a33e765c8ec5d8d54f48494006fdbf8922063e5340013e312871b7f8f8e5ea439c0d4cb78e2f19dd11f010729b692c65dd0d347f0ce53de9d849224666ea2f6487f1c6f953e8f9dbfd3d6de291c3e9d045e633cfd83c89d2f2327d0b2f31f72ac1604a3db1febc5f22cad08153278047210cc2894582c251a014c652e3951593e70e52a5d7451be8924b64f85c8247dab6268d24710b39fc1c07b4ac829fbda34ed79b5",
+	"d7314e8b1ff82100b8f5870da62b61c31ab37ace9e6a7b6f7d294571523783c1fdedcbc00dd487dd6f848c34aab493507d07071b5eb59d1a2346068c7f356755fbde3d2cab67514f8c3a12d6ff9f96a977a9ac9263491bd33122a904da5386b943d35a6ba383932df07f259b6b45f69e9b27b4ca124fb3ae143d709853eed86690bc2754d5f8865c355a44b5279d8eb31cdc00f7407fb5f5b34edc57fc7ace943565da2222dc80632ccf42f2f125ceb19714ea964c2e50603c9f8960c3f27c2ed0e18a559931c4352bd7422109a28c5e145003f55c9b7c664fdc985168868950396eaf6fefc7b73d815c1aca721d7c67da632925",
+	"2928b55c0e4d0f5cb4b60af59e9a702e3d616a8cf427c8bb03981fb8c29026d8f7d89161f36c11654f9a5e8ccb703595a58d671ecdc22c6a784abe363158682be4643002a7da5c9d268a30ea9a8d4cc24f562ab59f55c2b43af7dbcecc7e5ebe7494e82d74145a1e7d442125eb0431c5ea0939b27afa47f8ca97849f341f707660c7fbe49b7a0712fbcb6f7562ae2961425f27c7779c7534ecdeb8047ff3cb89a25159f3e1cefe42f9ef16426241f2c4d62c11d7ac43c4500dfcd184436bb4ef33260366f875230f26d81613c334dbda4736ba9d1d2966502914ec01bbe72d885606ec11da7a2cb01b29d35eebedbb0ecc73ed6c35",
+	"fd993f50e8a68c7b2c7f87511ce65b93c0aa94dcbdf2c9cca93816f0f3b2ab34c62c586fc507b4900a34cf9d0517e0fe10a89d154c5419c1f5e38de00e8834fe3dc1032abdeb10729a81655a69a12856a78ca6e12110580de879b086fd6608726541cfa9616326bdd36064bc0d1e5f9c93b41278bff6a13b2494b81e238c0c45aea1b07d855e8f3fe1478e373bd9d3957cf8a5e5b9003386793d994c7c575cff2322e2428cbbaa4f47560316ae3354a7478842ff7cc5dcbacb6e871e72b36f06d63a9aaeb9044cfb7974afdc238a5816f537dcf33ee40b4e1a5eb3cff2402b46d548264e133008d284f11b7e4e450bc3c5ff9f79b9c4",
+	"8df21892f5fc303b0de4adef1970186db6fe71bb3ea3094922e13afcfabf1d0be009f36d6f6310c5f9fda51f1a946507a055b645c296370440e5e83d8e906a2fb51f2b42de8856a81a4f28a73a8825c68ea08e5e366730bce8047011cb7d6d9be8c6f4211308fad21856284d5bc47d199988e0abf5badf8693ceeed0a2d98e8ae94b7775a42925edb1f697ffbd8e806af23145054a85e071819cca4cd48875290ca65e5ee72a9a54ff9f19c10ef4adaf8d04c9a9afcc73853fc128bbebc61f78702787c966ca6e1b1a0e4dab646acdfcd3c6bf3e5cfbec5ebe3e06c8abaa1de56e48421d87c46b5c78030afcafd91f27e7d7c85eb4872b",
+	"48ec6ec520f8e593d7b3f653eb15553de246723b81a6d0c3221aaa42a37420fba98a23796338dff5f845dce6d5a449be5ecc1887356619270461087e08d05fb60433a83d7bd00c002b09ea210b428965124b9b27d9105a71c826c1a2491cfd60e4cfa86c2da0c7100a8dc1c3f2f94b280d54e01e043acf0e966200d9fa8a41daf3b9382820786c75cadbb8841a1b2be5b6cbeb64878e4a231ae063a99b4e2308960ef0c8e2a16bb3545cc43bdf171493fb89a84f47e7973dc60cf75aeeca71e0a7ebe17d161d4fb9fe009941cc438f16a5bae6c99fcad08cac486eb2a48060b023d8730bf1d82fe60a2f036e6f52a5bff95f43bbe088933f",
+	"f4d84ed3e564c102600a795eaa9b1eaf4ad12f1a4deca1d042a0a2750ddf6201db03073d8bf553cb9dde48a1b0083827a609f7242b86584cc180964ae794b12ce55661e00e36a6ba4dbc389e6a5a85f1b45df9af7ead1b0a54db56e68639b9d438a91504e82c35d40c7bc7e048a53ac0b04accd0dadf4ac9884b0ca0e3cb5ba4336e3581be4c4760a553823ffa283a1120d4e145af56a59f2533903650f0b9e9ad9fe2e8a3c3c3dd03a1fcb709032c8835324839c735b0c051d0cbd8b5d867617c11023432e4bd275d3d0eb98a0b6cf58071a5b712922f2bc751ac7c2588c447444cde2f37a8ea5ec126425bf517e0d17c9e2999f52fee14b3",
+	"2ccea21bac9c2b70d3923309cbf2d7cb7abd1fcc8b8b002688870a80029c62397350c3c898194e5deea360bb963d26d485cb7963f8167586976ec0556950b2e86135f4a2800991ce8473bfd44a3c5e937a48b5e355ba5141bccf2131a83988d9d2a9e8e7635a956105b3512c05ef708139ced51d7a4e204c12d8a49a21e8dc6de2629a2fd092326885d9f218745fe09f6d91fb6afce250a30a63689534b6be1f26899ffa3767d835cf586aa47776700f94241bc999b1e3deefe188f37ff734f5f16ee6a00914323dc7b8a143c9137cdcc5cd08ae9566f04bb2941532674c97dff6ffa5ce3405ef8e5d27ec403114253dd6394c0167d72a0044c5",
+	"2b681c6398aee63bf862770341648bbcd31d7de7903c5903fe3d9469311320bb24d914f2af0cdca199c97214c7c679dc32a2800ba484a03c010ea6be3bb9f2c87e30a98b606050b8a3f297f12b8f92caaeceb3e844652115934874e0a1ab093a73d759b53f6a6c3096940dd22c2bb96ce6820a7b9c6d71a208de9892aa6a7209b0fff56a0cafea52b952cdd6f5752cff3309d448800b4e4c878aa595595b56b12b83fcd6ca89520c7da664e449d7b4438fc455888aad5de0fad9a06eed14afd3513b5ebbffe01775549b701181bd26370764f56eba52fdb24286ad1ac0f5418a7c429f7dfc7f3168437fa8eed7a2ed7c723a485e4c3ed14dea2e07",
+	"aadfd505a89f4aade2c3018258a7e039401b1fc6a7f3d87910dddbb880d372ec8a13c70d92245de5b8e5f9a285c33b99dc82fa2b22decee72b93a72211656ad7a52696c8e570f78be28c0e427a371dafde856e8d5ed24f83b0660b51e7fac05d93a8666dfde6def59af863f80f3e5f6801182c87422203df390dcb736b8f830052a8832eeeb0b4e27e732aaf793d166b5a3ec7745aeef3766937c2b75a276bddd145f6010c29d035e343e267cb2d828436876ec3a7ebe3b6347d4172f7a99d6821ce152e039e53deb33340b324c7f068ffb94b3cde35a8eaa12d15c3806a7ad0acec3e8c7078c1d32a28fd3eec9f32cb86e4c22166ff69e83785e851",
+	"1605b8cce529a9d6262fd4390d9e4ae5e14e0adc0ec89b028ef68dd0f373ea259aaa96f2967091dd0874c0105385e9e6da9ca68297c31afa44ef834535fb302ce5b4e49edacbbdf359fe1228a8172495b3e57014c27edd58b685110980056c50c398a64f4923f2d720b4df16d75cb36b4233660694182099c35028a972519c24764fc94e18e582b24deb3491535fc06b83837c7958522800e822201d694af0bd0aa3834e17d4b1ba36f470905ae5f8bbeeb6c4c8604d8af02baa347b07086d6989867ddd5e8e8ed7740c3469bfa2810519c55c6add1332c4c54ee9097961d6741cb12a09713a0d07645f784f42f5ad94b48b836b34263130b0483f15e3",
+	"ff9c6125b2f60bfd6c2427b279df070e430075096647599bdc68c531152c58e13858b82385d78c856092d6c74106e87ccf51ac7e673936332d9b223444eaa0e762ee258d8a733d3a515ec68ed73285e5ca183ae3278b4820b0ab2797feb1e7d8cc864df585dfb5ebe02a993325a9ad5e2d7d49d3132cf66013898351d044e0fe908ccdfeeebf651983601e3673a1f92d36510c0cc19b2e75856db8e4a41f92a51efa66d6cc22e414944c2c34a5a89ccde0be76f51410824e330d8e7c613194338c93732e8aea651fca18bcf1ac1824340c5553aff1e58d4ab8d7c8842b4712021e517cd6c140f6743c69c7bee05b10a8f24050a8caa4f96d1664909c5a06",
+	"6e85c2f8e1fdc3aaeb969da1258cb504bbf0070cd03d23b3fb5ee08feea5ee2e0ee1c71a5d0f4f701b351f4e4b4d74cb1e2ae6184814f77b62d2f08134b7236ebf6b67d8a6c9f01b4248b30667c555f5d8646dbfe291151b23c9c9857e33a4d5c847be29a5ee7b402e03bac02d1a4319acc0dd8f25e9c7a266f5e5c896cc11b5b238df96a0963ae806cb277abc515c298a3e61a3036b177acf87a56ca4478c4c6d0d468913de602ec891318bbaf52c97a77c35c5b7d164816cf24e4c4b0b5f45853882f716d61eb947a45ce2efa78f1c70a918512af1ad536cbe6148083385b34e207f5f690d7a954021e4b5f4258a385fd8a87809a481f34202af4caccb82",
+	"1e9b2c454e9de3a2d723d850331037dbf54133dbe27488ff757dd255833a27d8eb8a128ad12d0978b6884e25737086a704fb289aaaccf930d5b582ab4df1f55f0c429b6875edec3fe45464fa74164be056a55e243c4222c586bec5b18f39036aa903d98180f24f83d09a454dfa1e03a60e6a3ba4613e99c35f874d790174ee48a557f4f021ade4d1b278d7997ef094569b37b3db0505951e9ee8400adaea275c6db51b325ee730c69df97745b556ae41cd98741e28aa3a49544541eeb3da1b1e8fa4e8e9100d66dd0c7f5e2c271b1ecc077de79c462b9fe4c273543ecd82a5bea63c5acc01eca5fb780c7d7c8c9fe208ae8bd50cad1769693d92c6c8649d20d8",
+}

+ 177 - 0
src/golang.org/x/crypto/blake2b/blake2x.go

@@ -0,0 +1,177 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blake2b
+
+import (
+	"encoding/binary"
+	"errors"
+	"io"
+)
+
+// XOF defines the interface to hash functions that
+// support arbitrary-length output.
+type XOF interface {
+	// Write absorbs more data into the hash's state. It panics if called
+	// after Read.
+	io.Writer
+
+	// Read reads more output from the hash. It returns io.EOF if the limit
+	// has been reached.
+	io.Reader
+
+	// Clone returns a copy of the XOF in its current state.
+	Clone() XOF
+
+	// Reset resets the XOF to its initial state.
+	Reset()
+}
+
+// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
+// the length of the output is not known in advance.
+const OutputLengthUnknown = 0
+
+// magicUnknownOutputLength is a magic value for the output size that indicates
+// an unknown number of output bytes.
+const magicUnknownOutputLength = (1 << 32) - 1
+
+// maxOutputLength is the absolute maximum number of bytes to produce when the
+// number of output bytes is unknown.
+const maxOutputLength = (1 << 32) * 64
+
+// NewXOF creates a new variable-output-length hash. The hash either produce a
+// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
+// (size == OutputLengthUnknown). In the latter case, an absolute limit of
+// 256GiB applies.
+//
+// A non-nil key turns the hash into a MAC. The key must between
+// zero and 32 bytes long.
+func NewXOF(size uint32, key []byte) (XOF, error) {
+	if len(key) > Size {
+		return nil, errKeySize
+	}
+	if size == magicUnknownOutputLength {
+		// 2^32-1 indicates an unknown number of bytes and thus isn't a
+		// valid length.
+		return nil, errors.New("blake2b: XOF length too large")
+	}
+	if size == OutputLengthUnknown {
+		size = magicUnknownOutputLength
+	}
+	x := &xof{
+		d: digest{
+			size:   Size,
+			keyLen: len(key),
+		},
+		length: size,
+	}
+	copy(x.d.key[:], key)
+	x.Reset()
+	return x, nil
+}
+
+type xof struct {
+	d                digest
+	length           uint32
+	remaining        uint64
+	cfg, root, block [Size]byte
+	offset           int
+	nodeOffset       uint32
+	readMode         bool
+}
+
+func (x *xof) Write(p []byte) (n int, err error) {
+	if x.readMode {
+		panic("blake2b: write to XOF after read")
+	}
+	return x.d.Write(p)
+}
+
+func (x *xof) Clone() XOF {
+	clone := *x
+	return &clone
+}
+
+func (x *xof) Reset() {
+	x.cfg[0] = byte(Size)
+	binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
+	binary.LittleEndian.PutUint32(x.cfg[12:], x.length)    // XOF length
+	x.cfg[17] = byte(Size)                                 // inner hash size
+
+	x.d.Reset()
+	x.d.h[1] ^= uint64(x.length) << 32
+
+	x.remaining = uint64(x.length)
+	if x.remaining == magicUnknownOutputLength {
+		x.remaining = maxOutputLength
+	}
+	x.offset, x.nodeOffset = 0, 0
+	x.readMode = false
+}
+
+func (x *xof) Read(p []byte) (n int, err error) {
+	if !x.readMode {
+		x.d.finalize(&x.root)
+		x.readMode = true
+	}
+
+	if x.remaining == 0 {
+		return 0, io.EOF
+	}
+
+	n = len(p)
+	if uint64(n) > x.remaining {
+		n = int(x.remaining)
+		p = p[:n]
+	}
+
+	if x.offset > 0 {
+		blockRemaining := Size - x.offset
+		if n < blockRemaining {
+			x.offset += copy(p, x.block[x.offset:])
+			x.remaining -= uint64(n)
+			return
+		}
+		copy(p, x.block[x.offset:])
+		p = p[blockRemaining:]
+		x.offset = 0
+		x.remaining -= uint64(blockRemaining)
+	}
+
+	for len(p) >= Size {
+		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
+		x.nodeOffset++
+
+		x.d.initConfig(&x.cfg)
+		x.d.Write(x.root[:])
+		x.d.finalize(&x.block)
+
+		copy(p, x.block[:])
+		p = p[Size:]
+		x.remaining -= uint64(Size)
+	}
+
+	if todo := len(p); todo > 0 {
+		if x.remaining < uint64(Size) {
+			x.cfg[0] = byte(x.remaining)
+		}
+		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
+		x.nodeOffset++
+
+		x.d.initConfig(&x.cfg)
+		x.d.Write(x.root[:])
+		x.d.finalize(&x.block)
+
+		x.offset = copy(p, x.block[:todo])
+		x.remaining -= uint64(todo)
+	}
+	return
+}
+
+func (d *digest) initConfig(cfg *[Size]byte) {
+	d.offset, d.c[0], d.c[1] = 0, 0, 0
+	for i := range d.h {
+		d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
+	}
+}

+ 32 - 0
src/golang.org/x/crypto/blake2b/register.go

@@ -0,0 +1,32 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.9
+
+package blake2b
+
+import (
+	"crypto"
+	"hash"
+)
+
+func init() {
+	newHash256 := func() hash.Hash {
+		h, _ := New256(nil)
+		return h
+	}
+	newHash384 := func() hash.Hash {
+		h, _ := New384(nil)
+		return h
+	}
+
+	newHash512 := func() hash.Hash {
+		h, _ := New512(nil)
+		return h
+	}
+
+	crypto.RegisterHash(crypto.BLAKE2b_256, newHash256)
+	crypto.RegisterHash(crypto.BLAKE2b_384, newHash384)
+	crypto.RegisterHash(crypto.BLAKE2b_512, newHash512)
+}

+ 244 - 0
src/golang.org/x/crypto/blake2s/blake2s.go

@@ -0,0 +1,244 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blake2s implements the BLAKE2s hash algorithm defined by RFC 7693
+// and the extendable output function (XOF) BLAKE2Xs.
+//
+// For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf
+// and for BLAKE2Xs see https://blake2.net/blake2x.pdf
+//
+// If you aren't sure which function you need, use BLAKE2s (Sum256 or New256).
+// If you need a secret-key MAC (message authentication code), use the New256
+// function with a non-nil key.
+//
+// BLAKE2X is a construction to compute hash values larger than 32 bytes. It
+// can produce hash values between 0 and 65535 bytes.
+package blake2s // import "golang.org/x/crypto/blake2s"
+
+import (
+	"encoding/binary"
+	"errors"
+	"hash"
+)
+
+const (
+	// The blocksize of BLAKE2s in bytes.
+	BlockSize = 64
+
+	// The hash size of BLAKE2s-256 in bytes.
+	Size = 32
+
+	// The hash size of BLAKE2s-128 in bytes.
+	Size128 = 16
+)
+
+var errKeySize = errors.New("blake2s: invalid key size")
+
+var iv = [8]uint32{
+	0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+	0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
+}
+
+// Sum256 returns the BLAKE2s-256 checksum of the data.
+func Sum256(data []byte) [Size]byte {
+	var sum [Size]byte
+	checkSum(&sum, Size, data)
+	return sum
+}
+
+// New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
+// key turns the hash into a MAC. The key must between zero and 32 bytes long.
+// When the key is nil, the returned hash.Hash implements BinaryMarshaler
+// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
+func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
+
+// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
+// non-empty key. Note that a 128-bit digest is too small to be secure as a
+// cryptographic hash and should only be used as a MAC, thus the key argument
+// is not optional.
+func New128(key []byte) (hash.Hash, error) {
+	if len(key) == 0 {
+		return nil, errors.New("blake2s: a key is required for a 128-bit hash")
+	}
+	return newDigest(Size128, key)
+}
+
+func newDigest(hashSize int, key []byte) (*digest, error) {
+	if len(key) > Size {
+		return nil, errKeySize
+	}
+	d := &digest{
+		size:   hashSize,
+		keyLen: len(key),
+	}
+	copy(d.key[:], key)
+	d.Reset()
+	return d, nil
+}
+
+func checkSum(sum *[Size]byte, hashSize int, data []byte) {
+	var (
+		h [8]uint32
+		c [2]uint32
+	)
+
+	h = iv
+	h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
+
+	if length := len(data); length > BlockSize {
+		n := length &^ (BlockSize - 1)
+		if length == n {
+			n -= BlockSize
+		}
+		hashBlocks(&h, &c, 0, data[:n])
+		data = data[n:]
+	}
+
+	var block [BlockSize]byte
+	offset := copy(block[:], data)
+	remaining := uint32(BlockSize - offset)
+
+	if c[0] < remaining {
+		c[1]--
+	}
+	c[0] -= remaining
+
+	hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
+
+	for i, v := range h {
+		binary.LittleEndian.PutUint32(sum[4*i:], v)
+	}
+}
+
+type digest struct {
+	h      [8]uint32
+	c      [2]uint32
+	size   int
+	block  [BlockSize]byte
+	offset int
+
+	key    [BlockSize]byte
+	keyLen int
+}
+
+const (
+	magic         = "b2s"
+	marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+	if d.keyLen != 0 {
+		return nil, errors.New("crypto/blake2s: cannot marshal MACs")
+	}
+	b := make([]byte, 0, marshaledSize)
+	b = append(b, magic...)
+	for i := 0; i < 8; i++ {
+		b = appendUint32(b, d.h[i])
+	}
+	b = appendUint32(b, d.c[0])
+	b = appendUint32(b, d.c[1])
+	// Maximum value for size is 32
+	b = append(b, byte(d.size))
+	b = append(b, d.block[:]...)
+	b = append(b, byte(d.offset))
+	return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
+		return errors.New("crypto/blake2s: invalid hash state identifier")
+	}
+	if len(b) != marshaledSize {
+		return errors.New("crypto/blake2s: invalid hash state size")
+	}
+	b = b[len(magic):]
+	for i := 0; i < 8; i++ {
+		b, d.h[i] = consumeUint32(b)
+	}
+	b, d.c[0] = consumeUint32(b)
+	b, d.c[1] = consumeUint32(b)
+	d.size = int(b[0])
+	b = b[1:]
+	copy(d.block[:], b[:BlockSize])
+	b = b[BlockSize:]
+	d.offset = int(b[0])
+	return nil
+}
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Size() int { return d.size }
+
+func (d *digest) Reset() {
+	d.h = iv
+	d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
+	d.offset, d.c[0], d.c[1] = 0, 0, 0
+	if d.keyLen > 0 {
+		d.block = d.key
+		d.offset = BlockSize
+	}
+}
+
+func (d *digest) Write(p []byte) (n int, err error) {
+	n = len(p)
+
+	if d.offset > 0 {
+		remaining := BlockSize - d.offset
+		if n <= remaining {
+			d.offset += copy(d.block[d.offset:], p)
+			return
+		}
+		copy(d.block[d.offset:], p[:remaining])
+		hashBlocks(&d.h, &d.c, 0, d.block[:])
+		d.offset = 0
+		p = p[remaining:]
+	}
+
+	if length := len(p); length > BlockSize {
+		nn := length &^ (BlockSize - 1)
+		if length == nn {
+			nn -= BlockSize
+		}
+		hashBlocks(&d.h, &d.c, 0, p[:nn])
+		p = p[nn:]
+	}
+
+	d.offset += copy(d.block[:], p)
+	return
+}
+
+func (d *digest) Sum(sum []byte) []byte {
+	var hash [Size]byte
+	d.finalize(&hash)
+	return append(sum, hash[:d.size]...)
+}
+
+func (d *digest) finalize(hash *[Size]byte) {
+	var block [BlockSize]byte
+	h := d.h
+	c := d.c
+
+	copy(block[:], d.block[:d.offset])
+	remaining := uint32(BlockSize - d.offset)
+	if c[0] < remaining {
+		c[1]--
+	}
+	c[0] -= remaining
+
+	hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
+	for i, v := range h {
+		binary.LittleEndian.PutUint32(hash[4*i:], v)
+	}
+}
+
+func appendUint32(b []byte, x uint32) []byte {
+	var a [4]byte
+	binary.BigEndian.PutUint32(a[:], x)
+	return append(b, a[:]...)
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+	x := binary.BigEndian.Uint32(b)
+	return b[4:], x
+}

+ 32 - 0
src/golang.org/x/crypto/blake2s/blake2s_386.go

@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386,!gccgo,!appengine
+
+package blake2s
+
+import "golang.org/x/sys/cpu"
+
+var (
+	useSSE4  = false
+	useSSSE3 = cpu.X86.HasSSSE3
+	useSSE2  = cpu.X86.HasSSE2
+)
+
+//go:noescape
+func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+
+//go:noescape
+func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+
+func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
+	switch {
+	case useSSSE3:
+		hashBlocksSSSE3(h, c, flag, blocks)
+	case useSSE2:
+		hashBlocksSSE2(h, c, flag, blocks)
+	default:
+		hashBlocksGeneric(h, c, flag, blocks)
+	}
+}

+ 435 - 0
src/golang.org/x/crypto/blake2s/blake2s_386.s

@@ -0,0 +1,435 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386,!gccgo,!appengine
+
+#include "textflag.h"
+
+DATA iv0<>+0x00(SB)/4, $0x6a09e667
+DATA iv0<>+0x04(SB)/4, $0xbb67ae85
+DATA iv0<>+0x08(SB)/4, $0x3c6ef372
+DATA iv0<>+0x0c(SB)/4, $0xa54ff53a
+GLOBL iv0<>(SB), (NOPTR+RODATA), $16
+
+DATA iv1<>+0x00(SB)/4, $0x510e527f
+DATA iv1<>+0x04(SB)/4, $0x9b05688c
+DATA iv1<>+0x08(SB)/4, $0x1f83d9ab
+DATA iv1<>+0x0c(SB)/4, $0x5be0cd19
+GLOBL iv1<>(SB), (NOPTR+RODATA), $16
+
+DATA rol16<>+0x00(SB)/8, $0x0504070601000302
+DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
+GLOBL rol16<>(SB), (NOPTR+RODATA), $16
+
+DATA rol8<>+0x00(SB)/8, $0x0407060500030201
+DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09
+GLOBL rol8<>(SB), (NOPTR+RODATA), $16
+
+DATA counter<>+0x00(SB)/8, $0x40
+DATA counter<>+0x08(SB)/8, $0x0
+GLOBL counter<>(SB), (NOPTR+RODATA), $16
+
+#define ROTL_SSE2(n, t, v) \
+	MOVO  v, t;       \
+	PSLLL $n, t;      \
+	PSRLL $(32-n), v; \
+	PXOR  t, v
+
+#define ROTL_SSSE3(c, v) \
+	PSHUFB c, v
+
+#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \
+	PADDL  m0, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(16, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m1, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(24, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v1, v1; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v3, v3; \
+	PADDL  m2, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(16, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m3, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(24, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v3, v3; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v1, v1
+
+#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \
+	PADDL  m0, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c16, v3);  \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m1, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c8, v3);   \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v1, v1; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v3, v3; \
+	PADDL  m2, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c16, v3);  \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m3, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c8, v3);   \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v3, v3; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v1, v1
+
+#define PRECOMPUTE(dst, off, src, t) \
+	MOVL 0*4(src), t;          \
+	MOVL t, 0*4+off+0(dst);    \
+	MOVL t, 9*4+off+64(dst);   \
+	MOVL t, 5*4+off+128(dst);  \
+	MOVL t, 14*4+off+192(dst); \
+	MOVL t, 4*4+off+256(dst);  \
+	MOVL t, 2*4+off+320(dst);  \
+	MOVL t, 8*4+off+384(dst);  \
+	MOVL t, 12*4+off+448(dst); \
+	MOVL t, 3*4+off+512(dst);  \
+	MOVL t, 15*4+off+576(dst); \
+	MOVL 1*4(src), t;          \
+	MOVL t, 4*4+off+0(dst);    \
+	MOVL t, 8*4+off+64(dst);   \
+	MOVL t, 14*4+off+128(dst); \
+	MOVL t, 5*4+off+192(dst);  \
+	MOVL t, 12*4+off+256(dst); \
+	MOVL t, 11*4+off+320(dst); \
+	MOVL t, 1*4+off+384(dst);  \
+	MOVL t, 6*4+off+448(dst);  \
+	MOVL t, 10*4+off+512(dst); \
+	MOVL t, 3*4+off+576(dst);  \
+	MOVL 2*4(src), t;          \
+	MOVL t, 1*4+off+0(dst);    \
+	MOVL t, 13*4+off+64(dst);  \
+	MOVL t, 6*4+off+128(dst);  \
+	MOVL t, 8*4+off+192(dst);  \
+	MOVL t, 2*4+off+256(dst);  \
+	MOVL t, 0*4+off+320(dst);  \
+	MOVL t, 14*4+off+384(dst); \
+	MOVL t, 11*4+off+448(dst); \
+	MOVL t, 12*4+off+512(dst); \
+	MOVL t, 4*4+off+576(dst);  \
+	MOVL 3*4(src), t;          \
+	MOVL t, 5*4+off+0(dst);    \
+	MOVL t, 15*4+off+64(dst);  \
+	MOVL t, 9*4+off+128(dst);  \
+	MOVL t, 1*4+off+192(dst);  \
+	MOVL t, 11*4+off+256(dst); \
+	MOVL t, 7*4+off+320(dst);  \
+	MOVL t, 13*4+off+384(dst); \
+	MOVL t, 3*4+off+448(dst);  \
+	MOVL t, 6*4+off+512(dst);  \
+	MOVL t, 10*4+off+576(dst); \
+	MOVL 4*4(src), t;          \
+	MOVL t, 2*4+off+0(dst);    \
+	MOVL t, 1*4+off+64(dst);   \
+	MOVL t, 15*4+off+128(dst); \
+	MOVL t, 10*4+off+192(dst); \
+	MOVL t, 6*4+off+256(dst);  \
+	MOVL t, 8*4+off+320(dst);  \
+	MOVL t, 3*4+off+384(dst);  \
+	MOVL t, 13*4+off+448(dst); \
+	MOVL t, 14*4+off+512(dst); \
+	MOVL t, 5*4+off+576(dst);  \
+	MOVL 5*4(src), t;          \
+	MOVL t, 6*4+off+0(dst);    \
+	MOVL t, 11*4+off+64(dst);  \
+	MOVL t, 2*4+off+128(dst);  \
+	MOVL t, 9*4+off+192(dst);  \
+	MOVL t, 1*4+off+256(dst);  \
+	MOVL t, 13*4+off+320(dst); \
+	MOVL t, 4*4+off+384(dst);  \
+	MOVL t, 8*4+off+448(dst);  \
+	MOVL t, 15*4+off+512(dst); \
+	MOVL t, 7*4+off+576(dst);  \
+	MOVL 6*4(src), t;          \
+	MOVL t, 3*4+off+0(dst);    \
+	MOVL t, 7*4+off+64(dst);   \
+	MOVL t, 13*4+off+128(dst); \
+	MOVL t, 12*4+off+192(dst); \
+	MOVL t, 10*4+off+256(dst); \
+	MOVL t, 1*4+off+320(dst);  \
+	MOVL t, 9*4+off+384(dst);  \
+	MOVL t, 14*4+off+448(dst); \
+	MOVL t, 0*4+off+512(dst);  \
+	MOVL t, 6*4+off+576(dst);  \
+	MOVL 7*4(src), t;          \
+	MOVL t, 7*4+off+0(dst);    \
+	MOVL t, 14*4+off+64(dst);  \
+	MOVL t, 10*4+off+128(dst); \
+	MOVL t, 0*4+off+192(dst);  \
+	MOVL t, 5*4+off+256(dst);  \
+	MOVL t, 9*4+off+320(dst);  \
+	MOVL t, 12*4+off+384(dst); \
+	MOVL t, 1*4+off+448(dst);  \
+	MOVL t, 13*4+off+512(dst); \
+	MOVL t, 2*4+off+576(dst);  \
+	MOVL 8*4(src), t;          \
+	MOVL t, 8*4+off+0(dst);    \
+	MOVL t, 5*4+off+64(dst);   \
+	MOVL t, 4*4+off+128(dst);  \
+	MOVL t, 15*4+off+192(dst); \
+	MOVL t, 14*4+off+256(dst); \
+	MOVL t, 3*4+off+320(dst);  \
+	MOVL t, 11*4+off+384(dst); \
+	MOVL t, 10*4+off+448(dst); \
+	MOVL t, 7*4+off+512(dst);  \
+	MOVL t, 1*4+off+576(dst);  \
+	MOVL 9*4(src), t;          \
+	MOVL t, 12*4+off+0(dst);   \
+	MOVL t, 2*4+off+64(dst);   \
+	MOVL t, 11*4+off+128(dst); \
+	MOVL t, 4*4+off+192(dst);  \
+	MOVL t, 0*4+off+256(dst);  \
+	MOVL t, 15*4+off+320(dst); \
+	MOVL t, 10*4+off+384(dst); \
+	MOVL t, 7*4+off+448(dst);  \
+	MOVL t, 5*4+off+512(dst);  \
+	MOVL t, 9*4+off+576(dst);  \
+	MOVL 10*4(src), t;         \
+	MOVL t, 9*4+off+0(dst);    \
+	MOVL t, 4*4+off+64(dst);   \
+	MOVL t, 8*4+off+128(dst);  \
+	MOVL t, 13*4+off+192(dst); \
+	MOVL t, 3*4+off+256(dst);  \
+	MOVL t, 5*4+off+320(dst);  \
+	MOVL t, 7*4+off+384(dst);  \
+	MOVL t, 15*4+off+448(dst); \
+	MOVL t, 11*4+off+512(dst); \
+	MOVL t, 0*4+off+576(dst);  \
+	MOVL 11*4(src), t;         \
+	MOVL t, 13*4+off+0(dst);   \
+	MOVL t, 10*4+off+64(dst);  \
+	MOVL t, 0*4+off+128(dst);  \
+	MOVL t, 3*4+off+192(dst);  \
+	MOVL t, 9*4+off+256(dst);  \
+	MOVL t, 6*4+off+320(dst);  \
+	MOVL t, 15*4+off+384(dst); \
+	MOVL t, 4*4+off+448(dst);  \
+	MOVL t, 2*4+off+512(dst);  \
+	MOVL t, 12*4+off+576(dst); \
+	MOVL 12*4(src), t;         \
+	MOVL t, 10*4+off+0(dst);   \
+	MOVL t, 12*4+off+64(dst);  \
+	MOVL t, 1*4+off+128(dst);  \
+	MOVL t, 6*4+off+192(dst);  \
+	MOVL t, 13*4+off+256(dst); \
+	MOVL t, 4*4+off+320(dst);  \
+	MOVL t, 0*4+off+384(dst);  \
+	MOVL t, 2*4+off+448(dst);  \
+	MOVL t, 8*4+off+512(dst);  \
+	MOVL t, 14*4+off+576(dst); \
+	MOVL 13*4(src), t;         \
+	MOVL t, 14*4+off+0(dst);   \
+	MOVL t, 3*4+off+64(dst);   \
+	MOVL t, 7*4+off+128(dst);  \
+	MOVL t, 2*4+off+192(dst);  \
+	MOVL t, 15*4+off+256(dst); \
+	MOVL t, 12*4+off+320(dst); \
+	MOVL t, 6*4+off+384(dst);  \
+	MOVL t, 0*4+off+448(dst);  \
+	MOVL t, 9*4+off+512(dst);  \
+	MOVL t, 11*4+off+576(dst); \
+	MOVL 14*4(src), t;         \
+	MOVL t, 11*4+off+0(dst);   \
+	MOVL t, 0*4+off+64(dst);   \
+	MOVL t, 12*4+off+128(dst); \
+	MOVL t, 7*4+off+192(dst);  \
+	MOVL t, 8*4+off+256(dst);  \
+	MOVL t, 14*4+off+320(dst); \
+	MOVL t, 2*4+off+384(dst);  \
+	MOVL t, 5*4+off+448(dst);  \
+	MOVL t, 1*4+off+512(dst);  \
+	MOVL t, 13*4+off+576(dst); \
+	MOVL 15*4(src), t;         \
+	MOVL t, 15*4+off+0(dst);   \
+	MOVL t, 6*4+off+64(dst);   \
+	MOVL t, 3*4+off+128(dst);  \
+	MOVL t, 11*4+off+192(dst); \
+	MOVL t, 7*4+off+256(dst);  \
+	MOVL t, 10*4+off+320(dst); \
+	MOVL t, 5*4+off+384(dst);  \
+	MOVL t, 9*4+off+448(dst);  \
+	MOVL t, 4*4+off+512(dst);  \
+	MOVL t, 8*4+off+576(dst)
+
+// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+TEXT ·hashBlocksSSE2(SB), 0, $672-24 // frame = 656 + 16 byte alignment
+	MOVL h+0(FP), AX
+	MOVL c+4(FP), BX
+	MOVL flag+8(FP), CX
+	MOVL blocks_base+12(FP), SI
+	MOVL blocks_len+16(FP), DX
+
+	MOVL SP, BP
+	MOVL SP, DI
+	ADDL $15, DI
+	ANDL $~15, DI
+	MOVL DI, SP
+
+	MOVL CX, 8(SP)
+	MOVL 0(BX), CX
+	MOVL CX, 0(SP)
+	MOVL 4(BX), CX
+	MOVL CX, 4(SP)
+	XORL CX, CX
+	MOVL CX, 12(SP)
+
+	MOVOU 0(AX), X0
+	MOVOU 16(AX), X1
+	MOVOU counter<>(SB), X2
+
+loop:
+	MOVO  X0, X4
+	MOVO  X1, X5
+	MOVOU iv0<>(SB), X6
+	MOVOU iv1<>(SB), X7
+
+	MOVO  0(SP), X3
+	PADDQ X2, X3
+	PXOR  X3, X7
+	MOVO  X3, 0(SP)
+
+	PRECOMPUTE(SP, 16, SI, CX)
+	ROUND_SSE2(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X3)
+	ROUND_SSE2(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X3)
+
+	PXOR X4, X0
+	PXOR X5, X1
+	PXOR X6, X0
+	PXOR X7, X1
+
+	LEAL 64(SI), SI
+	SUBL $64, DX
+	JNE  loop
+
+	MOVL 0(SP), CX
+	MOVL CX, 0(BX)
+	MOVL 4(SP), CX
+	MOVL CX, 4(BX)
+
+	MOVOU X0, 0(AX)
+	MOVOU X1, 16(AX)
+
+	MOVL BP, SP
+	RET
+
+// func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+TEXT ·hashBlocksSSSE3(SB), 0, $704-24 // frame = 688 + 16 byte alignment
+	MOVL h+0(FP), AX
+	MOVL c+4(FP), BX
+	MOVL flag+8(FP), CX
+	MOVL blocks_base+12(FP), SI
+	MOVL blocks_len+16(FP), DX
+
+	MOVL SP, BP
+	MOVL SP, DI
+	ADDL $15, DI
+	ANDL $~15, DI
+	MOVL DI, SP
+
+	MOVL CX, 8(SP)
+	MOVL 0(BX), CX
+	MOVL CX, 0(SP)
+	MOVL 4(BX), CX
+	MOVL CX, 4(SP)
+	XORL CX, CX
+	MOVL CX, 12(SP)
+
+	MOVOU 0(AX), X0
+	MOVOU 16(AX), X1
+	MOVOU counter<>(SB), X2
+
+loop:
+	MOVO  X0, 656(SP)
+	MOVO  X1, 672(SP)
+	MOVO  X0, X4
+	MOVO  X1, X5
+	MOVOU iv0<>(SB), X6
+	MOVOU iv1<>(SB), X7
+
+	MOVO  0(SP), X3
+	PADDQ X2, X3
+	PXOR  X3, X7
+	MOVO  X3, 0(SP)
+
+	MOVOU rol16<>(SB), X0
+	MOVOU rol8<>(SB), X1
+
+	PRECOMPUTE(SP, 16, SI, CX)
+	ROUND_SSSE3(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X3, X0, X1)
+	ROUND_SSSE3(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X3, X0, X1)
+
+	MOVO 656(SP), X0
+	MOVO 672(SP), X1
+	PXOR X4, X0
+	PXOR X5, X1
+	PXOR X6, X0
+	PXOR X7, X1
+
+	LEAL 64(SI), SI
+	SUBL $64, DX
+	JNE  loop
+
+	MOVL 0(SP), CX
+	MOVL CX, 0(BX)
+	MOVL 4(SP), CX
+	MOVL CX, 4(BX)
+
+	MOVOU X0, 0(AX)
+	MOVOU X1, 16(AX)
+
+	MOVL BP, SP
+	RET

+ 37 - 0
src/golang.org/x/crypto/blake2s/blake2s_amd64.go

@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package blake2s
+
+import "golang.org/x/sys/cpu"
+
+var (
+	useSSE4  = cpu.X86.HasSSE41
+	useSSSE3 = cpu.X86.HasSSSE3
+	useSSE2  = cpu.X86.HasSSE2
+)
+
+//go:noescape
+func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+
+//go:noescape
+func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+
+//go:noescape
+func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+
+func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
+	switch {
+	case useSSE4:
+		hashBlocksSSE4(h, c, flag, blocks)
+	case useSSSE3:
+		hashBlocksSSSE3(h, c, flag, blocks)
+	case useSSE2:
+		hashBlocksSSE2(h, c, flag, blocks)
+	default:
+		hashBlocksGeneric(h, c, flag, blocks)
+	}
+}

+ 438 - 0
src/golang.org/x/crypto/blake2s/blake2s_amd64.s

@@ -0,0 +1,438 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+#include "textflag.h"
+
+DATA iv0<>+0x00(SB)/4, $0x6a09e667
+DATA iv0<>+0x04(SB)/4, $0xbb67ae85
+DATA iv0<>+0x08(SB)/4, $0x3c6ef372
+DATA iv0<>+0x0c(SB)/4, $0xa54ff53a
+GLOBL iv0<>(SB), (NOPTR+RODATA), $16
+
+DATA iv1<>+0x00(SB)/4, $0x510e527f
+DATA iv1<>+0x04(SB)/4, $0x9b05688c
+DATA iv1<>+0x08(SB)/4, $0x1f83d9ab
+DATA iv1<>+0x0c(SB)/4, $0x5be0cd19
+GLOBL iv1<>(SB), (NOPTR+RODATA), $16
+
+DATA rol16<>+0x00(SB)/8, $0x0504070601000302
+DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
+GLOBL rol16<>(SB), (NOPTR+RODATA), $16
+
+DATA rol8<>+0x00(SB)/8, $0x0407060500030201
+DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09
+GLOBL rol8<>(SB), (NOPTR+RODATA), $16
+
+DATA counter<>+0x00(SB)/8, $0x40
+DATA counter<>+0x08(SB)/8, $0x0
+GLOBL counter<>(SB), (NOPTR+RODATA), $16
+
+#define ROTL_SSE2(n, t, v) \
+	MOVO  v, t;       \
+	PSLLL $n, t;      \
+	PSRLL $(32-n), v; \
+	PXOR  t, v
+
+#define ROTL_SSSE3(c, v) \
+	PSHUFB c, v
+
+#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \
+	PADDL  m0, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(16, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m1, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(24, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v1, v1; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v3, v3; \
+	PADDL  m2, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(16, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m3, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSE2(24, t, v3); \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v3, v3; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v1, v1
+
+#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \
+	PADDL  m0, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c16, v3);  \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m1, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c8, v3);   \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v1, v1; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v3, v3; \
+	PADDL  m2, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c16, v3);  \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(20, t, v1); \
+	PADDL  m3, v0;        \
+	PADDL  v1, v0;        \
+	PXOR   v0, v3;        \
+	ROTL_SSSE3(c8, v3);   \
+	PADDL  v3, v2;        \
+	PXOR   v2, v1;        \
+	ROTL_SSE2(25, t, v1); \
+	PSHUFL $0x39, v3, v3; \
+	PSHUFL $0x4E, v2, v2; \
+	PSHUFL $0x93, v1, v1
+
+
+#define LOAD_MSG_SSE4(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) \
+	MOVL   i0*4(src), m0;      \
+	PINSRD $1, i1*4(src), m0;  \
+	PINSRD $2, i2*4(src), m0;  \
+	PINSRD $3, i3*4(src), m0;  \
+	MOVL   i4*4(src), m1;      \
+	PINSRD $1, i5*4(src), m1;  \
+	PINSRD $2, i6*4(src), m1;  \
+	PINSRD $3, i7*4(src), m1;  \
+	MOVL   i8*4(src), m2;      \
+	PINSRD $1, i9*4(src), m2;  \
+	PINSRD $2, i10*4(src), m2; \
+	PINSRD $3, i11*4(src), m2; \
+	MOVL   i12*4(src), m3;     \
+	PINSRD $1, i13*4(src), m3; \
+	PINSRD $2, i14*4(src), m3; \
+	PINSRD $3, i15*4(src), m3
+
+#define PRECOMPUTE_MSG(dst, off, src, R8, R9, R10, R11, R12, R13, R14, R15) \
+	MOVQ 0*4(src), R8;           \
+	MOVQ 2*4(src), R9;           \
+	MOVQ 4*4(src), R10;          \
+	MOVQ 6*4(src), R11;          \
+	MOVQ 8*4(src), R12;          \
+	MOVQ 10*4(src), R13;         \
+	MOVQ 12*4(src), R14;         \
+	MOVQ 14*4(src), R15;         \
+	                             \
+	MOVL R8, 0*4+off+0(dst);     \
+	MOVL R8, 9*4+off+64(dst);    \
+	MOVL R8, 5*4+off+128(dst);   \
+	MOVL R8, 14*4+off+192(dst);  \
+	MOVL R8, 4*4+off+256(dst);   \
+	MOVL R8, 2*4+off+320(dst);   \
+	MOVL R8, 8*4+off+384(dst);   \
+	MOVL R8, 12*4+off+448(dst);  \
+	MOVL R8, 3*4+off+512(dst);   \
+	MOVL R8, 15*4+off+576(dst);  \
+	SHRQ $32, R8;                \
+	MOVL R8, 4*4+off+0(dst);     \
+	MOVL R8, 8*4+off+64(dst);    \
+	MOVL R8, 14*4+off+128(dst);  \
+	MOVL R8, 5*4+off+192(dst);   \
+	MOVL R8, 12*4+off+256(dst);  \
+	MOVL R8, 11*4+off+320(dst);  \
+	MOVL R8, 1*4+off+384(dst);   \
+	MOVL R8, 6*4+off+448(dst);   \
+	MOVL R8, 10*4+off+512(dst);  \
+	MOVL R8, 3*4+off+576(dst);   \
+	                             \
+	MOVL R9, 1*4+off+0(dst);     \
+	MOVL R9, 13*4+off+64(dst);   \
+	MOVL R9, 6*4+off+128(dst);   \
+	MOVL R9, 8*4+off+192(dst);   \
+	MOVL R9, 2*4+off+256(dst);   \
+	MOVL R9, 0*4+off+320(dst);   \
+	MOVL R9, 14*4+off+384(dst);  \
+	MOVL R9, 11*4+off+448(dst);  \
+	MOVL R9, 12*4+off+512(dst);  \
+	MOVL R9, 4*4+off+576(dst);   \
+	SHRQ $32, R9;                \
+	MOVL R9, 5*4+off+0(dst);     \
+	MOVL R9, 15*4+off+64(dst);   \
+	MOVL R9, 9*4+off+128(dst);   \
+	MOVL R9, 1*4+off+192(dst);   \
+	MOVL R9, 11*4+off+256(dst);  \
+	MOVL R9, 7*4+off+320(dst);   \
+	MOVL R9, 13*4+off+384(dst);  \
+	MOVL R9, 3*4+off+448(dst);   \
+	MOVL R9, 6*4+off+512(dst);   \
+	MOVL R9, 10*4+off+576(dst);  \
+	                             \
+	MOVL R10, 2*4+off+0(dst);    \
+	MOVL R10, 1*4+off+64(dst);   \
+	MOVL R10, 15*4+off+128(dst); \
+	MOVL R10, 10*4+off+192(dst); \
+	MOVL R10, 6*4+off+256(dst);  \
+	MOVL R10, 8*4+off+320(dst);  \
+	MOVL R10, 3*4+off+384(dst);  \
+	MOVL R10, 13*4+off+448(dst); \
+	MOVL R10, 14*4+off+512(dst); \
+	MOVL R10, 5*4+off+576(dst);  \
+	SHRQ $32, R10;               \
+	MOVL R10, 6*4+off+0(dst);    \
+	MOVL R10, 11*4+off+64(dst);  \
+	MOVL R10, 2*4+off+128(dst);  \
+	MOVL R10, 9*4+off+192(dst);  \
+	MOVL R10, 1*4+off+256(dst);  \
+	MOVL R10, 13*4+off+320(dst); \
+	MOVL R10, 4*4+off+384(dst);  \
+	MOVL R10, 8*4+off+448(dst);  \
+	MOVL R10, 15*4+off+512(dst); \
+	MOVL R10, 7*4+off+576(dst);  \
+	                             \
+	MOVL R11, 3*4+off+0(dst);    \
+	MOVL R11, 7*4+off+64(dst);   \
+	MOVL R11, 13*4+off+128(dst); \
+	MOVL R11, 12*4+off+192(dst); \
+	MOVL R11, 10*4+off+256(dst); \
+	MOVL R11, 1*4+off+320(dst);  \
+	MOVL R11, 9*4+off+384(dst);  \
+	MOVL R11, 14*4+off+448(dst); \
+	MOVL R11, 0*4+off+512(dst);  \
+	MOVL R11, 6*4+off+576(dst);  \
+	SHRQ $32, R11;               \
+	MOVL R11, 7*4+off+0(dst);    \
+	MOVL R11, 14*4+off+64(dst);  \
+	MOVL R11, 10*4+off+128(dst); \
+	MOVL R11, 0*4+off+192(dst);  \
+	MOVL R11, 5*4+off+256(dst);  \
+	MOVL R11, 9*4+off+320(dst);  \
+	MOVL R11, 12*4+off+384(dst); \
+	MOVL R11, 1*4+off+448(dst);  \
+	MOVL R11, 13*4+off+512(dst); \
+	MOVL R11, 2*4+off+576(dst);  \
+	                             \
+	MOVL R12, 8*4+off+0(dst);    \
+	MOVL R12, 5*4+off+64(dst);   \
+	MOVL R12, 4*4+off+128(dst);  \
+	MOVL R12, 15*4+off+192(dst); \
+	MOVL R12, 14*4+off+256(dst); \
+	MOVL R12, 3*4+off+320(dst);  \
+	MOVL R12, 11*4+off+384(dst); \
+	MOVL R12, 10*4+off+448(dst); \
+	MOVL R12, 7*4+off+512(dst);  \
+	MOVL R12, 1*4+off+576(dst);  \
+	SHRQ $32, R12;               \
+	MOVL R12, 12*4+off+0(dst);   \
+	MOVL R12, 2*4+off+64(dst);   \
+	MOVL R12, 11*4+off+128(dst); \
+	MOVL R12, 4*4+off+192(dst);  \
+	MOVL R12, 0*4+off+256(dst);  \
+	MOVL R12, 15*4+off+320(dst); \
+	MOVL R12, 10*4+off+384(dst); \
+	MOVL R12, 7*4+off+448(dst);  \
+	MOVL R12, 5*4+off+512(dst);  \
+	MOVL R12, 9*4+off+576(dst);  \
+	                             \
+	MOVL R13, 9*4+off+0(dst);    \
+	MOVL R13, 4*4+off+64(dst);   \
+	MOVL R13, 8*4+off+128(dst);  \
+	MOVL R13, 13*4+off+192(dst); \
+	MOVL R13, 3*4+off+256(dst);  \
+	MOVL R13, 5*4+off+320(dst);  \
+	MOVL R13, 7*4+off+384(dst);  \
+	MOVL R13, 15*4+off+448(dst); \
+	MOVL R13, 11*4+off+512(dst); \
+	MOVL R13, 0*4+off+576(dst);  \
+	SHRQ $32, R13;               \
+	MOVL R13, 13*4+off+0(dst);   \
+	MOVL R13, 10*4+off+64(dst);  \
+	MOVL R13, 0*4+off+128(dst);  \
+	MOVL R13, 3*4+off+192(dst);  \
+	MOVL R13, 9*4+off+256(dst);  \
+	MOVL R13, 6*4+off+320(dst);  \
+	MOVL R13, 15*4+off+384(dst); \
+	MOVL R13, 4*4+off+448(dst);  \
+	MOVL R13, 2*4+off+512(dst);  \
+	MOVL R13, 12*4+off+576(dst); \
+	                             \
+	MOVL R14, 10*4+off+0(dst);   \
+	MOVL R14, 12*4+off+64(dst);  \
+	MOVL R14, 1*4+off+128(dst);  \
+	MOVL R14, 6*4+off+192(dst);  \
+	MOVL R14, 13*4+off+256(dst); \
+	MOVL R14, 4*4+off+320(dst);  \
+	MOVL R14, 0*4+off+384(dst);  \
+	MOVL R14, 2*4+off+448(dst);  \
+	MOVL R14, 8*4+off+512(dst);  \
+	MOVL R14, 14*4+off+576(dst); \
+	SHRQ $32, R14;               \
+	MOVL R14, 14*4+off+0(dst);   \
+	MOVL R14, 3*4+off+64(dst);   \
+	MOVL R14, 7*4+off+128(dst);  \
+	MOVL R14, 2*4+off+192(dst);  \
+	MOVL R14, 15*4+off+256(dst); \
+	MOVL R14, 12*4+off+320(dst); \
+	MOVL R14, 6*4+off+384(dst);  \
+	MOVL R14, 0*4+off+448(dst);  \
+	MOVL R14, 9*4+off+512(dst);  \
+	MOVL R14, 11*4+off+576(dst); \
+	                             \
+	MOVL R15, 11*4+off+0(dst);   \
+	MOVL R15, 0*4+off+64(dst);   \
+	MOVL R15, 12*4+off+128(dst); \
+	MOVL R15, 7*4+off+192(dst);  \
+	MOVL R15, 8*4+off+256(dst);  \
+	MOVL R15, 14*4+off+320(dst); \
+	MOVL R15, 2*4+off+384(dst);  \
+	MOVL R15, 5*4+off+448(dst);  \
+	MOVL R15, 1*4+off+512(dst);  \
+	MOVL R15, 13*4+off+576(dst); \
+	SHRQ $32, R15;               \
+	MOVL R15, 15*4+off+0(dst);   \
+	MOVL R15, 6*4+off+64(dst);   \
+	MOVL R15, 3*4+off+128(dst);  \
+	MOVL R15, 11*4+off+192(dst); \
+	MOVL R15, 7*4+off+256(dst);  \
+	MOVL R15, 10*4+off+320(dst); \
+	MOVL R15, 5*4+off+384(dst);  \
+	MOVL R15, 9*4+off+448(dst);  \
+	MOVL R15, 4*4+off+512(dst);  \
+	MOVL R15, 8*4+off+576(dst)
+
+#define BLAKE2s_SSE2() \
+	PRECOMPUTE_MSG(SP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15);               \
+	ROUND_SSE2(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X8);                 \
+	ROUND_SSE2(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X8);     \
+	ROUND_SSE2(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X8); \
+	ROUND_SSE2(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X8)
+
+#define BLAKE2s_SSSE3() \
+	PRECOMPUTE_MSG(SP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15);                          \
+	ROUND_SSSE3(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X8, X13, X14);                 \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X8, X13, X14);     \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X8, X13, X14); \
+	ROUND_SSSE3(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X8, X13, X14)
+
+#define BLAKE2s_SSE4() \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14);                               \
+	LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0); \
+	ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
+
+#define HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_FUNC) \
+	MOVQ  h, AX;                   \
+	MOVQ  c, BX;                   \
+	MOVL  flag, CX;                \
+	MOVQ  blocks_base, SI;         \
+	MOVQ  blocks_len, DX;          \
+	                               \
+	MOVQ  SP, BP;                  \
+	MOVQ  SP, R9;                  \
+	ADDQ  $15, R9;                 \
+	ANDQ  $~15, R9;                \
+	MOVQ  R9, SP;                  \
+	                               \
+	MOVQ  0(BX), R9;               \
+	MOVQ  R9, 0(SP);               \
+	XORQ  R9, R9;                  \
+	MOVQ  R9, 8(SP);               \
+	MOVL  CX, 8(SP);               \
+	                               \
+	MOVOU 0(AX), X0;               \
+	MOVOU 16(AX), X1;              \
+	MOVOU iv0<>(SB), X2;           \
+	MOVOU iv1<>(SB), X3            \
+	                               \
+	MOVOU counter<>(SB), X12;      \
+	MOVOU rol16<>(SB), X13;        \
+	MOVOU rol8<>(SB), X14;         \
+	MOVO  0(SP), X15;              \
+	                               \
+	loop:                          \
+	MOVO  X0, X4;                  \
+	MOVO  X1, X5;                  \
+	MOVO  X2, X6;                  \
+	MOVO  X3, X7;                  \
+	                               \
+	PADDQ X12, X15;                \
+	PXOR  X15, X7;                 \
+	                               \
+	BLAKE2s_FUNC();                \
+	                               \
+	PXOR  X4, X0;                  \
+	PXOR  X5, X1;                  \
+	PXOR  X6, X0;                  \
+	PXOR  X7, X1;                  \
+	                               \
+	LEAQ  64(SI), SI;              \
+	SUBQ  $64, DX;                 \
+	JNE   loop;                    \
+	                               \
+	MOVO  X15, 0(SP);              \
+	MOVQ  0(SP), R9;               \
+	MOVQ  R9, 0(BX);               \
+	                               \
+	MOVOU X0, 0(AX);               \
+	MOVOU X1, 16(AX);              \
+	                               \
+	MOVQ  BP, SP
+
+// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+TEXT ·hashBlocksSSE2(SB), 0, $672-48 // frame = 656 + 16 byte alignment
+	HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE2)
+	RET
+
+// func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+TEXT ·hashBlocksSSSE3(SB), 0, $672-48 // frame = 656 + 16 byte alignment
+	HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSSE3)
+	RET
+
+// func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
+TEXT ·hashBlocksSSE4(SB), 0, $32-48 // frame = 16 + 16 byte alignment
+	HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE4)
+	RET

+ 174 - 0
src/golang.org/x/crypto/blake2s/blake2s_generic.go

@@ -0,0 +1,174 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blake2s
+
+// the precomputed values for BLAKE2s
+// there are 10 16-byte arrays - one for each round
+// the entries are calculated from the sigma constants.
+var precomputed = [10][16]byte{
+	{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
+	{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
+	{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
+	{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
+	{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
+	{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
+	{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
+	{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
+	{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
+	{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
+}
+
+func hashBlocksGeneric(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
+	var m [16]uint32
+	c0, c1 := c[0], c[1]
+
+	for i := 0; i < len(blocks); {
+		c0 += BlockSize
+		if c0 < BlockSize {
+			c1++
+		}
+
+		v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
+		v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
+		v12 ^= c0
+		v13 ^= c1
+		v14 ^= flag
+
+		for j := range m {
+			m[j] = uint32(blocks[i]) | uint32(blocks[i+1])<<8 | uint32(blocks[i+2])<<16 | uint32(blocks[i+3])<<24
+			i += 4
+		}
+
+		for k := range precomputed {
+			s := &(precomputed[k])
+
+			v0 += m[s[0]]
+			v0 += v4
+			v12 ^= v0
+			v12 = v12<<(32-16) | v12>>16
+			v8 += v12
+			v4 ^= v8
+			v4 = v4<<(32-12) | v4>>12
+			v1 += m[s[1]]
+			v1 += v5
+			v13 ^= v1
+			v13 = v13<<(32-16) | v13>>16
+			v9 += v13
+			v5 ^= v9
+			v5 = v5<<(32-12) | v5>>12
+			v2 += m[s[2]]
+			v2 += v6
+			v14 ^= v2
+			v14 = v14<<(32-16) | v14>>16
+			v10 += v14
+			v6 ^= v10
+			v6 = v6<<(32-12) | v6>>12
+			v3 += m[s[3]]
+			v3 += v7
+			v15 ^= v3
+			v15 = v15<<(32-16) | v15>>16
+			v11 += v15
+			v7 ^= v11
+			v7 = v7<<(32-12) | v7>>12
+
+			v0 += m[s[4]]
+			v0 += v4
+			v12 ^= v0
+			v12 = v12<<(32-8) | v12>>8
+			v8 += v12
+			v4 ^= v8
+			v4 = v4<<(32-7) | v4>>7
+			v1 += m[s[5]]
+			v1 += v5
+			v13 ^= v1
+			v13 = v13<<(32-8) | v13>>8
+			v9 += v13
+			v5 ^= v9
+			v5 = v5<<(32-7) | v5>>7
+			v2 += m[s[6]]
+			v2 += v6
+			v14 ^= v2
+			v14 = v14<<(32-8) | v14>>8
+			v10 += v14
+			v6 ^= v10
+			v6 = v6<<(32-7) | v6>>7
+			v3 += m[s[7]]
+			v3 += v7
+			v15 ^= v3
+			v15 = v15<<(32-8) | v15>>8
+			v11 += v15
+			v7 ^= v11
+			v7 = v7<<(32-7) | v7>>7
+
+			v0 += m[s[8]]
+			v0 += v5
+			v15 ^= v0
+			v15 = v15<<(32-16) | v15>>16
+			v10 += v15
+			v5 ^= v10
+			v5 = v5<<(32-12) | v5>>12
+			v1 += m[s[9]]
+			v1 += v6
+			v12 ^= v1
+			v12 = v12<<(32-16) | v12>>16
+			v11 += v12
+			v6 ^= v11
+			v6 = v6<<(32-12) | v6>>12
+			v2 += m[s[10]]
+			v2 += v7
+			v13 ^= v2
+			v13 = v13<<(32-16) | v13>>16
+			v8 += v13
+			v7 ^= v8
+			v7 = v7<<(32-12) | v7>>12
+			v3 += m[s[11]]
+			v3 += v4
+			v14 ^= v3
+			v14 = v14<<(32-16) | v14>>16
+			v9 += v14
+			v4 ^= v9
+			v4 = v4<<(32-12) | v4>>12
+
+			v0 += m[s[12]]
+			v0 += v5
+			v15 ^= v0
+			v15 = v15<<(32-8) | v15>>8
+			v10 += v15
+			v5 ^= v10
+			v5 = v5<<(32-7) | v5>>7
+			v1 += m[s[13]]
+			v1 += v6
+			v12 ^= v1
+			v12 = v12<<(32-8) | v12>>8
+			v11 += v12
+			v6 ^= v11
+			v6 = v6<<(32-7) | v6>>7
+			v2 += m[s[14]]
+			v2 += v7
+			v13 ^= v2
+			v13 = v13<<(32-8) | v13>>8
+			v8 += v13
+			v7 ^= v8
+			v7 = v7<<(32-7) | v7>>7
+			v3 += m[s[15]]
+			v3 += v4
+			v14 ^= v3
+			v14 = v14<<(32-8) | v14>>8
+			v9 += v14
+			v4 ^= v9
+			v4 = v4<<(32-7) | v4>>7
+		}
+
+		h[0] ^= v0 ^ v8
+		h[1] ^= v1 ^ v9
+		h[2] ^= v2 ^ v10
+		h[3] ^= v3 ^ v11
+		h[4] ^= v4 ^ v12
+		h[5] ^= v5 ^ v13
+		h[6] ^= v6 ^ v14
+		h[7] ^= v7 ^ v15
+	}
+	c[0], c[1] = c0, c1
+}

+ 17 - 0
src/golang.org/x/crypto/blake2s/blake2s_ref.go

@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!386 gccgo appengine
+
+package blake2s
+
+var (
+	useSSE4  = false
+	useSSSE3 = false
+	useSSE2  = false
+)
+
+func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
+	hashBlocksGeneric(h, c, flag, blocks)
+}

+ 1050 - 0
src/golang.org/x/crypto/blake2s/blake2s_test.go

@@ -0,0 +1,1050 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blake2s
+
+import (
+	"bytes"
+	"encoding"
+	"encoding/hex"
+	"fmt"
+	"testing"
+)
+
+func TestHashes(t *testing.T) {
+	defer func(sse2, ssse3, sse4 bool) {
+		useSSE2, useSSSE3, useSSE4 = sse2, ssse3, sse4
+	}(useSSE2, useSSSE3, useSSE4)
+
+	if useSSE4 {
+		t.Log("SSE4 version")
+		testHashes(t)
+		testHashes128(t)
+		useSSE4 = false
+	}
+	if useSSSE3 {
+		t.Log("SSSE3 version")
+		testHashes(t)
+		testHashes128(t)
+		useSSSE3 = false
+	}
+	if useSSE2 {
+		t.Log("SSE2 version")
+		testHashes(t)
+		testHashes128(t)
+		useSSE2 = false
+	}
+
+	t.Log("generic version")
+	testHashes(t)
+	testHashes128(t)
+}
+
+func TestHashes2X(t *testing.T) {
+	defer func(sse2, ssse3, sse4 bool) {
+		useSSE2, useSSSE3, useSSE4 = sse2, ssse3, sse4
+	}(useSSE2, useSSSE3, useSSE4)
+
+	if useSSE4 {
+		t.Log("SSE4 version")
+		testHashes2X(t)
+		useSSE4 = false
+	}
+	if useSSSE3 {
+		t.Log("SSSE3 version")
+		testHashes2X(t)
+		useSSSE3 = false
+	}
+	if useSSE2 {
+		t.Log("SSE2 version")
+		testHashes2X(t)
+		useSSE2 = false
+	}
+
+	t.Log("generic version")
+	testHashes2X(t)
+}
+
+func TestMarshal(t *testing.T) {
+	input := make([]byte, 255)
+	for i := range input {
+		input[i] = byte(i)
+	}
+	for i := 0; i < 256; i++ {
+		h, err := New256(nil)
+		if err != nil {
+			t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err)
+		}
+		h2, err := New256(nil)
+		if err != nil {
+			t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err)
+		}
+
+		h.Write(input[:i/2])
+		halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary()
+		if err != nil {
+			t.Fatalf("len(input)=%d: could not marshal: %v", i, err)
+		}
+		err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate)
+		if err != nil {
+			t.Fatalf("len(input)=%d: could not unmarshal: %v", i, err)
+		}
+
+		h.Write(input[i/2 : i])
+		sum := h.Sum(nil)
+		h2.Write(input[i/2 : i])
+		sum2 := h2.Sum(nil)
+
+		if !bytes.Equal(sum, sum2) {
+			t.Fatalf("len(input)=%d: results do not match; sum = %v, sum2 = %v", i, sum, sum2)
+		}
+
+		h3, err := New256(nil)
+		if err != nil {
+			t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err)
+		}
+		h3.Write(input[:i])
+		sum3 := h3.Sum(nil)
+		if !bytes.Equal(sum, sum3) {
+			t.Fatalf("len(input)=%d: sum = %v, want %v", i, sum, sum3)
+		}
+	}
+}
+
+func testHashes(t *testing.T) {
+	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
+
+	input := make([]byte, 255)
+	for i := range input {
+		input[i] = byte(i)
+	}
+
+	for i, expectedHex := range hashes {
+		h, err := New256(key)
+		if err != nil {
+			t.Fatalf("#%d: error from New256: %v", i, err)
+		}
+
+		h.Write(input[:i])
+		sum := h.Sum(nil)
+
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+
+		h.Reset()
+		for j := 0; j < i; j++ {
+			h.Write(input[j : j+1])
+		}
+
+		sum = h.Sum(sum[:0])
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+	}
+}
+
+func testHashes128(t *testing.T) {
+	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
+
+	input := make([]byte, 255)
+	for i := range input {
+		input[i] = byte(i)
+	}
+
+	for i, expectedHex := range hashes128 {
+		h, err := New128(key)
+		if err != nil {
+			t.Fatalf("#%d: error from New128: %v", i, err)
+		}
+
+		h.Write(input[:i])
+		sum := h.Sum(nil)
+
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+
+		h.Reset()
+		for j := 0; j < i; j++ {
+			h.Write(input[j : j+1])
+		}
+
+		sum = h.Sum(sum[:0])
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+	}
+}
+
+func testHashes2X(t *testing.T) {
+	key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
+
+	input := make([]byte, 256)
+	for i := range input {
+		input[i] = byte(i)
+	}
+
+	for i, expectedHex := range hashes2X {
+		length := uint16(len(expectedHex) / 2)
+		sum := make([]byte, int(length))
+
+		h, err := NewXOF(length, key)
+		if err != nil {
+			t.Fatalf("#%d: error from NewXOF: %v", i, err)
+		}
+
+		if _, err := h.Write(input); err != nil {
+			t.Fatalf("#%d (single write): error from Write: %v", i, err)
+		}
+		if _, err := h.Read(sum); err != nil {
+			t.Fatalf("#%d (single write): error from Read: %v", i, err)
+		}
+
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+
+		h.Reset()
+		for j := 0; j < len(input); j++ {
+			h.Write(input[j : j+1])
+		}
+		for j := 0; j < len(sum); j++ {
+			h = h.Clone()
+			if _, err := h.Read(sum[j : j+1]); err != nil {
+				t.Fatalf("#%d (byte-by-byte) - Read %d: error from Read: %v", i, j, err)
+			}
+		}
+		if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
+			t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
+		}
+	}
+
+	h, err := NewXOF(OutputLengthUnknown, key)
+	if err != nil {
+		t.Fatalf("#unknown length: error from NewXOF: %v", err)
+	}
+	if _, err := h.Write(input); err != nil {
+		t.Fatalf("#unknown length: error from Write: %v", err)
+	}
+
+	var result [64]byte
+	if n, err := h.Read(result[:]); err != nil {
+		t.Fatalf("#unknown length: error from Read: %v", err)
+	} else if n != len(result) {
+		t.Fatalf("#unknown length: Read returned %d bytes, want %d", n, len(result))
+	}
+
+	const expected = "2a9a6977d915a2c4dd07dbcafe1918bf1682e56d9c8e567ecd19bfd7cd93528833c764d12b34a5e2a219c9fd463dab45e972c5574d73f45de5b2e23af72530d8"
+	if fmt.Sprintf("%x", result) != expected {
+		t.Fatalf("#unknown length: bad result %x, wanted %s", result, expected)
+	}
+}
+
+// Benchmarks
+
+func benchmarkSum(b *testing.B, size int) {
+	data := make([]byte, size)
+	b.SetBytes(int64(size))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		Sum256(data)
+	}
+}
+
+func benchmarkWrite(b *testing.B, size int) {
+	data := make([]byte, size)
+	h, _ := New256(nil)
+	b.SetBytes(int64(size))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		h.Write(data)
+	}
+}
+
+func BenchmarkWrite64(b *testing.B) { benchmarkWrite(b, 64) }
+func BenchmarkWrite1K(b *testing.B) { benchmarkWrite(b, 1024) }
+
+func BenchmarkSum64(b *testing.B) { benchmarkSum(b, 64) }
+func BenchmarkSum1K(b *testing.B) { benchmarkSum(b, 1024) }
+
+// hashes is taken from https://blake2.net/blake2s-test.txt
+var hashes = []string{
+	"48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49",
+	"40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1",
+	"6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803",
+	"1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b",
+	"f6c3fbadb4cc687a0064a5be6e791bec63b868ad62fba61b3757ef9ca52e05b2",
+	"49c1f21188dfd769aea0e911dd6b41f14dab109d2b85977aa3088b5c707e8598",
+	"fdd8993dcd43f696d44f3cea0ff35345234ec8ee083eb3cada017c7f78c17143",
+	"e6c8125637438d0905b749f46560ac89fd471cf8692e28fab982f73f019b83a9",
+	"19fc8ca6979d60e6edd3b4541e2f967ced740df6ec1eaebbfe813832e96b2974",
+	"a6ad777ce881b52bb5a4421ab6cdd2dfba13e963652d4d6d122aee46548c14a7",
+	"f5c4b2ba1a00781b13aba0425242c69cb1552f3f71a9a3bb22b4a6b4277b46dd",
+	"e33c4c9bd0cc7e45c80e65c77fa5997fec7002738541509e68a9423891e822a3",
+	"fba16169b2c3ee105be6e1e650e5cbf40746b6753d036ab55179014ad7ef6651",
+	"f5c4bec6d62fc608bf41cc115f16d61c7efd3ff6c65692bbe0afffb1fede7475",
+	"a4862e76db847f05ba17ede5da4e7f91b5925cf1ad4ba12732c3995742a5cd6e",
+	"65f4b860cd15b38ef814a1a804314a55be953caa65fd758ad989ff34a41c1eea",
+	"19ba234f0a4f38637d1839f9d9f76ad91c8522307143c97d5f93f69274cec9a7",
+	"1a67186ca4a5cb8e65fca0e2ecbc5ddc14ae381bb8bffeb9e0a103449e3ef03c",
+	"afbea317b5a2e89c0bd90ccf5d7fd0ed57fe585e4be3271b0a6bf0f5786b0f26",
+	"f1b01558ce541262f5ec34299d6fb4090009e3434be2f49105cf46af4d2d4124",
+	"13a0a0c86335635eaa74ca2d5d488c797bbb4f47dc07105015ed6a1f3309efce",
+	"1580afeebebb346f94d59fe62da0b79237ead7b1491f5667a90e45edf6ca8b03",
+	"20be1a875b38c573dd7faaa0de489d655c11efb6a552698e07a2d331b5f655c3",
+	"be1fe3c4c04018c54c4a0f6b9a2ed3c53abe3a9f76b4d26de56fc9ae95059a99",
+	"e3e3ace537eb3edd8463d9ad3582e13cf86533ffde43d668dd2e93bbdbd7195a",
+	"110c50c0bf2c6e7aeb7e435d92d132ab6655168e78a2decdec3330777684d9c1",
+	"e9ba8f505c9c80c08666a701f3367e6cc665f34b22e73c3c0417eb1c2206082f",
+	"26cd66fca02379c76df12317052bcafd6cd8c3a7b890d805f36c49989782433a",
+	"213f3596d6e3a5d0e9932cd2159146015e2abc949f4729ee2632fe1edb78d337",
+	"1015d70108e03be1c702fe97253607d14aee591f2413ea6787427b6459ff219a",
+	"3ca989de10cfe609909472c8d35610805b2f977734cf652cc64b3bfc882d5d89",
+	"b6156f72d380ee9ea6acd190464f2307a5c179ef01fd71f99f2d0f7a57360aea",
+	"c03bc642b20959cbe133a0303e0c1abff3e31ec8e1a328ec8565c36decff5265",
+	"2c3e08176f760c6264c3a2cd66fec6c3d78de43fc192457b2a4a660a1e0eb22b",
+	"f738c02f3c1b190c512b1a32deabf353728e0e9ab034490e3c3409946a97aeec",
+	"8b1880df301cc963418811088964839287ff7fe31c49ea6ebd9e48bdeee497c5",
+	"1e75cb21c60989020375f1a7a242839f0b0b68973a4c2a05cf7555ed5aaec4c1",
+	"62bf8a9c32a5bccf290b6c474d75b2a2a4093f1a9e27139433a8f2b3bce7b8d7",
+	"166c8350d3173b5e702b783dfd33c66ee0432742e9b92b997fd23c60dc6756ca",
+	"044a14d822a90cacf2f5a101428adc8f4109386ccb158bf905c8618b8ee24ec3",
+	"387d397ea43a994be84d2d544afbe481a2000f55252696bba2c50c8ebd101347",
+	"56f8ccf1f86409b46ce36166ae9165138441577589db08cbc5f66ca29743b9fd",
+	"9706c092b04d91f53dff91fa37b7493d28b576b5d710469df79401662236fc03",
+	"877968686c068ce2f7e2adcff68bf8748edf3cf862cfb4d3947a3106958054e3",
+	"8817e5719879acf7024787eccdb271035566cfa333e049407c0178ccc57a5b9f",
+	"8938249e4b50cadaccdf5b18621326cbb15253e33a20f5636e995d72478de472",
+	"f164abba4963a44d107257e3232d90aca5e66a1408248c51741e991db5227756",
+	"d05563e2b1cba0c4a2a1e8bde3a1a0d9f5b40c85a070d6f5fb21066ead5d0601",
+	"03fbb16384f0a3866f4c3117877666efbf124597564b293d4aab0d269fabddfa",
+	"5fa8486ac0e52964d1881bbe338eb54be2f719549224892057b4da04ba8b3475",
+	"cdfabcee46911111236a31708b2539d71fc211d9b09c0d8530a11e1dbf6eed01",
+	"4f82de03b9504793b82a07a0bdcdff314d759e7b62d26b784946b0d36f916f52",
+	"259ec7f173bcc76a0994c967b4f5f024c56057fb79c965c4fae41875f06a0e4c",
+	"193cc8e7c3e08bb30f5437aa27ade1f142369b246a675b2383e6da9b49a9809e",
+	"5c10896f0e2856b2a2eee0fe4a2c1633565d18f0e93e1fab26c373e8f829654d",
+	"f16012d93f28851a1eb989f5d0b43f3f39ca73c9a62d5181bff237536bd348c3",
+	"2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806",
+	"ddb8782485e900bc60bcf4c33a6fd585680cc683d516efa03eb9985fad8715fb",
+	"4c4d6e71aea05786413148fc7a786b0ecaf582cff1209f5a809fba8504ce662c",
+	"fb4c5e86d7b2229b99b8ba6d94c247ef964aa3a2bae8edc77569f28dbbff2d4e",
+	"e94f526de9019633ecd54ac6120f23958d7718f1e7717bf329211a4faeed4e6d",
+	"cbd6660a10db3f23f7a03d4b9d4044c7932b2801ac89d60bc9eb92d65a46c2a0",
+	"8818bbd3db4dc123b25cbba5f54c2bc4b3fcf9bf7d7a7709f4ae588b267c4ece",
+	"c65382513f07460da39833cb666c5ed82e61b9e998f4b0c4287cee56c3cc9bcd",
+	"8975b0577fd35566d750b362b0897a26c399136df07bababbde6203ff2954ed4",
+	"21fe0ceb0052be7fb0f004187cacd7de67fa6eb0938d927677f2398c132317a8",
+	"2ef73f3c26f12d93889f3c78b6a66c1d52b649dc9e856e2c172ea7c58ac2b5e3",
+	"388a3cd56d73867abb5f8401492b6e2681eb69851e767fd84210a56076fb3dd3",
+	"af533e022fc9439e4e3cb838ecd18692232adf6fe9839526d3c3dd1b71910b1a",
+	"751c09d41a9343882a81cd13ee40818d12eb44c6c7f40df16e4aea8fab91972a",
+	"5b73ddb68d9d2b0aa265a07988d6b88ae9aac582af83032f8a9b21a2e1b7bf18",
+	"3da29126c7c5d7f43e64242a79feaa4ef3459cdeccc898ed59a97f6ec93b9dab",
+	"566dc920293da5cb4fe0aa8abda8bbf56f552313bff19046641e3615c1e3ed3f",
+	"4115bea02f73f97f629e5c5590720c01e7e449ae2a6697d4d2783321303692f9",
+	"4ce08f4762468a7670012164878d68340c52a35e66c1884d5c864889abc96677",
+	"81ea0b7804124e0c22ea5fc71104a2afcb52a1fa816f3ecb7dcb5d9dea1786d0",
+	"fe362733b05f6bedaf9379d7f7936ede209b1f8323c3922549d9e73681b5db7b",
+	"eff37d30dfd20359be4e73fdf40d27734b3df90a97a55ed745297294ca85d09f",
+	"172ffc67153d12e0ca76a8b6cd5d4731885b39ce0cac93a8972a18006c8b8baf",
+	"c47957f1cc88e83ef9445839709a480a036bed5f88ac0fcc8e1e703ffaac132c",
+	"30f3548370cfdceda5c37b569b6175e799eef1a62aaa943245ae7669c227a7b5",
+	"c95dcb3cf1f27d0eef2f25d2413870904a877c4a56c2de1e83e2bc2ae2e46821",
+	"d5d0b5d705434cd46b185749f66bfb5836dcdf6ee549a2b7a4aee7f58007caaf",
+	"bbc124a712f15d07c300e05b668389a439c91777f721f8320c1c9078066d2c7e",
+	"a451b48c35a6c7854cfaae60262e76990816382ac0667e5a5c9e1b46c4342ddf",
+	"b0d150fb55e778d01147f0b5d89d99ecb20ff07e5e6760d6b645eb5b654c622b",
+	"34f737c0ab219951eee89a9f8dac299c9d4c38f33fa494c5c6eefc92b6db08bc",
+	"1a62cc3a00800dcbd99891080c1e098458193a8cc9f970ea99fbeff00318c289",
+	"cfce55ebafc840d7ae48281c7fd57ec8b482d4b704437495495ac414cf4a374b",
+	"6746facf71146d999dabd05d093ae586648d1ee28e72617b99d0f0086e1e45bf",
+	"571ced283b3f23b4e750bf12a2caf1781847bd890e43603cdc5976102b7bb11b",
+	"cfcb765b048e35022c5d089d26e85a36b005a2b80493d03a144e09f409b6afd1",
+	"4050c7a27705bb27f42089b299f3cbe5054ead68727e8ef9318ce6f25cd6f31d",
+	"184070bd5d265fbdc142cd1c5cd0d7e414e70369a266d627c8fba84fa5e84c34",
+	"9edda9a4443902a9588c0d0ccc62b930218479a6841e6fe7d43003f04b1fd643",
+	"e412feef7908324a6da1841629f35d3d358642019310ec57c614836b63d30763",
+	"1a2b8edff3f9acc1554fcbae3cf1d6298c6462e22e5eb0259684f835012bd13f",
+	"288c4ad9b9409762ea07c24a41f04f69a7d74bee2d95435374bde946d7241c7b",
+	"805691bb286748cfb591d3aebe7e6f4e4dc6e2808c65143cc004e4eb6fd09d43",
+	"d4ac8d3a0afc6cfa7b460ae3001baeb36dadb37da07d2e8ac91822df348aed3d",
+	"c376617014d20158bced3d3ba552b6eccf84e62aa3eb650e90029c84d13eea69",
+	"c41f09f43cecae7293d6007ca0a357087d5ae59be500c1cd5b289ee810c7b082",
+	"03d1ced1fba5c39155c44b7765cb760c78708dcfc80b0bd8ade3a56da8830b29",
+	"09bde6f152218dc92c41d7f45387e63e5869d807ec70b821405dbd884b7fcf4b",
+	"71c9036e18179b90b37d39e9f05eb89cc5fc341fd7c477d0d7493285faca08a4",
+	"5916833ebb05cd919ca7fe83b692d3205bef72392b2cf6bb0a6d43f994f95f11",
+	"f63aab3ec641b3b024964c2b437c04f6043c4c7e0279239995401958f86bbe54",
+	"f172b180bfb09740493120b6326cbdc561e477def9bbcfd28cc8c1c5e3379a31",
+	"cb9b89cc18381dd9141ade588654d4e6a231d5bf49d4d59ac27d869cbe100cf3",
+	"7bd8815046fdd810a923e1984aaebdcdf84d87c8992d68b5eeb460f93eb3c8d7",
+	"607be66862fd08ee5b19facac09dfdbcd40c312101d66e6ebd2b841f1b9a9325",
+	"9fe03bbe69ab1834f5219b0da88a08b30a66c5913f0151963c360560db0387b3",
+	"90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c",
+	"336ea0530f4a7469126e0218587ebbde3358a0b31c29d200f7dc7eb15c6aadd8",
+	"a79e76dc0abca4396f0747cd7b748df913007626b1d659da0c1f78b9303d01a3",
+	"44e78a773756e0951519504d7038d28d0213a37e0ce375371757bc996311e3b8",
+	"77ac012a3f754dcfeab5eb996be9cd2d1f96111b6e49f3994df181f28569d825",
+	"ce5a10db6fccdaf140aaa4ded6250a9c06e9222bc9f9f3658a4aff935f2b9f3a",
+	"ecc203a7fe2be4abd55bb53e6e673572e0078da8cd375ef430cc97f9f80083af",
+	"14a5186de9d7a18b0412b8563e51cc5433840b4a129a8ff963b33a3c4afe8ebb",
+	"13f8ef95cb86e6a638931c8e107673eb76ba10d7c2cd70b9d9920bbeed929409",
+	"0b338f4ee12f2dfcb78713377941e0b0632152581d1332516e4a2cab1942cca4",
+	"eaab0ec37b3b8ab796e9f57238de14a264a076f3887d86e29bb5906db5a00e02",
+	"23cb68b8c0e6dc26dc27766ddc0a13a99438fd55617aa4095d8f969720c872df",
+	"091d8ee30d6f2968d46b687dd65292665742de0bb83dcc0004c72ce10007a549",
+	"7f507abc6d19ba00c065a876ec5657868882d18a221bc46c7a6912541f5bc7ba",
+	"a0607c24e14e8c223db0d70b4d30ee88014d603f437e9e02aa7dafa3cdfbad94",
+	"ddbfea75cc467882eb3483ce5e2e756a4f4701b76b445519e89f22d60fa86e06",
+	"0c311f38c35a4fb90d651c289d486856cd1413df9b0677f53ece2cd9e477c60a",
+	"46a73a8dd3e70f59d3942c01df599def783c9da82fd83222cd662b53dce7dbdf",
+	"ad038ff9b14de84a801e4e621ce5df029dd93520d0c2fa38bff176a8b1d1698c",
+	"ab70c5dfbd1ea817fed0cd067293abf319e5d7901c2141d5d99b23f03a38e748",
+	"1fffda67932b73c8ecaf009a3491a026953babfe1f663b0697c3c4ae8b2e7dcb",
+	"b0d2cc19472dd57f2b17efc03c8d58c2283dbb19da572f7755855aa9794317a0",
+	"a0d19a6ee33979c325510e276622df41f71583d07501b87071129a0ad94732a5",
+	"724642a7032d1062b89e52bea34b75df7d8fe772d9fe3c93ddf3c4545ab5a99b",
+	"ade5eaa7e61f672d587ea03dae7d7b55229c01d06bc0a5701436cbd18366a626",
+	"013b31ebd228fcdda51fabb03bb02d60ac20ca215aafa83bdd855e3755a35f0b",
+	"332ed40bb10dde3c954a75d7b8999d4b26a1c063c1dc6e32c1d91bab7bbb7d16",
+	"c7a197b3a05b566bcc9facd20e441d6f6c2860ac9651cd51d6b9d2cdeeea0390",
+	"bd9cf64ea8953c037108e6f654914f3958b68e29c16700dc184d94a21708ff60",
+	"8835b0ac021151df716474ce27ce4d3c15f0b2dab48003cf3f3efd0945106b9a",
+	"3bfefa3301aa55c080190cffda8eae51d9af488b4c1f24c3d9a75242fd8ea01d",
+	"08284d14993cd47d53ebaecf0df0478cc182c89c00e1859c84851686ddf2c1b7",
+	"1ed7ef9f04c2ac8db6a864db131087f27065098e69c3fe78718d9b947f4a39d0",
+	"c161f2dcd57e9c1439b31a9dd43d8f3d7dd8f0eb7cfac6fb25a0f28e306f0661",
+	"c01969ad34c52caf3dc4d80d19735c29731ac6e7a92085ab9250c48dea48a3fc",
+	"1720b3655619d2a52b3521ae0e49e345cb3389ebd6208acaf9f13fdacca8be49",
+	"756288361c83e24c617cf95c905b22d017cdc86f0bf1d658f4756c7379873b7f",
+	"e7d0eda3452693b752abcda1b55e276f82698f5f1605403eff830bea0071a394",
+	"2c82ecaa6b84803e044af63118afe544687cb6e6c7df49ed762dfd7c8693a1bc",
+	"6136cbf4b441056fa1e2722498125d6ded45e17b52143959c7f4d4e395218ac2",
+	"721d3245aafef27f6a624f47954b6c255079526ffa25e9ff77e5dcff473b1597",
+	"9dd2fbd8cef16c353c0ac21191d509eb28dd9e3e0d8cea5d26ca839393851c3a",
+	"b2394ceacdebf21bf9df2ced98e58f1c3a4bbbff660dd900f62202d6785cc46e",
+	"57089f222749ad7871765f062b114f43ba20ec56422a8b1e3f87192c0ea718c6",
+	"e49a9459961cd33cdf4aae1b1078a5dea7c040e0fea340c93a724872fc4af806",
+	"ede67f720effd2ca9c88994152d0201dee6b0a2d2c077aca6dae29f73f8b6309",
+	"e0f434bf22e3088039c21f719ffc67f0f2cb5e98a7a0194c76e96bf4e8e17e61",
+	"277c04e2853484a4eba910ad336d01b477b67cc200c59f3c8d77eef8494f29cd",
+	"156d5747d0c99c7f27097d7b7e002b2e185cb72d8dd7eb424a0321528161219f",
+	"20ddd1ed9b1ca803946d64a83ae4659da67fba7a1a3eddb1e103c0f5e03e3a2c",
+	"f0af604d3dabbf9a0f2a7d3dda6bd38bba72c6d09be494fcef713ff10189b6e6",
+	"9802bb87def4cc10c4a5fd49aa58dfe2f3fddb46b4708814ead81d23ba95139b",
+	"4f8ce1e51d2fe7f24043a904d898ebfc91975418753413aa099b795ecb35cedb",
+	"bddc6514d7ee6ace0a4ac1d0e068112288cbcf560454642705630177cba608bd",
+	"d635994f6291517b0281ffdd496afa862712e5b3c4e52e4cd5fdae8c0e72fb08",
+	"878d9ca600cf87e769cc305c1b35255186615a73a0da613b5f1c98dbf81283ea",
+	"a64ebe5dc185de9fdde7607b6998702eb23456184957307d2fa72e87a47702d6",
+	"ce50eab7b5eb52bdc9ad8e5a480ab780ca9320e44360b1fe37e03f2f7ad7de01",
+	"eeddb7c0db6e30abe66d79e327511e61fcebbc29f159b40a86b046ecf0513823",
+	"787fc93440c1ec96b5ad01c16cf77916a1405f9426356ec921d8dff3ea63b7e0",
+	"7f0d5eab47eefda696c0bf0fbf86ab216fce461e9303aba6ac374120e890e8df",
+	"b68004b42f14ad029f4c2e03b1d5eb76d57160e26476d21131bef20ada7d27f4",
+	"b0c4eb18ae250b51a41382ead92d0dc7455f9379fc9884428e4770608db0faec",
+	"f92b7a870c059f4d46464c824ec96355140bdce681322cc3a992ff103e3fea52",
+	"5364312614813398cc525d4c4e146edeb371265fba19133a2c3d2159298a1742",
+	"f6620e68d37fb2af5000fc28e23b832297ecd8bce99e8be4d04e85309e3d3374",
+	"5316a27969d7fe04ff27b283961bffc3bf5dfb32fb6a89d101c6c3b1937c2871",
+	"81d1664fdf3cb33c24eebac0bd64244b77c4abea90bbe8b5ee0b2aafcf2d6a53",
+	"345782f295b0880352e924a0467b5fbc3e8f3bfbc3c7e48b67091fb5e80a9442",
+	"794111ea6cd65e311f74ee41d476cb632ce1e4b051dc1d9e9d061a19e1d0bb49",
+	"2a85daf6138816b99bf8d08ba2114b7ab07975a78420c1a3b06a777c22dd8bcb",
+	"89b0d5f289ec16401a069a960d0b093e625da3cf41ee29b59b930c5820145455",
+	"d0fdcb543943fc27d20864f52181471b942cc77ca675bcb30df31d358ef7b1eb",
+	"b17ea8d77063c709d4dc6b879413c343e3790e9e62ca85b7900b086f6b75c672",
+	"e71a3e2c274db842d92114f217e2c0eac8b45093fdfd9df4ca7162394862d501",
+	"c0476759ab7aa333234f6b44f5fd858390ec23694c622cb986e769c78edd733e",
+	"9ab8eabb1416434d85391341d56993c55458167d4418b19a0f2ad8b79a83a75b",
+	"7992d0bbb15e23826f443e00505d68d3ed7372995a5c3e498654102fbcd0964e",
+	"c021b30085151435df33b007ccecc69df1269f39ba25092bed59d932ac0fdc28",
+	"91a25ec0ec0d9a567f89c4bfe1a65a0e432d07064b4190e27dfb81901fd3139b",
+	"5950d39a23e1545f301270aa1a12f2e6c453776e4d6355de425cc153f9818867",
+	"d79f14720c610af179a3765d4b7c0968f977962dbf655b521272b6f1e194488e",
+	"e9531bfc8b02995aeaa75ba27031fadbcbf4a0dab8961d9296cd7e84d25d6006",
+	"34e9c26a01d7f16181b454a9d1623c233cb99d31c694656e9413aca3e918692f",
+	"d9d7422f437bd439ddd4d883dae2a08350173414be78155133fff1964c3d7972",
+	"4aee0c7aaf075414ff1793ead7eaca601775c615dbd60b640b0a9f0ce505d435",
+	"6bfdd15459c83b99f096bfb49ee87b063d69c1974c6928acfcfb4099f8c4ef67",
+	"9fd1c408fd75c336193a2a14d94f6af5adf050b80387b4b010fb29f4cc72707c",
+	"13c88480a5d00d6c8c7ad2110d76a82d9b70f4fa6696d4e5dd42a066dcaf9920",
+	"820e725ee25fe8fd3a8d5abe4c46c3ba889de6fa9191aa22ba67d5705421542b",
+	"32d93a0eb02f42fbbcaf2bad0085b282e46046a4df7ad10657c9d6476375b93e",
+	"adc5187905b1669cd8ec9c721e1953786b9d89a9bae30780f1e1eab24a00523c",
+	"e90756ff7f9ad810b239a10ced2cf9b2284354c1f8c7e0accc2461dc796d6e89",
+	"1251f76e56978481875359801db589a0b22f86d8d634dc04506f322ed78f17e8",
+	"3afa899fd980e73ecb7f4d8b8f291dc9af796bc65d27f974c6f193c9191a09fd",
+	"aa305be26e5deddc3c1010cbc213f95f051c785c5b431e6a7cd048f161787528",
+	"8ea1884ff32e9d10f039b407d0d44e7e670abd884aeee0fb757ae94eaa97373d",
+	"d482b2155d4dec6b4736a1f1617b53aaa37310277d3fef0c37ad41768fc235b4",
+	"4d413971387e7a8898a8dc2a27500778539ea214a2dfe9b3d7e8ebdce5cf3db3",
+	"696e5d46e6c57e8796e4735d08916e0b7929b3cf298c296d22e9d3019653371c",
+	"1f5647c1d3b088228885865c8940908bf40d1a8272821973b160008e7a3ce2eb",
+	"b6e76c330f021a5bda65875010b0edf09126c0f510ea849048192003aef4c61c",
+	"3cd952a0beada41abb424ce47f94b42be64e1ffb0fd0782276807946d0d0bc55",
+	"98d92677439b41b7bb513312afb92bcc8ee968b2e3b238cecb9b0f34c9bb63d0",
+	"ecbca2cf08ae57d517ad16158a32bfa7dc0382eaeda128e91886734c24a0b29d",
+	"942cc7c0b52e2b16a4b89fa4fc7e0bf609e29a08c1a8543452b77c7bfd11bb28",
+	"8a065d8b61a0dffb170d5627735a76b0e9506037808cba16c345007c9f79cf8f",
+	"1b9fa19714659c78ff413871849215361029ac802b1cbcd54e408bd87287f81f",
+	"8dab071bcd6c7292a9ef727b4ae0d86713301da8618d9a48adce55f303a869a1",
+	"8253e3e7c7b684b9cb2beb014ce330ff3d99d17abbdbabe4f4d674ded53ffc6b",
+	"f195f321e9e3d6bd7d074504dd2ab0e6241f92e784b1aa271ff648b1cab6d7f6",
+	"27e4cc72090f241266476a7c09495f2db153d5bcbd761903ef79275ec56b2ed8",
+	"899c2405788e25b99a1846355e646d77cf400083415f7dc5afe69d6e17c00023",
+	"a59b78c4905744076bfee894de707d4f120b5c6893ea0400297d0bb834727632",
+	"59dc78b105649707a2bb4419c48f005400d3973de3736610230435b10424b24f",
+	"c0149d1d7e7a6353a6d906efe728f2f329fe14a4149a3ea77609bc42b975ddfa",
+	"a32f241474a6c16932e9243be0cf09bcdc7e0ca0e7a6a1b9b1a0f01e41502377",
+	"b239b2e4f81841361c1339f68e2c359f929af9ad9f34e01aab4631ad6d5500b0",
+	"85fb419c7002a3e0b4b6ea093b4c1ac6936645b65dac5ac15a8528b7b94c1754",
+	"9619720625f190b93a3fad186ab314189633c0d3a01e6f9bc8c4a8f82f383dbf",
+	"7d620d90fe69fa469a6538388970a1aa09bb48a2d59b347b97e8ce71f48c7f46",
+	"294383568596fb37c75bbacd979c5ff6f20a556bf8879cc72924855df9b8240e",
+	"16b18ab314359c2b833c1c6986d48c55a9fc97cde9a3c1f10a3177140f73f738",
+	"8cbbdd14bc33f04cf45813e4a153a273d36adad5ce71f499eeb87fb8ac63b729",
+	"69c9a498db174ecaefcc5a3ac9fdedf0f813a5bec727f1e775babdec7718816e",
+	"b462c3be40448f1d4f80626254e535b08bc9cdcff599a768578d4b2881a8e3f0",
+	"553e9d9c5f360ac0b74a7d44e5a391dad4ced03e0c24183b7e8ecabdf1715a64",
+	"7a7c55a56fa9ae51e655e01975d8a6ff4ae9e4b486fcbe4eac044588f245ebea",
+	"2afdf3c82abc4867f5de111286c2b3be7d6e48657ba923cfbf101a6dfcf9db9a",
+	"41037d2edcdce0c49b7fb4a6aa0999ca66976c7483afe631d4eda283144f6dfc",
+	"c4466f8497ca2eeb4583a0b08e9d9ac74395709fda109d24f2e4462196779c5d",
+	"75f609338aa67d969a2ae2a2362b2da9d77c695dfd1df7224a6901db932c3364",
+	"68606ceb989d5488fc7cf649f3d7c272ef055da1a93faecd55fe06f6967098ca",
+	"44346bdeb7e052f6255048f0d9b42c425bab9c3dd24168212c3ecf1ebf34e6ae",
+	"8e9cf6e1f366471f2ac7d2ee9b5e6266fda71f8f2e4109f2237ed5f8813fc718",
+	"84bbeb8406d250951f8c1b3e86a7c010082921833dfd9555a2f909b1086eb4b8",
+	"ee666f3eef0f7e2a9c222958c97eaf35f51ced393d714485ab09a069340fdf88",
+	"c153d34a65c47b4a62c5cacf24010975d0356b2f32c8f5da530d338816ad5de6",
+	"9fc5450109e1b779f6c7ae79d56c27635c8dd426c5a9d54e2578db989b8c3b4e",
+	"d12bf3732ef4af5c22fa90356af8fc50fcb40f8f2ea5c8594737a3b3d5abdbd7",
+	"11030b9289bba5af65260672ab6fee88b87420acef4a1789a2073b7ec2f2a09e",
+	"69cb192b8444005c8c0ceb12c846860768188cda0aec27a9c8a55cdee2123632",
+	"db444c15597b5f1a03d1f9edd16e4a9f43a667cc275175dfa2b704e3bb1a9b83",
+	"3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd",
+}
+
+var hashes128 = []string{
+	"9536f9b267655743dee97b8a670f9f53",
+	"13bacfb85b48a1223c595f8c1e7e82cb",
+	"d47a9b1645e2feae501cd5fe44ce6333",
+	"1e2a79436a7796a3e9826bfedf07659f",
+	"7640360ed3c4f3054dba79a21dda66b7",
+	"d1207ac2bf5ac84fc9ef016da5a46a86",
+	"3123987871e59305ece3125abfc0099a",
+	"cf9e072ad522f2cda2d825218086731c",
+	"95d22870392efe2846b12b6e8e84efbb",
+	"7d63c30e2d51333f245601b038c0b93b",
+	"ed608b98e13976bdf4bedc63fa35e443",
+	"ed704b5cd1abf8e0dd67a6ac667a3fa5",
+	"77dc70109827dc74c70fd26cba379ae5",
+	"d2bf34508b07825ee934f33958f4560e",
+	"a340baa7b8a93a6e658adef42e78eeb7",
+	"b85c5ceaecbe9a251eac76f6932ba395",
+	"246519722001f6e8e97a2183f5985e53",
+	"5bce5aa0b7c6cac2ecf6406183cd779a",
+	"13408f1647c02f6efd0047ad8344f695",
+	"a63970f196760aa36cb965ab62f0e0fa",
+	"bc26f48421dd99fd45e15e736d3e7dac",
+	"4c6f70f9e3237cde918afb52d26f1823",
+	"45ed610cfbc37db80c4bf0eef14ae8d6",
+	"87c4c150705ea5078209ec008200539c",
+	"54de21f5e0e6f2afe04daeb822b6931e",
+	"9732a04e505064e19de3d542e7e71631",
+	"d2bd27e95531d6957eef511c4ba64ad4",
+	"7a36c9f70dcc7c3063b547101a5f6c35",
+	"322007d1a44c4257bc7903b183305529",
+	"dbcc9a09f412290ca2e0d53dfd142ddb",
+	"df12ed43b8e53a56db20e0f83764002c",
+	"d114cc11e7d5b33a360c45f18d4c7c6e",
+	"c43b5e836af88620a8a71b1652cb8640",
+	"9491c653e8867ed73c1b4ac6b5a9bb4d",
+	"06d0e988df94ada6c6f9f36f588ab7c5",
+	"561efad2480e93262c8eeaa3677615c4",
+	"ba8ffc702e5adc93503045eca8702312",
+	"5782be6ccdc78c8425285e85de8ccdc6",
+	"aa1c4393e4c07b53ea6e2b5b1e970771",
+	"42a229dc50e52271c51e8666023ebc1e",
+	"53706110e919f84de7f8d6c7f0e7b831",
+	"fc5ac8ee39cc1dd1424391323e2901bd",
+	"bed27b62ff66cac2fbb68193c727106a",
+	"cd5e689b96d0b9ea7e08dac36f7b211e",
+	"0b4c7f604eba058d18e322c6e1baf173",
+	"eb838227fdfad09a27f0f8413120675d",
+	"3149cf9d19a7fd529e6154a8b4c3b3ad",
+	"ca1e20126df930fd5fb7afe4422191e5",
+	"b23398f910599f3c09b6549fa81bcb46",
+	"27fb17c11b34fa5d8b5afe5ee3321ead",
+	"0f665f5f04cf2d46b7fead1a1f328158",
+	"8f068be73b3681f99f3b282e3c02bba5",
+	"ba189bbd13808dcf4e002a4dd21660d5",
+	"2732dcd1b16668ae6ab6a61595d0d62a",
+	"d410ccdd059f0e02b472ec9ec54bdd3c",
+	"b2eaa07b055b3a03a399971327f7e8c2",
+	"2e8a225655e9f99b69c60dc8b4d8e566",
+	"4eb55416c853f2152e67f8a224133cec",
+	"49552403790d8de0505a8e317a443687",
+	"7f2747cd41f56942752e868212c7d5ac",
+	"02a28f10e193b430df7112d2d98cf759",
+	"d4213404a9f1cf759017747cf5958270",
+	"faa34884344f9c65e944882db8476d34",
+	"ece382a8bd5018f1de5da44b72cea75b",
+	"f1efa90d2547036841ecd3627fafbc36",
+	"811ff8686d23a435ecbd0bdafcd27b1b",
+	"b21beea9c7385f657a76558530438721",
+	"9cb969da4f1b4fc5b13bf78fe366f0c4",
+	"8850d16d7b614d3268ccfa009d33c7fc",
+	"aa98a2b6176ea86415b9aff3268c6f6d",
+	"ec3e1efa5ed195eff667e16b1af1e39e",
+	"e40787dca57411d2630db2de699beb08",
+	"554835890735babd06318de23d31e78a",
+	"493957feecddc302ee2bb2086b6ebfd3",
+	"f6069709ad5b0139163717e9ce1114ab",
+	"ba5ed386098da284484b211555505a01",
+	"9244c8dfad8cbb68c118fa51465b3ae4",
+	"51e309a5008eb1f5185e5cc007cfb36f",
+	"6ce9ff712121b4f6087955f4911eafd4",
+	"59b51d8dcda031218ccdd7c760828155",
+	"0012878767a3d4f1c8194458cf1f8832",
+	"82900708afd5b6582dc16f008c655edd",
+	"21302c7e39b5a4cdf1d6f86b4f00c9b4",
+	"e894c7431591eab8d1ce0fe2aa1f01df",
+	"b67e1c40ee9d988226d605621854d955",
+	"6237bdafa34137cbbec6be43ea9bd22c",
+	"4172a8e19b0dcb09b978bb9eff7af52b",
+	"5714abb55bd4448a5a6ad09fbd872fdf",
+	"7ce1700bef423e1f958a94a77a94d44a",
+	"3742ec50cded528527775833453e0b26",
+	"5d41b135724c7c9c689495324b162f18",
+	"85c523333c6442c202e9e6e0f1185f93",
+	"5c71f5222d40ff5d90e7570e71ab2d30",
+	"6e18912e83d012efb4c66250ced6f0d9",
+	"4add4448c2e35e0b138a0bac7b4b1775",
+	"c0376c6bc5e7b8b9d2108ec25d2aab53",
+	"f72261d5ed156765c977751c8a13fcc1",
+	"cff4156c48614b6ceed3dd6b9058f17e",
+	"36bfb513f76c15f514bcb593419835aa",
+	"166bf48c6bffaf8291e6fdf63854bef4",
+	"0b67d33f8b859c3157fbabd9e6e47ed0",
+	"e4da659ca76c88e73a9f9f10f3d51789",
+	"33c1ae2a86b3f51c0642e6ed5b5aa1f1",
+	"27469b56aca2334449c1cf4970dcd969",
+	"b7117b2e363378aa0901b0d6a9f6ddc0",
+	"a9578233b09e5cd5231943fdb12cd90d",
+	"486d7d75253598b716a068243c1c3e89",
+	"66f6b02d682b78ffdc85e9ec86852489",
+	"38a07b9a4b228fbcc305476e4d2e05d2",
+	"aedb61c7970e7d05bf9002dae3c6858c",
+	"c03ef441f7dd30fdb61ad2d4d8e4c7da",
+	"7f45cc1eea9a00cb6aeb2dd748361190",
+	"a59538b358459132e55160899e47bd65",
+	"137010fef72364411820c3fbed15c8df",
+	"d8362b93fc504500dbd33ac74e1b4d70",
+	"a7e49f12c8f47e3b29cf8c0889b0a9c8",
+	"072e94ffbfc684bd8ab2a1b9dade2fd5",
+	"5ab438584bd2229e452052e002631a5f",
+	"f233d14221097baef57d3ec205c9e086",
+	"3a95db000c4a8ff98dc5c89631a7f162",
+	"0544f18c2994ab4ddf1728f66041ff16",
+	"0bc02116c60a3cc331928d6c9d3ba37e",
+	"b189dca6cb5b813c74200834fba97f29",
+	"ac8aaab075b4a5bc24419da239212650",
+	"1e9f19323dc71c29ae99c479dc7e8df9",
+	"12d944c3fa7caa1b3d62adfc492274dd",
+	"b4c68f1fffe8f0030e9b18aad8c9dc96",
+	"25887fab1422700d7fa3edc0b20206e2",
+	"8c09f698d03eaf88abf69f8147865ef6",
+	"5c363ae42a5bec26fbc5e996428d9bd7",
+	"7fdfc2e854fbb3928150d5e3abcf56d6",
+	"f0c944023f714df115f9e4f25bcdb89b",
+	"6d19534b4c332741c8ddd79a9644de2d",
+	"32595eb23764fbfc2ee7822649f74a12",
+	"5a51391aab33c8d575019b6e76ae052a",
+	"98b861ce2c620f10f913af5d704a5afd",
+	"b7fe2fc8b77fb1ce434f8465c7ddf793",
+	"0e8406e0cf8e9cc840668ece2a0fc64e",
+	"b89922db99c58f6a128ccffe19b6ce60",
+	"e1be9af665f0932b77d7f5631a511db7",
+	"74b96f20f58de8dc9ff5e31f91828523",
+	"36a4cfef5a2a7d8548db6710e50b3009",
+	"007e95e8d3b91948a1dedb91f75de76b",
+	"a87a702ce08f5745edf765bfcd5fbe0d",
+	"847e69a388a749a9c507354d0dddfe09",
+	"07176eefbc107a78f058f3d424ca6a54",
+	"ad7e80682333b68296f6cb2b4a8e446d",
+	"53c4aba43896ae422e5de5b9edbd46bf",
+	"33bd6c20ca2a7ab916d6e98003c6c5f8",
+	"060d088ea94aa093f9981a79df1dfcc8",
+	"5617b214b9df08d4f11e58f5e76d9a56",
+	"ca3a60ee85bd971e1daf9f7db059d909",
+	"cd2b7754505d8c884eddf736f1ec613e",
+	"f496163b252f1439e7e113ba2ecabd8e",
+	"5719c7dcf9d9f756d6213354acb7d5cf",
+	"6f7dd40b245c54411e7a9be83ae5701c",
+	"c8994dd9fdeb077a45ea04a30358b637",
+	"4b1184f1e35458c1c747817d527a252f",
+	"fc7df674afeac7a3fd994183f4c67a74",
+	"4f68e05ce4dcc533acf9c7c01d95711e",
+	"d4ebc59e918400720035dfc88e0c486a",
+	"d3105dd6fa123e543b0b3a6e0eeaea9e",
+	"874196128ed443f5bdb2800ca048fcad",
+	"01645f134978dc8f9cf0abc93b53780e",
+	"5b8b64caa257873a0ffd47c981ef6c3f",
+	"4ee208fc50ba0a6e65c5b58cec44c923",
+	"53f409a52427b3b7ffabb057ca088428",
+	"c1d6cd616f5341a93d921e356e5887a9",
+	"e85c20fea67fa7320dc23379181183c8",
+	"7912b6409489df001b7372bc94aebde7",
+	"e559f761ec866a87f1f331767fafc60f",
+	"20a6f5a36bc37043d977ed7708465ef8",
+	"6a72f526965ab120826640dd784c6cc4",
+	"bf486d92ad68e87c613689dd370d001b",
+	"d339fd0eb35edf3abd6419c8d857acaf",
+	"9521cd7f32306d969ddabc4e6a617f52",
+	"a1cd9f3e81520842f3cf6cc301cb0021",
+	"18e879b6f154492d593edd3f4554e237",
+	"66e2329c1f5137589e051592587e521e",
+	"e899566dd6c3e82cbc83958e69feb590",
+	"8a4b41d7c47e4e80659d77b4e4bfc9ae",
+	"f1944f6fcfc17803405a1101998c57dd",
+	"f6bcec07567b4f72851b307139656b18",
+	"22e7bb256918fe9924dce9093e2d8a27",
+	"dd25b925815fe7b50b7079f5f65a3970",
+	"0457f10f299acf0c230dd4007612e58f",
+	"ecb420c19efd93814fae2964d69b54af",
+	"14eb47b06dff685d88751c6e32789db4",
+	"e8f072dbb50d1ab6654aa162604a892d",
+	"69cff9c62092332f03a166c7b0034469",
+	"d3619f98970b798ca32c6c14cd25af91",
+	"2246d423774ee9d51a551e89c0539d9e",
+	"75e5d1a1e374a04a699247dad827b6cf",
+	"6d087dd1d4cd15bf47db07c7a96b1db8",
+	"967e4c055ac51b4b2a3e506cebd5826f",
+	"7417aa79247e473401bfa92a25b62e2a",
+	"24f3f4956da34b5c533d9a551ccd7b16",
+	"0c40382de693a5304e2331eb951cc962",
+	"9436f949d51b347db5c8e6258dafaaac",
+	"d2084297fe84c4ba6e04e4fb73d734fe",
+	"42a6f8ff590af21b512e9e088257aa34",
+	"c484ad06b1cdb3a54f3f6464a7a2a6fd",
+	"1b8ac860f5ceb4365400a201ed2917aa",
+	"c43eadabbe7b7473f3f837fc52650f54",
+	"0e5d3205406126b1f838875deb150d6a",
+	"6bf4946f8ec8a9c417f50cd1e67565be",
+	"42f09a2522314799c95b3fc121a0e3e8",
+	"06b8f1487f691a3f7c3f74e133d55870",
+	"1a70a65fb4f314dcf6a31451a9d2704f",
+	"7d4acdd0823279fd28a1e48b49a04669",
+	"09545cc8822a5dfc93bbab708fd69174",
+	"efc063db625013a83c9a426d39a9bddb",
+	"213bbf89b3f5be0ffdb14854bbcb2588",
+	"b69624d89fe2774df9a6f43695d755d4",
+	"c0f9ff9ded82bd73c512e365a894774d",
+	"d1b68507ed89c17ead6f69012982db71",
+	"14cf16db04648978e35c44850855d1b0",
+	"9f254d4eccab74cd91d694df863650a8",
+	"8f8946e2967baa4a814d36ff01d20813",
+	"6b9dc4d24ecba166cb2915d7a6cba43b",
+	"eb35a80418a0042b850e294db7898d4d",
+	"f55f925d280c637d54055c9df088ef5f",
+	"f48427a04f67e33f3ba0a17f7c9704a7",
+	"4a9f5bfcc0321aea2eced896cee65894",
+	"8723a67d1a1df90f1cef96e6fe81e702",
+	"c166c343ee25998f80bad4067960d3fd",
+	"dab67288d16702e676a040fd42344d73",
+	"c8e9e0d80841eb2c116dd14c180e006c",
+	"92294f546bacf0dea9042c93ecba8b34",
+	"013705b1502b37369ad22fe8237d444e",
+	"9b97f8837d5f2ebab0768fc9a6446b93",
+	"7e7e5236b05ec35f89edf8bf655498e7",
+	"7be8f2362c174c776fb9432fe93bf259",
+	"2422e80420276d2df5702c6470879b01",
+	"df645795db778bcce23bbe819a76ba48",
+	"3f97a4ac87dfc58761cda1782d749074",
+	"50e3f45df21ebfa1b706b9c0a1c245a8",
+	"7879541c7ff612c7ddf17cb8f7260183",
+	"67f6542b903b7ba1945eba1a85ee6b1c",
+	"b34b73d36ab6234b8d3f5494d251138e",
+	"0aea139641fdba59ab1103479a96e05f",
+	"02776815a87b8ba878453666d42afe3c",
+	"5929ab0a90459ebac5a16e2fb37c847e",
+	"c244def5b20ce0468f2b5012d04ac7fd",
+	"12116add6fefce36ed8a0aeccce9b6d3",
+	"3cd743841e9d8b878f34d91b793b4fad",
+	"45e87510cf5705262185f46905fae35f",
+	"276047016b0bfb501b2d4fc748165793",
+	"ddd245df5a799417d350bd7f4e0b0b7e",
+	"d34d917a54a2983f3fdbc4b14caae382",
+	"7730fbc09d0c1fb1939a8fc436f6b995",
+	"eb4899ef257a1711cc9270a19702e5b5",
+	"8a30932014bce35bba620895d374df7a",
+	"1924aabf9c50aa00bee5e1f95b5d9e12",
+	"1758d6f8b982aec9fbe50f20e3082b46",
+	"cd075928ab7e6883e697fe7fd3ac43ee",
+}
+
+// hashes2X is taken from
+// https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2-kat.json
+var hashes2X = []string{
+	"0e",
+	"5196",
+	"ad6bad",
+	"d8e4b32f",
+	"8eb89056f3",
+	"410497c2ed72",
+	"f0de771b375c90",
+	"8662db8685033611",
+	"9ef9f1eed88a3f52ca",
+	"08225082df0d2b0a815e",
+	"0f6e84a17439f1bc97c299",
+	"895ec39c78d3556cefdbfabc",
+	"2b396b3fa90ab556079a79b44d",
+	"abae26501c4c1d6123c0f2289111",
+	"bca098df9099b3f785a37ba40fce5f",
+	"19b827f054b67a120f11efb0d690be70",
+	"b88d32a338fd60b58570fda228a121113b",
+	"3f30143af1cad33f9b794576e078cc79062e",
+	"ffddb58d9aa8d38086fcdae07e6653e8f31dfc",
+	"abb99c2e74a74556919040ca0cd857c95ec985e9",
+	"71f13f89af55ba936f8a7188ee93d2e8fb0cf2a720",
+	"99734fdf0eef4838a7515426f4c59b800854e2fcdc1c",
+	"579b1652aa1f5779d2b0e61868af856855020bdd44d7a7",
+	"1383d4ab4a6d8672b4075d421a159f69380ff47e4bb518d5",
+	"d3fa1412712dbbab71d4c6265dc1585c8dcc73380cf807f76a",
+	"1d57868a71e7245667780455d9aaa9e0683baf08fbaf946091c2",
+	"ef80418fe7049c6251ed7960a6b0e9def0da2749781994b24593a0",
+	"ef91cb81e4bfb50231e89475e251e2ef2fde59357551cd227588b63f",
+	"d7f398a5d21c3139cff0562a84f154b6953c7bc18a5f4b60491c196b6d",
+	"0a2abc6d38f30aef253579a4088c5b9aec64391f37d576eb06a300c193a5",
+	"02dd758fa23113a14fd94830e50e0f6b86faec4e551e808b0ca8d00fef2a15",
+	"a4fe2bd0f96a215fa7164ae1a405f4030a586c12b0c29806a099d7d7fdd8dd72",
+	"7dce710a20f42ab687ec6ea83b53faaa418229ce0d5a2ff2a5e66defb0b65c03c9",
+	"0320c40b5eea641d0bc25420b7545ac1d796b61563728a4dc451207f1addeedcf860",
+	"460539415f2baeb626fad748dee0eb3e9f27221661160e13edf39d1b5d476ee0672400",
+	"02de8ffa5b9c748164f99ed9d678b02e53f4ae88fb26c6d94a8cefc328725a692eae78c2",
+	"348a61a0136436136910262ad67ef20644b32c15456d5fad6b1679386d0bea87cc1a2e2b5e",
+	"24c32966c803434d48d2283482ee8f404f598cf7a17961748125d2ed1da987039b1ce00f2ba7",
+	"bd07cb16121d3b47adf03b96c41c947beadc01e40548e0d0773e61780d48d33a0e2a675ca681a6",
+	"a35844e34c20b4b9371b6c52fac412afe5d80a4c1e40aa3a0e5a729dc3d41c2c3719d096f616f0ba",
+	"6df1efbb4567747fe98d218935612f8835852dde2ce3dec767792d7f1d876cdae0056fef085245449d",
+	"48d6094af78bd38d8f4b39c54279b80ef617bc6ad21def0b2c62113b656c5d6a55aea2e3fde94a254b92",
+	"cd6e684759d2f19083164712c2aca0038442efb5b646594396b1fccdbd21203290f44cfdecca0373b3801b",
+	"155dfbf26103c8354362663677fa27d0e1ce3487a821a2a7171014c1bd5dd071f4974df272b1374765b8f2e1",
+	"15b11067f311efa4ee813dbca48d690dc92780656bc4d4c56510523190a240180867c829a8b8b9844175a8aa23",
+	"9bc27953a17fb84d5eabe95b4ea6bc03ea450274abccfb6f3938ded8560fb59662459a11a86b0e0f32fbea6bb1f8",
+	"03b78fb0b34fb8662accdf350a6be75ace9789653ee4375d351e871f6a98ac5e782ca4b4a717665d25e49a5ae25d81",
+	"687e9a6fda6e2ce0e40e4d30fef38c31e3513d2892bbe85c991fc3715947e42bc49bcd079a40ed061c2c3665efe555ab",
+	"f3886027d2049a8909e26545bd202d6a6fa2a6f815d31c7d520f705a81fa606dd695369c37aee4fa77dc645e9b05813ceb",
+	"e4a412ccd20b97797d91ccc286904fcd17c5afe8bed0618f1af333c052c473cd327637d951c32e4af047106036a3bc8c1c45",
+	"92f4b8c240a28b6238bc2eabadaf2ff3c4bfe0e6c61268ace6aebdeb0691450caea4287db8b329bde96af8cdb8a0fe2f57ef2d",
+	"e506834b3445e1a9a9b7bae844e91e0834512a06c0dc75fa4604e3b903c4e23616f2e0c78b5cc496660b4a13064bb1138edef4ff",
+	"27031955a40d8dbd1591f26e3c26e367a3c68f8204a396c6a4ba34b89672896d11276966a42bd516716f35ed63e442e116dbcf35da",
+	"646b1635c68d2328dddd5ac26eb9877c24c28390a45753a65044c3136ae2fe4fb40d09bf555271646d3dceb1ab1b7c8d8e421f553f94",
+	"f6171f8d833743bdee7cc8f8b29c38614e1d2d8d6a5fff68bec2c0f4dd463d7941ff5c368e2683d8f1dc97119bde2b73ca412718bc8cb1",
+	"45db1c478b040aa2e23fb4427017079810775c62abe737e82ec0ef8dcd0fc51f521f29fe6412fff7eac9beb7bcf75f483f3f8b971e42454b",
+	"500dab14687db3ca3dde9304af5f54194b37bdf475628af46b07bfbf6bc2b64ecef284b17f9d1d9be41794699bc0e76c2878b3a55730f7142d",
+	"31bba2efc7b3f415c3f031d4c06bb590ae40085ad157370af30238e03e25a359c9e133212ed34b7a006f839173b577e7015a87fdff2270fafddb",
+	"0600b3fb4b5e1ed0c8b2698ac1d9905e67e027390764821f963ad8d2b33cbc378b9c25c3ee422992d22b760222ed5697be0576d73938ae9d634ed7",
+	"4c0ca4f177d132594a4c613bad68da24c564efa3b4da0d0a903f26534a2e09f8d799d10e78f48ccdb0203954a36c5cf1bf24c076632c2b022b041200",
+	"97aacf2e1b013677b2e14084f097cb1e64d7b3fa36f097e189d86dc4a263bcc46817cd1ee6ff0c7ccd9acef63201cdc0e36254e19204a7388643bb571f",
+	"71fd6846ce7adb0843d6063546a16b79b54ad6c0f018a479a45817624fa221f63525084860559d1a0679c8d89a80701c62743ec2da8419d503f8f0cd7946",
+	"f73dfb046def3362d6de36077dae2cee2587fe95fe0800548bb7d99737897096ba59052e0dadcc1fb0ccb5535391875328637a0376a43a4d89366758dfe3e2",
+	"ec470d0aa932c78c5bcf86203ec0014314114765fa679c3daef214f883a17e1b4ca12f44433772a6e4ef685c904b2fc35586c6bd88f325b965968b06d808d73f",
+	"cf601753ffa09fe48a8a84c37769991e96290e200bbaf1910c57760f989bd0c72e6128e294528ee861ad7eee70d589de3cf4a0c35f7197e1925a64d0133628d87d",
+	"f15413f7d6fc54bb55829f698da92ee42fcf58dde1aa1bd07d438ecdc32ad6bf2bcdbecc99f18ed43e81b33065af5a4ca29960ae50553e610c0bbf4153d580e73dbb",
+	"84b1738adb9757fb9402ef7113581291136184d7ae35fe0b6a738da6acb0889d4d5bac7a957024e3709fa80c77d3859871ed1aa25cf488e438a2d24cfadce6008761dd",
+	"e02814bb81f250c1835a05108396b74c7878e737654bb83155e241774d04e639bbc571b413cd9349092f926c8a149a53cd33e9b63f370b6d460e504199d2e7d849db6cbe",
+	"aeee4a789956ec0913592c30ce4f9c544894da77ba447c84df3be2c869100e4df8f7e316445d844b31c3209abcc912f647735fd4a7136c2f35c6fda5b2e6708f5ca951b2b0",
+	"8cfd11ca385de3c843de84c830d59278fe79b70fb5ddbfbfc1ddefeb22c329ef2f607d1d1abbd1cd0d0cc7c5d3ed922add76aadca0d2f57b66cb16c582b6f18f60aee2f7509b",
+	"852e5ce2047d8d8b42b4c7e4987b95d23e8026a202d4567951bbbd23111e389fe33a736318546a914d2bddedfbf53846036ad9e35f29318b1f96e33eba08f071d6dc665149feb6",
+	"f225c23164979d0d13874a90ee291627e4f61a672a5578506fd3d65a12cb48a182f78350dc24c637b2f3950dc4882a5c1d5d5bad551c6f3e0093aa87e962bea51566af3791d52d65",
+	"5f33864d882455f8ef046aed64e2d1691e5c1555e333b0852750592e6f00d3b5ec941d0c00e99629612795d5870cf93c984b45e4464ba072a34903b400a42824ac13da28c7c1cb1959",
+	"7baaee7c3eb68c18c5ae1d45ba381803de34e36a52e2d7ccc9d48a297273c4d8644b473195bc23005f7a4f5ca790b1fa11f6a96e585e635513f11745dd97a69c1222204ab28d3c7735df",
+	"d0a2a3fc450ef9af7ae982041feb2842901026467d87839c33b4a9e081ea63d5be60ae99ca6e42393ded45255b8f42886f87ba0310572d9f0d8b5a07ff4b6bae1f30559a844983cc568560",
+	"3aa4164462b3e7044c35b08b047b924790f6d5c520b1df4305b5d41f4717e81f0cd4bccb9a5a6594773832b8707443adde4047caaed2293f92234df257df54ed275a9658fab483d0576d33a9",
+	"c8b4239fd7f1b893d978268f77f6505b5775d89090374322d40083b0f4c437423f670ca213f7fe05c61069725da2561646eefaea597ac48e293fbad44c2872046857e56d04a426a84008cefd71",
+	"f94839a7024c0a16971271b6727c081770110c957b1f2e03be03d2200b565cf8240f2873b0426042aaea996a1784fadb2b27f23bc1a521b4f7320dfbed86cd38d75141365ba9b443defc0a3b4078",
+	"8af934fdc8b3376ca09bdd89f9057ed38b656bff96a8f8a3038d456a265689ca32036670cb01469cc6e958cc4a46f1e80d700ae56659828a65c0456b8e55f28f255bc86ce48e44377bf1f9970b617d",
+	"ada572989e42f0e38c1f7c22b46bb52a84df8f7b3b773c9f17a5823e59a9725248d703efb4cb011abc9474e8e711666ed3cfa60db48480a8160615dfabad761bc0eb843d2e46299c59b61a15b4422fdf",
+	"b11f1ea52a7e4bd2a5cf1e234b7c9eb909fb45860080f0a6bdb5517a37b5b7cd90f3a9e2297f995e96c293189b807a7bf6e7633bebbc36674544db5f18dd33020aeaf50ee832efe4d3d053873fd31ce3b9",
+	"e54b006cd96c43d19787c1ab1e08ea0f8922bdb7142e748212e7912a1f2c0a4fad1b9f5209c30960b8b83ef4960e929b155a8a48c8fb7ce4326915950cede6b98a96b6f1ecb12715b713985dacd1c1180413",
+	"ee2c2f31a414ccd8f6a790f55e09155fd50aac2a878f9014f6c6035cae9186f90cdef0b7adf3e207c3d24ddfba8cd321b2e9228b02a1182b6973da6698071fce8cc0a23a7bf0d5aefd21ab1b8dc7818549bba3",
+	"6d6810793bad6c7efe8fd56cac04a0fb8717a44c09cbfaebce196a80ac318c79ca5c2db54fee8191ee2d305b690a92bd9e2c947a3c29342a93ac05796484638787a184e4525e82aeb9afa2f9480caebb91014c51",
+	"91e4694366cff84854872667fd168d2d42eca9070cdc92fca9936e8361e7266931f418450d098a42686241d08024dd72f0024d22ba644bd414245e78608942321ff61860ba1245f83c88592dc7995c49c0c53aa8a9",
+	"608aa620a5cf145f4477694407ccd8faa3182465b29ae98d96a42f7409434c21e4671bcae079f6871a09d8f2965e4926a9b08277d32f9dd6a474e3a9fb232f27fc4235df9c02abf67f7e540ca9ddc270ee91b23a5b57",
+	"c14f75e92f75f4356ab01c8792af13383e7fef2ffb3064de55e8da0a50511fea364ccd8140134872adccad197228319260a7b77b67a39677a0dcdcadfb750333ac8e032121e278bdcdbed5e452dae0416011186d9ebf29",
+	"03fcb9f6e1f058091b11351e775184ff2cd1f31ee846c6ea8efd49dd344f4af473f92eb44eba8a019776f77bb24e294aa9f962b39feecf7c59d46f1a606f89b1e81c2715ac9aa252e9ce941d091ffb99bb52404961794cf8",
+	"11e189b1d90fcfe8111c79c5351d826f5ec15a602af3b71d50bc7ed813f36c9a682520984ae911669d3c3036223a53176794c7e17929efab2b1c5b500f24f8c83d3db5d1029c5714c6fd34eb800a913985c218071677b9885c",
+	"69f8f5db3ab0321a708ab2f4234645dade6bfda495851dbe7257f2b72e3e8378b9fa8120bc836b737a675271e519b4712d2b56b359e0f2234ba7552dd4828b939e0542e729878ac1f81b6ce14cb573e76af3a6aa227f95b2350e",
+	"be734d78fae92cacb009cc400e023086bc3a3a10e8ca7cb4d553ea85314f51383660b8508e8477af60baf7e07c04cc9e094690ae12c73e5f089763201b4b48d664b94b4f5820bd1540f4a84100fdf8fce7f6466aa5d5c34fcbab45",
+	"d61b77032403f9b6ea5ad2b760eb0157545e37f1712ec44d7926ccf130e8fc0fe8e9b15570a6214c3899a074811486182b250dc97ebdd3b61403614d935cd0a61c0899f31b0e49b81c8a9a4fe8409822c470aacfde229d965dd62f51",
+	"c31bd548e36d5fae95ed8fa6e807642711c897f0fcc3b0d00bd317ed2bca73412064618c6a84a61c71bce3e963333b0266a5656571dcc4ba8a8c9d84af4bdb445c34a7aef445b15d77698e0b13c436c928cc7fa7acd5f68867e8132993",
+	"9903b8adab803d085b634bfae2e109dd247a7d6249f203403216d9f7410c36142df8fa56fb4d6f78136eef5817bad5ea3608439bb19336628c37d42db16ab2df8018b773baedafb77278a50926370b48bd81710203c7abc7b4043f9a1751",
+	"4dadaf0d6a96022c8ce40d48f460526d9956da33260e1770315ead420da75b122c762762aa3ddc1aef9070ff2298b2304cf90443318b17183b60778f3859b141053e5827decfff27ff106a48cfdb0371d0ef614fc7400e860b676df3176d1a",
+	"314dda800f2f494ca9c9678f178940d2284cb29c51cb01ca2019a9bede0cdc50f8ecf2a77e238b884867e78e691461a66100b38f374c4ccac80309641533a3217eca7e6b9a9af01c026201f0afaec5a61629a59eb530c3cb81934b0cb5b45eae",
+	"4658b7500951f75c84e4509d74047ca621009835c0152f03c9f96ca73beb29608c44390ba4473323e621284be872bdb72175628780113e470036265d11dfcb284ac04604e667f1e4c1d357a411d3100d4d9f84a14a6fabd1e3f4de0ac81af50179",
+	"491f877592837e7912f16b73ee1fb06f4633d854a5723e156978f48ec48fbd8b5e863c24d838ff95fa865155d07e5513df42c8bb7706f8e3806b705866475c0ac04bbe5aa4b91b7dc373e82153483b1b03304a1a791b058926c1becd069509cbf46e",
+	"231034720c719ab31f7c146a702a971f5943b70086b80a2a3eb928fa9380b7a1ad8773bfd0739142d2ad6e19819765ca54f92db5f16c1df5fa4b445c266215a92527bd4ef50ed277b9a21aee3fb7a8128c14ce084f53eac878a7a660b7c011eb1a33c5",
+	"3366860c77804fe0b4f368b02bb5b0d150821d957e3ba37842da9fc8d336e9d702c8446ecafbd19d79b868702f32405853bc17695873a7306e0ce4573cd9ac0b7fc7dd35534d7635198d152a1802f7d8d6a4bb07600fcdaacfaa1c3f40a09bc02e974c99",
+	"ccbbbe621f910a95835f5f8d74b21e13f8a4b03f72f91f37b5c7e995aa3cd5539508d5e234e77a4668a42c239b2d13ef0e55ecf85142055e3f8a7e46320e21324a6b88e6c823ac04b485125c2aa59b61476481208f92ea4dd330cb18777c1cf0df7cd07893",
+	"87faf0e49e7e5ab66ee3147921f8817867fe637d4ab694c33ee8009c759e7d707f44c69c1b9754e2b4f8f47b25f51cd01de7273f548f4952e8efc4d9044c6ea72d1d5857e0ffeb3f44b0c88cb67683401cfb2f1d17f0ca5696641bef28d7579f68d9d066d968",
+	"38c876a007ec727c92e2503990c4d9407cea2271026aee88cd7b16c4396f00cc4b760576adf2d683713a3f6063cc13ecd7e4f3b6148ad914ca89f34d1375aa4c8e2033f1315153189507bfd116b07fc4bc14f751bbbb0e752f621153ae8df4d68491a22430b309",
+	"87d636a33dbd9ad81ecd6f3569e418bf8a972f97c5644787b99c361195231a72455a121dd7b3254d6ff80101a0a1e2b1eb1ca4866bd23063fe007310c88c4a2ab3b49f14755cd0ee0e5ffa2fd0d2c0ea41d89e67a27a8f6c94b134ba8d361491b3c20bacac3d226b",
+	"b021af793badbb857f9a353e320450c44c1030fce3885e6b271bcc02e6af65fdc5be4dc483ff44bd5d539ed1e7eb7efe3001252e92a87df8227ace601047e101c871d29302b3cb6c6f4639078afc81c4c0f4c2e04688612ecf3f7be1d58ea92894a5dab49b949f2089",
+	"c5c1f2fbf2c8504a686b615278fc6221858d401b7fe790b75fb6bca6885cdd128e9142bf925471ee126f9e62d984de1c30c9c677eff5fdbd5eb0fa4ef3bff6a831056cea20fd61cf44d56ffc5bda0e8472ecdc67946d63c40db4ba882bc4dfa16d8ddac600570b9b6bf3",
+	"88f8cc0daeaeaea7ab0520a311dff91b1fd9a7a3ec778c333422c9f3eb0bc183acc80dfefb17a5ac5f95c490693c45666ec69234919b83244003191bad837aa2a237daeb427e07b9e7aa6ca94b1db03d54ee8f4fe8d0802cb14a6599005eb6326eefe5008d9098d40aa851",
+	"2eb6b1a58e7fe39ff915ac84c2f21a22432c4f0d260380a3f993310af048b11647f95d23adf8a746500833ee4e467fb52ea9f1039519fa58bcb0f1d0151558147b3c92b83730aba0e20eeeea2b75f3ff3ad79f2f8a46cbbadb114a52e32f018342aeeaf827e03ad6d583bbce",
+	"3ba7dcd16a98be1df6b904457709b906cbf8d39516ef107006c0bf363db79f91aaae033466624d30858e61c2c368599963e49f22446e4473aa0df06e9c734e183a941510d540536377072334910e9cef56bc66c12df310ecd4b9dc14207439c1da0ac08bdd9be9f2c840df207e",
+	"a34a7926324ea96867dac6f0dba51d753268e497b1c4f272918c7eb0e34120be65b7b5ba044d583141ec3ea16fcedae6197116b16562fb0706a89dc8efd3ba173ccd0fd7d84d480e0a3dda3b580c326aa1caca623879b0fb91e7d173998889da704eda6495023b5ad4c9ad406298",
+	"5ef97d80b90d5c716322d9ba645a0e1b7a403968258a7d43d310320f60f96235f50e9f22cac0ad239636521fa0607d2f471051b505b371d88778c46fe6787d47a91a5bec4e3900fe6ed22918226fc9fbb3f70ee733c369420612b76b5f55988d757c891d7005d17ee55783fe506202",
+	"140d2c08dae0553f6a49585fd5c217796279152b2e100ebde6812d6e5f6b862b2a3a484aed4d6226197e511be2d7f05f55a916e32534ddcb81bdcf499c3f44f526eb515cc3b6fa4c4039ad251253241f541558bba7413ca29318a414179048a054104e433c674ca2d4b3a4c181878727",
+	"29fdfc1e859b001ee104d107216b5299a792d26b2418e823e0381fa390380d654e4a0a0720ba5ff59b2ff22d8c4e013284f980911dcfec7f0dca2f89867f311ced1ac8a14d669ef1114504a5b7626f67b22ecd86469800f1575543b72ab1d4c5c10ee08f06159a4a3e1ae09937f12aa173",
+	"52dfb643832a598a10786a430fc484d6370a05356ee61c80a101dbbcfac75847fba78e27e537cc4eb918eb5ab40b968d0fb23506fee2ad37e12fb7534fb55a9e50902b69ceb78d51db449cbe2d1fc0a8c0022d8a82e2182b0a059035e5f6c4f4cc90278518e178becfbea814f317f9e7c051",
+	"d32f69c6a8ee00ca83b82eaf82e312fbb00d9b2f6202412a1ffc6890b4509bbbeda4c4a90e8f7bca37e7fd82bd23307e2342d27aa10039a83da55e84ce273822740510e4ec239d73c52b0cbc245ad523af961994f19db225212bf4cc160f68a84760233952a8e09f2c963be9bb1d71ca4bb265",
+	"d1e603a46aa49ee1a9ded63918f80feca5fc22fb45f659fd837ff79be5ad7faf0bbd9c4ba91628ee293b478a7e6a7bd433fa265c20e5941b9ea7edc906055ce9799cbb06d0b33ae7ed7f4b918cc082c3d4a1ac317a4acec175a73cc3eeb7cb97d96d24133a29c19375c57f3a4105519846dd14d4",
+	"b45ac88fac2e8d8f5a4a90930cd7523730733369af9e39bf1ffb833c01108952198301f4619f04b9c399fef04c214bad3358999967c474b67a7c06457a1d61f9466489ed5c0c64c6cdc83027386d6263491d18e81ae8d68ca4e396a71207adaaa60997d0dca867065e68852e6dba9669b62dc7672b",
+	"d5f2893edd67f8a4b5245a616039ffe459d50e3d103ad4675102028f2c497ea69bf52fa62cd9e84f30ae2ea40449302932bbb0a5e426a054f166fdbe92c744314cc0a0aa58bbc3a8739f7e099961219ec208a8d01c1ae8a2a2b06534bf822aaa00ca96218e430f0389c69c7f3fd195e128c38d484ff6",
+	"37279a76e79f33f8b52f29358841db9ec2e03cc86d09a335f5a35c0a31a1db3e9c4eb7b1d1b978332f47f8c3e5409d4e443e1d15342a316f442e3bfa151f6a0d216df2443d80cbcf12c101c51f2946d81161583218584640f4f9c10de3bb3f4772bd3a0f4a365f444777456b913592719818afb26472b6",
+	"a46d252a0addf504ad2541e7d992cbed58a22ea5679980fb0df072d37540a77dd0a1448bdb7f172da7da19d6e4180a29356ecb2a8b5199b59a24e7028bb4521f3281313d2c00da9e1d284972ab6527066e9d508d68094c6aa03537226ef19c28d47f91dddebfcc796ec4221642ddf9de5b80b3b90c22d9e7",
+	"060c18d8b57b5e6572dee194c69e265c2743a48d4185a802eaa8d4dbd4c66c9ff725c93667f1fb816418f18c5f9be55e38b7718a9250bc06284bd834c7bd6dfcd11a97c14779ac539629bcd6e15b5fca3466d14fe60d8671af0fb8b080218703bc1c21563b8f640fde0304a3f4aeb9ec0482f880b5be0daa74",
+	"8f2f42bc01acca20d36054ec81272da60580a9a5414697e0bdb4e44a4ab18b8e690c8056d32f6eaaf9ee08f3448f1f23b9844cf33fb4a93cba5e8157b00b2179d18b6aa7215ae4e9dc9ad52484ad4bfb3688fc80565ddb246dd6db8f0937e01b0d2f2e2a64ad87e03c2a4ad74af5ab97976379445b96404f1d71",
+	"ccb9e524051cca0578aa1cb437116a01c400338f371f9e57525214ad5143b9c3416897eae8e584ce79347297071f67041f921cbc381c2be0b310b8004d039c7cc08cb8ff30ef83c3db413f3fb9c799e31cd930f64da1592ec980cc19830b2a448594cb12a61fc7a229e9c59fe1d66179772865894afd068f0942e5",
+	"3eb5dc42172022ab7d0bc465a3c725b2d82ee8d9844b396913ceb8a885323dbbbf9ef4ed549724cc96d451ea1d1d44a8175a75f2a7d44bb8bfc2c2dffed00db0328cfde52bf9171f4025770abbe59b3aefd8151c480bafa09f613955fd571e5d8c0d4936c670d182cf119c068d420ded12af694d63cd5aef2f4f6f71",
+	"20ea77e58e41337ad63f149ed962a8210b6efa3747fe9bea317c4b48f9641f7145b7906ed020a7ae7d2ee59435392edc32aee7eff978a661375af723fbd440dd84e4a152f2e6ef66f4ab1046b22c77ac52717de721dfe39aa8ba8cd5da27baca00cc1fffe12c52382f0ee83ad1418f4c6a122effaf7471e1e125d7e7ba",
+	"95c662b835171fa23f948c3c3ed27bab9b3c367bbfe267fe65f8037a35b50cd7fc6030bfce4000425ef646c34793f0762635ae70487a0216ef7428da622be895d1b6040423246511c2370d6876a5c5d2df8bbd48fb14f787b632ad2c1f5a927fdf36bc493c1c8606accfa52de33258669f7d2d73c9c81119591c8ea2b0ef",
+	"f708a230675d83299cc43167a771602d52fa37cbc068ef9128ef60d186e5d98efb8c98798da619d2011bf4673214f4a4c82e4b11156f6292f6e676d5b84dc1b81e7cc811b0d37310ac58da1bfcb339f6ba689d80dd876b82d131e03f450c6c9f15c3a3b3d4db43c273c94ed1d1bd6d369c4d30256ff80ea626bda56a6b94ea",
+	"f8417766ce86b275f2b7fec49da832ab9bf9cb6fdfe1b916979ae5b69176d7e0293f8d34cb55cf2b4264a8d671370cb595c419c1a3ce5b8afa642208481333522005fbe48cdc700e47b29254b79f685e1e91e7e34121784f53bd6a7d9fb6369571bba992c54316a54e309bbc2d488e9f4233d51d72a0dd8845772377f2c0feb9",
+	"3479e04efa2318afc441931a7d0134abc2f04227239fa5a6ae40f25189da1f1f313732026631969d3761aea0c478528b129808955be429136eeff003779dd0b8757e3b802bdff0f5f957e19278eabad72764aa74d469231e935f4c80040462ab56094e4a69a82346b3aeb075e73a8e30318e46fdaec0a42f17ccf5b592fb800613",
+	"03df0e061fa2ae63b42f94a1ba387661760deaab3ec8ffabcaff20eeed8d0717d8d09a0eafd9bde04e97b9501ac0c6f4255331f787d16054873f0673a3b42ce23b75a3b38c1ebcc04306d086c57a79d6095d8ce78e082a66c9efca7c2650c1046c6e0bbce0b2cba27c3824333e50e046e2a7703d3328ab3b82c9d6a51bc99b9516ff",
+	"76b488b801932932beefffdd8c19cf5b4632306e69e37e6a837e9a20c8e073bcadd5640549faa4972ebd7ee55cb2425b74cb041a52dd401b1a531beb6dfb23c4cfe74bc84f034156c8f55050ca93236eb73c4e2595d9fbf93dc49e1ec9a31705359732dda73f737ec4274e5c82626dc4ec929e5e2c7a2f5f5fb666181922bd8be575e3",
+	"ff17f6ef13abc0426b03d309dc6e8eeb822300f7b87eff4f9c44140a424098fd2aef860e5646066d22f5e8ed1e82a459c9b9ad7b9d5978c29718e17bff4eeefd1a80ba48108b551e62cd8be919e29edea8fbd5a96dfc97d01058d226105cfcdec0fba5d70769039c77be10bd182bd67f431e4b48b3345f534f08a4beb49628515d3e0b67",
+	"95b9d7b5b88431445ec80df511d4d106db2da75a2ba201484f90699157e5954d31a19f34d8f11524c1dabd88b9c3adcdba0520b2bdc8485def670409d1cd3707ff5f3e9dffe1bca56a23f254bf24770e2e636755f215814c8e897a062fd84c9f3f3fd62d16c6672a2578db26f65851b2c9f50e0f42685733a12dd9828cee198eb7c835b066",
+	"010e2192db21f3d49f96ba542b9977588025d823fc941c1c02d982eae87fb58c200b70b88d41bbe8ab0b0e8d6e0f14f7da03fde25e10148887d698289d2f686fa1408501422e1250af6b63e8bb30aac23dcdec4bba9c517361dff6dff5e6c6d9adcf42e1606e451b0004de10d90f0aed30dd853a7143e9e3f9256a1e638793713013ebee79d5",
+	"02aaf6b569e8e5b703ff5f28ccb6b89bf879b7311ea7f1a25edd372db62de8e000219afc1ad67e7909cc2f7c714c6fc63ba341062cebf24780980899950afc35cef38086ee88991e3002ae17c07fd8a16a49a8a90fc5540be0956dff95390c3d37629949de99920d93096eb35cf0427f75a6561cf68326e129dbeffb8772bfdce245d320f922ae",
+	"70752b3f18713e2f533246a2a46e38a83cc36dfccec07c1030b5204cba4432700735a8cee538b078d281a2d0262110381c5815a112bb84404f55af91652bd17502dd75e4910e062943d8a736ae3eecdfdd8e3f83e0a5e2ddeeff0ccbdadaddc95391310fc657a59724f7e6560c37dc1d5bb5db40170190f04a274c864ade9687c0f6a2a48283177a",
+	"01f3c1333b44077c518cc594d0fb90c37651fb7b2442e71fc0a5611097f1cf7bcfaf11c8e0ac1b1cab54afba15bb9332df6bc64d8032368e3f686c8324b0114e0979dad78a5ccd3fff88bbe89eef89c4be586ca092addef552ed33224e85d8c2f4fba85ac7735f34b6aa5ae5299154f861a9fb83046b0e8fca4db32c1343e02676f283975f43c086cf",
+	"509283ebc99ff8d87902fa00e2d2a6fa239e335fb840dbd0fdbab6ed2d95e8275402523f7ce9a2fabd4b6c9b533288fbe914bde84365a204711d0977a7d698f4614385984dd4c137e4820035dd6737da364edff1bb62283e87a8c7ae8637314fe9b5777ec4ec21276dafedb2ad5ee1aa0ac99e34a6c01c055c8a239fd28681607f65143082cd4553c529",
+	"c17e417e876db4e123c631f7136b8a85bfd6ce66a69180d0cd5ecfd6f037bb1c7bd7908d51f2c485bf9e92c0e1799ee5f6ab834ee481f5eb1a8020205adb4d0f90126d4e7c2c859c5a5f644bdfa9c649ff4f168e834de6f9769429732099d46d0af506ab86c6fd92175159bbc05c75db8e1fa867e6030d64250008d64c857c47caec3dc8b2ffb384d0193e",
+	"950988fbe9d62a66f5f2c492bc8dc944a78eb3796ec37ba94b6a81a9d402ccad03cd8497fff74c5f4a03081c5fecec48574fecb21c1de261332c23108195d3f6a96ff8e433a1a30eda53dd5bb414973334f8cde5510ff759f7c17046cbb5acd8e8c4a6eecf2a9121ec3fc4b22c4daa72678194ce809024cd45c4ebb9ccdb6f854205cdb624f0787480d8034d",
+	"552a212c403b473741da8e9c7b916d5e5e9bcc9949021ae1ca1ed46b7d4a98addbb604d9fff56175b7e0367db26c9635fa7813653dc8d610befdd09ec41e99b192a716106f4299eec8b940863e5a59cf26cdc2cd0c3017f9b4f215812bed15f69e77edf672178e13c55580982f01fcc2fa131ec3d736a55d56504c545f4be50fee83f1263e4d3f3c877cc6242c",
+	"b00c4283dd3d9cd26e44bd97cede6c771cb14f2571b51cfdaae4309560ffd165da025a1bbd31096c3aa8286e2d6dcc3e681b8d01f2c5064ea26dfd0b5156b7a7f5d1e046c5bd1628f8fdae24b03bdf7cf7366900cc013a8cbed9d7f5937c914b08f8c27683b956e1279812d04288515333fc6aba3684dde2292951f0610649d90fe61606630fc6a4cd383649252c",
+	"f6e79457bb6d0884dd223be2cf5ae412a1ed425f1e4012f75951b096aea3b9f3581f9013bcae1aff2d3fc1e5c7e06f24af6d53c2c5c238b71c71cc670b05a7ee5204400026a5c4e5ddec3ad96771e49fae4b0f75ec58049ad9d972e5749a32d90f847f1ed2a1bab83db181e541cf5c8adb6b29ecc64dc25add491d408d3eb3ddcb013de7f5ffb6de9dd7ff300a5fc6",
+	"fe1d71e1d5efa3f712d23216ee8ee9139e66bd648b83efc02cdb4d45a28cf36759ff190a84d14d9471477abefb5aea4111110336143dd80cf81e02f268120cc07d746538f968e9876bff8358d390f5b8e7eafa61ecd236cedaf276bd61865fdd3424988201dcdeda2e3e0c33c9e3b3670125dd1049106cc6df5695fb2dca443233ff440f265bbff055483bac1e859b83",
+	"4c80163562872a965dedd8725652906156ada6e9d999027d96f49289edb92f9ef043e9d7c3377e091b27f85275499454af32317535997fb4aaeaf93565ad481ff7d45d2abddd4df4b60f71a6923ec30496c6ae534dc5427107ab4c5e656a322c7ab058d4c13ec0ebafa76576560697ac98f84aa4a554f98ec87134c0d7dca9184cf70412a324aac91823c0aca02537d197",
+	"fdd58c5ffe88665beb7073c8f4c22472f4bc9390cdd27a42622ca55978b000ab7579f795d4de0dfcaf521b8268980ef1d20277b07567985c0fd5030784ad6c32541ac24e99ab706105a2255fc32935c0fce6fdad9bb224d94ae4eae2a3ff08836618a3adf193630647bce1952b69da4de360f59da303519278bfd39b733cf66820a5e9e971b702f45998b69a0889f4bec8ec",
+	"ff38b15aba3794e2c81d88003e045ac6cbfc9f4833cdf896cefd8ac0c88674727ad9a9fcb9ef36574deea480e6f6e8691c8390ad73b8ea0eb3665c914b0d886546948e67d7987eea248b5feb52346ffdd965d5c835144c3bc63daf325e74b11267e32e58a914ae4521a668839d9445fececa49c5fba41f9e171698bbc7c6c97fa163a377a96456958d6e1d74f91ada56a30df8",
+	"f048c19328d60b4e59ed76940415b2c84c23883198bba5699efb0a1774ad5da6d15390c7b55d77d66f37448fe08107f42a5336408d5322f4b630e3275865fc66dccab39f6e13fabc133e5a441fe352d81c7cd9a25f145a6e2e2417d3b0bbc79eafcd7ad688c02011fd268dd44ac3f4f87b37a84a46fd9e9975962fba92c9a3486deb0c45f6a2e044df4bb79f0feeea432c5008b0",
+	"1b3e5fe6f113cce28a6f8d6f7809d3cec398cabffe9ff2ff10a7fec29a4ee4b54186063fd5307a2be393c9ecd75a37620bdb94c9c18da69b658579676ec90351d10dc33a7cb3b75798b1234f9f684d4a73a0fab2df3d5d6fdb1c1b1514d0935c1f2dd21486f91c2595b2f8f8a500ff443b9305270fb6f3da7961d9316d4ed6a135a31c4a3611d40e6585bbb34f498cd5b9a5d92676",
+	"740db337baa12b16897f17a85fa5685acc85e48338867f8ac9c0198dd650f5dfa7c17725c1262c72207e365c8aa45ffaab6470a0e5afefbfc3bb702a9766064f28cc8b796878dfdd3ca9d0216c14941438fc541fb5be0a13d29a996c5c985db4f630df067a5626db5dcd8df3a2bff17dc446e46e4079b8815da4318cb228c7722684e2a795a0ca56f500ea51951a6a385385d886f678",
+	"1465f2d578d167faa017fe8f763ce3cc8dc1e8371d774ed2a8803f12585296ee71a1f2253dd16b717a81f91f0f3641018a0111182b4e65d884b0a3d0292631ad807cdccc88bdeecb476e76f72b5246a630aff6e2401fa9570f85acb73ccb4e19ef04a932a03d7b7985dbe1e5bb410df517fe362321469e6f8b0e0cef6c31d7aa8ec06aa220620d66cc0e133fdee963589b12320fc9678e",
+	"80c051952fa6f3ef6af0f1759ec3e83c8eb91abee1de360bfa09e74b05af2475a0dbf8f9135aa25892919bbe0515898cfb6f88abc9e1891f2b2180bb97370f578973d55c13c35edb22ed80647c2a7e2884d1ccb2dc2f92d7b6ec5843ade13a608a31190ce965bde97161c4d4af1d91ca9962053f9aa51865bdf04fc23fa35a6fc3c8e888941263a26ed66c2dd0b29b2325dfbd1227c5091c",
+	"9c1e2a1aed6406052eed12b4495365f2f80e9c9645473f3549b607f20910bcd16dc3a4b173ac8d128129cdb7c76ebbc8e9a2a1ba0d822c66b367e790a69ac71f0a60ed4bff0e979148e3f3ee6607c76dbc572ee5ff17c27e4b52adebb4bedddff517f591a1977299c7cb01106f1453b098d29848ba3751c816215bb0d090c50f9e445b41b2c49d4eec83b92ce6c269ce835fd279e7cbbb5e47",
+	"466abda8944d0329d2975c0f2e2afc901f117887af301881f63b714f49a2f692fa63a8871fc0b301fe8573dc9b2689880cd8969e5072c57671e0633b041481dab25e65c9de404af033a11a8070c8ab70ca6d465318501afdd9940c7efbe1bb6d49581c222fad251dba4ee0a98efe22a3c4f74da05844523b30bbad6b080ac8df70a02da80bc9d477dfb869adb211e209a316d5dd1fd89a6b8f8e",
+	"0e89a873e07799ba9372fc95d483193bd91a1ee6cc186374b51c8e4d1f40dd3d30e08f7feecfffbea5395d480ee588a294b96304b04f1ee7bbf6200cc8876395d1db3ac813e1019bb68d27204e514fe4a61ad2cbd1782dca0e38b5538c5390bca626c5895b745cfca5dac636fd4f37fed9014ab46ae1156c7789bbcbb956ff7ee5ce9effa560731d26783dc6ae8bddd53a5d28133614d0ddeddd9c",
+	"fdde2b80bc7a577ef0a6c03e59512bd5b62c265d860b75416ef0ce374d544cbb4e3a5dbd31e3b43e82975090c28bc77d1bdec907aeceb5d1c8b71375b6d631b84a46153f5f1d195bfcb2af6f597a9cdc83782c5bbbb58c5188a87ebf375eee5212fa52523820a83106e8ecd52bedd60d95cd646159774389c07e1adcaa6b6f649408f33399ec6e507d61659696b3dd249996892d5986b654d94ff337",
+	"f5d7d66929afcdff04de30e83f248e69e89604daea782e1d82d8032e91a95c1d6fb2f5578f79b51be4397e4cd7cbc608ce143fdddbc6fb6c43ffdd394a7df0124353b919aeeac025f3eb11ff246c3b9657c1a947fc534ce48e18feffada8797037c6bc7e2d9a9e2e019fe65627b3feb28e446473e3bd413047a2587f0be6a103403cb3c33fdc212dca14d8e386aa511c22308e632f5f9528dbabaf2deb",
+	"332990a8dba55f977bc814436cf386ebbf10cb487a5f6ce83e13741bac670c6810284fbbe4e303547ef411e964fae82854e8c13cf56979b89ecfedd337aad78260060122d13dfbbf8497acb2066ed89e30a1d5c11008bd4d145b5ec353956310536304d8b8bba0793baec6d8f3ff49718a56e6694f8122078265cf5731d9ba61292c1219a1affb3679576d4998290aba3684a205c3469d40761a5c4e96b2",
+	"efbdff285027610f03182009c89b953f19721cfcdb8accd74bab6ec4bdf3f555ab902cb0dd91284269d140638aaabd211748aa4da3b18cddc653b57e461b9ad8491807c535c08fe97d89eb587c6af19ca152e72479626ab764e8b62da89fefc8354c75a44851f985746d78715a5a92798dac1a4222be27897b3f0aa63d596aa7378545f49b259aa8518c3def8a2ec8f7aa956c43668c8717052035a7c36b47",
+	"0eea9bb83bdc324fd21b03669aa922fbebc448e7d25e210294c07862cfa6e061731dfb67b4810633f4dbe2130d90fa1c65843af436e74219d213c4458dcac1c48ec4541fc6e3b7918ab2bc621aedda53658050900c3865ca57cd5dfa1d28576827401956d2dd8b861fa90ab11bb0b544ded9bd3d62e3278ed484e17db8f2d5dc5ea4d19a0e15134ba6986714c2b22c59c2f0e517b74eb92ce40d2f5b89e6d79f",
+	"25da9f90d2d3f81b420ea5b03be69df8ccf05f91cc46d9ace62c7f56ead9de4af576fbeee747b906aad69e59104523fe03e1a0a4d5d902352df18d18dc8225855c46fefeec9bd09c508c916995ed4161ee633f6e6291cb16e8cac7edcce213417d34a2c1edea84a0e613278b1e853e25fb4d66ff4c7ee4584e7f9b681c319c874d43502534e8c16a57b1ae7cc0723783807738a55b661e617ee285bdb8b845607f",
+	"a76b6f81372df09322098868d469fb3fb9beafc5edb32c674974ca7032966aaca5b5c9bffef87bfe626bd8e33d1c5f054f7d5acd3b91ff95324d1ae39eb905b9f2694fe5cb03486cee86d2f661a751b0e6c716a61d1d405494c2d4e32bf803803dc02dba2c06eecf6f97fb1f6c5fd10cfc4215c06d627c46b6a16da0854e4c7c873d50aa1bd396b35961b5fa31ac962575230c07c369f8fbc1ff2256b47383a3df2a",
+	"f9db613812f2259972d91b1598ffb166031b339913925ee385f03b3b35dc4b2f1ae78a3c3d99c6ff6a07be129ce1f4b8d994d24988d7fbd31f20535d36ab6bd0592cfb4f8c1ed9244c7fa8a3c46e91272a1a40c6cfcf261c5658476c59793bf1a3775086e41a0492f88a31e2d9d1ce75cf1c6b4b928b3545d838d1de6b61b735d921bcf72e4e0615e9ff969ef76b4b947026cb016e2660ba39b0c4c953369a52c210de",
+	"e601c7e75f80b10a2d15b06c521618ddc1836fe9b024458385c53cbfcedd79f3b4239598cd7b9f72c42dec0b29dda9d4fa842173558ed16c2c0969f7117157317b57266990855b9acbf510e76310ebe4b96c0de47d7f6b00bb88d06fad2c2f01610b9a686079f3ed84613ba477922502bc2305681cd8dd465e70e357534503b7cbc68070ad16d9c51de96ccf0aae1599299331c5655b801fd1dd48dddf6902d0e9579f0c",
+	"ee5ff4ca16d1bde59ffaf2d064eac9141c1d8f120ea2bda942b7956ba3effc5f1e725a3b40b0b9223a14d7a50df1681d14ca0e0eda7bb09c428fa3b2701f83a7a3e139485a118f6287d266dbc7fe68c87b35becabc7782537c79cb8165bdc40cc103d7b6d4b627fafa0e4113f92341ab90ceab594bfae20dadbfafd401684584598941f1ffb8e23dc8a04ecd15376cda6d849fe0dfd177538c62413622d172d9d46e05c450",
+	"1daca80db6ed9cb162ae24aae07c02f4126f07cd09ecee8e798fa1bc25c26c644333b63731b4ebc3f287f2318a820c32a3a55fc976576bc936f7384e2553d2891e3771ff24dd4c7f0256906460a8f12d30ed2b23583a0259cb00a9065a757d654d6e4603e7c7eb4a8426b527ae8a849d9350e9094b890367df3e8b23ad2df4d7dcce416bd8ea3badd037f53f7b07c02e5926515f196d62aeb9b8b14c863f067fc12c5dfc90db",
+	"27ff4e58a34ff1fcd66855d014ea17889a3cf0021a9fea3fabfd5b270ae770f40b5439e00c0d26bd9766f6fb0b4f23c5fcc195edf6d04bf708e5b0bced4f5c256e5ae47cc5651e51cd9fe9dc5d101439b9bc5cc24f76a8e8847c72686e2af1ce7098ad7bc104dad00c096a6d48b6453322e9cd6773fb91fb1eabd05dc5185a9aea07a2f64c6fea9897681b4428aaffe1fe5fd3e8ceb890b12169ec9d51eaabf0ca3d5ba415770d",
+	"75e2fb56327983b04f640717be8cba6fef3655b4d8e5539587d6478356ec397efaed818b8425d052778eb30ef0dee656c52c2aeab079ed496ae4441a365f2130432c87ba757e25b4511656ad15e2eff84d342331fd2814d1f1d11af65d98a424c115ba183437c0d0aa55f5c44b8685028a47d89d0d36a0f20aed510c366ab338f074a941b404fb349caaec821e0850a627777cc8f5abce6b509290027a2a28ff1db62a5ed2f95fc6",
+	"c6ae8b6a060917cd498aa7874ad44baff73efc89a023d9f3e9d12c03d0b7f5bcb5e24e1bc2ab2f2c67b9a9d36ff8beb51b5affd4a3510361001c80642955b22ea4bf28b81a5affe5ecdbabd8d17960a6af3825a4522fe76b3d720b5d06e66bff5379d7a8de1f5cc3e7bb75163a854d77d9b3949bf904b6c4e568682f0dab7f217f80da7303cfdc9a53c17b6b51d8ddff0ce49541e0c7d7b2eed82a9d6be4aec73274c30895f5f0f5fa",
+	"606c9a15a89cd66a00f26122e33ab0a08c4f73f073d843e0f6a4c1618271cfd64e52a055327deaaea8841bdd5b778ebbbd46fbc5f43362326208fdb0d0f93153c57072e2e84cecfe3b45accae7cf9dd1b3eaf9d8250d8174b3dade2256ecc8c3acc77f79d1bf9795a53c46c0f04196d8b492608a9f2a0f0b80294e2abe012dc01e60af94323c467f44c536bf375cddbb068c78432843703dd00544f4fff3eaa1a5a1467afaae7815f80d",
+	"88b383cb266937c4259fc65b9005a8c190ee6cc4b7d3575900e6f3f091d0a2cefa26e601259ffb3fd03083270eb63db1ffb8b4515ec454d12f0944f8f9f6869eedc2c5f1689766a748d74e79ad83ff6a1639aefdec6109342dead31e9cead50bcc00c5b2206e8aaa47fdd01397b141880490174141a1e6e19268378c1b54a84aba60ca711fd72f7df88e120dfea2caa140085a0cf73342f3c588b7edfb5b5e5ccabd68a32364746d92d536",
+	"dc0b293f1ba02a326743509f41efdfeeac1efc45137ac03e397a3273a1f586a0190cfb4ea96d6c13ca692a4de6de905c8338c3e29a04cbae76272f568b9d795cea5d758106b9d9cff6f80ef650d6b7c428ea3946c3acc594907fe4227ed68faf31f2f6775f1be5139dc0b4d73ed6308fa226b9077561c9e4c7a4df68cc6b819b0f463a11b9a09682ba99752c4db7aea9beac1d9279f2c2675d42b551d27aa2c1c34125e32f2f6f45c35bca45",
+	"5d801a7413311e1d1b19b3c321542b22e2a4ccbe340545d272abede9223741d9835a0fc80cc9da97a13f8bb4110eb4ad71093efba165b1edad0da01da89d86726e0d8e42ae003b4b50297d233c87da08406f0e7fc58ba6da5ee5ba3d2d7142cbe6632734eb2e7b7863c15cc82198ee8f9a0ae0b7f93bdbda1ed269b3824d5d3c8e78513815b17a4c0cc8c9706b9c77423a309ae3fd98e1e05cdbe9e2577834fd71f964301b10b66c316a2d8f2c",
+	"2fd32a2bc15a9e96a100624404fd0a4e54ba9f8c0543d8ccf7c5c2e35f5e8c3c11dfd497320aa903900a4ca55a2b323b3ac4a7cfcd01bf0b448db8829072bee6b77c3d7bec2e1d8b414d907288d4a804d2379546ef2e2dc628269589164b13fceb32dba6fd5d48a956ce0b5c3eb28d894a95af58bf52f0d6d6cbe51317152744b4ccfc918ed17fa6856478d580b389016b772e1d02e57d2217a204e25361d91d4845a3fa20fefe2c5004f1f89ff7",
+	"f537b437662759bef8bd64368536b9c64fffbddc5e2cbdad465c3966b7f2c4bc5b96767ef40a1c144a4f1cd49edc4cc5b57e7eb30d9b90108f6fd3c0dc8a8808b9e0bd13aa3d661c4863637c5e4ba286553694a60bef18801299ae349df53a355051dcc46a7d003c4aa613808f430e9db8ca7dfe0b3f0a4c5ab6eb306aeb53e11a01f910064fbe6ca78b2a94fac34a2602f73de3f275953e13ff5c6bb5c39b82321ead17ec0f8ecc479e6afbc926e1",
+	"1dd9fb7d5b5d5074971e69300720014deba6fbdb942bd29704cdfcd40fa5281d2a1b9f5b776183e03ff99c29587f10e8d325cb49c5c93e94f5132741b92c4086eec1374dea5c1e772cbb230c7b31f3e962eb572be810076bdb926b63732522cdf815c3ab99bbc164a1036aab103cac7b823dd21a911aec9bc794028f07b7f839bae0e68211286441f1c8d3a35b281fd321312577bbda04f643ecb2a74ec4527bb5148dbccbeba749f5ea19b6072366ba",
+	"5bd63737449de2d20ca63943953338ecf4cdd6cd0a726241adb04376385a809cc6ba0f3482a310746fbc2cd5eb214f03a14cdc548777fb0d048d659cd75a962e490c4fe47affc2430a34b10275e4c76752a115aae3a24d4fb4fad89ce4d79d65de10292f3490bfdaeabfae08ed51bda6ec8230e66cb07ddbeec26e3ef68dd71c852900659fcf0c963f4574ffe4626a33db9abf0873dde68b21138498b81e8cc44d354be4073615889a7ddff633b5447d38",
+	"a683ec8250506571f9c640fb1837e1ebb06f123e745f95e521e4ea7a0b2b08a514bbe5bdfd316903d1d6a05f5a143d94dab61d8a3a146ab40b2d6b72df2f0e945875a8aa7051ed115975f6f1567cfcbf04c5e11e3a7027b8e179ba00739181ba10b028e3df7259d0712f4a6cef96469ff737865b85fee2c2db02a6423e32505381e18a1e0b4ce3c7998b8d6b1b5e09c3a280b85486d0984c9e193b0ad2043c2bc4ad04f5b00a73956715937eebf6b3e27afc",
+	"4df9d160b8e81c42930c48956fcb46b20b6656ee30e5a51dd6317876dc33e0160d31280fc185e58479f994991d575a917073b4439919c9ac49b6a7c3f985211d084c82c9d5c5b9a2d29c5699a22e79de3958d7b0e856b9aa97493cd4563aaa04fa3977a9bb89e0bc06a82296bdc76d20c8d393770176d648712454305fdfcf4e117d05acb5a5b006a9f8d0dc66dca708c4e4103ca825d2331750685c44ce3d9b3e753455580f4d6ac4533edeeb02cebec7cc84",
+	"67bb59c3ef5ee8bc79b89a673e331e581215076cc36b68f517ca0a74f74efafe9dcc240e6d8ca4b21019c27d6c9289f4419b4f218eeb39eb741c5ebebfe0ed2f6faeec5e8c477acf71907990e8e288f4d4049111779b0635c7bbec16b76493f1c22f645745fdac2b383679fee573e4f47af45ee08d84f63a5ace4ee1c06fa41e2e6e14b7bc392e38426813087a3a461efc62ed1941dc8f1728a2bdc04fde72a0b786558783c84abd4bd100e4926979a0a5e707b1",
+	"d341147169d2937ff2373bd0a9aefa77968ec8f0d993c6f9881eb174a1911e05cdc45993cb86d149a754bbe321ae38363f9518c50dd3faf087ffeeeb6a058b226ccab7858c00ba6de0e8f4d034b1d27508da5cc473f3a413189ee6fd912d7750486912944d4dc34405ce5ccc3885fb0aabcb922bcfa9081d0ab84c288022bd501235a835eb2e1124ed1d48fd4f8682da8e7919321031326502273375625c4e3a7282b9f53452195e53c6b4b57cd5c66f621bed1814",
+	"27e7872a54dfff359ea7f0fca256983f7600236e716e111be15a1fe72eb66923ea60038ca2953b0286447dfe4fe853ca13c4d1ddc7a578f1fc5fc8598b05809ad0c64a4363c0228f8d15e28280837a16a5c4dadab681e28968ae17934639fbc124bc59212138e494eecad48f6546c38366f1b7b2a0f56f579f41fb3aef75dc5a0958b25deaa50cb7fd1c69816aa9a51874a98e57911a33daf773c6e6166cecfeec7a0cf54df01ab4b931984f54424e92e08cd92d5e43",
+	"13dcc9c2783b3fbf6711d02505b924e72ec6736131159017b966dda90986b97522bf52fd15fc0560ecb91e2175322334aaaa0097e1f3777c0be6d5d3de18ed6fa3444133486068a777443a8d0fa212ca46994944555c87ad1fb3a367db711c7ebd8f7a7a6dbb3a0207de85851d1b0ad2f4149bdd5a5ba0e1a81ff742df95edee850c0de20e90dd01753137cb8f2c64e5e4638ceb893a3879ae2c049aa5bce44d56bf3f325b6c5029b2b8e1b2da8de7d4e48ca7d8f6fbdc",
+	"9ca875115b109eab538d4ec7023600ad953cacdb49b5abe263e68b48eafac89a15e803e838d048d9625972f271cc8f36344bed7bab69abf0bf05979a4cfff273b82f9961626509765fcb4b4e7fa48212bcb3ab2b1f2dd5e2af768cba6300a813514dd13e4d269e3d36548af0cacdb18bb2439ec9459f6d847d39f5598304ec46a26d75de1f9f0c2a88db915bd26e45e1f1e68c5b5b50d1890e97a3803c36755f026863d14176b8b57f42e91d3ff37787f9b38e333e9f0433",
+	"ec006ac11e6d62b6d9b32ebe2e18c002353a9ffd5dfbc5161ab887770ddd9b8c0e19e5321e5bc105add22e473050b71f0399327c7eba1ef809f8667c1f4e2c7172e10e753705e9a083f5bce88d77521225ecd9e89f1e1caed367fb0275dc28f620fbd67e6b176c9ae5d2659e6ec662116c9f2bbca3a93043233a4861e0688db6dc1800f752c5d58aa5033c250c891d9126e534ed921a9026eb333333fa8292059b8b446f336ca6a0cb4c7946b6aea3831653122f154a4ea1d7",
+	"23deadc94481ce28188f3a0ca3e85431964cb31b60fabf381e6bd45ef0332bd4dde774b0281d317dc2e7d0c298fcf8625fa734126968df8b68ef8a35c325d84ba4fc53936ff3ffdd8838d2a8cabf8a9cac54aa444ed9875944e55994a22f7fa8538b1e983b57d9215fac5c0052029644044e790ce2f5044655608c1d7ad3bb862203ba3aba3b526606f273d342ed5721648e3f600942d3f7546f679161436389d879dd8094e1bd1b1e12cde15cd3cda4c30a40835665e4e5cf94",
+	"94701e06340114f9cf715a1fb659988d33db59e87bc4844b1500448960af757b5282f6d52967a6ae11aa4ecfc6818c962b084c811a57724f5d401191567f24ce917e4f8c3963474fdc9d2c8613c16f62446448b6da6eeae54d672825ed7606a90e4611d0e318ff00566862c955b636b5e81fec3362e8672ad2a6d222a515cf410482836deba092a51a4d464dfbbab35c50a33437ac16a88256e9e23ddd3c827cc58d3e5000ee90b12e4c5175c5733662d4848ae0d406c2f0a4f498",
+	"735b0758d5a331b2304f01081172eb95ae4115de651b1a6693c5b9543de33df25d9f421dbaeca033fc8bff57313b482778005aa9fdcbca65c643da2f3320e34197868eec3848ff3c70d7ac7d910fc332e9a359f892ae01641be253013b554a0d3f249b3586b1857e5a0f9482ebd91432a852b221f4287a6e81ed24e8064645d5b28ab9a13b26cc1420ce73dbc47b31acf8a871601022ce23bc443b1222ce9a037a2fe5226295feb4efd4fd671338f459ae146032697cf82fc55c8fbf",
+	"c48d94f14549352790079fee69e3e72ebaa380510e3581a0824066413e7044a36ad08affbf9b52b21963d2f8e092ff0ac1c973c423ade3ece5d3bca852b894675e8173290529226939c24109f50b8b0d5c9f762ff10388833d99bea99c5ef3ebb2a9d19d2231e67ca6c9056d8834730605897426cd069cbeb6a46b9f5332be73ab45c03fcc35c2d91f22bf3861b2b2549f9ec8798aeff83ceaf707325c77e7389b388de8dab7c7c63a4110ec156c5145e42203c4a8e3d071a7cb83b4cd",
+	"553e9e0de274167ecdd7b5fc85f9c0e665be7c22c93ddc6ec840ce171cf5d1d1a476743eb7ea0c9492eac5a4c9837c62a91dd1a6ea9e6fff1f1470b22cc62359474a6ba0b0334b2739528454470f4e14b9c4eeb6fd2cdd7e7c6f97668eebd1000bef4388015630a8332de7b17c2004060ecb11e58029b3f9575040a5dd4e294e7c78e4fc99e4390c56534a4e933d9a45460f62ffaaba25da293f7765cd7a4ce78c28a85013b893a0099c1c128b01ee66a76f051dc1409bf4176e5afec90e",
+	"dea8f97c66a3e375d0a3412105ed4f0784f3973ec8c57b4f553d3da40fd4cfd39761de563ec96a9178804641f7ebbee48caf9dec17a14bc8246618b22e683c0090259e3db19dc5b6175710df80cdc735a92a990a3cfb166461ae713adda7d9fa3c4cf9f409b1467f3cf85d2141ef3f119d1c53f23c0380b1ebd728d7e932c535965bca41a414b6ea5bf0f9a381e098d282a554a25ce41980d7c7be75ff5ce4b1e54cc61e683f1dd817b8e2c1a430d7f895e5e7af13912cc110f0bbb95372fb",
+	"9dfda2e2f732867e60ed2b5fa99ab88eb82dc7a54334d02031258beef75fa4bd6962a1083b9c29e4eeb3e5ab8065f3e2fc732675b8d7705c16cfb4ef7305eb58120f1af5ddc55872a2cbde3a48661a0598f48f63e2e9aadc603545e2b6001748e3af9e86e1830af7b84ffd3e8f16679213d37cac91f07af0af02b37f5ed946ef5c955b60d488acc6ae736b10459ca7dabeacd7dabcfd656511ac913174f6d99327be59befe3e463a49afbb5235f0ce2840588c6edfbaaba00a4211c0764dd638",
+	"ddcd23e8b9dc8889b8599c721e7f8ecc2cbdca03e5a8fd5105f7f2941daec4e2906c654210bdd478374ddee43ee749a920ee91872e057a1157d384dcd111266221b3c79774476b4862fe450704ff2c5353e9a936cac87c96515c28ed4c830335a55d084cb5873c5fd2dd907f3266d8eb7bf13b6dd7cd4966982a0949efd8e428dae13daee549e01cc3c226211d6307823f742c5ef2155601a4644c46eddd603d4abd959c6d242e427768df3b1e22d87971df58a1564b38311a897c85b497a72556",
+	"39016647acfbc63fe55a74598bc1956eaf4e0cb49d532c5d8323fc6a3f15a0231597f06eafd74ad245e672bf6b21e4da503cb5bf9d15e9038ef354b38807564d91f38b4258378ccd9b9420a1562d7136196822a1291c913d83c4cd99fd8d420990c72cdc47607124de21da8d9c7f472fdcc780379f186a04da93cd87628abf323c8dadcd7fb8fbade37d7d2b5c9f9fc524ff77494c98f42f2158a6f68c906105ca9e8bb2df463863cfc1e9008d8344f55c4e3203dde6699b59812d49ce1279fa1c86",
+	"02cff7567067cbca5911664c6bd7daaf484181edd2a771d0b64566c3ab08d382e83932cdd7b4dbf86c9cdd1a4c353a511e68afb6746a507a9cd385c198246f4543d606c6149a5384e4ff54c1b90d663dc7a4b91aeac3cf716db7ca6f9a1914e3a33efe82e7ccc4215999c0b012782402db4726db1d7d1c73571d45739aa6fcb5a20eeb54a84d5f99902a8d356cbf95f34c9c28c8f2badfbc08c69233514493c0c04963268c88bc54039ab2999c7b06cba405936dfc43b48cb53f62e18e7ff8ff3f6eb9",
+	"5764812ae6ab9491d8d295a0299228ec7146148ff373241a510faee7db7080706a8dada87938bf726c754e416c8c63c0ac617266a0a4863c2582412bf0f53b827e9a3465949a03dc2db3cb10b8c75e45cb9bf65410a0f6e6410b7f71f3a7e229e647cbbd5a54904bb96f8358adea1aaa0e845ac2838f6dd16936baa15a7c755af8029ef50aed3066d375d3265eaaa38822d11b173f4a1de39461d17d1629c8df7334d8da1b6401daaf7f34b2b48d6556ae99cd29ed1073926bcda867421832a4c36c7095",
+	"4df3043cf0f90462b37d9106e67366d112e4938c4f06abae97869531af89e9feebce0812dffe71a226de5dc36be652e26ef6a4be47d9b2db5cdd43809a565e4fc0988bfe82037c505dd276b757b785203249fd083fb474a25acccc9f38dc5164ff9097e05989aa6e280739a755231f93670e7226e22046914c155bf33d135b3f736ccca84cc47ae643215a054b54b7e13ffcd7ad73cced9279dc3210b80700fcc757acfb64c68e0bc4da05aac2b6a99d5582e79b303c88a7ac4dd8ed4289516bba0e243527",
+	"bf041a11622715426c3a755c637d5f478dd7da949e50f05377bf333f1c62c671ebdbf9467d37b780c25f7af9d453fc67fafb2f065a3f9f15d4c3561eeaa73fa6c813bf96dcf02430a2e6b65da8d174d2558110dc1208bdcb7898e2670894c0b9e2c894da3b130f57a90ec8ea1bffd27a37b4da4645c546b2b141db4e2c919154dac00e78dd3eb6e4445974e3bb07905982da35e4069ee8f8c5acd0efcfa5c981b4fd5d42da83c633e3e35ebdc959bd14c8bacb52212b4334f94aa64d2ee183861db35d2d8a94",
+	"a170ceda0613adc9c3a1e427f07beacf3b16ed69fb42b6bc09a38d803f632ad2929dba215b85683b74e2feb1d18fe17d0ea0db84d1be4e2e73476917a2a4cff51d6eca7c5e82232afde00dd2286a4c20eb09800b4d5d80e7ea35b6965b9792d99e399abda8cf32174ae2b7414b9bdb9d63e148f7357635a7310b130c939593cd3479164724011966c4232142df9966f09422f34f20b30af4b640a2c6d3dd985fe0ba3dfa9083cbb9b8dfe540ff9f6c608d18481213040768ef33300d773f9890c724ead320a1e7",
+	"929477e9c2d0bbad3429a0e0de776695255013108261dc6404cb09828770e274d8bb650a50e490dfe917fc2047b0f8ee72e105927d9fa70523c727778cbf6ae876d641ad562938c870d12f2e047bb78920739dba0c3f8ce1fb77589623a5f1625f5d6ab81940c7dfc3dc3a641d82b2813629bab8282999317d6b93842334f123fb4693a9c2c9d8ba9bfc746642dfbd045cd2021b272eab7358aa954d453da53fc5392dfa7eb881f6f53809b692d27f3366595ff403289efcc691e118b4744a1147071d8909bef1e8",
+	"3e98bb14fff5bdf7db38a3960dc55ca7d02333daed8712cca13dd5bffd114636559279db72554cc0a0ee1f7e15557d77cab0f2f1131f94fe698db81be38300a856a5eca85e5cf915fb7b6f38ccd2f27350e62cc30ce10ffe835118be3d435d2342ed3d06199b7e20c8e34d68902f0ab8745bd8b7d5b863d525c1f5906d2dca598db8a0f1e67736182cac15677579c58b8c670cae1be3e3c882153b2aa2988933e579ec2d6dbb00c671da64443dfc027dee6dfc3233c99758304570a982bf9b2eb59ccd70d0b54c4b54",
+	"aa12c7fa50ffdc2811c1872e4bee15f43e6909212385c872eb489f7e06dc1787043f56126f8373bdfa4b3f61405c73dd4dfd3f40aa5cd207e8520849c26f67716a46c0989a99efff42f24e0736e327af8e607c401a1bac77341e9a78c91e35d55b2457bdd5317a405a1fcf7a2a23de68ef92b65819e8aa3807c545361dfc9fe89125123492da958dc313cb5d03cb4b192c54ac6b27fcbc498652f5ed36b587bb74942b3ad453a8d79e5ddc06ebf806dad5046b73251064582ef5777dc530f8701701761884783fdf197f",
+	"83e615cf6e17a29e63945710b548a6d9935850eec69830841e26cb6071e908bf72c87cf079ffb34c5eb1a390def72d004a9488224a18e189aa1092a0f1135712834d257a53dc1d0e2c6417d8f472ff13b181910f4c93a307420d44beec8875d5219a3160b8e921434ddf3f71d68db1c1d5c39d68edb7a604792f8b4e31ecda7895c99fc7031a5b98a22009c1da005ac8fd2da0b5d742743f5712d12fd76d11a18e487776ce21ca0d6e5ab9ca6d8c394c321b91c14e291399a642721361811a73b7392e8603a3004e7060bf",
+	"ae1a8f7bfe4b1a0fa94708921dadb2c20b938239d7b9a2c7c598528f20f49764d322ebe85a5b2ea15563cf2f2304baf55d6607c52e2e1160859dcb7af6d7856899eada0e9128a180d3de6fed9334ba52b80c5c362d5591a0ec30f86d37a399927eb1c53076a12d26775522c511c83eb5b7abc2a00bd2dfd5627a8febba53d85f9b74c4b7f0c862ddb0d9298899b646b774d6cc23e4e23ab47174fccd34499253996d5e0917210e2f6daa1685f89f2f1fdfd5509ebc38191d539ecfb54ff0f5bbe6ef36ea35d425af6462f518",
+	"1d033e06be253ab800c8176d3a9650ab2a5bcaa03e11ea95fb9ab3834b41eb0d1b2bcecfe219364c3104ef65a8d692bd77c798548b7d9a8faf7f5172db24ec7c93006d6e9839368291b8277a82c034a3731f1b2e298d6e0282ec8a7902e4f844d132f1d261d171375c646065e201849f2df73e3748d853a3122c2206aac92fea448500c5418ecfb3d80e0e6c0d51f85831ce74f6c659cc291f5348a1ef8b949f1b2a753633e382f40c1bd1b2f44748ea61127b6f568255ae25e1da9f52c8c53cd62cd482788ae430388a92694c",
+	"104bc838b16a641749dcf73c57b207ea3bcc84381170e4ca362065a3d492e892b426a1f4fd82f69461d1ce1f3aaf8fc291ea30d6667e7e1aea4c44f7d52a5fa6d34709e6658483260ff5da76bfb74e7d194ad40dcac00daf0e45e74db4bc2248100a8b256b257278c3c98f1f2e3a80cdb812352aaf4155b3a4033999fb9fe7f506994fcf3a8db31e9e5ca8ef8c2e9c6326ca5b0803724ba641950eca877fe6ed6afc2e014651c56d0e6a61eaff7c5ed0b861d4bebe42904c0a568c26aa8abb2e97da2bfb40f14eafb6bf16cd208f",
+	"5b92e4a175437d0a53eb10de2c56401720b11715a034459ebf506c3fd6534b5e817a0f09deac4bcfd353301d8d031b1331582ac09189b48e6ccea444655866c4bbd123d45ebabb774f877cf12d33b84cfca4a6a94f3f98869fcf2bbb6cc1b964c2438c2f348bcdf9001dce60a4706d20c169a040baa61cbeb0b8e58d505e6e3739ab03e110ae7efdf91347474033defbd1e86af322ec6456d3394699ca7ca6a29a70d9b10a38fe666eab2858bfe12dacb31568549c826c15af5b6fddf779954351be1872f04e53db7b3b5fbf61fd18",
+	"401cc7bd9f8227efaed70dad83fc8db3bd38efc166f0f11ab142c565c68ba9db680423a3d698b6f3476ef440051fd20b93f6a2ed045825567df5a65e3f62e4442ec396ad260a16a13a1dee46c7e8d88bdd7edf223ab76a9a787c1f4fe9925c051a4ca0e77a0e78baa29f36d193c862fd3a60653f544ea9e3f75f2f553891be8c1fb882f6a6aad118f576f3c2793efc67221b37a45ab6137434f6228cb002fc137b91fb8572c757f00736879453d64a8a868c131810ffdad9e9d028d132157ecb1da675d54047d19b27d3258c9b1bca0a",
+	"c20cf0354982ca6a19d9a4dbf78f810934db2373941a12c263adefa61a5f385c859bc47028829c531dc25ccc0004c7510e707175a102ec3c4b4c933e3f52033e67476ff5f864c446c042a21e6037f7798363d20267891b965879fde80af6b59d77862e3a229af01b7ac78b578e94bd9f9b073c38a627c1864df0083aabb17024bdab6c3c0f0f73d31d59480523a2f23b78baa0385c15f290114305d7f98786b7dbc17a8c2aad97448e8ea389e68ef71091a6a9735ac12ca5497b9171da11a93c28d3273f58b74e2e46279d3ce9d0b20d19",
+	"e2365c2754073b511f16a1881ff8a537541ca7362ae7b84223d3c7d1d49d03a37d6d05dd2b819af9705c015dacc9dda83474eb14b7d5fce6e8a8f8c58e870149338d320e5ae476da6749af45e65ffed550d225a39dc74ffd93ba7da476985d6f44e90fc8e82454496260458431804d802fe804d825f611772f9710667377adfb1a11e4275bcecb42175c515f6a9439a359824f82cc9d480954364e6693099a821ace362e6c7ecbe68be8823bb5b49b4f23ad81b64139e3b63d9d4d298a842f013ef0d91ce7915ee8f816c70ba2aa3994216f",
+	"9c43944676fe859327096f82049cf69e48b98715878400fdf2805e0d5ee642e6cc9c43739f418b701348a033c5cb96bf8702fcd2fac9be58262a843c1e4155ed8a1724b6ebf7cce659d88a95a0c54deb2d7d9574a45219b6419ee173d1d8fad3ace47c962b349abe1048565df85bbd0eb9b11698258c23598023a00fdd26573e41951452027125c6e894a97736ecd63fd15b29a55d8dd9dab7e2e18f541a2e341890a61b7c896e7dc67aa82f3479dacd4a8ec7558d40c34d9ae4060e13718d676c2450258d83de8a86e012813693098c165b4e",
+	"1c707c29582d98a0e99639211102f3f041660ca03ad0939fe3855b8c1b22d6a9b8673c93e3eabc0ab231509b2b0d73c76a290a363943d12d2ff0ea30c6dd54eda753767effe04cabb4c3966388fa4c83a1906a0f48519a5fba9aeb585e0f8c45d6123a75ebe98fd1d0272f733a3925119481a321fe7509346c05128302851ba17a137f956f184e057a305e79a148727a5926de6854eb0314d5492fd735fa773d99ea34c95ca7546bd3a3aa8e66bcc6d860cec3d35d0e2165d5fbe8be99b6e7967df6693e5a6243e94c9c4a2528ae6305cbeca209",
+	"8f1e88103ffa378f062cade0ec509bec99a5c73fb273e79dbef24abf718ac26ac23dfd2b8932038ed3cb9637b71643c161142019f45b25b4fa4c52356737a27027e805ec635154327a66bfe64efc6285cca98c34edc7fb6c0766970a545342cf840aec0a5ba1dd3c6949be4fe97b0f8c8186de07536fd9074db34d09b2f08af9dcf9424d6edbf9cd044102c0e5dc35aff78c36d079dbd2c500e19c8c985ae2abaf6b2a20716bb719754a8840ce97632116c4d0b0e3c83ccca27f11c4204b76b5d6cfe6348a9615d8e4af53500dc4c2cabf12ec8c76",
+	"b9a0c28f1a6156992c103a84655fc6e654fa6e45e45819513afa797024717c00cc195994512fd53ecd1e12dac4d2448e0c40308382312084d2111f7db147b2e6589ce6d977f6115f629508167df8f45bac98abd49f6b272bcc4fd874dd5e29fb6daceb2d727a2a892194cfb9269eda00626ac89b4e74bd29b21e9f6ef18cb69889a02d4f0a06a2e5718899c1dc3b051c2cfa29653e782f87fefa478e6465bf5ff27f8b6abdb500077aac97100bd955ec535a587d66f23354be51cd8170289344bac9451f74e8aee3639f7c09981f4885e018912324d7",
+	"456844a34ae1074246f8f71eeef2010ec8733265bed7c1cc60043d770edfa320cbd4284a94be2574337e16d27f125074ebd7e99031f7abb4547b9540a7b0b5148ef501b550dd929f3dfe39ac65519f563e9254424aaafa05b1d37c16c771882e9e25d4906ac58603da749adf686932cd73d81e2658134fe69294c7a521d257eaf2110c667fc9d6f09b52d24b93910e532184eeb96eae9d9c9750ac3c39e79367431ac1af7011172d0a8be46a31010219a0310a733068c589bfc4748f3626aa4ff8d355cc893d05111c287c9992e95ad47481a6c42d6eca",
+	"c5c4b9900b9727bdc24baa544cad5faf8340be6b3759361f53889f71f5f4b224aa0090d875a00ea7116772117dbefc3a81c6950ca7ceeae71e4ba975c50d61fec82e6d9448d3a0dfd10bb087bdf0673e3e19fa2aaa7e97eebf71f11b86034fcf5a61240c71444ac3da15ef09b27b3523d37d309e8722380f835c1aee4a767bb027ec0674040853e5b53d6a31657f51acff6d2487860becd5ce695696cfe5937f4a0217b69e01cc6facc24dfe5f5230b8692a0b718e3b3c789d682db36101795a9a5f8bbb838c3679be72f7941a1db180135347d0a884ab7c",
+	"1781df2fedd2c39137854737d054cd3ed16b0ade411e41d97888ac900fdb46d9ae26b3d2dd07e118fd57eabd0dfd03a55793c76420666444865371adffc9b2f35068a0d70f9cfda1ac27ccb4beff4ffa5b8bb8bddac843386675c38a181fd0d935d6d51b25d78e7ff4ecef27a9853c0f0d2879c395ed1c4883987d123890d04f851c3e042e1164c68c0d503de16816f4b0e554236e5f4c339ea11d01ce652f6208f78f457a2417a97c0a6a240f443262def4b6763abf53e597bf1a28f907dc7cbdc751a234ea7d75710ad5ab0c37e8e9805102a375abd44011",
+	"8963552ad1e729ead07750df599d734157aaa4bcdcac17e8eb19b4f99cdb162686ff433137aa4e8a0cc8df0053999196262115aec326cf37567d9ba4760e0ad21d5763977f1ab9b35c0fc667890fa87fc946ceb776a811b5adc69446bfb8f5d9908029dc5aa38db816e4a4e8f98e5a48cf0a01627031c5bd1ced8bc1940dcafe4ae2f1199b186468eafc07e96a89d95dc18ef0fed3eda5b58ce58f221a47ba5311313cc680367eeb058fafc7bcadce5f520b6371489d9e529278ae6ee2650a85aed82896879038bbd9aa8d685fc9528943ccf2235cdf69a86464",
+	"23ceae3008085134433f5de4b47bafe0f443d443491e6cd47b216dd2dcc3da65239515a6e6b9beb9a939ae9f1f1f5e11f88326475e0962f319d9bf75ddfb4a46e7cc3f799d7547f3c0b2e089018b75787b82ea1a7295e7411f4852f94c94170e98bb0647923b8eb7d184038e56560da46085540cbfef82b6b577c445d038f6c93fbfdfc96ab3a0191d20a57b8610efb4cc45cd95198198e6f80ac46b0601511885f650eb00992605be903bcb46cd53c360c6f86e476c4c9ca4ad052eb572bbf26eb81dd9c73bcbec137aea6ee27aa97dadf7bef733fa1555019dab",
+	"c0fd31e82c996d7edef095cccfcf669accb85a483ea9c59f368cc980f73da7202a95c5156c34192ae4ebf773c1a683c079b17ac9d08b4265b4054fcddaf6666ca50f38f1a2ef2497459a68c06837363a526e850ecfbd223f55dba67db017eadb7a9139abb5bf3854834478b838aafa16c5ee90ea52fb2f7b8db2bcefb85b06fc455c2b6c27d0af9a49dbf2f313bf2599370637393e7972b31d8bf6759f3e6115c618e672831f84d76ba1879c754144e1df4d56b1e264b1797dcb8ab165040c8d20b931071081d7f74fbff590bdc8e888e71acc6a720270da8db7c821",
+	"936fdab91fba396e4a8754a97a04ba333daadc29885c9d0c8fea3387165278f4974e468fea57f2bfd8428c4d0f010833283db73735d39de0c0cb5898d0c06c0ecd05f61098935cb6130a8da60d1a6c2ecfe420f972263fff5a631b09e81c837183c5528bb1c740b36fc39cb082f3383c2b4afb25d04ad1d1f4af63dcf26a0bf5a647cd2e35a51cc119c4dc5031f5715b3bfa1f2b92de06bdac0d670fdd30980f32c51f3936b51e5db6b95a8d36279da5faa4c4e454f2b7e54e9f488071011c7f6f9b63da260a2e46d796d36c9a9dcae88085806a10a77bbb670d475778",
+	"a55fe162b287bd6eebd6cf7e7aeea8672322d924ae42c7404ff89aedb98943f3755d2889bca488cc7000e6e9b8e7a0ef289273cd29c44cc600e330d1775e3cb767f12150e1615dca8c3f67466463a3ca993a1b788cf67a7a35b95dfff954206eb5ea1e1bf7fb06482a551625b5c9fd9a86e8414c8cf79d3a14104a153cbe04aac5172aa4c4a89349f5856c4262dd1d7317a7544c9afbbed449e7dcc2b58d9df6c9c9ed3883e42e80f5c2433550f30e73c7bce0fccdd880adc19282a392dae26a0108e7faf168cfc15937aeb046d60712603286b8ddfb27916b79242d56f1",
+	"2bd6976592408cdbc4e41dcd3ecfbb786775ddedef914d9058e6753f839fdfe15b17d549dbc084aa6cdf3befa0158aa84c5d58c5876144fd7e6c41ab7d42419d0dd353732e0e6d3fafc4f5626c07433390a4fd467197e85b5de7e2cf1c26cc575356adedcc0740008523b503df12ff571387726c5ccb280376d19cbacb1d7ce7aab8b13292c6a8b8881e949cbf6d4610d16ebba1d46cdb8d0459596e0aa683d0307bd926e14de19b9bfeaefa29d91b82248604673a455520cbb64eef3f38cfad8e126a3b1cfa1aaba53a784c8ae0c50279c0ecdab54095d36f67ace9b8ebbb",
+	"71913ae2b1c8729ed6da003c24a1d4f96e28d7faf55ca14ee0b2865282b9b61103ce6ee0b00b00aacf2081adedea5616f9dfd22c6d6d4f5907bcc02eb33edf92de0bd479794f51246d9b612b4543f6ff633c4fc83bfa6144c9d26721cdc690a3d5a8db54d8bc7873bfd32924eeb502810732b5ac2f1852bb021c401d26c39aa3b7eb09083093a9e89bf889b53383b5af61110aca1b9fdf38908c7d5a184fc5f46b3423a66a2749feb8de2c541c563987278dbd0513d99b732411012b5b75e385510de5f6839c3797dc094c9501d5f0504b06b43efb6e746f2129ca189c1da424",
+	"9d048a83294de08d3063d2ee4b4f3106641d9b340a3785c076233686dd3382d9064a349c9eaa78028d35652078b583e3f708e036eb2ced3f7f0e936c0fd98f5d0f8aa91b8d9badef298bd0c06843831279e7c0c67ca7e572f552cfdd984c12e924c08c13aeec6f7e13d161785546ebfd794b5d6a92a4744e52c4cab1d0df93b9468be6e264e8cfcc488f9c3c1817cbe501f4b9cc5999483b7433aea777226b25273a6ef2331b5f3b6db8091591e8e276015da3ef78bb2ee0526ffe23def2d8d193cbe594e8ced1f3d216fcedae2a1eb288da82e34cf98aebc28def658ee0849ae7",
+	"3251c96cbf82ee2e5264528c0b6cdfc23d20e1eb2d6441b5d62f0fd24c692a0d45a8bc8aac32884b7141ac0f4f113ec9fc7f6b4db3d696374177f9a42d602ca471275b928f639105a55b846da9ac7274cc37de8c38541f6895f94d72a81e117844b46601c201f7189b935a96e42505f2098ac985d92dfe86349a706ef6325b3c2e4060ced3c453e68ed09e043bcc75846b80118dc53530248da250fb57922d0afa53a7b2c89161aa4fa372a46b2a8e1307741cecedf585d2f998a9d496763800b6965c38a5d8aa566c709f13699c8185ab4fd8fdc8b824f4dd6d1c255b4788f50574",
+	"2de31dbc8a012254586f3229d3524fc529554e98850d30acdfc11406bba6a142029126ac165ee90b2de7509fc3571a8ee12e16b05054eb8baea879d135b39627f0d8331be3e66bc720c2096ce74e437daebf3bc53d8f2ccc228c3256d3edb6e9ae7c354a0c9350e6d663a9a30630bf9da3d96b96608a2a171ae28105714058b6c4b38a36c56561c4612c32aad25c65b7fb6faa4e4ecd44ebf9b2fad42ff9a807cda2581614fd30d41a7436069399b8d4f062a37a5bd4066a93d541fa5797a7d3e7dc9c4c40f0bbf5256f71613240f9ef128b3423eacaf428ada06b6a531f835281e4f3",
+	"07dadee629a08223dcd7ec441287b4c5e26347451d9c003e3a8496b4ea313b51126283a6720d7851e24423d9c9c818b4601247178f38a61f45fd4c8596d79529d416834226666a2c8552bbc901cc5cc3406a18fc88077fea52e1b620748553052ab7788c0d025b095b736fbe714cb3a968ec16b5917652eba2d7cf32ef3140d6c27b25d053e9786d24cd09a5306a0ef55e46201faa6196a91084267d7a7b5ca57c2efdeb2cb97d682d2a191b915553c8933f1d1b7faf0b4a1d83ef611f1e44438bc1c3d860fbfd12b5f26e5a6889a31ce26ae6a55c7a563b5816d113423ef3f25fa9befc",
+	"1d94166bb387526d519c4ce150221954da8930f66765fe6a5504e30a69962d595cfdd07a82c003843598864261f053bdb6f5086d516c261e089caa89990f0967605768ae9200bdfe4dcd7b77a93265cb33d9851a2a1036113c732bf3f37534530641300f0620de5c16101e16f4baf39d9fcbfcb01c52afce0992c329d8dbb438c314eee995c5020611d6f889e06b8a032785cba9a415580dbf752b5e510523c89f478cc6f047bd926f51e4a965c9749d1e76379c0e7e5b56803893bafaa4d2892b4c52f143b2fa777cd1035ea418684b8019df084f9a3f1f768753096621f342895c510d01",
+	"fc0073f199ed8a1d6edc8e7bdf182670003108d82b283aba82326e856f8de378987a03d0fe8d2041440fd29d51c63796aab44090d2b14ee00859b3a08cbe88f724badcd3c401226c5db8b307b8deea5be305412b080e9f99cf79d6d08d3646f347a7afebb62912e3e246e2e726f9aec5c101d916e47f984507b1d65d313697256c77da7eca3bc5811c87bee02a2826cefff0d92bae989609aaf95d70561b40d98474c37277c884aed887a1606d206b11e8a8a71d1f1d19319557b57351228ff0404be700a6cc56c0a30f3d4b7a0a046463fdaf19e7d5f59e155f378e35baa33db1e881f2207f",
+	"f42a6a91278d6a076feba985b1cf4ce0af1fa9d6d039c136e8971e665ff088a10b6b9a379a6f5526fc5957773a0ccb8972a4a19be0745ac13937030a54b18dee4f4c5df47a58a33a7516b90e646e5da999166ab0e52f457f7c9b7e391836a687eaae37b377e59a4c995ab0c57162c307ab951a9ba6590f429cd27250e7010eb794ec1b1ec35f8aad189b2fd3e8aff24d93601d91a4884e6f84b02757ce7620a02901519fccfda52f68ad6df709d112a9c25d66bcbb9622806427ca8b8d346b6db05874bde800cde9cf17df4b05baab0f133febd1ebbb053b49c109a7f5b1f864a304d10288e2f0",
+	"bbcefaf4a0739509f8a2f831c954071aac52e60cfa882a867b8b910dcf7edf92e1c0692bb027bc378c460a01cb6ecc8f2a012dd84ee5a678cd497b1457b6d393421fbee98ff544fc7eba24cbc3aae506254d9a2d74dde74437ce4c8a69010718506bf4c5943342a942e5e2d3406a3016280b6e37954c5d5e763346251afb0b746cad68cac757f9df765e092518729cfb9a5e76300c124e708ca33591a369767ffb63933cb72fba67beb2223d98984d0b75eb5d1a38615913747b520b3d613c715c0c77d2987bb88f3c419bcc5d38573cf4a8a4f550b2d876f05ca252d88c70a561d869a5018b32f7",
+	"dc2437010cb05d9cab2af5c275e1d2acd627ce19fb86355df91fb8d059e60d591663c8eb077d48388c9a321057a98136f49f0098348d9f29d808936f98bb1787c7ac75fb14f6076dfd2de5b59b1fa4848cabaa9a99a091dc24b561911c392ecdbe53f4adae82b852d830adea3a10490c908e337ce0a6d12354ce05a37ad3a06696b66820af8a1f67e6287533fd6f38a5f6ad1c6b078c08baf2c37d2683af01e6a5b33796c8ae48935a888f9bd265f4f11a4e27c433b8b1c9afd140bcd21a07e24378ad6badde8e47c57e3340f49e2406e8d49afadd65eaaa4c3d078c27d7e42118cb86cd248100a356",
+	"6c290db326dd3152e6fa9b9c0cd7d49e50a0221b96e32f5f34a8cb7d0c2edd3e937a7d025d6999b7b468add4d6894d8f7aceaabc18f4d9c171f1fe95ea1ae8570382a8450fbc595d95b1f51d24e1abc2970b0e1d20ca40aa21bdfb3656adf2f19882eda606f5ef1c03174e1d94c8d12f0fee8dce6852f42a364eeafa27a7971d4379405db8e46baac4d685b969238e5df06292a6c790bf1994a051b038e1d8db91e1bc4804f32443781c34a552ed2e8100cea374e77af56ba0e11c45990d3ba68df9087b1f4968cbcbb1c42f99b7267c76af926ff3134e093df28fab039cad420c6b70f2d9b5e678c155",
+	"ac724a22ebabaedbbb052953e3c264a4b6440f313bad501cdc1484b64f33402a2230898776db5c818c28035ffae6ea24abd04b7159e42159833903a0c23a7c564f7645e49ddedb748fd9e51bd6cbf2eced98caaa35226970f003ce1fd260ac5795e096f1c04aebf8fd36e5e2adeea929b5e963a3cb71d6b55c85bb7d3a2b03a7e74b4416de8fa68950168d7c3ae8ed2e29bad1e8a182a7c5418e5d564373163778cd3c34e9d320eb1a60480a8f98b12e0026cbd7752e6079812e3767d9f55f3f10b8c214a6eceb2a58954091a06b33862af171a9b60bf2c6a44e8766e6c56e98092c56f2a8510f6d05c103",
+	"8c70114f7cffb375c2b9a06e27297a5c32418b2daf68af5bbedcc7106edbc070e764bf40c1f8eb15079e2ab77f898afff3490108ed9afb7ea9cb05df41d263be0e42d2321d3d2656622d7bd232bf68d37375fe7314b09cba66f19c8b59424198ee69e7a9f3de0ecce0685127807ce336fa479ccaf7aa1ebc4e406271ce6c4923ec36093516498cc227f9218869346c80ba5ae83e023aca0ae2bc86b5bf5d115a4616b6587cb869d92f8c780ab70d5766de07a204af5e1c8dbba622516d2e911b36c82e4687e4d258ea616c07f76ff0baa376c8d5975cffac0b25817f779ae3ce88b72eb47e378484ce999bf0",
+	"0733d59f041036398233fd47a84b93f6778ae5259ef5d62aa3b9faedec34c7edb570c18b2a5d2c4c55cf656d98a1ae396d45a3b746b7ad6f07312c3d05d1a50ffa90bcdcdba105e25b7b0c52664223f8c2476925d46dc6ea2406ded7d0b0b292f6656cebcc7616cfa4b82aec68b35d1da67f6ed2bf0171849d6bb65128d8a140ea5cf97f1003f8d7093bee077be78def4f7bd2caccbf0644f26b26285225142c40038484c3bb9ba9597744f4389e76dca3eb695c33ccc621cab1fb603cb3535a0ad318d220385d5e94f8674f3d55e97e097f8d5c049e911946afbfce783819951d65d6bff4567dc951390d1aaa",
+	"398ddbba3dcb5642c102efa841c1fcdaf067062e7eef8e2ee0cd73d7f77e57372d6ee1a9b7b6f86ad12d575001ae71f593449cb5a476c6bfeddaa2af0f9239c1d7effdedf66ceaf413707b5ab9661a7cc0ef8cfe4d1651579c4f0f64e2d12a52653c54f2dd60864e769eab8a627c89c56ee93365d031f0d2523cb95664b1575d51b122f33c9e94de75432a690658c977b68aa5b721a393f9b9b3b612c10e920a7d510c6d8460b35f8614c42f5d2c241a01b28105aa7c1b521ac63ebbedafac6d5a38c898e8590f918a1927bc53aecc2b1c8b18d7df9107c6997d9b3fa4b0bdb1c603da619d9e75670b97a5b40f06",
+	"ef07bbc7c4150dd47f8c69a7989948fe831dc798b0424dcd6551bfa8e88216095a7e5d720909bf3d23526b9ba464b66ff6b63a7337c31451ab9a15f04ead809a62bb52206237de77597a730106d02d227dd6099ea9ee2a92cdc446ac3b9d024e32255adb3e9b56b561c431e0b5a721f0336f19568a5335d0ebc6c73ed8ff2c15e219477d9e4b67f2928e251f8a61a2848857e037d010806c718ab062967fd8e85f3722252957923f5f9005aae47b4b1b3fa464e3ba9df573a56055f17e903126fbbcb6cb96de92fe617c97f84ef3ba0d8f2651dc4aa80c157f372ae1bc02e5067ad076f3fe48bb72c0f3c99273f82b",
+	"c7076986d2333f3a6752adf11f1a9e5c6bc4755f341073cc86a9c7519c8db029d5ae833fdf3fee826ff4692c57880c5074620ea97c00f1dde1e8a0f18501627984ded4d1b5c4af35be5cc1bcc868060a49a968dc0547acde490b4c68d79924a93a986aa0ad060c7de706e8a99ce8f84a4f8707b52a8ee122b763ba580d6b1f35f6af25094c69f49247da96c836991851ad36f60bf577863d7471608a012afa7a56656abeee7cd9b4f1f4d9d13a8526c0f33cd251caf7486639e787250390e7e488e9ec311fc3d847a7266cc59bcc2bc34192554aa57cf25db10ce04bdabef3fde6db85f55195ecc2ff892b2e268ebea6",
+	"01789f40d42d8d3e4a416fd9ae7de78c3a30507809eda200e1afaaf8d7020cd1fad18eba62d821946f220506cf105ff0e2069a771a2c233714afa6b2f695497e4b95c9693dbb93ec4c9a14720676aa87ee31dd34e4e081756477032b4a57b328285f2cdec1b269754c474936927e93acc26012aff1bb36f30c2402aca0a9b9ce9568f5000e2c934263933b436c94f8d6589c89db7edabc5d03a8fe795fe50c5166beab64ed7c22662b984ae2c66dbe4c090b0df603b27c759278f8d66859afea3f6a8f02c2c2a2202b9fc29132256f164b5050a803b43688dc4c9ba86374a3522afba5d1a19bb3820b883aebc267627095",
+	"2c61944bd6a50da00ebb951d2b67d79fc6b6fb5aca83b1de3dbd7690ab756bb1e1a21051ccf1e24136ac8ccb42a2ee10be94d2cb9289d5f52b6f90e9d07a3478f36a1eb7d08c3dec52ca154fd1427ba92a4ecbe73a71bceafbd26e9a39d50821e2876d3a0c0e6e373b9795dbf72ea29cc439ff42706be798c90d4617b39c90ec84bf9fb699dc8a9a34e25d81759d6c57df45efb1d0d68aa51278564b99633ed5dc464bb7d53c5c21f798f33bcd868657ecfe75a1ed8149d394b398969ef624831b30f1458465bfd2fdf3f284f2ffc54bf2817b5fab2e02056e864f78bb6fd870c64f3609dab218f25da8060f756e45121e79",
+	"942fa0c68cc72f69518a3a7aac0cde45bab0e928b5cb2bd24d049fc313f74b6afa87c4e34150484f3b5200163f8a6472d04777928ecc49319539fc17d71a38090f55a74f757fe45781a3c09f08dcd3dd4c73c8533a5e00cf8a86ebe77fe45be2848574f7c5d25e9a0632a60d2dd41febdbf987d2a0487e4a4ce6ed5f49f2d741a88ecac232b1498253fa4ee8147bbd0f600abdf295e81f7570015aac5fe6ca7bb4a99bb3fc54287106d7fc1132a574af49db82a7b9a5f33e193cde527ca2176c52cdab672165e0fe5720f71ada57ee90060aa069ae2a0bfe67c1b71b17c601c3c2224bf9891bc11ba216e3ebcb51fd95b8d7cb",
+	"0d68cfe9c087ec116fe7572042385159cc705960f842aabad1ed1387ec1697f4413a23c6090041328fedd4b626c6eeaac5b5a71acc1fd1bb8fbd228857ac5bd045c364be7a5a26338ff04c99c4c473cf445a891db6422d1bdef4533442df171643fc36a092fabb464298e4194c9e2950884de13d113ee24160a416404c16ddc5d2476cb3fb80da543e6ed9105f6003977acb34e1fdd2cbdf7a00d5ff84350b74ac231418c0d88269d02d824802791ff42a51cc835deb9869a6023f867f82ef6dc0bfb03e6dfa835646bb18a4074773486e308aa39e532aaea4e6fb35dcada7e060f8282c371ed26d22302323d4fd142a85534671",
+	"45e24b167a0bbef1bd8f79dd047763d0754f36a7b623f298059d177e8ac994945c37d2c4af06f01318960301595941124592f2995af1459d854339998d3ae17534df2d9793d6e203857d02c98a0cd88991e641b3e640090ba303f87b907dca8ca462fac19ad079b2c82ea5b521ab891b10138b083b3d9fa214a8fe60d1cb3599c5d199c61a2cfb7ee2f39e5a5abad5ac4998b707545f73e92128d21803420526d2598a53bb314adf29a0ef56b94bd2221601eb53ecb8540e8fffd38fba7bd827ef255e4ef55491475c0f383a241f81c72af4e1dbf2a65cd4d18a497615aa0de2791a3511a7977a8d4d41492bfa4085f2fd4e8f751d",
+	"1c1bb695ae90e6e33fc1e8b2a62ab98bf835ac7193440f2351c8cdd830472b637d2fd9c9013cb83caef506abc1c4f7567706db6046b1d184579c7a9223ab1b35e32898c70a3c27628123ffcfa518612f080a2c4a9f8e0a927a47dc98307d2b48de9d5dddcb5c82f0b0e4e610d44f1baa9bbbf7f5a727134680bb7d1327b73b52d8e5e36dbb53971e99e699d79f75a3fc01316bd7012947d119d6aeb7f75b8fbf0479c03002148553fa0da450fd59d4f1bebc252caa11ed9bec5b6ef54279b5f8382b61cffc67ec03f4baa7ea476c31364b86aa8ccad9fd0818717f0ced2dd49477874b4341c602d7a1beab860eb476c7e3ce597e6926",
+	"7a3cd9bb2277e2c7f1134fe7233f0f7883c2db9fba80aa5742b03041de0fe589d9e5ea84470dabf41bb66816f3e33ebf19a0ca5aba1004cf971249b258ff26a98dbd0c37ec6cd574854109433357720040bafed4531e0079186b1e853e0ced35d08d27f6d732ed6e2c6651b51cc15c420a24f2dc36c16ef4b3896df1bb03b3963f9aaeb02a48eac5772abd5948c2fd0db2bb74e3351e5eabd681c4f413655bd94dec96b1544c1d5d2d1df4bdc26020d25fe81d5238de824687a5505e1fbe08d11b3924b3ccc070fd225bf01eb79e3d21f7b62a836cd3bcc11c931669c37613470e356143df87c48848a829f5e018973a5db88eb6c60203",
+	"3f158afd0733fcc5dfe1efc2dd4eada732f942af734ee664955bb1ba613eafd0f349e7554a14d68200c62d8f2dca2ec8b81c8350735eaf437041f78b452598825b6899560963ade66a0fc74ad01f8343d1d19c7bb327a8dc14ffdb1c42fa72b2970d9155e2da6a2e6419d4117842d826ff38ffab9617307a0283d3ea28c8104ad9a6e087bb750ed1d10fd8f7100b1663682e979d80e43968c33d9eff66f4d1344e583ee521e78d0a2193c0577516b978339c143bfc689bc744bbc4a9163063de82c9706384b6b385e54666c86b34f23c1e25be293af06092ca31d857e11e5b2caf0d19dd3afbe85380878eda76d718b4bb869c67e044e242",
+	"a177af4387b9bfa3d59e97ee7b0ff5f4ae4a326fd9204c8d28831a67fcc385ee6c4828247b16d11aea9bb8cd9e6c4d2876c6b2fa6d5041ad39e1b04039071e29c4d86417e7eac4fc7d3823958a021823e2c880a757dfbcd0c8196371db5bbfac15e4d1a0596508b6d26f8c4a664924c95082d173f817995b44c4285d625d9b2f56c86632fe1295c5a8a7a3760028072bcb07bc245a705e7174d06b9d5c0c8ca495b9ac218f1921fa63f2db3fd148f07545366d008fb5aead7497d902b91fbaa39669929d4ae9d07df8557f1f0aed7b51252f10c6606e5ff3ede1327530ca356b4896ecf14bf7322d77fddfbe28d52f6de7f66eeb81704c87e2",
+	"01a15b9018e35cc342c926b01d03ad9db4993a6bf92e0555969fee90033f28f3ec234c1268b11b040dfa0770d4ceb39edfeb8ee6a589f4eebcc08d2d1b0a1a52953aa26eb44fdf4a2743c3dacb212a0c0f325572f645f53027b6f3c0c55abaeb1b0918c89bedcb5028f094d743ea354f8ff553c45f111a8fd5a14a4e5c835164747d302472e19a67da04b4c8e39756a9d248ce14d1ed43de75aca86850f2455eccd4639b2af035bb3f504cc9065d091c1c47e036083cb3fc50bf39292b11737c7ce0b49673ba93981de304dc65a671775b6ff927e3ff93850b214fffb5792105a4bdc81354d5b09e84afbdd1792b8fb4e9d0ae3dad2492b03282",
+	"24f07ae31279ceed18ec6d35990f21200934ad6b132c6c62e82fe92a40a0e60a5bed10720eff5a1f728971888682772b2d9060d4fee88f37d0824e7384dddcc549475f0e1a44eda4804778b62febe46e04657a20577ee70acb3425e334881eebd8ddf714ae8c527ea747e3367de384e595a43b299b6bb3f6b0a4716cf90038e0f75a47d5057d7fcc3c8a8f9224992c67f8ae0d3251ea09a24aed9ce57ab637f6b3cbb7083df62b6287f64d0877984c4249d113bdb2b07865082aa24cd7ec07061b17de320f51f29f25b82d7073d369cf2dbf96310c0c311997911b2cc02f606f9cd99663c57e78499192a2a78f9c9fa67013e0f9817287faa69b22",
+	"4aeb32bf9d050f10bea18d9f71b4afea7bd08550e574e7d50df234c7413668b297b6721d7a0f0bdcdcceb2f55adddea28cd59bd44be0c5ec067039e428706caae11f565d961ad6e7f4c51b0aed6d05cc5b8d826c4b9c39daefb6c7da46dce619a359dc9ce215a215218fa8d54ee0b4f301b6c201c7c2c5f7cb1c6e0cb76ba6c6e8f63ef7a5213d550b0d0857fa0ff9e3e38e497161617413ac066e2fa539520233193a5cb7baa0c2cb20b45e56bfed2c40a9544d1f230dd0cd6d4976e7cf51da8a13200c3957c0154c8237b2931ce19b824963ac576ea49b548cc6aa85c47796b470fb2c6308d88f390bb13607e294c84a838b2713b14ca6a5e8bcee",
+	"77e607478be5502432230c913d9ec82f967d87c0ee169a74076f989648853eca693277287f8a5b306bc94dfdbf64ca5cb5dfc0bc498589d51a691b8d57d4b0a9ee247d038fe1b5571183be3e75c37045bf1235863ff1b84b208c10e7f1a5ba54ff36af5b2870129867164d013e0a6d2cc067a3509bba2f46390302c80b651cf590ef69aad8effd94cab28a9b44be6a38b58cfc47c9c725d6fa467894163383b6873d10d263b1cbbad932ded59ab503920267ac026726f794a335a88f6ef564f8968c6fa6f5d3ea161eb6062ca349b9a0e4038273399cfa297a6b07ceda1ebaa99c9de2d935ee230a08c5a488ad46f3393243371d40916b8063cac9da63",
+	"50957c407519951bd32e45d21129d6b83436e520b0801ec8292d79a828106a41583a0d607f853dc4410e0a1427f7e873455a75df065cfc6eef970f7e49d123b346976460aadd91cf513c140c356442a84656904a8b1d708dc6089db371c36f4fe059c62302eaab3c06c0cb3b429961f899dcf99798464b8571a440cac7a52b495f32417af6bc8f58adc63647531f804b4e96273b29b42434c1236bde80ba3744fef7b1d11c2f9db332b35bc25123338ac9a0796aac213c9709b3c514ea7ecd80e22d3d8a74f28c8194418a6e1ff30714d0f5a61c068b73b2ba6cad14e05569b4a5a100da3f91429d6e3ffee10ceea057845ec6fc47a6c5125b22e598b2dc",
+	"f2273ec31e03cf42d9ca953f8b87e78c291cb538098e0f2436194b308ce30583f553fccb21ae6c2d58f3a5a2ca6037c1b8b7afb291009e4310a0c518e75314c5bb1e813bf521f56d0a4891d0772ad84f09a00634815029a3f9ad4e41eafb4a745e409ef3d4f0b1cf6232b70a5ce262b9432f096e834201a0992db5d09ffa5cbc5471460519a4bc7cdc33ae6dfe6ffc1e80ea5d29813136406499c3514186ced71854a340701519ef33b6c82ca67049ab58578ff49c4c4fbf7d97bfec2ecd8fbefec1b6d6467503fea9d26e134e8c35739a422647aaf4db29c9a32e3df36e5845791fdd75a70903e0ce808313a3327431b7772567f779bbaee2e134c109a387",
+	"5784e614d538f7f26c803191deb464a884817002988c36448dcbecfad1997fe51ab0b3853c51ed49ce9f4e477522fb3f32cc50515b753c18fb89a8d965afcf1ed5e099b22c4225732baeb986f5c5bc88e4582d27915e2a19126d3d4555fab4f6516a6a156dbfeed9e982fc589e33ce2b9e1ba2b416e11852ddeab93025974267ac82c84f071c3d07f215f47e3565fd1d962c76e0d635892ea71488273765887d31f250a26c4ddc377ed89b17326e259f6cc1de0e63158e83aebb7f5a7c08c63c767876c8203639958a407acca096d1f606c04b4f4b3fd771781a5901b1c3cee7c04c3b6870226eee309b74f51edbf70a3817cc8da87875301e04d0416a65dc5d",
+}

+ 178 - 0
src/golang.org/x/crypto/blake2s/blake2x.go

@@ -0,0 +1,178 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blake2s
+
+import (
+	"encoding/binary"
+	"errors"
+	"io"
+)
+
+// XOF defines the interface to hash functions that
+// support arbitrary-length output.
+type XOF interface {
+	// Write absorbs more data into the hash's state. It panics if called
+	// after Read.
+	io.Writer
+
+	// Read reads more output from the hash. It returns io.EOF if the limit
+	// has been reached.
+	io.Reader
+
+	// Clone returns a copy of the XOF in its current state.
+	Clone() XOF
+
+	// Reset resets the XOF to its initial state.
+	Reset()
+}
+
+// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
+// the length of the output is not known in advance.
+const OutputLengthUnknown = 0
+
+// magicUnknownOutputLength is a magic value for the output size that indicates
+// an unknown number of output bytes.
+const magicUnknownOutputLength = 65535
+
+// maxOutputLength is the absolute maximum number of bytes to produce when the
+// number of output bytes is unknown.
+const maxOutputLength = (1 << 32) * 32
+
+// NewXOF creates a new variable-output-length hash. The hash either produce a
+// known number of bytes (1 <= size < 65535), or an unknown number of bytes
+// (size == OutputLengthUnknown). In the latter case, an absolute limit of
+// 128GiB applies.
+//
+// A non-nil key turns the hash into a MAC. The key must between
+// zero and 32 bytes long.
+func NewXOF(size uint16, key []byte) (XOF, error) {
+	if len(key) > Size {
+		return nil, errKeySize
+	}
+	if size == magicUnknownOutputLength {
+		// 2^16-1 indicates an unknown number of bytes and thus isn't a
+		// valid length.
+		return nil, errors.New("blake2s: XOF length too large")
+	}
+	if size == OutputLengthUnknown {
+		size = magicUnknownOutputLength
+	}
+	x := &xof{
+		d: digest{
+			size:   Size,
+			keyLen: len(key),
+		},
+		length: size,
+	}
+	copy(x.d.key[:], key)
+	x.Reset()
+	return x, nil
+}
+
+type xof struct {
+	d                digest
+	length           uint16
+	remaining        uint64
+	cfg, root, block [Size]byte
+	offset           int
+	nodeOffset       uint32
+	readMode         bool
+}
+
+func (x *xof) Write(p []byte) (n int, err error) {
+	if x.readMode {
+		panic("blake2s: write to XOF after read")
+	}
+	return x.d.Write(p)
+}
+
+func (x *xof) Clone() XOF {
+	clone := *x
+	return &clone
+}
+
+func (x *xof) Reset() {
+	x.cfg[0] = byte(Size)
+	binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
+	binary.LittleEndian.PutUint16(x.cfg[12:], x.length)    // XOF length
+	x.cfg[15] = byte(Size)                                 // inner hash size
+
+	x.d.Reset()
+	x.d.h[3] ^= uint32(x.length)
+
+	x.remaining = uint64(x.length)
+	if x.remaining == magicUnknownOutputLength {
+		x.remaining = maxOutputLength
+	}
+	x.offset, x.nodeOffset = 0, 0
+	x.readMode = false
+}
+
+func (x *xof) Read(p []byte) (n int, err error) {
+	if !x.readMode {
+		x.d.finalize(&x.root)
+		x.readMode = true
+	}
+
+	if x.remaining == 0 {
+		return 0, io.EOF
+	}
+
+	n = len(p)
+	if uint64(n) > x.remaining {
+		n = int(x.remaining)
+		p = p[:n]
+	}
+
+	if x.offset > 0 {
+		blockRemaining := Size - x.offset
+		if n < blockRemaining {
+			x.offset += copy(p, x.block[x.offset:])
+			x.remaining -= uint64(n)
+			return
+		}
+		copy(p, x.block[x.offset:])
+		p = p[blockRemaining:]
+		x.offset = 0
+		x.remaining -= uint64(blockRemaining)
+	}
+
+	for len(p) >= Size {
+		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
+		x.nodeOffset++
+
+		x.d.initConfig(&x.cfg)
+		x.d.Write(x.root[:])
+		x.d.finalize(&x.block)
+
+		copy(p, x.block[:])
+		p = p[Size:]
+		x.remaining -= uint64(Size)
+	}
+
+	if todo := len(p); todo > 0 {
+		if x.remaining < uint64(Size) {
+			x.cfg[0] = byte(x.remaining)
+		}
+		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
+		x.nodeOffset++
+
+		x.d.initConfig(&x.cfg)
+		x.d.Write(x.root[:])
+		x.d.finalize(&x.block)
+
+		x.offset = copy(p, x.block[:todo])
+		x.remaining -= uint64(todo)
+	}
+
+	return
+}
+
+func (d *digest) initConfig(cfg *[Size]byte) {
+	d.offset, d.c[0], d.c[1] = 0, 0, 0
+	for i := range d.h {
+		d.h[i] = iv[i] ^ binary.LittleEndian.Uint32(cfg[i*4:])
+	}
+}

+ 21 - 0
src/golang.org/x/crypto/blake2s/register.go

@@ -0,0 +1,21 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.9
+
+package blake2s
+
+import (
+	"crypto"
+	"hash"
+)
+
+func init() {
+	newHash256 := func() hash.Hash {
+		h, _ := New256(nil)
+		return h
+	}
+
+	crypto.RegisterHash(crypto.BLAKE2s_256, newHash256)
+}

+ 159 - 0
src/golang.org/x/crypto/blowfish/block.go

@@ -0,0 +1,159 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+// getNextWord returns the next big-endian uint32 value from the byte slice
+// at the given position in a circular manner, updating the position.
+func getNextWord(b []byte, pos *int) uint32 {
+	var w uint32
+	j := *pos
+	for i := 0; i < 4; i++ {
+		w = w<<8 | uint32(b[j])
+		j++
+		if j >= len(b) {
+			j = 0
+		}
+	}
+	*pos = j
+	return w
+}
+
+// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
+// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
+// pi and substitution tables for calls to Encrypt. This is used, primarily,
+// by the bcrypt package to reuse the Blowfish key schedule during its
+// set up. It's unlikely that you need to use this directly.
+func ExpandKey(key []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		// Using inlined getNextWord for performance.
+		var d uint32
+		for k := 0; k < 4; k++ {
+			d = d<<8 | uint32(key[j])
+			j++
+			if j >= len(key) {
+				j = 0
+			}
+		}
+		c.p[i] ^= d
+	}
+
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+// This is similar to ExpandKey, but folds the salt during the key
+// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
+// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
+// and specializing it here is useful.
+func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		c.p[i] ^= getNextWord(key, &j)
+	}
+
+	j = 0
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[0]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+	xr ^= c.p[17]
+	return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[17]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+	xr ^= c.p[0]
+	return xr, xl
+}

+ 274 - 0
src/golang.org/x/crypto/blowfish/blowfish_test.go

@@ -0,0 +1,274 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+import "testing"
+
+type CryptTest struct {
+	key []byte
+	in  []byte
+	out []byte
+}
+
+// Test vector values are from https://www.schneier.com/code/vectors.txt.
+var encryptTests = []CryptTest{
+	{
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+	{
+		[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+		[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+		[]byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
+	{
+		[]byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+		[]byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
+	{
+		[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+		[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+		[]byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
+
+	{
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+		[]byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
+	{
+		[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
+	{
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+	{
+		[]byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
+	{
+		[]byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
+		[]byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
+		[]byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
+	{
+		[]byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
+		[]byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
+		[]byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
+	{
+		[]byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
+		[]byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
+		[]byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
+	{
+		[]byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
+		[]byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
+		[]byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
+	{
+		[]byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
+		[]byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
+		[]byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
+	{
+		[]byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
+		[]byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
+		[]byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
+	{
+		[]byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
+		[]byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
+		[]byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
+	{
+		[]byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
+		[]byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
+		[]byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
+	{
+		[]byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
+		[]byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+		[]byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
+	{
+		[]byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
+		[]byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
+		[]byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
+	{
+		[]byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
+		[]byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
+		[]byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
+	{
+		[]byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
+		[]byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
+		[]byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
+	{
+		[]byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
+		[]byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
+		[]byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
+	{
+		[]byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
+		[]byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
+		[]byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
+	{
+		[]byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
+		[]byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
+		[]byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
+	{
+		[]byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
+		[]byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
+		[]byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
+	{
+		[]byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
+		[]byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
+		[]byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
+	{
+		[]byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
+		[]byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
+		[]byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
+	{
+		[]byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
+		[]byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
+		[]byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
+	{
+		[]byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
+	{
+		[]byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
+	{
+		[]byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
+	{
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+		[]byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
+	{
+		[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
+	{
+		[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		[]byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
+	{
+		[]byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+		[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+		[]byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
+}
+
+func TestCipherEncrypt(t *testing.T) {
+	for i, tt := range encryptTests {
+		c, err := NewCipher(tt.key)
+		if err != nil {
+			t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+			continue
+		}
+		ct := make([]byte, len(tt.out))
+		c.Encrypt(ct, tt.in)
+		for j, v := range ct {
+			if v != tt.out[j] {
+				t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
+				break
+			}
+		}
+	}
+}
+
+func TestCipherDecrypt(t *testing.T) {
+	for i, tt := range encryptTests {
+		c, err := NewCipher(tt.key)
+		if err != nil {
+			t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+			continue
+		}
+		pt := make([]byte, len(tt.in))
+		c.Decrypt(pt, tt.out)
+		for j, v := range pt {
+			if v != tt.in[j] {
+				t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
+				break
+			}
+		}
+	}
+}
+
+func TestSaltedCipherKeyLength(t *testing.T) {
+	if _, err := NewSaltedCipher(nil, []byte{'a'}); err != KeySizeError(0) {
+		t.Errorf("NewSaltedCipher with short key, gave error %#v, expected %#v", err, KeySizeError(0))
+	}
+
+	// A 57-byte key. One over the typical blowfish restriction.
+	key := []byte("012345678901234567890123456789012345678901234567890123456")
+	if _, err := NewSaltedCipher(key, []byte{'a'}); err != nil {
+		t.Errorf("NewSaltedCipher with long key, gave error %#v", err)
+	}
+}
+
+// Test vectors generated with Blowfish from OpenSSH.
+var saltedVectors = [][8]byte{
+	{0x0c, 0x82, 0x3b, 0x7b, 0x8d, 0x01, 0x4b, 0x7e},
+	{0xd1, 0xe1, 0x93, 0xf0, 0x70, 0xa6, 0xdb, 0x12},
+	{0xfc, 0x5e, 0xba, 0xde, 0xcb, 0xf8, 0x59, 0xad},
+	{0x8a, 0x0c, 0x76, 0xe7, 0xdd, 0x2c, 0xd3, 0xa8},
+	{0x2c, 0xcb, 0x7b, 0xee, 0xac, 0x7b, 0x7f, 0xf8},
+	{0xbb, 0xf6, 0x30, 0x6f, 0xe1, 0x5d, 0x62, 0xbf},
+	{0x97, 0x1e, 0xc1, 0x3d, 0x3d, 0xe0, 0x11, 0xe9},
+	{0x06, 0xd7, 0x4d, 0xb1, 0x80, 0xa3, 0xb1, 0x38},
+	{0x67, 0xa1, 0xa9, 0x75, 0x0e, 0x5b, 0xc6, 0xb4},
+	{0x51, 0x0f, 0x33, 0x0e, 0x4f, 0x67, 0xd2, 0x0c},
+	{0xf1, 0x73, 0x7e, 0xd8, 0x44, 0xea, 0xdb, 0xe5},
+	{0x14, 0x0e, 0x16, 0xce, 0x7f, 0x4a, 0x9c, 0x7b},
+	{0x4b, 0xfe, 0x43, 0xfd, 0xbf, 0x36, 0x04, 0x47},
+	{0xb1, 0xeb, 0x3e, 0x15, 0x36, 0xa7, 0xbb, 0xe2},
+	{0x6d, 0x0b, 0x41, 0xdd, 0x00, 0x98, 0x0b, 0x19},
+	{0xd3, 0xce, 0x45, 0xce, 0x1d, 0x56, 0xb7, 0xfc},
+	{0xd9, 0xf0, 0xfd, 0xda, 0xc0, 0x23, 0xb7, 0x93},
+	{0x4c, 0x6f, 0xa1, 0xe4, 0x0c, 0xa8, 0xca, 0x57},
+	{0xe6, 0x2f, 0x28, 0xa7, 0x0c, 0x94, 0x0d, 0x08},
+	{0x8f, 0xe3, 0xf0, 0xb6, 0x29, 0xe3, 0x44, 0x03},
+	{0xff, 0x98, 0xdd, 0x04, 0x45, 0xb4, 0x6d, 0x1f},
+	{0x9e, 0x45, 0x4d, 0x18, 0x40, 0x53, 0xdb, 0xef},
+	{0xb7, 0x3b, 0xef, 0x29, 0xbe, 0xa8, 0x13, 0x71},
+	{0x02, 0x54, 0x55, 0x41, 0x8e, 0x04, 0xfc, 0xad},
+	{0x6a, 0x0a, 0xee, 0x7c, 0x10, 0xd9, 0x19, 0xfe},
+	{0x0a, 0x22, 0xd9, 0x41, 0xcc, 0x23, 0x87, 0x13},
+	{0x6e, 0xff, 0x1f, 0xff, 0x36, 0x17, 0x9c, 0xbe},
+	{0x79, 0xad, 0xb7, 0x40, 0xf4, 0x9f, 0x51, 0xa6},
+	{0x97, 0x81, 0x99, 0xa4, 0xde, 0x9e, 0x9f, 0xb6},
+	{0x12, 0x19, 0x7a, 0x28, 0xd0, 0xdc, 0xcc, 0x92},
+	{0x81, 0xda, 0x60, 0x1e, 0x0e, 0xdd, 0x65, 0x56},
+	{0x7d, 0x76, 0x20, 0xb2, 0x73, 0xc9, 0x9e, 0xee},
+}
+
+func TestSaltedCipher(t *testing.T) {
+	var key, salt [32]byte
+	for i := range key {
+		key[i] = byte(i)
+		salt[i] = byte(i + 32)
+	}
+	for i, v := range saltedVectors {
+		c, err := NewSaltedCipher(key[:], salt[:i])
+		if err != nil {
+			t.Fatal(err)
+		}
+		var buf [8]byte
+		c.Encrypt(buf[:], buf[:])
+		if v != buf {
+			t.Errorf("%d: expected %x, got %x", i, v, buf)
+		}
+	}
+}
+
+func BenchmarkExpandKeyWithSalt(b *testing.B) {
+	key := make([]byte, 32)
+	salt := make([]byte, 16)
+	c, _ := NewCipher(key)
+	for i := 0; i < b.N; i++ {
+		expandKeyWithSalt(key, salt, c)
+	}
+}
+
+func BenchmarkExpandKey(b *testing.B) {
+	key := make([]byte, 32)
+	c, _ := NewCipher(key)
+	for i := 0; i < b.N; i++ {
+		ExpandKey(key, c)
+	}
+}

+ 91 - 0
src/golang.org/x/crypto/blowfish/cipher.go

@@ -0,0 +1,91 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
+package blowfish // import "golang.org/x/crypto/blowfish"
+
+// The code is a port of Bruce Schneier's C implementation.
+// See https://www.schneier.com/blowfish.html.
+
+import "strconv"
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+	p              [18]uint32
+	s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+	return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, from 1 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, error) {
+	var result Cipher
+	if k := len(key); k < 1 || k > 56 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	ExpandKey(key, &result)
+	return &result, nil
+}
+
+// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
+// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
+// sufficient and desirable. For bcrypt compatibility, the key can be over 56
+// bytes.
+func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
+	if len(salt) == 0 {
+		return NewCipher(key)
+	}
+	var result Cipher
+	if k := len(key); k < 1 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	expandKeyWithSalt(key, salt, &result)
+	return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Block interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = encryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = decryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+func initCipher(c *Cipher) {
+	copy(c.p[0:], p[0:])
+	copy(c.s0[0:], s0[0:])
+	copy(c.s1[0:], s1[0:])
+	copy(c.s2[0:], s2[0:])
+	copy(c.s3[0:], s3[0:])
+}

+ 199 - 0
src/golang.org/x/crypto/blowfish/const.go

@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// https://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+	0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+	0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+	0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+	0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+	0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+	0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+	0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+	0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+	0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+	0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+	0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+	0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+	0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+	0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+	0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+	0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+	0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+	0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+	0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+	0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+	0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+	0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+	0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+	0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+	0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+	0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+	0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+	0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+	0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+	0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+	0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+	0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+	0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+	0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+	0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+	0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+	0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+	0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+	0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+	0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+	0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+	0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+	0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+	0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+	0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+	0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+	0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+	0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+	0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+	0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+	0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+	0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+	0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+	0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+	0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+	0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+	0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+	0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+	0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+	0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+	0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+	0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+	0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+	0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+	0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+	0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+	0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+	0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+	0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+	0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+	0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+	0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+	0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+	0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+	0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+	0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+	0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+	0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+	0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+	0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+	0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+	0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+	0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+	0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+	0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}

+ 416 - 0
src/golang.org/x/crypto/bn256/bn256.go

@@ -0,0 +1,416 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bn256 implements a particular bilinear group.
+//
+// Bilinear groups are the basis of many of the new cryptographic protocols
+// that have been proposed over the past decade. They consist of a triplet of
+// groups (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ
+// (where gₓ is a generator of the respective group). That function is called
+// a pairing function.
+//
+// This package specifically implements the Optimal Ate pairing over a 256-bit
+// Barreto-Naehrig curve as described in
+// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
+// with the implementation described in that paper.
+//
+// (This package previously claimed to operate at a 128-bit security level.
+// However, recent improvements in attacks mean that is no longer true. See
+// https://moderncrypto.org/mail-archive/curves/2016/000740.html.)
+package bn256 // import "golang.org/x/crypto/bn256"
+
+import (
+	"crypto/rand"
+	"io"
+	"math/big"
+)
+
+// BUG(agl): this implementation is not constant time.
+// TODO(agl): keep GF(p²) elements in Mongomery form.
+
+// G1 is an abstract cyclic group. The zero value is suitable for use as the
+// output of an operation, but cannot be used as an input.
+type G1 struct {
+	p *curvePoint
+}
+
+// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.
+func RandomG1(r io.Reader) (*big.Int, *G1, error) {
+	var k *big.Int
+	var err error
+
+	for {
+		k, err = rand.Int(r, Order)
+		if err != nil {
+			return nil, nil, err
+		}
+		if k.Sign() > 0 {
+			break
+		}
+	}
+
+	return k, new(G1).ScalarBaseMult(k), nil
+}
+
+func (e *G1) String() string {
+	return "bn256.G1" + e.p.String()
+}
+
+// ScalarBaseMult sets e to g*k where g is the generator of the group and
+// then returns e.
+func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
+	if e.p == nil {
+		e.p = newCurvePoint(nil)
+	}
+	e.p.Mul(curveGen, k, new(bnPool))
+	return e
+}
+
+// ScalarMult sets e to a*k and then returns e.
+func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
+	if e.p == nil {
+		e.p = newCurvePoint(nil)
+	}
+	e.p.Mul(a.p, k, new(bnPool))
+	return e
+}
+
+// Add sets e to a+b and then returns e.
+// BUG(agl): this function is not complete: a==b fails.
+func (e *G1) Add(a, b *G1) *G1 {
+	if e.p == nil {
+		e.p = newCurvePoint(nil)
+	}
+	e.p.Add(a.p, b.p, new(bnPool))
+	return e
+}
+
+// Neg sets e to -a and then returns e.
+func (e *G1) Neg(a *G1) *G1 {
+	if e.p == nil {
+		e.p = newCurvePoint(nil)
+	}
+	e.p.Negative(a.p)
+	return e
+}
+
+// Marshal converts n to a byte slice.
+func (e *G1) Marshal() []byte {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if e.p.IsInfinity() {
+		return make([]byte, numBytes*2)
+	}
+
+	e.p.MakeAffine(nil)
+
+	xBytes := new(big.Int).Mod(e.p.x, p).Bytes()
+	yBytes := new(big.Int).Mod(e.p.y, p).Bytes()
+
+	ret := make([]byte, numBytes*2)
+	copy(ret[1*numBytes-len(xBytes):], xBytes)
+	copy(ret[2*numBytes-len(yBytes):], yBytes)
+
+	return ret
+}
+
+// Unmarshal sets e to the result of converting the output of Marshal back into
+// a group element and then returns e.
+func (e *G1) Unmarshal(m []byte) (*G1, bool) {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if len(m) != 2*numBytes {
+		return nil, false
+	}
+
+	if e.p == nil {
+		e.p = newCurvePoint(nil)
+	}
+
+	e.p.x.SetBytes(m[0*numBytes : 1*numBytes])
+	e.p.y.SetBytes(m[1*numBytes : 2*numBytes])
+
+	if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 {
+		// This is the point at infinity.
+		e.p.y.SetInt64(1)
+		e.p.z.SetInt64(0)
+		e.p.t.SetInt64(0)
+	} else {
+		e.p.z.SetInt64(1)
+		e.p.t.SetInt64(1)
+
+		if !e.p.IsOnCurve() {
+			return nil, false
+		}
+	}
+
+	return e, true
+}
+
+// G2 is an abstract cyclic group. The zero value is suitable for use as the
+// output of an operation, but cannot be used as an input.
+type G2 struct {
+	p *twistPoint
+}
+
+// RandomG1 returns x and g₂ˣ where x is a random, non-zero number read from r.
+func RandomG2(r io.Reader) (*big.Int, *G2, error) {
+	var k *big.Int
+	var err error
+
+	for {
+		k, err = rand.Int(r, Order)
+		if err != nil {
+			return nil, nil, err
+		}
+		if k.Sign() > 0 {
+			break
+		}
+	}
+
+	return k, new(G2).ScalarBaseMult(k), nil
+}
+
+func (e *G2) String() string {
+	return "bn256.G2" + e.p.String()
+}
+
+// ScalarBaseMult sets e to g*k where g is the generator of the group and
+// then returns out.
+func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
+	if e.p == nil {
+		e.p = newTwistPoint(nil)
+	}
+	e.p.Mul(twistGen, k, new(bnPool))
+	return e
+}
+
+// ScalarMult sets e to a*k and then returns e.
+func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
+	if e.p == nil {
+		e.p = newTwistPoint(nil)
+	}
+	e.p.Mul(a.p, k, new(bnPool))
+	return e
+}
+
+// Add sets e to a+b and then returns e.
+// BUG(agl): this function is not complete: a==b fails.
+func (e *G2) Add(a, b *G2) *G2 {
+	if e.p == nil {
+		e.p = newTwistPoint(nil)
+	}
+	e.p.Add(a.p, b.p, new(bnPool))
+	return e
+}
+
+// Marshal converts n into a byte slice.
+func (n *G2) Marshal() []byte {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if n.p.IsInfinity() {
+		return make([]byte, numBytes*4)
+	}
+
+	n.p.MakeAffine(nil)
+
+	xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes()
+	xyBytes := new(big.Int).Mod(n.p.x.y, p).Bytes()
+	yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes()
+	yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes()
+
+	ret := make([]byte, numBytes*4)
+	copy(ret[1*numBytes-len(xxBytes):], xxBytes)
+	copy(ret[2*numBytes-len(xyBytes):], xyBytes)
+	copy(ret[3*numBytes-len(yxBytes):], yxBytes)
+	copy(ret[4*numBytes-len(yyBytes):], yyBytes)
+
+	return ret
+}
+
+// Unmarshal sets e to the result of converting the output of Marshal back into
+// a group element and then returns e.
+func (e *G2) Unmarshal(m []byte) (*G2, bool) {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if len(m) != 4*numBytes {
+		return nil, false
+	}
+
+	if e.p == nil {
+		e.p = newTwistPoint(nil)
+	}
+
+	e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes])
+	e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes])
+	e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes])
+	e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes])
+
+	if e.p.x.x.Sign() == 0 &&
+		e.p.x.y.Sign() == 0 &&
+		e.p.y.x.Sign() == 0 &&
+		e.p.y.y.Sign() == 0 {
+		// This is the point at infinity.
+		e.p.y.SetOne()
+		e.p.z.SetZero()
+		e.p.t.SetZero()
+	} else {
+		e.p.z.SetOne()
+		e.p.t.SetOne()
+
+		if !e.p.IsOnCurve() {
+			return nil, false
+		}
+	}
+
+	return e, true
+}
+
+// GT is an abstract cyclic group. The zero value is suitable for use as the
+// output of an operation, but cannot be used as an input.
+type GT struct {
+	p *gfP12
+}
+
+func (g *GT) String() string {
+	return "bn256.GT" + g.p.String()
+}
+
+// ScalarMult sets e to a*k and then returns e.
+func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
+	if e.p == nil {
+		e.p = newGFp12(nil)
+	}
+	e.p.Exp(a.p, k, new(bnPool))
+	return e
+}
+
+// Add sets e to a+b and then returns e.
+func (e *GT) Add(a, b *GT) *GT {
+	if e.p == nil {
+		e.p = newGFp12(nil)
+	}
+	e.p.Mul(a.p, b.p, new(bnPool))
+	return e
+}
+
+// Neg sets e to -a and then returns e.
+func (e *GT) Neg(a *GT) *GT {
+	if e.p == nil {
+		e.p = newGFp12(nil)
+	}
+	e.p.Invert(a.p, new(bnPool))
+	return e
+}
+
+// Marshal converts n into a byte slice.
+func (n *GT) Marshal() []byte {
+	n.p.Minimal()
+
+	xxxBytes := n.p.x.x.x.Bytes()
+	xxyBytes := n.p.x.x.y.Bytes()
+	xyxBytes := n.p.x.y.x.Bytes()
+	xyyBytes := n.p.x.y.y.Bytes()
+	xzxBytes := n.p.x.z.x.Bytes()
+	xzyBytes := n.p.x.z.y.Bytes()
+	yxxBytes := n.p.y.x.x.Bytes()
+	yxyBytes := n.p.y.x.y.Bytes()
+	yyxBytes := n.p.y.y.x.Bytes()
+	yyyBytes := n.p.y.y.y.Bytes()
+	yzxBytes := n.p.y.z.x.Bytes()
+	yzyBytes := n.p.y.z.y.Bytes()
+
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	ret := make([]byte, numBytes*12)
+	copy(ret[1*numBytes-len(xxxBytes):], xxxBytes)
+	copy(ret[2*numBytes-len(xxyBytes):], xxyBytes)
+	copy(ret[3*numBytes-len(xyxBytes):], xyxBytes)
+	copy(ret[4*numBytes-len(xyyBytes):], xyyBytes)
+	copy(ret[5*numBytes-len(xzxBytes):], xzxBytes)
+	copy(ret[6*numBytes-len(xzyBytes):], xzyBytes)
+	copy(ret[7*numBytes-len(yxxBytes):], yxxBytes)
+	copy(ret[8*numBytes-len(yxyBytes):], yxyBytes)
+	copy(ret[9*numBytes-len(yyxBytes):], yyxBytes)
+	copy(ret[10*numBytes-len(yyyBytes):], yyyBytes)
+	copy(ret[11*numBytes-len(yzxBytes):], yzxBytes)
+	copy(ret[12*numBytes-len(yzyBytes):], yzyBytes)
+
+	return ret
+}
+
+// Unmarshal sets e to the result of converting the output of Marshal back into
+// a group element and then returns e.
+func (e *GT) Unmarshal(m []byte) (*GT, bool) {
+	// Each value is a 256-bit number.
+	const numBytes = 256 / 8
+
+	if len(m) != 12*numBytes {
+		return nil, false
+	}
+
+	if e.p == nil {
+		e.p = newGFp12(nil)
+	}
+
+	e.p.x.x.x.SetBytes(m[0*numBytes : 1*numBytes])
+	e.p.x.x.y.SetBytes(m[1*numBytes : 2*numBytes])
+	e.p.x.y.x.SetBytes(m[2*numBytes : 3*numBytes])
+	e.p.x.y.y.SetBytes(m[3*numBytes : 4*numBytes])
+	e.p.x.z.x.SetBytes(m[4*numBytes : 5*numBytes])
+	e.p.x.z.y.SetBytes(m[5*numBytes : 6*numBytes])
+	e.p.y.x.x.SetBytes(m[6*numBytes : 7*numBytes])
+	e.p.y.x.y.SetBytes(m[7*numBytes : 8*numBytes])
+	e.p.y.y.x.SetBytes(m[8*numBytes : 9*numBytes])
+	e.p.y.y.y.SetBytes(m[9*numBytes : 10*numBytes])
+	e.p.y.z.x.SetBytes(m[10*numBytes : 11*numBytes])
+	e.p.y.z.y.SetBytes(m[11*numBytes : 12*numBytes])
+
+	return e, true
+}
+
+// Pair calculates an Optimal Ate pairing.
+func Pair(g1 *G1, g2 *G2) *GT {
+	return &GT{optimalAte(g2.p, g1.p, new(bnPool))}
+}
+
+// bnPool implements a tiny cache of *big.Int objects that's used to reduce the
+// number of allocations made during processing.
+type bnPool struct {
+	bns   []*big.Int
+	count int
+}
+
+func (pool *bnPool) Get() *big.Int {
+	if pool == nil {
+		return new(big.Int)
+	}
+
+	pool.count++
+	l := len(pool.bns)
+	if l == 0 {
+		return new(big.Int)
+	}
+
+	bn := pool.bns[l-1]
+	pool.bns = pool.bns[:l-1]
+	return bn
+}
+
+func (pool *bnPool) Put(bn *big.Int) {
+	if pool == nil {
+		return
+	}
+	pool.bns = append(pool.bns, bn)
+	pool.count--
+}
+
+func (pool *bnPool) Count() int {
+	return pool.count
+}

+ 304 - 0
src/golang.org/x/crypto/bn256/bn256_test.go

@@ -0,0 +1,304 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+	"bytes"
+	"crypto/rand"
+	"math/big"
+	"testing"
+)
+
+func TestGFp2Invert(t *testing.T) {
+	pool := new(bnPool)
+
+	a := newGFp2(pool)
+	a.x.SetString("23423492374", 10)
+	a.y.SetString("12934872398472394827398470", 10)
+
+	inv := newGFp2(pool)
+	inv.Invert(a, pool)
+
+	b := newGFp2(pool).Mul(inv, a, pool)
+	if b.x.Int64() != 0 || b.y.Int64() != 1 {
+		t.Fatalf("bad result for a^-1*a: %s %s", b.x, b.y)
+	}
+
+	a.Put(pool)
+	b.Put(pool)
+	inv.Put(pool)
+
+	if c := pool.Count(); c > 0 {
+		t.Errorf("Pool count non-zero: %d\n", c)
+	}
+}
+
+func isZero(n *big.Int) bool {
+	return new(big.Int).Mod(n, p).Int64() == 0
+}
+
+func isOne(n *big.Int) bool {
+	return new(big.Int).Mod(n, p).Int64() == 1
+}
+
+func TestGFp6Invert(t *testing.T) {
+	pool := new(bnPool)
+
+	a := newGFp6(pool)
+	a.x.x.SetString("239487238491", 10)
+	a.x.y.SetString("2356249827341", 10)
+	a.y.x.SetString("082659782", 10)
+	a.y.y.SetString("182703523765", 10)
+	a.z.x.SetString("978236549263", 10)
+	a.z.y.SetString("64893242", 10)
+
+	inv := newGFp6(pool)
+	inv.Invert(a, pool)
+
+	b := newGFp6(pool).Mul(inv, a, pool)
+	if !isZero(b.x.x) ||
+		!isZero(b.x.y) ||
+		!isZero(b.y.x) ||
+		!isZero(b.y.y) ||
+		!isZero(b.z.x) ||
+		!isOne(b.z.y) {
+		t.Fatalf("bad result for a^-1*a: %s", b)
+	}
+
+	a.Put(pool)
+	b.Put(pool)
+	inv.Put(pool)
+
+	if c := pool.Count(); c > 0 {
+		t.Errorf("Pool count non-zero: %d\n", c)
+	}
+}
+
+func TestGFp12Invert(t *testing.T) {
+	pool := new(bnPool)
+
+	a := newGFp12(pool)
+	a.x.x.x.SetString("239846234862342323958623", 10)
+	a.x.x.y.SetString("2359862352529835623", 10)
+	a.x.y.x.SetString("928836523", 10)
+	a.x.y.y.SetString("9856234", 10)
+	a.x.z.x.SetString("235635286", 10)
+	a.x.z.y.SetString("5628392833", 10)
+	a.y.x.x.SetString("252936598265329856238956532167968", 10)
+	a.y.x.y.SetString("23596239865236954178968", 10)
+	a.y.y.x.SetString("95421692834", 10)
+	a.y.y.y.SetString("236548", 10)
+	a.y.z.x.SetString("924523", 10)
+	a.y.z.y.SetString("12954623", 10)
+
+	inv := newGFp12(pool)
+	inv.Invert(a, pool)
+
+	b := newGFp12(pool).Mul(inv, a, pool)
+	if !isZero(b.x.x.x) ||
+		!isZero(b.x.x.y) ||
+		!isZero(b.x.y.x) ||
+		!isZero(b.x.y.y) ||
+		!isZero(b.x.z.x) ||
+		!isZero(b.x.z.y) ||
+		!isZero(b.y.x.x) ||
+		!isZero(b.y.x.y) ||
+		!isZero(b.y.y.x) ||
+		!isZero(b.y.y.y) ||
+		!isZero(b.y.z.x) ||
+		!isOne(b.y.z.y) {
+		t.Fatalf("bad result for a^-1*a: %s", b)
+	}
+
+	a.Put(pool)
+	b.Put(pool)
+	inv.Put(pool)
+
+	if c := pool.Count(); c > 0 {
+		t.Errorf("Pool count non-zero: %d\n", c)
+	}
+}
+
+func TestCurveImpl(t *testing.T) {
+	pool := new(bnPool)
+
+	g := &curvePoint{
+		pool.Get().SetInt64(1),
+		pool.Get().SetInt64(-2),
+		pool.Get().SetInt64(1),
+		pool.Get().SetInt64(0),
+	}
+
+	x := pool.Get().SetInt64(32498273234)
+	X := newCurvePoint(pool).Mul(g, x, pool)
+
+	y := pool.Get().SetInt64(98732423523)
+	Y := newCurvePoint(pool).Mul(g, y, pool)
+
+	s1 := newCurvePoint(pool).Mul(X, y, pool).MakeAffine(pool)
+	s2 := newCurvePoint(pool).Mul(Y, x, pool).MakeAffine(pool)
+
+	if s1.x.Cmp(s2.x) != 0 ||
+		s2.x.Cmp(s1.x) != 0 {
+		t.Errorf("DH points don't match: (%s, %s) (%s, %s)", s1.x, s1.y, s2.x, s2.y)
+	}
+
+	pool.Put(x)
+	X.Put(pool)
+	pool.Put(y)
+	Y.Put(pool)
+	s1.Put(pool)
+	s2.Put(pool)
+	g.Put(pool)
+
+	if c := pool.Count(); c > 0 {
+		t.Errorf("Pool count non-zero: %d\n", c)
+	}
+}
+
+func TestOrderG1(t *testing.T) {
+	g := new(G1).ScalarBaseMult(Order)
+	if !g.p.IsInfinity() {
+		t.Error("G1 has incorrect order")
+	}
+
+	one := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
+	g.Add(g, one)
+	g.p.MakeAffine(nil)
+	if g.p.x.Cmp(one.p.x) != 0 || g.p.y.Cmp(one.p.y) != 0 {
+		t.Errorf("1+0 != 1 in G1")
+	}
+}
+
+func TestOrderG2(t *testing.T) {
+	g := new(G2).ScalarBaseMult(Order)
+	if !g.p.IsInfinity() {
+		t.Error("G2 has incorrect order")
+	}
+
+	one := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
+	g.Add(g, one)
+	g.p.MakeAffine(nil)
+	if g.p.x.x.Cmp(one.p.x.x) != 0 ||
+		g.p.x.y.Cmp(one.p.x.y) != 0 ||
+		g.p.y.x.Cmp(one.p.y.x) != 0 ||
+		g.p.y.y.Cmp(one.p.y.y) != 0 {
+		t.Errorf("1+0 != 1 in G2")
+	}
+}
+
+func TestOrderGT(t *testing.T) {
+	gt := Pair(&G1{curveGen}, &G2{twistGen})
+	g := new(GT).ScalarMult(gt, Order)
+	if !g.p.IsOne() {
+		t.Error("GT has incorrect order")
+	}
+}
+
+func TestBilinearity(t *testing.T) {
+	for i := 0; i < 2; i++ {
+		a, p1, _ := RandomG1(rand.Reader)
+		b, p2, _ := RandomG2(rand.Reader)
+		e1 := Pair(p1, p2)
+
+		e2 := Pair(&G1{curveGen}, &G2{twistGen})
+		e2.ScalarMult(e2, a)
+		e2.ScalarMult(e2, b)
+
+		minusE2 := new(GT).Neg(e2)
+		e1.Add(e1, minusE2)
+
+		if !e1.p.IsOne() {
+			t.Fatalf("bad pairing result: %s", e1)
+		}
+	}
+}
+
+func TestG1Marshal(t *testing.T) {
+	g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
+	form := g.Marshal()
+	_, ok := new(G1).Unmarshal(form)
+	if !ok {
+		t.Fatalf("failed to unmarshal")
+	}
+
+	g.ScalarBaseMult(Order)
+	form = g.Marshal()
+	g2, ok := new(G1).Unmarshal(form)
+	if !ok {
+		t.Fatalf("failed to unmarshal ∞")
+	}
+	if !g2.p.IsInfinity() {
+		t.Fatalf("∞ unmarshaled incorrectly")
+	}
+}
+
+func TestG2Marshal(t *testing.T) {
+	g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
+	form := g.Marshal()
+	_, ok := new(G2).Unmarshal(form)
+	if !ok {
+		t.Fatalf("failed to unmarshal")
+	}
+
+	g.ScalarBaseMult(Order)
+	form = g.Marshal()
+	g2, ok := new(G2).Unmarshal(form)
+	if !ok {
+		t.Fatalf("failed to unmarshal ∞")
+	}
+	if !g2.p.IsInfinity() {
+		t.Fatalf("∞ unmarshaled incorrectly")
+	}
+}
+
+func TestG1Identity(t *testing.T) {
+	g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(0))
+	if !g.p.IsInfinity() {
+		t.Error("failure")
+	}
+}
+
+func TestG2Identity(t *testing.T) {
+	g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(0))
+	if !g.p.IsInfinity() {
+		t.Error("failure")
+	}
+}
+
+func TestTripartiteDiffieHellman(t *testing.T) {
+	a, _ := rand.Int(rand.Reader, Order)
+	b, _ := rand.Int(rand.Reader, Order)
+	c, _ := rand.Int(rand.Reader, Order)
+
+	pa, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
+	qa, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
+	pb, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
+	qb, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
+	pc, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
+	qc, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
+
+	k1 := Pair(pb, qc)
+	k1.ScalarMult(k1, a)
+	k1Bytes := k1.Marshal()
+
+	k2 := Pair(pc, qa)
+	k2.ScalarMult(k2, b)
+	k2Bytes := k2.Marshal()
+
+	k3 := Pair(pa, qb)
+	k3.ScalarMult(k3, c)
+	k3Bytes := k3.Marshal()
+
+	if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) {
+		t.Errorf("keys didn't agree")
+	}
+}
+
+func BenchmarkPairing(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		Pair(&G1{curveGen}, &G2{twistGen})
+	}
+}

+ 44 - 0
src/golang.org/x/crypto/bn256/constants.go

@@ -0,0 +1,44 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+	"math/big"
+)
+
+func bigFromBase10(s string) *big.Int {
+	n, _ := new(big.Int).SetString(s, 10)
+	return n
+}
+
+// u is the BN parameter that determines the prime: 1868033³.
+var u = bigFromBase10("6518589491078791937")
+
+// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
+var p = bigFromBase10("65000549695646603732796438742359905742825358107623003571877145026864184071783")
+
+// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
+var Order = bigFromBase10("65000549695646603732796438742359905742570406053903786389881062969044166799969")
+
+// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+3.
+var xiToPMinus1Over6 = &gfP2{bigFromBase10("8669379979083712429711189836753509758585994370025260553045152614783263110636"), bigFromBase10("19998038925833620163537568958541907098007303196759855091367510456613536016040")}
+
+// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+3.
+var xiToPMinus1Over3 = &gfP2{bigFromBase10("26098034838977895781559542626833399156321265654106457577426020397262786167059"), bigFromBase10("15931493369629630809226283458085260090334794394361662678240713231519278691715")}
+
+// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+3.
+var xiToPMinus1Over2 = &gfP2{bigFromBase10("50997318142241922852281555961173165965672272825141804376761836765206060036244"), bigFromBase10("38665955945962842195025998234511023902832543644254935982879660597356748036009")}
+
+// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+3.
+var xiToPSquaredMinus1Over3 = bigFromBase10("65000549695646603727810655408050771481677621702948236658134783353303381437752")
+
+// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+3 (a cubic root of unity, mod p).
+var xiTo2PSquaredMinus2Over3 = bigFromBase10("4985783334309134261147736404674766913742361673560802634030")
+
+// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+3 (a cubic root of -1, mod p).
+var xiToPSquaredMinus1Over6 = bigFromBase10("65000549695646603727810655408050771481677621702948236658134783353303381437753")
+
+// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+3.
+var xiTo2PMinus2Over3 = &gfP2{bigFromBase10("19885131339612776214803633203834694332692106372356013117629940868870585019582"), bigFromBase10("21645619881471562101905880913352894726728173167203616652430647841922248593627")}

+ 287 - 0
src/golang.org/x/crypto/bn256/curve.go

@@ -0,0 +1,287 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+	"math/big"
+)
+
+// curvePoint implements the elliptic curve y²=x³+3. Points are kept in
+// Jacobian form and t=z² when valid. G₁ is the set of points of this curve on
+// GF(p).
+type curvePoint struct {
+	x, y, z, t *big.Int
+}
+
+var curveB = new(big.Int).SetInt64(3)
+
+// curveGen is the generator of G₁.
+var curveGen = &curvePoint{
+	new(big.Int).SetInt64(1),
+	new(big.Int).SetInt64(-2),
+	new(big.Int).SetInt64(1),
+	new(big.Int).SetInt64(1),
+}
+
+func newCurvePoint(pool *bnPool) *curvePoint {
+	return &curvePoint{
+		pool.Get(),
+		pool.Get(),
+		pool.Get(),
+		pool.Get(),
+	}
+}
+
+func (c *curvePoint) String() string {
+	c.MakeAffine(new(bnPool))
+	return "(" + c.x.String() + ", " + c.y.String() + ")"
+}
+
+func (c *curvePoint) Put(pool *bnPool) {
+	pool.Put(c.x)
+	pool.Put(c.y)
+	pool.Put(c.z)
+	pool.Put(c.t)
+}
+
+func (c *curvePoint) Set(a *curvePoint) {
+	c.x.Set(a.x)
+	c.y.Set(a.y)
+	c.z.Set(a.z)
+	c.t.Set(a.t)
+}
+
+// IsOnCurve returns true iff c is on the curve where c must be in affine form.
+func (c *curvePoint) IsOnCurve() bool {
+	yy := new(big.Int).Mul(c.y, c.y)
+	xxx := new(big.Int).Mul(c.x, c.x)
+	xxx.Mul(xxx, c.x)
+	yy.Sub(yy, xxx)
+	yy.Sub(yy, curveB)
+	if yy.Sign() < 0 || yy.Cmp(p) >= 0 {
+		yy.Mod(yy, p)
+	}
+	return yy.Sign() == 0
+}
+
+func (c *curvePoint) SetInfinity() {
+	c.z.SetInt64(0)
+}
+
+func (c *curvePoint) IsInfinity() bool {
+	return c.z.Sign() == 0
+}
+
+func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
+	if a.IsInfinity() {
+		c.Set(b)
+		return
+	}
+	if b.IsInfinity() {
+		c.Set(a)
+		return
+	}
+
+	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
+
+	// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
+	// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
+	// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
+	z1z1 := pool.Get().Mul(a.z, a.z)
+	z1z1.Mod(z1z1, p)
+	z2z2 := pool.Get().Mul(b.z, b.z)
+	z2z2.Mod(z2z2, p)
+	u1 := pool.Get().Mul(a.x, z2z2)
+	u1.Mod(u1, p)
+	u2 := pool.Get().Mul(b.x, z1z1)
+	u2.Mod(u2, p)
+
+	t := pool.Get().Mul(b.z, z2z2)
+	t.Mod(t, p)
+	s1 := pool.Get().Mul(a.y, t)
+	s1.Mod(s1, p)
+
+	t.Mul(a.z, z1z1)
+	t.Mod(t, p)
+	s2 := pool.Get().Mul(b.y, t)
+	s2.Mod(s2, p)
+
+	// Compute x = (2h)²(s²-u1-u2)
+	// where s = (s2-s1)/(u2-u1) is the slope of the line through
+	// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
+	// This is also:
+	// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
+	//                        = r² - j - 2v
+	// with the notations below.
+	h := pool.Get().Sub(u2, u1)
+	xEqual := h.Sign() == 0
+
+	t.Add(h, h)
+	// i = 4h²
+	i := pool.Get().Mul(t, t)
+	i.Mod(i, p)
+	// j = 4h³
+	j := pool.Get().Mul(h, i)
+	j.Mod(j, p)
+
+	t.Sub(s2, s1)
+	yEqual := t.Sign() == 0
+	if xEqual && yEqual {
+		c.Double(a, pool)
+		return
+	}
+	r := pool.Get().Add(t, t)
+
+	v := pool.Get().Mul(u1, i)
+	v.Mod(v, p)
+
+	// t4 = 4(s2-s1)²
+	t4 := pool.Get().Mul(r, r)
+	t4.Mod(t4, p)
+	t.Add(v, v)
+	t6 := pool.Get().Sub(t4, j)
+	c.x.Sub(t6, t)
+
+	// Set y = -(2h)³(s1 + s*(x/4h²-u1))
+	// This is also
+	// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
+	t.Sub(v, c.x) // t7
+	t4.Mul(s1, j) // t8
+	t4.Mod(t4, p)
+	t6.Add(t4, t4) // t9
+	t4.Mul(r, t)   // t10
+	t4.Mod(t4, p)
+	c.y.Sub(t4, t6)
+
+	// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
+	t.Add(a.z, b.z) // t11
+	t4.Mul(t, t)    // t12
+	t4.Mod(t4, p)
+	t.Sub(t4, z1z1) // t13
+	t4.Sub(t, z2z2) // t14
+	c.z.Mul(t4, h)
+	c.z.Mod(c.z, p)
+
+	pool.Put(z1z1)
+	pool.Put(z2z2)
+	pool.Put(u1)
+	pool.Put(u2)
+	pool.Put(t)
+	pool.Put(s1)
+	pool.Put(s2)
+	pool.Put(h)
+	pool.Put(i)
+	pool.Put(j)
+	pool.Put(r)
+	pool.Put(v)
+	pool.Put(t4)
+	pool.Put(t6)
+}
+
+func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
+	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
+	A := pool.Get().Mul(a.x, a.x)
+	A.Mod(A, p)
+	B := pool.Get().Mul(a.y, a.y)
+	B.Mod(B, p)
+	C := pool.Get().Mul(B, B)
+	C.Mod(C, p)
+
+	t := pool.Get().Add(a.x, B)
+	t2 := pool.Get().Mul(t, t)
+	t2.Mod(t2, p)
+	t.Sub(t2, A)
+	t2.Sub(t, C)
+	d := pool.Get().Add(t2, t2)
+	t.Add(A, A)
+	e := pool.Get().Add(t, A)
+	f := pool.Get().Mul(e, e)
+	f.Mod(f, p)
+
+	t.Add(d, d)
+	c.x.Sub(f, t)
+
+	t.Add(C, C)
+	t2.Add(t, t)
+	t.Add(t2, t2)
+	c.y.Sub(d, c.x)
+	t2.Mul(e, c.y)
+	t2.Mod(t2, p)
+	c.y.Sub(t2, t)
+
+	t.Mul(a.y, a.z)
+	t.Mod(t, p)
+	c.z.Add(t, t)
+
+	pool.Put(A)
+	pool.Put(B)
+	pool.Put(C)
+	pool.Put(t)
+	pool.Put(t2)
+	pool.Put(d)
+	pool.Put(e)
+	pool.Put(f)
+}
+
+func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint {
+	sum := newCurvePoint(pool)
+	sum.SetInfinity()
+	t := newCurvePoint(pool)
+
+	for i := scalar.BitLen(); i >= 0; i-- {
+		t.Double(sum, pool)
+		if scalar.Bit(i) != 0 {
+			sum.Add(t, a, pool)
+		} else {
+			sum.Set(t)
+		}
+	}
+
+	c.Set(sum)
+	sum.Put(pool)
+	t.Put(pool)
+	return c
+}
+
+// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
+// c to 0 : 1 : 0.
+func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
+	if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
+		return c
+	}
+	if c.IsInfinity() {
+		c.x.SetInt64(0)
+		c.y.SetInt64(1)
+		c.z.SetInt64(0)
+		c.t.SetInt64(0)
+		return c
+	}
+
+	zInv := pool.Get().ModInverse(c.z, p)
+	t := pool.Get().Mul(c.y, zInv)
+	t.Mod(t, p)
+	zInv2 := pool.Get().Mul(zInv, zInv)
+	zInv2.Mod(zInv2, p)
+	c.y.Mul(t, zInv2)
+	c.y.Mod(c.y, p)
+	t.Mul(c.x, zInv2)
+	t.Mod(t, p)
+	c.x.Set(t)
+	c.z.SetInt64(1)
+	c.t.SetInt64(1)
+
+	pool.Put(zInv)
+	pool.Put(t)
+	pool.Put(zInv2)
+
+	return c
+}
+
+func (c *curvePoint) Negative(a *curvePoint) {
+	c.x.Set(a.x)
+	c.y.Neg(a.y)
+	c.z.Set(a.z)
+	c.t.SetInt64(0)
+}

+ 43 - 0
src/golang.org/x/crypto/bn256/example_test.go

@@ -0,0 +1,43 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+	"crypto/rand"
+)
+
+func ExamplePair() {
+	// This implements the tripartite Diffie-Hellman algorithm from "A One
+	// Round Protocol for Tripartite Diffie-Hellman", A. Joux.
+	// http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf
+
+	// Each of three parties, a, b and c, generate a private value.
+	a, _ := rand.Int(rand.Reader, Order)
+	b, _ := rand.Int(rand.Reader, Order)
+	c, _ := rand.Int(rand.Reader, Order)
+
+	// Then each party calculates g₁ and g₂ times their private value.
+	pa := new(G1).ScalarBaseMult(a)
+	qa := new(G2).ScalarBaseMult(a)
+
+	pb := new(G1).ScalarBaseMult(b)
+	qb := new(G2).ScalarBaseMult(b)
+
+	pc := new(G1).ScalarBaseMult(c)
+	qc := new(G2).ScalarBaseMult(c)
+
+	// Now each party exchanges its public values with the other two and
+	// all parties can calculate the shared key.
+	k1 := Pair(pb, qc)
+	k1.ScalarMult(k1, a)
+
+	k2 := Pair(pc, qa)
+	k2.ScalarMult(k2, b)
+
+	k3 := Pair(pa, qb)
+	k3.ScalarMult(k3, c)
+
+	// k1, k2 and k3 will all be equal.
+}

+ 200 - 0
src/golang.org/x/crypto/bn256/gfp12.go

@@ -0,0 +1,200 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+// For details of the algorithms used, see "Multiplication and Squaring on
+// Pairing-Friendly Fields, Devegili et al.
+// http://eprint.iacr.org/2006/471.pdf.
+
+import (
+	"math/big"
+)
+
+// gfP12 implements the field of size p¹² as a quadratic extension of gfP6
+// where ω²=τ.
+type gfP12 struct {
+	x, y *gfP6 // value is xω + y
+}
+
+func newGFp12(pool *bnPool) *gfP12 {
+	return &gfP12{newGFp6(pool), newGFp6(pool)}
+}
+
+func (e *gfP12) String() string {
+	return "(" + e.x.String() + "," + e.y.String() + ")"
+}
+
+func (e *gfP12) Put(pool *bnPool) {
+	e.x.Put(pool)
+	e.y.Put(pool)
+}
+
+func (e *gfP12) Set(a *gfP12) *gfP12 {
+	e.x.Set(a.x)
+	e.y.Set(a.y)
+	return e
+}
+
+func (e *gfP12) SetZero() *gfP12 {
+	e.x.SetZero()
+	e.y.SetZero()
+	return e
+}
+
+func (e *gfP12) SetOne() *gfP12 {
+	e.x.SetZero()
+	e.y.SetOne()
+	return e
+}
+
+func (e *gfP12) Minimal() {
+	e.x.Minimal()
+	e.y.Minimal()
+}
+
+func (e *gfP12) IsZero() bool {
+	e.Minimal()
+	return e.x.IsZero() && e.y.IsZero()
+}
+
+func (e *gfP12) IsOne() bool {
+	e.Minimal()
+	return e.x.IsZero() && e.y.IsOne()
+}
+
+func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
+	e.x.Negative(a.x)
+	e.y.Set(a.y)
+	return a
+}
+
+func (e *gfP12) Negative(a *gfP12) *gfP12 {
+	e.x.Negative(a.x)
+	e.y.Negative(a.y)
+	return e
+}
+
+// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
+func (e *gfP12) Frobenius(a *gfP12, pool *bnPool) *gfP12 {
+	e.x.Frobenius(a.x, pool)
+	e.y.Frobenius(a.y, pool)
+	e.x.MulScalar(e.x, xiToPMinus1Over6, pool)
+	return e
+}
+
+// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
+func (e *gfP12) FrobeniusP2(a *gfP12, pool *bnPool) *gfP12 {
+	e.x.FrobeniusP2(a.x)
+	e.x.MulGFP(e.x, xiToPSquaredMinus1Over6)
+	e.y.FrobeniusP2(a.y)
+	return e
+}
+
+func (e *gfP12) Add(a, b *gfP12) *gfP12 {
+	e.x.Add(a.x, b.x)
+	e.y.Add(a.y, b.y)
+	return e
+}
+
+func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
+	e.x.Sub(a.x, b.x)
+	e.y.Sub(a.y, b.y)
+	return e
+}
+
+func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 {
+	tx := newGFp6(pool)
+	tx.Mul(a.x, b.y, pool)
+	t := newGFp6(pool)
+	t.Mul(b.x, a.y, pool)
+	tx.Add(tx, t)
+
+	ty := newGFp6(pool)
+	ty.Mul(a.y, b.y, pool)
+	t.Mul(a.x, b.x, pool)
+	t.MulTau(t, pool)
+	e.y.Add(ty, t)
+	e.x.Set(tx)
+
+	tx.Put(pool)
+	ty.Put(pool)
+	t.Put(pool)
+	return e
+}
+
+func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
+	e.x.Mul(e.x, b, pool)
+	e.y.Mul(e.y, b, pool)
+	return e
+}
+
+func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
+	sum := newGFp12(pool)
+	sum.SetOne()
+	t := newGFp12(pool)
+
+	for i := power.BitLen() - 1; i >= 0; i-- {
+		t.Square(sum, pool)
+		if power.Bit(i) != 0 {
+			sum.Mul(t, a, pool)
+		} else {
+			sum.Set(t)
+		}
+	}
+
+	c.Set(sum)
+
+	sum.Put(pool)
+	t.Put(pool)
+
+	return c
+}
+
+func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 {
+	// Complex squaring algorithm
+	v0 := newGFp6(pool)
+	v0.Mul(a.x, a.y, pool)
+
+	t := newGFp6(pool)
+	t.MulTau(a.x, pool)
+	t.Add(a.y, t)
+	ty := newGFp6(pool)
+	ty.Add(a.x, a.y)
+	ty.Mul(ty, t, pool)
+	ty.Sub(ty, v0)
+	t.MulTau(v0, pool)
+	ty.Sub(ty, t)
+
+	e.y.Set(ty)
+	e.x.Double(v0)
+
+	v0.Put(pool)
+	t.Put(pool)
+	ty.Put(pool)
+
+	return e
+}
+
+func (e *gfP12) Invert(a *gfP12, pool *bnPool) *gfP12 {
+	// See "Implementing cryptographic pairings", M. Scott, section 3.2.
+	// ftp://136.206.11.249/pub/crypto/pairings.pdf
+	t1 := newGFp6(pool)
+	t2 := newGFp6(pool)
+
+	t1.Square(a.x, pool)
+	t2.Square(a.y, pool)
+	t1.MulTau(t1, pool)
+	t1.Sub(t2, t1)
+	t2.Invert(t1, pool)
+
+	e.x.Negative(a.x)
+	e.y.Set(a.y)
+	e.MulScalar(e, t2, pool)
+
+	t1.Put(pool)
+	t2.Put(pool)
+
+	return e
+}

+ 219 - 0
src/golang.org/x/crypto/bn256/gfp2.go

@@ -0,0 +1,219 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+// For details of the algorithms used, see "Multiplication and Squaring on
+// Pairing-Friendly Fields, Devegili et al.
+// http://eprint.iacr.org/2006/471.pdf.
+
+import (
+	"math/big"
+)
+
+// gfP2 implements a field of size p² as a quadratic extension of the base
+// field where i²=-1.
+type gfP2 struct {
+	x, y *big.Int // value is xi+y.
+}
+
+func newGFp2(pool *bnPool) *gfP2 {
+	return &gfP2{pool.Get(), pool.Get()}
+}
+
+func (e *gfP2) String() string {
+	x := new(big.Int).Mod(e.x, p)
+	y := new(big.Int).Mod(e.y, p)
+	return "(" + x.String() + "," + y.String() + ")"
+}
+
+func (e *gfP2) Put(pool *bnPool) {
+	pool.Put(e.x)
+	pool.Put(e.y)
+}
+
+func (e *gfP2) Set(a *gfP2) *gfP2 {
+	e.x.Set(a.x)
+	e.y.Set(a.y)
+	return e
+}
+
+func (e *gfP2) SetZero() *gfP2 {
+	e.x.SetInt64(0)
+	e.y.SetInt64(0)
+	return e
+}
+
+func (e *gfP2) SetOne() *gfP2 {
+	e.x.SetInt64(0)
+	e.y.SetInt64(1)
+	return e
+}
+
+func (e *gfP2) Minimal() {
+	if e.x.Sign() < 0 || e.x.Cmp(p) >= 0 {
+		e.x.Mod(e.x, p)
+	}
+	if e.y.Sign() < 0 || e.y.Cmp(p) >= 0 {
+		e.y.Mod(e.y, p)
+	}
+}
+
+func (e *gfP2) IsZero() bool {
+	return e.x.Sign() == 0 && e.y.Sign() == 0
+}
+
+func (e *gfP2) IsOne() bool {
+	if e.x.Sign() != 0 {
+		return false
+	}
+	words := e.y.Bits()
+	return len(words) == 1 && words[0] == 1
+}
+
+func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
+	e.y.Set(a.y)
+	e.x.Neg(a.x)
+	return e
+}
+
+func (e *gfP2) Negative(a *gfP2) *gfP2 {
+	e.x.Neg(a.x)
+	e.y.Neg(a.y)
+	return e
+}
+
+func (e *gfP2) Add(a, b *gfP2) *gfP2 {
+	e.x.Add(a.x, b.x)
+	e.y.Add(a.y, b.y)
+	return e
+}
+
+func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
+	e.x.Sub(a.x, b.x)
+	e.y.Sub(a.y, b.y)
+	return e
+}
+
+func (e *gfP2) Double(a *gfP2) *gfP2 {
+	e.x.Lsh(a.x, 1)
+	e.y.Lsh(a.y, 1)
+	return e
+}
+
+func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
+	sum := newGFp2(pool)
+	sum.SetOne()
+	t := newGFp2(pool)
+
+	for i := power.BitLen() - 1; i >= 0; i-- {
+		t.Square(sum, pool)
+		if power.Bit(i) != 0 {
+			sum.Mul(t, a, pool)
+		} else {
+			sum.Set(t)
+		}
+	}
+
+	c.Set(sum)
+
+	sum.Put(pool)
+	t.Put(pool)
+
+	return c
+}
+
+// See "Multiplication and Squaring in Pairing-Friendly Fields",
+// http://eprint.iacr.org/2006/471.pdf
+func (e *gfP2) Mul(a, b *gfP2, pool *bnPool) *gfP2 {
+	tx := pool.Get().Mul(a.x, b.y)
+	t := pool.Get().Mul(b.x, a.y)
+	tx.Add(tx, t)
+	tx.Mod(tx, p)
+
+	ty := pool.Get().Mul(a.y, b.y)
+	t.Mul(a.x, b.x)
+	ty.Sub(ty, t)
+	e.y.Mod(ty, p)
+	e.x.Set(tx)
+
+	pool.Put(tx)
+	pool.Put(ty)
+	pool.Put(t)
+
+	return e
+}
+
+func (e *gfP2) MulScalar(a *gfP2, b *big.Int) *gfP2 {
+	e.x.Mul(a.x, b)
+	e.y.Mul(a.y, b)
+	return e
+}
+
+// MulXi sets e=ξa where ξ=i+3 and then returns e.
+func (e *gfP2) MulXi(a *gfP2, pool *bnPool) *gfP2 {
+	// (xi+y)(i+3) = (3x+y)i+(3y-x)
+	tx := pool.Get().Lsh(a.x, 1)
+	tx.Add(tx, a.x)
+	tx.Add(tx, a.y)
+
+	ty := pool.Get().Lsh(a.y, 1)
+	ty.Add(ty, a.y)
+	ty.Sub(ty, a.x)
+
+	e.x.Set(tx)
+	e.y.Set(ty)
+
+	pool.Put(tx)
+	pool.Put(ty)
+
+	return e
+}
+
+func (e *gfP2) Square(a *gfP2, pool *bnPool) *gfP2 {
+	// Complex squaring algorithm:
+	// (xi+b)² = (x+y)(y-x) + 2*i*x*y
+	t1 := pool.Get().Sub(a.y, a.x)
+	t2 := pool.Get().Add(a.x, a.y)
+	ty := pool.Get().Mul(t1, t2)
+	ty.Mod(ty, p)
+
+	t1.Mul(a.x, a.y)
+	t1.Lsh(t1, 1)
+
+	e.x.Mod(t1, p)
+	e.y.Set(ty)
+
+	pool.Put(t1)
+	pool.Put(t2)
+	pool.Put(ty)
+
+	return e
+}
+
+func (e *gfP2) Invert(a *gfP2, pool *bnPool) *gfP2 {
+	// See "Implementing cryptographic pairings", M. Scott, section 3.2.
+	// ftp://136.206.11.249/pub/crypto/pairings.pdf
+	t := pool.Get()
+	t.Mul(a.y, a.y)
+	t2 := pool.Get()
+	t2.Mul(a.x, a.x)
+	t.Add(t, t2)
+
+	inv := pool.Get()
+	inv.ModInverse(t, p)
+
+	e.x.Neg(a.x)
+	e.x.Mul(e.x, inv)
+	e.x.Mod(e.x, p)
+
+	e.y.Mul(a.y, inv)
+	e.y.Mod(e.y, p)
+
+	pool.Put(t)
+	pool.Put(t2)
+	pool.Put(inv)
+
+	return e
+}

+ 296 - 0
src/golang.org/x/crypto/bn256/gfp6.go

@@ -0,0 +1,296 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+// For details of the algorithms used, see "Multiplication and Squaring on
+// Pairing-Friendly Fields, Devegili et al.
+// http://eprint.iacr.org/2006/471.pdf.
+
+import (
+	"math/big"
+)
+
+// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
+// and ξ=i+3.
+type gfP6 struct {
+	x, y, z *gfP2 // value is xτ² + yτ + z
+}
+
+func newGFp6(pool *bnPool) *gfP6 {
+	return &gfP6{newGFp2(pool), newGFp2(pool), newGFp2(pool)}
+}
+
+func (e *gfP6) String() string {
+	return "(" + e.x.String() + "," + e.y.String() + "," + e.z.String() + ")"
+}
+
+func (e *gfP6) Put(pool *bnPool) {
+	e.x.Put(pool)
+	e.y.Put(pool)
+	e.z.Put(pool)
+}
+
+func (e *gfP6) Set(a *gfP6) *gfP6 {
+	e.x.Set(a.x)
+	e.y.Set(a.y)
+	e.z.Set(a.z)
+	return e
+}
+
+func (e *gfP6) SetZero() *gfP6 {
+	e.x.SetZero()
+	e.y.SetZero()
+	e.z.SetZero()
+	return e
+}
+
+func (e *gfP6) SetOne() *gfP6 {
+	e.x.SetZero()
+	e.y.SetZero()
+	e.z.SetOne()
+	return e
+}
+
+func (e *gfP6) Minimal() {
+	e.x.Minimal()
+	e.y.Minimal()
+	e.z.Minimal()
+}
+
+func (e *gfP6) IsZero() bool {
+	return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
+}
+
+func (e *gfP6) IsOne() bool {
+	return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
+}
+
+func (e *gfP6) Negative(a *gfP6) *gfP6 {
+	e.x.Negative(a.x)
+	e.y.Negative(a.y)
+	e.z.Negative(a.z)
+	return e
+}
+
+func (e *gfP6) Frobenius(a *gfP6, pool *bnPool) *gfP6 {
+	e.x.Conjugate(a.x)
+	e.y.Conjugate(a.y)
+	e.z.Conjugate(a.z)
+
+	e.x.Mul(e.x, xiTo2PMinus2Over3, pool)
+	e.y.Mul(e.y, xiToPMinus1Over3, pool)
+	return e
+}
+
+// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
+func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
+	// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
+	e.x.MulScalar(a.x, xiTo2PSquaredMinus2Over3)
+	// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
+	e.y.MulScalar(a.y, xiToPSquaredMinus1Over3)
+	e.z.Set(a.z)
+	return e
+}
+
+func (e *gfP6) Add(a, b *gfP6) *gfP6 {
+	e.x.Add(a.x, b.x)
+	e.y.Add(a.y, b.y)
+	e.z.Add(a.z, b.z)
+	return e
+}
+
+func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
+	e.x.Sub(a.x, b.x)
+	e.y.Sub(a.y, b.y)
+	e.z.Sub(a.z, b.z)
+	return e
+}
+
+func (e *gfP6) Double(a *gfP6) *gfP6 {
+	e.x.Double(a.x)
+	e.y.Double(a.y)
+	e.z.Double(a.z)
+	return e
+}
+
+func (e *gfP6) Mul(a, b *gfP6, pool *bnPool) *gfP6 {
+	// "Multiplication and Squaring on Pairing-Friendly Fields"
+	// Section 4, Karatsuba method.
+	// http://eprint.iacr.org/2006/471.pdf
+
+	v0 := newGFp2(pool)
+	v0.Mul(a.z, b.z, pool)
+	v1 := newGFp2(pool)
+	v1.Mul(a.y, b.y, pool)
+	v2 := newGFp2(pool)
+	v2.Mul(a.x, b.x, pool)
+
+	t0 := newGFp2(pool)
+	t0.Add(a.x, a.y)
+	t1 := newGFp2(pool)
+	t1.Add(b.x, b.y)
+	tz := newGFp2(pool)
+	tz.Mul(t0, t1, pool)
+
+	tz.Sub(tz, v1)
+	tz.Sub(tz, v2)
+	tz.MulXi(tz, pool)
+	tz.Add(tz, v0)
+
+	t0.Add(a.y, a.z)
+	t1.Add(b.y, b.z)
+	ty := newGFp2(pool)
+	ty.Mul(t0, t1, pool)
+	ty.Sub(ty, v0)
+	ty.Sub(ty, v1)
+	t0.MulXi(v2, pool)
+	ty.Add(ty, t0)
+
+	t0.Add(a.x, a.z)
+	t1.Add(b.x, b.z)
+	tx := newGFp2(pool)
+	tx.Mul(t0, t1, pool)
+	tx.Sub(tx, v0)
+	tx.Add(tx, v1)
+	tx.Sub(tx, v2)
+
+	e.x.Set(tx)
+	e.y.Set(ty)
+	e.z.Set(tz)
+
+	t0.Put(pool)
+	t1.Put(pool)
+	tx.Put(pool)
+	ty.Put(pool)
+	tz.Put(pool)
+	v0.Put(pool)
+	v1.Put(pool)
+	v2.Put(pool)
+	return e
+}
+
+func (e *gfP6) MulScalar(a *gfP6, b *gfP2, pool *bnPool) *gfP6 {
+	e.x.Mul(a.x, b, pool)
+	e.y.Mul(a.y, b, pool)
+	e.z.Mul(a.z, b, pool)
+	return e
+}
+
+func (e *gfP6) MulGFP(a *gfP6, b *big.Int) *gfP6 {
+	e.x.MulScalar(a.x, b)
+	e.y.MulScalar(a.y, b)
+	e.z.MulScalar(a.z, b)
+	return e
+}
+
+// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
+func (e *gfP6) MulTau(a *gfP6, pool *bnPool) {
+	tz := newGFp2(pool)
+	tz.MulXi(a.x, pool)
+	ty := newGFp2(pool)
+	ty.Set(a.y)
+	e.y.Set(a.z)
+	e.x.Set(ty)
+	e.z.Set(tz)
+	tz.Put(pool)
+	ty.Put(pool)
+}
+
+func (e *gfP6) Square(a *gfP6, pool *bnPool) *gfP6 {
+	v0 := newGFp2(pool).Square(a.z, pool)
+	v1 := newGFp2(pool).Square(a.y, pool)
+	v2 := newGFp2(pool).Square(a.x, pool)
+
+	c0 := newGFp2(pool).Add(a.x, a.y)
+	c0.Square(c0, pool)
+	c0.Sub(c0, v1)
+	c0.Sub(c0, v2)
+	c0.MulXi(c0, pool)
+	c0.Add(c0, v0)
+
+	c1 := newGFp2(pool).Add(a.y, a.z)
+	c1.Square(c1, pool)
+	c1.Sub(c1, v0)
+	c1.Sub(c1, v1)
+	xiV2 := newGFp2(pool).MulXi(v2, pool)
+	c1.Add(c1, xiV2)
+
+	c2 := newGFp2(pool).Add(a.x, a.z)
+	c2.Square(c2, pool)
+	c2.Sub(c2, v0)
+	c2.Add(c2, v1)
+	c2.Sub(c2, v2)
+
+	e.x.Set(c2)
+	e.y.Set(c1)
+	e.z.Set(c0)
+
+	v0.Put(pool)
+	v1.Put(pool)
+	v2.Put(pool)
+	c0.Put(pool)
+	c1.Put(pool)
+	c2.Put(pool)
+	xiV2.Put(pool)
+
+	return e
+}
+
+func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
+	// See "Implementing cryptographic pairings", M. Scott, section 3.2.
+	// ftp://136.206.11.249/pub/crypto/pairings.pdf
+
+	// Here we can give a short explanation of how it works: let j be a cubic root of
+	// unity in GF(p²) so that 1+j+j²=0.
+	// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
+	// = (xτ² + yτ + z)(Cτ²+Bτ+A)
+	// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
+	//
+	// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
+	// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
+	//
+	// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
+	t1 := newGFp2(pool)
+
+	A := newGFp2(pool)
+	A.Square(a.z, pool)
+	t1.Mul(a.x, a.y, pool)
+	t1.MulXi(t1, pool)
+	A.Sub(A, t1)
+
+	B := newGFp2(pool)
+	B.Square(a.x, pool)
+	B.MulXi(B, pool)
+	t1.Mul(a.y, a.z, pool)
+	B.Sub(B, t1)
+
+	C := newGFp2(pool)
+	C.Square(a.y, pool)
+	t1.Mul(a.x, a.z, pool)
+	C.Sub(C, t1)
+
+	F := newGFp2(pool)
+	F.Mul(C, a.y, pool)
+	F.MulXi(F, pool)
+	t1.Mul(A, a.z, pool)
+	F.Add(F, t1)
+	t1.Mul(B, a.x, pool)
+	t1.MulXi(t1, pool)
+	F.Add(F, t1)
+
+	F.Invert(F, pool)
+
+	e.x.Mul(C, F, pool)
+	e.y.Mul(B, F, pool)
+	e.z.Mul(A, F, pool)
+
+	t1.Put(pool)
+	A.Put(pool)
+	B.Put(pool)
+	C.Put(pool)
+	F.Put(pool)
+
+	return e
+}

+ 395 - 0
src/golang.org/x/crypto/bn256/optate.go

@@ -0,0 +1,395 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
+	// See the mixed addition algorithm from "Faster Computation of the
+	// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
+
+	B := newGFp2(pool).Mul(p.x, r.t, pool)
+
+	D := newGFp2(pool).Add(p.y, r.z)
+	D.Square(D, pool)
+	D.Sub(D, r2)
+	D.Sub(D, r.t)
+	D.Mul(D, r.t, pool)
+
+	H := newGFp2(pool).Sub(B, r.x)
+	I := newGFp2(pool).Square(H, pool)
+
+	E := newGFp2(pool).Add(I, I)
+	E.Add(E, E)
+
+	J := newGFp2(pool).Mul(H, E, pool)
+
+	L1 := newGFp2(pool).Sub(D, r.y)
+	L1.Sub(L1, r.y)
+
+	V := newGFp2(pool).Mul(r.x, E, pool)
+
+	rOut = newTwistPoint(pool)
+	rOut.x.Square(L1, pool)
+	rOut.x.Sub(rOut.x, J)
+	rOut.x.Sub(rOut.x, V)
+	rOut.x.Sub(rOut.x, V)
+
+	rOut.z.Add(r.z, H)
+	rOut.z.Square(rOut.z, pool)
+	rOut.z.Sub(rOut.z, r.t)
+	rOut.z.Sub(rOut.z, I)
+
+	t := newGFp2(pool).Sub(V, rOut.x)
+	t.Mul(t, L1, pool)
+	t2 := newGFp2(pool).Mul(r.y, J, pool)
+	t2.Add(t2, t2)
+	rOut.y.Sub(t, t2)
+
+	rOut.t.Square(rOut.z, pool)
+
+	t.Add(p.y, rOut.z)
+	t.Square(t, pool)
+	t.Sub(t, r2)
+	t.Sub(t, rOut.t)
+
+	t2.Mul(L1, p.x, pool)
+	t2.Add(t2, t2)
+	a = newGFp2(pool)
+	a.Sub(t2, t)
+
+	c = newGFp2(pool)
+	c.MulScalar(rOut.z, q.y)
+	c.Add(c, c)
+
+	b = newGFp2(pool)
+	b.SetZero()
+	b.Sub(b, L1)
+	b.MulScalar(b, q.x)
+	b.Add(b, b)
+
+	B.Put(pool)
+	D.Put(pool)
+	H.Put(pool)
+	I.Put(pool)
+	E.Put(pool)
+	J.Put(pool)
+	L1.Put(pool)
+	V.Put(pool)
+	t.Put(pool)
+	t2.Put(pool)
+
+	return
+}
+
+func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
+	// See the doubling algorithm for a=0 from "Faster Computation of the
+	// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
+
+	A := newGFp2(pool).Square(r.x, pool)
+	B := newGFp2(pool).Square(r.y, pool)
+	C := newGFp2(pool).Square(B, pool)
+
+	D := newGFp2(pool).Add(r.x, B)
+	D.Square(D, pool)
+	D.Sub(D, A)
+	D.Sub(D, C)
+	D.Add(D, D)
+
+	E := newGFp2(pool).Add(A, A)
+	E.Add(E, A)
+
+	G := newGFp2(pool).Square(E, pool)
+
+	rOut = newTwistPoint(pool)
+	rOut.x.Sub(G, D)
+	rOut.x.Sub(rOut.x, D)
+
+	rOut.z.Add(r.y, r.z)
+	rOut.z.Square(rOut.z, pool)
+	rOut.z.Sub(rOut.z, B)
+	rOut.z.Sub(rOut.z, r.t)
+
+	rOut.y.Sub(D, rOut.x)
+	rOut.y.Mul(rOut.y, E, pool)
+	t := newGFp2(pool).Add(C, C)
+	t.Add(t, t)
+	t.Add(t, t)
+	rOut.y.Sub(rOut.y, t)
+
+	rOut.t.Square(rOut.z, pool)
+
+	t.Mul(E, r.t, pool)
+	t.Add(t, t)
+	b = newGFp2(pool)
+	b.SetZero()
+	b.Sub(b, t)
+	b.MulScalar(b, q.x)
+
+	a = newGFp2(pool)
+	a.Add(r.x, E)
+	a.Square(a, pool)
+	a.Sub(a, A)
+	a.Sub(a, G)
+	t.Add(B, B)
+	t.Add(t, t)
+	a.Sub(a, t)
+
+	c = newGFp2(pool)
+	c.Mul(rOut.z, r.t, pool)
+	c.Add(c, c)
+	c.MulScalar(c, q.y)
+
+	A.Put(pool)
+	B.Put(pool)
+	C.Put(pool)
+	D.Put(pool)
+	E.Put(pool)
+	G.Put(pool)
+	t.Put(pool)
+
+	return
+}
+
+func mulLine(ret *gfP12, a, b, c *gfP2, pool *bnPool) {
+	a2 := newGFp6(pool)
+	a2.x.SetZero()
+	a2.y.Set(a)
+	a2.z.Set(b)
+	a2.Mul(a2, ret.x, pool)
+	t3 := newGFp6(pool).MulScalar(ret.y, c, pool)
+
+	t := newGFp2(pool)
+	t.Add(b, c)
+	t2 := newGFp6(pool)
+	t2.x.SetZero()
+	t2.y.Set(a)
+	t2.z.Set(t)
+	ret.x.Add(ret.x, ret.y)
+
+	ret.y.Set(t3)
+
+	ret.x.Mul(ret.x, t2, pool)
+	ret.x.Sub(ret.x, a2)
+	ret.x.Sub(ret.x, ret.y)
+	a2.MulTau(a2, pool)
+	ret.y.Add(ret.y, a2)
+
+	a2.Put(pool)
+	t3.Put(pool)
+	t2.Put(pool)
+	t.Put(pool)
+}
+
+// sixuPlus2NAF is 6u+2 in non-adjacent form.
+var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 1}
+
+// miller implements the Miller loop for calculating the Optimal Ate pairing.
+// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
+func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 {
+	ret := newGFp12(pool)
+	ret.SetOne()
+
+	aAffine := newTwistPoint(pool)
+	aAffine.Set(q)
+	aAffine.MakeAffine(pool)
+
+	bAffine := newCurvePoint(pool)
+	bAffine.Set(p)
+	bAffine.MakeAffine(pool)
+
+	minusA := newTwistPoint(pool)
+	minusA.Negative(aAffine, pool)
+
+	r := newTwistPoint(pool)
+	r.Set(aAffine)
+
+	r2 := newGFp2(pool)
+	r2.Square(aAffine.y, pool)
+
+	for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
+		a, b, c, newR := lineFunctionDouble(r, bAffine, pool)
+		if i != len(sixuPlus2NAF)-1 {
+			ret.Square(ret, pool)
+		}
+
+		mulLine(ret, a, b, c, pool)
+		a.Put(pool)
+		b.Put(pool)
+		c.Put(pool)
+		r.Put(pool)
+		r = newR
+
+		switch sixuPlus2NAF[i-1] {
+		case 1:
+			a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool)
+		case -1:
+			a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool)
+		default:
+			continue
+		}
+
+		mulLine(ret, a, b, c, pool)
+		a.Put(pool)
+		b.Put(pool)
+		c.Put(pool)
+		r.Put(pool)
+		r = newR
+	}
+
+	// In order to calculate Q1 we have to convert q from the sextic twist
+	// to the full GF(p^12) group, apply the Frobenius there, and convert
+	// back.
+	//
+	// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
+	// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
+	// where x̄ is the conjugate of x. If we are going to apply the inverse
+	// isomorphism we need a value with a single coefficient of ω² so we
+	// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
+	// p, 2p-2 is a multiple of six. Therefore we can rewrite as
+	// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
+	// ω².
+	//
+	// A similar argument can be made for the y value.
+
+	q1 := newTwistPoint(pool)
+	q1.x.Conjugate(aAffine.x)
+	q1.x.Mul(q1.x, xiToPMinus1Over3, pool)
+	q1.y.Conjugate(aAffine.y)
+	q1.y.Mul(q1.y, xiToPMinus1Over2, pool)
+	q1.z.SetOne()
+	q1.t.SetOne()
+
+	// For Q2 we are applying the p² Frobenius. The two conjugations cancel
+	// out and we are left only with the factors from the isomorphism. In
+	// the case of x, we end up with a pure number which is why
+	// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
+	// ignore this to end up with -Q2.
+
+	minusQ2 := newTwistPoint(pool)
+	minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3)
+	minusQ2.y.Set(aAffine.y)
+	minusQ2.z.SetOne()
+	minusQ2.t.SetOne()
+
+	r2.Square(q1.y, pool)
+	a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool)
+	mulLine(ret, a, b, c, pool)
+	a.Put(pool)
+	b.Put(pool)
+	c.Put(pool)
+	r.Put(pool)
+	r = newR
+
+	r2.Square(minusQ2.y, pool)
+	a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool)
+	mulLine(ret, a, b, c, pool)
+	a.Put(pool)
+	b.Put(pool)
+	c.Put(pool)
+	r.Put(pool)
+	r = newR
+
+	aAffine.Put(pool)
+	bAffine.Put(pool)
+	minusA.Put(pool)
+	r.Put(pool)
+	r2.Put(pool)
+
+	return ret
+}
+
+// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
+// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
+// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
+func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 {
+	t1 := newGFp12(pool)
+
+	// This is the p^6-Frobenius
+	t1.x.Negative(in.x)
+	t1.y.Set(in.y)
+
+	inv := newGFp12(pool)
+	inv.Invert(in, pool)
+	t1.Mul(t1, inv, pool)
+
+	t2 := newGFp12(pool).FrobeniusP2(t1, pool)
+	t1.Mul(t1, t2, pool)
+
+	fp := newGFp12(pool).Frobenius(t1, pool)
+	fp2 := newGFp12(pool).FrobeniusP2(t1, pool)
+	fp3 := newGFp12(pool).Frobenius(fp2, pool)
+
+	fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
+	fu.Exp(t1, u, pool)
+	fu2.Exp(fu, u, pool)
+	fu3.Exp(fu2, u, pool)
+
+	y3 := newGFp12(pool).Frobenius(fu, pool)
+	fu2p := newGFp12(pool).Frobenius(fu2, pool)
+	fu3p := newGFp12(pool).Frobenius(fu3, pool)
+	y2 := newGFp12(pool).FrobeniusP2(fu2, pool)
+
+	y0 := newGFp12(pool)
+	y0.Mul(fp, fp2, pool)
+	y0.Mul(y0, fp3, pool)
+
+	y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
+	y1.Conjugate(t1)
+	y5.Conjugate(fu2)
+	y3.Conjugate(y3)
+	y4.Mul(fu, fu2p, pool)
+	y4.Conjugate(y4)
+
+	y6 := newGFp12(pool)
+	y6.Mul(fu3, fu3p, pool)
+	y6.Conjugate(y6)
+
+	t0 := newGFp12(pool)
+	t0.Square(y6, pool)
+	t0.Mul(t0, y4, pool)
+	t0.Mul(t0, y5, pool)
+	t1.Mul(y3, y5, pool)
+	t1.Mul(t1, t0, pool)
+	t0.Mul(t0, y2, pool)
+	t1.Square(t1, pool)
+	t1.Mul(t1, t0, pool)
+	t1.Square(t1, pool)
+	t0.Mul(t1, y1, pool)
+	t1.Mul(t1, y0, pool)
+	t0.Square(t0, pool)
+	t0.Mul(t0, t1, pool)
+
+	inv.Put(pool)
+	t1.Put(pool)
+	t2.Put(pool)
+	fp.Put(pool)
+	fp2.Put(pool)
+	fp3.Put(pool)
+	fu.Put(pool)
+	fu2.Put(pool)
+	fu3.Put(pool)
+	fu2p.Put(pool)
+	fu3p.Put(pool)
+	y0.Put(pool)
+	y1.Put(pool)
+	y2.Put(pool)
+	y3.Put(pool)
+	y4.Put(pool)
+	y5.Put(pool)
+	y6.Put(pool)
+
+	return t0
+}
+
+func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 {
+	e := miller(a, b, pool)
+	ret := finalExponentiation(e, pool)
+	e.Put(pool)
+
+	if a.IsInfinity() || b.IsInfinity() {
+		ret.SetOne()
+	}
+
+	return ret
+}

+ 258 - 0
src/golang.org/x/crypto/bn256/twist.go

@@ -0,0 +1,258 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+	"math/big"
+)
+
+// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
+// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
+// n-torsion points of this curve over GF(p²) (where n = Order)
+type twistPoint struct {
+	x, y, z, t *gfP2
+}
+
+var twistB = &gfP2{
+	bigFromBase10("6500054969564660373279643874235990574282535810762300357187714502686418407178"),
+	bigFromBase10("45500384786952622612957507119651934019977750675336102500314001518804928850249"),
+}
+
+// twistGen is the generator of group G₂.
+var twistGen = &twistPoint{
+	&gfP2{
+		bigFromBase10("21167961636542580255011770066570541300993051739349375019639421053990175267184"),
+		bigFromBase10("64746500191241794695844075326670126197795977525365406531717464316923369116492"),
+	},
+	&gfP2{
+		bigFromBase10("20666913350058776956210519119118544732556678129809273996262322366050359951122"),
+		bigFromBase10("17778617556404439934652658462602675281523610326338642107814333856843981424549"),
+	},
+	&gfP2{
+		bigFromBase10("0"),
+		bigFromBase10("1"),
+	},
+	&gfP2{
+		bigFromBase10("0"),
+		bigFromBase10("1"),
+	},
+}
+
+func newTwistPoint(pool *bnPool) *twistPoint {
+	return &twistPoint{
+		newGFp2(pool),
+		newGFp2(pool),
+		newGFp2(pool),
+		newGFp2(pool),
+	}
+}
+
+func (c *twistPoint) String() string {
+	return "(" + c.x.String() + ", " + c.y.String() + ", " + c.z.String() + ")"
+}
+
+func (c *twistPoint) Put(pool *bnPool) {
+	c.x.Put(pool)
+	c.y.Put(pool)
+	c.z.Put(pool)
+	c.t.Put(pool)
+}
+
+func (c *twistPoint) Set(a *twistPoint) {
+	c.x.Set(a.x)
+	c.y.Set(a.y)
+	c.z.Set(a.z)
+	c.t.Set(a.t)
+}
+
+// IsOnCurve returns true iff c is on the curve where c must be in affine form.
+func (c *twistPoint) IsOnCurve() bool {
+	pool := new(bnPool)
+	yy := newGFp2(pool).Square(c.y, pool)
+	xxx := newGFp2(pool).Square(c.x, pool)
+	xxx.Mul(xxx, c.x, pool)
+	yy.Sub(yy, xxx)
+	yy.Sub(yy, twistB)
+	yy.Minimal()
+	return yy.x.Sign() == 0 && yy.y.Sign() == 0
+}
+
+func (c *twistPoint) SetInfinity() {
+	c.z.SetZero()
+}
+
+func (c *twistPoint) IsInfinity() bool {
+	return c.z.IsZero()
+}
+
+func (c *twistPoint) Add(a, b *twistPoint, pool *bnPool) {
+	// For additional comments, see the same function in curve.go.
+
+	if a.IsInfinity() {
+		c.Set(b)
+		return
+	}
+	if b.IsInfinity() {
+		c.Set(a)
+		return
+	}
+
+	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
+	z1z1 := newGFp2(pool).Square(a.z, pool)
+	z2z2 := newGFp2(pool).Square(b.z, pool)
+	u1 := newGFp2(pool).Mul(a.x, z2z2, pool)
+	u2 := newGFp2(pool).Mul(b.x, z1z1, pool)
+
+	t := newGFp2(pool).Mul(b.z, z2z2, pool)
+	s1 := newGFp2(pool).Mul(a.y, t, pool)
+
+	t.Mul(a.z, z1z1, pool)
+	s2 := newGFp2(pool).Mul(b.y, t, pool)
+
+	h := newGFp2(pool).Sub(u2, u1)
+	xEqual := h.IsZero()
+
+	t.Add(h, h)
+	i := newGFp2(pool).Square(t, pool)
+	j := newGFp2(pool).Mul(h, i, pool)
+
+	t.Sub(s2, s1)
+	yEqual := t.IsZero()
+	if xEqual && yEqual {
+		c.Double(a, pool)
+		return
+	}
+	r := newGFp2(pool).Add(t, t)
+
+	v := newGFp2(pool).Mul(u1, i, pool)
+
+	t4 := newGFp2(pool).Square(r, pool)
+	t.Add(v, v)
+	t6 := newGFp2(pool).Sub(t4, j)
+	c.x.Sub(t6, t)
+
+	t.Sub(v, c.x)       // t7
+	t4.Mul(s1, j, pool) // t8
+	t6.Add(t4, t4)      // t9
+	t4.Mul(r, t, pool)  // t10
+	c.y.Sub(t4, t6)
+
+	t.Add(a.z, b.z)    // t11
+	t4.Square(t, pool) // t12
+	t.Sub(t4, z1z1)    // t13
+	t4.Sub(t, z2z2)    // t14
+	c.z.Mul(t4, h, pool)
+
+	z1z1.Put(pool)
+	z2z2.Put(pool)
+	u1.Put(pool)
+	u2.Put(pool)
+	t.Put(pool)
+	s1.Put(pool)
+	s2.Put(pool)
+	h.Put(pool)
+	i.Put(pool)
+	j.Put(pool)
+	r.Put(pool)
+	v.Put(pool)
+	t4.Put(pool)
+	t6.Put(pool)
+}
+
+func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
+	// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
+	A := newGFp2(pool).Square(a.x, pool)
+	B := newGFp2(pool).Square(a.y, pool)
+	C := newGFp2(pool).Square(B, pool)
+
+	t := newGFp2(pool).Add(a.x, B)
+	t2 := newGFp2(pool).Square(t, pool)
+	t.Sub(t2, A)
+	t2.Sub(t, C)
+	d := newGFp2(pool).Add(t2, t2)
+	t.Add(A, A)
+	e := newGFp2(pool).Add(t, A)
+	f := newGFp2(pool).Square(e, pool)
+
+	t.Add(d, d)
+	c.x.Sub(f, t)
+
+	t.Add(C, C)
+	t2.Add(t, t)
+	t.Add(t2, t2)
+	c.y.Sub(d, c.x)
+	t2.Mul(e, c.y, pool)
+	c.y.Sub(t2, t)
+
+	t.Mul(a.y, a.z, pool)
+	c.z.Add(t, t)
+
+	A.Put(pool)
+	B.Put(pool)
+	C.Put(pool)
+	t.Put(pool)
+	t2.Put(pool)
+	d.Put(pool)
+	e.Put(pool)
+	f.Put(pool)
+}
+
+func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoint {
+	sum := newTwistPoint(pool)
+	sum.SetInfinity()
+	t := newTwistPoint(pool)
+
+	for i := scalar.BitLen(); i >= 0; i-- {
+		t.Double(sum, pool)
+		if scalar.Bit(i) != 0 {
+			sum.Add(t, a, pool)
+		} else {
+			sum.Set(t)
+		}
+	}
+
+	c.Set(sum)
+	sum.Put(pool)
+	t.Put(pool)
+	return c
+}
+
+// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
+// c to 0 : 1 : 0.
+func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint {
+	if c.z.IsOne() {
+		return c
+	}
+	if c.IsInfinity() {
+		c.x.SetZero()
+		c.y.SetOne()
+		c.z.SetZero()
+		c.t.SetZero()
+		return c
+	}
+
+	zInv := newGFp2(pool).Invert(c.z, pool)
+	t := newGFp2(pool).Mul(c.y, zInv, pool)
+	zInv2 := newGFp2(pool).Square(zInv, pool)
+	c.y.Mul(t, zInv2, pool)
+	t.Mul(c.x, zInv2, pool)
+	c.x.Set(t)
+	c.z.SetOne()
+	c.t.SetOne()
+
+	zInv.Put(pool)
+	t.Put(pool)
+	zInv2.Put(pool)
+
+	return c
+}
+
+func (c *twistPoint) Negative(a *twistPoint, pool *bnPool) {
+	c.x.Set(a.x)
+	c.y.SetZero()
+	c.y.Sub(c.y, a.y)
+	c.z.Set(a.z)
+	c.t.SetZero()
+}

+ 526 - 0
src/golang.org/x/crypto/cast5/cast5.go

@@ -0,0 +1,526 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
+// OpenPGP cipher.
+package cast5 // import "golang.org/x/crypto/cast5"
+
+import "errors"
+
+const BlockSize = 8
+const KeySize = 16
+
+type Cipher struct {
+	masking [16]uint32
+	rotate  [16]uint8
+}
+
+func NewCipher(key []byte) (c *Cipher, err error) {
+	if len(key) != KeySize {
+		return nil, errors.New("CAST5: keys must be 16 bytes")
+	}
+
+	c = new(Cipher)
+	c.keySchedule(key)
+	return
+}
+
+func (c *Cipher) BlockSize() int {
+	return BlockSize
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+	l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+	l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+	l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+	l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+
+	l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+	l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+	l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+	l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+
+	l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+	l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+	l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+	l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+
+	l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+	l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+	l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+	l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+
+	dst[0] = uint8(r >> 24)
+	dst[1] = uint8(r >> 16)
+	dst[2] = uint8(r >> 8)
+	dst[3] = uint8(r)
+	dst[4] = uint8(l >> 24)
+	dst[5] = uint8(l >> 16)
+	dst[6] = uint8(l >> 8)
+	dst[7] = uint8(l)
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+	l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+	l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+	l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+	l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+
+	l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+	l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+	l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+	l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+
+	l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+	l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+	l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+	l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+
+	l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+	l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+	l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+	l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+
+	dst[0] = uint8(r >> 24)
+	dst[1] = uint8(r >> 16)
+	dst[2] = uint8(r >> 8)
+	dst[3] = uint8(r)
+	dst[4] = uint8(l >> 24)
+	dst[5] = uint8(l >> 16)
+	dst[6] = uint8(l >> 8)
+	dst[7] = uint8(l)
+}
+
+type keyScheduleA [4][7]uint8
+type keyScheduleB [4][5]uint8
+
+// keyScheduleRound contains the magic values for a round of the key schedule.
+// The keyScheduleA deals with the lines like:
+//   z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
+// Conceptually, both x and z are in the same array, x first. The first
+// element describes which word of this array gets written to and the
+// second, which word gets read. So, for the line above, it's "4, 0", because
+// it's writing to the first word of z, which, being after x, is word 4, and
+// reading from the first word of x: word 0.
+//
+// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
+// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
+// that it's z that we're indexing.
+//
+// keyScheduleB deals with lines like:
+//   K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
+// "K1" is ignored because key words are always written in order. So the five
+// elements are the S-box indexes. They use the same form as in keyScheduleA,
+// above.
+
+type keyScheduleRound struct{}
+type keySchedule []keyScheduleRound
+
+var schedule = []struct {
+	a keyScheduleA
+	b keyScheduleB
+}{
+	{
+		keyScheduleA{
+			{4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
+			{5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+			{6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+			{7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+		},
+		keyScheduleB{
+			{16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
+			{16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
+			{16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
+			{16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
+		},
+	},
+	{
+		keyScheduleA{
+			{0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+			{1, 4, 0, 2, 1, 3, 16 + 2},
+			{2, 5, 7, 6, 5, 4, 16 + 1},
+			{3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+		},
+		keyScheduleB{
+			{3, 2, 0xc, 0xd, 8},
+			{1, 0, 0xe, 0xf, 0xd},
+			{7, 6, 8, 9, 3},
+			{5, 4, 0xa, 0xb, 7},
+		},
+	},
+	{
+		keyScheduleA{
+			{4, 0, 0xd, 0xf, 0xc, 0xe, 8},
+			{5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+			{6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+			{7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+		},
+		keyScheduleB{
+			{16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
+			{16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
+			{16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
+			{16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
+		},
+	},
+	{
+		keyScheduleA{
+			{0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+			{1, 4, 0, 2, 1, 3, 16 + 2},
+			{2, 5, 7, 6, 5, 4, 16 + 1},
+			{3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+		},
+		keyScheduleB{
+			{8, 9, 7, 6, 3},
+			{0xa, 0xb, 5, 4, 7},
+			{0xc, 0xd, 3, 2, 8},
+			{0xe, 0xf, 1, 0, 0xd},
+		},
+	},
+}
+
+func (c *Cipher) keySchedule(in []byte) {
+	var t [8]uint32
+	var k [32]uint32
+
+	for i := 0; i < 4; i++ {
+		j := i * 4
+		t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
+	}
+
+	x := []byte{6, 7, 4, 5}
+	ki := 0
+
+	for half := 0; half < 2; half++ {
+		for _, round := range schedule {
+			for j := 0; j < 4; j++ {
+				var a [7]uint8
+				copy(a[:], round.a[j][:])
+				w := t[a[1]]
+				w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
+				w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
+				w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
+				w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
+				w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
+				t[a[0]] = w
+			}
+
+			for j := 0; j < 4; j++ {
+				var b [5]uint8
+				copy(b[:], round.b[j][:])
+				w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
+				w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
+				w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
+				w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
+				w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
+				k[ki] = w
+				ki++
+			}
+		}
+	}
+
+	for i := 0; i < 16; i++ {
+		c.masking[i] = k[i]
+		c.rotate[i] = uint8(k[16+i] & 0x1f)
+	}
+}
+
+// These are the three 'f' functions. See RFC 2144, section 2.2.
+func f1(d, m uint32, r uint8) uint32 {
+	t := m + d
+	I := (t << r) | (t >> (32 - r))
+	return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
+}
+
+func f2(d, m uint32, r uint8) uint32 {
+	t := m ^ d
+	I := (t << r) | (t >> (32 - r))
+	return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
+}
+
+func f3(d, m uint32, r uint8) uint32 {
+	t := m - d
+	I := (t << r) | (t >> (32 - r))
+	return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
+}
+
+var sBox = [8][256]uint32{
+	{
+		0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+		0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+		0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+		0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+		0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+		0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+		0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+		0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+		0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+		0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+		0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+		0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+		0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+		0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+		0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+		0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+		0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+		0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+		0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+		0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+		0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+		0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+		0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+		0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+		0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+		0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+		0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+		0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+		0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+		0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+		0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+		0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
+	},
+	{
+		0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+		0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+		0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+		0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+		0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+		0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+		0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+		0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+		0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+		0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+		0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+		0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+		0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+		0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+		0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+		0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+		0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+		0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+		0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+		0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+		0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+		0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+		0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+		0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+		0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+		0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+		0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+		0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+		0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+		0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+		0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+		0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
+	},
+	{
+		0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+		0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+		0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+		0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+		0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+		0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+		0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+		0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+		0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+		0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+		0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+		0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+		0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+		0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+		0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+		0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+		0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+		0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+		0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+		0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+		0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+		0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+		0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+		0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+		0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+		0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+		0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+		0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+		0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+		0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+		0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+		0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
+	},
+	{
+		0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+		0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+		0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+		0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+		0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+		0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+		0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+		0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+		0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+		0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+		0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+		0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+		0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+		0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+		0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+		0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+		0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+		0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+		0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+		0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+		0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+		0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+		0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+		0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+		0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+		0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+		0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+		0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+		0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+		0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+		0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+		0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
+	},
+	{
+		0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+		0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+		0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+		0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+		0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+		0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+		0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+		0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+		0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+		0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+		0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+		0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+		0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+		0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+		0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+		0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+		0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+		0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+		0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+		0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+		0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+		0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+		0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+		0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+		0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+		0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+		0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+		0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+		0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+		0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+		0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+		0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
+	},
+	{
+		0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+		0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+		0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+		0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+		0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+		0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+		0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+		0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+		0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+		0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+		0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+		0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+		0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+		0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+		0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+		0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+		0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+		0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+		0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+		0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+		0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+		0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+		0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+		0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+		0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+		0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+		0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+		0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+		0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+		0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+		0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+		0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
+	},
+	{
+		0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+		0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+		0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+		0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+		0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+		0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+		0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+		0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+		0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+		0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+		0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+		0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+		0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+		0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+		0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+		0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+		0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+		0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+		0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+		0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+		0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+		0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+		0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+		0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+		0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+		0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+		0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+		0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+		0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+		0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+		0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+		0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
+	},
+	{
+		0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+		0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+		0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+		0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+		0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+		0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+		0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+		0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+		0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+		0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+		0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+		0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+		0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+		0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+		0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+		0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+		0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+		0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+		0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+		0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+		0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+		0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+		0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+		0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+		0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+		0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+		0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+		0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+		0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+		0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+		0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+		0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
+	},
+}

+ 106 - 0
src/golang.org/x/crypto/cast5/cast5_test.go

@@ -0,0 +1,106 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cast5
+
+import (
+	"bytes"
+	"encoding/hex"
+	"testing"
+)
+
+// This test vector is taken from RFC 2144, App B.1.
+// Since the other two test vectors are for reduced-round variants, we can't
+// use them.
+var basicTests = []struct {
+	key, plainText, cipherText string
+}{
+	{
+		"0123456712345678234567893456789a",
+		"0123456789abcdef",
+		"238b4fe5847e44b2",
+	},
+}
+
+func TestBasic(t *testing.T) {
+	for i, test := range basicTests {
+		key, _ := hex.DecodeString(test.key)
+		plainText, _ := hex.DecodeString(test.plainText)
+		expected, _ := hex.DecodeString(test.cipherText)
+
+		c, err := NewCipher(key)
+		if err != nil {
+			t.Errorf("#%d: failed to create Cipher: %s", i, err)
+			continue
+		}
+		var cipherText [BlockSize]byte
+		c.Encrypt(cipherText[:], plainText)
+		if !bytes.Equal(cipherText[:], expected) {
+			t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
+		}
+
+		var plainTextAgain [BlockSize]byte
+		c.Decrypt(plainTextAgain[:], cipherText[:])
+		if !bytes.Equal(plainTextAgain[:], plainText) {
+			t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
+		}
+	}
+}
+
+// TestFull performs the test specified in RFC 2144, App B.2.
+// However, due to the length of time taken, it's disabled here and a more
+// limited version is included, below.
+func TestFull(t *testing.T) {
+	if testing.Short() {
+		// This is too slow for normal testing
+		return
+	}
+
+	a, b := iterate(1000000)
+
+	const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
+	const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
+
+	if hex.EncodeToString(a) != expectedA {
+		t.Errorf("a: got:%x want:%s", a, expectedA)
+	}
+	if hex.EncodeToString(b) != expectedB {
+		t.Errorf("b: got:%x want:%s", b, expectedB)
+	}
+}
+
+func iterate(iterations int) ([]byte, []byte) {
+	const initValueHex = "0123456712345678234567893456789a"
+
+	initValue, _ := hex.DecodeString(initValueHex)
+
+	var a, b [16]byte
+	copy(a[:], initValue)
+	copy(b[:], initValue)
+
+	for i := 0; i < iterations; i++ {
+		c, _ := NewCipher(b[:])
+		c.Encrypt(a[:8], a[:8])
+		c.Encrypt(a[8:], a[8:])
+		c, _ = NewCipher(a[:])
+		c.Encrypt(b[:8], b[:8])
+		c.Encrypt(b[8:], b[8:])
+	}
+
+	return a[:], b[:]
+}
+
+func TestLimited(t *testing.T) {
+	a, b := iterate(1000)
+
+	const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
+	const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
+
+	if hex.EncodeToString(a) != expectedA {
+		t.Errorf("a: got:%x want:%s", a, expectedA)
+	}
+	if hex.EncodeToString(b) != expectedB {
+		t.Errorf("b: got:%x want:%s", b, expectedB)
+	}
+}

+ 101 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go

@@ -0,0 +1,101 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539,
+// and its extended nonce variant XChaCha20-Poly1305.
+package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
+
+import (
+	"crypto/cipher"
+	"encoding/binary"
+	"errors"
+)
+
+const (
+	// KeySize is the size of the key used by this AEAD, in bytes.
+	KeySize = 32
+
+	// NonceSize is the size of the nonce used with the standard variant of this
+	// AEAD, in bytes.
+	//
+	// Note that this is too short to be safely generated at random if the same
+	// key is reused more than 2³² times.
+	NonceSize = 12
+
+	// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
+	// variant of this AEAD, in bytes.
+	NonceSizeX = 24
+)
+
+type chacha20poly1305 struct {
+	key [8]uint32
+}
+
+// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
+func New(key []byte) (cipher.AEAD, error) {
+	if len(key) != KeySize {
+		return nil, errors.New("chacha20poly1305: bad key length")
+	}
+	ret := new(chacha20poly1305)
+	ret.key[0] = binary.LittleEndian.Uint32(key[0:4])
+	ret.key[1] = binary.LittleEndian.Uint32(key[4:8])
+	ret.key[2] = binary.LittleEndian.Uint32(key[8:12])
+	ret.key[3] = binary.LittleEndian.Uint32(key[12:16])
+	ret.key[4] = binary.LittleEndian.Uint32(key[16:20])
+	ret.key[5] = binary.LittleEndian.Uint32(key[20:24])
+	ret.key[6] = binary.LittleEndian.Uint32(key[24:28])
+	ret.key[7] = binary.LittleEndian.Uint32(key[28:32])
+	return ret, nil
+}
+
+func (c *chacha20poly1305) NonceSize() int {
+	return NonceSize
+}
+
+func (c *chacha20poly1305) Overhead() int {
+	return 16
+}
+
+func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	if len(nonce) != NonceSize {
+		panic("chacha20poly1305: bad nonce length passed to Seal")
+	}
+
+	if uint64(len(plaintext)) > (1<<38)-64 {
+		panic("chacha20poly1305: plaintext too large")
+	}
+
+	return c.seal(dst, nonce, plaintext, additionalData)
+}
+
+var errOpen = errors.New("chacha20poly1305: message authentication failed")
+
+func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	if len(nonce) != NonceSize {
+		panic("chacha20poly1305: bad nonce length passed to Open")
+	}
+	if len(ciphertext) < 16 {
+		return nil, errOpen
+	}
+	if uint64(len(ciphertext)) > (1<<38)-48 {
+		panic("chacha20poly1305: ciphertext too large")
+	}
+
+	return c.open(dst, nonce, ciphertext, additionalData)
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+	if total := len(in) + n; cap(in) >= total {
+		head = in[:total]
+	} else {
+		head = make([]byte, total)
+		copy(head, in)
+	}
+	tail = head[len(in):]
+	return
+}

+ 86 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go

@@ -0,0 +1,86 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+package chacha20poly1305
+
+import (
+	"encoding/binary"
+
+	"golang.org/x/crypto/internal/subtle"
+	"golang.org/x/sys/cpu"
+)
+
+//go:noescape
+func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
+
+//go:noescape
+func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
+
+var (
+	useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
+)
+
+// setupState writes a ChaCha20 input matrix to state. See
+// https://tools.ietf.org/html/rfc7539#section-2.3.
+func setupState(state *[16]uint32, key *[8]uint32, nonce []byte) {
+	state[0] = 0x61707865
+	state[1] = 0x3320646e
+	state[2] = 0x79622d32
+	state[3] = 0x6b206574
+
+	state[4] = key[0]
+	state[5] = key[1]
+	state[6] = key[2]
+	state[7] = key[3]
+	state[8] = key[4]
+	state[9] = key[5]
+	state[10] = key[6]
+	state[11] = key[7]
+
+	state[12] = 0
+	state[13] = binary.LittleEndian.Uint32(nonce[:4])
+	state[14] = binary.LittleEndian.Uint32(nonce[4:8])
+	state[15] = binary.LittleEndian.Uint32(nonce[8:12])
+}
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	if !cpu.X86.HasSSSE3 {
+		return c.sealGeneric(dst, nonce, plaintext, additionalData)
+	}
+
+	var state [16]uint32
+	setupState(&state, &c.key, nonce)
+
+	ret, out := sliceForAppend(dst, len(plaintext)+16)
+	if subtle.InexactOverlap(out, plaintext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+	chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
+	return ret
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	if !cpu.X86.HasSSSE3 {
+		return c.openGeneric(dst, nonce, ciphertext, additionalData)
+	}
+
+	var state [16]uint32
+	setupState(&state, &c.key, nonce)
+
+	ciphertext = ciphertext[:len(ciphertext)-16]
+	ret, out := sliceForAppend(dst, len(ciphertext))
+	if subtle.InexactOverlap(out, ciphertext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+	if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
+		for i := range out {
+			out[i] = 0
+		}
+		return nil, errOpen
+	}
+
+	return ret, nil
+}

+ 2695 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s

@@ -0,0 +1,2695 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+#include "textflag.h"
+// General register allocation
+#define oup DI
+#define inp SI
+#define inl BX
+#define adp CX // free to reuse, after we hash the additional data
+#define keyp R8 // free to reuse, when we copy the key to stack
+#define itr2 R9 // general iterator
+#define itr1 CX // general iterator
+#define acc0 R10
+#define acc1 R11
+#define acc2 R12
+#define t0 R13
+#define t1 R14
+#define t2 R15
+#define t3 R8
+// Register and stack allocation for the SSE code
+#define rStore (0*16)(BP)
+#define sStore (1*16)(BP)
+#define state1Store (2*16)(BP)
+#define state2Store (3*16)(BP)
+#define tmpStore (4*16)(BP)
+#define ctr0Store (5*16)(BP)
+#define ctr1Store (6*16)(BP)
+#define ctr2Store (7*16)(BP)
+#define ctr3Store (8*16)(BP)
+#define A0 X0
+#define A1 X1
+#define A2 X2
+#define B0 X3
+#define B1 X4
+#define B2 X5
+#define C0 X6
+#define C1 X7
+#define C2 X8
+#define D0 X9
+#define D1 X10
+#define D2 X11
+#define T0 X12
+#define T1 X13
+#define T2 X14
+#define T3 X15
+#define A3 T0
+#define B3 T1
+#define C3 T2
+#define D3 T3
+// Register and stack allocation for the AVX2 code
+#define rsStoreAVX2 (0*32)(BP)
+#define state1StoreAVX2 (1*32)(BP)
+#define state2StoreAVX2 (2*32)(BP)
+#define ctr0StoreAVX2 (3*32)(BP)
+#define ctr1StoreAVX2 (4*32)(BP)
+#define ctr2StoreAVX2 (5*32)(BP)
+#define ctr3StoreAVX2 (6*32)(BP)
+#define tmpStoreAVX2 (7*32)(BP) // 256 bytes on stack
+#define AA0 Y0
+#define AA1 Y5
+#define AA2 Y6
+#define AA3 Y7
+#define BB0 Y14
+#define BB1 Y9
+#define BB2 Y10
+#define BB3 Y11
+#define CC0 Y12
+#define CC1 Y13
+#define CC2 Y8
+#define CC3 Y15
+#define DD0 Y4
+#define DD1 Y1
+#define DD2 Y2
+#define DD3 Y3
+#define TT0 DD3
+#define TT1 AA3
+#define TT2 BB3
+#define TT3 CC3
+// ChaCha20 constants
+DATA ·chacha20Constants<>+0x00(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+0x04(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+0x08(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+0x0c(SB)/4, $0x6b206574
+DATA ·chacha20Constants<>+0x10(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+0x14(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+0x18(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+0x1c(SB)/4, $0x6b206574
+// <<< 16 with PSHUFB
+DATA ·rol16<>+0x00(SB)/8, $0x0504070601000302
+DATA ·rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
+DATA ·rol16<>+0x10(SB)/8, $0x0504070601000302
+DATA ·rol16<>+0x18(SB)/8, $0x0D0C0F0E09080B0A
+// <<< 8 with PSHUFB
+DATA ·rol8<>+0x00(SB)/8, $0x0605040702010003
+DATA ·rol8<>+0x08(SB)/8, $0x0E0D0C0F0A09080B
+DATA ·rol8<>+0x10(SB)/8, $0x0605040702010003
+DATA ·rol8<>+0x18(SB)/8, $0x0E0D0C0F0A09080B
+
+DATA ·avx2InitMask<>+0x00(SB)/8, $0x0
+DATA ·avx2InitMask<>+0x08(SB)/8, $0x0
+DATA ·avx2InitMask<>+0x10(SB)/8, $0x1
+DATA ·avx2InitMask<>+0x18(SB)/8, $0x0
+
+DATA ·avx2IncMask<>+0x00(SB)/8, $0x2
+DATA ·avx2IncMask<>+0x08(SB)/8, $0x0
+DATA ·avx2IncMask<>+0x10(SB)/8, $0x2
+DATA ·avx2IncMask<>+0x18(SB)/8, $0x0
+// Poly1305 key clamp
+DATA ·polyClampMask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
+DATA ·polyClampMask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
+DATA ·polyClampMask<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA ·polyClampMask<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+
+DATA ·sseIncMask<>+0x00(SB)/8, $0x1
+DATA ·sseIncMask<>+0x08(SB)/8, $0x0
+// To load/store the last < 16 bytes in a buffer
+DATA ·andMask<>+0x00(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+0x08(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x10(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+0x18(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x20(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+0x28(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x30(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+0x38(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x40(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+0x48(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x50(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+0x58(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x60(SB)/8, $0x00ffffffffffffff
+DATA ·andMask<>+0x68(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x70(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x78(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x80(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x88(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+0x90(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x98(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+0xa0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xa8(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+0xb0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xb8(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+0xc0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xc8(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+0xd0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xd8(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+0xe0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xe8(SB)/8, $0x00ffffffffffffff
+
+GLOBL ·chacha20Constants<>(SB), (NOPTR+RODATA), $32
+GLOBL ·rol16<>(SB), (NOPTR+RODATA), $32
+GLOBL ·rol8<>(SB), (NOPTR+RODATA), $32
+GLOBL ·sseIncMask<>(SB), (NOPTR+RODATA), $16
+GLOBL ·avx2IncMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·avx2InitMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·polyClampMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
+// No PALIGNR in Go ASM yet (but VPALIGNR is present).
+#define shiftB0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X3, X3
+#define shiftB1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x04 // PALIGNR $4, X4, X4
+#define shiftB2Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X5, X5
+#define shiftB3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X13, X13
+#define shiftC0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X6, X6
+#define shiftC1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x08 // PALIGNR $8, X7, X7
+#define shiftC2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc0; BYTE $0x08 // PALIGNR $8, X8, X8
+#define shiftC3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X14, X14
+#define shiftD0Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x0c // PALIGNR $12, X9, X9
+#define shiftD1Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x0c // PALIGNR $12, X10, X10
+#define shiftD2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X11, X11
+#define shiftD3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x0c // PALIGNR $12, X15, X15
+#define shiftB0Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X3, X3
+#define shiftB1Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x0c // PALIGNR $12, X4, X4
+#define shiftB2Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X5, X5
+#define shiftB3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X13, X13
+#define shiftC0Right shiftC0Left
+#define shiftC1Right shiftC1Left
+#define shiftC2Right shiftC2Left
+#define shiftC3Right shiftC3Left
+#define shiftD0Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x04 // PALIGNR $4, X9, X9
+#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10
+#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11
+#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15
+// Some macros
+#define chachaQR(A, B, C, D, T) \
+	PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D                            \
+	PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \
+	PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D                             \
+	PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B
+
+#define chachaQR_AVX2(A, B, C, D, T) \
+	VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol16<>(SB), D, D                         \
+	VPADDD D, C, C; VPXOR C, B, B; VPSLLD $12, B, T; VPSRLD $20, B, B; VPXOR T, B, B \
+	VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol8<>(SB), D, D                          \
+	VPADDD D, C, C; VPXOR C, B, B; VPSLLD $7, B, T; VPSRLD $25, B, B; VPXOR T, B, B
+
+#define polyAdd(S) ADDQ S, acc0; ADCQ 8+S, acc1; ADCQ $1, acc2
+#define polyMulStage1 MOVQ (0*8)(BP), AX; MOVQ AX, t2; MULQ acc0; MOVQ AX, t0; MOVQ DX, t1; MOVQ (0*8)(BP), AX; MULQ acc1; IMULQ acc2, t2; ADDQ AX, t1; ADCQ DX, t2
+#define polyMulStage2 MOVQ (1*8)(BP), AX; MOVQ AX, t3; MULQ acc0; ADDQ AX, t1; ADCQ $0, DX; MOVQ DX, acc0; MOVQ (1*8)(BP), AX; MULQ acc1; ADDQ AX, t2; ADCQ $0, DX
+#define polyMulStage3 IMULQ acc2, t3; ADDQ acc0, t2; ADCQ DX, t3
+#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t2:t3; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2
+
+#define polyMulStage1_AVX2 MOVQ (0*8)(BP), DX; MOVQ DX, t2; MULXQ acc0, t0, t1; IMULQ acc2, t2; MULXQ acc1, AX, DX; ADDQ AX, t1; ADCQ DX, t2
+#define polyMulStage2_AVX2 MOVQ (1*8)(BP), DX; MULXQ acc0, acc0, AX; ADDQ acc0, t1; MULXQ acc1, acc1, t3; ADCQ acc1, t2; ADCQ $0, t3
+#define polyMulStage3_AVX2 IMULQ acc2, DX; ADDQ AX, t2; ADCQ DX, t3
+
+#define polyMul polyMulStage1; polyMulStage2; polyMulStage3; polyMulReduceStage
+#define polyMulAVX2 polyMulStage1_AVX2; polyMulStage2_AVX2; polyMulStage3_AVX2; polyMulReduceStage
+// ----------------------------------------------------------------------------
+TEXT polyHashADInternal<>(SB), NOSPLIT, $0
+	// adp points to beginning of additional data
+	// itr2 holds ad length
+	XORQ acc0, acc0
+	XORQ acc1, acc1
+	XORQ acc2, acc2
+	CMPQ itr2, $13
+	JNE  hashADLoop
+
+openFastTLSAD:
+	// Special treatment for the TLS case of 13 bytes
+	MOVQ (adp), acc0
+	MOVQ 5(adp), acc1
+	SHRQ $24, acc1
+	MOVQ $1, acc2
+	polyMul
+	RET
+
+hashADLoop:
+	// Hash in 16 byte chunks
+	CMPQ itr2, $16
+	JB   hashADTail
+	polyAdd(0(adp))
+	LEAQ (1*16)(adp), adp
+	SUBQ $16, itr2
+	polyMul
+	JMP  hashADLoop
+
+hashADTail:
+	CMPQ itr2, $0
+	JE   hashADDone
+
+	// Hash last < 16 byte tail
+	XORQ t0, t0
+	XORQ t1, t1
+	XORQ t2, t2
+	ADDQ itr2, adp
+
+hashADTailLoop:
+	SHLQ $8, t1:t0
+	SHLQ $8, t0
+	MOVB -1(adp), t2
+	XORQ t2, t0
+	DECQ adp
+	DECQ itr2
+	JNE  hashADTailLoop
+
+hashADTailFinish:
+	ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+
+	// Finished AD
+hashADDone:
+	RET
+
+// ----------------------------------------------------------------------------
+// func chacha20Poly1305Open(dst, key, src, ad []byte) bool
+TEXT ·chacha20Poly1305Open(SB), 0, $288-97
+	// For aligned stack access
+	MOVQ SP, BP
+	ADDQ $32, BP
+	ANDQ $-32, BP
+	MOVQ dst+0(FP), oup
+	MOVQ key+24(FP), keyp
+	MOVQ src+48(FP), inp
+	MOVQ src_len+56(FP), inl
+	MOVQ ad+72(FP), adp
+
+	// Check for AVX2 support
+	CMPB ·useAVX2(SB), $1
+	JE   chacha20Poly1305Open_AVX2
+
+	// Special optimization, for very short buffers
+	CMPQ inl, $128
+	JBE  openSSE128 // About 16% faster
+
+	// For long buffers, prepare the poly key first
+	MOVOU ·chacha20Constants<>(SB), A0
+	MOVOU (1*16)(keyp), B0
+	MOVOU (2*16)(keyp), C0
+	MOVOU (3*16)(keyp), D0
+	MOVO  D0, T1
+
+	// Store state on stack for future use
+	MOVO B0, state1Store
+	MOVO C0, state2Store
+	MOVO D0, ctr3Store
+	MOVQ $10, itr2
+
+openSSEPreparePolyKey:
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	DECQ          itr2
+	JNE           openSSEPreparePolyKey
+
+	// A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+	PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0
+
+	// Clamp and store the key
+	PAND ·polyClampMask<>(SB), A0
+	MOVO A0, rStore; MOVO B0, sStore
+
+	// Hash AAD
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+openSSEMainLoop:
+	CMPQ inl, $256
+	JB   openSSEMainLoopDone
+
+	// Load state, increment counter blocks
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+
+	// There are 10 ChaCha20 iterations of 2QR each, so for 6 iterations we hash 2 blocks, and for the remaining 4 only 1 block - for a total of 16
+	MOVQ $4, itr1
+	MOVQ inp, itr2
+
+openSSEInternalLoop:
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyAdd(0(itr2))
+	shiftB0Left;  shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left;  shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left;  shiftD1Left; shiftD2Left; shiftD3Left
+	polyMulStage1
+	polyMulStage2
+	LEAQ          (2*8)(itr2), itr2
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	polyMulStage3
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyMulReduceStage
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	DECQ          itr1
+	JGE           openSSEInternalLoop
+
+	polyAdd(0(itr2))
+	polyMul
+	LEAQ (2*8)(itr2), itr2
+
+	CMPQ itr1, $-6
+	JG   openSSEInternalLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+
+	// Load - xor - store
+	MOVO  D3, tmpStore
+	MOVOU (0*16)(inp), D3; PXOR D3, A0; MOVOU A0, (0*16)(oup)
+	MOVOU (1*16)(inp), D3; PXOR D3, B0; MOVOU B0, (1*16)(oup)
+	MOVOU (2*16)(inp), D3; PXOR D3, C0; MOVOU C0, (2*16)(oup)
+	MOVOU (3*16)(inp), D3; PXOR D3, D0; MOVOU D0, (3*16)(oup)
+	MOVOU (4*16)(inp), D0; PXOR D0, A1; MOVOU A1, (4*16)(oup)
+	MOVOU (5*16)(inp), D0; PXOR D0, B1; MOVOU B1, (5*16)(oup)
+	MOVOU (6*16)(inp), D0; PXOR D0, C1; MOVOU C1, (6*16)(oup)
+	MOVOU (7*16)(inp), D0; PXOR D0, D1; MOVOU D1, (7*16)(oup)
+	MOVOU (8*16)(inp), D0; PXOR D0, A2; MOVOU A2, (8*16)(oup)
+	MOVOU (9*16)(inp), D0; PXOR D0, B2; MOVOU B2, (9*16)(oup)
+	MOVOU (10*16)(inp), D0; PXOR D0, C2; MOVOU C2, (10*16)(oup)
+	MOVOU (11*16)(inp), D0; PXOR D0, D2; MOVOU D2, (11*16)(oup)
+	MOVOU (12*16)(inp), D0; PXOR D0, A3; MOVOU A3, (12*16)(oup)
+	MOVOU (13*16)(inp), D0; PXOR D0, B3; MOVOU B3, (13*16)(oup)
+	MOVOU (14*16)(inp), D0; PXOR D0, C3; MOVOU C3, (14*16)(oup)
+	MOVOU (15*16)(inp), D0; PXOR tmpStore, D0; MOVOU D0, (15*16)(oup)
+	LEAQ  256(inp), inp
+	LEAQ  256(oup), oup
+	SUBQ  $256, inl
+	JMP   openSSEMainLoop
+
+openSSEMainLoopDone:
+	// Handle the various tail sizes efficiently
+	TESTQ inl, inl
+	JE    openSSEFinalize
+	CMPQ  inl, $64
+	JBE   openSSETail64
+	CMPQ  inl, $128
+	JBE   openSSETail128
+	CMPQ  inl, $192
+	JBE   openSSETail192
+	JMP   openSSETail256
+
+openSSEFinalize:
+	// Hash in the PT, AAD lengths
+	ADDQ ad_len+80(FP), acc0; ADCQ src_len+56(FP), acc1; ADCQ $1, acc2
+	polyMul
+
+	// Final reduce
+	MOVQ    acc0, t0
+	MOVQ    acc1, t1
+	MOVQ    acc2, t2
+	SUBQ    $-5, acc0
+	SBBQ    $-1, acc1
+	SBBQ    $3, acc2
+	CMOVQCS t0, acc0
+	CMOVQCS t1, acc1
+	CMOVQCS t2, acc2
+
+	// Add in the "s" part of the key
+	ADDQ 0+sStore, acc0
+	ADCQ 8+sStore, acc1
+
+	// Finally, constant time compare to the tag at the end of the message
+	XORQ    AX, AX
+	MOVQ    $1, DX
+	XORQ    (0*8)(inp), acc0
+	XORQ    (1*8)(inp), acc1
+	ORQ     acc1, acc0
+	CMOVQEQ DX, AX
+
+	// Return true iff tags are equal
+	MOVB AX, ret+96(FP)
+	RET
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 129 bytes
+openSSE128:
+	// For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks
+	MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0
+	MOVO  A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO  A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO  B0, T1; MOVO C0, T2; MOVO D1, T3
+	MOVQ  $10, itr2
+
+openSSE128InnerCipherLoop:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left;  shiftB1Left; shiftB2Left
+	shiftC0Left;  shiftC1Left; shiftC2Left
+	shiftD0Left;  shiftD1Left; shiftD2Left
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftB1Right; shiftB2Right
+	shiftC0Right; shiftC1Right; shiftC2Right
+	shiftD0Right; shiftD1Right; shiftD2Right
+	DECQ          itr2
+	JNE           openSSE128InnerCipherLoop
+
+	// A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL T1, B0; PADDL T1, B1; PADDL T1, B2
+	PADDL T2, C1; PADDL T2, C2
+	PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2
+
+	// Clamp and store the key
+	PAND  ·polyClampMask<>(SB), A0
+	MOVOU A0, rStore; MOVOU B0, sStore
+
+	// Hash
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+openSSE128Open:
+	CMPQ inl, $16
+	JB   openSSETail16
+	SUBQ $16, inl
+
+	// Load for hashing
+	polyAdd(0(inp))
+
+	// Load for decryption
+	MOVOU (inp), T0; PXOR T0, A1; MOVOU A1, (oup)
+	LEAQ  (1*16)(inp), inp
+	LEAQ  (1*16)(oup), oup
+	polyMul
+
+	// Shift the stream "left"
+	MOVO B1, A1
+	MOVO C1, B1
+	MOVO D1, C1
+	MOVO A2, D1
+	MOVO B2, A2
+	MOVO C2, B2
+	MOVO D2, C2
+	JMP  openSSE128Open
+
+openSSETail16:
+	TESTQ inl, inl
+	JE    openSSEFinalize
+
+	// We can safely load the CT from the end, because it is padded with the MAC
+	MOVQ   inl, itr2
+	SHLQ   $4, itr2
+	LEAQ   ·andMask<>(SB), t0
+	MOVOU  (inp), T0
+	ADDQ   inl, inp
+	PAND   -16(t0)(itr2*1), T0
+	MOVO   T0, 0+tmpStore
+	MOVQ   T0, t0
+	MOVQ   8+tmpStore, t1
+	PXOR   A1, T0
+
+	// We can only store one byte at a time, since plaintext can be shorter than 16 bytes
+openSSETail16Store:
+	MOVQ T0, t3
+	MOVB t3, (oup)
+	PSRLDQ $1, T0
+	INCQ   oup
+	DECQ   inl
+	JNE    openSSETail16Store
+	ADDQ   t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+	JMP    openSSEFinalize
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 64 bytes of ciphertext
+openSSETail64:
+	// Need to decrypt up to 64 bytes - prepare single block
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+	XORQ itr2, itr2
+	MOVQ inl, itr1
+	CMPQ itr1, $16
+	JB   openSSETail64LoopB
+
+openSSETail64LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+	SUBQ $16, itr1
+
+openSSETail64LoopB:
+	ADDQ          $16, itr2
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+
+	CMPQ itr1, $16
+	JAE  openSSETail64LoopA
+
+	CMPQ itr2, $160
+	JNE  openSSETail64LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0; PADDL state2Store, C0; PADDL ctr0Store, D0
+
+openSSETail64DecLoop:
+	CMPQ  inl, $16
+	JB    openSSETail64DecLoopDone
+	SUBQ  $16, inl
+	MOVOU (inp), T0
+	PXOR  T0, A0
+	MOVOU A0, (oup)
+	LEAQ  16(inp), inp
+	LEAQ  16(oup), oup
+	MOVO  B0, A0
+	MOVO  C0, B0
+	MOVO  D0, C0
+	JMP   openSSETail64DecLoop
+
+openSSETail64DecLoopDone:
+	MOVO A0, A1
+	JMP  openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+openSSETail128:
+	// Need to decrypt up to 128 bytes - prepare two blocks
+	MOVO ·chacha20Constants<>(SB), A1; MOVO state1Store, B1; MOVO state2Store, C1; MOVO ctr3Store, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr0Store
+	MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr1Store
+	XORQ itr2, itr2
+	MOVQ inl, itr1
+	ANDQ $-16, itr1
+
+openSSETail128LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+
+openSSETail128LoopB:
+	ADDQ          $16, itr2
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	shiftB1Left;  shiftC1Left; shiftD1Left
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+
+	CMPQ itr2, itr1
+	JB   openSSETail128LoopA
+
+	CMPQ itr2, $160
+	JNE  openSSETail128LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1
+	PADDL state1Store, B0; PADDL state1Store, B1
+	PADDL state2Store, C0; PADDL state2Store, C1
+	PADDL ctr1Store, D0; PADDL ctr0Store, D1
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+	MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup)
+
+	SUBQ $64, inl
+	LEAQ 64(inp), inp
+	LEAQ 64(oup), oup
+	JMP  openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 192 bytes of ciphertext
+openSSETail192:
+	// Need to decrypt up to 192 bytes - prepare three blocks
+	MOVO ·chacha20Constants<>(SB), A2; MOVO state1Store, B2; MOVO state2Store, C2; MOVO ctr3Store, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr0Store
+	MOVO A2, A1; MOVO B2, B1; MOVO C2, C1; MOVO D2, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+	MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr2Store
+
+	MOVQ    inl, itr1
+	MOVQ    $160, itr2
+	CMPQ    itr1, $160
+	CMOVQGT itr2, itr1
+	ANDQ    $-16, itr1
+	XORQ    itr2, itr2
+
+openSSLTail192LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+
+openSSLTail192LoopB:
+	ADDQ         $16, itr2
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left; shiftC0Left; shiftD0Left
+	shiftB1Left; shiftC1Left; shiftD1Left
+	shiftB2Left; shiftC2Left; shiftD2Left
+
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+	shiftB2Right; shiftC2Right; shiftD2Right
+
+	CMPQ itr2, itr1
+	JB   openSSLTail192LoopA
+
+	CMPQ itr2, $160
+	JNE  openSSLTail192LoopB
+
+	CMPQ inl, $176
+	JB   openSSLTail192Store
+
+	polyAdd(160(inp))
+	polyMul
+
+	CMPQ inl, $192
+	JB   openSSLTail192Store
+
+	polyAdd(176(inp))
+	polyMul
+
+openSSLTail192Store:
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2
+	PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2
+	PADDL ctr2Store, D0; PADDL ctr1Store, D1; PADDL ctr0Store, D2
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A2; PXOR T1, B2; PXOR T2, C2; PXOR T3, D2
+	MOVOU A2, (0*16)(oup); MOVOU B2, (1*16)(oup); MOVOU C2, (2*16)(oup); MOVOU D2, (3*16)(oup)
+
+	MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3
+	PXOR  T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+
+	SUBQ $128, inl
+	LEAQ 128(inp), inp
+	LEAQ 128(oup), oup
+	JMP  openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+openSSETail256:
+	// Need to decrypt up to 256 bytes - prepare four blocks
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+	XORQ itr2, itr2
+
+openSSETail256Loop:
+	// This loop inteleaves 8 ChaCha quarter rounds with 1 poly multiplication
+	polyAdd(0(inp)(itr2*1))
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	shiftB0Left;  shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left;  shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left;  shiftD1Left; shiftD2Left; shiftD3Left
+	polyMulStage1
+	polyMulStage2
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyMulStage3
+	polyMulReduceStage
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	ADDQ          $2*8, itr2
+	CMPQ          itr2, $160
+	JB            openSSETail256Loop
+	MOVQ          inl, itr1
+	ANDQ          $-16, itr1
+
+openSSETail256HashLoop:
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+	ADDQ $2*8, itr2
+	CMPQ itr2, itr1
+	JB   openSSETail256HashLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+	MOVO  D3, tmpStore
+
+	// Load - xor - store
+	MOVOU (0*16)(inp), D3; PXOR D3, A0
+	MOVOU (1*16)(inp), D3; PXOR D3, B0
+	MOVOU (2*16)(inp), D3; PXOR D3, C0
+	MOVOU (3*16)(inp), D3; PXOR D3, D0
+	MOVOU A0, (0*16)(oup)
+	MOVOU B0, (1*16)(oup)
+	MOVOU C0, (2*16)(oup)
+	MOVOU D0, (3*16)(oup)
+	MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+	PXOR  A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+	MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0
+	PXOR  A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+	MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup)
+	LEAQ  192(inp), inp
+	LEAQ  192(oup), oup
+	SUBQ  $192, inl
+	MOVO  A3, A0
+	MOVO  B3, B0
+	MOVO  C3, C0
+	MOVO  tmpStore, D0
+
+	JMP openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// ------------------------- AVX2 Code ----------------------------------------
+chacha20Poly1305Open_AVX2:
+	VZEROUPPER
+	VMOVDQU ·chacha20Constants<>(SB), AA0
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12
+	BYTE    $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4
+	VPADDD  ·avx2InitMask<>(SB), DD0, DD0
+
+	// Special optimization, for very short buffers
+	CMPQ inl, $192
+	JBE  openAVX2192
+	CMPQ inl, $320
+	JBE  openAVX2320
+
+	// For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+	VMOVDQA BB0, state1StoreAVX2
+	VMOVDQA CC0, state2StoreAVX2
+	VMOVDQA DD0, ctr3StoreAVX2
+	MOVQ    $10, itr2
+
+openAVX2PreparePolyKey:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+	DECQ     itr2
+	JNE      openAVX2PreparePolyKey
+
+	VPADDD ·chacha20Constants<>(SB), AA0, AA0
+	VPADDD state1StoreAVX2, BB0, BB0
+	VPADDD state2StoreAVX2, CC0, CC0
+	VPADDD ctr3StoreAVX2, DD0, DD0
+
+	VPERM2I128 $0x02, AA0, BB0, TT0
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA TT0, rsStoreAVX2
+
+	// Stream for the first 64 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+
+	// Hash AD + first 64 bytes
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+	XORQ itr1, itr1
+
+openAVX2InitialHash64:
+	polyAdd(0(inp)(itr1*1))
+	polyMulAVX2
+	ADDQ $16, itr1
+	CMPQ itr1, $64
+	JNE  openAVX2InitialHash64
+
+	// Decrypt the first 64 bytes
+	VPXOR   (0*32)(inp), AA0, AA0
+	VPXOR   (1*32)(inp), BB0, BB0
+	VMOVDQU AA0, (0*32)(oup)
+	VMOVDQU BB0, (1*32)(oup)
+	LEAQ    (2*32)(inp), inp
+	LEAQ    (2*32)(oup), oup
+	SUBQ    $64, inl
+
+openAVX2MainLoop:
+	CMPQ inl, $512
+	JB   openAVX2MainLoopDone
+
+	// Load state, increment counter blocks, store the incremented counters
+	VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+	XORQ    itr1, itr1
+
+openAVX2InternalLoop:
+	// Lets just say this spaghetti loop interleaves 2 quarter rounds with 3 poly multiplications
+	// Effectively per 512 bytes of stream we hash 480 bytes of ciphertext
+	polyAdd(0*8(inp)(itr1*1))
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage1_AVX2
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulStage2_AVX2
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyMulStage3_AVX2
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulReduceStage
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	polyAdd(2*8(inp)(itr1*1))
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage1_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage2_AVX2
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage3_AVX2
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulReduceStage
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(4*8(inp)(itr1*1))
+	LEAQ     (6*8)(itr1), itr1
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage1_AVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	polyMulStage2_AVX2
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage3_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulReduceStage
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+	CMPQ     itr1, $480
+	JNE      openAVX2InternalLoop
+
+	VPADDD  ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD  state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD  state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD  ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA CC3, tmpStoreAVX2
+
+	// We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+	polyAdd(480(inp))
+	polyMulAVX2
+	VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+	VPXOR      (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+	VMOVDQU    CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+	// and here
+	polyAdd(496(inp))
+	polyMulAVX2
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+	VPXOR      (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup)
+	LEAQ       (32*16)(inp), inp
+	LEAQ       (32*16)(oup), oup
+	SUBQ       $(32*16), inl
+	JMP        openAVX2MainLoop
+
+openAVX2MainLoopDone:
+	// Handle the various tail sizes efficiently
+	TESTQ inl, inl
+	JE    openSSEFinalize
+	CMPQ  inl, $128
+	JBE   openAVX2Tail128
+	CMPQ  inl, $256
+	JBE   openAVX2Tail256
+	CMPQ  inl, $384
+	JBE   openAVX2Tail384
+	JMP   openAVX2Tail512
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 193 bytes
+openAVX2192:
+	// For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
+	VMOVDQA AA0, AA1
+	VMOVDQA BB0, BB1
+	VMOVDQA CC0, CC1
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2
+	VMOVDQA BB0, BB2
+	VMOVDQA CC0, CC2
+	VMOVDQA DD0, DD2
+	VMOVDQA DD1, TT3
+	MOVQ    $10, itr2
+
+openAVX2192InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	DECQ       itr2
+	JNE        openAVX2192InnerCipherLoop
+	VPADDD     AA2, AA0, AA0; VPADDD AA2, AA1, AA1
+	VPADDD     BB2, BB0, BB0; VPADDD BB2, BB1, BB1
+	VPADDD     CC2, CC0, CC0; VPADDD CC2, CC1, CC1
+	VPADDD     DD2, DD0, DD0; VPADDD TT3, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, TT0
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA TT0, rsStoreAVX2
+
+	// Stream for up to 192 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+
+openAVX2ShortOpen:
+	// Hash
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+openAVX2ShortOpenLoop:
+	CMPQ inl, $32
+	JB   openAVX2ShortTail32
+	SUBQ $32, inl
+
+	// Load for hashing
+	polyAdd(0*8(inp))
+	polyMulAVX2
+	polyAdd(2*8(inp))
+	polyMulAVX2
+
+	// Load for decryption
+	VPXOR   (inp), AA0, AA0
+	VMOVDQU AA0, (oup)
+	LEAQ    (1*32)(inp), inp
+	LEAQ    (1*32)(oup), oup
+
+	// Shift stream left
+	VMOVDQA BB0, AA0
+	VMOVDQA CC0, BB0
+	VMOVDQA DD0, CC0
+	VMOVDQA AA1, DD0
+	VMOVDQA BB1, AA1
+	VMOVDQA CC1, BB1
+	VMOVDQA DD1, CC1
+	VMOVDQA AA2, DD1
+	VMOVDQA BB2, AA2
+	JMP     openAVX2ShortOpenLoop
+
+openAVX2ShortTail32:
+	CMPQ    inl, $16
+	VMOVDQA A0, A1
+	JB      openAVX2ShortDone
+
+	SUBQ $16, inl
+
+	// Load for hashing
+	polyAdd(0*8(inp))
+	polyMulAVX2
+
+	// Load for decryption
+	VPXOR      (inp), A0, T0
+	VMOVDQU    T0, (oup)
+	LEAQ       (1*16)(inp), inp
+	LEAQ       (1*16)(oup), oup
+	VPERM2I128 $0x11, AA0, AA0, AA0
+	VMOVDQA    A0, A1
+
+openAVX2ShortDone:
+	VZEROUPPER
+	JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 321 bytes
+openAVX2320:
+	// For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
+	VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3
+	MOVQ    $10, itr2
+
+openAVX2320InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+	DECQ     itr2
+	JNE      openAVX2320InnerCipherLoop
+
+	VMOVDQA ·chacha20Constants<>(SB), TT0
+	VPADDD  TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2
+	VPADDD  TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2
+	VPADDD  TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2
+	VMOVDQA ·avx2IncMask<>(SB), TT0
+	VPADDD  TT3, DD0, DD0; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD1, DD1; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD2, DD2
+
+	// Clamp and store poly key
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPAND      ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA    TT0, rsStoreAVX2
+
+	// Stream for up to 320 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+	VPERM2I128 $0x02, AA2, BB2, CC1
+	VPERM2I128 $0x02, CC2, DD2, DD1
+	VPERM2I128 $0x13, AA2, BB2, AA2
+	VPERM2I128 $0x13, CC2, DD2, BB2
+	JMP        openAVX2ShortOpen
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+openAVX2Tail128:
+	// Need to decrypt up to 128 bytes - prepare two blocks
+	VMOVDQA ·chacha20Constants<>(SB), AA1
+	VMOVDQA state1StoreAVX2, BB1
+	VMOVDQA state2StoreAVX2, CC1
+	VMOVDQA ctr3StoreAVX2, DD1
+	VPADDD  ·avx2IncMask<>(SB), DD1, DD1
+	VMOVDQA DD1, DD0
+
+	XORQ  itr2, itr2
+	MOVQ  inl, itr1
+	ANDQ  $-16, itr1
+	TESTQ itr1, itr1
+	JE    openAVX2Tail128LoopB
+
+openAVX2Tail128LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMulAVX2
+
+openAVX2Tail128LoopB:
+	ADDQ     $16, itr2
+	chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $4, DD1, DD1, DD1
+	CMPQ     itr2, itr1
+	JB       openAVX2Tail128LoopA
+	CMPQ     itr2, $160
+	JNE      openAVX2Tail128LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA1, AA1
+	VPADDD     state1StoreAVX2, BB1, BB1
+	VPADDD     state2StoreAVX2, CC1, CC1
+	VPADDD     DD0, DD1, DD1
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+
+openAVX2TailLoop:
+	CMPQ inl, $32
+	JB   openAVX2Tail
+	SUBQ $32, inl
+
+	// Load for decryption
+	VPXOR   (inp), AA0, AA0
+	VMOVDQU AA0, (oup)
+	LEAQ    (1*32)(inp), inp
+	LEAQ    (1*32)(oup), oup
+	VMOVDQA BB0, AA0
+	VMOVDQA CC0, BB0
+	VMOVDQA DD0, CC0
+	JMP     openAVX2TailLoop
+
+openAVX2Tail:
+	CMPQ    inl, $16
+	VMOVDQA A0, A1
+	JB      openAVX2TailDone
+	SUBQ    $16, inl
+
+	// Load for decryption
+	VPXOR      (inp), A0, T0
+	VMOVDQU    T0, (oup)
+	LEAQ       (1*16)(inp), inp
+	LEAQ       (1*16)(oup), oup
+	VPERM2I128 $0x11, AA0, AA0, AA0
+	VMOVDQA    A0, A1
+
+openAVX2TailDone:
+	VZEROUPPER
+	JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+openAVX2Tail256:
+	// Need to decrypt up to 256 bytes - prepare four blocks
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA DD0, TT1
+	VMOVDQA DD1, TT2
+
+	// Compute the number of iterations that will hash data
+	MOVQ    inl, tmpStoreAVX2
+	MOVQ    inl, itr1
+	SUBQ    $128, itr1
+	SHRQ    $4, itr1
+	MOVQ    $10, itr2
+	CMPQ    itr1, $10
+	CMOVQGT itr2, itr1
+	MOVQ    inp, inl
+	XORQ    itr2, itr2
+
+openAVX2Tail256LoopA:
+	polyAdd(0(inl))
+	polyMulAVX2
+	LEAQ 16(inl), inl
+
+	// Perform ChaCha rounds, while hashing the remaining input
+openAVX2Tail256LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	INCQ     itr2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	CMPQ     itr2, itr1
+	JB       openAVX2Tail256LoopA
+
+	CMPQ itr2, $10
+	JNE  openAVX2Tail256LoopB
+
+	MOVQ inl, itr2
+	SUBQ inp, inl
+	MOVQ inl, itr1
+	MOVQ tmpStoreAVX2, inl
+
+	// Hash the remainder of data (if any)
+openAVX2Tail256Hash:
+	ADDQ $16, itr1
+	CMPQ itr1, inl
+	JGT  openAVX2Tail256HashEnd
+	polyAdd (0(itr2))
+	polyMulAVX2
+	LEAQ 16(itr2), itr2
+	JMP  openAVX2Tail256Hash
+
+// Store 128 bytes safely, then go to store loop
+openAVX2Tail256HashEnd:
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1
+	VPADDD     TT1, DD0, DD0; VPADDD TT2, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, AA2; VPERM2I128 $0x02, CC0, DD0, BB2; VPERM2I128 $0x13, AA0, BB0, CC2; VPERM2I128 $0x13, CC0, DD0, DD2
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+
+	VPXOR   (0*32)(inp), AA2, AA2; VPXOR (1*32)(inp), BB2, BB2; VPXOR (2*32)(inp), CC2, CC2; VPXOR (3*32)(inp), DD2, DD2
+	VMOVDQU AA2, (0*32)(oup); VMOVDQU BB2, (1*32)(oup); VMOVDQU CC2, (2*32)(oup); VMOVDQU DD2, (3*32)(oup)
+	LEAQ    (4*32)(inp), inp
+	LEAQ    (4*32)(oup), oup
+	SUBQ    $4*32, inl
+
+	JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 384 bytes of ciphertext
+openAVX2Tail384:
+	// Need to decrypt up to 384 bytes - prepare six blocks
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VPADDD  ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA DD0, ctr0StoreAVX2
+	VMOVDQA DD1, ctr1StoreAVX2
+	VMOVDQA DD2, ctr2StoreAVX2
+
+	// Compute the number of iterations that will hash two blocks of data
+	MOVQ    inl, tmpStoreAVX2
+	MOVQ    inl, itr1
+	SUBQ    $256, itr1
+	SHRQ    $4, itr1
+	ADDQ    $6, itr1
+	MOVQ    $10, itr2
+	CMPQ    itr1, $10
+	CMOVQGT itr2, itr1
+	MOVQ    inp, inl
+	XORQ    itr2, itr2
+
+	// Perform ChaCha rounds, while hashing the remaining input
+openAVX2Tail384LoopB:
+	polyAdd(0(inl))
+	polyMulAVX2
+	LEAQ 16(inl), inl
+
+openAVX2Tail384LoopA:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	polyAdd(0(inl))
+	polyMulAVX2
+	LEAQ     16(inl), inl
+	INCQ     itr2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+
+	CMPQ itr2, itr1
+	JB   openAVX2Tail384LoopB
+
+	CMPQ itr2, $10
+	JNE  openAVX2Tail384LoopA
+
+	MOVQ inl, itr2
+	SUBQ inp, inl
+	MOVQ inl, itr1
+	MOVQ tmpStoreAVX2, inl
+
+openAVX2Tail384Hash:
+	ADDQ $16, itr1
+	CMPQ itr1, inl
+	JGT  openAVX2Tail384HashEnd
+	polyAdd(0(itr2))
+	polyMulAVX2
+	LEAQ 16(itr2), itr2
+	JMP  openAVX2Tail384Hash
+
+// Store 256 bytes safely, then go to store loop
+openAVX2Tail384HashEnd:
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2
+	VPADDD     ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2
+	VPERM2I128 $0x02, AA0, BB0, TT0; VPERM2I128 $0x02, CC0, DD0, TT1; VPERM2I128 $0x13, AA0, BB0, TT2; VPERM2I128 $0x13, CC0, DD0, TT3
+	VPXOR      (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, TT0; VPERM2I128 $0x02, CC1, DD1, TT1; VPERM2I128 $0x13, AA1, BB1, TT2; VPERM2I128 $0x13, CC1, DD1, TT3
+	VPXOR      (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup)
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	LEAQ       (8*32)(inp), inp
+	LEAQ       (8*32)(oup), oup
+	SUBQ       $8*32, inl
+	JMP        openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 512 bytes of ciphertext
+openAVX2Tail512:
+	VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+	XORQ    itr1, itr1
+	MOVQ    inp, itr2
+
+openAVX2Tail512LoopB:
+	polyAdd(0(itr2))
+	polyMulAVX2
+	LEAQ (2*8)(itr2), itr2
+
+openAVX2Tail512LoopA:
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyAdd(0*8(itr2))
+	polyMulAVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(2*8(itr2))
+	polyMulAVX2
+	LEAQ     (4*8)(itr2), itr2
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+	INCQ     itr1
+	CMPQ     itr1, $4
+	JLT      openAVX2Tail512LoopB
+
+	CMPQ itr1, $10
+	JNE  openAVX2Tail512LoopA
+
+	MOVQ inl, itr1
+	SUBQ $384, itr1
+	ANDQ $-16, itr1
+
+openAVX2Tail512HashLoop:
+	TESTQ itr1, itr1
+	JE    openAVX2Tail512HashEnd
+	polyAdd(0(itr2))
+	polyMulAVX2
+	LEAQ  16(itr2), itr2
+	SUBQ  $16, itr1
+	JMP   openAVX2Tail512HashLoop
+
+openAVX2Tail512HashEnd:
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD     ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA    CC3, tmpStoreAVX2
+	VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+	VPXOR      (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+	VMOVDQU    CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+
+	LEAQ (12*32)(inp), inp
+	LEAQ (12*32)(oup), oup
+	SUBQ $12*32, inl
+
+	JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// func chacha20Poly1305Seal(dst, key, src, ad []byte)
+TEXT ·chacha20Poly1305Seal(SB), 0, $288-96
+	// For aligned stack access
+	MOVQ SP, BP
+	ADDQ $32, BP
+	ANDQ $-32, BP
+	MOVQ dst+0(FP), oup
+	MOVQ key+24(FP), keyp
+	MOVQ src+48(FP), inp
+	MOVQ src_len+56(FP), inl
+	MOVQ ad+72(FP), adp
+
+	CMPB ·useAVX2(SB), $1
+	JE   chacha20Poly1305Seal_AVX2
+
+	// Special optimization, for very short buffers
+	CMPQ inl, $128
+	JBE  sealSSE128 // About 15% faster
+
+	// In the seal case - prepare the poly key + 3 blocks of stream in the first iteration
+	MOVOU ·chacha20Constants<>(SB), A0
+	MOVOU (1*16)(keyp), B0
+	MOVOU (2*16)(keyp), C0
+	MOVOU (3*16)(keyp), D0
+
+	// Store state on stack for future use
+	MOVO B0, state1Store
+	MOVO C0, state2Store
+
+	// Load state, increment counter blocks
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+	MOVQ $10, itr2
+
+sealSSEIntroLoop:
+	MOVO         C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO         tmpStore, C3
+	MOVO         C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO         tmpStore, C1
+	shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left
+
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	DECQ          itr2
+	JNE           sealSSEIntroLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+
+	// Clamp and store the key
+	PAND ·polyClampMask<>(SB), A0
+	MOVO A0, rStore
+	MOVO B0, sStore
+
+	// Hash AAD
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+	MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+	PXOR  A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+	MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup)
+	MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+	PXOR  A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+	MOVOU A2, (4*16)(oup); MOVOU B2, (5*16)(oup); MOVOU C2, (6*16)(oup); MOVOU D2, (7*16)(oup)
+
+	MOVQ $128, itr1
+	SUBQ $128, inl
+	LEAQ 128(inp), inp
+
+	MOVO A3, A1; MOVO B3, B1; MOVO C3, C1; MOVO D3, D1
+
+	CMPQ inl, $64
+	JBE  sealSSE128SealHash
+
+	MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+	PXOR  A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3
+	MOVOU A3, (8*16)(oup); MOVOU B3, (9*16)(oup); MOVOU C3, (10*16)(oup); MOVOU D3, (11*16)(oup)
+
+	ADDQ $64, itr1
+	SUBQ $64, inl
+	LEAQ 64(inp), inp
+
+	MOVQ $2, itr1
+	MOVQ $8, itr2
+
+	CMPQ inl, $64
+	JBE  sealSSETail64
+	CMPQ inl, $128
+	JBE  sealSSETail128
+	CMPQ inl, $192
+	JBE  sealSSETail192
+
+sealSSEMainLoop:
+	// Load state, increment counter blocks
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+
+sealSSEInnerLoop:
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyAdd(0(oup))
+	shiftB0Left;  shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left;  shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left;  shiftD1Left; shiftD2Left; shiftD3Left
+	polyMulStage1
+	polyMulStage2
+	LEAQ          (2*8)(oup), oup
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	polyMulStage3
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyMulReduceStage
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	DECQ          itr2
+	JGE           sealSSEInnerLoop
+	polyAdd(0(oup))
+	polyMul
+	LEAQ          (2*8)(oup), oup
+	DECQ          itr1
+	JG            sealSSEInnerLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+	MOVO  D3, tmpStore
+
+	// Load - xor - store
+	MOVOU (0*16)(inp), D3; PXOR D3, A0
+	MOVOU (1*16)(inp), D3; PXOR D3, B0
+	MOVOU (2*16)(inp), D3; PXOR D3, C0
+	MOVOU (3*16)(inp), D3; PXOR D3, D0
+	MOVOU A0, (0*16)(oup)
+	MOVOU B0, (1*16)(oup)
+	MOVOU C0, (2*16)(oup)
+	MOVOU D0, (3*16)(oup)
+	MOVO  tmpStore, D3
+
+	MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+	PXOR  A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+	MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0
+	PXOR  A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+	MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup)
+	ADDQ  $192, inp
+	MOVQ  $192, itr1
+	SUBQ  $192, inl
+	MOVO  A3, A1
+	MOVO  B3, B1
+	MOVO  C3, C1
+	MOVO  D3, D1
+	CMPQ  inl, $64
+	JBE   sealSSE128SealHash
+	MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+	PXOR  A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3
+	MOVOU A3, (12*16)(oup); MOVOU B3, (13*16)(oup); MOVOU C3, (14*16)(oup); MOVOU D3, (15*16)(oup)
+	LEAQ  64(inp), inp
+	SUBQ  $64, inl
+	MOVQ  $6, itr1
+	MOVQ  $4, itr2
+	CMPQ  inl, $192
+	JG    sealSSEMainLoop
+
+	MOVQ  inl, itr1
+	TESTQ inl, inl
+	JE    sealSSE128SealHash
+	MOVQ  $6, itr1
+	CMPQ  inl, $64
+	JBE   sealSSETail64
+	CMPQ  inl, $128
+	JBE   sealSSETail128
+	JMP   sealSSETail192
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 64 bytes of plaintext
+sealSSETail64:
+	// Need to encrypt up to 64 bytes - prepare single block, hash 192 or 256 bytes
+	MOVO  ·chacha20Constants<>(SB), A1
+	MOVO  state1Store, B1
+	MOVO  state2Store, C1
+	MOVO  ctr3Store, D1
+	PADDL ·sseIncMask<>(SB), D1
+	MOVO  D1, ctr0Store
+
+sealSSETail64LoopA:
+	// Perform ChaCha rounds, while hashing the previously encrypted ciphertext
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealSSETail64LoopB:
+	chachaQR(A1, B1, C1, D1, T1)
+	shiftB1Left;  shiftC1Left; shiftD1Left
+	chachaQR(A1, B1, C1, D1, T1)
+	shiftB1Right; shiftC1Right; shiftD1Right
+	polyAdd(0(oup))
+	polyMul
+	LEAQ          16(oup), oup
+
+	DECQ itr1
+	JG   sealSSETail64LoopA
+
+	DECQ  itr2
+	JGE   sealSSETail64LoopB
+	PADDL ·chacha20Constants<>(SB), A1
+	PADDL state1Store, B1
+	PADDL state2Store, C1
+	PADDL ctr0Store, D1
+
+	JMP sealSSE128Seal
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of plaintext
+sealSSETail128:
+	// Need to encrypt up to 128 bytes - prepare two blocks, hash 192 or 256 bytes
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+
+sealSSETail128LoopA:
+	// Perform ChaCha rounds, while hashing the previously encrypted ciphertext
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealSSETail128LoopB:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	shiftB1Left;  shiftC1Left; shiftD1Left
+	polyAdd(0(oup))
+	polyMul
+	LEAQ          16(oup), oup
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+
+	DECQ itr1
+	JG   sealSSETail128LoopA
+
+	DECQ itr2
+	JGE  sealSSETail128LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1
+	PADDL state1Store, B0; PADDL state1Store, B1
+	PADDL state2Store, C0; PADDL state2Store, C1
+	PADDL ctr0Store, D0; PADDL ctr1Store, D1
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0
+	MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup)
+
+	MOVQ $64, itr1
+	LEAQ 64(inp), inp
+	SUBQ $64, inl
+
+	JMP sealSSE128SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 192 bytes of plaintext
+sealSSETail192:
+	// Need to encrypt up to 192 bytes - prepare three blocks, hash 192 or 256 bytes
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr2Store
+
+sealSSETail192LoopA:
+	// Perform ChaCha rounds, while hashing the previously encrypted ciphertext
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealSSETail192LoopB:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left; shiftC0Left; shiftD0Left
+	shiftB1Left; shiftC1Left; shiftD1Left
+	shiftB2Left; shiftC2Left; shiftD2Left
+
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+	shiftB2Right; shiftC2Right; shiftD2Right
+
+	DECQ itr1
+	JG   sealSSETail192LoopA
+
+	DECQ itr2
+	JGE  sealSSETail192LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2
+	PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2
+	PADDL ctr0Store, D0; PADDL ctr1Store, D1; PADDL ctr2Store, D2
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0
+	MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup)
+	MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3
+	PXOR  T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+
+	MOVO A2, A1
+	MOVO B2, B1
+	MOVO C2, C1
+	MOVO D2, D1
+	MOVQ $128, itr1
+	LEAQ 128(inp), inp
+	SUBQ $128, inl
+
+	JMP sealSSE128SealHash
+
+// ----------------------------------------------------------------------------
+// Special seal optimization for buffers smaller than 129 bytes
+sealSSE128:
+	// For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks
+	MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0
+	MOVO  A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO  A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO  B0, T1; MOVO C0, T2; MOVO D1, T3
+	MOVQ  $10, itr2
+
+sealSSE128InnerCipherLoop:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left;  shiftB1Left; shiftB2Left
+	shiftC0Left;  shiftC1Left; shiftC2Left
+	shiftD0Left;  shiftD1Left; shiftD2Left
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftB1Right; shiftB2Right
+	shiftC0Right; shiftC1Right; shiftC2Right
+	shiftD0Right; shiftD1Right; shiftD2Right
+	DECQ          itr2
+	JNE           sealSSE128InnerCipherLoop
+
+	// A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL T1, B0; PADDL T1, B1; PADDL T1, B2
+	PADDL T2, C1; PADDL T2, C2
+	PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2
+	PAND  ·polyClampMask<>(SB), A0
+	MOVOU A0, rStore
+	MOVOU B0, sStore
+
+	// Hash
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+	XORQ itr1, itr1
+
+sealSSE128SealHash:
+	// itr1 holds the number of bytes encrypted but not yet hashed
+	CMPQ itr1, $16
+	JB   sealSSE128Seal
+	polyAdd(0(oup))
+	polyMul
+
+	SUBQ $16, itr1
+	ADDQ $16, oup
+
+	JMP sealSSE128SealHash
+
+sealSSE128Seal:
+	CMPQ inl, $16
+	JB   sealSSETail
+	SUBQ $16, inl
+
+	// Load for decryption
+	MOVOU (inp), T0
+	PXOR  T0, A1
+	MOVOU A1, (oup)
+	LEAQ  (1*16)(inp), inp
+	LEAQ  (1*16)(oup), oup
+
+	// Extract for hashing
+	MOVQ   A1, t0
+	PSRLDQ $8, A1
+	MOVQ A1, t1
+	ADDQ   t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+
+	// Shift the stream "left"
+	MOVO B1, A1
+	MOVO C1, B1
+	MOVO D1, C1
+	MOVO A2, D1
+	MOVO B2, A2
+	MOVO C2, B2
+	MOVO D2, C2
+	JMP  sealSSE128Seal
+
+sealSSETail:
+	TESTQ inl, inl
+	JE    sealSSEFinalize
+
+	// We can only load the PT one byte at a time to avoid read after end of buffer
+	MOVQ inl, itr2
+	SHLQ $4, itr2
+	LEAQ ·andMask<>(SB), t0
+	MOVQ inl, itr1
+	LEAQ -1(inp)(inl*1), inp
+	XORQ t2, t2
+	XORQ t3, t3
+	XORQ AX, AX
+
+sealSSETailLoadLoop:
+	SHLQ $8, t2, t3
+	SHLQ $8, t2
+	MOVB (inp), AX
+	XORQ AX, t2
+	LEAQ   -1(inp), inp
+	DECQ   itr1
+	JNE    sealSSETailLoadLoop
+	MOVQ t2, 0+tmpStore
+	MOVQ t3, 8+tmpStore
+	PXOR 0+tmpStore, A1
+	MOVOU  A1, (oup)
+	MOVOU  -16(t0)(itr2*1), T0
+	PAND   T0, A1
+	MOVQ   A1, t0
+	PSRLDQ $8, A1
+	MOVQ   A1, t1
+	ADDQ   t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+
+	ADDQ inl, oup
+
+sealSSEFinalize:
+	// Hash in the buffer lengths
+	ADDQ ad_len+80(FP), acc0
+	ADCQ src_len+56(FP), acc1
+	ADCQ $1, acc2
+	polyMul
+
+	// Final reduce
+	MOVQ    acc0, t0
+	MOVQ    acc1, t1
+	MOVQ    acc2, t2
+	SUBQ    $-5, acc0
+	SBBQ    $-1, acc1
+	SBBQ    $3, acc2
+	CMOVQCS t0, acc0
+	CMOVQCS t1, acc1
+	CMOVQCS t2, acc2
+
+	// Add in the "s" part of the key
+	ADDQ 0+sStore, acc0
+	ADCQ 8+sStore, acc1
+
+	// Finally store the tag at the end of the message
+	MOVQ acc0, (0*8)(oup)
+	MOVQ acc1, (1*8)(oup)
+	RET
+
+// ----------------------------------------------------------------------------
+// ------------------------- AVX2 Code ----------------------------------------
+chacha20Poly1305Seal_AVX2:
+	VZEROUPPER
+	VMOVDQU ·chacha20Constants<>(SB), AA0
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12
+	BYTE    $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4
+	VPADDD  ·avx2InitMask<>(SB), DD0, DD0
+
+	// Special optimizations, for very short buffers
+	CMPQ inl, $192
+	JBE  seal192AVX2 // 33% faster
+	CMPQ inl, $320
+	JBE  seal320AVX2 // 17% faster
+
+	// For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+	VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3; VMOVDQA BB0, state1StoreAVX2
+	VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3; VMOVDQA CC0, state2StoreAVX2
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1; VMOVDQA DD0, ctr0StoreAVX2
+	VPADDD  ·avx2IncMask<>(SB), DD1, DD2; VMOVDQA DD1, ctr1StoreAVX2
+	VPADDD  ·avx2IncMask<>(SB), DD2, DD3; VMOVDQA DD2, ctr2StoreAVX2
+	VMOVDQA DD3, ctr3StoreAVX2
+	MOVQ    $10, itr2
+
+sealAVX2IntroLoop:
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+	VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1
+	VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2
+	VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3
+
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+	VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1
+	VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2
+	VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3
+	DECQ     itr2
+	JNE      sealAVX2IntroLoop
+
+	VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+
+	VPERM2I128 $0x13, CC0, DD0, CC0 // Stream bytes 96 - 127
+	VPERM2I128 $0x02, AA0, BB0, DD0 // The Poly1305 key
+	VPERM2I128 $0x13, AA0, BB0, AA0 // Stream bytes 64 - 95
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), DD0, DD0
+	VMOVDQA DD0, rsStoreAVX2
+
+	// Hash AD
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+	// Can store at least 320 bytes
+	VPXOR   (0*32)(inp), AA0, AA0
+	VPXOR   (1*32)(inp), CC0, CC0
+	VMOVDQU AA0, (0*32)(oup)
+	VMOVDQU CC0, (1*32)(oup)
+
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (2*32)(inp), AA0, AA0; VPXOR (3*32)(inp), BB0, BB0; VPXOR (4*32)(inp), CC0, CC0; VPXOR (5*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (2*32)(oup); VMOVDQU BB0, (3*32)(oup); VMOVDQU CC0, (4*32)(oup); VMOVDQU DD0, (5*32)(oup)
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (6*32)(inp), AA0, AA0; VPXOR (7*32)(inp), BB0, BB0; VPXOR (8*32)(inp), CC0, CC0; VPXOR (9*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (6*32)(oup); VMOVDQU BB0, (7*32)(oup); VMOVDQU CC0, (8*32)(oup); VMOVDQU DD0, (9*32)(oup)
+
+	MOVQ $320, itr1
+	SUBQ $320, inl
+	LEAQ 320(inp), inp
+
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, CC3, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, CC3, DD3, DD0
+	CMPQ       inl, $128
+	JBE        sealAVX2SealHash
+
+	VPXOR   (0*32)(inp), AA0, AA0; VPXOR (1*32)(inp), BB0, BB0; VPXOR (2*32)(inp), CC0, CC0; VPXOR (3*32)(inp), DD0, DD0
+	VMOVDQU AA0, (10*32)(oup); VMOVDQU BB0, (11*32)(oup); VMOVDQU CC0, (12*32)(oup); VMOVDQU DD0, (13*32)(oup)
+	SUBQ    $128, inl
+	LEAQ    128(inp), inp
+
+	MOVQ $8, itr1
+	MOVQ $2, itr2
+
+	CMPQ inl, $128
+	JBE  sealAVX2Tail128
+	CMPQ inl, $256
+	JBE  sealAVX2Tail256
+	CMPQ inl, $384
+	JBE  sealAVX2Tail384
+	CMPQ inl, $512
+	JBE  sealAVX2Tail512
+
+	// We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+	VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1
+	VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2
+	VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3
+
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+	VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1
+	VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2
+	VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+
+	SUBQ $16, oup                  // Adjust the pointer
+	MOVQ $9, itr1
+	JMP  sealAVX2InternalLoopStart
+
+sealAVX2MainLoop:
+	// Load state, increment counter blocks, store the incremented counters
+	VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+	MOVQ    $10, itr1
+
+sealAVX2InternalLoop:
+	polyAdd(0*8(oup))
+	VPADDD  BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage1_AVX2
+	VPXOR   AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulStage2_AVX2
+	VPADDD  DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR   CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyMulStage3_AVX2
+	VMOVDQA CC3, tmpStoreAVX2
+	VPSLLD  $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD  $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD  $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD  $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA tmpStoreAVX2, CC3
+	polyMulReduceStage
+
+sealAVX2InternalLoopStart:
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	polyAdd(2*8(oup))
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage1_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage2_AVX2
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage3_AVX2
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulReduceStage
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(4*8(oup))
+	LEAQ     (6*8)(oup), oup
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage1_AVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	polyMulStage2_AVX2
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage3_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulReduceStage
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+	DECQ     itr1
+	JNE      sealAVX2InternalLoop
+
+	VPADDD  ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD  state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD  state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD  ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA CC3, tmpStoreAVX2
+
+	// We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	LEAQ       (4*8)(oup), oup
+	VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+	VPXOR      (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+	VMOVDQU    CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+	// and here
+	polyAdd(-2*8(oup))
+	polyMulAVX2
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+	VPXOR      (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup)
+	LEAQ       (32*16)(inp), inp
+	SUBQ       $(32*16), inl
+	CMPQ       inl, $512
+	JG         sealAVX2MainLoop
+
+	// Tail can only hash 480 bytes
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	polyAdd(2*8(oup))
+	polyMulAVX2
+	LEAQ 32(oup), oup
+
+	MOVQ $10, itr1
+	MOVQ $0, itr2
+	CMPQ inl, $128
+	JBE  sealAVX2Tail128
+	CMPQ inl, $256
+	JBE  sealAVX2Tail256
+	CMPQ inl, $384
+	JBE  sealAVX2Tail384
+	JMP  sealAVX2Tail512
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 193 bytes
+seal192AVX2:
+	// For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
+	VMOVDQA AA0, AA1
+	VMOVDQA BB0, BB1
+	VMOVDQA CC0, CC1
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2
+	VMOVDQA BB0, BB2
+	VMOVDQA CC0, CC2
+	VMOVDQA DD0, DD2
+	VMOVDQA DD1, TT3
+	MOVQ    $10, itr2
+
+sealAVX2192InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	DECQ       itr2
+	JNE        sealAVX2192InnerCipherLoop
+	VPADDD     AA2, AA0, AA0; VPADDD AA2, AA1, AA1
+	VPADDD     BB2, BB0, BB0; VPADDD BB2, BB1, BB1
+	VPADDD     CC2, CC0, CC0; VPADDD CC2, CC1, CC1
+	VPADDD     DD2, DD0, DD0; VPADDD TT3, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, TT0
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA TT0, rsStoreAVX2
+
+	// Stream for up to 192 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+
+sealAVX2ShortSeal:
+	// Hash aad
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+	XORQ itr1, itr1
+
+sealAVX2SealHash:
+	// itr1 holds the number of bytes encrypted but not yet hashed
+	CMPQ itr1, $16
+	JB   sealAVX2ShortSealLoop
+	polyAdd(0(oup))
+	polyMul
+	SUBQ $16, itr1
+	ADDQ $16, oup
+	JMP  sealAVX2SealHash
+
+sealAVX2ShortSealLoop:
+	CMPQ inl, $32
+	JB   sealAVX2ShortTail32
+	SUBQ $32, inl
+
+	// Load for encryption
+	VPXOR   (inp), AA0, AA0
+	VMOVDQU AA0, (oup)
+	LEAQ    (1*32)(inp), inp
+
+	// Now can hash
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	polyAdd(2*8(oup))
+	polyMulAVX2
+	LEAQ (1*32)(oup), oup
+
+	// Shift stream left
+	VMOVDQA BB0, AA0
+	VMOVDQA CC0, BB0
+	VMOVDQA DD0, CC0
+	VMOVDQA AA1, DD0
+	VMOVDQA BB1, AA1
+	VMOVDQA CC1, BB1
+	VMOVDQA DD1, CC1
+	VMOVDQA AA2, DD1
+	VMOVDQA BB2, AA2
+	JMP     sealAVX2ShortSealLoop
+
+sealAVX2ShortTail32:
+	CMPQ    inl, $16
+	VMOVDQA A0, A1
+	JB      sealAVX2ShortDone
+
+	SUBQ $16, inl
+
+	// Load for encryption
+	VPXOR   (inp), A0, T0
+	VMOVDQU T0, (oup)
+	LEAQ    (1*16)(inp), inp
+
+	// Hash
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	LEAQ       (1*16)(oup), oup
+	VPERM2I128 $0x11, AA0, AA0, AA0
+	VMOVDQA    A0, A1
+
+sealAVX2ShortDone:
+	VZEROUPPER
+	JMP sealSSETail
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 321 bytes
+seal320AVX2:
+	// For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
+	VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3
+	MOVQ    $10, itr2
+
+sealAVX2320InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+	DECQ     itr2
+	JNE      sealAVX2320InnerCipherLoop
+
+	VMOVDQA ·chacha20Constants<>(SB), TT0
+	VPADDD  TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2
+	VPADDD  TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2
+	VPADDD  TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2
+	VMOVDQA ·avx2IncMask<>(SB), TT0
+	VPADDD  TT3, DD0, DD0; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD1, DD1; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD2, DD2
+
+	// Clamp and store poly key
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPAND      ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA    TT0, rsStoreAVX2
+
+	// Stream for up to 320 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+	VPERM2I128 $0x02, AA2, BB2, CC1
+	VPERM2I128 $0x02, CC2, DD2, DD1
+	VPERM2I128 $0x13, AA2, BB2, AA2
+	VPERM2I128 $0x13, CC2, DD2, BB2
+	JMP        sealAVX2ShortSeal
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+sealAVX2Tail128:
+	// Need to decrypt up to 128 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0
+	VMOVDQA state1StoreAVX2, BB0
+	VMOVDQA state2StoreAVX2, CC0
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VMOVDQA DD0, DD1
+
+sealAVX2Tail128LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail128LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	polyAdd(0(oup))
+	polyMul
+	VPALIGNR $4, BB0, BB0, BB0
+	VPALIGNR $8, CC0, CC0, CC0
+	VPALIGNR $12, DD0, DD0, DD0
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	polyAdd(16(oup))
+	polyMul
+	LEAQ     32(oup), oup
+	VPALIGNR $12, BB0, BB0, BB0
+	VPALIGNR $8, CC0, CC0, CC0
+	VPALIGNR $4, DD0, DD0, DD0
+	DECQ     itr1
+	JG       sealAVX2Tail128LoopA
+	DECQ     itr2
+	JGE      sealAVX2Tail128LoopB
+
+	VPADDD ·chacha20Constants<>(SB), AA0, AA1
+	VPADDD state1StoreAVX2, BB0, BB1
+	VPADDD state2StoreAVX2, CC0, CC1
+	VPADDD DD1, DD0, DD1
+
+	VPERM2I128 $0x02, AA1, BB1, AA0
+	VPERM2I128 $0x02, CC1, DD1, BB0
+	VPERM2I128 $0x13, AA1, BB1, CC0
+	VPERM2I128 $0x13, CC1, DD1, DD0
+	JMP        sealAVX2ShortSealLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+sealAVX2Tail256:
+	// Need to decrypt up to 256 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA ·chacha20Constants<>(SB), AA1
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA state1StoreAVX2, BB1
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA state2StoreAVX2, CC1
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA DD0, TT1
+	VMOVDQA DD1, TT2
+
+sealAVX2Tail256LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail256LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	polyAdd(0(oup))
+	polyMul
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	polyAdd(16(oup))
+	polyMul
+	LEAQ     32(oup), oup
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	DECQ     itr1
+	JG       sealAVX2Tail256LoopA
+	DECQ     itr2
+	JGE      sealAVX2Tail256LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1
+	VPADDD     TT1, DD0, DD0; VPADDD TT2, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPERM2I128 $0x02, CC0, DD0, TT1
+	VPERM2I128 $0x13, AA0, BB0, TT2
+	VPERM2I128 $0x13, CC0, DD0, TT3
+	VPXOR      (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+	MOVQ       $128, itr1
+	LEAQ       128(inp), inp
+	SUBQ       $128, inl
+	VPERM2I128 $0x02, AA1, BB1, AA0
+	VPERM2I128 $0x02, CC1, DD1, BB0
+	VPERM2I128 $0x13, AA1, BB1, CC0
+	VPERM2I128 $0x13, CC1, DD1, DD0
+
+	JMP sealAVX2SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 384 bytes of ciphertext
+sealAVX2Tail384:
+	// Need to decrypt up to 384 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA DD0, TT1; VMOVDQA DD1, TT2; VMOVDQA DD2, TT3
+
+sealAVX2Tail384LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail384LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	polyAdd(0(oup))
+	polyMul
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	polyAdd(16(oup))
+	polyMul
+	LEAQ     32(oup), oup
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+	DECQ     itr1
+	JG       sealAVX2Tail384LoopA
+	DECQ     itr2
+	JGE      sealAVX2Tail384LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2
+	VPADDD     TT1, DD0, DD0; VPADDD TT2, DD1, DD1; VPADDD TT3, DD2, DD2
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPERM2I128 $0x02, CC0, DD0, TT1
+	VPERM2I128 $0x13, AA0, BB0, TT2
+	VPERM2I128 $0x13, CC0, DD0, TT3
+	VPXOR      (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, TT0
+	VPERM2I128 $0x02, CC1, DD1, TT1
+	VPERM2I128 $0x13, AA1, BB1, TT2
+	VPERM2I128 $0x13, CC1, DD1, TT3
+	VPXOR      (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup)
+	MOVQ       $256, itr1
+	LEAQ       256(inp), inp
+	SUBQ       $256, inl
+	VPERM2I128 $0x02, AA2, BB2, AA0
+	VPERM2I128 $0x02, CC2, DD2, BB0
+	VPERM2I128 $0x13, AA2, BB2, CC0
+	VPERM2I128 $0x13, CC2, DD2, DD0
+
+	JMP sealAVX2SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 512 bytes of ciphertext
+sealAVX2Tail512:
+	// Need to decrypt up to 512 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+
+sealAVX2Tail512LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail512LoopB:
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(2*8(oup))
+	polyMulAVX2
+	LEAQ     (4*8)(oup), oup
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+
+	DECQ itr1
+	JG   sealAVX2Tail512LoopA
+	DECQ itr2
+	JGE  sealAVX2Tail512LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD     ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA    CC3, tmpStoreAVX2
+	VPERM2I128 $0x02, AA0, BB0, CC3
+	VPXOR      (0*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (0*32)(oup)
+	VPERM2I128 $0x02, CC0, DD0, CC3
+	VPXOR      (1*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (1*32)(oup)
+	VPERM2I128 $0x13, AA0, BB0, CC3
+	VPXOR      (2*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (2*32)(oup)
+	VPERM2I128 $0x13, CC0, DD0, CC3
+	VPXOR      (3*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (3*32)(oup)
+
+	VPERM2I128 $0x02, AA1, BB1, AA0
+	VPERM2I128 $0x02, CC1, DD1, BB0
+	VPERM2I128 $0x13, AA1, BB1, CC0
+	VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+	VPERM2I128 $0x02, AA2, BB2, AA0
+	VPERM2I128 $0x02, CC2, DD2, BB0
+	VPERM2I128 $0x13, AA2, BB2, CC0
+	VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+
+	MOVQ       $384, itr1
+	LEAQ       384(inp), inp
+	SUBQ       $384, inl
+	VPERM2I128 $0x02, AA3, BB3, AA0
+	VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0
+	VPERM2I128 $0x13, AA3, BB3, CC0
+	VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+
+	JMP sealAVX2SealHash

+ 81 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go

@@ -0,0 +1,81 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+	"encoding/binary"
+
+	"golang.org/x/crypto/internal/chacha20"
+	"golang.org/x/crypto/internal/subtle"
+	"golang.org/x/crypto/poly1305"
+)
+
+func roundTo16(n int) int {
+	return 16 * ((n + 15) / 16)
+}
+
+func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
+	ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
+	if subtle.InexactOverlap(out, plaintext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+
+	var polyKey [32]byte
+	s := chacha20.New(c.key, [3]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+	})
+	s.XORKeyStream(polyKey[:], polyKey[:])
+	s.Advance() // skip the next 32 bytes
+	s.XORKeyStream(out, plaintext)
+
+	polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
+	copy(polyInput, additionalData)
+	copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
+
+	var tag [poly1305.TagSize]byte
+	poly1305.Sum(&tag, polyInput, &polyKey)
+	copy(out[len(plaintext):], tag[:])
+
+	return ret
+}
+
+func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	var tag [poly1305.TagSize]byte
+	copy(tag[:], ciphertext[len(ciphertext)-16:])
+	ciphertext = ciphertext[:len(ciphertext)-16]
+
+	var polyKey [32]byte
+	s := chacha20.New(c.key, [3]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+	})
+	s.XORKeyStream(polyKey[:], polyKey[:])
+	s.Advance() // skip the next 32 bytes
+
+	polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
+	copy(polyInput, additionalData)
+	copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
+
+	ret, out := sliceForAppend(dst, len(ciphertext))
+	if subtle.InexactOverlap(out, ciphertext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+	if !poly1305.Verify(&tag, polyInput, &polyKey) {
+		for i := range out {
+			out[i] = 0
+		}
+		return nil, errOpen
+	}
+
+	s.XORKeyStream(out, ciphertext)
+	return ret, nil
+}

+ 15 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go

@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64 !go1.7 gccgo appengine
+
+package chacha20poly1305
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	return c.sealGeneric(dst, nonce, plaintext, additionalData)
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	return c.openGeneric(dst, nonce, ciphertext, additionalData)
+}

+ 255 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go

@@ -0,0 +1,255 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+	"bytes"
+	"crypto/cipher"
+	cryptorand "crypto/rand"
+	"encoding/hex"
+	"fmt"
+	"log"
+	mathrand "math/rand"
+	"strconv"
+	"testing"
+)
+
+func TestVectors(t *testing.T) {
+	for i, test := range chacha20Poly1305Tests {
+		key, _ := hex.DecodeString(test.key)
+		nonce, _ := hex.DecodeString(test.nonce)
+		ad, _ := hex.DecodeString(test.aad)
+		plaintext, _ := hex.DecodeString(test.plaintext)
+
+		var (
+			aead cipher.AEAD
+			err  error
+		)
+		switch len(nonce) {
+		case NonceSize:
+			aead, err = New(key)
+		case NonceSizeX:
+			aead, err = NewX(key)
+		default:
+			t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce))
+		}
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		ct := aead.Seal(nil, nonce, plaintext, ad)
+		if ctHex := hex.EncodeToString(ct); ctHex != test.out {
+			t.Errorf("#%d: got %s, want %s", i, ctHex, test.out)
+			continue
+		}
+
+		plaintext2, err := aead.Open(nil, nonce, ct, ad)
+		if err != nil {
+			t.Errorf("#%d: Open failed", i)
+			continue
+		}
+
+		if !bytes.Equal(plaintext, plaintext2) {
+			t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+			continue
+		}
+
+		if len(ad) > 0 {
+			alterAdIdx := mathrand.Intn(len(ad))
+			ad[alterAdIdx] ^= 0x80
+			if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+				t.Errorf("#%d: Open was successful after altering additional data", i)
+			}
+			ad[alterAdIdx] ^= 0x80
+		}
+
+		alterNonceIdx := mathrand.Intn(aead.NonceSize())
+		nonce[alterNonceIdx] ^= 0x80
+		if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+			t.Errorf("#%d: Open was successful after altering nonce", i)
+		}
+		nonce[alterNonceIdx] ^= 0x80
+
+		alterCtIdx := mathrand.Intn(len(ct))
+		ct[alterCtIdx] ^= 0x80
+		if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+			t.Errorf("#%d: Open was successful after altering ciphertext", i)
+		}
+		ct[alterCtIdx] ^= 0x80
+	}
+}
+
+func TestRandom(t *testing.T) {
+	// Some random tests to verify Open(Seal) == Plaintext
+	f := func(t *testing.T, nonceSize int) {
+		for i := 0; i < 256; i++ {
+			var nonce = make([]byte, nonceSize)
+			var key [32]byte
+
+			al := mathrand.Intn(128)
+			pl := mathrand.Intn(16384)
+			ad := make([]byte, al)
+			plaintext := make([]byte, pl)
+			cryptorand.Read(key[:])
+			cryptorand.Read(nonce[:])
+			cryptorand.Read(ad)
+			cryptorand.Read(plaintext)
+
+			var (
+				aead cipher.AEAD
+				err  error
+			)
+			switch len(nonce) {
+			case NonceSize:
+				aead, err = New(key[:])
+			case NonceSizeX:
+				aead, err = NewX(key[:])
+			default:
+				t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce))
+			}
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			ct := aead.Seal(nil, nonce[:], plaintext, ad)
+
+			plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
+			if err != nil {
+				t.Errorf("Random #%d: Open failed", i)
+				continue
+			}
+
+			if !bytes.Equal(plaintext, plaintext2) {
+				t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+				continue
+			}
+
+			if len(ad) > 0 {
+				alterAdIdx := mathrand.Intn(len(ad))
+				ad[alterAdIdx] ^= 0x80
+				if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+					t.Errorf("Random #%d: Open was successful after altering additional data", i)
+				}
+				ad[alterAdIdx] ^= 0x80
+			}
+
+			alterNonceIdx := mathrand.Intn(aead.NonceSize())
+			nonce[alterNonceIdx] ^= 0x80
+			if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+				t.Errorf("Random #%d: Open was successful after altering nonce", i)
+			}
+			nonce[alterNonceIdx] ^= 0x80
+
+			alterCtIdx := mathrand.Intn(len(ct))
+			ct[alterCtIdx] ^= 0x80
+			if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+				t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
+			}
+			ct[alterCtIdx] ^= 0x80
+		}
+	}
+	t.Run("Standard", func(t *testing.T) { f(t, NonceSize) })
+	t.Run("X", func(t *testing.T) { f(t, NonceSizeX) })
+}
+
+func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) {
+	b.ReportAllocs()
+	b.SetBytes(int64(len(buf)))
+
+	var key [32]byte
+	var nonce = make([]byte, nonceSize)
+	var ad [13]byte
+	var out []byte
+
+	var aead cipher.AEAD
+	switch len(nonce) {
+	case NonceSize:
+		aead, _ = New(key[:])
+	case NonceSizeX:
+		aead, _ = NewX(key[:])
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		out = aead.Seal(out[:0], nonce[:], buf[:], ad[:])
+	}
+}
+
+func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) {
+	b.ReportAllocs()
+	b.SetBytes(int64(len(buf)))
+
+	var key [32]byte
+	var nonce = make([]byte, nonceSize)
+	var ad [13]byte
+	var ct []byte
+	var out []byte
+
+	var aead cipher.AEAD
+	switch len(nonce) {
+	case NonceSize:
+		aead, _ = New(key[:])
+	case NonceSizeX:
+		aead, _ = NewX(key[:])
+	}
+	ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:])
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		out, _ = aead.Open(out[:0], nonce[:], ct[:], ad[:])
+	}
+}
+
+func BenchmarkChacha20Poly1305(b *testing.B) {
+	for _, length := range []int{64, 1350, 8 * 1024} {
+		b.Run("Open-"+strconv.Itoa(length), func(b *testing.B) {
+			benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize)
+		})
+		b.Run("Seal-"+strconv.Itoa(length), func(b *testing.B) {
+			benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize)
+		})
+
+		b.Run("Open-"+strconv.Itoa(length)+"-X", func(b *testing.B) {
+			benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX)
+		})
+		b.Run("Seal-"+strconv.Itoa(length)+"-X", func(b *testing.B) {
+			benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX)
+		})
+	}
+}
+
+var key = make([]byte, KeySize)
+
+func ExampleNewX() {
+	aead, err := NewX(key)
+	if err != nil {
+		log.Fatalln("Failed to instantiate XChaCha20-Poly1305:", err)
+	}
+
+	for _, msg := range []string{
+		"Attack at dawn.",
+		"The eagle has landed.",
+		"Gophers, gophers, gophers everywhere!",
+	} {
+		// Encryption.
+		nonce := make([]byte, NonceSizeX)
+		if _, err := cryptorand.Read(nonce); err != nil {
+			panic(err)
+		}
+		ciphertext := aead.Seal(nil, nonce, []byte(msg), nil)
+
+		// Decryption.
+		plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
+		if err != nil {
+			log.Fatalln("Failed to decrypt or authenticate message:", err)
+		}
+
+		fmt.Printf("%s\n", plaintext)
+	}
+
+	// Output: Attack at dawn.
+	// The eagle has landed.
+	// Gophers, gophers, gophers everywhere!
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 101 - 0
src/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go


+ 104 - 0
src/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go

@@ -0,0 +1,104 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+	"crypto/cipher"
+	"encoding/binary"
+	"errors"
+
+	"golang.org/x/crypto/internal/chacha20"
+)
+
+type xchacha20poly1305 struct {
+	key [8]uint32
+}
+
+// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
+//
+// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
+// suitable to be generated randomly without risk of collisions. It should be
+// preferred when nonce uniqueness cannot be trivially ensured, or whenever
+// nonces are randomly generated.
+func NewX(key []byte) (cipher.AEAD, error) {
+	if len(key) != KeySize {
+		return nil, errors.New("chacha20poly1305: bad key length")
+	}
+	ret := new(xchacha20poly1305)
+	ret.key[0] = binary.LittleEndian.Uint32(key[0:4])
+	ret.key[1] = binary.LittleEndian.Uint32(key[4:8])
+	ret.key[2] = binary.LittleEndian.Uint32(key[8:12])
+	ret.key[3] = binary.LittleEndian.Uint32(key[12:16])
+	ret.key[4] = binary.LittleEndian.Uint32(key[16:20])
+	ret.key[5] = binary.LittleEndian.Uint32(key[20:24])
+	ret.key[6] = binary.LittleEndian.Uint32(key[24:28])
+	ret.key[7] = binary.LittleEndian.Uint32(key[28:32])
+	return ret, nil
+}
+
+func (*xchacha20poly1305) NonceSize() int {
+	return NonceSizeX
+}
+
+func (*xchacha20poly1305) Overhead() int {
+	return 16
+}
+
+func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	if len(nonce) != NonceSizeX {
+		panic("chacha20poly1305: bad nonce length passed to Seal")
+	}
+
+	// XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
+	// size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
+	// the second half of the counter is not available. This is unlikely to be
+	// an issue because the cipher.AEAD API requires the entire message to be in
+	// memory, and the counter overflows at 256 GB.
+	if uint64(len(plaintext)) > (1<<38)-64 {
+		panic("chacha20poly1305: plaintext too large")
+	}
+
+	hNonce := [4]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+		binary.LittleEndian.Uint32(nonce[12:16]),
+	}
+	c := &chacha20poly1305{
+		key: chacha20.HChaCha20(&x.key, &hNonce),
+	}
+	// The first 4 bytes of the final nonce are unused counter space.
+	cNonce := make([]byte, NonceSize)
+	copy(cNonce[4:12], nonce[16:24])
+
+	return c.seal(dst, cNonce[:], plaintext, additionalData)
+}
+
+func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	if len(nonce) != NonceSizeX {
+		panic("chacha20poly1305: bad nonce length passed to Open")
+	}
+	if len(ciphertext) < 16 {
+		return nil, errOpen
+	}
+	if uint64(len(ciphertext)) > (1<<38)-48 {
+		panic("chacha20poly1305: ciphertext too large")
+	}
+
+	hNonce := [4]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+		binary.LittleEndian.Uint32(nonce[12:16]),
+	}
+	c := &chacha20poly1305{
+		key: chacha20.HChaCha20(&x.key, &hNonce),
+	}
+	// The first 4 bytes of the final nonce are unused counter space.
+	cNonce := make([]byte, NonceSize)
+	copy(cNonce[4:12], nonce[16:24])
+
+	return c.open(dst, cNonce[:], ciphertext, additionalData)
+}

+ 1 - 0
src/golang.org/x/crypto/codereview.cfg

@@ -0,0 +1 @@
+issuerepo: golang/go

+ 751 - 0
src/golang.org/x/crypto/cryptobyte/asn1.go

@@ -0,0 +1,751 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cryptobyte
+
+import (
+	encoding_asn1 "encoding/asn1"
+	"fmt"
+	"math/big"
+	"reflect"
+	"time"
+
+	"golang.org/x/crypto/cryptobyte/asn1"
+)
+
+// This file contains ASN.1-related methods for String and Builder.
+
+// Builder
+
+// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
+func (b *Builder) AddASN1Int64(v int64) {
+	b.addASN1Signed(asn1.INTEGER, v)
+}
+
+// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the
+// given tag.
+func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) {
+	b.addASN1Signed(tag, v)
+}
+
+// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
+func (b *Builder) AddASN1Enum(v int64) {
+	b.addASN1Signed(asn1.ENUM, v)
+}
+
+func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) {
+	b.AddASN1(tag, func(c *Builder) {
+		length := 1
+		for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
+			length++
+		}
+
+		for ; length > 0; length-- {
+			i := v >> uint((length-1)*8) & 0xff
+			c.AddUint8(uint8(i))
+		}
+	})
+}
+
+// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
+func (b *Builder) AddASN1Uint64(v uint64) {
+	b.AddASN1(asn1.INTEGER, func(c *Builder) {
+		length := 1
+		for i := v; i >= 0x80; i >>= 8 {
+			length++
+		}
+
+		for ; length > 0; length-- {
+			i := v >> uint((length-1)*8) & 0xff
+			c.AddUint8(uint8(i))
+		}
+	})
+}
+
+// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
+func (b *Builder) AddASN1BigInt(n *big.Int) {
+	if b.err != nil {
+		return
+	}
+
+	b.AddASN1(asn1.INTEGER, func(c *Builder) {
+		if n.Sign() < 0 {
+			// A negative number has to be converted to two's-complement form. So we
+			// invert and subtract 1. If the most-significant-bit isn't set then
+			// we'll need to pad the beginning with 0xff in order to keep the number
+			// negative.
+			nMinus1 := new(big.Int).Neg(n)
+			nMinus1.Sub(nMinus1, bigOne)
+			bytes := nMinus1.Bytes()
+			for i := range bytes {
+				bytes[i] ^= 0xff
+			}
+			if bytes[0]&0x80 == 0 {
+				c.add(0xff)
+			}
+			c.add(bytes...)
+		} else if n.Sign() == 0 {
+			c.add(0)
+		} else {
+			bytes := n.Bytes()
+			if bytes[0]&0x80 != 0 {
+				c.add(0)
+			}
+			c.add(bytes...)
+		}
+	})
+}
+
+// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
+func (b *Builder) AddASN1OctetString(bytes []byte) {
+	b.AddASN1(asn1.OCTET_STRING, func(c *Builder) {
+		c.AddBytes(bytes)
+	})
+}
+
+const generalizedTimeFormatStr = "20060102150405Z0700"
+
+// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
+func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
+	if t.Year() < 0 || t.Year() > 9999 {
+		b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
+		return
+	}
+	b.AddASN1(asn1.GeneralizedTime, func(c *Builder) {
+		c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
+	})
+}
+
+// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not
+// support BIT STRINGs that are not a whole number of bytes.
+func (b *Builder) AddASN1BitString(data []byte) {
+	b.AddASN1(asn1.BIT_STRING, func(b *Builder) {
+		b.AddUint8(0)
+		b.AddBytes(data)
+	})
+}
+
+func (b *Builder) addBase128Int(n int64) {
+	var length int
+	if n == 0 {
+		length = 1
+	} else {
+		for i := n; i > 0; i >>= 7 {
+			length++
+		}
+	}
+
+	for i := length - 1; i >= 0; i-- {
+		o := byte(n >> uint(i*7))
+		o &= 0x7f
+		if i != 0 {
+			o |= 0x80
+		}
+
+		b.add(o)
+	}
+}
+
+func isValidOID(oid encoding_asn1.ObjectIdentifier) bool {
+	if len(oid) < 2 {
+		return false
+	}
+
+	if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) {
+		return false
+	}
+
+	for _, v := range oid {
+		if v < 0 {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) {
+	b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) {
+		if !isValidOID(oid) {
+			b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid)
+			return
+		}
+
+		b.addBase128Int(int64(oid[0])*40 + int64(oid[1]))
+		for _, v := range oid[2:] {
+			b.addBase128Int(int64(v))
+		}
+	})
+}
+
+func (b *Builder) AddASN1Boolean(v bool) {
+	b.AddASN1(asn1.BOOLEAN, func(b *Builder) {
+		if v {
+			b.AddUint8(0xff)
+		} else {
+			b.AddUint8(0)
+		}
+	})
+}
+
+func (b *Builder) AddASN1NULL() {
+	b.add(uint8(asn1.NULL), 0)
+}
+
+// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if
+// successful or records an error if one occurred.
+func (b *Builder) MarshalASN1(v interface{}) {
+	// NOTE(martinkr): This is somewhat of a hack to allow propagation of
+	// encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
+	// value embedded into a struct, its tag information is lost.
+	if b.err != nil {
+		return
+	}
+	bytes, err := encoding_asn1.Marshal(v)
+	if err != nil {
+		b.err = err
+		return
+	}
+	b.AddBytes(bytes)
+}
+
+// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
+// Tags greater than 30 are not supported and result in an error (i.e.
+// low-tag-number form only). The child builder passed to the
+// BuilderContinuation can be used to build the content of the ASN.1 object.
+func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
+	if b.err != nil {
+		return
+	}
+	// Identifiers with the low five bits set indicate high-tag-number format
+	// (two or more octets), which we don't support.
+	if tag&0x1f == 0x1f {
+		b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
+		return
+	}
+	b.AddUint8(uint8(tag))
+	b.addLengthPrefixed(1, true, f)
+}
+
+// String
+
+// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean
+// representation into out and advances. It reports whether the read
+// was successful.
+func (s *String) ReadASN1Boolean(out *bool) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 {
+		return false
+	}
+
+	switch bytes[0] {
+	case 0:
+		*out = false
+	case 0xff:
+		*out = true
+	default:
+		return false
+	}
+
+	return true
+}
+
+var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
+
+// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
+// not point to an integer or to a big.Int, it panics. It reports whether the
+// read was successful.
+func (s *String) ReadASN1Integer(out interface{}) bool {
+	if reflect.TypeOf(out).Kind() != reflect.Ptr {
+		panic("out is not a pointer")
+	}
+	switch reflect.ValueOf(out).Elem().Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		var i int64
+		if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
+			return false
+		}
+		reflect.ValueOf(out).Elem().SetInt(i)
+		return true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		var u uint64
+		if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
+			return false
+		}
+		reflect.ValueOf(out).Elem().SetUint(u)
+		return true
+	case reflect.Struct:
+		if reflect.TypeOf(out).Elem() == bigIntType {
+			return s.readASN1BigInt(out.(*big.Int))
+		}
+	}
+	panic("out does not point to an integer type")
+}
+
+func checkASN1Integer(bytes []byte) bool {
+	if len(bytes) == 0 {
+		// An INTEGER is encoded with at least one octet.
+		return false
+	}
+	if len(bytes) == 1 {
+		return true
+	}
+	if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
+		// Value is not minimally encoded.
+		return false
+	}
+	return true
+}
+
+var bigOne = big.NewInt(1)
+
+func (s *String) readASN1BigInt(out *big.Int) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) {
+		return false
+	}
+	if bytes[0]&0x80 == 0x80 {
+		// Negative number.
+		neg := make([]byte, len(bytes))
+		for i, b := range bytes {
+			neg[i] = ^b
+		}
+		out.SetBytes(neg)
+		out.Add(out, bigOne)
+		out.Neg(out)
+	} else {
+		out.SetBytes(bytes)
+	}
+	return true
+}
+
+func (s *String) readASN1Int64(out *int64) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
+		return false
+	}
+	return true
+}
+
+func asn1Signed(out *int64, n []byte) bool {
+	length := len(n)
+	if length > 8 {
+		return false
+	}
+	for i := 0; i < length; i++ {
+		*out <<= 8
+		*out |= int64(n[i])
+	}
+	// Shift up and down in order to sign extend the result.
+	*out <<= 64 - uint8(length)*8
+	*out >>= 64 - uint8(length)*8
+	return true
+}
+
+func (s *String) readASN1Uint64(out *uint64) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
+		return false
+	}
+	return true
+}
+
+func asn1Unsigned(out *uint64, n []byte) bool {
+	length := len(n)
+	if length > 9 || length == 9 && n[0] != 0 {
+		// Too large for uint64.
+		return false
+	}
+	if n[0]&0x80 != 0 {
+		// Negative number.
+		return false
+	}
+	for i := 0; i < length; i++ {
+		*out <<= 8
+		*out |= uint64(n[i])
+	}
+	return true
+}
+
+// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out
+// and advances. It reports whether the read was successful and resulted in a
+// value that can be represented in an int64.
+func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool {
+	var bytes String
+	return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes)
+}
+
+// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports
+// whether the read was successful.
+func (s *String) ReadASN1Enum(out *int) bool {
+	var bytes String
+	var i int64
+	if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
+		return false
+	}
+	if int64(int(i)) != i {
+		return false
+	}
+	*out = int(i)
+	return true
+}
+
+func (s *String) readBase128Int(out *int) bool {
+	ret := 0
+	for i := 0; len(*s) > 0; i++ {
+		if i == 4 {
+			return false
+		}
+		ret <<= 7
+		b := s.read(1)[0]
+		ret |= int(b & 0x7f)
+		if b&0x80 == 0 {
+			*out = ret
+			return true
+		}
+	}
+	return false // truncated
+}
+
+// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
+// advances. It reports whether the read was successful.
+func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 {
+		return false
+	}
+
+	// In the worst case, we get two elements from the first byte (which is
+	// encoded differently) and then every varint is a single byte long.
+	components := make([]int, len(bytes)+1)
+
+	// The first varint is 40*value1 + value2:
+	// According to this packing, value1 can take the values 0, 1 and 2 only.
+	// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
+	// then there are no restrictions on value2.
+	var v int
+	if !bytes.readBase128Int(&v) {
+		return false
+	}
+	if v < 80 {
+		components[0] = v / 40
+		components[1] = v % 40
+	} else {
+		components[0] = 2
+		components[1] = v - 80
+	}
+
+	i := 2
+	for ; len(bytes) > 0; i++ {
+		if !bytes.readBase128Int(&v) {
+			return false
+		}
+		components[i] = v
+	}
+	*out = components[:i]
+	return true
+}
+
+// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
+// advances. It reports whether the read was successful.
+func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
+		return false
+	}
+	t := string(bytes)
+	res, err := time.Parse(generalizedTimeFormatStr, t)
+	if err != nil {
+		return false
+	}
+	if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
+		return false
+	}
+	*out = res
+	return true
+}
+
+// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances.
+// It reports whether the read was successful.
+func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
+		return false
+	}
+
+	paddingBits := uint8(bytes[0])
+	bytes = bytes[1:]
+	if paddingBits > 7 ||
+		len(bytes) == 0 && paddingBits != 0 ||
+		len(bytes) > 0 && bytes[len(bytes)-1]&(1<<paddingBits-1) != 0 {
+		return false
+	}
+
+	out.BitLength = len(bytes)*8 - int(paddingBits)
+	out.Bytes = bytes
+	return true
+}
+
+// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is
+// an error if the BIT STRING is not a whole number of bytes. It reports
+// whether the read was successful.
+func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
+	var bytes String
+	if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
+		return false
+	}
+
+	paddingBits := uint8(bytes[0])
+	if paddingBits != 0 {
+		return false
+	}
+	*out = bytes[1:]
+	return true
+}
+
+// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including
+// tag and length bytes) into out, and advances. The element must match the
+// given tag. It reports whether the read was successful.
+func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool {
+	return s.ReadASN1((*String)(out), tag)
+}
+
+// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including
+// tag and length bytes) into out, and advances. The element must match the
+// given tag. It reports whether the read was successful.
+//
+// Tags greater than 30 are not supported (i.e. low-tag-number format only).
+func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
+	var t asn1.Tag
+	if !s.ReadAnyASN1(out, &t) || t != tag {
+		return false
+	}
+	return true
+}
+
+// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including
+// tag and length bytes) into out, and advances. The element must match the
+// given tag. It reports whether the read was successful.
+//
+// Tags greater than 30 are not supported (i.e. low-tag-number format only).
+func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
+	var t asn1.Tag
+	if !s.ReadAnyASN1Element(out, &t) || t != tag {
+		return false
+	}
+	return true
+}
+
+// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including
+// tag and length bytes) into out, sets outTag to its tag, and advances.
+// It reports whether the read was successful.
+//
+// Tags greater than 30 are not supported (i.e. low-tag-number format only).
+func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
+	return s.readASN1(out, outTag, true /* skip header */)
+}
+
+// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
+// (including tag and length bytes) into out, sets outTag to is tag, and
+// advances. It reports whether the read was successful.
+//
+// Tags greater than 30 are not supported (i.e. low-tag-number format only).
+func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
+	return s.readASN1(out, outTag, false /* include header */)
+}
+
+// PeekASN1Tag reports whether the next ASN.1 value on the string starts with
+// the given tag.
+func (s String) PeekASN1Tag(tag asn1.Tag) bool {
+	if len(s) == 0 {
+		return false
+	}
+	return asn1.Tag(s[0]) == tag
+}
+
+// SkipASN1 reads and discards an ASN.1 element with the given tag. It
+// reports whether the operation was successful.
+func (s *String) SkipASN1(tag asn1.Tag) bool {
+	var unused String
+	return s.ReadASN1(&unused, tag)
+}
+
+// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1
+// element (not including tag and length bytes) tagged with the given tag into
+// out. It stores whether an element with the tag was found in outPresent,
+// unless outPresent is nil. It reports whether the read was successful.
+func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool {
+	present := s.PeekASN1Tag(tag)
+	if outPresent != nil {
+		*outPresent = present
+	}
+	if present && !s.ReadASN1(out, tag) {
+		return false
+	}
+	return true
+}
+
+// SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or
+// else leaves s unchanged. It reports whether the operation was successful.
+func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
+	if !s.PeekASN1Tag(tag) {
+		return true
+	}
+	var unused String
+	return s.ReadASN1(&unused, tag)
+}
+
+// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
+// explicitly tagged with tag into out and advances. If no element with a
+// matching tag is present, it writes defaultValue into out instead. If out
+// does not point to an integer or to a big.Int, it panics. It reports
+// whether the read was successful.
+func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool {
+	if reflect.TypeOf(out).Kind() != reflect.Ptr {
+		panic("out is not a pointer")
+	}
+	var present bool
+	var i String
+	if !s.ReadOptionalASN1(&i, &present, tag) {
+		return false
+	}
+	if !present {
+		switch reflect.ValueOf(out).Elem().Kind() {
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
+		case reflect.Struct:
+			if reflect.TypeOf(out).Elem() != bigIntType {
+				panic("invalid integer type")
+			}
+			if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr ||
+				reflect.TypeOf(defaultValue).Elem() != bigIntType {
+				panic("out points to big.Int, but defaultValue does not")
+			}
+			out.(*big.Int).Set(defaultValue.(*big.Int))
+		default:
+			panic("invalid integer type")
+		}
+		return true
+	}
+	if !i.ReadASN1Integer(out) || !i.Empty() {
+		return false
+	}
+	return true
+}
+
+// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
+// explicitly tagged with tag into out and advances. If no element with a
+// matching tag is present, it sets "out" to nil instead. It reports
+// whether the read was successful.
+func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool {
+	var present bool
+	var child String
+	if !s.ReadOptionalASN1(&child, &present, tag) {
+		return false
+	}
+	if outPresent != nil {
+		*outPresent = present
+	}
+	if present {
+		var oct String
+		if !child.ReadASN1(&oct, asn1.OCTET_STRING) || !child.Empty() {
+			return false
+		}
+		*out = oct
+	} else {
+		*out = nil
+	}
+	return true
+}
+
+// ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or,
+// if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue.
+// It reports whether the operation was successful.
+func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
+	var present bool
+	var child String
+	if !s.ReadOptionalASN1(&child, &present, asn1.BOOLEAN) {
+		return false
+	}
+
+	if !present {
+		*out = defaultValue
+		return true
+	}
+
+	return s.ReadASN1Boolean(out)
+}
+
+func (s *String) readASN1(out *String, outTag *asn1.Tag, skipHeader bool) bool {
+	if len(*s) < 2 {
+		return false
+	}
+	tag, lenByte := (*s)[0], (*s)[1]
+
+	if tag&0x1f == 0x1f {
+		// ITU-T X.690 section 8.1.2
+		//
+		// An identifier octet with a tag part of 0x1f indicates a high-tag-number
+		// form identifier with two or more octets. We only support tags less than
+		// 31 (i.e. low-tag-number form, single octet identifier).
+		return false
+	}
+
+	if outTag != nil {
+		*outTag = asn1.Tag(tag)
+	}
+
+	// ITU-T X.690 section 8.1.3
+	//
+	// Bit 8 of the first length byte indicates whether the length is short- or
+	// long-form.
+	var length, headerLen uint32 // length includes headerLen
+	if lenByte&0x80 == 0 {
+		// Short-form length (section 8.1.3.4), encoded in bits 1-7.
+		length = uint32(lenByte) + 2
+		headerLen = 2
+	} else {
+		// Long-form length (section 8.1.3.5). Bits 1-7 encode the number of octets
+		// used to encode the length.
+		lenLen := lenByte & 0x7f
+		var len32 uint32
+
+		if lenLen == 0 || lenLen > 4 || len(*s) < int(2+lenLen) {
+			return false
+		}
+
+		lenBytes := String((*s)[2 : 2+lenLen])
+		if !lenBytes.readUnsigned(&len32, int(lenLen)) {
+			return false
+		}
+
+		// ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
+		// with the minimum number of octets.
+		if len32 < 128 {
+			// Length should have used short-form encoding.
+			return false
+		}
+		if len32>>((lenLen-1)*8) == 0 {
+			// Leading octet is 0. Length should have been at least one byte shorter.
+			return false
+		}
+
+		headerLen = 2 + uint32(lenLen)
+		if headerLen+len32 < len32 {
+			// Overflow.
+			return false
+		}
+		length = headerLen + len32
+	}
+
+	if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) {
+		return false
+	}
+	if skipHeader && !out.Skip(int(headerLen)) {
+		panic("cryptobyte: internal error")
+	}
+
+	return true
+}

+ 46 - 0
src/golang.org/x/crypto/cryptobyte/asn1/asn1.go

@@ -0,0 +1,46 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package asn1 contains supporting types for parsing and building ASN.1
+// messages with the cryptobyte package.
+package asn1 // import "golang.org/x/crypto/cryptobyte/asn1"
+
+// Tag represents an ASN.1 identifier octet, consisting of a tag number
+// (indicating a type) and class (such as context-specific or constructed).
+//
+// Methods in the cryptobyte package only support the low-tag-number form, i.e.
+// a single identifier octet with bits 7-8 encoding the class and bits 1-6
+// encoding the tag number.
+type Tag uint8
+
+const (
+	classConstructed     = 0x20
+	classContextSpecific = 0x80
+)
+
+// Constructed returns t with the constructed class bit set.
+func (t Tag) Constructed() Tag { return t | classConstructed }
+
+// ContextSpecific returns t with the context-specific class bit set.
+func (t Tag) ContextSpecific() Tag { return t | classContextSpecific }
+
+// The following is a list of standard tag and class combinations.
+const (
+	BOOLEAN           = Tag(1)
+	INTEGER           = Tag(2)
+	BIT_STRING        = Tag(3)
+	OCTET_STRING      = Tag(4)
+	NULL              = Tag(5)
+	OBJECT_IDENTIFIER = Tag(6)
+	ENUM              = Tag(10)
+	UTF8String        = Tag(12)
+	SEQUENCE          = Tag(16 | classConstructed)
+	SET               = Tag(17 | classConstructed)
+	PrintableString   = Tag(19)
+	T61String         = Tag(20)
+	IA5String         = Tag(22)
+	UTCTime           = Tag(23)
+	GeneralizedTime   = Tag(24)
+	GeneralString     = Tag(27)
+)

+ 333 - 0
src/golang.org/x/crypto/cryptobyte/asn1_test.go

@@ -0,0 +1,333 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cryptobyte
+
+import (
+	"bytes"
+	encoding_asn1 "encoding/asn1"
+	"math/big"
+	"reflect"
+	"testing"
+	"time"
+
+	"golang.org/x/crypto/cryptobyte/asn1"
+)
+
+type readASN1Test struct {
+	name string
+	in   []byte
+	tag  asn1.Tag
+	ok   bool
+	out  interface{}
+}
+
+var readASN1TestData = []readASN1Test{
+	{"valid", []byte{0x30, 2, 1, 2}, 0x30, true, []byte{1, 2}},
+	{"truncated", []byte{0x30, 3, 1, 2}, 0x30, false, nil},
+	{"zero length of length", []byte{0x30, 0x80}, 0x30, false, nil},
+	{"invalid long form length", []byte{0x30, 0x81, 1, 1}, 0x30, false, nil},
+	{"non-minimal length", append([]byte{0x30, 0x82, 0, 0x80}, make([]byte, 0x80)...), 0x30, false, nil},
+	{"invalid tag", []byte{0xa1, 3, 0x4, 1, 1}, 31, false, nil},
+	{"high tag", []byte{0x1f, 0x81, 0x80, 0x01, 2, 1, 2}, 0xff /* actually 0x4001, but tag is uint8 */, false, nil},
+}
+
+func TestReadASN1(t *testing.T) {
+	for _, test := range readASN1TestData {
+		t.Run(test.name, func(t *testing.T) {
+			var in, out String = test.in, nil
+			ok := in.ReadASN1(&out, test.tag)
+			if ok != test.ok || ok && !bytes.Equal(out, test.out.([]byte)) {
+				t.Errorf("in.ReadASN1() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
+			}
+		})
+	}
+}
+
+func TestReadASN1Optional(t *testing.T) {
+	var empty String
+	var present bool
+	ok := empty.ReadOptionalASN1(nil, &present, 0xa0)
+	if !ok || present {
+		t.Errorf("empty.ReadOptionalASN1() = %v, want true; present = %v want false", ok, present)
+	}
+
+	var in, out String = []byte{0xa1, 3, 0x4, 1, 1}, nil
+	ok = in.ReadOptionalASN1(&out, &present, 0xa0)
+	if !ok || present {
+		t.Errorf("in.ReadOptionalASN1() = %v, want true, present = %v, want false", ok, present)
+	}
+	ok = in.ReadOptionalASN1(&out, &present, 0xa1)
+	wantBytes := []byte{4, 1, 1}
+	if !ok || !present || !bytes.Equal(out, wantBytes) {
+		t.Errorf("in.ReadOptionalASN1() = %v, want true; present = %v, want true; out = %v, want = %v", ok, present, out, wantBytes)
+	}
+}
+
+var optionalOctetStringTestData = []struct {
+	readASN1Test
+	present bool
+}{
+	{readASN1Test{"empty", []byte{}, 0xa0, true, []byte{}}, false},
+	{readASN1Test{"invalid", []byte{0xa1, 3, 0x4, 2, 1}, 0xa1, false, []byte{}}, true},
+	{readASN1Test{"missing", []byte{0xa1, 3, 0x4, 1, 1}, 0xa0, true, []byte{}}, false},
+	{readASN1Test{"present", []byte{0xa1, 3, 0x4, 1, 1}, 0xa1, true, []byte{1}}, true},
+}
+
+func TestReadASN1OptionalOctetString(t *testing.T) {
+	for _, test := range optionalOctetStringTestData {
+		t.Run(test.name, func(t *testing.T) {
+			in := String(test.in)
+			var out []byte
+			var present bool
+			ok := in.ReadOptionalASN1OctetString(&out, &present, test.tag)
+			if ok != test.ok || present != test.present || !bytes.Equal(out, test.out.([]byte)) {
+				t.Errorf("in.ReadOptionalASN1OctetString() = %v, want %v; present = %v want %v; out = %v, want %v", ok, test.ok, present, test.present, out, test.out)
+			}
+		})
+	}
+}
+
+const defaultInt = -1
+
+var optionalIntTestData = []readASN1Test{
+	{"empty", []byte{}, 0xa0, true, defaultInt},
+	{"invalid", []byte{0xa1, 3, 0x2, 2, 127}, 0xa1, false, 0},
+	{"missing", []byte{0xa1, 3, 0x2, 1, 127}, 0xa0, true, defaultInt},
+	{"present", []byte{0xa1, 3, 0x2, 1, 42}, 0xa1, true, 42},
+}
+
+func TestReadASN1OptionalInteger(t *testing.T) {
+	for _, test := range optionalIntTestData {
+		t.Run(test.name, func(t *testing.T) {
+			in := String(test.in)
+			var out int
+			ok := in.ReadOptionalASN1Integer(&out, test.tag, defaultInt)
+			if ok != test.ok || ok && out != test.out.(int) {
+				t.Errorf("in.ReadOptionalASN1Integer() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
+			}
+		})
+	}
+}
+
+func TestReadASN1IntegerSigned(t *testing.T) {
+	testData64 := []struct {
+		in  []byte
+		out int64
+	}{
+		{[]byte{2, 3, 128, 0, 0}, -0x800000},
+		{[]byte{2, 2, 255, 0}, -256},
+		{[]byte{2, 2, 255, 127}, -129},
+		{[]byte{2, 1, 128}, -128},
+		{[]byte{2, 1, 255}, -1},
+		{[]byte{2, 1, 0}, 0},
+		{[]byte{2, 1, 1}, 1},
+		{[]byte{2, 1, 2}, 2},
+		{[]byte{2, 1, 127}, 127},
+		{[]byte{2, 2, 0, 128}, 128},
+		{[]byte{2, 2, 1, 0}, 256},
+		{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
+	}
+	for i, test := range testData64 {
+		in := String(test.in)
+		var out int64
+		ok := in.ReadASN1Integer(&out)
+		if !ok || out != test.out {
+			t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
+		}
+	}
+
+	// Repeat the same cases, reading into a big.Int.
+	t.Run("big.Int", func(t *testing.T) {
+		for i, test := range testData64 {
+			in := String(test.in)
+			var out big.Int
+			ok := in.ReadASN1Integer(&out)
+			if !ok || out.Int64() != test.out {
+				t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out.Int64(), test.out)
+			}
+		}
+	})
+
+	// Repeat with the implicit-tagging functions
+	t.Run("WithTag", func(t *testing.T) {
+		for i, test := range testData64 {
+			tag := asn1.Tag((i * 3) % 32).ContextSpecific()
+
+			testData := make([]byte, len(test.in))
+			copy(testData, test.in)
+
+			// Alter the tag of the test case.
+			testData[0] = uint8(tag)
+
+			in := String(testData)
+			var out int64
+			ok := in.ReadASN1Int64WithTag(&out, tag)
+			if !ok || out != test.out {
+				t.Errorf("#%d: in.ReadASN1Int64WithTag() = %v, want true; out = %d, want %d", i, ok, out, test.out)
+			}
+
+			var b Builder
+			b.AddASN1Int64WithTag(test.out, tag)
+			result, err := b.Bytes()
+
+			if err != nil {
+				t.Errorf("#%d: AddASN1Int64WithTag failed: %s", i, err)
+				continue
+			}
+
+			if !bytes.Equal(result, testData) {
+				t.Errorf("#%d: AddASN1Int64WithTag: got %x, want %x", i, result, testData)
+			}
+		}
+	})
+}
+
+func TestReadASN1IntegerUnsigned(t *testing.T) {
+	testData := []struct {
+		in  []byte
+		out uint64
+	}{
+		{[]byte{2, 1, 0}, 0},
+		{[]byte{2, 1, 1}, 1},
+		{[]byte{2, 1, 2}, 2},
+		{[]byte{2, 1, 127}, 127},
+		{[]byte{2, 2, 0, 128}, 128},
+		{[]byte{2, 2, 1, 0}, 256},
+		{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
+		{[]byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}, 0x7fffffffffffffff},
+		{[]byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}, 0x8000000000000000},
+		{[]byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}, 0xffffffffffffffff},
+	}
+	for i, test := range testData {
+		in := String(test.in)
+		var out uint64
+		ok := in.ReadASN1Integer(&out)
+		if !ok || out != test.out {
+			t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
+		}
+	}
+}
+
+func TestReadASN1IntegerInvalid(t *testing.T) {
+	testData := []String{
+		[]byte{3, 1, 0}, // invalid tag
+		// truncated
+		[]byte{2, 1},
+		[]byte{2, 2, 0},
+		// not minimally encoded
+		[]byte{2, 2, 0, 1},
+		[]byte{2, 2, 0xff, 0xff},
+	}
+
+	for i, test := range testData {
+		var out int64
+		if test.ReadASN1Integer(&out) {
+			t.Errorf("#%d: in.ReadASN1Integer() = true, want false (out = %d)", i, out)
+		}
+	}
+}
+
+func TestASN1ObjectIdentifier(t *testing.T) {
+	testData := []struct {
+		in  []byte
+		ok  bool
+		out []int
+	}{
+		{[]byte{}, false, []int{}},
+		{[]byte{6, 0}, false, []int{}},
+		{[]byte{5, 1, 85}, false, []int{2, 5}},
+		{[]byte{6, 1, 85}, true, []int{2, 5}},
+		{[]byte{6, 2, 85, 0x02}, true, []int{2, 5, 2}},
+		{[]byte{6, 4, 85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
+		{[]byte{6, 3, 0x81, 0x34, 0x03}, true, []int{2, 100, 3}},
+		{[]byte{6, 7, 85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
+	}
+
+	for i, test := range testData {
+		in := String(test.in)
+		var out encoding_asn1.ObjectIdentifier
+		ok := in.ReadASN1ObjectIdentifier(&out)
+		if ok != test.ok || ok && !out.Equal(test.out) {
+			t.Errorf("#%d: in.ReadASN1ObjectIdentifier() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
+			continue
+		}
+
+		var b Builder
+		b.AddASN1ObjectIdentifier(out)
+		result, err := b.Bytes()
+		if builderOk := err == nil; test.ok != builderOk {
+			t.Errorf("#%d: error from Builder.Bytes: %s", i, err)
+			continue
+		}
+		if test.ok && !bytes.Equal(result, test.in) {
+			t.Errorf("#%d: reserialisation didn't match, got %x, want %x", i, result, test.in)
+			continue
+		}
+	}
+}
+
+func TestReadASN1GeneralizedTime(t *testing.T) {
+	testData := []struct {
+		in  string
+		ok  bool
+		out time.Time
+	}{
+		{"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
+		{"20100102030405", false, time.Time{}},
+		{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
+		{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
+		/* These are invalid times. However, the time package normalises times
+		 * and they were accepted in some versions. See #11134. */
+		{"00000100000000Z", false, time.Time{}},
+		{"20101302030405Z", false, time.Time{}},
+		{"20100002030405Z", false, time.Time{}},
+		{"20100100030405Z", false, time.Time{}},
+		{"20100132030405Z", false, time.Time{}},
+		{"20100231030405Z", false, time.Time{}},
+		{"20100102240405Z", false, time.Time{}},
+		{"20100102036005Z", false, time.Time{}},
+		{"20100102030460Z", false, time.Time{}},
+		{"-20100102030410Z", false, time.Time{}},
+		{"2010-0102030410Z", false, time.Time{}},
+		{"2010-0002030410Z", false, time.Time{}},
+		{"201001-02030410Z", false, time.Time{}},
+		{"20100102-030410Z", false, time.Time{}},
+		{"2010010203-0410Z", false, time.Time{}},
+		{"201001020304-10Z", false, time.Time{}},
+	}
+	for i, test := range testData {
+		in := String(append([]byte{byte(asn1.GeneralizedTime), byte(len(test.in))}, test.in...))
+		var out time.Time
+		ok := in.ReadASN1GeneralizedTime(&out)
+		if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) {
+			t.Errorf("#%d: in.ReadASN1GeneralizedTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out)
+		}
+	}
+}
+
+func TestReadASN1BitString(t *testing.T) {
+	testData := []struct {
+		in  []byte
+		ok  bool
+		out encoding_asn1.BitString
+	}{
+		{[]byte{}, false, encoding_asn1.BitString{}},
+		{[]byte{0x00}, true, encoding_asn1.BitString{}},
+		{[]byte{0x07, 0x00}, true, encoding_asn1.BitString{Bytes: []byte{0}, BitLength: 1}},
+		{[]byte{0x07, 0x01}, false, encoding_asn1.BitString{}},
+		{[]byte{0x07, 0x40}, false, encoding_asn1.BitString{}},
+		{[]byte{0x08, 0x00}, false, encoding_asn1.BitString{}},
+		{[]byte{0xff}, false, encoding_asn1.BitString{}},
+		{[]byte{0xfe, 0x00}, false, encoding_asn1.BitString{}},
+	}
+	for i, test := range testData {
+		in := String(append([]byte{3, byte(len(test.in))}, test.in...))
+		var out encoding_asn1.BitString
+		ok := in.ReadASN1BitString(&out)
+		if ok != test.ok || ok && (!bytes.Equal(out.Bytes, test.out.Bytes) || out.BitLength != test.out.BitLength) {
+			t.Errorf("#%d: in.ReadASN1BitString() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
+		}
+	}
+}

+ 337 - 0
src/golang.org/x/crypto/cryptobyte/builder.go

@@ -0,0 +1,337 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cryptobyte
+
+import (
+	"errors"
+	"fmt"
+)
+
+// A Builder builds byte strings from fixed-length and length-prefixed values.
+// Builders either allocate space as needed, or are ‘fixed’, which means that
+// they write into a given buffer and produce an error if it's exhausted.
+//
+// The zero value is a usable Builder that allocates space as needed.
+//
+// Simple values are marshaled and appended to a Builder using methods on the
+// Builder. Length-prefixed values are marshaled by providing a
+// BuilderContinuation, which is a function that writes the inner contents of
+// the value to a given Builder. See the documentation for BuilderContinuation
+// for details.
+type Builder struct {
+	err            error
+	result         []byte
+	fixedSize      bool
+	child          *Builder
+	offset         int
+	pendingLenLen  int
+	pendingIsASN1  bool
+	inContinuation *bool
+}
+
+// NewBuilder creates a Builder that appends its output to the given buffer.
+// Like append(), the slice will be reallocated if its capacity is exceeded.
+// Use Bytes to get the final buffer.
+func NewBuilder(buffer []byte) *Builder {
+	return &Builder{
+		result: buffer,
+	}
+}
+
+// NewFixedBuilder creates a Builder that appends its output into the given
+// buffer. This builder does not reallocate the output buffer. Writes that
+// would exceed the buffer's capacity are treated as an error.
+func NewFixedBuilder(buffer []byte) *Builder {
+	return &Builder{
+		result:    buffer,
+		fixedSize: true,
+	}
+}
+
+// SetError sets the value to be returned as the error from Bytes. Writes
+// performed after calling SetError are ignored.
+func (b *Builder) SetError(err error) {
+	b.err = err
+}
+
+// Bytes returns the bytes written by the builder or an error if one has
+// occurred during building.
+func (b *Builder) Bytes() ([]byte, error) {
+	if b.err != nil {
+		return nil, b.err
+	}
+	return b.result[b.offset:], nil
+}
+
+// BytesOrPanic returns the bytes written by the builder or panics if an error
+// has occurred during building.
+func (b *Builder) BytesOrPanic() []byte {
+	if b.err != nil {
+		panic(b.err)
+	}
+	return b.result[b.offset:]
+}
+
+// AddUint8 appends an 8-bit value to the byte string.
+func (b *Builder) AddUint8(v uint8) {
+	b.add(byte(v))
+}
+
+// AddUint16 appends a big-endian, 16-bit value to the byte string.
+func (b *Builder) AddUint16(v uint16) {
+	b.add(byte(v>>8), byte(v))
+}
+
+// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
+// byte of the 32-bit input value is silently truncated.
+func (b *Builder) AddUint24(v uint32) {
+	b.add(byte(v>>16), byte(v>>8), byte(v))
+}
+
+// AddUint32 appends a big-endian, 32-bit value to the byte string.
+func (b *Builder) AddUint32(v uint32) {
+	b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+}
+
+// AddBytes appends a sequence of bytes to the byte string.
+func (b *Builder) AddBytes(v []byte) {
+	b.add(v...)
+}
+
+// BuilderContinuation is a continuation-passing interface for building
+// length-prefixed byte sequences. Builder methods for length-prefixed
+// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
+// supplied to them. The child builder passed to the continuation can be used
+// to build the content of the length-prefixed sequence. For example:
+//
+//   parent := cryptobyte.NewBuilder()
+//   parent.AddUint8LengthPrefixed(func (child *Builder) {
+//     child.AddUint8(42)
+//     child.AddUint8LengthPrefixed(func (grandchild *Builder) {
+//       grandchild.AddUint8(5)
+//     })
+//   })
+//
+// It is an error to write more bytes to the child than allowed by the reserved
+// length prefix. After the continuation returns, the child must be considered
+// invalid, i.e. users must not store any copies or references of the child
+// that outlive the continuation.
+//
+// If the continuation panics with a value of type BuildError then the inner
+// error will be returned as the error from Bytes. If the child panics
+// otherwise then Bytes will repanic with the same value.
+type BuilderContinuation func(child *Builder)
+
+// BuildError wraps an error. If a BuilderContinuation panics with this value,
+// the panic will be recovered and the inner error will be returned from
+// Builder.Bytes.
+type BuildError struct {
+	Err error
+}
+
+// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
+func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
+	b.addLengthPrefixed(1, false, f)
+}
+
+// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
+func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
+	b.addLengthPrefixed(2, false, f)
+}
+
+// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
+func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
+	b.addLengthPrefixed(3, false, f)
+}
+
+// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
+func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
+	b.addLengthPrefixed(4, false, f)
+}
+
+func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
+	if !*b.inContinuation {
+		*b.inContinuation = true
+
+		defer func() {
+			*b.inContinuation = false
+
+			r := recover()
+			if r == nil {
+				return
+			}
+
+			if buildError, ok := r.(BuildError); ok {
+				b.err = buildError.Err
+			} else {
+				panic(r)
+			}
+		}()
+	}
+
+	f(arg)
+}
+
+func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
+	// Subsequent writes can be ignored if the builder has encountered an error.
+	if b.err != nil {
+		return
+	}
+
+	offset := len(b.result)
+	b.add(make([]byte, lenLen)...)
+
+	if b.inContinuation == nil {
+		b.inContinuation = new(bool)
+	}
+
+	b.child = &Builder{
+		result:         b.result,
+		fixedSize:      b.fixedSize,
+		offset:         offset,
+		pendingLenLen:  lenLen,
+		pendingIsASN1:  isASN1,
+		inContinuation: b.inContinuation,
+	}
+
+	b.callContinuation(f, b.child)
+	b.flushChild()
+	if b.child != nil {
+		panic("cryptobyte: internal error")
+	}
+}
+
+func (b *Builder) flushChild() {
+	if b.child == nil {
+		return
+	}
+	b.child.flushChild()
+	child := b.child
+	b.child = nil
+
+	if child.err != nil {
+		b.err = child.err
+		return
+	}
+
+	length := len(child.result) - child.pendingLenLen - child.offset
+
+	if length < 0 {
+		panic("cryptobyte: internal error") // result unexpectedly shrunk
+	}
+
+	if child.pendingIsASN1 {
+		// For ASN.1, we reserved a single byte for the length. If that turned out
+		// to be incorrect, we have to move the contents along in order to make
+		// space.
+		if child.pendingLenLen != 1 {
+			panic("cryptobyte: internal error")
+		}
+		var lenLen, lenByte uint8
+		if int64(length) > 0xfffffffe {
+			b.err = errors.New("pending ASN.1 child too long")
+			return
+		} else if length > 0xffffff {
+			lenLen = 5
+			lenByte = 0x80 | 4
+		} else if length > 0xffff {
+			lenLen = 4
+			lenByte = 0x80 | 3
+		} else if length > 0xff {
+			lenLen = 3
+			lenByte = 0x80 | 2
+		} else if length > 0x7f {
+			lenLen = 2
+			lenByte = 0x80 | 1
+		} else {
+			lenLen = 1
+			lenByte = uint8(length)
+			length = 0
+		}
+
+		// Insert the initial length byte, make space for successive length bytes,
+		// and adjust the offset.
+		child.result[child.offset] = lenByte
+		extraBytes := int(lenLen - 1)
+		if extraBytes != 0 {
+			child.add(make([]byte, extraBytes)...)
+			childStart := child.offset + child.pendingLenLen
+			copy(child.result[childStart+extraBytes:], child.result[childStart:])
+		}
+		child.offset++
+		child.pendingLenLen = extraBytes
+	}
+
+	l := length
+	for i := child.pendingLenLen - 1; i >= 0; i-- {
+		child.result[child.offset+i] = uint8(l)
+		l >>= 8
+	}
+	if l != 0 {
+		b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
+		return
+	}
+
+	if b.fixedSize && &b.result[0] != &child.result[0] {
+		panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
+	}
+
+	b.result = child.result
+}
+
+func (b *Builder) add(bytes ...byte) {
+	if b.err != nil {
+		return
+	}
+	if b.child != nil {
+		panic("cryptobyte: attempted write while child is pending")
+	}
+	if len(b.result)+len(bytes) < len(bytes) {
+		b.err = errors.New("cryptobyte: length overflow")
+	}
+	if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
+		b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
+		return
+	}
+	b.result = append(b.result, bytes...)
+}
+
+// Unwrite rolls back n bytes written directly to the Builder. An attempt by a
+// child builder passed to a continuation to unwrite bytes from its parent will
+// panic.
+func (b *Builder) Unwrite(n int) {
+	if b.err != nil {
+		return
+	}
+	if b.child != nil {
+		panic("cryptobyte: attempted unwrite while child is pending")
+	}
+	length := len(b.result) - b.pendingLenLen - b.offset
+	if length < 0 {
+		panic("cryptobyte: internal error")
+	}
+	if n > length {
+		panic("cryptobyte: attempted to unwrite more than was written")
+	}
+	b.result = b.result[:len(b.result)-n]
+}
+
+// A MarshalingValue marshals itself into a Builder.
+type MarshalingValue interface {
+	// Marshal is called by Builder.AddValue. It receives a pointer to a builder
+	// to marshal itself into. It may return an error that occurred during
+	// marshaling, such as unset or invalid values.
+	Marshal(b *Builder) error
+}
+
+// AddValue calls Marshal on v, passing a pointer to the builder to append to.
+// If Marshal returns an error, it is set on the Builder so that subsequent
+// appends don't have an effect.
+func (b *Builder) AddValue(v MarshalingValue) {
+	err := v.Marshal(b)
+	if err != nil {
+		b.err = err
+	}
+}

+ 516 - 0
src/golang.org/x/crypto/cryptobyte/cryptobyte_test.go

@@ -0,0 +1,516 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cryptobyte
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"testing"
+)
+
+func builderBytesEq(b *Builder, want ...byte) error {
+	got := b.BytesOrPanic()
+	if !bytes.Equal(got, want) {
+		return fmt.Errorf("Bytes() = %v, want %v", got, want)
+	}
+	return nil
+}
+
+func TestContinuationError(t *testing.T) {
+	const errorStr = "TestContinuationError"
+	var b Builder
+	b.AddUint8LengthPrefixed(func(b *Builder) {
+		b.AddUint8(1)
+		panic(BuildError{Err: errors.New(errorStr)})
+	})
+
+	ret, err := b.Bytes()
+	if ret != nil {
+		t.Error("expected nil result")
+	}
+	if err == nil {
+		t.Fatal("unexpected nil error")
+	}
+	if s := err.Error(); s != errorStr {
+		t.Errorf("expected error %q, got %v", errorStr, s)
+	}
+}
+
+func TestContinuationNonError(t *testing.T) {
+	defer func() {
+		recover()
+	}()
+
+	var b Builder
+	b.AddUint8LengthPrefixed(func(b *Builder) {
+		b.AddUint8(1)
+		panic(1)
+	})
+
+	t.Error("Builder did not panic")
+}
+
+func TestGeneratedPanic(t *testing.T) {
+	defer func() {
+		recover()
+	}()
+
+	var b Builder
+	b.AddUint8LengthPrefixed(func(b *Builder) {
+		var p *byte
+		*p = 0
+	})
+
+	t.Error("Builder did not panic")
+}
+
+func TestBytes(t *testing.T) {
+	var b Builder
+	v := []byte("foobarbaz")
+	b.AddBytes(v[0:3])
+	b.AddBytes(v[3:4])
+	b.AddBytes(v[4:9])
+	if err := builderBytesEq(&b, v...); err != nil {
+		t.Error(err)
+	}
+	s := String(b.BytesOrPanic())
+	for _, w := range []string{"foo", "bar", "baz"} {
+		var got []byte
+		if !s.ReadBytes(&got, 3) {
+			t.Errorf("ReadBytes() = false, want true (w = %v)", w)
+		}
+		want := []byte(w)
+		if !bytes.Equal(got, want) {
+			t.Errorf("ReadBytes(): got = %v, want %v", got, want)
+		}
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+}
+
+func TestUint8(t *testing.T) {
+	var b Builder
+	b.AddUint8(42)
+	if err := builderBytesEq(&b, 42); err != nil {
+		t.Error(err)
+	}
+
+	var s String = b.BytesOrPanic()
+	var v uint8
+	if !s.ReadUint8(&v) {
+		t.Error("ReadUint8() = false, want true")
+	}
+	if v != 42 {
+		t.Errorf("v = %d, want 42", v)
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+}
+
+func TestUint16(t *testing.T) {
+	var b Builder
+	b.AddUint16(65534)
+	if err := builderBytesEq(&b, 255, 254); err != nil {
+		t.Error(err)
+	}
+	var s String = b.BytesOrPanic()
+	var v uint16
+	if !s.ReadUint16(&v) {
+		t.Error("ReadUint16() == false, want true")
+	}
+	if v != 65534 {
+		t.Errorf("v = %d, want 65534", v)
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+}
+
+func TestUint24(t *testing.T) {
+	var b Builder
+	b.AddUint24(0xfffefd)
+	if err := builderBytesEq(&b, 255, 254, 253); err != nil {
+		t.Error(err)
+	}
+
+	var s String = b.BytesOrPanic()
+	var v uint32
+	if !s.ReadUint24(&v) {
+		t.Error("ReadUint8() = false, want true")
+	}
+	if v != 0xfffefd {
+		t.Errorf("v = %d, want fffefd", v)
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+}
+
+func TestUint24Truncation(t *testing.T) {
+	var b Builder
+	b.AddUint24(0x10111213)
+	if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestUint32(t *testing.T) {
+	var b Builder
+	b.AddUint32(0xfffefdfc)
+	if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil {
+		t.Error(err)
+	}
+
+	var s String = b.BytesOrPanic()
+	var v uint32
+	if !s.ReadUint32(&v) {
+		t.Error("ReadUint8() = false, want true")
+	}
+	if v != 0xfffefdfc {
+		t.Errorf("v = %x, want fffefdfc", v)
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+}
+
+func TestUMultiple(t *testing.T) {
+	var b Builder
+	b.AddUint8(23)
+	b.AddUint32(0xfffefdfc)
+	b.AddUint16(42)
+	if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil {
+		t.Error(err)
+	}
+
+	var s String = b.BytesOrPanic()
+	var (
+		x uint8
+		y uint32
+		z uint16
+	)
+	if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) {
+		t.Error("ReadUint8() = false, want true")
+	}
+	if x != 23 || y != 0xfffefdfc || z != 42 {
+		t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z)
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+}
+
+func TestUint8LengthPrefixedSimple(t *testing.T) {
+	var b Builder
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		c.AddUint8(23)
+		c.AddUint8(42)
+	})
+	if err := builderBytesEq(&b, 2, 23, 42); err != nil {
+		t.Error(err)
+	}
+
+	var base, child String = b.BytesOrPanic(), nil
+	var x, y uint8
+	if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) ||
+		!child.ReadUint8(&y) {
+		t.Error("parsing failed")
+	}
+	if x != 23 || y != 42 {
+		t.Errorf("want x, y == 23, 42; got %d, %d", x, y)
+	}
+	if len(base) != 0 {
+		t.Errorf("len(base) = %d, want 0", len(base))
+	}
+	if len(child) != 0 {
+		t.Errorf("len(child) = %d, want 0", len(child))
+	}
+}
+
+func TestUint8LengthPrefixedMulti(t *testing.T) {
+	var b Builder
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		c.AddUint8(23)
+		c.AddUint8(42)
+	})
+	b.AddUint8(5)
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		c.AddUint8(123)
+		c.AddUint8(234)
+	})
+	if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil {
+		t.Error(err)
+	}
+
+	var s, child String = b.BytesOrPanic(), nil
+	var u, v, w, x, y uint8
+	if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) ||
+		!s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) {
+		t.Error("parsing failed")
+	}
+	if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 {
+		t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234",
+			u, v, w, x, y)
+	}
+	if len(s) != 0 {
+		t.Errorf("len(s) = %d, want 0", len(s))
+	}
+	if len(child) != 0 {
+		t.Errorf("len(child) = %d, want 0", len(child))
+	}
+}
+
+func TestUint8LengthPrefixedNested(t *testing.T) {
+	var b Builder
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		c.AddUint8(5)
+		c.AddUint8LengthPrefixed(func(d *Builder) {
+			d.AddUint8(23)
+			d.AddUint8(42)
+		})
+		c.AddUint8(123)
+	})
+	if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil {
+		t.Error(err)
+	}
+
+	var base, child1, child2 String = b.BytesOrPanic(), nil, nil
+	var u, v, w, x uint8
+	if !base.ReadUint8LengthPrefixed(&child1) {
+		t.Error("parsing base failed")
+	}
+	if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) {
+		t.Error("parsing child1 failed")
+	}
+	if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) {
+		t.Error("parsing child2 failed")
+	}
+	if u != 5 || v != 23 || w != 42 || x != 123 {
+		t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123",
+			u, v, w, x)
+	}
+	if len(base) != 0 {
+		t.Errorf("len(base) = %d, want 0", len(base))
+	}
+	if len(child1) != 0 {
+		t.Errorf("len(child1) = %d, want 0", len(child1))
+	}
+	if len(base) != 0 {
+		t.Errorf("len(child2) = %d, want 0", len(child2))
+	}
+}
+
+func TestPreallocatedBuffer(t *testing.T) {
+	var buf [5]byte
+	b := NewBuilder(buf[0:0])
+	b.AddUint8(1)
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		c.AddUint8(3)
+		c.AddUint8(4)
+	})
+	b.AddUint16(1286) // Outgrow buf by one byte.
+	want := []byte{1, 2, 3, 4, 0}
+	if !bytes.Equal(buf[:], want) {
+		t.Errorf("buf = %v want %v", buf, want)
+	}
+	if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestWriteWithPendingChild(t *testing.T) {
+	var b Builder
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		c.AddUint8LengthPrefixed(func(d *Builder) {
+			func() {
+				defer func() {
+					if recover() == nil {
+						t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
+					}
+				}()
+				c.AddUint8(2) // panics
+			}()
+
+			defer func() {
+				if recover() == nil {
+					t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
+				}
+			}()
+			b.AddUint8(2) // panics
+		})
+
+		defer func() {
+			if recover() == nil {
+				t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
+			}
+		}()
+		b.AddUint8(2) // panics
+	})
+}
+
+func TestSetError(t *testing.T) {
+	const errorStr = "TestSetError"
+	var b Builder
+	b.SetError(errors.New(errorStr))
+
+	ret, err := b.Bytes()
+	if ret != nil {
+		t.Error("expected nil result")
+	}
+	if err == nil {
+		t.Fatal("unexpected nil error")
+	}
+	if s := err.Error(); s != errorStr {
+		t.Errorf("expected error %q, got %v", errorStr, s)
+	}
+}
+
+func TestUnwrite(t *testing.T) {
+	var b Builder
+	b.AddBytes([]byte{1, 2, 3, 4, 5})
+	b.Unwrite(2)
+	if err := builderBytesEq(&b, 1, 2, 3); err != nil {
+		t.Error(err)
+	}
+
+	func() {
+		defer func() {
+			if recover() == nil {
+				t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
+			}
+		}()
+		b.Unwrite(4) // panics
+	}()
+
+	b = Builder{}
+	b.AddBytes([]byte{1, 2, 3, 4, 5})
+	b.AddUint8LengthPrefixed(func(b *Builder) {
+		b.AddBytes([]byte{1, 2, 3, 4, 5})
+
+		defer func() {
+			if recover() == nil {
+				t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
+			}
+		}()
+		b.Unwrite(6) // panics
+	})
+
+	b = Builder{}
+	b.AddBytes([]byte{1, 2, 3, 4, 5})
+	b.AddUint8LengthPrefixed(func(c *Builder) {
+		defer func() {
+			if recover() == nil {
+				t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
+			}
+		}()
+		b.Unwrite(2) // panics (attempted unwrite while child is pending)
+	})
+}
+
+func TestFixedBuilderLengthPrefixed(t *testing.T) {
+	bufCap := 10
+	inner := bytes.Repeat([]byte{0xff}, bufCap-2)
+	buf := make([]byte, 0, bufCap)
+	b := NewFixedBuilder(buf)
+	b.AddUint16LengthPrefixed(func(b *Builder) {
+		b.AddBytes(inner)
+	})
+	if got := b.BytesOrPanic(); len(got) != bufCap {
+		t.Errorf("Expected output length to be %d, got %d", bufCap, len(got))
+	}
+}
+
+func TestFixedBuilderPanicReallocate(t *testing.T) {
+	defer func() {
+		recover()
+	}()
+
+	b := NewFixedBuilder(make([]byte, 0, 10))
+	b1 := NewFixedBuilder(make([]byte, 0, 10))
+	b.AddUint16LengthPrefixed(func(b *Builder) {
+		*b = *b1
+	})
+
+	t.Error("Builder did not panic")
+}
+
+// ASN.1
+
+func TestASN1Int64(t *testing.T) {
+	tests := []struct {
+		in   int64
+		want []byte
+	}{
+		{-0x800000, []byte{2, 3, 128, 0, 0}},
+		{-256, []byte{2, 2, 255, 0}},
+		{-129, []byte{2, 2, 255, 127}},
+		{-128, []byte{2, 1, 128}},
+		{-1, []byte{2, 1, 255}},
+		{0, []byte{2, 1, 0}},
+		{1, []byte{2, 1, 1}},
+		{2, []byte{2, 1, 2}},
+		{127, []byte{2, 1, 127}},
+		{128, []byte{2, 2, 0, 128}},
+		{256, []byte{2, 2, 1, 0}},
+		{0x800000, []byte{2, 4, 0, 128, 0, 0}},
+	}
+	for i, tt := range tests {
+		var b Builder
+		b.AddASN1Int64(tt.in)
+		if err := builderBytesEq(&b, tt.want...); err != nil {
+			t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
+		}
+
+		var n int64
+		s := String(b.BytesOrPanic())
+		ok := s.ReadASN1Integer(&n)
+		if !ok || n != tt.in {
+			t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
+				ok, n, tt.in, i)
+		}
+		if len(s) != 0 {
+			t.Errorf("len(s) = %d, want 0", len(s))
+		}
+	}
+}
+
+func TestASN1Uint64(t *testing.T) {
+	tests := []struct {
+		in   uint64
+		want []byte
+	}{
+		{0, []byte{2, 1, 0}},
+		{1, []byte{2, 1, 1}},
+		{2, []byte{2, 1, 2}},
+		{127, []byte{2, 1, 127}},
+		{128, []byte{2, 2, 0, 128}},
+		{256, []byte{2, 2, 1, 0}},
+		{0x800000, []byte{2, 4, 0, 128, 0, 0}},
+		{0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}},
+		{0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}},
+		{0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
+	}
+	for i, tt := range tests {
+		var b Builder
+		b.AddASN1Uint64(tt.in)
+		if err := builderBytesEq(&b, tt.want...); err != nil {
+			t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
+		}
+
+		var n uint64
+		s := String(b.BytesOrPanic())
+		ok := s.ReadASN1Integer(&n)
+		if !ok || n != tt.in {
+			t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
+				ok, n, tt.in, i)
+		}
+		if len(s) != 0 {
+			t.Errorf("len(s) = %d, want 0", len(s))
+		}
+	}
+}

+ 154 - 0
src/golang.org/x/crypto/cryptobyte/example_test.go

@@ -0,0 +1,154 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cryptobyte_test
+
+import (
+	"errors"
+	"fmt"
+
+	"golang.org/x/crypto/cryptobyte"
+	"golang.org/x/crypto/cryptobyte/asn1"
+)
+
+func ExampleString_lengthPrefixed() {
+	// This is an example of parsing length-prefixed data (as found in, for
+	// example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed
+	// strings.
+
+	input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'})
+	var result []string
+
+	var values cryptobyte.String
+	if !input.ReadUint16LengthPrefixed(&values) ||
+		!input.Empty() {
+		panic("bad format")
+	}
+
+	for !values.Empty() {
+		var value cryptobyte.String
+		if !values.ReadUint8LengthPrefixed(&value) {
+			panic("bad format")
+		}
+
+		result = append(result, string(value))
+	}
+
+	// Output: []string{"hello", "world"}
+	fmt.Printf("%#v\n", result)
+}
+
+func ExampleString_aSN1() {
+	// This is an example of parsing ASN.1 data that looks like:
+	//    Foo ::= SEQUENCE {
+	//      version [6] INTEGER DEFAULT 0
+	//      data OCTET STRING
+	//    }
+
+	input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'})
+
+	var (
+		version                   int64
+		data, inner, versionBytes cryptobyte.String
+		haveVersion               bool
+	)
+	if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
+		!input.Empty() ||
+		!inner.ReadOptionalASN1(&versionBytes, &haveVersion, asn1.Tag(6).Constructed().ContextSpecific()) ||
+		(haveVersion && !versionBytes.ReadASN1Integer(&version)) ||
+		(haveVersion && !versionBytes.Empty()) ||
+		!inner.ReadASN1(&data, asn1.OCTET_STRING) ||
+		!inner.Empty() {
+		panic("bad format")
+	}
+
+	// Output: haveVersion: true, version: 2, data: hello
+	fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data))
+}
+
+func ExampleBuilder_aSN1() {
+	// This is an example of building ASN.1 data that looks like:
+	//    Foo ::= SEQUENCE {
+	//      version [6] INTEGER DEFAULT 0
+	//      data OCTET STRING
+	//    }
+
+	version := int64(2)
+	data := []byte("hello")
+	const defaultVersion = 0
+
+	var b cryptobyte.Builder
+	b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+		if version != defaultVersion {
+			b.AddASN1(asn1.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) {
+				b.AddASN1Int64(version)
+			})
+		}
+		b.AddASN1OctetString(data)
+	})
+
+	result, err := b.Bytes()
+	if err != nil {
+		panic(err)
+	}
+
+	// Output: 300ca603020102040568656c6c6f
+	fmt.Printf("%x\n", result)
+}
+
+func ExampleBuilder_lengthPrefixed() {
+	// This is an example of building length-prefixed data (as found in,
+	// for example, TLS). Imagine a 16-bit prefixed series of 8-bit
+	// prefixed strings.
+	input := []string{"hello", "world"}
+
+	var b cryptobyte.Builder
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		for _, value := range input {
+			b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes([]byte(value))
+			})
+		}
+	})
+
+	result, err := b.Bytes()
+	if err != nil {
+		panic(err)
+	}
+
+	// Output: 000c0568656c6c6f05776f726c64
+	fmt.Printf("%x\n", result)
+}
+
+func ExampleBuilder_lengthPrefixOverflow() {
+	// Writing more data that can be expressed by the length prefix results
+	// in an error from Bytes().
+
+	tooLarge := make([]byte, 256)
+
+	var b cryptobyte.Builder
+	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(tooLarge)
+	})
+
+	result, err := b.Bytes()
+	fmt.Printf("len=%d err=%s\n", len(result), err)
+
+	// Output: len=0 err=cryptobyte: pending child length 256 exceeds 1-byte length prefix
+}
+
+func ExampleBuilderContinuation_errorHandling() {
+	var b cryptobyte.Builder
+	// Continuations that panic with a BuildError will cause Bytes to
+	// return the inner error.
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint32(0)
+		panic(cryptobyte.BuildError{Err: errors.New("example error")})
+	})
+
+	result, err := b.Bytes()
+	fmt.Printf("len=%d err=%s\n", len(result), err)
+
+	// Output: len=0 err=example error
+}

+ 166 - 0
src/golang.org/x/crypto/cryptobyte/string.go

@@ -0,0 +1,166 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cryptobyte contains types that help with parsing and constructing
+// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage
+// contains useful ASN.1 constants.)
+//
+// The String type is for parsing. It wraps a []byte slice and provides helper
+// functions for consuming structures, value by value.
+//
+// The Builder type is for constructing messages. It providers helper functions
+// for appending values and also for appending length-prefixed submessages –
+// without having to worry about calculating the length prefix ahead of time.
+//
+// See the documentation and examples for the Builder and String types to get
+// started.
+package cryptobyte // import "golang.org/x/crypto/cryptobyte"
+
+// String represents a string of bytes. It provides methods for parsing
+// fixed-length and length-prefixed values from it.
+type String []byte
+
+// read advances a String by n bytes and returns them. If less than n bytes
+// remain, it returns nil.
+func (s *String) read(n int) []byte {
+	if len(*s) < n {
+		return nil
+	}
+	v := (*s)[:n]
+	*s = (*s)[n:]
+	return v
+}
+
+// Skip advances the String by n byte and reports whether it was successful.
+func (s *String) Skip(n int) bool {
+	return s.read(n) != nil
+}
+
+// ReadUint8 decodes an 8-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint8(out *uint8) bool {
+	v := s.read(1)
+	if v == nil {
+		return false
+	}
+	*out = uint8(v[0])
+	return true
+}
+
+// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint16(out *uint16) bool {
+	v := s.read(2)
+	if v == nil {
+		return false
+	}
+	*out = uint16(v[0])<<8 | uint16(v[1])
+	return true
+}
+
+// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint24(out *uint32) bool {
+	v := s.read(3)
+	if v == nil {
+		return false
+	}
+	*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
+	return true
+}
+
+// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint32(out *uint32) bool {
+	v := s.read(4)
+	if v == nil {
+		return false
+	}
+	*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
+	return true
+}
+
+func (s *String) readUnsigned(out *uint32, length int) bool {
+	v := s.read(length)
+	if v == nil {
+		return false
+	}
+	var result uint32
+	for i := 0; i < length; i++ {
+		result <<= 8
+		result |= uint32(v[i])
+	}
+	*out = result
+	return true
+}
+
+func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
+	lenBytes := s.read(lenLen)
+	if lenBytes == nil {
+		return false
+	}
+	var length uint32
+	for _, b := range lenBytes {
+		length = length << 8
+		length = length | uint32(b)
+	}
+	if int(length) < 0 {
+		// This currently cannot overflow because we read uint24 at most, but check
+		// anyway in case that changes in the future.
+		return false
+	}
+	v := s.read(int(length))
+	if v == nil {
+		return false
+	}
+	*outChild = v
+	return true
+}
+
+// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
+// into out and advances over it. It reports whether the read was successful.
+func (s *String) ReadUint8LengthPrefixed(out *String) bool {
+	return s.readLengthPrefixed(1, out)
+}
+
+// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
+// length-prefixed value into out and advances over it. It reports whether the
+// read was successful.
+func (s *String) ReadUint16LengthPrefixed(out *String) bool {
+	return s.readLengthPrefixed(2, out)
+}
+
+// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
+// length-prefixed value into out and advances over it. It reports whether
+// the read was successful.
+func (s *String) ReadUint24LengthPrefixed(out *String) bool {
+	return s.readLengthPrefixed(3, out)
+}
+
+// ReadBytes reads n bytes into out and advances over them. It reports
+// whether the read was successful.
+func (s *String) ReadBytes(out *[]byte, n int) bool {
+	v := s.read(n)
+	if v == nil {
+		return false
+	}
+	*out = v
+	return true
+}
+
+// CopyBytes copies len(out) bytes into out and advances over them. It reports
+// whether the copy operation was successful
+func (s *String) CopyBytes(out []byte) bool {
+	n := len(out)
+	v := s.read(n)
+	if v == nil {
+		return false
+	}
+	return copy(out, v) == n
+}
+
+// Empty reports whether the string does not contain any bytes.
+func (s String) Empty() bool {
+	return len(s) == 0
+}

+ 8 - 0
src/golang.org/x/crypto/curve25519/const_amd64.h

@@ -0,0 +1,8 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
+
+#define REDMASK51     0x0007FFFFFFFFFFFF

+ 20 - 0
src/golang.org/x/crypto/curve25519/const_amd64.s

@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// These constants cannot be encoded in non-MOVQ immediates.
+// We access them directly from memory instead.
+
+DATA ·_121666_213(SB)/8, $996687872
+GLOBL ·_121666_213(SB), 8, $8
+
+DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
+GLOBL ·_2P0(SB), 8, $8
+
+DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
+GLOBL ·_2P1234(SB), 8, $8

+ 65 - 0
src/golang.org/x/crypto/curve25519/cswap_amd64.s

@@ -0,0 +1,65 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+// func cswap(inout *[4][5]uint64, v uint64)
+TEXT ·cswap(SB),7,$0
+	MOVQ inout+0(FP),DI
+	MOVQ v+8(FP),SI
+
+	SUBQ $1, SI
+	NOTQ SI
+	MOVQ SI, X15
+	PSHUFD $0x44, X15, X15
+
+	MOVOU 0(DI), X0
+	MOVOU 16(DI), X2
+	MOVOU 32(DI), X4
+	MOVOU 48(DI), X6
+	MOVOU 64(DI), X8
+	MOVOU 80(DI), X1
+	MOVOU 96(DI), X3
+	MOVOU 112(DI), X5
+	MOVOU 128(DI), X7
+	MOVOU 144(DI), X9
+
+	MOVO X1, X10
+	MOVO X3, X11
+	MOVO X5, X12
+	MOVO X7, X13
+	MOVO X9, X14
+
+	PXOR X0, X10
+	PXOR X2, X11
+	PXOR X4, X12
+	PXOR X6, X13
+	PXOR X8, X14
+	PAND X15, X10
+	PAND X15, X11
+	PAND X15, X12
+	PAND X15, X13
+	PAND X15, X14
+	PXOR X10, X0
+	PXOR X10, X1
+	PXOR X11, X2
+	PXOR X11, X3
+	PXOR X12, X4
+	PXOR X12, X5
+	PXOR X13, X6
+	PXOR X13, X7
+	PXOR X14, X8
+	PXOR X14, X9
+
+	MOVOU X0, 0(DI)
+	MOVOU X2, 16(DI)
+	MOVOU X4, 32(DI)
+	MOVOU X6, 48(DI)
+	MOVOU X8, 64(DI)
+	MOVOU X1, 80(DI)
+	MOVOU X3, 96(DI)
+	MOVOU X5, 112(DI)
+	MOVOU X7, 128(DI)
+	MOVOU X9, 144(DI)
+	RET

+ 834 - 0
src/golang.org/x/crypto/curve25519/curve25519.go

@@ -0,0 +1,834 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// We have an implementation in amd64 assembly so this code is only run on
+// non-amd64 platforms. The amd64 assembly does not support gccgo.
+// +build !amd64 gccgo appengine
+
+package curve25519
+
+import (
+	"encoding/binary"
+)
+
+// This code is a port of the public domain, "ref10" implementation of
+// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
+
+// fieldElement represents an element of the field GF(2^255 - 19). An element
+// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+// context.
+type fieldElement [10]int32
+
+func feZero(fe *fieldElement) {
+	for i := range fe {
+		fe[i] = 0
+	}
+}
+
+func feOne(fe *fieldElement) {
+	feZero(fe)
+	fe[0] = 1
+}
+
+func feAdd(dst, a, b *fieldElement) {
+	for i := range dst {
+		dst[i] = a[i] + b[i]
+	}
+}
+
+func feSub(dst, a, b *fieldElement) {
+	for i := range dst {
+		dst[i] = a[i] - b[i]
+	}
+}
+
+func feCopy(dst, src *fieldElement) {
+	for i := range dst {
+		dst[i] = src[i]
+	}
+}
+
+// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
+//
+// Preconditions: b in {0,1}.
+func feCSwap(f, g *fieldElement, b int32) {
+	b = -b
+	for i := range f {
+		t := b & (f[i] ^ g[i])
+		f[i] ^= t
+		g[i] ^= t
+	}
+}
+
+// load3 reads a 24-bit, little-endian value from in.
+func load3(in []byte) int64 {
+	var r int64
+	r = int64(in[0])
+	r |= int64(in[1]) << 8
+	r |= int64(in[2]) << 16
+	return r
+}
+
+// load4 reads a 32-bit, little-endian value from in.
+func load4(in []byte) int64 {
+	return int64(binary.LittleEndian.Uint32(in))
+}
+
+func feFromBytes(dst *fieldElement, src *[32]byte) {
+	h0 := load4(src[:])
+	h1 := load3(src[4:]) << 6
+	h2 := load3(src[7:]) << 5
+	h3 := load3(src[10:]) << 3
+	h4 := load3(src[13:]) << 2
+	h5 := load4(src[16:])
+	h6 := load3(src[20:]) << 7
+	h7 := load3(src[23:]) << 5
+	h8 := load3(src[26:]) << 4
+	h9 := load3(src[29:]) << 2
+
+	var carry [10]int64
+	carry[9] = (h9 + 1<<24) >> 25
+	h0 += carry[9] * 19
+	h9 -= carry[9] << 25
+	carry[1] = (h1 + 1<<24) >> 25
+	h2 += carry[1]
+	h1 -= carry[1] << 25
+	carry[3] = (h3 + 1<<24) >> 25
+	h4 += carry[3]
+	h3 -= carry[3] << 25
+	carry[5] = (h5 + 1<<24) >> 25
+	h6 += carry[5]
+	h5 -= carry[5] << 25
+	carry[7] = (h7 + 1<<24) >> 25
+	h8 += carry[7]
+	h7 -= carry[7] << 25
+
+	carry[0] = (h0 + 1<<25) >> 26
+	h1 += carry[0]
+	h0 -= carry[0] << 26
+	carry[2] = (h2 + 1<<25) >> 26
+	h3 += carry[2]
+	h2 -= carry[2] << 26
+	carry[4] = (h4 + 1<<25) >> 26
+	h5 += carry[4]
+	h4 -= carry[4] << 26
+	carry[6] = (h6 + 1<<25) >> 26
+	h7 += carry[6]
+	h6 -= carry[6] << 26
+	carry[8] = (h8 + 1<<25) >> 26
+	h9 += carry[8]
+	h8 -= carry[8] << 26
+
+	dst[0] = int32(h0)
+	dst[1] = int32(h1)
+	dst[2] = int32(h2)
+	dst[3] = int32(h3)
+	dst[4] = int32(h4)
+	dst[5] = int32(h5)
+	dst[6] = int32(h6)
+	dst[7] = int32(h7)
+	dst[8] = int32(h8)
+	dst[9] = int32(h9)
+}
+
+// feToBytes marshals h to s.
+// Preconditions:
+//   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Write p=2^255-19; q=floor(h/p).
+// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+//
+// Proof:
+//   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+//   Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+//
+//   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+//   Then 0<y<1.
+//
+//   Write r=h-pq.
+//   Have 0<=r<=p-1=2^255-20.
+//   Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+//
+//   Write x=r+19(2^-255)r+y.
+//   Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+//
+//   Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+//   so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+func feToBytes(s *[32]byte, h *fieldElement) {
+	var carry [10]int32
+
+	q := (19*h[9] + (1 << 24)) >> 25
+	q = (h[0] + q) >> 26
+	q = (h[1] + q) >> 25
+	q = (h[2] + q) >> 26
+	q = (h[3] + q) >> 25
+	q = (h[4] + q) >> 26
+	q = (h[5] + q) >> 25
+	q = (h[6] + q) >> 26
+	q = (h[7] + q) >> 25
+	q = (h[8] + q) >> 26
+	q = (h[9] + q) >> 25
+
+	// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
+	h[0] += 19 * q
+	// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
+
+	carry[0] = h[0] >> 26
+	h[1] += carry[0]
+	h[0] -= carry[0] << 26
+	carry[1] = h[1] >> 25
+	h[2] += carry[1]
+	h[1] -= carry[1] << 25
+	carry[2] = h[2] >> 26
+	h[3] += carry[2]
+	h[2] -= carry[2] << 26
+	carry[3] = h[3] >> 25
+	h[4] += carry[3]
+	h[3] -= carry[3] << 25
+	carry[4] = h[4] >> 26
+	h[5] += carry[4]
+	h[4] -= carry[4] << 26
+	carry[5] = h[5] >> 25
+	h[6] += carry[5]
+	h[5] -= carry[5] << 25
+	carry[6] = h[6] >> 26
+	h[7] += carry[6]
+	h[6] -= carry[6] << 26
+	carry[7] = h[7] >> 25
+	h[8] += carry[7]
+	h[7] -= carry[7] << 25
+	carry[8] = h[8] >> 26
+	h[9] += carry[8]
+	h[8] -= carry[8] << 26
+	carry[9] = h[9] >> 25
+	h[9] -= carry[9] << 25
+	// h10 = carry9
+
+	// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+	// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
+	// evidently 2^255 h10-2^255 q = 0.
+	// Goal: Output h[0]+...+2^230 h[9].
+
+	s[0] = byte(h[0] >> 0)
+	s[1] = byte(h[0] >> 8)
+	s[2] = byte(h[0] >> 16)
+	s[3] = byte((h[0] >> 24) | (h[1] << 2))
+	s[4] = byte(h[1] >> 6)
+	s[5] = byte(h[1] >> 14)
+	s[6] = byte((h[1] >> 22) | (h[2] << 3))
+	s[7] = byte(h[2] >> 5)
+	s[8] = byte(h[2] >> 13)
+	s[9] = byte((h[2] >> 21) | (h[3] << 5))
+	s[10] = byte(h[3] >> 3)
+	s[11] = byte(h[3] >> 11)
+	s[12] = byte((h[3] >> 19) | (h[4] << 6))
+	s[13] = byte(h[4] >> 2)
+	s[14] = byte(h[4] >> 10)
+	s[15] = byte(h[4] >> 18)
+	s[16] = byte(h[5] >> 0)
+	s[17] = byte(h[5] >> 8)
+	s[18] = byte(h[5] >> 16)
+	s[19] = byte((h[5] >> 24) | (h[6] << 1))
+	s[20] = byte(h[6] >> 7)
+	s[21] = byte(h[6] >> 15)
+	s[22] = byte((h[6] >> 23) | (h[7] << 3))
+	s[23] = byte(h[7] >> 5)
+	s[24] = byte(h[7] >> 13)
+	s[25] = byte((h[7] >> 21) | (h[8] << 4))
+	s[26] = byte(h[8] >> 4)
+	s[27] = byte(h[8] >> 12)
+	s[28] = byte((h[8] >> 20) | (h[9] << 6))
+	s[29] = byte(h[9] >> 2)
+	s[30] = byte(h[9] >> 10)
+	s[31] = byte(h[9] >> 18)
+}
+
+// feMul calculates h = f * g
+// Can overlap h with f or g.
+//
+// Preconditions:
+//    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//    |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+//    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Notes on implementation strategy:
+//
+// Using schoolbook multiplication.
+// Karatsuba would save a little in some cost models.
+//
+// Most multiplications by 2 and 19 are 32-bit precomputations;
+// cheaper than 64-bit postcomputations.
+//
+// There is one remaining multiplication by 19 in the carry chain;
+// one *19 precomputation can be merged into this,
+// but the resulting data flow is considerably less clean.
+//
+// There are 12 carries below.
+// 10 of them are 2-way parallelizable and vectorizable.
+// Can get away with 11 carries, but then data flow is much deeper.
+//
+// With tighter constraints on inputs can squeeze carries into int32.
+func feMul(h, f, g *fieldElement) {
+	f0 := f[0]
+	f1 := f[1]
+	f2 := f[2]
+	f3 := f[3]
+	f4 := f[4]
+	f5 := f[5]
+	f6 := f[6]
+	f7 := f[7]
+	f8 := f[8]
+	f9 := f[9]
+	g0 := g[0]
+	g1 := g[1]
+	g2 := g[2]
+	g3 := g[3]
+	g4 := g[4]
+	g5 := g[5]
+	g6 := g[6]
+	g7 := g[7]
+	g8 := g[8]
+	g9 := g[9]
+	g1_19 := 19 * g1 // 1.4*2^29
+	g2_19 := 19 * g2 // 1.4*2^30; still ok
+	g3_19 := 19 * g3
+	g4_19 := 19 * g4
+	g5_19 := 19 * g5
+	g6_19 := 19 * g6
+	g7_19 := 19 * g7
+	g8_19 := 19 * g8
+	g9_19 := 19 * g9
+	f1_2 := 2 * f1
+	f3_2 := 2 * f3
+	f5_2 := 2 * f5
+	f7_2 := 2 * f7
+	f9_2 := 2 * f9
+	f0g0 := int64(f0) * int64(g0)
+	f0g1 := int64(f0) * int64(g1)
+	f0g2 := int64(f0) * int64(g2)
+	f0g3 := int64(f0) * int64(g3)
+	f0g4 := int64(f0) * int64(g4)
+	f0g5 := int64(f0) * int64(g5)
+	f0g6 := int64(f0) * int64(g6)
+	f0g7 := int64(f0) * int64(g7)
+	f0g8 := int64(f0) * int64(g8)
+	f0g9 := int64(f0) * int64(g9)
+	f1g0 := int64(f1) * int64(g0)
+	f1g1_2 := int64(f1_2) * int64(g1)
+	f1g2 := int64(f1) * int64(g2)
+	f1g3_2 := int64(f1_2) * int64(g3)
+	f1g4 := int64(f1) * int64(g4)
+	f1g5_2 := int64(f1_2) * int64(g5)
+	f1g6 := int64(f1) * int64(g6)
+	f1g7_2 := int64(f1_2) * int64(g7)
+	f1g8 := int64(f1) * int64(g8)
+	f1g9_38 := int64(f1_2) * int64(g9_19)
+	f2g0 := int64(f2) * int64(g0)
+	f2g1 := int64(f2) * int64(g1)
+	f2g2 := int64(f2) * int64(g2)
+	f2g3 := int64(f2) * int64(g3)
+	f2g4 := int64(f2) * int64(g4)
+	f2g5 := int64(f2) * int64(g5)
+	f2g6 := int64(f2) * int64(g6)
+	f2g7 := int64(f2) * int64(g7)
+	f2g8_19 := int64(f2) * int64(g8_19)
+	f2g9_19 := int64(f2) * int64(g9_19)
+	f3g0 := int64(f3) * int64(g0)
+	f3g1_2 := int64(f3_2) * int64(g1)
+	f3g2 := int64(f3) * int64(g2)
+	f3g3_2 := int64(f3_2) * int64(g3)
+	f3g4 := int64(f3) * int64(g4)
+	f3g5_2 := int64(f3_2) * int64(g5)
+	f3g6 := int64(f3) * int64(g6)
+	f3g7_38 := int64(f3_2) * int64(g7_19)
+	f3g8_19 := int64(f3) * int64(g8_19)
+	f3g9_38 := int64(f3_2) * int64(g9_19)
+	f4g0 := int64(f4) * int64(g0)
+	f4g1 := int64(f4) * int64(g1)
+	f4g2 := int64(f4) * int64(g2)
+	f4g3 := int64(f4) * int64(g3)
+	f4g4 := int64(f4) * int64(g4)
+	f4g5 := int64(f4) * int64(g5)
+	f4g6_19 := int64(f4) * int64(g6_19)
+	f4g7_19 := int64(f4) * int64(g7_19)
+	f4g8_19 := int64(f4) * int64(g8_19)
+	f4g9_19 := int64(f4) * int64(g9_19)
+	f5g0 := int64(f5) * int64(g0)
+	f5g1_2 := int64(f5_2) * int64(g1)
+	f5g2 := int64(f5) * int64(g2)
+	f5g3_2 := int64(f5_2) * int64(g3)
+	f5g4 := int64(f5) * int64(g4)
+	f5g5_38 := int64(f5_2) * int64(g5_19)
+	f5g6_19 := int64(f5) * int64(g6_19)
+	f5g7_38 := int64(f5_2) * int64(g7_19)
+	f5g8_19 := int64(f5) * int64(g8_19)
+	f5g9_38 := int64(f5_2) * int64(g9_19)
+	f6g0 := int64(f6) * int64(g0)
+	f6g1 := int64(f6) * int64(g1)
+	f6g2 := int64(f6) * int64(g2)
+	f6g3 := int64(f6) * int64(g3)
+	f6g4_19 := int64(f6) * int64(g4_19)
+	f6g5_19 := int64(f6) * int64(g5_19)
+	f6g6_19 := int64(f6) * int64(g6_19)
+	f6g7_19 := int64(f6) * int64(g7_19)
+	f6g8_19 := int64(f6) * int64(g8_19)
+	f6g9_19 := int64(f6) * int64(g9_19)
+	f7g0 := int64(f7) * int64(g0)
+	f7g1_2 := int64(f7_2) * int64(g1)
+	f7g2 := int64(f7) * int64(g2)
+	f7g3_38 := int64(f7_2) * int64(g3_19)
+	f7g4_19 := int64(f7) * int64(g4_19)
+	f7g5_38 := int64(f7_2) * int64(g5_19)
+	f7g6_19 := int64(f7) * int64(g6_19)
+	f7g7_38 := int64(f7_2) * int64(g7_19)
+	f7g8_19 := int64(f7) * int64(g8_19)
+	f7g9_38 := int64(f7_2) * int64(g9_19)
+	f8g0 := int64(f8) * int64(g0)
+	f8g1 := int64(f8) * int64(g1)
+	f8g2_19 := int64(f8) * int64(g2_19)
+	f8g3_19 := int64(f8) * int64(g3_19)
+	f8g4_19 := int64(f8) * int64(g4_19)
+	f8g5_19 := int64(f8) * int64(g5_19)
+	f8g6_19 := int64(f8) * int64(g6_19)
+	f8g7_19 := int64(f8) * int64(g7_19)
+	f8g8_19 := int64(f8) * int64(g8_19)
+	f8g9_19 := int64(f8) * int64(g9_19)
+	f9g0 := int64(f9) * int64(g0)
+	f9g1_38 := int64(f9_2) * int64(g1_19)
+	f9g2_19 := int64(f9) * int64(g2_19)
+	f9g3_38 := int64(f9_2) * int64(g3_19)
+	f9g4_19 := int64(f9) * int64(g4_19)
+	f9g5_38 := int64(f9_2) * int64(g5_19)
+	f9g6_19 := int64(f9) * int64(g6_19)
+	f9g7_38 := int64(f9_2) * int64(g7_19)
+	f9g8_19 := int64(f9) * int64(g8_19)
+	f9g9_38 := int64(f9_2) * int64(g9_19)
+	h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
+	h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
+	h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
+	h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
+	h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
+	h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
+	h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
+	h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
+	h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
+	h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
+	var carry [10]int64
+
+	// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+	//   i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+	// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+	//   i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+
+	carry[0] = (h0 + (1 << 25)) >> 26
+	h1 += carry[0]
+	h0 -= carry[0] << 26
+	carry[4] = (h4 + (1 << 25)) >> 26
+	h5 += carry[4]
+	h4 -= carry[4] << 26
+	// |h0| <= 2^25
+	// |h4| <= 2^25
+	// |h1| <= 1.51*2^58
+	// |h5| <= 1.51*2^58
+
+	carry[1] = (h1 + (1 << 24)) >> 25
+	h2 += carry[1]
+	h1 -= carry[1] << 25
+	carry[5] = (h5 + (1 << 24)) >> 25
+	h6 += carry[5]
+	h5 -= carry[5] << 25
+	// |h1| <= 2^24; from now on fits into int32
+	// |h5| <= 2^24; from now on fits into int32
+	// |h2| <= 1.21*2^59
+	// |h6| <= 1.21*2^59
+
+	carry[2] = (h2 + (1 << 25)) >> 26
+	h3 += carry[2]
+	h2 -= carry[2] << 26
+	carry[6] = (h6 + (1 << 25)) >> 26
+	h7 += carry[6]
+	h6 -= carry[6] << 26
+	// |h2| <= 2^25; from now on fits into int32 unchanged
+	// |h6| <= 2^25; from now on fits into int32 unchanged
+	// |h3| <= 1.51*2^58
+	// |h7| <= 1.51*2^58
+
+	carry[3] = (h3 + (1 << 24)) >> 25
+	h4 += carry[3]
+	h3 -= carry[3] << 25
+	carry[7] = (h7 + (1 << 24)) >> 25
+	h8 += carry[7]
+	h7 -= carry[7] << 25
+	// |h3| <= 2^24; from now on fits into int32 unchanged
+	// |h7| <= 2^24; from now on fits into int32 unchanged
+	// |h4| <= 1.52*2^33
+	// |h8| <= 1.52*2^33
+
+	carry[4] = (h4 + (1 << 25)) >> 26
+	h5 += carry[4]
+	h4 -= carry[4] << 26
+	carry[8] = (h8 + (1 << 25)) >> 26
+	h9 += carry[8]
+	h8 -= carry[8] << 26
+	// |h4| <= 2^25; from now on fits into int32 unchanged
+	// |h8| <= 2^25; from now on fits into int32 unchanged
+	// |h5| <= 1.01*2^24
+	// |h9| <= 1.51*2^58
+
+	carry[9] = (h9 + (1 << 24)) >> 25
+	h0 += carry[9] * 19
+	h9 -= carry[9] << 25
+	// |h9| <= 2^24; from now on fits into int32 unchanged
+	// |h0| <= 1.8*2^37
+
+	carry[0] = (h0 + (1 << 25)) >> 26
+	h1 += carry[0]
+	h0 -= carry[0] << 26
+	// |h0| <= 2^25; from now on fits into int32 unchanged
+	// |h1| <= 1.01*2^24
+
+	h[0] = int32(h0)
+	h[1] = int32(h1)
+	h[2] = int32(h2)
+	h[3] = int32(h3)
+	h[4] = int32(h4)
+	h[5] = int32(h5)
+	h[6] = int32(h6)
+	h[7] = int32(h7)
+	h[8] = int32(h8)
+	h[9] = int32(h9)
+}
+
+// feSquare calculates h = f*f. Can overlap h with f.
+//
+// Preconditions:
+//    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+//    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feSquare(h, f *fieldElement) {
+	f0 := f[0]
+	f1 := f[1]
+	f2 := f[2]
+	f3 := f[3]
+	f4 := f[4]
+	f5 := f[5]
+	f6 := f[6]
+	f7 := f[7]
+	f8 := f[8]
+	f9 := f[9]
+	f0_2 := 2 * f0
+	f1_2 := 2 * f1
+	f2_2 := 2 * f2
+	f3_2 := 2 * f3
+	f4_2 := 2 * f4
+	f5_2 := 2 * f5
+	f6_2 := 2 * f6
+	f7_2 := 2 * f7
+	f5_38 := 38 * f5 // 1.31*2^30
+	f6_19 := 19 * f6 // 1.31*2^30
+	f7_38 := 38 * f7 // 1.31*2^30
+	f8_19 := 19 * f8 // 1.31*2^30
+	f9_38 := 38 * f9 // 1.31*2^30
+	f0f0 := int64(f0) * int64(f0)
+	f0f1_2 := int64(f0_2) * int64(f1)
+	f0f2_2 := int64(f0_2) * int64(f2)
+	f0f3_2 := int64(f0_2) * int64(f3)
+	f0f4_2 := int64(f0_2) * int64(f4)
+	f0f5_2 := int64(f0_2) * int64(f5)
+	f0f6_2 := int64(f0_2) * int64(f6)
+	f0f7_2 := int64(f0_2) * int64(f7)
+	f0f8_2 := int64(f0_2) * int64(f8)
+	f0f9_2 := int64(f0_2) * int64(f9)
+	f1f1_2 := int64(f1_2) * int64(f1)
+	f1f2_2 := int64(f1_2) * int64(f2)
+	f1f3_4 := int64(f1_2) * int64(f3_2)
+	f1f4_2 := int64(f1_2) * int64(f4)
+	f1f5_4 := int64(f1_2) * int64(f5_2)
+	f1f6_2 := int64(f1_2) * int64(f6)
+	f1f7_4 := int64(f1_2) * int64(f7_2)
+	f1f8_2 := int64(f1_2) * int64(f8)
+	f1f9_76 := int64(f1_2) * int64(f9_38)
+	f2f2 := int64(f2) * int64(f2)
+	f2f3_2 := int64(f2_2) * int64(f3)
+	f2f4_2 := int64(f2_2) * int64(f4)
+	f2f5_2 := int64(f2_2) * int64(f5)
+	f2f6_2 := int64(f2_2) * int64(f6)
+	f2f7_2 := int64(f2_2) * int64(f7)
+	f2f8_38 := int64(f2_2) * int64(f8_19)
+	f2f9_38 := int64(f2) * int64(f9_38)
+	f3f3_2 := int64(f3_2) * int64(f3)
+	f3f4_2 := int64(f3_2) * int64(f4)
+	f3f5_4 := int64(f3_2) * int64(f5_2)
+	f3f6_2 := int64(f3_2) * int64(f6)
+	f3f7_76 := int64(f3_2) * int64(f7_38)
+	f3f8_38 := int64(f3_2) * int64(f8_19)
+	f3f9_76 := int64(f3_2) * int64(f9_38)
+	f4f4 := int64(f4) * int64(f4)
+	f4f5_2 := int64(f4_2) * int64(f5)
+	f4f6_38 := int64(f4_2) * int64(f6_19)
+	f4f7_38 := int64(f4) * int64(f7_38)
+	f4f8_38 := int64(f4_2) * int64(f8_19)
+	f4f9_38 := int64(f4) * int64(f9_38)
+	f5f5_38 := int64(f5) * int64(f5_38)
+	f5f6_38 := int64(f5_2) * int64(f6_19)
+	f5f7_76 := int64(f5_2) * int64(f7_38)
+	f5f8_38 := int64(f5_2) * int64(f8_19)
+	f5f9_76 := int64(f5_2) * int64(f9_38)
+	f6f6_19 := int64(f6) * int64(f6_19)
+	f6f7_38 := int64(f6) * int64(f7_38)
+	f6f8_38 := int64(f6_2) * int64(f8_19)
+	f6f9_38 := int64(f6) * int64(f9_38)
+	f7f7_38 := int64(f7) * int64(f7_38)
+	f7f8_38 := int64(f7_2) * int64(f8_19)
+	f7f9_76 := int64(f7_2) * int64(f9_38)
+	f8f8_19 := int64(f8) * int64(f8_19)
+	f8f9_38 := int64(f8) * int64(f9_38)
+	f9f9_38 := int64(f9) * int64(f9_38)
+	h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
+	h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
+	h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
+	h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
+	h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
+	h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
+	h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
+	h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
+	h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
+	h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
+	var carry [10]int64
+
+	carry[0] = (h0 + (1 << 25)) >> 26
+	h1 += carry[0]
+	h0 -= carry[0] << 26
+	carry[4] = (h4 + (1 << 25)) >> 26
+	h5 += carry[4]
+	h4 -= carry[4] << 26
+
+	carry[1] = (h1 + (1 << 24)) >> 25
+	h2 += carry[1]
+	h1 -= carry[1] << 25
+	carry[5] = (h5 + (1 << 24)) >> 25
+	h6 += carry[5]
+	h5 -= carry[5] << 25
+
+	carry[2] = (h2 + (1 << 25)) >> 26
+	h3 += carry[2]
+	h2 -= carry[2] << 26
+	carry[6] = (h6 + (1 << 25)) >> 26
+	h7 += carry[6]
+	h6 -= carry[6] << 26
+
+	carry[3] = (h3 + (1 << 24)) >> 25
+	h4 += carry[3]
+	h3 -= carry[3] << 25
+	carry[7] = (h7 + (1 << 24)) >> 25
+	h8 += carry[7]
+	h7 -= carry[7] << 25
+
+	carry[4] = (h4 + (1 << 25)) >> 26
+	h5 += carry[4]
+	h4 -= carry[4] << 26
+	carry[8] = (h8 + (1 << 25)) >> 26
+	h9 += carry[8]
+	h8 -= carry[8] << 26
+
+	carry[9] = (h9 + (1 << 24)) >> 25
+	h0 += carry[9] * 19
+	h9 -= carry[9] << 25
+
+	carry[0] = (h0 + (1 << 25)) >> 26
+	h1 += carry[0]
+	h0 -= carry[0] << 26
+
+	h[0] = int32(h0)
+	h[1] = int32(h1)
+	h[2] = int32(h2)
+	h[3] = int32(h3)
+	h[4] = int32(h4)
+	h[5] = int32(h5)
+	h[6] = int32(h6)
+	h[7] = int32(h7)
+	h[8] = int32(h8)
+	h[9] = int32(h9)
+}
+
+// feMul121666 calculates h = f * 121666. Can overlap h with f.
+//
+// Preconditions:
+//    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+//    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feMul121666(h, f *fieldElement) {
+	h0 := int64(f[0]) * 121666
+	h1 := int64(f[1]) * 121666
+	h2 := int64(f[2]) * 121666
+	h3 := int64(f[3]) * 121666
+	h4 := int64(f[4]) * 121666
+	h5 := int64(f[5]) * 121666
+	h6 := int64(f[6]) * 121666
+	h7 := int64(f[7]) * 121666
+	h8 := int64(f[8]) * 121666
+	h9 := int64(f[9]) * 121666
+	var carry [10]int64
+
+	carry[9] = (h9 + (1 << 24)) >> 25
+	h0 += carry[9] * 19
+	h9 -= carry[9] << 25
+	carry[1] = (h1 + (1 << 24)) >> 25
+	h2 += carry[1]
+	h1 -= carry[1] << 25
+	carry[3] = (h3 + (1 << 24)) >> 25
+	h4 += carry[3]
+	h3 -= carry[3] << 25
+	carry[5] = (h5 + (1 << 24)) >> 25
+	h6 += carry[5]
+	h5 -= carry[5] << 25
+	carry[7] = (h7 + (1 << 24)) >> 25
+	h8 += carry[7]
+	h7 -= carry[7] << 25
+
+	carry[0] = (h0 + (1 << 25)) >> 26
+	h1 += carry[0]
+	h0 -= carry[0] << 26
+	carry[2] = (h2 + (1 << 25)) >> 26
+	h3 += carry[2]
+	h2 -= carry[2] << 26
+	carry[4] = (h4 + (1 << 25)) >> 26
+	h5 += carry[4]
+	h4 -= carry[4] << 26
+	carry[6] = (h6 + (1 << 25)) >> 26
+	h7 += carry[6]
+	h6 -= carry[6] << 26
+	carry[8] = (h8 + (1 << 25)) >> 26
+	h9 += carry[8]
+	h8 -= carry[8] << 26
+
+	h[0] = int32(h0)
+	h[1] = int32(h1)
+	h[2] = int32(h2)
+	h[3] = int32(h3)
+	h[4] = int32(h4)
+	h[5] = int32(h5)
+	h[6] = int32(h6)
+	h[7] = int32(h7)
+	h[8] = int32(h8)
+	h[9] = int32(h9)
+}
+
+// feInvert sets out = z^-1.
+func feInvert(out, z *fieldElement) {
+	var t0, t1, t2, t3 fieldElement
+	var i int
+
+	feSquare(&t0, z)
+	for i = 1; i < 1; i++ {
+		feSquare(&t0, &t0)
+	}
+	feSquare(&t1, &t0)
+	for i = 1; i < 2; i++ {
+		feSquare(&t1, &t1)
+	}
+	feMul(&t1, z, &t1)
+	feMul(&t0, &t0, &t1)
+	feSquare(&t2, &t0)
+	for i = 1; i < 1; i++ {
+		feSquare(&t2, &t2)
+	}
+	feMul(&t1, &t1, &t2)
+	feSquare(&t2, &t1)
+	for i = 1; i < 5; i++ {
+		feSquare(&t2, &t2)
+	}
+	feMul(&t1, &t2, &t1)
+	feSquare(&t2, &t1)
+	for i = 1; i < 10; i++ {
+		feSquare(&t2, &t2)
+	}
+	feMul(&t2, &t2, &t1)
+	feSquare(&t3, &t2)
+	for i = 1; i < 20; i++ {
+		feSquare(&t3, &t3)
+	}
+	feMul(&t2, &t3, &t2)
+	feSquare(&t2, &t2)
+	for i = 1; i < 10; i++ {
+		feSquare(&t2, &t2)
+	}
+	feMul(&t1, &t2, &t1)
+	feSquare(&t2, &t1)
+	for i = 1; i < 50; i++ {
+		feSquare(&t2, &t2)
+	}
+	feMul(&t2, &t2, &t1)
+	feSquare(&t3, &t2)
+	for i = 1; i < 100; i++ {
+		feSquare(&t3, &t3)
+	}
+	feMul(&t2, &t3, &t2)
+	feSquare(&t2, &t2)
+	for i = 1; i < 50; i++ {
+		feSquare(&t2, &t2)
+	}
+	feMul(&t1, &t2, &t1)
+	feSquare(&t1, &t1)
+	for i = 1; i < 5; i++ {
+		feSquare(&t1, &t1)
+	}
+	feMul(out, &t1, &t0)
+}
+
+func scalarMult(out, in, base *[32]byte) {
+	var e [32]byte
+
+	copy(e[:], in[:])
+	e[0] &= 248
+	e[31] &= 127
+	e[31] |= 64
+
+	var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
+	feFromBytes(&x1, base)
+	feOne(&x2)
+	feCopy(&x3, &x1)
+	feOne(&z3)
+
+	swap := int32(0)
+	for pos := 254; pos >= 0; pos-- {
+		b := e[pos/8] >> uint(pos&7)
+		b &= 1
+		swap ^= int32(b)
+		feCSwap(&x2, &x3, swap)
+		feCSwap(&z2, &z3, swap)
+		swap = int32(b)
+
+		feSub(&tmp0, &x3, &z3)
+		feSub(&tmp1, &x2, &z2)
+		feAdd(&x2, &x2, &z2)
+		feAdd(&z2, &x3, &z3)
+		feMul(&z3, &tmp0, &x2)
+		feMul(&z2, &z2, &tmp1)
+		feSquare(&tmp0, &tmp1)
+		feSquare(&tmp1, &x2)
+		feAdd(&x3, &z3, &z2)
+		feSub(&z2, &z3, &z2)
+		feMul(&x2, &tmp1, &tmp0)
+		feSub(&tmp1, &tmp1, &tmp0)
+		feSquare(&z2, &z2)
+		feMul121666(&z3, &tmp1)
+		feSquare(&x3, &x3)
+		feAdd(&tmp0, &tmp0, &z3)
+		feMul(&z3, &x1, &z2)
+		feMul(&z2, &tmp1, &tmp0)
+	}
+
+	feCSwap(&x2, &x3, swap)
+	feCSwap(&z2, &z3, swap)
+
+	feInvert(&z2, &z2)
+	feMul(&x2, &x2, &z2)
+	feToBytes(out, &x2)
+}

+ 39 - 0
src/golang.org/x/crypto/curve25519/curve25519_test.go

@@ -0,0 +1,39 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package curve25519
+
+import (
+	"fmt"
+	"testing"
+)
+
+const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
+
+func TestBaseScalarMult(t *testing.T) {
+	var a, b [32]byte
+	in := &a
+	out := &b
+	a[0] = 1
+
+	for i := 0; i < 200; i++ {
+		ScalarBaseMult(out, in)
+		in, out = out, in
+	}
+
+	result := fmt.Sprintf("%x", in[:])
+	if result != expectedHex {
+		t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
+	}
+}
+
+func BenchmarkScalarBaseMult(b *testing.B) {
+	var in, out [32]byte
+	in[0] = 1
+
+	b.SetBytes(32)
+	for i := 0; i < b.N; i++ {
+		ScalarBaseMult(&out, &in)
+	}
+}

+ 23 - 0
src/golang.org/x/crypto/curve25519/doc.go

@@ -0,0 +1,23 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package curve25519 provides an implementation of scalar multiplication on
+// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html
+package curve25519 // import "golang.org/x/crypto/curve25519"
+
+// basePoint is the x coordinate of the generator of the curve.
+var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+// ScalarMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points and all values are in little-endian form.
+func ScalarMult(dst, in, base *[32]byte) {
+	scalarMult(dst, in, base)
+}
+
+// ScalarBaseMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points, base is the standard generator and all values
+// are in little-endian form.
+func ScalarBaseMult(dst, in *[32]byte) {
+	ScalarMult(dst, in, &basePoint)
+}

+ 73 - 0
src/golang.org/x/crypto/curve25519/freeze_amd64.s

@@ -0,0 +1,73 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+#include "const_amd64.h"
+
+// func freeze(inout *[5]uint64)
+TEXT ·freeze(SB),7,$0-8
+	MOVQ inout+0(FP), DI
+
+	MOVQ 0(DI),SI
+	MOVQ 8(DI),DX
+	MOVQ 16(DI),CX
+	MOVQ 24(DI),R8
+	MOVQ 32(DI),R9
+	MOVQ $REDMASK51,AX
+	MOVQ AX,R10
+	SUBQ $18,R10
+	MOVQ $3,R11
+REDUCELOOP:
+	MOVQ SI,R12
+	SHRQ $51,R12
+	ANDQ AX,SI
+	ADDQ R12,DX
+	MOVQ DX,R12
+	SHRQ $51,R12
+	ANDQ AX,DX
+	ADDQ R12,CX
+	MOVQ CX,R12
+	SHRQ $51,R12
+	ANDQ AX,CX
+	ADDQ R12,R8
+	MOVQ R8,R12
+	SHRQ $51,R12
+	ANDQ AX,R8
+	ADDQ R12,R9
+	MOVQ R9,R12
+	SHRQ $51,R12
+	ANDQ AX,R9
+	IMUL3Q $19,R12,R12
+	ADDQ R12,SI
+	SUBQ $1,R11
+	JA REDUCELOOP
+	MOVQ $1,R12
+	CMPQ R10,SI
+	CMOVQLT R11,R12
+	CMPQ AX,DX
+	CMOVQNE R11,R12
+	CMPQ AX,CX
+	CMOVQNE R11,R12
+	CMPQ AX,R8
+	CMOVQNE R11,R12
+	CMPQ AX,R9
+	CMOVQNE R11,R12
+	NEGQ R12
+	ANDQ R12,AX
+	ANDQ R12,R10
+	SUBQ R10,SI
+	SUBQ AX,DX
+	SUBQ AX,CX
+	SUBQ AX,R8
+	SUBQ AX,R9
+	MOVQ SI,0(DI)
+	MOVQ DX,8(DI)
+	MOVQ CX,16(DI)
+	MOVQ R8,24(DI)
+	MOVQ R9,32(DI)
+	RET

+ 1377 - 0
src/golang.org/x/crypto/curve25519/ladderstep_amd64.s

@@ -0,0 +1,1377 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+#include "const_amd64.h"
+
+// func ladderstep(inout *[5][5]uint64)
+TEXT ·ladderstep(SB),0,$296-8
+	MOVQ inout+0(FP),DI
+
+	MOVQ 40(DI),SI
+	MOVQ 48(DI),DX
+	MOVQ 56(DI),CX
+	MOVQ 64(DI),R8
+	MOVQ 72(DI),R9
+	MOVQ SI,AX
+	MOVQ DX,R10
+	MOVQ CX,R11
+	MOVQ R8,R12
+	MOVQ R9,R13
+	ADDQ ·_2P0(SB),AX
+	ADDQ ·_2P1234(SB),R10
+	ADDQ ·_2P1234(SB),R11
+	ADDQ ·_2P1234(SB),R12
+	ADDQ ·_2P1234(SB),R13
+	ADDQ 80(DI),SI
+	ADDQ 88(DI),DX
+	ADDQ 96(DI),CX
+	ADDQ 104(DI),R8
+	ADDQ 112(DI),R9
+	SUBQ 80(DI),AX
+	SUBQ 88(DI),R10
+	SUBQ 96(DI),R11
+	SUBQ 104(DI),R12
+	SUBQ 112(DI),R13
+	MOVQ SI,0(SP)
+	MOVQ DX,8(SP)
+	MOVQ CX,16(SP)
+	MOVQ R8,24(SP)
+	MOVQ R9,32(SP)
+	MOVQ AX,40(SP)
+	MOVQ R10,48(SP)
+	MOVQ R11,56(SP)
+	MOVQ R12,64(SP)
+	MOVQ R13,72(SP)
+	MOVQ 40(SP),AX
+	MULQ 40(SP)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 40(SP),AX
+	SHLQ $1,AX
+	MULQ 48(SP)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 40(SP),AX
+	SHLQ $1,AX
+	MULQ 56(SP)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 40(SP),AX
+	SHLQ $1,AX
+	MULQ 64(SP)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 40(SP),AX
+	SHLQ $1,AX
+	MULQ 72(SP)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 48(SP),AX
+	MULQ 48(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 48(SP),AX
+	SHLQ $1,AX
+	MULQ 56(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 48(SP),AX
+	SHLQ $1,AX
+	MULQ 64(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 48(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 72(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 56(SP),AX
+	MULQ 56(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 56(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 64(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 56(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 72(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 64(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 64(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 64(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 72(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 72(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 72(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	ANDQ DX,SI
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ADDQ R10,CX
+	ANDQ DX,R8
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ADDQ R12,CX
+	ANDQ DX,R9
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ADDQ R14,CX
+	ANDQ DX,AX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,80(SP)
+	MOVQ R8,88(SP)
+	MOVQ R9,96(SP)
+	MOVQ AX,104(SP)
+	MOVQ R10,112(SP)
+	MOVQ 0(SP),AX
+	MULQ 0(SP)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 0(SP),AX
+	SHLQ $1,AX
+	MULQ 8(SP)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 0(SP),AX
+	SHLQ $1,AX
+	MULQ 16(SP)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 0(SP),AX
+	SHLQ $1,AX
+	MULQ 24(SP)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 0(SP),AX
+	SHLQ $1,AX
+	MULQ 32(SP)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 8(SP),AX
+	MULQ 8(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 8(SP),AX
+	SHLQ $1,AX
+	MULQ 16(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 8(SP),AX
+	SHLQ $1,AX
+	MULQ 24(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 8(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 32(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 16(SP),AX
+	MULQ 16(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 16(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 24(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 16(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 32(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 24(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 24(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 24(SP),DX
+	IMUL3Q $38,DX,AX
+	MULQ 32(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 32(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	ANDQ DX,SI
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ADDQ R10,CX
+	ANDQ DX,R8
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ADDQ R12,CX
+	ANDQ DX,R9
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ADDQ R14,CX
+	ANDQ DX,AX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,120(SP)
+	MOVQ R8,128(SP)
+	MOVQ R9,136(SP)
+	MOVQ AX,144(SP)
+	MOVQ R10,152(SP)
+	MOVQ SI,SI
+	MOVQ R8,DX
+	MOVQ R9,CX
+	MOVQ AX,R8
+	MOVQ R10,R9
+	ADDQ ·_2P0(SB),SI
+	ADDQ ·_2P1234(SB),DX
+	ADDQ ·_2P1234(SB),CX
+	ADDQ ·_2P1234(SB),R8
+	ADDQ ·_2P1234(SB),R9
+	SUBQ 80(SP),SI
+	SUBQ 88(SP),DX
+	SUBQ 96(SP),CX
+	SUBQ 104(SP),R8
+	SUBQ 112(SP),R9
+	MOVQ SI,160(SP)
+	MOVQ DX,168(SP)
+	MOVQ CX,176(SP)
+	MOVQ R8,184(SP)
+	MOVQ R9,192(SP)
+	MOVQ 120(DI),SI
+	MOVQ 128(DI),DX
+	MOVQ 136(DI),CX
+	MOVQ 144(DI),R8
+	MOVQ 152(DI),R9
+	MOVQ SI,AX
+	MOVQ DX,R10
+	MOVQ CX,R11
+	MOVQ R8,R12
+	MOVQ R9,R13
+	ADDQ ·_2P0(SB),AX
+	ADDQ ·_2P1234(SB),R10
+	ADDQ ·_2P1234(SB),R11
+	ADDQ ·_2P1234(SB),R12
+	ADDQ ·_2P1234(SB),R13
+	ADDQ 160(DI),SI
+	ADDQ 168(DI),DX
+	ADDQ 176(DI),CX
+	ADDQ 184(DI),R8
+	ADDQ 192(DI),R9
+	SUBQ 160(DI),AX
+	SUBQ 168(DI),R10
+	SUBQ 176(DI),R11
+	SUBQ 184(DI),R12
+	SUBQ 192(DI),R13
+	MOVQ SI,200(SP)
+	MOVQ DX,208(SP)
+	MOVQ CX,216(SP)
+	MOVQ R8,224(SP)
+	MOVQ R9,232(SP)
+	MOVQ AX,240(SP)
+	MOVQ R10,248(SP)
+	MOVQ R11,256(SP)
+	MOVQ R12,264(SP)
+	MOVQ R13,272(SP)
+	MOVQ 224(SP),SI
+	IMUL3Q $19,SI,AX
+	MOVQ AX,280(SP)
+	MULQ 56(SP)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 232(SP),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,288(SP)
+	MULQ 48(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 200(SP),AX
+	MULQ 40(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 200(SP),AX
+	MULQ 48(SP)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 200(SP),AX
+	MULQ 56(SP)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 200(SP),AX
+	MULQ 64(SP)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 200(SP),AX
+	MULQ 72(SP)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 208(SP),AX
+	MULQ 40(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 208(SP),AX
+	MULQ 48(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 208(SP),AX
+	MULQ 56(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 208(SP),AX
+	MULQ 64(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 208(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 72(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 216(SP),AX
+	MULQ 40(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 216(SP),AX
+	MULQ 48(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 216(SP),AX
+	MULQ 56(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 216(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 64(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 216(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 72(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 224(SP),AX
+	MULQ 40(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 224(SP),AX
+	MULQ 48(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 280(SP),AX
+	MULQ 64(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 280(SP),AX
+	MULQ 72(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 232(SP),AX
+	MULQ 40(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 288(SP),AX
+	MULQ 56(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 288(SP),AX
+	MULQ 64(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 288(SP),AX
+	MULQ 72(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ANDQ DX,SI
+	ADDQ R10,CX
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ANDQ DX,R8
+	ADDQ R12,CX
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ANDQ DX,R9
+	ADDQ R14,CX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	ANDQ DX,AX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,40(SP)
+	MOVQ R8,48(SP)
+	MOVQ R9,56(SP)
+	MOVQ AX,64(SP)
+	MOVQ R10,72(SP)
+	MOVQ 264(SP),SI
+	IMUL3Q $19,SI,AX
+	MOVQ AX,200(SP)
+	MULQ 16(SP)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 272(SP),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,208(SP)
+	MULQ 8(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 240(SP),AX
+	MULQ 0(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 240(SP),AX
+	MULQ 8(SP)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 240(SP),AX
+	MULQ 16(SP)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 240(SP),AX
+	MULQ 24(SP)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 240(SP),AX
+	MULQ 32(SP)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 248(SP),AX
+	MULQ 0(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 248(SP),AX
+	MULQ 8(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 248(SP),AX
+	MULQ 16(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 248(SP),AX
+	MULQ 24(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 248(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 256(SP),AX
+	MULQ 0(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 256(SP),AX
+	MULQ 8(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 256(SP),AX
+	MULQ 16(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 256(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 24(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 256(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 264(SP),AX
+	MULQ 0(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 264(SP),AX
+	MULQ 8(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 200(SP),AX
+	MULQ 24(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 200(SP),AX
+	MULQ 32(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 272(SP),AX
+	MULQ 0(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 208(SP),AX
+	MULQ 16(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 208(SP),AX
+	MULQ 24(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 208(SP),AX
+	MULQ 32(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ANDQ DX,SI
+	ADDQ R10,CX
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ANDQ DX,R8
+	ADDQ R12,CX
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ANDQ DX,R9
+	ADDQ R14,CX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	ANDQ DX,AX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,DX
+	MOVQ R8,CX
+	MOVQ R9,R11
+	MOVQ AX,R12
+	MOVQ R10,R13
+	ADDQ ·_2P0(SB),DX
+	ADDQ ·_2P1234(SB),CX
+	ADDQ ·_2P1234(SB),R11
+	ADDQ ·_2P1234(SB),R12
+	ADDQ ·_2P1234(SB),R13
+	ADDQ 40(SP),SI
+	ADDQ 48(SP),R8
+	ADDQ 56(SP),R9
+	ADDQ 64(SP),AX
+	ADDQ 72(SP),R10
+	SUBQ 40(SP),DX
+	SUBQ 48(SP),CX
+	SUBQ 56(SP),R11
+	SUBQ 64(SP),R12
+	SUBQ 72(SP),R13
+	MOVQ SI,120(DI)
+	MOVQ R8,128(DI)
+	MOVQ R9,136(DI)
+	MOVQ AX,144(DI)
+	MOVQ R10,152(DI)
+	MOVQ DX,160(DI)
+	MOVQ CX,168(DI)
+	MOVQ R11,176(DI)
+	MOVQ R12,184(DI)
+	MOVQ R13,192(DI)
+	MOVQ 120(DI),AX
+	MULQ 120(DI)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 120(DI),AX
+	SHLQ $1,AX
+	MULQ 128(DI)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 120(DI),AX
+	SHLQ $1,AX
+	MULQ 136(DI)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 120(DI),AX
+	SHLQ $1,AX
+	MULQ 144(DI)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 120(DI),AX
+	SHLQ $1,AX
+	MULQ 152(DI)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 128(DI),AX
+	MULQ 128(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 128(DI),AX
+	SHLQ $1,AX
+	MULQ 136(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 128(DI),AX
+	SHLQ $1,AX
+	MULQ 144(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 128(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 152(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 136(DI),AX
+	MULQ 136(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 136(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 144(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 136(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 152(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 144(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 144(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 144(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 152(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 152(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 152(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	ANDQ DX,SI
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ADDQ R10,CX
+	ANDQ DX,R8
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ADDQ R12,CX
+	ANDQ DX,R9
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ADDQ R14,CX
+	ANDQ DX,AX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,120(DI)
+	MOVQ R8,128(DI)
+	MOVQ R9,136(DI)
+	MOVQ AX,144(DI)
+	MOVQ R10,152(DI)
+	MOVQ 160(DI),AX
+	MULQ 160(DI)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 160(DI),AX
+	SHLQ $1,AX
+	MULQ 168(DI)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 160(DI),AX
+	SHLQ $1,AX
+	MULQ 176(DI)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 160(DI),AX
+	SHLQ $1,AX
+	MULQ 184(DI)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 160(DI),AX
+	SHLQ $1,AX
+	MULQ 192(DI)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 168(DI),AX
+	MULQ 168(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 168(DI),AX
+	SHLQ $1,AX
+	MULQ 176(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 168(DI),AX
+	SHLQ $1,AX
+	MULQ 184(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 168(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 192(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 176(DI),AX
+	MULQ 176(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 176(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 184(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 176(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 192(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 184(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 184(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 184(DI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 192(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 192(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 192(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	ANDQ DX,SI
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ADDQ R10,CX
+	ANDQ DX,R8
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ADDQ R12,CX
+	ANDQ DX,R9
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ADDQ R14,CX
+	ANDQ DX,AX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,160(DI)
+	MOVQ R8,168(DI)
+	MOVQ R9,176(DI)
+	MOVQ AX,184(DI)
+	MOVQ R10,192(DI)
+	MOVQ 184(DI),SI
+	IMUL3Q $19,SI,AX
+	MOVQ AX,0(SP)
+	MULQ 16(DI)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 192(DI),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,8(SP)
+	MULQ 8(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 160(DI),AX
+	MULQ 0(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 160(DI),AX
+	MULQ 8(DI)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 160(DI),AX
+	MULQ 16(DI)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 160(DI),AX
+	MULQ 24(DI)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 160(DI),AX
+	MULQ 32(DI)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 168(DI),AX
+	MULQ 0(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 168(DI),AX
+	MULQ 8(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 168(DI),AX
+	MULQ 16(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 168(DI),AX
+	MULQ 24(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 168(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 176(DI),AX
+	MULQ 0(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 176(DI),AX
+	MULQ 8(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 176(DI),AX
+	MULQ 16(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 176(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 24(DI)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 176(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 184(DI),AX
+	MULQ 0(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 184(DI),AX
+	MULQ 8(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 0(SP),AX
+	MULQ 24(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 0(SP),AX
+	MULQ 32(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 192(DI),AX
+	MULQ 0(DI)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 8(SP),AX
+	MULQ 16(DI)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 8(SP),AX
+	MULQ 24(DI)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 8(SP),AX
+	MULQ 32(DI)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ANDQ DX,SI
+	ADDQ R10,CX
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ANDQ DX,R8
+	ADDQ R12,CX
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ANDQ DX,R9
+	ADDQ R14,CX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	ANDQ DX,AX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,160(DI)
+	MOVQ R8,168(DI)
+	MOVQ R9,176(DI)
+	MOVQ AX,184(DI)
+	MOVQ R10,192(DI)
+	MOVQ 144(SP),SI
+	IMUL3Q $19,SI,AX
+	MOVQ AX,0(SP)
+	MULQ 96(SP)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 152(SP),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,8(SP)
+	MULQ 88(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 120(SP),AX
+	MULQ 80(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 120(SP),AX
+	MULQ 88(SP)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 120(SP),AX
+	MULQ 96(SP)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 120(SP),AX
+	MULQ 104(SP)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 120(SP),AX
+	MULQ 112(SP)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 128(SP),AX
+	MULQ 80(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 128(SP),AX
+	MULQ 88(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 128(SP),AX
+	MULQ 96(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 128(SP),AX
+	MULQ 104(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 128(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 112(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 136(SP),AX
+	MULQ 80(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 136(SP),AX
+	MULQ 88(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 136(SP),AX
+	MULQ 96(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 136(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 104(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 136(SP),DX
+	IMUL3Q $19,DX,AX
+	MULQ 112(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 144(SP),AX
+	MULQ 80(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 144(SP),AX
+	MULQ 88(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 0(SP),AX
+	MULQ 104(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 0(SP),AX
+	MULQ 112(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 152(SP),AX
+	MULQ 80(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 8(SP),AX
+	MULQ 96(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 8(SP),AX
+	MULQ 104(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 8(SP),AX
+	MULQ 112(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ANDQ DX,SI
+	ADDQ R10,CX
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ANDQ DX,R8
+	ADDQ R12,CX
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ANDQ DX,R9
+	ADDQ R14,CX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	ANDQ DX,AX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,40(DI)
+	MOVQ R8,48(DI)
+	MOVQ R9,56(DI)
+	MOVQ AX,64(DI)
+	MOVQ R10,72(DI)
+	MOVQ 160(SP),AX
+	MULQ ·_121666_213(SB)
+	SHRQ $13,AX
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 168(SP),AX
+	MULQ ·_121666_213(SB)
+	SHRQ $13,AX
+	ADDQ AX,CX
+	MOVQ DX,R8
+	MOVQ 176(SP),AX
+	MULQ ·_121666_213(SB)
+	SHRQ $13,AX
+	ADDQ AX,R8
+	MOVQ DX,R9
+	MOVQ 184(SP),AX
+	MULQ ·_121666_213(SB)
+	SHRQ $13,AX
+	ADDQ AX,R9
+	MOVQ DX,R10
+	MOVQ 192(SP),AX
+	MULQ ·_121666_213(SB)
+	SHRQ $13,AX
+	ADDQ AX,R10
+	IMUL3Q $19,DX,DX
+	ADDQ DX,SI
+	ADDQ 80(SP),SI
+	ADDQ 88(SP),CX
+	ADDQ 96(SP),R8
+	ADDQ 104(SP),R9
+	ADDQ 112(SP),R10
+	MOVQ SI,80(DI)
+	MOVQ CX,88(DI)
+	MOVQ R8,96(DI)
+	MOVQ R9,104(DI)
+	MOVQ R10,112(DI)
+	MOVQ 104(DI),SI
+	IMUL3Q $19,SI,AX
+	MOVQ AX,0(SP)
+	MULQ 176(SP)
+	MOVQ AX,SI
+	MOVQ DX,CX
+	MOVQ 112(DI),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,8(SP)
+	MULQ 168(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 80(DI),AX
+	MULQ 160(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 80(DI),AX
+	MULQ 168(SP)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 80(DI),AX
+	MULQ 176(SP)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 80(DI),AX
+	MULQ 184(SP)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 80(DI),AX
+	MULQ 192(SP)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 88(DI),AX
+	MULQ 160(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 88(DI),AX
+	MULQ 168(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 88(DI),AX
+	MULQ 176(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 88(DI),AX
+	MULQ 184(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 88(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 192(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 96(DI),AX
+	MULQ 160(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 96(DI),AX
+	MULQ 168(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 96(DI),AX
+	MULQ 176(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 96(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 184(SP)
+	ADDQ AX,SI
+	ADCQ DX,CX
+	MOVQ 96(DI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 192(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 104(DI),AX
+	MULQ 160(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 104(DI),AX
+	MULQ 168(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 0(SP),AX
+	MULQ 184(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 0(SP),AX
+	MULQ 192(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 112(DI),AX
+	MULQ 160(SP)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 8(SP),AX
+	MULQ 176(SP)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 8(SP),AX
+	MULQ 184(SP)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 8(SP),AX
+	MULQ 192(SP)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ $REDMASK51,DX
+	SHLQ $13,CX:SI
+	ANDQ DX,SI
+	SHLQ $13,R9:R8
+	ANDQ DX,R8
+	ADDQ CX,R8
+	SHLQ $13,R11:R10
+	ANDQ DX,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ DX,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ DX,R14
+	ADDQ R13,R14
+	IMUL3Q $19,R15,CX
+	ADDQ CX,SI
+	MOVQ SI,CX
+	SHRQ $51,CX
+	ADDQ R8,CX
+	MOVQ CX,R8
+	SHRQ $51,CX
+	ANDQ DX,SI
+	ADDQ R10,CX
+	MOVQ CX,R9
+	SHRQ $51,CX
+	ANDQ DX,R8
+	ADDQ R12,CX
+	MOVQ CX,AX
+	SHRQ $51,CX
+	ANDQ DX,R9
+	ADDQ R14,CX
+	MOVQ CX,R10
+	SHRQ $51,CX
+	ANDQ DX,AX
+	IMUL3Q $19,CX,CX
+	ADDQ CX,SI
+	ANDQ DX,R10
+	MOVQ SI,80(DI)
+	MOVQ R8,88(DI)
+	MOVQ R9,96(DI)
+	MOVQ AX,104(DI)
+	MOVQ R10,112(DI)
+	RET

+ 240 - 0
src/golang.org/x/crypto/curve25519/mont25519_amd64.go

@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package curve25519
+
+// These functions are implemented in the .s files. The names of the functions
+// in the rest of the file are also taken from the SUPERCOP sources to help
+// people following along.
+
+//go:noescape
+
+func cswap(inout *[5]uint64, v uint64)
+
+//go:noescape
+
+func ladderstep(inout *[5][5]uint64)
+
+//go:noescape
+
+func freeze(inout *[5]uint64)
+
+//go:noescape
+
+func mul(dest, a, b *[5]uint64)
+
+//go:noescape
+
+func square(out, in *[5]uint64)
+
+// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
+func mladder(xr, zr *[5]uint64, s *[32]byte) {
+	var work [5][5]uint64
+
+	work[0] = *xr
+	setint(&work[1], 1)
+	setint(&work[2], 0)
+	work[3] = *xr
+	setint(&work[4], 1)
+
+	j := uint(6)
+	var prevbit byte
+
+	for i := 31; i >= 0; i-- {
+		for j < 8 {
+			bit := ((*s)[i] >> j) & 1
+			swap := bit ^ prevbit
+			prevbit = bit
+			cswap(&work[1], uint64(swap))
+			ladderstep(&work)
+			j--
+		}
+		j = 7
+	}
+
+	*xr = work[1]
+	*zr = work[2]
+}
+
+func scalarMult(out, in, base *[32]byte) {
+	var e [32]byte
+	copy(e[:], (*in)[:])
+	e[0] &= 248
+	e[31] &= 127
+	e[31] |= 64
+
+	var t, z [5]uint64
+	unpack(&t, base)
+	mladder(&t, &z, &e)
+	invert(&z, &z)
+	mul(&t, &t, &z)
+	pack(out, &t)
+}
+
+func setint(r *[5]uint64, v uint64) {
+	r[0] = v
+	r[1] = 0
+	r[2] = 0
+	r[3] = 0
+	r[4] = 0
+}
+
+// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
+// order.
+func unpack(r *[5]uint64, x *[32]byte) {
+	r[0] = uint64(x[0]) |
+		uint64(x[1])<<8 |
+		uint64(x[2])<<16 |
+		uint64(x[3])<<24 |
+		uint64(x[4])<<32 |
+		uint64(x[5])<<40 |
+		uint64(x[6]&7)<<48
+
+	r[1] = uint64(x[6])>>3 |
+		uint64(x[7])<<5 |
+		uint64(x[8])<<13 |
+		uint64(x[9])<<21 |
+		uint64(x[10])<<29 |
+		uint64(x[11])<<37 |
+		uint64(x[12]&63)<<45
+
+	r[2] = uint64(x[12])>>6 |
+		uint64(x[13])<<2 |
+		uint64(x[14])<<10 |
+		uint64(x[15])<<18 |
+		uint64(x[16])<<26 |
+		uint64(x[17])<<34 |
+		uint64(x[18])<<42 |
+		uint64(x[19]&1)<<50
+
+	r[3] = uint64(x[19])>>1 |
+		uint64(x[20])<<7 |
+		uint64(x[21])<<15 |
+		uint64(x[22])<<23 |
+		uint64(x[23])<<31 |
+		uint64(x[24])<<39 |
+		uint64(x[25]&15)<<47
+
+	r[4] = uint64(x[25])>>4 |
+		uint64(x[26])<<4 |
+		uint64(x[27])<<12 |
+		uint64(x[28])<<20 |
+		uint64(x[29])<<28 |
+		uint64(x[30])<<36 |
+		uint64(x[31]&127)<<44
+}
+
+// pack sets out = x where out is the usual, little-endian form of the 5,
+// 51-bit limbs in x.
+func pack(out *[32]byte, x *[5]uint64) {
+	t := *x
+	freeze(&t)
+
+	out[0] = byte(t[0])
+	out[1] = byte(t[0] >> 8)
+	out[2] = byte(t[0] >> 16)
+	out[3] = byte(t[0] >> 24)
+	out[4] = byte(t[0] >> 32)
+	out[5] = byte(t[0] >> 40)
+	out[6] = byte(t[0] >> 48)
+
+	out[6] ^= byte(t[1]<<3) & 0xf8
+	out[7] = byte(t[1] >> 5)
+	out[8] = byte(t[1] >> 13)
+	out[9] = byte(t[1] >> 21)
+	out[10] = byte(t[1] >> 29)
+	out[11] = byte(t[1] >> 37)
+	out[12] = byte(t[1] >> 45)
+
+	out[12] ^= byte(t[2]<<6) & 0xc0
+	out[13] = byte(t[2] >> 2)
+	out[14] = byte(t[2] >> 10)
+	out[15] = byte(t[2] >> 18)
+	out[16] = byte(t[2] >> 26)
+	out[17] = byte(t[2] >> 34)
+	out[18] = byte(t[2] >> 42)
+	out[19] = byte(t[2] >> 50)
+
+	out[19] ^= byte(t[3]<<1) & 0xfe
+	out[20] = byte(t[3] >> 7)
+	out[21] = byte(t[3] >> 15)
+	out[22] = byte(t[3] >> 23)
+	out[23] = byte(t[3] >> 31)
+	out[24] = byte(t[3] >> 39)
+	out[25] = byte(t[3] >> 47)
+
+	out[25] ^= byte(t[4]<<4) & 0xf0
+	out[26] = byte(t[4] >> 4)
+	out[27] = byte(t[4] >> 12)
+	out[28] = byte(t[4] >> 20)
+	out[29] = byte(t[4] >> 28)
+	out[30] = byte(t[4] >> 36)
+	out[31] = byte(t[4] >> 44)
+}
+
+// invert calculates r = x^-1 mod p using Fermat's little theorem.
+func invert(r *[5]uint64, x *[5]uint64) {
+	var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
+
+	square(&z2, x)        /* 2 */
+	square(&t, &z2)       /* 4 */
+	square(&t, &t)        /* 8 */
+	mul(&z9, &t, x)       /* 9 */
+	mul(&z11, &z9, &z2)   /* 11 */
+	square(&t, &z11)      /* 22 */
+	mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
+
+	square(&t, &z2_5_0)      /* 2^6 - 2^1 */
+	for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
+		square(&t, &t)
+	}
+	mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
+
+	square(&t, &z2_10_0)      /* 2^11 - 2^1 */
+	for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
+		square(&t, &t)
+	}
+	mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
+
+	square(&t, &z2_20_0)      /* 2^21 - 2^1 */
+	for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
+		square(&t, &t)
+	}
+	mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
+
+	square(&t, &t)            /* 2^41 - 2^1 */
+	for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
+		square(&t, &t)
+	}
+	mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
+
+	square(&t, &z2_50_0)      /* 2^51 - 2^1 */
+	for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
+		square(&t, &t)
+	}
+	mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
+
+	square(&t, &z2_100_0)      /* 2^101 - 2^1 */
+	for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
+		square(&t, &t)
+	}
+	mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
+
+	square(&t, &t)            /* 2^201 - 2^1 */
+	for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
+		square(&t, &t)
+	}
+	mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
+
+	square(&t, &t) /* 2^251 - 2^1 */
+	square(&t, &t) /* 2^252 - 2^2 */
+	square(&t, &t) /* 2^253 - 2^3 */
+
+	square(&t, &t) /* 2^254 - 2^4 */
+
+	square(&t, &t)   /* 2^255 - 2^5 */
+	mul(r, &t, &z11) /* 2^255 - 21 */
+}

+ 169 - 0
src/golang.org/x/crypto/curve25519/mul_amd64.s

@@ -0,0 +1,169 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+#include "const_amd64.h"
+
+// func mul(dest, a, b *[5]uint64)
+TEXT ·mul(SB),0,$16-24
+	MOVQ dest+0(FP), DI
+	MOVQ a+8(FP), SI
+	MOVQ b+16(FP), DX
+
+	MOVQ DX,CX
+	MOVQ 24(SI),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,0(SP)
+	MULQ 16(CX)
+	MOVQ AX,R8
+	MOVQ DX,R9
+	MOVQ 32(SI),DX
+	IMUL3Q $19,DX,AX
+	MOVQ AX,8(SP)
+	MULQ 8(CX)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 0(SI),AX
+	MULQ 0(CX)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 0(SI),AX
+	MULQ 8(CX)
+	MOVQ AX,R10
+	MOVQ DX,R11
+	MOVQ 0(SI),AX
+	MULQ 16(CX)
+	MOVQ AX,R12
+	MOVQ DX,R13
+	MOVQ 0(SI),AX
+	MULQ 24(CX)
+	MOVQ AX,R14
+	MOVQ DX,R15
+	MOVQ 0(SI),AX
+	MULQ 32(CX)
+	MOVQ AX,BX
+	MOVQ DX,BP
+	MOVQ 8(SI),AX
+	MULQ 0(CX)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 8(SI),AX
+	MULQ 8(CX)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 8(SI),AX
+	MULQ 16(CX)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 8(SI),AX
+	MULQ 24(CX)
+	ADDQ AX,BX
+	ADCQ DX,BP
+	MOVQ 8(SI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(CX)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 16(SI),AX
+	MULQ 0(CX)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 16(SI),AX
+	MULQ 8(CX)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 16(SI),AX
+	MULQ 16(CX)
+	ADDQ AX,BX
+	ADCQ DX,BP
+	MOVQ 16(SI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 24(CX)
+	ADDQ AX,R8
+	ADCQ DX,R9
+	MOVQ 16(SI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(CX)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 24(SI),AX
+	MULQ 0(CX)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ 24(SI),AX
+	MULQ 8(CX)
+	ADDQ AX,BX
+	ADCQ DX,BP
+	MOVQ 0(SP),AX
+	MULQ 24(CX)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 0(SP),AX
+	MULQ 32(CX)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 32(SI),AX
+	MULQ 0(CX)
+	ADDQ AX,BX
+	ADCQ DX,BP
+	MOVQ 8(SP),AX
+	MULQ 16(CX)
+	ADDQ AX,R10
+	ADCQ DX,R11
+	MOVQ 8(SP),AX
+	MULQ 24(CX)
+	ADDQ AX,R12
+	ADCQ DX,R13
+	MOVQ 8(SP),AX
+	MULQ 32(CX)
+	ADDQ AX,R14
+	ADCQ DX,R15
+	MOVQ $REDMASK51,SI
+	SHLQ $13,R9:R8
+	ANDQ SI,R8
+	SHLQ $13,R11:R10
+	ANDQ SI,R10
+	ADDQ R9,R10
+	SHLQ $13,R13:R12
+	ANDQ SI,R12
+	ADDQ R11,R12
+	SHLQ $13,R15:R14
+	ANDQ SI,R14
+	ADDQ R13,R14
+	SHLQ $13,BP:BX
+	ANDQ SI,BX
+	ADDQ R15,BX
+	IMUL3Q $19,BP,DX
+	ADDQ DX,R8
+	MOVQ R8,DX
+	SHRQ $51,DX
+	ADDQ R10,DX
+	MOVQ DX,CX
+	SHRQ $51,DX
+	ANDQ SI,R8
+	ADDQ R12,DX
+	MOVQ DX,R9
+	SHRQ $51,DX
+	ANDQ SI,CX
+	ADDQ R14,DX
+	MOVQ DX,AX
+	SHRQ $51,DX
+	ANDQ SI,R9
+	ADDQ BX,DX
+	MOVQ DX,R10
+	SHRQ $51,DX
+	ANDQ SI,AX
+	IMUL3Q $19,DX,DX
+	ADDQ DX,R8
+	ANDQ SI,R10
+	MOVQ R8,0(DI)
+	MOVQ CX,8(DI)
+	MOVQ R9,16(DI)
+	MOVQ AX,24(DI)
+	MOVQ R10,32(DI)
+	RET

+ 132 - 0
src/golang.org/x/crypto/curve25519/square_amd64.s

@@ -0,0 +1,132 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+#include "const_amd64.h"
+
+// func square(out, in *[5]uint64)
+TEXT ·square(SB),7,$0-16
+	MOVQ out+0(FP), DI
+	MOVQ in+8(FP), SI
+
+	MOVQ 0(SI),AX
+	MULQ 0(SI)
+	MOVQ AX,CX
+	MOVQ DX,R8
+	MOVQ 0(SI),AX
+	SHLQ $1,AX
+	MULQ 8(SI)
+	MOVQ AX,R9
+	MOVQ DX,R10
+	MOVQ 0(SI),AX
+	SHLQ $1,AX
+	MULQ 16(SI)
+	MOVQ AX,R11
+	MOVQ DX,R12
+	MOVQ 0(SI),AX
+	SHLQ $1,AX
+	MULQ 24(SI)
+	MOVQ AX,R13
+	MOVQ DX,R14
+	MOVQ 0(SI),AX
+	SHLQ $1,AX
+	MULQ 32(SI)
+	MOVQ AX,R15
+	MOVQ DX,BX
+	MOVQ 8(SI),AX
+	MULQ 8(SI)
+	ADDQ AX,R11
+	ADCQ DX,R12
+	MOVQ 8(SI),AX
+	SHLQ $1,AX
+	MULQ 16(SI)
+	ADDQ AX,R13
+	ADCQ DX,R14
+	MOVQ 8(SI),AX
+	SHLQ $1,AX
+	MULQ 24(SI)
+	ADDQ AX,R15
+	ADCQ DX,BX
+	MOVQ 8(SI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 32(SI)
+	ADDQ AX,CX
+	ADCQ DX,R8
+	MOVQ 16(SI),AX
+	MULQ 16(SI)
+	ADDQ AX,R15
+	ADCQ DX,BX
+	MOVQ 16(SI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 24(SI)
+	ADDQ AX,CX
+	ADCQ DX,R8
+	MOVQ 16(SI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 32(SI)
+	ADDQ AX,R9
+	ADCQ DX,R10
+	MOVQ 24(SI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 24(SI)
+	ADDQ AX,R9
+	ADCQ DX,R10
+	MOVQ 24(SI),DX
+	IMUL3Q $38,DX,AX
+	MULQ 32(SI)
+	ADDQ AX,R11
+	ADCQ DX,R12
+	MOVQ 32(SI),DX
+	IMUL3Q $19,DX,AX
+	MULQ 32(SI)
+	ADDQ AX,R13
+	ADCQ DX,R14
+	MOVQ $REDMASK51,SI
+	SHLQ $13,R8:CX
+	ANDQ SI,CX
+	SHLQ $13,R10:R9
+	ANDQ SI,R9
+	ADDQ R8,R9
+	SHLQ $13,R12:R11
+	ANDQ SI,R11
+	ADDQ R10,R11
+	SHLQ $13,R14:R13
+	ANDQ SI,R13
+	ADDQ R12,R13
+	SHLQ $13,BX:R15
+	ANDQ SI,R15
+	ADDQ R14,R15
+	IMUL3Q $19,BX,DX
+	ADDQ DX,CX
+	MOVQ CX,DX
+	SHRQ $51,DX
+	ADDQ R9,DX
+	ANDQ SI,CX
+	MOVQ DX,R8
+	SHRQ $51,DX
+	ADDQ R11,DX
+	ANDQ SI,R8
+	MOVQ DX,R9
+	SHRQ $51,DX
+	ADDQ R13,DX
+	ANDQ SI,R9
+	MOVQ DX,AX
+	SHRQ $51,DX
+	ADDQ R15,DX
+	ANDQ SI,AX
+	MOVQ DX,R10
+	SHRQ $51,DX
+	IMUL3Q $19,DX,DX
+	ADDQ DX,CX
+	ANDQ SI,R10
+	MOVQ CX,0(DI)
+	MOVQ R8,8(DI)
+	MOVQ R9,16(DI)
+	MOVQ AX,24(DI)
+	MOVQ R10,32(DI)
+	RET

+ 217 - 0
src/golang.org/x/crypto/ed25519/ed25519.go

@@ -0,0 +1,217 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ed25519 implements the Ed25519 signature algorithm. See
+// https://ed25519.cr.yp.to/.
+//
+// These functions are also compatible with the “Ed25519” function defined in
+// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
+// representation includes a public key suffix to make multiple signing
+// operations with the same key more efficient. This package refers to the RFC
+// 8032 private key as the “seed”.
+package ed25519
+
+// This code is a port of the public domain, “ref10” implementation of ed25519
+// from SUPERCOP.
+
+import (
+	"bytes"
+	"crypto"
+	cryptorand "crypto/rand"
+	"crypto/sha512"
+	"errors"
+	"io"
+	"strconv"
+
+	"golang.org/x/crypto/ed25519/internal/edwards25519"
+)
+
+const (
+	// PublicKeySize is the size, in bytes, of public keys as used in this package.
+	PublicKeySize = 32
+	// PrivateKeySize is the size, in bytes, of private keys as used in this package.
+	PrivateKeySize = 64
+	// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+	SignatureSize = 64
+	// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
+	SeedSize = 32
+)
+
+// PublicKey is the type of Ed25519 public keys.
+type PublicKey []byte
+
+// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
+type PrivateKey []byte
+
+// Public returns the PublicKey corresponding to priv.
+func (priv PrivateKey) Public() crypto.PublicKey {
+	publicKey := make([]byte, PublicKeySize)
+	copy(publicKey, priv[32:])
+	return PublicKey(publicKey)
+}
+
+// Seed returns the private key seed corresponding to priv. It is provided for
+// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
+// in this package.
+func (priv PrivateKey) Seed() []byte {
+	seed := make([]byte, SeedSize)
+	copy(seed, priv[:32])
+	return seed
+}
+
+// Sign signs the given message with priv.
+// Ed25519 performs two passes over messages to be signed and therefore cannot
+// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
+// indicate the message hasn't been hashed. This can be achieved by passing
+// crypto.Hash(0) as the value for opts.
+func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
+	if opts.HashFunc() != crypto.Hash(0) {
+		return nil, errors.New("ed25519: cannot sign hashed message")
+	}
+
+	return Sign(priv, message), nil
+}
+
+// GenerateKey generates a public/private key pair using entropy from rand.
+// If rand is nil, crypto/rand.Reader will be used.
+func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
+	if rand == nil {
+		rand = cryptorand.Reader
+	}
+
+	seed := make([]byte, SeedSize)
+	if _, err := io.ReadFull(rand, seed); err != nil {
+		return nil, nil, err
+	}
+
+	privateKey := NewKeyFromSeed(seed)
+	publicKey := make([]byte, PublicKeySize)
+	copy(publicKey, privateKey[32:])
+
+	return publicKey, privateKey, nil
+}
+
+// NewKeyFromSeed calculates a private key from a seed. It will panic if
+// len(seed) is not SeedSize. This function is provided for interoperability
+// with RFC 8032. RFC 8032's private keys correspond to seeds in this
+// package.
+func NewKeyFromSeed(seed []byte) PrivateKey {
+	if l := len(seed); l != SeedSize {
+		panic("ed25519: bad seed length: " + strconv.Itoa(l))
+	}
+
+	digest := sha512.Sum512(seed)
+	digest[0] &= 248
+	digest[31] &= 127
+	digest[31] |= 64
+
+	var A edwards25519.ExtendedGroupElement
+	var hBytes [32]byte
+	copy(hBytes[:], digest[:])
+	edwards25519.GeScalarMultBase(&A, &hBytes)
+	var publicKeyBytes [32]byte
+	A.ToBytes(&publicKeyBytes)
+
+	privateKey := make([]byte, PrivateKeySize)
+	copy(privateKey, seed)
+	copy(privateKey[32:], publicKeyBytes[:])
+
+	return privateKey
+}
+
+// Sign signs the message with privateKey and returns a signature. It will
+// panic if len(privateKey) is not PrivateKeySize.
+func Sign(privateKey PrivateKey, message []byte) []byte {
+	if l := len(privateKey); l != PrivateKeySize {
+		panic("ed25519: bad private key length: " + strconv.Itoa(l))
+	}
+
+	h := sha512.New()
+	h.Write(privateKey[:32])
+
+	var digest1, messageDigest, hramDigest [64]byte
+	var expandedSecretKey [32]byte
+	h.Sum(digest1[:0])
+	copy(expandedSecretKey[:], digest1[:])
+	expandedSecretKey[0] &= 248
+	expandedSecretKey[31] &= 63
+	expandedSecretKey[31] |= 64
+
+	h.Reset()
+	h.Write(digest1[32:])
+	h.Write(message)
+	h.Sum(messageDigest[:0])
+
+	var messageDigestReduced [32]byte
+	edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
+	var R edwards25519.ExtendedGroupElement
+	edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
+
+	var encodedR [32]byte
+	R.ToBytes(&encodedR)
+
+	h.Reset()
+	h.Write(encodedR[:])
+	h.Write(privateKey[32:])
+	h.Write(message)
+	h.Sum(hramDigest[:0])
+	var hramDigestReduced [32]byte
+	edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
+
+	var s [32]byte
+	edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
+
+	signature := make([]byte, SignatureSize)
+	copy(signature[:], encodedR[:])
+	copy(signature[32:], s[:])
+
+	return signature
+}
+
+// Verify reports whether sig is a valid signature of message by publicKey. It
+// will panic if len(publicKey) is not PublicKeySize.
+func Verify(publicKey PublicKey, message, sig []byte) bool {
+	if l := len(publicKey); l != PublicKeySize {
+		panic("ed25519: bad public key length: " + strconv.Itoa(l))
+	}
+
+	if len(sig) != SignatureSize || sig[63]&224 != 0 {
+		return false
+	}
+
+	var A edwards25519.ExtendedGroupElement
+	var publicKeyBytes [32]byte
+	copy(publicKeyBytes[:], publicKey)
+	if !A.FromBytes(&publicKeyBytes) {
+		return false
+	}
+	edwards25519.FeNeg(&A.X, &A.X)
+	edwards25519.FeNeg(&A.T, &A.T)
+
+	h := sha512.New()
+	h.Write(sig[:32])
+	h.Write(publicKey[:])
+	h.Write(message)
+	var digest [64]byte
+	h.Sum(digest[:0])
+
+	var hReduced [32]byte
+	edwards25519.ScReduce(&hReduced, &digest)
+
+	var R edwards25519.ProjectiveGroupElement
+	var s [32]byte
+	copy(s[:], sig[32:])
+
+	// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
+	// the range [0, order) in order to prevent signature malleability.
+	if !edwards25519.ScMinimal(&s) {
+		return false
+	}
+
+	edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
+
+	var checkR [32]byte
+	R.ToBytes(&checkR)
+	return bytes.Equal(sig[:32], checkR[:])
+}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio