aboutsummaryrefslogtreecommitdiff
path: root/pkg/oaddr/oaddr.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/oaddr/oaddr.go')
-rw-r--r--pkg/oaddr/oaddr.go58
1 files changed, 58 insertions, 0 deletions
diff --git a/pkg/oaddr/oaddr.go b/pkg/oaddr/oaddr.go
new file mode 100644
index 0000000..f065ec9
--- /dev/null
+++ b/pkg/oaddr/oaddr.go
@@ -0,0 +1,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}
+}