Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fadb0b165 | ||
|
|
a6a393ffd6 | ||
|
|
1c7450041f | ||
|
|
d4e7c9cb6c | ||
|
|
332fd656f4 | ||
|
|
0b431c7de3 | ||
|
|
349231f7e4 | ||
|
|
44c9b0ff9e | ||
|
|
67b13616a5 | ||
|
|
477a5b4c32 | ||
|
|
59b5a86796 | ||
|
|
10f366e7a2 | ||
|
|
905d78a692 | ||
|
|
ebb717d630 | ||
|
|
0da2a6a1bb | ||
|
|
5defcc193a | ||
|
|
d042a396a6 | ||
|
|
b92bf9480d | ||
|
|
6f79b5a20c | ||
|
|
8d0d405eed | ||
|
|
b91329d961 | ||
|
|
7067223927 | ||
|
|
0d2316b267 | ||
|
|
0aab8d07ae | ||
|
|
5bead598a0 | ||
|
|
1a865804d5 | ||
|
|
1c981e6f81 | ||
|
|
62c9f1799c | ||
|
|
405cb3bdea | ||
|
|
913d3ae741 |
+20
-1
@@ -15,6 +15,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -271,9 +272,27 @@ func (c *Client) httpClient() *http.Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// packageVersion is the version of the module that contains this package, for
|
// packageVersion is the version of the module that contains this package, for
|
||||||
// sending as part of the User-Agent header. It's set in version_go112.go.
|
// sending as part of the User-Agent header.
|
||||||
var packageVersion string
|
var packageVersion string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Set packageVersion if the binary was built in modules mode and x/crypto
|
||||||
|
// was not replaced with a different module.
|
||||||
|
info, ok := debug.ReadBuildInfo()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, m := range info.Deps {
|
||||||
|
if m.Path != "golang.org/x/crypto" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m.Replace == nil {
|
||||||
|
packageVersion = m.Version
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// userAgent returns the User-Agent header value. It includes the package name,
|
// userAgent returns the User-Agent header value. It includes the package name,
|
||||||
// the module version (if available), and the c.UserAgent value (if set).
|
// the module version (if available), and the c.UserAgent value (if set).
|
||||||
func (c *Client) userAgent() string {
|
func (c *Client) userAgent() string {
|
||||||
|
|||||||
@@ -1,27 +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.12
|
|
||||||
|
|
||||||
package acme
|
|
||||||
|
|
||||||
import "runtime/debug"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Set packageVersion if the binary was built in modules mode and x/crypto
|
|
||||||
// was not replaced with a different module.
|
|
||||||
info, ok := debug.ReadBuildInfo()
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, m := range info.Deps {
|
|
||||||
if m.Path != "golang.org/x/crypto" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if m.Replace == nil {
|
|
||||||
packageVersion = m.Version
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
|
// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
|
||||||
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
|
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
|
||||||
package bcrypt // import "golang.org/x/crypto/bcrypt"
|
package bcrypt
|
||||||
|
|
||||||
// The code is a port of Provos and Mazières's C implementation.
|
// The code is a port of Provos and Mazières's C implementation.
|
||||||
import (
|
import (
|
||||||
|
|||||||
+9
-1
@@ -16,9 +16,10 @@
|
|||||||
//
|
//
|
||||||
// BLAKE2X is a construction to compute hash values larger than 32 bytes. It
|
// BLAKE2X is a construction to compute hash values larger than 32 bytes. It
|
||||||
// can produce hash values between 0 and 65535 bytes.
|
// can produce hash values between 0 and 65535 bytes.
|
||||||
package blake2s // import "golang.org/x/crypto/blake2s"
|
package blake2s
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"hash"
|
"hash"
|
||||||
@@ -55,6 +56,13 @@ func Sum256(data []byte) [Size]byte {
|
|||||||
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
|
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
|
||||||
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
crypto.RegisterHash(crypto.BLAKE2s_256, func() hash.Hash {
|
||||||
|
h, _ := New256(nil)
|
||||||
|
return h
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
|
// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
|
||||||
// non-empty key. Note that a 128-bit digest is too small to be secure as a
|
// non-empty key. Note that a 128-bit digest is too small to be secure as a
|
||||||
// cryptographic hash and should only be used as a MAC, thus the key argument
|
// cryptographic hash and should only be used as a MAC, thus the key argument
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build go1.9
|
|
||||||
|
|
||||||
package blake2s
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
newHash256 := func() hash.Hash {
|
|
||||||
h, _ := New256(nil)
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
crypto.RegisterHash(crypto.BLAKE2s_256, newHash256)
|
|
||||||
}
|
|
||||||
+1
-1
@@ -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.
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@
|
|||||||
// elliptic curve. This package is frozen, and not implemented in constant time.
|
// elliptic curve. This package is frozen, and not implemented in constant time.
|
||||||
// There is a more complete implementation at github.com/cloudflare/bn256, but
|
// There is a more complete implementation at github.com/cloudflare/bn256, but
|
||||||
// note that it suffers from the same security issues of the underlying curve.
|
// note that it suffers from the same security issues of the underlying curve.
|
||||||
package bn256 // import "golang.org/x/crypto/bn256"
|
package bn256
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|||||||
+1
-1
@@ -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 cast5 // import "golang.org/x/crypto/cast5"
|
package cast5
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|||||||
+52
-58
@@ -33,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
|
||||||
@@ -53,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
|
||||||
@@ -70,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
|
||||||
@@ -87,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
|
||||||
|
|
||||||
@@ -97,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
|
||||||
@@ -128,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
|
||||||
@@ -165,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
|
||||||
@@ -195,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
|
||||||
@@ -225,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
|
||||||
@@ -249,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
|
||||||
@@ -431,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.
|
||||||
@@ -439,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)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
|
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
|
||||||
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
|
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
|
||||||
// draft-irtf-cfrg-xchacha-01.
|
// draft-irtf-cfrg-xchacha-01.
|
||||||
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
package chacha20poly1305
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// Package asn1 contains supporting types for parsing and building ASN.1
|
// Package asn1 contains supporting types for parsing and building ASN.1
|
||||||
// messages with the cryptobyte package.
|
// messages with the cryptobyte package.
|
||||||
package asn1 // import "golang.org/x/crypto/cryptobyte/asn1"
|
package asn1
|
||||||
|
|
||||||
// Tag represents an ASN.1 identifier octet, consisting of a tag number
|
// Tag represents an ASN.1 identifier octet, consisting of a tag number
|
||||||
// (indicating a type) and class (such as context-specific or constructed).
|
// (indicating a type) and class (such as context-specific or constructed).
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
//
|
//
|
||||||
// See the documentation and examples for the Builder and String types to get
|
// See the documentation and examples for the Builder and String types to get
|
||||||
// started.
|
// started.
|
||||||
package cryptobyte // import "golang.org/x/crypto/cryptobyte"
|
package cryptobyte
|
||||||
|
|
||||||
// String represents a string of bytes. It provides methods for parsing
|
// String represents a string of bytes. It provides methods for parsing
|
||||||
// fixed-length and length-prefixed values from it.
|
// fixed-length and length-prefixed values from it.
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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())
|
|
||||||
}
|
|
||||||
@@ -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.
|
|
||||||
@@ -1,298 +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.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
. "github.com/mmcloughlin/avo/build"
|
|
||||||
. "github.com/mmcloughlin/avo/gotypes"
|
|
||||||
. "github.com/mmcloughlin/avo/operand"
|
|
||||||
. "github.com/mmcloughlin/avo/reg"
|
|
||||||
|
|
||||||
// Ensure "go mod tidy" doesn't remove the golang.org/x/crypto module
|
|
||||||
// dependency, which is necessary to access the field.Element type.
|
|
||||||
_ "golang.org/x/crypto/curve25519"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run . -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
Package("golang.org/x/crypto/curve25519/internal/field")
|
|
||||||
ConstraintExpr("amd64,gc,!purego")
|
|
||||||
feMul()
|
|
||||||
feSquare()
|
|
||||||
Generate()
|
|
||||||
}
|
|
||||||
|
|
||||||
type namedComponent struct {
|
|
||||||
Component
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c namedComponent) String() string { return c.name }
|
|
||||||
|
|
||||||
type uint128 struct {
|
|
||||||
name string
|
|
||||||
hi, lo GPVirtual
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c uint128) String() string { return c.name }
|
|
||||||
|
|
||||||
func feSquare() {
|
|
||||||
TEXT("feSquare", NOSPLIT, "func(out, a *Element)")
|
|
||||||
Doc("feSquare sets out = a * a. It works like feSquareGeneric.")
|
|
||||||
Pragma("noescape")
|
|
||||||
|
|
||||||
a := Dereference(Param("a"))
|
|
||||||
l0 := namedComponent{a.Field("l0"), "l0"}
|
|
||||||
l1 := namedComponent{a.Field("l1"), "l1"}
|
|
||||||
l2 := namedComponent{a.Field("l2"), "l2"}
|
|
||||||
l3 := namedComponent{a.Field("l3"), "l3"}
|
|
||||||
l4 := namedComponent{a.Field("l4"), "l4"}
|
|
||||||
|
|
||||||
// r0 = l0×l0 + 19×2×(l1×l4 + l2×l3)
|
|
||||||
r0 := uint128{"r0", GP64(), GP64()}
|
|
||||||
mul64(r0, 1, l0, l0)
|
|
||||||
addMul64(r0, 38, l1, l4)
|
|
||||||
addMul64(r0, 38, l2, l3)
|
|
||||||
|
|
||||||
// r1 = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
|
|
||||||
r1 := uint128{"r1", GP64(), GP64()}
|
|
||||||
mul64(r1, 2, l0, l1)
|
|
||||||
addMul64(r1, 38, l2, l4)
|
|
||||||
addMul64(r1, 19, l3, l3)
|
|
||||||
|
|
||||||
// r2 = = 2×l0×l2 + l1×l1 + 19×2×l3×l4
|
|
||||||
r2 := uint128{"r2", GP64(), GP64()}
|
|
||||||
mul64(r2, 2, l0, l2)
|
|
||||||
addMul64(r2, 1, l1, l1)
|
|
||||||
addMul64(r2, 38, l3, l4)
|
|
||||||
|
|
||||||
// r3 = = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
|
|
||||||
r3 := uint128{"r3", GP64(), GP64()}
|
|
||||||
mul64(r3, 2, l0, l3)
|
|
||||||
addMul64(r3, 2, l1, l2)
|
|
||||||
addMul64(r3, 19, l4, l4)
|
|
||||||
|
|
||||||
// r4 = = 2×l0×l4 + 2×l1×l3 + l2×l2
|
|
||||||
r4 := uint128{"r4", GP64(), GP64()}
|
|
||||||
mul64(r4, 2, l0, l4)
|
|
||||||
addMul64(r4, 2, l1, l3)
|
|
||||||
addMul64(r4, 1, l2, l2)
|
|
||||||
|
|
||||||
Comment("First reduction chain")
|
|
||||||
maskLow51Bits := GP64()
|
|
||||||
MOVQ(Imm((1<<51)-1), maskLow51Bits)
|
|
||||||
c0, r0lo := shiftRightBy51(&r0)
|
|
||||||
c1, r1lo := shiftRightBy51(&r1)
|
|
||||||
c2, r2lo := shiftRightBy51(&r2)
|
|
||||||
c3, r3lo := shiftRightBy51(&r3)
|
|
||||||
c4, r4lo := shiftRightBy51(&r4)
|
|
||||||
maskAndAdd(r0lo, maskLow51Bits, c4, 19)
|
|
||||||
maskAndAdd(r1lo, maskLow51Bits, c0, 1)
|
|
||||||
maskAndAdd(r2lo, maskLow51Bits, c1, 1)
|
|
||||||
maskAndAdd(r3lo, maskLow51Bits, c2, 1)
|
|
||||||
maskAndAdd(r4lo, maskLow51Bits, c3, 1)
|
|
||||||
|
|
||||||
Comment("Second reduction chain (carryPropagate)")
|
|
||||||
// c0 = r0 >> 51
|
|
||||||
MOVQ(r0lo, c0)
|
|
||||||
SHRQ(Imm(51), c0)
|
|
||||||
// c1 = r1 >> 51
|
|
||||||
MOVQ(r1lo, c1)
|
|
||||||
SHRQ(Imm(51), c1)
|
|
||||||
// c2 = r2 >> 51
|
|
||||||
MOVQ(r2lo, c2)
|
|
||||||
SHRQ(Imm(51), c2)
|
|
||||||
// c3 = r3 >> 51
|
|
||||||
MOVQ(r3lo, c3)
|
|
||||||
SHRQ(Imm(51), c3)
|
|
||||||
// c4 = r4 >> 51
|
|
||||||
MOVQ(r4lo, c4)
|
|
||||||
SHRQ(Imm(51), c4)
|
|
||||||
maskAndAdd(r0lo, maskLow51Bits, c4, 19)
|
|
||||||
maskAndAdd(r1lo, maskLow51Bits, c0, 1)
|
|
||||||
maskAndAdd(r2lo, maskLow51Bits, c1, 1)
|
|
||||||
maskAndAdd(r3lo, maskLow51Bits, c2, 1)
|
|
||||||
maskAndAdd(r4lo, maskLow51Bits, c3, 1)
|
|
||||||
|
|
||||||
Comment("Store output")
|
|
||||||
out := Dereference(Param("out"))
|
|
||||||
Store(r0lo, out.Field("l0"))
|
|
||||||
Store(r1lo, out.Field("l1"))
|
|
||||||
Store(r2lo, out.Field("l2"))
|
|
||||||
Store(r3lo, out.Field("l3"))
|
|
||||||
Store(r4lo, out.Field("l4"))
|
|
||||||
|
|
||||||
RET()
|
|
||||||
}
|
|
||||||
|
|
||||||
func feMul() {
|
|
||||||
TEXT("feMul", NOSPLIT, "func(out, a, b *Element)")
|
|
||||||
Doc("feMul sets out = a * b. It works like feMulGeneric.")
|
|
||||||
Pragma("noescape")
|
|
||||||
|
|
||||||
a := Dereference(Param("a"))
|
|
||||||
a0 := namedComponent{a.Field("l0"), "a0"}
|
|
||||||
a1 := namedComponent{a.Field("l1"), "a1"}
|
|
||||||
a2 := namedComponent{a.Field("l2"), "a2"}
|
|
||||||
a3 := namedComponent{a.Field("l3"), "a3"}
|
|
||||||
a4 := namedComponent{a.Field("l4"), "a4"}
|
|
||||||
|
|
||||||
b := Dereference(Param("b"))
|
|
||||||
b0 := namedComponent{b.Field("l0"), "b0"}
|
|
||||||
b1 := namedComponent{b.Field("l1"), "b1"}
|
|
||||||
b2 := namedComponent{b.Field("l2"), "b2"}
|
|
||||||
b3 := namedComponent{b.Field("l3"), "b3"}
|
|
||||||
b4 := namedComponent{b.Field("l4"), "b4"}
|
|
||||||
|
|
||||||
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
|
|
||||||
r0 := uint128{"r0", GP64(), GP64()}
|
|
||||||
mul64(r0, 1, a0, b0)
|
|
||||||
addMul64(r0, 19, a1, b4)
|
|
||||||
addMul64(r0, 19, a2, b3)
|
|
||||||
addMul64(r0, 19, a3, b2)
|
|
||||||
addMul64(r0, 19, a4, b1)
|
|
||||||
|
|
||||||
// r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
|
|
||||||
r1 := uint128{"r1", GP64(), GP64()}
|
|
||||||
mul64(r1, 1, a0, b1)
|
|
||||||
addMul64(r1, 1, a1, b0)
|
|
||||||
addMul64(r1, 19, a2, b4)
|
|
||||||
addMul64(r1, 19, a3, b3)
|
|
||||||
addMul64(r1, 19, a4, b2)
|
|
||||||
|
|
||||||
// r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
|
|
||||||
r2 := uint128{"r2", GP64(), GP64()}
|
|
||||||
mul64(r2, 1, a0, b2)
|
|
||||||
addMul64(r2, 1, a1, b1)
|
|
||||||
addMul64(r2, 1, a2, b0)
|
|
||||||
addMul64(r2, 19, a3, b4)
|
|
||||||
addMul64(r2, 19, a4, b3)
|
|
||||||
|
|
||||||
// r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
|
|
||||||
r3 := uint128{"r3", GP64(), GP64()}
|
|
||||||
mul64(r3, 1, a0, b3)
|
|
||||||
addMul64(r3, 1, a1, b2)
|
|
||||||
addMul64(r3, 1, a2, b1)
|
|
||||||
addMul64(r3, 1, a3, b0)
|
|
||||||
addMul64(r3, 19, a4, b4)
|
|
||||||
|
|
||||||
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
|
|
||||||
r4 := uint128{"r4", GP64(), GP64()}
|
|
||||||
mul64(r4, 1, a0, b4)
|
|
||||||
addMul64(r4, 1, a1, b3)
|
|
||||||
addMul64(r4, 1, a2, b2)
|
|
||||||
addMul64(r4, 1, a3, b1)
|
|
||||||
addMul64(r4, 1, a4, b0)
|
|
||||||
|
|
||||||
Comment("First reduction chain")
|
|
||||||
maskLow51Bits := GP64()
|
|
||||||
MOVQ(Imm((1<<51)-1), maskLow51Bits)
|
|
||||||
c0, r0lo := shiftRightBy51(&r0)
|
|
||||||
c1, r1lo := shiftRightBy51(&r1)
|
|
||||||
c2, r2lo := shiftRightBy51(&r2)
|
|
||||||
c3, r3lo := shiftRightBy51(&r3)
|
|
||||||
c4, r4lo := shiftRightBy51(&r4)
|
|
||||||
maskAndAdd(r0lo, maskLow51Bits, c4, 19)
|
|
||||||
maskAndAdd(r1lo, maskLow51Bits, c0, 1)
|
|
||||||
maskAndAdd(r2lo, maskLow51Bits, c1, 1)
|
|
||||||
maskAndAdd(r3lo, maskLow51Bits, c2, 1)
|
|
||||||
maskAndAdd(r4lo, maskLow51Bits, c3, 1)
|
|
||||||
|
|
||||||
Comment("Second reduction chain (carryPropagate)")
|
|
||||||
// c0 = r0 >> 51
|
|
||||||
MOVQ(r0lo, c0)
|
|
||||||
SHRQ(Imm(51), c0)
|
|
||||||
// c1 = r1 >> 51
|
|
||||||
MOVQ(r1lo, c1)
|
|
||||||
SHRQ(Imm(51), c1)
|
|
||||||
// c2 = r2 >> 51
|
|
||||||
MOVQ(r2lo, c2)
|
|
||||||
SHRQ(Imm(51), c2)
|
|
||||||
// c3 = r3 >> 51
|
|
||||||
MOVQ(r3lo, c3)
|
|
||||||
SHRQ(Imm(51), c3)
|
|
||||||
// c4 = r4 >> 51
|
|
||||||
MOVQ(r4lo, c4)
|
|
||||||
SHRQ(Imm(51), c4)
|
|
||||||
maskAndAdd(r0lo, maskLow51Bits, c4, 19)
|
|
||||||
maskAndAdd(r1lo, maskLow51Bits, c0, 1)
|
|
||||||
maskAndAdd(r2lo, maskLow51Bits, c1, 1)
|
|
||||||
maskAndAdd(r3lo, maskLow51Bits, c2, 1)
|
|
||||||
maskAndAdd(r4lo, maskLow51Bits, c3, 1)
|
|
||||||
|
|
||||||
Comment("Store output")
|
|
||||||
out := Dereference(Param("out"))
|
|
||||||
Store(r0lo, out.Field("l0"))
|
|
||||||
Store(r1lo, out.Field("l1"))
|
|
||||||
Store(r2lo, out.Field("l2"))
|
|
||||||
Store(r3lo, out.Field("l3"))
|
|
||||||
Store(r4lo, out.Field("l4"))
|
|
||||||
|
|
||||||
RET()
|
|
||||||
}
|
|
||||||
|
|
||||||
// mul64 sets r to i * aX * bX.
|
|
||||||
func mul64(r uint128, i int, aX, bX namedComponent) {
|
|
||||||
switch i {
|
|
||||||
case 1:
|
|
||||||
Comment(fmt.Sprintf("%s = %s×%s", r, aX, bX))
|
|
||||||
Load(aX, RAX)
|
|
||||||
case 2:
|
|
||||||
Comment(fmt.Sprintf("%s = 2×%s×%s", r, aX, bX))
|
|
||||||
Load(aX, RAX)
|
|
||||||
SHLQ(Imm(1), RAX)
|
|
||||||
default:
|
|
||||||
panic("unsupported i value")
|
|
||||||
}
|
|
||||||
MULQ(mustAddr(bX)) // RDX, RAX = RAX * bX
|
|
||||||
MOVQ(RAX, r.lo)
|
|
||||||
MOVQ(RDX, r.hi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addMul64 sets r to r + i * aX * bX.
|
|
||||||
func addMul64(r uint128, i uint64, aX, bX namedComponent) {
|
|
||||||
switch i {
|
|
||||||
case 1:
|
|
||||||
Comment(fmt.Sprintf("%s += %s×%s", r, aX, bX))
|
|
||||||
Load(aX, RAX)
|
|
||||||
default:
|
|
||||||
Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
|
|
||||||
IMUL3Q(Imm(i), Load(aX, GP64()), RAX)
|
|
||||||
}
|
|
||||||
MULQ(mustAddr(bX)) // RDX, RAX = RAX * bX
|
|
||||||
ADDQ(RAX, r.lo)
|
|
||||||
ADCQ(RDX, r.hi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shiftRightBy51 returns r >> 51 and r.lo.
|
|
||||||
//
|
|
||||||
// After this function is called, the uint128 may not be used anymore.
|
|
||||||
func shiftRightBy51(r *uint128) (out, lo GPVirtual) {
|
|
||||||
out = r.hi
|
|
||||||
lo = r.lo
|
|
||||||
SHLQ(Imm(64-51), r.lo, r.hi)
|
|
||||||
r.lo, r.hi = nil, nil // make sure the uint128 is unusable
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// maskAndAdd sets r = r&mask + c*i.
|
|
||||||
func maskAndAdd(r, mask, c GPVirtual, i uint64) {
|
|
||||||
ANDQ(mask, r)
|
|
||||||
if i != 1 {
|
|
||||||
IMUL3Q(Imm(i), c, c)
|
|
||||||
}
|
|
||||||
ADDQ(c, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustAddr(c Component) Op {
|
|
||||||
b, err := c.Resolve()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return b.Addr
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
module asm
|
|
||||||
|
|
||||||
go 1.18
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/mmcloughlin/avo v0.5.0
|
|
||||||
golang.org/x/crypto v0.1.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace golang.org/x/crypto v0.1.0 => ../../../..
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU=
|
|
||||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
|
||||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
|
||||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
|
||||||
golang.org/x/sys v0.14.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-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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -1,126 +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.
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"testing/quick"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkAliasingOneArg(f func(v, x *Element) *Element) func(v, x Element) bool {
|
|
||||||
return func(v, x Element) bool {
|
|
||||||
x1, v1 := x, x
|
|
||||||
|
|
||||||
// Calculate a reference f(x) without aliasing.
|
|
||||||
if out := f(&v, &x); out != &v && isInBounds(out) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test aliasing the argument and the receiver.
|
|
||||||
if out := f(&v1, &v1); out != &v1 || v1 != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the arguments was not modified.
|
|
||||||
return x == x1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAliasingTwoArgs(f func(v, x, y *Element) *Element) func(v, x, y Element) bool {
|
|
||||||
return func(v, x, y Element) bool {
|
|
||||||
x1, y1, v1 := x, y, Element{}
|
|
||||||
|
|
||||||
// Calculate a reference f(x, y) without aliasing.
|
|
||||||
if out := f(&v, &x, &y); out != &v && isInBounds(out) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test aliasing the first argument and the receiver.
|
|
||||||
v1 = x
|
|
||||||
if out := f(&v1, &v1, &y); out != &v1 || v1 != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Test aliasing the second argument and the receiver.
|
|
||||||
v1 = y
|
|
||||||
if out := f(&v1, &x, &v1); out != &v1 || v1 != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate a reference f(x, x) without aliasing.
|
|
||||||
if out := f(&v, &x, &x); out != &v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test aliasing the first argument and the receiver.
|
|
||||||
v1 = x
|
|
||||||
if out := f(&v1, &v1, &x); out != &v1 || v1 != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Test aliasing the second argument and the receiver.
|
|
||||||
v1 = x
|
|
||||||
if out := f(&v1, &x, &v1); out != &v1 || v1 != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Test aliasing both arguments and the receiver.
|
|
||||||
v1 = x
|
|
||||||
if out := f(&v1, &v1, &v1); out != &v1 || v1 != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the arguments were not modified.
|
|
||||||
return x == x1 && y == y1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestAliasing checks that receivers and arguments can alias each other without
|
|
||||||
// leading to incorrect results. That is, it ensures that it's safe to write
|
|
||||||
//
|
|
||||||
// v.Invert(v)
|
|
||||||
//
|
|
||||||
// or
|
|
||||||
//
|
|
||||||
// v.Add(v, v)
|
|
||||||
//
|
|
||||||
// without any of the inputs getting clobbered by the output being written.
|
|
||||||
func TestAliasing(t *testing.T) {
|
|
||||||
type target struct {
|
|
||||||
name string
|
|
||||||
oneArgF func(v, x *Element) *Element
|
|
||||||
twoArgsF func(v, x, y *Element) *Element
|
|
||||||
}
|
|
||||||
for _, tt := range []target{
|
|
||||||
{name: "Absolute", oneArgF: (*Element).Absolute},
|
|
||||||
{name: "Invert", oneArgF: (*Element).Invert},
|
|
||||||
{name: "Negate", oneArgF: (*Element).Negate},
|
|
||||||
{name: "Set", oneArgF: (*Element).Set},
|
|
||||||
{name: "Square", oneArgF: (*Element).Square},
|
|
||||||
{name: "Multiply", twoArgsF: (*Element).Multiply},
|
|
||||||
{name: "Add", twoArgsF: (*Element).Add},
|
|
||||||
{name: "Subtract", twoArgsF: (*Element).Subtract},
|
|
||||||
{
|
|
||||||
name: "Select0",
|
|
||||||
twoArgsF: func(v, x, y *Element) *Element {
|
|
||||||
return (*Element).Select(v, x, y, 0)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Select1",
|
|
||||||
twoArgsF: func(v, x, y *Element) *Element {
|
|
||||||
return (*Element).Select(v, x, y, 1)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
var err error
|
|
||||||
switch {
|
|
||||||
case tt.oneArgF != nil:
|
|
||||||
err = quick.Check(checkAliasingOneArg(tt.oneArgF), &quick.Config{MaxCountScale: 1 << 8})
|
|
||||||
case tt.twoArgsF != nil:
|
|
||||||
err = quick.Check(checkAliasingTwoArgs(tt.twoArgsF), &quick.Config{MaxCountScale: 1 << 8})
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v: %v", tt.name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +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
|
|
||||||
|
|
||||||
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)
|
|
||||||
@@ -1,378 +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
|
|
||||||
|
|
||||||
#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
|
|
||||||
@@ -1,11 +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
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
|
|
||||||
|
|
||||||
func feSquare(v, x *Element) { feSquareGeneric(v, x) }
|
|
||||||
@@ -1,15 +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
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func carryPropagate(v *Element)
|
|
||||||
|
|
||||||
func (v *Element) carryPropagate() *Element {
|
|
||||||
carryPropagate(v)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
@@ -1,42 +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
|
|
||||||
|
|
||||||
#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
|
|
||||||
@@ -1,11 +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
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
func (v *Element) carryPropagate() *Element {
|
|
||||||
return v.carryPropagateGeneric()
|
|
||||||
}
|
|
||||||
@@ -1,36 +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.
|
|
||||||
|
|
||||||
package field
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func BenchmarkAdd(b *testing.B) {
|
|
||||||
var x, y Element
|
|
||||||
x.One()
|
|
||||||
y.Add(feOne, feOne)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
x.Add(&x, &y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMultiply(b *testing.B) {
|
|
||||||
var x, y Element
|
|
||||||
x.One()
|
|
||||||
y.Add(feOne, feOne)
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
x.Multiply(&x, &y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkMult32(b *testing.B) {
|
|
||||||
var x Element
|
|
||||||
x.One()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
x.Mult32(&x, 0xaa42aa42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -1,558 +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 (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"math/bits"
|
|
||||||
mathrand "math/rand"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"testing/quick"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (v Element) String() string {
|
|
||||||
return hex.EncodeToString(v.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
// quickCheckConfig1024 will make each quickcheck test run (1024 * -quickchecks)
|
|
||||||
// times. The default value of -quickchecks is 100.
|
|
||||||
var quickCheckConfig1024 = &quick.Config{MaxCountScale: 1 << 10}
|
|
||||||
|
|
||||||
func generateFieldElement(rand *mathrand.Rand) Element {
|
|
||||||
const maskLow52Bits = (1 << 52) - 1
|
|
||||||
return Element{
|
|
||||||
rand.Uint64() & maskLow52Bits,
|
|
||||||
rand.Uint64() & maskLow52Bits,
|
|
||||||
rand.Uint64() & maskLow52Bits,
|
|
||||||
rand.Uint64() & maskLow52Bits,
|
|
||||||
rand.Uint64() & maskLow52Bits,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// weirdLimbs can be combined to generate a range of edge-case field elements.
|
|
||||||
// 0 and -1 are intentionally more weighted, as they combine well.
|
|
||||||
var (
|
|
||||||
weirdLimbs51 = []uint64{
|
|
||||||
0, 0, 0, 0,
|
|
||||||
1,
|
|
||||||
19 - 1,
|
|
||||||
19,
|
|
||||||
0x2aaaaaaaaaaaa,
|
|
||||||
0x5555555555555,
|
|
||||||
(1 << 51) - 20,
|
|
||||||
(1 << 51) - 19,
|
|
||||||
(1 << 51) - 1, (1 << 51) - 1,
|
|
||||||
(1 << 51) - 1, (1 << 51) - 1,
|
|
||||||
}
|
|
||||||
weirdLimbs52 = []uint64{
|
|
||||||
0, 0, 0, 0, 0, 0,
|
|
||||||
1,
|
|
||||||
19 - 1,
|
|
||||||
19,
|
|
||||||
0x2aaaaaaaaaaaa,
|
|
||||||
0x5555555555555,
|
|
||||||
(1 << 51) - 20,
|
|
||||||
(1 << 51) - 19,
|
|
||||||
(1 << 51) - 1, (1 << 51) - 1,
|
|
||||||
(1 << 51) - 1, (1 << 51) - 1,
|
|
||||||
(1 << 51) - 1, (1 << 51) - 1,
|
|
||||||
1 << 51,
|
|
||||||
(1 << 51) + 1,
|
|
||||||
(1 << 52) - 19,
|
|
||||||
(1 << 52) - 1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func generateWeirdFieldElement(rand *mathrand.Rand) Element {
|
|
||||||
return Element{
|
|
||||||
weirdLimbs52[rand.Intn(len(weirdLimbs52))],
|
|
||||||
weirdLimbs51[rand.Intn(len(weirdLimbs51))],
|
|
||||||
weirdLimbs51[rand.Intn(len(weirdLimbs51))],
|
|
||||||
weirdLimbs51[rand.Intn(len(weirdLimbs51))],
|
|
||||||
weirdLimbs51[rand.Intn(len(weirdLimbs51))],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Element) Generate(rand *mathrand.Rand, size int) reflect.Value {
|
|
||||||
if rand.Intn(2) == 0 {
|
|
||||||
return reflect.ValueOf(generateWeirdFieldElement(rand))
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(generateFieldElement(rand))
|
|
||||||
}
|
|
||||||
|
|
||||||
// isInBounds returns whether the element is within the expected bit size bounds
|
|
||||||
// after a light reduction.
|
|
||||||
func isInBounds(x *Element) bool {
|
|
||||||
return bits.Len64(x.l0) <= 52 &&
|
|
||||||
bits.Len64(x.l1) <= 52 &&
|
|
||||||
bits.Len64(x.l2) <= 52 &&
|
|
||||||
bits.Len64(x.l3) <= 52 &&
|
|
||||||
bits.Len64(x.l4) <= 52
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMultiplyDistributesOverAdd(t *testing.T) {
|
|
||||||
multiplyDistributesOverAdd := func(x, y, z Element) bool {
|
|
||||||
// Compute t1 = (x+y)*z
|
|
||||||
t1 := new(Element)
|
|
||||||
t1.Add(&x, &y)
|
|
||||||
t1.Multiply(t1, &z)
|
|
||||||
|
|
||||||
// Compute t2 = x*z + y*z
|
|
||||||
t2 := new(Element)
|
|
||||||
t3 := new(Element)
|
|
||||||
t2.Multiply(&x, &z)
|
|
||||||
t3.Multiply(&y, &z)
|
|
||||||
t2.Add(t2, t3)
|
|
||||||
|
|
||||||
return t1.Equal(t2) == 1 && isInBounds(t1) && isInBounds(t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quick.Check(multiplyDistributesOverAdd, quickCheckConfig1024); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMul64to128(t *testing.T) {
|
|
||||||
a := uint64(5)
|
|
||||||
b := uint64(5)
|
|
||||||
r := mul64(a, b)
|
|
||||||
if r.lo != 0x19 || r.hi != 0 {
|
|
||||||
t.Errorf("lo-range wide mult failed, got %d + %d*(2**64)", r.lo, r.hi)
|
|
||||||
}
|
|
||||||
|
|
||||||
a = uint64(18014398509481983) // 2^54 - 1
|
|
||||||
b = uint64(18014398509481983) // 2^54 - 1
|
|
||||||
r = mul64(a, b)
|
|
||||||
if r.lo != 0xff80000000000001 || r.hi != 0xfffffffffff {
|
|
||||||
t.Errorf("hi-range wide mult failed, got %d + %d*(2**64)", r.lo, r.hi)
|
|
||||||
}
|
|
||||||
|
|
||||||
a = uint64(1125899906842661)
|
|
||||||
b = uint64(2097155)
|
|
||||||
r = mul64(a, b)
|
|
||||||
r = addMul64(r, a, b)
|
|
||||||
r = addMul64(r, a, b)
|
|
||||||
r = addMul64(r, a, b)
|
|
||||||
r = addMul64(r, a, b)
|
|
||||||
if r.lo != 16888498990613035 || r.hi != 640 {
|
|
||||||
t.Errorf("wrong answer: %d + %d*(2**64)", r.lo, r.hi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetBytesRoundTrip(t *testing.T) {
|
|
||||||
f1 := func(in [32]byte, fe Element) bool {
|
|
||||||
fe.SetBytes(in[:])
|
|
||||||
|
|
||||||
// Mask the most significant bit as it's ignored by SetBytes. (Now
|
|
||||||
// instead of earlier so we check the masking in SetBytes is working.)
|
|
||||||
in[len(in)-1] &= (1 << 7) - 1
|
|
||||||
|
|
||||||
return bytes.Equal(in[:], fe.Bytes()) && isInBounds(&fe)
|
|
||||||
}
|
|
||||||
if err := quick.Check(f1, nil); err != nil {
|
|
||||||
t.Errorf("failed bytes->FE->bytes round-trip: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f2 := func(fe, r Element) bool {
|
|
||||||
r.SetBytes(fe.Bytes())
|
|
||||||
|
|
||||||
// Intentionally not using Equal not to go through Bytes again.
|
|
||||||
// Calling reduce because both Generate and SetBytes can produce
|
|
||||||
// non-canonical representations.
|
|
||||||
fe.reduce()
|
|
||||||
r.reduce()
|
|
||||||
return fe == r
|
|
||||||
}
|
|
||||||
if err := quick.Check(f2, nil); err != nil {
|
|
||||||
t.Errorf("failed FE->bytes->FE round-trip: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check some fixed vectors from dalek
|
|
||||||
type feRTTest struct {
|
|
||||||
fe Element
|
|
||||||
b []byte
|
|
||||||
}
|
|
||||||
var tests = []feRTTest{
|
|
||||||
{
|
|
||||||
fe: Element{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676},
|
|
||||||
b: []byte{74, 209, 69, 197, 70, 70, 161, 222, 56, 226, 229, 19, 112, 60, 25, 92, 187, 74, 222, 56, 50, 153, 51, 233, 40, 74, 57, 6, 160, 185, 213, 31},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fe: Element{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972},
|
|
||||||
b: []byte{199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250, 44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 122},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
b := tt.fe.Bytes()
|
|
||||||
if !bytes.Equal(b, tt.b) || new(Element).SetBytes(tt.b).Equal(&tt.fe) != 1 {
|
|
||||||
t.Errorf("Failed fixed roundtrip: %v", tt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func swapEndianness(buf []byte) []byte {
|
|
||||||
for i := 0; i < len(buf)/2; i++ {
|
|
||||||
buf[i], buf[len(buf)-i-1] = buf[len(buf)-i-1], buf[i]
|
|
||||||
}
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBytesBigEquivalence(t *testing.T) {
|
|
||||||
f1 := func(in [32]byte, fe, fe1 Element) bool {
|
|
||||||
fe.SetBytes(in[:])
|
|
||||||
|
|
||||||
in[len(in)-1] &= (1 << 7) - 1 // mask the most significant bit
|
|
||||||
b := new(big.Int).SetBytes(swapEndianness(in[:]))
|
|
||||||
fe1.fromBig(b)
|
|
||||||
|
|
||||||
if fe != fe1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, 32) // pad with zeroes
|
|
||||||
copy(buf, swapEndianness(fe1.toBig().Bytes()))
|
|
||||||
|
|
||||||
return bytes.Equal(fe.Bytes(), buf) && isInBounds(&fe) && isInBounds(&fe1)
|
|
||||||
}
|
|
||||||
if err := quick.Check(f1, nil); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fromBig sets v = n, and returns v. The bit length of n must not exceed 256.
|
|
||||||
func (v *Element) fromBig(n *big.Int) *Element {
|
|
||||||
if n.BitLen() > 32*8 {
|
|
||||||
panic("edwards25519: invalid field element input size")
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, 0, 32)
|
|
||||||
for _, word := range n.Bits() {
|
|
||||||
for i := 0; i < bits.UintSize; i += 8 {
|
|
||||||
if len(buf) >= cap(buf) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
buf = append(buf, byte(word))
|
|
||||||
word >>= 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return v.SetBytes(buf[:32])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Element) fromDecimal(s string) *Element {
|
|
||||||
n, ok := new(big.Int).SetString(s, 10)
|
|
||||||
if !ok {
|
|
||||||
panic("not a valid decimal: " + s)
|
|
||||||
}
|
|
||||||
return v.fromBig(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// toBig returns v as a big.Int.
|
|
||||||
func (v *Element) toBig() *big.Int {
|
|
||||||
buf := v.Bytes()
|
|
||||||
|
|
||||||
words := make([]big.Word, 32*8/bits.UintSize)
|
|
||||||
for n := range words {
|
|
||||||
for i := 0; i < bits.UintSize; i += 8 {
|
|
||||||
if len(buf) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
words[n] |= big.Word(buf[0]) << big.Word(i)
|
|
||||||
buf = buf[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new(big.Int).SetBits(words)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecimalConstants(t *testing.T) {
|
|
||||||
sqrtM1String := "19681161376707505956807079304988542015446066515923890162744021073123829784752"
|
|
||||||
if exp := new(Element).fromDecimal(sqrtM1String); sqrtM1.Equal(exp) != 1 {
|
|
||||||
t.Errorf("sqrtM1 is %v, expected %v", sqrtM1, exp)
|
|
||||||
}
|
|
||||||
// d is in the parent package, and we don't want to expose d or fromDecimal.
|
|
||||||
// dString := "37095705934669439343138083508754565189542113879843219016388785533085940283555"
|
|
||||||
// if exp := new(Element).fromDecimal(dString); d.Equal(exp) != 1 {
|
|
||||||
// t.Errorf("d is %v, expected %v", d, exp)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetBytesRoundTripEdgeCases(t *testing.T) {
|
|
||||||
// TODO: values close to 0, close to 2^255-19, between 2^255-19 and 2^255-1,
|
|
||||||
// and between 2^255 and 2^256-1. Test both the documented SetBytes
|
|
||||||
// behavior, and that Bytes reduces them.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests self-consistency between Multiply and Square.
|
|
||||||
func TestConsistency(t *testing.T) {
|
|
||||||
var x Element
|
|
||||||
var x2, x2sq Element
|
|
||||||
|
|
||||||
x = Element{1, 1, 1, 1, 1}
|
|
||||||
x2.Multiply(&x, &x)
|
|
||||||
x2sq.Square(&x)
|
|
||||||
|
|
||||||
if x2 != x2sq {
|
|
||||||
t.Fatalf("all ones failed\nmul: %x\nsqr: %x\n", x2, x2sq)
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes [32]byte
|
|
||||||
|
|
||||||
_, err := io.ReadFull(rand.Reader, bytes[:])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
x.SetBytes(bytes[:])
|
|
||||||
|
|
||||||
x2.Multiply(&x, &x)
|
|
||||||
x2sq.Square(&x)
|
|
||||||
|
|
||||||
if x2 != x2sq {
|
|
||||||
t.Fatalf("all ones failed\nmul: %x\nsqr: %x\n", x2, x2sq)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEqual(t *testing.T) {
|
|
||||||
x := Element{1, 1, 1, 1, 1}
|
|
||||||
y := Element{5, 4, 3, 2, 1}
|
|
||||||
|
|
||||||
eq := x.Equal(&x)
|
|
||||||
if eq != 1 {
|
|
||||||
t.Errorf("wrong about equality")
|
|
||||||
}
|
|
||||||
|
|
||||||
eq = x.Equal(&y)
|
|
||||||
if eq != 0 {
|
|
||||||
t.Errorf("wrong about inequality")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInvert(t *testing.T) {
|
|
||||||
x := Element{1, 1, 1, 1, 1}
|
|
||||||
one := Element{1, 0, 0, 0, 0}
|
|
||||||
var xinv, r Element
|
|
||||||
|
|
||||||
xinv.Invert(&x)
|
|
||||||
r.Multiply(&x, &xinv)
|
|
||||||
r.reduce()
|
|
||||||
|
|
||||||
if one != r {
|
|
||||||
t.Errorf("inversion identity failed, got: %x", r)
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes [32]byte
|
|
||||||
|
|
||||||
_, err := io.ReadFull(rand.Reader, bytes[:])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
x.SetBytes(bytes[:])
|
|
||||||
|
|
||||||
xinv.Invert(&x)
|
|
||||||
r.Multiply(&x, &xinv)
|
|
||||||
r.reduce()
|
|
||||||
|
|
||||||
if one != r {
|
|
||||||
t.Errorf("random inversion identity failed, got: %x for field element %x", r, x)
|
|
||||||
}
|
|
||||||
|
|
||||||
zero := Element{}
|
|
||||||
x.Set(&zero)
|
|
||||||
if xx := xinv.Invert(&x); xx != &xinv {
|
|
||||||
t.Errorf("inverting zero did not return the receiver")
|
|
||||||
} else if xinv.Equal(&zero) != 1 {
|
|
||||||
t.Errorf("inverting zero did not return zero")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectSwap(t *testing.T) {
|
|
||||||
a := Element{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676}
|
|
||||||
b := Element{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972}
|
|
||||||
|
|
||||||
var c, d Element
|
|
||||||
|
|
||||||
c.Select(&a, &b, 1)
|
|
||||||
d.Select(&a, &b, 0)
|
|
||||||
|
|
||||||
if c.Equal(&a) != 1 || d.Equal(&b) != 1 {
|
|
||||||
t.Errorf("Select failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Swap(&d, 0)
|
|
||||||
|
|
||||||
if c.Equal(&a) != 1 || d.Equal(&b) != 1 {
|
|
||||||
t.Errorf("Swap failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Swap(&d, 1)
|
|
||||||
|
|
||||||
if c.Equal(&b) != 1 || d.Equal(&a) != 1 {
|
|
||||||
t.Errorf("Swap failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMult32(t *testing.T) {
|
|
||||||
mult32EquivalentToMul := func(x Element, y uint32) bool {
|
|
||||||
t1 := new(Element)
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
t1.Mult32(&x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty := new(Element)
|
|
||||||
ty.l0 = uint64(y)
|
|
||||||
|
|
||||||
t2 := new(Element)
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
t2.Multiply(&x, ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
return t1.Equal(t2) == 1 && isInBounds(t1) && isInBounds(t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quick.Check(mult32EquivalentToMul, quickCheckConfig1024); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSqrtRatio(t *testing.T) {
|
|
||||||
// From draft-irtf-cfrg-ristretto255-decaf448-00, Appendix A.4.
|
|
||||||
type test struct {
|
|
||||||
u, v string
|
|
||||||
wasSquare int
|
|
||||||
r string
|
|
||||||
}
|
|
||||||
var tests = []test{
|
|
||||||
// If u is 0, the function is defined to return (0, TRUE), even if v
|
|
||||||
// is zero. Note that where used in this package, the denominator v
|
|
||||||
// is never zero.
|
|
||||||
{
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
1, "0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
// 0/1 == 0²
|
|
||||||
{
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
1, "0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
// If u is non-zero and v is zero, defined to return (0, FALSE).
|
|
||||||
{
|
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
0, "0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
// 2/1 is not square in this field.
|
|
||||||
{
|
|
||||||
"0200000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
0, "3c5ff1b5d8e4113b871bd052f9e7bcd0582804c266ffb2d4f4203eb07fdb7c54",
|
|
||||||
},
|
|
||||||
// 4/1 == 2²
|
|
||||||
{
|
|
||||||
"0400000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
1, "0200000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
// 1/4 == (2⁻¹)² == (2^(p-2))² per Euler's theorem
|
|
||||||
{
|
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0400000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
1, "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
u := new(Element).SetBytes(decodeHex(tt.u))
|
|
||||||
v := new(Element).SetBytes(decodeHex(tt.v))
|
|
||||||
want := new(Element).SetBytes(decodeHex(tt.r))
|
|
||||||
got, wasSquare := new(Element).SqrtRatio(u, v)
|
|
||||||
if got.Equal(want) == 0 || wasSquare != tt.wasSquare {
|
|
||||||
t.Errorf("%d: got (%v, %v), want (%v, %v)", i, got, wasSquare, want, tt.wasSquare)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCarryPropagate(t *testing.T) {
|
|
||||||
asmLikeGeneric := func(a [5]uint64) bool {
|
|
||||||
t1 := &Element{a[0], a[1], a[2], a[3], a[4]}
|
|
||||||
t2 := &Element{a[0], a[1], a[2], a[3], a[4]}
|
|
||||||
|
|
||||||
t1.carryPropagate()
|
|
||||||
t2.carryPropagateGeneric()
|
|
||||||
|
|
||||||
if *t1 != *t2 {
|
|
||||||
t.Logf("got: %#v,\nexpected: %#v", t1, t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return *t1 == *t2 && isInBounds(t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quick.Check(asmLikeGeneric, quickCheckConfig1024); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !asmLikeGeneric([5]uint64{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}) {
|
|
||||||
t.Errorf("failed for {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFeSquare(t *testing.T) {
|
|
||||||
asmLikeGeneric := func(a Element) bool {
|
|
||||||
t1 := a
|
|
||||||
t2 := a
|
|
||||||
|
|
||||||
feSquareGeneric(&t1, &t1)
|
|
||||||
feSquare(&t2, &t2)
|
|
||||||
|
|
||||||
if t1 != t2 {
|
|
||||||
t.Logf("got: %#v,\nexpected: %#v", t1, t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return t1 == t2 && isInBounds(&t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quick.Check(asmLikeGeneric, quickCheckConfig1024); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFeMul(t *testing.T) {
|
|
||||||
asmLikeGeneric := func(a, b Element) bool {
|
|
||||||
a1 := a
|
|
||||||
a2 := a
|
|
||||||
b1 := b
|
|
||||||
b2 := b
|
|
||||||
|
|
||||||
feMulGeneric(&a1, &a1, &b1)
|
|
||||||
feMul(&a2, &a2, &b2)
|
|
||||||
|
|
||||||
if a1 != a2 || b1 != b2 {
|
|
||||||
t.Logf("got: %#v,\nexpected: %#v", a1, a2)
|
|
||||||
t.Logf("got: %#v,\nexpected: %#v", b1, b2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return a1 == a2 && isInBounds(&a2) &&
|
|
||||||
b1 == b2 && isInBounds(&b2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quick.Check(asmLikeGeneric, quickCheckConfig1024); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeHex(s string) []byte {
|
|
||||||
b, err := hex.DecodeString(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
b0c49ae9f59d233526f8934262c5bbbe14d4358d
|
|
||||||
@@ -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
|
|
||||||
+1
-3
@@ -11,9 +11,7 @@
|
|||||||
// operations with the same key more efficient. This package refers to the RFC
|
// operations with the same key more efficient. This package refers to the RFC
|
||||||
// 8032 private key as the “seed”.
|
// 8032 private key as the “seed”.
|
||||||
//
|
//
|
||||||
// Beginning with Go 1.13, the functionality of this package was moved to the
|
// This package is a wrapper around the standard library crypto/ed25519 package.
|
||||||
// standard library as crypto/ed25519. This package only acts as a compatibility
|
|
||||||
// wrapper.
|
|
||||||
package ed25519
|
package ed25519
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
module golang.org/x/crypto
|
module golang.org/x/crypto
|
||||||
|
|
||||||
go 1.18
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/net v0.10.0 // tagx:ignore
|
golang.org/x/net v0.21.0 // tagx:ignore
|
||||||
golang.org/x/sys v0.16.0
|
golang.org/x/sys v0.22.0
|
||||||
golang.org/x/term v0.16.0
|
golang.org/x/term v0.22.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/text v0.14.0 // indirect
|
require golang.org/x/text v0.16.0 // indirect
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
// HKDF is a cryptographic key derivation function (KDF) with the goal of
|
// HKDF is a cryptographic key derivation function (KDF) with the goal of
|
||||||
// expanding limited input keying material into one or more cryptographically
|
// expanding limited input keying material into one or more cryptographically
|
||||||
// strong secret keys.
|
// strong secret keys.
|
||||||
package hkdf // import "golang.org/x/crypto/hkdf"
|
package hkdf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
|
|||||||
@@ -19,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; \
|
||||||
@@ -37,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; \
|
||||||
@@ -75,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
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ func CommandContext(t testing.TB, ctx context.Context, name string, args ...stri
|
|||||||
// grace periods to clean up: one for the delay between the first
|
// grace periods to clean up: one for the delay between the first
|
||||||
// termination signal being sent (via the Cancel callback when the Context
|
// termination signal being sent (via the Cancel callback when the Context
|
||||||
// expires) and the process being forcibly terminated (via the WaitDelay
|
// expires) and the process being forcibly terminated (via the WaitDelay
|
||||||
// field), and a second one for the delay becween the process being
|
// field), and a second one for the delay between the process being
|
||||||
// terminated and and the test logging its output for debugging.
|
// terminated and the test logging its output for debugging.
|
||||||
//
|
//
|
||||||
// (We want to ensure that the test process itself has enough time to
|
// (We want to ensure that the test process itself has enough time to
|
||||||
// log the output before it is also terminated.)
|
// log the output before it is also terminated.)
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
// 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 go1.20
|
|
||||||
|
|
||||||
package wycheproof
|
package wycheproof
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
// 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 go1.13
|
|
||||||
|
|
||||||
package wycheproof
|
package wycheproof
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
+2
-2
@@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
// Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
|
// Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
|
||||||
//
|
//
|
||||||
// Deprecated: MD4 is cryptographically broken and should should only be used
|
// Deprecated: MD4 is cryptographically broken and should only be used
|
||||||
// where compatibility with legacy systems, not security, is the goal. Instead,
|
// where compatibility with legacy systems, not security, is the goal. Instead,
|
||||||
// use a secure hash like SHA-256 (from crypto/sha256).
|
// use a secure hash like SHA-256 (from crypto/sha256).
|
||||||
package md4 // import "golang.org/x/crypto/md4"
|
package md4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ Anonymous sealing/opening is an extension of NaCl defined by and interoperable
|
|||||||
with libsodium:
|
with libsodium:
|
||||||
https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
|
https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
|
||||||
*/
|
*/
|
||||||
package box // import "golang.org/x/crypto/nacl/box"
|
package box
|
||||||
|
|
||||||
import (
|
import (
|
||||||
cryptorand "crypto/rand"
|
cryptorand "crypto/rand"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ chunk size.
|
|||||||
|
|
||||||
This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
|
This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
|
||||||
*/
|
*/
|
||||||
package secretbox // import "golang.org/x/crypto/nacl/secretbox"
|
package secretbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"golang.org/x/crypto/internal/alias"
|
"golang.org/x/crypto/internal/alias"
|
||||||
|
|||||||
+8
-7
@@ -5,7 +5,7 @@
|
|||||||
// Package ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
|
// Package ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
|
||||||
// are signed messages attesting to the validity of a certificate for a small
|
// are signed messages attesting to the validity of a certificate for a small
|
||||||
// period of time. This is used to manage revocation for X.509 certificates.
|
// period of time. This is used to manage revocation for X.509 certificates.
|
||||||
package ocsp // import "golang.org/x/crypto/ocsp"
|
package ocsp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
@@ -279,21 +279,22 @@ func getOIDFromHashAlgorithm(target crypto.Hash) asn1.ObjectIdentifier {
|
|||||||
|
|
||||||
// This is the exposed reflection of the internal OCSP structures.
|
// This is the exposed reflection of the internal OCSP structures.
|
||||||
|
|
||||||
// The status values that can be expressed in OCSP. See RFC 6960.
|
// The status values that can be expressed in OCSP. See RFC 6960.
|
||||||
|
// These are used for the Response.Status field.
|
||||||
const (
|
const (
|
||||||
// Good means that the certificate is valid.
|
// Good means that the certificate is valid.
|
||||||
Good = iota
|
Good = 0
|
||||||
// Revoked means that the certificate has been deliberately revoked.
|
// Revoked means that the certificate has been deliberately revoked.
|
||||||
Revoked
|
Revoked = 1
|
||||||
// Unknown means that the OCSP responder doesn't know about the certificate.
|
// Unknown means that the OCSP responder doesn't know about the certificate.
|
||||||
Unknown
|
Unknown = 2
|
||||||
// ServerFailed is unused and was never used (see
|
// ServerFailed is unused and was never used (see
|
||||||
// https://go-review.googlesource.com/#/c/18944). ParseResponse will
|
// https://go-review.googlesource.com/#/c/18944). ParseResponse will
|
||||||
// return a ResponseError when an error response is parsed.
|
// return a ResponseError when an error response is parsed.
|
||||||
ServerFailed
|
ServerFailed = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
// The enumerated reasons for revoking a certificate. See RFC 5280.
|
// The enumerated reasons for revoking a certificate. See RFC 5280.
|
||||||
const (
|
const (
|
||||||
Unspecified = 0
|
Unspecified = 0
|
||||||
KeyCompromise = 1
|
KeyCompromise = 1
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
// 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 go1.7
|
|
||||||
|
|
||||||
package ocsp
|
package ocsp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -10,14 +10,15 @@
|
|||||||
// for their specific task. If you are required to interoperate with OpenPGP
|
// for their specific task. If you are required to interoperate with OpenPGP
|
||||||
// systems and need a maintained package, consider a community fork.
|
// systems and need a maintained package, consider a community fork.
|
||||||
// See https://golang.org/issue/44226.
|
// See https://golang.org/issue/44226.
|
||||||
package armor // import "golang.org/x/crypto/openpgp/armor"
|
package armor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"golang.org/x/crypto/openpgp/errors"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Block represents an OpenPGP armored structure.
|
// A Block represents an OpenPGP armored structure.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
// for their specific task. If you are required to interoperate with OpenPGP
|
// for their specific task. If you are required to interoperate with OpenPGP
|
||||||
// systems and need a maintained package, consider a community fork.
|
// systems and need a maintained package, consider a community fork.
|
||||||
// See https://golang.org/issue/44226.
|
// See https://golang.org/issue/44226.
|
||||||
package clearsign // import "golang.org/x/crypto/openpgp/clearsign"
|
package clearsign
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
// https://golang.org/issue/44226), and ElGamal in the OpenPGP ecosystem has
|
// https://golang.org/issue/44226), and ElGamal in the OpenPGP ecosystem has
|
||||||
// compatibility and security issues (see https://eprint.iacr.org/2021/923).
|
// compatibility and security issues (see https://eprint.iacr.org/2021/923).
|
||||||
// Moreover, this package doesn't protect against side-channel attacks.
|
// Moreover, this package doesn't protect against side-channel attacks.
|
||||||
package elgamal // import "golang.org/x/crypto/openpgp/elgamal"
|
package elgamal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// for their specific task. If you are required to interoperate with OpenPGP
|
// for their specific task. If you are required to interoperate with OpenPGP
|
||||||
// systems and need a maintained package, consider a community fork.
|
// systems and need a maintained package, consider a community fork.
|
||||||
// See https://golang.org/issue/44226.
|
// See https://golang.org/issue/44226.
|
||||||
package errors // import "golang.org/x/crypto/openpgp/errors"
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func TestRevokedUserID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission.
|
// TestExternallyRevocableKey attempts to load and parse a key with a third party revocation permission.
|
||||||
func TestExternallyRevocableKey(t *testing.T) {
|
func TestExternallyRevocableKey(t *testing.T) {
|
||||||
kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex))
|
kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// for their specific task. If you are required to interoperate with OpenPGP
|
// for their specific task. If you are required to interoperate with OpenPGP
|
||||||
// systems and need a maintained package, consider a community fork.
|
// systems and need a maintained package, consider a community fork.
|
||||||
// See https://golang.org/issue/44226.
|
// See https://golang.org/issue/44226.
|
||||||
package packet // import "golang.org/x/crypto/openpgp/packet"
|
package packet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
// for their specific task. If you are required to interoperate with OpenPGP
|
// for their specific task. If you are required to interoperate with OpenPGP
|
||||||
// systems and need a maintained package, consider a community fork.
|
// systems and need a maintained package, consider a community fork.
|
||||||
// See https://golang.org/issue/44226.
|
// See https://golang.org/issue/44226.
|
||||||
package openpgp // import "golang.org/x/crypto/openpgp"
|
package openpgp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
// for their specific task. If you are required to interoperate with OpenPGP
|
// for their specific task. If you are required to interoperate with OpenPGP
|
||||||
// systems and need a maintained package, consider a community fork.
|
// systems and need a maintained package, consider a community fork.
|
||||||
// See https://golang.org/issue/44226.
|
// See https://golang.org/issue/44226.
|
||||||
package s2k // import "golang.org/x/crypto/openpgp/s2k"
|
package s2k
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
// The version of OTR implemented by this package has been deprecated
|
// The version of OTR implemented by this package has been deprecated
|
||||||
// (https://bugs.otr.im/lib/libotr/issues/140). An implementation of OTRv3 is
|
// (https://bugs.otr.im/lib/libotr/issues/140). An implementation of OTRv3 is
|
||||||
// available at https://github.com/coyim/otr3.
|
// available at https://github.com/coyim/otr3.
|
||||||
package otr // import "golang.org/x/crypto/otr"
|
package otr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
|
|||||||
choose, you can pass the `New` functions from the different SHA packages to
|
choose, you can pass the `New` functions from the different SHA packages to
|
||||||
pbkdf2.Key.
|
pbkdf2.Key.
|
||||||
*/
|
*/
|
||||||
package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
|
package pbkdf2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
// For encryption, use the full ChaCha20-Poly1305 construction implemented by
|
// For encryption, use the full ChaCha20-Poly1305 construction implemented by
|
||||||
// golang.org/x/crypto/chacha20poly1305. For authentication, use a general
|
// golang.org/x/crypto/chacha20poly1305. For authentication, use a general
|
||||||
// purpose MAC such as HMAC implemented by crypto/hmac.
|
// purpose MAC such as HMAC implemented by crypto/hmac.
|
||||||
package poly1305 // import "golang.org/x/crypto/poly1305"
|
package poly1305
|
||||||
|
|
||||||
import "golang.org/x/crypto/internal/poly1305"
|
import "golang.org/x/crypto/internal/poly1305"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// Deprecated: RIPEMD-160 is a legacy hash and should not be used for new
|
// Deprecated: RIPEMD-160 is a legacy hash and should not be used for new
|
||||||
// applications. Also, this package does not and will not provide an optimized
|
// applications. Also, this package does not and will not provide an optimized
|
||||||
// implementation. Instead, use a modern hash like SHA-256 (from crypto/sha256).
|
// implementation. Instead, use a modern hash like SHA-256 (from crypto/sha256).
|
||||||
package ripemd160 // import "golang.org/x/crypto/ripemd160"
|
package ripemd160
|
||||||
|
|
||||||
// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart
|
// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart
|
||||||
// Preneel with specifications available at:
|
// Preneel with specifications available at:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Package salsa provides low-level access to functions in the Salsa family.
|
// Package salsa provides low-level access to functions in the Salsa family.
|
||||||
package salsa // import "golang.org/x/crypto/salsa20/salsa"
|
package salsa
|
||||||
|
|
||||||
import "math/bits"
|
import "math/bits"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ This package also implements XSalsa20: a version of Salsa20 with a 24-byte
|
|||||||
nonce as specified in https://cr.yp.to/snuffle/xsalsa-20081128.pdf. Simply
|
nonce as specified in https://cr.yp.to/snuffle/xsalsa-20081128.pdf. Simply
|
||||||
passing a 24-byte slice as the nonce triggers XSalsa20.
|
passing a 24-byte slice as the nonce triggers XSalsa20.
|
||||||
*/
|
*/
|
||||||
package salsa20 // import "golang.org/x/crypto/salsa20"
|
package salsa20
|
||||||
|
|
||||||
// TODO(agl): implement XORKeyStream12 and XORKeyStream8 - the reduced round variants of Salsa20.
|
// TODO(agl): implement XORKeyStream12 and XORKeyStream8 - the reduced round variants of Salsa20.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
// Package scrypt implements the scrypt key derivation function as defined in
|
// Package scrypt implements the scrypt key derivation function as defined in
|
||||||
// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
|
// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
|
||||||
// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf).
|
// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf).
|
||||||
package scrypt // import "golang.org/x/crypto/scrypt"
|
package scrypt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2023 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 !noopt
|
||||||
|
|
||||||
|
package sha3_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sink byte
|
||||||
|
|
||||||
|
func TestAllocations(t *testing.T) {
|
||||||
|
want := 0.0
|
||||||
|
|
||||||
|
if runtime.GOARCH == "s390x" {
|
||||||
|
// On s390x the returned hash.Hash is conditional so it escapes.
|
||||||
|
want = 3.0
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("New", func(t *testing.T) {
|
||||||
|
if allocs := testing.AllocsPerRun(10, func() {
|
||||||
|
h := sha3.New256()
|
||||||
|
b := []byte("ABC")
|
||||||
|
h.Write(b)
|
||||||
|
out := make([]byte, 0, 32)
|
||||||
|
out = h.Sum(out)
|
||||||
|
sink ^= out[0]
|
||||||
|
}); allocs > want {
|
||||||
|
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("NewShake", func(t *testing.T) {
|
||||||
|
if allocs := testing.AllocsPerRun(10, func() {
|
||||||
|
h := sha3.NewShake128()
|
||||||
|
b := []byte("ABC")
|
||||||
|
h.Write(b)
|
||||||
|
out := make([]byte, 0, 32)
|
||||||
|
out = h.Sum(out)
|
||||||
|
sink ^= out[0]
|
||||||
|
h.Read(out)
|
||||||
|
sink ^= out[0]
|
||||||
|
}); allocs > want {
|
||||||
|
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("Sum", func(t *testing.T) {
|
||||||
|
if allocs := testing.AllocsPerRun(10, func() {
|
||||||
|
b := []byte("ABC")
|
||||||
|
out := sha3.Sum256(b)
|
||||||
|
sink ^= out[0]
|
||||||
|
}); allocs > want {
|
||||||
|
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
+1
-1
@@ -59,4 +59,4 @@
|
|||||||
// They produce output of the same length, with the same security strengths
|
// They produce output of the same length, with the same security strengths
|
||||||
// against all attacks. This means, in particular, that SHA3-256 only has
|
// against all attacks. This means, in particular, that SHA3-256 only has
|
||||||
// 128-bit collision resistance, because its output length is 32 bytes.
|
// 128-bit collision resistance, because its output length is 32 bytes.
|
||||||
package sha3 // import "golang.org/x/crypto/sha3"
|
package sha3
|
||||||
|
|||||||
+27
-15
@@ -9,6 +9,7 @@ package sha3
|
|||||||
// bytes.
|
// bytes.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto"
|
||||||
"hash"
|
"hash"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,39 +17,50 @@ import (
|
|||||||
// Its generic security strength is 224 bits against preimage attacks,
|
// Its generic security strength is 224 bits against preimage attacks,
|
||||||
// and 112 bits against collision attacks.
|
// and 112 bits against collision attacks.
|
||||||
func New224() hash.Hash {
|
func New224() hash.Hash {
|
||||||
if h := new224Asm(); h != nil {
|
return new224()
|
||||||
return h
|
|
||||||
}
|
|
||||||
return &state{rate: 144, outputLen: 28, dsbyte: 0x06}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New256 creates a new SHA3-256 hash.
|
// New256 creates a new SHA3-256 hash.
|
||||||
// Its generic security strength is 256 bits against preimage attacks,
|
// Its generic security strength is 256 bits against preimage attacks,
|
||||||
// and 128 bits against collision attacks.
|
// and 128 bits against collision attacks.
|
||||||
func New256() hash.Hash {
|
func New256() hash.Hash {
|
||||||
if h := new256Asm(); h != nil {
|
return new256()
|
||||||
return h
|
|
||||||
}
|
|
||||||
return &state{rate: 136, outputLen: 32, dsbyte: 0x06}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New384 creates a new SHA3-384 hash.
|
// New384 creates a new SHA3-384 hash.
|
||||||
// Its generic security strength is 384 bits against preimage attacks,
|
// Its generic security strength is 384 bits against preimage attacks,
|
||||||
// and 192 bits against collision attacks.
|
// and 192 bits against collision attacks.
|
||||||
func New384() hash.Hash {
|
func New384() hash.Hash {
|
||||||
if h := new384Asm(); h != nil {
|
return new384()
|
||||||
return h
|
|
||||||
}
|
|
||||||
return &state{rate: 104, outputLen: 48, dsbyte: 0x06}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New512 creates a new SHA3-512 hash.
|
// New512 creates a new SHA3-512 hash.
|
||||||
// Its generic security strength is 512 bits against preimage attacks,
|
// Its generic security strength is 512 bits against preimage attacks,
|
||||||
// and 256 bits against collision attacks.
|
// and 256 bits against collision attacks.
|
||||||
func New512() hash.Hash {
|
func New512() hash.Hash {
|
||||||
if h := new512Asm(); h != nil {
|
return new512()
|
||||||
return h
|
}
|
||||||
}
|
|
||||||
|
func init() {
|
||||||
|
crypto.RegisterHash(crypto.SHA3_224, New224)
|
||||||
|
crypto.RegisterHash(crypto.SHA3_256, New256)
|
||||||
|
crypto.RegisterHash(crypto.SHA3_384, New384)
|
||||||
|
crypto.RegisterHash(crypto.SHA3_512, New512)
|
||||||
|
}
|
||||||
|
|
||||||
|
func new224Generic() *state {
|
||||||
|
return &state{rate: 144, outputLen: 28, dsbyte: 0x06}
|
||||||
|
}
|
||||||
|
|
||||||
|
func new256Generic() *state {
|
||||||
|
return &state{rate: 136, outputLen: 32, dsbyte: 0x06}
|
||||||
|
}
|
||||||
|
|
||||||
|
func new384Generic() *state {
|
||||||
|
return &state{rate: 104, outputLen: 48, dsbyte: 0x06}
|
||||||
|
}
|
||||||
|
|
||||||
|
func new512Generic() *state {
|
||||||
return &state{rate: 72, outputLen: 64, dsbyte: 0x06}
|
return &state{rate: 72, outputLen: 64, dsbyte: 0x06}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build !gc || purego || !s390x
|
|
||||||
|
|
||||||
package sha3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// new224Asm returns an assembly implementation of SHA3-224 if available,
|
|
||||||
// otherwise it returns nil.
|
|
||||||
func new224Asm() hash.Hash { return nil }
|
|
||||||
|
|
||||||
// new256Asm returns an assembly implementation of SHA3-256 if available,
|
|
||||||
// otherwise it returns nil.
|
|
||||||
func new256Asm() hash.Hash { return nil }
|
|
||||||
|
|
||||||
// new384Asm returns an assembly implementation of SHA3-384 if available,
|
|
||||||
// otherwise it returns nil.
|
|
||||||
func new384Asm() hash.Hash { return nil }
|
|
||||||
|
|
||||||
// new512Asm returns an assembly implementation of SHA3-512 if available,
|
|
||||||
// otherwise it returns nil.
|
|
||||||
func new512Asm() hash.Hash { return nil }
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !gc || purego || !s390x
|
||||||
|
|
||||||
|
package sha3
|
||||||
|
|
||||||
|
func new224() *state {
|
||||||
|
return new224Generic()
|
||||||
|
}
|
||||||
|
|
||||||
|
func new256() *state {
|
||||||
|
return new256Generic()
|
||||||
|
}
|
||||||
|
|
||||||
|
func new384() *state {
|
||||||
|
return new384Generic()
|
||||||
|
}
|
||||||
|
|
||||||
|
func new512() *state {
|
||||||
|
return new512Generic()
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright 2014 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.4
|
|
||||||
|
|
||||||
package sha3
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
crypto.RegisterHash(crypto.SHA3_224, New224)
|
|
||||||
crypto.RegisterHash(crypto.SHA3_256, New256)
|
|
||||||
crypto.RegisterHash(crypto.SHA3_384, New384)
|
|
||||||
crypto.RegisterHash(crypto.SHA3_512, New512)
|
|
||||||
}
|
|
||||||
+25
-37
@@ -23,7 +23,6 @@ const (
|
|||||||
type state struct {
|
type state struct {
|
||||||
// Generic sponge components.
|
// Generic sponge components.
|
||||||
a [25]uint64 // main state of the hash
|
a [25]uint64 // main state of the hash
|
||||||
buf []byte // points into storage
|
|
||||||
rate int // the number of bytes of state to use
|
rate int // the number of bytes of state to use
|
||||||
|
|
||||||
// dsbyte contains the "domain separation" bits and the first bit of
|
// dsbyte contains the "domain separation" bits and the first bit of
|
||||||
@@ -40,7 +39,8 @@ type state struct {
|
|||||||
// Extendable-Output Functions (May 2014)"
|
// Extendable-Output Functions (May 2014)"
|
||||||
dsbyte byte
|
dsbyte byte
|
||||||
|
|
||||||
storage storageBuf
|
i, n int // storage[i:n] is the buffer, i is only used while squeezing
|
||||||
|
storage [maxRate]byte
|
||||||
|
|
||||||
// Specific to SHA-3 and SHAKE.
|
// Specific to SHA-3 and SHAKE.
|
||||||
outputLen int // the default output size in bytes
|
outputLen int // the default output size in bytes
|
||||||
@@ -54,24 +54,18 @@ func (d *state) BlockSize() int { return d.rate }
|
|||||||
func (d *state) Size() int { return d.outputLen }
|
func (d *state) Size() int { return d.outputLen }
|
||||||
|
|
||||||
// Reset clears the internal state by zeroing the sponge state and
|
// Reset clears the internal state by zeroing the sponge state and
|
||||||
// the byte buffer, and setting Sponge.state to absorbing.
|
// the buffer indexes, and setting Sponge.state to absorbing.
|
||||||
func (d *state) Reset() {
|
func (d *state) Reset() {
|
||||||
// Zero the permutation's state.
|
// Zero the permutation's state.
|
||||||
for i := range d.a {
|
for i := range d.a {
|
||||||
d.a[i] = 0
|
d.a[i] = 0
|
||||||
}
|
}
|
||||||
d.state = spongeAbsorbing
|
d.state = spongeAbsorbing
|
||||||
d.buf = d.storage.asBytes()[:0]
|
d.i, d.n = 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *state) clone() *state {
|
func (d *state) clone() *state {
|
||||||
ret := *d
|
ret := *d
|
||||||
if ret.state == spongeAbsorbing {
|
|
||||||
ret.buf = ret.storage.asBytes()[:len(ret.buf)]
|
|
||||||
} else {
|
|
||||||
ret.buf = ret.storage.asBytes()[d.rate-cap(d.buf) : d.rate]
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ret
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,43 +76,40 @@ func (d *state) permute() {
|
|||||||
case spongeAbsorbing:
|
case spongeAbsorbing:
|
||||||
// If we're absorbing, we need to xor the input into the state
|
// If we're absorbing, we need to xor the input into the state
|
||||||
// before applying the permutation.
|
// before applying the permutation.
|
||||||
xorIn(d, d.buf)
|
xorIn(d, d.storage[:d.rate])
|
||||||
d.buf = d.storage.asBytes()[:0]
|
d.n = 0
|
||||||
keccakF1600(&d.a)
|
keccakF1600(&d.a)
|
||||||
case spongeSqueezing:
|
case spongeSqueezing:
|
||||||
// If we're squeezing, we need to apply the permutation before
|
// If we're squeezing, we need to apply the permutation before
|
||||||
// copying more output.
|
// copying more output.
|
||||||
keccakF1600(&d.a)
|
keccakF1600(&d.a)
|
||||||
d.buf = d.storage.asBytes()[:d.rate]
|
d.i = 0
|
||||||
copyOut(d, d.buf)
|
copyOut(d, d.storage[:d.rate])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pads appends the domain separation bits in dsbyte, applies
|
// pads appends the domain separation bits in dsbyte, applies
|
||||||
// the multi-bitrate 10..1 padding rule, and permutes the state.
|
// the multi-bitrate 10..1 padding rule, and permutes the state.
|
||||||
func (d *state) padAndPermute(dsbyte byte) {
|
func (d *state) padAndPermute() {
|
||||||
if d.buf == nil {
|
|
||||||
d.buf = d.storage.asBytes()[:0]
|
|
||||||
}
|
|
||||||
// Pad with this instance's domain-separator bits. We know that there's
|
// Pad with this instance's domain-separator bits. We know that there's
|
||||||
// at least one byte of space in d.buf because, if it were full,
|
// at least one byte of space in d.buf because, if it were full,
|
||||||
// permute would have been called to empty it. dsbyte also contains the
|
// permute would have been called to empty it. dsbyte also contains the
|
||||||
// first one bit for the padding. See the comment in the state struct.
|
// first one bit for the padding. See the comment in the state struct.
|
||||||
d.buf = append(d.buf, dsbyte)
|
d.storage[d.n] = d.dsbyte
|
||||||
zerosStart := len(d.buf)
|
d.n++
|
||||||
d.buf = d.storage.asBytes()[:d.rate]
|
for d.n < d.rate {
|
||||||
for i := zerosStart; i < d.rate; i++ {
|
d.storage[d.n] = 0
|
||||||
d.buf[i] = 0
|
d.n++
|
||||||
}
|
}
|
||||||
// This adds the final one bit for the padding. Because of the way that
|
// This adds the final one bit for the padding. Because of the way that
|
||||||
// bits are numbered from the LSB upwards, the final bit is the MSB of
|
// bits are numbered from the LSB upwards, the final bit is the MSB of
|
||||||
// the last byte.
|
// the last byte.
|
||||||
d.buf[d.rate-1] ^= 0x80
|
d.storage[d.rate-1] ^= 0x80
|
||||||
// Apply the permutation
|
// Apply the permutation
|
||||||
d.permute()
|
d.permute()
|
||||||
d.state = spongeSqueezing
|
d.state = spongeSqueezing
|
||||||
d.buf = d.storage.asBytes()[:d.rate]
|
d.n = d.rate
|
||||||
copyOut(d, d.buf)
|
copyOut(d, d.storage[:d.rate])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write absorbs more data into the hash's state. It panics if any
|
// Write absorbs more data into the hash's state. It panics if any
|
||||||
@@ -127,28 +118,25 @@ func (d *state) Write(p []byte) (written int, err error) {
|
|||||||
if d.state != spongeAbsorbing {
|
if d.state != spongeAbsorbing {
|
||||||
panic("sha3: Write after Read")
|
panic("sha3: Write after Read")
|
||||||
}
|
}
|
||||||
if d.buf == nil {
|
|
||||||
d.buf = d.storage.asBytes()[:0]
|
|
||||||
}
|
|
||||||
written = len(p)
|
written = len(p)
|
||||||
|
|
||||||
for len(p) > 0 {
|
for len(p) > 0 {
|
||||||
if len(d.buf) == 0 && len(p) >= d.rate {
|
if d.n == 0 && len(p) >= d.rate {
|
||||||
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
|
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
|
||||||
xorIn(d, p[:d.rate])
|
xorIn(d, p[:d.rate])
|
||||||
p = p[d.rate:]
|
p = p[d.rate:]
|
||||||
keccakF1600(&d.a)
|
keccakF1600(&d.a)
|
||||||
} else {
|
} else {
|
||||||
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
|
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
|
||||||
todo := d.rate - len(d.buf)
|
todo := d.rate - d.n
|
||||||
if todo > len(p) {
|
if todo > len(p) {
|
||||||
todo = len(p)
|
todo = len(p)
|
||||||
}
|
}
|
||||||
d.buf = append(d.buf, p[:todo]...)
|
d.n += copy(d.storage[d.n:], p[:todo])
|
||||||
p = p[todo:]
|
p = p[todo:]
|
||||||
|
|
||||||
// If the sponge is full, apply the permutation.
|
// If the sponge is full, apply the permutation.
|
||||||
if len(d.buf) == d.rate {
|
if d.n == d.rate {
|
||||||
d.permute()
|
d.permute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,19 +149,19 @@ func (d *state) Write(p []byte) (written int, err error) {
|
|||||||
func (d *state) Read(out []byte) (n int, err error) {
|
func (d *state) Read(out []byte) (n int, err error) {
|
||||||
// If we're still absorbing, pad and apply the permutation.
|
// If we're still absorbing, pad and apply the permutation.
|
||||||
if d.state == spongeAbsorbing {
|
if d.state == spongeAbsorbing {
|
||||||
d.padAndPermute(d.dsbyte)
|
d.padAndPermute()
|
||||||
}
|
}
|
||||||
|
|
||||||
n = len(out)
|
n = len(out)
|
||||||
|
|
||||||
// Now, do the squeezing.
|
// Now, do the squeezing.
|
||||||
for len(out) > 0 {
|
for len(out) > 0 {
|
||||||
n := copy(out, d.buf)
|
n := copy(out, d.storage[d.i:d.n])
|
||||||
d.buf = d.buf[n:]
|
d.i += n
|
||||||
out = out[n:]
|
out = out[n:]
|
||||||
|
|
||||||
// Apply the permutation if we've squeezed the sponge dry.
|
// Apply the permutation if we've squeezed the sponge dry.
|
||||||
if len(d.buf) == 0 {
|
if d.i == d.rate {
|
||||||
d.permute()
|
d.permute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-26
@@ -143,6 +143,12 @@ func (s *asmState) Write(b []byte) (int, error) {
|
|||||||
|
|
||||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||||
func (s *asmState) Read(out []byte) (n int, err error) {
|
func (s *asmState) Read(out []byte) (n int, err error) {
|
||||||
|
// The 'compute last message digest' instruction only stores the digest
|
||||||
|
// at the first operand (dst) for SHAKE functions.
|
||||||
|
if s.function != shake_128 && s.function != shake_256 {
|
||||||
|
panic("sha3: can only call Read for SHAKE functions")
|
||||||
|
}
|
||||||
|
|
||||||
n = len(out)
|
n = len(out)
|
||||||
|
|
||||||
// need to pad if we were absorbing
|
// need to pad if we were absorbing
|
||||||
@@ -202,8 +208,17 @@ func (s *asmState) Sum(b []byte) []byte {
|
|||||||
|
|
||||||
// Hash the buffer. Note that we don't clear it because we
|
// Hash the buffer. Note that we don't clear it because we
|
||||||
// aren't updating the state.
|
// aren't updating the state.
|
||||||
klmd(s.function, &a, nil, s.buf)
|
switch s.function {
|
||||||
return append(b, a[:s.outputLen]...)
|
case sha3_224, sha3_256, sha3_384, sha3_512:
|
||||||
|
klmd(s.function, &a, nil, s.buf)
|
||||||
|
return append(b, a[:s.outputLen]...)
|
||||||
|
case shake_128, shake_256:
|
||||||
|
d := make([]byte, s.outputLen, 64)
|
||||||
|
klmd(s.function, &a, d, s.buf)
|
||||||
|
return append(b, d[:s.outputLen]...)
|
||||||
|
default:
|
||||||
|
panic("sha3: unknown function")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset resets the Hash to its initial state.
|
// Reset resets the Hash to its initial state.
|
||||||
@@ -233,56 +248,56 @@ func (s *asmState) Clone() ShakeHash {
|
|||||||
return s.clone()
|
return s.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// new224Asm returns an assembly implementation of SHA3-224 if available,
|
// new224 returns an assembly implementation of SHA3-224 if available,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns a generic implementation.
|
||||||
func new224Asm() hash.Hash {
|
func new224() hash.Hash {
|
||||||
if cpu.S390X.HasSHA3 {
|
if cpu.S390X.HasSHA3 {
|
||||||
return newAsmState(sha3_224)
|
return newAsmState(sha3_224)
|
||||||
}
|
}
|
||||||
return nil
|
return new224Generic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// new256Asm returns an assembly implementation of SHA3-256 if available,
|
// new256 returns an assembly implementation of SHA3-256 if available,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns a generic implementation.
|
||||||
func new256Asm() hash.Hash {
|
func new256() hash.Hash {
|
||||||
if cpu.S390X.HasSHA3 {
|
if cpu.S390X.HasSHA3 {
|
||||||
return newAsmState(sha3_256)
|
return newAsmState(sha3_256)
|
||||||
}
|
}
|
||||||
return nil
|
return new256Generic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// new384Asm returns an assembly implementation of SHA3-384 if available,
|
// new384 returns an assembly implementation of SHA3-384 if available,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns a generic implementation.
|
||||||
func new384Asm() hash.Hash {
|
func new384() hash.Hash {
|
||||||
if cpu.S390X.HasSHA3 {
|
if cpu.S390X.HasSHA3 {
|
||||||
return newAsmState(sha3_384)
|
return newAsmState(sha3_384)
|
||||||
}
|
}
|
||||||
return nil
|
return new384Generic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// new512Asm returns an assembly implementation of SHA3-512 if available,
|
// new512 returns an assembly implementation of SHA3-512 if available,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns a generic implementation.
|
||||||
func new512Asm() hash.Hash {
|
func new512() hash.Hash {
|
||||||
if cpu.S390X.HasSHA3 {
|
if cpu.S390X.HasSHA3 {
|
||||||
return newAsmState(sha3_512)
|
return newAsmState(sha3_512)
|
||||||
}
|
}
|
||||||
return nil
|
return new512Generic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
|
// newShake128 returns an assembly implementation of SHAKE-128 if available,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns a generic implementation.
|
||||||
func newShake128Asm() ShakeHash {
|
func newShake128() ShakeHash {
|
||||||
if cpu.S390X.HasSHA3 {
|
if cpu.S390X.HasSHA3 {
|
||||||
return newAsmState(shake_128)
|
return newAsmState(shake_128)
|
||||||
}
|
}
|
||||||
return nil
|
return newShake128Generic()
|
||||||
}
|
}
|
||||||
|
|
||||||
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
|
// newShake256 returns an assembly implementation of SHAKE-256 if available,
|
||||||
// otherwise it returns nil.
|
// otherwise it returns a generic implementation.
|
||||||
func newShake256Asm() ShakeHash {
|
func newShake256() ShakeHash {
|
||||||
if cpu.S390X.HasSHA3 {
|
if cpu.S390X.HasSHA3 {
|
||||||
return newAsmState(shake_256)
|
return newAsmState(shake_256)
|
||||||
}
|
}
|
||||||
return nil
|
return newShake256Generic()
|
||||||
}
|
}
|
||||||
|
|||||||
+167
-160
@@ -76,86 +76,73 @@ type KeccakKats struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
|
|
||||||
xorInOrig, copyOutOrig := xorIn, copyOut
|
|
||||||
xorIn, copyOut = xorInGeneric, copyOutGeneric
|
|
||||||
testf("generic")
|
|
||||||
if xorImplementationUnaligned != "generic" {
|
|
||||||
xorIn, copyOut = xorInUnaligned, copyOutUnaligned
|
|
||||||
testf("unaligned")
|
|
||||||
}
|
|
||||||
xorIn, copyOut = xorInOrig, copyOutOrig
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestKeccakKats tests the SHA-3 and Shake implementations against all the
|
// TestKeccakKats tests the SHA-3 and Shake implementations against all the
|
||||||
// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
|
// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
|
||||||
// (The testvectors are stored in keccakKats.json.deflate due to their length.)
|
// (The testvectors are stored in keccakKats.json.deflate due to their length.)
|
||||||
func TestKeccakKats(t *testing.T) {
|
func TestKeccakKats(t *testing.T) {
|
||||||
testUnalignedAndGeneric(t, func(impl string) {
|
// Read the KATs.
|
||||||
// Read the KATs.
|
deflated, err := os.Open(katFilename)
|
||||||
deflated, err := os.Open(katFilename)
|
if err != nil {
|
||||||
if err != nil {
|
t.Errorf("error opening %s: %s", katFilename, err)
|
||||||
t.Errorf("error opening %s: %s", katFilename, err)
|
}
|
||||||
}
|
file := flate.NewReader(deflated)
|
||||||
file := flate.NewReader(deflated)
|
dec := json.NewDecoder(file)
|
||||||
dec := json.NewDecoder(file)
|
var katSet KeccakKats
|
||||||
var katSet KeccakKats
|
err = dec.Decode(&katSet)
|
||||||
err = dec.Decode(&katSet)
|
if err != nil {
|
||||||
if err != nil {
|
t.Errorf("error decoding KATs: %s", err)
|
||||||
t.Errorf("error decoding KATs: %s", err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for algo, function := range testDigests {
|
for algo, function := range testDigests {
|
||||||
d := function()
|
d := function()
|
||||||
for _, kat := range katSet.Kats[algo] {
|
for _, kat := range katSet.Kats[algo] {
|
||||||
d.Reset()
|
d.Reset()
|
||||||
in, err := hex.DecodeString(kat.Message)
|
in, err := hex.DecodeString(kat.Message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error decoding KAT: %s", err)
|
t.Errorf("error decoding KAT: %s", err)
|
||||||
}
|
|
||||||
d.Write(in[:kat.Length/8])
|
|
||||||
got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
|
|
||||||
if got != kat.Digest {
|
|
||||||
t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
|
|
||||||
algo, impl, kat.Length, kat.Message, got, kat.Digest)
|
|
||||||
t.Logf("wanted %+v", kat)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
d.Write(in[:kat.Length/8])
|
||||||
|
got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
|
||||||
for algo, v := range testShakes {
|
if got != kat.Digest {
|
||||||
for _, kat := range katSet.Kats[algo] {
|
t.Errorf("function=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
|
||||||
N, err := hex.DecodeString(kat.N)
|
algo, kat.Length, kat.Message, got, kat.Digest)
|
||||||
if err != nil {
|
t.Logf("wanted %+v", kat)
|
||||||
t.Errorf("error decoding KAT: %s", err)
|
t.FailNow()
|
||||||
}
|
|
||||||
|
|
||||||
S, err := hex.DecodeString(kat.S)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("error decoding KAT: %s", err)
|
|
||||||
}
|
|
||||||
d := v.constructor(N, S)
|
|
||||||
in, err := hex.DecodeString(kat.Message)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("error decoding KAT: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
d.Write(in[:kat.Length/8])
|
|
||||||
out := make([]byte, len(kat.Digest)/2)
|
|
||||||
d.Read(out)
|
|
||||||
got := strings.ToUpper(hex.EncodeToString(out))
|
|
||||||
if got != kat.Digest {
|
|
||||||
t.Errorf("function=%s, implementation=%s, length=%d N:%s\n S:%s\nmessage:\n %s \ngot:\n %s\nwanted:\n %s",
|
|
||||||
algo, impl, kat.Length, kat.N, kat.S, kat.Message, got, kat.Digest)
|
|
||||||
t.Logf("wanted %+v", kat)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
for algo, v := range testShakes {
|
||||||
|
for _, kat := range katSet.Kats[algo] {
|
||||||
|
N, err := hex.DecodeString(kat.N)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error decoding KAT: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
S, err := hex.DecodeString(kat.S)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error decoding KAT: %s", err)
|
||||||
|
}
|
||||||
|
d := v.constructor(N, S)
|
||||||
|
in, err := hex.DecodeString(kat.Message)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error decoding KAT: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Write(in[:kat.Length/8])
|
||||||
|
out := make([]byte, len(kat.Digest)/2)
|
||||||
|
d.Read(out)
|
||||||
|
got := strings.ToUpper(hex.EncodeToString(out))
|
||||||
|
if got != kat.Digest {
|
||||||
|
t.Errorf("function=%s, length=%d N:%s\n S:%s\nmessage:\n %s \ngot:\n %s\nwanted:\n %s",
|
||||||
|
algo, kat.Length, kat.N, kat.S, kat.Message, got, kat.Digest)
|
||||||
|
t.Logf("wanted %+v", kat)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestKeccak does a basic test of the non-standardized Keccak hash functions.
|
// TestKeccak does a basic test of the non-standardized Keccak hash functions.
|
||||||
@@ -188,122 +175,142 @@ func TestKeccak(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestShakeSum tests that the output of Sum matches the output of Read.
|
||||||
|
func TestShakeSum(t *testing.T) {
|
||||||
|
tests := [...]struct {
|
||||||
|
name string
|
||||||
|
hash ShakeHash
|
||||||
|
expectedLen int
|
||||||
|
}{
|
||||||
|
{"SHAKE128", NewShake128(), 32},
|
||||||
|
{"SHAKE256", NewShake256(), 64},
|
||||||
|
{"cSHAKE128", NewCShake128([]byte{'X'}, nil), 32},
|
||||||
|
{"cSHAKE256", NewCShake256([]byte{'X'}, nil), 64},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
s := test.hash.Sum(nil)
|
||||||
|
if len(s) != test.expectedLen {
|
||||||
|
t.Errorf("Unexpected digest length: got %d, want %d", len(s), test.expectedLen)
|
||||||
|
}
|
||||||
|
r := make([]byte, test.expectedLen)
|
||||||
|
test.hash.Read(r)
|
||||||
|
if !bytes.Equal(s, r) {
|
||||||
|
t.Errorf("Mismatch between Sum and Read:\nSum: %s\nRead: %s", hex.EncodeToString(s), hex.EncodeToString(r))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestUnalignedWrite tests that writing data in an arbitrary pattern with
|
// TestUnalignedWrite tests that writing data in an arbitrary pattern with
|
||||||
// small input buffers.
|
// small input buffers.
|
||||||
func TestUnalignedWrite(t *testing.T) {
|
func TestUnalignedWrite(t *testing.T) {
|
||||||
testUnalignedAndGeneric(t, func(impl string) {
|
buf := sequentialBytes(0x10000)
|
||||||
buf := sequentialBytes(0x10000)
|
for alg, df := range testDigests {
|
||||||
for alg, df := range testDigests {
|
d := df()
|
||||||
d := df()
|
d.Reset()
|
||||||
d.Reset()
|
d.Write(buf)
|
||||||
d.Write(buf)
|
want := d.Sum(nil)
|
||||||
want := d.Sum(nil)
|
d.Reset()
|
||||||
d.Reset()
|
for i := 0; i < len(buf); {
|
||||||
for i := 0; i < len(buf); {
|
// Cycle through offsets which make a 137 byte sequence.
|
||||||
// Cycle through offsets which make a 137 byte sequence.
|
// Because 137 is prime this sequence should exercise all corner cases.
|
||||||
// Because 137 is prime this sequence should exercise all corner cases.
|
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
|
||||||
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
|
for _, j := range offsets {
|
||||||
for _, j := range offsets {
|
if v := len(buf) - i; v < j {
|
||||||
if v := len(buf) - i; v < j {
|
j = v
|
||||||
j = v
|
|
||||||
}
|
|
||||||
d.Write(buf[i : i+j])
|
|
||||||
i += j
|
|
||||||
}
|
}
|
||||||
}
|
d.Write(buf[i : i+j])
|
||||||
got := d.Sum(nil)
|
i += j
|
||||||
if !bytes.Equal(got, want) {
|
|
||||||
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
got := d.Sum(nil)
|
||||||
|
if !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("Unaligned writes, alg=%s\ngot %q, want %q", alg, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Same for SHAKE
|
// Same for SHAKE
|
||||||
for alg, df := range testShakes {
|
for alg, df := range testShakes {
|
||||||
want := make([]byte, 16)
|
want := make([]byte, 16)
|
||||||
got := make([]byte, 16)
|
got := make([]byte, 16)
|
||||||
d := df.constructor([]byte(df.defAlgoName), []byte(df.defCustomStr))
|
d := df.constructor([]byte(df.defAlgoName), []byte(df.defCustomStr))
|
||||||
|
|
||||||
d.Reset()
|
d.Reset()
|
||||||
d.Write(buf)
|
d.Write(buf)
|
||||||
d.Read(want)
|
d.Read(want)
|
||||||
d.Reset()
|
d.Reset()
|
||||||
for i := 0; i < len(buf); {
|
for i := 0; i < len(buf); {
|
||||||
// Cycle through offsets which make a 137 byte sequence.
|
// Cycle through offsets which make a 137 byte sequence.
|
||||||
// Because 137 is prime this sequence should exercise all corner cases.
|
// Because 137 is prime this sequence should exercise all corner cases.
|
||||||
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
|
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
|
||||||
for _, j := range offsets {
|
for _, j := range offsets {
|
||||||
if v := len(buf) - i; v < j {
|
if v := len(buf) - i; v < j {
|
||||||
j = v
|
j = v
|
||||||
}
|
|
||||||
d.Write(buf[i : i+j])
|
|
||||||
i += j
|
|
||||||
}
|
}
|
||||||
}
|
d.Write(buf[i : i+j])
|
||||||
d.Read(got)
|
i += j
|
||||||
if !bytes.Equal(got, want) {
|
|
||||||
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
d.Read(got)
|
||||||
|
if !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("Unaligned writes, alg=%s\ngot %q, want %q", alg, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAppend checks that appending works when reallocation is necessary.
|
// TestAppend checks that appending works when reallocation is necessary.
|
||||||
func TestAppend(t *testing.T) {
|
func TestAppend(t *testing.T) {
|
||||||
testUnalignedAndGeneric(t, func(impl string) {
|
d := New224()
|
||||||
d := New224()
|
|
||||||
|
|
||||||
for capacity := 2; capacity <= 66; capacity += 64 {
|
for capacity := 2; capacity <= 66; capacity += 64 {
|
||||||
// The first time around the loop, Sum will have to reallocate.
|
// The first time around the loop, Sum will have to reallocate.
|
||||||
// The second time, it will not.
|
// The second time, it will not.
|
||||||
buf := make([]byte, 2, capacity)
|
buf := make([]byte, 2, capacity)
|
||||||
d.Reset()
|
d.Reset()
|
||||||
d.Write([]byte{0xcc})
|
d.Write([]byte{0xcc})
|
||||||
buf = d.Sum(buf)
|
buf = d.Sum(buf)
|
||||||
expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
||||||
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
||||||
t.Errorf("got %s, want %s", got, expected)
|
t.Errorf("got %s, want %s", got, expected)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
|
// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
|
||||||
func TestAppendNoRealloc(t *testing.T) {
|
func TestAppendNoRealloc(t *testing.T) {
|
||||||
testUnalignedAndGeneric(t, func(impl string) {
|
buf := make([]byte, 1, 200)
|
||||||
buf := make([]byte, 1, 200)
|
d := New224()
|
||||||
d := New224()
|
d.Write([]byte{0xcc})
|
||||||
d.Write([]byte{0xcc})
|
buf = d.Sum(buf)
|
||||||
buf = d.Sum(buf)
|
expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
||||||
expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
||||||
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
t.Errorf("got %s, want %s", got, expected)
|
||||||
t.Errorf("%s: got %s, want %s", impl, got, expected)
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSqueezing checks that squeezing the full output a single time produces
|
// TestSqueezing checks that squeezing the full output a single time produces
|
||||||
// the same output as repeatedly squeezing the instance.
|
// the same output as repeatedly squeezing the instance.
|
||||||
func TestSqueezing(t *testing.T) {
|
func TestSqueezing(t *testing.T) {
|
||||||
testUnalignedAndGeneric(t, func(impl string) {
|
for algo, v := range testShakes {
|
||||||
for algo, v := range testShakes {
|
d0 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
|
||||||
d0 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
|
d0.Write([]byte(testString))
|
||||||
d0.Write([]byte(testString))
|
ref := make([]byte, 32)
|
||||||
ref := make([]byte, 32)
|
d0.Read(ref)
|
||||||
d0.Read(ref)
|
|
||||||
|
|
||||||
d1 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
|
d1 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
|
||||||
d1.Write([]byte(testString))
|
d1.Write([]byte(testString))
|
||||||
var multiple []byte
|
var multiple []byte
|
||||||
for range ref {
|
for range ref {
|
||||||
one := make([]byte, 1)
|
one := make([]byte, 1)
|
||||||
d1.Read(one)
|
d1.Read(one)
|
||||||
multiple = append(multiple, one...)
|
multiple = append(multiple, one...)
|
||||||
}
|
|
||||||
if !bytes.Equal(ref, multiple) {
|
|
||||||
t.Errorf("%s (%s): squeezing %d bytes one at a time failed", algo, impl, len(ref))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
if !bytes.Equal(ref, multiple) {
|
||||||
|
t.Errorf("%s: squeezing %d bytes one at a time failed", algo, len(ref))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
|
// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
|
||||||
|
|||||||
+9
-7
@@ -115,19 +115,21 @@ func (c *state) Clone() ShakeHash {
|
|||||||
// Its generic security strength is 128 bits against all attacks if at
|
// Its generic security strength is 128 bits against all attacks if at
|
||||||
// least 32 bytes of its output are used.
|
// least 32 bytes of its output are used.
|
||||||
func NewShake128() ShakeHash {
|
func NewShake128() ShakeHash {
|
||||||
if h := newShake128Asm(); h != nil {
|
return newShake128()
|
||||||
return h
|
|
||||||
}
|
|
||||||
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
|
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
|
||||||
// Its generic security strength is 256 bits against all attacks if
|
// Its generic security strength is 256 bits against all attacks if
|
||||||
// at least 64 bytes of its output are used.
|
// at least 64 bytes of its output are used.
|
||||||
func NewShake256() ShakeHash {
|
func NewShake256() ShakeHash {
|
||||||
if h := newShake256Asm(); h != nil {
|
return newShake256()
|
||||||
return h
|
}
|
||||||
}
|
|
||||||
|
func newShake128Generic() *state {
|
||||||
|
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newShake256Generic() *state {
|
||||||
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
|
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build !gc || purego || !s390x
|
|
||||||
|
|
||||||
package sha3
|
|
||||||
|
|
||||||
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
|
|
||||||
// otherwise it returns nil.
|
|
||||||
func newShake128Asm() ShakeHash {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
|
|
||||||
// otherwise it returns nil.
|
|
||||||
func newShake256Asm() ShakeHash {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !gc || purego || !s390x
|
||||||
|
|
||||||
|
package sha3
|
||||||
|
|
||||||
|
func newShake128() *state {
|
||||||
|
return newShake128Generic()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newShake256() *state {
|
||||||
|
return newShake256Generic()
|
||||||
|
}
|
||||||
+31
-14
@@ -2,22 +2,39 @@
|
|||||||
// 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 (!amd64 && !386 && !ppc64le) || purego
|
|
||||||
|
|
||||||
package sha3
|
package sha3
|
||||||
|
|
||||||
// A storageBuf is an aligned array of maxRate bytes.
|
import (
|
||||||
type storageBuf [maxRate]byte
|
"crypto/subtle"
|
||||||
|
"encoding/binary"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
func (b *storageBuf) asBytes() *[maxRate]byte {
|
"golang.org/x/sys/cpu"
|
||||||
return (*[maxRate]byte)(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
xorIn = xorInGeneric
|
|
||||||
copyOut = copyOutGeneric
|
|
||||||
xorInUnaligned = xorInGeneric
|
|
||||||
copyOutUnaligned = copyOutGeneric
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const xorImplementationUnaligned = "generic"
|
// xorIn xors the bytes in buf into the state.
|
||||||
|
func xorIn(d *state, buf []byte) {
|
||||||
|
if cpu.IsBigEndian {
|
||||||
|
for i := 0; len(buf) >= 8; i++ {
|
||||||
|
a := binary.LittleEndian.Uint64(buf)
|
||||||
|
d.a[i] ^= a
|
||||||
|
buf = buf[8:]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a))
|
||||||
|
subtle.XORBytes(ab[:], ab[:], buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyOut copies uint64s to a byte buffer.
|
||||||
|
func copyOut(d *state, b []byte) {
|
||||||
|
if cpu.IsBigEndian {
|
||||||
|
for i := 0; len(b) >= 8; i++ {
|
||||||
|
binary.LittleEndian.PutUint64(b, d.a[i])
|
||||||
|
b = b[8:]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a))
|
||||||
|
copy(b, ab[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package sha3
|
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
// xorInGeneric xors the bytes in buf into the state; it
|
|
||||||
// makes no non-portable assumptions about memory layout
|
|
||||||
// or alignment.
|
|
||||||
func xorInGeneric(d *state, buf []byte) {
|
|
||||||
n := len(buf) / 8
|
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
a := binary.LittleEndian.Uint64(buf)
|
|
||||||
d.a[i] ^= a
|
|
||||||
buf = buf[8:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyOutGeneric copies uint64s to a byte buffer.
|
|
||||||
func copyOutGeneric(d *state, b []byte) {
|
|
||||||
for i := 0; len(b) >= 8; i++ {
|
|
||||||
binary.LittleEndian.PutUint64(b, d.a[i])
|
|
||||||
b = b[8:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (amd64 || 386 || ppc64le) && !purego
|
|
||||||
|
|
||||||
package sha3
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
// A storageBuf is an aligned array of maxRate bytes.
|
|
||||||
type storageBuf [maxRate / 8]uint64
|
|
||||||
|
|
||||||
func (b *storageBuf) asBytes() *[maxRate]byte {
|
|
||||||
return (*[maxRate]byte)(unsafe.Pointer(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// xorInUnaligned uses unaligned reads and writes to update d.a to contain d.a
|
|
||||||
// XOR buf.
|
|
||||||
func xorInUnaligned(d *state, buf []byte) {
|
|
||||||
n := len(buf)
|
|
||||||
bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8]
|
|
||||||
if n >= 72 {
|
|
||||||
d.a[0] ^= bw[0]
|
|
||||||
d.a[1] ^= bw[1]
|
|
||||||
d.a[2] ^= bw[2]
|
|
||||||
d.a[3] ^= bw[3]
|
|
||||||
d.a[4] ^= bw[4]
|
|
||||||
d.a[5] ^= bw[5]
|
|
||||||
d.a[6] ^= bw[6]
|
|
||||||
d.a[7] ^= bw[7]
|
|
||||||
d.a[8] ^= bw[8]
|
|
||||||
}
|
|
||||||
if n >= 104 {
|
|
||||||
d.a[9] ^= bw[9]
|
|
||||||
d.a[10] ^= bw[10]
|
|
||||||
d.a[11] ^= bw[11]
|
|
||||||
d.a[12] ^= bw[12]
|
|
||||||
}
|
|
||||||
if n >= 136 {
|
|
||||||
d.a[13] ^= bw[13]
|
|
||||||
d.a[14] ^= bw[14]
|
|
||||||
d.a[15] ^= bw[15]
|
|
||||||
d.a[16] ^= bw[16]
|
|
||||||
}
|
|
||||||
if n >= 144 {
|
|
||||||
d.a[17] ^= bw[17]
|
|
||||||
}
|
|
||||||
if n >= 168 {
|
|
||||||
d.a[18] ^= bw[18]
|
|
||||||
d.a[19] ^= bw[19]
|
|
||||||
d.a[20] ^= bw[20]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyOutUnaligned(d *state, buf []byte) {
|
|
||||||
ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0]))
|
|
||||||
copy(buf, ab[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
xorIn = xorInUnaligned
|
|
||||||
copyOut = copyOutUnaligned
|
|
||||||
)
|
|
||||||
|
|
||||||
const xorImplementationUnaligned = "unaligned"
|
|
||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
// References:
|
// References:
|
||||||
//
|
//
|
||||||
// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
|
// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
|
||||||
package agent // import "golang.org/x/crypto/ssh/agent"
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|||||||
@@ -164,15 +164,23 @@ func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert
|
|||||||
data := []byte("hello")
|
data := []byte("hello")
|
||||||
sig, err := agent.Sign(pubKey, data)
|
sig, err := agent.Sign(pubKey, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
|
t.Logf("sign failed with key type %q", pubKey.Type())
|
||||||
}
|
// In integration tests ssh-dss and ssh-rsa (SHA1 signatures) may be
|
||||||
|
// disabled for security reasons, we check SHA-2 variants later.
|
||||||
if err := pubKey.Verify(data, sig); err != nil {
|
if pubKey.Type() != ssh.KeyAlgoDSA && pubKey.Type() != ssh.KeyAlgoRSA && pubKey.Type() != ssh.CertAlgoRSAv01 {
|
||||||
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
|
t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := pubKey.Verify(data, sig); err != nil {
|
||||||
|
t.Logf("verify failed with key type %q", pubKey.Type())
|
||||||
|
if pubKey.Type() != ssh.KeyAlgoRSA {
|
||||||
|
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For tests on RSA keys, try signing with SHA-256 and SHA-512 flags
|
// For tests on RSA keys, try signing with SHA-256 and SHA-512 flags
|
||||||
if pubKey.Type() == "ssh-rsa" {
|
if pubKey.Type() == ssh.KeyAlgoRSA {
|
||||||
sshFlagTest := func(flag SignatureFlags, expectedSigFormat string) {
|
sshFlagTest := func(flag SignatureFlags, expectedSigFormat string) {
|
||||||
sig, err = agent.SignWithFlags(pubKey, data, flag)
|
sig, err = agent.SignWithFlags(pubKey, data, flag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -185,7 +193,6 @@ func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert
|
|||||||
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
|
t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sshFlagTest(0, ssh.KeyAlgoRSA)
|
|
||||||
sshFlagTest(SignatureFlagRsaSha256, ssh.KeyAlgoRSASHA256)
|
sshFlagTest(SignatureFlagRsaSha256, ssh.KeyAlgoRSASHA256)
|
||||||
sshFlagTest(SignatureFlagRsaSha512, ssh.KeyAlgoRSASHA512)
|
sshFlagTest(SignatureFlagRsaSha512, ssh.KeyAlgoRSASHA512)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -367,21 +367,21 @@ func TestCertTypes(t *testing.T) {
|
|||||||
|
|
||||||
func TestCertSignWithMultiAlgorithmSigner(t *testing.T) {
|
func TestCertSignWithMultiAlgorithmSigner(t *testing.T) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
sigAlgo string
|
sigAlgo string
|
||||||
algoritms []string
|
algorithms []string
|
||||||
}
|
}
|
||||||
cases := []testcase{
|
cases := []testcase{
|
||||||
{
|
{
|
||||||
sigAlgo: KeyAlgoRSA,
|
sigAlgo: KeyAlgoRSA,
|
||||||
algoritms: []string{KeyAlgoRSA, KeyAlgoRSASHA512},
|
algorithms: []string{KeyAlgoRSA, KeyAlgoRSASHA512},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sigAlgo: KeyAlgoRSASHA256,
|
sigAlgo: KeyAlgoRSASHA256,
|
||||||
algoritms: []string{KeyAlgoRSASHA256, KeyAlgoRSA, KeyAlgoRSASHA512},
|
algorithms: []string{KeyAlgoRSASHA256, KeyAlgoRSA, KeyAlgoRSASHA512},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sigAlgo: KeyAlgoRSASHA512,
|
sigAlgo: KeyAlgoRSASHA512,
|
||||||
algoritms: []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256},
|
algorithms: []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ func TestCertSignWithMultiAlgorithmSigner(t *testing.T) {
|
|||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.sigAlgo, func(t *testing.T) {
|
t.Run(c.sigAlgo, func(t *testing.T) {
|
||||||
signer, err := NewSignerWithAlgorithms(testSigners["rsa"].(AlgorithmSigner), c.algoritms)
|
signer, err := NewSignerWithAlgorithms(testSigners["rsa"].(AlgorithmSigner), c.algorithms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewSignerWithAlgorithms error: %v", err)
|
t.Fatalf("NewSignerWithAlgorithms error: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-3
@@ -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
|
||||||
@@ -404,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 {
|
||||||
@@ -425,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
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+1
-1
@@ -384,7 +384,7 @@ func ExampleCertificate_SignCert() {
|
|||||||
}
|
}
|
||||||
mas, err := ssh.NewSignerWithAlgorithms(signer.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256})
|
mas, err := ssh.NewSignerWithAlgorithms(signer.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("unable to create signer with algoritms: ", err)
|
log.Fatal("unable to create signer with algorithms: ", err)
|
||||||
}
|
}
|
||||||
certificate := ssh.Certificate{
|
certificate := ssh.Certificate{
|
||||||
Key: publicKey,
|
Key: publicKey,
|
||||||
|
|||||||
@@ -904,6 +904,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 +1004,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
|
||||||
|
|||||||
+48
-2
@@ -610,7 +610,7 @@ func TestKnownHostsParsing(t *testing.T) {
|
|||||||
func TestFingerprintLegacyMD5(t *testing.T) {
|
func TestFingerprintLegacyMD5(t *testing.T) {
|
||||||
pub, _ := getTestKey()
|
pub, _ := getTestKey()
|
||||||
fingerprint := FingerprintLegacyMD5(pub)
|
fingerprint := FingerprintLegacyMD5(pub)
|
||||||
want := "fb:61:6d:1a:e3:f0:95:45:3c:a0:79:be:4a:93:63:66" // ssh-keygen -lf -E md5 rsa
|
want := "b7:ef:d3:d5:89:29:52:96:9f:df:47:41:4d:15:37:f4" // ssh-keygen -lf -E md5 rsa
|
||||||
if fingerprint != want {
|
if fingerprint != want {
|
||||||
t.Errorf("got fingerprint %q want %q", fingerprint, want)
|
t.Errorf("got fingerprint %q want %q", fingerprint, want)
|
||||||
}
|
}
|
||||||
@@ -619,7 +619,7 @@ func TestFingerprintLegacyMD5(t *testing.T) {
|
|||||||
func TestFingerprintSHA256(t *testing.T) {
|
func TestFingerprintSHA256(t *testing.T) {
|
||||||
pub, _ := getTestKey()
|
pub, _ := getTestKey()
|
||||||
fingerprint := FingerprintSHA256(pub)
|
fingerprint := FingerprintSHA256(pub)
|
||||||
want := "SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8" // ssh-keygen -lf rsa
|
want := "SHA256:fi5+D7UmDZDE9Q2sAVvvlpcQSIakN4DERdINgXd2AnE" // ssh-keygen -lf rsa
|
||||||
if fingerprint != want {
|
if fingerprint != want {
|
||||||
t.Errorf("got fingerprint %q want %q", fingerprint, want)
|
t.Errorf("got fingerprint %q want %q", fingerprint, want)
|
||||||
}
|
}
|
||||||
@@ -726,3 +726,49 @@ func TestNewSignerWithAlgos(t *testing.T) {
|
|||||||
t.Error("signer with algos created with restricted algorithms")
|
t.Error("signer with algos created with restricted algorithms")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCryptoPublicKey(t *testing.T) {
|
||||||
|
for _, priv := range testSigners {
|
||||||
|
p1 := priv.PublicKey()
|
||||||
|
key, ok := p1.(CryptoPublicKey)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p2, err := NewPublicKey(key.CryptoPublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewPublicKey(CryptoPublicKey) failed for %s, got: %v", p1.Type(), err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(p1, p2) {
|
||||||
|
t.Errorf("got %#v in NewPublicKey, want %#v", p2, p1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, d := range testdata.SKData {
|
||||||
|
p1, _, _, _, err := ParseAuthorizedKey(d.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parseAuthorizedKey returned error: %v", err)
|
||||||
|
}
|
||||||
|
k1, ok := p1.(CryptoPublicKey)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("%T does not implement CryptoPublicKey", p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var p2 PublicKey
|
||||||
|
switch pub := k1.CryptoPublicKey().(type) {
|
||||||
|
case *ecdsa.PublicKey:
|
||||||
|
p2 = &skECDSAPublicKey{
|
||||||
|
application: "ssh:",
|
||||||
|
PublicKey: *pub,
|
||||||
|
}
|
||||||
|
case ed25519.PublicKey:
|
||||||
|
p2 = &skEd25519PublicKey{
|
||||||
|
application: "ssh:",
|
||||||
|
PublicKey: pub,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected type %T from CryptoPublicKey()", pub)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(p1, p2) {
|
||||||
|
t.Errorf("got %#v, want %#v", p2, p1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+150
-50
@@ -426,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
|
||||||
@@ -433,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 {
|
||||||
@@ -471,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 {
|
||||||
@@ -491,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
|
||||||
}
|
}
|
||||||
@@ -518,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
|
||||||
}
|
}
|
||||||
@@ -562,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)
|
||||||
}
|
}
|
||||||
@@ -578,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,
|
||||||
@@ -629,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)
|
||||||
@@ -685,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 {
|
||||||
|
|||||||
@@ -0,0 +1,412 @@
|
|||||||
|
// 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 ssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func doClientServerAuth(t *testing.T, serverConfig *ServerConfig, clientConfig *ClientConfig) ([]error, error) {
|
||||||
|
c1, c2, err := netPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("netPipe: %v", err)
|
||||||
|
}
|
||||||
|
defer c1.Close()
|
||||||
|
defer c2.Close()
|
||||||
|
|
||||||
|
var serverAuthErrors []error
|
||||||
|
|
||||||
|
serverConfig.AddHostKey(testSigners["rsa"])
|
||||||
|
serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
|
||||||
|
serverAuthErrors = append(serverAuthErrors, err)
|
||||||
|
}
|
||||||
|
go newServer(c1, serverConfig)
|
||||||
|
c, _, _, err := NewClientConn(c2, "", clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
return serverAuthErrors, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultiStepAuth(t *testing.T) {
|
||||||
|
// This user can login with password, public key or public key + password.
|
||||||
|
username := "testuser"
|
||||||
|
// This user can login with public key + password only.
|
||||||
|
usernameSecondFactor := "testuser_second_factor"
|
||||||
|
errPwdAuthFailed := errors.New("password auth failed")
|
||||||
|
errWrongSequence := errors.New("wrong sequence")
|
||||||
|
|
||||||
|
serverConfig := &ServerConfig{
|
||||||
|
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||||
|
if conn.User() == usernameSecondFactor {
|
||||||
|
return nil, errWrongSequence
|
||||||
|
}
|
||||||
|
if conn.User() == username && string(password) == clientPassword {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errPwdAuthFailed
|
||||||
|
},
|
||||||
|
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
|
||||||
|
if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
|
||||||
|
if conn.User() == usernameSecondFactor {
|
||||||
|
return nil, &PartialSuccessError{
|
||||||
|
Next: ServerAuthCallbacks{
|
||||||
|
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||||
|
if string(password) == clientPassword {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errPwdAuthFailed
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig := &ClientConfig{
|
||||||
|
User: usernameSecondFactor,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err := doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client login error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - partial success
|
||||||
|
// - nil
|
||||||
|
if len(serverAuthErrors) != 3 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[1].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatalf("expected partial success error, got: %v", serverAuthErrors[1])
|
||||||
|
}
|
||||||
|
// Now test a wrong sequence.
|
||||||
|
clientConfig.Auth = []AuthMethod{
|
||||||
|
Password(clientPassword),
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("client login with wrong sequence must fail")
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - wrong sequence
|
||||||
|
// - partial success
|
||||||
|
if len(serverAuthErrors) != 3 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if serverAuthErrors[1] != errWrongSequence {
|
||||||
|
t.Fatal("server not returned wrong sequence")
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[2].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatalf("expected partial success error, got: %v", serverAuthErrors[2])
|
||||||
|
}
|
||||||
|
// Now test using a correct sequence but a wrong password before the right
|
||||||
|
// one.
|
||||||
|
n := 0
|
||||||
|
passwords := []string{"WRONG", "WRONG", clientPassword}
|
||||||
|
clientConfig.Auth = []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
RetryableAuthMethod(PasswordCallback(func() (string, error) {
|
||||||
|
p := passwords[n]
|
||||||
|
n++
|
||||||
|
return p, nil
|
||||||
|
}), 3),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client login error: %s", err)
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - partial success
|
||||||
|
// - wrong password
|
||||||
|
// - wrong password
|
||||||
|
// - nil
|
||||||
|
if len(serverAuthErrors) != 5 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[1].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
if serverAuthErrors[2] != errPwdAuthFailed {
|
||||||
|
t.Fatal("server not returned password authentication failed")
|
||||||
|
}
|
||||||
|
if serverAuthErrors[3] != errPwdAuthFailed {
|
||||||
|
t.Fatal("server not returned password authentication failed")
|
||||||
|
}
|
||||||
|
// Only password authentication should fail.
|
||||||
|
clientConfig.Auth = []AuthMethod{
|
||||||
|
Password(clientPassword),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("client login with password only must fail")
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - wrong sequence
|
||||||
|
if len(serverAuthErrors) != 2 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if serverAuthErrors[1] != errWrongSequence {
|
||||||
|
t.Fatal("server not returned wrong sequence")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only public key authentication should fail.
|
||||||
|
clientConfig.Auth = []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("client login with public key only must fail")
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - partial success
|
||||||
|
if len(serverAuthErrors) != 2 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[1].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public key and wrong password.
|
||||||
|
clientConfig.Auth = []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
Password("WRONG"),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("client login with wrong password after public key must fail")
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - partial success
|
||||||
|
// - password auth failed
|
||||||
|
if len(serverAuthErrors) != 3 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[1].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
if serverAuthErrors[2] != errPwdAuthFailed {
|
||||||
|
t.Fatal("server not returned password authentication failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public key, public key again and then correct password. Public key
|
||||||
|
// authentication is attempted only once because the partial success error
|
||||||
|
// returns only "password" as the allowed authentication method.
|
||||||
|
clientConfig.Auth = []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
Password(clientPassword),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client login error: %s", err)
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - no auth passed yet
|
||||||
|
// - partial success
|
||||||
|
// - nil
|
||||||
|
if len(serverAuthErrors) != 3 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[1].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The unrestricted username can do anything
|
||||||
|
clientConfig = &ClientConfig{
|
||||||
|
User: username,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unrestricted client login error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig = &ClientConfig{
|
||||||
|
User: username,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unrestricted client login error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig = &ClientConfig{
|
||||||
|
User: username,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unrestricted client login error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDynamicAuthCallbacks(t *testing.T) {
|
||||||
|
user1 := "user1"
|
||||||
|
user2 := "user2"
|
||||||
|
errInvalidCredentials := errors.New("invalid credentials")
|
||||||
|
|
||||||
|
serverConfig := &ServerConfig{
|
||||||
|
NoClientAuth: true,
|
||||||
|
NoClientAuthCallback: func(conn ConnMetadata) (*Permissions, error) {
|
||||||
|
switch conn.User() {
|
||||||
|
case user1:
|
||||||
|
return nil, &PartialSuccessError{
|
||||||
|
Next: ServerAuthCallbacks{
|
||||||
|
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||||
|
if conn.User() == user1 && string(password) == clientPassword {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errInvalidCredentials
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case user2:
|
||||||
|
return nil, &PartialSuccessError{
|
||||||
|
Next: ServerAuthCallbacks{
|
||||||
|
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
|
||||||
|
if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
|
||||||
|
if conn.User() == user2 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errInvalidCredentials
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, errInvalidCredentials
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig := &ClientConfig{
|
||||||
|
User: user1,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err := doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client login error: %s", err)
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - partial success
|
||||||
|
// - nil
|
||||||
|
if len(serverAuthErrors) != 2 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[0].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig = &ClientConfig{
|
||||||
|
User: user2,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client login error: %s", err)
|
||||||
|
}
|
||||||
|
// The error sequence is:
|
||||||
|
// - partial success
|
||||||
|
// - nil
|
||||||
|
if len(serverAuthErrors) != 2 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[0].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
|
||||||
|
// user1 cannot login with public key
|
||||||
|
clientConfig = &ClientConfig{
|
||||||
|
User: user1,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("user1 login with public key must fail")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "no supported methods remain") {
|
||||||
|
t.Errorf("got %v, expected 'no supported methods remain'", err)
|
||||||
|
}
|
||||||
|
if len(serverAuthErrors) != 1 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[0].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
// user2 cannot login with password
|
||||||
|
clientConfig = &ClientConfig{
|
||||||
|
User: user2,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err = doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("user2 login with password must fail")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "no supported methods remain") {
|
||||||
|
t.Errorf("got %v, expected 'no supported methods remain'", err)
|
||||||
|
}
|
||||||
|
if len(serverAuthErrors) != 1 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if _, ok := serverAuthErrors[0].(*PartialSuccessError); !ok {
|
||||||
|
t.Fatal("server not returned partial success")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,12 @@
|
|||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -62,6 +66,133 @@ func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMaxAuthTriesNoneMethod(t *testing.T) {
|
||||||
|
username := "testuser"
|
||||||
|
serverConfig := &ServerConfig{
|
||||||
|
MaxAuthTries: 2,
|
||||||
|
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||||
|
if conn.User() == username && string(password) == clientPassword {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("invalid credentials")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c1, c2, err := netPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("netPipe: %v", err)
|
||||||
|
}
|
||||||
|
defer c1.Close()
|
||||||
|
defer c2.Close()
|
||||||
|
|
||||||
|
var serverAuthErrors []error
|
||||||
|
|
||||||
|
serverConfig.AddHostKey(testSigners["rsa"])
|
||||||
|
serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
|
||||||
|
serverAuthErrors = append(serverAuthErrors, err)
|
||||||
|
}
|
||||||
|
go newServer(c1, serverConfig)
|
||||||
|
|
||||||
|
clientConfig := ClientConfig{
|
||||||
|
User: username,
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
clientConfig.SetDefaults()
|
||||||
|
// Our client will send 'none' auth only once, so we need to send the
|
||||||
|
// requests manually.
|
||||||
|
c := &connection{
|
||||||
|
sshConn: sshConn{
|
||||||
|
conn: c2,
|
||||||
|
user: username,
|
||||||
|
clientVersion: []byte(packageVersion),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to exchange version: %v", err)
|
||||||
|
}
|
||||||
|
c.transport = newClientTransport(
|
||||||
|
newTransport(c.sshConn.conn, clientConfig.Rand, true /* is client */),
|
||||||
|
c.clientVersion, c.serverVersion, &clientConfig, "", c.sshConn.RemoteAddr())
|
||||||
|
if err := c.transport.waitSession(); err != nil {
|
||||||
|
t.Fatalf("unable to wait session: %v", err)
|
||||||
|
}
|
||||||
|
c.sessionID = c.transport.getSessionID()
|
||||||
|
if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil {
|
||||||
|
t.Fatalf("unable to send ssh-userauth message: %v", err)
|
||||||
|
}
|
||||||
|
packet, err := c.transport.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(packet) > 0 && packet[0] == msgExtInfo {
|
||||||
|
packet, err = c.transport.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var serviceAccept serviceAcceptMsg
|
||||||
|
if err := Unmarshal(packet, &serviceAccept); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for i := 0; i <= serverConfig.MaxAuthTries; i++ {
|
||||||
|
auth := new(noneAuth)
|
||||||
|
_, _, err := auth.auth(c.sessionID, clientConfig.User, c.transport, clientConfig.Rand, nil)
|
||||||
|
if i < serverConfig.MaxAuthTries {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("client: got no error")
|
||||||
|
} else if !strings.Contains(err.Error(), "too many authentication failures") {
|
||||||
|
t.Fatalf("client: got unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(serverAuthErrors) != 3 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
for _, err := range serverAuthErrors {
|
||||||
|
if !errors.Is(err, ErrNoAuth) {
|
||||||
|
t.Errorf("go error: %v; want: %v", err, ErrNoAuth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMaxAuthTriesFirstNoneAuthErrorIgnored(t *testing.T) {
|
||||||
|
username := "testuser"
|
||||||
|
serverConfig := &ServerConfig{
|
||||||
|
MaxAuthTries: 1,
|
||||||
|
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||||
|
if conn.User() == username && string(password) == clientPassword {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("invalid credentials")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
clientConfig := &ClientConfig{
|
||||||
|
User: username,
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
serverAuthErrors, err := doClientServerAuth(t, serverConfig, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client login error: %s", err)
|
||||||
|
}
|
||||||
|
if len(serverAuthErrors) != 2 {
|
||||||
|
t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
|
||||||
|
}
|
||||||
|
if !errors.Is(serverAuthErrors[0], ErrNoAuth) {
|
||||||
|
t.Errorf("go error: %v; want: %v", serverAuthErrors[0], ErrNoAuth)
|
||||||
|
}
|
||||||
|
if serverAuthErrors[1] != nil {
|
||||||
|
t.Errorf("unexpected error: %v", serverAuthErrors[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewServerConnValidationErrors(t *testing.T) {
|
func TestNewServerConnValidationErrors(t *testing.T) {
|
||||||
serverConf := &ServerConfig{
|
serverConf := &ServerConfig{
|
||||||
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},
|
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},
|
||||||
@@ -96,6 +227,78 @@ func TestNewServerConnValidationErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBannerError(t *testing.T) {
|
||||||
|
serverConfig := &ServerConfig{
|
||||||
|
BannerCallback: func(ConnMetadata) string {
|
||||||
|
return "banner from BannerCallback"
|
||||||
|
},
|
||||||
|
NoClientAuth: true,
|
||||||
|
NoClientAuthCallback: func(ConnMetadata) (*Permissions, error) {
|
||||||
|
err := &BannerError{
|
||||||
|
Err: errors.New("error from NoClientAuthCallback"),
|
||||||
|
Message: "banner from NoClientAuthCallback",
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("wrapped: %w", err)
|
||||||
|
},
|
||||||
|
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
|
||||||
|
return &Permissions{}, nil
|
||||||
|
},
|
||||||
|
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
|
||||||
|
return nil, &BannerError{
|
||||||
|
Err: errors.New("error from PublicKeyCallback"),
|
||||||
|
Message: "banner from PublicKeyCallback",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
KeyboardInteractiveCallback: func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) {
|
||||||
|
return nil, &BannerError{
|
||||||
|
Err: nil, // make sure that a nil inner error is allowed
|
||||||
|
Message: "banner from KeyboardInteractiveCallback",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
serverConfig.AddHostKey(testSigners["rsa"])
|
||||||
|
|
||||||
|
var banners []string
|
||||||
|
clientConfig := &ClientConfig{
|
||||||
|
User: "test",
|
||||||
|
Auth: []AuthMethod{
|
||||||
|
PublicKeys(testSigners["rsa"]),
|
||||||
|
KeyboardInteractive(func(name, instruction string, questions []string, echos []bool) ([]string, error) {
|
||||||
|
return []string{"letmein"}, nil
|
||||||
|
}),
|
||||||
|
Password(clientPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: InsecureIgnoreHostKey(),
|
||||||
|
BannerCallback: func(msg string) error {
|
||||||
|
banners = append(banners, msg)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c1, c2, err := netPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("netPipe: %v", err)
|
||||||
|
}
|
||||||
|
defer c1.Close()
|
||||||
|
defer c2.Close()
|
||||||
|
go newServer(c1, serverConfig)
|
||||||
|
c, _, _, err := NewClientConn(c2, "", clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("client connection failed: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
wantBanners := []string{
|
||||||
|
"banner from BannerCallback",
|
||||||
|
"banner from NoClientAuthCallback",
|
||||||
|
"banner from PublicKeyCallback",
|
||||||
|
"banner from KeyboardInteractiveCallback",
|
||||||
|
}
|
||||||
|
if !slices.Equal(banners, wantBanners) {
|
||||||
|
t.Errorf("got banners:\n%q\nwant banners:\n%q", banners, wantBanners)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type markerConn struct {
|
type markerConn struct {
|
||||||
closed uint32
|
closed uint32
|
||||||
used uint32
|
used uint32
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func TestCertLogin(t *testing.T) {
|
|||||||
s := newServer(t)
|
s := newServer(t)
|
||||||
|
|
||||||
// Use a key different from the default.
|
// Use a key different from the default.
|
||||||
clientKey := testSigners["dsa"]
|
clientKey := testSigners["ed25519"]
|
||||||
caAuthKey := testSigners["ecdsa"]
|
caAuthKey := testSigners["ecdsa"]
|
||||||
cert := &ssh.Certificate{
|
cert := &ssh.Certificate{
|
||||||
Key: clientKey.PublicKey(),
|
Key: clientKey.PublicKey(),
|
||||||
|
|||||||
+1
-1
@@ -4,4 +4,4 @@
|
|||||||
|
|
||||||
// Package test contains integration tests for the
|
// Package test contains integration tests for the
|
||||||
// golang.org/x/crypto/ssh package.
|
// golang.org/x/crypto/ssh package.
|
||||||
package test // import "golang.org/x/crypto/ssh/test"
|
package test
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type exitStatusMsg struct {
|
|||||||
Status uint32
|
Status uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// goServer is a test Go SSH server that accepts public key and certificate
|
// goTestServer is a test Go SSH server that accepts public key and certificate
|
||||||
// authentication and replies with a 0 exit status to any exec request without
|
// authentication and replies with a 0 exit status to any exec request without
|
||||||
// running any commands.
|
// running any commands.
|
||||||
type goTestServer struct {
|
type goTestServer struct {
|
||||||
|
|||||||
@@ -357,11 +357,6 @@ func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
|
|||||||
|
|
||||||
numBytes := 4096
|
numBytes := 4096
|
||||||
|
|
||||||
// Exercise sending data to the server
|
|
||||||
if _, _, err := conn.Conn.SendRequest("drop-me", false, make([]byte, numBytes)); err != nil {
|
|
||||||
t.Fatalf("SendRequest: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exercise receiving data from the server
|
// Exercise receiving data from the server
|
||||||
session, err := conn.NewSession()
|
session, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -377,6 +372,11 @@ func testOneCipher(t *testing.T, cipher string, cipherOrder []string) {
|
|||||||
if len(out) != numBytes {
|
if len(out) != numBytes {
|
||||||
t.Fatalf("got %d bytes, want %d bytes", len(out), numBytes)
|
t.Fatalf("got %d bytes, want %d bytes", len(out), numBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exercise sending data to the server
|
||||||
|
if _, _, err := conn.Conn.SendRequest("drop-me", false, make([]byte, numBytes)); err != nil {
|
||||||
|
t.Fatalf("SendRequest: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var deprecatedCiphers = []string{
|
var deprecatedCiphers = []string{
|
||||||
@@ -448,7 +448,6 @@ func TestKeyExchanges(t *testing.T) {
|
|||||||
func TestClientAuthAlgorithms(t *testing.T) {
|
func TestClientAuthAlgorithms(t *testing.T) {
|
||||||
for _, key := range []string{
|
for _, key := range []string{
|
||||||
"rsa",
|
"rsa",
|
||||||
"dsa",
|
|
||||||
"ecdsa",
|
"ecdsa",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
} {
|
} {
|
||||||
@@ -469,3 +468,72 @@ func TestClientAuthAlgorithms(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClientAuthDisconnect(t *testing.T) {
|
||||||
|
// Use a static key that is not accepted by server.
|
||||||
|
// This key has been generated with following ssh-keygen command and
|
||||||
|
// used exclusively in this unit test:
|
||||||
|
// $ ssh-keygen -t RSA -b 2048 -f /tmp/static_key \
|
||||||
|
// -C "Static RSA key for golang.org/x/crypto/ssh unit test"
|
||||||
|
|
||||||
|
const privKeyData = `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
|
||||||
|
NhAAAAAwEAAQAAAQEAwV1Zg3MqX27nIQQNWd8V09P4q4F1fx7H2xNJdL3Yg3y91GFLJ92+
|
||||||
|
0IiGV8n1VMGL/71PPhzyqBpUYSTpWjiU2JZSfA+iTg1GJBcOaEOA6vrXsTtXTHZ//mOT4d
|
||||||
|
mlvuP4+9NqfCBLGXN7ZJpT+amkD8AVW9YW9QN3ipY61ZWxPaAocVpDd8rVgJTk54KvaPa7
|
||||||
|
t4ddOSQDQq61aubIDR1Z3P+XjkB4piWOsbck3HJL+veTALy12C09tAhwUnZUAXS+DjhxOL
|
||||||
|
xpDVclF/yXYhAvBvsjwyk/OC3+nK9F799hpQZsjxmbP7oN+tGwz06BUcAKi7u7QstENvvk
|
||||||
|
85SDZy1q1QAAA/A7ylbJO8pWyQAAAAdzc2gtcnNhAAABAQDBXVmDcypfbuchBA1Z3xXT0/
|
||||||
|
irgXV/HsfbE0l0vdiDfL3UYUsn3b7QiIZXyfVUwYv/vU8+HPKoGlRhJOlaOJTYllJ8D6JO
|
||||||
|
DUYkFw5oQ4Dq+texO1dMdn/+Y5Ph2aW+4/j702p8IEsZc3tkmlP5qaQPwBVb1hb1A3eKlj
|
||||||
|
rVlbE9oChxWkN3ytWAlOTngq9o9ru3h105JANCrrVq5sgNHVnc/5eOQHimJY6xtyTcckv6
|
||||||
|
95MAvLXYLT20CHBSdlQBdL4OOHE4vGkNVyUX/JdiEC8G+yPDKT84Lf6cr0Xv32GlBmyPGZ
|
||||||
|
s/ug360bDPToFRwAqLu7tCy0Q2++TzlINnLWrVAAAAAwEAAQAAAQAIvPDHMiyIxgCksGPF
|
||||||
|
uyv9F9U4XjVip8/abE9zkAMJWW5++wuT/bRlBOUPRrWIXZEM9ETbtsqswo3Wxah+7CjRIH
|
||||||
|
qR7SdFlYTP1jPk4yIKXF4OvggBUPySkMpAGJ9hwOMW8Ymcb4gn77JJ4aMoWIcXssje+XiC
|
||||||
|
8iO+4UWU3SV2i6K7flK1UDCI5JVCyBr3DVf3QhMOgvwJl9TgD7FzWy1hkjuZq/Pzdv+fA2
|
||||||
|
OfrUFiSukLNolidNoI9+KWa1yxixE+B2oN4Xan3ZbqGbL6Wc1dB+K9h/bNcu+SKf7fXWRi
|
||||||
|
/vVG44A61xGDZzen1+eQlqFp7narkKXoaU71+45VXDThAAAAgBPWUdQykEEm0yOS6hPIW+
|
||||||
|
hS8z1LXWGTEcag9fMwJXKE7cQFO3LEk+dXMbClHdhD/ydswOZYGSNepxwvmo/a5LiO2ulp
|
||||||
|
W+5tnsNhcK3skdaf71t+boUEXBNZ6u3WNTkU7tDN8h9tebI+xlNceDGSGjOlNoHQVMKZdA
|
||||||
|
W9TA4ZqXUPAAAAgQDWU0UZVOSCAOODPz4PYsbFKdCfXNP8O4+t9txyc9E3hsLAsVs+CpVX
|
||||||
|
Gr219MGLrublzAxojipyzuQb6Tp1l9nsu7VkcBrPL8I1tokz0AyTnmNF3A9KszBal7gGNS
|
||||||
|
a2qYuf6JO4cub1KzonxUJQHZPZq9YhCxOtDwTd+uyHZiPy9QAAAIEA5vayd+nfVJgCKTdf
|
||||||
|
z5MFsxBSUj/cAYg7JYPS/0bZ5bEkLosL22wl5Tm/ZftJa8apkyBPhguAWt6jEWLoDiK+kn
|
||||||
|
Fv0SaEq1HUdXgWmISVnWzv2pxdAtq/apmbxTg3iIJyrAwEDo13iImR3k6rNPx1m3i/jX56
|
||||||
|
HLcvWM4Y6bFzbGEAAAA0U3RhdGljIFJTQSBrZXkgZm9yIGdvbGFuZy5vcmcveC9jcnlwdG
|
||||||
|
8vc3NoIHVuaXQgdGVzdAECAwQFBgc=
|
||||||
|
-----END OPENSSH PRIVATE KEY-----`
|
||||||
|
|
||||||
|
signer, err := ssh.ParsePrivateKey([]byte(privKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create signer from key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start server with MaxAuthTries 1 and publickey and password auth
|
||||||
|
// enabled
|
||||||
|
server := newServerForConfig(t, "MaxAuthTries", map[string]string{})
|
||||||
|
|
||||||
|
// Connect to server, expect failure, that PublicKeysCallback is called
|
||||||
|
// and that PasswordCallback is not called.
|
||||||
|
publicKeysCallbackCalled := false
|
||||||
|
config := clientConfig()
|
||||||
|
config.Auth = []ssh.AuthMethod{
|
||||||
|
ssh.PublicKeysCallback(func() ([]ssh.Signer, error) {
|
||||||
|
publicKeysCallbackCalled = true
|
||||||
|
return []ssh.Signer{signer}, nil
|
||||||
|
}),
|
||||||
|
ssh.PasswordCallback(func() (string, error) {
|
||||||
|
t.Errorf("unexpected call to PasswordCallback()")
|
||||||
|
return "notaverygoodpassword", nil
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
client, err := server.TryDial(config)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected TryDial() to fail")
|
||||||
|
_ = client.Close()
|
||||||
|
}
|
||||||
|
if !publicKeysCallbackCalled {
|
||||||
|
t.Errorf("expected PublicKeysCallback() to be called")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,12 +58,17 @@ UsePAM yes
|
|||||||
PasswordAuthentication yes
|
PasswordAuthentication yes
|
||||||
ChallengeResponseAuthentication yes
|
ChallengeResponseAuthentication yes
|
||||||
AuthenticationMethods {{.AuthMethods}}
|
AuthenticationMethods {{.AuthMethods}}
|
||||||
|
`
|
||||||
|
maxAuthTriesSshdConfigTail = `
|
||||||
|
PasswordAuthentication yes
|
||||||
|
MaxAuthTries 1
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
var configTmpl = map[string]*template.Template{
|
var configTmpl = map[string]*template.Template{
|
||||||
"default": template.Must(template.New("").Parse(defaultSshdConfig)),
|
"default": template.Must(template.New("").Parse(defaultSshdConfig)),
|
||||||
"MultiAuth": template.Must(template.New("").Parse(defaultSshdConfig + multiAuthSshdConfigTail))}
|
"MultiAuth": template.Must(template.New("").Parse(defaultSshdConfig + multiAuthSshdConfigTail)),
|
||||||
|
"MaxAuthTries": template.Must(template.New("").Parse(defaultSshdConfig + maxAuthTriesSshdConfigTail))}
|
||||||
|
|
||||||
type server struct {
|
type server struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
|
|||||||
Vendored
+1
-1
@@ -5,4 +5,4 @@
|
|||||||
// This package contains test data shared between the various subpackages of
|
// This package contains test data shared between the various subpackages of
|
||||||
// the golang.org/x/crypto/ssh package. Under no circumstance should
|
// the golang.org/x/crypto/ssh package. Under no circumstance should
|
||||||
// this data be used for production code.
|
// this data be used for production code.
|
||||||
package testdata // import "golang.org/x/crypto/ssh/testdata"
|
package testdata
|
||||||
|
|||||||
Vendored
+29
-17
@@ -46,19 +46,31 @@ FFlRjzoB3Oxu8UQgb+MWPedtH9XYBbg9biz4jJLkXQ==
|
|||||||
-----END EC PRIVATE KEY-----
|
-----END EC PRIVATE KEY-----
|
||||||
`),
|
`),
|
||||||
"rsa": []byte(`-----BEGIN RSA PRIVATE KEY-----
|
"rsa": []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIICXAIBAAKBgQC8A6FGHDiWCSREAXCq6yBfNVr0xCVG2CzvktFNRpue+RXrGs/2
|
MIIEpQIBAAKCAQEAnuozKMtcQkIImZGSe4IujS4+Lkas9jmlBivziWGU3waivkpU
|
||||||
a6ySEJQb3IYquw7HlJgu6fg3WIWhOmHCjfpG0PrL4CRwbqQ2LaPPXhJErWYejcD8
|
vYspgJbh7vSvnHOPtKscdIJ+3UUyViDUoM73GumsmHvfeRCoA9YROZK4fQR9G0a1
|
||||||
Di00cF3677+G10KMZk9RXbmHtuBFZT98wxg8j+ZsBMqGM1+7yrWUvynswQIDAQAB
|
wfoRqsrJXGToCzTvr/I2KIwpUG0bRE9rUvsW+JN9xgri+cIJWtu/dGYDkILO4bkF
|
||||||
AoGAJMCk5vqfSRzyXOTXLGIYCuR4Kj6pdsbNSeuuRGfYBeR1F2c/XdFAg7D/8s5R
|
IxtEvHNVvhGLenyOHFhPw3hAZ7/bKq8kvKzm9D2zOllHe1wWncMkhVmEFF9Houeh
|
||||||
38p/Ih52/Ty5S8BfJtwtvgVY9ecf/JlU/rl/QzhG8/8KC0NG7KsyXklbQ7gJT8UT
|
jbddmeIAAxBpRUFfzp1dD7503ADBlJdK306D4CeI4KIFiqE1VrmfcMgP8fti0S0b
|
||||||
Ojmw5QpMk+rKv17ipDVkQQmPaj+gJXYNAHqImke5mm/K/h0CQQDciPmviQ+DOhOq
|
4JtmvevYoPd+/wB9ItFqvhc6nyuxF0PfWH+SvwIDAQABAoIBAQCCcpNeSFjKVvRC
|
||||||
2ZBqUfH8oXHgFmp7/6pXw80DpMIxgV3CwkxxIVx6a8lVH9bT/AFySJ6vXq4zTuV9
|
Q1nwIrPd1njaec+fK0CIqWl3e2++B+9trwySrvp5gOGjyp2hGsd7Mf7gsQI81oF0
|
||||||
6QmZcZzDAkEA2j/UXJPIs1fQ8z/6sONOkU/BjtoePFIWJlRxdN35cZjXnBraX5UR
|
a+y+uEXlhK3WWdDey0pwI7ft/7+LeDTOQCQRQBpijaXvPzGviVu7nWLRtARx7a41
|
||||||
fFHkePv4YwqmXNqrBOvSu+w2WdSDci+IKwJAcsPRc/jWmsrJW1q3Ha0hSf/WG/Bu
|
S9A4xL5dfI0BFYyuIpaVS8+EV/1TEJIbceZ5q5RBlARA1rc+nBvjygNzYdRq9Rao
|
||||||
X7MPuXaKpP/DkzGoUmb8ks7yqj6XWnYkPNLjCc8izU5vRwIiyWBRf4mxMwJBAILa
|
yyehvnXZ7pQrATnwofPolbZNseW2Q9sRMmtm1E60XJJ433P7nFbxXtsMAYgxWSQc
|
||||||
NDvRS0rjwt6lJGv7zPZoqDc65VfrK2aNyHx2PgFyzwrEOtuF57bu7pnvEIxpLTeM
|
V/92iRPYeD7sN/b7qulLEgC6e8el2gLGIB9aQyG7B6KFqloqvx/ymYs07+bWIQCU
|
||||||
z26i6XVMeYXAWZMTloMCQBbpGgEERQpeUknLBqUHhg/wXF6+lFA+vEGnkY+Dwab2
|
6i9y7LABAoGBANKB2Rs0lF5c+gpEE3w0AWoxGyL04TZECtl2hQ/b2jc2n8hLqLhv
|
||||||
KCXFGd+SQ5GdUcEMe9isUH6DYj/6/yCDoFrXXmpQb+M=
|
zNIKN+xzEP6j0ijXajjEMLiQH10qQ6+Plv8C7o8GJC1V/Oj4u4kbPqfVV1kSxuWm
|
||||||
|
FBjz6+c8VPbEBgXq5lCMEgC2Ii8XVRoyd3iSSOh+LIMBu/Br3JEsjJq/AoGBAMFC
|
||||||
|
CvODTiThrZo8v765dRSHrLOvB4jZOPrEKLWECLaQDQpuhgzZhyWm9zFfxGB+LWE9
|
||||||
|
R9pU6ZCFPtPfd4cRZ9cezrp+lgdrqjcUX/2ZLLMk21WXFuRaw/4KTlKNsMY6lbAK
|
||||||
|
qVkUFWIZWaCQ8bdVCP48polipRNmN9mAHsIhIwgBAoGBAM6yn1qeS11I0GAKLlPT
|
||||||
|
wNvjsfCmIQmm0DxtqwRCbUevxD7pQ5cueCB51iW/ap2OgEqIEo4A3pIrOhDB8kpN
|
||||||
|
pQdrepFHh3hYqYicy5A6B1DHJAibbl+Krss9n5KjZA4VtpBS8al/kCHQtUomD/M0
|
||||||
|
QKlMgnh/g/dzWXYegyqtYraDAoGAGbeBH5B8iJnjcR/eYDHrq5S2XZ7QANzvISeT
|
||||||
|
RzxPsIOQyK+WdQVJX7BNOqvExRZlUYhHFH2yKwIgLy+Qh0/Aora9ycFok4o3N2cl
|
||||||
|
suh8M0aXTVdyu2Z8qESU0ZV7TZWkL63rhSgQBGLdM2m2ULAnJzXI74VJ9D/o9K+A
|
||||||
|
6FJiiAECgYEAujJ/hKxVKEUvxwloGSDhKCUH86+7UOkb/EM2zZFrlPYAz1VcCwr3
|
||||||
|
K14r8BtmLFXuLXOlACpoH0Wf4uia+t6n8m9JK3mvpJ7fempAsptP3AdZMQFe7xUm
|
||||||
|
SXEGQBYxcyS5Q+ncwWZuPgby5wJ9D4Fd6TQH+wwG52sFugt/fGxbPug=
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
`),
|
`),
|
||||||
"pkcs8": []byte(`-----BEGIN PRIVATE KEY-----
|
"pkcs8": []byte(`-----BEGIN PRIVATE KEY-----
|
||||||
@@ -190,17 +202,17 @@ var SSHCertificates = map[string][]byte{
|
|||||||
//
|
//
|
||||||
// 2. Assumes "ca" key above in file named "ca", sign a cert for "rsa.pub":
|
// 2. Assumes "ca" key above in file named "ca", sign a cert for "rsa.pub":
|
||||||
// ssh-keygen -s ca -h -n host.example.com -V +500w -I host.example.com-key rsa.pub
|
// ssh-keygen -s ca -h -n host.example.com -V +500w -I host.example.com-key rsa.pub
|
||||||
"rsa": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgLjYqmmuTSEmjVhSfLQphBSTJMLwIZhRgmpn8FHKLiEIAAAADAQABAAAAgQC8A6FGHDiWCSREAXCq6yBfNVr0xCVG2CzvktFNRpue+RXrGs/2a6ySEJQb3IYquw7HlJgu6fg3WIWhOmHCjfpG0PrL4CRwbqQ2LaPPXhJErWYejcD8Di00cF3677+G10KMZk9RXbmHtuBFZT98wxg8j+ZsBMqGM1+7yrWUvynswQAAAAAAAAAAAAAAAgAAABRob3N0LmV4YW1wbGUuY29tLWtleQAAABQAAAAQaG9zdC5leGFtcGxlLmNvbQAAAABZHN8UAAAAAGsjIYUAAAAAAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC+D11D0hEbn2Vglv4YRJ8pZNyHjIGmvth3DWOQrq++2vH2MujmGQDxfr4SVE9GpMBlKU3lwGbpgIBxAg6yZcNSfo6PWVU9ACg6NMFO+yMzc2MaG+/naQdNjSewywF5j2rkNO2XOaViRVSrZroe2B/aY2LTV0jDl8nu5NOjwRs1/s7SLe5z1rw/X0dpmXk0qJY3gQhmR8HZZ1dhEkJUGwaBCPd0T8asSYf1Ag2rUD4aQ28r3q69mbwfWOOa6rMemVZruUV5dzHwVNVNtVv+ImtnYtz8m8g+K0plaGptHn3KsaOnASkh3tujhaE7kvc4HR9Igli9+76jhZie3h/dTN5zAAABDwAAAAdzc2gtcnNhAAABALeDea+60H6xJGhktAyosHaSY7AYzLocaqd8hJQjEIDifBwzoTlnBmcK9CxGhKuaoJFThdCLdaevCeOSuquh8HTkf+2ebZZc/G5T+2thPvPqmcuEcmMosWo+SIjYhbP3S6KD49aLC1X0kz8IBQeauFvURhkZ5ZjhA1L4aQYt9NjL73nqOl8PplRui+Ov5w8b4ldul4zOvYAFrzfcP6wnnXk3c1Zzwwf5wynD5jakO8GpYKBuhM7Z4crzkKSQjU3hla7xqgfomC5Gz4XbR2TNjcQiRrJQ0UlKtX3X3ObRCEhuvG0Kzjklhv+Ddw6txrhKjMjiSi/Yyius/AE8TmC1p4U= host.example.com
|
"rsa": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgWcP1x+t9PQTxkt/fRa8v5HXz0FFW/fwN3mpR5jdGo3UAAAADAQABAAABAQCe6jMoy1xCQgiZkZJ7gi6NLj4uRqz2OaUGK/OJYZTfBqK+SlS9iymAluHu9K+cc4+0qxx0gn7dRTJWINSgzvca6ayYe995EKgD1hE5krh9BH0bRrXB+hGqyslcZOgLNO+v8jYojClQbRtET2tS+xb4k33GCuL5wgla2790ZgOQgs7huQUjG0S8c1W+EYt6fI4cWE/DeEBnv9sqryS8rOb0PbM6WUd7XBadwySFWYQUX0ei56GNt12Z4gADEGlFQV/OnV0PvnTcAMGUl0rfToPgJ4jgogWKoTVWuZ9wyA/x+2LRLRvgm2a969ig937/AH0i0Wq+FzqfK7EXQ99Yf5K/AAAAAAAAAAAAAAACAAAAFGhvc3QuZXhhbXBsZS5jb20ta2V5AAAAFAAAABBob3N0LmV4YW1wbGUuY29tAAAAAGXEzUQAAAAAd8sPtQAAAAAAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBAL4PXUPSERufZWCW/hhEnylk3IeMgaa+2HcNY5Cur77a8fYy6OYZAPF+vhJUT0akwGUpTeXAZumAgHECDrJlw1J+jo9ZVT0AKDo0wU77IzNzYxob7+dpB02NJ7DLAXmPauQ07Zc5pWJFVKtmuh7YH9pjYtNXSMOXye7k06PBGzX+ztIt7nPWvD9fR2mZeTSoljeBCGZHwdlnV2ESQlQbBoEI93RPxqxJh/UCDatQPhpDbyverr2ZvB9Y45rqsx6ZVmu5RXl3MfBU1U21W/4ia2di3PybyD4rSmVoam0efcqxo6cBKSHe26OFoTuS9zgdH0iCWL37vqOFmJ7eH91M3nMAAAEPAAAAB3NzaC1yc2EAAAEAs8/78EsftS/0+6CfUAtRhmgpOPZVH8XJc2o4Qx/lQCBg/uB2sucGGx/5BuFUwAjhMNQ1UejJ6+AbNgZNlH7LIssGxpcW+eKQXLfd9KwWNPCU3DqZGiMBsYESNtVLjKAMuvJmxKFFu4rceyya+GZfsQFJR7G++XK0cQQ4rgDSnQo3pxQnHwguFWeHtwjdOj0helYER4XDKjKQlo0SxI1nVo7n1jkl8QghdxX6HKia6MP7MqstgNujTvrCEUJ6L3YflD/SJ00Y3ySD9+5hqvfqrDh4c4rRuc4+k0e3fYZwyWO2NNtKHRBOZAgW8zzfR3G99YdTw8N8+2oXeAdvB9k0tA== host.example.com
|
||||||
`),
|
`),
|
||||||
"rsa-sha2-256": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgOyK28gunJkM60qp4EbsYAjgbUsyjS8u742OLjipIgc0AAAADAQABAAAAgQC8A6FGHDiWCSREAXCq6yBfNVr0xCVG2CzvktFNRpue+RXrGs/2a6ySEJQb3IYquw7HlJgu6fg3WIWhOmHCjfpG0PrL4CRwbqQ2LaPPXhJErWYejcD8Di00cF3677+G10KMZk9RXbmHtuBFZT98wxg8j+ZsBMqGM1+7yrWUvynswQAAAAAAAAAAAAAAAgAAABRob3N0LmV4YW1wbGUuY29tLWtleQAAABQAAAAQaG9zdC5leGFtcGxlLmNvbQAAAABeSMJ4AAAAAHBPBLwAAAAAAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC+D11D0hEbn2Vglv4YRJ8pZNyHjIGmvth3DWOQrq++2vH2MujmGQDxfr4SVE9GpMBlKU3lwGbpgIBxAg6yZcNSfo6PWVU9ACg6NMFO+yMzc2MaG+/naQdNjSewywF5j2rkNO2XOaViRVSrZroe2B/aY2LTV0jDl8nu5NOjwRs1/s7SLe5z1rw/X0dpmXk0qJY3gQhmR8HZZ1dhEkJUGwaBCPd0T8asSYf1Ag2rUD4aQ28r3q69mbwfWOOa6rMemVZruUV5dzHwVNVNtVv+ImtnYtz8m8g+K0plaGptHn3KsaOnASkh3tujhaE7kvc4HR9Igli9+76jhZie3h/dTN5zAAABFAAAAAxyc2Etc2hhMi0yNTYAAAEAbG4De/+QiqopPS3O1H7ySeEUCY56qmdgr02sFErnihdXPDaWXUXxacvJHaEtLrSTSaPL/3v3iKvjLWDOHaQ5c+cN9J7Tqzso7RQCXZD2nK9bwCUyBoiDyBCRe8w4DQEtfL5okpVzQsSAiojQ8hBohMOpy3gFfXrdm4PVC1ZKqlZh4fAc7ajieRq/Tpq2xOLdHwxkcgPNR83WVHva6K9/xjev/5n227/gkHo0qbGs8YYDOFXIEhENi+B23IzxdNVieWdyQpYpe0C2i95Jhyo0wJmaFY2ArruTS+D1jGQQpMPvAQRy26/A5hI83GLhpwyhrN/M8wCxzAhyPL6Ieuh5tQ== host.example.com
|
"rsa-sha2-256": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg4+hKHVPKv183MU/Q7XD/mzDBFSc2YY3eraltxLMGJo0AAAADAQABAAABAQCe6jMoy1xCQgiZkZJ7gi6NLj4uRqz2OaUGK/OJYZTfBqK+SlS9iymAluHu9K+cc4+0qxx0gn7dRTJWINSgzvca6ayYe995EKgD1hE5krh9BH0bRrXB+hGqyslcZOgLNO+v8jYojClQbRtET2tS+xb4k33GCuL5wgla2790ZgOQgs7huQUjG0S8c1W+EYt6fI4cWE/DeEBnv9sqryS8rOb0PbM6WUd7XBadwySFWYQUX0ei56GNt12Z4gADEGlFQV/OnV0PvnTcAMGUl0rfToPgJ4jgogWKoTVWuZ9wyA/x+2LRLRvgm2a969ig937/AH0i0Wq+FzqfK7EXQ99Yf5K/AAAAAAAAAAAAAAACAAAAFGhvc3QuZXhhbXBsZS5jb20ta2V5AAAAFAAAABBob3N0LmV4YW1wbGUuY29tAAAAAGXEzYAAAAAAd8sP4wAAAAAAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBAL4PXUPSERufZWCW/hhEnylk3IeMgaa+2HcNY5Cur77a8fYy6OYZAPF+vhJUT0akwGUpTeXAZumAgHECDrJlw1J+jo9ZVT0AKDo0wU77IzNzYxob7+dpB02NJ7DLAXmPauQ07Zc5pWJFVKtmuh7YH9pjYtNXSMOXye7k06PBGzX+ztIt7nPWvD9fR2mZeTSoljeBCGZHwdlnV2ESQlQbBoEI93RPxqxJh/UCDatQPhpDbyverr2ZvB9Y45rqsx6ZVmu5RXl3MfBU1U21W/4ia2di3PybyD4rSmVoam0efcqxo6cBKSHe26OFoTuS9zgdH0iCWL37vqOFmJ7eH91M3nMAAAEUAAAADHJzYS1zaGEyLTI1NgAAAQA/ByIegNZYJRRl413S/8LxGvTZnbxsPwaluoJ/54niGZV9P28THz7d9jXfSHPjalhH93jNPfTYXvI4opnDC37ua1Nu8KKfk40IWXnnDdZLWraUxEidIzhmfVtz8kGdGoFQ8H0EzubL7zKNOTlfSfOoDlmQVOuxT/+eh2mEp4ri0/+8J1mLfLBr8tREX0/iaNjK+RKdcyTMicKursAYMCDdu8vlaphxea+ocyHM9izSX/l33t44V13ueTqIOh2Zbl2UE2k+jk+0dc1CmV0SEoiWiIyt8TRM4yQry1vPlQLsrf28sYM/QMwnhCVhyZO3vs5F25aQWrB9d51VEzBW9/fd host.example.com
|
||||||
`),
|
`),
|
||||||
"rsa-sha2-512": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgFGv4IpXfs4L/Y0b3rmUdPFhWoUrVnXuPxXr6aHGs7wgAAAADAQABAAAAgQC8A6FGHDiWCSREAXCq6yBfNVr0xCVG2CzvktFNRpue+RXrGs/2a6ySEJQb3IYquw7HlJgu6fg3WIWhOmHCjfpG0PrL4CRwbqQ2LaPPXhJErWYejcD8Di00cF3677+G10KMZk9RXbmHtuBFZT98wxg8j+ZsBMqGM1+7yrWUvynswQAAAAAAAAAAAAAAAgAAABRob3N0LmV4YW1wbGUuY29tLWtleQAAABQAAAAQaG9zdC5leGFtcGxlLmNvbQAAAABeSMRYAAAAAHBPBp4AAAAAAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC+D11D0hEbn2Vglv4YRJ8pZNyHjIGmvth3DWOQrq++2vH2MujmGQDxfr4SVE9GpMBlKU3lwGbpgIBxAg6yZcNSfo6PWVU9ACg6NMFO+yMzc2MaG+/naQdNjSewywF5j2rkNO2XOaViRVSrZroe2B/aY2LTV0jDl8nu5NOjwRs1/s7SLe5z1rw/X0dpmXk0qJY3gQhmR8HZZ1dhEkJUGwaBCPd0T8asSYf1Ag2rUD4aQ28r3q69mbwfWOOa6rMemVZruUV5dzHwVNVNtVv+ImtnYtz8m8g+K0plaGptHn3KsaOnASkh3tujhaE7kvc4HR9Igli9+76jhZie3h/dTN5zAAABFAAAAAxyc2Etc2hhMi01MTIAAAEAnF4fVj6mm+UFeNCIf9AKJCv9WzymjjPvzzmaMWWkPWqoV0P0m5SiYfvbY9SbA73Blpv8SOr0DmpublF183kodREia4KyVuC8hLhSCV2Y16hy9MBegOZMepn80w+apj7Rn9QCz5OfEakDdztp6OWTBtqxnZFcTQ4XrgFkNWeWRElGdEvAVNn2WHwHi4EIdz0mdv48Imv5SPlOuW862ZdFG4Do1dUfDIiGsBofLlgcyIYlf+eNHul6sBeUkuwFxisMpI5DQzNp8PX1g/QJA2wzwT674PTqDXNttKjyh50Fdr4sXxm9Gz1+jVLoESvFNa55ERdSyAqNu4wTy11MZsWwSA== host.example.com
|
"rsa-sha2-512": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgylCoUX+0nYXGG9k/KEepcgEd22921eUwSQsYuQXKOswAAAADAQABAAABAQCe6jMoy1xCQgiZkZJ7gi6NLj4uRqz2OaUGK/OJYZTfBqK+SlS9iymAluHu9K+cc4+0qxx0gn7dRTJWINSgzvca6ayYe995EKgD1hE5krh9BH0bRrXB+hGqyslcZOgLNO+v8jYojClQbRtET2tS+xb4k33GCuL5wgla2790ZgOQgs7huQUjG0S8c1W+EYt6fI4cWE/DeEBnv9sqryS8rOb0PbM6WUd7XBadwySFWYQUX0ei56GNt12Z4gADEGlFQV/OnV0PvnTcAMGUl0rfToPgJ4jgogWKoTVWuZ9wyA/x+2LRLRvgm2a969ig937/AH0i0Wq+FzqfK7EXQ99Yf5K/AAAAAAAAAAAAAAACAAAAFGhvc3QuZXhhbXBsZS5jb20ta2V5AAAAFAAAABBob3N0LmV4YW1wbGUuY29tAAAAAGXEzbwAAAAAd8sQBAAAAAAAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBAL4PXUPSERufZWCW/hhEnylk3IeMgaa+2HcNY5Cur77a8fYy6OYZAPF+vhJUT0akwGUpTeXAZumAgHECDrJlw1J+jo9ZVT0AKDo0wU77IzNzYxob7+dpB02NJ7DLAXmPauQ07Zc5pWJFVKtmuh7YH9pjYtNXSMOXye7k06PBGzX+ztIt7nPWvD9fR2mZeTSoljeBCGZHwdlnV2ESQlQbBoEI93RPxqxJh/UCDatQPhpDbyverr2ZvB9Y45rqsx6ZVmu5RXl3MfBU1U21W/4ia2di3PybyD4rSmVoam0efcqxo6cBKSHe26OFoTuS9zgdH0iCWL37vqOFmJ7eH91M3nMAAAEUAAAADHJzYS1zaGEyLTUxMgAAAQADOjYUNxzwYZ9O3zjjZSKhX7Ix/vUBq8lIltBRckbKJtcjn2/qqtaeZK2ijkbMlnPFCJ59U+Z6m4DMU6gxYF8R9/WJrANlWYNQ4+52fXjE/FPDdJkwB/kPWABt+ffEiM1HfzP4/zXgTtOJ0GogEzTYoMSrhAlpdKACUaC9nCQ7gjmO+owGkrB3ZbyQS4gltqQZjiBNqF0P/vxmXP+0Kx66/ei8JNYUpEPCXT4ZhLZmsVptaYD1gpvc2i5T5LnjRrsvf4Q6EKR+gwJEjlwnylhH5+h+ZU/KXydkw1hhEVP+ZiIBkVo9nN78Qb/VMJum4Fdoltuyh/9k2lMDeyDuRVh7 host.example.com
|
||||||
`),
|
`),
|
||||||
// Assumes "ca" key above in file named "ca", sign a user cert for "rsa.pub"
|
// Assumes "ca" key above in file named "ca", sign a user cert for "rsa.pub"
|
||||||
// using "testcertificate" as principal:
|
// using "testcertificate" as principal:
|
||||||
//
|
//
|
||||||
// ssh-keygen -s ca -I username -n testcertificate rsa.pub
|
// ssh-keygen -s ca -I username -n testcertificate rsa.pub
|
||||||
"rsa-user-testcertificate": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgr0MnhSf+KkQWEQmweJOGsJfOrUt80pQZDaI9YiwSfDUAAAADAQABAAAAgQC8A6FGHDiWCSREAXCq6yBfNVr0xCVG2CzvktFNRpue+RXrGs/2a6ySEJQb3IYquw7HlJgu6fg3WIWhOmHCjfpG0PrL4CRwbqQ2LaPPXhJErWYejcD8Di00cF3677+G10KMZk9RXbmHtuBFZT98wxg8j+ZsBMqGM1+7yrWUvynswQAAAAAAAAAAAAAAAQAAAAh1c2VybmFtZQAAABMAAAAPdGVzdGNlcnRpZmljYXRlAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC+D11D0hEbn2Vglv4YRJ8pZNyHjIGmvth3DWOQrq++2vH2MujmGQDxfr4SVE9GpMBlKU3lwGbpgIBxAg6yZcNSfo6PWVU9ACg6NMFO+yMzc2MaG+/naQdNjSewywF5j2rkNO2XOaViRVSrZroe2B/aY2LTV0jDl8nu5NOjwRs1/s7SLe5z1rw/X0dpmXk0qJY3gQhmR8HZZ1dhEkJUGwaBCPd0T8asSYf1Ag2rUD4aQ28r3q69mbwfWOOa6rMemVZruUV5dzHwVNVNtVv+ImtnYtz8m8g+K0plaGptHn3KsaOnASkh3tujhaE7kvc4HR9Igli9+76jhZie3h/dTN5zAAABFAAAAAxyc2Etc2hhMi01MTIAAAEAFuA+67KvnlmcodIp0Lv4mR9UW/CHghAaN1csBJTkI8mx3wXKyIPTsS2uXboEhWD0a7S9gps2SEwC5m6E3kV2Rzg7aH1S03GZqMvVlK2VHe7fzuoW2yOKk6yEPjeTF0pKCFbUQ6mce8pRpD/zdvjG0Z287XM3c3Axlrn7qq7TS0MDTjEZ/dsUNFHxep3co/HuAsWVWPVDItr/FPnvZ6WVH1yc8N/AJn0gLHobkGgug22vI9rNIge1wrnXxU9BUSouzkau/PQsrCQapnn+I1H7HaQt0wdk45nxMP+ags+HRI9qpX/p8WDn6+zpqYqN/nfw2aoytyaJqhsV32Teuqtrgg== rsa.pub
|
"rsa-user-testcertificate": []byte(`ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgEKR9xnhXkbi/pgP669VjBH6XVTYR0yx1wunCtOIjzjUAAAADAQABAAABAQCe6jMoy1xCQgiZkZJ7gi6NLj4uRqz2OaUGK/OJYZTfBqK+SlS9iymAluHu9K+cc4+0qxx0gn7dRTJWINSgzvca6ayYe995EKgD1hE5krh9BH0bRrXB+hGqyslcZOgLNO+v8jYojClQbRtET2tS+xb4k33GCuL5wgla2790ZgOQgs7huQUjG0S8c1W+EYt6fI4cWE/DeEBnv9sqryS8rOb0PbM6WUd7XBadwySFWYQUX0ei56GNt12Z4gADEGlFQV/OnV0PvnTcAMGUl0rfToPgJ4jgogWKoTVWuZ9wyA/x+2LRLRvgm2a969ig937/AH0i0Wq+FzqfK7EXQ99Yf5K/AAAAAAAAAAAAAAABAAAACHVzZXJuYW1lAAAAEwAAAA90ZXN0Y2VydGlmaWNhdGUAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBAL4PXUPSERufZWCW/hhEnylk3IeMgaa+2HcNY5Cur77a8fYy6OYZAPF+vhJUT0akwGUpTeXAZumAgHECDrJlw1J+jo9ZVT0AKDo0wU77IzNzYxob7+dpB02NJ7DLAXmPauQ07Zc5pWJFVKtmuh7YH9pjYtNXSMOXye7k06PBGzX+ztIt7nPWvD9fR2mZeTSoljeBCGZHwdlnV2ESQlQbBoEI93RPxqxJh/UCDatQPhpDbyverr2ZvB9Y45rqsx6ZVmu5RXl3MfBU1U21W/4ia2di3PybyD4rSmVoam0efcqxo6cBKSHe26OFoTuS9zgdH0iCWL37vqOFmJ7eH91M3nMAAAEUAAAADHJzYS1zaGEyLTUxMgAAAQCKVn2S7FJYhXTRVbcz1Di1HLz1g5Yae5WBhd0Tg471XkNw7ylcCK23Wnrzj1GxrW0oWCCGHROtUnxQXei1xNWt8HONN+eeafrJSZJR6ald3Yd4OveXlHNT6mEDPgqRj4B56OPoY33LzpaFlQZlZ6U9KXySshNaCTjVp3ojTj6uPNxcuOnG9O5emEPC2eaM4QYsz4cqHNJ9SWWEu+HIQgpx5SM12qcrq/KhN6WJhG3edL1YAsxkf1/THEcfi6wvsHi+DKewJ5hZ876//japjHBKA9SB7gsCrLx3m+0XI8TkWUZTZJHETJHHVjJN8xjRvMv5gWKLvRsz7ScmnN1+ckL6 rsa.pub
|
||||||
`),
|
`),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
// implementation. Instead, use AES (from crypto/aes, if necessary in an AEAD
|
// implementation. Instead, use AES (from crypto/aes, if necessary in an AEAD
|
||||||
// mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
|
// mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
|
||||||
// golang.org/x/crypto/chacha20poly1305).
|
// golang.org/x/crypto/chacha20poly1305).
|
||||||
package twofish // import "golang.org/x/crypto/twofish"
|
package twofish
|
||||||
|
|
||||||
// Twofish is defined in https://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
|
// Twofish is defined in https://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
|
||||||
|
|
||||||
|
|||||||
@@ -1526,6 +1526,24 @@ u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
|
|||||||
bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
|
bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
|
||||||
fF6adulZkMV8gzURZVE=
|
fF6adulZkMV8gzURZVE=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
# CN=FIRMAPROFESIONAL CA ROOT-A WEB,O=Firmaprofesional SA,C=ES,2.5.4.97=#130f56415445532d413632363334303638
|
||||||
|
# bef256daf26e9c69bdec1602359798f3caf71821a03e018257c53c65617f3d4a
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw
|
||||||
|
CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE
|
||||||
|
YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB
|
||||||
|
IFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2WhcNNDcwMzMxMDkwMTM2WjBuMQsw
|
||||||
|
CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE
|
||||||
|
YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB
|
||||||
|
IFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zf
|
||||||
|
e9MEkVz6iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6C
|
||||||
|
cyvHZpsKjECcfIr28jlgst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB
|
||||||
|
/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FDY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0O
|
||||||
|
BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO
|
||||||
|
PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw
|
||||||
|
hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG
|
||||||
|
XSaQpYXFuXqUPoeovQA=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
# CN=GDCA TrustAUTH R5 ROOT,O=GUANG DONG CERTIFICATE AUTHORITY CO.\,LTD.,C=CN
|
# CN=GDCA TrustAUTH R5 ROOT,O=GUANG DONG CERTIFICATE AUTHORITY CO.\,LTD.,C=CN
|
||||||
# bfff8fd04433487d6a8aa60c1a29767a9fc2bbb05e420f713a13b992891d3893
|
# bfff8fd04433487d6a8aa60c1a29767a9fc2bbb05e420f713a13b992891d3893
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
@@ -3078,34 +3096,6 @@ WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
|
|||||||
e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
|
e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
|
||||||
TpPDpFQUWw==
|
TpPDpFQUWw==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1,OU=Kamu Sertifikasyon Merkezi - Kamu SM,O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK,L=Gebze - Kocaeli,C=TR
|
|
||||||
# 46edc3689046d53a453fb3104ab80dcaec658b2660ea1629dd7e867990648716
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx
|
|
||||||
GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp
|
|
||||||
bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w
|
|
||||||
KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0
|
|
||||||
BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy
|
|
||||||
dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG
|
|
||||||
EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll
|
|
||||||
IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU
|
|
||||||
QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT
|
|
||||||
TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg
|
|
||||||
LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7
|
|
||||||
a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr
|
|
||||||
LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr
|
|
||||||
N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X
|
|
||||||
YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/
|
|
||||||
iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f
|
|
||||||
AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH
|
|
||||||
V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
|
|
||||||
BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
|
|
||||||
AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf
|
|
||||||
IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4
|
|
||||||
lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c
|
|
||||||
8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf
|
|
||||||
lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW
|
# CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW
|
||||||
# 59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b
|
# 59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
@@ -3162,6 +3152,58 @@ lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn
|
|||||||
aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
|
aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
|
||||||
YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
|
YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
# CN=Telekom Security TLS ECC Root 2020,O=Deutsche Telekom Security GmbH,C=DE
|
||||||
|
# 578af4ded0853f4e5998db4aeaf9cbea8d945f60b620a38d1a3c13b2bc7ba8e1
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw
|
||||||
|
CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH
|
||||||
|
bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw
|
||||||
|
MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx
|
||||||
|
JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE
|
||||||
|
AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49
|
||||||
|
AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O
|
||||||
|
tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP
|
||||||
|
f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f
|
||||||
|
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
|
||||||
|
MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di
|
||||||
|
z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn
|
||||||
|
27iQ7t0l
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
# CN=Telekom Security TLS RSA Root 2023,O=Deutsche Telekom Security GmbH,C=DE
|
||||||
|
# efc65cadbb59adb6efe84da22311b35624b71b3b1ea0da8b6655174ec8978646
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj
|
||||||
|
MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0
|
||||||
|
eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy
|
||||||
|
MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC
|
||||||
|
REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG
|
||||||
|
A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ
|
||||||
|
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9
|
||||||
|
cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV
|
||||||
|
cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA
|
||||||
|
U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6
|
||||||
|
Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug
|
||||||
|
BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy
|
||||||
|
8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J
|
||||||
|
co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg
|
||||||
|
8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8
|
||||||
|
rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12
|
||||||
|
mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg
|
||||||
|
+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX
|
||||||
|
gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2
|
||||||
|
p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ
|
||||||
|
pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm
|
||||||
|
9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw
|
||||||
|
M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd
|
||||||
|
GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+
|
||||||
|
CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t
|
||||||
|
xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+
|
||||||
|
w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK
|
||||||
|
L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj
|
||||||
|
X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q
|
||||||
|
ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm
|
||||||
|
dTdmQRCsu/WU48IxK63nI1bMNSWSs1A=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
# CN=Telia Root CA v2,O=Telia Finland Oyj,C=FI
|
# CN=Telia Root CA v2,O=Telia Finland Oyj,C=FI
|
||||||
# 242b69742fcb1e5b2abf98898b94572187544e5b4d9911786573621f6a74b82c
|
# 242b69742fcb1e5b2abf98898b94572187544e5b4d9911786573621f6a74b82c
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
@@ -3740,28 +3782,6 @@ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
|||||||
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||||
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# OU=Security Communication RootCA1,O=SECOM Trust.net,C=JP
|
|
||||||
# e75e72ed9f560eec6eb4800073a43fc3ad19195a392282017895974a99026b6c
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
|
|
||||||
MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
|
|
||||||
dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
|
|
||||||
WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD
|
|
||||||
VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3
|
|
||||||
DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8
|
|
||||||
9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ
|
|
||||||
DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9
|
|
||||||
Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N
|
|
||||||
QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ
|
|
||||||
xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G
|
|
||||||
A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T
|
|
||||||
AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG
|
|
||||||
kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr
|
|
||||||
Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
|
|
||||||
Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
|
|
||||||
JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
|
|
||||||
RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# OU=Security Communication RootCA2,O=SECOM Trust Systems CO.\,LTD.,C=JP
|
# OU=Security Communication RootCA2,O=SECOM Trust Systems CO.\,LTD.,C=JP
|
||||||
# 513b2cecb810d4cde5dd85391adfc6c2dd60d87bb736d2b521484aa47a0ebef6
|
# 513b2cecb810d4cde5dd85391adfc6c2dd60d87bb736d2b521484aa47a0ebef6
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
|
|||||||
@@ -147,6 +147,20 @@ func parseTrustClass(s *bufio.Scanner) ([sha1.Size]byte, *trustObj, error) {
|
|||||||
return h, to, nil
|
return h, to, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// manualExclusions contains a map of SHA1 fingerprints of roots that we manually exclude
|
||||||
|
// from the bundle for various reasons.
|
||||||
|
var manualExclusions = map[string]bool{
|
||||||
|
// TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
|
||||||
|
// We exclude this root because mozilla manually constrains this root to
|
||||||
|
// issue names under .tr, but this information is only encoded in the CCADB
|
||||||
|
// IncludedCACertificateReport, in a field the format of which is
|
||||||
|
// undocumented, and is only used for this particular certificate. Rather
|
||||||
|
// than adding special parsing for this, we skip it. When code constraint
|
||||||
|
// support is available, we may also want to simply add a manual constraint,
|
||||||
|
// rather than a manual exclusion.
|
||||||
|
"3143649becce27eced3a3f0b8f0de4e891ddeeca": true,
|
||||||
|
}
|
||||||
|
|
||||||
// Parse parses a NSS certdata.txt formatted file, returning only
|
// Parse parses a NSS certdata.txt formatted file, returning only
|
||||||
// trusted serverAuth roots, as well as any additional constraints. This parser
|
// trusted serverAuth roots, as well as any additional constraints. This parser
|
||||||
// is very opinionated, only returning roots that are currently trusted for
|
// is very opinionated, only returning roots that are currently trusted for
|
||||||
@@ -248,6 +262,9 @@ func Parse(r io.Reader) ([]*Certificate, error) {
|
|||||||
if !e.trust.trusted {
|
if !e.trust.trusted {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if manualExclusions[fmt.Sprintf("%x", h)] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
nssCert := &Certificate{X509: e.cert.c}
|
nssCert := &Certificate{X509: e.cert.c}
|
||||||
if e.cert.DistrustAfter != nil {
|
if e.cert.DistrustAfter != nil {
|
||||||
nssCert.Constraints = append(nssCert.Constraints, DistrustAfter(*e.cert.DistrustAfter))
|
nssCert.Constraints = append(nssCert.Constraints, DistrustAfter(*e.cert.DistrustAfter))
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,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 xtea // import "golang.org/x/crypto/xtea"
|
package xtea
|
||||||
|
|
||||||
// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
|
// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@
|
|||||||
//
|
//
|
||||||
// Note that XTS is usually not appropriate for any use besides disk encryption.
|
// Note that XTS is usually not appropriate for any use besides disk encryption.
|
||||||
// Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
|
// Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead.
|
||||||
package xts // import "golang.org/x/crypto/xts"
|
package xts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
|||||||
Reference in New Issue
Block a user