Compare commits

...
50 Commits
Author SHA1 Message Date
Gopher Robot 959f8f3db0 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: I1e9480e5897a08cac746309acdc8bbdf0bce8060
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/663256
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-04-06 09:04:20 -07:00
Nicola Murino 769bcd6997 ssh: use the configured rand in kex init
Change-Id: I4f89c395886b9dd07b584d1fcf1a0f2df215b91b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/644435
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Carlos Amedee <carlos@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
2025-04-03 13:05:29 -07:00
Simon Josefsson d0a798f774 cryptobyte: fix typo 'octects' into 'octets' for asn1.go
This typo ends up into lots of executables that trigger 'codespell'-style linter checks.

Change-Id: I2a7e3a6597272ca7c97ebddc54c5eef4cb5cab88
GitHub-Last-Rev: e42f734f00aa575030b72dd1e328d2acefb02625
GitHub-Pull-Request: golang/crypto#310
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/646375
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2025-03-17 08:22:34 -07:00
Mateusz Poliwczak acbcbef23f acme: remove unnecessary []byte conversion
Change-Id: Iddbe6bcb7a5487678c48df65903571b4625fc9f9
GitHub-Last-Rev: 2552a8d99c7472f029d7da270fa814398793b564
GitHub-Pull-Request: golang/crypto#243
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/456438
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Sean Liao <sean@liao.dev>
Auto-Submit: Sean Liao <sean@liao.dev>
2025-03-17 08:22:03 -07:00
Roland Shoemaker 376eb14006 x509roots: support constrained roots
Adds support for roots with the distrust-after bit set. The constraint
function construction is a little funky, but I couldn't think of an
obvious better way to do it.

Fixes golang/go#70777
Fixes golang/go#70623

Change-Id: I780f866416b626360eaee9368185768da7bc75ef
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/652996
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-03-13 16:44:06 -07:00
Xiaolin Zhao b369b723c8 crypto/internal/poly1305: implement function update in assembly on loong64
The performance improvements on Loongson-3A5000 and Loongson-3A6000 are as follows:

goos: linux
goarch: loong64
pkg: golang.org/x/crypto/internal/poly1305
cpu: Loongson-3A5000 @ 2500.00MHz
                 |  bench.old   |              bench.new              |
                 |    sec/op    |   sec/op     vs base                |
64                  122.8n ± 0%   100.0n ± 0%  -18.57% (p=0.000 n=10)
1K                 1152.0n ± 0%   732.2n ± 0%  -36.44% (p=0.000 n=10)
2M                  2.356m ± 0%   1.443m ± 0%  -38.74% (p=0.000 n=10)
64Unaligned         122.7n ± 0%   101.5n ± 0%  -17.24% (p=0.000 n=10)
1KUnaligned        1152.0n ± 0%   745.4n ± 0%  -35.30% (p=0.000 n=10)
2MUnaligned         2.336m ± 0%   1.473m ± 0%  -36.94% (p=0.000 n=10)
Write64             77.92n ± 0%   54.88n ± 0%  -29.57% (p=0.000 n=10)
Write1K            1106.0n ± 0%   683.3n ± 0%  -38.22% (p=0.000 n=10)
Write2M             2.356m ± 0%   1.444m ± 0%  -38.72% (p=0.000 n=10)
Write64Unaligned    77.87n ± 0%   55.69n ± 0%  -28.49% (p=0.000 n=10)
Write1KUnaligned   1106.0n ± 0%   708.1n ± 0%  -35.97% (p=0.000 n=10)
Write2MUnaligned    2.335m ± 0%   1.471m ± 0%  -37.01% (p=0.000 n=10)
geomean             6.373µ        4.272µ       -32.96%

                 |  bench.old   |               bench.new               |
                 |     B/s      |      B/s       vs base                |
64                 497.1Mi ± 0%    610.3Mi ± 0%  +22.78% (p=0.000 n=10)
1K                 847.6Mi ± 0%   1333.7Mi ± 0%  +57.35% (p=0.000 n=10)
2M                 849.0Mi ± 0%   1385.9Mi ± 0%  +63.24% (p=0.000 n=10)
64Unaligned        497.4Mi ± 0%    600.9Mi ± 0%  +20.81% (p=0.000 n=10)
1KUnaligned        847.6Mi ± 0%   1310.1Mi ± 0%  +54.57% (p=0.000 n=10)
2MUnaligned        856.3Mi ± 0%   1357.9Mi ± 0%  +58.58% (p=0.000 n=10)
Write64            783.3Mi ± 0%   1112.2Mi ± 0%  +41.99% (p=0.000 n=10)
Write1K            882.8Mi ± 0%   1429.1Mi ± 0%  +61.88% (p=0.000 n=10)
Write2M            849.0Mi ± 0%   1385.4Mi ± 0%  +63.18% (p=0.000 n=10)
Write64Unaligned   783.8Mi ± 0%   1096.1Mi ± 0%  +39.85% (p=0.000 n=10)
Write1KUnaligned   882.8Mi ± 0%   1379.0Mi ± 0%  +56.20% (p=0.000 n=10)
Write2MUnaligned   856.5Mi ± 0%   1359.9Mi ± 0%  +58.76% (p=0.000 n=10)
geomean            772.2Mi         1.125Gi       +49.18%

goos: linux
goarch: loong64
pkg: golang.org/x/crypto/internal/poly1305
cpu: Loongson-3A6000-HV @ 2500.00MHz
                 |  bench.old  |              bench.new              |
                 |   sec/op    |   sec/op     vs base                |
64                 92.06n ± 0%   71.55n ± 0%  -22.28% (p=0.000 n=10)
1K                 998.4n ± 0%   607.7n ± 0%  -39.13% (p=0.000 n=10)
2M                 1.976m ± 0%   1.165m ± 0%  -41.07% (p=0.000 n=10)
64Unaligned        92.05n ± 0%   71.55n ± 0%  -22.27% (p=0.000 n=10)
1KUnaligned        998.3n ± 0%   607.6n ± 0%  -39.13% (p=0.000 n=10)
2MUnaligned        1.975m ± 0%   1.222m ± 0%  -38.11% (p=0.000 n=10)
Write64            65.24n ± 0%   45.23n ± 0%  -30.67% (p=0.000 n=10)
Write1K            970.8n ± 0%   577.6n ± 0%  -40.51% (p=0.000 n=10)
Write2M            1.965m ± 0%   1.163m ± 0%  -40.81% (p=0.000 n=10)
Write64Unaligned   65.24n ± 0%   45.24n ± 0%  -30.66% (p=0.000 n=10)
Write1KUnaligned   970.8n ± 0%   577.6n ± 0%  -40.50% (p=0.000 n=10)
Write2MUnaligned   1.965m ± 0%   1.222m ± 0%  -37.81% (p=0.000 n=10)
geomean            5.317µ        3.426µ       -35.58%

                 |   bench.old   |               bench.new               |
                 |      B/s      |      B/s       vs base                |
64                  663.0Mi ± 0%    853.1Mi ± 0%  +28.67% (p=0.000 n=10)
1K                  978.1Mi ± 0%   1606.9Mi ± 0%  +64.28% (p=0.000 n=10)
2M                 1012.0Mi ± 0%   1717.4Mi ± 0%  +69.70% (p=0.000 n=10)
64Unaligned         663.1Mi ± 0%    853.1Mi ± 0%  +28.65% (p=0.000 n=10)
1KUnaligned         978.2Mi ± 0%   1607.1Mi ± 0%  +64.29% (p=0.000 n=10)
2MUnaligned        1012.6Mi ± 0%   1636.2Mi ± 0%  +61.58% (p=0.000 n=10)
Write64             935.5Mi ± 0%   1349.3Mi ± 0%  +44.23% (p=0.000 n=10)
Write1K            1005.9Mi ± 0%   1690.9Mi ± 0%  +68.09% (p=0.000 n=10)
Write2M            1017.7Mi ± 0%   1719.5Mi ± 0%  +68.95% (p=0.000 n=10)
Write64Unaligned    935.6Mi ± 0%   1349.3Mi ± 0%  +44.22% (p=0.000 n=10)
Write1KUnaligned   1006.0Mi ± 0%   1690.9Mi ± 0%  +68.08% (p=0.000 n=10)
Write2MUnaligned   1017.7Mi ± 0%   1636.4Mi ± 0%  +60.80% (p=0.000 n=10)
geomean             925.6Mi         1.403Gi       +55.22%

Change-Id: If05a8bfc868b3e6f903ff169eed7a894af741f9b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/638455
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: abner chenc <chenguoqi@loongson.cn>
2025-03-11 17:59:26 -07:00
Carlos A Becker 6b853fbea3 ssh/knownhosts: check more than one key
I believe this fixes https://github.com/golang/go/issues/36126 .

The problem was that it was keeping only the first known key of each
type found.
If you have a server advertising multiple keys of the same type,
you might get a missmatch key error.

Per sshd(8) man page, it should allow reapeatable hosts with
different host keys, although it don't specify anything about
hosts being from different types:

"It is permissible (but not recommended) to have several lines or
different host keys for the same names.  This will inevitably happen when
short forms of host names from different domains are put in the file.  It
is possible that the files contain conflicting information;
authentication is accepted if valid information can be found from either
file."

So, this changes knownhosts behavior to accept any of the keys for a
given host, regardless of type.

Fixes #36126

Change-Id: I3450ff954259a403f2471082d013a5f79def0e16
GitHub-Last-Rev: 361bd2bcd20348956aaf114ef159a5350397eaf4
GitHub-Pull-Request: golang/crypto#254
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/478535
Reviewed-by: Junyang Shao <shaojunyang@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
2025-03-06 10:51:46 -08:00
Gopher Robot 49bf5b80c8 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Ieae7a2d210a65d5cd2cb7e2670d283176922c767
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/655018
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
2025-03-05 09:04:21 -08:00
Ilia Mirkin 24852b6b3f ssh: add decode support for banners
These banners can be printed when enabling debugHandshake, add decode
support so that they're not printed as unknown messages.

Change-Id: Ic8d56079d8225c35aac843accdbc80a642dd6249
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/650635
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2025-03-03 11:16:37 -08:00
cuishuang bbc689cf5c ssh: use a more straightforward return value
Change-Id: Ie5ee95efe4924f75719087c6fe8d4867607934bf
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/653198
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
2025-02-28 12:03:19 -08:00
Nicola Murino 7292932d45 ssh: limit the size of the internal packet queue while waiting for KEX
In the SSH protocol, clients and servers execute the key exchange to
generate one-time session keys used for encryption and authentication.
The key exchange is performed initially after the connection is
established and then periodically after a configurable amount of data.
While a key exchange is in progress, we add the received packets to an
internal queue until we receive SSH_MSG_KEXINIT from the other side.
This can result in high memory usage if the other party is slow to
respond to the SSH_MSG_KEXINIT packet, or memory exhaustion if a
malicious client never responds to an SSH_MSG_KEXINIT packet during a
large file transfer.
We now limit the internal queue to 64 packets: this means 2MB with the
typical 32KB packet size.
When the internal queue is full we block further writes until the
pending key exchange is completed or there is a read or write error.

Thanks to Yuichi Watanabe for reporting this issue.

Change-Id: I1ce2214cc16e08b838d4bc346c74c72addafaeec
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/652135
Reviewed-by: Neal Patel <nealpatel@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-02-24 09:39:25 -08:00
Roland Shoemaker f66f74b0a4 acme/autocert: check host policy before probing the cache
Avoid unnessecary cache probes for names that don't match the host
policy.

Fixes golang/go#71199

Change-Id: I11e8465b0416e960a549b0c0d74a622026c39931
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/651296
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2025-02-21 16:31:38 -08:00
Dmitri Shuralyov b0784b7bfb x509roots/fallback: drop obsolete build constraint
Back when Go 1.20 and 1.19 were supported, the go1.20 build constraint
was there to establish 1.20 as the minimum for the package, because it
requires an API that was added only in Go 1.20 and there was no way to
make it work with 1.19's APIs.

By now only Go 1.24 and 1.23 are supported, and the minimum is set via
the go directive in go.mod.

For golang/go#57792.

Change-Id: Ie4d37d34993374cdd380667930ee667af97eeccb
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/649716
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-02-21 09:26:01 -08:00
Roland Shoemaker 911360c8a4 all: bump golang.org/x/crypto dependencies of asm generators
Change-Id: Ieb2f0d45f82647978f0bd1eb47bb347f0bfb7d13
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/649499
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-02-14 15:32:41 -08:00
Gopher Robot 89ff08d67c all: upgrade go directive to at least 1.23.0 [generated]
By now Go 1.24.0 has been released, and Go 1.22 is no longer supported
per the Go Release Policy (https://go.dev/doc/devel/release#policy).

For golang/go#69095.

[git-generate]
(cd . && go get go@1.23.0 && go mod tidy && go fix ./... && go mod edit -toolchain=none)
(cd x509roots/fallback && go get go@1.23.0 && go mod tidy && go fix ./... && go mod edit -toolchain=none)

Change-Id: I879bced994b310927c41f820ec272a518aa0c8a5
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/649715
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
2025-02-14 12:15:19 -08:00
Sean Liao e47973b1c1 all: update certs for go1.24
Fixes golang/go#71612

Change-Id: I5cb0596b33cb18016eb1883d1518319588ae1454
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/647975
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
2025-02-10 08:33:42 -08:00
Gopher Robot 9290511cd2 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Ib9440df43bc2fde0268cbe327c1df839e793f675
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/646220
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2025-02-04 11:03:03 -08:00
Gopher Robot fa5273e461 x509roots/fallback: update bundle
This is an automated CL which updates the NSS root bundle.

Change-Id: I3a4388574221a77486b184e73f4b776ff0afc09f
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/646215
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2025-02-03 08:51:27 -08:00
Brad Fitzpatrick a8ea4be81f ssh: add ServerConfig.PreAuthConnCallback, ServerPreAuthConn (banner) interface
Fixes golang/go#68688

Change-Id: Id5f72b32c61c9383a26ec182339486a432c7cdf5
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/613856
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2025-01-18 11:27:23 -08:00
Evgeny Shatokhin 71d3a4cfdb acme: support challenges that require the ACME client to send a non-empty JSON body in a response to the challenge.
A new extension to the ACME protocol is proposed to support device attestation: https://datatracker.ietf.org/doc/draft-acme-device-attest/
Based on the recent IETF meetings, the proposal is likely to be accepted.
To support the new extension, the ACME client will need to send a non-empty JSON body in the response to a "device-attest-01" challenge.
Fixes golang/go#68674

Change-Id: I29b420ec837f682e3d59071a4a82af56dc319134
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/608975
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Roland Shoemaker <roland@golang.org>
2025-01-16 08:17:40 -08:00
Gopher Robot 8929309228 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: I86bc4657bf10e469231536cff39cbdb86c1135c7
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/640455
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
2025-01-06 06:44:30 -08:00
cuishuang 4a75ba54c2 all: make function and struct comments match the names
Change-Id: Iba9c1fc2895adca0d3455f8068b040d0ca006408
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/639575
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>
2025-01-02 08:15:46 -08:00
Roland Shoemaker b4f1988a35 ssh: make the public key cache a 1-entry FIFO cache
Users of the the ssh package seem to extremely commonly misuse the
PublicKeyCallback API, assuming that the key passed in the last call
before a connection is established is the key used for authentication.
Some users then make authorization decisions based on this key. This
property is not documented, and may not be correct, due to the caching
behavior of the package, resulting in users making incorrect
authorization decisions about the connection.

This change makes the cache a one entry FIFO cache, making the assumed
property, that the last call to PublicKeyCallback represents the key
actually used for authentication, actually hold.

Thanks to Damien Tournoud, Patrick Dawkins, Vince Parker, and
Jules Duvivier from the Platform.sh / Upsun engineering team
for reporting this issue.

Fixes golang/go#70779
Fixes CVE-2024-45337

Change-Id: Ife7c7b4045d8b6bcd7e3a417bdfae370c709797f
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/635315
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-12-11 09:50:49 -08:00
Roland Shoemaker 7042ebcbe0 openpgp/clearsign: just use rand.Reader in tests
Instead of a convoluted fake rand, it is _basically_ just as fast, and
fixes errors that pop up due to bad entropy.

Fixes golang/go#70682

Change-Id: Ib0f605398d1092b516b03135f602c644be2a060f
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/633655
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
2024-12-04 19:36:17 +00:00
Gopher Robot 3e90321ac7 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: I580d412fc4a135696d4054f8007593cfa4f64224
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/633480
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
2024-12-04 16:35:48 +00:00
Gopher Robot 8c4e668694 x509roots/fallback: update bundle
This is an automated CL which updates the NSS root bundle.

Change-Id: Ic5267bf9d66b676e1cfc5fc2ae153afb8f33b29c
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/631635
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-11-27 18:44:53 +00:00
Gopher Robot 6018723c74 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Ib4976eb0b062bcd71c208afc9ff53e8c3068fbf9
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/626377
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-11-07 22:54:53 +00:00
Ian Lance Taylor 71ed71b4fa README: don't recommend go get
These days people will just import the packages and the go tool will
do the right thing. We don't need to explain it.

Add a pointer to the git repo, though.

For golang/go#62645

Change-Id: I8b1e4a877bd83fe6891688a44d27a6c7902c8979
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/624155
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2024-11-04 00:10:25 +00:00
Filippo Valsorda 750a45fe5e sha3: add MarshalBinary, AppendBinary, and UnmarshalBinary
Fixes golang/go#24617

Change-Id: I1d9d529950aa8a5953435e8d3412cda44b075d55
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/616635
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Michael Pratt <mpratt@google.com>
2024-10-22 19:51:02 +00:00
Filippo Valsorda 36b172546b sha3: avoid trailing permutation
If you read a multiple of the rate, and then stop, there is no point in
running the final permutation.

Change-Id: Ic95e70f78b6e139aca1d3e3c11e09d2bbcf54f6c
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/620555
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
2024-10-22 19:50:23 +00:00
Filippo Valsorda 80ea76eb17 sha3: fix padding for long cSHAKE parameters
We used to compute the incorrect value if len(initBlock) % rate == 0.

Also, add a test vector for golang/go#66232, confirmed to fail on
GOARCH=386 without CL 570876.

Fixes golang/go#69169

Change-Id: I3f2400926fca111dd0ca1327d6b5975e51b28f96
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/616576
Reviewed-by: Andrew Ekstedt <andrew.ekstedt@gmail.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2024-10-22 19:50:19 +00:00
Filippo Valsorda c17aa50fbd sha3: avoid buffer copy
Previously, the package worked by copying the input (or the output) into
a buffer, and then XOR'ing (or copying) it into (or out of) the state.
(Except for an input fast path.) There's no need for that! We can XOR
straight into the state, and copy straight out of it, at least on little
endian machines. This is a bit faster, almost halves the state size, and
will make it easier to implement marshaling, but most importantly look
at how much simpler it makes the code!

go: go1.23.0
goos: linux
goarch: amd64
pkg: golang.org/x/crypto/sha3
cpu: AMD Ryzen 7 PRO 8700GE w/ Radeon 780M Graphics
                      │ v0.27.0-2-g42ee18b9637 │    v0.27.0-2-g42ee18b9637-dirty    │
                      │         sec/op         │   sec/op     vs base               │
PermutationFunction-8              270.8n ± 0%   270.4n ± 0%       ~ (p=0.099 n=10)
Sha3_512_MTU-8                     5.762µ ± 0%   5.658µ ± 0%  -1.80% (p=0.000 n=10)
Sha3_384_MTU-8                     4.179µ ± 0%   4.070µ ± 0%  -2.60% (p=0.000 n=10)
Sha3_256_MTU-8                     3.316µ ± 0%   3.214µ ± 0%  -3.08% (p=0.000 n=10)
Sha3_224_MTU-8                     3.175µ ± 0%   3.061µ ± 0%  -3.61% (p=0.000 n=10)
Shake128_MTU-8                     2.779µ ± 0%   2.681µ ± 0%  -3.51% (p=0.000 n=10)
Shake256_MTU-8                     2.947µ ± 0%   2.957µ ± 0%  +0.32% (p=0.000 n=10)
Shake256_16x-8                     44.15µ ± 0%   44.45µ ± 0%  +0.67% (p=0.000 n=10)
Shake256_1MiB-8                    2.319m ± 0%   2.274m ± 0%  -1.93% (p=0.000 n=10)
Sha3_512_1MiB-8                    4.204m ± 0%   4.219m ± 0%  +0.34% (p=0.000 n=10)
geomean                            13.75µ        13.54µ       -1.55%

                      │ v0.27.0-2-g42ee18b9637 │    v0.27.0-2-g42ee18b9637-dirty     │
                      │          B/s           │     B/s       vs base               │
PermutationFunction-8             704.3Mi ± 0%   705.4Mi ± 0%       ~ (p=0.105 n=10)
Sha3_512_MTU-8                    223.5Mi ± 0%   227.6Mi ± 0%  +1.83% (p=0.000 n=10)
Sha3_384_MTU-8                    308.1Mi ± 0%   316.4Mi ± 0%  +2.67% (p=0.000 n=10)
Sha3_256_MTU-8                    388.2Mi ± 0%   400.5Mi ± 0%  +3.17% (p=0.000 n=10)
Sha3_224_MTU-8                    405.5Mi ± 0%   420.7Mi ± 0%  +3.73% (p=0.000 n=10)
Shake128_MTU-8                    463.4Mi ± 0%   480.2Mi ± 0%  +3.64% (p=0.000 n=10)
Shake256_MTU-8                    436.9Mi ± 0%   435.5Mi ± 0%  -0.32% (p=0.000 n=10)
Shake256_16x-8                    353.9Mi ± 0%   351.5Mi ± 0%  -0.66% (p=0.000 n=10)
Shake256_1MiB-8                   431.2Mi ± 0%   439.7Mi ± 0%  +1.97% (p=0.000 n=10)
Sha3_512_1MiB-8                   237.8Mi ± 0%   237.1Mi ± 0%  -0.33% (p=0.000 n=10)
geomean                           375.7Mi        381.6Mi       +1.57%

Even stronger effect when patched on top of CL 616555 (forced on).

go: go1.23.0
goos: darwin
goarch: arm64
pkg: golang.org/x/crypto/sha3
cpu: Apple M2
                      │    old    │               new                   │
                      │   sec/op  │     sec/op     vs base              │
PermutationFunction-8   154.7n ± 2%   153.8n ± 1%        ~ (p=0.469 n=10)
Sha3_512_MTU-8          3.260µ ± 2%   3.143µ ± 2%   -3.60% (p=0.000 n=10)
Sha3_384_MTU-8          2.389µ ± 2%   2.244µ ± 2%   -6.07% (p=0.000 n=10)
Sha3_256_MTU-8          1.950µ ± 2%   1.758µ ± 1%   -9.87% (p=0.000 n=10)
Sha3_224_MTU-8          1.874µ ± 2%   1.686µ ± 1%  -10.06% (p=0.000 n=10)
Shake128_MTU-8          1.827µ ± 3%   1.447µ ± 1%  -20.80% (p=0.000 n=10)
Shake256_MTU-8          1.665µ ± 3%   1.604µ ± 3%   -3.63% (p=0.003 n=10)
Shake256_16x-8          25.14µ ± 1%   25.23µ ± 2%        ~ (p=0.912 n=10)
Shake256_1MiB-8         1.236m ± 2%   1.243m ± 2%        ~ (p=0.631 n=10)
Sha3_512_1MiB-8         2.296m ± 2%   2.305m ± 1%        ~ (p=0.315 n=10)
geomean                 7.906µ        7.467µ        -5.56%

                      │    old    │               new                   │
                      │    B/op   │      B/op      vs base              │
PermutationFunction-8   1.204Gi ± 2%   1.212Gi ± 1%        ~ (p=0.529 n=10)
Sha3_512_MTU-8          394.9Mi ± 2%   409.7Mi ± 2%   +3.73% (p=0.000 n=10)
Sha3_384_MTU-8          539.0Mi ± 2%   573.8Mi ± 2%   +6.45% (p=0.000 n=10)
Sha3_256_MTU-8          660.3Mi ± 2%   732.6Mi ± 1%  +10.95% (p=0.000 n=10)
Sha3_224_MTU-8          687.1Mi ± 2%   763.9Mi ± 1%  +11.17% (p=0.000 n=10)
Shake128_MTU-8          704.7Mi ± 2%   889.6Mi ± 2%  +26.24% (p=0.000 n=10)
Shake256_MTU-8          773.4Mi ± 3%   802.5Mi ± 3%   +3.76% (p=0.004 n=10)
Shake256_16x-8          621.6Mi ± 1%   619.3Mi ± 2%        ~ (p=0.912 n=10)
Shake256_1MiB-8         809.1Mi ± 2%   804.7Mi ± 2%        ~ (p=0.631 n=10)
Sha3_512_1MiB-8         435.6Mi ± 2%   433.9Mi ± 1%        ~ (p=0.315 n=10)
geomean                 653.6Mi        692.0Mi        +5.88%

Change-Id: I33a0a1ddf305c395f99bf17f81473e2f42c5ce42
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/616575
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Andrew Ekstedt <andrew.ekstedt@gmail.com>
2024-10-21 19:02:20 +00:00
samiponkanen 7cfb9161e8 ssh: return unexpected msg error when server fails keyboard-interactive auth early
Seems the OpenSSH server running on windows fails keyboard-interactive
auth this way without sending any prompt to client. In such case the
golang ssh client should not retry keyboard-interactive auth when the
auth method is wrapped in a RetryableAuthMethod(). Rather the auth
method should be immediately marked as tried&failed and the client auth
process should move on to next available and acceptable auth method.

Fixes golang/go#67855

Change-Id: I6c64ae58ff8325774e37af716601b112f8833d8f
GitHub-Last-Rev: 7fafc4d1c81284b31000d7d6ccadd934dda26d24
GitHub-Pull-Request: golang/crypto#297
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/590956
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
2024-10-16 07:16:19 +00:00
Paul E. Murphy b61b08db44 chacha20: extend ppc64le support to ppc64
This requires fixing an incorrect save of the counter. It is a word
value. It happens to work on LE because length is limited to u32.

Refactor the constant table to load correctly independent of byte
ordering.

Add byte order swapping where output needs converted to LE
ordering for storage.

Change-Id: Ic7e09bd1c769bb77dd6e817f5a8639ba765f4c0f
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/614297
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Archana Ravindar <aravinda@redhat.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-10-11 17:09:09 +00:00
Paul E. Murphy 6c21748958 internal/poly1305: extend ppc64le support to ppc64
The cipher needs to load the stream in LE order. Use the byte
reversing loads on BE.

Also, remove the unused variable poly1305Mask in the PPC64
asm file too.

Change-Id: Ie90fe7bb0ea7a3bcb76583e0cf9c1e4133499541
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/614298
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Archana Ravindar <aravinda@redhat.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
2024-10-04 20:59:56 +00:00
Gopher Robot adef4cc1a8 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: Id321d3b5909ecb66c0311ba86008509c7895863b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/617958
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2024-10-04 15:35:24 +00:00
Yawning Angel a0819fbb02 sha3: fix cSHAKE initialization for extremely large N and or S
While both impractical and unlikely, the multiplication could overflow
on 32-bit architectures.

The 64-bit architecture case is unaffected by both the maximum length
of Go slices being too small to trigger the overflow (everything except
s390), and it being safe to assume no machine has more than 2 EiB of
memory.

Fixes golang/go#66232

Change-Id: I19c15d42d2d6af35e296697159d43d02f513e614
GitHub-Last-Rev: 503e180debfdc93ab99977172af2b64290cb80e8
GitHub-Pull-Request: golang/crypto#286
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/570876
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
2024-09-30 15:41:13 +00:00
Nicola Murino 42ee18b963 ssh: return ServerAuthError after too many auth failures
if a client is disconnected due to too many authentication attempts
we should return a ServerAuthError instead of a generic error.

Some users check the error returned by NewServerConn to determine
whether or not a client attempted to authenticate.

Fixes golang/go#69191

Change-Id: If68fcecdefd6c810fe9df8256b1216e320d8a916
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/566398
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Tim King <taking@google.com>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
2024-09-16 20:42:53 +00:00
cuishuang 9e92970a1e bn256: add missing symbols in comment
Change-Id: Ibd48a070bd8ce35ef5795a8b73bc4ecac43a993e
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/611735
Run-TryBot: shuang cui <imcusg@gmail.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
2024-09-10 20:43:33 +00:00
Dmitri Shuralyov c9da6b9a40 all: fix printf(var) mistakes detected by latest printf checker
These were problematic but previously easy to miss. They're now
easy to spot thanks to build failures at Go tip as of CL 610736.

For golang/go#68796.

Change-Id: I167f2cce2376b4070460389c673d973e4521d3dc
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/610797
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
2024-09-04 21:26:08 +00:00
Gopher Robot b35ab4fde0 go.mod: update golang.org/x dependencies
Update golang.org/x dependencies to their latest tagged versions.

Change-Id: I94bb1c6a4bb08aff8c146e84a9d4b3e353f098c2
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/610638
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
2024-09-04 20:46:08 +00:00
Garrett Bodley bcb0f91bbc internal/poly1305: Port sum_amd64.s to Avo
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
ASM_PATH="internal/poly1305/sum_amd64.s"
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE:$ASM_PATH") \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  "$ASM_PATH" \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

Change-Id: I80212c95d1b05335d7f6b73a3030b6f812f6105b
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/600035
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-09-04 20:35:25 +00:00
Garrett Bodley 7eace71069 chacha20poly1305: Avo port of chacha20poly1305_amd64.s
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Parameter metadata not found in the reference assembly file has been
added, leading to a diff on the lines where those symbols are
referenced.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
ASM_PATH="chacha20poly1305/chacha20poly1305_amd64.s"
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE:$ASM_PATH") \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  "$ASM_PATH" \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

155,157c155,157
< MOVQ dst(FP), DI
< MOVQ key+24(FP), R8
< MOVQ src+48(FP), SI
---
> MOVQ dst_base(FP), DI
> MOVQ key_base+24(FP), R8
> MOVQ src_base+48(FP), SI
159c159
< MOVQ ad+72(FP), CX
---
> MOVQ ad_base+72(FP), CX
4684,4686c4684,4686
< MOVQ dst(FP), DI
< MOVQ key+24(FP), R8
< MOVQ src+48(FP), SI
---
> MOVQ dst_base(FP), DI
> MOVQ key_base+24(FP), R8
> MOVQ src_base+48(FP), SI
4688c4688
< MOVQ ad+72(FP), CX
---
> MOVQ ad_base+72(FP), CX

Change-Id: Ia3a8e70b7440944ee739499c41ddceb70e054ef9
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/601442
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2024-09-04 20:35:14 +00:00
Garrett Bodley 620dfbc770 salsa20/salsa: Port salsa20_amd64.s to Avo
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE":salsa20/salsa/salsa20_amd64.s) \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  salsa20/salsa/salsa20_amd64.s \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

Change-Id: Ica0bb06f8b074ad566a979d33ddc81d8a38491b1
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/601217
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2024-09-04 20:34:59 +00:00
Garrett Bodley 82942cf1d8 blake2b: port blake2b_amd64.s to Avo
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
ASM_PATH="blake2b/blake2b_amd64.s"
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE:$ASM_PATH") \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  "$ASM_PATH" \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

Change-Id: I6dd59fb0b0365674aa5e43b69a57ea60fbcc4ba1
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/600456
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
2024-09-04 20:34:46 +00:00
Garrett Bodley 0484c26df7 blake2b: port blake2bAVX2_amd64.s to Avo
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
ASM_PATH="blake2b/blake2bAVX2_amd64.s"
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE:$ASM_PATH") \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  "$ASM_PATH" \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

Change-Id: Ia2af1b82c871e26b89bd9a2d9fb187cc49e18341
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/600836
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-09-04 20:34:34 +00:00
Garrett Bodley 38ed1bc0ec blake2s: port blake2s_amd64.s to Avo
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
ASM_PATH="blake2s/blake2s_amd64.s"
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE:$ASM_PATH") \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  "$ASM_PATH" \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

Change-Id: Ica8bf9f0b42dc93714aa54e783fa74ed19e6b9f4
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/601216
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
2024-09-04 20:34:20 +00:00
Garrett Bodley 38a0b5da75 argon2: Avo port of blamka_amd64.s
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.

To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.

Commands used to verify Avo output:

GOROOT=$(go env GOROOT)
ASM_PATH="argon2/blamka_amd64.s"
REFERENCE="b2d3a6a4b4d36521cd7f653879cf6981e7c5c340"

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  <(git cat-file -p "$REFERENCE:$ASM_PATH") \
  > /tmp/reference.s

go tool asm -o /dev/null -I "$GOROOT"/src/runtime -debug \
  "$ASM_PATH" \
  > /tmp/avo.s

normalize(){
  awk '{
    $1=$2=$3="";
    print substr($0,4)
  }'
}

diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)

Change-Id: I3567eb80ef80dff248225f17470122c0a4e6951e
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/600315
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2024-09-04 20:33:49 +00:00
Gopher Robot bf5f14f545 x509roots/fallback: update bundle
This is an automated CL which updates the NSS root bundle.

Change-Id: I95cf0b3e86f1e013d486a0bbd050a8b4bea5d6e9
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/610060
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
2024-09-03 18:00:24 +00:00
Nicola Murino b2d3a6a4b4 ssh/agent: ensure to not add duplicated keys
When adding a new key, if we already have a Signer with the same public
key, we now replace it with the new one instead of duplicating it.

Before this change we had this:

$ ssh-add -l
3072 SHA256:bsBRHC/xgiqBJdSuvSTNpJNLTISP/G356jNMCRYC5Es nicola@p1 (RSA)
3072 SHA256:bsBRHC/xgiqBJdSuvSTNpJNLTISP/G356jNMCRYC5Es nicola@p1 (RSA-CERT)

$ ssh-add /home/nicola/ssh_certs/id_rsa
Identity added: /home/nicola/ssh_certs/id_rsa (nicola@p1)
Certificate added: /home/nicola/ssh_certs/id_rsa-cert.pub (myid)

$ ssh-add -l
3072 SHA256:bsBRHC/xgiqBJdSuvSTNpJNLTISP/G356jNMCRYC5Es nicola@p1 (RSA)
3072 SHA256:bsBRHC/xgiqBJdSuvSTNpJNLTISP/G356jNMCRYC5Es nicola@p1 (RSA-CERT)
3072 SHA256:bsBRHC/xgiqBJdSuvSTNpJNLTISP/G356jNMCRYC5Es nicola@p1 (RSA)
3072 SHA256:bsBRHC/xgiqBJdSuvSTNpJNLTISP/G356jNMCRYC5Es nicola@p1 (RSA-CERT)

