chore(deps): update module golang.org/x/crypto to v0.27.0 #6

Merged
kekskurse merged 1 commit from renovate/golang.org-x-crypto-0.x into main 2024-09-14 01:35:19 +00:00
386 changed files with 11678 additions and 6350 deletions

4
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/rs/zerolog v1.33.0 github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.27.4 github.com/urfave/cli/v2 v2.27.4
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.27.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@ -22,5 +22,5 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/sys v0.13.0 // indirect golang.org/x/sys v0.25.0 // indirect
) )

4
go.sum
View file

@ -54,6 +54,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@ -74,6 +76,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

4
vendor/golang.org/x/crypto/LICENSE generated vendored
View file

@ -1,4 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved. Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the in the documentation and/or other materials provided with the
distribution. distribution.
* Neither the name of Google Inc. nor the names of its * Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.

View file

@ -11,7 +11,7 @@
// Deprecated: any new system should use AES (from crypto/aes, if necessary in // Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from // an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305). // golang.org/x/crypto/chacha20poly1305).
package blowfish // import "golang.org/x/crypto/blowfish" package blowfish
// The code is a port of Bruce Schneier's C implementation. // The code is a port of Bruce Schneier's C implementation.
// See https://www.schneier.com/blowfish.html. // See https://www.schneier.com/blowfish.html.

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20 package chacha20

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego //go:build (!arm64 && !s390x && !ppc64le) || !gc || purego
// +build !arm64,!s390x,!ppc64le !gc purego
package chacha20 package chacha20

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20 package chacha20

View file

@ -20,7 +20,6 @@
// due to the calling conventions and initialization of constants. // due to the calling conventions and initialization of constants.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"
@ -34,6 +33,9 @@
#define CONSTBASE R16 #define CONSTBASE R16
#define BLOCKS R17 #define BLOCKS R17
// for VPERMXOR
#define MASK R18
DATA consts<>+0x00(SB)/8, $0x3320646e61707865 DATA consts<>+0x00(SB)/8, $0x3320646e61707865
DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 DATA consts<>+0x08(SB)/8, $0x6b20657479622d32
DATA consts<>+0x10(SB)/8, $0x0000000000000001 DATA consts<>+0x10(SB)/8, $0x0000000000000001
@ -54,7 +56,11 @@ DATA consts<>+0x80(SB)/8, $0x6b2065746b206574
DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 DATA consts<>+0x88(SB)/8, $0x6b2065746b206574
DATA consts<>+0x90(SB)/8, $0x0000000100000000 DATA consts<>+0x90(SB)/8, $0x0000000100000000
DATA consts<>+0x98(SB)/8, $0x0000000300000002 DATA consts<>+0x98(SB)/8, $0x0000000300000002
GLOBL consts<>(SB), RODATA, $0xa0 DATA consts<>+0xa0(SB)/8, $0x5566774411223300
DATA consts<>+0xa8(SB)/8, $0xddeeffcc99aabb88
DATA consts<>+0xb0(SB)/8, $0x6677445522330011
DATA consts<>+0xb8(SB)/8, $0xeeffccddaabb8899
GLOBL consts<>(SB), RODATA, $0xc0
//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) //func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
@ -71,6 +77,9 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
MOVD $48, R10 MOVD $48, R10
MOVD $64, R11 MOVD $64, R11
SRD $6, LEN, BLOCKS SRD $6, LEN, BLOCKS
// for VPERMXOR
MOVD $consts<>+0xa0(SB), MASK
MOVD $16, R20
// V16 // V16
LXVW4X (CONSTBASE)(R0), VS48 LXVW4X (CONSTBASE)(R0), VS48
ADD $80,CONSTBASE ADD $80,CONSTBASE
@ -88,6 +97,10 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
// V28 // V28
LXVW4X (CONSTBASE)(R11), VS60 LXVW4X (CONSTBASE)(R11), VS60
// Load mask constants for VPERMXOR
LXVW4X (MASK)(R0), V20
LXVW4X (MASK)(R20), V21
// splat slot from V19 -> V26 // splat slot from V19 -> V26
VSPLTW $0, V19, V26 VSPLTW $0, V19, V26
@ -98,7 +111,7 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
MOVD $10, R14 MOVD $10, R14
MOVD R14, CTR MOVD R14, CTR
PCALIGN $16
loop_outer_vsx: loop_outer_vsx:
// V0, V1, V2, V3 // V0, V1, V2, V3
LXVW4X (R0)(CONSTBASE), VS32 LXVW4X (R0)(CONSTBASE), VS32
@ -129,22 +142,17 @@ loop_outer_vsx:
VSPLTISW $12, V28 VSPLTISW $12, V28
VSPLTISW $8, V29 VSPLTISW $8, V29
VSPLTISW $7, V30 VSPLTISW $7, V30
PCALIGN $16
loop_vsx: loop_vsx:
VADDUWM V0, V4, V0 VADDUWM V0, V4, V0
VADDUWM V1, V5, V1 VADDUWM V1, V5, V1
VADDUWM V2, V6, V2 VADDUWM V2, V6, V2
VADDUWM V3, V7, V3 VADDUWM V3, V7, V3
VXOR V12, V0, V12 VPERMXOR V12, V0, V21, V12
VXOR V13, V1, V13 VPERMXOR V13, V1, V21, V13
VXOR V14, V2, V14 VPERMXOR V14, V2, V21, V14
VXOR V15, V3, V15 VPERMXOR V15, V3, V21, V15
VRLW V12, V27, V12
VRLW V13, V27, V13
VRLW V14, V27, V14
VRLW V15, V27, V15
VADDUWM V8, V12, V8 VADDUWM V8, V12, V8
VADDUWM V9, V13, V9 VADDUWM V9, V13, V9
@ -166,15 +174,10 @@ loop_vsx:
VADDUWM V2, V6, V2 VADDUWM V2, V6, V2
VADDUWM V3, V7, V3 VADDUWM V3, V7, V3
VXOR V12, V0, V12 VPERMXOR V12, V0, V20, V12
VXOR V13, V1, V13 VPERMXOR V13, V1, V20, V13
VXOR V14, V2, V14 VPERMXOR V14, V2, V20, V14
VXOR V15, V3, V15 VPERMXOR V15, V3, V20, V15
VRLW V12, V29, V12
VRLW V13, V29, V13
VRLW V14, V29, V14
VRLW V15, V29, V15
VADDUWM V8, V12, V8 VADDUWM V8, V12, V8
VADDUWM V9, V13, V9 VADDUWM V9, V13, V9
@ -196,15 +199,10 @@ loop_vsx:
VADDUWM V2, V7, V2 VADDUWM V2, V7, V2
VADDUWM V3, V4, V3 VADDUWM V3, V4, V3
VXOR V15, V0, V15 VPERMXOR V15, V0, V21, V15
VXOR V12, V1, V12 VPERMXOR V12, V1, V21, V12
VXOR V13, V2, V13 VPERMXOR V13, V2, V21, V13
VXOR V14, V3, V14 VPERMXOR V14, V3, V21, V14
VRLW V15, V27, V15
VRLW V12, V27, V12
VRLW V13, V27, V13
VRLW V14, V27, V14
VADDUWM V10, V15, V10 VADDUWM V10, V15, V10
VADDUWM V11, V12, V11 VADDUWM V11, V12, V11
@ -226,15 +224,10 @@ loop_vsx:
VADDUWM V2, V7, V2 VADDUWM V2, V7, V2
VADDUWM V3, V4, V3 VADDUWM V3, V4, V3
VXOR V15, V0, V15 VPERMXOR V15, V0, V20, V15
VXOR V12, V1, V12 VPERMXOR V12, V1, V20, V12
VXOR V13, V2, V13 VPERMXOR V13, V2, V20, V13
VXOR V14, V3, V14 VPERMXOR V14, V3, V20, V14
VRLW V15, V29, V15
VRLW V12, V29, V12
VRLW V13, V29, V13
VRLW V14, V29, V14
VADDUWM V10, V15, V10 VADDUWM V10, V15, V10
VADDUWM V11, V12, V11 VADDUWM V11, V12, V11
@ -250,48 +243,48 @@ loop_vsx:
VRLW V6, V30, V6 VRLW V6, V30, V6
VRLW V7, V30, V7 VRLW V7, V30, V7
VRLW V4, V30, V4 VRLW V4, V30, V4
BC 16, LT, loop_vsx BDNZ loop_vsx
VADDUWM V12, V26, V12 VADDUWM V12, V26, V12
WORD $0x13600F8C // VMRGEW V0, V1, V27 VMRGEW V0, V1, V27
WORD $0x13821F8C // VMRGEW V2, V3, V28 VMRGEW V2, V3, V28
WORD $0x10000E8C // VMRGOW V0, V1, V0 VMRGOW V0, V1, V0
WORD $0x10421E8C // VMRGOW V2, V3, V2 VMRGOW V2, V3, V2
WORD $0x13A42F8C // VMRGEW V4, V5, V29 VMRGEW V4, V5, V29
WORD $0x13C63F8C // VMRGEW V6, V7, V30 VMRGEW V6, V7, V30
XXPERMDI VS32, VS34, $0, VS33 XXPERMDI VS32, VS34, $0, VS33
XXPERMDI VS32, VS34, $3, VS35 XXPERMDI VS32, VS34, $3, VS35
XXPERMDI VS59, VS60, $0, VS32 XXPERMDI VS59, VS60, $0, VS32
XXPERMDI VS59, VS60, $3, VS34 XXPERMDI VS59, VS60, $3, VS34
WORD $0x10842E8C // VMRGOW V4, V5, V4 VMRGOW V4, V5, V4
WORD $0x10C63E8C // VMRGOW V6, V7, V6 VMRGOW V6, V7, V6
WORD $0x13684F8C // VMRGEW V8, V9, V27 VMRGEW V8, V9, V27
WORD $0x138A5F8C // VMRGEW V10, V11, V28 VMRGEW V10, V11, V28
XXPERMDI VS36, VS38, $0, VS37 XXPERMDI VS36, VS38, $0, VS37
XXPERMDI VS36, VS38, $3, VS39 XXPERMDI VS36, VS38, $3, VS39
XXPERMDI VS61, VS62, $0, VS36 XXPERMDI VS61, VS62, $0, VS36
XXPERMDI VS61, VS62, $3, VS38 XXPERMDI VS61, VS62, $3, VS38
WORD $0x11084E8C // VMRGOW V8, V9, V8 VMRGOW V8, V9, V8
WORD $0x114A5E8C // VMRGOW V10, V11, V10 VMRGOW V10, V11, V10
WORD $0x13AC6F8C // VMRGEW V12, V13, V29 VMRGEW V12, V13, V29
WORD $0x13CE7F8C // VMRGEW V14, V15, V30 VMRGEW V14, V15, V30
XXPERMDI VS40, VS42, $0, VS41 XXPERMDI VS40, VS42, $0, VS41
XXPERMDI VS40, VS42, $3, VS43 XXPERMDI VS40, VS42, $3, VS43
XXPERMDI VS59, VS60, $0, VS40 XXPERMDI VS59, VS60, $0, VS40
XXPERMDI VS59, VS60, $3, VS42 XXPERMDI VS59, VS60, $3, VS42
WORD $0x118C6E8C // VMRGOW V12, V13, V12 VMRGOW V12, V13, V12
WORD $0x11CE7E8C // VMRGOW V14, V15, V14 VMRGOW V14, V15, V14
VSPLTISW $4, V27 VSPLTISW $4, V27
VADDUWM V26, V27, V26 VADDUWM V26, V27, V26
@ -432,7 +425,7 @@ tail_vsx:
ADD $-1, R11, R12 ADD $-1, R11, R12
ADD $-1, INP ADD $-1, INP
ADD $-1, OUT ADD $-1, OUT
PCALIGN $16
looptail_vsx: looptail_vsx:
// Copying the result to OUT // Copying the result to OUT
// in bytes. // in bytes.
@ -440,7 +433,7 @@ looptail_vsx:
MOVBZU 1(INP), TMP MOVBZU 1(INP), TMP
XOR KEY, TMP, KEY XOR KEY, TMP, KEY
MOVBU KEY, 1(OUT) MOVBU KEY, 1(OUT)
BC 16, LT, looptail_vsx BDNZ looptail_vsx
// Clear the stack values // Clear the stack values
STXVW4X VS48, (R11)(R0) STXVW4X VS48, (R11)(R0)

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20 package chacha20

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "go_asm.h" #include "go_asm.h"
#include "textflag.h" #include "textflag.h"

View file

