Update dependencies (#975)
parent
b9354de8fd
commit
0f708daf2d
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,43 @@
|
|||||||
|
package whatsapp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Rhymen/go-whatsapp/binary"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pictures must be JPG 640x640 and 96x96, respectively
|
||||||
|
func (wac *Conn) UploadProfilePic(image, preview []byte) (<-chan string, error) {
|
||||||
|
tag := fmt.Sprintf("%d.--%d", time.Now().Unix(), wac.msgCount*19)
|
||||||
|
n := binary.Node{
|
||||||
|
Description: "action",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"type": "set",
|
||||||
|
"epoch": strconv.Itoa(wac.msgCount),
|
||||||
|
},
|
||||||
|
Content: []interface{}{
|
||||||
|
binary.Node{
|
||||||
|
Description: "picture",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"id": tag,
|
||||||
|
"jid": wac.Info.Wid,
|
||||||
|
"type": "set",
|
||||||
|
},
|
||||||
|
Content: []binary.Node{
|
||||||
|
{
|
||||||
|
Description: "image",
|
||||||
|
Attributes: nil,
|
||||||
|
Content: image,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Description: "preview",
|
||||||
|
Attributes: nil,
|
||||||
|
Content: preview,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return wac.writeBinary(n, profile, 136, tag)
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
dist: bionic
|
|
||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- "1.12.x"
|
|
||||||
|
|
||||||
install:
|
|
||||||
- go build -v ./...
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go test -v ./...
|
|
||||||
- go test -run=^$ -bench=BenchmarkReference -benchmem
|
|
||||||
- ./s/test_with_codecoverage.sh
|
|
||||||
- ./s/ci_fuzzit.sh
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
|
@ -0,0 +1,3 @@
|
|||||||
|
module github.com/jpillora/backoff
|
||||||
|
|
||||||
|
go 1.13
|
@ -0,0 +1 @@
|
|||||||
|
module github.com/magiconair/properties
|
@ -1,3 +1,5 @@
|
|||||||
module github.com/mattn/go-isatty
|
module github.com/mattn/go-isatty
|
||||||
|
|
||||||
require golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a
|
go 1.12
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.0.0-20191026070338-33540a1f6037
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
// +build plan9
|
||||||
|
|
||||||
|
package isatty
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(fd uintptr) bool {
|
||||||
|
path, err := syscall.Fd2path(int(fd))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return path == "/dev/cons" || path == "/mnt/term/dev/cons"
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||||
|
// terminal. This is also always false on this environment.
|
||||||
|
func IsCygwinTerminal(fd uintptr) bool {
|
||||||
|
return false
|
||||||
|
}
|
@ -1,29 +1,20 @@
|
|||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
/bin/
|
||||||
*.o
|
/build/
|
||||||
*.a
|
/var/
|
||||||
*.so
|
/vendor/
|
||||||
|
|
||||||
# Folders
|
# IDE integration
|
||||||
_obj
|
/.vscode/*
|
||||||
_test
|
!/.vscode/launch.json
|
||||||
|
!/.vscode/tasks.json
|
||||||
# Architecture specific extensions/prefixes
|
/.idea/*
|
||||||
*.[568vq]
|
!/.idea/codeStyles/
|
||||||
[568vq].out
|
!/.idea/copyright/
|
||||||
|
!/.idea/dataSources.xml
|
||||||
*.cgo1.go
|
!/.idea/*.iml
|
||||||
*.cgo2.c
|
!/.idea/externalDependencies.xml
|
||||||
_cgo_defun.c
|
!/.idea/go.imports.xml
|
||||||
_cgo_gotypes.go
|
!/.idea/modules.xml
|
||||||
_cgo_export.*
|
!/.idea/runConfigurations/
|
||||||
|
!/.idea/scopes/
|
||||||
_testmain.go
|
!/.idea/sqldialects.xml
|
||||||
|
|
||||||
*.exe
|
|
||||||
*.test
|
|
||||||
*.bench
|
|
||||||
|
|
||||||
.vscode
|
|
||||||
|
|
||||||
# exclude dependencies in the `/vendor` folder
|
|
||||||
vendor
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
linters-settings:
|
||||||
|
golint:
|
||||||
|
min-confidence: 0.1
|
||||||
|
goimports:
|
||||||
|
local-prefixes: github.com/spf13/viper
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- funlen
|
||||||
|
- maligned
|
||||||
|
|
||||||
|
# TODO: fix me
|
||||||
|
- wsl
|
||||||
|
- gochecknoinits
|
||||||
|
- gosimple
|
||||||
|
- gochecknoglobals
|
||||||
|
- errcheck
|
||||||
|
- lll
|
||||||
|
- godox
|
||||||
|
- scopelint
|
||||||
|
- gocyclo
|
||||||
|
- gocognit
|
||||||
|
- gocritic
|
@ -0,0 +1,71 @@
|
|||||||
|
# A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
|
||||||
|
|
||||||
|
OS = $(shell uname | tr A-Z a-z)
|
||||||
|
|
||||||
|
# Build variables
|
||||||
|
BUILD_DIR ?= build
|
||||||
|
ifeq (${VERBOSE}, 1)
|
||||||
|
ifeq ($(filter -v,${GOARGS}),)
|
||||||
|
GOARGS += -v
|
||||||
|
endif
|
||||||
|
TEST_FORMAT = short-verbose
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Dependency versions
|
||||||
|
GOTESTSUM_VERSION = 0.3.5
|
||||||
|
GOLANGCI_VERSION = 1.21.0
|
||||||
|
|
||||||
|
# Add the ability to override some variables
|
||||||
|
# Use with care
|
||||||
|
-include override.mk
|
||||||
|
|
||||||
|
.PHONY: clear
|
||||||
|
clear: ## Clear the working area and the project
|
||||||
|
rm -rf bin/
|
||||||
|
|
||||||
|
.PHONY: check
|
||||||
|
check: test lint ## Run tests and linters
|
||||||
|
|
||||||
|
bin/gotestsum: bin/gotestsum-${GOTESTSUM_VERSION}
|
||||||
|
@ln -sf gotestsum-${GOTESTSUM_VERSION} bin/gotestsum
|
||||||
|
bin/gotestsum-${GOTESTSUM_VERSION}:
|
||||||
|
@mkdir -p bin
|
||||||
|
curl -L https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_${OS}_amd64.tar.gz | tar -zOxf - gotestsum > ./bin/gotestsum-${GOTESTSUM_VERSION} && chmod +x ./bin/gotestsum-${GOTESTSUM_VERSION}
|
||||||
|
|
||||||
|
TEST_PKGS ?= ./...
|
||||||
|
TEST_REPORT_NAME ?= results.xml
|
||||||
|
.PHONY: test
|
||||||
|
test: TEST_REPORT ?= main
|
||||||
|
test: TEST_FORMAT ?= short
|
||||||
|
test: SHELL = /bin/bash
|
||||||
|
test: bin/gotestsum ## Run tests
|
||||||
|
@mkdir -p ${BUILD_DIR}/test_results/${TEST_REPORT}
|
||||||
|
bin/gotestsum --no-summary=skipped --junitfile ${BUILD_DIR}/test_results/${TEST_REPORT}/${TEST_REPORT_NAME} --format ${TEST_FORMAT} -- $(filter-out -v,${GOARGS}) $(if ${TEST_PKGS},${TEST_PKGS},./...)
|
||||||
|
|
||||||
|
bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION}
|
||||||
|
@ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint
|
||||||
|
bin/golangci-lint-${GOLANGCI_VERSION}:
|
||||||
|
@mkdir -p bin
|
||||||
|
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | BINARY=golangci-lint bash -s -- v${GOLANGCI_VERSION}
|
||||||
|
@mv bin/golangci-lint $@
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: bin/golangci-lint ## Run linter
|
||||||
|
bin/golangci-lint run
|
||||||
|
|
||||||
|
.PHONY: fix
|
||||||
|
fix: bin/golangci-lint ## Fix lint violations
|
||||||
|
bin/golangci-lint run --fix
|
||||||
|
|
||||||
|
.PHONY: list
|
||||||
|
list: ## List all make targets
|
||||||
|
@${MAKE} -pRrn : -f $(MAKEFILE_LIST) 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | sort
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
help:
|
||||||
|
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
# Variable outputting/exporting rules
|
||||||
|
var-%: ; @echo $($*)
|
||||||
|
varexport-%: ; @echo $*=$($*)
|
@ -0,0 +1 @@
|
|||||||
|
HELLO=world
|
@ -0,0 +1 @@
|
|||||||
|
lol$wut
|
@ -0,0 +1,3 @@
|
|||||||
|
*.test
|
||||||
|
*.out
|
||||||
|
annotate.json
|
@ -0,0 +1,10 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.x
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
script:
|
||||||
|
- go test -test.v -coverprofile=coverage.out -covermode=count
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
@ -0,0 +1,47 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [1.2.0] - 2019-08-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `Must` helper to raise an error as panic. It can be used with `Load` and `OverLoad`.
|
||||||
|
- Add more tests to be 100% coverage.
|
||||||
|
- Add CHANGELOG
|
||||||
|
- Add more OS for the test: OSX and Windows
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Reduce complexity and improve source code for having `A+` score in [goreportcard](https://goreportcard.com/report/github.com/subosito/gotenv).
|
||||||
|
- Updated README with mentions to all available functions
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove `ErrFormat`
|
||||||
|
- Remove `MustLoad` and `MustOverload`, replaced with `Must` helper.
|
||||||
|
|
||||||
|
## [1.1.1] - 2018-06-05
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Replace `os.Getenv` with `os.LookupEnv` to ensure that the environment variable is not set, by [radding](https://github.com/radding)
|
||||||
|
|
||||||
|
## [1.1.0] - 2017-03-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Supports carriage return in env
|
||||||
|
- Handle files with UTF-8 BOM
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Whitespace handling
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Incorrect variable expansion
|
||||||
|
- Handling escaped '$' characters
|
||||||
|
|
||||||
|
## [1.0.0] - 2014-10-05
|
||||||
|
|
||||||
|
First stable release.
|
||||||
|
|
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Alif Rachmawadi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
@ -0,0 +1,131 @@
|
|||||||
|
# gotenv
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/subosito/gotenv.svg?branch=master)](https://travis-ci.org/subosito/gotenv)
|
||||||
|
[![Build status](https://ci.appveyor.com/api/projects/status/wb2e075xkfl0m0v2/branch/master?svg=true)](https://ci.appveyor.com/project/subosito/gotenv/branch/master)
|
||||||
|
[![Coverage Status](https://badgen.net/codecov/c/github/subosito/gotenv)](https://codecov.io/gh/subosito/gotenv)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/subosito/gotenv)](https://goreportcard.com/report/github.com/subosito/gotenv)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/subosito/gotenv?status.svg)](https://godoc.org/github.com/subosito/gotenv)
|
||||||
|
|
||||||
|
Load environment variables dynamically in Go.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Put the gotenv package on your `import` statement:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/subosito/gotenv"
|
||||||
|
```
|
||||||
|
|
||||||
|
To modify your app environment variables, `gotenv` expose 2 main functions:
|
||||||
|
|
||||||
|
- `gotenv.Load`
|
||||||
|
- `gotenv.Apply`
|
||||||
|
|
||||||
|
By default, `gotenv.Load` will look for a file called `.env` in the current working directory.
|
||||||
|
|
||||||
|
Behind the scene, it will then load `.env` file and export the valid variables to the environment variables. Make sure you call the method as soon as possible to ensure it loads all variables, say, put it on `init()` function.
|
||||||
|
|
||||||
|
Once loaded you can use `os.Getenv()` to get the value of the variable.
|
||||||
|
|
||||||
|
Let's say you have `.env` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
APP_ID=1234567
|
||||||
|
APP_SECRET=abcdef
|
||||||
|
```
|
||||||
|
|
||||||
|
Here's the example of your app:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gotenv.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.Println(os.Getenv("APP_ID")) // "1234567"
|
||||||
|
log.Println(os.Getenv("APP_SECRET")) // "abcdef"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also load other than `.env` file if you wish. Just supply filenames when calling `Load()`. It will load them in order and the first value set for a variable will win.:
|
||||||
|
|
||||||
|
```go
|
||||||
|
gotenv.Load(".env.production", "credentials")
|
||||||
|
```
|
||||||
|
|
||||||
|
While `gotenv.Load` loads entries from `.env` file, `gotenv.Apply` allows you to use any `io.Reader`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
gotenv.Apply(strings.NewReader("APP_ID=1234567"))
|
||||||
|
|
||||||
|
log.Println(os.Getenv("APP_ID"))
|
||||||
|
// Output: "1234567"
|
||||||
|
```
|
||||||
|
|
||||||
|
Both `gotenv.Load` and `gotenv.Apply` **DO NOT** overrides existing environment variables. If you want to override existing ones, you can see section below.
|
||||||
|
|
||||||
|
### Environment Overrides
|
||||||
|
|
||||||
|
Besides above functions, `gotenv` also provides another functions that overrides existing:
|
||||||
|
|
||||||
|
- `gotenv.OverLoad`
|
||||||
|
- `gotenv.OverApply`
|
||||||
|
|
||||||
|
|
||||||
|
Here's the example of this overrides behavior:
|
||||||
|
|
||||||
|
```go
|
||||||
|
os.Setenv("HELLO", "world")
|
||||||
|
|
||||||
|
// NOTE: using Apply existing value will be reserved
|
||||||
|
gotenv.Apply(strings.NewReader("HELLO=universe"))
|
||||||
|
fmt.Println(os.Getenv("HELLO"))
|
||||||
|
// Output: "world"
|
||||||
|
|
||||||
|
// NOTE: using OverApply existing value will be overridden
|
||||||
|
gotenv.OverApply(strings.NewReader("HELLO=universe"))
|
||||||
|
fmt.Println(os.Getenv("HELLO"))
|
||||||
|
// Output: "universe"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Throw a Panic
|
||||||
|
|
||||||
|
Both `gotenv.Load` and `gotenv.OverLoad` returns an error on something wrong occurred, like your env file is not exist, and so on. To make it easier to use, `gotenv` also provides `gotenv.Must` helper, to let it panic when an error returned.
|
||||||
|
|
||||||
|
```go
|
||||||
|
err := gotenv.Load(".env-is-not-exist")
|
||||||
|
fmt.Println("error", err)
|
||||||
|
// error: open .env-is-not-exist: no such file or directory
|
||||||
|
|
||||||
|
gotenv.Must(gotenv.Load, ".env-is-not-exist")
|
||||||
|
// it will throw a panic
|
||||||
|
// panic: open .env-is-not-exist: no such file or directory
|
||||||
|
```
|
||||||
|
|
||||||
|
### Another Scenario
|
||||||
|
|
||||||
|
Just in case you want to parse environment variables from any `io.Reader`, gotenv keeps its `Parse` and `StrictParse` function as public API so you can use that.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// import "strings"
|
||||||
|
|
||||||
|
pairs := gotenv.Parse(strings.NewReader("FOO=test\nBAR=$FOO"))
|
||||||
|
// gotenv.Env{"FOO": "test", "BAR": "test"}
|
||||||
|
|
||||||
|
err, pairs = gotenv.StrictParse(strings.NewReader(`FOO="bar"`))
|
||||||
|
// gotenv.Env{"FOO": "bar"}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Parse` ignores invalid lines and returns `Env` of valid environment variables, while `StrictParse` returns an error for invalid lines.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The gotenv package is a Go port of [`dotenv`](https://github.com/bkeepers/dotenv) project with some additions made for Go. For general features, it aims to be compatible as close as possible.
|
@ -0,0 +1,9 @@
|
|||||||
|
build: off
|
||||||
|
clone_folder: c:\gopath\src\github.com\subosito\gotenv
|
||||||
|
environment:
|
||||||
|
GOPATH: c:\gopath
|
||||||
|
stack: go 1.10
|
||||||
|
before_test:
|
||||||
|
- go get -t
|
||||||
|
test_script:
|
||||||
|
- go test -v -cover -race
|
@ -0,0 +1,265 @@
|
|||||||
|
// Package gotenv provides functionality to dynamically load the environment variables
|
||||||
|
package gotenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Pattern for detecting valid line format
|
||||||
|
linePattern = `\A\s*(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?\s*(?:\s*\#.*)?\z`
|
||||||
|
|
||||||
|
// Pattern for detecting valid variable within a value
|
||||||
|
variablePattern = `(\\)?(\$)(\{?([A-Z0-9_]+)?\}?)`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Env holds key/value pair of valid environment variable
|
||||||
|
type Env map[string]string
|
||||||
|
|
||||||
|
/*
|
||||||
|
Load is a function to load a file or multiple files and then export the valid variables into environment variables if they do not exist.
|
||||||
|
When it's called with no argument, it will load `.env` file on the current path and set the environment variables.
|
||||||
|
Otherwise, it will loop over the filenames parameter and set the proper environment variables.
|
||||||
|
*/
|
||||||
|
func Load(filenames ...string) error {
|
||||||
|
return loadenv(false, filenames...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
OverLoad is a function to load a file or multiple files and then export and override the valid variables into environment variables.
|
||||||
|
*/
|
||||||
|
func OverLoad(filenames ...string) error {
|
||||||
|
return loadenv(true, filenames...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Must is wrapper function that will panic when supplied function returns an error.
|
||||||
|
*/
|
||||||
|
func Must(fn func(filenames ...string) error, filenames ...string) {
|
||||||
|
if err := fn(filenames...); err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Apply is a function to load an io Reader then export the valid variables into environment variables if they do not exist.
|
||||||
|
*/
|
||||||
|
func Apply(r io.Reader) error {
|
||||||
|
return parset(r, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
OverApply is a function to load an io Reader then export and override the valid variables into environment variables.
|
||||||
|
*/
|
||||||
|
func OverApply(r io.Reader) error {
|
||||||
|
return parset(r, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadenv(override bool, filenames ...string) error {
|
||||||
|
if len(filenames) == 0 {
|
||||||
|
filenames = []string{".env"}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filename := range filenames {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = parset(f, override)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse and set :)
|
||||||
|
func parset(r io.Reader, override bool) error {
|
||||||
|
env, err := StrictParse(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, val := range env {
|
||||||
|
setenv(key, val, override)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setenv(key, val string, override bool) {
|
||||||
|
if override {
|
||||||
|
os.Setenv(key, val)
|
||||||
|
} else {
|
||||||
|
if _, present := os.LookupEnv(key); !present {
|
||||||
|
os.Setenv(key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
|
||||||
|
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
|
||||||
|
// This function is skipping any invalid lines and only processing the valid one.
|
||||||
|
func Parse(r io.Reader) Env {
|
||||||
|
env, _ := StrictParse(r)
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictParse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
|
||||||
|
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
|
||||||
|
// This function is returning an error if there are any invalid lines.
|
||||||
|
func StrictParse(r io.Reader) (Env, error) {
|
||||||
|
env := make(Env)
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
|
||||||
|
i := 1
|
||||||
|
bom := string([]byte{239, 187, 191})
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
if i == 1 {
|
||||||
|
line = strings.TrimPrefix(line, bom)
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
|
||||||
|
err := parseLine(line, env)
|
||||||
|
if err != nil {
|
||||||
|
return env, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLine(s string, env Env) error {
|
||||||
|
rl := regexp.MustCompile(linePattern)
|
||||||
|
rm := rl.FindStringSubmatch(s)
|
||||||
|
|
||||||
|
if len(rm) == 0 {
|
||||||
|
return checkFormat(s, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := rm[1]
|
||||||
|
val := rm[2]
|
||||||
|
|
||||||
|
// determine if string has quote prefix
|
||||||
|
hdq := strings.HasPrefix(val, `"`)
|
||||||
|
|
||||||
|
// determine if string has single quote prefix
|
||||||
|
hsq := strings.HasPrefix(val, `'`)
|
||||||
|
|
||||||
|
// trim whitespace
|
||||||
|
val = strings.Trim(val, " ")
|
||||||
|
|
||||||
|
// remove quotes '' or ""
|
||||||
|
rq := regexp.MustCompile(`\A(['"])(.*)(['"])\z`)
|
||||||
|
val = rq.ReplaceAllString(val, "$2")
|
||||||
|
|
||||||
|
if hdq {
|
||||||
|
val = strings.Replace(val, `\n`, "\n", -1)
|
||||||
|
val = strings.Replace(val, `\r`, "\r", -1)
|
||||||
|
|
||||||
|
// Unescape all characters except $ so variables can be escaped properly
|
||||||
|
re := regexp.MustCompile(`\\([^$])`)
|
||||||
|
val = re.ReplaceAllString(val, "$1")
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := regexp.MustCompile(variablePattern)
|
||||||
|
fv := func(s string) string {
|
||||||
|
return varReplacement(s, hsq, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
val = rv.ReplaceAllStringFunc(val, fv)
|
||||||
|
val = parseVal(val, env)
|
||||||
|
|
||||||
|
env[key] = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseExport(st string, env Env) error {
|
||||||
|
if strings.HasPrefix(st, "export") {
|
||||||
|
vs := strings.SplitN(st, " ", 2)
|
||||||
|
|
||||||
|
if len(vs) > 1 {
|
||||||
|
if _, ok := env[vs[1]]; !ok {
|
||||||
|
return fmt.Errorf("line `%s` has an unset variable", st)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func varReplacement(s string, hsq bool, env Env) string {
|
||||||
|
if strings.HasPrefix(s, "\\") {
|
||||||
|
return strings.TrimPrefix(s, "\\")
|
||||||
|
}
|
||||||
|
|
||||||
|
if hsq {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
sn := `(\$)(\{?([A-Z0-9_]+)\}?)`
|
||||||
|
rn := regexp.MustCompile(sn)
|
||||||
|
mn := rn.FindStringSubmatch(s)
|
||||||
|
|
||||||
|
if len(mn) == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
v := mn[3]
|
||||||
|
|
||||||
|
replace, ok := env[v]
|
||||||
|
if !ok {
|
||||||
|
replace = os.Getenv(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return replace
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFormat(s string, env Env) error {
|
||||||
|
st := strings.TrimSpace(s)
|
||||||
|
|
||||||
|
if (st == "") || strings.HasPrefix(st, "#") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := parseExport(st, env); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("line `%s` doesn't match format", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseVal(val string, env Env) string {
|
||||||
|
if strings.Contains(val, "=") {
|
||||||
|
if !(val == "\n" || val == "\r") {
|
||||||
|
kv := strings.Split(val, "\n")
|
||||||
|
|
||||||
|
if len(kv) == 1 {
|
||||||
|
kv = strings.Split(val, "\r")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(kv) > 1 {
|
||||||
|
val = kv[0]
|
||||||
|
|
||||||
|
for i := 1; i < len(kv); i++ {
|
||||||
|
parseLine(kv[i], env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
@ -0,0 +1,392 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package acme
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeactivateReg permanently disables an existing account associated with c.Key.
|
||||||
|
// A deactivated account can no longer request certificate issuance or access
|
||||||
|
// resources related to the account, such as orders or authorizations.
|
||||||
|
//
|
||||||
|
// It only works with CAs implementing RFC 8555.
|
||||||
|
func (c *Client) DeactivateReg(ctx context.Context) error {
|
||||||
|
url := string(c.accountKID(ctx))
|
||||||
|
if url == "" {
|
||||||
|
return ErrNoAccount
|
||||||
|
}
|
||||||
|
req := json.RawMessage(`{"status": "deactivated"}`)
|
||||||
|
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerRFC is quivalent to c.Register but for CAs implementing RFC 8555.
|
||||||
|
// It expects c.Discover to have already been called.
|
||||||
|
// TODO: Implement externalAccountBinding.
|
||||||
|
func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
|
||||||
|
c.cacheMu.Lock() // guard c.kid access
|
||||||
|
defer c.cacheMu.Unlock()
|
||||||
|
|
||||||
|
req := struct {
|
||||||
|
TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
|
||||||
|
Contact []string `json:"contact,omitempty"`
|
||||||
|
}{
|
||||||
|
Contact: acct.Contact,
|
||||||
|
}
|
||||||
|
if c.dir.Terms != "" {
|
||||||
|
req.TermsAgreed = prompt(c.dir.Terms)
|
||||||
|
}
|
||||||
|
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(
|
||||||
|
http.StatusOK, // account with this key already registered
|
||||||
|
http.StatusCreated, // new account created
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
a, err := responseAccount(res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Cache Account URL even if we return an error to the caller.
|
||||||
|
// It is by all means a valid and usable "kid" value for future requests.
|
||||||
|
c.kid = keyID(a.URI)
|
||||||
|
if res.StatusCode == http.StatusOK {
|
||||||
|
return nil, ErrAccountAlreadyExists
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateGegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
|
||||||
|
// It expects c.Discover to have already been called.
|
||||||
|
func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) {
|
||||||
|
url := string(c.accountKID(ctx))
|
||||||
|
if url == "" {
|
||||||
|
return nil, ErrNoAccount
|
||||||
|
}
|
||||||
|
req := struct {
|
||||||
|
Contact []string `json:"contact,omitempty"`
|
||||||
|
}{
|
||||||
|
Contact: a.Contact,
|
||||||
|
}
|
||||||
|
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
return responseAccount(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getGegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555.
|
||||||
|
// It expects c.Discover to have already been called.
|
||||||
|
func (c *Client) getRegRFC(ctx context.Context) (*Account, error) {
|
||||||
|
req := json.RawMessage(`{"onlyReturnExisting": true}`)
|
||||||
|
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK))
|
||||||
|
if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" {
|
||||||
|
return nil, ErrNoAccount
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
return responseAccount(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func responseAccount(res *http.Response) (*Account, error) {
|
||||||
|
var v struct {
|
||||||
|
Status string
|
||||||
|
Contact []string
|
||||||
|
Orders string
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||||
|
return nil, fmt.Errorf("acme: invalid account response: %v", err)
|
||||||
|
}
|
||||||
|
return &Account{
|
||||||
|
URI: res.Header.Get("Location"),
|
||||||
|
Status: v.Status,
|
||||||
|
Contact: v.Contact,
|
||||||
|
OrdersURL: v.Orders,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizeOrder initiates the order-based application for certificate issuance,
|
||||||
|
// as opposed to pre-authorization in Authorize.
|
||||||
|
// It is only supported by CAs implementing RFC 8555.
|
||||||
|
//
|
||||||
|
// The caller then needs to fetch each authorization with GetAuthorization,
|
||||||
|
// identify those with StatusPending status and fulfill a challenge using Accept.
|
||||||
|
// Once all authorizations are satisfied, the caller will typically want to poll
|
||||||
|
// order status using WaitOrder until it's in StatusReady state.
|
||||||
|
// To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert.
|
||||||
|
func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) {
|
||||||
|
dir, err := c.Discover(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req := struct {
|
||||||
|
Identifiers []wireAuthzID `json:"identifiers"`
|
||||||
|
NotBefore string `json:"notBefore,omitempty"`
|
||||||
|
NotAfter string `json:"notAfter,omitempty"`
|
||||||
|
}{}
|
||||||
|
for _, v := range id {
|
||||||
|
req.Identifiers = append(req.Identifiers, wireAuthzID{
|
||||||
|
Type: v.Type,
|
||||||
|
Value: v.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, o := range opt {
|
||||||
|
switch o := o.(type) {
|
||||||
|
case orderNotBeforeOpt:
|
||||||
|
req.NotBefore = time.Time(o).Format(time.RFC3339)
|
||||||
|
case orderNotAfterOpt:
|
||||||
|
req.NotAfter = time.Time(o).Format(time.RFC3339)
|
||||||
|
default:
|
||||||
|
// Package's fault if we let this happen.
|
||||||
|
panic(fmt.Sprintf("unsupported order option type %T", o))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
return responseOrder(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOrder retrives an order identified by the given URL.
|
||||||
|
// For orders created with AuthorizeOrder, the url value is Order.URI.
|
||||||
|
//
|
||||||
|
// If a caller needs to poll an order until its status is final,
|
||||||
|
// see the WaitOrder method.
|
||||||
|
func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) {
|
||||||
|
if _, err := c.Discover(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
return responseOrder(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitOrder polls an order from the given URL until it is in one of the final states,
|
||||||
|
// StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error
|
||||||
|
// or the context is done.
|
||||||
|
//
|
||||||
|
// It returns a non-nil Order only if its Status is StatusReady or StatusValid.
|
||||||
|
// In all other cases WaitOrder returns an error.
|
||||||
|
// If the Status is StatusInvalid, the returned error is of type *OrderError.
|
||||||
|
func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) {
|
||||||
|
if _, err := c.Discover(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o, err := responseOrder(res)
|
||||||
|
res.Body.Close()
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
// Skip and retry.
|
||||||
|
case o.Status == StatusInvalid:
|
||||||
|
return nil, &OrderError{OrderURL: o.URI, Status: o.Status}
|
||||||
|
case o.Status == StatusReady || o.Status == StatusValid:
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
d := retryAfter(res.Header.Get("Retry-After"))
|
||||||
|
if d == 0 {
|
||||||
|
// Default retry-after.
|
||||||
|
// Same reasoning as in WaitAuthorization.
|
||||||
|
d = time.Second
|
||||||
|
}
|
||||||
|
t := time.NewTimer(d)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Stop()
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-t.C:
|
||||||
|
// Retry.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func responseOrder(res *http.Response) (*Order, error) {
|
||||||
|
var v struct {
|
||||||
|
Status string
|
||||||
|
Expires time.Time
|
||||||
|
Identifiers []wireAuthzID
|
||||||
|
NotBefore time.Time
|
||||||
|
NotAfter time.Time
|
||||||
|
Error *wireError
|
||||||
|
Authorizations []string
|
||||||
|
Finalize string
|
||||||
|
Certificate string
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||||
|
return nil, fmt.Errorf("acme: error reading order: %v", err)
|
||||||
|
}
|
||||||
|
o := &Order{
|
||||||
|
URI: res.Header.Get("Location"),
|
||||||
|
Status: v.Status,
|
||||||
|
Expires: v.Expires,
|
||||||
|
NotBefore: v.NotBefore,
|
||||||
|
NotAfter: v.NotAfter,
|
||||||
|
AuthzURLs: v.Authorizations,
|
||||||
|
FinalizeURL: v.Finalize,
|
||||||
|
CertURL: v.Certificate,
|
||||||
|
}
|
||||||
|
for _, id := range v.Identifiers {
|
||||||
|
o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value})
|
||||||
|
}
|
||||||
|
if v.Error != nil {
|
||||||
|
o.Error = v.Error.error(nil /* headers */)
|
||||||
|
}
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL.
|
||||||
|
// The URL is the FinalizeURL field of an Order created with AuthorizeOrder.
|
||||||
|
//
|
||||||
|
// If the bundle argument is true, the returned value also contain the CA (issuer)
|
||||||
|
// certificate chain. Otherwise, only a leaf certificate is returned.
|
||||||
|
// The returned URL can be used to re-fetch the certificate using FetchCert.
|
||||||
|
//
|
||||||
|
// This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs.
|
||||||
|
//
|
||||||
|
// CreateOrderCert returns an error if the CA's response is unreasonably large.
|
||||||
|
// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
|
||||||
|
func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) {
|
||||||
|
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFC describes this as "finalize order" request.
|
||||||
|
req := struct {
|
||||||
|
CSR string `json:"csr"`
|
||||||
|
}{
|
||||||
|
CSR: base64.RawURLEncoding.EncodeToString(csr),
|
||||||
|
}
|
||||||
|
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
o, err := responseOrder(res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for CA to issue the cert if they haven't.
|
||||||
|
if o.Status != StatusValid {
|
||||||
|
o, err = c.WaitOrder(ctx, o.URI)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
// The only acceptable status post finalize and WaitOrder is "valid".
|
||||||
|
if o.Status != StatusValid {
|
||||||
|
return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status}
|
||||||
|
}
|
||||||
|
crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle)
|
||||||
|
return crt, o.CertURL, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchCertRFC downloads issued certificate from the given URL.
|
||||||
|
// It expects the CA to respond with PEM-encoded certificate chain.
|
||||||
|
//
|
||||||
|
// The URL argument is the CertURL field of Order.
|
||||||
|
func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) {
|
||||||
|
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
// Get all the bytes up to a sane maximum.
|
||||||
|
// Account very roughly for base64 overhead.
|
||||||
|
const max = maxCertChainSize + maxCertChainSize/33
|
||||||
|
b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("acme: fetch cert response stream: %v", err)
|
||||||
|
}
|
||||||
|
if len(b) > max {
|
||||||
|
return nil, errors.New("acme: certificate chain is too big")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode PEM chain.
|
||||||
|
var chain [][]byte
|
||||||
|
for {
|
||||||
|
var p *pem.Block
|
||||||
|
p, b = pem.Decode(b)
|
||||||
|
if p == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if p.Type != "CERTIFICATE" {
|
||||||
|
return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
chain = append(chain, p.Bytes)
|
||||||
|
if !bundle {
|
||||||
|
return chain, nil
|
||||||
|
}
|
||||||
|
if len(chain) > maxChainLen {
|
||||||
|
return nil, errors.New("acme: certificate chain is too long")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(chain) == 0 {
|
||||||
|
return nil, errors.New("acme: certificate chain is empty")
|
||||||
|
}
|
||||||
|
return chain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise.
|
||||||
|
func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
|
||||||
|
req := &struct {
|
||||||
|
Cert string `json:"certificate"`
|
||||||
|
Reason int `json:"reason"`
|
||||||
|
}{
|
||||||
|
Cert: base64.RawURLEncoding.EncodeToString(cert),
|
||||||
|
Reason: int(reason),
|
||||||
|
}
|
||||||
|
res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK))
|
||||||
|
if err != nil {
|
||||||
|
if isAlreadyRevoked(err) {
|
||||||
|
// Assume it is not an error to revoke an already revoked cert.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAlreadyRevoked(err error) bool {
|
||||||
|
e, ok := err.(*Error)
|
||||||
|
return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked"
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// 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,!appengine
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
@ -0,0 +1,364 @@
|
|||||||
|
// 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.
|
||||||
|
buf [bufSize]byte
|
||||||
|
len int
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
src = src[len(keyStream):]
|
||||||
|
dst = dst[len(keyStream):]
|
||||||
|
}
|
||||||
|
|
||||||
|
const blocksPerBuf = bufSize / blockSize
|
||||||
|
numBufs := (uint64(len(src)) + bufSize - 1) / bufSize
|
||||||
|
if uint64(s.counter)+numBufs*blocksPerBuf >= 1<<32 {
|
||||||
|
panic("chacha20: counter overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
rem := len(src) % bufSize
|
||||||
|
full := len(src) - rem
|
||||||
|
|
||||||
|
if full > 0 {
|
||||||
|
s.xorKeyStreamBlocks(dst[:full], src[:full])
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
|
||||||
|
// keep the leftover keystream for the next XORKeyStream invocation.
|
||||||
|
if rem > 0 {
|
||||||
|
s.buf = [bufSize]byte{}
|
||||||
|
copy(s.buf[:], src[full:])
|
||||||
|
s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
|
||||||
|
s.len = bufSize - copy(dst[full:], 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
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(src); i += blockSize {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, add back the initial state to generate the key stream.
|
||||||
|
x0 += c0
|
||||||
|
x1 += c1
|
||||||
|
x2 += c2
|
||||||
|
x3 += c3
|
||||||
|
x4 += c4
|
||||||
|
x5 += c5
|
||||||
|
x6 += c6
|
||||||
|
x7 += c7
|
||||||
|
x8 += c8
|
||||||
|
x9 += c9
|
||||||
|
x10 += c10
|
||||||
|
x11 += c11
|
||||||
|
x12 += s.counter
|
||||||
|
x13 += c13
|
||||||
|
x14 += c14
|
||||||
|
x15 += c15
|
||||||
|
|
||||||
|
s.counter += 1
|
||||||
|
if s.counter == 0 {
|
||||||
|
panic("chacha20: internal error: counter overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
in, out := src[i:], dst[i:]
|
||||||
|
in, out = in[:blockSize], out[:blockSize] // bounds check elimination 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
// 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 !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo appengine
|
||||||
|
|
||||||
|
package chacha20
|
||||||
|
|
||||||
|
const bufSize = blockSize
|
||||||
|
|
||||||
|
func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
|
||||||
|
s.xorKeyStreamBlocksGeneric(dst, src)
|
||||||
|
}
|
@ -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,!appengine
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
@ -0,0 +1,449 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Based on CRYPTOGAMS code with the following comment:
|
||||||
|
// # ====================================================================
|
||||||
|
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||||
|
// # project. The module is, however, dual licensed under OpenSSL and
|
||||||
|
// # CRYPTOGAMS licenses depending on where you obtain it. For further
|
||||||
|
// # details see http://www.openssl.org/~appro/cryptogams/.
|
||||||
|
// # ====================================================================
|
||||||
|
|
||||||
|
// Code for the perl script that generates the ppc64 assembler
|
||||||
|
// can be found in the cryptogams repository at the link below. It is based on
|
||||||
|
// the original from openssl.
|
||||||
|
|
||||||
|
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91
|
||||||
|
|
||||||
|
// The differences in this and the original implementation are
|
||||||
|
// due to the calling conventions and initialization of constants.
|
||||||
|
|
||||||
|
// +build !gccgo,!appengine
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
#define OUT R3
|
||||||
|
#define INP R4
|
||||||
|
#define LEN R5
|
||||||
|
#define KEY R6
|
||||||
|
#define CNT R7
|
||||||
|
#define TMP R15
|
||||||
|
|
||||||
|
#define CONSTBASE R16
|
||||||
|
#define BLOCKS R17
|
||||||
|
|
||||||
|
DATA consts<>+0x00(SB)/8, $0x3320646e61707865
|
||||||
|
DATA consts<>+0x08(SB)/8, $0x6b20657479622d32
|
||||||
|
DATA consts<>+0x10(SB)/8, $0x0000000000000001
|
||||||
|
DATA consts<>+0x18(SB)/8, $0x0000000000000000
|
||||||
|
DATA consts<>+0x20(SB)/8, $0x0000000000000004
|
||||||
|
DATA consts<>+0x28(SB)/8, $0x0000000000000000
|
||||||
|
DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d
|
||||||
|
DATA consts<>+0x38(SB)/8, $0x0203000106070405
|
||||||
|
DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c
|
||||||
|
DATA consts<>+0x48(SB)/8, $0x0102030005060704
|
||||||
|
DATA consts<>+0x50(SB)/8, $0x6170786561707865
|
||||||
|
DATA consts<>+0x58(SB)/8, $0x6170786561707865
|
||||||
|
DATA consts<>+0x60(SB)/8, $0x3320646e3320646e
|
||||||
|
DATA consts<>+0x68(SB)/8, $0x3320646e3320646e
|
||||||
|
DATA consts<>+0x70(SB)/8, $0x79622d3279622d32
|
||||||
|
DATA consts<>+0x78(SB)/8, $0x79622d3279622d32
|
||||||
|
DATA consts<>+0x80(SB)/8, $0x6b2065746b206574
|
||||||
|
DATA consts<>+0x88(SB)/8, $0x6b2065746b206574
|
||||||
|
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 *[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 counter+32(FP), CNT
|
||||||
|
|
||||||
|
// Addressing for constants
|
||||||
|
MOVD $consts<>+0x00(SB), CONSTBASE
|
||||||
|
MOVD $16, R8
|
||||||
|
MOVD $32, R9
|
||||||
|
MOVD $48, R10
|
||||||
|
MOVD $64, R11
|
||||||
|
SRD $6, LEN, BLOCKS
|
||||||
|
// V16
|
||||||
|
LXVW4X (CONSTBASE)(R0), VS48
|
||||||
|
ADD $80,CONSTBASE
|
||||||
|
|
||||||
|
// Load key into V17,V18
|
||||||
|
LXVW4X (KEY)(R0), VS49
|
||||||
|
LXVW4X (KEY)(R8), VS50
|
||||||
|
|
||||||
|
// Load CNT, NONCE into V19
|
||||||
|
LXVW4X (CNT)(R0), VS51
|
||||||
|
|
||||||
|
// Clear V27
|
||||||
|
VXOR V27, V27, V27
|
||||||
|
|
||||||
|
// V28
|
||||||
|
LXVW4X (CONSTBASE)(R11), VS60
|
||||||
|
|
||||||
|
// splat slot from V19 -> V26
|
||||||
|
VSPLTW $0, V19, V26
|
||||||
|
|
||||||
|
VSLDOI $4, V19, V27, V19
|
||||||
|
VSLDOI $12, V27, V19, V19
|
||||||
|
|
||||||
|
VADDUWM V26, V28, V26
|
||||||
|
|
||||||
|
MOVD $10, R14
|
||||||
|
MOVD R14, CTR
|
||||||
|
|
||||||
|
loop_outer_vsx:
|
||||||
|
// V0, V1, V2, V3
|
||||||
|
LXVW4X (R0)(CONSTBASE), VS32
|
||||||
|
LXVW4X (R8)(CONSTBASE), VS33
|
||||||
|
LXVW4X (R9)(CONSTBASE), VS34
|
||||||
|
LXVW4X (R10)(CONSTBASE), VS35
|
||||||
|
|
||||||
|
// splat values from V17, V18 into V4-V11
|
||||||
|
VSPLTW $0, V17, V4
|
||||||
|
VSPLTW $1, V17, V5
|
||||||
|
VSPLTW $2, V17, V6
|
||||||
|
VSPLTW $3, V17, V7
|
||||||
|
VSPLTW $0, V18, V8
|
||||||
|
VSPLTW $1, V18, V9
|
||||||
|
VSPLTW $2, V18, V10
|
||||||
|
VSPLTW $3, V18, V11
|
||||||
|
|
||||||
|
// VOR
|
||||||
|
VOR V26, V26, V12
|
||||||
|
|
||||||
|
// splat values from V19 -> V13, V14, V15
|
||||||
|
VSPLTW $1, V19, V13
|
||||||
|
VSPLTW $2, V19, V14
|
||||||
|
VSPLTW $3, V19, V15
|
||||||
|
|
||||||
|
// splat const values
|
||||||
|
VSPLTISW $-16, V27
|
||||||
|
VSPLTISW $12, V28
|
||||||
|
VSPLTISW $8, V29
|
||||||
|
VSPLTISW $7, V30
|
||||||
|
|
||||||
|
loop_vsx:
|
||||||
|
VADDUWM V0, V4, V0
|
||||||
|
VADDUWM V1, V5, V1
|
||||||
|
VADDUWM V2, V6, V2
|
||||||
|
VADDUWM V3, V7, V3
|
||||||
|
|
||||||
|
VXOR V12, V0, V12
|
||||||
|
VXOR V13, V1, V13
|
||||||
|
VXOR V14, V2, V14
|
||||||
|
VXOR V15, V3, V15
|
||||||
|
|
||||||
|
VRLW V12, V27, V12
|
||||||
|
VRLW V13, V27, V13
|
||||||
|
VRLW V14, V27, V14
|
||||||
|
VRLW V15, V27, V15
|
||||||
|
|
||||||
|
VADDUWM V8, V12, V8
|
||||||
|
VADDUWM V9, V13, V9
|
||||||
|
VADDUWM V10, V14, V10
|
||||||
|
VADDUWM V11, V15, V11
|
||||||
|
|
||||||
|
VXOR V4, V8, V4
|
||||||
|
VXOR V5, V9, V5
|
||||||
|
VXOR V6, V10, V6
|
||||||
|
VXOR V7, V11, V7
|
||||||
|
|
||||||
|
VRLW V4, V28, V4
|
||||||
|
VRLW V5, V28, V5
|
||||||
|
VRLW V6, V28, V6
|
||||||
|
VRLW V7, V28, V7
|
||||||
|
|
||||||
|
VADDUWM V0, V4, V0
|
||||||
|
VADDUWM V1, V5, V1
|
||||||
|
VADDUWM V2, V6, V2
|
||||||
|
VADDUWM V3, V7, V3
|
||||||
|
|
||||||
|
VXOR V12, V0, V12
|
||||||
|
VXOR V13, V1, V13
|
||||||
|
VXOR V14, V2, V14
|
||||||
|
VXOR V15, V3, V15
|
||||||
|
|
||||||
|
VRLW V12, V29, V12
|
||||||
|
VRLW V13, V29, V13
|
||||||
|
VRLW V14, V29, V14
|
||||||
|
VRLW V15, V29, V15
|
||||||
|
|
||||||
|
VADDUWM V8, V12, V8
|
||||||
|
VADDUWM V9, V13, V9
|
||||||
|
VADDUWM V10, V14, V10
|
||||||
|
VADDUWM V11, V15, V11
|
||||||
|
|
||||||
|
VXOR V4, V8, V4
|
||||||
|
VXOR V5, V9, V5
|
||||||
|
VXOR V6, V10, V6
|
||||||
|
VXOR V7, V11, V7
|
||||||
|
|
||||||
|
VRLW V4, V30, V4
|
||||||
|
VRLW V5, V30, V5
|
||||||
|
VRLW V6, V30, V6
|
||||||
|
VRLW V7, V30, V7
|
||||||
|
|
||||||
|
VADDUWM V0, V5, V0
|
||||||
|
VADDUWM V1, V6, V1
|
||||||
|
VADDUWM V2, V7, V2
|
||||||
|
VADDUWM V3, V4, V3
|
||||||
|
|
||||||
|
VXOR V15, V0, V15
|
||||||
|
VXOR V12, V1, V12
|
||||||
|
VXOR V13, V2, V13
|
||||||
|
VXOR V14, V3, V14
|
||||||
|
|
||||||
|
VRLW V15, V27, V15
|
||||||
|
VRLW V12, V27, V12
|
||||||
|
VRLW V13, V27, V13
|
||||||
|
VRLW V14, V27, V14
|
||||||
|
|
||||||
|
VADDUWM V10, V15, V10
|
||||||
|
VADDUWM V11, V12, V11
|
||||||
|
VADDUWM V8, V13, V8
|
||||||
|
VADDUWM V9, V14, V9
|
||||||
|
|
||||||
|
VXOR V5, V10, V5
|
||||||
|
VXOR V6, V11, V6
|
||||||
|
VXOR V7, V8, V7
|
||||||
|
VXOR V4, V9, V4
|
||||||
|
|
||||||
|
VRLW V5, V28, V5
|
||||||
|
VRLW V6, V28, V6
|
||||||
|
VRLW V7, V28, V7
|
||||||
|
VRLW V4, V28, V4
|
||||||
|
|
||||||
|
VADDUWM V0, V5, V0
|
||||||
|
VADDUWM V1, V6, V1
|
||||||
|
VADDUWM V2, V7, V2
|
||||||
|
VADDUWM V3, V4, V3
|
||||||
|
|
||||||
|
VXOR V15, V0, V15
|
||||||
|
VXOR V12, V1, V12
|
||||||
|
VXOR V13, V2, V13
|
||||||
|
VXOR V14, V3, V14
|
||||||
|
|
||||||
|
VRLW V15, V29, V15
|
||||||
|
VRLW V12, V29, V12
|
||||||
|
VRLW V13, V29, V13
|
||||||
|
VRLW V14, V29, V14
|
||||||
|
|
||||||
|
VADDUWM V10, V15, V10
|
||||||
|
VADDUWM V11, V12, V11
|
||||||
|
VADDUWM V8, V13, V8
|
||||||
|
VADDUWM V9, V14, V9
|
||||||
|
|
||||||
|
VXOR V5, V10, V5
|
||||||
|
VXOR V6, V11, V6
|
||||||
|
VXOR V7, V8, V7
|
||||||
|
VXOR V4, V9, V4
|
||||||
|
|
||||||
|
VRLW V5, V30, V5
|
||||||
|
VRLW V6, V30, V6
|
||||||
|
VRLW V7, V30, V7
|
||||||
|
VRLW V4, V30, V4
|
||||||
|
BC 16, LT, loop_vsx
|
||||||
|
|
||||||
|
VADDUWM V12, V26, V12
|
||||||
|
|
||||||
|
WORD $0x13600F8C // VMRGEW V0, V1, V27
|
||||||
|
WORD $0x13821F8C // VMRGEW V2, V3, V28
|
||||||
|
|
||||||
|
WORD $0x10000E8C // VMRGOW V0, V1, V0
|
||||||
|
WORD $0x10421E8C // VMRGOW V2, V3, V2
|
||||||
|
|
||||||
|
WORD $0x13A42F8C // VMRGEW V4, V5, V29
|
||||||
|
WORD $0x13C63F8C // VMRGEW V6, V7, V30
|
||||||
|
|
||||||
|
XXPERMDI VS32, VS34, $0, VS33
|
||||||
|
XXPERMDI VS32, VS34, $3, VS35
|
||||||
|
XXPERMDI VS59, VS60, $0, VS32
|
||||||
|
XXPERMDI VS59, VS60, $3, VS34
|
||||||
|
|
||||||
|
WORD $0x10842E8C // VMRGOW V4, V5, V4
|
||||||
|
WORD $0x10C63E8C // VMRGOW V6, V7, V6
|
||||||
|
|
||||||
|
WORD $0x13684F8C // VMRGEW V8, V9, V27
|
||||||
|
WORD $0x138A5F8C // VMRGEW V10, V11, V28
|
||||||
|
|
||||||
|
XXPERMDI VS36, VS38, $0, VS37
|
||||||
|
XXPERMDI VS36, VS38, $3, VS39
|
||||||
|
XXPERMDI VS61, VS62, $0, VS36
|
||||||
|
XXPERMDI VS61, VS62, $3, VS38
|
||||||
|
|
||||||
|
WORD $0x11084E8C // VMRGOW V8, V9, V8
|
||||||
|
WORD $0x114A5E8C // VMRGOW V10, V11, V10
|
||||||
|
|
||||||
|
WORD $0x13AC6F8C // VMRGEW V12, V13, V29
|
||||||
|
WORD $0x13CE7F8C // VMRGEW V14, V15, V30
|
||||||
|
|
||||||
|
XXPERMDI VS40, VS42, $0, VS41
|
||||||
|
XXPERMDI VS40, VS42, $3, VS43
|
||||||
|
XXPERMDI VS59, VS60, $0, VS40
|
||||||
|
XXPERMDI VS59, VS60, $3, VS42
|
||||||
|
|
||||||
|
WORD $0x118C6E8C // VMRGOW V12, V13, V12
|
||||||
|
WORD $0x11CE7E8C // VMRGOW V14, V15, V14
|
||||||
|
|
||||||
|
VSPLTISW $4, V27
|
||||||
|
VADDUWM V26, V27, V26
|
||||||
|
|
||||||
|
XXPERMDI VS44, VS46, $0, VS45
|
||||||
|
XXPERMDI VS44, VS46, $3, VS47
|
||||||
|
XXPERMDI VS61, VS62, $0, VS44
|
||||||
|
XXPERMDI VS61, VS62, $3, VS46
|
||||||
|
|
||||||
|
VADDUWM V0, V16, V0
|
||||||
|
VADDUWM V4, V17, V4
|
||||||
|
VADDUWM V8, V18, V8
|
||||||
|
VADDUWM V12, V19, V12
|
||||||
|
|
||||||
|
CMPU LEN, $64
|
||||||
|
BLT tail_vsx
|
||||||
|
|
||||||
|
// Bottom of loop
|
||||||
|
LXVW4X (INP)(R0), VS59
|
||||||
|
LXVW4X (INP)(R8), VS60
|
||||||
|
LXVW4X (INP)(R9), VS61
|
||||||
|
LXVW4X (INP)(R10), VS62
|
||||||
|
|
||||||
|
VXOR V27, V0, V27
|
||||||
|
VXOR V28, V4, V28
|
||||||
|
VXOR V29, V8, V29
|
||||||
|
VXOR V30, V12, V30
|
||||||
|
|
||||||
|
STXVW4X VS59, (OUT)(R0)
|
||||||
|
STXVW4X VS60, (OUT)(R8)
|
||||||
|
ADD $64, INP
|
||||||
|
STXVW4X VS61, (OUT)(R9)
|
||||||
|
ADD $-64, LEN
|
||||||
|
STXVW4X VS62, (OUT)(R10)
|
||||||
|
ADD $64, OUT
|
||||||
|
BEQ done_vsx
|
||||||
|
|
||||||
|
VADDUWM V1, V16, V0
|
||||||
|
VADDUWM V5, V17, V4
|
||||||
|
VADDUWM V9, V18, V8
|
||||||
|
VADDUWM V13, V19, V12
|
||||||
|
|
||||||
|
CMPU LEN, $64
|
||||||
|
BLT tail_vsx
|
||||||
|
|
||||||
|
LXVW4X (INP)(R0), VS59
|
||||||
|
LXVW4X (INP)(R8), VS60
|
||||||
|
LXVW4X (INP)(R9), VS61
|
||||||
|
LXVW4X (INP)(R10), VS62
|
||||||
|
VXOR V27, V0, V27
|
||||||
|
|
||||||
|
VXOR V28, V4, V28
|
||||||
|
VXOR V29, V8, V29
|
||||||
|
VXOR V30, V12, V30
|
||||||
|
|
||||||
|
STXVW4X VS59, (OUT)(R0)
|
||||||
|
STXVW4X VS60, (OUT)(R8)
|
||||||
|
ADD $64, INP
|
||||||
|
STXVW4X VS61, (OUT)(R9)
|
||||||
|
ADD $-64, LEN
|
||||||
|
STXVW4X VS62, (OUT)(V10)
|
||||||
|
ADD $64, OUT
|
||||||
|
BEQ done_vsx
|
||||||
|
|
||||||
|
VADDUWM V2, V16, V0
|
||||||
|
VADDUWM V6, V17, V4
|
||||||
|
VADDUWM V10, V18, V8
|
||||||
|
VADDUWM V14, V19, V12
|
||||||
|
|
||||||
|
CMPU LEN, $64
|
||||||
|
BLT tail_vsx
|
||||||
|
|
||||||
|
LXVW4X (INP)(R0), VS59
|
||||||
|
LXVW4X (INP)(R8), VS60
|
||||||
|
LXVW4X (INP)(R9), VS61
|
||||||
|
LXVW4X (INP)(R10), VS62
|
||||||
|
|
||||||
|
VXOR V27, V0, V27
|
||||||
|
VXOR V28, V4, V28
|
||||||
|
VXOR V29, V8, V29
|
||||||
|
VXOR V30, V12, V30
|
||||||
|
|
||||||
|
STXVW4X VS59, (OUT)(R0)
|
||||||
|
STXVW4X VS60, (OUT)(R8)
|
||||||
|
ADD $64, INP
|
||||||
|
STXVW4X VS61, (OUT)(R9)
|
||||||
|
ADD $-64, LEN
|
||||||
|
STXVW4X VS62, (OUT)(R10)
|
||||||
|
ADD $64, OUT
|
||||||
|
BEQ done_vsx
|
||||||
|
|
||||||
|
VADDUWM V3, V16, V0
|
||||||
|
VADDUWM V7, V17, V4
|
||||||
|
VADDUWM V11, V18, V8
|
||||||
|
VADDUWM V15, V19, V12
|
||||||
|
|
||||||
|
CMPU LEN, $64
|
||||||
|
BLT tail_vsx
|
||||||
|
|
||||||
|
LXVW4X (INP)(R0), VS59
|
||||||
|
LXVW4X (INP)(R8), VS60
|
||||||
|
LXVW4X (INP)(R9), VS61
|
||||||
|
LXVW4X (INP)(R10), VS62
|
||||||
|
|
||||||
|
VXOR V27, V0, V27
|
||||||
|
VXOR V28, V4, V28
|
||||||
|
VXOR V29, V8, V29
|
||||||
|
VXOR V30, V12, V30
|
||||||
|
|
||||||
|
STXVW4X VS59, (OUT)(R0)
|
||||||
|
STXVW4X VS60, (OUT)(R8)
|
||||||
|
ADD $64, INP
|
||||||
|
STXVW4X VS61, (OUT)(R9)
|
||||||
|
ADD $-64, LEN
|
||||||
|
STXVW4X VS62, (OUT)(R10)
|
||||||
|
ADD $64, OUT
|
||||||
|
|
||||||
|
MOVD $10, R14
|
||||||
|
MOVD R14, CTR
|
||||||
|
BNE loop_outer_vsx
|
||||||
|
|
||||||
|
done_vsx:
|
||||||
|
// Increment counter by number of 64 byte blocks
|
||||||
|
MOVD (CNT), R14
|
||||||
|
ADD BLOCKS, R14
|
||||||
|
MOVD R14, (CNT)
|
||||||
|
RET
|
||||||
|
|
||||||
|
tail_vsx:
|
||||||
|
ADD $32, R1, R11
|
||||||
|
MOVD LEN, CTR
|
||||||
|
|
||||||
|
// Save values on stack to copy from
|
||||||
|
STXVW4X VS32, (R11)(R0)
|
||||||
|
STXVW4X VS36, (R11)(R8)
|
||||||
|
STXVW4X VS40, (R11)(R9)
|
||||||
|
STXVW4X VS44, (R11)(R10)
|
||||||
|
ADD $-1, R11, R12
|
||||||
|
ADD $-1, INP
|
||||||
|
ADD $-1, OUT
|
||||||
|
|
||||||
|
looptail_vsx:
|
||||||
|
// Copying the result to OUT
|
||||||
|
// in bytes.
|
||||||
|
MOVBZU 1(R12), KEY
|
||||||
|
MOVBZU 1(INP), TMP
|
||||||
|
XOR KEY, TMP, KEY
|
||||||
|
MOVBU KEY, 1(OUT)
|
||||||
|
BC 16, LT, looptail_vsx
|
||||||
|
|
||||||
|
// Clear the stack values
|
||||||
|
STXVW4X VS48, (R11)(R0)
|
||||||
|
STXVW4X VS48, (R11)(R8)
|
||||||
|
STXVW4X VS48, (R11)(R9)
|
||||||
|
STXVW4X VS48, (R11)(R10)
|
||||||
|
BR done_vsx
|
@ -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,!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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// We have an implementation in amd64 assembly so this code is only run on
|
// Package curve25519 provides an implementation of the X25519 function, which
|
||||||
// non-amd64 platforms. The amd64 assembly does not support gccgo.
|
// performs scalar multiplication on the elliptic curve known as Curve25519.
|
||||||
// +build !amd64 gccgo appengine
|
// See RFC 7748.
|
||||||
|
package curve25519 // import "golang.org/x/crypto/curve25519"
|
||||||
package curve25519
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"crypto/subtle"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This code is a port of the public domain, "ref10" implementation of
|
// ScalarMult sets dst to the product scalar * point.
|
||||||
// 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.
|
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
|
||||||
// Have 0<=r<=p-1=2^255-20.
|
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
|
||||||
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
|
// will return an error.
|
||||||
//
|
func ScalarMult(dst, scalar, point *[32]byte) {
|
||||||
// Write x=r+19(2^-255)r+y.
|
scalarMult(dst, scalar, point)
|
||||||
// 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
|
// ScalarBaseMult sets dst to the product scalar * base where base is the
|
||||||
// Can overlap h with f or g.
|
// standard generator.
|
||||||
//
|
|
||||||
// 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;
|
// It is recommended to use the X25519 function with Basepoint instead, as
|
||||||
// cheaper than 64-bit postcomputations.
|
// copying into fixed size arrays can lead to unexpected bugs.
|
||||||
//
|
func ScalarBaseMult(dst, scalar *[32]byte) {
|
||||||
// There is one remaining multiplication by 19 in the carry chain;
|
ScalarMult(dst, scalar, &basePoint)
|
||||||
// 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.
|
const (
|
||||||
//
|
// ScalarSize is the size of the scalar input to X25519.
|
||||||
// Preconditions:
|
ScalarSize = 32
|
||||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
// PointSize is the size of the point input to X25519.
|
||||||
//
|
PointSize = 32
|
||||||
// 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
|
// Basepoint is the canonical Curve25519 generator.
|
||||||
h5 += carry[4]
|
var Basepoint []byte
|
||||||
h4 -= carry[4] << 26
|
|
||||||
carry[8] = (h8 + (1 << 25)) >> 26
|
|
||||||
h9 += carry[8]
|
|
||||||
h8 -= carry[8] << 26
|
|
||||||
|
|
||||||
carry[9] = (h9 + (1 << 24)) >> 25
|
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}
|
||||||
h0 += carry[9] * 19
|
|
||||||
h9 -= carry[9] << 25
|
|
||||||
|
|
||||||
carry[0] = (h0 + (1 << 25)) >> 26
|
func init() { Basepoint = basePoint[:] }
|
||||||
h1 += carry[0]
|
|
||||||
h0 -= carry[0] << 26
|
|
||||||
|
|
||||||
h[0] = int32(h0)
|
func checkBasepoint() {
|
||||||
h[1] = int32(h1)
|
if subtle.ConstantTimeCompare(Basepoint, []byte{
|
||||||
h[2] = int32(h2)
|
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
h[3] = int32(h3)
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
h[4] = int32(h4)
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
h[5] = int32(h5)
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
h[6] = int32(h6)
|
}) != 1 {
|
||||||
h[7] = int32(h7)
|
panic("curve25519: global Basepoint value was modified")
|
||||||
h[8] = int32(h8)
|
}
|
||||||
h[9] = int32(h9)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// feMul121666 calculates h = f * 121666. Can overlap h with f.
|
// 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.
|
||||||
//
|
//
|
||||||
// Preconditions:
|
// scalar can be generated at random, for example with crypto/rand. point should
|
||||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
// be either Basepoint or the output of another X25519 call.
|
||||||
//
|
//
|
||||||
// Postconditions:
|
// If point is Basepoint (but not if it's a different slice with the same
|
||||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
// contents) a precomputed implementation might be used for performance.
|
||||||
func feMul121666(h, f *fieldElement) {
|
func X25519(scalar, point []byte) ([]byte, error) {
|
||||||
h0 := int64(f[0]) * 121666
|
// Outline the body of function, to let the allocation be inlined in the
|
||||||
h1 := int64(f[1]) * 121666
|
// caller, and possibly avoid escaping to the heap.
|
||||||
h2 := int64(f[2]) * 121666
|
var dst [32]byte
|
||||||
h3 := int64(f[3]) * 121666
|
return x25519(&dst, scalar, point)
|
||||||
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) {
|
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
|
||||||
var e [32]byte
|
var in [32]byte
|
||||||
|
if l := len(scalar); l != 32 {
|
||||||
copy(e[:], in[:])
|
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32)
|
||||||
e[0] &= 248
|
}
|
||||||
e[31] &= 127
|
if l := len(point); l != 32 {
|
||||||
e[31] |= 64
|
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32)
|
||||||
|
}
|
||||||
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
|
copy(in[:], scalar)
|
||||||
feFromBytes(&x1, base)
|
if &point[0] == &Basepoint[0] {
|
||||||
feOne(&x2)
|
checkBasepoint()
|
||||||
feCopy(&x3, &x1)
|
ScalarBaseMult(dst, &in)
|
||||||
feOne(&z3)
|
} else {
|
||||||
|
var base, zero [32]byte
|
||||||
swap := int32(0)
|
copy(base[:], point)
|
||||||
for pos := 254; pos >= 0; pos-- {
|
ScalarMult(dst, &in, &base)
|
||||||
b := e[pos/8] >> uint(pos&7)
|
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
|
||||||
b &= 1
|
return nil, fmt.Errorf("bad input point: low order point")
|
||||||
swap ^= int32(b)
|
}
|
||||||
feCSwap(&x2, &x3, swap)
|
}
|
||||||
feCSwap(&z2, &z3, swap)
|
return dst[:], nil
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,668 +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.
|
|
||||||
|
|
||||||
// Based on CRYPTOGAMS code with the following comment:
|
|
||||||
// # ====================================================================
|
|
||||||
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
|
||||||
// # project. The module is, however, dual licensed under OpenSSL and
|
|
||||||
// # CRYPTOGAMS licenses depending on where you obtain it. For further
|
|
||||||
// # details see http://www.openssl.org/~appro/cryptogams/.
|
|
||||||
// # ====================================================================
|
|
||||||
|
|
||||||
// Original code can be found at the link below:
|
|
||||||
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff
|
|
||||||
|
|
||||||
// There are some differences between CRYPTOGAMS code and this one. The round
|
|
||||||
// loop for "_int" isn't the same as the original. Some adjustments were
|
|
||||||
// necessary because there are less vector registers available. For example, some
|
|
||||||
// X variables (r12, r13, r14, and r15) share the same register used by the
|
|
||||||
// counter. The original code uses ctr to name the counter. Here we use CNT
|
|
||||||
// because golang uses CTR as the counter register name.
|
|
||||||
|
|
||||||
// +build ppc64le,!gccgo,!appengine
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define OUT R3
|
|
||||||
#define INP R4
|
|
||||||
#define LEN R5
|
|
||||||
#define KEY R6
|
|
||||||
#define CNT R7
|
|
||||||
|
|
||||||
#define TEMP R8
|
|
||||||
|
|
||||||
#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 CON0 X0
|
|
||||||
#define CON1 X1
|
|
||||||
#define CON2 X2
|
|
||||||
#define CON3 X3
|
|
||||||
|
|
||||||
#define KEY0 X4
|
|
||||||
#define KEY1 X5
|
|
||||||
#define KEY2 X6
|
|
||||||
#define KEY3 X7
|
|
||||||
#define KEY4 X8
|
|
||||||
#define KEY5 X9
|
|
||||||
#define KEY6 X10
|
|
||||||
#define KEY7 X11
|
|
||||||
|
|
||||||
#define CNT0 X12
|
|
||||||
#define CNT1 X13
|
|
||||||
#define CNT2 X14
|
|
||||||
#define CNT3 X15
|
|
||||||
|
|
||||||
#define TMP0 R9
|
|
||||||
#define TMP1 R10
|
|
||||||
#define TMP2 R28
|
|
||||||
#define TMP3 R29
|
|
||||||
|
|
||||||
#define CONSTS R8
|
|
||||||
|
|
||||||
#define A0 V0
|
|
||||||
#define B0 V1
|
|
||||||
#define C0 V2
|
|
||||||
#define D0 V3
|
|
||||||
#define A1 V4
|
|
||||||
#define B1 V5
|
|
||||||
#define C1 V6
|
|
||||||
#define D1 V7
|
|
||||||
#define A2 V8
|
|
||||||
#define B2 V9
|
|
||||||
#define C2 V10
|
|
||||||
#define D2 V11
|
|
||||||
#define T0 V12
|
|
||||||
#define T1 V13
|
|
||||||
#define T2 V14
|
|
||||||
|
|
||||||
#define K0 V15
|
|
||||||
#define K1 V16
|
|
||||||
#define K2 V17
|
|
||||||
#define K3 V18
|
|
||||||
#define K4 V19
|
|
||||||
#define K5 V20
|
|
||||||
|
|
||||||
#define FOUR V21
|
|
||||||
#define SIXTEEN V22
|
|
||||||
#define TWENTY4 V23
|
|
||||||
#define TWENTY V24
|
|
||||||
#define TWELVE V25
|
|
||||||
#define TWENTY5 V26
|
|
||||||
#define SEVEN V27
|
|
||||||
|
|
||||||
#define INPPERM V28
|
|
||||||
#define OUTPERM V29
|
|
||||||
#define OUTMASK V30
|
|
||||||
|
|
||||||
#define DD0 V31
|
|
||||||
#define DD1 SEVEN
|
|
||||||
#define DD2 T0
|
|
||||||
#define DD3 T1
|
|
||||||
#define DD4 T2
|
|
||||||
|
|
||||||
DATA ·consts+0x00(SB)/8, $0x3320646e61707865
|
|
||||||
DATA ·consts+0x08(SB)/8, $0x6b20657479622d32
|
|
||||||
DATA ·consts+0x10(SB)/8, $0x0000000000000001
|
|
||||||
DATA ·consts+0x18(SB)/8, $0x0000000000000000
|
|
||||||
DATA ·consts+0x20(SB)/8, $0x0000000000000004
|
|
||||||
DATA ·consts+0x28(SB)/8, $0x0000000000000000
|
|
||||||
DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d
|
|
||||||
DATA ·consts+0x38(SB)/8, $0x0203000106070405
|
|
||||||
DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c
|
|
||||||
DATA ·consts+0x48(SB)/8, $0x0102030005060704
|
|
||||||
GLOBL ·consts(SB), RODATA, $80
|
|
||||||
|
|
||||||
//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte)
|
|
||||||
TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0
|
|
||||||
// Load the arguments inside the registers
|
|
||||||
MOVD out+0(FP), OUT
|
|
||||||
MOVD inp+8(FP), INP
|
|
||||||
MOVD len+16(FP), LEN
|
|
||||||
MOVD key+24(FP), KEY
|
|
||||||
MOVD counter+32(FP), CNT
|
|
||||||
|
|
||||||
MOVD $·consts(SB), CONSTS // point to consts addr
|
|
||||||
|
|
||||||
MOVD $16, X0
|
|
||||||
MOVD $32, X1
|
|
||||||
MOVD $48, X2
|
|
||||||
MOVD $64, X3
|
|
||||||
MOVD $31, X4
|
|
||||||
MOVD $15, X5
|
|
||||||
|
|
||||||
// Load key
|
|
||||||
LVX (KEY)(R0), K1
|
|
||||||
LVSR (KEY)(R0), T0
|
|
||||||
LVX (KEY)(X0), K2
|
|
||||||
LVX (KEY)(X4), DD0
|
|
||||||
|
|
||||||
// Load counter
|
|
||||||
LVX (CNT)(R0), K3
|
|
||||||
LVSR (CNT)(R0), T1
|
|
||||||
LVX (CNT)(X5), DD1
|
|
||||||
|
|
||||||
// Load constants
|
|
||||||
LVX (CONSTS)(R0), K0
|
|
||||||
LVX (CONSTS)(X0), K5
|
|
||||||
LVX (CONSTS)(X1), FOUR
|
|
||||||
LVX (CONSTS)(X2), SIXTEEN
|
|
||||||
LVX (CONSTS)(X3), TWENTY4
|
|
||||||
|
|
||||||
// Align key and counter
|
|
||||||
VPERM K2, K1, T0, K1
|
|
||||||
VPERM DD0, K2, T0, K2
|
|
||||||
VPERM DD1, K3, T1, K3
|
|
||||||
|
|
||||||
// Load counter to GPR
|
|
||||||
MOVWZ 0(CNT), CNT0
|
|
||||||
MOVWZ 4(CNT), CNT1
|
|
||||||
MOVWZ 8(CNT), CNT2
|
|
||||||
MOVWZ 12(CNT), CNT3
|
|
||||||
|
|
||||||
// Adjust vectors for the initial state
|
|
||||||
VADDUWM K3, K5, K3
|
|
||||||
VADDUWM K3, K5, K4
|
|
||||||
VADDUWM K4, K5, K5
|
|
||||||
|
|
||||||
// Synthesized constants
|
|
||||||
VSPLTISW $-12, TWENTY
|
|
||||||
VSPLTISW $12, TWELVE
|
|
||||||
VSPLTISW $-7, TWENTY5
|
|
||||||
|
|
||||||
VXOR T0, T0, T0
|
|
||||||
VSPLTISW $-1, OUTMASK
|
|
||||||
LVSR (INP)(R0), INPPERM
|
|
||||||
LVSL (OUT)(R0), OUTPERM
|
|
||||||
VPERM OUTMASK, T0, OUTPERM, OUTMASK
|
|
||||||
|
|
||||||
loop_outer_vmx:
|
|
||||||
// Load constant
|
|
||||||
MOVD $0x61707865, CON0
|
|
||||||
MOVD $0x3320646e, CON1
|
|
||||||
MOVD $0x79622d32, CON2
|
|
||||||
MOVD $0x6b206574, CON3
|
|
||||||
|
|
||||||
VOR K0, K0, A0
|
|
||||||
VOR K0, K0, A1
|
|
||||||
VOR K0, K0, A2
|
|
||||||
VOR K1, K1, B0
|
|
||||||
|
|
||||||
MOVD $10, TEMP
|
|
||||||
|
|
||||||
// Load key to GPR
|
|
||||||
MOVWZ 0(KEY), X4
|
|
||||||
MOVWZ 4(KEY), X5
|
|
||||||
MOVWZ 8(KEY), X6
|
|
||||||
MOVWZ 12(KEY), X7
|
|
||||||
VOR K1, K1, B1
|
|
||||||
VOR K1, K1, B2
|
|
||||||
MOVWZ 16(KEY), X8
|
|
||||||
MOVWZ 0(CNT), X12
|
|
||||||
MOVWZ 20(KEY), X9
|
|
||||||
MOVWZ 4(CNT), X13
|
|
||||||
VOR K2, K2, C0
|
|
||||||
VOR K2, K2, C1
|
|
||||||
MOVWZ 24(KEY), X10
|
|
||||||
MOVWZ 8(CNT), X14
|
|
||||||
VOR K2, K2, C2
|
|
||||||
VOR K3, K3, D0
|
|
||||||
MOVWZ 28(KEY), X11
|
|
||||||
MOVWZ 12(CNT), X15
|
|
||||||
VOR K4, K4, D1
|
|
||||||
VOR K5, K5, D2
|
|
||||||
|
|
||||||
MOVD X4, TMP0
|
|
||||||
MOVD X5, TMP1
|
|
||||||
MOVD X6, TMP2
|
|
||||||
MOVD X7, TMP3
|
|
||||||
VSPLTISW $7, SEVEN
|
|
||||||
|
|
||||||
MOVD TEMP, CTR
|
|
||||||
|
|
||||||
loop_vmx:
|
|
||||||
// CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible
|
|
||||||
// using assembly macros. Therefore, the macro expansion result was used
|
|
||||||
// in order to maintain the algorithm efficiency.
|
|
||||||
// This loop generates three keystream blocks using VMX instructions and,
|
|
||||||
// in parallel, one keystream block using scalar instructions.
|
|
||||||
ADD X4, X0, X0
|
|
||||||
ADD X5, X1, X1
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
ADD X6, X2, X2
|
|
||||||
ADD X7, X3, X3
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
XOR X0, X12, X12
|
|
||||||
XOR X1, X13, X13
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
XOR X2, X14, X14
|
|
||||||
XOR X3, X15, X15
|
|
||||||
VPERM D0, D0, SIXTEEN, D0
|
|
||||||
VPERM D1, D1, SIXTEEN, D1
|
|
||||||
ROTLW $16, X12, X12
|
|
||||||
ROTLW $16, X13, X13
|
|
||||||
VPERM D2, D2, SIXTEEN, D2
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
ROTLW $16, X14, X14
|
|
||||||
ROTLW $16, X15, X15
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
ADD X12, X8, X8
|
|
||||||
ADD X13, X9, X9
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
ADD X14, X10, X10
|
|
||||||
ADD X15, X11, X11
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
VRLW T0, TWELVE, B0
|
|
||||||
XOR X8, X4, X4
|
|
||||||
XOR X9, X5, X5
|
|
||||||
VRLW T1, TWELVE, B1
|
|
||||||
VRLW T2, TWELVE, B2
|
|
||||||
XOR X10, X6, X6
|
|
||||||
XOR X11, X7, X7
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
ROTLW $12, X4, X4
|
|
||||||
ROTLW $12, X5, X5
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
ROTLW $12, X6, X6
|
|
||||||
ROTLW $12, X7, X7
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
ADD X4, X0, X0
|
|
||||||
ADD X5, X1, X1
|
|
||||||
VPERM D0, D0, TWENTY4, D0
|
|
||||||
VPERM D1, D1, TWENTY4, D1
|
|
||||||
ADD X6, X2, X2
|
|
||||||
ADD X7, X3, X3
|
|
||||||
VPERM D2, D2, TWENTY4, D2
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
XOR X0, X12, X12
|
|
||||||
XOR X1, X13, X13
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
XOR X2, X14, X14
|
|
||||||
XOR X3, X15, X15
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
ROTLW $8, X12, X12
|
|
||||||
ROTLW $8, X13, X13
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
VRLW T0, SEVEN, B0
|
|
||||||
ROTLW $8, X14, X14
|
|
||||||
ROTLW $8, X15, X15
|
|
||||||
VRLW T1, SEVEN, B1
|
|
||||||
VRLW T2, SEVEN, B2
|
|
||||||
ADD X12, X8, X8
|
|
||||||
ADD X13, X9, X9
|
|
||||||
VSLDOI $8, C0, C0, C0
|
|
||||||
VSLDOI $8, C1, C1, C1
|
|
||||||
ADD X14, X10, X10
|
|
||||||
ADD X15, X11, X11
|
|
||||||
VSLDOI $8, C2, C2, C2
|
|
||||||
VSLDOI $12, B0, B0, B0
|
|
||||||
XOR X8, X4, X4
|
|
||||||
XOR X9, X5, X5
|
|
||||||
VSLDOI $12, B1, B1, B1
|
|
||||||
VSLDOI $12, B2, B2, B2
|
|
||||||
XOR X10, X6, X6
|
|
||||||
XOR X11, X7, X7
|
|
||||||
VSLDOI $4, D0, D0, D0
|
|
||||||
VSLDOI $4, D1, D1, D1
|
|
||||||
ROTLW $7, X4, X4
|
|
||||||
ROTLW $7, X5, X5
|
|
||||||
VSLDOI $4, D2, D2, D2
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
ROTLW $7, X6, X6
|
|
||||||
ROTLW $7, X7, X7
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
ADD X5, X0, X0
|
|
||||||
ADD X6, X1, X1
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
ADD X7, X2, X2
|
|
||||||
ADD X4, X3, X3
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
VPERM D0, D0, SIXTEEN, D0
|
|
||||||
XOR X0, X15, X15
|
|
||||||
XOR X1, X12, X12
|
|
||||||
VPERM D1, D1, SIXTEEN, D1
|
|
||||||
VPERM D2, D2, SIXTEEN, D2
|
|
||||||
XOR X2, X13, X13
|
|
||||||
XOR X3, X14, X14
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
ROTLW $16, X15, X15
|
|
||||||
ROTLW $16, X12, X12
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
ROTLW $16, X13, X13
|
|
||||||
ROTLW $16, X14, X14
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
ADD X15, X10, X10
|
|
||||||
ADD X12, X11, X11
|
|
||||||
VRLW T0, TWELVE, B0
|
|
||||||
VRLW T1, TWELVE, B1
|
|
||||||
ADD X13, X8, X8
|
|
||||||
ADD X14, X9, X9
|
|
||||||
VRLW T2, TWELVE, B2
|
|
||||||
VADDUWM A0, B0, A0
|
|
||||||
XOR X10, X5, X5
|
|
||||||
XOR X11, X6, X6
|
|
||||||
VADDUWM A1, B1, A1
|
|
||||||
VADDUWM A2, B2, A2
|
|
||||||
XOR X8, X7, X7
|
|
||||||
XOR X9, X4, X4
|
|
||||||
VXOR D0, A0, D0
|
|
||||||
VXOR D1, A1, D1
|
|
||||||
ROTLW $12, X5, X5
|
|
||||||
ROTLW $12, X6, X6
|
|
||||||
VXOR D2, A2, D2
|
|
||||||
VPERM D0, D0, TWENTY4, D0
|
|
||||||
ROTLW $12, X7, X7
|
|
||||||
ROTLW $12, X4, X4
|
|
||||||
VPERM D1, D1, TWENTY4, D1
|
|
||||||
VPERM D2, D2, TWENTY4, D2
|
|
||||||
ADD X5, X0, X0
|
|
||||||
ADD X6, X1, X1
|
|
||||||
VADDUWM C0, D0, C0
|
|
||||||
VADDUWM C1, D1, C1
|
|
||||||
ADD X7, X2, X2
|
|
||||||
ADD X4, X3, X3
|
|
||||||
VADDUWM C2, D2, C2
|
|
||||||
VXOR B0, C0, T0
|
|
||||||
XOR X0, X15, X15
|
|
||||||
XOR X1, X12, X12
|
|
||||||
VXOR B1, C1, T1
|
|
||||||
VXOR B2, C2, T2
|
|
||||||
XOR X2, X13, X13
|
|
||||||
XOR X3, X14, X14
|
|
||||||
VRLW T0, SEVEN, B0
|
|
||||||
VRLW T1, SEVEN, B1
|
|
||||||
ROTLW $8, X15, X15
|
|
||||||
ROTLW $8, X12, X12
|
|
||||||
VRLW T2, SEVEN, B2
|
|
||||||
VSLDOI $8, C0, C0, C0
|
|
||||||
ROTLW $8, X13, X13
|
|
||||||
ROTLW $8, X14, X14
|
|
||||||
VSLDOI $8, C1, C1, C1
|
|
||||||
VSLDOI $8, C2, C2, C2
|
|
||||||
ADD X15, X10, X10
|
|
||||||
ADD X12, X11, X11
|
|
||||||
VSLDOI $4, B0, B0, B0
|
|
||||||
VSLDOI $4, B1, B1, B1
|
|
||||||
ADD X13, X8, X8
|
|
||||||
ADD X14, X9, X9
|
|
||||||
VSLDOI $4, B2, B2, B2
|
|
||||||
VSLDOI $12, D0, D0, D0
|
|
||||||
XOR X10, X5, X5
|
|
||||||
XOR X11, X6, X6
|
|
||||||
VSLDOI $12, D1, D1, D1
|
|
||||||
VSLDOI $12, D2, D2, D2
|
|
||||||
XOR X8, X7, X7
|
|
||||||
XOR X9, X4, X4
|
|
||||||
ROTLW $7, X5, X5
|
|
||||||
ROTLW $7, X6, X6
|
|
||||||
ROTLW $7, X7, X7
|
|
||||||
ROTLW $7, X4, X4
|
|
||||||
BC 0x10, 0, loop_vmx
|
|
||||||
|
|
||||||
SUB $256, LEN, LEN
|
|
||||||
|
|
||||||
// Accumulate key block
|
|
||||||
ADD $0x61707865, X0, X0
|
|
||||||
ADD $0x3320646e, X1, X1
|
|
||||||
ADD $0x79622d32, X2, X2
|
|
||||||
ADD $0x6b206574, X3, X3
|
|
||||||
ADD TMP0, X4, X4
|
|
||||||
ADD TMP1, X5, X5
|
|
||||||
ADD TMP2, X6, X6
|
|
||||||
ADD TMP3, X7, X7
|
|
||||||
MOVWZ 16(KEY), TMP0
|
|
||||||
MOVWZ 20(KEY), TMP1
|
|
||||||
MOVWZ 24(KEY), TMP2
|
|
||||||
MOVWZ 28(KEY), TMP3
|
|
||||||
ADD TMP0, X8, X8
|
|
||||||
ADD TMP1, X9, X9
|
|
||||||
ADD TMP2, X10, X10
|
|
||||||
ADD TMP3, X11, X11
|
|
||||||
|
|
||||||
MOVWZ 12(CNT), TMP0
|
|
||||||
MOVWZ 8(CNT), TMP1
|
|
||||||
MOVWZ 4(CNT), TMP2
|
|
||||||
MOVWZ 0(CNT), TEMP
|
|
||||||
ADD TMP0, X15, X15
|
|
||||||
ADD TMP1, X14, X14
|
|
||||||
ADD TMP2, X13, X13
|
|
||||||
ADD TEMP, X12, X12
|
|
||||||
|
|
||||||
// Accumulate key block
|
|
||||||
VADDUWM A0, K0, A0
|
|
||||||
VADDUWM A1, K0, A1
|
|
||||||
VADDUWM A2, K0, A2
|
|
||||||
VADDUWM B0, K1, B0
|
|
||||||
VADDUWM B1, K1, B1
|
|
||||||
VADDUWM B2, K1, B2
|
|
||||||
VADDUWM C0, K2, C0
|
|
||||||
VADDUWM C1, K2, C1
|
|
||||||
VADDUWM C2, K2, C2
|
|
||||||
VADDUWM D0, K3, D0
|
|
||||||
VADDUWM D1, K4, D1
|
|
||||||
VADDUWM D2, K5, D2
|
|
||||||
|
|
||||||
// Increment counter
|
|
||||||
ADD $4, TEMP, TEMP
|
|
||||||
MOVW TEMP, 0(CNT)
|
|
||||||
|
|
||||||
VADDUWM K3, FOUR, K3
|
|
||||||
VADDUWM K4, FOUR, K4
|
|
||||||
VADDUWM K5, FOUR, K5
|
|
||||||
|
|
||||||
// XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3).
|
|
||||||
|
|
||||||
// Load input (aligned or not)
|
|
||||||
MOVWZ 0(INP), TMP0
|
|
||||||
MOVWZ 4(INP), TMP1
|
|
||||||
MOVWZ 8(INP), TMP2
|
|
||||||
MOVWZ 12(INP), TMP3
|
|
||||||
|
|
||||||
// XOR with input
|
|
||||||
XOR TMP0, X0, X0
|
|
||||||
XOR TMP1, X1, X1
|
|
||||||
XOR TMP2, X2, X2
|
|
||||||
XOR TMP3, X3, X3
|
|
||||||
MOVWZ 16(INP), TMP0
|
|
||||||
MOVWZ 20(INP), TMP1
|
|
||||||
MOVWZ 24(INP), TMP2
|
|
||||||
MOVWZ 28(INP), TMP3
|
|
||||||
XOR TMP0, X4, X4
|
|
||||||
XOR TMP1, X5, X5
|
|
||||||
XOR TMP2, X6, X6
|
|
||||||
XOR TMP3, X7, X7
|
|
||||||
MOVWZ 32(INP), TMP0
|
|
||||||
MOVWZ 36(INP), TMP1
|
|
||||||
MOVWZ 40(INP), TMP2
|
|
||||||
MOVWZ 44(INP), TMP3
|
|
||||||
XOR TMP0, X8, X8
|
|
||||||
XOR TMP1, X9, X9
|
|
||||||
XOR TMP2, X10, X10
|
|
||||||
XOR TMP3, X11, X11
|
|
||||||
MOVWZ 48(INP), TMP0
|
|
||||||
MOVWZ 52(INP), TMP1
|
|
||||||
MOVWZ 56(INP), TMP2
|
|
||||||
MOVWZ 60(INP), TMP3
|
|
||||||
XOR TMP0, X12, X12
|
|
||||||
XOR TMP1, X13, X13
|
|
||||||
XOR TMP2, X14, X14
|
|
||||||
XOR TMP3, X15, X15
|
|
||||||
|
|
||||||
// Store output (aligned or not)
|
|
||||||
MOVW X0, 0(OUT)
|
|
||||||
MOVW X1, 4(OUT)
|
|
||||||
MOVW X2, 8(OUT)
|
|
||||||
MOVW X3, 12(OUT)
|
|
||||||
|
|
||||||
ADD $64, INP, INP // INP points to the end of the slice for the alignment code below
|
|
||||||
|
|
||||||
MOVW X4, 16(OUT)
|
|
||||||
MOVD $16, TMP0
|
|
||||||
MOVW X5, 20(OUT)
|
|
||||||
MOVD $32, TMP1
|
|
||||||
MOVW X6, 24(OUT)
|
|
||||||
MOVD $48, TMP2
|
|
||||||
MOVW X7, 28(OUT)
|
|
||||||
MOVD $64, TMP3
|
|
||||||
MOVW X8, 32(OUT)
|
|
||||||
MOVW X9, 36(OUT)
|
|
||||||
MOVW X10, 40(OUT)
|
|
||||||
MOVW X11, 44(OUT)
|
|
||||||
MOVW X12, 48(OUT)
|
|
||||||
MOVW X13, 52(OUT)
|
|
||||||
MOVW X14, 56(OUT)
|
|
||||||
MOVW X15, 60(OUT)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
|
|
||||||
// Load input
|
|
||||||
LVX (INP)(R0), DD0
|
|
||||||
LVX (INP)(TMP0), DD1
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
LVX (INP)(TMP3), DD4
|
|
||||||
ADD $64, INP, INP
|
|
||||||
|
|
||||||
VPERM DD1, DD0, INPPERM, DD0 // Align input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD4, DD3, INPPERM, DD3
|
|
||||||
VXOR A0, DD0, A0 // XOR with input
|
|
||||||
VXOR B0, DD1, B0
|
|
||||||
LVX (INP)(TMP0), DD1 // Keep loading input
|
|
||||||
VXOR C0, DD2, C0
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
VXOR D0, DD3, D0
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
LVX (INP)(TMP3), DD0
|
|
||||||
ADD $64, INP, INP
|
|
||||||
MOVD $63, TMP3 // 63 is not a typo
|
|
||||||
VPERM A0, A0, OUTPERM, A0
|
|
||||||
VPERM B0, B0, OUTPERM, B0
|
|
||||||
VPERM C0, C0, OUTPERM, C0
|
|
||||||
VPERM D0, D0, OUTPERM, D0
|
|
||||||
|
|
||||||
VPERM DD1, DD4, INPPERM, DD4 // Align input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD0, DD3, INPPERM, DD3
|
|
||||||
VXOR A1, DD4, A1
|
|
||||||
VXOR B1, DD1, B1
|
|
||||||
LVX (INP)(TMP0), DD1 // Keep loading
|
|
||||||
VXOR C1, DD2, C1
|
|
||||||
LVX (INP)(TMP1), DD2
|
|
||||||
VXOR D1, DD3, D1
|
|
||||||
LVX (INP)(TMP2), DD3
|
|
||||||
|
|
||||||
// Note that the LVX address is always rounded down to the nearest 16-byte
|
|
||||||
// boundary, and that it always points to at most 15 bytes beyond the end of
|
|
||||||
// the slice, so we cannot cross a page boundary.
|
|
||||||
LVX (INP)(TMP3), DD4 // Redundant in aligned case.
|
|
||||||
ADD $64, INP, INP
|
|
||||||
VPERM A1, A1, OUTPERM, A1 // Pre-misalign output
|
|
||||||
VPERM B1, B1, OUTPERM, B1
|
|
||||||
VPERM C1, C1, OUTPERM, C1
|
|
||||||
VPERM D1, D1, OUTPERM, D1
|
|
||||||
|
|
||||||
VPERM DD1, DD0, INPPERM, DD0 // Align Input
|
|
||||||
VPERM DD2, DD1, INPPERM, DD1
|
|
||||||
VPERM DD3, DD2, INPPERM, DD2
|
|
||||||
VPERM DD4, DD3, INPPERM, DD3
|
|
||||||
VXOR A2, DD0, A2
|
|
||||||
VXOR B2, DD1, B2
|
|
||||||
VXOR C2, DD2, C2
|
|
||||||
VXOR D2, DD3, D2
|
|
||||||
VPERM A2, A2, OUTPERM, A2
|
|
||||||
VPERM B2, B2, OUTPERM, B2
|
|
||||||
VPERM C2, C2, OUTPERM, C2
|
|
||||||
VPERM D2, D2, OUTPERM, D2
|
|
||||||
|
|
||||||
ANDCC $15, OUT, X1 // Is out aligned?
|
|
||||||
MOVD OUT, X0
|
|
||||||
|
|
||||||
VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output
|
|
||||||
VSEL B0, C0, OUTMASK, DD1
|
|
||||||
VSEL C0, D0, OUTMASK, DD2
|
|
||||||
VSEL D0, A1, OUTMASK, DD3
|
|
||||||
VSEL A1, B1, OUTMASK, B0
|
|
||||||
VSEL B1, C1, OUTMASK, C0
|
|
||||||
VSEL C1, D1, OUTMASK, D0
|
|
||||||
VSEL D1, A2, OUTMASK, A1
|
|
||||||
VSEL A2, B2, OUTMASK, B1
|
|
||||||
VSEL B2, C2, OUTMASK, C1
|
|
||||||
VSEL C2, D2, OUTMASK, D1
|
|
||||||
|
|
||||||
STVX DD0, (OUT+TMP0)
|
|
||||||
STVX DD1, (OUT+TMP1)
|
|
||||||
STVX DD2, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
STVX DD3, (OUT+R0)
|
|
||||||
STVX B0, (OUT+TMP0)
|
|
||||||
STVX C0, (OUT+TMP1)
|
|
||||||
STVX D0, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
STVX A1, (OUT+R0)
|
|
||||||
STVX B1, (OUT+TMP0)
|
|
||||||
STVX C1, (OUT+TMP1)
|
|
||||||
STVX D1, (OUT+TMP2)
|
|
||||||
ADD $64, OUT, OUT
|
|
||||||
|
|
||||||
BEQ aligned_vmx
|
|
||||||
|
|
||||||
SUB X1, OUT, X2 // in misaligned case edges
|
|
||||||
MOVD $0, X3 // are written byte-by-byte
|
|
||||||
|
|
||||||
unaligned_tail_vmx:
|
|
||||||
STVEBX D2, (X2+X3)
|
|
||||||
ADD $1, X3, X3
|
|
||||||
CMPW X3, X1
|
|
||||||
BNE unaligned_tail_vmx
|
|
||||||
SUB X1, X0, X2
|
|
||||||
|
|
||||||
unaligned_head_vmx:
|
|
||||||
STVEBX A0, (X2+X1)
|
|
||||||
CMPW X1, $15
|
|
||||||
ADD $1, X1, X1
|
|
||||||
BNE unaligned_head_vmx
|
|
||||||
|
|
||||||
CMPU LEN, $255 // done with 256-byte block yet?
|
|
||||||
BGT loop_outer_vmx
|
|
||||||
|
|
||||||
JMP done_vmx
|
|
||||||
|
|
||||||
aligned_vmx:
|
|
||||||
STVX A0, (X0+R0)
|
|
||||||
CMPU LEN, $255 // done with 256-byte block yet?
|
|
||||||
BGT loop_outer_vmx
|
|
||||||
|
|
||||||
done_vmx:
|
|
||||||
RET
|
|
@ -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])
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
@ -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 !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
|
|
||||||
|
|
||||||
package chacha20
|
|
||||||
|
|
||||||
const (
|
|
||||||
bufSize = 64
|
|
||||||
haveAsm = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
@ -1,52 +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"
|
|
||||||
|
|
||||||
const (
|
|
||||||
bufSize = 256
|
|
||||||
haveAsm = true
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
|
||||||
|
|
||||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
||||||
if len(src) >= bufSize {
|
|
||||||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter)
|
|
||||||
}
|
|
||||||
if len(src)%bufSize != 0 {
|
|
||||||
chaCha20_ctr32_vmx(&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)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue