mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-15 18:08:45 -07:00
356c5055ad
### Purpose Remove the `lib/sha256` package, because it's no longer necessary. Go's standard library now has the same performance and is on par with `sha256-simd` since [Since Go 1.21](1a64574f42
). Therefore using `sha256-simd` has no benefits anymore. ARM already has optimized sha256 assembly code since7b8a7f8272
, `sha256-simd` published their results before that optimized assembly was implemented,f941fedda8
. The assembly looks very similar and the benchmarks in the Go commit match that of `sha256-simd`. This patch removes all of the related code of `lib/sha256` and makes `crypto/sha256` the 'default'. Benchmark of `sha256-simd` and `crypto/sha256`: <details> ``` cpu: AMD Ryzen 5 3600X 6-Core Processor │ simd.txt │ go.txt │ │ sec/op │ sec/op vs base │ Hash/8Bytes-12 63.25n ± 1% 73.38n ± 1% +16.02% (p=0.002 n=6) Hash/64Bytes-12 98.73n ± 1% 105.30n ± 1% +6.65% (p=0.002 n=6) Hash/1K-12 567.2n ± 1% 572.8n ± 1% +0.99% (p=0.002 n=6) Hash/8K-12 4.062µ ± 1% 4.062µ ± 1% ~ (p=0.396 n=6) Hash/1M-12 512.1µ ± 0% 510.6µ ± 1% ~ (p=0.485 n=6) Hash/5M-12 2.556m ± 1% 2.564m ± 0% ~ (p=0.093 n=6) Hash/10M-12 5.112m ± 0% 5.127m ± 0% ~ (p=0.093 n=6) geomean 13.82µ 14.27µ +3.28% │ simd.txt │ go.txt │ │ B/s │ B/s vs base │ Hash/8Bytes-12 120.6Mi ± 1% 104.0Mi ± 1% -13.81% (p=0.002 n=6) Hash/64Bytes-12 618.2Mi ± 1% 579.8Mi ± 1% -6.22% (p=0.002 n=6) Hash/1K-12 1.682Gi ± 1% 1.665Gi ± 1% -0.98% (p=0.002 n=6) Hash/8K-12 1.878Gi ± 1% 1.878Gi ± 1% ~ (p=0.310 n=6) Hash/1M-12 1.907Gi ± 0% 1.913Gi ± 1% ~ (p=0.485 n=6) Hash/5M-12 1.911Gi ± 1% 1.904Gi ± 0% ~ (p=0.093 n=6) Hash/10M-12 1.910Gi ± 0% 1.905Gi ± 0% ~ (p=0.093 n=6) geomean 1.066Gi 1.032Gi -3.18% ``` </details> ### Testing Compiled and tested on Linux. ### Documentation https://github.com/syncthing/docs/pull/874
222 lines
4.4 KiB
Go
222 lines
4.4 KiB
Go
// Copyright (C) 2014 The Protocol Authors.
|
|
|
|
package protocol
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/base32"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
DeviceIDLength = 32
|
|
// keep consistent with shortIDStringLength in gui/default/syncthing/app.js
|
|
ShortIDStringLength = 7
|
|
)
|
|
|
|
type (
|
|
DeviceID [DeviceIDLength]byte
|
|
ShortID uint64
|
|
)
|
|
|
|
var (
|
|
LocalDeviceID = repeatedDeviceID(0xff)
|
|
GlobalDeviceID = repeatedDeviceID(0xf8)
|
|
EmptyDeviceID = DeviceID{ /* all zeroes */ }
|
|
)
|
|
|
|
func repeatedDeviceID(v byte) (d DeviceID) {
|
|
for i := range d {
|
|
d[i] = v
|
|
}
|
|
return
|
|
}
|
|
|
|
// NewDeviceID generates a new device ID from the raw bytes of a certificate
|
|
func NewDeviceID(rawCert []byte) DeviceID {
|
|
return DeviceID(sha256.Sum256(rawCert))
|
|
}
|
|
|
|
func DeviceIDFromString(s string) (DeviceID, error) {
|
|
var n DeviceID
|
|
err := n.UnmarshalText([]byte(s))
|
|
return n, err
|
|
}
|
|
|
|
func DeviceIDFromBytes(bs []byte) (DeviceID, error) {
|
|
var n DeviceID
|
|
if len(bs) != len(n) {
|
|
return n, errors.New("incorrect length of byte slice representing device ID")
|
|
}
|
|
copy(n[:], bs)
|
|
return n, nil
|
|
}
|
|
|
|
// String returns the canonical string representation of the device ID
|
|
func (n DeviceID) String() string {
|
|
if n == EmptyDeviceID {
|
|
return ""
|
|
}
|
|
id := base32.StdEncoding.EncodeToString(n[:])
|
|
id = strings.Trim(id, "=")
|
|
id, err := luhnify(id)
|
|
if err != nil {
|
|
// Should never happen
|
|
panic(err)
|
|
}
|
|
id = chunkify(id)
|
|
return id
|
|
}
|
|
|
|
func (n DeviceID) GoString() string {
|
|
return n.String()
|
|
}
|
|
|
|
func (n DeviceID) Compare(other DeviceID) int {
|
|
return bytes.Compare(n[:], other[:])
|
|
}
|
|
|
|
func (n DeviceID) Equals(other DeviceID) bool {
|
|
return bytes.Equal(n[:], other[:])
|
|
}
|
|
|
|
// Short returns an integer representing bits 0-63 of the device ID.
|
|
func (n DeviceID) Short() ShortID {
|
|
return ShortID(binary.BigEndian.Uint64(n[:]))
|
|
}
|
|
|
|
func (n DeviceID) MarshalText() ([]byte, error) {
|
|
return []byte(n.String()), nil
|
|
}
|
|
|
|
func (s ShortID) String() string {
|
|
if s == 0 {
|
|
return ""
|
|
}
|
|
var bs [8]byte
|
|
binary.BigEndian.PutUint64(bs[:], uint64(s))
|
|
return base32.StdEncoding.EncodeToString(bs[:])[:ShortIDStringLength]
|
|
}
|
|
|
|
func (n *DeviceID) UnmarshalText(bs []byte) error {
|
|
id := string(bs)
|
|
id = strings.Trim(id, "=")
|
|
id = strings.ToUpper(id)
|
|
id = untypeoify(id)
|
|
id = unchunkify(id)
|
|
|
|
var err error
|
|
switch len(id) {
|
|
case 0:
|
|
*n = EmptyDeviceID
|
|
return nil
|
|
case 56:
|
|
// New style, with check digits
|
|
id, err = unluhnify(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fallthrough
|
|
case 52:
|
|
// Old style, no check digits
|
|
dec, err := base32.StdEncoding.DecodeString(id + "====")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
copy(n[:], dec)
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("%q: device ID invalid: incorrect length", bs)
|
|
}
|
|
}
|
|
|
|
func (*DeviceID) ProtoSize() int {
|
|
// Used by protobuf marshaller.
|
|
return DeviceIDLength
|
|
}
|
|
|
|
func (n *DeviceID) MarshalTo(bs []byte) (int, error) {
|
|
// Used by protobuf marshaller.
|
|
if len(bs) < DeviceIDLength {
|
|
return 0, errors.New("destination too short")
|
|
}
|
|
copy(bs, (*n)[:])
|
|
return DeviceIDLength, nil
|
|
}
|
|
|
|
func (n *DeviceID) Unmarshal(bs []byte) error {
|
|
// Used by protobuf marshaller.
|
|
if len(bs) < DeviceIDLength {
|
|
return fmt.Errorf("%q: not enough data", bs)
|
|
}
|
|
copy((*n)[:], bs)
|
|
return nil
|
|
}
|
|
|
|
func luhnify(s string) (string, error) {
|
|
if len(s) != 52 {
|
|
panic("unsupported string length")
|
|
}
|
|
|
|
res := make([]byte, 4*(13+1))
|
|
for i := 0; i < 4; i++ {
|
|
p := s[i*13 : (i+1)*13]
|
|
copy(res[i*(13+1):], p)
|
|
l, err := luhn32(p)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
res[(i+1)*(13)+i] = byte(l)
|
|
}
|
|
return string(res), nil
|
|
}
|
|
|
|
func unluhnify(s string) (string, error) {
|
|
if len(s) != 56 {
|
|
return "", fmt.Errorf("%q: unsupported string length %d", s, len(s))
|
|
}
|
|
|
|
res := make([]byte, 52)
|
|
for i := 0; i < 4; i++ {
|
|
p := s[i*(13+1) : (i+1)*(13+1)-1]
|
|
copy(res[i*13:], p)
|
|
l, err := luhn32(p)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if s[(i+1)*14-1] != byte(l) {
|
|
return "", fmt.Errorf("%q: check digit incorrect", s)
|
|
}
|
|
}
|
|
return string(res), nil
|
|
}
|
|
|
|
func chunkify(s string) string {
|
|
chunks := len(s) / 7
|
|
res := make([]byte, chunks*(7+1)-1)
|
|
for i := 0; i < chunks; i++ {
|
|
if i > 0 {
|
|
res[i*(7+1)-1] = '-'
|
|
}
|
|
copy(res[i*(7+1):], s[i*7:(i+1)*7])
|
|
}
|
|
return string(res)
|
|
}
|
|
|
|
func unchunkify(s string) string {
|
|
s = strings.ReplaceAll(s, "-", "")
|
|
s = strings.ReplaceAll(s, " ", "")
|
|
return s
|
|
}
|
|
|
|
func untypeoify(s string) string {
|
|
s = strings.ReplaceAll(s, "0", "O")
|
|
s = strings.ReplaceAll(s, "1", "I")
|
|
s = strings.ReplaceAll(s, "8", "B")
|
|
return s
|
|
}
|