@ -6,9 +6,11 @@
// performs scalar multiplication on the elliptic curve known as Curve25519. // performs scalar multiplication on the elliptic curve known as Curve25519.
// See RFC 7748. // See RFC 7748.
// //
// Starting in Go 1.20, this package is a wrapper for the X25519 implementation // This package is a wrapper for the X25519 implementation
// in the crypto/ecdh package. // in the crypto/ecdh package.
package curve25519 // import "golang.org/x/crypto/curve25519" package curve25519
import "crypto/ecdh"
// ScalarMult sets dst to the product scalar * point. // ScalarMult sets dst to the product scalar * point.
// //
@ -16,7 +18,13 @@ package curve25519 // import "golang.org/x/crypto/curve25519"
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which // zeroes, irrespective of the scalar. Instead, use the X25519 function, which
// will return an error. // will return an error.
func ScalarMult(dst, scalar, point *[32]byte) { func ScalarMult(dst, scalar, point *[32]byte) {
scalarMult(dst, scalar, point) if _, err := x25519(dst, scalar[:], point[:]); err != nil {
// The only error condition for x25519 when the inputs are 32 bytes long
// is if the output would have been the all-zero value.
for i := range dst {
dst[i] = 0
}
}
} }
// ScalarBaseMult sets dst to the product scalar * base where base is the // ScalarBaseMult sets dst to the product scalar * base where base is the
@ -25,7 +33,12 @@ func ScalarMult(dst, scalar, point *[32]byte) {
// It is recommended to use the X25519 function with Basepoint instead, as // It is recommended to use the X25519 function with Basepoint instead, as
// copying into fixed size arrays can lead to unexpected bugs. // copying into fixed size arrays can lead to unexpected bugs.
func ScalarBaseMult(dst, scalar *[32]byte) { func ScalarBaseMult(dst, scalar *[32]byte) {
scalarBaseMult(dst, scalar) curve := ecdh.X25519()
priv, err := curve.NewPrivateKey(scalar[:])
if err != nil {
panic("curve25519: internal error: scalarBaseMult was not 32 bytes")
}
copy(dst[:], priv.PublicKey().Bytes())
} }
const ( const (
@ -57,3 +70,21 @@ func X25519(scalar, point []byte) ([]byte, error) {
var dst [32]byte var dst [32]byte
return x25519(&dst, scalar, point) return x25519(&dst, scalar, point)
} }
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
curve := ecdh.X25519()
pub, err := curve.NewPublicKey(point)
if err != nil {
return nil, err
}
priv, err := curve.NewPrivateKey(scalar)
if err != nil {
return nil, err
}
out, err := priv.ECDH(pub)
if err != nil {
return nil, err
}
copy(dst[:], out)
return dst[:], nil
}

View file

@ -1,105 +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 !go1.20
package curve25519
import (
"crypto/subtle"
"errors"
"strconv"
"golang.org/x/crypto/curve25519/internal/field"
)
func scalarMult(dst, scalar, point *[32]byte) {
var e [32]byte
copy(e[:], scalar[:])
e[0] &= 248
e[31] &= 127
e[31] |= 64
var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
x1.SetBytes(point[:])
x2.One()
x3.Set(&x1)
z3.One()
swap := 0
for pos := 254; pos >= 0; pos-- {
b := e[pos/8] >> uint(pos&7)
b &= 1
swap ^= int(b)
x2.Swap(&x3, swap)
z2.Swap(&z3, swap)
swap = int(b)
tmp0.Subtract(&x3, &z3)
tmp1.Subtract(&x2, &z2)
x2.Add(&x2, &z2)
z2.Add(&x3, &z3)
z3.Multiply(&tmp0, &x2)
z2.Multiply(&z2, &tmp1)
tmp0.Square(&tmp1)
tmp1.Square(&x2)
x3.Add(&z3, &z2)
z2.Subtract(&z3, &z2)
x2.Multiply(&tmp1, &tmp0)
tmp1.Subtract(&tmp1, &tmp0)
z2.Square(&z2)
z3.Mult32(&tmp1, 121666)
x3.Square(&x3)
tmp0.Add(&tmp0, &z3)
z3.Multiply(&x1, &z2)
z2.Multiply(&tmp1, &tmp0)
}
x2.Swap(&x3, swap)
z2.Swap(&z3, swap)
z2.Invert(&z2)
x2.Multiply(&x2, &z2)
copy(dst[:], x2.Bytes())
}
func scalarBaseMult(dst, scalar *[32]byte) {
checkBasepoint()
scalarMult(dst, scalar, &basePoint)
}
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
var in [32]byte
if l := len(scalar); l != 32 {
return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32")
}
if l := len(point); l != 32 {
return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32")
}
copy(in[:], scalar)
if &point[0] == &Basepoint[0] {
scalarBaseMult(dst, &in)
} else {
var base, zero [32]byte
copy(base[:], point)
scalarMult(dst, &in, &base)
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
return nil, errors.New("bad input point: low order point")
}
}
return dst[:], nil
}
func checkBasepoint() {
if subtle.ConstantTimeCompare(Basepoint, []byte{
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}) != 1 {
panic("curve25519: global Basepoint value was modified")
}
}

View file

@ -1,46 +0,0 @@
// Copyright 2022 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 go1.20
package curve25519
import "crypto/ecdh"
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
curve := ecdh.X25519()
pub, err := curve.NewPublicKey(point)
if err != nil {
return nil, err
}
priv, err := curve.NewPrivateKey(scalar)
if err != nil {
return nil, err
}
out, err := priv.ECDH(pub)
if err != nil {
return nil, err
}
copy(dst[:], out)
return dst[:], nil
}
func scalarMult(dst, scalar, point *[32]byte) {
if _, err := x25519(dst, scalar[:], point[:]); err != nil {
// The only error condition for x25519 when the inputs are 32 bytes long
// is if the output would have been the all-zero value.
for i := range dst {
dst[i] = 0
}
}
}
func scalarBaseMult(dst, scalar *[32]byte) {
curve := ecdh.X25519()
priv, err := curve.NewPrivateKey(scalar[:])
if err != nil {
panic("curve25519: internal error: scalarBaseMult was not 32 bytes")
}
copy(dst[:], priv.PublicKey().Bytes())
}

View file

@ -1,7 +0,0 @@
This package is kept in sync with crypto/ed25519/internal/edwards25519/field in
the standard library.
If there are any changes in the standard library that need to be synced to this
package, run sync.sh. It will not overwrite any local changes made since the
previous sync, so it's ok to land changes in this package first, and then sync
to the standard library later.

View file

@ -1,416 +0,0 @@
// Copyright (c) 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package field implements fast arithmetic modulo 2^255-19.
package field
import (
"crypto/subtle"
"encoding/binary"
"math/bits"
)
// Element represents an element of the field GF(2^255-19). Note that this
// is not a cryptographically secure group, and should only be used to interact
// with edwards25519.Point coordinates.
//
// This type works similarly to math/big.Int, and all arguments and receivers
// are allowed to alias.
//
// The zero value is a valid zero element.
type Element struct {
// An element t represents the integer
// t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
//
// Between operations, all limbs are expected to be lower than 2^52.
l0 uint64
l1 uint64
l2 uint64
l3 uint64
l4 uint64
}
const maskLow51Bits uint64 = (1 << 51) - 1
var feZero = &Element{0, 0, 0, 0, 0}
// Zero sets v = 0, and returns v.
func (v *Element) Zero() *Element {
*v = *feZero
return v
}
var feOne = &Element{1, 0, 0, 0, 0}
// One sets v = 1, and returns v.
func (v *Element) One() *Element {
*v = *feOne
return v
}
// reduce reduces v modulo 2^255 - 19 and returns it.
func (v *Element) reduce() *Element {
v.carryPropagate()
// After the light reduction we now have a field element representation
// v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
c := (v.l0 + 19) >> 51
c = (v.l1 + c) >> 51
c = (v.l2 + c) >> 51
c = (v.l3 + c) >> 51
c = (v.l4 + c) >> 51
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
// effectively applying the reduction identity to the carry.
v.l0 += 19 * c
v.l1 += v.l0 >> 51
v.l0 = v.l0 & maskLow51Bits
v.l2 += v.l1 >> 51
v.l1 = v.l1 & maskLow51Bits
v.l3 += v.l2 >> 51
v.l2 = v.l2 & maskLow51Bits
v.l4 += v.l3 >> 51
v.l3 = v.l3 & maskLow51Bits
// no additional carry
v.l4 = v.l4 & maskLow51Bits
return v
}
// Add sets v = a + b, and returns v.
func (v *Element) Add(a, b *Element) *Element {
v.l0 = a.l0 + b.l0
v.l1 = a.l1 + b.l1
v.l2 = a.l2 + b.l2
v.l3 = a.l3 + b.l3
v.l4 = a.l4 + b.l4
// Using the generic implementation here is actually faster than the
// assembly. Probably because the body of this function is so simple that
// the compiler can figure out better optimizations by inlining the carry
// propagation. TODO
return v.carryPropagateGeneric()
}
// Subtract sets v = a - b, and returns v.
func (v *Element) Subtract(a, b *Element) *Element {
// We first add 2 * p, to guarantee the subtraction won't underflow, and
// then subtract b (which can be up to 2^255 + 2^13 * 19).
v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
return v.carryPropagate()
}
// Negate sets v = -a, and returns v.
func (v *Element) Negate(a *Element) *Element {
return v.Subtract(feZero, a)
}
// Invert sets v = 1/z mod p, and returns v.
//
// If z == 0, Invert returns v = 0.
func (v *Element) Invert(z *Element) *Element {
// Inversion is implemented as exponentiation with exponent p 2. It uses the
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
z2.Square(z) // 2
t.Square(&z2) // 4
t.Square(&t) // 8
z9.Multiply(&t, z) // 9
z11.Multiply(&z9, &z2) // 11
t.Square(&z11) // 22
z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
t.Square(&z2_5_0) // 2^6 - 2^1
for i := 0; i < 4; i++ {
t.Square(&t) // 2^10 - 2^5
}
z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
t.Square(&z2_10_0) // 2^11 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^20 - 2^10
}
z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
t.Square(&z2_20_0) // 2^21 - 2^1
for i := 0; i < 19; i++ {
t.Square(&t) // 2^40 - 2^20
}
t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
t.Square(&t) // 2^41 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^50 - 2^10
}
z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
t.Square(&z2_50_0) // 2^51 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^100 - 2^50
}
z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
t.Square(&z2_100_0) // 2^101 - 2^1
for i := 0; i < 99; i++ {
t.Square(&t) // 2^200 - 2^100
}
t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
t.Square(&t) // 2^201 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^250 - 2^50
}
t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
t.Square(&t) // 2^251 - 2^1
t.Square(&t) // 2^252 - 2^2
t.Square(&t) // 2^253 - 2^3
t.Square(&t) // 2^254 - 2^4
t.Square(&t) // 2^255 - 2^5
return v.Multiply(&t, &z11) // 2^255 - 21
}
// Set sets v = a, and returns v.
func (v *Element) Set(a *Element) *Element {
*v = *a
return v
}
// SetBytes sets v to x, which must be a 32-byte little-endian encoding.
//
// Consistent with RFC 7748, the most significant bit (the high bit of the
// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
// are accepted. Note that this is laxer than specified by RFC 8032.
func (v *Element) SetBytes(x []byte) *Element {
if len(x) != 32 {
panic("edwards25519: invalid field element input size")
}
// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
v.l0 = binary.LittleEndian.Uint64(x[0:8])
v.l0 &= maskLow51Bits
// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
v.l1 &= maskLow51Bits
// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
v.l2 &= maskLow51Bits
// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
v.l3 &= maskLow51Bits
// Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
// Note: not bytes 25:33, shift 4, to avoid overread.
v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
v.l4 &= maskLow51Bits
return v
}
// Bytes returns the canonical 32-byte little-endian encoding of v.
func (v *Element) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var out [32]byte
return v.bytes(&out)
}
func (v *Element) bytes(out *[32]byte) []byte {
t := *v
t.reduce()
var buf [8]byte
for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
bitsOffset := i * 51
binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
for i, bb := range buf {
off := bitsOffset/8 + i
if off >= len(out) {
break
}
out[off] |= bb
}
}
return out[:]
}
// Equal returns 1 if v and u are equal, and 0 otherwise.
func (v *Element) Equal(u *Element) int {
sa, sv := u.Bytes(), v.Bytes()
return subtle.ConstantTimeCompare(sa, sv)
}
// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
// Select sets v to a if cond == 1, and to b if cond == 0.
func (v *Element) Select(a, b *Element, cond int) *Element {
m := mask64Bits(cond)
v.l0 = (m & a.l0) | (^m & b.l0)
v.l1 = (m & a.l1) | (^m & b.l1)
v.l2 = (m & a.l2) | (^m & b.l2)
v.l3 = (m & a.l3) | (^m & b.l3)
v.l4 = (m & a.l4) | (^m & b.l4)
return v
}
// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
func (v *Element) Swap(u *Element, cond int) {
m := mask64Bits(cond)
t := m & (v.l0 ^ u.l0)
v.l0 ^= t
u.l0 ^= t
t = m & (v.l1 ^ u.l1)
v.l1 ^= t
u.l1 ^= t
t = m & (v.l2 ^ u.l2)
v.l2 ^= t
u.l2 ^= t
t = m & (v.l3 ^ u.l3)
v.l3 ^= t
u.l3 ^= t
t = m & (v.l4 ^ u.l4)
v.l4 ^= t
u.l4 ^= t
}
// IsNegative returns 1 if v is negative, and 0 otherwise.
func (v *Element) IsNegative() int {
return int(v.Bytes()[0] & 1)
}
// Absolute sets v to |u|, and returns v.
func (v *Element) Absolute(u *Element) *Element {
return v.Select(new(Element).Negate(u), u, u.IsNegative())
}
// Multiply sets v = x * y, and returns v.
func (v *Element) Multiply(x, y *Element) *Element {
feMul(v, x, y)
return v
}
// Square sets v = x * x, and returns v.
func (v *Element) Square(x *Element) *Element {
feSquare(v, x)
return v
}
// Mult32 sets v = x * y, and returns v.
func (v *Element) Mult32(x *Element, y uint32) *Element {
x0lo, x0hi := mul51(x.l0, y)
x1lo, x1hi := mul51(x.l1, y)
x2lo, x2hi := mul51(x.l2, y)
x3lo, x3hi := mul51(x.l3, y)
x4lo, x4hi := mul51(x.l4, y)
v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
v.l1 = x1lo + x0hi
v.l2 = x2lo + x1hi
v.l3 = x3lo + x2hi
v.l4 = x4lo + x3hi
// The hi portions are going to be only 32 bits, plus any previous excess,
// so we can skip the carry propagation.
return v
}
// mul51 returns lo + hi * 2⁵¹ = a * b.
func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
mh, ml := bits.Mul64(a, uint64(b))
lo = ml & maskLow51Bits
hi = (mh << 13) | (ml >> 51)
return
}
// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
func (v *Element) Pow22523(x *Element) *Element {
var t0, t1, t2 Element
t0.Square(x) // x^2
t1.Square(&t0) // x^4
t1.Square(&t1) // x^8
t1.Multiply(x, &t1) // x^9
t0.Multiply(&t0, &t1) // x^11
t0.Square(&t0) // x^22
t0.Multiply(&t1, &t0) // x^31
t1.Square(&t0) // x^62
for i := 1; i < 5; i++ { // x^992
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
t1.Square(&t0) // 2^11 - 2
for i := 1; i < 10; i++ { // 2^20 - 2^10
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^20 - 1
t2.Square(&t1) // 2^21 - 2
for i := 1; i < 20; i++ { // 2^40 - 2^20
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^40 - 1
t1.Square(&t1) // 2^41 - 2
for i := 1; i < 10; i++ { // 2^50 - 2^10
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^50 - 1
t1.Square(&t0) // 2^51 - 2
for i := 1; i < 50; i++ { // 2^100 - 2^50
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^100 - 1
t2.Square(&t1) // 2^101 - 2
for i := 1; i < 100; i++ { // 2^200 - 2^100
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^200 - 1
t1.Square(&t1) // 2^201 - 2
for i := 1; i < 50; i++ { // 2^250 - 2^50
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^250 - 1
t0.Square(&t0) // 2^251 - 2
t0.Square(&t0) // 2^252 - 4
return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
}
// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
var sqrtM1 = &Element{1718705420411056, 234908883556509,
2233514472574048, 2117202627021982, 765476049583133}
// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
//
// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
// and returns r and 0.
func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
var a, b Element
// r = (u * v3) * (u * v7)^((p-5)/8)
v2 := a.Square(v)
uv3 := b.Multiply(u, b.Multiply(v2, v))
uv7 := a.Multiply(uv3, a.Square(v2))
r.Multiply(uv3, r.Pow22523(uv7))
check := a.Multiply(v, a.Square(r)) // check = v * r^2
uNeg := b.Negate(u)
correctSignSqrt := check.Equal(u)
flippedSignSqrt := check.Equal(uNeg)
flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
r.Absolute(r) // Choose the nonnegative square root.
return r, correctSignSqrt | flippedSignSqrt
}

View file

@ -1,16 +0,0 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
package field
// feMul sets out = a * b. It works like feMulGeneric.
//
//go:noescape
func feMul(out *Element, a *Element, b *Element)
// feSquare sets out = a * a. It works like feSquareGeneric.
//
//go:noescape
func feSquare(out *Element, a *Element)

View file

@ -1,379 +0,0 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h"
// func feMul(out *Element, a *Element, b *Element)
TEXT ·feMul(SB), NOSPLIT, $0-24
MOVQ a+8(FP), CX
MOVQ b+16(FP), BX
// r0 = a0×b0
MOVQ (CX), AX
MULQ (BX)
MOVQ AX, DI
MOVQ DX, SI
// r0 += 19×a1×b4
MOVQ 8(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a2×b3
MOVQ 16(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a3×b2
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 16(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a4×b1
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 8(BX)
ADDQ AX, DI
ADCQ DX, SI
// r1 = a0×b1
MOVQ (CX), AX
MULQ 8(BX)
MOVQ AX, R9
MOVQ DX, R8
// r1 += a1×b0
MOVQ 8(CX), AX
MULQ (BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a2×b4
MOVQ 16(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a3×b3
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a4×b2
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 16(BX)
ADDQ AX, R9
ADCQ DX, R8
// r2 = a0×b2
MOVQ (CX), AX
MULQ 16(BX)
MOVQ AX, R11
MOVQ DX, R10
// r2 += a1×b1
MOVQ 8(CX), AX
MULQ 8(BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += a2×b0
MOVQ 16(CX), AX
MULQ (BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += 19×a3×b4
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += 19×a4×b3
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, R11
ADCQ DX, R10
// r3 = a0×b3
MOVQ (CX), AX
MULQ 24(BX)
MOVQ AX, R13
MOVQ DX, R12
// r3 += a1×b2
MOVQ 8(CX), AX
MULQ 16(BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += a2×b1
MOVQ 16(CX), AX
MULQ 8(BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += a3×b0
MOVQ 24(CX), AX
MULQ (BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += 19×a4×b4
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R13
ADCQ DX, R12
// r4 = a0×b4
MOVQ (CX), AX
MULQ 32(BX)
MOVQ AX, R15
MOVQ DX, R14
// r4 += a1×b3
MOVQ 8(CX), AX
MULQ 24(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a2×b2
MOVQ 16(CX), AX
MULQ 16(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a3×b1
MOVQ 24(CX), AX
MULQ 8(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a4×b0
MOVQ 32(CX), AX
MULQ (BX)
ADDQ AX, R15
ADCQ DX, R14
// First reduction chain
MOVQ $0x0007ffffffffffff, AX
SHLQ $0x0d, DI, SI
SHLQ $0x0d, R9, R8
SHLQ $0x0d, R11, R10
SHLQ $0x0d, R13, R12
SHLQ $0x0d, R15, R14
ANDQ AX, DI
IMUL3Q $0x13, R14, R14
ADDQ R14, DI
ANDQ AX, R9
ADDQ SI, R9
ANDQ AX, R11
ADDQ R8, R11
ANDQ AX, R13
ADDQ R10, R13
ANDQ AX, R15
ADDQ R12, R15
// Second reduction chain (carryPropagate)
MOVQ DI, SI
SHRQ $0x33, SI
MOVQ R9, R8
SHRQ $0x33, R8
MOVQ R11, R10
SHRQ $0x33, R10
MOVQ R13, R12
SHRQ $0x33, R12
MOVQ R15, R14
SHRQ $0x33, R14
ANDQ AX, DI
IMUL3Q $0x13, R14, R14
ADDQ R14, DI
ANDQ AX, R9
ADDQ SI, R9
ANDQ AX, R11
ADDQ R8, R11
ANDQ AX, R13
ADDQ R10, R13
ANDQ AX, R15
ADDQ R12, R15
// Store output
MOVQ out+0(FP), AX
MOVQ DI, (AX)
MOVQ R9, 8(AX)
MOVQ R11, 16(AX)
MOVQ R13, 24(AX)
MOVQ R15, 32(AX)
RET
// func feSquare(out *Element, a *Element)
TEXT ·feSquare(SB), NOSPLIT, $0-16
MOVQ a+8(FP), CX
// r0 = l0×l0
MOVQ (CX), AX
MULQ (CX)
MOVQ AX, SI
MOVQ DX, BX
// r0 += 38×l1×l4
MOVQ 8(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, SI
ADCQ DX, BX
// r0 += 38×l2×l3
MOVQ 16(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 24(CX)
ADDQ AX, SI
ADCQ DX, BX
// r1 = 2×l0×l1
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 8(CX)
MOVQ AX, R8
MOVQ DX, DI
// r1 += 38×l2×l4
MOVQ 16(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, R8
ADCQ DX, DI
// r1 += 19×l3×l3
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(CX)
ADDQ AX, R8
ADCQ DX, DI
// r2 = 2×l0×l2
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 16(CX)
MOVQ AX, R10
MOVQ DX, R9
// r2 += l1×l1
MOVQ 8(CX), AX
MULQ 8(CX)
ADDQ AX, R10
ADCQ DX, R9
// r2 += 38×l3×l4
MOVQ 24(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, R10
ADCQ DX, R9
// r3 = 2×l0×l3
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 24(CX)
MOVQ AX, R12
MOVQ DX, R11
// r3 += 2×l1×l2
MOVQ 8(CX), AX
IMUL3Q $0x02, AX, AX
MULQ 16(CX)
ADDQ AX, R12
ADCQ DX, R11
// r3 += 19×l4×l4
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(CX)
ADDQ AX, R12
ADCQ DX, R11
// r4 = 2×l0×l4
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 32(CX)
MOVQ AX, R14
MOVQ DX, R13
// r4 += 2×l1×l3
MOVQ 8(CX), AX
IMUL3Q $0x02, AX, AX
MULQ 24(CX)
ADDQ AX, R14
ADCQ DX, R13
// r4 += l2×l2
MOVQ 16(CX), AX
MULQ 16(CX)
ADDQ AX, R14
ADCQ DX, R13
// First reduction chain
MOVQ $0x0007ffffffffffff, AX
SHLQ $0x0d, SI, BX
SHLQ $0x0d, R8, DI
SHLQ $0x0d, R10, R9
SHLQ $0x0d, R12, R11
SHLQ $0x0d, R14, R13
ANDQ AX, SI
IMUL3Q $0x13, R13, R13
ADDQ R13, SI
ANDQ AX, R8
ADDQ BX, R8
ANDQ AX, R10
ADDQ DI, R10
ANDQ AX, R12
ADDQ R9, R12
ANDQ AX, R14
ADDQ R11, R14
// Second reduction chain (carryPropagate)
MOVQ SI, BX
SHRQ $0x33, BX
MOVQ R8, DI
SHRQ $0x33, DI
MOVQ R10, R9
SHRQ $0x33, R9
MOVQ R12, R11
SHRQ $0x33, R11
MOVQ R14, R13
SHRQ $0x33, R13
ANDQ AX, SI
IMUL3Q $0x13, R13, R13
ADDQ R13, SI
ANDQ AX, R8
ADDQ BX, R8
ANDQ AX, R10
ADDQ DI, R10
ANDQ AX, R12
ADDQ R9, R12
ANDQ AX, R14
ADDQ R11, R14
// Store output
MOVQ out+0(FP), AX
MOVQ SI, (AX)
MOVQ R8, 8(AX)
MOVQ R10, 16(AX)
MOVQ R12, 24(AX)
MOVQ R14, 32(AX)
RET

View file

@ -1,12 +0,0 @@
// Copyright (c) 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 !amd64 || !gc || purego
// +build !amd64 !gc purego
package field
func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
func feSquare(v, x *Element) { feSquareGeneric(v, x) }

View file

@ -1,16 +0,0 @@
// Copyright (c) 2020 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 arm64 && gc && !purego
// +build arm64,gc,!purego
package field
//go:noescape
func carryPropagate(v *Element)
func (v *Element) carryPropagate() *Element {
carryPropagate(v)
return v
}

View file

@ -1,43 +0,0 @@
// Copyright (c) 2020 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 arm64 && gc && !purego
// +build arm64,gc,!purego
#include "textflag.h"
// carryPropagate works exactly like carryPropagateGeneric and uses the
// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
// avoids loading R0-R4 twice and uses LDP and STP.
//
// See https://golang.org/issues/43145 for the main compiler issue.
//
// func carryPropagate(v *Element)
TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
MOVD v+0(FP), R20
LDP 0(R20), (R0, R1)
LDP 16(R20), (R2, R3)
MOVD 32(R20), R4
AND $0x7ffffffffffff, R0, R10
AND $0x7ffffffffffff, R1, R11
AND $0x7ffffffffffff, R2, R12
AND $0x7ffffffffffff, R3, R13
AND $0x7ffffffffffff, R4, R14
ADD R0>>51, R11, R11
ADD R1>>51, R12, R12
ADD R2>>51, R13, R13
ADD R3>>51, R14, R14
// R4>>51 * 19 + R10 -> R10
LSR $51, R4, R21
MOVD $19, R22
MADD R22, R10, R21, R10
STP (R10, R11), 0(R20)
STP (R12, R13), 16(R20)
MOVD R14, 32(R20)
RET

View file

@ -1,12 +0,0 @@
// Copyright (c) 2021 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 !arm64 || !gc || purego
// +build !arm64 !gc purego
package field
func (v *Element) carryPropagate() *Element {
return v.carryPropagateGeneric()
}

View file

@ -1,264 +0,0 @@
// Copyright (c) 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package field
import "math/bits"
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
// bits.Mul64 and bits.Add64 intrinsics.
type uint128 struct {
lo, hi uint64
}
// mul64 returns a * b.
func mul64(a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
// addMul64 returns v + a * b.
func addMul64(v uint128, a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
lo, c := bits.Add64(lo, v.lo, 0)
hi, _ = bits.Add64(hi, v.hi, c)
return uint128{lo, hi}
}
// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
func shiftRightBy51(a uint128) uint64 {
return (a.hi << (64 - 51)) | (a.lo >> 51)
}
func feMulGeneric(v, a, b *Element) {
a0 := a.l0
a1 := a.l1
a2 := a.l2
a3 := a.l3
a4 := a.l4
b0 := b.l0
b1 := b.l1
b2 := b.l2
b3 := b.l3
b4 := b.l4
// Limb multiplication works like pen-and-paper columnar multiplication, but
// with 51-bit limbs instead of digits.
//
// a4 a3 a2 a1 a0 x
// b4 b3 b2 b1 b0 =
// ------------------------
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a4b1 a3b1 a2b1 a1b1 a0b1 +
// a4b2 a3b2 a2b2 a1b2 a0b2 +
// a4b3 a3b3 a2b3 a1b3 a0b3 +
// a4b4 a3b4 a2b4 a1b4 a0b4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
// reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
// r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
//
// Reduction can be carried out simultaneously to multiplication. For
// example, we do not compute r5: whenever the result of a multiplication
// belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
//
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a3b1 a2b1 a1b1 a0b1 19×a4b1 +
// a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
// a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
// a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// Finally we add up the columns into wide, overlapping limbs.
a1_19 := a1 * 19
a2_19 := a2 * 19
a3_19 := a3 * 19
a4_19 := a4 * 19
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
r0 := mul64(a0, b0)
r0 = addMul64(r0, a1_19, b4)
r0 = addMul64(r0, a2_19, b3)
r0 = addMul64(r0, a3_19, b2)
r0 = addMul64(r0, a4_19, b1)
// r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
r1 := mul64(a0, b1)
r1 = addMul64(r1, a1, b0)
r1 = addMul64(r1, a2_19, b4)
r1 = addMul64(r1, a3_19, b3)
r1 = addMul64(r1, a4_19, b2)
// r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
r2 := mul64(a0, b2)
r2 = addMul64(r2, a1, b1)
r2 = addMul64(r2, a2, b0)
r2 = addMul64(r2, a3_19, b4)
r2 = addMul64(r2, a4_19, b3)
// r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
r3 := mul64(a0, b3)
r3 = addMul64(r3, a1, b2)
r3 = addMul64(r3, a2, b1)
r3 = addMul64(r3, a3, b0)
r3 = addMul64(r3, a4_19, b4)
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
r4 := mul64(a0, b4)
r4 = addMul64(r4, a1, b3)
r4 = addMul64(r4, a2, b2)
r4 = addMul64(r4, a3, b1)
r4 = addMul64(r4, a4, b0)
// After the multiplication, we need to reduce (carry) the five coefficients
// to obtain a result with limbs that are at most slightly larger than 2⁵¹,
// to respect the Element invariant.
//
// Overall, the reduction works the same as carryPropagate, except with
// wider inputs: we take the carry for each coefficient by shifting it right
// by 51, and add it to the limb above it. The top carry is multiplied by 19
// according to the reduction identity and added to the lowest limb.
//
// The largest coefficient (r0) will be at most 111 bits, which guarantees
// that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
//
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
// r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
// r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
// r0 < 2⁷ × 2⁵² × 2⁵²
// r0 < 2¹¹¹
//
// Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
// 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
// allows us to easily apply the reduction identity.
//
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
// r4 < 5 × 2⁵² × 2⁵²
// r4 < 2¹⁰⁷
//
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
// Now all coefficients fit into 64-bit registers but are still too large to
// be passed around as a Element. We therefore do one last carry chain,
// where the carries will be small enough to fit in the wiggle room above 2⁵¹.
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
func feSquareGeneric(v, a *Element) {
l0 := a.l0
l1 := a.l1
l2 := a.l2
l3 := a.l3
l4 := a.l4
// Squaring works precisely like multiplication above, but thanks to its
// symmetry we get to group a few terms together.
//
// l4 l3 l2 l1 l0 x
// l4 l3 l2 l1 l0 =
// ------------------------
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l4l1 l3l1 l2l1 l1l1 l0l1 +
// l4l2 l3l2 l2l2 l1l2 l0l2 +
// l4l3 l3l3 l2l3 l1l3 l0l3 +
// l4l4 l3l4 l2l4 l1l4 l0l4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l3l1 l2l1 l1l1 l0l1 19×l4l1 +
// l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
// l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
// l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
// only three Mul64 and four Add64, instead of five and eight.
l0_2 := l0 * 2
l1_2 := l1 * 2
l1_38 := l1 * 38
l2_38 := l2 * 38
l3_38 := l3 * 38
l3_19 := l3 * 19
l4_19 := l4 * 19
// r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
r0 := mul64(l0, l0)
r0 = addMul64(r0, l1_38, l4)
r0 = addMul64(r0, l2_38, l3)
// r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
r1 := mul64(l0_2, l1)
r1 = addMul64(r1, l2_38, l4)
r1 = addMul64(r1, l3_19, l3)
// r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
r2 := mul64(l0_2, l2)
r2 = addMul64(r2, l1, l1)
r2 = addMul64(r2, l3_38, l4)
// r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
r3 := mul64(l0_2, l3)
r3 = addMul64(r3, l1_2, l2)
r3 = addMul64(r3, l4_19, l4)
// r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
r4 := mul64(l0_2, l4)
r4 = addMul64(r4, l1_2, l3)
r4 = addMul64(r4, l2, l2)
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
// carryPropagateGeneric brings the limbs below 52 bits by applying the reduction
// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. TODO inline
func (v *Element) carryPropagateGeneric() *Element {
c0 := v.l0 >> 51
c1 := v.l1 >> 51
c2 := v.l2 >> 51
c3 := v.l3 >> 51
c4 := v.l4 >> 51
v.l0 = v.l0&maskLow51Bits + c4*19
v.l1 = v.l1&maskLow51Bits + c0
v.l2 = v.l2&maskLow51Bits + c1
v.l3 = v.l3&maskLow51Bits + c2
v.l4 = v.l4&maskLow51Bits + c3
return v
}

View file

@ -1 +0,0 @@
b0c49ae9f59d233526f8934262c5bbbe14d4358d

View file

@ -1,19 +0,0 @@
#! /bin/bash
set -euo pipefail
cd "$(git rev-parse --show-toplevel)"
STD_PATH=src/crypto/ed25519/internal/edwards25519/field
LOCAL_PATH=curve25519/internal/field
LAST_SYNC_REF=$(cat $LOCAL_PATH/sync.checkpoint)
git fetch https://go.googlesource.com/go master
if git diff --quiet $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH; then
echo "No changes."
else
NEW_REF=$(git rev-parse FETCH_HEAD | tee $LOCAL_PATH/sync.checkpoint)
echo "Applying changes from $LAST_SYNC_REF to $NEW_REF..."
git diff $LAST_SYNC_REF:$STD_PATH FETCH_HEAD:$STD_PATH | \
git apply -3 --directory=$LOCAL_PATH
fi

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !purego //go:build !purego
// +build !purego
// Package alias implements memory aliasing tests. // Package alias implements memory aliasing tests.
package alias package alias

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build purego //go:build purego
// +build purego
// Package alias implements memory aliasing tests. // Package alias implements memory aliasing tests.
package alias package alias

View file

@ -1,40 +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 !go1.13
// +build !go1.13
package poly1305
// Generic fallbacks for the math/bits intrinsics, copied from
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
// variable time fallbacks until Go 1.13.
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
sum = x + y + carry
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
return
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
diff = x - y - borrow
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
return
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
const mask32 = 1<<32 - 1
x0 := x & mask32
x1 := x >> 32
y0 := y & mask32
y1 := y >> 32
w0 := x0 * y0
t := x1*y0 + w0>>32
w1 := t & mask32
w2 := t >> 32
w1 += x0 * y1
hi = x1*y1 + w2 + w1>>32
lo = x * y
return
}

View file

@ -1,22 +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 go1.13
// +build go1.13
package poly1305
import "math/bits"
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
return bits.Add64(x, y, carry)
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
return bits.Sub64(x, y, borrow)
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
return bits.Mul64(x, y)
}

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego //go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
// +build !amd64,!ppc64le,!s390x !gc purego
package poly1305 package poly1305

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package poly1305 package poly1305

View file

@ -1,109 +1,93 @@
// Copyright 2012 The Go Authors. All rights reserved. // Code generated by command: go run sum_amd64_asm.go -out ../sum_amd64.s -pkg poly1305. DO NOT EDIT.
// 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
// +build gc,!purego
#include "textflag.h" // func update(state *macState, msg []byte)
#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)
TEXT ·update(SB), $0-32 TEXT ·update(SB), $0-32
MOVQ state+0(FP), DI MOVQ state+0(FP), DI
MOVQ msg_base+8(FP), SI MOVQ msg_base+8(FP), SI
MOVQ msg_len+16(FP), R15 MOVQ msg_len+16(FP), R15
MOVQ (DI), R8
MOVQ 0(DI), R8 // h0 MOVQ 8(DI), R9
MOVQ 8(DI), R9 // h1 MOVQ 16(DI), R10
MOVQ 16(DI), R10 // h2 MOVQ 24(DI), R11
MOVQ 24(DI), R11 // r0 MOVQ 32(DI), R12
MOVQ 32(DI), R12 // r1 CMPQ R15, $0x10
CMPQ R15, $16
JB bytes_between_0_and_15 JB bytes_between_0_and_15
loop: loop:
POLY1305_ADD(SI, R8, R9, R10) ADDQ (SI), R8
ADCQ 8(SI), R9
ADCQ $0x01, R10
LEAQ 16(SI), SI
multiply: multiply:
POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) MOVQ R11, AX
SUBQ $16, R15 MULQ R8
CMPQ R15, $16 MOVQ AX, BX
JAE loop 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: bytes_between_0_and_15:
TESTQ R15, R15 TESTQ R15, R15
JZ done JZ done
MOVQ $1, BX MOVQ $0x00000001, BX
XORQ CX, CX XORQ CX, CX
XORQ R13, R13 XORQ R13, R13
ADDQ R15, SI ADDQ R15, SI
flush_buffer: flush_buffer:
SHLQ $8, BX, CX SHLQ $0x08, BX, CX
SHLQ $8, BX SHLQ $0x08, BX
MOVB -1(SI), R13 MOVB -1(SI), R13
XORQ R13, BX XORQ R13, BX
DECQ SI DECQ SI
DECQ R15 DECQ R15
JNZ flush_buffer JNZ flush_buffer
ADDQ BX, R8 ADDQ BX, R8
ADCQ CX, R9 ADCQ CX, R9
ADCQ $0, R10 ADCQ $0x00, R10
MOVQ $16, R15 MOVQ $0x00000010, R15
JMP multiply JMP multiply
done: done:
MOVQ R8, 0(DI) MOVQ R8, (DI)
MOVQ R9, 8(DI) MOVQ R9, 8(DI)
MOVQ R10, 16(DI) MOVQ R10, 16(DI)
RET RET

View file

@ -7,7 +7,10 @@
package poly1305 package poly1305
import "encoding/binary" import (
"encoding/binary"
"math/bits"
)
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag // Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
// for a 64 bytes message is approximately // for a 64 bytes message is approximately
@ -114,13 +117,13 @@ type uint128 struct {
} }
func mul64(a, b uint64) uint128 { func mul64(a, b uint64) uint128 {
hi, lo := bitsMul64(a, b) hi, lo := bits.Mul64(a, b)
return uint128{lo, hi} return uint128{lo, hi}
} }
func add128(a, b uint128) uint128 { func add128(a, b uint128) uint128 {
lo, c := bitsAdd64(a.lo, b.lo, 0) lo, c := bits.Add64(a.lo, b.lo, 0)
hi, c := bitsAdd64(a.hi, b.hi, c) hi, c := bits.Add64(a.hi, b.hi, c)
if c != 0 { if c != 0 {
panic("poly1305: unexpected overflow") panic("poly1305: unexpected overflow")
} }
@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) {
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just // hide leading zeroes. For full chunks, that's 1 << 128, so we can just
// add 1 to the most significant (2¹²⁸) limb, h2. // add 1 to the most significant (2¹²⁸) limb, h2.
if len(msg) >= TagSize { if len(msg) >= TagSize {
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
h2 += c + 1 h2 += c + 1
msg = msg[TagSize:] msg = msg[TagSize:]
@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) {
copy(buf[:], msg) copy(buf[:], msg)
buf[len(msg)] = 1 buf[len(msg)] = 1
h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
h2 += c h2 += c
msg = nil msg = nil
@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) {
m3 := h2r1 m3 := h2r1
t0 := m0.lo t0 := m0.lo
t1, c := bitsAdd64(m1.lo, m0.hi, 0) t1, c := bits.Add64(m1.lo, m0.hi, 0)
t2, c := bitsAdd64(m2.lo, m1.hi, c) t2, c := bits.Add64(m2.lo, m1.hi, c)
t3, _ := bitsAdd64(m3.lo, m2.hi, c) t3, _ := bits.Add64(m3.lo, m2.hi, c)
// Now we have the result as 4 64-bit limbs, and we need to reduce it // Now we have the result as 4 64-bit limbs, and we need to reduce it
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) {
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
h0, c = bitsAdd64(h0, cc.lo, 0) h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bitsAdd64(h1, cc.hi, c) h1, c = bits.Add64(h1, cc.hi, c)
h2 += c h2 += c
cc = shiftRightBy2(cc) cc = shiftRightBy2(cc)
h0, c = bitsAdd64(h0, cc.lo, 0) h0, c = bits.Add64(h0, cc.lo, 0)
h1, c = bitsAdd64(h1, cc.hi, c) h1, c = bits.Add64(h1, cc.hi, c)
h2 += c h2 += c
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
// result if the subtraction underflows, and t otherwise. // result if the subtraction underflows, and t otherwise.
hMinusP0, b := bitsSub64(h0, p0, 0) hMinusP0, b := bits.Sub64(h0, p0, 0)
hMinusP1, b := bitsSub64(h1, p1, b) hMinusP1, b := bits.Sub64(h1, p1, b)
_, b = bitsSub64(h2, p2, b) _, b = bits.Sub64(h2, p2, b)
// h = h if h < p else h - p // h = h if h < p else h - p
h0 = select64(b, h0, hMinusP0) h0 = select64(b, h0, hMinusP0)
@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
// //
// by just doing a wide addition with the 128 low bits of h and discarding // by just doing a wide addition with the 128 low bits of h and discarding
// the overflow. // the overflow.
h0, c := bitsAdd64(h0, s[0], 0) h0, c := bits.Add64(h0, s[0], 0)
h1, _ = bitsAdd64(h1, s[1], c) h1, _ = bits.Add64(h1, s[1], c)
binary.LittleEndian.PutUint64(out[0:8], h0) binary.LittleEndian.PutUint64(out[0:8], h0)
binary.LittleEndian.PutUint64(out[8:16], h1) binary.LittleEndian.PutUint64(out[8:16], h1)

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package poly1305 package poly1305

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"
@ -20,15 +19,14 @@
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ #define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \
MULLD r0, h0, t0; \ MULLD r0, h0, t0; \
MULLD r0, h1, t4; \
MULHDU r0, h0, t1; \ MULHDU r0, h0, t1; \
MULLD r0, h1, t4; \
MULHDU r0, h1, t5; \ MULHDU r0, h1, t5; \
ADDC t4, t1, t1; \ ADDC t4, t1, t1; \
MULLD r0, h2, t2; \ MULLD r0, h2, t2; \
ADDZE t5; \
MULHDU r1, h0, t4; \ MULHDU r1, h0, t4; \
MULLD r1, h0, h0; \ MULLD r1, h0, h0; \
ADD t5, t2, t2; \ ADDE t5, t2, t2; \
ADDC h0, t1, t1; \ ADDC h0, t1, t1; \
MULLD h2, r1, t3; \ MULLD h2, r1, t3; \
ADDZE t4, h0; \ ADDZE t4, h0; \
@ -38,13 +36,11 @@
ADDE t5, t3, t3; \ ADDE t5, t3, t3; \
ADDC h0, t2, t2; \ ADDC h0, t2, t2; \
MOVD $-4, t4; \ MOVD $-4, t4; \
MOVD t0, h0; \
MOVD t1, h1; \
ADDZE t3; \ ADDZE t3; \
ANDCC $3, t2, h2; \ RLDICL $0, t2, $62, h2; \
AND t2, t4, t0; \ AND t2, t4, h0; \
ADDC t0, h0, h0; \ ADDC t0, h0, h0; \
ADDE t3, h1, h1; \ ADDE t3, t1, h1; \
SLD $62, t3, t4; \ SLD $62, t3, t4; \
SRD $2, t2; \ SRD $2, t2; \
ADDZE h2; \ ADDZE h2; \
@ -76,6 +72,7 @@ TEXT ·update(SB), $0-32
loop: loop:
POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22)
PCALIGN $16
multiply: multiply:
POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21)
ADD $-16, R5 ADD $-16, R5

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package poly1305 package poly1305

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View file

@ -187,9 +187,11 @@ type channel struct {
pending *buffer pending *buffer
extPending *buffer extPending *buffer
// windowMu protects myWindow, the flow-control window. // windowMu protects myWindow, the flow-control window, and myConsumed,
windowMu sync.Mutex // the number of bytes consumed since we last increased myWindow
myWindow uint32 windowMu sync.Mutex
myWindow uint32
myConsumed uint32
// writeMu serializes calls to mux.conn.writePacket() and // writeMu serializes calls to mux.conn.writePacket() and
// protects sentClose and packetPool. This mutex must be // protects sentClose and packetPool. This mutex must be
@ -332,14 +334,24 @@ func (ch *channel) handleData(packet []byte) error {
return nil return nil
} }
func (c *channel) adjustWindow(n uint32) error { func (c *channel) adjustWindow(adj uint32) error {
c.windowMu.Lock() c.windowMu.Lock()
// Since myWindow is managed on our side, and can never exceed // Since myConsumed and myWindow are managed on our side, and can never
// the initial window setting, we don't worry about overflow. // exceed the initial window setting, we don't worry about overflow.
c.myWindow += uint32(n) c.myConsumed += adj
var sendAdj uint32
if (channelWindowSize-c.myWindow > 3*c.maxIncomingPayload) ||
(c.myWindow < channelWindowSize/2) {
sendAdj = c.myConsumed
c.myConsumed = 0
c.myWindow += sendAdj
}
c.windowMu.Unlock() c.windowMu.Unlock()
if sendAdj == 0 {
return nil
}
return c.sendMessage(windowAdjustMsg{ return c.sendMessage(windowAdjustMsg{
AdditionalBytes: uint32(n), AdditionalBytes: sendAdj,
}) })
} }

View file

@ -82,7 +82,7 @@ func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan
if err := conn.clientHandshake(addr, &fullConf); err != nil { if err := conn.clientHandshake(addr, &fullConf); err != nil {
c.Close() c.Close()
return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %w", err)
} }
conn.mux = newMux(conn.transport) conn.mux = newMux(conn.transport)
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil

View file

@ -71,6 +71,10 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
for auth := AuthMethod(new(noneAuth)); auth != nil; { for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions) ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil { if err != nil {
// On disconnect, return error immediately
if _, ok := err.(*disconnectMsg); ok {
return err
}
// We return the error later if there is no other method left to // We return the error later if there is no other method left to
// try. // try.
ok = authFailure ok = authFailure
@ -307,7 +311,10 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
} }
var methods []string var methods []string
var errSigAlgo error var errSigAlgo error
for _, signer := range signers {
origSignersLen := len(signers)
for idx := 0; idx < len(signers); idx++ {
signer := signers[idx]
pub := signer.PublicKey() pub := signer.PublicKey()
as, algo, err := pickSignatureAlgorithm(signer, extensions) as, algo, err := pickSignatureAlgorithm(signer, extensions)
if err != nil && errSigAlgo == nil { if err != nil && errSigAlgo == nil {
@ -321,6 +328,21 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
// OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512
// in the "server-sig-algs" extension but doesn't support these
// algorithms for certificate authentication, so if the server rejects
// the key try to use the obtained algorithm as if "server-sig-algs" had
// not been implemented if supported from the algorithm signer.
if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 {
if contains(as.Algorithms(), KeyAlgoRSA) {
// We retry using the compat algorithm after all signers have
// been tried normally.
signers = append(signers, &multiAlgorithmSigner{
AlgorithmSigner: as,
supportedAlgorithms: []string{KeyAlgoRSA},
})
}
}
if !ok { if !ok {
continue continue
} }
@ -386,10 +408,10 @@ func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, e
return false, err return false, err
} }
return confirmKeyAck(key, algo, c) return confirmKeyAck(key, c)
} }
func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) { func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
pubKey := key.Marshal() pubKey := key.Marshal()
for { for {
@ -407,7 +429,15 @@ func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) {
if err := Unmarshal(packet, &msg); err != nil { if err := Unmarshal(packet, &msg); err != nil {
return false, err return false, err
} }
if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) { // According to RFC 4252 Section 7 the algorithm in
// SSH_MSG_USERAUTH_PK_OK should match that of the request but some
// servers send the key type instead. OpenSSH allows any algorithm
// that matches the public key, so we do the same.
// https://github.com/openssh/openssh-portable/blob/86bdd385/sshconnect2.c#L709
if !contains(algorithmsForKeyFormat(key.Type()), msg.Algo) {
return false, nil
}
if !bytes.Equal(msg.PubKey, pubKey) {
return false, nil return false, nil
} }
return true, nil return true, nil

View file

@ -10,7 +10,6 @@ import (
"fmt" "fmt"
"io" "io"
"math" "math"
"strings"
"sync" "sync"
_ "crypto/sha1" _ "crypto/sha1"
@ -128,6 +127,14 @@ func isRSA(algo string) bool {
return contains(algos, underlyingAlgo(algo)) return contains(algos, underlyingAlgo(algo))
} }
func isRSACert(algo string) bool {
_, ok := certKeyAlgoNames[algo]
if !ok {
return false
}
return isRSA(algo)
}
// supportedPubKeyAuthAlgos specifies the supported client public key // supportedPubKeyAuthAlgos specifies the supported client public key
// authentication algorithms. Note that this doesn't include certificate types // authentication algorithms. Note that this doesn't include certificate types
// since those use the underlying algorithm. This list is sent to the client if // since those use the underlying algorithm. This list is sent to the client if
@ -140,8 +147,6 @@ var supportedPubKeyAuthAlgos = []string{
KeyAlgoDSA, KeyAlgoDSA,
} }
var supportedPubKeyAuthAlgosList = strings.Join(supportedPubKeyAuthAlgos, ",")
// unexpectedMessageError results when the SSH message that we received didn't // unexpectedMessageError results when the SSH message that we received didn't
// match what we wanted. // match what we wanted.
func unexpectedMessageError(expected, got uint8) error { func unexpectedMessageError(expected, got uint8) error {

View file

@ -20,4 +20,4 @@ References:
This package does not fall under the stability promise of the Go language itself, This package does not fall under the stability promise of the Go language itself,
so its API may be changed when pressing needs arise. so its API may be changed when pressing needs arise.
*/ */
package ssh // import "golang.org/x/crypto/ssh" package ssh

View file

@ -11,6 +11,7 @@ import (
"io" "io"
"log" "log"
"net" "net"
"strings"
"sync" "sync"
) )
@ -34,6 +35,16 @@ type keyingTransport interface {
// direction will be effected if a msgNewKeys message is sent // direction will be effected if a msgNewKeys message is sent
// or received. // or received.
prepareKeyChange(*algorithms, *kexResult) error prepareKeyChange(*algorithms, *kexResult) error
// setStrictMode sets the strict KEX mode, notably triggering
// sequence number resets on sending or receiving msgNewKeys.
// If the sequence number is already > 1 when setStrictMode
// is called, an error is returned.
setStrictMode() error
// setInitialKEXDone indicates to the transport that the initial key exchange
// was completed
setInitialKEXDone()
} }
// handshakeTransport implements rekeying on top of a keyingTransport // handshakeTransport implements rekeying on top of a keyingTransport
@ -50,6 +61,10 @@ type handshakeTransport struct {
// connection. // connection.
hostKeys []Signer hostKeys []Signer
// publicKeyAuthAlgorithms is non-empty if we are the server. In that case,
// it contains the supported client public key authentication algorithms.
publicKeyAuthAlgorithms []string
// hostKeyAlgorithms is non-empty if we are the client. In that case, // hostKeyAlgorithms is non-empty if we are the client. In that case,
// we accept these key types from the server as host key. // we accept these key types from the server as host key.
hostKeyAlgorithms []string hostKeyAlgorithms []string
@ -95,6 +110,10 @@ type handshakeTransport struct {
// The session ID or nil if first kex did not complete yet. // The session ID or nil if first kex did not complete yet.
sessionID []byte sessionID []byte
// strictMode indicates if the other side of the handshake indicated
// that we should be following the strict KEX protocol restrictions.
strictMode bool
} }
type pendingKex struct { type pendingKex struct {
@ -141,6 +160,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
t.hostKeys = config.hostKeys t.hostKeys = config.hostKeys
t.publicKeyAuthAlgorithms = config.PublicKeyAuthAlgorithms
go t.readLoop() go t.readLoop()
go t.kexLoop() go t.kexLoop()
return t return t
@ -203,7 +223,10 @@ func (t *handshakeTransport) readLoop() {
close(t.incoming) close(t.incoming)
break break
} }
if p[0] == msgIgnore || p[0] == msgDebug { // If this is the first kex, and strict KEX mode is enabled,
// we don't ignore any messages, as they may be used to manipulate
// the packet sequence numbers.
if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) {
continue continue
} }
t.incoming <- p t.incoming <- p
@ -435,6 +458,11 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
return successPacket, nil return successPacket, nil
} }
const (
kexStrictClient = "kex-strict-c-v00@openssh.com"
kexStrictServer = "kex-strict-s-v00@openssh.com"
)
// sendKexInit sends a key change message. // sendKexInit sends a key change message.
func (t *handshakeTransport) sendKexInit() error { func (t *handshakeTransport) sendKexInit() error {
t.mu.Lock() t.mu.Lock()
@ -448,7 +476,6 @@ func (t *handshakeTransport) sendKexInit() error {
} }
msg := &kexInitMsg{ msg := &kexInitMsg{
KexAlgos: t.config.KeyExchanges,
CiphersClientServer: t.config.Ciphers, CiphersClientServer: t.config.Ciphers,
CiphersServerClient: t.config.Ciphers, CiphersServerClient: t.config.Ciphers,
MACsClientServer: t.config.MACs, MACsClientServer: t.config.MACs,
@ -458,6 +485,13 @@ func (t *handshakeTransport) sendKexInit() error {
} }
io.ReadFull(rand.Reader, msg.Cookie[:]) io.ReadFull(rand.Reader, 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
// user owned KeyExchanges, we create our own slice in order to avoid using user
// owned memory by mistake.
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
isServer := len(t.hostKeys) > 0 isServer := len(t.hostKeys) > 0
if isServer { if isServer {
for _, k := range t.hostKeys { for _, k := range t.hostKeys {
@ -482,17 +516,24 @@ func (t *handshakeTransport) sendKexInit() error {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat) msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
} }
} }
if t.sessionID == nil {
msg.KexAlgos = append(msg.KexAlgos, kexStrictServer)
}
} else { } else {
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what // As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
// algorithms the server supports for public key authentication. See RFC // algorithms the server supports for public key authentication. See RFC
// 8308, Section 2.1. // 8308, Section 2.1.
//
// We also send the strict KEX mode extension algorithm, in order to opt
// into the strict KEX mode.
if firstKeyExchange := t.sessionID == nil; firstKeyExchange { if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1)
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
msg.KexAlgos = append(msg.KexAlgos, "ext-info-c") msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
msg.KexAlgos = append(msg.KexAlgos, kexStrictClient)
} }
} }
packet := Marshal(msg) packet := Marshal(msg)
@ -598,6 +639,13 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
return err return err
} }
if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) {
t.strictMode = true
if err := t.conn.setStrictMode(); err != nil {
return err
}
}
// We don't send FirstKexFollows, but we handle receiving it. // We don't send FirstKexFollows, but we handle receiving it.
// //
// RFC 4253 section 7 defines the kex and the agreement method for // RFC 4253 section 7 defines the kex and the agreement method for
@ -649,6 +697,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
// message with the server-sig-algs extension if the client supports it. See // message with the server-sig-algs extension if the client supports it. See
// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9. // RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") { if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") {
supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
extInfo := &extInfoMsg{ extInfo := &extInfoMsg{
NumExtensions: 2, NumExtensions: 2,
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1), Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
@ -672,6 +721,12 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
return unexpectedMessageError(msgNewKeys, packet[0]) return unexpectedMessageError(msgNewKeys, packet[0])
} }
if firstKeyExchange {
// Indicates to the transport that the first key exchange is completed
// after receiving SSH_MSG_NEWKEYS.
t.conn.setInitialKEXDone()
}
return nil return nil
} }

View file

@ -488,7 +488,49 @@ func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
h := hash.New() h := hash.New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob)
// Signatures in PKCS1v15 must match the key's modulus in
// length. However with SSH, some signers provide RSA
// signatures which are missing the MSB 0's of the bignum
// represented. With ssh-rsa signatures, this is encouraged by
// the spec (even though e.g. OpenSSH will give the full
// length unconditionally). With rsa-sha2-* signatures, the
// verifier is allowed to support these, even though they are
// out of spec. See RFC 4253 Section 6.6 for ssh-rsa and RFC
// 8332 Section 3 for rsa-sha2-* details.
//
// In practice:
// * OpenSSH always allows "short" signatures:
// https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L526
// but always generates padded signatures:
// https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L439
//
// * PuTTY versions 0.81 and earlier will generate short
// signatures for all RSA signature variants. Note that
// PuTTY is embedded in other software, such as WinSCP and
// FileZilla. At the time of writing, a patch has been
// applied to PuTTY to generate padded signatures for
// rsa-sha2-*, but not yet released:
// https://git.tartarus.org/?p=simon/putty.git;a=commitdiff;h=a5bcf3d384e1bf15a51a6923c3724cbbee022d8e
//
// * SSH.NET versions 2024.0.0 and earlier will generate short
// signatures for all RSA signature variants, fixed in 2024.1.0:
// https://github.com/sshnet/SSH.NET/releases/tag/2024.1.0
//
// As a result, we pad these up to the key size by inserting
// leading 0's.
//
// Note that support for short signatures with rsa-sha2-* may
// be removed in the future due to such signatures not being
// allowed by the spec.
blob := sig.Blob
keySize := (*rsa.PublicKey)(r).Size()
if len(blob) < keySize {
padded := make([]byte, keySize)
copy(padded[keySize-len(blob):], blob)
blob = padded
}
return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, blob)
} }
func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
@ -904,6 +946,10 @@ func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
return errors.New("ssh: signature did not verify") return errors.New("ssh: signature did not verify")
} }
func (k *skECDSAPublicKey) CryptoPublicKey() crypto.PublicKey {
return &k.PublicKey
}
type skEd25519PublicKey struct { type skEd25519PublicKey struct {
// application is a URL-like string, typically "ssh:" for SSH. // application is a URL-like string, typically "ssh:" for SSH.
// see openssh/PROTOCOL.u2f for details. // see openssh/PROTOCOL.u2f for details.
@ -1000,6 +1046,10 @@ func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
return nil return nil
} }
func (k *skEd25519PublicKey) CryptoPublicKey() crypto.PublicKey {
return k.PublicKey
}
// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, // NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
// *ecdsa.PrivateKey or any other crypto.Signer and returns a // *ecdsa.PrivateKey or any other crypto.Signer and returns a
// corresponding Signer instance. ECDSA keys must use P-256, P-384 or // corresponding Signer instance. ECDSA keys must use P-256, P-384 or
@ -1232,16 +1282,27 @@ func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{},
return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err) return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
} }
var result interface{}
switch block.Type { switch block.Type {
case "RSA PRIVATE KEY": case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(buf) result, err = x509.ParsePKCS1PrivateKey(buf)
case "EC PRIVATE KEY": case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(buf) result, err = x509.ParseECPrivateKey(buf)
case "DSA PRIVATE KEY": case "DSA PRIVATE KEY":
return ParseDSAPrivateKey(buf) result, err = ParseDSAPrivateKey(buf)
default: default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
} }
// Because of deficiencies in the format, DecryptPEMBlock does not always
// detect an incorrect password. In these cases decrypted DER bytes is
// random noise. If the parsing of the key returns an asn1.StructuralError
// we return x509.IncorrectPasswordError.
if _, ok := err.(asn1.StructuralError); ok {
return nil, x509.IncorrectPasswordError
}
return result, err
} }
// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as // ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as

View file

@ -64,6 +64,13 @@ type ServerConfig struct {
// Config contains configuration shared between client and server. // Config contains configuration shared between client and server.
Config Config
// PublicKeyAuthAlgorithms specifies the supported client public key
// authentication algorithms. Note that this should not include certificate
// types since those use the underlying algorithm. This list is sent to the
// client if it supports the server-sig-algs extension. Order is irrelevant.
// If unspecified then a default set of algorithms is used.
PublicKeyAuthAlgorithms []string
hostKeys []Signer hostKeys []Signer
// NoClientAuth is true if clients are allowed to connect without // NoClientAuth is true if clients are allowed to connect without
@ -201,9 +208,20 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
if fullConf.MaxAuthTries == 0 { if fullConf.MaxAuthTries == 0 {
fullConf.MaxAuthTries = 6 fullConf.MaxAuthTries = 6
} }
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
} else {
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
if !contains(supportedPubKeyAuthAlgos, algo) {
c.Close()
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
}
}
}
// Check if the config contains any unsupported key exchanges // Check if the config contains any unsupported key exchanges
for _, kex := range fullConf.KeyExchanges { for _, kex := range fullConf.KeyExchanges {
if _, ok := serverForbiddenKexAlgos[kex]; ok { if _, ok := serverForbiddenKexAlgos[kex]; ok {
c.Close()
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex) return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
} }
} }
@ -321,7 +339,7 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
} }
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection, func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) { sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
gssAPIServer := gssapiConfig.Server gssAPIServer := gssapiConfig.Server
defer gssAPIServer.DeleteSecContext() defer gssAPIServer.DeleteSecContext()
@ -331,7 +349,7 @@ func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *c
outToken []byte outToken []byte
needContinue bool needContinue bool
) )
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken) outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
if err != nil { if err != nil {
return err, nil, nil return err, nil, nil
} }
@ -353,6 +371,7 @@ func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *c
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
return nil, nil, err return nil, nil, err
} }
token = userAuthGSSAPITokenReq.Token
} }
packet, err := s.transport.readPacket() packet, err := s.transport.readPacket()
if err != nil { if err != nil {
@ -407,6 +426,35 @@ func (l ServerAuthError) Error() string {
return "[" + strings.Join(errs, ", ") + "]" return "[" + strings.Join(errs, ", ") + "]"
} }
// ServerAuthCallbacks defines server-side authentication callbacks.
type ServerAuthCallbacks struct {
// PasswordCallback behaves like [ServerConfig.PasswordCallback].
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
// PublicKeyCallback behaves like [ServerConfig.PublicKeyCallback].
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
// KeyboardInteractiveCallback behaves like [ServerConfig.KeyboardInteractiveCallback].
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
// GSSAPIWithMICConfig behaves like [ServerConfig.GSSAPIWithMICConfig].
GSSAPIWithMICConfig *GSSAPIWithMICConfig
}
// PartialSuccessError can be returned by any of the [ServerConfig]
// authentication callbacks to indicate to the client that authentication has
// partially succeeded, but further steps are required.
type PartialSuccessError struct {
// Next defines the authentication callbacks to apply to further steps. The
// available methods communicated to the client are based on the non-nil
// ServerAuthCallbacks fields.
Next ServerAuthCallbacks
}
func (p *PartialSuccessError) Error() string {
return "ssh: authenticated with partial success"
}
// ErrNoAuth is the error value returned if no // ErrNoAuth is the error value returned if no
// authentication method has been passed yet. This happens as a normal // authentication method has been passed yet. This happens as a normal
// part of the authentication loop, since the client first tries // part of the authentication loop, since the client first tries
@ -414,14 +462,42 @@ func (l ServerAuthError) Error() string {
// It is returned in ServerAuthError.Errors from NewServerConn. // It is returned in ServerAuthError.Errors from NewServerConn.
var ErrNoAuth = errors.New("ssh: no auth passed yet") var ErrNoAuth = errors.New("ssh: no auth passed yet")
// BannerError is an error that can be returned by authentication handlers in
// ServerConfig to send a banner message to the client.
type BannerError struct {
Err error
Message string
}
func (b *BannerError) Unwrap() error {
return b.Err
}
func (b *BannerError) Error() string {
if b.Err == nil {
return b.Message
}
return b.Err.Error()
}
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
sessionID := s.transport.getSessionID() sessionID := s.transport.getSessionID()
var cache pubKeyCache var cache pubKeyCache
var perms *Permissions var perms *Permissions
authFailures := 0 authFailures := 0
noneAuthCount := 0
var authErrs []error var authErrs []error
var displayedBanner bool var displayedBanner bool
partialSuccessReturned := false
// Set the initial authentication callbacks from the config. They can be
// changed if a PartialSuccessError is returned.
authConfig := ServerAuthCallbacks{
PasswordCallback: config.PasswordCallback,
PublicKeyCallback: config.PublicKeyCallback,
KeyboardInteractiveCallback: config.KeyboardInteractiveCallback,
GSSAPIWithMICConfig: config.GSSAPIWithMICConfig,
}
userAuthLoop: userAuthLoop:
for { for {
@ -452,6 +528,11 @@ userAuthLoop:
return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
} }
if s.user != userAuthReq.User && partialSuccessReturned {
return nil, fmt.Errorf("ssh: client changed the user after a partial success authentication, previous user %q, current user %q",
s.user, userAuthReq.User)
}
s.user = userAuthReq.User s.user = userAuthReq.User
if !displayedBanner && config.BannerCallback != nil { if !displayedBanner && config.BannerCallback != nil {
@ -472,20 +553,18 @@ userAuthLoop:
switch userAuthReq.Method { switch userAuthReq.Method {
case "none": case "none":
if config.NoClientAuth { noneAuthCount++
// We don't allow none authentication after a partial success
// response.
if config.NoClientAuth && !partialSuccessReturned {
if config.NoClientAuthCallback != nil { if config.NoClientAuthCallback != nil {
perms, authErr = config.NoClientAuthCallback(s) perms, authErr = config.NoClientAuthCallback(s)
} else { } else {
authErr = nil authErr = nil
} }
} }
// allow initial attempt of 'none' without penalty
if authFailures == 0 {
authFailures--
}
case "password": case "password":
if config.PasswordCallback == nil { if authConfig.PasswordCallback == nil {
authErr = errors.New("ssh: password auth not configured") authErr = errors.New("ssh: password auth not configured")
break break
} }
@ -499,17 +578,17 @@ userAuthLoop:
return nil, parseError(msgUserAuthRequest) return nil, parseError(msgUserAuthRequest)
} }
perms, authErr = config.PasswordCallback(s, password) perms, authErr = authConfig.PasswordCallback(s, password)
case "keyboard-interactive": case "keyboard-interactive":
if config.KeyboardInteractiveCallback == nil { if authConfig.KeyboardInteractiveCallback == nil {
authErr = errors.New("ssh: keyboard-interactive auth not configured") authErr = errors.New("ssh: keyboard-interactive auth not configured")
break break
} }
prompter := &sshClientKeyboardInteractive{s} prompter := &sshClientKeyboardInteractive{s}
perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) perms, authErr = authConfig.KeyboardInteractiveCallback(s, prompter.Challenge)
case "publickey": case "publickey":
if config.PublicKeyCallback == nil { if authConfig.PublicKeyCallback == nil {
authErr = errors.New("ssh: publickey auth not configured") authErr = errors.New("ssh: publickey auth not configured")
break break
} }
@ -524,7 +603,7 @@ userAuthLoop:
return nil, parseError(msgUserAuthRequest) return nil, parseError(msgUserAuthRequest)
} }
algo := string(algoBytes) algo := string(algoBytes)
if !contains(supportedPubKeyAuthAlgos, underlyingAlgo(algo)) { if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
break break
} }
@ -543,11 +622,18 @@ userAuthLoop:
if !ok { if !ok {
candidate.user = s.user candidate.user = s.user
candidate.pubKeyData = pubKeyData candidate.pubKeyData = pubKeyData
candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey)
if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { _, isPartialSuccessError := candidate.result.(*PartialSuccessError)
candidate.result = checkSourceAddress(
if (candidate.result == nil || isPartialSuccessError) &&
candidate.perms != nil &&
candidate.perms.CriticalOptions != nil &&
candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
if err := checkSourceAddress(
s.RemoteAddr(), s.RemoteAddr(),
candidate.perms.CriticalOptions[sourceAddressCriticalOption]) candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil {
candidate.result = err
}
} }
cache.add(candidate) cache.add(candidate)
} }
@ -559,8 +645,8 @@ userAuthLoop:
if len(payload) > 0 { if len(payload) > 0 {
return nil, parseError(msgUserAuthRequest) return nil, parseError(msgUserAuthRequest)
} }
_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
if candidate.result == nil { if candidate.result == nil || isPartialSuccessError {
okMsg := userAuthPubKeyOkMsg{ okMsg := userAuthPubKeyOkMsg{
Algo: algo, Algo: algo,
PubKey: pubKeyData, PubKey: pubKeyData,
@ -591,7 +677,7 @@ userAuthLoop:
// algorithm name that corresponds to algo with // algorithm name that corresponds to algo with
// sig.Format. This is usually the same, but // sig.Format. This is usually the same, but
// for certs, the names differ. // for certs, the names differ.
if !contains(supportedPubKeyAuthAlgos, sig.Format) { if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
break break
} }
@ -610,11 +696,11 @@ userAuthLoop:
perms = candidate.perms perms = candidate.perms
} }
case "gssapi-with-mic": case "gssapi-with-mic":
if config.GSSAPIWithMICConfig == nil { if authConfig.GSSAPIWithMICConfig == nil {
authErr = errors.New("ssh: gssapi-with-mic auth not configured") authErr = errors.New("ssh: gssapi-with-mic auth not configured")
break break
} }
gssapiConfig := config.GSSAPIWithMICConfig gssapiConfig := authConfig.GSSAPIWithMICConfig
userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload) userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
if err != nil { if err != nil {
return nil, parseError(msgUserAuthRequest) return nil, parseError(msgUserAuthRequest)
@ -666,53 +752,86 @@ userAuthLoop:
config.AuthLogCallback(s, userAuthReq.Method, authErr) config.AuthLogCallback(s, userAuthReq.Method, authErr)
} }
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 {
return nil, err
}
}
}
if authErr == nil { if authErr == nil {
break userAuthLoop break userAuthLoop
} }
authFailures++ var failureMsg userAuthFailureMsg
if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
// If we have hit the max attempts, don't bother sending the if partialSuccess, ok := authErr.(*PartialSuccessError); ok {
// final SSH_MSG_USERAUTH_FAILURE message, since there are // After a partial success error we don't allow changing the user
// no more authentication methods which can be attempted, // name and execute the NoClientAuthCallback.
// and this message may cause the client to re-attempt partialSuccessReturned = true
// authentication while we send the disconnect message.
// Continue, and trigger the disconnect at the start of // In case a partial success is returned, the server may send
// the loop. // a new set of authentication methods.
// authConfig = partialSuccess.Next
// The SSH specification is somewhat confusing about this,
// RFC 4252 Section 5.1 requires each authentication failure // Reset pubkey cache, as the new PublicKeyCallback might
// be responded to with a respective SSH_MSG_USERAUTH_FAILURE // accept a different set of public keys.
// message, but Section 4 says the server should disconnect cache = pubKeyCache{}
// after some number of attempts, but it isn't explicit which
// message should take precedence (i.e. should there be a failure // Send back a partial success message to the user.
// message than a disconnect message, or if we are going to failureMsg.PartialSuccess = true
// disconnect, should we only send that message.) } else {
// // Allow initial attempt of 'none' without penalty.
// Either way, OpenSSH disconnects immediately after the last if authFailures > 0 || userAuthReq.Method != "none" || noneAuthCount != 1 {
// failed authnetication attempt, and given they are typically authFailures++
// considered the golden implementation it seems reasonable }
// to match that behavior. if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
continue // If we have hit the max attempts, don't bother sending the
// final SSH_MSG_USERAUTH_FAILURE message, since there are
// no more authentication methods which can be attempted,
// and this message may cause the client to re-attempt
// authentication while we send the disconnect message.
// Continue, and trigger the disconnect at the start of
// the loop.
//
// The SSH specification is somewhat confusing about this,
// RFC 4252 Section 5.1 requires each authentication failure
// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
// message, but Section 4 says the server should disconnect
// after some number of attempts, but it isn't explicit which
// message should take precedence (i.e. should there be a failure
// message than a disconnect message, or if we are going to
// disconnect, should we only send that message.)
//
// Either way, OpenSSH disconnects immediately after the last
// failed authentication attempt, and given they are typically
// considered the golden implementation it seems reasonable
// to match that behavior.
continue
}
} }
var failureMsg userAuthFailureMsg if authConfig.PasswordCallback != nil {
if config.PasswordCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "password") failureMsg.Methods = append(failureMsg.Methods, "password")
} }
if config.PublicKeyCallback != nil { if authConfig.PublicKeyCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "publickey") failureMsg.Methods = append(failureMsg.Methods, "publickey")
} }
if config.KeyboardInteractiveCallback != nil { if authConfig.KeyboardInteractiveCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
} }
if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil && if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil &&
config.GSSAPIWithMICConfig.AllowLogin != nil { authConfig.GSSAPIWithMICConfig.AllowLogin != nil {
failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic") failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
} }
if len(failureMsg.Methods) == 0 { if len(failureMsg.Methods) == 0 {
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") return nil, errors.New("ssh: no authentication methods available")
} }
if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {

View file

@ -5,6 +5,7 @@
package ssh package ssh
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -332,6 +333,40 @@ func (l *tcpListener) Addr() net.Addr {
return l.laddr return l.laddr
} }
// DialContext initiates a connection to the addr from the remote host.
//
// The provided Context must be non-nil. If the context expires before the
// connection is complete, an error is returned. Once successfully connected,
// any expiration of the context will not affect the connection.
//
// See func Dial for additional information.
func (c *Client) DialContext(ctx context.Context, n, addr string) (net.Conn, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
type connErr struct {
conn net.Conn
err error
}
ch := make(chan connErr)
go func() {
conn, err := c.Dial(n, addr)
select {
case ch <- connErr{conn, err}:
case <-ctx.Done():
if conn != nil {
conn.Close()
}
}
}()
select {
case res := <-ch:
return res.conn, res.err
case <-ctx.Done():
return nil, ctx.Err()
}
}
// Dial initiates a connection to the addr from the remote host. // Dial initiates a connection to the addr from the remote host.
// The resulting connection has a zero LocalAddr() and RemoteAddr(). // The resulting connection has a zero LocalAddr() and RemoteAddr().
func (c *Client) Dial(n, addr string) (net.Conn, error) { func (c *Client) Dial(n, addr string) (net.Conn, error) {

View file

@ -49,6 +49,9 @@ type transport struct {
rand io.Reader rand io.Reader
isClient bool isClient bool
io.Closer io.Closer
strictMode bool
initialKEXDone bool
} }
// packetCipher represents a combination of SSH encryption/MAC // packetCipher represents a combination of SSH encryption/MAC
@ -74,6 +77,18 @@ type connectionState struct {
pendingKeyChange chan packetCipher pendingKeyChange chan packetCipher
} }
func (t *transport) setStrictMode() error {
if t.reader.seqNum != 1 {
return errors.New("ssh: sequence number != 1 when strict KEX mode requested")
}
t.strictMode = true
return nil
}
func (t *transport) setInitialKEXDone() {
t.initialKEXDone = true
}
// prepareKeyChange sets up key material for a keychange. The key changes in // prepareKeyChange sets up key material for a keychange. The key changes in
// both directions are triggered by reading and writing a msgNewKey packet // both directions are triggered by reading and writing a msgNewKey packet
// respectively. // respectively.
@ -112,11 +127,12 @@ func (t *transport) printPacket(p []byte, write bool) {
// Read and decrypt next packet. // Read and decrypt next packet.
func (t *transport) readPacket() (p []byte, err error) { func (t *transport) readPacket() (p []byte, err error) {
for { for {
p, err = t.reader.readPacket(t.bufReader) p, err = t.reader.readPacket(t.bufReader, t.strictMode)
if err != nil { if err != nil {
break break
} }
if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { // in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX
if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) {
break break
} }
} }
@ -127,7 +143,7 @@ func (t *transport) readPacket() (p []byte, err error) {
return p, err return p, err
} }
func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) {
packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
s.seqNum++ s.seqNum++
if err == nil && len(packet) == 0 { if err == nil && len(packet) == 0 {
@ -140,6 +156,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
select { select {
case cipher := <-s.pendingKeyChange: case cipher := <-s.pendingKeyChange:
s.packetCipher = cipher s.packetCipher = cipher
if strictMode {
s.seqNum = 0
}
default: default:
return nil, errors.New("ssh: got bogus newkeys message") return nil, errors.New("ssh: got bogus newkeys message")
} }
@ -170,10 +189,10 @@ func (t *transport) writePacket(packet []byte) error {
if debugTransport { if debugTransport {
t.printPacket(packet, true) t.printPacket(packet, true)
} }
return t.writer.writePacket(t.bufWriter, t.rand, packet) return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode)
} }
func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error {
changeKeys := len(packet) > 0 && packet[0] == msgNewKeys changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
@ -188,6 +207,9 @@ func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []
select { select {
case cipher := <-s.pendingKeyChange: case cipher := <-s.pendingKeyChange:
s.packetCipher = cipher s.packetCipher = cipher
if strictMode {
s.seqNum = 0
}
default: default:
panic("ssh: no key material for msgNewKeys") panic("ssh: no key material for msgNewKeys")
} }

4
vendor/golang.org/x/sys/LICENSE generated vendored
View file

@ -1,4 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved. Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the in the documentation and/or other materials provided with the
distribution. distribution.
* Neither the name of Google Inc. nor the names of its * Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"

22
vendor/golang.org/x/sys/cpu/cpu.go generated vendored
View file

@ -103,7 +103,10 @@ var ARM64 struct {
HasASIMDDP bool // Advanced SIMD double precision instruction set HasASIMDDP bool // Advanced SIMD double precision instruction set
HasSHA512 bool // SHA512 hardware implementation HasSHA512 bool // SHA512 hardware implementation
HasSVE bool // Scalable Vector Extensions HasSVE bool // Scalable Vector Extensions
HasSVE2 bool // Scalable Vector Extensions 2
HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32
HasDIT bool // Data Independent Timing support
HasI8MM bool // Advanced SIMD Int8 matrix multiplication instructions
_ CacheLinePad _ CacheLinePad
} }
@ -198,6 +201,25 @@ var S390X struct {
_ CacheLinePad _ CacheLinePad
} }
// RISCV64 contains the supported CPU features and performance characteristics for riscv64
// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate
// the presence of RISC-V extensions.
//
// It is safe to assume that all the RV64G extensions are supported and so they are omitted from
// this structure. As riscv64 Go programs require at least RV64G, the code that populates
// this structure cannot run successfully if some of the RV64G extensions are missing.
// The struct is padded to avoid false sharing.
var RISCV64 struct {
_ CacheLinePad
HasFastMisaligned bool // Fast misaligned accesses
HasC bool // Compressed instruction-set extension
HasV bool // Vector extension compatible with RVV 1.0
HasZba bool // Address generation instructions extension
HasZbb bool // Basic bit-manipulation extension
HasZbs bool // Single-bit instructions extension
_ CacheLinePad
}
func init() { func init() {
archInit() archInit()
initOptions() initOptions()

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build aix //go:build aix
// +build aix
package cpu package cpu

View file

@ -28,6 +28,7 @@ func initOptions() {
{Name: "sm3", Feature: &ARM64.HasSM3}, {Name: "sm3", Feature: &ARM64.HasSM3},
{Name: "sm4", Feature: &ARM64.HasSM4}, {Name: "sm4", Feature: &ARM64.HasSM4},
{Name: "sve", Feature: &ARM64.HasSVE}, {Name: "sve", Feature: &ARM64.HasSVE},
{Name: "sve2", Feature: &ARM64.HasSVE2},
{Name: "crc32", Feature: &ARM64.HasCRC32}, {Name: "crc32", Feature: &ARM64.HasCRC32},
{Name: "atomics", Feature: &ARM64.HasATOMICS}, {Name: "atomics", Feature: &ARM64.HasATOMICS},
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, {Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
@ -37,6 +38,8 @@ func initOptions() {
{Name: "dcpop", Feature: &ARM64.HasDCPOP}, {Name: "dcpop", Feature: &ARM64.HasDCPOP},
{Name: "asimddp", Feature: &ARM64.HasASIMDDP}, {Name: "asimddp", Feature: &ARM64.HasASIMDDP},
{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
{Name: "dit", Feature: &ARM64.HasDIT},
{Name: "i8mm", Feature: &ARM64.HasI8MM},
} }
} }
@ -144,6 +147,11 @@ func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
ARM64.HasLRCPC = true ARM64.HasLRCPC = true
} }
switch extractBits(isar1, 52, 55) {
case 1:
ARM64.HasI8MM = true
}
// ID_AA64PFR0_EL1 // ID_AA64PFR0_EL1
switch extractBits(pfr0, 16, 19) { switch extractBits(pfr0, 16, 19) {
case 0: case 0:
@ -164,6 +172,20 @@ func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
switch extractBits(pfr0, 32, 35) { switch extractBits(pfr0, 32, 35) {
case 1: case 1:
ARM64.HasSVE = true ARM64.HasSVE = true
parseARM64SVERegister(getzfr0())
}
switch extractBits(pfr0, 48, 51) {
case 1:
ARM64.HasDIT = true
}
}
func parseARM64SVERegister(zfr0 uint64) {
switch extractBits(zfr0, 0, 3) {
case 1:
ARM64.HasSVE2 = true
} }
} }

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"
@ -30,3 +29,11 @@ TEXT ·getpfr0(SB),NOSPLIT,$0-8
WORD $0xd5380400 WORD $0xd5380400
MOVD R0, ret+0(FP) MOVD R0, ret+0(FP)
RET RET
// func getzfr0() uint64
TEXT ·getzfr0(SB),NOSPLIT,$0-8
// get SVE Feature Register 0 into x0
// mrs x0, ID_AA64ZFR0_EL1 = d5380480
WORD $0xd5380480
MOVD R0, ret+0(FP)
RET

View file

@ -3,10 +3,10 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
package cpu package cpu
func getisar0() uint64 func getisar0() uint64
func getisar1() uint64 func getisar1() uint64
func getpfr0() uint64 func getpfr0() uint64
func getzfr0() uint64

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
package cpu package cpu

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (386 || amd64 || amd64p32) && gc //go:build (386 || amd64 || amd64p32) && gc
// +build 386 amd64 amd64p32
// +build gc
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gccgo //go:build gccgo
// +build gccgo
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gccgo //go:build gccgo
// +build gccgo
package cpu package cpu

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (386 || amd64 || amd64p32) && gccgo //go:build (386 || amd64 || amd64p32) && gccgo
// +build 386 amd64 amd64p32
// +build gccgo
#include <cpuid.h> #include <cpuid.h>
#include <stdint.h> #include <stdint.h>

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (386 || amd64 || amd64p32) && gccgo //go:build (386 || amd64 || amd64p32) && gccgo
// +build 386 amd64 amd64p32
// +build gccgo
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !386 && !amd64 && !amd64p32 && !arm64 //go:build !386 && !amd64 && !amd64p32 && !arm64
// +build !386,!amd64,!amd64p32,!arm64
package cpu package cpu

View file

@ -35,6 +35,10 @@ const (
hwcap_SHA512 = 1 << 21 hwcap_SHA512 = 1 << 21
hwcap_SVE = 1 << 22 hwcap_SVE = 1 << 22
hwcap_ASIMDFHM = 1 << 23 hwcap_ASIMDFHM = 1 << 23
hwcap_DIT = 1 << 24
hwcap2_SVE2 = 1 << 1
hwcap2_I8MM = 1 << 13
) )
// linuxKernelCanEmulateCPUID reports whether we're running // linuxKernelCanEmulateCPUID reports whether we're running
@ -104,6 +108,12 @@ func doinit() {
ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512)
ARM64.HasSVE = isSet(hwCap, hwcap_SVE) ARM64.HasSVE = isSet(hwCap, hwcap_SVE)
ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
ARM64.HasDIT = isSet(hwCap, hwcap_DIT)
// HWCAP2 feature bits
ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2)
ARM64.HasI8MM = isSet(hwCap2, hwcap2_I8MM)
} }
func isSet(hwc uint, value uint) bool { func isSet(hwc uint, value uint) bool {

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && (mips64 || mips64le) //go:build linux && (mips64 || mips64le)
// +build linux
// +build mips64 mips64le
package cpu package cpu

View file

@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x //go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x
package cpu package cpu

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && (ppc64 || ppc64le) //go:build linux && (ppc64 || ppc64le)
// +build linux
// +build ppc64 ppc64le
package cpu package cpu

137
vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go generated vendored Normal file
View file

@ -0,0 +1,137 @@
// 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 cpu
import (
"syscall"
"unsafe"
)
// RISC-V extension discovery code for Linux. The approach here is to first try the riscv_hwprobe
// syscall falling back to HWCAP to check for the C extension if riscv_hwprobe is not available.
//
// A note on detection of the Vector extension using HWCAP.
//
// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5.
// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe
// syscall is not available then neither is the Vector extension (which needs kernel support).
// The riscv_hwprobe syscall should then be all we need to detect the Vector extension.
// However, some RISC-V board manufacturers ship boards with an older kernel on top of which
// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe
// patches. These kernels advertise support for the Vector extension using HWCAP. Falling
// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not
// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option.
//
// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by
// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board
// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified
// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use
// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector
// extension are binary incompatible. HWCAP can then not be used in isolation to populate the
// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0.
//
// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector
// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype
// register. This check would allow us to safely detect version 1.0 of the Vector extension
// with HWCAP, if riscv_hwprobe were not available. However, the check cannot
// be added until the assembler supports the Vector instructions.
//
// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the
// extensions it advertises support for are explicitly versioned. It's also worth noting that
// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zba.
// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority
// of RISC-V extensions.
//
// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information.
// golang.org/x/sys/cpu is not allowed to depend on golang.org/x/sys/unix so we must
// reproduce the constants, types and functions needed to make the riscv_hwprobe syscall
// here.
const (
// Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go.
riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4
riscv_HWPROBE_IMA_C = 0x2
riscv_HWPROBE_IMA_V = 0x4
riscv_HWPROBE_EXT_ZBA = 0x8
riscv_HWPROBE_EXT_ZBB = 0x10
riscv_HWPROBE_EXT_ZBS = 0x20
riscv_HWPROBE_KEY_CPUPERF_0 = 0x5
riscv_HWPROBE_MISALIGNED_FAST = 0x3
riscv_HWPROBE_MISALIGNED_MASK = 0x7
)
const (
// sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go.
sys_RISCV_HWPROBE = 258
)
// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go.
type riscvHWProbePairs struct {
key int64
value uint64
}
const (
// CPU features
hwcap_RISCV_ISA_C = 1 << ('C' - 'A')
)
func doinit() {
// A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key
// field should be initialised with one of the key constants defined above, e.g.,
// RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value.
// If the kernel does not recognise a key it will set the key field to -1 and the value field to 0.
pairs := []riscvHWProbePairs{
{riscv_HWPROBE_KEY_IMA_EXT_0, 0},
{riscv_HWPROBE_KEY_CPUPERF_0, 0},
}
// This call only indicates that extensions are supported if they are implemented on all cores.
if riscvHWProbe(pairs, 0) {
if pairs[0].key != -1 {
v := uint(pairs[0].value)
RISCV64.HasC = isSet(v, riscv_HWPROBE_IMA_C)
RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V)
RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA)
RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB)
RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS)
}
if pairs[1].key != -1 {
v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK
RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST
}
}
// Let's double check with HWCAP if the C extension does not appear to be supported.
// This may happen if we're running on a kernel older than 6.4.
if !RISCV64.HasC {
RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C)
}
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}
// riscvHWProbe is a simplified version of the generated wrapper function found in
// golang.org/x/sys/unix/zsyscall_linux_riscv64.go. We simplify it by removing the
// cpuCount and cpus parameters which we do not need. We always want to pass 0 for
// these parameters here so the kernel only reports the extensions that are present
// on all cores.
func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool {
var _zero uintptr
var p0 unsafe.Pointer
if len(pairs) > 0 {
p0 = unsafe.Pointer(&pairs[0])
} else {
p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(p0), uintptr(len(pairs)), uintptr(0), uintptr(0), uintptr(flags), 0)
return e1 == 0
}

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build loong64 //go:build loong64
// +build loong64
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build mips64 || mips64le //go:build mips64 || mips64le
// +build mips64 mips64le
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build mips || mipsle //go:build mips || mipsle
// +build mips mipsle
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !linux && arm //go:build !linux && arm
// +build !linux,arm
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !linux && !netbsd && !openbsd && arm64 //go:build !linux && !netbsd && !openbsd && arm64
// +build !linux,!netbsd,!openbsd,arm64
package cpu package cpu

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !linux && (mips64 || mips64le) //go:build !linux && (mips64 || mips64le)
// +build !linux
// +build mips64 mips64le
package cpu package cpu

