mirror of
https://github.com/cloudflare/cloudflared.git
synced 2026-08-07 23:31:56 +00:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7260f3e487 | |||
| a42b66e8bd | |||
| 28d556b8d4 | |||
| 33701f50ec | |||
| abfeebf67d | |||
| 3b293048f4 | |||
| ac3638f6b1 | |||
| f7ff41f1dc | |||
| f5c8ff77e9 | |||
| 87e06100df | |||
| 1ed9e0fceb | |||
| b9d6aaebbe | |||
| a99780ed9d | |||
| 92765b4261 | |||
| 8b88b4a403 | |||
| 2ce6720a6e | |||
| 772ccc9607 | |||
| 7724ff8176 | |||
| 2a3d486126 | |||
| 932e383051 | |||
| dbe3516204 | |||
| 6fc9f1b405 | |||
| 370c17e48c | |||
| 92da73aa9d | |||
| 0c65daaa7d | |||
| b46acd7f63 | |||
| e3a9aa4296 | |||
| 3886021ba5 | |||
| 4d3ebaf984 | |||
| 9131e842a5 | |||
| 4f9cfa6542 | |||
| a1a8645294 | |||
| b95b289a8c | |||
| 425554077f | |||
| 7b2f286210 | |||
| 0f893fab47 | |||
| 12c615e2e6 | |||
| 6e5ccd7c85 | |||
| 3ec500bdbb | |||
| 8f75feac94 | |||
| 448a7798f7 | |||
| dc3a228d51 | |||
| 554c97a8cb | |||
| fd1941dfbe | |||
| 5fd348dcfc | |||
| 1a6403b2fd | |||
| 55acf7283c | |||
| acb7d604fd | |||
| 6e761cb7ae | |||
| ae8d784e36 | |||
| c716dd273c |
@@ -0,0 +1,8 @@
|
||||
images:
|
||||
- name: cloudflared
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
registries:
|
||||
- name: docker.io/cloudflare
|
||||
user: env:DOCKER_USER
|
||||
password: env:DOCKER_PASSWORD
|
||||
@@ -9,6 +9,7 @@ guide/public
|
||||
\#*\#
|
||||
cscope.*
|
||||
cloudflared
|
||||
cloudflared.pkg
|
||||
cloudflared.exe
|
||||
!cmd/cloudflared/
|
||||
.DS_Store
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# uninstall first in case this is an upgrade
|
||||
/usr/local/bin/cloudflared service uninstall
|
||||
|
||||
# install the new service using launchctl
|
||||
/usr/local/bin/cloudflared service install
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
/usr/local/bin/cloudflared service uninstall
|
||||
rm /usr/local/bin/cloudflared
|
||||
pkgutil --forget com.cloudflare.cloudflared
|
||||
Vendored
-6
@@ -2,12 +2,6 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if ! git describe --tags --exact-match 2>/dev/null ; then
|
||||
echo "Skipping public release for an untagged commit."
|
||||
echo "##teamcity[buildStatus status='SUCCESS' text='Skipped due to lack of tag']"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$(uname)" != "Darwin" ]] ; then
|
||||
echo "This should be run on macOS"
|
||||
exit 1
|
||||
|
||||
Vendored
+1
-4
@@ -64,7 +64,4 @@ git config user.name "cloudflare-warp-bot"
|
||||
git config user.email "warp-bot@cloudflare.com"
|
||||
git commit -m "Release Argo Tunnel $VERSION"
|
||||
|
||||
#git push -v origin master
|
||||
# don't push to master, push to some testing branch
|
||||
git checkout -b deploy-test
|
||||
git push -v origin deploy-test
|
||||
git push -v origin master
|
||||
|
||||
@@ -4,7 +4,8 @@ VERSION_FLAGS := -ldflags='-X "main.Version=$(VERSION)" -X "main.BuildTime=$(DAT
|
||||
|
||||
IMPORT_PATH := github.com/cloudflare/cloudflared
|
||||
PACKAGE_DIR := $(CURDIR)/packaging
|
||||
INSTALL_BINDIR := usr/local/bin
|
||||
INSTALL_BINDIR := /usr/bin/
|
||||
MAN_DIR := /usr/share/man/man1/
|
||||
|
||||
EQUINOX_FLAGS = --version="$(VERSION)" \
|
||||
--platforms="$(EQUINOX_BUILD_PLATFORMS)" \
|
||||
@@ -17,7 +18,9 @@ ifeq ($(EQUINOX_IS_DRAFT), true)
|
||||
endif
|
||||
|
||||
LOCAL_ARCH ?= $(shell uname -m)
|
||||
ifeq ($(LOCAL_ARCH),x86_64)
|
||||
ifneq ($(GOARCH),)
|
||||
TARGET_ARCH ?= $(GOARCH)
|
||||
else ifeq ($(LOCAL_ARCH),x86_64)
|
||||
TARGET_ARCH ?= amd64
|
||||
else ifeq ($(shell echo $(LOCAL_ARCH) | head -c 5),armv8)
|
||||
TARGET_ARCH ?= arm64
|
||||
@@ -40,6 +43,20 @@ else
|
||||
$(error This system's OS $(LOCAL_OS) isn't supported)
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_OS), windows)
|
||||
EXECUTABLE_PATH=./cloudflared.exe
|
||||
else
|
||||
EXECUTABLE_PATH=./cloudflared
|
||||
endif
|
||||
|
||||
ifeq ($(FLAVOR), centos-7)
|
||||
TARGET_PUBLIC_REPO ?= el7
|
||||
else ifeq ($(FLAVOR), centos-6)
|
||||
TARGET_PUBLIC_REPO ?= el6
|
||||
else
|
||||
TARGET_PUBLIC_REPO ?= $(FLAVOR)
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: cloudflared test
|
||||
|
||||
@@ -63,12 +80,42 @@ test: vet
|
||||
test-ssh-server:
|
||||
docker-compose -f ssh_server_tests/docker-compose.yml up
|
||||
|
||||
.PHONY: cloudflared-deb
|
||||
cloudflared-deb: cloudflared
|
||||
define publish_package
|
||||
for HOST in $(CF_PKG_HOSTS); do \
|
||||
ssh-keyscan -t rsa $$HOST >> ~/.ssh/known_hosts; \
|
||||
scp -4 cloudflared_$(VERSION)_amd64.deb cfsync@$$HOST:/state/cf-pkg/staging/$(1)/$(TARGET_PUBLIC_REPO)/cloudflared/; \
|
||||
done
|
||||
endef
|
||||
|
||||
.PHONY: publish-deb
|
||||
publish-deb: cloudflared-deb
|
||||
$(call publish_package,apt)
|
||||
|
||||
.PHONY: publish-rpm
|
||||
publish-rpm: cloudflared-rpm
|
||||
$(call publish_package,yum)
|
||||
|
||||
define build_package
|
||||
mkdir -p $(PACKAGE_DIR)
|
||||
cp cloudflared $(PACKAGE_DIR)/cloudflared
|
||||
fakeroot fpm -C $(PACKAGE_DIR) -s dir -t deb --deb-compression bzip2 \
|
||||
-a $(TARGET_ARCH) -v $(VERSION) -n cloudflared cloudflared=/usr/local/bin/
|
||||
cat cloudflared_man_template | sed -e 's/\$${VERSION}/$(VERSION)/; s/\$${DATE}/$(DATE)/' > $(PACKAGE_DIR)/cloudflared.1
|
||||
fakeroot fpm -C $(PACKAGE_DIR) -s dir -t $(1) --$(1)-compression bzip2 \
|
||||
--description 'Cloudflare Argo tunnel daemon' \
|
||||
--vendor 'Cloudflare' \
|
||||
--license 'Cloudflare Service Agreement' \
|
||||
--url 'https://github.com/cloudflare/cloudflared' \
|
||||
-m 'Cloudflare <support@cloudflare.com>' \
|
||||
-a $(TARGET_ARCH) -v $(VERSION) -n cloudflared --after-install postinst.sh --after-remove postrm.sh \
|
||||
cloudflared=$(INSTALL_BINDIR) cloudflared.1=$(MAN_DIR)
|
||||
endef
|
||||
|
||||
.PHONY: cloudflared-deb
|
||||
cloudflared-deb: cloudflared
|
||||
$(call build_package,deb)
|
||||
|
||||
.PHONY: cloudflared-rpm
|
||||
cloudflared-rpm: cloudflared
|
||||
$(call build_package,rpm)
|
||||
|
||||
.PHONY: cloudflared-darwin-amd64.tgz
|
||||
cloudflared-darwin-amd64.tgz: cloudflared
|
||||
@@ -88,6 +135,10 @@ homebrew-release: homebrew-upload
|
||||
release: bin/equinox
|
||||
bin/equinox release $(EQUINOX_FLAGS) -- $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared
|
||||
|
||||
.PHONY: github-release
|
||||
github-release: cloudflared
|
||||
python3 github_release.py --path $(EXECUTABLE_PATH) --release-version $(VERSION)
|
||||
|
||||
bin/equinox:
|
||||
mkdir -p bin
|
||||
curl -s https://bin.equinox.io/c/75JtLRTsJ3n/release-tool-beta-$(EQUINOX_PLATFORM).tgz | tar xz -C bin/
|
||||
|
||||
@@ -1,3 +1,60 @@
|
||||
2020.7.2
|
||||
- 2020-07-02 AUTH-2644: Change install location and add man page
|
||||
- 2020-07-02 TUN-3131: Allow user to specify tunnel credentials path, and remove it in tunnel delete command
|
||||
- 2020-07-03 TUN-3008: Implement cloudflared tunnel cleanup command
|
||||
- 2020-07-02 TUN-3150: cloudflared tunnel list's table should use intelligent column width
|
||||
- 2020-07-07 TUN-3169: Move on to the next address when edge returns duplicate connection. There's no point in trying to connect to the same address since it will be hashed to the same metal. Improve logging of errors from serve tunnel loop, hide useless context cancelled error.
|
||||
- 2020-07-08 beautify package meta information generated by fpm (#218)
|
||||
- 2020-07-06 AUTH-2871: fix rpm builds
|
||||
- 2020-07-08 AUTH-2858: Set file to disable autoupdate
|
||||
- 2020-07-09 AUTH-2872: Adds centos-6 build
|
||||
|
||||
2020.7.1
|
||||
- 2020-07-02 DEVTOOLS-7321: Push GitHub homebrew updates to master
|
||||
- 2020-07-06 TUN-3161: Upgrade golang.org/x/ deps
|
||||
- 2020-06-30 AUTH-2854: Create cloudflared RPMs
|
||||
- 2020-06-26 AUTH-2850 log config file path
|
||||
|
||||
2020.7.0
|
||||
- 2020-06-30 TUN-3140: Add timestamps to terminal log entries
|
||||
- 2020-06-30 AUTH-2860: Fix builds
|
||||
- 2020-06-25 TUN-3007: Implement named tunnel connection registration and unregistration.
|
||||
|
||||
2020.6.6
|
||||
- 2020-06-23 AUTH-2685: Adds script to create release
|
||||
- 2020-06-25 AUTH-2652: Update cloudflare repo
|
||||
- 2020-06-26 AUTH-2718: Add target for publishing deb to pkg.cloudflare repo
|
||||
- 2020-06-26 AUTH-2849 all log output to stderr
|
||||
- 2020-06-17 TUN-3106: Pass NamedTunnel config to StartServer
|
||||
- 2020-06-18 TUN-3107: UnregisterConnection shouldn't wrap nil error as RPC error
|
||||
- 2020-06-17 AUTH-2652: Adds .docker-images to push images to docker hub
|
||||
- 2020-06-18 AUTH-2712 mac package build script and better config file handling when started as a service
|
||||
|
||||
2020.6.5
|
||||
- 2020-06-16 DEVTOOLS-7321: Don't skip macOS builds based on tag
|
||||
- 2020-06-16 fix for a flaky test
|
||||
- 2020-06-16 AUTH-2815 flag check was wrong. stupid oversight
|
||||
- 2020-06-16 TUN-3101: Tunnel list command should only show non-deleted, by default
|
||||
- 2020-06-16 TUN-3066: Command line action for tunnel run
|
||||
- 2020-06-16 TUN-3100 make updater report the right text
|
||||
|
||||
2020.6.4
|
||||
- 2020-06-11 TUN-3085: Pass connection authentication information using TunnelAuth struct
|
||||
- 2020-06-15 TUN-3084: Generate and store tunnel_secret value during tunnel creation
|
||||
- 2020-06-16 AUTH-2815 add the log file to support the config.yaml file
|
||||
- 2020-06-02 TUN-3015: Add a new cap'n'proto RPC interface for connection registration as well as matching client and server implementations. The old interface extends the new one for backward compatibility.
|
||||
|
||||
2020.6.3
|
||||
- 2020-06-15 DEVTOOLS-7321: Add openssh-client pkg for missing ssh-keyscan
|
||||
- 2020-06-15 AUTH-2813 adds back a single file support a cloudflared log file
|
||||
|
||||
2020.6.2
|
||||
- 2020-06-11 AUTH-2648 updated usage text
|
||||
- 2020-06-11 AUTH-2763 don't redirect from curl command
|
||||
- 2020-06-12 TUN-3090: Upgrade crypto dep
|
||||
- 2020-06-11 TUN-3038: Add connections to tunnel list table
|
||||
- 2020-06-12 AUTH-2810 added warn for backwards compatibility sake
|
||||
|
||||
2020.6.1
|
||||
- 2020-06-09 AUTH-2796 fixed windows build
|
||||
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ func BuildAccessRequest(options *StartOptions, logger logger.Service) (*http.Req
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, err := token.FetchToken(req.URL, logger)
|
||||
token, err := token.FetchTokenWithRedirect(req.URL, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+132
@@ -22,6 +22,18 @@ stretch: &stretch
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make cloudflared-deb
|
||||
publish-deb:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go
|
||||
- build-essential
|
||||
- fakeroot
|
||||
- rubygem-fpm
|
||||
- openssh-client
|
||||
post-cache:
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make publish-deb
|
||||
release-linux-amd64:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
@@ -31,6 +43,18 @@ stretch: &stretch
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make release
|
||||
github-release-linux-amd64:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go
|
||||
- build-essential
|
||||
- python3-setuptools
|
||||
- python3-pip
|
||||
post-cache:
|
||||
- pip3 install pygithub
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make github-release
|
||||
release-linux-armv6:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
@@ -42,6 +66,20 @@ stretch: &stretch
|
||||
- export GOARCH=arm
|
||||
- export CC=arm-linux-gnueabihf-gcc
|
||||
- make release
|
||||
github-release-linux-armv6:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go
|
||||
- crossbuild-essential-armhf
|
||||
- gcc-arm-linux-gnueabihf
|
||||
- python3-setuptools
|
||||
- python3-pip
|
||||
post-cache:
|
||||
- pip3 install pygithub
|
||||
- export GOOS=linux
|
||||
- export GOARCH=arm
|
||||
- export CC=arm-linux-gnueabihf-gcc
|
||||
- make github-release
|
||||
release-linux-386:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
@@ -51,6 +89,18 @@ stretch: &stretch
|
||||
- export GOOS=linux
|
||||
- export GOARCH=386
|
||||
- make release
|
||||
github-release-linux-386:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go
|
||||
- gcc-multilib
|
||||
- python3-setuptools
|
||||
- python3-pip
|
||||
post-cache:
|
||||
- pip3 install pygithub
|
||||
- export GOOS=linux
|
||||
- export GOARCH=386
|
||||
- make github-release
|
||||
release-windows-amd64:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
@@ -61,6 +111,19 @@ stretch: &stretch
|
||||
- export GOARCH=amd64
|
||||
- export CC=x86_64-w64-mingw32-gcc
|
||||
- make release
|
||||
github-release-windows-amd64:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go
|
||||
- gcc-mingw-w64
|
||||
- python3-setuptools
|
||||
- python3-pip
|
||||
post-cache:
|
||||
- pip3 install pygithub
|
||||
- export GOOS=windows
|
||||
- export GOARCH=amd64
|
||||
- export CC=x86_64-w64-mingw32-gcc
|
||||
- make github-release
|
||||
release-windows-386:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
@@ -71,6 +134,19 @@ stretch: &stretch
|
||||
- export GOARCH=386
|
||||
- export CC=i686-w64-mingw32-gcc-win32
|
||||
- make release
|
||||
github-release-windows-386:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
- *pinned_go
|
||||
- gcc-mingw-w64
|
||||
- python3-setuptools
|
||||
- python3-pip
|
||||
post-cache:
|
||||
- pip3 install pygithub
|
||||
- export GOOS=windows
|
||||
- export GOARCH=386
|
||||
- export CC=i686-w64-mingw32-gcc-win32
|
||||
- make github-release
|
||||
test:
|
||||
build_dir: *build_dir
|
||||
builddeps:
|
||||
@@ -85,6 +161,7 @@ stretch: &stretch
|
||||
- make test
|
||||
update-homebrew:
|
||||
builddeps:
|
||||
- openssh-client
|
||||
- s3cmd
|
||||
post-cache:
|
||||
- .teamcity/update-homebrew.sh
|
||||
@@ -93,6 +170,61 @@ jessie: *stretch
|
||||
|
||||
buster: *stretch
|
||||
|
||||
centos-6:
|
||||
build-rpm:
|
||||
build_dir: *build_dir
|
||||
builddeps: &el6_builddeps
|
||||
- https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
|
||||
post-cache:
|
||||
- source /usr/local/rvm/scripts/rvm
|
||||
- rvm use 1.9
|
||||
- sudo yum install -y fakeroot
|
||||
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
|
||||
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
|
||||
- export PATH=$PATH:/usr/local/go/bin
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make cloudflared-rpm
|
||||
publish-rpm:
|
||||
build_dir: *build_dir
|
||||
builddeps: *el6_builddeps
|
||||
post-cache:
|
||||
- source /usr/local/rvm/scripts/rvm
|
||||
- rvm use 1.9
|
||||
- sudo yum install -y fakeroot
|
||||
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
|
||||
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
|
||||
- export PATH=$PATH:/usr/local/go/bin
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make publish-rpm
|
||||
|
||||
|
||||
centos-7:
|
||||
publish-rpm:
|
||||
build_dir: *build_dir
|
||||
builddeps: &el7_builddeps
|
||||
- https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
post-cache:
|
||||
- sudo yum install -y fakeroot
|
||||
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
|
||||
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
|
||||
- export PATH=$PATH:/usr/local/go/bin
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make publish-rpm
|
||||
build-rpm:
|
||||
build_dir: *build_dir
|
||||
builddeps: *el7_builddeps
|
||||
post-cache:
|
||||
- sudo yum install -y fakeroot
|
||||
- wget https://golang.org/dl/go1.12.9.linux-amd64.tar.gz -P /tmp/
|
||||
- sudo tar -C /usr/local -xzf /tmp/go1.12.9.linux-amd64.tar.gz
|
||||
- export PATH=$PATH:/usr/local/go/bin
|
||||
- export GOOS=linux
|
||||
- export GOARCH=amd64
|
||||
- make cloudflared-rpm
|
||||
|
||||
# cfsetup compose
|
||||
default-stack: test_dbconnect
|
||||
test_dbconnect:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
.\" Manpage for cloudflared.
|
||||
.TH man 1 ${DATE} "${VERSION}" "cloudflared man page"
|
||||
.SH NAME
|
||||
cloudflared \- creates a connection to the cloudflare edge network
|
||||
.SH DESCRIPTION
|
||||
cloudflared creates a persistent connection between a local service and the Cloudflare network. Once the daemon is running and the Tunnel has been configured, the local service can be locked down to only allow connections from Cloudflare.
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/cloudflare/cloudflared/carrier"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||
"github.com/cloudflare/cloudflared/h2mux"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
@@ -36,6 +37,10 @@ func StartForwarder(forwarder config.Forwarder, shutdown <-chan struct{}, logger
|
||||
headers.Set(h2mux.CFAccessClientSecretHeader, forwarder.TokenSecret)
|
||||
}
|
||||
|
||||
if forwarder.Destination != "" {
|
||||
headers.Add(h2mux.CFJumpDestinationHeader, forwarder.Destination)
|
||||
}
|
||||
|
||||
options := &carrier.StartOptions{
|
||||
OriginURL: forwarder.URL,
|
||||
Headers: headers, //TODO: TUN-2688 support custom headers from config file
|
||||
@@ -67,7 +72,7 @@ func ssh(c *cli.Context) error {
|
||||
|
||||
logger, err := logger.New(logger.DefaultFile(logDirectory), logger.LogLevelString(logLevel))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
return cliutil.PrintLoggerSetupError("error setting up logger", err)
|
||||
}
|
||||
|
||||
// get the hostname from the cmdline and error out if its not provided
|
||||
@@ -101,7 +106,7 @@ func ssh(c *cli.Context) error {
|
||||
wsConn := carrier.NewWSConnection(logger, false)
|
||||
|
||||
if c.NArg() > 0 || c.IsSet(sshURLFlag) {
|
||||
localForwarder, err := config.ValidateUrl(c)
|
||||
localForwarder, err := config.ValidateUrl(c, true)
|
||||
if err != nil {
|
||||
logger.Errorf("Error validating origin URL: %s", err)
|
||||
return errors.Wrap(err, "error validating origin URL")
|
||||
|
||||
@@ -351,7 +351,7 @@ func sshGen(c *cli.Context) error {
|
||||
// this fetchToken function mutates the appURL param. We should refactor that
|
||||
fetchTokenURL := &url.URL{}
|
||||
*fetchTokenURL = *originURL
|
||||
cfdToken, err := token.FetchToken(fetchTokenURL, logger)
|
||||
cfdToken, err := token.FetchTokenWithRedirect(fetchTokenURL, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package cliutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
@@ -39,3 +41,15 @@ func ErrorHandler(actionFunc cli.ActionFunc) cli.ActionFunc {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// PrintLoggerSetupError returns an error to stdout to notify when a logger can't start
|
||||
func PrintLoggerSetupError(msg string, err error) error {
|
||||
l, le := logger.New()
|
||||
if le != nil {
|
||||
log.Printf("%s: %s", msg, err)
|
||||
} else {
|
||||
l.Errorf("%s: %s", msg, err)
|
||||
}
|
||||
|
||||
return errors.Wrap(err, msg)
|
||||
}
|
||||
|
||||
@@ -4,25 +4,65 @@ import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/cloudflare/cloudflared/validation"
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"gopkg.in/urfave/cli.v2/altsrc"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cloudflare/cloudflared/validation"
|
||||
)
|
||||
|
||||
var (
|
||||
// File names from which we attempt to read configuration.
|
||||
// DefaultConfigFiles is the file names from which we attempt to read configuration.
|
||||
DefaultConfigFiles = []string{"config.yml", "config.yaml"}
|
||||
|
||||
// DefaultUnixConfigLocation is the primary location to find a config file
|
||||
DefaultUnixConfigLocation = "/usr/local/etc/cloudflared"
|
||||
|
||||
// DefaultUnixLogLocation is the primary location to find log files
|
||||
DefaultUnixLogLocation = "/var/log/cloudflared"
|
||||
|
||||
// Launchd doesn't set root env variables, so there is default
|
||||
// Windows default config dir was ~/cloudflare-warp in documentation; let's keep it compatible
|
||||
DefaultConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/cloudflare-warp", "/usr/local/etc/cloudflared", "/etc/cloudflared"}
|
||||
DefaultConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/cloudflare-warp", "/etc/cloudflared", DefaultUnixConfigLocation}
|
||||
)
|
||||
|
||||
const DefaultCredentialFile = "cert.pem"
|
||||
|
||||
// DefaultConfigDirectory returns the default directory of the config file
|
||||
func DefaultConfigDirectory() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
path := os.Getenv("CFDPATH")
|
||||
if path == "" {
|
||||
path = filepath.Join(os.Getenv("ProgramFiles(x86)"), "cloudflared")
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) { //doesn't exist, so return an empty failure string
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
return DefaultUnixConfigLocation
|
||||
}
|
||||
|
||||
// DefaultLogDirectory returns the default directory for log files
|
||||
func DefaultLogDirectory() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return DefaultConfigDirectory()
|
||||
}
|
||||
return DefaultUnixLogLocation
|
||||
}
|
||||
|
||||
// DefaultConfigPath returns the default location of a config file
|
||||
func DefaultConfigPath() string {
|
||||
dir := DefaultConfigDirectory()
|
||||
if dir == "" {
|
||||
return DefaultConfigFiles[0]
|
||||
}
|
||||
return filepath.Join(dir, DefaultConfigFiles[0])
|
||||
}
|
||||
|
||||
// FileExists checks to see if a file exist at the provided path.
|
||||
func FileExists(path string) (bool, error) {
|
||||
f, err := os.Open(path)
|
||||
@@ -64,10 +104,43 @@ func FindDefaultConfigPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// FindOrCreateConfigPath returns the first path that contains a config file
|
||||
// or creates one in the primary default path if it doesn't exist
|
||||
func FindOrCreateConfigPath() string {
|
||||
path := FindDefaultConfigPath()
|
||||
|
||||
if path == "" {
|
||||
// create the default directory if it doesn't exist
|
||||
path = DefaultConfigPath()
|
||||
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// write a new config file out
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
logDir := DefaultLogDirectory()
|
||||
os.MkdirAll(logDir, os.ModePerm) //try and create it. Doesn't matter if it succeed or not, only byproduct will be no logs
|
||||
|
||||
c := Root{
|
||||
LogDirectory: logDir,
|
||||
}
|
||||
if err := yaml.NewEncoder(file).Encode(&c); err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// FindLogSettings gets the log directory and level from the config file
|
||||
func FindLogSettings() (string, string) {
|
||||
configPath := FindDefaultConfigPath()
|
||||
defaultDirectory := filepath.Dir(configPath)
|
||||
configPath := FindOrCreateConfigPath()
|
||||
defaultDirectory := DefaultLogDirectory()
|
||||
defaultLevel := "info"
|
||||
|
||||
file, err := os.Open(configPath)
|
||||
@@ -104,9 +177,9 @@ func ValidateUnixSocket(c *cli.Context) (string, error) {
|
||||
|
||||
// ValidateUrl will validate url flag correctness. It can be either from --url or argument
|
||||
// Notice ValidateUnixSocket, it will enforce --unix-socket is not used with --url or argument
|
||||
func ValidateUrl(c *cli.Context) (string, error) {
|
||||
func ValidateUrl(c *cli.Context, allowFromArgs bool) (string, error) {
|
||||
var url = c.String("url")
|
||||
if c.NArg() > 0 {
|
||||
if allowFromArgs && c.NArg() > 0 {
|
||||
if c.IsSet("url") {
|
||||
return "", errors.New("Specified origin urls using both --url and argument. Decide which one you want, I can only support one.")
|
||||
}
|
||||
|
||||
@@ -49,9 +49,6 @@ func TestConfigChanged(t *testing.T) {
|
||||
os.Remove(filePath)
|
||||
}()
|
||||
c := &Root{
|
||||
OrgKey: "abcd",
|
||||
ConfigType: "mytype",
|
||||
CheckinInterval: 1,
|
||||
Forwarders: []Forwarder{
|
||||
{
|
||||
URL: "test.daltoniam.com",
|
||||
|
||||
@@ -13,6 +13,7 @@ type Forwarder struct {
|
||||
Listener string `json:"listener"`
|
||||
TokenClientID string `json:"service_token_id" yaml:"serviceTokenID"`
|
||||
TokenSecret string `json:"secret_token_id" yaml:"serviceTokenSecret"`
|
||||
Destination string `json:"destination"`
|
||||
}
|
||||
|
||||
// Tunnel represents a tunnel that should be started
|
||||
@@ -33,14 +34,11 @@ type DNSResolver struct {
|
||||
|
||||
// Root is the base options to configure the service
|
||||
type Root struct {
|
||||
OrgKey string `json:"org_key" yaml:"orgKey"`
|
||||
ConfigType string `json:"type"`
|
||||
LogDirectory string `json:"log_directory" yaml:"logDirectory,omitempty"`
|
||||
LogLevel string `json:"log_level" yaml:"logLevel"`
|
||||
CheckinInterval int `json:"checkin_interval" yaml:"checkinInterval"`
|
||||
Forwarders []Forwarder `json:"forwarders,omitempty"`
|
||||
Tunnels []Tunnel `json:"tunnels,omitempty"`
|
||||
Resolver DNSResolver `json:"resolver,omitempty"`
|
||||
LogDirectory string `json:"log_directory" yaml:"logDirectory,omitempty"`
|
||||
LogLevel string `json:"log_level" yaml:"logLevel,omitempty"`
|
||||
Forwarders []Forwarder `json:"forwarders,omitempty" yaml:"forwarders,omitempty"`
|
||||
Tunnels []Tunnel `json:"tunnels,omitempty" yaml:"tunnels,omitempty"`
|
||||
Resolver DNSResolver `json:"resolver,omitempty" yaml:"resolver,omitempty"`
|
||||
}
|
||||
|
||||
// Hash returns the computed values to see if the forwarder values change
|
||||
@@ -50,6 +48,7 @@ func (f *Forwarder) Hash() string {
|
||||
io.WriteString(h, f.Listener)
|
||||
io.WriteString(h, f.TokenClientID)
|
||||
io.WriteString(h, f.TokenSecret)
|
||||
io.WriteString(h, f.Destination)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/access"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/tunnel"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/updater"
|
||||
@@ -61,7 +62,7 @@ func main() {
|
||||
app := &cli.App{}
|
||||
app.Name = "cloudflared"
|
||||
app.Usage = "Cloudflare's command-line tool and agent"
|
||||
app.ArgsUsage = "origin-url"
|
||||
app.UsageText = "cloudflared [global options] [command] [command options]"
|
||||
app.Copyright = fmt.Sprintf(
|
||||
`(c) %d Cloudflare Inc.
|
||||
Your installation of cloudflared software constitutes a symbol of your signature indicating that you accept
|
||||
@@ -128,7 +129,7 @@ func action(version string, shutdownC, graceShutdownC chan struct{}) cli.ActionF
|
||||
tags := make(map[string]string)
|
||||
tags["hostname"] = c.String("hostname")
|
||||
raven.SetTagsContext(tags)
|
||||
raven.CapturePanic(func() { err = tunnel.StartServer(c, version, shutdownC, graceShutdownC) }, nil)
|
||||
raven.CapturePanic(func() { err = tunnel.StartServer(c, version, shutdownC, graceShutdownC, nil) }, nil)
|
||||
exitCode := 0
|
||||
if err != nil {
|
||||
handleError(err)
|
||||
@@ -165,16 +166,15 @@ func handleError(err error) {
|
||||
|
||||
// cloudflared was started without any flags
|
||||
func handleServiceMode(shutdownC chan struct{}) error {
|
||||
defer log.SharedWriteManager.Shutdown()
|
||||
logDirectory, logLevel := config.FindLogSettings()
|
||||
|
||||
logger, err := log.New(log.DefaultFile(logDirectory), log.LogLevelString(logLevel))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
return cliutil.PrintLoggerSetupError("error setting up logger", err)
|
||||
}
|
||||
logger.Infof("logging to directory: %s", logDirectory)
|
||||
|
||||
defer log.SharedWriteManager.Shutdown()
|
||||
|
||||
// start the main run loop that reads from the config file
|
||||
f, err := watcher.NewFile()
|
||||
if err != nil {
|
||||
@@ -182,12 +182,13 @@ func handleServiceMode(shutdownC chan struct{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
configPath := config.FindDefaultConfigPath()
|
||||
configPath := config.FindOrCreateConfigPath()
|
||||
configManager, err := config.NewFileManager(f, configPath, logger)
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot setup config file for monitoring: %s", err)
|
||||
return err
|
||||
}
|
||||
logger.Infof("monitoring config file at: %s", configPath)
|
||||
|
||||
serviceCallback := func(t string, name string, err error) {
|
||||
if err != nil {
|
||||
|
||||
@@ -127,8 +127,20 @@ func isTokenLocked(lockFilePath string) bool {
|
||||
return exists && err == nil
|
||||
}
|
||||
|
||||
// FetchTokenWithRedirect will either load a stored token or generate a new one
|
||||
// it appends a redirect URL to the access cli request if opening the browser
|
||||
func FetchTokenWithRedirect(appURL *url.URL, logger logger.Service) (string, error) {
|
||||
return getToken(appURL, true, logger)
|
||||
}
|
||||
|
||||
// FetchToken will either load a stored token or generate a new one
|
||||
// it doesn't append a redirect URL to the access cli request if opening the browser
|
||||
func FetchToken(appURL *url.URL, logger logger.Service) (string, error) {
|
||||
return getToken(appURL, false, logger)
|
||||
}
|
||||
|
||||
// getToken will either load a stored token or generate a new one
|
||||
func getToken(appURL *url.URL, shouldRedirect bool, logger logger.Service) (string, error) {
|
||||
if token, err := GetTokenIfExists(appURL); token != "" && err == nil {
|
||||
return token, nil
|
||||
}
|
||||
@@ -154,7 +166,7 @@ func FetchToken(appURL *url.URL, logger logger.Service) (string, error) {
|
||||
// this weird parameter is the resource name (token) and the key/value
|
||||
// we want to send to the transfer service. the key is token and the value
|
||||
// is blank (basically just the id generated in the transfer service)
|
||||
token, err := transfer.Run(appURL, keyName, keyName, "", path, true, logger)
|
||||
token, err := transfer.Run(appURL, keyName, keyName, "", path, true, shouldRedirect, logger)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ const (
|
||||
// The "dance" we refer to is building a HTTP request, opening that in a browser waiting for
|
||||
// the user to complete an action, while it long polls in the background waiting for an
|
||||
// action to be completed to download the resource.
|
||||
func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncrypt bool, logger logger.Service) ([]byte, error) {
|
||||
func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncrypt bool, shouldRedirect bool, logger logger.Service) ([]byte, error) {
|
||||
encrypterClient, err := encrypter.New("cloudflared_priv.pem", "cloudflared_pub.pem")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requestURL, err := buildRequestURL(transferURL, key, value+encrypterClient.PublicKey(), shouldEncrypt)
|
||||
requestURL, err := buildRequestURL(transferURL, key, value+encrypterClient.PublicKey(), shouldEncrypt, shouldRedirect)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func Run(transferURL *url.URL, resourceName, key, value, path string, shouldEncr
|
||||
// BuildRequestURL creates a request suitable for a resource transfer.
|
||||
// it will return a constructed url based off the base url and query key/value provided.
|
||||
// cli will build a url for cli transfer request.
|
||||
func buildRequestURL(baseURL *url.URL, key, value string, cli bool) (string, error) {
|
||||
func buildRequestURL(baseURL *url.URL, key, value string, cli, shouldRedirect bool) (string, error) {
|
||||
q := baseURL.Query()
|
||||
q.Set(key, value)
|
||||
baseURL.RawQuery = q.Encode()
|
||||
@@ -90,8 +90,10 @@ func buildRequestURL(baseURL *url.URL, key, value string, cli bool) (string, err
|
||||
return baseURL.String(), nil
|
||||
}
|
||||
|
||||
q.Set("redirect_url", baseURL.String()) // we add the token as a query param on both the redirect_url
|
||||
baseURL.RawQuery = q.Encode() // and this actual baseURL.
|
||||
if shouldRedirect {
|
||||
q.Set("redirect_url", baseURL.String()) // we add the token as a query param on both the redirect_url and the main url
|
||||
}
|
||||
baseURL.RawQuery = q.Encode() // and this actual baseURL.
|
||||
baseURL.Path = "cdn-cgi/access/cli"
|
||||
return baseURL.String(), nil
|
||||
}
|
||||
|
||||
@@ -172,6 +172,8 @@ func Commands() []*cli.Command {
|
||||
subcommands = append(subcommands, buildCreateCommand())
|
||||
subcommands = append(subcommands, buildListCommand())
|
||||
subcommands = append(subcommands, buildDeleteCommand())
|
||||
subcommands = append(subcommands, buildRunCommand())
|
||||
subcommands = append(subcommands, buildCleanupCommand())
|
||||
|
||||
cmds = append(cmds, &cli.Command{
|
||||
Name: "tunnel",
|
||||
@@ -206,7 +208,7 @@ func Commands() []*cli.Command {
|
||||
}
|
||||
|
||||
func tunnel(c *cli.Context) error {
|
||||
return StartServer(c, version, shutdownC, graceShutdownC)
|
||||
return StartServer(c, version, shutdownC, graceShutdownC, nil)
|
||||
}
|
||||
|
||||
func Init(v string, s, g chan struct{}) {
|
||||
@@ -215,7 +217,12 @@ func Init(v string, s, g chan struct{}) {
|
||||
|
||||
func createLogger(c *cli.Context, isTransport bool) (logger.Service, error) {
|
||||
loggerOpts := []logger.Option{}
|
||||
logPath := c.String(logDirectoryFlag)
|
||||
|
||||
logPath := c.String("logfile")
|
||||
if logPath == "" {
|
||||
logPath = c.String(logDirectoryFlag)
|
||||
}
|
||||
|
||||
if logPath != "" {
|
||||
loggerOpts = append(loggerOpts, logger.DefaultFile(logPath))
|
||||
}
|
||||
@@ -223,16 +230,19 @@ func createLogger(c *cli.Context, isTransport bool) (logger.Service, error) {
|
||||
logLevel := c.String("loglevel")
|
||||
if isTransport {
|
||||
logLevel = c.String("transport-loglevel")
|
||||
if logLevel == "" {
|
||||
logLevel = "fatal"
|
||||
}
|
||||
}
|
||||
loggerOpts = append(loggerOpts, logger.LogLevelString(logLevel))
|
||||
|
||||
return logger.New(loggerOpts...)
|
||||
}
|
||||
|
||||
func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan struct{}) error {
|
||||
func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan struct{}, namedTunnel *origin.NamedTunnelConfig) error {
|
||||
logger, err := createLogger(c, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
return cliutil.PrintLoggerSetupError("error setting up logger", err)
|
||||
}
|
||||
|
||||
_ = raven.SetDSN(sentryDSN)
|
||||
@@ -350,7 +360,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||
defer wg.Done()
|
||||
hello.StartHelloWorldServer(logger, helloListener, shutdownC)
|
||||
}()
|
||||
c.Set("url", "https://"+helloListener.Addr().String())
|
||||
forceSetFlag(c, "url", "https://"+helloListener.Addr().String())
|
||||
}
|
||||
|
||||
if c.IsSet(sshServerFlag) {
|
||||
@@ -400,7 +410,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||
close(shutdownC)
|
||||
}
|
||||
}()
|
||||
c.Set("url", "ssh://"+localServerAddress)
|
||||
forceSetFlag(c, "url", "ssh://"+localServerAddress)
|
||||
}
|
||||
|
||||
url := c.String("url")
|
||||
@@ -444,7 +454,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||
}
|
||||
errC <- websocket.StartProxyServer(logger, listener, staticHost, shutdownC, streamHandler)
|
||||
}()
|
||||
c.Set("url", "http://"+listener.Addr().String())
|
||||
forceSetFlag(c, "url", "http://"+listener.Addr().String())
|
||||
}
|
||||
|
||||
transportLogger, err := createLogger(c, true)
|
||||
@@ -452,7 +462,7 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||
return errors.Wrap(err, "error setting up transport logger")
|
||||
}
|
||||
|
||||
tunnelConfig, err := prepareTunnelConfig(c, buildInfo, version, logger, transportLogger)
|
||||
tunnelConfig, err := prepareTunnelConfig(c, buildInfo, version, logger, transportLogger, namedTunnel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -472,10 +482,19 @@ func StartServer(c *cli.Context, version string, shutdownC, graceShutdownC chan
|
||||
return waitToShutdown(&wg, errC, shutdownC, graceShutdownC, c.Duration("grace-period"), logger)
|
||||
}
|
||||
|
||||
// forceSetFlag attempts to set the given flag value in the closest context that has it defined
|
||||
func forceSetFlag(c *cli.Context, name, value string) {
|
||||
for _, ctx := range c.Lineage() {
|
||||
if err := ctx.Set(name, value); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Before(c *cli.Context) error {
|
||||
logger, err := createLogger(c, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
return cliutil.PrintLoggerSetupError("error setting up logger", err)
|
||||
}
|
||||
|
||||
if c.String("config") == "" {
|
||||
@@ -830,12 +849,17 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
|
||||
Hidden: shouldHide,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: logDirectoryFlag,
|
||||
Aliases: []string{"logfile"}, // This flag used to be called logfile when it was a single file
|
||||
Usage: "Save application log to this directory for reporting issues.",
|
||||
Name: "logfile",
|
||||
Usage: "Save application log to this file for reporting issues.",
|
||||
EnvVars: []string{"TUNNEL_LOGFILE"},
|
||||
Hidden: shouldHide,
|
||||
}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: logDirectoryFlag,
|
||||
Usage: "Save application log to this directory for reporting issues.",
|
||||
EnvVars: []string{"TUNNEL_LOGDIRECTORY"},
|
||||
Hidden: shouldHide,
|
||||
}),
|
||||
altsrc.NewIntFlag(&cli.IntFlag{
|
||||
Name: "ha-connections",
|
||||
Value: 4,
|
||||
@@ -955,13 +979,6 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
|
||||
EnvVars: []string{"TUNNEL_USE_RECONNECT_TOKEN"},
|
||||
Hidden: true,
|
||||
}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{
|
||||
Name: "use-quick-reconnects",
|
||||
Usage: "Test reestablishing connections with the new 'connection digest' flow.",
|
||||
Value: true,
|
||||
EnvVars: []string{"TUNNEL_USE_QUICK_RECONNECTS"},
|
||||
Hidden: true,
|
||||
}),
|
||||
altsrc.NewDurationFlag(&cli.DurationFlag{
|
||||
Name: "dial-edge-timeout",
|
||||
Usage: "Maximum wait time to set up a connection with the edge",
|
||||
@@ -1079,8 +1096,8 @@ func stdinControl(reconnectCh chan origin.ReconnectSignal, logger logger.Service
|
||||
logger.Infof("Unknown command: %s", command)
|
||||
fallthrough
|
||||
case "help":
|
||||
logger.Info(`Supported command:
|
||||
reconnect [delay]
|
||||
logger.Info(`Supported command:
|
||||
reconnect [delay]
|
||||
- restarts one randomly chosen connection with optional delay before reconnect`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,10 @@ func prepareTunnelConfig(
|
||||
version string,
|
||||
logger logger.Service,
|
||||
transportLogger logger.Service,
|
||||
namedTunnel *origin.NamedTunnelConfig,
|
||||
) (*origin.TunnelConfig, error) {
|
||||
compatibilityMode := namedTunnel == nil
|
||||
|
||||
hostname, err := validation.ValidateHostname(c.String("hostname"))
|
||||
if err != nil {
|
||||
logger.Errorf("Invalid hostname: %s", err)
|
||||
@@ -181,7 +184,7 @@ func prepareTunnelConfig(
|
||||
|
||||
tags = append(tags, tunnelpogs.Tag{Name: "ID", Value: clientID})
|
||||
|
||||
originURL, err := config.ValidateUrl(c)
|
||||
originURL, err := config.ValidateUrl(c, compatibilityMode)
|
||||
if err != nil {
|
||||
logger.Errorf("Error validating origin URL: %s", err)
|
||||
return nil, errors.Wrap(err, "Error validating origin URL")
|
||||
@@ -254,38 +257,52 @@ func prepareTunnelConfig(
|
||||
return nil, errors.Wrap(err, "unable to create TLS config to connect with edge")
|
||||
}
|
||||
|
||||
if namedTunnel != nil {
|
||||
clientUUID, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't generate clientUUID")
|
||||
}
|
||||
namedTunnel.Client = tunnelpogs.ClientInfo{
|
||||
ClientID: clientUUID[:],
|
||||
Features: []string{origin.FeatureSerializedHeaders},
|
||||
Version: version,
|
||||
Arch: fmt.Sprintf("%s_%s", buildInfo.GoOS, buildInfo.GoArch),
|
||||
}
|
||||
}
|
||||
|
||||
return &origin.TunnelConfig{
|
||||
BuildInfo: buildInfo,
|
||||
ClientID: clientID,
|
||||
ClientTlsConfig: httpTransport.TLSClientConfig,
|
||||
CompressionQuality: c.Uint64("compression-quality"),
|
||||
EdgeAddrs: c.StringSlice("edge"),
|
||||
GracePeriod: c.Duration("grace-period"),
|
||||
HAConnections: c.Int("ha-connections"),
|
||||
HTTPTransport: httpTransport,
|
||||
HeartbeatInterval: c.Duration("heartbeat-interval"),
|
||||
Hostname: hostname,
|
||||
HTTPHostHeader: c.String("http-host-header"),
|
||||
IncidentLookup: origin.NewIncidentLookup(),
|
||||
IsAutoupdated: c.Bool("is-autoupdated"),
|
||||
IsFreeTunnel: isFreeTunnel,
|
||||
LBPool: c.String("lb-pool"),
|
||||
Logger: logger,
|
||||
TransportLogger: transportLogger,
|
||||
MaxHeartbeats: c.Uint64("heartbeat-count"),
|
||||
Metrics: tunnelMetrics,
|
||||
MetricsUpdateFreq: c.Duration("metrics-update-freq"),
|
||||
NoChunkedEncoding: c.Bool("no-chunked-encoding"),
|
||||
OriginCert: originCert,
|
||||
OriginUrl: originURL,
|
||||
ReportedVersion: version,
|
||||
Retries: c.Uint("retries"),
|
||||
RunFromTerminal: isRunningFromTerminal(),
|
||||
Tags: tags,
|
||||
TlsConfig: toEdgeTLSConfig,
|
||||
UseDeclarativeTunnel: c.Bool("use-declarative-tunnels"),
|
||||
UseReconnectToken: c.Bool("use-reconnect-token"),
|
||||
UseQuickReconnects: c.Bool("use-quick-reconnects"),
|
||||
BuildInfo: buildInfo,
|
||||
ClientID: clientID,
|
||||
ClientTlsConfig: httpTransport.TLSClientConfig,
|
||||
CompressionQuality: c.Uint64("compression-quality"),
|
||||
EdgeAddrs: c.StringSlice("edge"),
|
||||
GracePeriod: c.Duration("grace-period"),
|
||||
HAConnections: c.Int("ha-connections"),
|
||||
HTTPTransport: httpTransport,
|
||||
HeartbeatInterval: c.Duration("heartbeat-interval"),
|
||||
Hostname: hostname,
|
||||
HTTPHostHeader: c.String("http-host-header"),
|
||||
IncidentLookup: origin.NewIncidentLookup(),
|
||||
IsAutoupdated: c.Bool("is-autoupdated"),
|
||||
IsFreeTunnel: isFreeTunnel,
|
||||
LBPool: c.String("lb-pool"),
|
||||
Logger: logger,
|
||||
TransportLogger: transportLogger,
|
||||
MaxHeartbeats: c.Uint64("heartbeat-count"),
|
||||
Metrics: tunnelMetrics,
|
||||
MetricsUpdateFreq: c.Duration("metrics-update-freq"),
|
||||
NoChunkedEncoding: c.Bool("no-chunked-encoding"),
|
||||
OriginCert: originCert,
|
||||
OriginUrl: originURL,
|
||||
ReportedVersion: version,
|
||||
Retries: c.Uint("retries"),
|
||||
RunFromTerminal: isRunningFromTerminal(),
|
||||
Tags: tags,
|
||||
TlsConfig: toEdgeTLSConfig,
|
||||
NamedTunnel: namedTunnel,
|
||||
ReplaceExisting: c.Bool("force"),
|
||||
// turn off use of reconnect token and auth refresh when using named tunnels
|
||||
UseReconnectToken: compatibilityMode && c.Bool("use-reconnect-token"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ func login(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = transfer.Run(loginURL, "cert", "callback", callbackStoreURL, path, false, logger)
|
||||
_, err = transfer.Run(loginURL, "cert", "callback", callbackStoreURL, path, false, true, logger)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write the certificate due to the following error:\n%v\n\nYour browser will download the certificate instead. You will have to manually\ncopy it to the following path:\n\n%s\n", err, path)
|
||||
return err
|
||||
|
||||
@@ -1,27 +1,60 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cloudflare/cloudflared/certutil"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/origin"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
"github.com/cloudflare/cloudflared/tunnelstore"
|
||||
)
|
||||
|
||||
const (
|
||||
credFileFlagAlias = "cred-file"
|
||||
)
|
||||
|
||||
var (
|
||||
showDeletedFlag = &cli.BoolFlag{
|
||||
Name: "show-deleted",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "Include deleted tunnels in the list",
|
||||
}
|
||||
outputFormatFlag = &cli.StringFlag{
|
||||
Name: "output",
|
||||
Aliases: []string{"o"},
|
||||
Usage: "Render output using given `FORMAT`. Valid options are 'json' or 'yaml'",
|
||||
}
|
||||
forceFlag = &cli.BoolFlag{
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "By default, if a tunnel is currently being run from a cloudflared, you can't " +
|
||||
"simultaneously rerun it again from a second cloudflared. The --force flag lets you " +
|
||||
"overwrite the previous tunnel. If you want to use a single hostname with multiple " +
|
||||
"tunnels, you can do so with Cloudflare's Load Balancer product.",
|
||||
}
|
||||
credentialsFileFlag = &cli.StringFlag{
|
||||
Name: "credentials-file",
|
||||
Aliases: []string{credFileFlagAlias},
|
||||
Usage: "File path of tunnel credentials",
|
||||
}
|
||||
)
|
||||
|
||||
const hideSubcommands = true
|
||||
@@ -37,6 +70,13 @@ func buildCreateCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// generateTunnelSecret as an array of 32 bytes using secure random number generator
|
||||
func generateTunnelSecret() ([]byte, error) {
|
||||
randomBytes := make([]byte, 32)
|
||||
_, err := rand.Read(randomBytes)
|
||||
return randomBytes, err
|
||||
}
|
||||
|
||||
func createTunnel(c *cli.Context) error {
|
||||
if c.NArg() != 1 {
|
||||
return cliutil.UsageError(`"cloudflared tunnel create" requires exactly 1 argument, the name of tunnel to create.`)
|
||||
@@ -48,16 +88,36 @@ func createTunnel(c *cli.Context) error {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
client, err := newTunnelstoreClient(c, logger)
|
||||
tunnelSecret, err := generateTunnelSecret()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tunnel, err := client.CreateTunnel(name)
|
||||
cert, originCertPath, err := getOriginCertFromContext(c, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := newTunnelstoreClient(c, cert, logger)
|
||||
|
||||
tunnel, err := client.CreateTunnel(name, tunnelSecret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error creating a new tunnel")
|
||||
}
|
||||
|
||||
if writeFileErr := writeTunnelCredentials(tunnel.ID, cert.AccountID, originCertPath, tunnelSecret, logger); err != nil {
|
||||
var errorLines []string
|
||||
errorLines = append(errorLines, fmt.Sprintf("Your tunnel '%v' was created with ID %v. However, cloudflared couldn't write to the tunnel credentials file at %v.json.", tunnel.Name, tunnel.ID, tunnel.ID))
|
||||
errorLines = append(errorLines, fmt.Sprintf("The file-writing error is: %v", writeFileErr))
|
||||
if deleteErr := client.DeleteTunnel(tunnel.ID); deleteErr != nil {
|
||||
errorLines = append(errorLines, fmt.Sprintf("Cloudflared tried to delete the tunnel for you, but encountered an error. You should use `cloudflared tunnel delete %v` to delete the tunnel yourself, because the tunnel can't be run without the tunnelfile.", tunnel.ID))
|
||||
errorLines = append(errorLines, fmt.Sprintf("The delete tunnel error is: %v", deleteErr))
|
||||
} else {
|
||||
errorLines = append(errorLines, fmt.Sprintf("The tunnel was deleted, because the tunnel can't be run without the tunnelfile"))
|
||||
}
|
||||
errorMsg := strings.Join(errorLines, "\n")
|
||||
return errors.New(errorMsg)
|
||||
}
|
||||
|
||||
if outputFormat := c.String(outputFormatFlag.Name); outputFormat != "" {
|
||||
return renderOutput(outputFormat, &tunnel)
|
||||
}
|
||||
@@ -66,6 +126,83 @@ func createTunnel(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tunnelFilePath(tunnelID, directory string) (string, error) {
|
||||
fileName := fmt.Sprintf("%v.json", tunnelID)
|
||||
filePath := filepath.Clean(fmt.Sprintf("%s/%s", directory, fileName))
|
||||
return homedir.Expand(filePath)
|
||||
}
|
||||
|
||||
func writeTunnelCredentials(tunnelID, accountID, originCertPath string, tunnelSecret []byte, logger logger.Service) error {
|
||||
originCertDir := filepath.Dir(originCertPath)
|
||||
filePath, err := tunnelFilePath(tunnelID, originCertDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := json.Marshal(pogs.TunnelAuth{
|
||||
AccountTag: accountID,
|
||||
TunnelSecret: tunnelSecret,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to marshal tunnel credentials to JSON")
|
||||
}
|
||||
logger.Infof("Writing tunnel credentials to %v. cloudflared chose this file based on where your origin certificate was found.", filePath)
|
||||
logger.Infof("Keep this file secret. To revoke these credentials, delete the tunnel.")
|
||||
return ioutil.WriteFile(filePath, body, 400)
|
||||
}
|
||||
|
||||
func readTunnelCredentials(c *cli.Context, tunnelID string, logger logger.Service) (*pogs.TunnelAuth, error) {
|
||||
filePath, err := tunnelCredentialsPath(c, tunnelID, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "couldn't read tunnel credentials from %v", filePath)
|
||||
}
|
||||
|
||||
var auth pogs.TunnelAuth
|
||||
if err = json.Unmarshal(body, &auth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &auth, nil
|
||||
}
|
||||
|
||||
func tunnelCredentialsPath(c *cli.Context, tunnelID string, logger logger.Service) (string, error) {
|
||||
if filePath := c.String("credentials-file"); filePath != "" {
|
||||
if validFilePath(filePath) {
|
||||
return filePath, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to look for tunnel credentials in the origin cert directory
|
||||
if originCertPath, err := findOriginCert(c, logger); err == nil {
|
||||
originCertDir := filepath.Dir(originCertPath)
|
||||
if filePath, err := tunnelFilePath(tunnelID, originCertDir); err == nil {
|
||||
if validFilePath(filePath) {
|
||||
return filePath, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort look under default config directories
|
||||
for _, configDir := range config.DefaultConfigDirs {
|
||||
if filePath, err := tunnelFilePath(tunnelID, configDir); err == nil {
|
||||
if validFilePath(filePath) {
|
||||
return filePath, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Tunnel credentials file not found")
|
||||
}
|
||||
|
||||
func validFilePath(path string) bool {
|
||||
fileStat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !fileStat.IsDir()
|
||||
}
|
||||
|
||||
func buildListCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "list",
|
||||
@@ -73,7 +210,7 @@ func buildListCommand() *cli.Command {
|
||||
Usage: "List existing tunnels",
|
||||
ArgsUsage: " ",
|
||||
Hidden: hideSubcommands,
|
||||
Flags: []cli.Flag{outputFormatFlag},
|
||||
Flags: []cli.Flag{outputFormatFlag, showDeletedFlag},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,25 +220,34 @@ func listTunnels(c *cli.Context) error {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
client, err := newTunnelstoreClient(c, logger)
|
||||
cert, _, err := getOriginCertFromContext(c, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := newTunnelstoreClient(c, cert, logger)
|
||||
|
||||
tunnels, err := client.ListTunnels()
|
||||
allTunnels, err := client.ListTunnels()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error listing tunnels")
|
||||
}
|
||||
|
||||
var tunnels []tunnelstore.Tunnel
|
||||
if c.Bool("show-deleted") {
|
||||
tunnels = allTunnels
|
||||
} else {
|
||||
for _, tunnel := range allTunnels {
|
||||
if tunnel.DeletedAt.IsZero() {
|
||||
tunnels = append(tunnels, tunnel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if outputFormat := c.String(outputFormatFlag.Name); outputFormat != "" {
|
||||
return renderOutput(outputFormat, tunnels)
|
||||
}
|
||||
|
||||
if len(tunnels) > 0 {
|
||||
const listFormat = "%-40s%-40s%s\n"
|
||||
fmt.Printf(listFormat, "ID", "NAME", "CREATED")
|
||||
for _, t := range tunnels {
|
||||
fmt.Printf(listFormat, t.ID, t.Name, t.CreatedAt.Format(time.RFC3339))
|
||||
}
|
||||
fmtAndPrintTunnelList(tunnels)
|
||||
} else {
|
||||
fmt.Println("You have no tunnels, use 'cloudflared tunnel create' to define a new tunnel")
|
||||
}
|
||||
@@ -109,6 +255,53 @@ func listTunnels(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func fmtAndPrintTunnelList(tunnels []tunnelstore.Tunnel) {
|
||||
const (
|
||||
minWidth = 0
|
||||
tabWidth = 8
|
||||
padding = 1
|
||||
padChar = ' '
|
||||
flags = 0
|
||||
)
|
||||
|
||||
writer := tabwriter.NewWriter(os.Stdout, minWidth, tabWidth, padding, padChar, flags)
|
||||
|
||||
// Print column headers with tabbed columns
|
||||
fmt.Fprintln(writer, "ID\tNAME\tCREATED\tCONNECTIONS\t")
|
||||
|
||||
// Loop through tunnels, create formatted string for each, and print using tabwriter
|
||||
for _, t := range tunnels {
|
||||
formattedStr := fmt.Sprintf("%s\t%s\t%s\t%s\t", t.ID, t.Name, t.CreatedAt.Format(time.RFC3339), fmtConnections(t.Connections))
|
||||
fmt.Fprintln(writer, formattedStr)
|
||||
}
|
||||
|
||||
// Write data buffered in tabwriter to output
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func fmtConnections(connections []tunnelstore.Connection) string {
|
||||
|
||||
// Count connections per colo
|
||||
numConnsPerColo := make(map[string]uint, len(connections))
|
||||
for _, connection := range connections {
|
||||
numConnsPerColo[connection.ColoName]++
|
||||
}
|
||||
|
||||
// Get sorted list of colos
|
||||
sortedColos := []string{}
|
||||
for coloName := range numConnsPerColo {
|
||||
sortedColos = append(sortedColos, coloName)
|
||||
}
|
||||
sort.Strings(sortedColos)
|
||||
|
||||
// Map each colo to its frequency, combine into output string.
|
||||
var output []string
|
||||
for _, coloName := range sortedColos {
|
||||
output = append(output, fmt.Sprintf("%dx%s", numConnsPerColo[coloName], coloName))
|
||||
}
|
||||
return strings.Join(output, ", ")
|
||||
}
|
||||
|
||||
func buildDeleteCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "delete",
|
||||
@@ -116,6 +309,7 @@ func buildDeleteCommand() *cli.Command {
|
||||
Usage: "Delete existing tunnel with given ID",
|
||||
ArgsUsage: "TUNNEL-ID",
|
||||
Hidden: hideSubcommands,
|
||||
Flags: []cli.Flag{credentialsFileFlag},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,15 +324,26 @@ func deleteTunnel(c *cli.Context) error {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
client, err := newTunnelstoreClient(c, logger)
|
||||
cert, _, err := getOriginCertFromContext(c, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := newTunnelstoreClient(c, cert, logger)
|
||||
|
||||
if err := client.DeleteTunnel(id); err != nil {
|
||||
return errors.Wrapf(err, "Error deleting tunnel %s", id)
|
||||
}
|
||||
|
||||
tunnelCredentialsPath, err := tunnelCredentialsPath(c, id, logger)
|
||||
if err != nil {
|
||||
logger.Infof("Cannot locate tunnel credentials to delete, error: %v. Please delete the file manually", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = os.Remove(tunnelCredentialsPath); err != nil {
|
||||
logger.Infof("Cannot delete tunnel credentials, error: %v. Please delete the file manually", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -155,27 +360,99 @@ func renderOutput(format string, v interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
func newTunnelstoreClient(c *cli.Context, logger logger.Service) (tunnelstore.Client, error) {
|
||||
originCertPath, err := findOriginCert(c, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error locating origin cert")
|
||||
}
|
||||
func newTunnelstoreClient(c *cli.Context, cert *certutil.OriginCert, logger logger.Service) tunnelstore.Client {
|
||||
client := tunnelstore.NewRESTClient(c.String("api-url"), cert.AccountID, cert.ServiceKey, logger)
|
||||
return client
|
||||
}
|
||||
|
||||
func getOriginCertFromContext(c *cli.Context, logger logger.Service) (cert *certutil.OriginCert, originCertPath string, err error) {
|
||||
originCertPath, err = findOriginCert(c, logger)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "Error locating origin cert")
|
||||
}
|
||||
blocks, err := readOriginCert(originCertPath, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Can't read origin cert from %s", originCertPath)
|
||||
return nil, "", errors.Wrapf(err, "Can't read origin cert from %s", originCertPath)
|
||||
}
|
||||
|
||||
cert, err := certutil.DecodeOriginCert(blocks)
|
||||
cert, err = certutil.DecodeOriginCert(blocks)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error decoding origin cert")
|
||||
return nil, "", errors.Wrap(err, "Error decoding origin cert")
|
||||
}
|
||||
|
||||
if cert.AccountID == "" {
|
||||
return nil, errors.Errorf(`Origin certificate needs to be refreshed before creating new tunnels.\nDelete %s and run "cloudflared login" to obtain a new cert.`, originCertPath)
|
||||
return nil, "", errors.Errorf(`Origin certificate needs to be refreshed before creating new tunnels.\nDelete %s and run "cloudflared login" to obtain a new cert.`, originCertPath)
|
||||
}
|
||||
return cert, originCertPath, nil
|
||||
}
|
||||
|
||||
func buildRunCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "run",
|
||||
Action: cliutil.ErrorHandler(runTunnel),
|
||||
Usage: "Proxy a local web server by running the given tunnel",
|
||||
ArgsUsage: "TUNNEL-ID",
|
||||
Hidden: hideSubcommands,
|
||||
Flags: []cli.Flag{forceFlag, credentialsFileFlag},
|
||||
}
|
||||
}
|
||||
|
||||
func runTunnel(c *cli.Context) error {
|
||||
if c.NArg() != 1 {
|
||||
return cliutil.UsageError(`"cloudflared tunnel run" requires exactly 1 argument, the ID of the tunnel to run.`)
|
||||
}
|
||||
id := c.Args().First()
|
||||
tunnelID, err := uuid.Parse(id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error parsing tunnel ID")
|
||||
}
|
||||
|
||||
client := tunnelstore.NewRESTClient(c.String("api-url"), cert.AccountID, cert.ServiceKey, logger)
|
||||
logger, err := logger.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
return client, nil
|
||||
credentials, err := readTunnelCredentials(c, id, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("Read credentials for %v", credentials.AccountTag)
|
||||
return StartServer(c, version, shutdownC, graceShutdownC, &origin.NamedTunnelConfig{Auth: *credentials, ID: tunnelID})
|
||||
}
|
||||
|
||||
func buildCleanupCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "cleanup",
|
||||
Action: cliutil.ErrorHandler(cleanupConnections),
|
||||
Usage: "Cleanup connections for the tunnel with given IDs",
|
||||
ArgsUsage: "TUNNEL-IDS",
|
||||
Hidden: hideSubcommands,
|
||||
}
|
||||
}
|
||||
|
||||
func cleanupConnections(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
return cliutil.UsageError(`"cloudflared tunnel cleanup" requires at least 1 argument, the IDs of the tunnels to cleanup connections.`)
|
||||
}
|
||||
|
||||
logger, err := logger.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
cert, _, err := getOriginCertFromContext(c, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := newTunnelstoreClient(c, cert, logger)
|
||||
|
||||
for i := 0; i < c.NArg(); i++ {
|
||||
id := c.Args().Get(i)
|
||||
logger.Infof("Cleanup connection for tunnel %s", id)
|
||||
if err := client.CleanupConnections(id); err != nil {
|
||||
logger.Errorf("Error cleaning up connections for tunnel %s, error :%v", id, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudflare/cloudflared/tunnelstore"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_fmtConnections(t *testing.T) {
|
||||
type args struct {
|
||||
connections []tunnelstore.Connection
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
args: args{
|
||||
connections: []tunnelstore.Connection{},
|
||||
},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "trivial",
|
||||
args: args{
|
||||
connections: []tunnelstore.Connection{
|
||||
{
|
||||
ColoName: "DFW",
|
||||
ID: uuid.MustParse("ea550130-57fd-4463-aab1-752822231ddd"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "1xDFW",
|
||||
},
|
||||
{
|
||||
name: "many colos",
|
||||
args: args{
|
||||
connections: []tunnelstore.Connection{
|
||||
{
|
||||
ColoName: "YRV",
|
||||
ID: uuid.MustParse("ea550130-57fd-4463-aab1-752822231ddd"),
|
||||
},
|
||||
{
|
||||
ColoName: "DFW",
|
||||
ID: uuid.MustParse("c13c0b3b-0fbf-453c-8169-a1990fced6d0"),
|
||||
},
|
||||
{
|
||||
ColoName: "ATL",
|
||||
ID: uuid.MustParse("70c90639-e386-4e8d-9a4e-7f046d70e63f"),
|
||||
},
|
||||
{
|
||||
ColoName: "DFW",
|
||||
ID: uuid.MustParse("30ad6251-0305-4635-a670-d3994f474981"),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "1xATL, 2xDFW, 1xYRV",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := fmtConnections(tt.args.connections); got != tt.want {
|
||||
t.Errorf("fmtConnections() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTunnelfilePath(t *testing.T) {
|
||||
originCertDir := filepath.Dir("~/.cloudflared/cert.pem")
|
||||
actual, err := tunnelFilePath("tunnel", originCertDir)
|
||||
assert.NoError(t, err)
|
||||
homeDir, err := homedir.Dir()
|
||||
assert.NoError(t, err)
|
||||
expected := fmt.Sprintf("%s/.cloudflared/tunnel.json", homeDir)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
@@ -4,12 +4,14 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/equinox-io/equinox"
|
||||
"github.com/facebookgo/grace/gracenet"
|
||||
@@ -17,10 +19,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultCheckUpdateFreq = time.Hour * 24
|
||||
appID = "app_idCzgxYerVD"
|
||||
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/"
|
||||
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
|
||||
DefaultCheckUpdateFreq = time.Hour * 24
|
||||
appID = "app_idCzgxYerVD"
|
||||
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/"
|
||||
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
|
||||
noUpdateManagedPackageMessage = "cloudflared will not automatically update if installed by a package manager."
|
||||
isManagedInstallFile = ".installedFromPackageManager"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -67,7 +71,7 @@ type UpdateOutcome struct {
|
||||
}
|
||||
|
||||
func (uo *UpdateOutcome) noUpdate() bool {
|
||||
return uo.Error != nil && uo.Updated == false
|
||||
return uo.Error == nil && uo.Updated == false
|
||||
}
|
||||
|
||||
func checkForUpdateAndApply() UpdateOutcome {
|
||||
@@ -98,6 +102,11 @@ func Update(_ *cli.Context) error {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
}
|
||||
|
||||
if wasInstalledFromPackageManager() {
|
||||
logger.Error("cloudflared was installed by a package manager. Please update using the same method.")
|
||||
return nil
|
||||
}
|
||||
|
||||
updateOutcome := loggedUpdate(logger)
|
||||
if updateOutcome.Error != nil {
|
||||
return &statusErr{updateOutcome.Error}
|
||||
@@ -217,6 +226,11 @@ func SupportAutoUpdate(logger logger.Service) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if wasInstalledFromPackageManager() {
|
||||
logger.Info(noUpdateManagedPackageMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
if isRunningFromTerminal() {
|
||||
logger.Info(noUpdateInShellMessage)
|
||||
return false
|
||||
@@ -224,6 +238,11 @@ func SupportAutoUpdate(logger logger.Service) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func wasInstalledFromPackageManager() bool {
|
||||
ok, _ := config.FileExists(filepath.Join(config.DefaultUnixConfigLocation, isManagedInstallFile))
|
||||
return ok
|
||||
}
|
||||
|
||||
func isRunningFromTerminal() bool {
|
||||
return terminal.IsTerminal(int(os.Stdout.Fd()))
|
||||
}
|
||||
|
||||
Executable
+128
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Creates Github Releases and uploads assets
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
|
||||
from github import Github, GithubException, UnknownObjectException
|
||||
|
||||
FORMAT = "%(levelname)s - %(asctime)s: %(message)s"
|
||||
logging.basicConfig(format=FORMAT)
|
||||
|
||||
CLOUDFLARED_REPO = os.environ.get("GITHUB_REPO", "cloudflare/cloudflared")
|
||||
GITHUB_CONFLICT_CODE = "already_exists"
|
||||
|
||||
|
||||
def assert_tag_exists(repo, version):
|
||||
""" Raise exception if repo does not contain a tag matching version """
|
||||
tags = repo.get_tags()
|
||||
if not tags or tags[0].name != version:
|
||||
raise Exception("Tag {} not found".format(version))
|
||||
|
||||
|
||||
def get_or_create_release(repo, version, dry_run=False):
|
||||
"""
|
||||
Get a Github Release matching the version tag or create a new one.
|
||||
If a conflict occurs on creation, attempt to fetch the Release on last time
|
||||
"""
|
||||
try:
|
||||
release = repo.get_release(version)
|
||||
logging.info("Release %s found", version)
|
||||
return release
|
||||
except UnknownObjectException:
|
||||
logging.info("Release %s not found", version)
|
||||
|
||||
# We dont want to create a new release tag if one doesnt already exist
|
||||
assert_tag_exists(repo, version)
|
||||
|
||||
if dry_run:
|
||||
logging.info("Skipping Release creation because of dry-run")
|
||||
return
|
||||
|
||||
try:
|
||||
logging.info("Creating release %s", version)
|
||||
return repo.create_git_release(version, version, "")
|
||||
except GithubException as e:
|
||||
errors = e.data.get("errors", [])
|
||||
if e.status == 422 and any(
|
||||
[err.get("code") == GITHUB_CONFLICT_CODE for err in errors]
|
||||
):
|
||||
logging.warning(
|
||||
"Conflict: Release was likely just made by a different build: %s",
|
||||
e.data,
|
||||
)
|
||||
return repo.get_release(version)
|
||||
raise e
|
||||
|
||||
|
||||
def parse_args():
|
||||
""" Parse and validate args """
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Creates Github Releases and uploads assets."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--api-key", default=os.environ.get("API_KEY"), help="Github API key"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--release-version",
|
||||
metavar="version",
|
||||
default=os.environ.get("VERSION"),
|
||||
help="Release version",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--path", default=os.environ.get("ASSET_PATH"), help="Asset path"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--name", default=os.environ.get("ASSET_NAME"), help="Asset Name"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run", action="store_true", help="Do not create release or upload asset"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
is_valid = True
|
||||
if not args.release_version:
|
||||
logging.error("Missing release version")
|
||||
is_valid = False
|
||||
|
||||
if not args.path:
|
||||
logging.error("Missing asset path")
|
||||
is_valid = False
|
||||
|
||||
if not args.name:
|
||||
logging.error("Missing asset name")
|
||||
is_valid = False
|
||||
|
||||
if not args.api_key:
|
||||
logging.error("Missing API key")
|
||||
is_valid = False
|
||||
|
||||
if is_valid:
|
||||
return args
|
||||
|
||||
parser.print_usage()
|
||||
exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
""" Attempts to upload Asset to Github Release. Creates Release if it doesnt exist """
|
||||
try:
|
||||
args = parse_args()
|
||||
client = Github(args.api_key)
|
||||
repo = client.get_repo(CLOUDFLARED_REPO)
|
||||
release = get_or_create_release(repo, args.release_version, args.dry_run)
|
||||
|
||||
if args.dry_run:
|
||||
logging.info("Skipping asset upload because of dry-run")
|
||||
return
|
||||
|
||||
release.upload_asset(args.path, name=args.name)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
exit(1)
|
||||
|
||||
|
||||
main()
|
||||
@@ -54,15 +54,14 @@ require (
|
||||
github.com/prometheus/common v0.7.0 // indirect
|
||||
github.com/prometheus/procfs v0.0.5 // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/tinylib/msgp v1.1.0 // indirect
|
||||
github.com/xo/dburl v0.0.0-20191005012637-293c3298d6c0
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
||||
google.golang.org/appengine v1.5.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd // indirect
|
||||
google.golang.org/grpc v1.24.0 // indirect
|
||||
|
||||
@@ -204,6 +204,10 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@@ -222,6 +226,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
@@ -243,6 +249,9 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9Y
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2 h1:nq114VpM8lsSlP+lyUbANecYHYiFcSNFtqcBlxRV+gA=
|
||||
golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ func (w *MuxWriter) writeStreamData(stream *MuxedStream, logger logger.Service)
|
||||
}
|
||||
// update the amount of data wrote
|
||||
w.bytesWrote.IncrementBy(uint64(len(payload)))
|
||||
logger.Errorf("mux - write: output data: %d: streamID: %d", len(payload), stream.streamID)
|
||||
logger.Debugf("mux - write: output data: %d: streamID: %d", len(payload), stream.streamID)
|
||||
|
||||
if sentEOF {
|
||||
if stream.readBuffer.Closed() {
|
||||
|
||||
+5
-14
@@ -114,21 +114,12 @@ func New(opts ...Option) (Service, error) {
|
||||
}
|
||||
|
||||
if !config.terminalOutputDisabled {
|
||||
terminalFormatter := NewTerminalFormatter(time.RFC3339)
|
||||
|
||||
if len(config.supportedTerminalLevels) == 0 {
|
||||
l.Add(os.Stdout, NewTerminalFormatter(""), InfoLevel)
|
||||
l.Add(os.Stderr, NewTerminalFormatter(""), ErrorLevel, FatalLevel)
|
||||
l.Add(os.Stderr, terminalFormatter, InfoLevel, ErrorLevel, FatalLevel)
|
||||
} else {
|
||||
errLevels := []Level{}
|
||||
outLevels := []Level{}
|
||||
for _, level := range config.supportedTerminalLevels {
|
||||
if level == ErrorLevel || level == FatalLevel {
|
||||
errLevels = append(errLevels, level)
|
||||
} else {
|
||||
outLevels = append(outLevels, level)
|
||||
}
|
||||
}
|
||||
l.Add(os.Stdout, NewTerminalFormatter(""), outLevels...)
|
||||
l.Add(os.Stderr, NewTerminalFormatter(""), errLevels...)
|
||||
l.Add(os.Stderr, terminalFormatter, config.supportedTerminalLevels...)
|
||||
}
|
||||
}
|
||||
return l, nil
|
||||
@@ -141,7 +132,7 @@ func ParseLevelString(lvl string) ([]Level, error) {
|
||||
return []Level{FatalLevel}, nil
|
||||
case "error":
|
||||
return []Level{FatalLevel, ErrorLevel}, nil
|
||||
case "info":
|
||||
case "info", "warn":
|
||||
return []Level{FatalLevel, ErrorLevel, InfoLevel}, nil
|
||||
case "debug":
|
||||
return []Level{FatalLevel, ErrorLevel, InfoLevel, DebugLevel}, nil
|
||||
|
||||
+25
-5
@@ -33,7 +33,7 @@ func NewFileRollingWriter(directory, baseFileName string, maxFileSize int64, max
|
||||
// Write is an implementation of io.writer the rolls the file once it reaches its max size
|
||||
// It is expected the caller to Write is doing so in a thread safe manner (as WriteManager does).
|
||||
func (w *FileRollingWriter) Write(p []byte) (n int, err error) {
|
||||
logFile := buildPath(w.directory, w.baseFileName)
|
||||
logFile, isSingleFile := buildPath(w.directory, w.baseFileName)
|
||||
if w.fileHandle == nil {
|
||||
h, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664)
|
||||
if err != nil {
|
||||
@@ -55,7 +55,7 @@ func (w *FileRollingWriter) Write(p []byte) (n int, err error) {
|
||||
written, err := w.fileHandle.Write(p)
|
||||
|
||||
// check if the file needs to be rolled
|
||||
if err == nil && info.Size()+int64(written) > w.maxFileSize {
|
||||
if err == nil && info.Size()+int64(written) > w.maxFileSize && !isSingleFile {
|
||||
// close the file handle than do the renaming. A new one will be opened on the next write
|
||||
w.Close()
|
||||
w.rename(logFile, 1)
|
||||
@@ -77,7 +77,10 @@ func (w *FileRollingWriter) Close() {
|
||||
// but if cloudflared-1.log already exists, it is renamed to cloudflared-2.log,
|
||||
// then the other files move in to their postion
|
||||
func (w *FileRollingWriter) rename(sourcePath string, index uint) {
|
||||
destinationPath := buildPath(w.directory, fmt.Sprintf("%s-%d", w.baseFileName, index))
|
||||
destinationPath, isSingleFile := buildPath(w.directory, fmt.Sprintf("%s-%d", w.baseFileName, index))
|
||||
if isSingleFile {
|
||||
return //don't need to rename anything, it is a single file
|
||||
}
|
||||
|
||||
// rolled to the max amount of files allowed on disk
|
||||
if index >= w.maxFileCount {
|
||||
@@ -93,8 +96,13 @@ func (w *FileRollingWriter) rename(sourcePath string, index uint) {
|
||||
os.Rename(sourcePath, destinationPath)
|
||||
}
|
||||
|
||||
func buildPath(directory, fileName string) string {
|
||||
return filepath.Join(directory, fileName+".log")
|
||||
// return the path to the log file and if it is a single file or not.
|
||||
// true means a single file. false means a rolled file
|
||||
func buildPath(directory, fileName string) (string, bool) {
|
||||
if !isDirectory(directory) { // not a directory, so try and treat it as a single file for backwards compatibility sake
|
||||
return directory, true
|
||||
}
|
||||
return filepath.Join(directory, fileName+".log"), false
|
||||
}
|
||||
|
||||
func exists(filePath string) bool {
|
||||
@@ -103,3 +111,15 @@ func exists(filePath string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isDirectory(path string) bool {
|
||||
if path == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fileInfo.IsDir()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -31,18 +32,23 @@ func TestFileWrite(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRolling(t *testing.T) {
|
||||
dirName := "testdir"
|
||||
err := os.Mkdir(dirName, 0755)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fileName := "test_file"
|
||||
firstFile := fileName + ".log"
|
||||
secondFile := fileName + "-1.log"
|
||||
thirdFile := fileName + "-2.log"
|
||||
firstFile := filepath.Join(dirName, fileName+".log")
|
||||
secondFile := filepath.Join(dirName, fileName+"-1.log")
|
||||
thirdFile := filepath.Join(dirName, fileName+"-2.log")
|
||||
|
||||
defer func() {
|
||||
os.RemoveAll(dirName)
|
||||
os.Remove(firstFile)
|
||||
os.Remove(secondFile)
|
||||
os.Remove(thirdFile)
|
||||
}()
|
||||
|
||||
w := NewFileRollingWriter("", fileName, 1000, 2)
|
||||
w := NewFileRollingWriter(dirName, fileName, 1000, 2)
|
||||
defer w.Close()
|
||||
|
||||
for i := 99; i >= 1; i-- {
|
||||
@@ -52,5 +58,51 @@ func TestRolling(t *testing.T) {
|
||||
assert.FileExists(t, firstFile, "first file doesn't exist as expected")
|
||||
assert.FileExists(t, secondFile, "second file doesn't exist as expected")
|
||||
assert.FileExists(t, thirdFile, "third file doesn't exist as expected")
|
||||
assert.False(t, exists(fileName+"-3.log"), "limited to two files and there is more")
|
||||
assert.False(t, exists(filepath.Join(dirName, fileName+"-3.log")), "limited to two files and there is more")
|
||||
}
|
||||
|
||||
func TestSingleFile(t *testing.T) {
|
||||
fileName := "test_file"
|
||||
testData := []byte(string("hello Dalton, how are you doing?"))
|
||||
defer func() {
|
||||
os.Remove(fileName)
|
||||
}()
|
||||
|
||||
w := NewFileRollingWriter(fileName, fileName, 1000, 2)
|
||||
defer w.Close()
|
||||
|
||||
l, err := w.Write(testData)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, l, len(testData), "expected write length and data length to match")
|
||||
|
||||
d, err := ioutil.ReadFile(fileName)
|
||||
assert.FileExists(t, fileName, "file doesn't exist at expected path")
|
||||
assert.Equal(t, d, testData, "expected data in file to match test data")
|
||||
}
|
||||
|
||||
func TestSingleFileInDirectory(t *testing.T) {
|
||||
dirName := "testdir"
|
||||
err := os.Mkdir(dirName, 0755)
|
||||
assert.NoError(t, err)
|
||||
|
||||
fileName := "test_file"
|
||||
fullPath := filepath.Join(dirName, fileName+".log")
|
||||
testData := []byte(string("hello Dalton, how are you doing?"))
|
||||
defer func() {
|
||||
os.Remove(fullPath)
|
||||
os.RemoveAll(dirName)
|
||||
}()
|
||||
|
||||
w := NewFileRollingWriter(fullPath, fileName, 1000, 2)
|
||||
defer w.Close()
|
||||
|
||||
l, err := w.Write(testData)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, l, len(testData), "expected write length and data length to match")
|
||||
|
||||
d, err := ioutil.ReadFile(fullPath)
|
||||
assert.FileExists(t, fullPath, "file doesn't exist at expected path")
|
||||
assert.Equal(t, d, testData, "expected data in file to match test data")
|
||||
}
|
||||
|
||||
+19
-7
@@ -2,6 +2,7 @@ package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/acmacalister/skittles"
|
||||
@@ -58,34 +59,45 @@ func (f *DefaultFormatter) Content(l Level, c string) string {
|
||||
|
||||
// TerminalFormatter is setup for colored output
|
||||
type TerminalFormatter struct {
|
||||
format string
|
||||
format string
|
||||
supportsColor bool
|
||||
}
|
||||
|
||||
// NewTerminalFormatter creates a Terminal formatter for colored output
|
||||
// format is the time format to use for timestamp formatting
|
||||
func NewTerminalFormatter(format string) Formatter {
|
||||
supportsColor := (runtime.GOOS != "windows")
|
||||
return &TerminalFormatter{
|
||||
format: format,
|
||||
format: format,
|
||||
supportsColor: supportsColor,
|
||||
}
|
||||
}
|
||||
|
||||
// Timestamp returns the log level with a matching color to the log type
|
||||
func (f *TerminalFormatter) Timestamp(l Level, d time.Time) string {
|
||||
t := ""
|
||||
dateStr := "[" + d.Format(f.format) + "] "
|
||||
switch l {
|
||||
case InfoLevel:
|
||||
t = skittles.Cyan("[INFO] ")
|
||||
t = f.output("INFO", skittles.Cyan)
|
||||
case ErrorLevel:
|
||||
t = skittles.Red("[ERROR] ")
|
||||
t = f.output("ERROR", skittles.Red)
|
||||
case DebugLevel:
|
||||
t = skittles.Yellow("[DEBUG] ")
|
||||
t = f.output("DEBUG", skittles.Yellow)
|
||||
case FatalLevel:
|
||||
t = skittles.Red("[FATAL] ")
|
||||
t = f.output("FATAL", skittles.Red)
|
||||
}
|
||||
return t
|
||||
return t + dateStr
|
||||
}
|
||||
|
||||
// Content just writes the log line straight to the sources
|
||||
func (f *TerminalFormatter) Content(l Level, c string) string {
|
||||
return c
|
||||
}
|
||||
|
||||
func (f *TerminalFormatter) output(msg string, colorFunc func(interface{}) string) string {
|
||||
if f.supportsColor {
|
||||
return colorFunc(msg)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
TARGET_DIRECTORY=".build"
|
||||
BINARY_NAME="cloudflared"
|
||||
VERSION=$(git describe --tags --always --dirty="-dev")
|
||||
PRODUCT="cloudflared"
|
||||
|
||||
|
||||
echo "building cloudflared"
|
||||
make cloudflared
|
||||
|
||||
echo "creating build directory"
|
||||
mkdir ${TARGET_DIRECTORY}
|
||||
mkdir ${TARGET_DIRECTORY}/contents
|
||||
cp -r .mac_resources/scripts ${TARGET_DIRECTORY}/scripts
|
||||
|
||||
echo "move cloudflared into the build directory"
|
||||
mv $BINARY_NAME {$TARGET_DIRECTORY}/contents/${PRODUCT}
|
||||
|
||||
echo "build the installer package"
|
||||
pkgbuild --identifier com.cloudflare.${PRODUCT} \
|
||||
--version ${VERSION} \
|
||||
--scripts ${TARGET_DIRECTORY}/scripts \
|
||||
--root ${TARGET_DIRECTORY}/contents \
|
||||
--install-location /usr/local/bin \
|
||||
${PRODUCT}.pkg
|
||||
# TODO: our iOS/Mac account doesn't have this installer certificate type.
|
||||
# need to find how we can get it --sign "Developer ID Installer: Cloudflare" \
|
||||
|
||||
echo "cleaning up the build directory"
|
||||
rm -rf $TARGET_DIRECTORY
|
||||
@@ -80,7 +80,7 @@ type tunnelError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func NewSupervisor(config *TunnelConfig, u uuid.UUID) (*Supervisor, error) {
|
||||
func NewSupervisor(config *TunnelConfig, cloudflaredUUID uuid.UUID) (*Supervisor, error) {
|
||||
var (
|
||||
edgeIPs *edgediscovery.Edge
|
||||
err error
|
||||
@@ -93,8 +93,9 @@ func NewSupervisor(config *TunnelConfig, u uuid.UUID) (*Supervisor, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Supervisor{
|
||||
cloudflaredUUID: u,
|
||||
cloudflaredUUID: cloudflaredUUID,
|
||||
config: config,
|
||||
edgeIPs: edgeIPs,
|
||||
tunnelErrors: make(chan tunnelError),
|
||||
@@ -226,17 +227,17 @@ func (s *Supervisor) startFirstTunnel(ctx context.Context, connectedSignal *sign
|
||||
addr *net.TCPAddr
|
||||
err error
|
||||
)
|
||||
const thisConnID = 0
|
||||
const firstConnIndex = 0
|
||||
defer func() {
|
||||
s.tunnelErrors <- tunnelError{index: thisConnID, addr: addr, err: err}
|
||||
s.tunnelErrors <- tunnelError{index: firstConnIndex, addr: addr, err: err}
|
||||
}()
|
||||
|
||||
addr, err = s.edgeIPs.GetAddr(thisConnID)
|
||||
addr, err = s.edgeIPs.GetAddr(firstConnIndex)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ServeTunnelLoop(ctx, s, s.config, addr, thisConnID, connectedSignal, s.cloudflaredUUID, s.bufferPool, reconnectCh)
|
||||
err = ServeTunnelLoop(ctx, s, s.config, addr, firstConnIndex, connectedSignal, s.cloudflaredUUID, s.bufferPool, reconnectCh)
|
||||
// If the first tunnel disconnects, keep restarting it.
|
||||
edgeErrors := 0
|
||||
for s.unusedIPs() {
|
||||
@@ -254,12 +255,12 @@ func (s *Supervisor) startFirstTunnel(ctx context.Context, connectedSignal *sign
|
||||
return
|
||||
}
|
||||
if edgeErrors >= 2 {
|
||||
addr, err = s.edgeIPs.GetDifferentAddr(thisConnID)
|
||||
addr, err = s.edgeIPs.GetDifferentAddr(firstConnIndex)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = ServeTunnelLoop(ctx, s, s.config, addr, thisConnID, connectedSignal, s.cloudflaredUUID, s.bufferPool, reconnectCh)
|
||||
err = ServeTunnelLoop(ctx, s, s.config, addr, firstConnIndex, connectedSignal, s.cloudflaredUUID, s.bufferPool, reconnectCh)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+175
-84
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/signal"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
|
||||
"github.com/cloudflare/cloudflared/validation"
|
||||
"github.com/cloudflare/cloudflared/websocket"
|
||||
@@ -47,47 +48,46 @@ type registerRPCName string
|
||||
const (
|
||||
register registerRPCName = "register"
|
||||
reconnect registerRPCName = "reconnect"
|
||||
unknown registerRPCName = "unknown"
|
||||
)
|
||||
|
||||
type TunnelConfig struct {
|
||||
BuildInfo *buildinfo.BuildInfo
|
||||
ClientID string
|
||||
ClientTlsConfig *tls.Config
|
||||
CloseConnOnce *sync.Once // Used to close connectedSignal no more than once
|
||||
CompressionQuality uint64
|
||||
EdgeAddrs []string
|
||||
GracePeriod time.Duration
|
||||
HAConnections int
|
||||
HTTPTransport http.RoundTripper
|
||||
HeartbeatInterval time.Duration
|
||||
Hostname string
|
||||
HTTPHostHeader string
|
||||
IncidentLookup IncidentLookup
|
||||
IsAutoupdated bool
|
||||
IsFreeTunnel bool
|
||||
LBPool string
|
||||
Logger logger.Service
|
||||
TransportLogger logger.Service
|
||||
MaxHeartbeats uint64
|
||||
Metrics *TunnelMetrics
|
||||
MetricsUpdateFreq time.Duration
|
||||
NoChunkedEncoding bool
|
||||
OriginCert []byte
|
||||
ReportedVersion string
|
||||
Retries uint
|
||||
RunFromTerminal bool
|
||||
Tags []tunnelpogs.Tag
|
||||
TlsConfig *tls.Config
|
||||
UseDeclarativeTunnel bool
|
||||
WSGI bool
|
||||
BuildInfo *buildinfo.BuildInfo
|
||||
ClientID string
|
||||
ClientTlsConfig *tls.Config
|
||||
CloseConnOnce *sync.Once // Used to close connectedSignal no more than once
|
||||
CompressionQuality uint64
|
||||
EdgeAddrs []string
|
||||
GracePeriod time.Duration
|
||||
HAConnections int
|
||||
HTTPTransport http.RoundTripper
|
||||
HeartbeatInterval time.Duration
|
||||
Hostname string
|
||||
HTTPHostHeader string
|
||||
IncidentLookup IncidentLookup
|
||||
IsAutoupdated bool
|
||||
IsFreeTunnel bool
|
||||
LBPool string
|
||||
Logger logger.Service
|
||||
TransportLogger logger.Service
|
||||
MaxHeartbeats uint64
|
||||
Metrics *TunnelMetrics
|
||||
MetricsUpdateFreq time.Duration
|
||||
NoChunkedEncoding bool
|
||||
OriginCert []byte
|
||||
ReportedVersion string
|
||||
Retries uint
|
||||
RunFromTerminal bool
|
||||
Tags []tunnelpogs.Tag
|
||||
TlsConfig *tls.Config
|
||||
WSGI bool
|
||||
// OriginUrl may not be used if a user specifies a unix socket.
|
||||
OriginUrl string
|
||||
|
||||
// feature-flag to use new edge reconnect tokens
|
||||
UseReconnectToken bool
|
||||
// feature-flag for using ConnectionDigest
|
||||
UseQuickReconnects bool
|
||||
|
||||
NamedTunnel *NamedTunnelConfig
|
||||
ReplaceExisting bool
|
||||
}
|
||||
|
||||
// ReconnectTunnelCredentialManager is invoked by functions in this file to
|
||||
@@ -102,8 +102,10 @@ type ReconnectTunnelCredentialManager interface {
|
||||
|
||||
type dupConnRegisterTunnelError struct{}
|
||||
|
||||
var errDuplicationConnection = &dupConnRegisterTunnelError{}
|
||||
|
||||
func (e dupConnRegisterTunnelError) Error() string {
|
||||
return "already connected to this server"
|
||||
return "already connected to this server, trying another address"
|
||||
}
|
||||
|
||||
type muxerShutdownError struct{}
|
||||
@@ -170,12 +172,31 @@ func (c *TunnelConfig) RegistrationOptions(connectionID uint8, OriginLocalIP str
|
||||
}
|
||||
}
|
||||
|
||||
func (c *TunnelConfig) SupportedFeatures() []string {
|
||||
basic := []string{FeatureSerializedHeaders}
|
||||
if c.UseQuickReconnects {
|
||||
basic = append(basic, FeatureQuickReconnects)
|
||||
func (c *TunnelConfig) ConnectionOptions(originLocalAddr string) *tunnelpogs.ConnectionOptions {
|
||||
// attempt to parse out origin IP, but don't fail since it's informational field
|
||||
host, _, _ := net.SplitHostPort(originLocalAddr)
|
||||
originIP := net.ParseIP(host)
|
||||
|
||||
return &tunnelpogs.ConnectionOptions{
|
||||
Client: c.NamedTunnel.Client,
|
||||
OriginLocalIP: originIP,
|
||||
ReplaceExisting: c.ReplaceExisting,
|
||||
CompressionQuality: uint8(c.CompressionQuality),
|
||||
}
|
||||
return basic
|
||||
}
|
||||
|
||||
func (c *TunnelConfig) SupportedFeatures() []string {
|
||||
features := []string{FeatureSerializedHeaders}
|
||||
if c.NamedTunnel == nil {
|
||||
features = append(features, FeatureQuickReconnects)
|
||||
}
|
||||
return features
|
||||
}
|
||||
|
||||
type NamedTunnelConfig struct {
|
||||
Auth pogs.TunnelAuth
|
||||
ID uuid.UUID
|
||||
Client pogs.ClientInfo
|
||||
}
|
||||
|
||||
func StartTunnelDaemon(ctx context.Context, config *TunnelConfig, connectedSignal *signal.Signal, cloudflaredID uuid.UUID, reconnectCh chan ReconnectSignal) error {
|
||||
@@ -190,9 +211,9 @@ func ServeTunnelLoop(ctx context.Context,
|
||||
credentialManager ReconnectTunnelCredentialManager,
|
||||
config *TunnelConfig,
|
||||
addr *net.TCPAddr,
|
||||
connectionID uint8,
|
||||
connectionIndex uint8,
|
||||
connectedSignal *signal.Signal,
|
||||
u uuid.UUID,
|
||||
cloudflaredUUID uuid.UUID,
|
||||
bufferPool *buffer.Pool,
|
||||
reconnectCh chan ReconnectSignal,
|
||||
) error {
|
||||
@@ -213,16 +234,16 @@ func ServeTunnelLoop(ctx context.Context,
|
||||
credentialManager,
|
||||
config,
|
||||
config.Logger,
|
||||
addr, connectionID,
|
||||
addr, connectionIndex,
|
||||
connectedFuse,
|
||||
&backoff,
|
||||
u,
|
||||
cloudflaredUUID,
|
||||
bufferPool,
|
||||
reconnectCh,
|
||||
)
|
||||
if recoverable {
|
||||
if duration, ok := backoff.GetBackoffDuration(ctx); ok {
|
||||
config.Logger.Infof("Retrying in %s seconds: connectionID: %d", duration, connectionID)
|
||||
config.Logger.Infof("Retrying connection %d in %s seconds", connectionIndex, duration)
|
||||
backoff.Backoff(ctx)
|
||||
continue
|
||||
}
|
||||
@@ -237,10 +258,10 @@ func ServeTunnel(
|
||||
config *TunnelConfig,
|
||||
logger logger.Service,
|
||||
addr *net.TCPAddr,
|
||||
connectionID uint8,
|
||||
connectionIndex uint8,
|
||||
connectedFuse *h2mux.BooleanFuse,
|
||||
backoff *BackoffHandler,
|
||||
u uuid.UUID,
|
||||
cloudflaredUUID uuid.UUID,
|
||||
bufferPool *buffer.Pool,
|
||||
reconnectCh chan ReconnectSignal,
|
||||
) (err error, recoverable bool) {
|
||||
@@ -256,22 +277,18 @@ func ServeTunnel(
|
||||
}
|
||||
}()
|
||||
|
||||
connectionTag := uint8ToString(connectionID)
|
||||
|
||||
// additional tags to send other than hostname which is set in cloudflared main package
|
||||
tags := make(map[string]string)
|
||||
tags["ha"] = connectionTag
|
||||
connectionTag := uint8ToString(connectionIndex)
|
||||
|
||||
// Returns error from parsing the origin URL or handshake errors
|
||||
handler, originLocalIP, err := NewTunnelHandler(ctx, config, addr, connectionID, bufferPool)
|
||||
handler, originLocalAddr, err := NewTunnelHandler(ctx, config, addr, connectionIndex, bufferPool)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case connection.DialError:
|
||||
logger.Errorf("Unable to dial edge: %s connectionID: %d", err, connectionID)
|
||||
logger.Errorf("Connection %d unable to dial edge: %s", connectionIndex, err)
|
||||
case h2mux.MuxerHandshakeError:
|
||||
logger.Errorf("Handshake failed with edge server: %s connectionID: %d", err, connectionID)
|
||||
logger.Errorf("Connection %d handshake with edge server failed: %s", connectionIndex, err)
|
||||
default:
|
||||
logger.Errorf("Tunnel creation failure: %s connectionID: %d", err, connectionID)
|
||||
logger.Errorf("Connection %d failed: %s", connectionIndex, err)
|
||||
return err, false
|
||||
}
|
||||
return err, true
|
||||
@@ -287,20 +304,21 @@ func ServeTunnel(
|
||||
}
|
||||
}()
|
||||
|
||||
if config.NamedTunnel != nil {
|
||||
return RegisterConnection(ctx, handler.muxer, config, connectionIndex, originLocalAddr)
|
||||
}
|
||||
|
||||
if config.UseReconnectToken && connectedFuse.Value() {
|
||||
token, tokenErr := credentialManager.ReconnectToken()
|
||||
eventDigest, eventDigestErr := credentialManager.EventDigest()
|
||||
// if we have both credentials, we can reconnect
|
||||
if tokenErr == nil && eventDigestErr == nil {
|
||||
var connDigest []byte
|
||||
|
||||
// check if we can use Quick Reconnects
|
||||
if config.UseQuickReconnects {
|
||||
if digest, connDigestErr := credentialManager.ConnDigest(connectionID); connDigestErr == nil {
|
||||
connDigest = digest
|
||||
}
|
||||
if digest, connDigestErr := credentialManager.ConnDigest(connectionIndex); connDigestErr == nil {
|
||||
connDigest = digest
|
||||
}
|
||||
return ReconnectTunnel(serveCtx, token, eventDigest, connDigest, handler.muxer, config, logger, connectionID, originLocalIP, u, credentialManager)
|
||||
|
||||
return ReconnectTunnel(serveCtx, token, eventDigest, connDigest, handler.muxer, config, logger, connectionIndex, originLocalAddr, cloudflaredUUID, credentialManager)
|
||||
}
|
||||
// log errors and proceed to RegisterTunnel
|
||||
if tokenErr != nil {
|
||||
@@ -310,7 +328,7 @@ func ServeTunnel(
|
||||
logger.Errorf("Couldn't get event digest: %s", eventDigestErr)
|
||||
}
|
||||
}
|
||||
return RegisterTunnel(serveCtx, credentialManager, handler.muxer, config, logger, connectionID, originLocalIP, u)
|
||||
return RegisterTunnel(serveCtx, credentialManager, handler.muxer, config, logger, connectionIndex, originLocalAddr, cloudflaredUUID)
|
||||
})
|
||||
|
||||
errGroup.Go(func() error {
|
||||
@@ -319,12 +337,15 @@ func ServeTunnel(
|
||||
select {
|
||||
case <-serveCtx.Done():
|
||||
// UnregisterTunnel blocks until the RPC call returns
|
||||
var err error
|
||||
if connectedFuse.Value() {
|
||||
err = UnregisterTunnel(handler.muxer, config.GracePeriod, config.TransportLogger)
|
||||
if config.NamedTunnel != nil {
|
||||
_ = UnregisterConnection(ctx, handler.muxer, config)
|
||||
} else {
|
||||
_ = UnregisterTunnel(handler.muxer, config.GracePeriod, config.TransportLogger)
|
||||
}
|
||||
}
|
||||
handler.muxer.Shutdown()
|
||||
return err
|
||||
return nil
|
||||
case <-updateMetricsTickC:
|
||||
handler.UpdateMetrics(connectionTag)
|
||||
}
|
||||
@@ -355,31 +376,33 @@ func ServeTunnel(
|
||||
|
||||
err = errGroup.Wait()
|
||||
if err != nil {
|
||||
_ = newClientRegisterTunnelError(err, config.Metrics.regFail, unknown)
|
||||
|
||||
switch castedErr := err.(type) {
|
||||
case dupConnRegisterTunnelError:
|
||||
logger.Info("Already connected to this server, selecting a different one")
|
||||
return err, true
|
||||
case serverRegisterTunnelError:
|
||||
logger.Errorf("Register tunnel error from server side: %s", castedErr.cause)
|
||||
switch err := err.(type) {
|
||||
case *dupConnRegisterTunnelError:
|
||||
// don't retry this connection anymore, let supervisor pick new a address
|
||||
return err, false
|
||||
case *serverRegisterTunnelError:
|
||||
logger.Errorf("Register tunnel error from server side: %s", err.cause)
|
||||
// Don't send registration error return from server to Sentry. They are
|
||||
// logged on server side
|
||||
if incidents := config.IncidentLookup.ActiveIncidents(); len(incidents) > 0 {
|
||||
logger.Error(activeIncidentsMsg(incidents))
|
||||
}
|
||||
return castedErr.cause, !castedErr.permanent
|
||||
case clientRegisterTunnelError:
|
||||
logger.Errorf("Register tunnel error on client side: %s", castedErr.cause)
|
||||
return err.cause, !err.permanent
|
||||
case *clientRegisterTunnelError:
|
||||
logger.Errorf("Register tunnel error on client side: %s", err.cause)
|
||||
return err, true
|
||||
case muxerShutdownError:
|
||||
case *muxerShutdownError:
|
||||
logger.Info("Muxer shutdown")
|
||||
return err, true
|
||||
case *ReconnectSignal:
|
||||
logger.Infof("Restarting due to reconnect signal in %d seconds", castedErr.Delay)
|
||||
castedErr.DelayBeforeReconnect()
|
||||
logger.Infof("Restarting connection %d due to reconnect signal in %d seconds", connectionIndex, err.Delay)
|
||||
err.DelayBeforeReconnect()
|
||||
return err, true
|
||||
default:
|
||||
if err == context.Canceled {
|
||||
logger.Debugf("Serve tunnel error: %s", err)
|
||||
return err, false
|
||||
}
|
||||
logger.Errorf("Serve tunnel error: %s", err)
|
||||
return err, true
|
||||
}
|
||||
@@ -387,6 +410,74 @@ func ServeTunnel(
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func RegisterConnection(
|
||||
ctx context.Context,
|
||||
muxer *h2mux.Muxer,
|
||||
config *TunnelConfig,
|
||||
connectionIndex uint8,
|
||||
originLocalAddr string,
|
||||
) error {
|
||||
const registerConnection = "registerConnection"
|
||||
|
||||
config.TransportLogger.Debug("initiating RPC stream for RegisterConnection")
|
||||
rpc, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger, openStreamTimeout)
|
||||
if err != nil {
|
||||
// RPC stream open error
|
||||
return newClientRegisterTunnelError(err, config.Metrics.rpcFail, registerConnection)
|
||||
}
|
||||
defer rpc.Close()
|
||||
|
||||
conn, err := rpc.RegisterConnection(
|
||||
ctx,
|
||||
config.NamedTunnel.Auth,
|
||||
config.NamedTunnel.ID,
|
||||
connectionIndex,
|
||||
config.ConnectionOptions(originLocalAddr),
|
||||
)
|
||||
if err != nil {
|
||||
if err.Error() == DuplicateConnectionError {
|
||||
config.Metrics.regFail.WithLabelValues("dup_edge_conn", registerConnection).Inc()
|
||||
return errDuplicationConnection
|
||||
}
|
||||
config.Metrics.regFail.WithLabelValues("server_error", registerConnection).Inc()
|
||||
return serverRegistrationErrorFromRPC(err)
|
||||
}
|
||||
|
||||
config.Metrics.regSuccess.WithLabelValues(registerConnection).Inc()
|
||||
config.Logger.Infof("Connection %d registered with %s using ID %s", connectionIndex, conn.Location, conn.UUID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func serverRegistrationErrorFromRPC(err error) *serverRegisterTunnelError {
|
||||
if retryable, ok := err.(*tunnelpogs.RetryableError); ok {
|
||||
return &serverRegisterTunnelError{
|
||||
cause: retryable.Unwrap(),
|
||||
permanent: false,
|
||||
}
|
||||
}
|
||||
return &serverRegisterTunnelError{
|
||||
cause: err,
|
||||
permanent: true,
|
||||
}
|
||||
}
|
||||
|
||||
func UnregisterConnection(
|
||||
ctx context.Context,
|
||||
muxer *h2mux.Muxer,
|
||||
config *TunnelConfig,
|
||||
) error {
|
||||
config.TransportLogger.Debug("initiating RPC stream for UnregisterConnection")
|
||||
rpc, err := connection.NewRPCClient(ctx, muxer, config.TransportLogger, openStreamTimeout)
|
||||
if err != nil {
|
||||
// RPC stream open error
|
||||
return newClientRegisterTunnelError(err, config.Metrics.rpcFail, register)
|
||||
}
|
||||
defer rpc.Close()
|
||||
|
||||
return rpc.UnregisterConnection(ctx)
|
||||
}
|
||||
|
||||
func RegisterTunnel(
|
||||
ctx context.Context,
|
||||
credentialManager ReconnectTunnelCredentialManager,
|
||||
@@ -431,7 +522,7 @@ func ReconnectTunnel(
|
||||
config *TunnelConfig,
|
||||
logger logger.Service,
|
||||
connectionID uint8,
|
||||
originLocalIP string,
|
||||
originLocalAddr string,
|
||||
uuid uuid.UUID,
|
||||
credentialManager ReconnectTunnelCredentialManager,
|
||||
) error {
|
||||
@@ -453,7 +544,7 @@ func ReconnectTunnel(
|
||||
eventDigest,
|
||||
connDigest,
|
||||
config.Hostname,
|
||||
config.RegistrationOptions(connectionID, originLocalIP, uuid),
|
||||
config.RegistrationOptions(connectionID, originLocalAddr, uuid),
|
||||
)
|
||||
if registrationErr := registration.DeserializeError(); registrationErr != nil {
|
||||
// ReconnectTunnel RPC failure
|
||||
@@ -502,11 +593,11 @@ func processRegistrationSuccess(
|
||||
func processRegisterTunnelError(err tunnelpogs.TunnelRegistrationError, metrics *TunnelMetrics, name registerRPCName) error {
|
||||
if err.Error() == DuplicateConnectionError {
|
||||
metrics.regFail.WithLabelValues("dup_edge_conn", string(name)).Inc()
|
||||
return dupConnRegisterTunnelError{}
|
||||
return errDuplicationConnection
|
||||
}
|
||||
metrics.regFail.WithLabelValues("server_error", string(name)).Inc()
|
||||
return serverRegisterTunnelError{
|
||||
cause: fmt.Errorf("Server error: %s", err.Error()),
|
||||
cause: err,
|
||||
permanent: err.IsPermanent(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
ln -s /usr/bin/cloudflared /usr/local/bin/cloudflared
|
||||
mkdir -p /usr/local/etc/cloudflared/
|
||||
touch /usr/local/etc/cloudflared/.installedFromPackageManager || true
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
rm /usr/local/bin/cloudflared
|
||||
rm /usr/local/etc/cloudflared/.installedFromPackageManager || true
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/proxy"
|
||||
@@ -58,7 +59,6 @@ func startTestServer(t *testing.T, httpHandler func(w http.ResponseWriter, r *ht
|
||||
|
||||
// start the servers
|
||||
go http.ListenAndServe(":8085", mux)
|
||||
|
||||
}
|
||||
|
||||
func respondWithJSON(w http.ResponseWriter, v interface{}, status int) {
|
||||
@@ -78,6 +78,7 @@ func OkJSONResponseHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func TestSocksConnection(t *testing.T) {
|
||||
startTestServer(t, OkJSONResponseHandler)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
b := sendSocksRequest(t)
|
||||
assert.True(t, len(b) > 0, "no data returned!")
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ func TestSessionLogWrite(t *testing.T) {
|
||||
testStr := "hi"
|
||||
logger := createSessionLogger(t)
|
||||
defer func() {
|
||||
logger.Close()
|
||||
os.Remove(sessionLogFileName)
|
||||
}()
|
||||
|
||||
logger.Write([]byte(testStr))
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
logger.Close()
|
||||
|
||||
f, err := os.Open(sessionLogFileName)
|
||||
if err != nil {
|
||||
t.Fatal("couldn't read the log file!", err)
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/config"
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/cloudflare/cloudflared/metrics"
|
||||
@@ -31,7 +32,7 @@ func Run(c *cli.Context) error {
|
||||
logDirectory, logLevel := config.FindLogSettings()
|
||||
logger, err := logger.New(logger.DefaultFile(logDirectory), logger.LogLevelString(logLevel))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error setting up logger")
|
||||
return cliutil.PrintLoggerSetupError("error setting up logger", err)
|
||||
}
|
||||
|
||||
metricsListener, err := net.Listen("tcp", c.String("metrics"))
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"zombiezen.com/go/capnproto2/pogs"
|
||||
"zombiezen.com/go/capnproto2/server"
|
||||
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
)
|
||||
|
||||
type RegistrationServer interface {
|
||||
RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error)
|
||||
UnregisterConnection(ctx context.Context)
|
||||
}
|
||||
|
||||
type ClientInfo struct {
|
||||
ClientID []byte `capnp:"clientId"` // must be a slice for capnp compatibility
|
||||
Features []string
|
||||
Version string
|
||||
Arch string
|
||||
}
|
||||
|
||||
type ConnectionOptions struct {
|
||||
Client ClientInfo
|
||||
OriginLocalIP net.IP `capnp:"originLocalIp"`
|
||||
ReplaceExisting bool
|
||||
CompressionQuality uint8
|
||||
}
|
||||
|
||||
type TunnelAuth struct {
|
||||
AccountTag string
|
||||
TunnelSecret []byte
|
||||
}
|
||||
|
||||
func (p *ConnectionOptions) MarshalCapnproto(s tunnelrpc.ConnectionOptions) error {
|
||||
return pogs.Insert(tunnelrpc.ConnectionOptions_TypeID, s.Struct, p)
|
||||
}
|
||||
|
||||
func (p *ConnectionOptions) UnmarshalCapnproto(s tunnelrpc.ConnectionOptions) error {
|
||||
return pogs.Extract(p, tunnelrpc.ConnectionOptions_TypeID, s.Struct)
|
||||
}
|
||||
|
||||
func (a *TunnelAuth) MarshalCapnproto(s tunnelrpc.TunnelAuth) error {
|
||||
return pogs.Insert(tunnelrpc.TunnelAuth_TypeID, s.Struct, a)
|
||||
}
|
||||
|
||||
func (a *TunnelAuth) UnmarshalCapnproto(s tunnelrpc.TunnelAuth) error {
|
||||
return pogs.Extract(a, tunnelrpc.TunnelAuth_TypeID, s.Struct)
|
||||
}
|
||||
|
||||
type ConnectionDetails struct {
|
||||
UUID uuid.UUID
|
||||
Location string
|
||||
}
|
||||
|
||||
func (details *ConnectionDetails) MarshalCapnproto(s tunnelrpc.ConnectionDetails) error {
|
||||
if err := s.SetUuid(details.UUID[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.SetLocationName(details.Location); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (details *ConnectionDetails) UnmarshalCapnproto(s tunnelrpc.ConnectionDetails) error {
|
||||
uuidBytes, err := s.Uuid()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
details.UUID, err = uuid.FromBytes(uuidBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
details.Location, err = s.LocationName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func MarshalError(s tunnelrpc.ConnectionError, err error) error {
|
||||
if err := s.SetCause(err.Error()); err != nil {
|
||||
return err
|
||||
}
|
||||
if retryableErr, ok := err.(*RetryableError); ok {
|
||||
s.SetShouldRetry(true)
|
||||
s.SetRetryAfter(int64(retryableErr.Delay))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i TunnelServer_PogsImpl) RegisterConnection(p tunnelrpc.RegistrationServer_registerConnection) error {
|
||||
server.Ack(p.Options)
|
||||
|
||||
auth, err := p.Params.Auth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var pogsAuth TunnelAuth
|
||||
err = pogsAuth.UnmarshalCapnproto(auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uuidBytes, err := p.Params.TunnelId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tunnelID, err := uuid.FromBytes(uuidBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
connIndex := p.Params.ConnIndex()
|
||||
options, err := p.Params.Options()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var pogsOptions ConnectionOptions
|
||||
err = pogsOptions.UnmarshalCapnproto(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
connDetails, callError := i.impl.RegisterConnection(p.Ctx, pogsAuth, tunnelID, connIndex, &pogsOptions)
|
||||
|
||||
resp, err := p.Results.NewResult()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if callError != nil {
|
||||
if connError, err := resp.Result().NewError(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return MarshalError(connError, callError)
|
||||
}
|
||||
}
|
||||
|
||||
if details, err := resp.Result().NewConnectionDetails(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return connDetails.MarshalCapnproto(details)
|
||||
}
|
||||
}
|
||||
|
||||
func (i TunnelServer_PogsImpl) UnregisterConnection(p tunnelrpc.RegistrationServer_unregisterConnection) error {
|
||||
server.Ack(p.Options)
|
||||
|
||||
i.impl.UnregisterConnection(p.Ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TunnelServer_PogsClient) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) {
|
||||
client := tunnelrpc.TunnelServer{Client: c.Client}
|
||||
promise := client.RegisterConnection(ctx, func(p tunnelrpc.RegistrationServer_registerConnection_Params) error {
|
||||
tunnelAuth, err := p.NewAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = auth.MarshalCapnproto(tunnelAuth); err != nil {
|
||||
return err
|
||||
}
|
||||
err = p.SetAuth(tunnelAuth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = p.SetTunnelId(tunnelID[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.SetConnIndex(connIndex)
|
||||
connectionOptions, err := p.NewOptions()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = options.MarshalCapnproto(connectionOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
response, err := promise.Result().Struct()
|
||||
if err != nil {
|
||||
return nil, wrapRPCError(err)
|
||||
}
|
||||
result := response.Result()
|
||||
switch result.Which() {
|
||||
case tunnelrpc.ConnectionResponse_result_Which_error:
|
||||
resultError, err := result.Error()
|
||||
if err != nil {
|
||||
return nil, wrapRPCError(err)
|
||||
}
|
||||
cause, err := resultError.Cause()
|
||||
if err != nil {
|
||||
return nil, wrapRPCError(err)
|
||||
}
|
||||
err = errors.New(cause)
|
||||
if resultError.ShouldRetry() {
|
||||
err = RetryErrorAfter(err, time.Duration(resultError.RetryAfter()))
|
||||
}
|
||||
return nil, err
|
||||
|
||||
case tunnelrpc.ConnectionResponse_result_Which_connectionDetails:
|
||||
connDetails, err := result.ConnectionDetails()
|
||||
if err != nil {
|
||||
return nil, wrapRPCError(err)
|
||||
}
|
||||
details := new(ConnectionDetails)
|
||||
if err = details.UnmarshalCapnproto(connDetails); err != nil {
|
||||
return nil, wrapRPCError(err)
|
||||
}
|
||||
return details, nil
|
||||
}
|
||||
|
||||
return nil, newRPCError("unknown result which %d", result.Which())
|
||||
}
|
||||
|
||||
func (c TunnelServer_PogsClient) UnregisterConnection(ctx context.Context) error {
|
||||
client := tunnelrpc.TunnelServer{Client: c.Client}
|
||||
promise := client.UnregisterConnection(ctx, func(p tunnelrpc.RegistrationServer_unregisterConnection_Params) error {
|
||||
return nil
|
||||
})
|
||||
_, err := promise.Struct()
|
||||
if err != nil {
|
||||
return wrapRPCError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
capnp "zombiezen.com/go/capnproto2"
|
||||
"zombiezen.com/go/capnproto2/rpc"
|
||||
|
||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||
)
|
||||
|
||||
const testAccountTag = "abc123"
|
||||
|
||||
func TestMarshalConnectionOptions(t *testing.T) {
|
||||
clientID := uuid.New()
|
||||
orig := ConnectionOptions{
|
||||
Client: ClientInfo{
|
||||
ClientID: clientID[:],
|
||||
Features: []string{"a", "b"},
|
||||
Version: "1.2.3",
|
||||
Arch: "macos",
|
||||
},
|
||||
OriginLocalIP: []byte{10, 2, 3, 4},
|
||||
ReplaceExisting: false,
|
||||
CompressionQuality: 1,
|
||||
}
|
||||
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
require.NoError(t, err)
|
||||
capnpOpts, err := tunnelrpc.NewConnectionOptions(seg)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = orig.MarshalCapnproto(capnpOpts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var pogsOpts ConnectionOptions
|
||||
err = pogsOpts.UnmarshalCapnproto(capnpOpts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, orig, pogsOpts)
|
||||
}
|
||||
|
||||
func TestConnectionRegistrationRPC(t *testing.T) {
|
||||
p1, p2 := net.Pipe()
|
||||
|
||||
t1, t2 := rpc.StreamTransport(p1), rpc.StreamTransport(p2)
|
||||
|
||||
// Server-side
|
||||
testImpl := testConnectionRegistrationServer{}
|
||||
srv := TunnelServer_ServerToClient(&testImpl)
|
||||
serverConn := rpc.NewConn(t1, rpc.MainInterface(srv.Client))
|
||||
defer serverConn.Wait()
|
||||
|
||||
ctx := context.Background()
|
||||
clientConn := rpc.NewConn(t2)
|
||||
defer clientConn.Close()
|
||||
client := TunnelServer_PogsClient{
|
||||
Client: clientConn.Bootstrap(ctx),
|
||||
Conn: clientConn,
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
clientID := uuid.New()
|
||||
options := &ConnectionOptions{
|
||||
Client: ClientInfo{
|
||||
ClientID: clientID[:],
|
||||
Features: []string{"foo"},
|
||||
Version: "1.2.3",
|
||||
Arch: "macos",
|
||||
},
|
||||
OriginLocalIP: net.IP{10, 20, 30, 40},
|
||||
ReplaceExisting: true,
|
||||
CompressionQuality: 0,
|
||||
}
|
||||
|
||||
expectedDetails := ConnectionDetails{
|
||||
UUID: uuid.New(),
|
||||
Location: "TEST",
|
||||
}
|
||||
testImpl.details = &expectedDetails
|
||||
testImpl.err = nil
|
||||
|
||||
auth := TunnelAuth{
|
||||
AccountTag: testAccountTag,
|
||||
TunnelSecret: []byte{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
// success
|
||||
tunnelID := uuid.New()
|
||||
details, err := client.RegisterConnection(ctx, auth, tunnelID, 2, options)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedDetails, *details)
|
||||
|
||||
// regular error
|
||||
testImpl.details = nil
|
||||
testImpl.err = errors.New("internal")
|
||||
|
||||
_, err = client.RegisterConnection(ctx, auth, tunnelID, 2, options)
|
||||
assert.EqualError(t, err, "internal")
|
||||
|
||||
// retriable error
|
||||
testImpl.details = nil
|
||||
const delay = 27 * time.Second
|
||||
testImpl.err = RetryErrorAfter(errors.New("retryable"), delay)
|
||||
|
||||
_, err = client.RegisterConnection(ctx, auth, tunnelID, 2, options)
|
||||
assert.EqualError(t, err, "retryable")
|
||||
|
||||
re, ok := err.(*RetryableError)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, delay, re.Delay)
|
||||
}
|
||||
|
||||
type testConnectionRegistrationServer struct {
|
||||
mockTunnelServerBase
|
||||
|
||||
details *ConnectionDetails
|
||||
err error
|
||||
}
|
||||
|
||||
func (t *testConnectionRegistrationServer) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) {
|
||||
if auth.AccountTag != testAccountTag {
|
||||
panic("bad account tag: " + auth.AccountTag)
|
||||
}
|
||||
if t.err != nil {
|
||||
return nil, t.err
|
||||
}
|
||||
if t.details != nil {
|
||||
return t.details, nil
|
||||
}
|
||||
|
||||
panic("either details or err mush be set")
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RetryableError struct {
|
||||
err error
|
||||
Delay time.Duration
|
||||
}
|
||||
|
||||
func (re *RetryableError) Error() string {
|
||||
return re.err.Error()
|
||||
}
|
||||
|
||||
// RetryErrorAfter wraps err to indicate that client should retry after delay
|
||||
func RetryErrorAfter(err error, delay time.Duration) *RetryableError {
|
||||
return &RetryableError{
|
||||
err: err,
|
||||
Delay: delay,
|
||||
}
|
||||
}
|
||||
|
||||
func (re *RetryableError) Unwrap() error {
|
||||
return re.err
|
||||
}
|
||||
|
||||
// RPCError is used to indicate errors returned by the RPC subsystem rather
|
||||
// than failure of a remote operation
|
||||
type RPCError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (re *RPCError) Error() string {
|
||||
return re.err.Error()
|
||||
}
|
||||
|
||||
func wrapRPCError(err error) *RPCError {
|
||||
if err != nil {
|
||||
return &RPCError{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newRPCError(format string, args ...interface{}) *RPCError {
|
||||
return &RPCError{
|
||||
fmt.Errorf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
func (re *RPCError) Unwrap() error {
|
||||
return re.err
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// mockTunnelServerBase provides a placeholder implementation
|
||||
// for TunnelServer interface that can be used to build
|
||||
// mocks for specific unit tests without having to implement every method
|
||||
type mockTunnelServerBase struct{}
|
||||
|
||||
func (mockTunnelServerBase) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) {
|
||||
panic("unexpected call to RegisterConnection")
|
||||
}
|
||||
|
||||
func (mockTunnelServerBase) UnregisterConnection(ctx context.Context) {
|
||||
panic("unexpected call to UnregisterConnection")
|
||||
}
|
||||
|
||||
func (mockTunnelServerBase) RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) *TunnelRegistration {
|
||||
panic("unexpected call to RegisterTunnel")
|
||||
}
|
||||
|
||||
func (mockTunnelServerBase) GetServerInfo(ctx context.Context) (*ServerInfo, error) {
|
||||
panic("unexpected call to GetServerInfo")
|
||||
}
|
||||
|
||||
func (mockTunnelServerBase) UnregisterTunnel(ctx context.Context, gracePeriodNanoSec int64) error {
|
||||
panic("unexpected call to UnregisterTunnel")
|
||||
}
|
||||
|
||||
func (mockTunnelServerBase) Authenticate(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) (*AuthenticateResponse, error) {
|
||||
panic("unexpected call to Authenticate")
|
||||
}
|
||||
|
||||
func (mockTunnelServerBase) ReconnectTunnel(ctx context.Context, jwt, eventDigest, connDigest []byte, hostname string, options *RegistrationOptions) (*TunnelRegistration, error) {
|
||||
panic("unexpected call to ReconnectTunnel")
|
||||
}
|
||||
|
||||
@@ -201,6 +201,7 @@ func UnmarshalServerInfo(s tunnelrpc.ServerInfo) (*ServerInfo, error) {
|
||||
}
|
||||
|
||||
type TunnelServer interface {
|
||||
RegistrationServer
|
||||
RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) *TunnelRegistration
|
||||
GetServerInfo(ctx context.Context) (*ServerInfo, error)
|
||||
UnregisterTunnel(ctx context.Context, gracePeriodNanoSec int64) error
|
||||
|
||||
@@ -78,7 +78,60 @@ struct AuthenticateResponse {
|
||||
hoursUntilRefresh @3 :UInt8;
|
||||
}
|
||||
|
||||
interface TunnelServer {
|
||||
struct ClientInfo {
|
||||
# The tunnel client's unique identifier, used to verify a reconnection.
|
||||
clientId @0 :Data;
|
||||
# Set of features this cloudflared knows it supports
|
||||
features @1 :List(Text);
|
||||
# Information about the running binary.
|
||||
version @2 :Text;
|
||||
# Client OS and CPU info
|
||||
arch @3 :Text;
|
||||
}
|
||||
|
||||
struct ConnectionOptions {
|
||||
# client details
|
||||
client @0 :ClientInfo;
|
||||
# origin LAN IP
|
||||
originLocalIp @1 :Data;
|
||||
# What to do if connection already exists
|
||||
replaceExisting @2 :Bool;
|
||||
# cross stream compression setting, 0 - off, 3 - high
|
||||
compressionQuality @3 :UInt8;
|
||||
}
|
||||
|
||||
struct ConnectionResponse {
|
||||
result :union {
|
||||
error @0 :ConnectionError;
|
||||
connectionDetails @1 :ConnectionDetails;
|
||||
}
|
||||
}
|
||||
|
||||
struct ConnectionError {
|
||||
cause @0 :Text;
|
||||
# How long should this connection wait to retry in ns
|
||||
retryAfter @1 :Int64;
|
||||
shouldRetry @2 :Bool;
|
||||
}
|
||||
|
||||
struct ConnectionDetails {
|
||||
# identifier of this connection
|
||||
uuid @0 :Data;
|
||||
# airport code of the colo where this connection landed
|
||||
locationName @1 :Text;
|
||||
}
|
||||
|
||||
struct TunnelAuth {
|
||||
accountTag @0 :Text;
|
||||
tunnelSecret @1 :Data;
|
||||
}
|
||||
|
||||
interface RegistrationServer {
|
||||
registerConnection @0 (auth :TunnelAuth, tunnelId :Data, connIndex :UInt8, options :ConnectionOptions) -> (result :ConnectionResponse);
|
||||
unregisterConnection @1 () -> ();
|
||||
}
|
||||
|
||||
interface TunnelServer extends (RegistrationServer) {
|
||||
registerTunnel @0 (originCert :Data, hostname :Text, options :RegistrationOptions) -> (result :TunnelRegistration);
|
||||
getServerInfo @1 () -> (result :ServerInfo);
|
||||
unregisterTunnel @2 (gracePeriodNanoSec :Int64) -> ();
|
||||
|
||||
+1366
-126
File diff suppressed because it is too large
Load Diff
+39
-18
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cloudflared/logger"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -26,16 +27,24 @@ var (
|
||||
)
|
||||
|
||||
type Tunnel struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
DeletedAt time.Time `json:"deleted_at"`
|
||||
Connections []Connection `json:"connections"`
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
ColoName string `json:"colo_name"`
|
||||
ID uuid.UUID `json:"uuid"`
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
CreateTunnel(name string) (*Tunnel, error)
|
||||
GetTunnel(id string) (*Tunnel, error)
|
||||
DeleteTunnel(id string) error
|
||||
CreateTunnel(name string, tunnelSecret []byte) (*Tunnel, error)
|
||||
GetTunnel(tunnelID string) (*Tunnel, error)
|
||||
DeleteTunnel(tunnelID string) error
|
||||
ListTunnels() ([]Tunnel, error)
|
||||
CleanupConnections(tunnelID string) error
|
||||
}
|
||||
|
||||
type RESTClient struct {
|
||||
@@ -67,15 +76,17 @@ func NewRESTClient(baseURL string, accountTag string, authToken string, logger l
|
||||
}
|
||||
|
||||
type newTunnel struct {
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name"`
|
||||
TunnelSecret []byte `json:"tunnel_secret"`
|
||||
}
|
||||
|
||||
func (r *RESTClient) CreateTunnel(name string) (*Tunnel, error) {
|
||||
func (r *RESTClient) CreateTunnel(name string, tunnelSecret []byte) (*Tunnel, error) {
|
||||
if name == "" {
|
||||
return nil, errors.New("tunnel name required")
|
||||
}
|
||||
body, err := json.Marshal(&newTunnel{
|
||||
Name: name,
|
||||
Name: name,
|
||||
TunnelSecret: tunnelSecret,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to serialize new tunnel request")
|
||||
@@ -94,11 +105,11 @@ func (r *RESTClient) CreateTunnel(name string) (*Tunnel, error) {
|
||||
return nil, ErrTunnelNameConflict
|
||||
}
|
||||
|
||||
return nil, statusCodeToError("create", resp)
|
||||
return nil, statusCodeToError("create tunnel", resp)
|
||||
}
|
||||
|
||||
func (r *RESTClient) GetTunnel(id string) (*Tunnel, error) {
|
||||
resp, err := r.sendRequest("GET", id, nil)
|
||||
func (r *RESTClient) GetTunnel(tunnelID string) (*Tunnel, error) {
|
||||
resp, err := r.sendRequest("GET", tunnelID, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "REST request failed")
|
||||
}
|
||||
@@ -108,17 +119,17 @@ func (r *RESTClient) GetTunnel(id string) (*Tunnel, error) {
|
||||
return unmarshalTunnel(resp.Body)
|
||||
}
|
||||
|
||||
return nil, statusCodeToError("read", resp)
|
||||
return nil, statusCodeToError("get tunnel", resp)
|
||||
}
|
||||
|
||||
func (r *RESTClient) DeleteTunnel(id string) error {
|
||||
resp, err := r.sendRequest("DELETE", id, nil)
|
||||
func (r *RESTClient) DeleteTunnel(tunnelID string) error {
|
||||
resp, err := r.sendRequest("DELETE", tunnelID, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "REST request failed")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return statusCodeToError("delete", resp)
|
||||
return statusCodeToError("delete tunnel", resp)
|
||||
}
|
||||
|
||||
func (r *RESTClient) ListTunnels() ([]Tunnel, error) {
|
||||
@@ -136,7 +147,17 @@ func (r *RESTClient) ListTunnels() ([]Tunnel, error) {
|
||||
return tunnels, nil
|
||||
}
|
||||
|
||||
return nil, statusCodeToError("list", resp)
|
||||
return nil, statusCodeToError("list tunnels", resp)
|
||||
}
|
||||
|
||||
func (r *RESTClient) CleanupConnections(tunnelID string) error {
|
||||
resp, err := r.sendRequest("DELETE", fmt.Sprintf("%s/connections", tunnelID), nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "REST request failed")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return statusCodeToError("cleanup connections", resp)
|
||||
}
|
||||
|
||||
func (r *RESTClient) resolve(target string) string {
|
||||
@@ -179,6 +200,6 @@ func statusCodeToError(op string, resp *http.Response) error {
|
||||
case http.StatusNotFound:
|
||||
return ErrNotFound
|
||||
}
|
||||
return errors.Errorf("API call to %s tunnel failed with status %d: %s", op,
|
||||
return errors.Errorf("API call to %s failed with status %d: %s", op,
|
||||
resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||
}
|
||||
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
// 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.
|
||||
//
|
||||
// BLAKE2b is optimized for 64-bit platforms—including NEON-enabled ARMs—and
|
||||
// produces digests of any size between 1 and 64 bytes.
|
||||
// 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 be 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 be 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 be 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 be 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,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,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,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,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
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
// 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"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// 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 = bits.RotateLeft64(v12, -32)
|
||||
v8 += v12
|
||||
v4 ^= v8
|
||||
v4 = bits.RotateLeft64(v4, -24)
|
||||
v1 += m[s[1]]
|
||||
v1 += v5
|
||||
v13 ^= v1
|
||||
v13 = bits.RotateLeft64(v13, -32)
|
||||
v9 += v13
|
||||
v5 ^= v9
|
||||
v5 = bits.RotateLeft64(v5, -24)
|
||||
v2 += m[s[2]]
|
||||
v2 += v6
|
||||
v14 ^= v2
|
||||
v14 = bits.RotateLeft64(v14, -32)
|
||||
v10 += v14
|
||||
v6 ^= v10
|
||||
v6 = bits.RotateLeft64(v6, -24)
|
||||
v3 += m[s[3]]
|
||||
v3 += v7
|
||||
v15 ^= v3
|
||||
v15 = bits.RotateLeft64(v15, -32)
|
||||
v11 += v15
|
||||
v7 ^= v11
|
||||
v7 = bits.RotateLeft64(v7, -24)
|
||||
|
||||
v0 += m[s[4]]
|
||||
v0 += v4
|
||||
v12 ^= v0
|
||||
v12 = bits.RotateLeft64(v12, -16)
|
||||
v8 += v12
|
||||
v4 ^= v8
|
||||
v4 = bits.RotateLeft64(v4, -63)
|
||||
v1 += m[s[5]]
|
||||
v1 += v5
|
||||
v13 ^= v1
|
||||
v13 = bits.RotateLeft64(v13, -16)
|
||||
v9 += v13
|
||||
v5 ^= v9
|
||||
v5 = bits.RotateLeft64(v5, -63)
|
||||
v2 += m[s[6]]
|
||||
v2 += v6
|
||||
v14 ^= v2
|
||||
v14 = bits.RotateLeft64(v14, -16)
|
||||
v10 += v14
|
||||
v6 ^= v10
|
||||
v6 = bits.RotateLeft64(v6, -63)
|
||||
v3 += m[s[7]]
|
||||
v3 += v7
|
||||
v15 ^= v3
|
||||
v15 = bits.RotateLeft64(v15, -16)
|
||||
v11 += v15
|
||||
v7 ^= v11
|
||||
v7 = bits.RotateLeft64(v7, -63)
|
||||
|
||||
v0 += m[s[8]]
|
||||
v0 += v5
|
||||
v15 ^= v0
|
||||
v15 = bits.RotateLeft64(v15, -32)
|
||||
v10 += v15
|
||||
v5 ^= v10
|
||||
v5 = bits.RotateLeft64(v5, -24)
|
||||
v1 += m[s[9]]
|
||||
v1 += v6
|
||||
v12 ^= v1
|
||||
v12 = bits.RotateLeft64(v12, -32)
|
||||
v11 += v12
|
||||
v6 ^= v11
|
||||
v6 = bits.RotateLeft64(v6, -24)
|
||||
v2 += m[s[10]]
|
||||
v2 += v7
|
||||
v13 ^= v2
|
||||
v13 = bits.RotateLeft64(v13, -32)
|
||||
v8 += v13
|
||||
v7 ^= v8
|
||||
v7 = bits.RotateLeft64(v7, -24)
|
||||
v3 += m[s[11]]
|
||||
v3 += v4
|
||||
v14 ^= v3
|
||||
v14 = bits.RotateLeft64(v14, -32)
|
||||
v9 += v14
|
||||
v4 ^= v9
|
||||
v4 = bits.RotateLeft64(v4, -24)
|
||||
|
||||
v0 += m[s[12]]
|
||||
v0 += v5
|
||||
v15 ^= v0
|
||||
v15 = bits.RotateLeft64(v15, -16)
|
||||
v10 += v15
|
||||
v5 ^= v10
|
||||
v5 = bits.RotateLeft64(v5, -63)
|
||||
v1 += m[s[13]]
|
||||
v1 += v6
|
||||
v12 ^= v1
|
||||
v12 = bits.RotateLeft64(v12, -16)
|
||||
v11 += v12
|
||||
v6 ^= v11
|
||||
v6 = bits.RotateLeft64(v6, -63)
|
||||
v2 += m[s[14]]
|
||||
v2 += v7
|
||||
v13 ^= v2
|
||||
v13 = bits.RotateLeft64(v13, -16)
|
||||
v8 += v13
|
||||
v7 ^= v8
|
||||
v7 = bits.RotateLeft64(v7, -63)
|
||||
v3 += m[s[15]]
|
||||
v3 += v4
|
||||
v14 ^= v3
|
||||
v14 = bits.RotateLeft64(v14, -16)
|
||||
v9 += v14
|
||||
v4 ^= v9
|
||||
v4 = bits.RotateLeft64(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,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)
|
||||
}
|
||||
+177
@@ -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,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)
|
||||
}
|
||||
+159
@@ -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
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
// 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.
|
||||
//
|
||||
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
|
||||
// birthday bound attacks (see https://sweet32.info). It should only be used
|
||||
// where compatibility with legacy systems, not security, is the goal.
|
||||
//
|
||||
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
|
||||
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
|
||||
// golang.org/x/crypto/chacha20poly1305).
|
||||
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,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,
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.11,!gccgo,!purego
|
||||
|
||||
package chacha20
|
||||
|
||||
const bufSize = 256
|
||||
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
||||
|
||||
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
|
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
|
||||
}
|
||||
Generated
Vendored
+1
-2
@@ -2,8 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.11
|
||||
// +build !gccgo,!appengine
|
||||
// +build go1.11,!gccgo,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
// 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 chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
|
||||
// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/bits"
|
||||
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
)
|
||||
|
||||
const (
|
||||
// KeySize is the size of the key used by this cipher, in bytes.
|
||||
KeySize = 32
|
||||
|
||||
// NonceSize is the size of the nonce used with the standard variant of this
|
||||
// cipher, 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 variant of
|
||||
// this cipher, in bytes.
|
||||
NonceSizeX = 24
|
||||
)
|
||||
|
||||
// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
|
||||
// and nonce. A *Cipher implements the cipher.Stream interface.
|
||||
type Cipher struct {
|
||||
// The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
|
||||
// (incremented after each block), and 3 of nonce.
|
||||
key [8]uint32
|
||||
counter uint32
|
||||
nonce [3]uint32
|
||||
|
||||
// The last len bytes of buf are leftover key stream bytes from the previous
|
||||
// XORKeyStream invocation. The size of buf depends on how many blocks are
|
||||
// computed at a time by xorKeyStreamBlocks.
|
||||
buf [bufSize]byte
|
||||
len int
|
||||
|
||||
// overflow is set when the counter overflowed, no more blocks can be
|
||||
// generated, and the next XORKeyStream call should panic.
|
||||
overflow bool
|
||||
|
||||
// The counter-independent results of the first round are cached after they
|
||||
// are computed the first time.
|
||||
precompDone bool
|
||||
p1, p5, p9, p13 uint32
|
||||
p2, p6, p10, p14 uint32
|
||||
p3, p7, p11, p15 uint32
|
||||
}
|
||||
|
||||
var _ cipher.Stream = (*Cipher)(nil)
|
||||
|
||||
// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
|
||||
// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
|
||||
// the XChaCha20 construction will be used. It returns an error if key or nonce
|
||||
// have any other length.
|
||||
//
|
||||
// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
|
||||
// attackers to silently tamper with the plaintext. For this reason, it is more
|
||||
// appropriate as a building block than as a standalone encryption mechanism.
|
||||
// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
|
||||
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
|
||||
// This function is split into a wrapper so that the Cipher allocation will
|
||||
// be inlined, and depending on how the caller uses the return value, won't
|
||||
// escape to the heap.
|
||||
c := &Cipher{}
|
||||
return newUnauthenticatedCipher(c, key, nonce)
|
||||
}
|
||||
|
||||
func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20: wrong key size")
|
||||
}
|
||||
if len(nonce) == NonceSizeX {
|
||||
// XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
|
||||
// derived key, allowing it to operate on a nonce of 24 bytes. See
|
||||
// draft-irtf-cfrg-xchacha-01, Section 2.3.
|
||||
key, _ = HChaCha20(key, nonce[0:16])
|
||||
cNonce := make([]byte, NonceSize)
|
||||
copy(cNonce[4:12], nonce[16:24])
|
||||
nonce = cNonce
|
||||
} else if len(nonce) != NonceSize {
|
||||
return nil, errors.New("chacha20: wrong nonce size")
|
||||
}
|
||||
|
||||
key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
|
||||
c.key = [8]uint32{
|
||||
binary.LittleEndian.Uint32(key[0:4]),
|
||||
binary.LittleEndian.Uint32(key[4:8]),
|
||||
binary.LittleEndian.Uint32(key[8:12]),
|
||||
binary.LittleEndian.Uint32(key[12:16]),
|
||||
binary.LittleEndian.Uint32(key[16:20]),
|
||||
binary.LittleEndian.Uint32(key[20:24]),
|
||||
binary.LittleEndian.Uint32(key[24:28]),
|
||||
binary.LittleEndian.Uint32(key[28:32]),
|
||||
}
|
||||
c.nonce = [3]uint32{
|
||||
binary.LittleEndian.Uint32(nonce[0:4]),
|
||||
binary.LittleEndian.Uint32(nonce[4:8]),
|
||||
binary.LittleEndian.Uint32(nonce[8:12]),
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// The constant first 4 words of the ChaCha20 state.
|
||||
const (
|
||||
j0 uint32 = 0x61707865 // expa
|
||||
j1 uint32 = 0x3320646e // nd 3
|
||||
j2 uint32 = 0x79622d32 // 2-by
|
||||
j3 uint32 = 0x6b206574 // te k
|
||||
)
|
||||
|
||||
const blockSize = 64
|
||||
|
||||
// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
|
||||
// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
|
||||
// words each round, in columnar or diagonal groups of 4 at a time.
|
||||
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
|
||||
a += b
|
||||
d ^= a
|
||||
d = bits.RotateLeft32(d, 16)
|
||||
c += d
|
||||
b ^= c
|
||||
b = bits.RotateLeft32(b, 12)
|
||||
a += b
|
||||
d ^= a
|
||||
d = bits.RotateLeft32(d, 8)
|
||||
c += d
|
||||
b ^= c
|
||||
b = bits.RotateLeft32(b, 7)
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
|
||||
// behave as if (64 * counter) bytes had been encrypted so far.
|
||||
//
|
||||
// To prevent accidental counter reuse, SetCounter panics if counter is less
|
||||
// than the current value.
|
||||
//
|
||||
// Note that the execution time of XORKeyStream is not independent of the
|
||||
// counter value.
|
||||
func (s *Cipher) SetCounter(counter uint32) {
|
||||
// Internally, s may buffer multiple blocks, which complicates this
|
||||
// implementation slightly. When checking whether the counter has rolled
|
||||
// back, we must use both s.counter and s.len to determine how many blocks
|
||||
// we have already output.
|
||||
outputCounter := s.counter - uint32(s.len)/blockSize
|
||||
if s.overflow || counter < outputCounter {
|
||||
panic("chacha20: SetCounter attempted to rollback counter")
|
||||
}
|
||||
|
||||
// In the general case, we set the new counter value and reset s.len to 0,
|
||||
// causing the next call to XORKeyStream to refill the buffer. However, if
|
||||
// we're advancing within the existing buffer, we can save work by simply
|
||||
// setting s.len.
|
||||
if counter < s.counter {
|
||||
s.len = int(s.counter-counter) * blockSize
|
||||
} else {
|
||||
s.counter = counter
|
||||
s.len = 0
|
||||
}
|
||||
}
|
||||
|
||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, XORKeyStream will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to XORKeyStream behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, Cipher
|
||||
// maintains state and does not reset at each XORKeyStream call.
|
||||
func (s *Cipher) XORKeyStream(dst, src []byte) {
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("chacha20: output smaller than input")
|
||||
}
|
||||
dst = dst[:len(src)]
|
||||
if subtle.InexactOverlap(dst, src) {
|
||||
panic("chacha20: invalid buffer overlap")
|
||||
}
|
||||
|
||||
// First, drain any remaining key stream from a previous XORKeyStream.
|
||||
if s.len != 0 {
|
||||
keyStream := s.buf[bufSize-s.len:]
|
||||
if len(src) < len(keyStream) {
|
||||
keyStream = keyStream[:len(src)]
|
||||
}
|
||||
_ = src[len(keyStream)-1] // bounds check elimination hint
|
||||
for i, b := range keyStream {
|
||||
dst[i] = src[i] ^ b
|
||||
}
|
||||
s.len -= len(keyStream)
|
||||
dst, src = dst[len(keyStream):], src[len(keyStream):]
|
||||
}
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// If we'd need to let the counter overflow and keep generating output,
|
||||
// panic immediately. If instead we'd only reach the last block, remember
|
||||
// not to generate any more output after the buffer is drained.
|
||||
numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
|
||||
if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
|
||||
panic("chacha20: counter overflow")
|
||||
} else if uint64(s.counter)+numBlocks == 1<<32 {
|
||||
s.overflow = true
|
||||
}
|
||||
|
||||
// xorKeyStreamBlocks implementations expect input lengths that are a
|
||||
// multiple of bufSize. Platform-specific ones process multiple blocks at a
|
||||
// time, so have bufSizes that are a multiple of blockSize.
|
||||
|
||||
full := len(src) - len(src)%bufSize
|
||||
if full > 0 {
|
||||
s.xorKeyStreamBlocks(dst[:full], src[:full])
|
||||
}
|
||||
dst, src = dst[full:], src[full:]
|
||||
|
||||
// If using a multi-block xorKeyStreamBlocks would overflow, use the generic
|
||||
// one that does one block at a time.
|
||||
const blocksPerBuf = bufSize / blockSize
|
||||
if uint64(s.counter)+blocksPerBuf > 1<<32 {
|
||||
s.buf = [bufSize]byte{}
|
||||
numBlocks := (len(src) + blockSize - 1) / blockSize
|
||||
buf := s.buf[bufSize-numBlocks*blockSize:]
|
||||
copy(buf, src)
|
||||
s.xorKeyStreamBlocksGeneric(buf, buf)
|
||||
s.len = len(buf) - copy(dst, buf)
|
||||
return
|
||||
}
|
||||
|
||||
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
|
||||
// keep the leftover keystream for the next XORKeyStream invocation.
|
||||
if len(src) > 0 {
|
||||
s.buf = [bufSize]byte{}
|
||||
copy(s.buf[:], src)
|
||||
s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
|
||||
s.len = bufSize - copy(dst, s.buf[:])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
|
||||
if len(dst) != len(src) || len(dst)%blockSize != 0 {
|
||||
panic("chacha20: internal error: wrong dst and/or src length")
|
||||
}
|
||||
|
||||
// To generate each block of key stream, the initial cipher state
|
||||
// (represented below) is passed through 20 rounds of shuffling,
|
||||
// alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
|
||||
// or by diagonals (like 1, 6, 11, 12).
|
||||
//
|
||||
// 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
|
||||
// 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
|
||||
// 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
|
||||
// 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
|
||||
//
|
||||
// c=constant k=key b=blockcount n=nonce
|
||||
var (
|
||||
c0, c1, c2, c3 = j0, j1, j2, j3
|
||||
c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3]
|
||||
c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
|
||||
_, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
|
||||
)
|
||||
|
||||
// Three quarters of the first round don't depend on the counter, so we can
|
||||
// calculate them here, and reuse them for multiple blocks in the loop, and
|
||||
// for future XORKeyStream invocations.
|
||||
if !s.precompDone {
|
||||
s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
|
||||
s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
|
||||
s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
|
||||
s.precompDone = true
|
||||
}
|
||||
|
||||
// A condition of len(src) > 0 would be sufficient, but this also
|
||||
// acts as a bounds check elimination hint.
|
||||
for len(src) >= 64 && len(dst) >= 64 {
|
||||
// The remainder of the first column round.
|
||||
fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
|
||||
|
||||
// The second diagonal round.
|
||||
x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
|
||||
x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
|
||||
x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
|
||||
x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)
|
||||
|
||||
// The remaining 18 rounds.
|
||||
for i := 0; i < 9; i++ {
|
||||
// Column round.
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
||||
|
||||
// Diagonal round.
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
// Add back the initial state to generate the key stream, then
|
||||
// XOR the key stream with the source and write out the result.
|
||||
addXor(dst[0:4], src[0:4], x0, c0)
|
||||
addXor(dst[4:8], src[4:8], x1, c1)
|
||||
addXor(dst[8:12], src[8:12], x2, c2)
|
||||
addXor(dst[12:16], src[12:16], x3, c3)
|
||||
addXor(dst[16:20], src[16:20], x4, c4)
|
||||
addXor(dst[20:24], src[20:24], x5, c5)
|
||||
addXor(dst[24:28], src[24:28], x6, c6)
|
||||
addXor(dst[28:32], src[28:32], x7, c7)
|
||||
addXor(dst[32:36], src[32:36], x8, c8)
|
||||
addXor(dst[36:40], src[36:40], x9, c9)
|
||||
addXor(dst[40:44], src[40:44], x10, c10)
|
||||
addXor(dst[44:48], src[44:48], x11, c11)
|
||||
addXor(dst[48:52], src[48:52], x12, s.counter)
|
||||
addXor(dst[52:56], src[52:56], x13, c13)
|
||||
addXor(dst[56:60], src[56:60], x14, c14)
|
||||
addXor(dst[60:64], src[60:64], x15, c15)
|
||||
|
||||
s.counter += 1
|
||||
|
||||
src, dst = src[blockSize:], dst[blockSize:]
|
||||
}
|
||||
}
|
||||
|
||||
// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
|
||||
// key and a 16 bytes nonce. It returns an error if key or nonce have any other
|
||||
// length. It is used as part of the XChaCha20 construction.
|
||||
func HChaCha20(key, nonce []byte) ([]byte, error) {
|
||||
// This function is split into a wrapper so that the slice allocation will
|
||||
// be inlined, and depending on how the caller uses the return value, won't
|
||||
// escape to the heap.
|
||||
out := make([]byte, 32)
|
||||
return hChaCha20(out, key, nonce)
|
||||
}
|
||||
|
||||
func hChaCha20(out, key, nonce []byte) ([]byte, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20: wrong HChaCha20 key size")
|
||||
}
|
||||
if len(nonce) != 16 {
|
||||
return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
|
||||
}
|
||||
|
||||
x0, x1, x2, x3 := j0, j1, j2, j3
|
||||
x4 := binary.LittleEndian.Uint32(key[0:4])
|
||||
x5 := binary.LittleEndian.Uint32(key[4:8])
|
||||
x6 := binary.LittleEndian.Uint32(key[8:12])
|
||||
x7 := binary.LittleEndian.Uint32(key[12:16])
|
||||
x8 := binary.LittleEndian.Uint32(key[16:20])
|
||||
x9 := binary.LittleEndian.Uint32(key[20:24])
|
||||
x10 := binary.LittleEndian.Uint32(key[24:28])
|
||||
x11 := binary.LittleEndian.Uint32(key[28:32])
|
||||
x12 := binary.LittleEndian.Uint32(nonce[0:4])
|
||||
x13 := binary.LittleEndian.Uint32(nonce[4:8])
|
||||
x14 := binary.LittleEndian.Uint32(nonce[8:12])
|
||||
x15 := binary.LittleEndian.Uint32(nonce[12:16])
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
// Diagonal round.
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
||||
|
||||
// Column round.
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
_ = out[31] // bounds check elimination hint
|
||||
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||
binary.LittleEndian.PutUint32(out[16:20], x12)
|
||||
binary.LittleEndian.PutUint32(out[20:24], x13)
|
||||
binary.LittleEndian.PutUint32(out[24:28], x14)
|
||||
binary.LittleEndian.PutUint32(out[28:32], x15)
|
||||
return out, nil
|
||||
}
|
||||
Generated
Vendored
+4
-7
@@ -2,15 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo appengine
|
||||
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo purego
|
||||
|
||||
package chacha20
|
||||
|
||||
const (
|
||||
bufSize = 64
|
||||
haveAsm = false
|
||||
)
|
||||
const bufSize = blockSize
|
||||
|
||||
func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
|
||||
panic("not implemented")
|
||||
func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
|
||||
s.xorKeyStreamBlocksGeneric(dst, src)
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright 2019 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 !gccgo,!purego
|
||||
|
||||
package chacha20
|
||||
|
||||
const bufSize = 256
|
||||
|
||||
//go:noescape
|
||||
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
||||
|
||||
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
|
||||
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
|
||||
}
|
||||
Generated
Vendored
+7
-23
@@ -19,7 +19,7 @@
|
||||
// The differences in this and the original implementation are
|
||||
// due to the calling conventions and initialization of constants.
|
||||
|
||||
// +build ppc64le,!gccgo,!appengine
|
||||
// +build !gccgo,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
@@ -31,24 +31,7 @@
|
||||
#define TMP R15
|
||||
|
||||
#define CONSTBASE R16
|
||||
|
||||
#define X0 R11
|
||||
#define X1 R12
|
||||
#define X2 R14
|
||||
#define X3 R15
|
||||
#define X4 R16
|
||||
#define X5 R17
|
||||
#define X6 R18
|
||||
#define X7 R19
|
||||
#define X8 R20
|
||||
#define X9 R21
|
||||
#define X10 R22
|
||||
#define X11 R23
|
||||
#define X12 R24
|
||||
#define X13 R25
|
||||
#define X14 R26
|
||||
#define X15 R27
|
||||
|
||||
#define BLOCKS R17
|
||||
|
||||
DATA consts<>+0x00(SB)/8, $0x3320646e61707865
|
||||
DATA consts<>+0x08(SB)/8, $0x6b20657479622d32
|
||||
@@ -72,13 +55,13 @@ DATA consts<>+0x90(SB)/8, $0x0000000100000000
|
||||
DATA consts<>+0x98(SB)/8, $0x0000000300000002
|
||||
GLOBL consts<>(SB), RODATA, $0xa0
|
||||
|
||||
//func chaCha20_ctr32_vsx(out, inp []byte, len int, key *[32]byte, counter *[16]byte)
|
||||
//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
||||
TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
|
||||
MOVD out+0(FP), OUT
|
||||
MOVD inp+8(FP), INP
|
||||
MOVD len+16(FP), LEN
|
||||
MOVD key+24(FP), KEY
|
||||
MOVD cnt+32(FP), CNT
|
||||
MOVD counter+32(FP), CNT
|
||||
|
||||
// Addressing for constants
|
||||
MOVD $consts<>+0x00(SB), CONSTBASE
|
||||
@@ -86,6 +69,7 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
|
||||
MOVD $32, R9
|
||||
MOVD $48, R10
|
||||
MOVD $64, R11
|
||||
SRD $6, LEN, BLOCKS
|
||||
// V16
|
||||
LXVW4X (CONSTBASE)(R0), VS48
|
||||
ADD $80,CONSTBASE
|
||||
@@ -429,9 +413,9 @@ loop_vsx:
|
||||
BNE loop_outer_vsx
|
||||
|
||||
done_vsx:
|
||||
// Increment counter by 4
|
||||
// Increment counter by number of 64 byte blocks
|
||||
MOVD (CNT), R14
|
||||
ADD $4, R14
|
||||
ADD BLOCKS, R14
|
||||
MOVD R14, (CNT)
|
||||
RET
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo,!purego
|
||||
|
||||
package chacha20
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
var haveAsm = cpu.S390X.HasVX
|
||||
|
||||
const bufSize = 256
|
||||
|
||||
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
|
||||
// be called when the vector facility is available. Implementation in asm_s390x.s.
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
||||
|
||||
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
|
||||
if cpu.S390X.HasVX {
|
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
|
||||
} else {
|
||||
c.xorKeyStreamBlocksGeneric(dst, src)
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+2
-38
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build s390x,!gccgo,!appengine
|
||||
// +build !gccgo,!purego
|
||||
|
||||
#include "go_asm.h"
|
||||
#include "textflag.h"
|
||||
@@ -24,15 +24,6 @@ DATA ·constants<>+0x14(SB)/4, $0x3320646e
|
||||
DATA ·constants<>+0x18(SB)/4, $0x79622d32
|
||||
DATA ·constants<>+0x1c(SB)/4, $0x6b206574
|
||||
|
||||
// EXRL targets:
|
||||
TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0
|
||||
MVC $1, (R1), (R8)
|
||||
RET
|
||||
|
||||
TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0
|
||||
MVC $1, (R8), (R9)
|
||||
RET
|
||||
|
||||
#define BSWAP V5
|
||||
#define J0 V6
|
||||
#define KEY0 V7
|
||||
@@ -144,7 +135,7 @@ TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0
|
||||
VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]}
|
||||
VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]}
|
||||
|
||||
// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
|
||||
// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
||||
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
|
||||
MOVD $·constants<>(SB), R1
|
||||
MOVD dst+0(FP), R2 // R2=&dst[0]
|
||||
@@ -152,25 +143,10 @@ TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
|
||||
MOVD key+48(FP), R5 // R5=key
|
||||
MOVD nonce+56(FP), R6 // R6=nonce
|
||||
MOVD counter+64(FP), R7 // R7=counter
|
||||
MOVD buf+72(FP), R8 // R8=buf
|
||||
MOVD len+80(FP), R9 // R9=len
|
||||
|
||||
// load BSWAP and J0
|
||||
VLM (R1), BSWAP, J0
|
||||
|
||||
// set up tail buffer
|
||||
ADD $-1, R4, R12
|
||||
MOVBZ R12, R12
|
||||
CMPUBEQ R12, $255, aligned
|
||||
MOVD R4, R1
|
||||
AND $~255, R1
|
||||
MOVD $(R3)(R1*1), R1
|
||||
EXRL $·mvcSrcToBuf(SB), R12
|
||||
MOVD $255, R0
|
||||
SUB R12, R0
|
||||
MOVD R0, (R9) // update len
|
||||
|
||||
aligned:
|
||||
// setup
|
||||
MOVD $95, R0
|
||||
VLM (R5), KEY0, KEY1
|
||||
@@ -217,9 +193,7 @@ loop:
|
||||
|
||||
// decrement length
|
||||
ADD $-256, R4
|
||||
BLT tail
|
||||
|
||||
continue:
|
||||
// rearrange vectors
|
||||
SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3)
|
||||
ADDV(J0, X0, X1, X2, X3)
|
||||
@@ -245,16 +219,6 @@ continue:
|
||||
MOVD $256(R3), R3
|
||||
|
||||
CMPBNE R4, $0, chacha
|
||||
CMPUBEQ R12, $255, return
|
||||
EXRL $·mvcBufToDst(SB), R12 // len was updated during setup
|
||||
|
||||
return:
|
||||
VSTEF $0, CTR, (R7)
|
||||
RET
|
||||
|
||||
tail:
|
||||
MOVD R2, R9
|
||||
MOVD R8, R2
|
||||
MOVD R8, R3
|
||||
MOVD $0, R4
|
||||
JMP continue
|
||||
Generated
Vendored
+10
-11
@@ -4,9 +4,7 @@
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
import "runtime"
|
||||
|
||||
// Platforms that have fast unaligned 32-bit little endian accesses.
|
||||
const unaligned = runtime.GOARCH == "386" ||
|
||||
@@ -15,10 +13,10 @@ const unaligned = runtime.GOARCH == "386" ||
|
||||
runtime.GOARCH == "ppc64le" ||
|
||||
runtime.GOARCH == "s390x"
|
||||
|
||||
// xor reads a little endian uint32 from src, XORs it with u and
|
||||
// addXor reads a little endian uint32 from src, XORs it with (a + b) and
|
||||
// places the result in little endian byte order in dst.
|
||||
func xor(dst, src []byte, u uint32) {
|
||||
_, _ = src[3], dst[3] // eliminate bounds checks
|
||||
func addXor(dst, src []byte, a, b uint32) {
|
||||
_, _ = src[3], dst[3] // bounds check elimination hint
|
||||
if unaligned {
|
||||
// The compiler should optimize this code into
|
||||
// 32-bit unaligned little endian loads and stores.
|
||||
@@ -29,15 +27,16 @@ func xor(dst, src []byte, u uint32) {
|
||||
v |= uint32(src[1]) << 8
|
||||
v |= uint32(src[2]) << 16
|
||||
v |= uint32(src[3]) << 24
|
||||
v ^= u
|
||||
v ^= a + b
|
||||
dst[0] = byte(v)
|
||||
dst[1] = byte(v >> 8)
|
||||
dst[2] = byte(v >> 16)
|
||||
dst[3] = byte(v >> 24)
|
||||
} else {
|
||||
dst[0] = src[0] ^ byte(u)
|
||||
dst[1] = src[1] ^ byte(u>>8)
|
||||
dst[2] = src[2] ^ byte(u>>16)
|
||||
dst[3] = src[3] ^ byte(u>>24)
|
||||
a += b
|
||||
dst[0] = src[0] ^ byte(a)
|
||||
dst[1] = src[1] ^ byte(a>>8)
|
||||
dst[2] = src[2] ^ byte(a>>16)
|
||||
dst[3] = src[3] ^ byte(a>>24)
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
// 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
@@ -1,20 +0,0 @@
|
||||
// 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
@@ -1,65 +0,0 @@
|
||||
// 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
|
||||
+79
-818
@@ -1,834 +1,95 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Copyright 2019 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
|
||||
// Package curve25519 provides an implementation of the X25519 function, which
|
||||
// performs scalar multiplication on the elliptic curve known as Curve25519.
|
||||
// See RFC 7748.
|
||||
package curve25519 // import "golang.org/x/crypto/curve25519"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// This code is a port of the public domain, "ref10" implementation of
|
||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
||||
// ScalarMult sets dst to the product scalar * point.
|
||||
//
|
||||
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
|
||||
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
|
||||
// will return an error.
|
||||
func ScalarMult(dst, scalar, point *[32]byte) {
|
||||
scalarMult(dst, scalar, point)
|
||||
}
|
||||
|
||||
// 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
|
||||
// ScalarBaseMult sets dst to the product scalar * base where base is the
|
||||
// standard generator.
|
||||
//
|
||||
// It is recommended to use the X25519 function with Basepoint instead, as
|
||||
// copying into fixed size arrays can lead to unexpected bugs.
|
||||
func ScalarBaseMult(dst, scalar *[32]byte) {
|
||||
ScalarMult(dst, scalar, &basePoint)
|
||||
}
|
||||
|
||||
func feZero(fe *fieldElement) {
|
||||
for i := range fe {
|
||||
fe[i] = 0
|
||||
const (
|
||||
// ScalarSize is the size of the scalar input to X25519.
|
||||
ScalarSize = 32
|
||||
// PointSize is the size of the point input to X25519.
|
||||
PointSize = 32
|
||||
)
|
||||
|
||||
// Basepoint is the canonical Curve25519 generator.
|
||||
var Basepoint []byte
|
||||
|
||||
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}
|
||||
|
||||
func init() { Basepoint = basePoint[:] }
|
||||
|
||||
func checkBasepoint() {
|
||||
if subtle.ConstantTimeCompare(Basepoint, []byte{
|
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}) != 1 {
|
||||
panic("curve25519: global Basepoint value was modified")
|
||||
}
|
||||
}
|
||||
|
||||
func feOne(fe *fieldElement) {
|
||||
feZero(fe)
|
||||
fe[0] = 1
|
||||
// X25519 returns the result of the scalar multiplication (scalar * point),
|
||||
// according to RFC 7748, Section 5. scalar, point and the return value are
|
||||
// slices of 32 bytes.
|
||||
//
|
||||
// scalar can be generated at random, for example with crypto/rand. point should
|
||||
// be either Basepoint or the output of another X25519 call.
|
||||
//
|
||||
// If point is Basepoint (but not if it's a different slice with the same
|
||||
// contents) a precomputed implementation might be used for performance.
|
||||
func X25519(scalar, point []byte) ([]byte, error) {
|
||||
// Outline the body of function, to let the allocation be inlined in the
|
||||
// caller, and possibly avoid escaping to the heap.
|
||||
var dst [32]byte
|
||||
return x25519(&dst, scalar, point)
|
||||
}
|
||||
|
||||
func feAdd(dst, a, b *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = a[i] + b[i]
|
||||
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
|
||||
var in [32]byte
|
||||
if l := len(scalar); l != 32 {
|
||||
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32)
|
||||
}
|
||||
}
|
||||
|
||||
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:]) & 0x7fffff) << 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)
|
||||
if l := len(point); l != 32 {
|
||||
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32)
|
||||
}
|
||||
copy(in[:], scalar)
|
||||
if &point[0] == &Basepoint[0] {
|
||||
checkBasepoint()
|
||||
ScalarBaseMult(dst, &in)
|
||||
} else {
|
||||
var base, zero [32]byte
|
||||
copy(base[:], point)
|
||||
ScalarMult(dst, &in, &base)
|
||||
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
|
||||
return nil, fmt.Errorf("bad input point: low order point")
|
||||
}
|
||||
}
|
||||
return dst[:], nil
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
// +build amd64,!gccgo,!appengine,!purego
|
||||
|
||||
package curve25519
|
||||
|
||||
Generated
Vendored
+418
-2
@@ -5,9 +5,84 @@
|
||||
// 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
|
||||
// +build amd64,!gccgo,!appengine,!purego
|
||||
|
||||
#include "const_amd64.h"
|
||||
#define REDMASK51 0x0007FFFFFFFFFFFF
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// func ladderstep(inout *[5][5]uint64)
|
||||
TEXT ·ladderstep(SB),0,$296-8
|
||||
@@ -1375,3 +1450,344 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MOVQ AX,104(DI)
|
||||
MOVQ R10,112(DI)
|
||||
RET
|
||||
|
||||
// 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
|
||||
|
||||
// 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,R8,R9
|
||||
ANDQ SI,R8
|
||||
SHLQ $13,R10,R11
|
||||
ANDQ SI,R10
|
||||
ADDQ R9,R10
|
||||
SHLQ $13,R12,R13
|
||||
ANDQ SI,R12
|
||||
ADDQ R11,R12
|
||||
SHLQ $13,R14,R15
|
||||
ANDQ SI,R14
|
||||
ADDQ R13,R14
|
||||
SHLQ $13,BX,BP
|
||||
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
|
||||
|
||||
// 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,CX,R8
|
||||
ANDQ SI,CX
|
||||
SHLQ $13,R9,R10
|
||||
ANDQ SI,R9
|
||||
ADDQ R8,R9
|
||||
SHLQ $13,R11,R12
|
||||
ANDQ SI,R11
|
||||
ADDQ R10,R11
|
||||
SHLQ $13,R13,R14
|
||||
ANDQ SI,R13
|
||||
ADDQ R12,R13
|
||||
SHLQ $13,R15,BX
|
||||
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
|
||||
+828
@@ -0,0 +1,828 @@
|
||||
// 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.
|
||||
|
||||
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:]) & 0x7fffff) << 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 scalarMultGeneric(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)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2019 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 purego
|
||||
|
||||
package curve25519
|
||||
|
||||
func scalarMult(out, in, base *[32]byte) {
|
||||
scalarMultGeneric(out, in, base)
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// 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
@@ -1,73 +0,0 @@
|
||||
// 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
|
||||
-169
@@ -1,169 +0,0 @@
|
||||
// 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,R8,R9
|
||||
ANDQ SI,R8
|
||||
SHLQ $13,R10,R11
|
||||
ANDQ SI,R10
|
||||
ADDQ R9,R10
|
||||
SHLQ $13,R12,R13
|
||||
ANDQ SI,R12
|
||||
ADDQ R11,R12
|
||||
SHLQ $13,R14,R15
|
||||
ANDQ SI,R14
|
||||
ADDQ R13,R14
|
||||
SHLQ $13,BX,BP
|
||||
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
@@ -1,132 +0,0 @@
|
||||
// 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,CX,R8
|
||||
ANDQ SI,CX
|
||||
SHLQ $13,R9,R10
|
||||
ANDQ SI,R9
|
||||
ADDQ R8,R9
|
||||
SHLQ $13,R11,R12
|
||||
ANDQ SI,R11
|
||||
ADDQ R10,R11
|
||||
SHLQ $13,R13,R14
|
||||
ANDQ SI,R13
|
||||
ADDQ R12,R13
|
||||
SHLQ $13,R15,BX
|
||||
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
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.11
|
||||
// +build !gccgo
|
||||
|
||||
package chacha20
|
||||
|
||||
const (
|
||||
haveAsm = true
|
||||
bufSize = 256
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
|
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
||||
|
||||
if len(src) >= bufSize {
|
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
|
||||
}
|
||||
|
||||
if len(src)%bufSize != 0 {
|
||||
i := len(src) - len(src)%bufSize
|
||||
c.buf = [bufSize]byte{}
|
||||
copy(c.buf[:], src[i:])
|
||||
xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter)
|
||||
c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize])
|
||||
}
|
||||
}
|
||||
-264
@@ -1,264 +0,0 @@
|
||||
// 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 ChaCha20 implements the core ChaCha20 function as specified
|
||||
// in https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
)
|
||||
|
||||
// assert that *Cipher implements cipher.Stream
|
||||
var _ cipher.Stream = (*Cipher)(nil)
|
||||
|
||||
// Cipher is a stateful instance of ChaCha20 using a particular key
|
||||
// and nonce. A *Cipher implements the cipher.Stream interface.
|
||||
type Cipher struct {
|
||||
key [8]uint32
|
||||
counter uint32 // incremented after each block
|
||||
nonce [3]uint32
|
||||
buf [bufSize]byte // buffer for unused keystream bytes
|
||||
len int // number of unused keystream bytes at end of buf
|
||||
}
|
||||
|
||||
// New creates a new ChaCha20 stream cipher with the given key and nonce.
|
||||
// The initial counter value is set to 0.
|
||||
func New(key [8]uint32, nonce [3]uint32) *Cipher {
|
||||
return &Cipher{key: key, nonce: nonce}
|
||||
}
|
||||
|
||||
// ChaCha20 constants spelling "expand 32-byte k"
|
||||
const (
|
||||
j0 uint32 = 0x61707865
|
||||
j1 uint32 = 0x3320646e
|
||||
j2 uint32 = 0x79622d32
|
||||
j3 uint32 = 0x6b206574
|
||||
)
|
||||
|
||||
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
|
||||
a += b
|
||||
d ^= a
|
||||
d = (d << 16) | (d >> 16)
|
||||
c += d
|
||||
b ^= c
|
||||
b = (b << 12) | (b >> 20)
|
||||
a += b
|
||||
d ^= a
|
||||
d = (d << 8) | (d >> 24)
|
||||
c += d
|
||||
b ^= c
|
||||
b = (b << 7) | (b >> 25)
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, XORKeyStream will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to XORKeyStream behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, Cipher
|
||||
// maintains state and does not reset at each XORKeyStream call.
|
||||
func (s *Cipher) XORKeyStream(dst, src []byte) {
|
||||
if len(dst) < len(src) {
|
||||
panic("chacha20: output smaller than input")
|
||||
}
|
||||
if subtle.InexactOverlap(dst[:len(src)], src) {
|
||||
panic("chacha20: invalid buffer overlap")
|
||||
}
|
||||
|
||||
// xor src with buffered keystream first
|
||||
if s.len != 0 {
|
||||
buf := s.buf[len(s.buf)-s.len:]
|
||||
if len(src) < len(buf) {
|
||||
buf = buf[:len(src)]
|
||||
}
|
||||
td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
|
||||
for i, b := range buf {
|
||||
td[i] = ts[i] ^ b
|
||||
}
|
||||
s.len -= len(buf)
|
||||
if s.len != 0 {
|
||||
return
|
||||
}
|
||||
s.buf = [len(s.buf)]byte{} // zero the empty buffer
|
||||
src = src[len(buf):]
|
||||
dst = dst[len(buf):]
|
||||
}
|
||||
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
if haveAsm {
|
||||
if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
|
||||
panic("chacha20: counter overflow")
|
||||
}
|
||||
s.xorKeyStreamAsm(dst, src)
|
||||
return
|
||||
}
|
||||
|
||||
// set up a 64-byte buffer to pad out the final block if needed
|
||||
// (hoisted out of the main loop to avoid spills)
|
||||
rem := len(src) % 64 // length of final block
|
||||
fin := len(src) - rem // index of final block
|
||||
if rem > 0 {
|
||||
copy(s.buf[len(s.buf)-64:], src[fin:])
|
||||
}
|
||||
|
||||
// pre-calculate most of the first round
|
||||
s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
|
||||
s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
|
||||
s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
|
||||
|
||||
n := len(src)
|
||||
src, dst = src[:n:n], dst[:n:n] // BCE hint
|
||||
for i := 0; i < n; i += 64 {
|
||||
// calculate the remainder of the first round
|
||||
s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
|
||||
|
||||
// execute the second round
|
||||
x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
|
||||
x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
|
||||
x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
|
||||
x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
|
||||
|
||||
// execute the remaining 18 rounds
|
||||
for i := 0; i < 9; i++ {
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
||||
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
x0 += j0
|
||||
x1 += j1
|
||||
x2 += j2
|
||||
x3 += j3
|
||||
|
||||
x4 += s.key[0]
|
||||
x5 += s.key[1]
|
||||
x6 += s.key[2]
|
||||
x7 += s.key[3]
|
||||
x8 += s.key[4]
|
||||
x9 += s.key[5]
|
||||
x10 += s.key[6]
|
||||
x11 += s.key[7]
|
||||
|
||||
x12 += s.counter
|
||||
x13 += s.nonce[0]
|
||||
x14 += s.nonce[1]
|
||||
x15 += s.nonce[2]
|
||||
|
||||
// increment the counter
|
||||
s.counter += 1
|
||||
if s.counter == 0 {
|
||||
panic("chacha20: counter overflow")
|
||||
}
|
||||
|
||||
// pad to 64 bytes if needed
|
||||
in, out := src[i:], dst[i:]
|
||||
if i == fin {
|
||||
// src[fin:] has already been copied into s.buf before
|
||||
// the main loop
|
||||
in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
|
||||
}
|
||||
in, out = in[:64], out[:64] // BCE hint
|
||||
|
||||
// XOR the key stream with the source and write out the result
|
||||
xor(out[0:], in[0:], x0)
|
||||
xor(out[4:], in[4:], x1)
|
||||
xor(out[8:], in[8:], x2)
|
||||
xor(out[12:], in[12:], x3)
|
||||
xor(out[16:], in[16:], x4)
|
||||
xor(out[20:], in[20:], x5)
|
||||
xor(out[24:], in[24:], x6)
|
||||
xor(out[28:], in[28:], x7)
|
||||
xor(out[32:], in[32:], x8)
|
||||
xor(out[36:], in[36:], x9)
|
||||
xor(out[40:], in[40:], x10)
|
||||
xor(out[44:], in[44:], x11)
|
||||
xor(out[48:], in[48:], x12)
|
||||
xor(out[52:], in[52:], x13)
|
||||
xor(out[56:], in[56:], x14)
|
||||
xor(out[60:], in[60:], x15)
|
||||
}
|
||||
// copy any trailing bytes out of the buffer and into dst
|
||||
if rem != 0 {
|
||||
s.len = 64 - rem
|
||||
copy(dst[fin:], s.buf[len(s.buf)-64:])
|
||||
}
|
||||
}
|
||||
|
||||
// Advance discards bytes in the key stream until the next 64 byte block
|
||||
// boundary is reached and updates the counter accordingly. If the key
|
||||
// stream is already at a block boundary no bytes will be discarded and
|
||||
// the counter will be unchanged.
|
||||
func (s *Cipher) Advance() {
|
||||
s.len -= s.len % 64
|
||||
if s.len == 0 {
|
||||
s.buf = [len(s.buf)]byte{}
|
||||
}
|
||||
}
|
||||
|
||||
// XORKeyStream crypts bytes from in to out using the given key and counters.
|
||||
// In and out must overlap entirely or not at all. Counter contains the raw
|
||||
// ChaCha20 counter bytes (i.e. block counter followed by nonce).
|
||||
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
|
||||
s := Cipher{
|
||||
key: [8]uint32{
|
||||
binary.LittleEndian.Uint32(key[0:4]),
|
||||
binary.LittleEndian.Uint32(key[4:8]),
|
||||
binary.LittleEndian.Uint32(key[8:12]),
|
||||
binary.LittleEndian.Uint32(key[12:16]),
|
||||
binary.LittleEndian.Uint32(key[16:20]),
|
||||
binary.LittleEndian.Uint32(key[20:24]),
|
||||
binary.LittleEndian.Uint32(key[24:28]),
|
||||
binary.LittleEndian.Uint32(key[28:32]),
|
||||
},
|
||||
nonce: [3]uint32{
|
||||
binary.LittleEndian.Uint32(counter[4:8]),
|
||||
binary.LittleEndian.Uint32(counter[8:12]),
|
||||
binary.LittleEndian.Uint32(counter[12:16]),
|
||||
},
|
||||
counter: binary.LittleEndian.Uint32(counter[0:4]),
|
||||
}
|
||||
s.XORKeyStream(out, in)
|
||||
}
|
||||
|
||||
// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
|
||||
// nonce. It should only be used as part of the XChaCha20 construction.
|
||||
func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
|
||||
x0, x1, x2, x3 := j0, j1, j2, j3
|
||||
x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
|
||||
x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
|
||||
x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
||||
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
var out [8]uint32
|
||||
out[0], out[1], out[2], out[3] = x0, x1, x2, x3
|
||||
out[4], out[5], out[6], out[7] = x12, x13, x14, x15
|
||||
return out
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
// Copyright 2019 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 ppc64le,!gccgo,!appengine
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
var haveAsm = true
|
||||
|
||||
const bufSize = 256
|
||||
|
||||
//go:noescape
|
||||
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
||||
// This implementation can handle buffers that aren't multiples of
|
||||
// 256.
|
||||
if len(src) >= bufSize {
|
||||
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
|
||||
} else if len(src)%bufSize != 0 {
|
||||
chaCha20_ctr32_vsx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
||||
start := len(src) - len(src)%bufSize
|
||||
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
||||
// Unroll loop to XOR 32 bytes per iteration.
|
||||
for i := 0; i < len(ts)-32; i += 32 {
|
||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
||||
s0 := binary.LittleEndian.Uint64(ts[0:8])
|
||||
s1 := binary.LittleEndian.Uint64(ts[8:16])
|
||||
s2 := binary.LittleEndian.Uint64(ts[16:24])
|
||||
s3 := binary.LittleEndian.Uint64(ts[24:32])
|
||||
b0 := binary.LittleEndian.Uint64(tb[0:8])
|
||||
b1 := binary.LittleEndian.Uint64(tb[8:16])
|
||||
b2 := binary.LittleEndian.Uint64(tb[16:24])
|
||||
b3 := binary.LittleEndian.Uint64(tb[24:32])
|
||||
binary.LittleEndian.PutUint64(td[0:8], s0^b0)
|
||||
binary.LittleEndian.PutUint64(td[8:16], s1^b1)
|
||||
binary.LittleEndian.PutUint64(td[16:24], s2^b2)
|
||||
binary.LittleEndian.PutUint64(td[24:32], s3^b3)
|
||||
ts, td, tb = ts[32:], td[32:], tb[32:]
|
||||
}
|
||||
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
||||
for i, v := range ts {
|
||||
td[i] = tb[i] ^ v
|
||||
}
|
||||
c.len = bufSize - (len(src) % bufSize)
|
||||
}
|
||||
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build s390x,!gccgo,!appengine
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
var haveAsm = cpu.S390X.HasVX
|
||||
|
||||
const bufSize = 256
|
||||
|
||||
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
|
||||
// be called when the vector facility is available.
|
||||
// Implementation in asm_s390x.s.
|
||||
//go:noescape
|
||||
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
|
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
||||
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len)
|
||||
}
|
||||
|
||||
// EXRL targets, DO NOT CALL!
|
||||
func mvcSrcToBuf()
|
||||
func mvcBufToDst()
|
||||
+81
-2
@@ -31,19 +31,30 @@ Thus large amounts of data should be chunked so that each message is small.
|
||||
chunk size.
|
||||
|
||||
This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
|
||||
Anonymous sealing/opening is an extension of NaCl defined by and interoperable
|
||||
with libsodium:
|
||||
https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
|
||||
*/
|
||||
package box // import "golang.org/x/crypto/nacl/box"
|
||||
|
||||
import (
|
||||
cryptorand "crypto/rand"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
"golang.org/x/crypto/salsa20/salsa"
|
||||
)
|
||||
|
||||
// Overhead is the number of bytes of overhead when boxing a message.
|
||||
const Overhead = secretbox.Overhead
|
||||
const (
|
||||
// Overhead is the number of bytes of overhead when boxing a message.
|
||||
Overhead = secretbox.Overhead
|
||||
|
||||
// AnonymousOverhead is the number of bytes of overhead when using anonymous
|
||||
// sealed boxes.
|
||||
AnonymousOverhead = Overhead + 32
|
||||
)
|
||||
|
||||
// GenerateKey generates a new public/private key pair suitable for use with
|
||||
// Seal and Open.
|
||||
@@ -101,3 +112,71 @@ func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte
|
||||
func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) {
|
||||
return secretbox.Open(out, box, nonce, sharedKey)
|
||||
}
|
||||
|
||||
// SealAnonymous appends an encrypted and authenticated copy of message to out,
|
||||
// which will be AnonymousOverhead bytes longer than the original and must not
|
||||
// overlap it. This differs from Seal in that the sender is not required to
|
||||
// provide a private key.
|
||||
func SealAnonymous(out, message []byte, recipient *[32]byte, rand io.Reader) ([]byte, error) {
|
||||
if rand == nil {
|
||||
rand = cryptorand.Reader
|
||||
}
|
||||
ephemeralPub, ephemeralPriv, err := GenerateKey(rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nonce [24]byte
|
||||
if err := sealNonce(ephemeralPub, recipient, &nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if total := len(out) + AnonymousOverhead + len(message); cap(out) < total {
|
||||
original := out
|
||||
out = make([]byte, 0, total)
|
||||
out = append(out, original...)
|
||||
}
|
||||
out = append(out, ephemeralPub[:]...)
|
||||
|
||||
return Seal(out, message, &nonce, recipient, ephemeralPriv), nil
|
||||
}
|
||||
|
||||
// OpenAnonymous authenticates and decrypts a box produced by SealAnonymous and
|
||||
// appends the message to out, which must not overlap box. The output will be
|
||||
// AnonymousOverhead bytes smaller than box.
|
||||
func OpenAnonymous(out, box []byte, publicKey, privateKey *[32]byte) (message []byte, ok bool) {
|
||||
if len(box) < AnonymousOverhead {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var ephemeralPub [32]byte
|
||||
copy(ephemeralPub[:], box[:32])
|
||||
|
||||
var nonce [24]byte
|
||||
if err := sealNonce(&ephemeralPub, publicKey, &nonce); err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return Open(out, box[32:], &nonce, &ephemeralPub, privateKey)
|
||||
}
|
||||
|
||||
// sealNonce generates a 24 byte nonce that is a blake2b digest of the
|
||||
// ephemeral public key and the receiver's public key.
|
||||
func sealNonce(ephemeralPub, peersPublicKey *[32]byte, nonce *[24]byte) error {
|
||||
h, err := blake2b.New(24, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = h.Write(ephemeralPub[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = h.Write(peersPublicKey[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Sum(nonce[:0])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2019 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.13
|
||||
|
||||
package poly1305
|
||||
|
||||
// Generic fallbacks for the math/bits intrinsics, copied from
|
||||
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
|
||||
// variable time fallbacks until Go 1.13.
|
||||
|
||||
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
|
||||
sum = x + y + carry
|
||||
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
|
||||
return
|
||||
}
|
||||
|
||||
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
|
||||
diff = x - y - borrow
|
||||
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
|
||||
return
|
||||
}
|
||||
|
||||
func bitsMul64(x, y uint64) (hi, lo uint64) {
|
||||
const mask32 = 1<<32 - 1
|
||||
x0 := x & mask32
|
||||
x1 := x >> 32
|
||||
y0 := y & mask32
|
||||
y1 := y >> 32
|
||||
w0 := x0 * y0
|
||||
t := x1*y0 + w0>>32
|
||||
w1 := t & mask32
|
||||
w2 := t >> 32
|
||||
w1 += x0 * y1
|
||||
hi = x1*y1 + w2 + w1>>32
|
||||
lo = x * y
|
||||
return
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// Copyright 2019 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.13
|
||||
|
||||
package poly1305
|
||||
|
||||
import "math/bits"
|
||||
|
||||
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
|
||||
return bits.Add64(x, y, carry)
|
||||
}
|
||||
|
||||
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
|
||||
return bits.Sub64(x, y, borrow)
|
||||
}
|
||||
|
||||
func bitsMul64(x, y uint64) (hi, lo uint64) {
|
||||
return bits.Mul64(x, y)
|
||||
}
|
||||
+1
-3
@@ -2,10 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64,!ppc64le gccgo appengine
|
||||
// +build !amd64,!ppc64le,!s390x gccgo purego
|
||||
|
||||
package poly1305
|
||||
|
||||
type mac struct{ macGeneric }
|
||||
|
||||
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }
|
||||
|
||||
+25
-9
@@ -22,8 +22,16 @@ import "crypto/subtle"
|
||||
// TagSize is the size, in bytes, of a poly1305 authenticator.
|
||||
const TagSize = 16
|
||||
|
||||
// Verify returns true if mac is a valid authenticator for m with the given
|
||||
// key.
|
||||
// Sum generates an authenticator for msg using a one-time key and puts the
|
||||
// 16-byte result into out. Authenticating two different messages with the same
|
||||
// key allows an attacker to forge messages at will.
|
||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
||||
h := New(key)
|
||||
h.Write(m)
|
||||
h.Sum(out[:0])
|
||||
}
|
||||
|
||||
// Verify returns true if mac is a valid authenticator for m with the given key.
|
||||
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
|
||||
var tmp [16]byte
|
||||
Sum(&tmp, m, key)
|
||||
@@ -40,10 +48,9 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
|
||||
// two different messages with the same key allows an attacker
|
||||
// to forge messages at will.
|
||||
func New(key *[32]byte) *MAC {
|
||||
return &MAC{
|
||||
mac: newMAC(key),
|
||||
finalized: false,
|
||||
}
|
||||
m := &MAC{}
|
||||
initialize(key, &m.macState)
|
||||
return m
|
||||
}
|
||||
|
||||
// MAC is an io.Writer computing an authentication tag
|
||||
@@ -52,7 +59,7 @@ func New(key *[32]byte) *MAC {
|
||||
// MAC cannot be used like common hash.Hash implementations,
|
||||
// because using a poly1305 key twice breaks its security.
|
||||
// Therefore writing data to a running MAC after calling
|
||||
// Sum causes it to panic.
|
||||
// Sum or Verify causes it to panic.
|
||||
type MAC struct {
|
||||
mac // platform-dependent implementation
|
||||
|
||||
@@ -65,10 +72,10 @@ func (h *MAC) Size() int { return TagSize }
|
||||
// Write adds more data to the running message authentication code.
|
||||
// It never returns an error.
|
||||
//
|
||||
// It must not be called after the first call of Sum.
|
||||
// It must not be called after the first call of Sum or Verify.
|
||||
func (h *MAC) Write(p []byte) (n int, err error) {
|
||||
if h.finalized {
|
||||
panic("poly1305: write to MAC after Sum")
|
||||
panic("poly1305: write to MAC after Sum or Verify")
|
||||
}
|
||||
return h.mac.Write(p)
|
||||
}
|
||||
@@ -81,3 +88,12 @@ func (h *MAC) Sum(b []byte) []byte {
|
||||
h.finalized = true
|
||||
return append(b, mac[:]...)
|
||||
}
|
||||
|
||||
// Verify returns whether the authenticator of all data written to
|
||||
// the message authentication code matches the expected value.
|
||||
func (h *MAC) Verify(expected []byte) bool {
|
||||
var mac [TagSize]byte
|
||||
h.mac.Sum(&mac)
|
||||
h.finalized = true
|
||||
return subtle.ConstantTimeCompare(expected, mac[:]) == 1
|
||||
}
|
||||
|
||||
+22
-43
@@ -2,67 +2,46 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
// +build !gccgo,!purego
|
||||
|
||||
package poly1305
|
||||
|
||||
//go:noescape
|
||||
func initialize(state *[7]uint64, key *[32]byte)
|
||||
func update(state *macState, msg []byte)
|
||||
|
||||
//go:noescape
|
||||
func update(state *[7]uint64, msg []byte)
|
||||
// mac is a wrapper for macGeneric that redirects calls that would have gone to
|
||||
// updateGeneric to update.
|
||||
//
|
||||
// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
|
||||
// using function pointers would carry a major performance cost.
|
||||
type mac struct{ macGeneric }
|
||||
|
||||
//go:noescape
|
||||
func finalize(tag *[TagSize]byte, state *[7]uint64)
|
||||
|
||||
// Sum generates an authenticator for m using a one-time key and puts the
|
||||
// 16-byte result into out. Authenticating two different messages with the same
|
||||
// key allows an attacker to forge messages at will.
|
||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
||||
h := newMAC(key)
|
||||
h.Write(m)
|
||||
h.Sum(out)
|
||||
}
|
||||
|
||||
func newMAC(key *[32]byte) (h mac) {
|
||||
initialize(&h.state, key)
|
||||
return
|
||||
}
|
||||
|
||||
type mac struct {
|
||||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
|
||||
|
||||
buffer [TagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (h *mac) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
func (h *mac) Write(p []byte) (int, error) {
|
||||
nn := len(p)
|
||||
if h.offset > 0 {
|
||||
remaining := TagSize - h.offset
|
||||
if n < remaining {
|
||||
h.offset += copy(h.buffer[h.offset:], p)
|
||||
return n, nil
|
||||
n := copy(h.buffer[h.offset:], p)
|
||||
if h.offset+n < TagSize {
|
||||
h.offset += n
|
||||
return nn, nil
|
||||
}
|
||||
copy(h.buffer[h.offset:], p[:remaining])
|
||||
p = p[remaining:]
|
||||
p = p[n:]
|
||||
h.offset = 0
|
||||
update(&h.state, h.buffer[:])
|
||||
update(&h.macState, h.buffer[:])
|
||||
}
|
||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
||||
update(&h.state, p[:nn])
|
||||
p = p[nn:]
|
||||
if n := len(p) - (len(p) % TagSize); n > 0 {
|
||||
update(&h.macState, p[:n])
|
||||
p = p[n:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
h.offset += copy(h.buffer[h.offset:], p)
|
||||
}
|
||||
return n, nil
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (h *mac) Sum(out *[16]byte) {
|
||||
state := h.state
|
||||
state := h.macState
|
||||
if h.offset > 0 {
|
||||
update(&state, h.buffer[:h.offset])
|
||||
}
|
||||
finalize(out, &state)
|
||||
finalize(out, &state.h, &state.s)
|
||||
}
|
||||
|
||||
+1
-41
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
// +build !gccgo,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
@@ -54,10 +54,6 @@
|
||||
ADCQ t3, h1; \
|
||||
ADCQ $0, h2
|
||||
|
||||
DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
|
||||
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
|
||||
GLOBL ·poly1305Mask<>(SB), RODATA, $16
|
||||
|
||||
// func update(state *[7]uint64, msg []byte)
|
||||
TEXT ·update(SB), $0-32
|
||||
MOVQ state+0(FP), DI
|
||||
@@ -110,39 +106,3 @@ done:
|
||||
MOVQ R9, 8(DI)
|
||||
MOVQ R10, 16(DI)
|
||||
RET
|
||||
|
||||
// func initialize(state *[7]uint64, key *[32]byte)
|
||||
TEXT ·initialize(SB), $0-16
|
||||
MOVQ state+0(FP), DI
|
||||
MOVQ key+8(FP), SI
|
||||
|
||||
// state[0...7] is initialized with zero
|
||||
MOVOU 0(SI), X0
|
||||
MOVOU 16(SI), X1
|
||||
MOVOU ·poly1305Mask<>(SB), X2
|
||||
PAND X2, X0
|
||||
MOVOU X0, 24(DI)
|
||||
MOVOU X1, 40(DI)
|
||||
RET
|
||||
|
||||
// func finalize(tag *[TagSize]byte, state *[7]uint64)
|
||||
TEXT ·finalize(SB), $0-16
|
||||
MOVQ tag+0(FP), DI
|
||||
MOVQ state+8(FP), SI
|
||||
|
||||
MOVQ 0(SI), AX
|
||||
MOVQ 8(SI), BX
|
||||
MOVQ 16(SI), CX
|
||||
MOVQ AX, R8
|
||||
MOVQ BX, R9
|
||||
SUBQ $0xFFFFFFFFFFFFFFFB, AX
|
||||
SBBQ $0xFFFFFFFFFFFFFFFF, BX
|
||||
SBBQ $3, CX
|
||||
CMOVQCS R8, AX
|
||||
CMOVQCS R9, BX
|
||||
ADDQ 40(SI), AX
|
||||
ADCQ 48(SI), BX
|
||||
|
||||
MOVQ AX, 0(DI)
|
||||
MOVQ BX, 8(DI)
|
||||
RET
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build arm,!gccgo,!appengine,!nacl
|
||||
|
||||
package poly1305
|
||||
|
||||
// This function is implemented in sum_arm.s
|
||||
//go:noescape
|
||||
func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
|
||||
|
||||
// Sum generates an authenticator for m using a one-time key and puts the
|
||||
// 16-byte result into out. Authenticating two different messages with the same
|
||||
// key allows an attacker to forge messages at will.
|
||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
||||
var mPtr *byte
|
||||
if len(m) > 0 {
|
||||
mPtr = &m[0]
|
||||
}
|
||||
poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
|
||||
}
|
||||
-427
@@ -1,427 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build arm,!gccgo,!appengine,!nacl
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This code was translated into a form compatible with 5a from the public
|
||||
// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
|
||||
|
||||
DATA ·poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
|
||||
DATA ·poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
|
||||
DATA ·poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
|
||||
DATA ·poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
|
||||
DATA ·poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
|
||||
GLOBL ·poly1305_init_constants_armv6<>(SB), 8, $20
|
||||
|
||||
// Warning: the linker may use R11 to synthesize certain instructions. Please
|
||||
// take care and verify that no synthetic instructions use it.
|
||||
|
||||
TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0
|
||||
// Needs 16 bytes of stack and 64 bytes of space pointed to by R0. (It
|
||||
// might look like it's only 60 bytes of space but the final four bytes
|
||||
// will be written by another function.) We need to skip over four
|
||||
// bytes of stack because that's saving the value of 'g'.
|
||||
ADD $4, R13, R8
|
||||
MOVM.IB [R4-R7], (R8)
|
||||
MOVM.IA.W (R1), [R2-R5]
|
||||
MOVW $·poly1305_init_constants_armv6<>(SB), R7
|
||||
MOVW R2, R8
|
||||
MOVW R2>>26, R9
|
||||
MOVW R3>>20, g
|
||||
MOVW R4>>14, R11
|
||||
MOVW R5>>8, R12
|
||||
ORR R3<<6, R9, R9
|
||||
ORR R4<<12, g, g
|
||||
ORR R5<<18, R11, R11
|
||||
MOVM.IA (R7), [R2-R6]
|
||||
AND R8, R2, R2
|
||||
AND R9, R3, R3
|
||||
AND g, R4, R4
|
||||
AND R11, R5, R5
|
||||
AND R12, R6, R6
|
||||
MOVM.IA.W [R2-R6], (R0)
|
||||
EOR R2, R2, R2
|
||||
EOR R3, R3, R3
|
||||
EOR R4, R4, R4
|
||||
EOR R5, R5, R5
|
||||
EOR R6, R6, R6
|
||||
MOVM.IA.W [R2-R6], (R0)
|
||||
MOVM.IA.W (R1), [R2-R5]
|
||||
MOVM.IA [R2-R6], (R0)
|
||||
ADD $20, R13, R0
|
||||
MOVM.DA (R0), [R4-R7]
|
||||
RET
|
||||
|
||||
#define MOVW_UNALIGNED(Rsrc, Rdst, Rtmp, offset) \
|
||||
MOVBU (offset+0)(Rsrc), Rtmp; \
|
||||
MOVBU Rtmp, (offset+0)(Rdst); \
|
||||
MOVBU (offset+1)(Rsrc), Rtmp; \
|
||||
MOVBU Rtmp, (offset+1)(Rdst); \
|
||||
MOVBU (offset+2)(Rsrc), Rtmp; \
|
||||
MOVBU Rtmp, (offset+2)(Rdst); \
|
||||
MOVBU (offset+3)(Rsrc), Rtmp; \
|
||||
MOVBU Rtmp, (offset+3)(Rdst)
|
||||
|
||||
TEXT poly1305_blocks_armv6<>(SB), NOSPLIT, $0
|
||||
// Needs 24 bytes of stack for saved registers and then 88 bytes of
|
||||
// scratch space after that. We assume that 24 bytes at (R13) have
|
||||
// already been used: four bytes for the link register saved in the
|
||||
// prelude of poly1305_auth_armv6, four bytes for saving the value of g
|
||||
// in that function and 16 bytes of scratch space used around
|
||||
// poly1305_finish_ext_armv6_skip1.
|
||||
ADD $24, R13, R12
|
||||
MOVM.IB [R4-R8, R14], (R12)
|
||||
MOVW R0, 88(R13)
|
||||
MOVW R1, 92(R13)
|
||||
MOVW R2, 96(R13)
|
||||
MOVW R1, R14
|
||||
MOVW R2, R12
|
||||
MOVW 56(R0), R8
|
||||
WORD $0xe1180008 // TST R8, R8 not working see issue 5921
|
||||
EOR R6, R6, R6
|
||||
MOVW.EQ $(1<<24), R6
|
||||
MOVW R6, 84(R13)
|
||||
ADD $116, R13, g
|
||||
MOVM.IA (R0), [R0-R9]
|
||||
MOVM.IA [R0-R4], (g)
|
||||
CMP $16, R12
|
||||
BLO poly1305_blocks_armv6_done
|
||||
|
||||
poly1305_blocks_armv6_mainloop:
|
||||
WORD $0xe31e0003 // TST R14, #3 not working see issue 5921
|
||||
BEQ poly1305_blocks_armv6_mainloop_aligned
|
||||
ADD $100, R13, g
|
||||
MOVW_UNALIGNED(R14, g, R0, 0)
|
||||
MOVW_UNALIGNED(R14, g, R0, 4)
|
||||
MOVW_UNALIGNED(R14, g, R0, 8)
|
||||
MOVW_UNALIGNED(R14, g, R0, 12)
|
||||
MOVM.IA (g), [R0-R3]
|
||||
ADD $16, R14
|
||||
B poly1305_blocks_armv6_mainloop_loaded
|
||||
|
||||
poly1305_blocks_armv6_mainloop_aligned:
|
||||
MOVM.IA.W (R14), [R0-R3]
|
||||
|
||||
poly1305_blocks_armv6_mainloop_loaded:
|
||||
MOVW R0>>26, g
|
||||
MOVW R1>>20, R11
|
||||
MOVW R2>>14, R12
|
||||
MOVW R14, 92(R13)
|
||||
MOVW R3>>8, R4
|
||||
ORR R1<<6, g, g
|
||||
ORR R2<<12, R11, R11
|
||||
ORR R3<<18, R12, R12
|
||||
BIC $0xfc000000, R0, R0
|
||||
BIC $0xfc000000, g, g
|
||||
MOVW 84(R13), R3
|
||||
BIC $0xfc000000, R11, R11
|
||||
BIC $0xfc000000, R12, R12
|
||||
ADD R0, R5, R5
|
||||
ADD g, R6, R6
|
||||
ORR R3, R4, R4
|
||||
ADD R11, R7, R7
|
||||
ADD $116, R13, R14
|
||||
ADD R12, R8, R8
|
||||
ADD R4, R9, R9
|
||||
MOVM.IA (R14), [R0-R4]
|
||||
MULLU R4, R5, (R11, g)
|
||||
MULLU R3, R5, (R14, R12)
|
||||
MULALU R3, R6, (R11, g)
|
||||
MULALU R2, R6, (R14, R12)
|
||||
MULALU R2, R7, (R11, g)
|
||||
MULALU R1, R7, (R14, R12)
|
||||
ADD R4<<2, R4, R4
|
||||
ADD R3<<2, R3, R3
|
||||
MULALU R1, R8, (R11, g)
|
||||
MULALU R0, R8, (R14, R12)
|
||||
MULALU R0, R9, (R11, g)
|
||||
MULALU R4, R9, (R14, R12)
|
||||
MOVW g, 76(R13)
|
||||
MOVW R11, 80(R13)
|
||||
MOVW R12, 68(R13)
|
||||
MOVW R14, 72(R13)
|
||||
MULLU R2, R5, (R11, g)
|
||||
MULLU R1, R5, (R14, R12)
|
||||
MULALU R1, R6, (R11, g)
|
||||
MULALU R0, R6, (R14, R12)
|
||||
MULALU R0, R7, (R11, g)
|
||||
MULALU R4, R7, (R14, R12)
|
||||
ADD R2<<2, R2, R2
|
||||
ADD R1<<2, R1, R1
|
||||
MULALU R4, R8, (R11, g)
|
||||
MULALU R3, R8, (R14, R12)
|
||||
MULALU R3, R9, (R11, g)
|
||||
MULALU R2, R9, (R14, R12)
|
||||
MOVW g, 60(R13)
|
||||
MOVW R11, 64(R13)
|
||||
MOVW R12, 52(R13)
|
||||
MOVW R14, 56(R13)
|
||||
MULLU R0, R5, (R11, g)
|
||||
MULALU R4, R6, (R11, g)
|
||||
MULALU R3, R7, (R11, g)
|
||||
MULALU R2, R8, (R11, g)
|
||||
MULALU R1, R9, (R11, g)
|
||||
ADD $52, R13, R0
|
||||
MOVM.IA (R0), [R0-R7]
|
||||
MOVW g>>26, R12
|
||||
MOVW R4>>26, R14
|
||||
ORR R11<<6, R12, R12
|
||||
ORR R5<<6, R14, R14
|
||||
BIC $0xfc000000, g, g
|
||||
BIC $0xfc000000, R4, R4
|
||||
ADD.S R12, R0, R0
|
||||
ADC $0, R1, R1
|
||||
ADD.S R14, R6, R6
|
||||
ADC $0, R7, R7
|
||||
MOVW R0>>26, R12
|
||||
MOVW R6>>26, R14
|
||||
ORR R1<<6, R12, R12
|
||||
ORR R7<<6, R14, R14
|
||||
BIC $0xfc000000, R0, R0
|
||||
BIC $0xfc000000, R6, R6
|
||||
ADD R14<<2, R14, R14
|
||||
ADD.S R12, R2, R2
|
||||
ADC $0, R3, R3
|
||||
ADD R14, g, g
|
||||
MOVW R2>>26, R12
|
||||
MOVW g>>26, R14
|
||||
ORR R3<<6, R12, R12
|
||||
BIC $0xfc000000, g, R5
|
||||
BIC $0xfc000000, R2, R7
|
||||
ADD R12, R4, R4
|
||||
ADD R14, R0, R0
|
||||
MOVW R4>>26, R12
|
||||
BIC $0xfc000000, R4, R8
|
||||
ADD R12, R6, R9
|
||||
MOVW 96(R13), R12
|
||||
MOVW 92(R13), R14
|
||||
MOVW R0, R6
|
||||
CMP $32, R12
|
||||
SUB $16, R12, R12
|
||||
MOVW R12, 96(R13)
|
||||
BHS poly1305_blocks_armv6_mainloop
|
||||
|
||||
poly1305_blocks_armv6_done:
|
||||
MOVW 88(R13), R12
|
||||
MOVW R5, 20(R12)
|
||||
MOVW R6, 24(R12)
|
||||
MOVW R7, 28(R12)
|
||||
MOVW R8, 32(R12)
|
||||
MOVW R9, 36(R12)
|
||||
ADD $48, R13, R0
|
||||
MOVM.DA (R0), [R4-R8, R14]
|
||||
RET
|
||||
|
||||
#define MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) \
|
||||
MOVBU.P 1(Rsrc), Rtmp; \
|
||||
MOVBU.P Rtmp, 1(Rdst); \
|
||||
MOVBU.P 1(Rsrc), Rtmp; \
|
||||
MOVBU.P Rtmp, 1(Rdst)
|
||||
|
||||
#define MOVWP_UNALIGNED(Rsrc, Rdst, Rtmp) \
|
||||
MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp); \
|
||||
MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp)
|
||||
|
||||
// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key)
|
||||
TEXT ·poly1305_auth_armv6(SB), $196-16
|
||||
// The value 196, just above, is the sum of 64 (the size of the context
|
||||
// structure) and 132 (the amount of stack needed).
|
||||
//
|
||||
// At this point, the stack pointer (R13) has been moved down. It
|
||||
// points to the saved link register and there's 196 bytes of free
|
||||
// space above it.
|
||||
//
|
||||
// The stack for this function looks like:
|
||||
//
|
||||
// +---------------------
|
||||
// |
|
||||
// | 64 bytes of context structure
|
||||
// |
|
||||
// +---------------------
|
||||
// |
|
||||
// | 112 bytes for poly1305_blocks_armv6
|
||||
// |
|
||||
// +---------------------
|
||||
// | 16 bytes of final block, constructed at
|
||||
// | poly1305_finish_ext_armv6_skip8
|
||||
// +---------------------
|
||||
// | four bytes of saved 'g'
|
||||
// +---------------------
|
||||
// | lr, saved by prelude <- R13 points here
|
||||
// +---------------------
|
||||
MOVW g, 4(R13)
|
||||
|
||||
MOVW out+0(FP), R4
|
||||
MOVW m+4(FP), R5
|
||||
MOVW mlen+8(FP), R6
|
||||
MOVW key+12(FP), R7
|
||||
|
||||
ADD $136, R13, R0 // 136 = 4 + 4 + 16 + 112
|
||||
MOVW R7, R1
|
||||
|
||||
// poly1305_init_ext_armv6 will write to the stack from R13+4, but
|
||||
// that's ok because none of the other values have been written yet.
|
||||
BL poly1305_init_ext_armv6<>(SB)
|
||||
BIC.S $15, R6, R2
|
||||
BEQ poly1305_auth_armv6_noblocks
|
||||
ADD $136, R13, R0
|
||||
MOVW R5, R1
|
||||
ADD R2, R5, R5
|
||||
SUB R2, R6, R6
|
||||
BL poly1305_blocks_armv6<>(SB)
|
||||
|
||||
poly1305_auth_armv6_noblocks:
|
||||
ADD $136, R13, R0
|
||||
MOVW R5, R1
|
||||
MOVW R6, R2
|
||||
MOVW R4, R3
|
||||
|
||||
MOVW R0, R5
|
||||
MOVW R1, R6
|
||||
MOVW R2, R7
|
||||
MOVW R3, R8
|
||||
AND.S R2, R2, R2
|
||||
BEQ poly1305_finish_ext_armv6_noremaining
|
||||
EOR R0, R0
|
||||
ADD $8, R13, R9 // 8 = offset to 16 byte scratch space
|
||||
MOVW R0, (R9)
|
||||
MOVW R0, 4(R9)
|
||||
MOVW R0, 8(R9)
|
||||
MOVW R0, 12(R9)
|
||||
WORD $0xe3110003 // TST R1, #3 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_aligned
|
||||
WORD $0xe3120008 // TST R2, #8 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip8
|
||||
MOVWP_UNALIGNED(R1, R9, g)
|
||||
MOVWP_UNALIGNED(R1, R9, g)
|
||||
|
||||
poly1305_finish_ext_armv6_skip8:
|
||||
WORD $0xe3120004 // TST $4, R2 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip4
|
||||
MOVWP_UNALIGNED(R1, R9, g)
|
||||
|
||||
poly1305_finish_ext_armv6_skip4:
|
||||
WORD $0xe3120002 // TST $2, R2 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip2
|
||||
MOVHUP_UNALIGNED(R1, R9, g)
|
||||
B poly1305_finish_ext_armv6_skip2
|
||||
|
||||
poly1305_finish_ext_armv6_aligned:
|
||||
WORD $0xe3120008 // TST R2, #8 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip8_aligned
|
||||
MOVM.IA.W (R1), [g-R11]
|
||||
MOVM.IA.W [g-R11], (R9)
|
||||
|
||||
poly1305_finish_ext_armv6_skip8_aligned:
|
||||
WORD $0xe3120004 // TST $4, R2 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip4_aligned
|
||||
MOVW.P 4(R1), g
|
||||
MOVW.P g, 4(R9)
|
||||
|
||||
poly1305_finish_ext_armv6_skip4_aligned:
|
||||
WORD $0xe3120002 // TST $2, R2 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip2
|
||||
MOVHU.P 2(R1), g
|
||||
MOVH.P g, 2(R9)
|
||||
|
||||
poly1305_finish_ext_armv6_skip2:
|
||||
WORD $0xe3120001 // TST $1, R2 not working see issue 5921
|
||||
BEQ poly1305_finish_ext_armv6_skip1
|
||||
MOVBU.P 1(R1), g
|
||||
MOVBU.P g, 1(R9)
|
||||
|
||||
poly1305_finish_ext_armv6_skip1:
|
||||
MOVW $1, R11
|
||||
MOVBU R11, 0(R9)
|
||||
MOVW R11, 56(R5)
|
||||
MOVW R5, R0
|
||||
ADD $8, R13, R1
|
||||
MOVW $16, R2
|
||||
BL poly1305_blocks_armv6<>(SB)
|
||||
|
||||
poly1305_finish_ext_armv6_noremaining:
|
||||
MOVW 20(R5), R0
|
||||
MOVW 24(R5), R1
|
||||
MOVW 28(R5), R2
|
||||
MOVW 32(R5), R3
|
||||
MOVW 36(R5), R4
|
||||
MOVW R4>>26, R12
|
||||
BIC $0xfc000000, R4, R4
|
||||
ADD R12<<2, R12, R12
|
||||
ADD R12, R0, R0
|
||||
MOVW R0>>26, R12
|
||||
BIC $0xfc000000, R0, R0
|
||||
ADD R12, R1, R1
|
||||
MOVW R1>>26, R12
|
||||
BIC $0xfc000000, R1, R1
|
||||
ADD R12, R2, R2
|
||||
MOVW R2>>26, R12
|
||||
BIC $0xfc000000, R2, R2
|
||||
ADD R12, R3, R3
|
||||
MOVW R3>>26, R12
|
||||
BIC $0xfc000000, R3, R3
|
||||
ADD R12, R4, R4
|
||||
ADD $5, R0, R6
|
||||
MOVW R6>>26, R12
|
||||
BIC $0xfc000000, R6, R6
|
||||
ADD R12, R1, R7
|
||||
MOVW R7>>26, R12
|
||||
BIC $0xfc000000, R7, R7
|
||||
ADD R12, R2, g
|
||||
MOVW g>>26, R12
|
||||
BIC $0xfc000000, g, g
|
||||
ADD R12, R3, R11
|
||||
MOVW $-(1<<26), R12
|
||||
ADD R11>>26, R12, R12
|
||||
BIC $0xfc000000, R11, R11
|
||||
ADD R12, R4, R9
|
||||
MOVW R9>>31, R12
|
||||
SUB $1, R12
|
||||
AND R12, R6, R6
|
||||
AND R12, R7, R7
|
||||
AND R12, g, g
|
||||
AND R12, R11, R11
|
||||
AND R12, R9, R9
|
||||
MVN R12, R12
|
||||
AND R12, R0, R0
|
||||
AND R12, R1, R1
|
||||
AND R12, R2, R2
|
||||
AND R12, R3, R3
|
||||
AND R12, R4, R4
|
||||
ORR R6, R0, R0
|
||||
ORR R7, R1, R1
|
||||
ORR g, R2, R2
|
||||
ORR R11, R3, R3
|
||||
ORR R9, R4, R4
|
||||
ORR R1<<26, R0, R0
|
||||
MOVW R1>>6, R1
|
||||
ORR R2<<20, R1, R1
|
||||
MOVW R2>>12, R2
|
||||
ORR R3<<14, R2, R2
|
||||
MOVW R3>>18, R3
|
||||
ORR R4<<8, R3, R3
|
||||
MOVW 40(R5), R6
|
||||
MOVW 44(R5), R7
|
||||
MOVW 48(R5), g
|
||||
MOVW 52(R5), R11
|
||||
ADD.S R6, R0, R0
|
||||
ADC.S R7, R1, R1
|
||||
ADC.S g, R2, R2
|
||||
ADC.S R11, R3, R3
|
||||
MOVM.IA [R0-R3], (R8)
|
||||
MOVW R5, R12
|
||||
EOR R0, R0, R0
|
||||
EOR R1, R1, R1
|
||||
EOR R2, R2, R2
|
||||
EOR R3, R3, R3
|
||||
EOR R4, R4, R4
|
||||
EOR R5, R5, R5
|
||||
EOR R6, R6, R6
|
||||
EOR R7, R7, R7
|
||||
MOVM.IA.W [R0-R7], (R12)
|
||||
MOVM.IA [R0-R7], (R12)
|
||||
MOVW 4(R13), g
|
||||
RET
|
||||
+256
-118
@@ -2,171 +2,309 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file provides the generic implementation of Sum and MAC. Other files
|
||||
// might provide optimized assembly implementations of some of this code.
|
||||
|
||||
package poly1305
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
const (
|
||||
msgBlock = uint32(1 << 24)
|
||||
finalBlock = uint32(0)
|
||||
)
|
||||
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
|
||||
// for a 64 bytes message is approximately
|
||||
//
|
||||
// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5
|
||||
//
|
||||
// for some secret r and s. It can be computed sequentially like
|
||||
//
|
||||
// for len(msg) > 0:
|
||||
// h += read(msg, 16)
|
||||
// h *= r
|
||||
// h %= 2¹³⁰ - 5
|
||||
// return h + s
|
||||
//
|
||||
// All the complexity is about doing performant constant-time math on numbers
|
||||
// larger than any available numeric type.
|
||||
|
||||
// sumGeneric generates an authenticator for msg using a one-time key and
|
||||
// puts the 16-byte result into out. This is the generic implementation of
|
||||
// Sum and should be called if no assembly implementation is available.
|
||||
func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
|
||||
h := newMACGeneric(key)
|
||||
h.Write(msg)
|
||||
h.Sum(out)
|
||||
}
|
||||
|
||||
func newMACGeneric(key *[32]byte) (h macGeneric) {
|
||||
h.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff
|
||||
h.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03
|
||||
h.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff
|
||||
h.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff
|
||||
h.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff
|
||||
func newMACGeneric(key *[32]byte) macGeneric {
|
||||
m := macGeneric{}
|
||||
initialize(key, &m.macState)
|
||||
return m
|
||||
}
|
||||
|
||||
h.s[0] = binary.LittleEndian.Uint32(key[16:])
|
||||
h.s[1] = binary.LittleEndian.Uint32(key[20:])
|
||||
h.s[2] = binary.LittleEndian.Uint32(key[24:])
|
||||
h.s[3] = binary.LittleEndian.Uint32(key[28:])
|
||||
return
|
||||
// macState holds numbers in saturated 64-bit little-endian limbs. That is,
|
||||
// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸.
|
||||
type macState struct {
|
||||
// h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but
|
||||
// can grow larger during and after rounds. It must, however, remain below
|
||||
// 2 * (2¹³⁰ - 5).
|
||||
h [3]uint64
|
||||
// r and s are the private key components.
|
||||
r [2]uint64
|
||||
s [2]uint64
|
||||
}
|
||||
|
||||
type macGeneric struct {
|
||||
h, r [5]uint32
|
||||
s [4]uint32
|
||||
macState
|
||||
|
||||
buffer [TagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (h *macGeneric) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
// Write splits the incoming message into TagSize chunks, and passes them to
|
||||
// update. It buffers incomplete chunks.
|
||||
func (h *macGeneric) Write(p []byte) (int, error) {
|
||||
nn := len(p)
|
||||
if h.offset > 0 {
|
||||
remaining := TagSize - h.offset
|
||||
if n < remaining {
|
||||
h.offset += copy(h.buffer[h.offset:], p)
|
||||
return n, nil
|
||||
n := copy(h.buffer[h.offset:], p)
|
||||
if h.offset+n < TagSize {
|
||||
h.offset += n
|
||||
return nn, nil
|
||||
}
|
||||
copy(h.buffer[h.offset:], p[:remaining])
|
||||
p = p[remaining:]
|
||||
p = p[n:]
|
||||
h.offset = 0
|
||||
updateGeneric(h.buffer[:], msgBlock, &(h.h), &(h.r))
|
||||
updateGeneric(&h.macState, h.buffer[:])
|
||||
}
|
||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
||||
updateGeneric(p, msgBlock, &(h.h), &(h.r))
|
||||
p = p[nn:]
|
||||
if n := len(p) - (len(p) % TagSize); n > 0 {
|
||||
updateGeneric(&h.macState, p[:n])
|
||||
p = p[n:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
h.offset += copy(h.buffer[h.offset:], p)
|
||||
}
|
||||
return n, nil
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (h *macGeneric) Sum(out *[16]byte) {
|
||||
H, R := h.h, h.r
|
||||
// Sum flushes the last incomplete chunk from the buffer, if any, and generates
|
||||
// the MAC output. It does not modify its state, in order to allow for multiple
|
||||
// calls to Sum, even if no Write is allowed after Sum.
|
||||
func (h *macGeneric) Sum(out *[TagSize]byte) {
|
||||
state := h.macState
|
||||
if h.offset > 0 {
|
||||
var buffer [TagSize]byte
|
||||
copy(buffer[:], h.buffer[:h.offset])
|
||||
buffer[h.offset] = 1 // invariant: h.offset < TagSize
|
||||
updateGeneric(buffer[:], finalBlock, &H, &R)
|
||||
updateGeneric(&state, h.buffer[:h.offset])
|
||||
}
|
||||
finalizeGeneric(out, &H, &(h.s))
|
||||
finalize(out, &state.h, &state.s)
|
||||
}
|
||||
|
||||
func updateGeneric(msg []byte, flag uint32, h, r *[5]uint32) {
|
||||
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
|
||||
r0, r1, r2, r3, r4 := uint64(r[0]), uint64(r[1]), uint64(r[2]), uint64(r[3]), uint64(r[4])
|
||||
R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5
|
||||
// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It
|
||||
// clears some bits of the secret coefficient to make it possible to implement
|
||||
// multiplication more efficiently.
|
||||
const (
|
||||
rMask0 = 0x0FFFFFFC0FFFFFFF
|
||||
rMask1 = 0x0FFFFFFC0FFFFFFC
|
||||
)
|
||||
|
||||
for len(msg) >= TagSize {
|
||||
// h += msg
|
||||
h0 += binary.LittleEndian.Uint32(msg[0:]) & 0x3ffffff
|
||||
h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff
|
||||
h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff
|
||||
h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff
|
||||
h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | flag
|
||||
// initialize loads the 256-bit key into the two 128-bit secret values r and s.
|
||||
func initialize(key *[32]byte, m *macState) {
|
||||
m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0
|
||||
m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1
|
||||
m.s[0] = binary.LittleEndian.Uint64(key[16:24])
|
||||
m.s[1] = binary.LittleEndian.Uint64(key[24:32])
|
||||
}
|
||||
|
||||
// h *= r
|
||||
d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1)
|
||||
d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2)
|
||||
d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3)
|
||||
d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4)
|
||||
d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0)
|
||||
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
|
||||
// bits.Mul64 and bits.Add64 intrinsics.
|
||||
type uint128 struct {
|
||||
lo, hi uint64
|
||||
}
|
||||
|
||||
// h %= p
|
||||
h0 = uint32(d0) & 0x3ffffff
|
||||
h1 = uint32(d1) & 0x3ffffff
|
||||
h2 = uint32(d2) & 0x3ffffff
|
||||
h3 = uint32(d3) & 0x3ffffff
|
||||
h4 = uint32(d4) & 0x3ffffff
|
||||
func mul64(a, b uint64) uint128 {
|
||||
hi, lo := bitsMul64(a, b)
|
||||
return uint128{lo, hi}
|
||||
}
|
||||
|
||||
h0 += uint32(d4>>26) * 5
|
||||
h1 += h0 >> 26
|
||||
h0 = h0 & 0x3ffffff
|
||||
func add128(a, b uint128) uint128 {
|
||||
lo, c := bitsAdd64(a.lo, b.lo, 0)
|
||||
hi, c := bitsAdd64(a.hi, b.hi, c)
|
||||
if c != 0 {
|
||||
panic("poly1305: unexpected overflow")
|
||||
}
|
||||
return uint128{lo, hi}
|
||||
}
|
||||
|
||||
msg = msg[TagSize:]
|
||||
func shiftRightBy2(a uint128) uint128 {
|
||||
a.lo = a.lo>>2 | (a.hi&3)<<62
|
||||
a.hi = a.hi >> 2
|
||||
return a
|
||||
}
|
||||
|
||||
// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of
|
||||
// 128 bits of message, it computes
|
||||
//
|
||||
// h₊ = (h + m) * r mod 2¹³⁰ - 5
|
||||
//
|
||||
// If the msg length is not a multiple of TagSize, it assumes the last
|
||||
// incomplete chunk is the final one.
|
||||
func updateGeneric(state *macState, msg []byte) {
|
||||
h0, h1, h2 := state.h[0], state.h[1], state.h[2]
|
||||
r0, r1 := state.r[0], state.r[1]
|
||||
|
||||
for len(msg) > 0 {
|
||||
var c uint64
|
||||
|
||||
// For the first step, h + m, we use a chain of bits.Add64 intrinsics.
|
||||
// The resulting value of h might exceed 2¹³⁰ - 5, but will be partially
|
||||
// reduced at the end of the multiplication below.
|
||||
//
|
||||
// The spec requires us to set a bit just above the message size, not to
|
||||
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just
|
||||
// add 1 to the most significant (2¹²⁸) limb, h2.
|
||||
if len(msg) >= TagSize {
|
||||
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
|
||||
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
|
||||
h2 += c + 1
|
||||
|
||||
msg = msg[TagSize:]
|
||||
} else {
|
||||
var buf [TagSize]byte
|
||||
copy(buf[:], msg)
|
||||
buf[len(msg)] = 1
|
||||
|
||||
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
|
||||
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
|
||||
h2 += c
|
||||
|
||||
msg = nil
|
||||
}
|
||||
|
||||
// Multiplication of big number limbs is similar to elementary school
|
||||
// columnar multiplication. Instead of digits, there are 64-bit limbs.
|
||||
//
|
||||
// We are multiplying a 3 limbs number, h, by a 2 limbs number, r.
|
||||
//
|
||||
// h2 h1 h0 x
|
||||
// r1 r0 =
|
||||
// ----------------
|
||||
// h2r0 h1r0 h0r0 <-- individual 128-bit products
|
||||
// + h2r1 h1r1 h0r1
|
||||
// ------------------------
|
||||
// m3 m2 m1 m0 <-- result in 128-bit overlapping limbs
|
||||
// ------------------------
|
||||
// m3.hi m2.hi m1.hi m0.hi <-- carry propagation
|
||||
// + m3.lo m2.lo m1.lo m0.lo
|
||||
// -------------------------------
|
||||
// t4 t3 t2 t1 t0 <-- final result in 64-bit limbs
|
||||
//
|
||||
// The main difference from pen-and-paper multiplication is that we do
|
||||
// carry propagation in a separate step, as if we wrote two digit sums
|
||||
// at first (the 128-bit limbs), and then carried the tens all at once.
|
||||
|
||||
h0r0 := mul64(h0, r0)
|
||||
h1r0 := mul64(h1, r0)
|
||||
h2r0 := mul64(h2, r0)
|
||||
h0r1 := mul64(h0, r1)
|
||||
h1r1 := mul64(h1, r1)
|
||||
h2r1 := mul64(h2, r1)
|
||||
|
||||
// Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their
|
||||
// top 4 bits cleared by rMask{0,1}, we know that their product is not going
|
||||
// to overflow 64 bits, so we can ignore the high part of the products.
|
||||
//
|
||||
// This also means that the product doesn't have a fifth limb (t4).
|
||||
if h2r0.hi != 0 {
|
||||
panic("poly1305: unexpected overflow")
|
||||
}
|
||||
if h2r1.hi != 0 {
|
||||
panic("poly1305: unexpected overflow")
|
||||
}
|
||||
|
||||
m0 := h0r0
|
||||
m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again
|
||||
m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1.
|
||||
m3 := h2r1
|
||||
|
||||
t0 := m0.lo
|
||||
t1, c := bitsAdd64(m1.lo, m0.hi, 0)
|
||||
t2, c := bitsAdd64(m2.lo, m1.hi, c)
|
||||
t3, _ := bitsAdd64(m3.lo, m2.hi, c)
|
||||
|
||||
// Now we have the result as 4 64-bit limbs, and we need to reduce it
|
||||
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
|
||||
// a cheap partial reduction according to the reduction identity
|
||||
//
|
||||
// c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5
|
||||
//
|
||||
// because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is
|
||||
// likely to be larger than 2¹³⁰ - 5, but still small enough to fit the
|
||||
// assumptions we make about h in the rest of the code.
|
||||
//
|
||||
// See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23
|
||||
|
||||
// We split the final result at the 2¹³⁰ mark into h and cc, the carry.
|
||||
// Note that the carry bits are effectively shifted left by 2, in other
|
||||
// words, cc = c * 4 for the c in the reduction identity.
|
||||
h0, h1, h2 = t0, t1, t2&maskLow2Bits
|
||||
cc := uint128{t2 & maskNotLow2Bits, t3}
|
||||
|
||||
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
|
||||
|
||||
h0, c = bitsAdd64(h0, cc.lo, 0)
|
||||
h1, c = bitsAdd64(h1, cc.hi, c)
|
||||
h2 += c
|
||||
|
||||
cc = shiftRightBy2(cc)
|
||||
|
||||
h0, c = bitsAdd64(h0, cc.lo, 0)
|
||||
h1, c = bitsAdd64(h1, cc.hi, c)
|
||||
h2 += c
|
||||
|
||||
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
|
||||
//
|
||||
// 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1
|
||||
}
|
||||
|
||||
h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4
|
||||
state.h[0], state.h[1], state.h[2] = h0, h1, h2
|
||||
}
|
||||
|
||||
func finalizeGeneric(out *[TagSize]byte, h *[5]uint32, s *[4]uint32) {
|
||||
h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4]
|
||||
const (
|
||||
maskLow2Bits uint64 = 0x0000000000000003
|
||||
maskNotLow2Bits uint64 = ^maskLow2Bits
|
||||
)
|
||||
|
||||
// h %= p reduction
|
||||
h2 += h1 >> 26
|
||||
h1 &= 0x3ffffff
|
||||
h3 += h2 >> 26
|
||||
h2 &= 0x3ffffff
|
||||
h4 += h3 >> 26
|
||||
h3 &= 0x3ffffff
|
||||
h0 += 5 * (h4 >> 26)
|
||||
h4 &= 0x3ffffff
|
||||
h1 += h0 >> 26
|
||||
h0 &= 0x3ffffff
|
||||
// select64 returns x if v == 1 and y if v == 0, in constant time.
|
||||
func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y }
|
||||
|
||||
// h - p
|
||||
t0 := h0 + 5
|
||||
t1 := h1 + (t0 >> 26)
|
||||
t2 := h2 + (t1 >> 26)
|
||||
t3 := h3 + (t2 >> 26)
|
||||
t4 := h4 + (t3 >> 26) - (1 << 26)
|
||||
t0 &= 0x3ffffff
|
||||
t1 &= 0x3ffffff
|
||||
t2 &= 0x3ffffff
|
||||
t3 &= 0x3ffffff
|
||||
// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order.
|
||||
const (
|
||||
p0 = 0xFFFFFFFFFFFFFFFB
|
||||
p1 = 0xFFFFFFFFFFFFFFFF
|
||||
p2 = 0x0000000000000003
|
||||
)
|
||||
|
||||
// select h if h < p else h - p
|
||||
t_mask := (t4 >> 31) - 1
|
||||
h_mask := ^t_mask
|
||||
h0 = (h0 & h_mask) | (t0 & t_mask)
|
||||
h1 = (h1 & h_mask) | (t1 & t_mask)
|
||||
h2 = (h2 & h_mask) | (t2 & t_mask)
|
||||
h3 = (h3 & h_mask) | (t3 & t_mask)
|
||||
h4 = (h4 & h_mask) | (t4 & t_mask)
|
||||
// finalize completes the modular reduction of h and computes
|
||||
//
|
||||
// out = h + s mod 2¹²⁸
|
||||
//
|
||||
func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
|
||||
h0, h1, h2 := h[0], h[1], h[2]
|
||||
|
||||
// h %= 2^128
|
||||
h0 |= h1 << 26
|
||||
h1 = ((h1 >> 6) | (h2 << 20))
|
||||
h2 = ((h2 >> 12) | (h3 << 14))
|
||||
h3 = ((h3 >> 18) | (h4 << 8))
|
||||
// After the partial reduction in updateGeneric, h might be more than
|
||||
// 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction
|
||||
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
|
||||
// result if the subtraction underflows, and t otherwise.
|
||||
|
||||
// s: the s part of the key
|
||||
// tag = (h + s) % (2^128)
|
||||
t := uint64(h0) + uint64(s[0])
|
||||
h0 = uint32(t)
|
||||
t = uint64(h1) + uint64(s[1]) + (t >> 32)
|
||||
h1 = uint32(t)
|
||||
t = uint64(h2) + uint64(s[2]) + (t >> 32)
|
||||
h2 = uint32(t)
|
||||
t = uint64(h3) + uint64(s[3]) + (t >> 32)
|
||||
h3 = uint32(t)
|
||||
hMinusP0, b := bitsSub64(h0, p0, 0)
|
||||
hMinusP1, b := bitsSub64(h1, p1, b)
|
||||
_, b = bitsSub64(h2, p2, b)
|
||||
|
||||
binary.LittleEndian.PutUint32(out[0:], h0)
|
||||
binary.LittleEndian.PutUint32(out[4:], h1)
|
||||
binary.LittleEndian.PutUint32(out[8:], h2)
|
||||
binary.LittleEndian.PutUint32(out[12:], h3)
|
||||
// h = h if h < p else h - p
|
||||
h0 = select64(b, h0, hMinusP0)
|
||||
h1 = select64(b, h1, hMinusP1)
|
||||
|
||||
// Finally, we compute the last Poly1305 step
|
||||
//
|
||||
// tag = h + s mod 2¹²⁸
|
||||
//
|
||||
// by just doing a wide addition with the 128 low bits of h and discarding
|
||||
// the overflow.
|
||||
h0, c := bitsAdd64(h0, s[0], 0)
|
||||
h1, _ = bitsAdd64(h1, s[1], c)
|
||||
|
||||
binary.LittleEndian.PutUint64(out[0:8], h0)
|
||||
binary.LittleEndian.PutUint64(out[8:16], h1)
|
||||
}
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build s390x,!go1.11 !arm,!amd64,!s390x,!ppc64le gccgo appengine nacl
|
||||
|
||||
package poly1305
|
||||
|
||||
// Sum generates an authenticator for msg using a one-time key and puts the
|
||||
// 16-byte result into out. Authenticating two different messages with the same
|
||||
// key allows an attacker to forge messages at will.
|
||||
func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
|
||||
h := newMAC(key)
|
||||
h.Write(msg)
|
||||
h.Sum(out)
|
||||
}
|
||||
+22
-43
@@ -2,67 +2,46 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ppc64le,!gccgo,!appengine
|
||||
// +build !gccgo,!purego
|
||||
|
||||
package poly1305
|
||||
|
||||
//go:noescape
|
||||
func initialize(state *[7]uint64, key *[32]byte)
|
||||
func update(state *macState, msg []byte)
|
||||
|
||||
//go:noescape
|
||||
func update(state *[7]uint64, msg []byte)
|
||||
// mac is a wrapper for macGeneric that redirects calls that would have gone to
|
||||
// updateGeneric to update.
|
||||
//
|
||||
// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
|
||||
// using function pointers would carry a major performance cost.
|
||||
type mac struct{ macGeneric }
|
||||
|
||||
//go:noescape
|
||||
func finalize(tag *[TagSize]byte, state *[7]uint64)
|
||||
|
||||
// Sum generates an authenticator for m using a one-time key and puts the
|
||||
// 16-byte result into out. Authenticating two different messages with the same
|
||||
// key allows an attacker to forge messages at will.
|
||||
func Sum(out *[16]byte, m []byte, key *[32]byte) {
|
||||
h := newMAC(key)
|
||||
h.Write(m)
|
||||
h.Sum(out)
|
||||
}
|
||||
|
||||
func newMAC(key *[32]byte) (h mac) {
|
||||
initialize(&h.state, key)
|
||||
return
|
||||
}
|
||||
|
||||
type mac struct {
|
||||
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
|
||||
|
||||
buffer [TagSize]byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (h *mac) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
func (h *mac) Write(p []byte) (int, error) {
|
||||
nn := len(p)
|
||||
if h.offset > 0 {
|
||||
remaining := TagSize - h.offset
|
||||
if n < remaining {
|
||||
h.offset += copy(h.buffer[h.offset:], p)
|
||||
return n, nil
|
||||
n := copy(h.buffer[h.offset:], p)
|
||||
if h.offset+n < TagSize {
|
||||
h.offset += n
|
||||
return nn, nil
|
||||
}
|
||||
copy(h.buffer[h.offset:], p[:remaining])
|
||||
p = p[remaining:]
|
||||
p = p[n:]
|
||||
h.offset = 0
|
||||
update(&h.state, h.buffer[:])
|
||||
update(&h.macState, h.buffer[:])
|
||||
}
|
||||
if nn := len(p) - (len(p) % TagSize); nn > 0 {
|
||||
update(&h.state, p[:nn])
|
||||
p = p[nn:]
|
||||
if n := len(p) - (len(p) % TagSize); n > 0 {
|
||||
update(&h.macState, p[:n])
|
||||
p = p[n:]
|
||||
}
|
||||
if len(p) > 0 {
|
||||
h.offset += copy(h.buffer[h.offset:], p)
|
||||
}
|
||||
return n, nil
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (h *mac) Sum(out *[16]byte) {
|
||||
state := h.state
|
||||
state := h.macState
|
||||
if h.offset > 0 {
|
||||
update(&state, h.buffer[:h.offset])
|
||||
}
|
||||
finalize(out, &state)
|
||||
finalize(out, &state.h, &state.s)
|
||||
}
|
||||
|
||||
+1
-67
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ppc64le,!gccgo,!appengine
|
||||
// +build !gccgo,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
@@ -58,7 +58,6 @@ DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
|
||||
GLOBL ·poly1305Mask<>(SB), RODATA, $16
|
||||
|
||||
// func update(state *[7]uint64, msg []byte)
|
||||
|
||||
TEXT ·update(SB), $0-32
|
||||
MOVD state+0(FP), R3
|
||||
MOVD msg_base+8(FP), R4
|
||||
@@ -180,68 +179,3 @@ done:
|
||||
MOVD R9, 8(R3)
|
||||
MOVD R10, 16(R3)
|
||||
RET
|
||||
|
||||
// func initialize(state *[7]uint64, key *[32]byte)
|
||||
TEXT ·initialize(SB), $0-16
|
||||
MOVD state+0(FP), R3
|
||||
MOVD key+8(FP), R4
|
||||
|
||||
// state[0...7] is initialized with zero
|
||||
// Load key
|
||||
MOVD 0(R4), R5
|
||||
MOVD 8(R4), R6
|
||||
MOVD 16(R4), R7
|
||||
MOVD 24(R4), R8
|
||||
|
||||
// Address of key mask
|
||||
MOVD $·poly1305Mask<>(SB), R9
|
||||
|
||||
// Save original key in state
|
||||
MOVD R7, 40(R3)
|
||||
MOVD R8, 48(R3)
|
||||
|
||||
// Get mask
|
||||
MOVD (R9), R7
|
||||
MOVD 8(R9), R8
|
||||
|
||||
// And with key
|
||||
AND R5, R7, R5
|
||||
AND R6, R8, R6
|
||||
|
||||
// Save masked key in state
|
||||
MOVD R5, 24(R3)
|
||||
MOVD R6, 32(R3)
|
||||
RET
|
||||
|
||||
// func finalize(tag *[TagSize]byte, state *[7]uint64)
|
||||
TEXT ·finalize(SB), $0-16
|
||||
MOVD tag+0(FP), R3
|
||||
MOVD state+8(FP), R4
|
||||
|
||||
// Get h0, h1, h2 from state
|
||||
MOVD 0(R4), R5
|
||||
MOVD 8(R4), R6
|
||||
MOVD 16(R4), R7
|
||||
|
||||
// Save h0, h1
|
||||
MOVD R5, R8
|
||||
MOVD R6, R9
|
||||
MOVD $3, R20
|
||||
MOVD $-1, R21
|
||||
SUBC $-5, R5
|
||||
SUBE R21, R6
|
||||
SUBE R20, R7
|
||||
MOVD $0, R21
|
||||
SUBZE R21
|
||||
|
||||
// Check for carry
|
||||
CMP $0, R21
|
||||
ISEL $2, R5, R8, R5
|
||||
ISEL $2, R6, R9, R6
|
||||
MOVD 40(R4), R8
|
||||
MOVD 48(R4), R9
|
||||
ADDC R8, R5
|
||||
ADDE R9, R6
|
||||
MOVD R5, 0(R3)
|
||||
MOVD R6, 8(R3)
|
||||
RET
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user