summaryrefslogtreecommitdiff
path: root/vendor/github.com/wybiral/torgo/ed25519.go
blob: bbdd0c743462dabcb8d7c7b26741805a854b6f2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package torgo

import (
	"crypto/sha512"
	"encoding/base32"
	"encoding/base64"
	"errors"
	"strings"

	"golang.org/x/crypto/ed25519"
	"golang.org/x/crypto/sha3"
)

// OnionFromEd25519 returns an Onion instance from an ED25519 private key which
// can be used to start a hidden service with controller.AddOnion.
func OnionFromEd25519(pri ed25519.PrivateKey) (*Onion, error) {
	pub, ok := pri.Public().(ed25519.PublicKey)
	if !ok {
		return nil, errors.New("torgo: unable to extract ed25519.PublicKey")
	}
	serviceID, err := ServiceIDFromEd25519(pub)
	if err != nil {
		return nil, err
	}
	h := sha512.Sum512(pri[:32])
	// Set bits so that h[:32] is private scalar "a"
	h[0] &= 248
	h[31] &= 127
	h[31] |= 64
	// Since h[32:] is RH, h is now (a || RH)
	key := base64.StdEncoding.EncodeToString(h[:])
	return &Onion{
		Ports:          make(map[int]string),
		ServiceID:      serviceID,
		PrivateKey:     key,
		PrivateKeyType: "ED25519-V3",
	}, nil
}

// ServiceIDFromEd25519 calculates a Tor service ID from an ed25519.PublicKey.
func ServiceIDFromEd25519(pub ed25519.PublicKey) (string, error) {
	checkdigits := ed25519Checkdigits(pub)
	combined := pub[:]
	combined = append(combined, checkdigits...)
	combined = append(combined, 0x03)
	serviceID := base32.StdEncoding.EncodeToString(combined)
	return strings.ToLower(serviceID), nil
}

// ed25519Checkdigits calculates tje check digits used to create service ID.
func ed25519Checkdigits(pub ed25519.PublicKey) []byte {
	checkstr := []byte(".onion checksum")
	checkstr = append(checkstr, pub...)
	checkstr = append(checkstr, 0x03)
	checksum := sha3.Sum256(checkstr)
	return checksum[:2]
}