package keyimport ()const (// PublicKeySize is the size of an Ed25519 public key, in bytes.PublicKeySize = ed25519.PublicKeySize// PrivateKeySize is the size of an Ed25519 private key, in bytes.PrivateKeySize = ed25519.PrivateKeySize// SeedSize is the size of an Ed25519 private key seed, in bytes.SeedSize = ed25519.SeedSize// SignatureSize is the size of an Ed25519 signature, in bytes.SignatureSize = ed25519.SignatureSize)// zBase32 is the z-base-32 encoding used by pkarr (https://pkarr.org) for// endpoint-id domain names. Its alphabet differs from RFC 4648 base32.const zBase32Alphabet = "ybndrfg8ejkmcpqxot1uwisza345h769"// Errors returned when parsing keys.var (// ErrInvalidKeyData is returned when bytes do not represent a valid // Ed25519 curve point.ErrInvalidKeyData = errors.New("data is not a valid public key")// ErrInvalidKeyLength is returned when key bytes have the wrong length.ErrInvalidKeyLength = errors.New("invalid length")// ErrDecodeHex is returned when a string cannot be decoded as hex.ErrDecodeHex = errors.New("failed to decode hex string")// ErrDecodeBase32 is returned when a string cannot be decoded as base32.ErrDecodeBase32 = errors.New("failed to decode base32 string"))// PublicKey is a public Ed25519 key. It is verified to be a valid curve point// when created.//// The zero value is not usable; construct a PublicKey with [NewPublicKey],// [ParsePublicKey], or [SecretKey.Public].typePublicKeystruct { bytes [PublicKeySize]byte}// EndpointID is a network-facing identifier for an endpoint.//// Use EndpointID in network-facing APIs and [PublicKey] when performing// cryptographic operations.typeEndpointIDPublicKey// NewPublicKey constructs a PublicKey from a 32-byte array. It returns// [ErrInvalidKeyData] if the bytes do not decompress to a valid Ed25519 curve// point. It never fails for bytes returned from [PublicKey.Bytes].func ( [PublicKeySize]byte) (PublicKey, error) {if , := new(edwards25519.Point).SetBytes([:]); != nil {returnPublicKey{}, ErrInvalidKeyData }returnPublicKey{bytes: }, nil}// NewEndpointID constructs an EndpointID from a 32-byte array.func ( [PublicKeySize]byte) (EndpointID, error) { , := NewPublicKey()if != nil {returnEndpointID{}, }return .EndpointID(), nil}// PublicKeyFromEd25519 constructs a PublicKey from a crypto/ed25519 public key.func ( ed25519.PublicKey) (PublicKey, error) {returnPublicKeyFromSlice()}// PublicKeyFromSlice constructs a PublicKey from a byte slice. It returns// [ErrInvalidKeyLength] if the slice is not 32 bytes and [ErrInvalidKeyData] if// the bytes are not a valid curve point.func ( []byte) (PublicKey, error) {iflen() != PublicKeySize {returnPublicKey{}, ErrInvalidKeyLength }var [PublicKeySize]bytecopy([:], )returnNewPublicKey()}// EndpointIDFromSlice constructs an EndpointID from a byte slice.func ( []byte) (EndpointID, error) { , := PublicKeyFromSlice()if != nil {returnEndpointID{}, }return .EndpointID(), nil}// EndpointID returns the endpoint identifier for k.func ( PublicKey) () EndpointID { returnEndpointID() }// Bytes returns the public key as a 32-byte array.func ( PublicKey) () [PublicKeySize]byte { return .bytes }// Ed25519 returns the key as a crypto/ed25519 public key. The returned slice is// a copy and may be modified by the caller.func ( PublicKey) () ed25519.PublicKey { := make(ed25519.PublicKey, PublicKeySize)copy(, .bytes[:])return}// Verify reports whether sig is a valid signature of message by k. It returns// nil on success and [ErrInvalidSignature] otherwise.//// Verification uses crypto/ed25519 (cofactored, RFC 8032). The Rust reference// uses ed25519-dalek's verify_strict (cofactorless). The two agree for every// signature an honest iroh peer produces; they differ only for adversarially// malleable signatures, which iroh drops anyway. This divergence is benign for// iroh's drop-on-failure model (relay handshake, TLS raw-key, and pkarr packet// verification all reject on failure).func ( PublicKey) ( []byte, Signature) error {return .verify(, )}// IsZero reports whether k is the unusable zero value.func ( PublicKey) () bool { return == PublicKey{} }// Equal reports whether k and other are the same key.func ( PublicKey) ( PublicKey) bool { return .bytes == .bytes }// Compare returns -1, 0, or +1 comparing k and other by their raw bytes. It// gives PublicKey a total order suitable for sorting and map-free ordered use.func ( PublicKey) ( PublicKey) int {returnbytes.Compare(.bytes[:], .bytes[:])}// String returns the lowercase-hex encoding of the key. It is the canonical// human-readable form and round-trips through [ParsePublicKey].func ( PublicKey) () string {returnhex.EncodeToString(.bytes[:])}// Short returns a short, friendly hex string of the first 5 bytes of the key,// for logging. It is not a complete or parseable representation.func ( PublicKey) () string {returnhex.EncodeToString(.bytes[:5])}// PublicKey returns id as a public key for cryptographic operations.func ( EndpointID) () PublicKey { returnPublicKey() }// Bytes returns the endpoint id as a 32-byte array.func ( EndpointID) () [PublicKeySize]byte { return .PublicKey().Bytes() }// IsZero reports whether id is the unusable zero value.func ( EndpointID) () bool { return == EndpointID{} }// Equal reports whether id and other are the same endpoint id.func ( EndpointID) ( EndpointID) bool {return .PublicKey().Equal(.PublicKey())}// Compare returns -1, 0, or +1 comparing id and other by their raw bytes. It// gives EndpointID a total order suitable for sorting and map-free ordered use.func ( EndpointID) ( EndpointID) int {return .PublicKey().Compare(.PublicKey())}// String returns the lowercase-hex encoding of the endpoint id. It is the// canonical human-readable form and round-trips through [ParseEndpointID].func ( EndpointID) () string { return .PublicKey().String() }// Short returns a short, friendly hex string of the first 5 bytes of the// endpoint id, for logging. It is not a complete or parseable representation.func ( EndpointID) () string { return .PublicKey().Short() }// Z32 encodes the endpoint id in z-base-32, the encoding used by pkarr domain// names.func ( EndpointID) () string { := .PublicKey()returnencodeZBase32(.bytes[:])}// ParseEndpointIDZ32 parses an endpoint id from its z-base-32 encoding.func ( string) (EndpointID, error) { , := decodeZBase32()if != nil {returnEndpointID{}, ErrDecodeBase32 }returnEndpointIDFromSlice()}// ParsePublicKey parses a PublicKey from its hex or base32 string form. A string// of exactly 64 characters is decoded as lowercase hex; otherwise it is decoded// as RFC 4648 base32 (no padding, case-insensitive). [PublicKey.String] always// produces the hex form.func ( string) (PublicKey, error) { , := decodeBase32OrHex()if != nil {returnPublicKey{}, }returnNewPublicKey()}// ParseEndpointID parses an EndpointID from its hex or base32 string form.func ( string) (EndpointID, error) { , := ParsePublicKey()if != nil {returnEndpointID{}, }return .EndpointID(), nil}// MarshalText implements encoding.TextMarshaler, producing the hex form.func ( PublicKey) () ([]byte, error) {return []byte(.String()), nil}// UnmarshalText implements encoding.TextUnmarshaler, parsing the hex or base32// form.func ( *PublicKey) ( []byte) error { , := ParsePublicKey(string())if != nil {return } * = returnnil}// MarshalText implements encoding.TextMarshaler, producing the hex form.func ( EndpointID) () ([]byte, error) {return []byte(.String()), nil}// UnmarshalText implements encoding.TextUnmarshaler, parsing the hex or base32// form.func ( *EndpointID) ( []byte) error { , := ParseEndpointID(string())if != nil {return } * = returnnil}// MarshalBinary implements encoding.BinaryMarshaler, producing the 32 raw bytes.func ( PublicKey) () ([]byte, error) { := .bytesreturn [:], nil}// UnmarshalBinary implements encoding.BinaryUnmarshaler from 32 raw bytes.func ( *PublicKey) ( []byte) error { , := PublicKeyFromSlice()if != nil {return } * = returnnil}// MarshalBinary implements encoding.BinaryMarshaler, producing the 32 raw bytes.func ( EndpointID) () ([]byte, error) {return .PublicKey().MarshalBinary()}// UnmarshalBinary implements encoding.BinaryUnmarshaler from 32 raw bytes.func ( *EndpointID) ( []byte) error { , := EndpointIDFromSlice()if != nil {return } * = returnnil}// SecretKey is a secret endpoint identity key. Its public part can always be// recovered.//// Go has no destructors, so unlike the Rust original this type is not cleared// automatically. Call [SecretKey.Clear] to overwrite the key material when a// long-lived secret is no longer needed.//// The zero value is not usable; construct with [GenerateSecretKey],// [NewSecretKey], or [ParseSecretKey].typeSecretKeystruct { signing ed25519.PrivateKey// 64 bytes: seed||public}// GenerateSecretKey generates a new SecretKey using crypto/ed25519.func () (SecretKey, error) { , , := ed25519.GenerateKey(rand.Reader)if != nil {returnSecretKey{}, fmt.Errorf("generate secret key: %w", ) }returnSecretKey{signing: }, nil}// NewSecretKey constructs a SecretKey from its 32-byte seed.func ( [SeedSize]byte) SecretKey {returnSecretKey{signing: ed25519.NewKeyFromSeed([:])}}// SecretKeyFromEd25519 constructs a SecretKey from a crypto/ed25519 private key.// The private key is copied.func ( ed25519.PrivateKey) (SecretKey, error) {iflen() != PrivateKeySize {returnSecretKey{}, ErrInvalidKeyLength }returnSecretKey{signing: append(ed25519.PrivateKey(nil), ...)}, nil}// SecretKeyFromSlice constructs a SecretKey from a 32-byte seed slice. It// returns [ErrInvalidKeyLength] if the slice is not 32 bytes.func ( []byte) (SecretKey, error) {iflen() != SeedSize {returnSecretKey{}, ErrInvalidKeyLength }var [SeedSize]bytecopy([:], )returnNewSecretKey(), nil}// ParseSecretKey parses a SecretKey from its hex or base32 string form, matching// the rules of [ParsePublicKey].func ( string) (SecretKey, error) { , := decodeBase32OrHex()if != nil {returnSecretKey{}, }returnNewSecretKey(), nil}// Public returns the public key of this secret key.func ( SecretKey) () PublicKey { , := PublicKeyFromEd25519(.signing.Public().(ed25519.PublicKey))return}// Sign signs msg and returns the signature.func ( SecretKey) ( []byte) Signature {return .sign()}// Ed25519 returns the key as a crypto/ed25519 private key. The returned key is// a copy and satisfies crypto.Signer.func ( SecretKey) () ed25519.PrivateKey {returnappend(ed25519.PrivateKey(nil), .signing...)}// Bytes returns the 32-byte seed of the secret key. The public part can be// recovered from it.func ( SecretKey) () [SeedSize]byte {var [SeedSize]bytecopy([:], .signing.Seed())return}// Clear overwrites k's key material and resets k to the zero value. It does not// clear copies already made by value or by [SecretKey.Bytes], [SecretKey.Ed25519],// or [SecretKey.MarshalBinary].func ( *SecretKey) () {if == nil {return }clear(.signing) .signing = nil}// IsZero reports whether k is the unusable zero value.func ( SecretKey) () bool { return .signing == nil }// MarshalBinary implements encoding.BinaryMarshaler, producing the 32-byte seed.func ( SecretKey) () ([]byte, error) { := .Bytes()return [:], nil}// UnmarshalBinary implements encoding.BinaryUnmarshaler from a 32-byte seed.func ( *SecretKey) ( []byte) error { , := SecretKeyFromSlice()if != nil {return } * = returnnil}// Signature is a signature produced by a [SecretKey].typeSignaturestruct { bytes [SignatureSize]byte}// NewSignature constructs a Signature from its 64 raw bytes.func ( [SignatureSize]byte) Signature {returnSignature{bytes: }}// SignatureFromEd25519 constructs a Signature from a crypto/ed25519 signature.func ( []byte) (Signature, error) {returnSignatureFromSlice()}// SignatureFromSlice constructs a Signature from a byte slice. It returns// [ErrInvalidSignatureParse] if the slice is not 64 bytes.func ( []byte) (Signature, error) {iflen() != SignatureSize {returnSignature{}, ErrInvalidSignatureParse }var [SignatureSize]bytecopy([:], )returnSignature{bytes: }, nil}// Bytes returns the signature as a 64-byte array.func ( Signature) () [SignatureSize]byte { return .bytes }// Ed25519 returns the signature bytes used by crypto/ed25519. The returned// slice is a copy and may be modified by the caller.func ( Signature) () []byte { := make([]byte, SignatureSize)copy(, .bytes[:])return}// String returns the lowercase-hex encoding of the signature.func ( Signature) () string { returnhex.EncodeToString(.bytes[:]) }// MarshalText implements encoding.TextMarshaler, producing the hex form.func ( Signature) () ([]byte, error) {return []byte(.String()), nil}// UnmarshalText implements encoding.TextUnmarshaler, parsing the hex form.func ( *Signature) ( []byte) error { , := hex.DecodeString(string())if != nil {returnErrDecodeHex } , := SignatureFromSlice()if != nil {return } * = returnnil}// MarshalBinary implements encoding.BinaryMarshaler, producing the 64 raw// signature bytes.func ( Signature) () ([]byte, error) { := .bytesreturn [:], nil}// UnmarshalBinary implements encoding.BinaryUnmarshaler from 64 raw bytes.func ( *Signature) ( []byte) error { , := SignatureFromSlice()if != nil {return } * = returnnil}// Equal reports whether s and other are the same signature.func ( Signature) ( Signature) bool { return .bytes == .bytes }// Signature parsing and verification errors.var (// ErrInvalidSignatureParse is returned when bytes cannot be parsed as an // Ed25519 signature.ErrInvalidSignatureParse = errors.New("could not parse ed25519 signature")// ErrInvalidSignature is returned when signature verification fails.ErrInvalidSignature = errors.New("invalid signature"))// decodeBase32OrHex decodes a 32-byte value from a key's string form: 64-char// strings are lowercase hex, others are RFC 4648 base32 (no padding).func decodeBase32OrHex( string) ([32]byte, error) {var [32]byteiflen() == PublicKeySize*2 { , := hex.DecodeString()if != nil {return , ErrDecodeHex }copy([:], )return , nil } , := decodeStdBase32NoPad(strings.ToUpper())if != nil {return , ErrDecodeBase32 }iflen() != PublicKeySize {return , ErrInvalidKeyLength }copy([:], )return , nil}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.