Documentation
¶
Overview ¶
Package hyperspace provides a Go interface to Hyperbeam for P2P connections using X25519-derived passcodes.
Hyperspace enables two parties with X25519 keypairs to establish a direct P2P connection through NAT traversal. The passcode is derived from the X25519 shared secret, allowing both parties to compute the same passcode without exchanging any additional information.
Usage:
// Derive passcode from X25519 keys
passcode, err := hyperspace.DerivePasscode(mySecretKey, theirPublicKey)
if err != nil {
log.Fatal(err)
}
// Connect via Hyperbeam
conn, err := hyperspace.Connect(passcode)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// Use conn as an io.ReadWriteCloser
conn.Write([]byte("Hello, peer!"))
Example (PasscodeEncoding) ¶
ExamplePasscodeEncoding demonstrates encoding functions.
package main
import (
"fmt"
"log"
"codeberg.org/OperatorFoundation/hyperspace"
)
func main() {
// Create a passcode
sharedSecret := make([]byte, 32)
for i := range sharedSecret {
sharedSecret[i] = byte(i)
}
passcode, _ := hyperspace.DerivePasscode(sharedSecret)
// Z-base-32 encoding (what hyperbeam expects)
z32 := hyperspace.PasscodeToZ32(passcode)
fmt.Printf("z-base-32: %s\n", z32)
// Hex encoding (for debugging)
hex := hyperspace.PasscodeToHex(passcode)
fmt.Printf("hex: %s\n", hex)
// Decode z-base-32 back to bytes
decoded, err := hyperspace.Z32ToPasscode(z32)
if err != nil {
log.Fatal(err)
}
_ = decoded
}
Output:
Index ¶
- Constants
- Variables
- func ComputeSharedSecret(privateKey, peerPublicKey []byte) ([]byte, error)
- func DefaultNodePath() string
- func DerivePasscode(sharedSecret []byte) ([]byte, error)
- func DerivePasscodeFromKeys(myPrivateKey, theirPublicKey []byte) ([]byte, error)
- func EnsureHyperbeam() error
- func HyperbeamPath() (string, error)
- func InstallHyperbeam() error
- func IsHyperbeamInstalled() bool
- func NodePath() (string, error)
- func NpmPath() (string, error)
- func PasscodeToHex(passcode []byte) string
- func PasscodeToZ32(passcode []byte) string
- func Z32ToPasscode(z32 string) ([]byte, error)
- type ConnectOptions
- type Connection
Examples ¶
Constants ¶
const PasscodeContext = "hyperspace-v1"
PasscodeContext is the domain separation string for passcode derivation. This prevents cross-protocol attacks if the same X25519 keys are used for multiple purposes.
const PasscodeSize = 32
PasscodeSize is the size of the derived passcode in bytes (32 bytes = SHA-256 output).
Variables ¶
var ( ErrInvalidKeySize = fmt.Errorf("key must be %d bytes", curve25519.PointSize) ErrHyperbeamNotFound = fmt.Errorf("hyperbeam not found - install with: npm install -g hyperbeam") )
Errors returned by the package.
Functions ¶
func ComputeSharedSecret ¶
ComputeSharedSecret performs X25519 key exchange between a private key and a peer's public key.
func DefaultNodePath ¶
func DefaultNodePath() string
DefaultNodePath returns the default path for Node.js installation. This is useful for debugging installation issues.
func DerivePasscode ¶
DerivePasscode derives a 32-byte passcode from an X25519 shared secret. The passcode is: SHA-256(sharedSecret || context)
This passcode can be used directly with Hyperbeam.
Example ¶
ExampleDerivePasscode demonstrates passcode derivation.
package main
import (
"fmt"
"log"
"codeberg.org/OperatorFoundation/hyperspace"
)
func main() {
// X25519 keys (32 bytes each)
myPrivateKey := make([]byte, 32)
myPrivateKey[0] = 1 // Non-zero for valid key
theirPublicKey := make([]byte, 32)
theirPublicKey[0] = 2
// Derive passcode
passcode, err := hyperspace.DerivePasscodeFromKeys(myPrivateKey, theirPublicKey)
if err != nil {
log.Fatal(err)
}
// Convert to z-base-32 for hyperbeam
z32 := hyperspace.PasscodeToZ32(passcode)
fmt.Printf("Passcode: %s\n", z32)
}
Output: Passcode: wtb1teqygth1xoni8cdssiu39ypb7n9i5pabjepuofde88qoccto
func DerivePasscodeFromKeys ¶
DerivePasscodeFromKeys derives a passcode directly from X25519 keypairs. This is a convenience function that combines ComputeSharedSecret and DerivePasscode.
func EnsureHyperbeam ¶
func EnsureHyperbeam() error
EnsureHyperbeam ensures hyperbeam is installed, installing if necessary.
func HyperbeamPath ¶
HyperbeamPath returns the path to the hyperbeam executable. It first checks the HYPERBEAM_PATH environment variable, then searches the PATH.
func InstallHyperbeam ¶
func InstallHyperbeam() error
InstallHyperbeam attempts to install hyperbeam globally via npm. Returns an error if npm is not available or installation fails.
func IsHyperbeamInstalled ¶
func IsHyperbeamInstalled() bool
IsHyperbeamInstalled returns true if hyperbeam is available.
func PasscodeToHex ¶
PasscodeToHex converts a passcode to a hexadecimal string.
func PasscodeToZ32 ¶
PasscodeToZ32 encodes a passcode to z-base-32 format. Hyperbeam expects z-base-32 encoded passphrases. z-base-32 uses the alphabet: ybndrfg8ejkmcpqxot1uwisza345h769
func Z32ToPasscode ¶
Z32ToPasscode decodes a z-base-32 string to a passcode.
Types ¶
type ConnectOptions ¶
type ConnectOptions struct {
// Env is additional environment variables.
Env []string
}
ConnectOptions provides optional configuration for connections.
type Connection ¶
type Connection struct {
// contains filtered or unexported fields
}
Connection represents an active Hyperbeam connection.
func Connect ¶
func Connect(passcode string) (*Connection, error)
Connect establishes a P2P connection via Hyperbeam using the given passcode. The passcode should be a z-base-32 encoded string (use PasscodeToZ32).
This function spawns a hyperbeam process and returns a Connection that implements io.ReadWriteCloser.
func ConnectWithKeys ¶
func ConnectWithKeys(myPrivateKey, theirPublicKey []byte) (*Connection, error)
ConnectWithKeys derives a passcode from X25519 keys and establishes a connection. This is a convenience function that combines key exchange, passcode derivation, and connection.
Example ¶
ExampleConnectWithKeys demonstrates basic connection flow.
package main
import (
"fmt"
"log"
"codeberg.org/OperatorFoundation/hyperspace"
)
func main() {
// In a real application, these would come from the keychain:
// myPrivateKey: from keychain.Store.LoadSecret(myKeyID)
// theirPublicKey: from keychain.AddressBook.GetContactPublicKeys(contactID)
// For demonstration, generate test keys
myPrivateKey := make([]byte, 32)
theirPublicKey := make([]byte, 32)
for i := range myPrivateKey {
myPrivateKey[i] = byte(i)
theirPublicKey[i] = byte(i + 1)
}
// Check if hyperbeam is installed
if !hyperspace.IsHyperbeamInstalled() {
fmt.Println("Installing hyperbeam...")
if err := hyperspace.InstallHyperbeam(); err != nil {
log.Fatal(err)
}
}
// Connect using keys directly
conn, err := hyperspace.ConnectWithKeys(myPrivateKey, theirPublicKey)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// Use the connection
_, _ = conn.Write([]byte("Hello, peer!"))
}
Output:
func ConnectWithPasscode ¶
func ConnectWithPasscode(passcode string, opts *ConnectOptions) (*Connection, error)
ConnectWithPasscode establishes a P2P connection via Hyperbeam. If opts is nil, default options are used.
func (*Connection) Close ¶
func (c *Connection) Close() error
Close closes the connection and terminates the hyperbeam process.
func (*Connection) Process ¶
func (c *Connection) Process() *exec.Cmd
Process returns the underlying hyperbeam process. This is exposed for advanced use cases.
func (*Connection) Read ¶
func (c *Connection) Read(p []byte) (n int, err error)
Read reads data from the connection.
func (*Connection) SetOnClose ¶
func (c *Connection) SetOnClose(fn func())
SetOnClose sets a callback to be called when the connection closes.
func (*Connection) Stderr ¶
func (c *Connection) Stderr() io.Reader
Stderr returns a reader for the hyperbeam process's stderr output. Useful for debugging connection issues.