mirror of
https://github.com/luxfi/utxo.git
synced 2026-10-30 15:13:57 +00:00
70 lines
1.9 KiB
Go
70 lines
1.9 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package ed25519fx provides Ed25519 credentials for UTXO spending on X-Chain.
|
|
//
|
|
// Ed25519 is a high-performance EdDSA signature scheme over Curve25519.
|
|
// It is the native signature scheme for Solana, Cardano, NEAR, Polkadot,
|
|
// and many other ecosystems.
|
|
//
|
|
// Fixed sizes:
|
|
// - Public key: 32 bytes
|
|
// - Signature: 64 bytes
|
|
package ed25519fx
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/formatting"
|
|
)
|
|
|
|
const (
|
|
PubKeyLen = ed25519.PublicKeySize // 32
|
|
SigLen = ed25519.SignatureSize // 64
|
|
)
|
|
|
|
var (
|
|
ErrNilCredential = errors.New("nil Ed25519 credential")
|
|
ErrEmptyCredential = errors.New("empty Ed25519 credential")
|
|
ErrInvalidSignature = errors.New("invalid Ed25519 signature")
|
|
ErrWrongSigLen = errors.New("Ed25519 signature wrong length")
|
|
)
|
|
|
|
// Credential contains Ed25519 signatures for spending UTXOs.
|
|
// Unlike secp256k1, Ed25519 cannot recover the public key from a signature,
|
|
// so the credential must carry the public keys alongside the signatures.
|
|
type Credential struct {
|
|
Sigs [][SigLen]byte `serialize:"true" json:"signatures"`
|
|
PubKeys [][]byte `serialize:"true" json:"publicKeys"`
|
|
}
|
|
|
|
// Verify validates the credential structure.
|
|
func (cr *Credential) Verify() error {
|
|
if cr == nil {
|
|
return ErrNilCredential
|
|
}
|
|
if len(cr.Sigs) == 0 {
|
|
return ErrEmptyCredential
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MarshalJSON marshals the credential to JSON with hex-encoded signatures
|
|
func (cr *Credential) MarshalJSON() ([]byte, error) {
|
|
sigs := make([]string, len(cr.Sigs))
|
|
for i, sig := range cr.Sigs {
|
|
sigStr, err := formatting.Encode(formatting.HexNC, sig[:])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't encode signature %d: %w", i, err)
|
|
}
|
|
sigs[i] = sigStr
|
|
}
|
|
|
|
return json.Marshal(map[string]interface{}{
|
|
"signatures": sigs,
|
|
})
|
|
}
|