aboutsummaryrefslogtreecommitdiff
path: root/pkg/oaddr/oaddr.go
blob: f065ec974bb4275bb7b06b8582d6d4abc2c6e825 (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
58
// Package oaddr provides onion address formatting
package oaddr

import (
	"crypto"
	"crypto/ed25519"
	"encoding/base32"
	"fmt"
	"strings"

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

// OnionAddress is an Ed25519 public key that represents a v3 onion address
type OnionAddress [ed25519.PublicKeySize]byte

// New outputs an onion address from a public key as defined in RFC 8032
func New(pub []byte) (addr OnionAddress, err error) {
	if got, want := len(pub), ed25519.PublicKeySize; got != want {
		return addr, fmt.Errorf("invalid public key size: %d", got)
	}

	copy(addr[:], pub)
	return addr, nil
}

// NewFromSigner outputs an onion address for a given signer
func NewFromSigner(s crypto.Signer) (addr OnionAddress, err error) {
	switch t := s.Public().(type) {
	case ed25519.PublicKey:
		addr, err = New(s.Public().(ed25519.PublicKey))
	default:
		err = fmt.Errorf("unknown key type: %v", t)
	}
	return
}

// String formats addr as defined in rend-spec-v3, see:
// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt#n2160
func (addr OnionAddress) String() string {
	b := addr[:]
	b = append(b, addr.checksum()...)
	b = append(b, addr.version()...)
	return strings.ToLower(base32.StdEncoding.EncodeToString(b)) + ".onion"
}

func (addr OnionAddress) checksum() []byte {
	h := sha3.New256()
	h.Write([]byte(".onion checksum"))
	h.Write(addr[:])
	h.Write(addr.version())
	sum := h.Sum(nil)
	return sum[:2]
}

func (addr OnionAddress) version() []byte {
	return []byte{0x03}
}