Change-Id: Iad1b1a6dc94f68f53f05d7d1172f0017839976fc
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/602955
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2024-08-06 16:07:48 +00:00
78 changed files with 32787 additions and 5727 deletions
+5 -8
View File
@@ -2,20 +2,17 @@
[![Go Reference](https://pkg.go.dev/badge/golang.org/x/crypto.svg)](https://pkg.go.dev/golang.org/x/crypto)
This repository holds supplementary Go cryptography libraries.
## Download/Install
The easiest way to install is to run `go get -u golang.org/x/crypto/...`. You
can also manually git clone the repository to `$GOPATH/src/golang.org/x/crypto`.
This repository holds supplementary Go cryptography packages.
## Report Issues / Send Patches
This repository uses Gerrit for code changes. To learn how to submit changes to
this repository, see https://golang.org/doc/contribute.html.
this repository, see https://go.dev/doc/contribute.
The git repository is https://go.googlesource.com/crypto.
The main issue tracker for the crypto repository is located at
https://github.com/golang/go/issues. Prefix your issue with "x/crypto:" in the
https://go.dev/issues. Prefix your issue with "x/crypto:" in the
subject line, so it is easy to find.
Note that contributions to the cryptography package receive additional scrutiny
+5 -1
View File
@@ -514,7 +514,11 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
return nil, err
}
res, err := c.post(ctx, nil, chal.URI, json.RawMessage("{}"), wantStatus(
payload := json.RawMessage("{}")
if len(chal.Payload) != 0 {
payload = chal.Payload
}
res, err := c.post(ctx, nil, chal.URI, payload, wantStatus(
http.StatusOK, // according to the spec
http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
))
+1 -1
View File
@@ -757,7 +757,7 @@ func TestTLSALPN01ChallengeCert(t *testing.T) {
}
func TestTLSChallengeCertOpt(t *testing.T) {
key, err := rsa.GenerateKey(rand.Reader, 512)
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
t.Fatal(err)
}
+4 -3
View File
@@ -292,6 +292,10 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
}
// regular domain
if err := m.hostPolicy()(ctx, name); err != nil {
return nil, err
}
ck := certKey{
domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
isRSA: !supportsECDSA(hello),
@@ -305,9 +309,6 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
}
// first-time
if err := m.hostPolicy()(ctx, name); err != nil {
return nil, err
}
cert, err = m.createCert(ctx, ck)
if err != nil {
return nil, err
+2 -2
View File
@@ -619,7 +619,7 @@ func TestCache(t *testing.T) {
PrivateKey: ecdsaKey,
}
rsaKey, err := rsa.GenerateKey(rand.Reader, 512)
rsaKey, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
t.Fatal(err)
}
@@ -694,7 +694,7 @@ func TestValidCert(t *testing.T) {
if err != nil {
t.Fatal(err)
}
key3, err := rsa.GenerateKey(rand.Reader, 512)
key3, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
t.Fatal(err)
}
+6 -6
View File
@@ -308,7 +308,7 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
}
if err := decodePayload(&req, r.Body); err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.httpErrorf(w, http.StatusBadRequest, "%v", err)
return
}
@@ -328,7 +328,7 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
Identifiers []struct{ Value string }
}
if err := decodePayload(&req, r.Body); err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.httpErrorf(w, http.StatusBadRequest, "%v", err)
return
}
ca.mu.Lock()
@@ -352,7 +352,7 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
defer ca.mu.Unlock()
o, err := ca.storedOrder(strings.TrimPrefix(r.URL.Path, "/orders/"))
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.httpErrorf(w, http.StatusBadRequest, "%v", err)
return
}
if err := json.NewEncoder(w).Encode(o); err != nil {
@@ -412,7 +412,7 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
orderID := strings.TrimPrefix(r.URL.Path, "/new-cert/")
o, err := ca.storedOrder(orderID)
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.httpErrorf(w, http.StatusBadRequest, "%v", err)
return
}
if o.Status != acme.StatusReady {
@@ -427,7 +427,7 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
csr, err := x509.ParseCertificateRequest(b)
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.httpErrorf(w, http.StatusBadRequest, "%v", err)
return
}
// Issue the certificate.
@@ -449,7 +449,7 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
defer ca.mu.Unlock()
o, err := ca.storedOrder(strings.TrimPrefix(r.URL.Path, "/issued-cert/"))
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.httpErrorf(w, http.StatusBadRequest, "%v", err)
return
}
if o.Status != acme.StatusValid {
+1 -1
View File
@@ -92,7 +92,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, ur
if err != nil {
return nil, err
}
phead := base64.RawURLEncoding.EncodeToString([]byte(phJSON))
phead := base64.RawURLEncoding.EncodeToString(phJSON)
var payload string
if val, ok := claimset.(string); ok {
payload = val
+12 -1
View File
@@ -7,6 +7,7 @@ package acme
import (
"crypto"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -288,7 +289,7 @@ type Directory struct {
// KeyChangeURL allows to perform account key rollover flow.
KeyChangeURL string
// Term is a URI identifying the current terms of service.
// Terms is a URI identifying the current terms of service.
Terms string
// Website is an HTTP or HTTPS URL locating a website
@@ -527,6 +528,16 @@ type Challenge struct {
// when this challenge was used.
// The type of a non-nil value is *Error.
Error error
// Payload is the JSON-formatted payload that the client sends
// to the server to indicate it is ready to respond to the challenge.
// When unset, it defaults to an empty JSON object: {}.
// For most challenges, the client must not set Payload,
// see https://tools.ietf.org/html/rfc8555#section-7.5.1.
// Payload is used only for newer challenges (such as "device-attest-01")
// where the client must send additional data for the server to validate
// the challenge.
Payload json.RawMessage
}
// wireChallenge is ACME JSON challenge representation.
+287
View File
@@ -0,0 +1,287 @@
// Copyright 2024 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 main
import (
. "github.com/mmcloughlin/avo/build"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
_ "golang.org/x/crypto/argon2"
)
//go:generate go run . -out ../blamka_amd64.s -pkg argon2
func main() {
Package("golang.org/x/crypto/argon2")
ConstraintExpr("amd64,gc,!purego")
blamkaSSE4()
mixBlocksSSE2()
xorBlocksSSE2()
Generate()
}
func blamkaSSE4() {
Implement("blamkaSSE4")
Attributes(NOSPLIT)
AllocLocal(0)
Load(Param("b"), RAX)
c40 := c40_DATA()
c48 := c48_DATA()
MOVOU(c40, X10)
MOVOU(c48, X11)
BLAMKA_ROUND_0(AX, 0, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 16, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 32, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 48, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 64, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 80, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 96, X8, X9, X10, X11)
BLAMKA_ROUND_0(AX, 112, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 0, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 2, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 4, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 6, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 8, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 10, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 12, X8, X9, X10, X11)
BLAMKA_ROUND_1(AX, 14, X8, X9, X10, X11)
RET()
}
func mixBlocksSSE2() {
Implement("mixBlocksSSE2")
Attributes(NOSPLIT)
AllocLocal(0)
Load(Param("out"), RDX)
Load(Param("a"), RAX)
Load(Param("b"), RBX)
Load(Param("c"), RCX)
MOVQ(U32(128), RDI)
Label("loop")
MOVOU(Mem{Base: AX}.Offset(0), X0)
MOVOU(Mem{Base: BX}.Offset(0), X1)
MOVOU(Mem{Base: CX}.Offset(0), X2)
PXOR(X1, X0)
PXOR(X2, X0)
MOVOU(X0, Mem{Base: DX}.Offset(0))
ADDQ(Imm(16), RAX)
ADDQ(Imm(16), RBX)
ADDQ(Imm(16), RCX)
ADDQ(Imm(16), RDX)
SUBQ(Imm(2), RDI)
JA(LabelRef("loop"))
RET()
}
func xorBlocksSSE2() {
Implement("xorBlocksSSE2")
Attributes(NOSPLIT)
AllocLocal(0)
Load(Param("out"), RDX)
Load(Param("a"), RAX)
Load(Param("b"), RBX)
Load(Param("c"), RCX)
MOVQ(U32(128), RDI)
Label("loop")
MOVOU(Mem{Base: AX}.Offset(0), X0)
MOVOU(Mem{Base: BX}.Offset(0), X1)
MOVOU(Mem{Base: CX}.Offset(0), X2)
MOVOU(Mem{Base: DX}.Offset(0), X3)
PXOR(X1, X0)
PXOR(X2, X0)
PXOR(X3, X0)
MOVOU(X0, Mem{Base: DX}.Offset(0))
ADDQ(Imm(16), RAX)
ADDQ(Imm(16), RBX)
ADDQ(Imm(16), RCX)
ADDQ(Imm(16), RDX)
SUBQ(Imm(2), RDI)
JA(LabelRef("loop"))
RET()
}
func SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2 VecPhysical) {
MOVO(v4, t1)
MOVO(v5, v4)
MOVO(t1, v5)
MOVO(v6, t1)
PUNPCKLQDQ(v6, t2)
PUNPCKHQDQ(v7, v6)
PUNPCKHQDQ(t2, v6)
PUNPCKLQDQ(v7, t2)
MOVO(t1, v7)
MOVO(v2, t1)
PUNPCKHQDQ(t2, v7)
PUNPCKLQDQ(v3, t2)
PUNPCKHQDQ(t2, v2)
PUNPCKLQDQ(t1, t2)
PUNPCKHQDQ(t2, v3)
}
func SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2 VecPhysical) {
MOVO(v4, t1)
MOVO(v5, v4)
MOVO(t1, v5)
MOVO(v2, t1)
PUNPCKLQDQ(v2, t2)
PUNPCKHQDQ(v3, v2)
PUNPCKHQDQ(t2, v2)
PUNPCKLQDQ(v3, t2)
MOVO(t1, v3)
MOVO(v6, t1)
PUNPCKHQDQ(t2, v3)
PUNPCKLQDQ(v7, t2)
PUNPCKHQDQ(t2, v6)
PUNPCKLQDQ(t1, t2)
PUNPCKHQDQ(t2, v7)
}
func HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, t0, c40, c48 VecPhysical) {
MOVO(v0, t0)
PMULULQ(v2, t0)
PADDQ(v2, v0)
PADDQ(t0, v0)
PADDQ(t0, v0)
PXOR(v0, v6)
PSHUFD(Imm(0xB1), v6, v6)
MOVO(v4, t0)
PMULULQ(v6, t0)
PADDQ(v6, v4)
PADDQ(t0, v4)
PADDQ(t0, v4)
PXOR(v4, v2)
PSHUFB(c40, v2)
MOVO(v0, t0)
PMULULQ(v2, t0)
PADDQ(v2, v0)
PADDQ(t0, v0)
PADDQ(t0, v0)
PXOR(v0, v6)
PSHUFB(c48, v6)
MOVO(v4, t0)
PMULULQ(v6, t0)
PADDQ(v6, v4)
PADDQ(t0, v4)
PADDQ(t0, v4)
PXOR(v4, v2)
MOVO(v2, t0)
PADDQ(v2, t0)
PSRLQ(Imm(63), v2)
PXOR(t0, v2)
MOVO(v1, t0)
PMULULQ(v3, t0)
PADDQ(v3, v1)
PADDQ(t0, v1)
PADDQ(t0, v1)
PXOR(v1, v7)
PSHUFD(Imm(0xB1), v7, v7)
MOVO(v5, t0)
PMULULQ(v7, t0)
PADDQ(v7, v5)
PADDQ(t0, v5)
PADDQ(t0, v5)
PXOR(v5, v3)
PSHUFB(c40, v3)
MOVO(v1, t0)
PMULULQ(v3, t0)
PADDQ(v3, v1)
PADDQ(t0, v1)
PADDQ(t0, v1)
PXOR(v1, v7)
PSHUFB(c48, v7)
MOVO(v5, t0)
PMULULQ(v7, t0)
PADDQ(v7, v5)
PADDQ(t0, v5)
PADDQ(t0, v5)
PXOR(v5, v3)
MOVO(v3, t0)
PADDQ(v3, t0)
PSRLQ(Imm(63), v3)
PXOR(t0, v3)
}
func LOAD_MSG_0(block GPPhysical, off int) {
var registers = []VecPhysical{X0, X1, X2, X3, X4, X5, X6, X7}
for i, r := range registers {
MOVOU(Mem{Base: block}.Offset(8*(off+(i*2))), r)
}
}
func STORE_MSG_0(block GPPhysical, off int) {
var registers = []VecPhysical{X0, X1, X2, X3, X4, X5, X6, X7}
for i, r := range registers {
MOVOU(r, Mem{Base: block}.Offset(8*(off+(i*2))))
}
}
func LOAD_MSG_1(block GPPhysical, off int) {
var registers = []VecPhysical{X0, X1, X2, X3, X4, X5, X6, X7}
for i, r := range registers {
MOVOU(Mem{Base: block}.Offset(8*off+i*16*8), r)
}
}
func STORE_MSG_1(block GPPhysical, off int) {
var registers = []VecPhysical{X0, X1, X2, X3, X4, X5, X6, X7}
for i, r := range registers {
MOVOU(r, Mem{Base: block}.Offset(8*off+i*16*8))
}
}
func BLAMKA_ROUND_0(block GPPhysical, off int, t0, t1, c40, c48 VecPhysical) {
LOAD_MSG_0(block, off)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48)
SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1)
STORE_MSG_0(block, off)
}
func BLAMKA_ROUND_1(block GPPhysical, off int, t0, t1, c40, c48 VecPhysical) {
LOAD_MSG_1(block, off)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48)
SHUFFLE(X2, X3, X4, X5, X6, X7, t0, t1)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, t0, c40, c48)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, t0, t1)
STORE_MSG_1(block, off)
}
// ##------------------DATA SECTION-------------------##
var c40_DATA_ptr, c48_DATA_ptr *Mem
func c40_DATA() Mem {
if c40_DATA_ptr != nil {
return *c40_DATA_ptr
}
c40_DATA := GLOBL("·c40", NOPTR|RODATA)
c40_DATA_ptr = &c40_DATA
DATA(0x00, U64(0x0201000706050403))
DATA(0x08, U64(0x0a09080f0e0d0c0b))
return c40_DATA
}
func c48_DATA() Mem {
if c48_DATA_ptr != nil {
return *c48_DATA_ptr
}
c48_DATA := GLOBL("·c48", NOPTR|RODATA)
c48_DATA_ptr = &c48_DATA
DATA(0x00, U64(0x0100070605040302))
DATA(0x08, U64(0x09080f0e0d0c0b0a))
return c48_DATA
}
+15
View File
@@ -0,0 +1,15 @@
module argon2/_asm
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+2761 -213
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+16
View File
@@ -0,0 +1,16 @@
module blake2b/_asm/AVX2
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+361
View File
@@ -0,0 +1,361 @@
// Copyright 2024 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 main
import (
. "github.com/mmcloughlin/avo/build"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
_ "golang.org/x/crypto/blake2b"
)
//go:generate go run . -out ../../blake2b_amd64.s -pkg blake2b
const ThatPeskyUnicodeDot = "\u00b7"
var iv0_DATA_ptr, iv1_DATA_ptr, iv2_DATA_ptr, iv3_DATA_ptr, c40_DATA_ptr, c48_DATA_ptr *Mem
func main() {
Package("golang.org/x/crypto/blake2b")
ConstraintExpr("amd64,gc,!purego")
hashBlocksSSE4()
Generate()
}
func SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2 VecPhysical) {
MOVO(v4, t1)
MOVO(v5, v4)
MOVO(t1, v5)
MOVO(v6, t1)
PUNPCKLQDQ(v6, t2)
PUNPCKHQDQ(v7, v6)
PUNPCKHQDQ(t2, v6)
PUNPCKLQDQ(v7, t2)
MOVO(t1, v7)
MOVO(v2, t1)
PUNPCKHQDQ(t2, v7)
PUNPCKLQDQ(v3, t2)
PUNPCKHQDQ(t2, v2)
PUNPCKLQDQ(t1, t2)
PUNPCKHQDQ(t2, v3)
}
func SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2 VecPhysical) {
MOVO(v4, t1)
MOVO(v5, v4)
MOVO(t1, v5)
MOVO(v2, t1)
PUNPCKLQDQ(v2, t2)
PUNPCKHQDQ(v3, v2)
PUNPCKHQDQ(t2, v2)
PUNPCKLQDQ(v3, t2)
MOVO(t1, v3)
MOVO(v6, t1)
PUNPCKHQDQ(t2, v3)
PUNPCKLQDQ(v7, t2)
PUNPCKHQDQ(t2, v6)
PUNPCKLQDQ(t1, t2)
PUNPCKHQDQ(t2, v7)
}
func HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7 VecPhysical, m0, m1, m2, m3 Op, t0, c40, c48 VecPhysical) {
PADDQ(m0, v0)
PADDQ(m1, v1)
PADDQ(v2, v0)
PADDQ(v3, v1)
PXOR(v0, v6)
PXOR(v1, v7)
PSHUFD(Imm(0xB1), v6, v6)
PSHUFD(Imm(0xB1), v7, v7)
PADDQ(v6, v4)
PADDQ(v7, v5)
PXOR(v4, v2)
PXOR(v5, v3)
PSHUFB(c40, v2)
PSHUFB(c40, v3)
PADDQ(m2, v0)
PADDQ(m3, v1)
PADDQ(v2, v0)
PADDQ(v3, v1)
PXOR(v0, v6)
PXOR(v1, v7)
PSHUFB(c48, v6)
PSHUFB(c48, v7)
PADDQ(v6, v4)
PADDQ(v7, v5)
PXOR(v4, v2)
PXOR(v5, v3)
MOVOU(v2, t0)
PADDQ(v2, t0)
PSRLQ(Imm(63), v2)
PXOR(t0, v2)
MOVOU(v3, t0)
PADDQ(v3, t0)
PSRLQ(Imm(63), v3)
PXOR(t0, v3)
}
func LOAD_MSG(m0, m1, m2, m3 VecPhysical, src GPPhysical, i0, i1, i2, i3, i4, i5, i6, i7 int) {
MOVQ(Mem{Base: src}.Offset(i0*8), m0)
PINSRQ(Imm(1), Mem{Base: src}.Offset(i1*8), m0)
MOVQ(Mem{Base: src}.Offset(i2*8), m1)
PINSRQ(Imm(1), Mem{Base: src}.Offset(i3*8), m1)
MOVQ(Mem{Base: src}.Offset(i4*8), m2)
PINSRQ(Imm(1), Mem{Base: src}.Offset(i5*8), m2)
MOVQ(Mem{Base: src}.Offset(i6*8), m3)
PINSRQ(Imm(1), Mem{Base: src}.Offset(i7*8), m3)
}
func hashBlocksSSE4() {
Implement("hashBlocksSSE4")
Attributes(4)
AllocLocal(288) // frame size = 272 + 16 byte alignment
Load(Param("h"), RAX)
Load(Param("c"), RBX)
Load(Param("flag"), RCX)
Load(Param("blocks").Base(), RSI)
Load(Param("blocks").Len(), RDI)
MOVQ(RSP, R10)
ADDQ(Imm(15), R10)
ANDQ(I32(-16), R10)
iv3 := iv3_DATA()
MOVOU(iv3, X0)
MOVO(X0, Mem{Base: R10}.Offset(0))
XORQ(RCX, Mem{Base: R10}.Offset(0)) // 0(R10) = ·iv3 ^ (CX || 0)
c40 := c40_DATA()
c48 := c48_DATA()
MOVOU(c40, X13)
MOVOU(c48, X14)
MOVOU(Mem{Base: AX}.Offset(0), X12)
MOVOU(Mem{Base: AX}.Offset(16), X15)
MOVQ(Mem{Base: BX}.Offset(0), R8)
MOVQ(Mem{Base: BX}.Offset(8), R9)
Label("loop")
ADDQ(Imm(128), R8)
CMPQ(R8, Imm(128))
JGE(LabelRef("noinc"))
INCQ(R9)
Label("noinc")
MOVQ(R8, X8)
PINSRQ(Imm(1), R9, X8)
iv0 := iv0_DATA()
iv1 := iv1_DATA()
iv2 := iv2_DATA()
MOVO(X12, X0)
MOVO(X15, X1)
MOVOU(Mem{Base: AX}.Offset(32), X2)
MOVOU(Mem{Base: AX}.Offset(48), X3)
MOVOU(iv0, X4)
MOVOU(iv1, X5)
MOVOU(iv2, X6)
PXOR(X8, X6)
MOVO(Mem{Base: R10}.Offset(0), X7)
LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7)
MOVO(X8, Mem{Base: R10}.Offset(16))
MOVO(X9, Mem{Base: R10}.Offset(32))
MOVO(X10, Mem{Base: R10}.Offset(48))
MOVO(X11, Mem{Base: R10}.Offset(64))
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15)
MOVO(X8, Mem{Base: R10}.Offset(80))
MOVO(X9, Mem{Base: R10}.Offset(96))
MOVO(X10, Mem{Base: R10}.Offset(112))
MOVO(X11, Mem{Base: R10}.Offset(128))
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6)
MOVO(X8, Mem{Base: R10}.Offset(144))
MOVO(X9, Mem{Base: R10}.Offset(160))
MOVO(X10, Mem{Base: R10}.Offset(176))
MOVO(X11, Mem{Base: R10}.Offset(192))
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3)
MOVO(X8, Mem{Base: R10}.Offset(208))
MOVO(X9, Mem{Base: R10}.Offset(224))
MOVO(X10, Mem{Base: R10}.Offset(240))
MOVO(X11, Mem{Base: R10}.Offset(256))
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, Mem{Base: R10}.Offset(16), Mem{Base: R10}.Offset(32), Mem{Base: R10}.Offset(48), Mem{Base: R10}.Offset(64), X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, Mem{Base: R10}.Offset(80), Mem{Base: R10}.Offset(96), Mem{Base: R10}.Offset(112), Mem{Base: R10}.Offset(128), X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, Mem{Base: R10}.Offset(144), Mem{Base: R10}.Offset(160), Mem{Base: R10}.Offset(176), Mem{Base: R10}.Offset(192), X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, Mem{Base: R10}.Offset(208), Mem{Base: R10}.Offset(224), Mem{Base: R10}.Offset(240), Mem{Base: R10}.Offset(256), X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
MOVOU(Mem{Base: AX}.Offset(32), X10)
MOVOU(Mem{Base: AX}.Offset(48), X11)
PXOR(X0, X12)
PXOR(X1, X15)
PXOR(X2, X10)
PXOR(X3, X11)
PXOR(X4, X12)
PXOR(X5, X15)
PXOR(X6, X10)
PXOR(X7, X11)
MOVOU(X10, Mem{Base: AX}.Offset(32))
MOVOU(X11, Mem{Base: AX}.Offset(48))
LEAQ(Mem{Base: SI}.Offset(128), RSI)
SUBQ(Imm(128), RDI)
JNE(LabelRef("loop"))
MOVOU(X12, Mem{Base: AX}.Offset(0))
MOVOU(X15, Mem{Base: AX}.Offset(16))
MOVQ(R8, Mem{Base: BX}.Offset(0))
MOVQ(R9, Mem{Base: BX}.Offset(8))
RET()
}
// #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DATA SECTION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
func iv0_DATA() Mem {
if iv0_DATA_ptr != nil {
return *iv0_DATA_ptr
}
iv0 := GLOBL(ThatPeskyUnicodeDot+"iv0", NOPTR|RODATA)
iv0_DATA_ptr = &iv0
DATA(0x00, U64(0x6a09e667f3bcc908))
DATA(0x08, U64(0xbb67ae8584caa73b))
return iv0
}
func iv1_DATA() Mem {
if iv1_DATA_ptr != nil {
return *iv1_DATA_ptr
}
iv1 := GLOBL(ThatPeskyUnicodeDot+"iv1", NOPTR|RODATA)
iv1_DATA_ptr = &iv1
DATA(0x00, U64(0x3c6ef372fe94f82b))
DATA(0x08, U64(0xa54ff53a5f1d36f1))
return iv1
}
func iv2_DATA() Mem {
if iv2_DATA_ptr != nil {
return *iv2_DATA_ptr
}
iv2 := GLOBL(ThatPeskyUnicodeDot+"iv2", NOPTR|RODATA)
iv2_DATA_ptr = &iv2
DATA(0x00, U64(0x510e527fade682d1))
DATA(0x08, U64(0x9b05688c2b3e6c1f))
return iv2
}
func iv3_DATA() Mem {
if iv3_DATA_ptr != nil {
return *iv3_DATA_ptr
}
iv3 := GLOBL(ThatPeskyUnicodeDot+"iv3", NOPTR|RODATA)
iv3_DATA_ptr = &iv3
DATA(0x00, U64(0x1f83d9abfb41bd6b))
DATA(0x08, U64(0x5be0cd19137e2179))
return iv3
}
func c40_DATA() Mem {
if c40_DATA_ptr != nil {
return *c40_DATA_ptr
}
c40 := GLOBL(ThatPeskyUnicodeDot+"c40", NOPTR|RODATA)
c40_DATA_ptr = &c40
DATA(0x00, U64(0x0201000706050403))
DATA(0x08, U64(0x0a09080f0e0d0c0b))
return c40
}
func c48_DATA() Mem {
if c48_DATA_ptr != nil {
return *c48_DATA_ptr
}
c48 := GLOBL(ThatPeskyUnicodeDot+"c48", NOPTR|RODATA)
c48_DATA_ptr = &c48
DATA(0x00, U64(0x0100070605040302))
DATA(0x08, U64(0x09080f0e0d0c0b0a))
return c48
}
+15
View File
@@ -0,0 +1,15 @@
module blake2b/_asm
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+4492 -677
View File
File diff suppressed because it is too large Load Diff
+1427 -264
View File
File diff suppressed because it is too large Load Diff
+525
View File
@@ -0,0 +1,525 @@
// Copyright 2024 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 main
import (
. "github.com/mmcloughlin/avo/build"
"github.com/mmcloughlin/avo/ir"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
_ "golang.org/x/crypto/blake2s"
)
//go:generate go run . -out ../blake2s_amd64.s -pkg blake2s
func main() {
Package("golang.org/x/crypto/blake2s")
ConstraintExpr("amd64,gc,!purego")
hashBlocksSSE2()
hashBlocksSSSE3()
hashBlocksSSE4()
Generate()
}
func ROTL_SSE2(n uint64, t, v VecPhysical) {
MOVO(v, t)
PSLLL(Imm(n), t)
PSRLL(Imm(32-n), v)
PXOR(t, v)
}
func ROTL_SSSE3(c, v VecPhysical) {
PSHUFB(c, v)
}
func ROUND_SSE2(v0, v1, v2, v3 VecPhysical, m0, m1, m2, m3 Mem, t VecPhysical) {
PADDL(m0, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSE2(16, t, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(20, t, v1)
PADDL(m1, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSE2(24, t, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(25, t, v1)
PSHUFL(Imm(0x39), v1, v1)
PSHUFL(Imm(0x4E), v2, v2)
PSHUFL(Imm(0x93), v3, v3)
PADDL(m2, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSE2(16, t, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(20, t, v1)
PADDL(m3, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSE2(24, t, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(25, t, v1)
PSHUFL(Imm(0x39), v3, v3)
PSHUFL(Imm(0x4E), v2, v2)
PSHUFL(Imm(0x93), v1, v1)
}
func ROUND_SSSE3(v0, v1, v2, v3 VecPhysical, m0, m1, m2, m3 Op, t, c16, c8 VecPhysical) {
PADDL(m0, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSSE3(c16, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(20, t, v1)
PADDL(m1, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSSE3(c8, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(25, t, v1)
PSHUFL(Imm(0x39), v1, v1)
PSHUFL(Imm(0x4E), v2, v2)
PSHUFL(Imm(0x93), v3, v3)
PADDL(m2, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSSE3(c16, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(20, t, v1)
PADDL(m3, v0)
PADDL(v1, v0)
PXOR(v0, v3)
ROTL_SSSE3(c8, v3)
PADDL(v3, v2)
PXOR(v2, v1)
ROTL_SSE2(25, t, v1)
PSHUFL(Imm(0x39), v3, v3)
PSHUFL(Imm(0x4E), v2, v2)
PSHUFL(Imm(0x93), v1, v1)
}
func LOAD_MSG_SSE4(m0, m1, m2, m3 VecPhysical, src GPPhysical, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15 int) {
// Hack to get Avo to emit a MOVL instruction with a VecPhysical as the destination
Instruction(&ir.Instruction{Opcode: "MOVL", Operands: []Op{Mem{Base: src}.Offset(i0 * 4), m0}})
PINSRD(Imm(1), Mem{Base: src}.Offset(i1*4), m0)
PINSRD(Imm(2), Mem{Base: src}.Offset(i2*4), m0)
PINSRD(Imm(3), Mem{Base: src}.Offset(i3*4), m0)
Instruction(&ir.Instruction{Opcode: "MOVL", Operands: []Op{Mem{Base: src}.Offset(i4 * 4), m1}})
PINSRD(Imm(1), Mem{Base: src}.Offset(i5*4), m1)
PINSRD(Imm(2), Mem{Base: src}.Offset(i6*4), m1)
PINSRD(Imm(3), Mem{Base: src}.Offset(i7*4), m1)
Instruction(&ir.Instruction{Opcode: "MOVL", Operands: []Op{Mem{Base: src}.Offset(i8 * 4), m2}})
PINSRD(Imm(1), Mem{Base: src}.Offset(i9*4), m2)
PINSRD(Imm(2), Mem{Base: src}.Offset(i10*4), m2)
PINSRD(Imm(3), Mem{Base: src}.Offset(i11*4), m2)
Instruction(&ir.Instruction{Opcode: "MOVL", Operands: []Op{Mem{Base: src}.Offset(i12 * 4), m3}})
PINSRD(Imm(1), Mem{Base: src}.Offset(i13*4), m3)
PINSRD(Imm(2), Mem{Base: src}.Offset(i14*4), m3)
PINSRD(Imm(3), Mem{Base: src}.Offset(i15*4), m3)
}
func PRECOMPUTE_MSG(dst GPPhysical, off int, src, R8, R9, R10, R11, R12, R13, R14, R15 GPPhysical) {
MOVQ(Mem{Base: src}.Offset(0*4), R8)
MOVQ(Mem{Base: src}.Offset(2*4), R9)
MOVQ(Mem{Base: src}.Offset(4*4), R10)
MOVQ(Mem{Base: src}.Offset(6*4), R11)
MOVQ(Mem{Base: src}.Offset(8*4), R12)
MOVQ(Mem{Base: src}.Offset(10*4), R13)
MOVQ(Mem{Base: src}.Offset(12*4), R14)
MOVQ(Mem{Base: src}.Offset(14*4), R15)
MOVL(R8L, Mem{Base: dst}.Offset(0*4+off+0))
MOVL(R8L, Mem{Base: dst}.Offset(9*4+off+64))
MOVL(R8L, Mem{Base: dst}.Offset(5*4+off+128))
MOVL(R8L, Mem{Base: dst}.Offset(14*4+off+192))
MOVL(R8L, Mem{Base: dst}.Offset(4*4+off+256))
MOVL(R8L, Mem{Base: dst}.Offset(2*4+off+320))
MOVL(R8L, Mem{Base: dst}.Offset(8*4+off+384))
MOVL(R8L, Mem{Base: dst}.Offset(12*4+off+448))
MOVL(R8L, Mem{Base: dst}.Offset(3*4+off+512))
MOVL(R8L, Mem{Base: dst}.Offset(15*4+off+576))
SHRQ(Imm(32), R8)
MOVL(R8L, Mem{Base: dst}.Offset(4*4+off+0))
MOVL(R8L, Mem{Base: dst}.Offset(8*4+off+64))
MOVL(R8L, Mem{Base: dst}.Offset(14*4+off+128))
MOVL(R8L, Mem{Base: dst}.Offset(5*4+off+192))
MOVL(R8L, Mem{Base: dst}.Offset(12*4+off+256))
MOVL(R8L, Mem{Base: dst}.Offset(11*4+off+320))
MOVL(R8L, Mem{Base: dst}.Offset(1*4+off+384))
MOVL(R8L, Mem{Base: dst}.Offset(6*4+off+448))
MOVL(R8L, Mem{Base: dst}.Offset(10*4+off+512))
MOVL(R8L, Mem{Base: dst}.Offset(3*4+off+576))
MOVL(R9L, Mem{Base: dst}.Offset(1*4+off+0))
MOVL(R9L, Mem{Base: dst}.Offset(13*4+off+64))
MOVL(R9L, Mem{Base: dst}.Offset(6*4+off+128))
MOVL(R9L, Mem{Base: dst}.Offset(8*4+off+192))
MOVL(R9L, Mem{Base: dst}.Offset(2*4+off+256))
MOVL(R9L, Mem{Base: dst}.Offset(0*4+off+320))
MOVL(R9L, Mem{Base: dst}.Offset(14*4+off+384))
MOVL(R9L, Mem{Base: dst}.Offset(11*4+off+448))
MOVL(R9L, Mem{Base: dst}.Offset(12*4+off+512))
MOVL(R9L, Mem{Base: dst}.Offset(4*4+off+576))
SHRQ(Imm(32), R9)
MOVL(R9L, Mem{Base: dst}.Offset(5*4+off+0))
MOVL(R9L, Mem{Base: dst}.Offset(15*4+off+64))
MOVL(R9L, Mem{Base: dst}.Offset(9*4+off+128))
MOVL(R9L, Mem{Base: dst}.Offset(1*4+off+192))
MOVL(R9L, Mem{Base: dst}.Offset(11*4+off+256))
MOVL(R9L, Mem{Base: dst}.Offset(7*4+off+320))
MOVL(R9L, Mem{Base: dst}.Offset(13*4+off+384))
MOVL(R9L, Mem{Base: dst}.Offset(3*4+off+448))
MOVL(R9L, Mem{Base: dst}.Offset(6*4+off+512))
MOVL(R9L, Mem{Base: dst}.Offset(10*4+off+576))
MOVL(R10L, Mem{Base: dst}.Offset(2*4+off+0))
MOVL(R10L, Mem{Base: dst}.Offset(1*4+off+64))
MOVL(R10L, Mem{Base: dst}.Offset(15*4+off+128))
MOVL(R10L, Mem{Base: dst}.Offset(10*4+off+192))
MOVL(R10L, Mem{Base: dst}.Offset(6*4+off+256))
MOVL(R10L, Mem{Base: dst}.Offset(8*4+off+320))
MOVL(R10L, Mem{Base: dst}.Offset(3*4+off+384))
MOVL(R10L, Mem{Base: dst}.Offset(13*4+off+448))
MOVL(R10L, Mem{Base: dst}.Offset(14*4+off+512))
MOVL(R10L, Mem{Base: dst}.Offset(5*4+off+576))
SHRQ(Imm(32), R10)
MOVL(R10L, Mem{Base: dst}.Offset(6*4+off+0))
MOVL(R10L, Mem{Base: dst}.Offset(11*4+off+64))
MOVL(R10L, Mem{Base: dst}.Offset(2*4+off+128))
MOVL(R10L, Mem{Base: dst}.Offset(9*4+off+192))
MOVL(R10L, Mem{Base: dst}.Offset(1*4+off+256))
MOVL(R10L, Mem{Base: dst}.Offset(13*4+off+320))
MOVL(R10L, Mem{Base: dst}.Offset(4*4+off+384))
MOVL(R10L, Mem{Base: dst}.Offset(8*4+off+448))
MOVL(R10L, Mem{Base: dst}.Offset(15*4+off+512))
MOVL(R10L, Mem{Base: dst}.Offset(7*4+off+576))
MOVL(R11L, Mem{Base: dst}.Offset(3*4+off+0))
MOVL(R11L, Mem{Base: dst}.Offset(7*4+off+64))
MOVL(R11L, Mem{Base: dst}.Offset(13*4+off+128))
MOVL(R11L, Mem{Base: dst}.Offset(12*4+off+192))
MOVL(R11L, Mem{Base: dst}.Offset(10*4+off+256))
MOVL(R11L, Mem{Base: dst}.Offset(1*4+off+320))
MOVL(R11L, Mem{Base: dst}.Offset(9*4+off+384))
MOVL(R11L, Mem{Base: dst}.Offset(14*4+off+448))
MOVL(R11L, Mem{Base: dst}.Offset(0*4+off+512))
MOVL(R11L, Mem{Base: dst}.Offset(6*4+off+576))
SHRQ(Imm(32), R11)
MOVL(R11L, Mem{Base: dst}.Offset(7*4+off+0))
MOVL(R11L, Mem{Base: dst}.Offset(14*4+off+64))
MOVL(R11L, Mem{Base: dst}.Offset(10*4+off+128))
MOVL(R11L, Mem{Base: dst}.Offset(0*4+off+192))
MOVL(R11L, Mem{Base: dst}.Offset(5*4+off+256))
MOVL(R11L, Mem{Base: dst}.Offset(9*4+off+320))
MOVL(R11L, Mem{Base: dst}.Offset(12*4+off+384))
MOVL(R11L, Mem{Base: dst}.Offset(1*4+off+448))
MOVL(R11L, Mem{Base: dst}.Offset(13*4+off+512))
MOVL(R11L, Mem{Base: dst}.Offset(2*4+off+576))
MOVL(R12L, Mem{Base: dst}.Offset(8*4+off+0))
MOVL(R12L, Mem{Base: dst}.Offset(5*4+off+64))
MOVL(R12L, Mem{Base: dst}.Offset(4*4+off+128))
MOVL(R12L, Mem{Base: dst}.Offset(15*4+off+192))
MOVL(R12L, Mem{Base: dst}.Offset(14*4+off+256))
MOVL(R12L, Mem{Base: dst}.Offset(3*4+off+320))
MOVL(R12L, Mem{Base: dst}.Offset(11*4+off+384))
MOVL(R12L, Mem{Base: dst}.Offset(10*4+off+448))
MOVL(R12L, Mem{Base: dst}.Offset(7*4+off+512))
MOVL(R12L, Mem{Base: dst}.Offset(1*4+off+576))
SHRQ(Imm(32), R12)
MOVL(R12L, Mem{Base: dst}.Offset(12*4+off+0))
MOVL(R12L, Mem{Base: dst}.Offset(2*4+off+64))
MOVL(R12L, Mem{Base: dst}.Offset(11*4+off+128))
MOVL(R12L, Mem{Base: dst}.Offset(4*4+off+192))
MOVL(R12L, Mem{Base: dst}.Offset(0*4+off+256))
MOVL(R12L, Mem{Base: dst}.Offset(15*4+off+320))
MOVL(R12L, Mem{Base: dst}.Offset(10*4+off+384))
MOVL(R12L, Mem{Base: dst}.Offset(7*4+off+448))
MOVL(R12L, Mem{Base: dst}.Offset(5*4+off+512))
MOVL(R12L, Mem{Base: dst}.Offset(9*4+off+576))
MOVL(R13L, Mem{Base: dst}.Offset(9*4+off+0))
MOVL(R13L, Mem{Base: dst}.Offset(4*4+off+64))
MOVL(R13L, Mem{Base: dst}.Offset(8*4+off+128))
MOVL(R13L, Mem{Base: dst}.Offset(13*4+off+192))
MOVL(R13L, Mem{Base: dst}.Offset(3*4+off+256))
MOVL(R13L, Mem{Base: dst}.Offset(5*4+off+320))
MOVL(R13L, Mem{Base: dst}.Offset(7*4+off+384))
MOVL(R13L, Mem{Base: dst}.Offset(15*4+off+448))
MOVL(R13L, Mem{Base: dst}.Offset(11*4+off+512))
MOVL(R13L, Mem{Base: dst}.Offset(0*4+off+576))
SHRQ(Imm(32), R13)
MOVL(R13L, Mem{Base: dst}.Offset(13*4+off+0))
MOVL(R13L, Mem{Base: dst}.Offset(10*4+off+64))
MOVL(R13L, Mem{Base: dst}.Offset(0*4+off+128))
MOVL(R13L, Mem{Base: dst}.Offset(3*4+off+192))
MOVL(R13L, Mem{Base: dst}.Offset(9*4+off+256))
MOVL(R13L, Mem{Base: dst}.Offset(6*4+off+320))
MOVL(R13L, Mem{Base: dst}.Offset(15*4+off+384))
MOVL(R13L, Mem{Base: dst}.Offset(4*4+off+448))
MOVL(R13L, Mem{Base: dst}.Offset(2*4+off+512))
MOVL(R13L, Mem{Base: dst}.Offset(12*4+off+576))
MOVL(R14L, Mem{Base: dst}.Offset(10*4+off+0))
MOVL(R14L, Mem{Base: dst}.Offset(12*4+off+64))
MOVL(R14L, Mem{Base: dst}.Offset(1*4+off+128))
MOVL(R14L, Mem{Base: dst}.Offset(6*4+off+192))
MOVL(R14L, Mem{Base: dst}.Offset(13*4+off+256))
MOVL(R14L, Mem{Base: dst}.Offset(4*4+off+320))
MOVL(R14L, Mem{Base: dst}.Offset(0*4+off+384))
MOVL(R14L, Mem{Base: dst}.Offset(2*4+off+448))
MOVL(R14L, Mem{Base: dst}.Offset(8*4+off+512))
MOVL(R14L, Mem{Base: dst}.Offset(14*4+off+576))
SHRQ(Imm(32), R14)
MOVL(R14L, Mem{Base: dst}.Offset(14*4+off+0))
MOVL(R14L, Mem{Base: dst}.Offset(3*4+off+64))
MOVL(R14L, Mem{Base: dst}.Offset(7*4+off+128))
MOVL(R14L, Mem{Base: dst}.Offset(2*4+off+192))
MOVL(R14L, Mem{Base: dst}.Offset(15*4+off+256))
MOVL(R14L, Mem{Base: dst}.Offset(12*4+off+320))
MOVL(R14L, Mem{Base: dst}.Offset(6*4+off+384))
MOVL(R14L, Mem{Base: dst}.Offset(0*4+off+448))
MOVL(R14L, Mem{Base: dst}.Offset(9*4+off+512))
MOVL(R14L, Mem{Base: dst}.Offset(11*4+off+576))
MOVL(R15L, Mem{Base: dst}.Offset(11*4+off+0))
MOVL(R15L, Mem{Base: dst}.Offset(0*4+off+64))
MOVL(R15L, Mem{Base: dst}.Offset(12*4+off+128))
MOVL(R15L, Mem{Base: dst}.Offset(7*4+off+192))
MOVL(R15L, Mem{Base: dst}.Offset(8*4+off+256))
MOVL(R15L, Mem{Base: dst}.Offset(14*4+off+320))
MOVL(R15L, Mem{Base: dst}.Offset(2*4+off+384))
MOVL(R15L, Mem{Base: dst}.Offset(5*4+off+448))
MOVL(R15L, Mem{Base: dst}.Offset(1*4+off+512))
MOVL(R15L, Mem{Base: dst}.Offset(13*4+off+576))
SHRQ(Imm(32), R15)
MOVL(R15L, Mem{Base: dst}.Offset(15*4+off+0))
MOVL(R15L, Mem{Base: dst}.Offset(6*4+off+64))
MOVL(R15L, Mem{Base: dst}.Offset(3*4+off+128))
MOVL(R15L, Mem{Base: dst}.Offset(11*4+off+192))
MOVL(R15L, Mem{Base: dst}.Offset(7*4+off+256))
MOVL(R15L, Mem{Base: dst}.Offset(10*4+off+320))
MOVL(R15L, Mem{Base: dst}.Offset(5*4+off+384))
MOVL(R15L, Mem{Base: dst}.Offset(9*4+off+448))
MOVL(R15L, Mem{Base: dst}.Offset(4*4+off+512))
MOVL(R15L, Mem{Base: dst}.Offset(8*4+off+576))
}
func BLAKE2s_SSE2() {
PRECOMPUTE_MSG(BP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15)
for i := 0; i < 10; i++ {
ROUND_SSE2(X4, X5, X6, X7, Mem{Base: BP}.Offset(16+64*i), Mem{Base: BP}.Offset(32+64*i), Mem{Base: BP}.Offset(48+64*i), Mem{Base: BP}.Offset(64+64*i), X8)
}
}
func BLAKE2s_SSSE3() {
PRECOMPUTE_MSG(BP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15)
for i := 0; i < 10; i++ {
ROUND_SSSE3(X4, X5, X6, X7, Mem{Base: BP}.Offset(16+64*i), Mem{Base: BP}.Offset(32+64*i), Mem{Base: BP}.Offset(48+64*i), Mem{Base: BP}.Offset(64+64*i), X8, X13, X14)
}
}
func BLAKE2s_SSE4() {
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0)
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
}
func HASH_BLOCKS(h, c, flag, blocks_base, blocks_len Mem, BLAKE2s_FUNC func()) {
MOVQ(h, RAX)
MOVQ(c, RBX)
MOVL(flag, ECX)
MOVQ(blocks_base, RSI)
MOVQ(blocks_len, RDX)
MOVQ(RSP, RBP)
ADDQ(Imm(15), RBP)
ANDQ(I32(^15), RBP)
MOVQ(Mem{Base: BX}.Offset(0), R9)
MOVQ(R9, Mem{Base: BP}.Offset(0))
MOVQ(RCX, Mem{Base: BP}.Offset(8))
MOVOU(Mem{Base: AX}.Offset(0), X0)
MOVOU(Mem{Base: AX}.Offset(16), X1)
iv0 := iv0_DATA()
iv1 := iv1_DATA()
MOVOU(iv0, X2)
MOVOU(iv1, X3)
counter := counter_DATA()
rol16 := rol16_DATA()
rol8 := rol8_DATA()
MOVOU(counter, X12)
MOVOU(rol16, X13)
MOVOU(rol8, X14)
MOVO(Mem{Base: BP}.Offset(0), X15)
Label("loop")
MOVO(X0, X4)
MOVO(X1, X5)
MOVO(X2, X6)
MOVO(X3, X7)
PADDQ(X12, X15)
PXOR(X15, X7)
BLAKE2s_FUNC()
PXOR(X4, X0)
PXOR(X5, X1)
PXOR(X6, X0)
PXOR(X7, X1)
LEAQ(Mem{Base: SI}.Offset(64), RSI)
SUBQ(Imm(64), RDX)
JNE(LabelRef("loop"))
MOVO(X15, Mem{Base: BP}.Offset(0))
MOVQ(Mem{Base: BP}.Offset(0), R9)
MOVQ(R9, Mem{Base: BX}.Offset(0))
MOVOU(X0, Mem{Base: AX}.Offset(0))
MOVOU(X1, Mem{Base: AX}.Offset(16))
}
func hashBlocksSSE2() {
Implement("hashBlocksSSE2")
Attributes(0)
AllocLocal(672) // frame = 656 + 16 byte alignment
h := NewParamAddr("h", 0)
c := NewParamAddr("c", 8)
flag := NewParamAddr("flag", 16)
blocks_base := NewParamAddr("blocks_base", 24)
blocks_len := NewParamAddr("blocks_len", 32)
HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_SSE2)
RET()
}
func hashBlocksSSSE3() {
Implement("hashBlocksSSSE3")
Attributes(0)
AllocLocal(672) // frame = 656 + 16 byte alignment
h := NewParamAddr("h", 0)
c := NewParamAddr("c", 8)
flag := NewParamAddr("flag", 16)
blocks_base := NewParamAddr("blocks_base", 24)
blocks_len := NewParamAddr("blocks_len", 32)
HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_SSSE3)
RET()
}
func hashBlocksSSE4() {
Implement("hashBlocksSSE4")
Attributes(0)
AllocLocal(32) // frame = 16 + 16 byte alignment
h := NewParamAddr("h", 0)
c := NewParamAddr("c", 8)
flag := NewParamAddr("flag", 16)
blocks_base := NewParamAddr("blocks_base", 24)
blocks_len := NewParamAddr("blocks_len", 32)
HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_SSE4)
RET()
}
// ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DATA SECTION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
var iv0_DATA_ptr, iv1_DATA_ptr, rol16_DATA_ptr, rol8_DATA_ptr, counter_DATA_ptr *Mem
func iv0_DATA() Mem {
if iv0_DATA_ptr != nil {
return *iv0_DATA_ptr
}
iv0_DATA := GLOBL("iv0", NOPTR|RODATA)
iv0_DATA_ptr = &iv0_DATA
DATA(0x00, U32(0x6a09e667))
DATA(0x04, U32(0xbb67ae85))
DATA(0x08, U32(0x3c6ef372))
DATA(0x0c, U32(0xa54ff53a))
return iv0_DATA
}
func iv1_DATA() Mem {
if iv1_DATA_ptr != nil {
return *iv1_DATA_ptr
}
iv1_DATA := GLOBL("iv1", NOPTR|RODATA)
iv1_DATA_ptr = &iv1_DATA
DATA(0x00, U32(0x510e527f))
DATA(0x04, U32(0x9b05688c))
DATA(0x08, U32(0x1f83d9ab))
DATA(0x0c, U32(0x5be0cd19))
return iv1_DATA
}
func rol16_DATA() Mem {
if rol16_DATA_ptr != nil {
return *rol16_DATA_ptr
}
rol16_DATA := GLOBL("rol16", NOPTR|RODATA)
rol16_DATA_ptr = &rol16_DATA
DATA(0x00, U64(0x0504070601000302))
DATA(0x08, U64(0x0D0C0F0E09080B0A))
return rol16_DATA
}
func rol8_DATA() Mem {
if rol8_DATA_ptr != nil {
return *rol8_DATA_ptr
}
rol8_DATA := GLOBL("rol8", NOPTR|RODATA)
rol8_DATA_ptr = &rol8_DATA
DATA(0x00, U64(0x0407060500030201))
DATA(0x08, U64(0x0C0F0E0D080B0A09))
return rol8_DATA
}
func counter_DATA() Mem {
if counter_DATA_ptr != nil {
return *counter_DATA_ptr
}
counter_DATA := GLOBL("counter", NOPTR|RODATA)
counter_DATA_ptr = &counter_DATA
DATA(0x00, U64(0x0000000000000040))
DATA(0x08, U64(0x0000000000000000))
return counter_DATA
}
+15
View File
@@ -0,0 +1,15 @@
module blake2s/_asm
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+2160 -419
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5,7 +5,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
+1 -1
View File
@@ -5,7 +5,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
+1 -1
View File
@@ -5,7 +5,7 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// Pairing-Friendly Fields", Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego
//go:build (!arm64 && !s390x && !ppc64 && !ppc64le) || !gc || purego
package chacha20
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc && !purego
//go:build gc && !purego && (ppc64 || ppc64le)
package chacha20
@@ -19,7 +19,7 @@
// The differences in this and the original implementation are
// due to the calling conventions and initialization of constants.
//go:build gc && !purego
//go:build gc && !purego && (ppc64 || ppc64le)
#include "textflag.h"
@@ -36,32 +36,68 @@
// for VPERMXOR
#define MASK R18
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
DATA consts<>+0xa0(SB)/8, $0x5566774411223300
DATA consts<>+0xa8(SB)/8, $0xddeeffcc99aabb88
DATA consts<>+0xb0(SB)/8, $0x6677445522330011
DATA consts<>+0xb8(SB)/8, $0xeeffccddaabb8899
DATA consts<>+0x00(SB)/4, $0x61707865
DATA consts<>+0x04(SB)/4, $0x3320646e
DATA consts<>+0x08(SB)/4, $0x79622d32
DATA consts<>+0x0c(SB)/4, $0x6b206574
DATA consts<>+0x10(SB)/4, $0x00000001
DATA consts<>+0x14(SB)/4, $0x00000000
DATA consts<>+0x18(SB)/4, $0x00000000
DATA consts<>+0x1c(SB)/4, $0x00000000
DATA consts<>+0x20(SB)/4, $0x00000004
DATA consts<>+0x24(SB)/4, $0x00000000
DATA consts<>+0x28(SB)/4, $0x00000000
DATA consts<>+0x2c(SB)/4, $0x00000000
DATA consts<>+0x30(SB)/4, $0x0e0f0c0d
DATA consts<>+0x34(SB)/4, $0x0a0b0809
DATA consts<>+0x38(SB)/4, $0x06070405
DATA consts<>+0x3c(SB)/4, $0x02030001
DATA consts<>+0x40(SB)/4, $0x0d0e0f0c
DATA consts<>+0x44(SB)/4, $0x090a0b08
DATA consts<>+0x48(SB)/4, $0x05060704
DATA consts<>+0x4c(SB)/4, $0x01020300
DATA consts<>+0x50(SB)/4, $0x61707865
DATA consts<>+0x54(SB)/4, $0x61707865
DATA consts<>+0x58(SB)/4, $0x61707865
DATA consts<>+0x5c(SB)/4, $0x61707865
DATA consts<>+0x60(SB)/4, $0x3320646e
DATA consts<>+0x64(SB)/4, $0x3320646e
DATA consts<>+0x68(SB)/4, $0x3320646e
DATA consts<>+0x6c(SB)/4, $0x3320646e
DATA consts<>+0x70(SB)/4, $0x79622d32
DATA consts<>+0x74(SB)/4, $0x79622d32
DATA consts<>+0x78(SB)/4, $0x79622d32
DATA consts<>+0x7c(SB)/4, $0x79622d32
DATA consts<>+0x80(SB)/4, $0x6b206574
DATA consts<>+0x84(SB)/4, $0x6b206574
DATA consts<>+0x88(SB)/4, $0x6b206574
DATA consts<>+0x8c(SB)/4, $0x6b206574
DATA consts<>+0x90(SB)/4, $0x00000000
DATA consts<>+0x94(SB)/4, $0x00000001
DATA consts<>+0x98(SB)/4, $0x00000002
DATA consts<>+0x9c(SB)/4, $0x00000003
DATA consts<>+0xa0(SB)/4, $0x11223300
DATA consts<>+0xa4(SB)/4, $0x55667744
DATA consts<>+0xa8(SB)/4, $0x99aabb88
DATA consts<>+0xac(SB)/4, $0xddeeffcc
DATA consts<>+0xb0(SB)/4, $0x22330011
DATA consts<>+0xb4(SB)/4, $0x66774455
DATA consts<>+0xb8(SB)/4, $0xaabb8899
DATA consts<>+0xbc(SB)/4, $0xeeffccdd
GLOBL consts<>(SB), RODATA, $0xc0
#ifdef GOARCH_ppc64
#define BE_XXBRW_INIT() \
LVSL (R0)(R0), V24 \
VSPLTISB $3, V25 \
VXOR V24, V25, V24 \
#define BE_XXBRW(vr) VPERM vr, vr, V24, vr
#else
#define BE_XXBRW_INIT()
#define BE_XXBRW(vr)
#endif
//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
@@ -94,6 +130,8 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
// Clear V27
VXOR V27, V27, V27
BE_XXBRW_INIT()
// V28
LXVW4X (CONSTBASE)(R11), VS60
@@ -299,6 +337,11 @@ loop_vsx:
VADDUWM V8, V18, V8
VADDUWM V12, V19, V12
BE_XXBRW(V0)
BE_XXBRW(V4)
BE_XXBRW(V8)
BE_XXBRW(V12)
CMPU LEN, $64
BLT tail_vsx
@@ -327,6 +370,11 @@ loop_vsx:
VADDUWM V9, V18, V8
VADDUWM V13, V19, V12
BE_XXBRW(V0)
BE_XXBRW(V4)
BE_XXBRW(V8)
BE_XXBRW(V12)
CMPU LEN, $64
BLT tail_vsx
@@ -334,8 +382,8 @@ loop_vsx:
LXVW4X (INP)(R8), VS60
LXVW4X (INP)(R9), VS61
LXVW4X (INP)(R10), VS62
VXOR V27, V0, V27
VXOR V27, V0, V27
VXOR V28, V4, V28
VXOR V29, V8, V29
VXOR V30, V12, V30
@@ -354,6 +402,11 @@ loop_vsx:
VADDUWM V10, V18, V8
VADDUWM V14, V19, V12
BE_XXBRW(V0)
BE_XXBRW(V4)
BE_XXBRW(V8)
BE_XXBRW(V12)
CMPU LEN, $64
BLT tail_vsx
@@ -381,6 +434,11 @@ loop_vsx:
VADDUWM V11, V18, V8
VADDUWM V15, V19, V12
BE_XXBRW(V0)
BE_XXBRW(V4)
BE_XXBRW(V8)
BE_XXBRW(V12)
CMPU LEN, $64
BLT tail_vsx
@@ -408,9 +466,9 @@ loop_vsx:
done_vsx:
// Increment counter by number of 64 byte blocks
MOVD (CNT), R14
MOVWZ (CNT), R14
ADD BLOCKS, R14
MOVD R14, (CNT)
MOVWZ R14, (CNT)
RET
tail_vsx:
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
module chacha20poly1305/_asm
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -234,7 +234,7 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
// Identifiers with the low five bits set indicate high-tag-number format
// (two or more octets), which we don't support.
if tag&0x1f == 0x1f {
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octets not supported: 0x%x", tag)
return
}
b.AddUint8(uint8(tag))
+4 -4
View File
@@ -1,11 +1,11 @@
module golang.org/x/crypto
go 1.20
go 1.23.0
require (
golang.org/x/net v0.21.0 // tagx:ignore
golang.org/x/sys v0.23.0
golang.org/x/term v0.23.0
golang.org/x/sys v0.32.0
golang.org/x/term v0.31.0
)
require golang.org/x/text v0.17.0 // indirect
require golang.org/x/text v0.24.0 // indirect
+6 -6
View File
@@ -1,8 +1,8 @@
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+15
View File
@@ -0,0 +1,15 @@
module internal/poly1305/_asm
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+126
View File
@@ -0,0 +1,126 @@
// Copyright 2024 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 main
import (
. "github.com/mmcloughlin/avo/build"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
_ "golang.org/x/crypto/sha3"
)
//go:generate go run . -out ../sum_amd64.s -pkg poly1305
func main() {
Package("golang.org/x/crypto/internal/poly1305")
ConstraintExpr("gc,!purego")
update()
Generate()
}
func update() {
Implement("update")
Load(Param("state"), RDI)
MOVQ(NewParamAddr("msg_base", 8), RSI)
MOVQ(NewParamAddr("msg_len", 16), R15)
MOVQ(Mem{Base: DI}.Offset(0), R8) // h0
MOVQ(Mem{Base: DI}.Offset(8), R9) // h1
MOVQ(Mem{Base: DI}.Offset(16), R10) // h2
MOVQ(Mem{Base: DI}.Offset(24), R11) // r0
MOVQ(Mem{Base: DI}.Offset(32), R12) // r1
CMPQ(R15, Imm(16))
JB(LabelRef("bytes_between_0_and_15"))
Label("loop")
POLY1305_ADD(RSI, R8, R9, R10)
Label("multiply")
POLY1305_MUL(R8, R9, R10, R11, R12, RBX, RCX, R13, R14)
SUBQ(Imm(16), R15)
CMPQ(R15, Imm(16))
JAE(LabelRef("loop"))
Label("bytes_between_0_and_15")
TESTQ(R15, R15)
JZ(LabelRef("done"))
MOVQ(U32(1), RBX)
XORQ(RCX, RCX)
XORQ(R13, R13)
ADDQ(R15, RSI)
Label("flush_buffer")
SHLQ(Imm(8), RBX, RCX)
SHLQ(Imm(8), RBX)
MOVB(Mem{Base: SI}.Offset(-1), R13B)
XORQ(R13, RBX)
DECQ(RSI)
DECQ(R15)
JNZ(LabelRef("flush_buffer"))
ADDQ(RBX, R8)
ADCQ(RCX, R9)
ADCQ(Imm(0), R10)
MOVQ(U32(16), R15)
JMP(LabelRef("multiply"))
Label("done")
MOVQ(R8, Mem{Base: DI}.Offset(0))
MOVQ(R9, Mem{Base: DI}.Offset(8))
MOVQ(R10, Mem{Base: DI}.Offset(16))
RET()
}
func POLY1305_ADD(msg, h0, h1, h2 GPPhysical) {
ADDQ(Mem{Base: msg}.Offset(0), h0)
ADCQ(Mem{Base: msg}.Offset(8), h1)
ADCQ(Imm(1), h2)
LEAQ(Mem{Base: msg}.Offset(16), msg)
}
func POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3 GPPhysical) {
MOVQ(r0, RAX)
MULQ(h0)
MOVQ(RAX, t0)
MOVQ(RDX, t1)
MOVQ(r0, RAX)
MULQ(h1)
ADDQ(RAX, t1)
ADCQ(Imm(0), RDX)
MOVQ(r0, t2)
IMULQ(h2, t2)
ADDQ(RDX, t2)
MOVQ(r1, RAX)
MULQ(h0)
ADDQ(RAX, t1)
ADCQ(Imm(0), RDX)
MOVQ(RDX, h0)
MOVQ(r1, t3)
IMULQ(h2, t3)
MOVQ(r1, RAX)
MULQ(h1)
ADDQ(RAX, t2)
ADCQ(RDX, t3)
ADDQ(h0, t2)
ADCQ(Imm(0), t3)
MOVQ(t0, h0)
MOVQ(t1, h1)
MOVQ(t2, h2)
ANDQ(Imm(3), h2)
MOVQ(t2, t0)
ANDQ(I32(-4), t0)
ADDQ(t0, h0)
ADCQ(t3, h1)
ADCQ(Imm(0), h2)
SHRQ(Imm(2), t3, t2)
SHRQ(Imm(2), t3)
ADDQ(t2, h0)
ADCQ(t3, h1)
ADCQ(Imm(0), h2)
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego
package poly1305
+59 -74
View File
@@ -1,108 +1,93 @@
// 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.
// Code generated by command: go run sum_amd64_asm.go -out ../sum_amd64.s -pkg poly1305. DO NOT EDIT.
//go:build gc && !purego
#include "textflag.h"
#define POLY1305_ADD(msg, h0, h1, h2) \
ADDQ 0(msg), h0; \
ADCQ 8(msg), h1; \
ADCQ $1, h2; \
LEAQ 16(msg), msg
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \
MOVQ r0, AX; \
MULQ h0; \
MOVQ AX, t0; \
MOVQ DX, t1; \
MOVQ r0, AX; \
MULQ h1; \
ADDQ AX, t1; \
ADCQ $0, DX; \
MOVQ r0, t2; \
IMULQ h2, t2; \
ADDQ DX, t2; \
\
MOVQ r1, AX; \
MULQ h0; \
ADDQ AX, t1; \
ADCQ $0, DX; \
MOVQ DX, h0; \
MOVQ r1, t3; \
IMULQ h2, t3; \
MOVQ r1, AX; \
MULQ h1; \
ADDQ AX, t2; \
ADCQ DX, t3; \
ADDQ h0, t2; \
ADCQ $0, t3; \
\
MOVQ t0, h0; \
MOVQ t1, h1; \
MOVQ t2, h2; \
ANDQ $3, h2; \
MOVQ t2, t0; \
ANDQ $0xFFFFFFFFFFFFFFFC, t0; \
ADDQ t0, h0; \
ADCQ t3, h1; \
ADCQ $0, h2; \
SHRQ $2, t3, t2; \
SHRQ $2, t3; \
ADDQ t2, h0; \
ADCQ t3, h1; \
ADCQ $0, h2
// func update(state *[7]uint64, msg []byte)
// func update(state *macState, msg []byte)
TEXT ·update(SB), $0-32
MOVQ state+0(FP), DI
MOVQ msg_base+8(FP), SI
MOVQ msg_len+16(FP), R15
MOVQ 0(DI), R8 // h0
MOVQ 8(DI), R9 // h1
MOVQ 16(DI), R10 // h2
MOVQ 24(DI), R11 // r0
MOVQ 32(DI), R12 // r1
CMPQ R15, $16
MOVQ (DI), R8
MOVQ 8(DI), R9
MOVQ 16(DI), R10
MOVQ 24(DI), R11
MOVQ 32(DI), R12
CMPQ R15, $0x10
JB bytes_between_0_and_15
loop:
POLY1305_ADD(SI, R8, R9, R10)
ADDQ (SI), R8
ADCQ 8(SI), R9
ADCQ $0x01, R10
LEAQ 16(SI), SI
multiply:
POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14)
SUBQ $16, R15
CMPQ R15, $16
JAE loop
MOVQ R11, AX
MULQ R8
MOVQ AX, BX
MOVQ DX, CX
MOVQ R11, AX
MULQ R9
ADDQ AX, CX
ADCQ $0x00, DX
MOVQ R11, R13
IMULQ R10, R13
ADDQ DX, R13
MOVQ R12, AX
MULQ R8
ADDQ AX, CX
ADCQ $0x00, DX
MOVQ DX, R8
MOVQ R12, R14
IMULQ R10, R14
MOVQ R12, AX
MULQ R9
ADDQ AX, R13
ADCQ DX, R14
ADDQ R8, R13
ADCQ $0x00, R14
MOVQ BX, R8
MOVQ CX, R9
MOVQ R13, R10
ANDQ $0x03, R10
MOVQ R13, BX
ANDQ $-4, BX
ADDQ BX, R8
ADCQ R14, R9
ADCQ $0x00, R10
SHRQ $0x02, R14, R13
SHRQ $0x02, R14
ADDQ R13, R8
ADCQ R14, R9
ADCQ $0x00, R10
SUBQ $0x10, R15
CMPQ R15, $0x10
JAE loop
bytes_between_0_and_15:
TESTQ R15, R15
JZ done
MOVQ $1, BX
MOVQ $0x00000001, BX
XORQ CX, CX
XORQ R13, R13
ADDQ R15, SI
flush_buffer:
SHLQ $8, BX, CX
SHLQ $8, BX
SHLQ $0x08, BX, CX
SHLQ $0x08, BX
MOVB -1(SI), R13
XORQ R13, BX
DECQ SI
DECQ R15
JNZ flush_buffer
ADDQ BX, R8
ADCQ CX, R9
ADCQ $0, R10
MOVQ $16, R15
ADCQ $0x00, R10
MOVQ $0x00000010, R15
JMP multiply
done:
MOVQ R8, 0(DI)
MOVQ R8, (DI)
MOVQ R9, 8(DI)
MOVQ R10, 16(DI)
RET
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc && !purego
//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le)
package poly1305
+123
View File
@@ -0,0 +1,123 @@
// Copyright 2025 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.
//go:build gc && !purego
// func update(state *macState, msg []byte)
TEXT ·update(SB), $0-32
MOVV state+0(FP), R4
MOVV msg_base+8(FP), R5
MOVV msg_len+16(FP), R6
MOVV $0x10, R7
MOVV (R4), R8 // h0
MOVV 8(R4), R9 // h1
MOVV 16(R4), R10 // h2
MOVV 24(R4), R11 // r0
MOVV 32(R4), R12 // r1
BLT R6, R7, bytes_between_0_and_15
loop:
MOVV (R5), R14 // msg[0:8]
MOVV 8(R5), R16 // msg[8:16]
ADDV R14, R8, R8 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow)
ADDV R16, R9, R27
SGTU R14, R8, R24 // h0.carry
SGTU R9, R27, R28
ADDV R27, R24, R9 // h1
SGTU R27, R9, R24
OR R24, R28, R24 // h1.carry
ADDV $0x01, R24, R24
ADDV R10, R24, R10 // h2
ADDV $16, R5, R5 // msg = msg[16:]
multiply:
MULV R8, R11, R14 // h0r0.lo
MULHVU R8, R11, R15 // h0r0.hi
MULV R9, R11, R13 // h1r0.lo
MULHVU R9, R11, R16 // h1r0.hi
ADDV R13, R15, R15
SGTU R13, R15, R24
ADDV R24, R16, R16
MULV R10, R11, R25
ADDV R16, R25, R25
MULV R8, R12, R13 // h0r1.lo
MULHVU R8, R12, R16 // h0r1.hi
ADDV R13, R15, R15
SGTU R13, R15, R24
ADDV R24, R16, R16
MOVV R16, R8
MULV R10, R12, R26 // h2r1
MULV R9, R12, R13 // h1r1.lo
MULHVU R9, R12, R16 // h1r1.hi
ADDV R13, R25, R25
ADDV R16, R26, R27
SGTU R13, R25, R24
ADDV R27, R24, R26
ADDV R8, R25, R25
SGTU R8, R25, R24
ADDV R24, R26, R26
AND $3, R25, R10
AND $-4, R25, R17
ADDV R17, R14, R8
ADDV R26, R15, R27
SGTU R17, R8, R24
SGTU R26, R27, R28
ADDV R27, R24, R9
SGTU R27, R9, R24
OR R24, R28, R24
ADDV R24, R10, R10
SLLV $62, R26, R27
SRLV $2, R25, R28
SRLV $2, R26, R26
OR R27, R28, R25
ADDV R25, R8, R8
ADDV R26, R9, R27
SGTU R25, R8, R24
SGTU R26, R27, R28
ADDV R27, R24, R9
SGTU R27, R9, R24
OR R24, R28, R24
ADDV R24, R10, R10
SUBV $16, R6, R6
BGE R6, R7, loop
bytes_between_0_and_15:
BEQ R6, R0, done
MOVV $1, R14
XOR R15, R15
ADDV R6, R5, R5
flush_buffer:
MOVBU -1(R5), R25
SRLV $56, R14, R24
SLLV $8, R15, R28
SLLV $8, R14, R14
OR R24, R28, R15
XOR R25, R14, R14
SUBV $1, R6, R6
SUBV $1, R5, R5
BNE R6, R0, flush_buffer
ADDV R14, R8, R8
SGTU R14, R8, R24
ADDV R15, R9, R27
SGTU R15, R27, R28
ADDV R27, R24, R9
SGTU R27, R9, R24
OR R24, R28, R24
ADDV R10, R24, R10
MOVV $16, R6
JMP multiply
done:
MOVV R8, (R4)
MOVV R9, 8(R4)
MOVV R10, 16(R4)
RET
-47
View File
@@ -1,47 +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.
//go:build gc && !purego
package poly1305
//go:noescape
func update(state *macState, msg []byte)
// mac is a wrapper for macGeneric that redirects calls that would have gone to
// updateGeneric to update.
//
// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
// using function pointers would carry a major performance cost.
type mac struct{ macGeneric }
func (h *mac) Write(p []byte) (int, error) {
nn := len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < TagSize {
h.offset += n
return nn, nil
}
p = p[n:]
h.offset = 0
update(&h.macState, h.buffer[:])
}
if n := len(p) - (len(p) % TagSize); n > 0 {
update(&h.macState, p[:n])
p = p[n:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return nn, nil
}
func (h *mac) Sum(out *[16]byte) {
state := h.macState
if h.offset > 0 {
update(&state, h.buffer[:h.offset])
}
finalize(out, &state.h, &state.s)
}
@@ -2,15 +2,25 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc && !purego
//go:build gc && !purego && (ppc64 || ppc64le)
#include "textflag.h"
// This was ported from the amd64 implementation.
#ifdef GOARCH_ppc64le
#define LE_MOVD MOVD
#define LE_MOVWZ MOVWZ
#define LE_MOVHZ MOVHZ
#else
#define LE_MOVD MOVDBR
#define LE_MOVWZ MOVWBR
#define LE_MOVHZ MOVHBR
#endif
#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \
MOVD (msg), t0; \
MOVD 8(msg), t1; \
LE_MOVD (msg)( R0), t0; \
LE_MOVD (msg)(R24), t1; \
MOVD $1, t2; \
ADDC t0, h0, h0; \
ADDE t1, h1, h1; \
@@ -50,10 +60,6 @@
ADDE t3, h1, h1; \
ADDZE h2
DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
GLOBL ·poly1305Mask<>(SB), RODATA, $16
// func update(state *[7]uint64, msg []byte)
TEXT ·update(SB), $0-32
MOVD state+0(FP), R3
@@ -66,6 +72,8 @@ TEXT ·update(SB), $0-32
MOVD 24(R3), R11 // r0
MOVD 32(R3), R12 // r1
MOVD $8, R24
CMP R5, $16
BLT bytes_between_0_and_15
@@ -94,7 +102,7 @@ flush_buffer:
// Greater than 8 -- load the rightmost remaining bytes in msg
// and put into R17 (h1)
MOVD (R4)(R21), R17
LE_MOVD (R4)(R21), R17
MOVD $16, R22
// Find the offset to those bytes
@@ -118,7 +126,7 @@ just1:
BLT less8
// Exactly 8
MOVD (R4), R16
LE_MOVD (R4), R16
CMP R17, $0
@@ -133,7 +141,7 @@ less8:
MOVD $0, R22 // shift count
CMP R5, $4
BLT less4
MOVWZ (R4), R16
LE_MOVWZ (R4), R16
ADD $4, R4
ADD $-4, R5
MOVD $32, R22
@@ -141,7 +149,7 @@ less8:
less4:
CMP R5, $2
BLT less2
MOVHZ (R4), R21
LE_MOVHZ (R4), R21
SLD R22, R21, R21
OR R16, R21, R16
ADD $16, R22
+1 -13
View File
@@ -123,24 +123,12 @@ func TestSigning(t *testing.T) {
}
}
// We use this to make test keys, so that they aren't all the same.
type quickRand byte
func (qr *quickRand) Read(p []byte) (int, error) {
for i := range p {
p[i] = byte(*qr)
}
*qr++
return len(p), nil
}
func TestMultiSign(t *testing.T) {
if testing.Short() {
t.Skip("skipping long test in -short mode")
}
zero := quickRand(0)
config := packet.Config{Rand: &zero}
var config packet.Config
for nKeys := 0; nKeys < 4; nKeys++ {
nextTest:
+1 -1
View File
@@ -26,7 +26,7 @@ type pbeCipher interface {
create(key []byte) (cipher.Block, error)
// deriveKey returns a key derived from the given password and salt.
deriveKey(salt, password []byte, iterations int) []byte
// deriveKey returns an IV derived from the given password and salt.
// deriveIV returns an IV derived from the given password and salt.
deriveIV(salt, password []byte, iterations int) []byte
}
+14
View File
@@ -0,0 +1,14 @@
module salsa20/salsa/_asm
go 1.23
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/tools v0.24.0 // indirect
)
+10
View File
@@ -0,0 +1,10 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+932
View File
@@ -0,0 +1,932 @@
// Copyright 2024 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
package main
import (
. "github.com/mmcloughlin/avo/build"
"github.com/mmcloughlin/avo/ir"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
_ "golang.org/x/crypto/salsa20/salsa"
)
//go:generate go run . -out ../salsa20_amd64.s -pkg salsa
func main() {
Package("golang.org/x/crypto/salsa20/salsa")
ConstraintExpr("amd64,!purego,gc")
salsa2020XORKeyStream()
Generate()
}
func salsa2020XORKeyStream() {
Implement("salsa2020XORKeyStream")
Attributes(0)
AllocLocal(456) // frame = 424 + 32 byte alignment
Comment("This needs up to 64 bytes at 360(R12); hence the non-obvious frame size.")
Load(Param("out"), RDI)
Load(Param("in"), RSI)
Load(Param("n"), RDX)
Load(Param("nonce"), RCX)
Load(Param("key"), R8)
MOVQ(RSP, R12)
ADDQ(Imm(31), R12)
ANDQ(I32(^31), R12)
MOVQ(RDX, R9)
MOVQ(RCX, RDX)
MOVQ(R8, R10)
CMPQ(R9, Imm(0))
JBE(LabelRef("DONE"))
START()
BYTESATLEAST256()
MAINLOOP1()
BYTESBETWEEN1AND255()
NOCOPY()
MAINLOOP2()
Label("BYTESATLEAST64")
Label("DONE")
RET()
Label("BYTESATLEAST65")
SUBQ(Imm(64), R9)
ADDQ(Imm(64), RDI)
ADDQ(Imm(64), RSI)
JMP(LabelRef("BYTESBETWEEN1AND255"))
}
func START() {
Label("START")
MOVL(Mem{Base: R10}.Offset(20), ECX)
MOVL(Mem{Base: R10}.Offset(0), R8L)
MOVL(Mem{Base: EDX}.Offset(0), EAX)
MOVL(Mem{Base: R10}.Offset(16), R11L)
MOVL(ECX, Mem{Base: R12}.Offset(0))
MOVL(R8L, Mem{Base: R12}.Offset(4))
MOVL(EAX, Mem{Base: R12}.Offset(8))
MOVL(R11L, Mem{Base: R12}.Offset(12))
MOVL(Mem{Base: EDX}.Offset(8), ECX)
MOVL(Mem{Base: R10}.Offset(24), R8L)
MOVL(Mem{Base: R10}.Offset(4), EAX)
MOVL(Mem{Base: EDX}.Offset(4), R11L)
MOVL(ECX, Mem{Base: R12}.Offset(16))
MOVL(R8L, Mem{Base: R12}.Offset(20))
MOVL(EAX, Mem{Base: R12}.Offset(24))
MOVL(R11L, Mem{Base: R12}.Offset(28))
MOVL(Mem{Base: EDX}.Offset(12), ECX)
MOVL(Mem{Base: R10}.Offset(12), EDX)
MOVL(Mem{Base: R10}.Offset(28), R8L)
MOVL(Mem{Base: R10}.Offset(8), EAX)
MOVL(EDX, Mem{Base: R12}.Offset(32))
MOVL(ECX, Mem{Base: R12}.Offset(36))
MOVL(R8L, Mem{Base: R12}.Offset(40))
MOVL(EAX, Mem{Base: R12}.Offset(44))
MOVQ(Imm(1634760805), RDX)
MOVQ(Imm(857760878), RCX)
MOVQ(Imm(2036477234), R8)
MOVQ(Imm(1797285236), RAX)
MOVL(EDX, Mem{Base: R12}.Offset(48))
MOVL(ECX, Mem{Base: R12}.Offset(52))
MOVL(R8L, Mem{Base: R12}.Offset(56))
MOVL(EAX, Mem{Base: R12}.Offset(60))
CMPQ(R9, U32(256))
JB(LabelRef("BYTESBETWEEN1AND255"))
MOVOA(Mem{Base: R12}.Offset(48), X0)
PSHUFL(Imm(0x55), X0, X1)
PSHUFL(Imm(0xAA), X0, X2)
PSHUFL(Imm(0xFF), X0, X3)
PSHUFL(Imm(0x00), X0, X0)
MOVOA(X1, Mem{Base: R12}.Offset(64))
MOVOA(X2, Mem{Base: R12}.Offset(80))
MOVOA(X3, Mem{Base: R12}.Offset(96))
MOVOA(X0, Mem{Base: R12}.Offset(112))
MOVOA(Mem{Base: R12}.Offset(0), X0)
PSHUFL(Imm(0xAA), X0, X1)
PSHUFL(Imm(0xFF), X0, X2)
PSHUFL(Imm(0x00), X0, X3)
PSHUFL(Imm(0x55), X0, X0)
MOVOA(X1, Mem{Base: R12}.Offset(128))
MOVOA(X2, Mem{Base: R12}.Offset(144))
MOVOA(X3, Mem{Base: R12}.Offset(160))
MOVOA(X0, Mem{Base: R12}.Offset(176))
MOVOA(Mem{Base: R12}.Offset(16), X0)
PSHUFL(Imm(0xFF), X0, X1)
PSHUFL(Imm(0x55), X0, X2)
PSHUFL(Imm(0xAA), X0, X0)
MOVOA(X1, Mem{Base: R12}.Offset(192))
MOVOA(X2, Mem{Base: R12}.Offset(208))
MOVOA(X0, Mem{Base: R12}.Offset(224))
MOVOA(Mem{Base: R12}.Offset(32), X0)
PSHUFL(Imm(0x00), X0, X1)
PSHUFL(Imm(0xAA), X0, X2)
PSHUFL(Imm(0xFF), X0, X0)
MOVOA(X1, Mem{Base: R12}.Offset(240))
MOVOA(X2, Mem{Base: R12}.Offset(256))
MOVOA(X0, Mem{Base: R12}.Offset(272))
}
func BYTESATLEAST256() {
Label("BYTESATLEAST256")
MOVL(Mem{Base: R12}.Offset(16), EDX)
MOVL(Mem{Base: R12}.Offset(36), ECX)
MOVL(EDX, Mem{Base: R12}.Offset(288))
MOVL(ECX, Mem{Base: R12}.Offset(304))
SHLQ(Imm(32), RCX)
ADDQ(RCX, RDX)
ADDQ(Imm(1), RDX)
MOVQ(RDX, RCX)
SHRQ(Imm(32), RCX)
MOVL(EDX, Mem{Base: R12}.Offset(292))
MOVL(ECX, Mem{Base: R12}.Offset(308))
ADDQ(Imm(1), RDX)
MOVQ(RDX, RCX)
SHRQ(Imm(32), RCX)
MOVL(EDX, Mem{Base: R12}.Offset(296))
MOVL(ECX, Mem{Base: R12}.Offset(312))
ADDQ(Imm(1), RDX)
MOVQ(RDX, RCX)
SHRQ(Imm(32), RCX)
MOVL(EDX, Mem{Base: R12}.Offset(300))
MOVL(ECX, Mem{Base: R12}.Offset(316))
ADDQ(Imm(1), RDX)
MOVQ(RDX, RCX)
SHRQ(Imm(32), RCX)
MOVL(EDX, Mem{Base: R12}.Offset(16))
MOVL(ECX, Mem{Base: R12}.Offset(36))
MOVQ(R9, Mem{Base: R12}.Offset(352))
MOVQ(U32(20), RDX)
MOVOA(Mem{Base: R12}.Offset(64), X0)
MOVOA(Mem{Base: R12}.Offset(80), X1)
MOVOA(Mem{Base: R12}.Offset(96), X2)
MOVOA(Mem{Base: R12}.Offset(256), X3)
MOVOA(Mem{Base: R12}.Offset(272), X4)
MOVOA(Mem{Base: R12}.Offset(128), X5)
MOVOA(Mem{Base: R12}.Offset(144), X6)
MOVOA(Mem{Base: R12}.Offset(176), X7)
MOVOA(Mem{Base: R12}.Offset(192), X8)
MOVOA(Mem{Base: R12}.Offset(208), X9)
MOVOA(Mem{Base: R12}.Offset(224), X10)
MOVOA(Mem{Base: R12}.Offset(304), X11)
MOVOA(Mem{Base: R12}.Offset(112), X12)
MOVOA(Mem{Base: R12}.Offset(160), X13)
MOVOA(Mem{Base: R12}.Offset(240), X14)
MOVOA(Mem{Base: R12}.Offset(288), X15)
}
func MAINLOOP1() {
Label("MAINLOOP1")
MOVOA(X1, Mem{Base: R12}.Offset(320))
MOVOA(X2, Mem{Base: R12}.Offset(336))
MOVOA(X13, X1)
PADDL(X12, X1)
MOVOA(X1, X2)
PSLLL(Imm(7), X1)
PXOR(X1, X14)
PSRLL(Imm(25), X2)
PXOR(X2, X14)
MOVOA(X7, X1)
PADDL(X0, X1)
MOVOA(X1, X2)
PSLLL(Imm(7), X1)
PXOR(X1, X11)
PSRLL(Imm(25), X2)
PXOR(X2, X11)
MOVOA(X12, X1)
PADDL(X14, X1)
MOVOA(X1, X2)
PSLLL(Imm(9), X1)
PXOR(X1, X15)
PSRLL(Imm(23), X2)
PXOR(X2, X15)
MOVOA(X0, X1)
PADDL(X11, X1)
MOVOA(X1, X2)
PSLLL(Imm(9), X1)
PXOR(X1, X9)
PSRLL(Imm(23), X2)
PXOR(X2, X9)
MOVOA(X14, X1)
PADDL(X15, X1)
MOVOA(X1, X2)
PSLLL(Imm(13), X1)
PXOR(X1, X13)
PSRLL(Imm(19), X2)
PXOR(X2, X13)
MOVOA(X11, X1)
PADDL(X9, X1)
MOVOA(X1, X2)
PSLLL(Imm(13), X1)
PXOR(X1, X7)
PSRLL(Imm(19), X2)
PXOR(X2, X7)
MOVOA(X15, X1)
PADDL(X13, X1)
MOVOA(X1, X2)
PSLLL(Imm(18), X1)
PXOR(X1, X12)
PSRLL(Imm(14), X2)
PXOR(X2, X12)
MOVOA(Mem{Base: R12}.Offset(320), X1)
MOVOA(X12, Mem{Base: R12}.Offset(320))
MOVOA(X9, X2)
PADDL(X7, X2)
MOVOA(X2, X12)
PSLLL(Imm(18), X2)
PXOR(X2, X0)
PSRLL(Imm(14), X12)
PXOR(X12, X0)
MOVOA(X5, X2)
PADDL(X1, X2)
MOVOA(X2, X12)
PSLLL(Imm(7), X2)
PXOR(X2, X3)
PSRLL(Imm(25), X12)
PXOR(X12, X3)
MOVOA(Mem{Base: R12}.Offset(336), X2)
MOVOA(X0, Mem{Base: R12}.Offset(336))
MOVOA(X6, X0)
PADDL(X2, X0)
MOVOA(X0, X12)
PSLLL(Imm(7), X0)
PXOR(X0, X4)
PSRLL(Imm(25), X12)
PXOR(X12, X4)
MOVOA(X1, X0)
PADDL(X3, X0)
MOVOA(X0, X12)
PSLLL(Imm(9), X0)
PXOR(X0, X10)
PSRLL(Imm(23), X12)
PXOR(X12, X10)
MOVOA(X2, X0)
PADDL(X4, X0)
MOVOA(X0, X12)
PSLLL(Imm(9), X0)
PXOR(X0, X8)
PSRLL(Imm(23), X12)
PXOR(X12, X8)
MOVOA(X3, X0)
PADDL(X10, X0)
MOVOA(X0, X12)
PSLLL(Imm(13), X0)
PXOR(X0, X5)
PSRLL(Imm(19), X12)
PXOR(X12, X5)
MOVOA(X4, X0)
PADDL(X8, X0)
MOVOA(X0, X12)
PSLLL(Imm(13), X0)
PXOR(X0, X6)
PSRLL(Imm(19), X12)
PXOR(X12, X6)
MOVOA(X10, X0)
PADDL(X5, X0)
MOVOA(X0, X12)
PSLLL(Imm(18), X0)
PXOR(X0, X1)
PSRLL(Imm(14), X12)
PXOR(X12, X1)
MOVOA(Mem{Base: R12}.Offset(320), X0)
MOVOA(X1, Mem{Base: R12}.Offset(320))
MOVOA(X4, X1)
PADDL(X0, X1)
MOVOA(X1, X12)
PSLLL(Imm(7), X1)
PXOR(X1, X7)
PSRLL(Imm(25), X12)
PXOR(X12, X7)
MOVOA(X8, X1)
PADDL(X6, X1)
MOVOA(X1, X12)
PSLLL(Imm(18), X1)
PXOR(X1, X2)
PSRLL(Imm(14), X12)
PXOR(X12, X2)
MOVOA(Mem{Base: R12}.Offset(336), X12)
MOVOA(X2, Mem{Base: R12}.Offset(336))
MOVOA(X14, X1)
PADDL(X12, X1)
MOVOA(X1, X2)
PSLLL(Imm(7), X1)
PXOR(X1, X5)
PSRLL(Imm(25), X2)
PXOR(X2, X5)
MOVOA(X0, X1)
PADDL(X7, X1)
MOVOA(X1, X2)
PSLLL(Imm(9), X1)
PXOR(X1, X10)
PSRLL(Imm(23), X2)
PXOR(X2, X10)
MOVOA(X12, X1)
PADDL(X5, X1)
MOVOA(X1, X2)
PSLLL(Imm(9), X1)
PXOR(X1, X8)
PSRLL(Imm(23), X2)
PXOR(X2, X8)
MOVOA(X7, X1)
PADDL(X10, X1)
MOVOA(X1, X2)
PSLLL(Imm(13), X1)
PXOR(X1, X4)
PSRLL(Imm(19), X2)
PXOR(X2, X4)
MOVOA(X5, X1)
PADDL(X8, X1)
MOVOA(X1, X2)
PSLLL(Imm(13), X1)
PXOR(X1, X14)
PSRLL(Imm(19), X2)
PXOR(X2, X14)
MOVOA(X10, X1)
PADDL(X4, X1)
MOVOA(X1, X2)
PSLLL(Imm(18), X1)
PXOR(X1, X0)
PSRLL(Imm(14), X2)
PXOR(X2, X0)
MOVOA(Mem{Base: R12}.Offset(320), X1)
MOVOA(X0, Mem{Base: R12}.Offset(320))
MOVOA(X8, X0)
PADDL(X14, X0)
MOVOA(X0, X2)
PSLLL(Imm(18), X0)
PXOR(X0, X12)
PSRLL(Imm(14), X2)
PXOR(X2, X12)
MOVOA(X11, X0)
PADDL(X1, X0)
MOVOA(X0, X2)
PSLLL(Imm(7), X0)
PXOR(X0, X6)
PSRLL(Imm(25), X2)
PXOR(X2, X6)
MOVOA(Mem{Base: R12}.Offset(336), X2)
MOVOA(X12, Mem{Base: R12}.Offset(336))
MOVOA(X3, X0)
PADDL(X2, X0)
MOVOA(X0, X12)
PSLLL(Imm(7), X0)
PXOR(X0, X13)
PSRLL(Imm(25), X12)
PXOR(X12, X13)
MOVOA(X1, X0)
PADDL(X6, X0)
MOVOA(X0, X12)
PSLLL(Imm(9), X0)
PXOR(X0, X15)
PSRLL(Imm(23), X12)
PXOR(X12, X15)
MOVOA(X2, X0)
PADDL(X13, X0)
MOVOA(X0, X12)
PSLLL(Imm(9), X0)
PXOR(X0, X9)
PSRLL(Imm(23), X12)
PXOR(X12, X9)
MOVOA(X6, X0)
PADDL(X15, X0)
MOVOA(X0, X12)
PSLLL(Imm(13), X0)
PXOR(X0, X11)
PSRLL(Imm(19), X12)
PXOR(X12, X11)
MOVOA(X13, X0)
PADDL(X9, X0)
MOVOA(X0, X12)
PSLLL(Imm(13), X0)
PXOR(X0, X3)
PSRLL(Imm(19), X12)
PXOR(X12, X3)
MOVOA(X15, X0)
PADDL(X11, X0)
MOVOA(X0, X12)
PSLLL(Imm(18), X0)
PXOR(X0, X1)
PSRLL(Imm(14), X12)
PXOR(X12, X1)
MOVOA(X9, X0)
PADDL(X3, X0)
MOVOA(X0, X12)
PSLLL(Imm(18), X0)
PXOR(X0, X2)
PSRLL(Imm(14), X12)
PXOR(X12, X2)
MOVOA(Mem{Base: R12}.Offset(320), X12)
MOVOA(Mem{Base: R12}.Offset(336), X0)
SUBQ(Imm(2), RDX)
JA(LabelRef("MAINLOOP1"))
PADDL(Mem{Base: R12}.Offset(112), X12)
PADDL(Mem{Base: R12}.Offset(176), X7)
PADDL(Mem{Base: R12}.Offset(224), X10)
PADDL(Mem{Base: R12}.Offset(272), X4)
MOVD(X12, EDX)
MOVD(X7, ECX)
MOVD(X10, R8)
MOVD(X4, R9)
PSHUFL(Imm(0x39), X12, X12)
PSHUFL(Imm(0x39), X7, X7)
PSHUFL(Imm(0x39), X10, X10)
PSHUFL(Imm(0x39), X4, X4)
XORL(Mem{Base: SI}.Offset(0), EDX)
XORL(Mem{Base: SI}.Offset(4), ECX)
XORL(Mem{Base: SI}.Offset(8), R8L)
XORL(Mem{Base: SI}.Offset(12), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(0))
MOVL(ECX, Mem{Base: DI}.Offset(4))
MOVL(R8L, Mem{Base: DI}.Offset(8))
MOVL(R9L, Mem{Base: DI}.Offset(12))
MOVD(X12, EDX)
MOVD(X7, ECX)
MOVD(X10, R8)
MOVD(X4, R9)
PSHUFL(Imm(0x39), X12, X12)
PSHUFL(Imm(0x39), X7, X7)
PSHUFL(Imm(0x39), X10, X10)
PSHUFL(Imm(0x39), X4, X4)
XORL(Mem{Base: SI}.Offset(64), EDX)
XORL(Mem{Base: SI}.Offset(68), ECX)
XORL(Mem{Base: SI}.Offset(72), R8L)
XORL(Mem{Base: SI}.Offset(76), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(64))
MOVL(ECX, Mem{Base: DI}.Offset(68))
MOVL(R8L, Mem{Base: DI}.Offset(72))
MOVL(R9L, Mem{Base: DI}.Offset(76))
MOVD(X12, EDX)
MOVD(X7, ECX)
MOVD(X10, R8)
MOVD(X4, R9)
PSHUFL(Imm(0x39), X12, X12)
PSHUFL(Imm(0x39), X7, X7)
PSHUFL(Imm(0x39), X10, X10)
PSHUFL(Imm(0x39), X4, X4)
XORL(Mem{Base: SI}.Offset(128), EDX)
XORL(Mem{Base: SI}.Offset(132), ECX)
XORL(Mem{Base: SI}.Offset(136), R8L)
XORL(Mem{Base: SI}.Offset(140), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(128))
MOVL(ECX, Mem{Base: DI}.Offset(132))
MOVL(R8L, Mem{Base: DI}.Offset(136))
MOVL(R9L, Mem{Base: DI}.Offset(140))
MOVD(X12, EDX)
MOVD(X7, ECX)
MOVD(X10, R8)
MOVD(X4, R9)
XORL(Mem{Base: SI}.Offset(192), EDX)
XORL(Mem{Base: SI}.Offset(196), ECX)
XORL(Mem{Base: SI}.Offset(200), R8L)
XORL(Mem{Base: SI}.Offset(204), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(192))
MOVL(ECX, Mem{Base: DI}.Offset(196))
MOVL(R8L, Mem{Base: DI}.Offset(200))
MOVL(R9L, Mem{Base: DI}.Offset(204))
PADDL(Mem{Base: R12}.Offset(240), X14)
PADDL(Mem{Base: R12}.Offset(64), X0)
PADDL(Mem{Base: R12}.Offset(128), X5)
PADDL(Mem{Base: R12}.Offset(192), X8)
MOVD(X14, EDX)
MOVD(X0, ECX)
MOVD(X5, R8)
MOVD(X8, R9)
PSHUFL(Imm(0x39), X14, X14)
PSHUFL(Imm(0x39), X0, X0)
PSHUFL(Imm(0x39), X5, X5)
PSHUFL(Imm(0x39), X8, X8)
XORL(Mem{Base: SI}.Offset(16), EDX)
XORL(Mem{Base: SI}.Offset(20), ECX)
XORL(Mem{Base: SI}.Offset(24), R8L)
XORL(Mem{Base: SI}.Offset(28), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(16))
MOVL(ECX, Mem{Base: DI}.Offset(20))
MOVL(R8L, Mem{Base: DI}.Offset(24))
MOVL(R9L, Mem{Base: DI}.Offset(28))
MOVD(X14, EDX)
MOVD(X0, ECX)
MOVD(X5, R8)
MOVD(X8, R9)
PSHUFL(Imm(0x39), X14, X14)
PSHUFL(Imm(0x39), X0, X0)
PSHUFL(Imm(0x39), X5, X5)
PSHUFL(Imm(0x39), X8, X8)
XORL(Mem{Base: SI}.Offset(80), EDX)
XORL(Mem{Base: SI}.Offset(84), ECX)
XORL(Mem{Base: SI}.Offset(88), R8L)
XORL(Mem{Base: SI}.Offset(92), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(80))
MOVL(ECX, Mem{Base: DI}.Offset(84))
MOVL(R8L, Mem{Base: DI}.Offset(88))
MOVL(R9L, Mem{Base: DI}.Offset(92))
MOVD(X14, EDX)
MOVD(X0, ECX)
MOVD(X5, R8)
MOVD(X8, R9)
PSHUFL(Imm(0x39), X14, X14)
PSHUFL(Imm(0x39), X0, X0)
PSHUFL(Imm(0x39), X5, X5)
PSHUFL(Imm(0x39), X8, X8)
XORL(Mem{Base: SI}.Offset(144), EDX)
XORL(Mem{Base: SI}.Offset(148), ECX)
XORL(Mem{Base: SI}.Offset(152), R8L)
XORL(Mem{Base: SI}.Offset(156), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(144))
MOVL(ECX, Mem{Base: DI}.Offset(148))
MOVL(R8L, Mem{Base: DI}.Offset(152))
MOVL(R9L, Mem{Base: DI}.Offset(156))
MOVD(X14, EDX)
MOVD(X0, ECX)
MOVD(X5, R8)
MOVD(X8, R9)
XORL(Mem{Base: SI}.Offset(208), EDX)
XORL(Mem{Base: SI}.Offset(212), ECX)
XORL(Mem{Base: SI}.Offset(216), R8L)
XORL(Mem{Base: SI}.Offset(220), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(208))
MOVL(ECX, Mem{Base: DI}.Offset(212))
MOVL(R8L, Mem{Base: DI}.Offset(216))
MOVL(R9L, Mem{Base: DI}.Offset(220))
PADDL(Mem{Base: R12}.Offset(288), X15)
PADDL(Mem{Base: R12}.Offset(304), X11)
PADDL(Mem{Base: R12}.Offset(80), X1)
PADDL(Mem{Base: R12}.Offset(144), X6)
MOVD(X15, EDX)
MOVD(X11, ECX)
MOVD(X1, R8)
MOVD(X6, R9)
PSHUFL(Imm(0x39), X15, X15)
PSHUFL(Imm(0x39), X11, X11)
PSHUFL(Imm(0x39), X1, X1)
PSHUFL(Imm(0x39), X6, X6)
XORL(Mem{Base: SI}.Offset(32), EDX)
XORL(Mem{Base: SI}.Offset(36), ECX)
XORL(Mem{Base: SI}.Offset(40), R8L)
XORL(Mem{Base: SI}.Offset(44), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(32))
MOVL(ECX, Mem{Base: DI}.Offset(36))
MOVL(R8L, Mem{Base: DI}.Offset(40))
MOVL(R9L, Mem{Base: DI}.Offset(44))
MOVD(X15, EDX)
MOVD(X11, ECX)
MOVD(X1, R8)
MOVD(X6, R9)
PSHUFL(Imm(0x39), X15, X15)
PSHUFL(Imm(0x39), X11, X11)
PSHUFL(Imm(0x39), X1, X1)
PSHUFL(Imm(0x39), X6, X6)
XORL(Mem{Base: SI}.Offset(96), EDX)
XORL(Mem{Base: SI}.Offset(100), ECX)
XORL(Mem{Base: SI}.Offset(104), R8L)
XORL(Mem{Base: SI}.Offset(108), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(96))
MOVL(ECX, Mem{Base: DI}.Offset(100))
MOVL(R8L, Mem{Base: DI}.Offset(104))
MOVL(R9L, Mem{Base: DI}.Offset(108))
MOVD(X15, EDX)
MOVD(X11, ECX)
MOVD(X1, R8)
MOVD(X6, R9)
PSHUFL(Imm(0x39), X15, X15)
PSHUFL(Imm(0x39), X11, X11)
PSHUFL(Imm(0x39), X1, X1)
PSHUFL(Imm(0x39), X6, X6)
XORL(Mem{Base: SI}.Offset(160), EDX)
XORL(Mem{Base: SI}.Offset(164), ECX)
XORL(Mem{Base: SI}.Offset(168), R8L)
XORL(Mem{Base: SI}.Offset(172), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(160))
MOVL(ECX, Mem{Base: DI}.Offset(164))
MOVL(R8L, Mem{Base: DI}.Offset(168))
MOVL(R9L, Mem{Base: DI}.Offset(172))
MOVD(X15, EDX)
MOVD(X11, ECX)
MOVD(X1, R8)
MOVD(X6, R9)
XORL(Mem{Base: SI}.Offset(224), EDX)
XORL(Mem{Base: SI}.Offset(228), ECX)
XORL(Mem{Base: SI}.Offset(232), R8L)
XORL(Mem{Base: SI}.Offset(236), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(224))
MOVL(ECX, Mem{Base: DI}.Offset(228))
MOVL(R8L, Mem{Base: DI}.Offset(232))
MOVL(R9L, Mem{Base: DI}.Offset(236))
PADDL(Mem{Base: R12}.Offset(160), X13)
PADDL(Mem{Base: R12}.Offset(208), X9)
PADDL(Mem{Base: R12}.Offset(256), X3)
PADDL(Mem{Base: R12}.Offset(96), X2)
MOVD(X13, EDX)
MOVD(X9, ECX)
MOVD(X3, R8)
MOVD(X2, R9)
PSHUFL(Imm(0x39), X13, X13)
PSHUFL(Imm(0x39), X9, X9)
PSHUFL(Imm(0x39), X3, X3)
PSHUFL(Imm(0x39), X2, X2)
XORL(Mem{Base: SI}.Offset(48), EDX)
XORL(Mem{Base: SI}.Offset(52), ECX)
XORL(Mem{Base: SI}.Offset(56), R8L)
XORL(Mem{Base: SI}.Offset(60), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(48))
MOVL(ECX, Mem{Base: DI}.Offset(52))
MOVL(R8L, Mem{Base: DI}.Offset(56))
MOVL(R9L, Mem{Base: DI}.Offset(60))
MOVD(X13, EDX)
MOVD(X9, ECX)
MOVD(X3, R8)
MOVD(X2, R9)
PSHUFL(Imm(0x39), X13, X13)
PSHUFL(Imm(0x39), X9, X9)
PSHUFL(Imm(0x39), X3, X3)
PSHUFL(Imm(0x39), X2, X2)
XORL(Mem{Base: SI}.Offset(112), EDX)
XORL(Mem{Base: SI}.Offset(116), ECX)
XORL(Mem{Base: SI}.Offset(120), R8L)
XORL(Mem{Base: SI}.Offset(124), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(112))
MOVL(ECX, Mem{Base: DI}.Offset(116))
MOVL(R8L, Mem{Base: DI}.Offset(120))
MOVL(R9L, Mem{Base: DI}.Offset(124))
MOVD(X13, EDX)
MOVD(X9, ECX)
MOVD(X3, R8)
MOVD(X2, R9)
PSHUFL(Imm(0x39), X13, X13)
PSHUFL(Imm(0x39), X9, X9)
PSHUFL(Imm(0x39), X3, X3)
PSHUFL(Imm(0x39), X2, X2)
XORL(Mem{Base: SI}.Offset(176), EDX)
XORL(Mem{Base: SI}.Offset(180), ECX)
XORL(Mem{Base: SI}.Offset(184), R8L)
XORL(Mem{Base: SI}.Offset(188), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(176))
MOVL(ECX, Mem{Base: DI}.Offset(180))
MOVL(R8L, Mem{Base: DI}.Offset(184))
MOVL(R9L, Mem{Base: DI}.Offset(188))
MOVD(X13, EDX)
MOVD(X9, ECX)
MOVD(X3, R8)
MOVD(X2, R9)
XORL(Mem{Base: SI}.Offset(240), EDX)
XORL(Mem{Base: SI}.Offset(244), ECX)
XORL(Mem{Base: SI}.Offset(248), R8L)
XORL(Mem{Base: SI}.Offset(252), R9L)
MOVL(EDX, Mem{Base: DI}.Offset(240))
MOVL(ECX, Mem{Base: DI}.Offset(244))
MOVL(R8L, Mem{Base: DI}.Offset(248))
MOVL(R9L, Mem{Base: DI}.Offset(252))
MOVQ(Mem{Base: R12}.Offset(352), R9)
SUBQ(U32(256), R9)
ADDQ(U32(256), RSI)
ADDQ(U32(256), RDI)
CMPQ(R9, U32(256))
JAE(LabelRef("BYTESATLEAST256"))
CMPQ(R9, Imm(0))
JBE(LabelRef("DONE"))
}
func BYTESBETWEEN1AND255() {
Label("BYTESBETWEEN1AND255")
CMPQ(R9, Imm(64))
JAE(LabelRef("NOCOPY"))
MOVQ(RDI, RDX)
LEAQ(Mem{Base: R12}.Offset(360), RDI)
MOVQ(R9, RCX)
// Hack to get Avo to emit:
// REP; MOVSB
Instruction(&ir.Instruction{Opcode: "REP; MOVSB"})
LEAQ(Mem{Base: R12}.Offset(360), RDI)
LEAQ(Mem{Base: R12}.Offset(360), RSI)
}
func NOCOPY() {
Label("NOCOPY")
MOVQ(R9, Mem{Base: R12}.Offset(352))
MOVOA(Mem{Base: R12}.Offset(48), X0)
MOVOA(Mem{Base: R12}.Offset(0), X1)
MOVOA(Mem{Base: R12}.Offset(16), X2)
MOVOA(Mem{Base: R12}.Offset(32), X3)
MOVOA(X1, X4)
MOVQ(U32(20), RCX)
}
func MAINLOOP2() {
Label("MAINLOOP2")
PADDL(X0, X4)
MOVOA(X0, X5)
MOVOA(X4, X6)
PSLLL(Imm(7), X4)
PSRLL(Imm(25), X6)
PXOR(X4, X3)
PXOR(X6, X3)
PADDL(X3, X5)
MOVOA(X3, X4)
MOVOA(X5, X6)
PSLLL(Imm(9), X5)
PSRLL(Imm(23), X6)
PXOR(X5, X2)
PSHUFL(Imm(0x93), X3, X3)
PXOR(X6, X2)
PADDL(X2, X4)
MOVOA(X2, X5)
MOVOA(X4, X6)
PSLLL(Imm(13), X4)
PSRLL(Imm(19), X6)
PXOR(X4, X1)
PSHUFL(Imm(0x4E), X2, X2)
PXOR(X6, X1)
PADDL(X1, X5)
MOVOA(X3, X4)
MOVOA(X5, X6)
PSLLL(Imm(18), X5)
PSRLL(Imm(14), X6)
PXOR(X5, X0)
PSHUFL(Imm(0x39), X1, X1)
PXOR(X6, X0)
PADDL(X0, X4)
MOVOA(X0, X5)
MOVOA(X4, X6)
PSLLL(Imm(7), X4)
PSRLL(Imm(25), X6)
PXOR(X4, X1)
PXOR(X6, X1)
PADDL(X1, X5)
MOVOA(X1, X4)
MOVOA(X5, X6)
PSLLL(Imm(9), X5)
PSRLL(Imm(23), X6)
PXOR(X5, X2)
PSHUFL(Imm(0x93), X1, X1)
PXOR(X6, X2)
PADDL(X2, X4)
MOVOA(X2, X5)
MOVOA(X4, X6)
PSLLL(Imm(13), X4)
PSRLL(Imm(19), X6)
PXOR(X4, X3)
PSHUFL(Imm(0x4E), X2, X2)
PXOR(X6, X3)
PADDL(X3, X5)
MOVOA(X1, X4)
MOVOA(X5, X6)
PSLLL(Imm(18), X5)
PSRLL(Imm(14), X6)
PXOR(X5, X0)
PSHUFL(Imm(0x39), X3, X3)
PXOR(X6, X0)
PADDL(X0, X4)
MOVOA(X0, X5)
MOVOA(X4, X6)
PSLLL(Imm(7), X4)
PSRLL(Imm(25), X6)
PXOR(X4, X3)
PXOR(X6, X3)
PADDL(X3, X5)
MOVOA(X3, X4)
MOVOA(X5, X6)
PSLLL(Imm(9), X5)
PSRLL(Imm(23), X6)
PXOR(X5, X2)
PSHUFL(Imm(0x93), X3, X3)
PXOR(X6, X2)
PADDL(X2, X4)
MOVOA(X2, X5)
MOVOA(X4, X6)
PSLLL(Imm(13), X4)
PSRLL(Imm(19), X6)
PXOR(X4, X1)
PSHUFL(Imm(0x4E), X2, X2)
PXOR(X6, X1)
PADDL(X1, X5)
MOVOA(X3, X4)
MOVOA(X5, X6)
PSLLL(Imm(18), X5)
PSRLL(Imm(14), X6)
PXOR(X5, X0)
PSHUFL(Imm(0x39), X1, X1)
PXOR(X6, X0)
PADDL(X0, X4)
MOVOA(X0, X5)
MOVOA(X4, X6)
PSLLL(Imm(7), X4)
PSRLL(Imm(25), X6)
PXOR(X4, X1)
PXOR(X6, X1)
PADDL(X1, X5)
MOVOA(X1, X4)
MOVOA(X5, X6)
PSLLL(Imm(9), X5)
PSRLL(Imm(23), X6)
PXOR(X5, X2)
PSHUFL(Imm(0x93), X1, X1)
PXOR(X6, X2)
PADDL(X2, X4)
MOVOA(X2, X5)
MOVOA(X4, X6)
PSLLL(Imm(13), X4)
PSRLL(Imm(19), X6)
PXOR(X4, X3)
PSHUFL(Imm(0x4E), X2, X2)
PXOR(X6, X3)
SUBQ(Imm(4), RCX)
PADDL(X3, X5)
MOVOA(X1, X4)
MOVOA(X5, X6)
PSLLL(Imm(18), X5)
PXOR(X7, X7)
PSRLL(Imm(14), X6)
PXOR(X5, X0)
PSHUFL(Imm(0x39), X3, X3)
PXOR(X6, X0)
JA(LabelRef("MAINLOOP2"))
PADDL(Mem{Base: R12}.Offset(48), X0)
PADDL(Mem{Base: R12}.Offset(0), X1)
PADDL(Mem{Base: R12}.Offset(16), X2)
PADDL(Mem{Base: R12}.Offset(32), X3)
MOVD(X0, ECX)
MOVD(X1, R8)
MOVD(X2, R9)
MOVD(X3, EAX)
PSHUFL(Imm(0x39), X0, X0)
PSHUFL(Imm(0x39), X1, X1)
PSHUFL(Imm(0x39), X2, X2)
PSHUFL(Imm(0x39), X3, X3)
XORL(Mem{Base: SI}.Offset(0), ECX)
XORL(Mem{Base: SI}.Offset(48), R8L)
XORL(Mem{Base: SI}.Offset(32), R9L)
XORL(Mem{Base: SI}.Offset(16), EAX)
MOVL(ECX, Mem{Base: DI}.Offset(0))
MOVL(R8L, Mem{Base: DI}.Offset(48))
MOVL(R9L, Mem{Base: DI}.Offset(32))
MOVL(EAX, Mem{Base: DI}.Offset(16))
MOVD(X0, ECX)
MOVD(X1, R8)
MOVD(X2, R9)
MOVD(X3, EAX)
PSHUFL(Imm(0x39), X0, X0)
PSHUFL(Imm(0x39), X1, X1)
PSHUFL(Imm(0x39), X2, X2)
PSHUFL(Imm(0x39), X3, X3)
XORL(Mem{Base: SI}.Offset(20), ECX)
XORL(Mem{Base: SI}.Offset(4), R8L)
XORL(Mem{Base: SI}.Offset(52), R9L)
XORL(Mem{Base: SI}.Offset(36), EAX)
MOVL(ECX, Mem{Base: DI}.Offset(20))
MOVL(R8L, Mem{Base: DI}.Offset(4))
MOVL(R9L, Mem{Base: DI}.Offset(52))
MOVL(EAX, Mem{Base: DI}.Offset(36))
MOVD(X0, ECX)
MOVD(X1, R8)
MOVD(X2, R9)
MOVD(X3, EAX)
PSHUFL(Imm(0x39), X0, X0)
PSHUFL(Imm(0x39), X1, X1)
PSHUFL(Imm(0x39), X2, X2)
PSHUFL(Imm(0x39), X3, X3)
XORL(Mem{Base: SI}.Offset(40), ECX)
XORL(Mem{Base: SI}.Offset(24), R8L)
XORL(Mem{Base: SI}.Offset(8), R9L)
XORL(Mem{Base: SI}.Offset(56), EAX)
MOVL(ECX, Mem{Base: DI}.Offset(40))
MOVL(R8L, Mem{Base: DI}.Offset(24))
MOVL(R9L, Mem{Base: DI}.Offset(8))
MOVL(EAX, Mem{Base: DI}.Offset(56))
MOVD(X0, ECX)
MOVD(X1, R8)
MOVD(X2, R9)
MOVD(X3, EAX)
XORL(Mem{Base: SI}.Offset(60), ECX)
XORL(Mem{Base: SI}.Offset(44), R8L)
XORL(Mem{Base: SI}.Offset(28), R9L)
XORL(Mem{Base: SI}.Offset(12), EAX)
MOVL(ECX, Mem{Base: DI}.Offset(60))
MOVL(R8L, Mem{Base: DI}.Offset(44))
MOVL(R9L, Mem{Base: DI}.Offset(28))
MOVL(EAX, Mem{Base: DI}.Offset(12))
MOVQ(Mem{Base: R12}.Offset(352), R9)
MOVL(Mem{Base: R12}.Offset(16), ECX)
MOVL(Mem{Base: R12}.Offset(36), R8L)
ADDQ(Imm(1), RCX)
SHLQ(Imm(32), R8)
ADDQ(R8, RCX)
MOVQ(RCX, R8)
SHRQ(Imm(32), R8)
MOVL(ECX, Mem{Base: R12}.Offset(16))
MOVL(R8L, Mem{Base: R12}.Offset(36))
CMPQ(R9, Imm(64))
JA(LabelRef("BYTESATLEAST65"))
JAE(LabelRef("BYTESATLEAST64"))
MOVQ(RDI, RSI)
MOVQ(RDX, RDI)
MOVQ(R9, RCX)
// Hack to get Avo to emit:
// REP; MOVSB
Instruction(&ir.Instruction{Opcode: "REP; MOVSB"})
}
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -4,12 +4,12 @@ go 1.22
require (
github.com/mmcloughlin/avo v0.6.0
golang.org/x/crypto v0.25.0
golang.org/x/crypto v0.33.0
)
require (
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/tools v0.23.0 // indirect
)
+4 -4
View File
@@ -1,12 +1,12 @@
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+4
View File
@@ -5,6 +5,10 @@
// Package sha3 implements the SHA-3 fixed-output-length hash functions and
// the SHAKE variable-output-length hash functions defined by FIPS-202.
//
// All types in this package also implement [encoding.BinaryMarshaler],
// [encoding.BinaryAppender] and [encoding.BinaryUnmarshaler] to marshal and
// unmarshal the internal state of the hash.
//
// Both types of hash function use the "sponge" construction and the Keccak
// permutation. For a detailed specification see http://keccak.noekeon.org/
//
+25 -6
View File
@@ -48,33 +48,52 @@ func init() {
crypto.RegisterHash(crypto.SHA3_512, New512)
}
const (
dsbyteSHA3 = 0b00000110
dsbyteKeccak = 0b00000001
dsbyteShake = 0b00011111
dsbyteCShake = 0b00000100
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
rateK256 = (1600 - 256) / 8
rateK448 = (1600 - 448) / 8
rateK512 = (1600 - 512) / 8
rateK768 = (1600 - 768) / 8
rateK1024 = (1600 - 1024) / 8
)
func new224Generic() *state {
return &state{rate: 144, outputLen: 28, dsbyte: 0x06}
return &state{rate: rateK448, outputLen: 28, dsbyte: dsbyteSHA3}
}
func new256Generic() *state {
return &state{rate: 136, outputLen: 32, dsbyte: 0x06}
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteSHA3}
}
func new384Generic() *state {
return &state{rate: 104, outputLen: 48, dsbyte: 0x06}
return &state{rate: rateK768, outputLen: 48, dsbyte: dsbyteSHA3}
}
func new512Generic() *state {
return &state{rate: 72, outputLen: 64, dsbyte: 0x06}
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteSHA3}
}
// NewLegacyKeccak256 creates a new Keccak-256 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New256 instead.
func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
func NewLegacyKeccak256() hash.Hash {
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
}
// NewLegacyKeccak512 creates a new Keccak-512 hash.
//
// Only use this function if you require compatibility with an existing cryptosystem
// that uses non-standard padding. All other users should use New512 instead.
func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} }
func NewLegacyKeccak512() hash.Hash {
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
}
// Sum224 returns the SHA3-224 digest of the data.
func Sum224(data []byte) (digest [28]byte) {
+122 -63
View File
@@ -4,6 +4,15 @@
package sha3
import (
"crypto/subtle"
"encoding/binary"
"errors"
"unsafe"
"golang.org/x/sys/cpu"
)
// spongeDirection indicates the direction bytes are flowing through the sponge.
type spongeDirection int
@@ -14,16 +23,13 @@ const (
spongeSqueezing
)
const (
// maxRate is the maximum size of the internal buffer. SHAKE-256
// currently needs the largest buffer.
maxRate = 168
)
type state struct {
// Generic sponge components.
a [25]uint64 // main state of the hash
rate int // the number of bytes of state to use
a [1600 / 8]byte // main state of the hash
// a[n:rate] is the buffer. If absorbing, it's the remaining space to XOR
// into before running the permutation. If squeezing, it's the remaining
// output to produce before running the permutation.
n, rate int
// dsbyte contains the "domain separation" bits and the first bit of
// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
@@ -39,10 +45,6 @@ type state struct {
// Extendable-Output Functions (May 2014)"
dsbyte byte
i, n int // storage[i:n] is the buffer, i is only used while squeezing
storage [maxRate]byte
// Specific to SHA-3 and SHAKE.
outputLen int // the default output size in bytes
state spongeDirection // whether the sponge is absorbing or squeezing
}
@@ -61,7 +63,7 @@ func (d *state) Reset() {
d.a[i] = 0
}
d.state = spongeAbsorbing
d.i, d.n = 0, 0
d.n = 0
}
func (d *state) clone() *state {
@@ -69,22 +71,25 @@ func (d *state) clone() *state {
return &ret
}
// permute applies the KeccakF-1600 permutation. It handles
// any input-output buffering.
// permute applies the KeccakF-1600 permutation.
func (d *state) permute() {
switch d.state {
case spongeAbsorbing:
// If we're absorbing, we need to xor the input into the state
// before applying the permutation.
xorIn(d, d.storage[:d.rate])
d.n = 0
keccakF1600(&d.a)
case spongeSqueezing:
// If we're squeezing, we need to apply the permutation before
// copying more output.
keccakF1600(&d.a)
d.i = 0
copyOut(d, d.storage[:d.rate])
var a *[25]uint64
if cpu.IsBigEndian {
a = new([25]uint64)
for i := range a {
a[i] = binary.LittleEndian.Uint64(d.a[i*8:])
}
} else {
a = (*[25]uint64)(unsafe.Pointer(&d.a))
}
keccakF1600(a)
d.n = 0
if cpu.IsBigEndian {
for i := range a {
binary.LittleEndian.PutUint64(d.a[i*8:], a[i])
}
}
}
@@ -92,53 +97,36 @@ func (d *state) permute() {
// the multi-bitrate 10..1 padding rule, and permutes the state.
func (d *state) padAndPermute() {
// Pad with this instance's domain-separator bits. We know that there's
// at least one byte of space in d.buf because, if it were full,
// at least one byte of space in the sponge because, if it were full,
// permute would have been called to empty it. dsbyte also contains the
// first one bit for the padding. See the comment in the state struct.
d.storage[d.n] = d.dsbyte
d.n++
for d.n < d.rate {
d.storage[d.n] = 0
d.n++
}
d.a[d.n] ^= d.dsbyte
// This adds the final one bit for the padding. Because of the way that
// bits are numbered from the LSB upwards, the final bit is the MSB of
// the last byte.
d.storage[d.rate-1] ^= 0x80
d.a[d.rate-1] ^= 0x80
// Apply the permutation
d.permute()
d.state = spongeSqueezing
d.n = d.rate
copyOut(d, d.storage[:d.rate])
}
// Write absorbs more data into the hash's state. It panics if any
// output has already been read.
func (d *state) Write(p []byte) (written int, err error) {
func (d *state) Write(p []byte) (n int, err error) {
if d.state != spongeAbsorbing {
panic("sha3: Write after Read")
}
written = len(p)
n = len(p)
for len(p) > 0 {
if d.n == 0 && len(p) >= d.rate {
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
xorIn(d, p[:d.rate])
p = p[d.rate:]
keccakF1600(&d.a)
} else {
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
todo := d.rate - d.n
if todo > len(p) {
todo = len(p)
}
d.n += copy(d.storage[d.n:], p[:todo])
p = p[todo:]
x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p)
d.n += x
p = p[x:]
// If the sponge is full, apply the permutation.
if d.n == d.rate {
d.permute()
}
// If the sponge is full, apply the permutation.
if d.n == d.rate {
d.permute()
}
}
@@ -156,14 +144,14 @@ func (d *state) Read(out []byte) (n int, err error) {
// Now, do the squeezing.
for len(out) > 0 {
n := copy(out, d.storage[d.i:d.n])
d.i += n
out = out[n:]
// Apply the permutation if we've squeezed the sponge dry.
if d.i == d.rate {
if d.n == d.rate {
d.permute()
}
x := copy(out, d.a[d.n:d.rate])
d.n += x
out = out[x:]
}
return
@@ -183,3 +171,74 @@ func (d *state) Sum(in []byte) []byte {
dup.Read(hash)
return append(in, hash...)
}
const (
magicSHA3 = "sha\x08"
magicShake = "sha\x09"
magicCShake = "sha\x0a"
magicKeccak = "sha\x0b"
// magic || rate || main state || n || sponge direction
marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1
)
func (d *state) MarshalBinary() ([]byte, error) {
return d.AppendBinary(make([]byte, 0, marshaledSize))
}
func (d *state) AppendBinary(b []byte) ([]byte, error) {
switch d.dsbyte {
case dsbyteSHA3:
b = append(b, magicSHA3...)
case dsbyteShake:
b = append(b, magicShake...)
case dsbyteCShake:
b = append(b, magicCShake...)
case dsbyteKeccak:
b = append(b, magicKeccak...)
default:
panic("unknown dsbyte")
}
// rate is at most 168, and n is at most rate.
b = append(b, byte(d.rate))
b = append(b, d.a[:]...)
b = append(b, byte(d.n), byte(d.state))
return b, nil
}
func (d *state) UnmarshalBinary(b []byte) error {
if len(b) != marshaledSize {
return errors.New("sha3: invalid hash state")
}
magic := string(b[:len(magicSHA3)])
b = b[len(magicSHA3):]
switch {
case magic == magicSHA3 && d.dsbyte == dsbyteSHA3:
case magic == magicShake && d.dsbyte == dsbyteShake:
case magic == magicCShake && d.dsbyte == dsbyteCShake:
case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
default:
return errors.New("sha3: invalid hash state identifier")
}
rate := int(b[0])
b = b[1:]
if rate != d.rate {
return errors.New("sha3: invalid hash state function")
}
copy(d.a[:], b)
b = b[len(d.a):]
n, state := int(b[0]), spongeDirection(b[1])
if n > d.rate {
return errors.New("sha3: invalid hash state")
}
d.n = n
if state != spongeAbsorbing && state != spongeSqueezing {
return errors.New("sha3: invalid hash state")
}
d.state = state
return nil
}
+149
View File
@@ -13,10 +13,12 @@ package sha3
import (
"bytes"
"compress/flate"
"encoding"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"io"
"math/rand"
"os"
"strings"
@@ -375,6 +377,153 @@ func TestClone(t *testing.T) {
}
}
func TestCSHAKEAccumulated(t *testing.T) {
// Generated with pycryptodome@3.20.0
//
// from Crypto.Hash import cSHAKE128
// rng = cSHAKE128.new()
// acc = cSHAKE128.new()
// for n in range(200):
// N = rng.read(n)
// for s in range(200):
// S = rng.read(s)
// c = cSHAKE128.cSHAKE_XOF(data=None, custom=S, capacity=256, function=N)
// c.update(rng.read(100))
// acc.update(c.read(200))
// c = cSHAKE128.cSHAKE_XOF(data=None, custom=S, capacity=256, function=N)
// c.update(rng.read(168))
// acc.update(c.read(200))
// c = cSHAKE128.cSHAKE_XOF(data=None, custom=S, capacity=256, function=N)
// c.update(rng.read(200))
// acc.update(c.read(200))
// print(acc.read(32).hex())
//
// and with @noble/hashes@v1.5.0
//
// import { bytesToHex } from "@noble/hashes/utils";
// import { cshake128 } from "@noble/hashes/sha3-addons";
// const rng = cshake128.create();
// const acc = cshake128.create();
// for (let n = 0; n < 200; n++) {
// const N = rng.xof(n);
// for (let s = 0; s < 200; s++) {
// const S = rng.xof(s);
// let c = cshake128.create({ NISTfn: N, personalization: S });
// c.update(rng.xof(100));
// acc.update(c.xof(200));
// c = cshake128.create({ NISTfn: N, personalization: S });
// c.update(rng.xof(168));
// acc.update(c.xof(200));
// c = cshake128.create({ NISTfn: N, personalization: S });
// c.update(rng.xof(200));
// acc.update(c.xof(200));
// }
// }
// console.log(bytesToHex(acc.xof(32)));
//
t.Run("cSHAKE128", func(t *testing.T) {
testCSHAKEAccumulated(t, NewCShake128, rateK256,
"bb14f8657c6ec5403d0b0e2ef3d3393497e9d3b1a9a9e8e6c81dbaa5fd809252")
})
t.Run("cSHAKE256", func(t *testing.T) {
testCSHAKEAccumulated(t, NewCShake256, rateK512,
"0baaf9250c6e25f0c14ea5c7f9bfde54c8a922c8276437db28f3895bdf6eeeef")
})
}
func testCSHAKEAccumulated(t *testing.T, newCShake func(N, S []byte) ShakeHash, rate int64, exp string) {
rnd := newCShake(nil, nil)
acc := newCShake(nil, nil)
for n := 0; n < 200; n++ {
N := make([]byte, n)
rnd.Read(N)
for s := 0; s < 200; s++ {
S := make([]byte, s)
rnd.Read(S)
c := newCShake(N, S)
io.CopyN(c, rnd, 100 /* < rate */)
io.CopyN(acc, c, 200)
c.Reset()
io.CopyN(c, rnd, rate)
io.CopyN(acc, c, 200)
c.Reset()
io.CopyN(c, rnd, 200 /* > rate */)
io.CopyN(acc, c, 200)
}
}
if got := hex.EncodeToString(acc.Sum(nil)[:32]); got != exp {
t.Errorf("got %s, want %s", got, exp)
}
}
func TestCSHAKELargeS(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
// See https://go.dev/issue/66232.
const s = (1<<32)/8 + 1000 // s * 8 > 2^32
S := make([]byte, s)
rnd := NewShake128()
rnd.Read(S)
c := NewCShake128(nil, S)
io.CopyN(c, rnd, 1000)
// Generated with pycryptodome@3.20.0
//
// from Crypto.Hash import cSHAKE128
// rng = cSHAKE128.new()
// S = rng.read(536871912)
// c = cSHAKE128.new(custom=S)
// c.update(rng.read(1000))
// print(c.read(32).hex())
//
exp := "2cb9f237767e98f2614b8779cf096a52da9b3a849280bbddec820771ae529cf0"
if got := hex.EncodeToString(c.Sum(nil)); got != exp {
t.Errorf("got %s, want %s", got, exp)
}
}
func TestMarshalUnmarshal(t *testing.T) {
t.Run("SHA3-224", func(t *testing.T) { testMarshalUnmarshal(t, New224()) })
t.Run("SHA3-256", func(t *testing.T) { testMarshalUnmarshal(t, New256()) })
t.Run("SHA3-384", func(t *testing.T) { testMarshalUnmarshal(t, New384()) })
t.Run("SHA3-512", func(t *testing.T) { testMarshalUnmarshal(t, New512()) })
t.Run("SHAKE128", func(t *testing.T) { testMarshalUnmarshal(t, NewShake128()) })
t.Run("SHAKE256", func(t *testing.T) { testMarshalUnmarshal(t, NewShake256()) })
t.Run("cSHAKE128", func(t *testing.T) { testMarshalUnmarshal(t, NewCShake128([]byte("N"), []byte("S"))) })
t.Run("cSHAKE256", func(t *testing.T) { testMarshalUnmarshal(t, NewCShake256([]byte("N"), []byte("S"))) })
t.Run("Keccak-256", func(t *testing.T) { testMarshalUnmarshal(t, NewLegacyKeccak256()) })
t.Run("Keccak-512", func(t *testing.T) { testMarshalUnmarshal(t, NewLegacyKeccak512()) })
}
// TODO(filippo): move this to crypto/internal/cryptotest.
func testMarshalUnmarshal(t *testing.T, h hash.Hash) {
buf := make([]byte, 200)
rand.Read(buf)
n := rand.Intn(200)
h.Write(buf)
want := h.Sum(nil)
h.Reset()
h.Write(buf[:n])
b, err := h.(encoding.BinaryMarshaler).MarshalBinary()
if err != nil {
t.Errorf("MarshalBinary: %v", err)
}
h.Write(bytes.Repeat([]byte{0}, 200))
if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary(b); err != nil {
t.Errorf("UnmarshalBinary: %v", err)
}
h.Write(buf[n:])
got := h.Sum(nil)
if !bytes.Equal(got, want) {
t.Errorf("got %x, want %x", got, want)
}
}
// BenchmarkPermutationFunction measures the speed of the permutation function
// with no input data.
func BenchmarkPermutationFunction(b *testing.B) {
+53 -34
View File
@@ -16,9 +16,12 @@ package sha3
// [2] https://doi.org/10.6028/NIST.SP.800-185
import (
"bytes"
"encoding/binary"
"errors"
"hash"
"io"
"math/bits"
)
// ShakeHash defines the interface to hash functions that support
@@ -50,44 +53,36 @@ type cshakeState struct {
initBlock []byte
}
// Consts for configuring initial SHA-3 state
const (
dsbyteShake = 0x1f
dsbyteCShake = 0x04
rate128 = 168
rate256 = 136
)
func bytepad(input []byte, w int) []byte {
// leftEncode always returns max 9 bytes
buf := make([]byte, 0, 9+len(input)+w)
buf = append(buf, leftEncode(uint64(w))...)
buf = append(buf, input...)
padlen := w - (len(buf) % w)
return append(buf, make([]byte, padlen)...)
func bytepad(data []byte, rate int) []byte {
out := make([]byte, 0, 9+len(data)+rate-1)
out = append(out, leftEncode(uint64(rate))...)
out = append(out, data...)
if padlen := rate - len(out)%rate; padlen < rate {
out = append(out, make([]byte, padlen)...)
}
return out
}
func leftEncode(value uint64) []byte {
var b [9]byte
binary.BigEndian.PutUint64(b[1:], value)
// Trim all but last leading zero bytes
i := byte(1)
for i < 8 && b[i] == 0 {
i++
func leftEncode(x uint64) []byte {
// Let n be the smallest positive integer for which 2^(8n) > x.
n := (bits.Len64(x) + 7) / 8
if n == 0 {
n = 1
}
// Prepend number of encoded bytes
b[i-1] = 9 - i
return b[i-1:]
// Return n || x with n as a byte and x an n bytes in big-endian order.
b := make([]byte, 9)
binary.BigEndian.PutUint64(b[1:], x)
b = b[9-n-1:]
b[0] = byte(n)
return b
}
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
// leftEncode returns max 9 bytes
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
c.initBlock = make([]byte, 0, 9+len(N)+9+len(S)) // leftEncode returns max 9 bytes
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...)
c.initBlock = append(c.initBlock, N...)
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...)
c.initBlock = append(c.initBlock, S...)
c.Write(bytepad(c.initBlock, c.rate))
return &c
@@ -111,6 +106,30 @@ func (c *state) Clone() ShakeHash {
return c.clone()
}
func (c *cshakeState) MarshalBinary() ([]byte, error) {
return c.AppendBinary(make([]byte, 0, marshaledSize+len(c.initBlock)))
}
func (c *cshakeState) AppendBinary(b []byte) ([]byte, error) {
b, err := c.state.AppendBinary(b)
if err != nil {
return nil, err
}
b = append(b, c.initBlock...)
return b, nil
}
func (c *cshakeState) UnmarshalBinary(b []byte) error {
if len(b) <= marshaledSize {
return errors.New("sha3: invalid hash state")
}
if err := c.state.UnmarshalBinary(b[:marshaledSize]); err != nil {
return err
}
c.initBlock = bytes.Clone(b[marshaledSize:])
return nil
}
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
// Its generic security strength is 128 bits against all attacks if at
// least 32 bytes of its output are used.
@@ -126,11 +145,11 @@ func NewShake256() ShakeHash {
}
func newShake128Generic() *state {
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
return &state{rate: rateK256, outputLen: 32, dsbyte: dsbyteShake}
}
func newShake256Generic() *state {
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
return &state{rate: rateK512, outputLen: 64, dsbyte: dsbyteShake}
}
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
@@ -143,7 +162,7 @@ func NewCShake128(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake128()
}
return newCShake(N, S, rate128, 32, dsbyteCShake)
return newCShake(N, S, rateK256, 32, dsbyteCShake)
}
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
@@ -156,7 +175,7 @@ func NewCShake256(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake256()
}
return newCShake(N, S, rate256, 64, dsbyteCShake)
return newCShake(N, S, rateK512, 64, dsbyteCShake)
}
// ShakeSum128 writes an arbitrary-length digest of data into hash.
-40
View File
@@ -1,40 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sha3
import (
"crypto/subtle"
"encoding/binary"
"unsafe"
"golang.org/x/sys/cpu"
)
// xorIn xors the bytes in buf into the state.
func xorIn(d *state, buf []byte) {
if cpu.IsBigEndian {
for i := 0; len(buf) >= 8; i++ {
a := binary.LittleEndian.Uint64(buf)
d.a[i] ^= a
buf = buf[8:]
}
} else {
ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a))
subtle.XORBytes(ab[:], ab[:], buf)
}
}
// copyOut copies uint64s to a byte buffer.
func copyOut(d *state, b []byte) {
if cpu.IsBigEndian {
for i := 0; len(b) >= 8; i++ {
binary.LittleEndian.PutUint64(b, d.a[i])
b = b[8:]
}
} else {
ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a))
copy(b, ab[:])
}
}
+9
View File
@@ -175,6 +175,15 @@ func (r *keyring) Add(key AddedKey) error {
p.expire = &t
}
// If we already have a Signer with the same public key, replace it with the
// new one.
for idx, k := range r.keys {
if bytes.Equal(k.signer.PublicKey().Marshal(), p.signer.PublicKey().Marshal()) {
r.keys[idx] = p
return nil
}
}
r.keys = append(r.keys, p)
return nil
+46
View File
@@ -29,6 +29,10 @@ func validateListedKeys(t *testing.T, a Agent, expectedKeys []string) {
t.Fatalf("failed to list keys: %v", err)
return
}
if len(listedKeys) != len(expectedKeys) {
t.Fatalf("expeted %d key, got %d", len(expectedKeys), len(listedKeys))
return
}
actualKeys := make(map[string]bool)
for _, key := range listedKeys {
actualKeys[key.Comment] = true
@@ -74,3 +78,45 @@ func TestKeyringAddingAndRemoving(t *testing.T) {
}
validateListedKeys(t, k, []string{})
}
func TestAddDuplicateKey(t *testing.T) {
keyNames := []string{"rsa", "user"}
k := NewKeyring()
for _, keyName := range keyNames {
addTestKey(t, k, keyName)
}
validateListedKeys(t, k, keyNames)
// Add the keys again.
for _, keyName := range keyNames {
addTestKey(t, k, keyName)
}
validateListedKeys(t, k, keyNames)
// Add an existing key with an updated comment.
keyName := keyNames[0]
addedKey := AddedKey{
PrivateKey: testPrivateKeys[keyName],
Comment: "comment updated",
}
err := k.Add(addedKey)
if err != nil {
t.Fatalf("failed to add key %q: %v", keyName, err)
}
// Check the that key is found and the comment was updated.
keys, err := k.List()
if err != nil {
t.Fatalf("failed to list keys: %v", err)
}
if len(keys) != len(keyNames) {
t.Fatalf("expected %d keys, got %d", len(keyNames), len(keys))
}
isFound := false
for _, key := range keys {
if key.Comment == addedKey.Comment {
isFound = true
}
}
if !isFound {
t.Fatal("key with the updated comment not found")
}
}
+6 -8
View File
@@ -15,14 +15,12 @@ import (
"reflect"
"testing"
"time"
"golang.org/x/crypto/ssh/testdata"
)
// Cert generated by ssh-keygen 6.0p1 Debian-4.
// % ssh-keygen -s ca-key -I test user-key
const exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=`
func TestParseCert(t *testing.T) {
authKeyBytes := []byte(exampleSSHCert)
authKeyBytes := bytes.TrimSuffix(testdata.SSHCertificates["rsa"], []byte(" host.example.com\n"))
key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes)
if err != nil {
@@ -103,7 +101,7 @@ func TestParseCertWithOptions(t *testing.T) {
}
func TestValidateCert(t *testing.T) {
key, _, _, _, err := ParseAuthorizedKey([]byte(exampleSSHCert))
key, _, _, _, err := ParseAuthorizedKey(testdata.SSHCertificates["rsa-user-testcertificate"])
if err != nil {
t.Fatalf("ParseAuthorizedKey: %v", err)
}
@@ -116,7 +114,7 @@ func TestValidateCert(t *testing.T) {
return bytes.Equal(k.Marshal(), validCert.SignatureKey.Marshal())
}
if err := checker.CheckCert("user", validCert); err != nil {
if err := checker.CheckCert("testcertificate", validCert); err != nil {
t.Errorf("Unable to validate certificate: %v", err)
}
invalidCert := &Certificate{
@@ -125,7 +123,7 @@ func TestValidateCert(t *testing.T) {
ValidBefore: CertTimeInfinity,
Signature: &Signature{},
}
if err := checker.CheckCert("user", invalidCert); err == nil {
if err := checker.CheckCert("testcertificate", invalidCert); err == nil {
t.Error("Invalid cert signature passed validation")
}
}
+5
View File
@@ -555,6 +555,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
}
gotMsgExtInfo := false
gotUserAuthInfoRequest := false
for {
packet, err := c.readPacket()
if err != nil {
@@ -585,6 +586,9 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
if msg.PartialSuccess {
return authPartialSuccess, msg.Methods, nil
}
if !gotUserAuthInfoRequest {
return authFailure, msg.Methods, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
}
return authFailure, msg.Methods, nil
case msgUserAuthSuccess:
return authSuccess, nil, nil
@@ -596,6 +600,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
if err := Unmarshal(packet, &msg); err != nil {
return authFailure, nil, err
}
gotUserAuthInfoRequest = true
// Manually unpack the prompt/echo pairs.
rest := msg.Prompts
+108 -8
View File
@@ -38,7 +38,7 @@ func tryAuth(t *testing.T, config *ClientConfig) error {
return err
}
// tryAuth runs a handshake with a given config against an SSH server
// tryAuthWithGSSAPIWithMICConfig runs a handshake with a given config against an SSH server
// with a given GSSAPIWithMICConfig and config serverConfig. Returns both client and server side errors.
func tryAuthWithGSSAPIWithMICConfig(t *testing.T, clientConfig *ClientConfig, gssAPIWithMICConfig *GSSAPIWithMICConfig) error {
err, _ := tryAuthBothSides(t, clientConfig, gssAPIWithMICConfig)
@@ -641,17 +641,28 @@ func TestClientAuthMaxAuthTries(t *testing.T) {
defer c1.Close()
defer c2.Close()
go newServer(c1, serverConfig)
_, _, _, err = NewClientConn(c2, "", clientConfig)
if tries > 2 {
if err == nil {
errCh := make(chan error, 1)
go func() {
_, err := newServer(c1, serverConfig)
errCh <- err
}()
_, _, _, cliErr := NewClientConn(c2, "", clientConfig)
srvErr := <-errCh
if tries > serverConfig.MaxAuthTries {
if cliErr == nil {
t.Fatalf("client: got no error, want %s", expectedErr)
} else if err.Error() != expectedErr.Error() {
} else if cliErr.Error() != expectedErr.Error() {
t.Fatalf("client: got %s, want %s", err, expectedErr)
}
var authErr *ServerAuthError
if !errors.As(srvErr, &authErr) {
t.Errorf("expected ServerAuthError, got: %v", srvErr)
}
} else {
if err != nil {
t.Fatalf("client: got %s, want no error", err)
if cliErr != nil {
t.Fatalf("client: got %s, want no error", cliErr)
}
}
}
@@ -1282,3 +1293,92 @@ func TestCertAuthOpenSSHCompat(t *testing.T) {
t.Fatalf("unable to dial remote side: %s", err)
}
}
func TestKeyboardInteractiveAuthEarlyFail(t *testing.T) {
const maxAuthTries = 2
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
// Start testserver
serverConfig := &ServerConfig{
MaxAuthTries: maxAuthTries,
KeyboardInteractiveCallback: func(c ConnMetadata,
client KeyboardInteractiveChallenge) (*Permissions, error) {
// Fail keyboard-interactive authentication early before
// any prompt is sent to client.
return nil, errors.New("keyboard-interactive auth failed")
},
PasswordCallback: func(c ConnMetadata,
pass []byte) (*Permissions, error) {
if string(pass) == clientPassword {
return nil, nil
}
return nil, errors.New("password auth failed")
},
}
serverConfig.AddHostKey(testSigners["rsa"])
serverDone := make(chan struct{})
go func() {
defer func() { serverDone <- struct{}{} }()
conn, chans, reqs, err := NewServerConn(c2, serverConfig)
if err != nil {
return
}
_ = conn.Close()
discarderDone := make(chan struct{})
go func() {
defer func() { discarderDone <- struct{}{} }()
DiscardRequests(reqs)
}()
for newChannel := range chans {
newChannel.Reject(Prohibited,
"testserver not accepting requests")
}
<-discarderDone
}()
// Connect to testserver, expect KeyboardInteractive() to be not called,
// PasswordCallback() to be called and connection to succeed.
passwordCallbackCalled := false
clientConfig := &ClientConfig{
User: "testuser",
Auth: []AuthMethod{
RetryableAuthMethod(KeyboardInteractive(func(name,
instruction string, questions []string,
echos []bool) ([]string, error) {
t.Errorf("unexpected call to KeyboardInteractive()")
return []string{clientPassword}, nil
}), maxAuthTries),
RetryableAuthMethod(PasswordCallback(func() (secret string,
err error) {
t.Logf("PasswordCallback()")
passwordCallbackCalled = true
return clientPassword, nil
}), maxAuthTries),
},
HostKeyCallback: InsecureIgnoreHostKey(),
}
conn, _, _, err := NewClientConn(c1, "", clientConfig)
if err != nil {
t.Errorf("unexpected NewClientConn() error: %v", err)
}
if conn != nil {
conn.Close()
}
// Wait for server to finish.
<-serverDone
if !passwordCallbackCalled {
t.Errorf("expected PasswordCallback() to be called")
}
}
+50 -14
View File
@@ -5,7 +5,6 @@
package ssh
import (
"crypto/rand"
"errors"
"fmt"
"io"
@@ -25,6 +24,11 @@ const debugHandshake = false
// quickly.
const chanSize = 16
// maxPendingPackets sets the maximum number of packets to queue while waiting
// for KEX to complete. This limits the total pending data to maxPendingPackets
// * maxPacket bytes, which is ~16.8MB.
const maxPendingPackets = 64
// keyingTransport is a packet based transport that supports key
// changes. It need not be thread-safe. It should pass through
// msgNewKeys in both directions.
@@ -73,13 +77,22 @@ type handshakeTransport struct {
incoming chan []byte
readError error
mu sync.Mutex
writeError error
sentInitPacket []byte
sentInitMsg *kexInitMsg
pendingPackets [][]byte // Used when a key exchange is in progress.
mu sync.Mutex
// Condition for the above mutex. It is used to notify a completed key
// exchange or a write failure. Writes can wait for this condition while a
// key exchange is in progress.
writeCond *sync.Cond
writeError error
sentInitPacket []byte
sentInitMsg *kexInitMsg
// Used to queue writes when a key exchange is in progress. The length is
// limited by pendingPacketsSize. Once full, writes will block until the key
// exchange is completed or an error occurs. If not empty, it is emptied
// all at once when the key exchange is completed in kexLoop.
pendingPackets [][]byte
writePacketsLeft uint32
writeBytesLeft int64
userAuthComplete bool // whether the user authentication phase is complete
// If the read loop wants to schedule a kex, it pings this
// channel, and the write loop will send out a kex
@@ -133,6 +146,7 @@ func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion,
config: config,
}
t.writeCond = sync.NewCond(&t.mu)
t.resetReadThresholds()
t.resetWriteThresholds()
@@ -259,6 +273,7 @@ func (t *handshakeTransport) recordWriteError(err error) {
defer t.mu.Unlock()
if t.writeError == nil && err != nil {
t.writeError = err
t.writeCond.Broadcast()
}
}
@@ -362,6 +377,8 @@ write:
}
}
t.pendingPackets = t.pendingPackets[:0]
// Unblock writePacket if waiting for KEX.
t.writeCond.Broadcast()
t.mu.Unlock()
}
@@ -483,7 +500,7 @@ func (t *handshakeTransport) sendKexInit() error {
CompressionClientServer: supportedCompressions,
CompressionServerClient: supportedCompressions,
}
io.ReadFull(rand.Reader, msg.Cookie[:])
io.ReadFull(t.config.Rand, msg.Cookie[:])
// We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm,
// and possibly to add the ext-info extension algorithm. Since the slice may be the
@@ -552,26 +569,44 @@ func (t *handshakeTransport) sendKexInit() error {
return nil
}
var errSendBannerPhase = errors.New("ssh: SendAuthBanner outside of authentication phase")
func (t *handshakeTransport) writePacket(p []byte) error {
t.mu.Lock()
defer t.mu.Unlock()
switch p[0] {
case msgKexInit:
return errors.New("ssh: only handshakeTransport can send kexInit")
case msgNewKeys:
return errors.New("ssh: only handshakeTransport can send newKeys")
case msgUserAuthBanner:
if t.userAuthComplete {
return errSendBannerPhase
}
case msgUserAuthSuccess:
t.userAuthComplete = true
}
t.mu.Lock()
defer t.mu.Unlock()
if t.writeError != nil {
return t.writeError
}
if t.sentInitMsg != nil {
// Copy the packet so the writer can reuse the buffer.
cp := make([]byte, len(p))
copy(cp, p)
t.pendingPackets = append(t.pendingPackets, cp)
return nil
if len(t.pendingPackets) < maxPendingPackets {
// Copy the packet so the writer can reuse the buffer.
cp := make([]byte, len(p))
copy(cp, p)
t.pendingPackets = append(t.pendingPackets, cp)
return nil
}
for t.sentInitMsg != nil {
// Block and wait for KEX to complete or an error.
t.writeCond.Wait()
if t.writeError != nil {
return t.writeError
}
}
}
if t.writeBytesLeft > 0 {
@@ -588,6 +623,7 @@ func (t *handshakeTransport) writePacket(p []byte) error {
if err := t.pushPacket(p); err != nil {
t.writeError = err
t.writeCond.Broadcast()
}
return nil
+220
View File
@@ -539,6 +539,226 @@ func TestDisconnect(t *testing.T) {
}
}
type mockKeyingTransport struct {
packetConn
kexInitAllowed chan struct{}
kexInitSent chan struct{}
}
func (n *mockKeyingTransport) prepareKeyChange(*algorithms, *kexResult) error {
return nil
}
func (n *mockKeyingTransport) writePacket(packet []byte) error {
if packet[0] == msgKexInit {
<-n.kexInitAllowed
n.kexInitSent <- struct{}{}
}
return n.packetConn.writePacket(packet)
}
func (n *mockKeyingTransport) readPacket() ([]byte, error) {
return n.packetConn.readPacket()
}
func (n *mockKeyingTransport) setStrictMode() error { return nil }
func (n *mockKeyingTransport) setInitialKEXDone() {}
func TestHandshakePendingPacketsWait(t *testing.T) {
a, b := memPipe()
trS := &mockKeyingTransport{
packetConn: a,
kexInitAllowed: make(chan struct{}, 2),
kexInitSent: make(chan struct{}, 2),
}
// Allow the first KEX.
trS.kexInitAllowed <- struct{}{}
trC := &mockKeyingTransport{
packetConn: b,
kexInitAllowed: make(chan struct{}, 2),
kexInitSent: make(chan struct{}, 2),
}
// Allow the first KEX.
trC.kexInitAllowed <- struct{}{}
clientConf := &ClientConfig{
HostKeyCallback: InsecureIgnoreHostKey(),
}
clientConf.SetDefaults()
v := []byte("version")
client := newClientTransport(trC, v, v, clientConf, "addr", nil)
serverConf := &ServerConfig{}
serverConf.AddHostKey(testSigners["ecdsa"])
serverConf.AddHostKey(testSigners["rsa"])
serverConf.SetDefaults()
server := newServerTransport(trS, v, v, serverConf)
if err := server.waitSession(); err != nil {
t.Fatalf("server.waitSession: %v", err)
}
if err := client.waitSession(); err != nil {
t.Fatalf("client.waitSession: %v", err)
}
<-trC.kexInitSent
<-trS.kexInitSent
// Allow and request new KEX server side.
trS.kexInitAllowed <- struct{}{}
server.requestKeyExchange()
// Wait until the KEX init is sent.
<-trS.kexInitSent
// The client is not allowed to respond to the KEX, so writes will be
// blocked on the server side once the packets queue is full.
for i := 0; i < maxPendingPackets; i++ {
p := []byte{msgRequestSuccess, byte(i)}
if err := server.writePacket(p); err != nil {
t.Errorf("unexpected write error: %v", err)
}
}
// The packets queue is now full, the next write will block.
server.mu.Lock()
if len(server.pendingPackets) != maxPendingPackets {
t.Errorf("unexpected pending packets size; got: %d, want: %d", len(server.pendingPackets), maxPendingPackets)
}
server.mu.Unlock()
writeDone := make(chan struct{})
go func() {
defer close(writeDone)
p := []byte{msgRequestSuccess, byte(65)}
// This write will block until KEX completes.
err := server.writePacket(p)
if err != nil {
t.Errorf("unexpected write error: %v", err)
}
}()
// Consume packets on the client side
readDone := make(chan bool)
go func() {
defer close(readDone)
for {
if _, err := client.readPacket(); err != nil {
if err != io.EOF {
t.Errorf("unexpected read error: %v", err)
}
break
}
}
}()
// Allow the client to reply to the KEX and so unblock the write goroutine.
trC.kexInitAllowed <- struct{}{}
<-trC.kexInitSent
<-writeDone
// Close the client to unblock the read goroutine.
client.Close()
<-readDone
server.Close()
}
func TestHandshakePendingPacketsError(t *testing.T) {
a, b := memPipe()
trS := &mockKeyingTransport{
packetConn: a,
kexInitAllowed: make(chan struct{}, 2),
kexInitSent: make(chan struct{}, 2),
}
// Allow the first KEX.
trS.kexInitAllowed <- struct{}{}
trC := &mockKeyingTransport{
packetConn: b,
kexInitAllowed: make(chan struct{}, 2),
kexInitSent: make(chan struct{}, 2),
}
// Allow the first KEX.
trC.kexInitAllowed <- struct{}{}
clientConf := &ClientConfig{
HostKeyCallback: InsecureIgnoreHostKey(),
}
clientConf.SetDefaults()
v := []byte("version")
client := newClientTransport(trC, v, v, clientConf, "addr", nil)
serverConf := &ServerConfig{}
serverConf.AddHostKey(testSigners["ecdsa"])
serverConf.AddHostKey(testSigners["rsa"])
serverConf.SetDefaults()
server := newServerTransport(trS, v, v, serverConf)
if err := server.waitSession(); err != nil {
t.Fatalf("server.waitSession: %v", err)
}
if err := client.waitSession(); err != nil {
t.Fatalf("client.waitSession: %v", err)
}
<-trC.kexInitSent
<-trS.kexInitSent
// Allow and request new KEX server side.
trS.kexInitAllowed <- struct{}{}
server.requestKeyExchange()
// Wait until the KEX init is sent.
<-trS.kexInitSent
// The client is not allowed to respond to the KEX, so writes will be
// blocked on the server side once the packets queue is full.
for i := 0; i < maxPendingPackets; i++ {
p := []byte{msgRequestSuccess, byte(i)}
if err := server.writePacket(p); err != nil {
t.Errorf("unexpected write error: %v", err)
}
}
// The packets queue is now full, the next write will block.
writeDone := make(chan struct{})
go func() {
defer close(writeDone)
p := []byte{msgRequestSuccess, byte(65)}
// This write will block until KEX completes.
err := server.writePacket(p)
if err != io.EOF {
t.Errorf("unexpected write error: %v", err)
}
}()
// Consume packets on the client side
readDone := make(chan bool)
go func() {
defer close(readDone)
for {
if _, err := client.readPacket(); err != nil {
if err != io.EOF {
t.Errorf("unexpected read error: %v", err)
}
break
}
}
}()
// Close the server to unblock the write after an error
server.Close()
<-writeDone
// Unblock the pending write and close the client to unblock the read
// goroutine.
trC.kexInitAllowed <- struct{}{}
client.Close()
<-readDone
}
func TestHandshakeRekeyDefault(t *testing.T) {
clientConf := &ClientConfig{
Config: Config{
+12 -26
View File
@@ -302,8 +302,8 @@ func (k *KnownKey) String() string {
// applications can offer an interactive prompt to the user.
type KeyError struct {
// Want holds the accepted host keys. For each key algorithm,
// there can be one hostkey. If Want is empty, the host is
// unknown. If Want is non-empty, there was a mismatch, which
// there can be multiple hostkeys. If Want is empty, the host
// is unknown. If Want is non-empty, there was a mismatch, which
// can signify a MITM attack.
Want []KnownKey
}
@@ -358,34 +358,20 @@ func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
// is just a key for the IP address, but not for the
// hostname?
// Algorithm => key.
knownKeys := map[string]KnownKey{}
keyErr := &KeyError{}
for _, l := range db.lines {
if l.match(a) {
typ := l.knownKey.Key.Type()
if _, ok := knownKeys[typ]; !ok {
knownKeys[typ] = l.knownKey
}
if !l.match(a) {
continue
}
keyErr.Want = append(keyErr.Want, l.knownKey)
if keyEq(l.knownKey.Key, remoteKey) {
return nil
}
}
keyErr := &KeyError{}
for _, v := range knownKeys {
keyErr.Want = append(keyErr.Want, v)
}
// Unknown remote host.
if len(knownKeys) == 0 {
return keyErr
}
// If the remote host starts using a different, unknown key type, we
// also interpret that as a mismatch.
if known, ok := knownKeys[remoteKey.Type()]; !ok || !keyEq(known.Key, remoteKey) {
return keyErr
}
return nil
return keyErr
}
// The Read function parses file contents.
+13 -11
View File
@@ -201,17 +201,6 @@ func TestHostNamePrecedence(t *testing.T) {
}
}
func TestDBOrderingPrecedenceKeyType(t *testing.T) {
str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr)
db := testDB(t, str)
if err := db.check("server.org:22", testAddr, alternateEdKey); err == nil {
t.Errorf("check succeeded")
} else if _, ok := err.(*KeyError); !ok {
t.Errorf("got %T, want *KeyError", err)
}
}
func TestNegate(t *testing.T) {
str := fmt.Sprintf("%s,!server.org %s", testAddr, edKeyStr)
db := testDB(t, str)
@@ -354,3 +343,16 @@ func TestHashedHostkeyCheck(t *testing.T) {
t.Errorf("got error %v, want %v", got, want)
}
}
func TestIssue36126(t *testing.T) {
str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr)
db := testDB(t, str)
if err := db.check("server.org:22", testAddr, edKey); err != nil {
t.Errorf("should have passed the check, got %v", err)
}
if err := db.check("server.org:22", testAddr, alternateEdKey); err != nil {
t.Errorf("should have passed the check, got %v", err)
}
}
+2
View File
@@ -818,6 +818,8 @@ func decode(packet []byte) (interface{}, error) {
return new(userAuthSuccessMsg), nil
case msgUserAuthFailure:
msg = new(userAuthFailureMsg)
case msgUserAuthBanner:
msg = new(userAuthBannerMsg)
case msgUserAuthPubKeyOk:
msg = new(userAuthPubKeyOkMsg)
case msgGlobalRequest:
+56
View File
@@ -206,6 +206,62 @@ func TestMarshalMultiTag(t *testing.T) {
}
}
func TestDecode(t *testing.T) {
rnd := rand.New(rand.NewSource(0))
kexInit := new(kexInitMsg).Generate(rnd, 10).Interface()
kexDHInit := new(kexDHInitMsg).Generate(rnd, 10).Interface()
kexDHReply := new(kexDHReplyMsg)
kexDHReply.Y = randomInt(rnd)
// Note: userAuthSuccessMsg can't be tested directly since it
// doesn't have a field for sshtype. So it's tested separately
// at the end.
decodeMessageTypes := []interface{}{
new(disconnectMsg),
new(serviceRequestMsg),
new(serviceAcceptMsg),
new(extInfoMsg),
kexInit,
kexDHInit,
kexDHReply,
new(userAuthRequestMsg),
new(userAuthFailureMsg),
new(userAuthBannerMsg),
new(userAuthPubKeyOkMsg),
new(globalRequestMsg),
new(globalRequestSuccessMsg),
new(globalRequestFailureMsg),
new(channelOpenMsg),
new(channelDataMsg),
new(channelOpenConfirmMsg),
new(channelOpenFailureMsg),
new(windowAdjustMsg),
new(channelEOFMsg),
new(channelCloseMsg),
new(channelRequestMsg),
new(channelRequestSuccessMsg),
new(channelRequestFailureMsg),
new(userAuthGSSAPIToken),
new(userAuthGSSAPIMIC),
new(userAuthGSSAPIErrTok),
new(userAuthGSSAPIError),
}
for _, msg := range decodeMessageTypes {
decoded, err := decode(Marshal(msg))
if err != nil {
t.Errorf("error decoding %T", msg)
} else if reflect.TypeOf(msg) != reflect.TypeOf(decoded) {
t.Errorf("error decoding %T, unexpected %T", msg, decoded)
}
}
userAuthSuccess, err := decode([]byte{msgUserAuthSuccess})
if err != nil {
t.Errorf("error decoding userAuthSuccessMsg")
} else if reflect.TypeOf(userAuthSuccess) != reflect.TypeOf((*userAuthSuccessMsg)(nil)) {
t.Errorf("error decoding userAuthSuccessMsg, unexpected %T", userAuthSuccess)
}
}
func randomBytes(out []byte, rand *rand.Rand) {
for i := 0; i < len(out); i++ {
out[i] = byte(rand.Int31())
+50 -19
View File
@@ -59,6 +59,27 @@ type GSSAPIWithMICConfig struct {
Server GSSAPIServer
}
// SendAuthBanner implements [ServerPreAuthConn].
func (s *connection) SendAuthBanner(msg string) error {
return s.transport.writePacket(Marshal(&userAuthBannerMsg{
Message: msg,
}))
}
func (*connection) unexportedMethodForFutureProofing() {}
// ServerPreAuthConn is the interface available on an incoming server
// connection before authentication has completed.
type ServerPreAuthConn interface {
unexportedMethodForFutureProofing() // permits growing ServerPreAuthConn safely later, ala testing.TB
ConnMetadata
// SendAuthBanner sends a banner message to the client.
// It returns an error once the authentication phase has ended.
SendAuthBanner(string) error
}
// ServerConfig holds server specific configuration data.
type ServerConfig struct {
// Config contains configuration shared between client and server.
@@ -118,6 +139,12 @@ type ServerConfig struct {
// attempts.
AuthLogCallback func(conn ConnMetadata, method string, err error)
// PreAuthConnCallback, if non-nil, is called upon receiving a new connection
// before any authentication has started. The provided ServerPreAuthConn
// can be used at any time before authentication is complete, including
// after this callback has returned.
PreAuthConnCallback func(ServerPreAuthConn)
// ServerVersion is the version identification string to announce in
// the public handshake.
// If empty, a reasonable default is used.
@@ -149,7 +176,7 @@ func (s *ServerConfig) AddHostKey(key Signer) {
}
// cachedPubKey contains the results of querying whether a public key is
// acceptable for a user.
// acceptable for a user. This is a FIFO cache.
type cachedPubKey struct {
user string
pubKeyData []byte
@@ -157,7 +184,13 @@ type cachedPubKey struct {
perms *Permissions
}
const maxCachedPubKeys = 16
// maxCachedPubKeys is the number of cache entries we store.
//
// Due to consistent misuse of the PublicKeyCallback API, we have reduced this
// to 1, such that the only key in the cache is the most recently seen one. This
// forces the behavior that the last call to PublicKeyCallback will always be
// with the key that is used for authentication.
const maxCachedPubKeys = 1
// pubKeyCache caches tests for public keys. Since SSH clients
// will query whether a public key is acceptable before attempting to
@@ -179,9 +212,10 @@ func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
// add adds the given tuple to the cache.
func (c *pubKeyCache) add(candidate cachedPubKey) {
if len(c.keys) < maxCachedPubKeys {
c.keys = append(c.keys, candidate)
if len(c.keys) >= maxCachedPubKeys {
c.keys = c.keys[1:]
}
c.keys = append(c.keys, candidate)
}
// ServerConn is an authenticated SSH connection, as seen from the
@@ -481,6 +515,10 @@ func (b *BannerError) Error() string {
}
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
if config.PreAuthConnCallback != nil {
config.PreAuthConnCallback(s)
}
sessionID := s.transport.getSessionID()
var cache pubKeyCache
var perms *Permissions
@@ -488,7 +526,7 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err
authFailures := 0
noneAuthCount := 0
var authErrs []error
var displayedBanner bool
var calledBannerCallback bool
partialSuccessReturned := false
// Set the initial authentication callbacks from the config. They can be
// changed if a PartialSuccessError is returned.
@@ -510,8 +548,8 @@ userAuthLoop:
if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
return nil, err
}
return nil, discMsg
authErrs = append(authErrs, discMsg)
return nil, &ServerAuthError{Errors: authErrs}
}
var userAuthReq userAuthRequestMsg
@@ -535,14 +573,10 @@ userAuthLoop:
s.user = userAuthReq.User
if !displayedBanner && config.BannerCallback != nil {
displayedBanner = true
msg := config.BannerCallback(s)
if msg != "" {
bannerMsg := &userAuthBannerMsg{
Message: msg,
}
if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
if !calledBannerCallback && config.BannerCallback != nil {
calledBannerCallback = true
if msg := config.BannerCallback(s); msg != "" {
if err := s.SendAuthBanner(msg); err != nil {
return nil, err
}
}
@@ -755,10 +789,7 @@ userAuthLoop:
var bannerErr *BannerError
if errors.As(authErr, &bannerErr) {
if bannerErr.Message != "" {
bannerMsg := &userAuthBannerMsg{
Message: bannerErr.Message,
}
if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
if err := s.SendAuthBanner(bannerErr.Message); err != nil {
return nil, err
}
}
+135
View File
@@ -5,6 +5,7 @@
package ssh
import (
"bytes"
"errors"
"fmt"
"io"
@@ -299,6 +300,140 @@ func TestBannerError(t *testing.T) {
}
}
func TestPublicKeyCallbackLastSeen(t *testing.T) {
var lastSeenKey PublicKey
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
serverConf := &ServerConfig{
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
lastSeenKey = key
fmt.Printf("seen %#v\n", key)
if _, ok := key.(*dsaPublicKey); !ok {
return nil, errors.New("nope")
}
return nil, nil
},
}
serverConf.AddHostKey(testSigners["ecdsap256"])
done := make(chan struct{})
go func() {
defer close(done)
NewServerConn(c1, serverConf)
}()
clientConf := ClientConfig{
User: "user",
Auth: []AuthMethod{
PublicKeys(testSigners["rsa"], testSigners["dsa"], testSigners["ed25519"]),
},
HostKeyCallback: InsecureIgnoreHostKey(),
}
_, _, _, err = NewClientConn(c2, "", &clientConf)
if err != nil {
t.Fatal(err)
}
<-done
expectedPublicKey := testSigners["dsa"].PublicKey().Marshal()
lastSeenMarshalled := lastSeenKey.Marshal()
if !bytes.Equal(lastSeenMarshalled, expectedPublicKey) {
t.Errorf("unexpected key: got %#v, want %#v", lastSeenKey, testSigners["dsa"].PublicKey())
}
}
func TestPreAuthConnAndBanners(t *testing.T) {
testDone := make(chan struct{})
defer close(testDone)
authConnc := make(chan ServerPreAuthConn, 1)
serverConfig := &ServerConfig{
PreAuthConnCallback: func(c ServerPreAuthConn) {
t.Logf("got ServerPreAuthConn: %v", c)
authConnc <- c // for use later in the test
for _, s := range []string{"hello1", "hello2"} {
if err := c.SendAuthBanner(s); err != nil {
t.Errorf("failed to send banner %q: %v", s, err)
}
}
// Now start a goroutine to spam SendAuthBanner in hopes
// of hitting a race.
go func() {
for {
select {
case <-testDone:
return
default:
if err := c.SendAuthBanner("attempted-race"); err != nil && err != errSendBannerPhase {
t.Errorf("unexpected error from SendAuthBanner: %v", err)
}
time.Sleep(5 * time.Millisecond)
}
}
}()
},
NoClientAuth: true,
NoClientAuthCallback: func(ConnMetadata) (*Permissions, error) {
t.Logf("got NoClientAuthCallback")
return &Permissions{}, nil
},
}
serverConfig.AddHostKey(testSigners["rsa"])
var banners []string
clientConfig := &ClientConfig{
User: "test",
HostKeyCallback: InsecureIgnoreHostKey(),
BannerCallback: func(msg string) error {
if msg != "attempted-race" {
banners = append(banners, msg)
}
return nil
},
}
c1, c2, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
defer c1.Close()
defer c2.Close()
go newServer(c1, serverConfig)
c, _, _, err := NewClientConn(c2, "", clientConfig)
if err != nil {
t.Fatalf("client connection failed: %v", err)
}
defer c.Close()
wantBanners := []string{
"hello1",
"hello2",
}
if !reflect.DeepEqual(banners, wantBanners) {
t.Errorf("got banners:\n%q\nwant banners:\n%q", banners, wantBanners)
}
// Now that we're authenticated, verify that use of SendBanner
// is an error.
var bc ServerPreAuthConn
select {
case bc = <-authConnc:
default:
t.Fatal("expected ServerPreAuthConn")
}
if err := bc.SendAuthBanner("wrong-phase"); err == nil {
t.Error("unexpected success of SendAuthBanner after authentication")
} else if err != errSendBannerPhase {
t.Errorf("unexpected error: %v; want %v", err, errSendBannerPhase)
}
}
type markerConn struct {
closed uint32
used uint32
+1 -1
View File
@@ -459,7 +459,7 @@ func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel
return nil, err
}
go DiscardRequests(in)
return ch, err
return ch, nil
}
type tcpChan struct {
+1142 -576
View File
File diff suppressed because it is too large Load Diff
+13 -4
View File
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.20
// Package fallback embeds a set of fallback X.509 trusted roots in the
// application by automatically invoking [x509.SetFallbackRoots]. This allows
// the application to work correctly even if the operating system does not
@@ -24,8 +22,19 @@ import "crypto/x509"
func init() {
p := x509.NewCertPool()
for _, c := range bundle {
p.AddCert(c)
for _, c := range parsedCertificates {
if len(c.constraints) == 0 {
p.AddCert(c.cert)
} else {
p.AddCertWithConstraint(c.cert, func(chain []*x509.Certificate) error {
for _, constraint := range c.constraints {
if err := constraint(chain); err != nil {
return err
}
}
return nil
})
}
}
x509.SetFallbackRoots(p)
}
+1 -1
View File
@@ -1,3 +1,3 @@
module golang.org/x/crypto/x509roots/fallback
go 1.20
go 1.23.0
+73 -28
View File
@@ -21,46 +21,77 @@ import (
"net/http"
"os"
"sort"
"time"
"golang.org/x/crypto/x509roots/nss"
)
const tmpl = `// Code generated by gen_fallback_bundle.go; DO NOT EDIT.
//go:build go1.20
package fallback
import "crypto/x509"
import "encoding/pem"
import (
"crypto/x509"
"encoding/pem"
"fmt"
"time"
)
func mustParse(b []byte) []*x509.Certificate {
var roots []*x509.Certificate
for len(b) > 0 {
var block *pem.Block
block, b = pem.Decode(b)
type unparsedCertificate struct {
cn string
sha256Hash string
pem string
// possible constraints
distrustAfter string
}
type parsedCertificate struct {
cert *x509.Certificate
constraints []func([]*x509.Certificate) error
}
func mustParse(unparsedCerts []unparsedCertificate) []parsedCertificate {
var b []parsedCertificate
for _, unparsed := range unparsedCerts {
block, rest := pem.Decode([]byte(unparsed.pem))
if block == nil {
break
panic(fmt.Sprintf("unexpected nil PEM block for %q", unparsed.cn))
}
if len(rest) != 0 {
panic(fmt.Sprintf("unexpected trailing data in PEM for %q", unparsed.cn))
}
if block.Type != "CERTIFICATE" {
panic("unexpected PEM block type: " + block.Type)
panic(fmt.Sprintf("unexpected PEM block type for %q: %s", unparsed.cn, block.Type))
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
panic(err)
}
roots = append(roots, cert)
parsed := parsedCertificate{cert: cert}
// parse possible constraints, this should check all fields of unparsedCertificate.
if unparsed.distrustAfter != "" {
distrustAfter, err := time.Parse(time.RFC3339, unparsed.distrustAfter)
if err != nil {
panic(fmt.Sprintf("failed to parse distrustAfter %q: %s", unparsed.distrustAfter, err))
}
parsed.constraints = append(parsed.constraints, func(chain []*x509.Certificate) error {
for _, c := range chain {
if c.NotBefore.After(distrustAfter) {
return fmt.Errorf("certificate issued after distrust-after date %q", distrustAfter)
}
}
return nil
})
}
b = append(b, parsed)
}
return roots
return b
}
var bundle = mustParse([]byte(pemRoots))
// Format of the PEM list is:
// * Subject common name
// * SHA256 hash
// * PEM block
var parsedCertificates = mustParse(unparsedCertificates)
var unparsedCertificates = []unparsedCertificate{
`
var (
@@ -124,19 +155,33 @@ func main() {
b := new(bytes.Buffer)
b.WriteString(tmpl)
fmt.Fprintln(b, "const pemRoots = `")
for _, c := range certs {
if len(c.Constraints) > 0 {
// Until the constrained roots API lands, skip anything that has any
// additional constraints. Once that API is available, we can add
// build constraints that support both the current version and the
// new version.
var constraints []string
var skip bool
for _, constraint := range c.Constraints {
switch t := constraint.(type) {
case nss.DistrustAfter:
constraints = append(constraints, fmt.Sprintf("distrustAfter: \"%s\",", time.Time(t).Format(time.RFC3339)))
default:
// If we encounter any constraints we don't support, skip the certificate.
skip = true
break
}
}
if skip {
continue
}
fmt.Fprintf(b, "# %s\n# %x\n", c.X509.Subject.String(), sha256.Sum256(c.X509.Raw))
pem.Encode(b, &pem.Block{Type: "CERTIFICATE", Bytes: c.X509.Raw})
fmt.Fprintf(b, "{\ncn: %q,\nsha256Hash: \"%x\",\npem: `%s`,\n",
c.X509.Subject.String(),
sha256.Sum256(c.X509.Raw),
string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: c.X509.Raw})),
)
for _, constraint := range constraints {
fmt.Fprintln(b, constraint)
}
fmt.Fprintln(b, "},")
}
fmt.Fprintln(b, "`")
fmt.Fprintln(b, "}")
formatted, err := format.Source(b.Bytes())
if err != nil {