View file

@ -3,9 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !aix && !linux && (ppc64 || ppc64le) //go:build !aix && !linux && (ppc64 || ppc64le)
// +build !aix
// +build !linux
// +build ppc64 ppc64le
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !linux && riscv64 //go:build !linux && riscv64
// +build !linux,riscv64
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build ppc64 || ppc64le //go:build ppc64 || ppc64le
// +build ppc64 ppc64le
package cpu package cpu

View file

@ -3,10 +3,18 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build riscv64 //go:build riscv64
// +build riscv64
package cpu package cpu
const cacheLineSize = 64 const cacheLineSize = 64
func initOptions() {} func initOptions() {
options = []option{
{Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned},
{Name: "c", Feature: &RISCV64.HasC},
{Name: "v", Feature: &RISCV64.HasV},
{Name: "zba", Feature: &RISCV64.HasZba},
{Name: "zbb", Feature: &RISCV64.HasZbb},
{Name: "zbs", Feature: &RISCV64.HasZbs},
}
}

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build wasm //go:build wasm
// +build wasm
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build 386 || amd64 || amd64p32 //go:build 386 || amd64 || amd64p32
// +build 386 amd64 amd64p32
package cpu package cpu

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (386 || amd64 || amd64p32) && gc //go:build (386 || amd64 || amd64p32) && gc
// +build 386 amd64 amd64p32
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64 //go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
// +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh || wasm //go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh || wasm
// +build 386 amd64 amd64p32 alpha arm arm64 loong64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh wasm
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && arm64 //go:build linux && arm64
// +build linux,arm64
package cpu package cpu

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.21 //go:build go1.21
// +build go1.21
package cpu package cpu

View file

@ -9,7 +9,6 @@
// gccgo's libgo and thus must not used a CGo method. // gccgo's libgo and thus must not used a CGo method.
//go:build aix && gccgo //go:build aix && gccgo
// +build aix,gccgo
package cpu package cpu

View file

@ -7,7 +7,6 @@
// (See golang.org/issue/32102) // (See golang.org/issue/32102)
//go:build aix && ppc64 && gc //go:build aix && ppc64 && gc
// +build aix,ppc64,gc
package cpu package cpu

View file

@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
// +build go1.9
package unix package unix

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc //go:build (freebsd || netbsd || openbsd) && gc
// +build freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc //go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
// +build darwin dragonfly freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc //go:build (freebsd || netbsd || openbsd) && gc
// +build freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc //go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc //go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc //go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc //go:build gc
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,9 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && arm64 && gc //go:build linux && arm64 && gc
// +build linux
// +build arm64
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,9 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && loong64 && gc //go:build linux && loong64 && gc
// +build linux
// +build loong64
// +build gc
#include "textflag.h" #include "textflag.h"

View file

@ -3,9 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build linux && (mips64 || mips64le) && gc //go:build linux && (mips64 || mips64le) && gc
// +build linux
// +build mips64 mips64le
// +build gc
#include "textflag.h" #include "textflag.h"

Some files were not shown because too many files have changed in this diff Show more